설치
게임에 넣는 항목
섹션 제목: “게임에 넣는 항목”게임에는 ServerStorage.Devplorer 폴더 하나만 넣으면 되며, 그 안에는 다음 두 항목이 있습니다.
| 이름 | 종류 | 설명 |
|---|---|---|
Server |
ModuleScript | 서버 모듈입니다. 이 아래에 Fiu 모듈이 함께 들어갑니다. |
Client |
ScreenGui | 클라이언트 번들입니다. UI 코드와 라이브러리가 들어 있으며, 평소에는 아무에게도 복제되지 않습니다. |
저장소의 default.project.json에는 DevplorerDev와 DevplorerDevBoot도 있습니다.
이 둘은 이 저장소의 개발 플레이스 전용이므로 게임에 넣을 필요가 없습니다.
Rojo로 연결하기
섹션 제목: “Rojo로 연결하기”1. 저장소와 라이브러리 받기
섹션 제목: “1. 저장소와 라이브러리 받기”저장소를 게임 프로젝트 옆(또는 안)에 두고 scripts/vendor.sh를 한 번 실행합니다.
이 스크립트는 vendor.lock.json에 고정된 라이브러리(quad, Fiu)를 vendor/ 아래에 내려받습니다.
인터프리터용 컴파일러도 같은 곳에 내려받으며, 인터프리터를 쓰지 않더라도 그대로 두면 됩니다.
scripts/vendor.shvendor/는 git에 올라가지 않으며, 고정된 해시로 언제든 다시 만들 수 있습니다.
2. 프로젝트 파일에 트리 추가하기
섹션 제목: “2. 프로젝트 파일에 트리 추가하기”게임의 Rojo 프로젝트 파일(default.project.json)의 ServerStorage 아래에 다음을 추가합니다.
devplorer/ 부분은 저장소를 둔 상대 경로로 바꿔 주세요.
"ServerStorage": { "$className": "ServerStorage", "Devplorer": { "$className": "Folder", "Server": { "$path": "devplorer/src/Server", "Fiu": { "$path": "devplorer/vendor/fiu/Source.lua" } }, "Client": { "$className": "ScreenGui", "Boot": { "$path": "devplorer/src/Client/Boot.client.luau" }, "App": { "$path": "devplorer/src/Client/App" }, "Shared": { "$path": "devplorer/src/Client/Shared" }, "quad-roblox": { "$className": "Folder", "src": { "$path": "devplorer/vendor/quad/quad-roblox/src" }, "luau_packages": { "$path": "devplorer/vendor/quad/quad-roblox/luau_packages" } }, "quad-roblox-devui": { "$className": "Folder", "src": { "$path": "devplorer/vendor/quad/quad-roblox-devui/src" } }, "$properties": { "ResetOnSpawn": false, "ZIndexBehavior": "Sibling", "DisplayOrder": 1000, "Enabled": true } } }}Start 호출하기
섹션 제목: “Start 호출하기”서버 Script(예: ServerScriptService 아래)에서 Server.Start를 한 번 호출합니다.
local Devplorer = require(game.ServerStorage.Devplorer.Server)
Devplorer.Start({ Provider = function(player: Player): string? -- 판정 함수는 아래에서 설명합니다 return nil end,})Provider를 넘기지 않으면 아무에게도 권한이 없으며, 이 경우 콘솔 명령(Grant)으로만 권한을 줄 수 있습니다.
Start는 서버Script에서 직접 호출해 주세요.pcall이나task.spawn안에서 호출하면 devplorer가 호출한 스크립트를 찾지 못해 경고를 출력하고, 그 스크립트를 편집으로부터 보호할 수 없습니다.- 이미 시작한 뒤에 다시 호출하면 아무 일도 일어나지 않습니다.
- 모든 설정은 Start 설정에서 설명합니다.
Provider 예시
섹션 제목: “Provider 예시”Provider는 (player) -> 레벨? 형태의 함수입니다. 레벨 이름("Tester", "MainTester", "Developer")을 돌려주거나, 권한이 없으면 nil을 돌려줍니다.
요청마다 호출되므로 가볍게 작성해야 합니다.
local Developers: { [number]: boolean } = { [1234567] = true,}local MainTesters: { [number]: boolean } = { [2345678] = true,}local Testers: { [number]: boolean } = { [3456789] = true,}
Devplorer.Start({ Provider = function(player: Player): string? if Developers[player.UserId] then return "Developer" elseif MainTesters[player.UserId] then return "MainTester" elseif Testers[player.UserId] then return "Tester" end return nil end,})Studio에서 시험하기
섹션 제목: “Studio에서 시험하기”Devplorer.MockProvider는 Studio 안에서는 모두를 Developer로 판정하고, Studio 밖에서는 아무에게도 레벨을 주지 않습니다.
Studio에서 먼저 시험해 볼 때 쓸 수 있습니다.
Devplorer.Start({ Provider = Devplorer.MockProvider })창 열기
섹션 제목: “창 열기”Start만으로는 창이 열리지 않습니다. 서버가 Devplorer.Open(대상)을 호출해야 해당 플레이어에게 번들이 복제됩니다.
Open은 권한을 다시 확인하므로, 권한이 없는 사람에게 호출해도 창은 열리지 않습니다.
여는 방법은 게임에 맞게 정할 수 있습니다. 대표적인 방법은 다음과 같습니다.
방법 1. 서버 콘솔
섹션 제목: “방법 1. 서버 콘솔”서버 콘솔(F9)에서 개발자가 직접 호출합니다.
local D = require(game.ServerStorage.Devplorer.Server)D.Open("Username")방법 2. 플레이어가 들어올 때 자동으로
섹션 제목: “방법 2. 플레이어가 들어올 때 자동으로”local Players = game:GetService("Players")
local function open(player: Player) pcall(Devplorer.Open, player)endPlayers.PlayerAdded:Connect(open)for _, player in Players:GetPlayers() do task.spawn(open, player)end권한이 없는 플레이어에게는 Open이 에러를 내고 감사 기록에 Denied가 남기 때문에 pcall로 감쌌습니다.
권한이 있는 사람이 많은 게임이라면 자동으로 여는 것보다 아래 방법을 권합니다.
방법 3. 게임이 만든 단축키 또는 채팅 명령
섹션 제목: “방법 3. 게임이 만든 단축키 또는 채팅 명령”키 입력과 채팅 명령은 클라이언트에서만 감지할 수 있는데, devplorer는 모든 클라이언트에 키 감지 코드를 넣지 않습니다. 그래서 게임의 원격 객체 하나로 서버에 창을 열어 달라고 요청하는 방식을 씁니다.
서버 Script:
local Players = game:GetService("Players")local ReplicatedStorage = game:GetService("ReplicatedStorage")
local request = Instance.new("RemoteEvent")request.Name = "OpenDevplorer"request.Parent = ReplicatedStorage
local lastAsk: { [Player]: number } = {}request.OnServerEvent:Connect(function(player: Player) -- Open에는 요청 빈도 제한이 없으므로 게임이 간격을 둡니다 local now = os.clock() if now - (lastAsk[player] or -10) < 2 then return end lastAsk[player] = now -- 권한은 Open이 다시 확인합니다. 권한이 없으면 에러가 나므로 pcall pcall(Devplorer.Open, player)end)Players.PlayerRemoving:Connect(function(player: Player) lastAsk[player] = nilend)게임의 LocalScript (단축키 예시):
local UserInputService = game:GetService("UserInputService")local ReplicatedStorage = game:GetService("ReplicatedStorage")
local request = ReplicatedStorage:WaitForChild("OpenDevplorer") :: RemoteEvent
UserInputService.InputBegan:Connect(function(input: InputObject, gameProcessed: boolean) if gameProcessed then return end if input.KeyCode == Enum.KeyCode.F10 then request:FireServer() endend)