# 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)

if not success or errorOrAccessCode == nil or errorOrAccessCode == "" 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를 저장하면, 특정 세션으로 다시 이동하거나 진행 중인 게임 세션에 재입장하는 구조를 만들 수 있습니다.
* 콘텐츠를 플레이스 단위로 나누면, 각 서버가 필요한 공간과 로직만 실행하도록 구성하여 서버 부하를 줄일 수 있습니다.
* 규모가 큰 월드는 기능별 플레이스로 분리하여 로딩 부담과 관리 복잡도를 낮출 수 있습니다.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.overdare.com/korean/manual/studio-manual/game-development/place-and-teleport.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
