> For the complete documentation index, see [llms.txt](https://docs.overdare.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.overdare.com/korean/manual/studio-manual/game-development/place-and-teleport.md).

# Place & Teleport

## 개요

플레이스는 **하나의 월드를 여러 공간**으로 구성하는 단위입니다.

하나의 월드는 **시작 플레이스**(Start Place)와 **여러 서브 플레이스**로 구성되며, TeleportService를 통해 플레이어를 원하는 플레이스로 자유롭게 이동시킬 수 있습니다.

이를 활용하면 로비, 게임 스테이지, 상점, 개인 공간 등 **다양한 경험을 하나의 월드 안에서 유기적으로 연결**할 수 있습니다.

## 플레이스 구성 예시

플레이스를 활용하면 다음과 같은 구조를 구성할 수 있습니다.

* 로비와 인게임 공간 분리
* 게임모드별 독립 공간 구성
* 서버 단위 부하 분산
* 장시간 플레이 콘텐츠 구성
* 매치 기반 게임 구조 구현

## 월드와 플레이스 구조

월드는 하나의 게임 경험 단위를 의미하며, 플레이스는 해당 월드 안에 포함되는 세부 공간입니다.

```
[World A]
 ├─ Place : Lobby
 ├─ Place : Battle (A Mode)
 ├─ Place : Battle (B Mode)
 └─ Place : MyHome
```

* 하나의 월드는 여러 플레이스를 포함할 수 있습니다.
* 하나의 플레이스는 하나의 월드에만 속할 수 있습니다.
* 시작 플레이스는 월드 진입 시 최초로 입장하는 기본 플레이스입니다.
* 서브 플레이스는 로비, 전투, 결과 화면 등 기능별 공간으로 구성할 수 있습니다.

## 플레이스 관리

### 플레이스 등록 및 연결

OVERDARE Studio에서 프로젝트를 첫 퍼블리시할 때, 기존 월드의 서브 플레이스로 연결할 수 있습니다.

월드가 아닌 플레이스로 등록하려면, 월드 정보 입력 페이지에서 **Add to Existing World를 활성화**합니다.\
(해당 항목을 설정하려면 **Owner**를 먼저 설정해야 합니다.)

<figure><img src="/files/8ydtDGvZePHKkT6Wm2rv" alt=""><figcaption></figcaption></figure>

연결할 월드의 **Connect 버튼**을 클릭합니다.

<figure><img src="/files/5vZ2KUjQFCVFae12Ucc3" alt=""><figcaption></figcaption></figure>

상세 정보를 입력한 다음, **Next 버튼**을 선택합니다.

<figure><img src="/files/yAehBAmZT2GpwXd5qRCs" alt=""><figcaption></figcaption></figure>

### 연결된 플레이스 확인

Studio 또는 Creator Hub에서 현재 월드에 연결된 플레이스 목록을 확인할 수 있습니다.

Studio Home의 **My Worlds 탭**에서 각 월드에 연결된 플레이스를 확인할 수 있습니다.

<figure><img src="/files/jwgf92t3ngydXjqUQVHT" alt=""><figcaption></figcaption></figure>

Studio에서 프로젝트를 열고 **Asset Manager** 패널의 **Places**를 선택하면, 현재 프로젝트가 속한 월드의 연결된 플레이스 목록과 현재 편집 중인 플레이스를 확인할 수 있습니다.\
(플레이스를 우클릭하면 표시되는 메뉴에서 Place Id를 복사할 수 있습니다.)

<figure><img src="/files/m4lAOSOgQ6Hruq8nhAwt" alt=""><figcaption></figcaption></figure>

Creator Hub의 Dashboard에서 월드를 클릭한 다음, **Place 탭**을 선택하면 연결된 플레이스를 확인할 수 있습니다.

<figure><img src="/files/Wfa9idSVzBfImvmNMlvA" alt=""><figcaption></figcaption></figure>

### 플레이스 연결 해제

Studio Home에서 월드에 연결된 플레이스의 옵션 메뉴를 연 다음, **Remove from World**를 선택하여 해당 플레이스를 월드에서 연결 해제할 수 있습니다.

<figure><img src="/files/eljMlhBouuzsgLsVW025" alt=""><figcaption></figcaption></figure>

Creator Hub의 Dashboard에서 월드의 **Place** **탭**을 연 다음, 연결을 해제할 플레이스의 옵션 메뉴에서 **Remove from World**를 선택하여 월드에서 연결 해제할 수 있습니다.

<figure><img src="/files/ztve3MAN49CBQQKCO0qa" alt=""><figcaption></figcaption></figure>

### 연결되지 않은 플레이스 확인 및 재연결

Studio Home의 **Detached Places 섹션**에서 월드에 연결되지 않은 플레이스를 확인할 수 있습니다.

<figure><img src="/files/XXXA2ANQB3udLD319MKg" alt=""><figcaption></figcaption></figure>

Creator Hub의 Dashboard에서 월드의 **Place 탭**을 연 다음, **Add Place 버튼**을 눌러 월드에 연결되지 않은 플레이스를 확인할 수 있습니다.

연결할 플레이스의 **Add 버튼**을 선택하면 해당 월드에 플레이스를 추가할 수 있습니다.

<figure><img src="/files/EEXzV22QvttYVucUMtrs" alt=""><figcaption></figcaption></figure>

### 서브 플레이스 정보 갱신

Creator Hub와 달리, **Studio**에 표시되는 **플레이스 연결 정보는 1분 주기로 갱신**됩니다.

즉시 최신 상태를 반영하려면 다시 로그인하거나, Studio Home 또는 프로젝트를 다시 열어야 합니다.

## 스크립트 기능

### 주의 사항

* 텔레포트 기능은 **서버측 스크립트에서만** 사용할 수 있습니다.
* TeleportService를 통한 플레이스 이동은 **해당 월드에 연결된 플레이스 간에만** 지원됩니다.
* 텔레포트 실패 상황을 반드시 고려하여 예외 처리를 구성하는 것을 권장합니다.

### 공개 세션 플레이스로 이동 (TeleportAsync)

공개 서버 기반으로 플레이어를 다른 플레이스로 이동할 때 사용합니다.

```lua
local TeleportService = game:GetService("TeleportService")

-- 텔레포트 실행
local success, errorOrResult = pcall(function()
    local targetPlaceId = 1234 -- 월드에 연결된 Place의 Id
    local players = { player } -- 텔레포트할 플레이어 목록
		
    local teleportResult = TeleportService:TeleportAsync(targetPlaceId, players)     
    return teleportResult
end)
```

* 현재 입장한 PlaceId로 이동 시도시, 다른 서버 세션으로 입장할 수 있습니다.
  * 즉, 현재 입장 중인 PlaceId로 다시 이동하더라도, 동일한 서버 세션으로 재입장하는 것은 보장되지 않습니다.

### 비공개 세션 플레이스로 이동 (TeleportAsync)

#### 비공개 세션 생성 (ShouldReserveServer 옵션)

텔레포트 시 새로운 비공개 서버 세션을 생성할 때 사용합니다.

```lua
local TeleportService = game:GetService("TeleportService")

-- TeleportOptions 설정
local options = Instance.new("TeleportOptions")	
options.ShouldReserveServer = true -- 새로운 예약 서버 생성 여부

-- 텔레포트 실행
local success, errorOrResult = pcall(function()
    local targetPlaceId = 1234 -- 월드에 연결된 Place의 Id
    local players = { player } -- 텔레포트할 플레이어 목록
		
    local teleportResult = TeleportService:TeleportAsync(targetPlaceId, players, options)     
    return teleportResult
end)
```

#### 특정 서버 인스턴스로 이동 (ServerInstanceId 옵션)

실행 중인 특정 서버 인스턴스로 플레이어를 이동할 때 사용합니다.

```lua
local TeleportService = game:GetService("TeleportService")
local DataStoreService = game:GetService("DataStoreService") 
local SessionStore = DataStoreService:GetDataStore("PlayerPrevSessionId")

-- 저장된 이전 세션 Id 가져오기
local jobId = nil
local success, errorOrLoadValue = pcall(function()
    return SessionStore:GetAsync(player.UserId)
end) 

if not success or errorOrLoadValue == nil then
    return
end
jobId = errorOrLoadValue 

-- TeleportOptions 설정
local options = Instance.new("TeleportOptions")	
options.ServerInstanceId = jobId    -- 특정 공개 서버로 입장(game.JobId 값 전달)
options.ShouldReserveServer = false -- 새로운 예약 서버 생성 여부 (ServerInstanceId 사용시 false여야 합니다.)

-- 텔레포트 실행
local success, errorOrResult = pcall(function()
    local targetPlaceId = 1234 -- 월드에 연결된 Place의 Id
    local players = { player } -- 텔레포트할 플레이어 목록
		
    local teleportResult = TeleportService:TeleportAsync(targetPlaceId, players, options)     
    return teleportResult
end)
```

* ServerInstanceId는 공개 서버 세션에만 사용할 수 있으며, 종료된 세션에는 입장할 수 없습니다.

### 전용 서버 생성 및 이동 (ReserveServerAsync)

독립된 서버 세션을 생성하고 해당 서버로 플레이어를 이동할 때 사용합니다.

```lua
local TeleportService = game:GetService("TeleportService")

local targetPlaceId = 1234 -- 월드에 연결된 Place의 Id

-- 전용 서버 생성
local success, errorOrAccessCode = pcall(function()
    return TeleportService:ReserveServerAsync(targetPlaceId)
end)

-- QR 퍼블리시 환경에서는 AccessCode 값이 빈 문자열("")로 반환될 수 있습니다.
if not success or errorOrAccessCode == nil then
    return
end

-- TeleportOptions 설정
local options = Instance.new("TeleportOptions")	
options.ReservedServerAccessCode = errorOrAccessCode -- 예약 서버 접근 코드
options.ShouldReserveServer = false                  -- 새로운 예약 서버 생성 여부 (ReservedServerAccessCode 사용시 false여야 합니다.)

-- 텔레포트 실행
local success, errorOrResult = pcall(function()
    local players = { player } -- 텔레포트할 플레이어 목록
		
    local teleportResult = TeleportService:TeleportAsync(targetPlaceId, players, options)     
    return teleportResult
end)

print("TeleportAsyncResult.ReservedServerAccessCode : ", errorOrResult.ReservedServerAccessCode)
```

* 전용 서버 생성 및 이동에 사용된 placeId가 동일해야 합니다.
* 예약 서버 세션이 종료되면, 해당 AccessCode는 더 이상 사용할 수 없습니다.

### 텔레포트 실패 이벤트 (TeleportInitFailed)

텔레포트 실패 시 예외 처리 및 재시도 로직을 구현할 때 사용합니다.

teleportOptions를 재사용하면 동일한 설정으로 텔레포트를 재시도할 수 있습니다.

```lua
local TeleportService = game:GetService("TeleportService")

local function OnTeleportInitFailed(player, teleportResult, errorMessage, placeId, teleportOptions)
    print("[TeleportInitFailed] playerName : ", player.Name)		  
    print("[TeleportInitFailed] Result : ", teleportResult)
    print("[TeleportInitFailed] Error : ", errorMessage)
    print("[TeleportInitFailed] Target Place : ", placeId)       
end
TeleportService.TeleportInitFailed:Connect(OnTeleportInitFailed)	
```

### 서버 세션 ID 가져오기 (game.JobId)

game.JobId는 현재 실행 중인 서버 세션을 식별하는 고유 ID입니다.

현재 서버 세션을 식별하거나 ServerInstanceId를 이용해 특정 세션으로 이동할 때 사용합니다.

```lua
local DataStoreService = game:GetService("DataStoreService") 
local SessionStore = DataStoreService:GetDataStore("PlayerPrevSessionId")

local success, errorOrLoadValue = pcall(function()
    local saveValue = game.JobId    		
    SessionStore:SetAsync(player.UserId, saveValue) 
        
     print("Save Prev Session Id : ", saveValue)
end)
```

### 플레이스 ID 가져오기 (game.PlaceId)

현재 플레이스를 식별하거나 플레이스 기반 로직을 처리할 때 사용합니다.

```lua
local placeId = game.PlaceId

local PLACE_DATA =
{
	["Lobby"] = 1234,
	["Stage1"] = 1235,	
	["Stage2"] = 1236,	
	-- ...
}

if placeId == PLACE_DATA.Lobby then
    print("Lobby")
end
```

### 미지원 기능

* TeleportOptions의 SetTeleportData, GetTeleportData 메서드
* PrivateId 및 PrivateServerId 속성

## 활용 예시

* 로비와 게임 공간을 분리하면, 로비에서 매칭을 진행한 뒤 전투 전용 플레이스로 이동시킬 수 있습니다.
* 파티 플레이어를 전용 서버로 이동시키면, 같은 파티원만 입장하는 비공개 세션을 구성할 수 있습니다.
* 게임 모드별로 플레이스를 분리하면, PvP, PvE, 튜토리얼, 이벤트 공간을 독립적으로 운영할 수 있습니다.
* 난이도별 플레이스를 구성하면, Easy, Normal, Hard 등 선택한 난이도에 맞는 공간으로 이동시킬 수 있습니다.
* JobId를 저장하면, 특정 세션으로 다시 이동하거나 진행 중인 게임 세션에 재입장하는 구조를 만들 수 있습니다.
* 콘텐츠를 플레이스 단위로 나누면, 각 서버가 필요한 공간과 로직만 실행하도록 구성하여 서버 부하를 줄일 수 있습니다.
* 규모가 큰 월드는 기능별 플레이스로 분리하여 로딩 부담과 관리 복잡도를 낮출 수 있습니다.
