룸 정의 레퍼런스

stateMachine 룸에서 실행하는 룰의 작성 방법, Room API, 실행 규칙, 상한값

stateMachine 룸에서는 GS2-StateMachine에 등록한 룰(GSL)을 룸 안에서 실행하여, 공유 오브젝트의 생성·갱신, 조작 검증, 시간 경과 처리를 수행합니다. 이 페이지에서는 그 룰을 작성하기 위한 사양을 정리합니다.

룰은 C#으로 작성하여 GSL을 생성하는 것이 기본입니다. C# 기술 형식(상태 record, Step 등)은 StateMachine과 공통이므로 C# 정의 레퍼런스도 함께 참조해 주세요. 절차를 따라 시험해 보려면 튜토리얼을 참조해 주세요.

룰의 전체 구조

대상배치 위치예
룰GS2-StateMachine의 StateMachineMaster(버전 관리된다)적의 생성, 공격 검증, 부활
룸의 진행 상태룰의 상태 record. 클라이언트에는 배포되지 않는다플로어 번호, 적의 오브젝트 ID
공유하는 값공유 오브젝트. 모든 참가자에게 배포된다위치, HP, 보스의 페이즈
표시Unity의 GameObjectHP 바, 위치 보간

룸의 상태와 공유 오브젝트는 룸이 동작하는 동안에만 유지됩니다. 룸이 끝나면 사라지며, 영구 저장되지 않습니다.

C#으로 작성하는 방법

룰 클래스에는 다음 3종류의 메서드를 작성합니다.

메서드호출되는 시점
public static Step Start()룸 시작 시 한 번
public static Step Interact(TState state, int objectId, int method)플레이어가 SharedObject.Interact(method)를 전송했을 때
public static Step Timer(TState state, int objectId, int eventId)Room.After로 예약한 시각이 되었을 때
public static Step Tick(TState state, int tick)DefineTickRate로 지정한 간격마다(틱)

Start에서는 공유 오브젝트의 종류를 정의하고 초기 오브젝트를 생성한 후, Step.WaitFor(nameof(Interact), state).Or(nameof(Timer))로 입력을 기다립니다. Interact와 Timer는 처리 후에 Step.Stay(state)로 같은 입력을 계속 기다립니다.

플레이어가 전송할 수 있는 조작은 Interact뿐입니다. 조작의 종류는 method 값으로 구분합니다. C#에 public 메서드를 추가해도 클라이언트에서 호출할 수 있게 되지는 않습니다.

생성 설정에서는 hostProfile에 RealtimeRoomV1을 지정합니다. 이 프로파일에서는 GameRewards(보상)와 GameRandom(난수)을 사용할 수 없습니다.

Room API

C#에서는 Room.*, GSL의 Lua에서는 같은 이름의 room.*을 호출합니다. 값은 모두 int32입니다.

오브젝트의 종류 정의하기

룸의 초기화 중(Start부터 첫 입력 대기까지)에만 호출할 수 있습니다.

API내용
DefineServerPrefab<TSchema>()동기화 스키마 TSchema의 종류를 서버가 관리하는 오브젝트로 정의한다
DefineLeasedPrefab<TSchema>(leaseMilliseconds)동기화 스키마 TSchema의 종류를 플레이어에게 조작 권한을 대여하는 오브젝트로 정의한다
DefineServerPrefab(prefab, fields)Prefab ID와 동기화할 필드의 비트 마스크를 직접 지정하여 정의한다
DefineLeasedPrefab(prefab, fields, leaseMilliseconds)위와 동일. 조작 권한의 대여 기간을 밀리초로 지정한다
DefineSimulatedPrefab<TSchema>() / DefineSimulatedPrefab(prefab, fields)플레이어가 생성하고 룰이 틱마다 움직이는 오브젝트로 정의한다(틱)
DefineRuleSpawnedPrefab<TSchema>() / DefineRuleSpawnedPrefab(prefab, fields)DefineSimulatedPrefab과 같지만 플레이어는 생성할 수 없고, 룰의 SpawnOwned만 생성한다(탄 등)
DefineTickRate(ticksPerSecond)Tick을 초당 몇 번 실행할지 지정한다(1~60)
DefineHitbox<TSchema>(radius) / DefineHitbox(prefab, radius)그 종류의 오브젝트에 판정 영역(반경 radius의 구. 2D에서는 원)을 붙인다. DefineTickRate 다음에 호출한다(지연 보상)
DefineRelevance<TSchema>(distance) / DefineRelevance(prefab, distance)그 종류의 오브젝트의 갱신을 받는 플레이어로부터 멀수록 줄여서 보낸다. DefineTickRate 다음에 호출한다(전송 빈도)
관리 방법값을 변경할 수 있는 것용도의 예
서버 관리룰의 Room.Set뿐적의 HP, 문, 보스의 페이즈, 스코어
조작 권한 대여조작 권한을 얻은 1개의 접속뿐. 룰에서는 변경할 수 없다들고 옮기는 상자, 패들, 조작석
시뮬레이션룰의 Room.Set뿐. 소유한 플레이어는 입력을 보낸다플레이어 캐릭터, 탈것

