UNPKG

greybel-js

Version:

Transpiler/Interpreter for GreyScript. (GreyHack)

170 lines (165 loc) 7.29 kB
import GreyHackMessageHookClientPkg from 'greyhack-message-hook-client'; import { generateAutoCompileCode } from './scripts/auto-compile-helper.js'; import { generateAutoGenerateFoldersCode } from './scripts/auto-generate-folders.js'; import { createBasePath } from '../helper/create-base-path.js'; import { logger } from '../helper/logger.js'; import EventEmitter from 'node:events'; const { BuildAgent: Agent } = GreyHackMessageHookClientPkg; var ClientMessageType; (function (ClientMessageType) { ClientMessageType[ClientMessageType["CreatedBuildRpc"] = 1100] = "CreatedBuildRpc"; ClientMessageType[ClientMessageType["AddedResourceToBuildRpc"] = 1101] = "AddedResourceToBuildRpc"; ClientMessageType[ClientMessageType["AddedScriptRpc"] = 1102] = "AddedScriptRpc"; ClientMessageType[ClientMessageType["BuildStateRpc"] = 1103] = "BuildStateRpc"; ClientMessageType[ClientMessageType["BuildFinishedRpc"] = 1104] = "BuildFinishedRpc"; ClientMessageType[ClientMessageType["DisposedBuildRpc"] = 1110] = "DisposedBuildRpc"; })(ClientMessageType || (ClientMessageType = {})); var BuildState; (function (BuildState) { BuildState[BuildState["Initial"] = 0] = "Initial"; BuildState[BuildState["Allocating"] = 1] = "Allocating"; BuildState[BuildState["PreScript"] = 2] = "PreScript"; BuildState[BuildState["CreatingEntities"] = 3] = "CreatingEntities"; BuildState[BuildState["PostScript"] = 4] = "PostScript"; BuildState[BuildState["Closing"] = 5] = "Closing"; BuildState[BuildState["Complete"] = 10] = "Complete"; BuildState[BuildState["Failed"] = 20] = "Failed"; BuildState[BuildState["Unknown"] = 30] = "Unknown"; })(BuildState || (BuildState = {})); class Importer { importRefs; rootDir; agent; _instance; rootPaths; ingameDirectory; resourceDirectory; port; autoCompile; constructor(options) { this.agent = new Agent({ warn: () => { }, error: () => { }, info: () => { }, debug: () => { } }, this.port); this._instance = null; this.rootDir = options.rootDir; this.rootPaths = options.rootPaths; this.port = options.port; this.ingameDirectory = options.ingameDirectory.trim().replace(/\/$/i, ''); this.resourceDirectory = options.resourceDirectory.trim().replace(/\/$/i, ''); this.importRefs = this.createImportList(options.rootDir, options.result); this.autoCompile = options.autoCompile; } createImportList(rootDir, parseResult) { return Object.entries(parseResult).reduce((result, [target, code]) => { const ingameFilepath = createBasePath(rootDir, target, ''); result.set(target, { ingameFilepath, content: code }); return result; }, new Map()); } async addPrepareFoldersScript() { const ingamePaths = Array.from(this.importRefs.values()).map((it) => it.ingameFilepath); await this._instance.addScriptToBuild(10, generateAutoGenerateFoldersCode(ingamePaths)); } async addResources() { const items = Array.from(this.importRefs.values()); // increase max listeners to avoid warning when importing many files this.agent.buildClient.core._responseManager.setMaxListeners(items.length + 1); await Promise.all(items.map((item) => { return this._instance.addResourceToBuild(item.ingameFilepath, item.content); })); this.agent.buildClient.core._responseManager.setMaxListeners(EventEmitter.defaultMaxListeners); } async addAutoCompile() { const rootImports = this.rootPaths.map((it) => { return this.importRefs.get(it); }); await this._instance.addScriptToBuild(20, generateAutoCompileCode({ rootFilePaths: rootImports.map((it) => it.ingameFilepath), importPaths: Array.from(this.importRefs.values()).map((it) => it.ingameFilepath), allowImport: this.autoCompile.allowImport })); } async import() { try { const result = await this.agent.tryToCreateBuild(this.ingameDirectory, this.resourceDirectory, this.autoCompile.enabled); if (!result.success) { return { buildID: null, state: BuildState.Unknown, errorMessage: result.message, output: '' }; } this._instance = result.value; await this.addPrepareFoldersScript(); await this.addResources(); if (this.autoCompile.enabled) { await this.addAutoCompile(); } await this._instance.performBuild(); const buildResult = await this._instance.waitForResponse((id) => { return (id === ClientMessageType.BuildFinishedRpc || id === ClientMessageType.DisposedBuildRpc); }); return { buildID: buildResult.buildID, state: buildResult.state, errorMessage: buildResult.errorMessage, output: buildResult.output }; } catch (e) { return { buildID: null, state: BuildState.Unknown, errorMessage: e.message, output: '' }; } finally { try { await this._instance.dispose(); } catch { } this._instance = null; await this.agent.dispose(); } } } var CommonImportErrorReason; (function (CommonImportErrorReason) { CommonImportErrorReason["NoAvailableSocket"] = "There is no available socket!"; CommonImportErrorReason["NewGameVersion"] = "A new game update is available."; })(CommonImportErrorReason || (CommonImportErrorReason = {})); const reportFailure = (result) => { if (result.errorMessage.indexOf(CommonImportErrorReason.NoAvailableSocket) !== -1) { logger.debug(`File import failed The issue appears to be due to the lack of an available socket. This could suggest that the BepInEx plugin is not installed correctly, or the game is not running. Double-check the plugin installation and ensure the game is running. For detailed troubleshooting steps, please consult the documentation: https://github.com/ayecue/greybel-js?tab=readme-ov-file#message-hook.`); return; } else if (result.errorMessage.indexOf(CommonImportErrorReason.NewGameVersion) !== -1) { logger.debug(`File import failed It seems that the game has received an update. This can sometimes cause issues with the import process. Please wait for the Greybel developers to update the package and try again later.`); return; } logger.debug(`File import failed! ${result.errorMessage}`); }; export const executeImport = async (options) => { const importer = new Importer(options); const result = await importer.import(); if (result.state !== BuildState.Complete) { reportFailure(result); return false; } logger.debug(`Files got imported to ${options.ingameDirectory}!`); return true; };