@minecraft/creator-tools
Version:
Minecraft Creator Tools command line and libraries.
280 lines (279 loc) • 12.9 kB
JavaScript
"use strict";
/**
* Handles Dedicated Server commands from the renderer process.
*
* This module manages the Minecraft Dedicated Server lifecycle, including
* starting, stopping, and sending commands to the server.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DedicatedServerCommandHandler = void 0;
const Utilities_1 = __importDefault(require("../core/Utilities"));
const ServerManager_1 = __importDefault(require("../local/ServerManager"));
const ServerMessage_1 = require("../local/ServerMessage");
class DedicatedServerCommandHandler {
_dsm;
_pendingCommands = [];
_pendingRequestIds = [];
_activeStdIn = null;
_currentCommandId = 0;
_lastResult = "";
_activeProcess = null;
_window;
_ipcMain;
_utils;
constructor(browserWindow, incomingIpcMain, env, creatorTools, utils) {
this._window = browserWindow;
this._ipcMain = incomingIpcMain;
this._utils = utils;
this.startServer = this.startServer.bind(this);
this.stopServer = this.stopServer.bind(this);
this.handleServerOutput = this.handleServerOutput.bind(this);
this.handleServerStopped = this.handleServerStopped.bind(this);
this.getDedicatedServerProjectPath = this.getDedicatedServerProjectPath.bind(this);
this.getDedicatedServerWorldPath = this.getDedicatedServerWorldPath.bind(this);
this.getDedicatedServerStatus = this.getDedicatedServerStatus.bind(this);
this.command = this.command.bind(this);
this.debugPause = this.debugPause.bind(this);
this.debugResume = this.debugResume.bind(this);
this.debugStartProfiler = this.debugStartProfiler.bind(this);
this.debugStopProfiler = this.debugStopProfiler.bind(this);
this._dsm = new ServerManager_1.default(env, creatorTools);
this._dsm.onServerOutput.subscribe(this.handleServerOutput);
this._dsm.onServerStopped.subscribe(this.handleServerStopped);
// Subscribe to debug events from the ServerManager and forward them via IPC
this._dsm.onDebugConnected.subscribe(this._handleDebugConnected.bind(this));
this._dsm.onDebugDisconnected.subscribe(this._handleDebugDisconnected.bind(this));
this._dsm.onDebugStats.subscribe(this._handleDebugStats.bind(this));
this._dsm.onDebugPaused.subscribe(this._handleDebugPaused.bind(this));
this._dsm.onDebugResumed.subscribe(this._handleDebugResumed.bind(this));
this._dsm.onProfilerCapture.subscribe(this._handleProfilerCapture.bind(this));
this._ipcMain.handle("asyncstartDedicatedServer", this.startServer);
this._ipcMain.handle("asyncstopDedicatedServer", this.stopServer);
this._ipcMain.handle("asyncdedicatedServerCommand", this.command);
this._ipcMain.handle("asyncgetDedicatedServerProjectDir", this.getDedicatedServerProjectPath);
this._ipcMain.handle("asyncgetDedicatedServerStatus", this.getDedicatedServerStatus);
this._ipcMain.handle("asyncgetDedicatedServerWorldDir", this.getDedicatedServerWorldPath);
this._ipcMain.handle("asyncdebugPause", this.debugPause);
this._ipcMain.handle("asyncdebugResume", this.debugResume);
this._ipcMain.handle("asyncdebugStartProfiler", this.debugStartProfiler);
this._ipcMain.handle("asyncdebugStopProfiler", this.debugStopProfiler);
}
command(_event, data) {
const slargs = data.split("|");
const newCommand = this._pendingCommands.length;
if (Utilities_1.default.isUsableAsObjectKey(String(newCommand))) {
this._pendingCommands[newCommand] = slargs[1];
this._pendingRequestIds[newCommand] = slargs[0];
}
if (newCommand === this._currentCommandId) {
this.executeNextCommand();
}
}
async executeNextCommand() {
if (this._currentCommandId < this._pendingCommands.length) {
this._currentCommandId++;
const nextCommand = this._currentCommandId - 1;
if (nextCommand >= this._pendingCommands.length) {
return;
}
const commandLine = this._pendingCommands[nextCommand];
const srv = await this._dsm.ensureActiveServer(0);
if (!srv) {
return;
}
await srv.writeToServer(commandLine);
this._window.webContents.send("appsvc", "asyncdedicatedServerComplete|" + this._pendingRequestIds[nextCommand] + "|" + this._lastResult);
await this.executeNextCommand();
}
}
async getDedicatedServerStatus(_event, data) {
const slargs = data.split("|");
const ds = this._dsm.getActiveServer(0);
if (!ds) {
this._window.webContents.send("appsvc", "asyncgetDedicatedServerStatusComplete|" + slargs[0] + "|-1");
}
else {
this._window.webContents.send("appsvc", "asyncgetDedicatedServerStatusComplete|" + slargs[0] + "|" + ds.status.toString());
}
}
async getDedicatedServerProjectPath(_event, data) {
const slargs = data.split("|");
const ds = this._dsm.getActiveServer(0);
let projectPath = ds ? ds.serverPath : "";
if (projectPath && projectPath.length > 0) {
const uniqueId = this._utils.ensureMappingForPath(projectPath);
projectPath = "<pt_" + uniqueId + ">";
}
this._window.webContents.send("appsvc", "asyncgetDedicatedServerProjectDirComplete|" + slargs[0] + "|" + projectPath);
}
async getDedicatedServerWorldPath(_event, data) {
const slargs = data.split("|");
const ds = this._dsm.getActiveServer(0);
const rawWorldPath = ds?.defaultWorldFolder?.fullPath ?? "";
let worldPath = rawWorldPath;
if (rawWorldPath.length > 0) {
const uniqueId = this._utils.ensureMappingForPath(rawWorldPath);
worldPath = "<pt_" + uniqueId + ">";
}
this._window.webContents.send("appsvc", "asyncgetDedicatedServerWorldDirComplete|" + slargs[0] + "|" + worldPath);
}
async stopServer(_event, data) {
const slargs = data.split("|");
await this._dsm.stopAllDedicatedServers();
this._window.webContents.send("appsvc", "dedicatedServerStopped|");
this._window.webContents.send("appsvc", "asyncdedicatedServerStopComplete|" + slargs[0] + "|");
}
processServerState(serverState) {
let mess = {};
if (serverState !== "") {
try {
mess = JSON.parse(serverState);
}
catch (e) {
return {};
}
this._dsm.environment.iAgreeToTheMinecraftEndUserLicenseAgreementAndPrivacyStatementAtMinecraftDotNetSlashEula = mess.iagree;
}
return mess;
}
async startServer(_event, data) {
const slargs = data.split("|");
const serverState = slargs[1];
const mess = this.processServerState(serverState);
const srv = await this._dsm.ensureActiveServer(0, mess);
if (!srv) {
this._window.webContents.send("appsvc", "dedicatedServerError|Could not create a server.");
return;
}
await srv.startServer(false, mess);
this._window.webContents.send("appsvc", "asyncdedicatedServerStartComplete|" + slargs[0] + "|");
}
handleServerOutput(_server, message) {
if (!message || !message.fullMessage) {
return;
}
// Don't forward internal system messages (e.g., querytarget polling output) to the renderer
if (message.category === ServerMessage_1.ServerMessageCategory.internalSystemMessage) {
return;
}
if (message.fullMessage.indexOf("Server started") >= 0) {
this._window.webContents.send("appsvc", "dedicatedServerStarted|");
}
this._window.webContents.send("appsvc", "dedicatedServerMessage|" + message.fullMessage);
}
handleServerStopped(_server, _message) {
this._window.webContents.send("appsvc", "dedicatedServerStopped|");
}
// ============================================================================
// Debug Event Handlers - Forward debug events from ServerManager to renderer
// ============================================================================
_handleDebugConnected(_server, sessionInfo) {
const body = {
eventName: "debugConnected",
protocolVersion: sessionInfo.protocolVersion,
sessionId: sessionInfo.targetModuleUuid,
};
this._window.webContents.send("appsvc", "dedicatedServerDebugConnected|" + JSON.stringify(body));
}
_handleDebugDisconnected(_server, reason) {
const body = {
eventName: "debugDisconnected",
reason: reason,
};
this._window.webContents.send("appsvc", "dedicatedServerDebugDisconnected|" + JSON.stringify(body));
}
_handleDebugStats(_server, statsData) {
// Flatten IStatData to IDebugStatItem format for the renderer
const items = statsData.stats.map((s) => ({
name: s.name,
values: s.values,
parent: s.parent_name || undefined,
}));
const body = {
eventName: "debugStats",
tick: statsData.tick,
stats: items,
};
this._window.webContents.send("appsvc", "dedicatedServerDebugStats|" + JSON.stringify(body));
}
_handleDebugPaused(_server, reason) {
const body = {
eventName: "debugPaused",
reason: reason,
};
this._window.webContents.send("appsvc", "dedicatedServerDebugPaused|" + JSON.stringify(body));
}
_handleDebugResumed(_server) {
const body = {
eventName: "debugResumed",
};
this._window.webContents.send("appsvc", "dedicatedServerDebugResumed|" + JSON.stringify(body));
}
_handleProfilerCapture(_server, captureEvent) {
const body = {
eventName: "profilerCapture",
captureBasePath: captureEvent.capture_base_path,
captureData: captureEvent.capture_data,
};
this._window.webContents.send("appsvc", "dedicatedServerProfilerCapture|" + JSON.stringify(body));
}
// ============================================================================
// Debug Command Handlers - Forward debug commands from renderer to debug client
// ============================================================================
async debugPause(_event, data) {
const slargs = data.split("|");
const ds = this._dsm.getActiveServer(0);
if (ds?.debugClient) {
ds.debugClient.pause();
}
this._window.webContents.send("appsvc", "asyncdebugPauseComplete|" + slargs[0] + "|");
}
async debugResume(_event, data) {
const slargs = data.split("|");
const ds = this._dsm.getActiveServer(0);
if (ds?.debugClient) {
ds.debugClient.resume();
}
this._window.webContents.send("appsvc", "asyncdebugResumeComplete|" + slargs[0] + "|");
}
async debugStartProfiler(_event, data) {
const slargs = data.split("|");
const ds = this._dsm.getActiveServer(0);
if (ds?.debugClient) {
try {
ds.debugClient.startProfiler();
// Send profiler state update
const body = { eventName: "debugProfilerState", isRunning: true };
this._window.webContents.send("appsvc", "dedicatedServerDebugProfilerState|" + JSON.stringify(body));
}
catch (e) {
// Profiler not supported
}
}
this._window.webContents.send("appsvc", "asyncdebugStartProfilerComplete|" + slargs[0] + "|");
}
async debugStopProfiler(_event, data) {
const slargs = data.split("|");
const ds = this._dsm.getActiveServer(0);
if (ds?.debugClient) {
try {
ds.debugClient.stopProfiler("profiler_captures");
// Send profiler state update
const body = { eventName: "debugProfilerState", isRunning: false };
this._window.webContents.send("appsvc", "dedicatedServerDebugProfilerState|" + JSON.stringify(body));
}
catch (e) {
// Profiler not supported
}
}
this._window.webContents.send("appsvc", "asyncdebugStopProfilerComplete|" + slargs[0] + "|");
}
register() {
// All handlers are registered in constructor
}
}
exports.DedicatedServerCommandHandler = DedicatedServerCommandHandler;
exports.default = DedicatedServerCommandHandler;