오브젝트를 생성하고 값 읽고 쓰기

API내용
Spawn<TSchema>(x, y, z) / Spawn(prefab, x, y, z)오브젝트를 생성하고 오브젝트 ID를 반환한다. x y z는 위치 필드의 초기값이며, 다른 필드는 0에서 시작한다
SpawnOwned<TSchema>(ownerObjectId, x, y, z) / SpawnOwned(prefab, ownerObjectId, x, y, z)Simulated 오브젝트를 ownerObjectId 오브젝트를 소유한 플레이어의 소유물로 생성한다. 그 플레이어의 입력으로 움직인다(탄이나 리스폰에 사용). 그 플레이어가 이미 64개를 소유하고 있으면 생성하지 않고 0을 반환한다
Despawn(objectId)서버 관리·대여·Simulated 오브젝트를 삭제하고 그 타이머도 취소한다. 플레이어 오브젝트는 삭제할 수 없다
Get(objectId, field)필드의 값을 읽는다
Set(objectId, field, value)필드의 값을 쓴다. 서버 관리 오브젝트와 Simulated 오브젝트만

field에는 동기화 스키마의 enum 값(EnemyFields.Health 등)이나 RoomFields.PositionX 등의 표준 필드를 지정합니다. 룰 안에서 읽고 쓴 값은 같은 입력의 처리 안에서 즉시 Get에 반영됩니다.

위치 값은 단위 간격으로 나눈 정수입니다. 표준 단위 간격(0.01)에서는 50이 Unity의 0.5에 해당합니다.

시간 경과로 처리하기

API내용
After(objectId, milliseconds, eventId)milliseconds 후에 Timer(state, objectId, eventId)를 한 번만 호출하도록 예약한다
CancelTimer(objectId)해당 오브젝트의 예약을 취소한다

예약은 1개의 오브젝트당 1개이며, 같은 오브젝트에 After를 호출하면 예약을 대체합니다. 일정 간격으로 반복하는 처리는 Timer 안에서 다음 After를 예약합니다. 적의 행동 간격, 문이 닫힐 때까지의 시간, 부활까지의 대기 시간 등에 사용합니다.

타이머는 룸 안에서 약 50밀리초마다 처리됩니다. Unity의 렌더링 프레임과는 동기화되지 않으며, 정확한 시각에서의 실행을 보장하지는 않습니다. 발화한 타이머는 룰이 거부·실패하더라도 소비됩니다.

일정 간격으로 시뮬레이션하기(틱)

초기화에서 DefineTickRate를 호출하면, 룸은 초당 정해진 횟수만큼 Tick(state, int tick)을 실행합니다. 플레이어 캐릭터의 이동 등을 서버가 입력으로부터 계산하는 경우에 사용합니다. 클라이언트는 위치를 쓸 수 없으므로 이동 속도 변조나 벽 통과를 막을 수 있습니다.

API내용
Input(objectId, field)Simulated 오브젝트의 소유자가 현재 틱용으로 보낸 입력 값을 읽는다(슬롯 0~31). Simulated 이외의 오브젝트를 지정하면 오류가 된다
ObjectCount<TSchema>() / ObjectCount(prefab)그 종류의 오브젝트 수(이 처리에서 생성한 것을 포함)
ObjectAt<TSchema>(index) / ObjectAt(prefab, index)그 종류의 index번째 오브젝트 ID(ID가 작은 순)
// Position is the standard XYZ (fields 0..2, 0.01 units); custom fields start at 6.
[RoomSchema(5, StandardFields = RoomSync.Position)]
public enum Character { Hits = 6 }

