Start 설정
게임의 서버 Script에서 Server.Start를 한 번 호출합니다. 모든 설정은 선택 사항입니다.
local Devplorer = require(game.ServerStorage.Devplorer.Server)
Devplorer.Start({ Provider = provider, Audit = audit, -- ...})Start는 실패할 수 있는 작업(설정 검사)을 먼저 마친 뒤에 상태를 바꿉니다. 설정이 잘못되면 에러를 내고 아무것도 시작하지 않습니다.
필드 한눈에 보기
섹션 제목: “필드 한눈에 보기”| 필드 | 타입 | 기본값 | 하는 일 |
|---|---|---|---|
Provider |
(Player) -> Level? |
없음(아무도 권한 없음) | 레벨 판정 |
Audit |
(AuditEntry) -> () |
없음 | 감사 기록을 게임으로 넘김 |
SettingsStore |
저장소, false |
DataStore | 북마크와 창 배치 저장 |
Secret |
(Instance, Player) -> boolean |
없음 | 서버 값 가리기 |
Editable |
(Player, Instance, string, any) -> any |
없음(허용) | 서버 편집 허용 후크 |
RedactLog |
(string) -> string? |
없음 | 서버 출력 거르기 |
LevelCapabilities |
{ [string]: { Capability } } |
기본 표 | 레벨별 능력 |
ActionAllowed |
(Player, string, string) -> any |
없음(통과) | 디버그 액션 허용 후크 |
History |
boolean |
켬 | 서버 수치 기록 |
Interpreter |
{ Compiler: ModuleScript } |
꺼짐 | 인터프리터 |
ClientActions |
{ { Module, MinLevel? } } |
없음 | 클라이언트 디버그 액션 |
Provider
섹션 제목: “Provider”레벨을 정하는 판정 함수입니다. 권한을 주려면 사실상 필요합니다.
- 형태:
(player: Player) -> Level?. 레벨은"Tester","MainTester","Developer"중 하나입니다. - 요청마다 호출되므로 yield하지 않도록 작성하고, 웹 호출이 필요한 판정은 미리 캐시해 두는 것을 권합니다.
- 에러가 나거나 레벨이 아닌 값을 돌려주면 권한 없음입니다. 에러는 플레이어마다 한 번만 경고로 출력됩니다.
- 서버 콘솔의
Grant와Revoke가Provider보다 우선합니다.
Provider = function(player: Player): string? if Admins[player.UserId] then return "Developer" end return nilend,Audit
섹션 제목: “Audit”권한 부여, 회수, 창 열기, 거부, 편집, 실행을 게임의 감사 기록으로 넘기는 콜백입니다.
서버 출력에는 이 설정과 상관없이 [Devplorer] ... 줄이 남습니다.
콜백은 task.spawn 안에서 pcall로 호출됩니다. 에러가 나도 devplorer는 멈추지 않고 경고만 출력합니다.
AuditEntry의 형태는 다음과 같습니다.
| 필드 | 설명 |
|---|---|
Kind |
"Grant", "Revoke", "Reset", "Open", "Close", "Denied", "Edit", "Execute", "Action", "ClientAction", "Agent" 중 하나 |
UserId, Name |
행동한 사람 |
Detail |
한 줄 설명 |
Data |
구조화된 기록(없을 수 있음) |
Data의 내용은 종류마다 다릅니다.
Kind |
Data |
|---|---|
Edit |
Property, Value, Targets, Previous |
Execute |
인터프리터: Target, Source(전체 코드). Remote 디버깅: Remote, Target, Args |
Action |
Action, Args(이름 → 글), Status, Result |
ClientAction |
Action, Status |
Agent |
Expose, Minutes |
서버 출력 줄에는 편집한 값, 보낸 인자 같은 값을 싣지 않습니다. 서버 출력은 Logs 능력이 있는 사람이 읽을 수 있기 때문입니다.
값은 이 콜백의 Data로만 갑니다.
Audit = function(entry) -- 예: 게임의 로그 서비스에 남깁니다 MyLogger.write(entry.Kind, entry.UserId, entry.Detail, entry.Data)end,SettingsStore
섹션 제목: “SettingsStore”뷰어 설정(북마크와 창 배치)을 어디에 저장할지 정합니다. 키는 u<UserId>입니다.
| 값 | 동작 |
|---|---|
| 없음 | DataStore "DevplorerSettings"에 저장합니다. DataStore를 쓸 수 없으면 서버 메모리를 대신 사용합니다. |
false |
서버 메모리에만 둡니다. 서버가 닫히면 사라집니다. |
Devplorer.DataStoreSettings("이름") |
다른 이름의 DataStore를 씁니다(1~50자). |
{ Load, Save } 표 |
직접 만든 저장소입니다. |
DataStore 저장소는 다음과 같이 동작합니다.
- 쓰기는 사람마다 8초에 한 번으로 모아 마지막 값만 저장합니다. 서버가 닫힐 때 밀린 쓰기를 마저 처리합니다.
- 불러오기에 실패한 사람의 값은 DataStore에 쓰지 않습니다(저장된 값을 기본값으로 덮지 않게).
- Studio에서는 API 접근을 켜야 DataStore가 동작합니다. 꺼져 있으면 서버 메모리를 대신 사용합니다.
직접 만든 저장소는 다음 형태여야 합니다.
SettingsStore = { Load = function(userId: number): any return MyStore[userId] end, Save = function(userId: number, data: any) MyStore[userId] = data end,},Load와 Save는 yield하거나 에러를 내도 됩니다(서버가 pcall로 감쌉니다). 값의 형식과 크기는 서버가 미리 검사합니다.
저장소 객체가 아닌 값(예: 함수가 빠진 테이블)을 넘기면 Start가 에러를 냅니다.
Secret
섹션 제목: “Secret”값을 가릴 서버 인스턴스를 판정하는 함수입니다. 형태는 (instance: Instance, player: Player) -> boolean입니다.
nil과false가 아닌 값을 돌려주면 그 인스턴스의 속성, 특성 값, 태그를 가려서 보냅니다. 이름과 트리 구조는 보입니다.- 에러가 나면 가립니다(fail closed).
- 가려진 인스턴스는 편집, 옮기기, 복제, 지우기가 막히고 Remote 디버깅 대상으로도 쓸 수 없습니다.
- 자손까지 가리려면 판정 안에서 조상을 확인하면 됩니다. 폴더 자체도 포함해야 합니다.
FindFirstAncestor의 반환값을 그대로 돌려줘도 됩니다. 찾으면 인스턴스, 찾지 못하면nil입니다.
Secret = function(instance: Instance): any return instance.Name == "Secrets" or instance:FindFirstAncestor("Secrets")end,한계: 클라이언트에 이미 복제된 인스턴스의 값은 가릴 수 없습니다. 클라이언트가 직접 읽기 때문입니다.
Secret은 ServerStorage나 ServerScriptService 같은 서버 전용 위치의 값에만 의미가 있습니다.
Editable
섹션 제목: “Editable”서버 편집을 허용할지 판정하는 후크입니다. 형태는 (user: Player, target: Instance, propName: string, value: any) -> any입니다.
- 정확히
true를 돌려줄 때만 편집을 허용합니다. 다른 값을 돌려주거나 에러가 나면 막습니다. - 후크가 없으면 허용입니다(이미
Edit권한이 있는 사람에 한해서). - 도구 자신, 비밀 인스턴스, 서비스 같은 늘 막음은 후크로 풀 수 없습니다.
- yield하지 않는 것을 권합니다.
propName은 속성 편집이면 속성 이름이고, 그 밖의 편집은 예약 이름입니다.
propName |
뜻 | value |
|---|---|---|
| (속성 이름) | 속성 편집 | 새 값. 참조 속성이면 대상 Instance(비우기는 nil) |
"Attribute:<이름>" |
특성 편집 | 새 값. 지우기는 nil |
"Tags" |
태그 편집 | { Add, Remove } |
"$Create" |
만들기 (target은 부모) |
클래스 이름 |
"$Destroy" |
지우기 | |
"Parent" |
옮기기 | 새 부모 |
"$Clone" |
복제 | 붙일 부모 |
"$Watch" |
Remote와 Bindable 보기 켜기/끄기 | 켜기 여부 |
"$Send" |
Remote 보내기 | 받을 UserId, nil이면 모두 |
"$Invoke" |
Remote 부르기 | UserId 또는 nil |
Editable = function(user: Player, target: Instance, propName: string, value: any): boolean -- Workspace 안에서만 편집을 허용합니다 return target:IsDescendantOf(workspace)end,RedactLog
섹션 제목: “RedactLog”서버 출력을 Logs 능력이 있는 사람에게 보내기 전에 필터링하는 후크입니다. 형태는 (text: string) -> string?입니다.
- 문자열을 돌려주면 그 내용으로 바꾸고,
nil을 돌려주거나 에러가 나면 그 줄을 뺍니다. - 서버 출력 모으기, 에러의 메시지와 스택과 출처 경로, 디버그 액션의 결과, 마커에 모두 적용됩니다.
서버 로그에 토큰이나 웹훅 주소를 출력하는 게임이라면 여기서 가릴 수 있습니다.
RedactLog = function(text: string): string? return (string.gsub(text, "sk_%w+", "sk_***"))end,LevelCapabilities
섹션 제목: “LevelCapabilities”레벨별 능력을 바꿉니다. 여기에 적은 레벨은 적힌 능력만 가지며 누적되지 않습니다. 적지 않은 레벨은 기본 구성을 따릅니다.
능력 이름은 "View", "Server", "ServerValues", "Logs", "Edit", "Execute"입니다.
LevelCapabilities = { Tester = { "View", "Server", "Logs" }, -- 서버 값 읽기는 MainTester부터},자세한 내용은 권한과 레벨에서 다룹니다.
ActionAllowed
섹션 제목: “ActionAllowed”모든 디버그 액션에 적용되는 허용 후크입니다. 형태는 (player: Player, name: string, group: string) -> any입니다.
- 정확히
true를 돌려줄 때만 해당 사용자가 그 액션을 보고 실행할 수 있습니다. 에러가 나면 거부됩니다. - 액션의
MinLevel,Allow와 함께 검사합니다. 셋 다 통과해야 합니다. Provider와 마찬가지로 devplorer로 편집할 수 없는 값만 읽어야 합니다.- 액션 목록을 보낼 때마다 모든 액션에 대해 호출됩니다. yield 없이 빠르게 끝나도록 작성해야 하며, DataStore나 HTTP를 호출하면 안 됩니다.
ActionAllowed = function(player: Player, name: string, group: string): boolean return group ~= "Moderation" or Moderators[player.UserId] == trueend,자세한 내용은 디버그 액션에서 다룹니다.
History
섹션 제목: “History”서버 수치를 Start 시점부터 1초마다 표본으로 쌓는 기록기입니다. 기본으로 켜져 있으며 false로 끌 수 있습니다.
- 기록하는 수치: Heartbeat 시간, 물리 스텝 시간, 인스턴스 수, 움직이는 프리미티브 수, 메모리, 스크립트 메모리, 송수신 속도, 플레이어 수, 에러 수.
- 버킷 크기는 10초(1시간), 1분(24시간), 10분(72시간)입니다. 버킷마다 평균과 최대가 남습니다.
- 서버 메모리에 쌓이며 서버가 닫히면 사라집니다.
History = false,기록은 Inspect에서 확인할 수 있습니다.
Interpreter
섹션 제목: “Interpreter”게임이 컴파일러 모듈을 넘긴 경우에만 인터프리터가 켜집니다.
Interpreter = { Compiler = game.ServerStorage.LuauCompiler },Compiler는ModuleScript여야 하고ServerStorage나ServerScriptService아래에 있어야 합니다. 아니면Start가 에러를 냅니다.- 켜면
Execute능력이 있는 사람이 서버에서 코드를 실행할 수 있습니다.Start가 어느 레벨이Execute를 갖는지 출력합니다.
자세한 내용은 인터프리터 켜기에서 다룹니다.
ClientActions
섹션 제목: “ClientActions”클라이언트에서 실행되는 디버그 액션 묶음입니다.
ClientActions = { { Module = game.ServerStorage.QAClientActions, MinLevel = "Tester" },},Module은ModuleScript이고ServerStorage나ServerScriptService아래여야 합니다. 스크립트 자손이 있으면Start가 거절합니다.MinLevel의 기본값은"Developer"입니다. 창을 열 때 레벨이MinLevel이상인 사람의 번들에만 모듈을 복제합니다.- 서버는 이 모듈을
require하지 않습니다.
자세한 내용은 클라이언트 액션에서 다룹니다.