디버그 액션
디버그 액션은 게임 서버 코드에 미리 등록해 두는 확인용 명령입니다. QA 담당자 분은 명령 팔레트(Ctrl+K)에서 액션을 선택하고 인자를 채워 실행할 수 있습니다.
- 전달되는 것은 액션 이름과 서버가 다시 검사한 인자뿐이며, 코드는 전달되지 않습니다.
- 등록한 액션이 없으면 도구를 켜도 이 기능으로 할 수 있는 일이 없습니다.
- 액션마다 최소 레벨을 정할 수 있어서 아이템 지급, 순간이동, 밴 같은 일을 권한별로 나눌 수 있습니다.
등록하기
섹션 제목: “등록하기”Server.Action에 정의 테이블을 넘깁니다. 게임의 서버 Script에서 Start를 호출한 뒤에 등록해 주세요.
local Devplorer = require(game.ServerStorage.Devplorer.Server)
Devplorer.Action({ Name = "Give test tool", Group = "Items", Description = "Puts a test Tool into the target's Backpack.", MinLevel = "MainTester", Cooldown = 2, Args = { { Name = "Target", Type = "Player", Default = "Self" }, { Name = "Tool", Type = "Choice", Choices = { "Sword", "Flashlight", "Radio" } }, { Name = "Count", Type = "Integer", Min = 1, Max = 5, Default = 1 }, }, Run = function(player: Player, args) local backpack = args.Target:FindFirstChildOfClass("Backpack") if backpack == nil then Devplorer.ActionFail("the target has no Backpack yet") end for _ = 1, args.Count do local tool = Instance.new("Tool") tool.Name = args.Tool tool.RequiresHandle = false tool.Parent = backpack end return `gave {args.Count} {args.Tool} to {args.Target.Name}` end,})- 정의가 틀리면
Action이 바로 에러를 냅니다. 모르는 키(오타)도 에러입니다. - 같은 이름을 두 번 등록하면 에러입니다.
- 등록은
Start를 호출한 것과 같은 환경의 서버 스크립트에서 해야 합니다.Actor안이나 콘솔에서 require한 사본에서 등록하면 에러가 납니다.
정의의 필드
섹션 제목: “정의의 필드”| 필드 | 타입 | 기본값 | 설명 |
|---|---|---|---|
Name |
string |
필수 | 이름. 60바이트까지. |
Run |
(player, args) -> ... |
필수 | 실행 함수. |
Group |
string |
"General" |
목록에서 묶는 이름. 40바이트까지. |
Description |
string |
"" |
설명. 300바이트까지. |
MinLevel |
레벨 | "Developer" |
이 레벨 이상만 보고 실행할 수 있습니다. |
Args |
{ ArgDef } |
없음 | 인자 정의 목록. 16개까지. |
Allow |
(player) -> any |
없음 | 액션 자신의 허용 판정. 정확히 true일 때만 통과. |
Check |
(player, args) -> () |
없음 | Run 전에 실행되는 인자 검사. |
LiveCheck |
number |
없음 | 초 단위. 지정하면 인자를 입력하는 동안에도 Check를 실행합니다. Check가 있어야 합니다. 0.2~60. |
Confirm |
boolean 또는 string |
없음 | 실행 전에 한 번 더 확인합니다. 문자열이면 그 내용을 표시합니다(200바이트까지). |
Cooldown |
number |
0.5 |
같은 사람이 같은 액션을 다시 실행할 수 있기까지의 초. 0~3600. |
Timeout |
number |
8 |
요청이 결과를 기다리는 초. 1~8. |
세 가지를 모두 통과해야 액션이 보이고 실행됩니다. 요청마다 다시 검사합니다.
- 사람의 레벨이
MinLevel이상. - 액션의
Allow(player)가 정확히true. (없으면 통과) Start의ActionAllowed후크가 정확히true. (없으면 통과)
권한 밖의 액션은 목록에서 이름과 모양까지 가려집니다.
Args의 각 항목에는 Name과 Type이 있습니다. 인자 이름은 40바이트까지이고 서로 겹치면 안 됩니다.
모든 타입에 쓸 수 있는 키는 Name, Type, Description(300바이트까지), Optional, Default입니다.
Optional = true이면 비워 둘 수 있습니다. 비우면args에 그 이름이 없습니다.Default를 주면 비웠을 때 그 값을 씁니다.- 타입에 맞지 않는 키를 주면 등록할 때 에러가 납니다(예:
Number에MaxLength).
Type |
Run에서 받는 값 |
쓸 수 있는 키 |
|---|---|---|
String |
string |
MaxLength(기본 200, 최대 2000), Multiline |
Number |
number |
Min, Max |
Integer |
정수 number |
Min, Max |
Boolean |
boolean |
|
Vector3 |
Vector3 |
Min, Max(성분마다) |
Vector2 |
Vector2 |
Min, Max(성분마다) |
Color3 |
Color3 |
|
Choice |
string |
Choices: 문자열 목록, 또는 목록을 돌려주는 함수 |
Enum |
EnumItem |
Enum: Roblox Enum 이름(예: "Material") |
Player |
Player |
|
UserId |
양의 정수 number |
|
Instance |
Instance |
Class(필수), Roots |
타입별 참고 사항
섹션 제목: “타입별 참고 사항”Number,Integer,Vector:Min과Max를 주지 않으면 절댓값 10억까지만 받습니다.Max를 항상 지정하는 것을 권합니다. 값은 유한해야 합니다.String: 올바른 UTF-8이어야 하고 제어 문자는 거절합니다.Multiline = true이면 개행과 탭은 허용합니다.Color3: 각 성분이 0~1이어야 합니다.Choice: 실행할 때 목록을 다시 계산해 값이 들어 있는지 확인합니다. 함수로 지정하면 목록을 보낼 때와 실행할 때 호출합니다. 한 항목은 100바이트까지, 화면에는 1000개까지 전달합니다(나머지도 실행할 때는 통과합니다).Default는 목록에 있어야 합니다.Enum: 없는 Enum 이름이면 등록할 때 에러가 납니다.Default는 지원하지 않습니다.Player: 이 서버에 있는 플레이어입니다.Default로는"Self"(실행한 사람)만 쓸 수 있습니다.UserId: 이미 나간 사람을 지정할 때 유용합니다.Instance:Class가 필수이고IsA로 거릅니다.Roots에 인스턴스 목록을 주면 그 아래의 것만 받습니다. devplorer 자신과Secret이 가리는 인스턴스는 늘 거절합니다.Default는 지원하지 않습니다.
Check: 인자 사전 검사
섹션 제목: “Check: 인자 사전 검사”Check(player, args)는 서버가 인자를 검사한 뒤, Run 전에 실행됩니다.
args는 얼린 사본이라 고칠 수 없습니다.- yield해도 되지만 2초 안에 끝나야 합니다. 넘으면 실행되지 않은 것으로 처리합니다. 사용한 시간만큼
Run의 제한 시간이 줄어듭니다. nil(또는true)을 돌려주면 통과입니다.false같은 다른 값을 돌려주면 막힙니다.- 실행을 막을 때는
ArgFail이나ActionFail을 호출하는 방법이 정식입니다. Check가 막으면Run은 실행되지 않으며 쿨다운도 되돌리지 않습니다.Check가 끝난 뒤 실행 직전에 창, 레벨,Allow,ActionAllowed,Secret을 다시 확인합니다.
Lazy와 Live
섹션 제목: “Lazy와 Live”- Lazy (기본):
LiveCheck가 없으면 실행할 때만 검사합니다. 화면에는 실행 전까지 에러가 표시되지 않는다는 안내가 나타납니다. - Live:
LiveCheck = 초를 지정하면 인자를 입력하는 동안에도 서버가Check를 실행해 잘못된 칸을 표시합니다. 서버는 사람마다 그 간격(5% 오차 허용)보다 잦은 요청은 실행하지 않습니다.
Live 검사는 감사 기록에 남지 않습니다. 실행을 시도하면 Run 직전에 Check가 항상 다시 실행되고, 그때 기록됩니다.
Devplorer.Action({ Name = "Ban (demo)", Group = "Moderation", Description = "Demo only: prints instead of banning.", MinLevel = "Developer", Confirm = "Ban this user? (demo: prints only)", Args = { { Name = "User", Type = "UserId" }, { Name = "Reason", Type = "String", MaxLength = 100 }, }, Check = function(player: Player, args) if args.User == player.UserId then Devplorer.ArgFail("User", "you cannot ban yourself") end if #args.Reason < 3 then Devplorer.ArgFail(2, "give a reason of at least 3 characters") end end, Run = function(player: Player, args) print(`demo ban of {args.User} by {player.Name}: {args.Reason}`) return `would ban {args.User}` end,})ActionFail와 ArgFail
섹션 제목: “ActionFail와 ArgFail”| 함수 | 쓰는 곳 | 효과 |
|---|---|---|
Devplorer.ActionFail(message) |
Check, Run |
실행한 사람에게 message를 이유로 표시합니다. |
Devplorer.ArgFail(arg, reason) |
Check, Run |
특정 인자가 잘못되었다고 표시합니다. arg는 인자 번호(1부터) 또는 이름입니다. 화면에서 해당 칸이 빨갛게 바뀌고 이유가 표시됩니다. |
- 정의에 없는 번호나 이름이면 이유만 표시됩니다.
- 이유 문구는
RedactLog를 거쳐 실행한 사람에게 그대로 전달됩니다. 대상의 등급처럼 민감할 수 있는 내용은 알려도 되는지 확인한 뒤 적어 주세요. - 이 두 함수 외의 에러는 서버 출력에만 자세히 남습니다. 실행한 사람은
Logs능력이 있을 때만 (RedactLog를 거친) 에러 내용을 볼 수 있고, 없으면action failed만 표시됩니다.
실행과 결과
섹션 제목: “실행과 결과”- 서버가 인자를 스키마로 다시 검사한 뒤 별도 스레드에서
Run(player, args)를 실행합니다. - 반환값은 문자열로 변환되어 2000자까지,
RedactLog를 거쳐 실행한 사람에게 전달됩니다. - 요청은
Timeout초까지 결과를 기다리고, 넘으면 아직 실행 중이라고 응답합니다. 스레드는 중단되지 않으며, 끝나면 서버 출력에 상태 한 줄을 남깁니다. - 동시 실행은 사람마다 2개, 서버 전체 16개까지입니다.
Run이 끝나지 않아도 5분이 지나면 실행 슬롯을 비웁니다(스레드는 중단하지 않습니다). - 쿨다운은 사람마다, 액션마다 따로 계산합니다.
- 실행할 때마다
Action감사 기록이 남습니다. 서버 출력에는 액션 이름만 남고, 인자와 결과는Audit의Data로 전달됩니다.
제거하기
섹션 제목: “제거하기”local removed: boolean = Devplorer.RemoveAction("Give test tool")RemoveAction은 등록을 지우고, 지웠으면 true를 돌려줍니다.
게임 개발자가 지켜야 할 점
섹션 제목: “게임 개발자가 지켜야 할 점”서버가 강제할 수 없어 개발자가 직접 챙겨야 하는 내용입니다.
- 액션은 좁고 구체적으로 작성해야 합니다. 경로, 함수 이름, 코드를 인자로 받아 무엇이든 호출하는 액션은 코드 실행 경로가 됩니다.
Confirm은 화면에서의 확인일 뿐입니다. 되돌릴 수 없는 작업은Run안에서도 따로 막아야 합니다.Player와UserId인자로는 더 높은 레벨의 사람도 선택할 수 있습니다. 밴이나 강퇴 같은 액션은Check에서 대상을 직접 비교하고ArgFail로 알려 주세요.Check와Run사이에 대상의 레벨이 바뀔 수 있으므로, 되돌릴 수 없는 작업은Run에서도 다시 확인하는 것이 좋습니다.Allow,ActionAllowed, 함수로 된Choices는 목록을 요청할 때마다 모든 액션에 대해 호출됩니다. yield 없이 빠르게 끝나야 하며, DataStore나 HTTP를 호출하면 안 됩니다.InvokeClient처럼 상대가 응답하지 않으면 끝나지 않는 호출은Check에서 쓰면 안 됩니다.Run은 실행이 끝나도록 작성해야 합니다. 제한 시간을 넘겨도 중단되지 않고, 권한이 철회되어도 이미 시작한Run은 계속 실행됩니다.- 문자열 인자는 로그, 채팅, DataStore 키로 쓰기 전에 다시 정리해 주세요. 에러 문구에 그대로 넣으면 안 됩니다.
Run의 반환값과ActionFail문구에는Secret으로 가린 인스턴스의 이름이나 경로, 개인정보를 넣으면 안 됩니다.- 동시 실행이 같은 정의를 공유하므로,
Run에서 쓰는 모듈 수준 상태는 경쟁 상태가 될 수 있습니다. Grant,Revoke,Reset을 액션 안에서 호출하면 안 됩니다. 액션을 실행할 권한이 곧 레벨을 주는 권한이 됩니다.Action,RemoveAction,Grant등을 클라이언트 입력으로 호출하면 안 됩니다.
클라이언트에서 실행되는 액션은 클라이언트 액션에서 다룹니다.