public static Step Start() {
    Room.DefineTickRate(30);
    Room.DefineSimulatedPrefab<Character>();
    return Step.WaitFor(nameof(Tick), new State(0));
}
public static Step Tick(State state, int tick) {
    int count = Room.ObjectCount<Character>();
    for (int i = 0; i < count; i++) {
        int id = Room.ObjectAt<Character>(i);
        int dx = System.Math.Max(-1, System.Math.Min(1, Room.Input(id, 0)));
        int dy = System.Math.Max(-1, System.Math.Min(1, Room.Input(id, 1)));
        Room.Set(id, RoomFields.PositionX, Room.Get(id, RoomFields.PositionX) + dx * 10);
        Room.Set(id, RoomFields.PositionY, Room.Get(id, RoomFields.PositionY) + dy * 10);
    }
    return Step.Stay(state);
}
  • Tick의 인수 이름은 tick(1부터 시작하는 틱 번호)으로 고정입니다. DefineTickRate를 사용하는 정의에 Tick이 없으면 컴파일 오류가 됩니다.
  • Tick을 받아들이는 입력 대기 동안에만 실행됩니다. Interact나 Timer와 함께 기다릴 수도 있습니다(.Or(nameof(Interact))). 시뮬레이션을 계속할 모든 입력 대기에 Tick을 포함하세요. 포함하지 않는 동안에도 틱 번호는 진행됩니다.
  • Tick이 오류가 된 틱은 아무것도 변경되지 않으며, 다음 틱은 평소대로 실행됩니다.
  • DefineSimulatedPrefab의 종류는 플레이어 오브젝트와 마찬가지로 클라이언트가 생성하고 그 플레이어가 소유합니다. 클라이언트가 생성할 수 있는 것은 종류마다 하나까지이며, 요청에서 사용되는 것은 위치와 회전뿐입니다(다른 필드는 0에서 시작합니다). 값을 쓰거나 삭제할 수 있는 것은 룰뿐이며, 소유자의 쓰기와 삭제는 거부됩니다. 소유자가 퇴장하면 삭제됩니다.
  • Input·DefineHitbox·DefineRelevance·Raycast·Overlap을 사용하는 정의에 DefineTickRate가 없으면 컴파일 오류가 됩니다.
  • 플레이어는 “어느 틱에 사용할 입력인지"를 붙여 입력을 보냅니다. 그 틱의 입력이 도착하지 않았으면 직전의 입력이 사용됩니다.
  • 틱에서 변경한 값은 정기 전송(UDP를 사용할 수 있을 때는 UDP)으로 클라이언트에 전달됩니다.
  • 처리가 늦어졌을 때는 한 번에 최대 3틱까지 모아서 실행하고 나머지는 건너뜁니다.
  • 룰의 계산은 정수만 사용합니다. 위치는 단위 간격으로 나눈 정수(기본은 0.01 단위)로 다룹니다.

쏜 쪽의 화면대로 맞히기(지연 보상)

플레이어의 화면에 보이는 다른 캐릭터는 통신 지연과 보간만큼 조금 과거의 위치입니다. 그대로 판정하면 화면에서는 맞았는데 빗나갑니다. 클라이언트는 입력마다 “그때 화면이 얼마나 늦었는지"를 보내므로, 룸은 쏜 플레이어가 보고 있던 위치에서 판정할 수 있습니다.

