@minecraft/creator-tools
Version:
Minecraft Creator Tools command line and libraries.
446 lines (445 loc) • 17.9 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const CreatorTools_1 = require("../app/CreatorTools");
const IMinecraft_1 = require("../app/IMinecraft");
const AppServiceProxy_1 = __importStar(require("../core/AppServiceProxy"));
const ste_events_1 = require("ste-events");
const Log_1 = __importDefault(require("../core/Log"));
const Utilities_1 = __importDefault(require("../core/Utilities"));
const ProjectExporter_1 = __importDefault(require("../app/ProjectExporter"));
const GameStateManager_1 = __importDefault(require("../minecraft/GameStateManager"));
const ICreatorToolsData_1 = require("../app/ICreatorToolsData");
const Status_1 = require("../app/Status");
class ProcessHostedMinecraft {
_creatorTools;
_project;
_gameStateManager;
errorStatus;
errorMessage;
state;
dedicatedServerStorage;
_dsDeployBehaviorPacksFolder;
worldFolder;
projectFolder;
worldContentStorage;
worldProject;
_onWorldStorageReady = new ste_events_1.EventDispatcher();
_onProjectStorageReady = new ste_events_1.EventDispatcher();
_onMessage = new ste_events_1.EventDispatcher();
_onStateChanged = new ste_events_1.EventDispatcher();
_onRefreshed = new ste_events_1.EventDispatcher();
// Debug event dispatchers for IPC-bridged debug data
_onDebugConnected = new ste_events_1.EventDispatcher();
_onDebugDisconnected = new ste_events_1.EventDispatcher();
_onDebugStats = new ste_events_1.EventDispatcher();
_onDebugPaused = new ste_events_1.EventDispatcher();
_onDebugResumed = new ste_events_1.EventDispatcher();
_onDebugProfilerState = new ste_events_1.EventDispatcher();
_onProfilerCapture = new ste_events_1.EventDispatcher();
get onWorldFolderReady() {
return this._onWorldStorageReady.asEvent();
}
get onProjectFolderReady() {
return this._onProjectStorageReady.asEvent();
}
get onDebugConnected() {
return this._onDebugConnected.asEvent();
}
get onDebugDisconnected() {
return this._onDebugDisconnected.asEvent();
}
get onDebugStats() {
return this._onDebugStats.asEvent();
}
get onDebugPaused() {
return this._onDebugPaused.asEvent();
}
get onDebugResumed() {
return this._onDebugResumed.asEvent();
}
get onDebugProfilerState() {
return this._onDebugProfilerState.asEvent();
}
get onProfilerCapture() {
return this._onProfilerCapture.asEvent();
}
get onMessage() {
return this._onMessage.asEvent();
}
get gameStateManager() {
return this._gameStateManager;
}
get onRefreshed() {
return this._onRefreshed.asEvent();
}
get onStateChanged() {
return this._onStateChanged.asEvent();
}
get activeProject() {
return this._project;
}
set activeProject(newProject) {
this._project = newProject;
}
get canDeployFiles() {
return true;
}
constructor(creatorTools) {
this._creatorTools = creatorTools;
this._gameStateManager = new GameStateManager_1.default(this._creatorTools);
this.dedicatedServerStorage = null;
this.state = CreatorTools_1.CreatorToolsMinecraftState.none;
this._dsDeployBehaviorPacksFolder = null;
this.updateStatus();
}
async updateStatus() {
const result = await AppServiceProxy_1.default.sendAsync(AppServiceProxy_1.AppServiceProxyCommands.getDedicatedServerStatus, "");
if (result) {
let resultNum = -1;
try {
resultNum = parseInt(result);
}
catch (e) { }
if (resultNum >= 0) {
if (resultNum === 1) {
this.notifyStateChanged(CreatorTools_1.CreatorToolsMinecraftState.stopped);
}
else if (resultNum === 2) {
this.notifyStateChanged(CreatorTools_1.CreatorToolsMinecraftState.initializing);
}
else if (resultNum === 3) {
this.notifyStateChanged(CreatorTools_1.CreatorToolsMinecraftState.preparing);
}
else if (resultNum === 4) {
this.notifyStateChanged(CreatorTools_1.CreatorToolsMinecraftState.starting);
}
else if (resultNum === 5) {
this.notifyStateChanged(CreatorTools_1.CreatorToolsMinecraftState.started);
}
}
}
return this.state;
}
async prepare(force) { }
processExternalMessage(command, data) {
switch (command) {
case "dedicatedServerStarted":
this.notifyStateChanged(CreatorTools_1.CreatorToolsMinecraftState.started);
if (!this._creatorTools.successfullyStartedMinecraftServer) {
this._creatorTools.successfullyStartedMinecraftServer = true;
this._creatorTools.save();
}
this._initWorldFolderOnStart();
break;
case "dedicatedServerRefreshed":
this.notifyRefreshed();
break;
case "dedicatedServerStopped":
this.notifyStateChanged(CreatorTools_1.CreatorToolsMinecraftState.stopped);
break;
case "dedicatedServerGameEvents":
this.notifyGameEvents(data);
break;
case "dedicatedServerMessage":
this._creatorTools.notifyStatusUpdate("Server: " + data, Status_1.StatusTopic.minecraft);
break;
case "dedicatedServerError":
this._creatorTools.notifyStatusUpdate("Server Error: " + data, Status_1.StatusTopic.minecraft);
break;
case "dedicatedServerDebugConnected":
try {
const connBody = JSON.parse(data);
this._onDebugConnected.dispatch(this, connBody);
}
catch (e) {
Log_1.default.debug("Failed to parse debugConnected IPC: " + e);
}
break;
case "dedicatedServerDebugDisconnected":
try {
const discBody = JSON.parse(data);
this._onDebugDisconnected.dispatch(this, discBody);
}
catch (e) {
Log_1.default.debug("Failed to parse debugDisconnected IPC: " + e);
}
break;
case "dedicatedServerDebugStats":
try {
const statsBody = JSON.parse(data);
this._onDebugStats.dispatch(this, statsBody);
}
catch (e) {
Log_1.default.debug("Failed to parse debugStats IPC: " + e);
}
break;
case "dedicatedServerDebugPaused":
try {
const pauseBody = JSON.parse(data);
this._onDebugPaused.dispatch(this, pauseBody);
}
catch (e) {
Log_1.default.debug("Failed to parse debugPaused IPC: " + e);
}
break;
case "dedicatedServerDebugResumed":
try {
const resumeBody = JSON.parse(data);
this._onDebugResumed.dispatch(this, resumeBody);
}
catch (e) {
Log_1.default.debug("Failed to parse debugResumed IPC: " + e);
}
break;
case "dedicatedServerDebugProfilerState":
try {
const profStateBody = JSON.parse(data);
this._onDebugProfilerState.dispatch(this, profStateBody);
}
catch (e) {
Log_1.default.debug("Failed to parse debugProfilerState IPC: " + e);
}
break;
case "dedicatedServerProfilerCapture":
try {
const captBody = JSON.parse(data);
this._onProfilerCapture.dispatch(this, captBody);
}
catch (e) {
Log_1.default.debug("Failed to parse profilerCapture IPC: " + e);
}
break;
}
}
async initialize() {
await this.start();
}
get dedicatedServerBehaviorPacksFolder() {
return this._dsDeployBehaviorPacksFolder;
}
notifyGameEvents(data) {
let obj = undefined;
try {
obj = JSON.parse(data);
}
catch (e) { }
if (!obj || !obj.length) {
return;
}
for (let i = 0; i < obj.length; i++) {
const event = obj[i];
this._gameStateManager?.handleEvent(event);
}
}
_updateDedicatedServerStorage() {
if (this._creatorTools.ensureLocalFolder === undefined ||
!AppServiceProxy_1.default.hasAppService ||
this._creatorTools.dedicatedServerPath === undefined) {
return;
}
const folder = this._creatorTools.ensureLocalFolder(this._creatorTools.dedicatedServerPath);
this.dedicatedServerStorage = folder.storage;
if (this.dedicatedServerStorage != null) {
this._dsDeployBehaviorPacksFolder =
this.dedicatedServerStorage.rootFolder.ensureFolder("development_behavior_packs");
}
else {
this._dsDeployBehaviorPacksFolder = null;
}
}
/**
* Send a debug pause command to the main process.
*/
async debugPause() {
await AppServiceProxy_1.default.sendAsync(AppServiceProxy_1.AppServiceProxyCommands.debugPause, "");
}
/**
* Send a debug resume command to the main process.
*/
async debugResume() {
await AppServiceProxy_1.default.sendAsync(AppServiceProxy_1.AppServiceProxyCommands.debugResume, "");
}
/**
* Send a debug start profiler command to the main process.
*/
async debugStartProfiler() {
await AppServiceProxy_1.default.sendAsync(AppServiceProxy_1.AppServiceProxyCommands.debugStartProfiler, "");
}
/**
* Send a debug stop profiler command to the main process.
*/
async debugStopProfiler() {
await AppServiceProxy_1.default.sendAsync(AppServiceProxy_1.AppServiceProxyCommands.debugStopProfiler, "");
}
/**
* When the dedicated server starts, query the main process for the world folder path
* via IPC so that the world map and debug stats panels appear in MinecraftDisplay
* immediately, without requiring a deploy operation first.
*/
async _initWorldFolderOnStart() {
if (this.worldFolder) {
return; // Already set from a previous deploy
}
// Ask the main process for the world folder path - this works regardless of
// whether dedicatedServerPath is set (auto mode vs manual mode)
const worldPath = await AppServiceProxy_1.default.sendAsync(AppServiceProxy_1.AppServiceProxyCommands.getDedicatedServerWorldDeployDir, "");
if (worldPath && worldPath.length > 0 && this._creatorTools.ensureLocalFolder) {
const worldFolder = this._creatorTools.ensureLocalFolder(worldPath);
this.worldFolder = worldFolder;
this._onWorldStorageReady.dispatch(this, worldFolder);
}
}
notifyStateChanged(newVal) {
this.state = newVal;
this._onStateChanged.dispatch(this, newVal);
}
notifyRefreshed(newVal) {
if (newVal) {
this.state = newVal;
}
this._onRefreshed.dispatch(this, this.state);
}
async start() {
const path = this.getDedicatedServerSyntax();
this.notifyStateChanged(CreatorTools_1.CreatorToolsMinecraftState.starting);
await AppServiceProxy_1.default.sendAsync(AppServiceProxy_1.AppServiceProxyCommands.startDedicatedServer, path);
}
async prepareDedicatedServer(project) {
await this.syncWithDeployment();
return await this.deployDedicatedServerWorld(project);
}
async restartDedicatedServer(project) {
await this.stop();
await this.prepareDedicatedServer(project);
await this.start();
}
canPrepare() {
return true;
}
async prepareAndStart(push) {
let worldName = undefined;
if (this._project) {
worldName = await this.prepareDedicatedServer(this._project);
}
await this.start();
return {
type: IMinecraft_1.PrepareAndStartResultType.started,
worldName: worldName,
};
}
async syncWithDeployment() {
if (this._creatorTools.ensureLocalFolder == null) {
throw new Error("This instance doesn't support deployment");
}
if (!this._project) {
return;
}
const folderPath = await AppServiceProxy_1.default.sendAsync(AppServiceProxy_1.AppServiceProxyCommands.getDedicatedServerProjectDeployDir, "");
if (folderPath && folderPath.length > 0) {
const deployFolder = this._creatorTools.ensureLocalFolder(folderPath);
const deployFolderExists = deployFolder;
if (deployFolderExists) {
await ProjectExporter_1.default.deployProject(this._creatorTools, this._project, deployFolder);
}
}
}
async runCommand(command) {
const result = await AppServiceProxy_1.default.sendAsync(AppServiceProxy_1.AppServiceProxyCommands.dedicatedServerCommand, command);
return result;
}
async runActionSet(actionSet) {
return undefined;
}
async deployDedicatedServerWorld(project) {
if (this.dedicatedServerStorage === null) {
return;
}
const worldFolderName = project.deployWorldId;
const worldDisplayName = project.name + " _mct";
const worldFolder = this.dedicatedServerStorage.rootFolder.ensureFolder("worlds").ensureFolder(worldFolderName);
await worldFolder.ensureExists();
await ProjectExporter_1.default.syncFlatPackRefWorldTo(this._creatorTools, project, worldFolder, worldDisplayName);
await worldFolder.saveAll();
await project.save();
this.worldFolder = worldFolder;
this._onWorldStorageReady.dispatch(this, worldFolder);
return worldDisplayName;
}
getDedicatedServerSyntax() {
if (!this._creatorTools.worldSettings) {
Log_1.default.debugAlert("World settings are not defined.");
throw new Error();
}
if (this._creatorTools.dedicatedServerMode !== ICreatorToolsData_1.DedicatedServerMode.auto &&
(this._creatorTools.dedicatedServerPath === null || this._creatorTools.dedicatedServerPath === undefined)) {
Log_1.default.debugAlert("Server folder path is not defined, and the path cannot be set.");
throw new Error();
}
let path = this._creatorTools.dedicatedServerPath;
if (!path) {
path = "";
}
let worldSettings = this._creatorTools.worldSettings;
if (this._project && this._project.worldSettings) {
if (this._project.worldSettings.useCustomSettings) {
worldSettings = this._project.worldSettings;
}
}
if (!worldSettings.name) {
worldSettings.name = "world";
}
const mess = {
path: Utilities_1.default.ensureEndsWithBackSlash(path),
iagree: this._creatorTools
.iAgreeToTheMinecraftEndUserLicenseAgreementAndPrivacyStatementAtMinecraftDotNetSlashEula
? true
: false,
mode: this._creatorTools.dedicatedServerMode,
track: this._creatorTools.track,
worldSettings: worldSettings,
};
return JSON.stringify(mess);
}
async stop() {
const path = this.getDedicatedServerSyntax();
this.notifyStateChanged(CreatorTools_1.CreatorToolsMinecraftState.stopping);
await AppServiceProxy_1.default.sendAsync(AppServiceProxy_1.AppServiceProxyCommands.stopDedicatedServer, path);
}
}
exports.default = ProcessHostedMinecraft;