스크립팅 레퍼런스
창작자가 부를 수 있는 모든 이름입니다. 무엇을 받고 무엇을 돌려주는지, 그리고 언제 부를 수 있는지. 어떻게 쓰는지는 매뉴얼에 있습니다.
클라이언트 스크립트플레이어의 기계에서 도는 것
Chain2D
클라이언트 스크립트가 보는 뿌리. 로비(`client/boot/main.luau`)와 게임 화면(`client/main.luau`)이 같은 VM 에서 이 표를 봅니다. 단계가 맞지 않는 호출은 사라지는 대신 이유와 함께 거부됩니다 — 단계마다 다른 전역을 주면 창작자는 `attempt to index nil` 을 보게 되고, 그것은 무엇이 잘못됐는지 말해주지 않습니다. 단계 검사는 프리루드가 아니라 네이티브에 있습니다. 스크립트가 닿을 수 있는 파일에 둔 검사는 그 파일을 고칠 수 있는 누구든 지울 수 있고, 그러면 검사가 아니기 때문입니다. `Chain2D` 도 그 아래 표도 모두 얼려져 있어서 스크립트가 갈아끼울 수 없습니다.
10개
Chain2D.Auth
로그인. 어떤 방법이 있는지 묻고, 하나를 골라 시작하고, 실패했다는 것을 듣습니다. 로그인 실패는 접속 실패와 따로 옵니다 — 다음에 눌러야 할 것이 다르기 때문입니다.
3개
Chain2D.Connection
서버와의 연결이 붙어 있는지, 끊겼는지, 다시 이을지. 끊김은 단계가 아닙니다 — 단계는 오르기만 하고, 연결이 끊겼다고 로그인이나 내려받기가 없던 일이 되지는 않습니다. 세션도 파일도 그대로입니다. 되감기로 다루면 방금까지 되던 호출이 실패하기 시작하고, 창작자가 쓴 어떤 것도 그것을 설명하지 못합니다. 그래서 단계와는 별개의 축으로 둡니다.
3개
Chain2D.Network
서버와 주고받는 메시지. 양쪽 다 표를 주고받습니다 — 문자열을 건네고 파싱을 창작자에게 떠넘기면 게임마다 같은 파서를 다시 쓰게 되고, 그중 하나는 반드시 서버와 다르게 읽습니다.
2개
Chain2D.Realms
이 게임의 렐름 목록. 어디로 들어갈지 고르는 데 쓰고, 고른 렐름의 `id` 를 `Chain2D.join` 에 넘깁니다.
1개
Chain2D.UI
화면. 구조는 문서고 변화는 스크립트입니다 — 릴리스가 들고 있는 `client/**/ui/<이름>.json` 을 열어 바꾸고, 미리 적어 둘 수 없는 목록에서 만들어지는 화면만 스크립트가 직접 짓습니다. Axmol 은 여기 나오지 않습니다. 그 API 는 남의 일정으로 바뀌고, 거기에 대고 쓴 게임은 바뀔 때마다 깨집니다. 만드는 쪽은 모두 손잡이를 돌려줍니다. 숫자 id 를 그대로 주면 창작자가 그것으로 무엇을 할 수 있는지 알 수 없고, 실수로 다른 id 를 넘겨도 아무도 모릅니다. 손잡이는 얼려 두어 가리키는 것이 바뀌지 않습니다. 아래에서 요소 하나의 손잡이를 `Element`, `UI.load` 가 돌려주는 것을 `Screen` 이라고 적습니다 — 엔진의 타입 이름이 아니라 이 문서가 쓰는 이름입니다.
10개
Chain2D.Update
릴리스의 파일을 내려받습니다. 언제 받을지는 창작자가 정합니다 — 셀룰러에서 오백 메가를 묻지도 않고 받는 클라이언트는 만들면 안 되고, 연출이 도는 동안 미리 받고 싶을 수도 있습니다. 넘기는 것은 시점뿐입니다: 무엇을 받을지와 순서와 검증은 엔진이 쥐고 있어서, 건너뛰는 방법도 다 받았다고 말하는 방법도 없습니다.
3개
서버 스크립트판단하는 쪽
Chain2D
서버 스크립트의 뿌리. `Chain2D` 자체에 게임 코드를 거는 자리는 두 곳입니다 — 채널이 사람을 받기 전에 한 번, 그리고 매 틱 한 번. 사람과 메시지에 거는 자리는 `Chain2D.Players` 와 `Chain2D.Network` 에 따로 있습니다. 이 둘은 한 번만 등록할 수 있고, 콜백 뒤에 붙은 인자는 조용히 버려지지 않고 거부됩니다.
4개
Chain2D.Channels
한 게임 서버는 채널을 여럿 돌리고, 채널마다 이 스크립트가 한 벌씩 돕니다. 같은 게임의 다른 방이라고 생각하면 됩니다. 여기 있는 것은 사람을 다른 채널로 보내는 하나뿐입니다.
1개
Chain2D.Data
세 개의 서랍 — 게임 전체, 이 렐름, 한 사람. 무엇을 어디에 두는지가 곧 누가 그것을 볼 수 있는지입니다. 세 함수는 모두 같은 모양의 문서를 돌려주고, 문서에는 `get`, `set`, `remove`, `save` 네 가지가 있습니다. `set` 과 `remove` 는 런타임이 들고 있는 사본만 고치고 문서를 바뀐 것으로 표시할 뿐입니다 — 실제로 중앙에 쓰는 것은 5초마다 도는 자동 저장과 `save` 입니다. 자동 저장은 바뀐 문서를 전부 저장하고, 실패하면 로그에 남기고 문서를 바뀐 채로 두어 다음 번에 다시 시도합니다. 사람이 나갈 때는 `playerRemoving` 이 끝난 뒤 그 사람의 문서를 한 번 저장하고, 서버가 정상 종료할 때는 남은 문서를 전부 저장합니다.
7개
Chain2D.Map
맵 하나에 대한 손잡이. `Chain2D.Maps` 의 함수들이 돌려주는 것이 이것이고, 맵을 말하지 않는 게임에도 맵은 하나 있습니다 — 그것이 `Chain2D.Map` 이고, 사람은 연결되는 순간 여기 놓입니다.
이름을 닫아 쥔 함수들이지 self 를 받는 메서드가 아니므로 점으로 부릅니다. 여기만 콜론이면 `Map.setMap(w, h, ...)` 이 w 를 맵으로 읽는 조용한 오류가 되고, 그것은 맵이 여럿이 되기 전에 쓰인 모든 게임이 쓰는 바로 그 문장입니다.
몸은 `{ slot, generation, map }` 세 숫자로 된 언 표이고, 아래에서 `Body` 라고 씁니다. 위치를 쓰는 짝은 없습니다 — 몸은 의도(`setInput`)로 움직이고, 어디까지 갈 수 있는지는 솔버가 정합니다.
21개
Chain2D.Map.Tile
타일에 붙는 성질. 창작자에게는 브러시로 보이는 것들입니다. 플레이 방식의 차이가 여기서 나옵니다 — one-way 발판도 사다리도 별도의 Controller 가 아니라 칠하는 속성입니다.
값은 비트라서 한 칸이 여러 성질을 함께 가질 수 있고, 레이어가 겹친 칸의 판정은 모든 레이어의 합집합입니다. `Map.setMap` 에 넘기는 것이 이 값들이고, 타일셋으로 그린 맵에서는 어떤 타일이 무엇을 하는지를 타일셋이 이 값들로 적어 둡니다.
7개
Chain2D.Maps
한 채널이 쥐고 있는 맵들. 맵은 이름으로 다룹니다 — 여기서 돌려주는 손잡이는 그 이름을 닫아 쥔 함수들의 표이고, 맵 자체를 쥐지 않습니다. 언로드된 맵을 쥔 손잡이는 채널이 더는 갖고 있지 않은 메모리에 쓰는 일이 되고, 그 사이에도 참인 채로 남는 것은 이름뿐이기 때문입니다.
그래서 손잡이의 함수는 부를 때마다 이름을 첫 인자로 넘겨 맵을 다시 찾습니다. 이 표의 함수들은 그렇지 않습니다 — `Maps.of` 와 `Maps.move` 는 사람으로 묻고, `Maps.get` 과 `Maps.list` 는 채널이 아는 이름 전부를 훑습니다.
7개
Chain2D.Network
클라이언트와 주고받는 메시지. 입력과 스냅샷은 엔진이 나르므로 여기 오가는 것은 그 밖의 것 — 채팅, 상점, 문을 열었다는 사실 — 입니다. 양쪽 다 표를 주고받습니다: 서버와 클라이언트가 같은 JSON 파일을 박아 쓰기 때문에 보낸 표는 같은 표로 도착합니다. 이름 규칙을 검사하는 쪽은 서버입니다 — 클라이언트의 `Network.send` 는 `Chain2D.` 로 시작하는 이름만 그 자리에서 거부합니다. 채널마다 이 스크립트가 한 벌씩 돌기 때문에, 여기서 닿을 수 있는 사람은 이 채널에 접속해 있는 사람뿐입니다.
3개
Chain2D.Players
이 채널에 접속해 있는 사람들. 채널마다 이 스크립트가 한 벌씩 돌기 때문에, 여기서 보이는 것은 이 채널의 사람들뿐입니다. 건네받는 Player 는 얼린 표이고 `id`, `channelOrdinal`, 이 사람의 Data 문서를 들고 있습니다.
Player 를 받는 호출이 그 표를 얼마나 따지는지는 호출마다 다릅니다. `Chain2D.Network.send` 와 `Chain2D.Channels.move` 는 이 표 자체를 요구해서, 같은 `id` 를 담아 새로 만든 표는 거부됩니다. `Chain2D.Data.player` 는 표가 들고 있는 문서가 그 `id` 의 문서인지를 봅니다. `Chain2D.Maps` 쪽 호출들(`of`, `move`, `bodyOf`, `setOwner`)은 표이고 `id` 가 문자열인지만 보고 그 `id` 를 엔진에 넘깁니다 — 여기서는 손으로 만든 표도 통과합니다.
8개
task
기다리고, 나중에 하고, 따로 도는 흐름을 만드는 것. `Chain2D` 아래가 아니라 전역 `task` 입니다. 어디서 기다리는지가 중요합니다 — 런타임이 직접 부른 콜백 안에서 기다리면 그 콜백이 끝날 때까지 채널 전체가 멈춥니다. 런타임은 콜백의 흐름이 끝나기를 기다리는 동안 시뮬레이션을 진행하지도, 스냅샷을 보내지도 않습니다. `task.spawn` / `task.defer` / `task.delay` 로 떼어 낸 흐름은 콜백이 끝난 뒤에도 남아 있어서, 그 안에서 기다리는 동안에는 세계가 계속 돕니다.
5개