public static Step Start() {
    Room.DefineTickRate(30);
    Room.DefineSimulatedPrefab<Character>();
    Room.DefineHitbox<Character>(50);   // DefineTickRate 다음
    return Step.WaitFor(nameof(Tick), new State(0));
}
static void Fire(int id) {
    if (Room.Input(id, 2) == 0) return;
    int target = Room.Raycast<Character>(id,
        Room.Get(id, RoomFields.PositionX), Room.Get(id, RoomFields.PositionY), 0,
        Room.Input(id, 3), Room.Input(id, 4), 0, 2000);
    if (target != 0) Room.Set(target, Character.Hits, Room.Get(target, Character.Hits) + 1);
}
API내용
Raycast<TSchema>(shooterId, x, y, z, dx, dy, dz, distance)(x, y, z)에서 (dx, dy, dz) 방향으로 distance까지 나아가는 선에 처음 맞은 오브젝트의 ID. 없으면 0
Overlap<TSchema>(shooterId, x, y, z, radius)반경 radius의 구와 겹치는 가장 가까운 오브젝트의 ID. 없으면 0
  • 판정 영역은 위치 필드(0~2번. 표준 Position)를 중심으로 한 구입니다. 2D 게임에서는 Z를 0으로 하면 원으로 다룰 수 있습니다.
  • shooterId가 Simulated 오브젝트이면, 다른 오브젝트는 그 소유자가 현재 틱의 입력을 보냈을 때 보고 있던 위치로 되돌려 판정합니다. 틱 사이는 보간합니다. 되돌릴 수 있는 것은 최대 500밀리초입니다. shooterId 자신은 판정 대상이 되지 않습니다.
  • shooterId에는 존재하는 오브젝트를 지정합니다(0은 지정할 수 없습니다).
  • 쏘는 위치와 방향은 인수의 값이 그대로 사용됩니다. 쏘는 쪽의 현재 위치를 전달하세요(쏘는 쪽의 위치는 소유자의 클라이언트가 예측하므로 화면과 일치합니다).
  • [Predict] 처리에서는 호출할 수 없습니다. 클라이언트에서는 이펙트만 먼저 표시하고, 대미지는 룸의 결과가 도착한 후에 반영하세요.

먼 오브젝트의 갱신 줄이기

인원이 많은 룸에서는 모든 사람의 위치를 모든 사람에게 매 틱 보내면 통신량이 커집니다. DefineRelevance를 선언하면 그 종류의 오브젝트의 갱신은 받는 플레이어의 캐릭터로부터 멀수록 적은 빈도로 도착합니다.

Room.DefineRelevance<Character>(300);   // DefineTickRate 다음
받는 플레이어의 캐릭터로부터의 거리전송 빈도
distance 이내매 틱
2배 이내2틱마다
4배 이내4틱마다
그보다 멀다8틱마다
  • 거리는 그 플레이어가 소유한 Simulated 오브젝트 중 가장 가까운 것으로부터 위치 필드(0~2번)로 측정합니다. 자신의 캐릭터는 매 틱 도착합니다.
  • 줄인 동안 바뀐 값은 다음에 보낼 때 최신 값으로 도착합니다. 표시는 보간되므로 먼 캐릭터도 부드럽게 움직입니다.
  • Simulated 오브젝트를 갖지 않은 플레이어(관전 등)에게는 매 틱 보냅니다.
  • 1초마다의 재전송과 RPC 등의 직전에 보내는 값은 줄이지 않습니다.
  • 예: 64명이 20m 사방에 흩어져 모두 움직이는 경우(distance 300), 갱신의 통신량은 약 3분의 1이 됩니다.

클라이언트에서 먼저 움직이기(예측)

오브젝트 하나를 움직이는 처리를 private 보조 함수로 분리하고 [Predict(typeof(스키마))]를 붙이면, 소유자의 클라이언트도 그 처리를 실행하여 자신의 캐릭터를 입력한 순간에 움직일 수 있습니다.

public static Step Tick(State state, int tick) {
    int count = Room.ObjectCount<Character>();
    for (int i = 0; i < count; i++)
        Move(Room.ObjectAt<Character>(i), tick);
    return Step.Stay(state);
}

[Predict(typeof(Character))]
static void Move(int id, int tick) {
    int dx = System.Math.Max(-1, System.Math.Min(1, Room.Input(id, 0)));
    Room.Set(id, RoomFields.PositionX, Room.Get(id, RoomFields.PositionX) + dx * 10);
}
  • 대상 보조 함수는 private static void 이름(int objectId) 또는 (int objectId, int tick) 형태로 합니다. [Predict]는 스키마 하나당 하나입니다. 룸에서는 Tick에서 평소대로 호출됩니다.
  • 컴파일러는 이 보조 함수와 거기서 호출하는 보조 함수를 Unity용 C#(unity/<룰 클래스 이름>Prediction.cs)으로도 출력합니다. 값의 계산은 룸과 같은 정수 연산이 됩니다.
  • 예측하는 처리에서 사용할 수 있는 것은 int와 bool 값, System.Math.Min과 Max, 룰 클래스의 보조 함수, Room.Get·Set·Input·ObjectCount·ObjectAt·SpawnOwned·Despawn입니다. 계산은 모두 int나 bool로 합니다(스키마의 필드는 이름으로 지정하며, enum으로의 캐스트는 할 수 없습니다). 그 밖의 것(float, 정적 필드, 상태 state의 읽기 등)을 사용하면 컴파일 오류가 됩니다.
  • 예측하는 처리 안에서 SpawnOwned를 호출하면(탄 발사 등) 쏜 플레이어의 화면에는 탄이 바로 표시됩니다(예측 스폰). 룸이 생성한 탄이 도착하면 표시 중인 같은 오브젝트에 그대로 인계됩니다. 룸이 생성하지 않은 경우에는 사라집니다. 탄을 올바르게 대응시키기 위해 SpawnOwned는 예측하는 처리 안에서만 호출하고, 판정은 룸에서만 실행하는 처리로 나누세요.
  • 클라이언트에서는 다른 플레이어의 입력은 0으로, 다른 오브젝트의 값은 룸에서 도착한 최신 값으로 계산합니다. 캐릭터끼리 부딪히는 경우 등에는 예측이 빗나갈 수 있지만, 룸의 결과로 보정됩니다.

