import { readFileSync, writeFileSync } from 'node:fs'; // 플레이어 입력 잠금: 맵 로드 시 LocalPlayer의 PlayerControllerComponent를 런타임 설정. // (gen-camera.mjs에서 분리 — 카메라 제어와 플레이어 제어를 주체별로 나눔) // · 입력 차단(턴제 전투) · 시선을 오른쪽(전투 포메이션 방향)으로 고정 // 정적 이동 차단은 freeze-turn-player.mjs(Global/DefaultPlayer.model)가 담당하며, 이 스크립트는 런타임 컨트롤러를 제어한다. const LOOK_DIRECTION_X = 1; // 1 = 오른쪽(몬스터가 배치된 전투 포메이션 방향) const FIXED_LOOK_AT = true; // 바라보는 방향 고정 const CONTROLLER_ENABLE = false; // 플레이어 입력 차단 const MAP_NUMBERS = Array.from({ length: 11 }, (_, i) => i + 1); // map01~11 function prop(Type, Name, DefaultValue = 'nil') { return { Type, DefaultValue, SyncDirection: 0, Attributes: [], Name }; } function method(Name, Code, Arguments = [], ExecSpace = 6) { return { Return: { Type: 'void', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: null }, Arguments, Code, Scope: 2, ExecSpace, Attributes: [], Name, }; } function writeCodeblock() { const cb = { Id: '', GameId: '', EntryKey: 'codeblock://playerlock', ContentType: 'x-mod/codeblock', Content: '', Usage: 0, UsePublish: 1, UseService: 0, CoreVersion: '26.5.0.0', StudioVersion: '', DynamicLoading: 0, ContentProto: { Use: 'Json', Json: { CoreVersion: { Major: 0, Minor: 2 }, ScriptVersion: { Major: 1, Minor: 0 }, Description: '', Id: 'PlayerLock', Language: 1, Name: 'PlayerLock', Type: 1, Source: 0, Target: null, Properties: [prop('number', 'LockTries', '0')], Methods: [ method('OnBeginPlay', `self.LockTries = 0 local eventId = 0 local function apply() self.LockTries = self.LockTries + 1 local pc = nil local lp = _UserService.LocalPlayer if lp ~= nil then pc = lp.PlayerControllerComponent end if pc ~= nil then pc.LookDirectionX = ${LOOK_DIRECTION_X} pc.FixedLookAt = ${FIXED_LOOK_AT} pc.Enable = ${CONTROLLER_ENABLE} end if pc ~= nil then _TimerService:ClearTimer(eventId) elseif self.LockTries > 30 then _TimerService:ClearTimer(eventId) end end eventId = _TimerService:SetTimerRepeat(apply, 0.1)`), ], EntityEventHandlers: [], }, }, }; writeFileSync('RootDesk/MyDesk/PlayerLock.codeblock', JSON.stringify(cb, null, 2), 'utf8'); } function patchMap(nn) { const tag = String(nn).padStart(2, '0'); const file = `map/map${tag}.map`; const map = JSON.parse(readFileSync(file, 'utf8')); const root = map.ContentProto.Entities.find((e) => e.path === `/maps/map${tag}`); if (!root) throw new Error(`[gen-player-lock] 맵 루트 없음: ${file}`); // idempotent: 기존 script.PlayerLock 제거 후 재추가 root.jsonString['@components'] = root.jsonString['@components'].filter((c) => c['@type'] !== 'script.PlayerLock'); root.jsonString['@components'].push({ '@type': 'script.PlayerLock', Enable: true }); const names = (root.componentNames || '').split(',').filter((s) => s && s !== 'script.PlayerLock'); names.push('script.PlayerLock'); root.componentNames = names.join(','); writeFileSync(file, JSON.stringify(map, null, 2), 'utf8'); return `map${tag}`; } writeCodeblock(); const patched = MAP_NUMBERS.map(patchMap); console.log('PlayerLock codeblock written; patched maps:', patched.join(', '));