조작한 사용자 확인하기

API내용
SenderUserId()조작한 플레이어의 userId. 액세스 토큰으로부터 취득한 값이며, 클라이언트가 변경할 수 없다
SenderConnectionId()조작한 접속의 ID. 재접속하면 바뀐다

Start와 Timer에는 조작한 플레이어가 없으므로 SenderUserId()는 빈 문자열, SenderConnectionId()는 0을 반환합니다. 타이머 처리에서 「누가 시작한 조작인지」가 필요하다면 Interact 처리에서 상태 record에 저장해 둡니다.

플레이어별 소유물이나 순서를 관리할 때는 재접속해도 바뀌지 않는 SenderUserId()를 사용해 주세요.

동기화 스키마

공유 오브젝트의 동기화할 값은 RoomSchema 속성을 붙인 enum으로 선언합니다. 이 선언으로부터 룰의 정의와 Unity의 동기화 스키마(.realtimeschema)가 모두 생성됩니다.

[RoomSchema(7, StandardFields = RoomSync.Position)]
public enum EnemyFields
{
    Health = 6,
}

[RoomSchema(8)]
public enum SwitchFields
{
    [RoomField(typeof(bool))] IsOpen = 6,
    [RoomField(typeof(float), Precision = 0.01f)] Progress = 7,
}
항목내용
RoomSchema(prefab)Prefab ID. 양의 int32이며, 다른 동기화 스키마와 중복될 수 없다
StandardFields위치·회전의 표준 필드. RoomSync.Position(필드 02), RoomSync.Rotation(35), RoomSync.Transform(양쪽 모두)
PositionPrecision / RotationPrecision표준 필드의 단위 간격. 기본값은 0.01과 360 / 4096도
enum 값통신상의 필드 번호(0~31). 표준 필드의 번호와 겹치지 않도록 6 이상을 사용한다
RoomField(typeof(...))Unity에서의 타입. int(기본값), bool, float
Precisionfloat의 단위 간격. 룰에서는 정수로 다루고, Unity에서는 「정수 × 단위 간격」으로 받는다

위의 예에서 Progress에 125를 Set하면 Unity에서는 1.25f로 받습니다. bool에는 0 또는 1을 설정합니다.

필드 번호는 통신상의 식별자입니다. 릴리스한 후에 번호를 바꾸거나, 순서 변경으로 번호가 어긋나지 않도록 해 주세요.

입력 1회의 처리와 취소

1회의 입력(Interact 또는 Timer)으로 수행한 변경은 한꺼번에 확정하거나 한꺼번에 취소합니다.

룰의 결과동작
Step.Next같은 입력의 처리로서 다음 처리로 진행한다
입력 대기 도달(WaitFor / Stay)·Step.End상태, 공유 오브젝트, 타이머의 변경을 확정하고 전원에게 배포한다
Step.Ignore이 입력으로 수행한 변경을 모두 취소한다. 이유는 클라이언트에 전달된다
예외, 실행 시간·전이 횟수의 상한 초과이 입력으로 수행한 변경을 모두 취소한다. 클라이언트에는 InvalidOperation이 전달된다

Step.Ignore의 이유 값은 조작한 클라이언트의 CommandCompleted에 그대로 전달됩니다. 값 1~7은 시스템 결과 코드(MissingObject 등)와 같은 번호이므로, 이유에는 1000 이상의 값을 사용해 주세요. 클라이언트가 받는 결과 목록은 Unity 클라이언트를 참조해 주세요.

Step.End는 룰의 실행을 끝낼 뿐이며, 공유 오브젝트의 삭제나 룸의 종료는 수행하지 않습니다.

생성과 등록

순서내용
생성project.json의 hostProfile에 RealtimeRoomV1을 지정하여 생성한다. 설정 항목은 C# 정의의 생성 설정을 참조
등록생성한 main.gsl의 내용을 GS2-StateMachine의 UpdateStateMachineMaster의 payload에 지정한다. mainStateMachineName은 룰의 클래스명
룸에 설정Realtime 네임스페이스에서 서버 타입 stateMachine과 룰의 저장 위치 네임스페이스(stateMachineSetting.namespaceId)를 지정한다. 버전(stateMachineSetting.version)은 생략하면 최신을 사용하며, 고정하고 싶을 때만 지정한다

생성물은 다음과 같습니다.

파일용도
main.gsl등록할 룰
package.zipmain.gsl만 넣은 배포용 파일. 등록할 때는 안의 main.gsl을 읽어 payload에 지정한다
unity/<스키마 이름>.realtimeschemaUnity의 NetworkEntity에 지정하는 동기화 스키마
source-map.json생성된 위치로부터 원래 C#을 찾기 위한 개발용 파일. 등록에는 사용하지 않는다

룸은 할당되었을 때 룰을 한 번만 읽어 들입니다. 버전을 생략한 경우에는 그 시점의 최신 룰을, 지정한 경우에는 해당 버전을 읽어 들입니다. 저장 위치에 룰이 1건도 등록되어 있지 않은 경우나, 읽기 또는 초기화에 실패한 경우에는 룸이 사용되지 않습니다. 동작 중인 룸은 끝까지 같은 버전을 사용하며, 새로운 룰은 그 이후에 할당되는 룸부터 사용됩니다.

룰(GSL)과 동기화 스키마는 같은 C# 정의로부터 동시에 생성한 것을 조합하여 배포해 주세요.

상한값

대상상한
1룸의 참가자64접속
1룸의 공유 오브젝트4096개
오브젝트의 종류초기화 중의 정의는 64종류까지. 룸 전체에서 4096종류까지
1개 오브젝트의 필드32개(번호 0~31)
조작 권한의 대여 기간50밀리초~1일(86,400,000밀리초)
After의 대기 시간50밀리초~1일(86,400,000밀리초)
After의 eventId1 이상
예약 중인 타이머1오브젝트당 1개, 룸 전체에서 4096개
입력 1회당 변경생성·값 변경은 각각 64오브젝트까지. 타이머 예약·취소는 64오브젝트까지
입력 1회당 처리실행 시간 100밀리초, Next에 의한 전이 32회까지
1회의 처리 주기에서 실행하는 타이머64개까지. 초과한 분은 다음 주기로 넘어간다
틱 빈도초당 1~60회
1틱당 변경값 변경·생성·삭제는 각각 1024오브젝트까지. 한 명이 소유할 수 있는 것은 64오브젝트까지
판정 되감기500밀리초까지(위치 기록은 1초분)
미리 보낼 수 있는 입력1초 분량의 틱까지
룰(GSL)의 크기1 MiB

사용할 수 없는 기능

룸의 룰은 룸 안에서 완결되는 처리만 실행합니다. 다음 기능은 사용할 수 없습니다.

  • GameRewards(보상 부여), GameRandom(난수)
  • GSL의 Script(GS2-Script 호출)
  • 외부 API, 파일, 네트워크 접근
  • Unity API나 임의의 .NET 라이브러리

룰에서 사용할 수 있는 C# 구문은 C# 정의 레퍼런스를 참조해 주세요.

GSL을 직접 작성하는 경우

C#을 사용하지 않고 GSL을 직접 작성할 수도 있습니다. GSL의 기본 서식은 GSL 포맷을 참조해 주세요. 룸에서 실행하는 GSL에는 다음 규칙이 있습니다.

  • 상태 변수는 map run과 map execution 2개입니다.

  • 입력을 기다리는 WaitTask에서 받는 이벤트는 다음 시그니처로 합니다.

    이벤트파라미터
    Interactint revision, int objectId, int method
    Timerint revision, int objectId, int eventId
    Tickint revision, int tick
  • Task의 Payload에 작성한 Lua에서 room.Spawn 등의 Room API를 호출합니다.

  • Script에 의한 GS2-Script 호출은 사용할 수 없습니다.