From e5a187ce19eab56a496d4e328d7a83d39b8582bd Mon Sep 17 00:00:00 2001 From: austin Date: Tue, 2 Jul 2024 16:14:05 -0400 Subject: [PATCH] script engine work --- .gitignore | 5 +- .vscode/settings.json | 4 +- assets/Scripts/compiler/compiler.js | 113 ++++++++++ assets/Scripts/compiler/file_resolution.js | 23 +++ assets/Scripts/compiler/get_typescript.sh | 1 + assets/Scripts/compiler/host_access.js | 9 + assets/Scripts/compiler/require_polyfill.js | 36 ++++ assets/Scripts/engine/engine-init.ts | 7 + assets/Scripts/engine/engine-interface.ts | 9 + assets/Scripts/test.js | 1 - .../highlevel-design/locations/biomesindex.md | 3 +- .../locations/minidungeons.md | 4 + docs/src/progress/currenttarget.md | 1 - docs/src/progress/renderertodo.md | 4 +- .../java/electrosphere/engine/Globals.java | 1 - src/main/java/electrosphere/engine/Main.java | 3 + .../entity/scene/SceneLoader.java | 9 +- .../java/electrosphere/logger/Logger.java | 4 + .../electrosphere/logger/LoggerInterface.java | 2 + .../electrosphere/script/ScriptEngine.java | 194 ++++++++++++++++-- tsconfig.json | 9 + 21 files changed, 414 insertions(+), 28 deletions(-) create mode 100644 assets/Scripts/compiler/compiler.js create mode 100644 assets/Scripts/compiler/file_resolution.js create mode 100644 assets/Scripts/compiler/get_typescript.sh create mode 100644 assets/Scripts/compiler/host_access.js create mode 100644 assets/Scripts/compiler/require_polyfill.js create mode 100644 assets/Scripts/engine/engine-init.ts create mode 100644 assets/Scripts/engine/engine-interface.ts delete mode 100644 assets/Scripts/test.js create mode 100644 docs/src/highlevel-design/locations/minidungeons.md create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index c1d9c062..2c74bff9 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,7 @@ /docs/DoxygenWarningLog.txt #imgui local layout -/imgui.ini \ No newline at end of file +/imgui.ini + +#script engine related +/assets/Scripts/compiler/typescript.js diff --git a/.vscode/settings.json b/.vscode/settings.json index 28f63e27..681aca98 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,7 @@ "**/.git/objects/**": true, "**/node_modules/**": true }, - "java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx2G -Xms100m -Xlog:disable" + "java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx2G -Xms100m -Xlog:disable", + "javascript.preferences.importModuleSpecifier": "non-relative", + "typescript.preferences.importModuleSpecifier": "non-relative" } \ No newline at end of file diff --git a/assets/Scripts/compiler/compiler.js b/assets/Scripts/compiler/compiler.js new file mode 100644 index 00000000..0aa2234a --- /dev/null +++ b/assets/Scripts/compiler/compiler.js @@ -0,0 +1,113 @@ + +/** + * The map of all source files to their content and compiled value + */ +let COMPILER_fileMap = { } + +/** + * The compiled program + */ +let COMPILER_emitted_value = '' + + +/** + * Registers a file with the compiler + * @param {*} fileName The file's name + * @param {*} content The content of the file + */ +const COMPILER_registerFile = (fileName, content) => { + let normalizedFilePath = FILE_RESOLUTION_getFilePath(fileName,false) + loggerScripts.INFO('REGISTER FILE ' + normalizedFilePath) + COMPILER_fileMap[normalizedFilePath] = { + content: content, + compiled: ts.createSourceFile( + normalizedFilePath, content, ts.ScriptTarget.Latest + ) + } +} + + +/** + * The callback invoked when the compiler host tries to read a file + * @param {*} fileName The name of the file + * @param {*} languageVersion The language version + * @returns The file if it exists, null otherwise + */ +const COMPILER_getSourceFile = (fileName, languageVersion) => { + if(!!COMPILER_fileMap[fileName]){ + return COMPILER_fileMap[fileName].compiled + } else { + return null + } +} + + +/** + * Constructs the compiler host + * https://www.typescriptlang.org/tsconfig/#compilerOptions + */ +const COMPILER_customCompilerHost = { + getSourceFile: COMPILER_getSourceFile, + writeFile: (fileName, data) => { + let normalizedFilePath = FILE_RESOLUTION_getFilePath(fileName) + loggerScripts.INFO("EMIT FILE " + normalizedFilePath) + let finalData = + "let exports = { }\n" + + data + "\n" + + "return exports" + // COMPILER_emitted_value = data + COMPILER_fileMap[normalizedFilePath] = { + content: data, //to be eval'd from top level + moduleContent: finalData, //to be eval'd from require() + } + }, + getDefaultLibFileName: () => "lib.d.ts", + useCaseSensitiveFileNames: () => false, + getCanonicalFileName: filename => filename, + getCurrentDirectory: () => "", + getNewLine: () => "\n", + getDirectories: () => [], + fileExists: () => true, + readFile: () => "" +} + +/** + * Instructs Typescript to emit the final compiled value + */ +const COMPILER_run = () => { + loggerScripts.INFO('COMPILE ALL REGISTERED FILES') + + const compilerOptions = { } + + const COMPILER_program = ts.createProgram( + Object.keys(COMPILER_fileMap), compilerOptions, COMPILER_customCompilerHost + ) + COMPILER_program.emit() +} + +/** + * Loads a file + * @param {*} fileName The name of the file to load (preferably already has .ts at the end) + */ +const COMPILER_runFile = (fileName) => { + let normalizedFilePath = FILE_RESOLUTION_getFilePath(fileName) + if(!!COMPILER_fileMap[normalizedFilePath]){ + loggerScripts.INFO('RUN FILE ' + normalizedFilePath) + eval(COMPILER_fileMap[normalizedFilePath].content) + } else { + loggerScripts.WARNING('FAILED TO RESOLVE FILE ' + normalizedFilePath) + } +} + +/** + * Loads a file + * @param {*} fileName The name of the file to load (preferably already has .ts at the end) + */ +const COMPILER_printSource = (fileName) => { + let normalizedFilePath = FILE_RESOLUTION_getFilePath(fileName) + if(!!COMPILER_fileMap[normalizedFilePath]){ + loggerScripts.INFO('FILE CONTENT ' + normalizedFilePath) + } else { + loggerScripts.WARNING('FAILED TO RESOLVE FILE ' + normalizedFilePath) + } +} diff --git a/assets/Scripts/compiler/file_resolution.js b/assets/Scripts/compiler/file_resolution.js new file mode 100644 index 00000000..212b1f23 --- /dev/null +++ b/assets/Scripts/compiler/file_resolution.js @@ -0,0 +1,23 @@ + +/** + * Normalizes a file path + * @param {*} rawFilePath The raw file path + * @returns The normalized file path + */ +const FILE_RESOLUTION_getFilePath = (rawFilePath, isJavascript = true) => { + let fileName = rawFilePath + if(isJavascript && fileName.includes('.ts')){ + fileName = fileName.replace('.ts','.js') + } + if(fileName.startsWith('/Scripts')){ + fileName = fileName.replace('/Scripts','') + } + if(fileName.startsWith('Scripts/')){ + fileName = fileName.replace('Scripts/','/') + } + if(isJavascript && !fileName.endsWith(".js")){ + fileName = fileName + ".js" + } + return fileName +} + diff --git a/assets/Scripts/compiler/get_typescript.sh b/assets/Scripts/compiler/get_typescript.sh new file mode 100644 index 00000000..eeb4384c --- /dev/null +++ b/assets/Scripts/compiler/get_typescript.sh @@ -0,0 +1 @@ +wget -O typescript.js https://unpkg.com/typescript@latest/lib/typescript.js \ No newline at end of file diff --git a/assets/Scripts/compiler/host_access.js b/assets/Scripts/compiler/host_access.js new file mode 100644 index 00000000..c85f60e9 --- /dev/null +++ b/assets/Scripts/compiler/host_access.js @@ -0,0 +1,9 @@ + +/** + * The host context that contains the core engine functions + */ +export let HOST = { + classes: { }, //the classes available to the script engine + singletons: { }, //the singletons available to the script engine +} + diff --git a/assets/Scripts/compiler/require_polyfill.js b/assets/Scripts/compiler/require_polyfill.js new file mode 100644 index 00000000..969629eb --- /dev/null +++ b/assets/Scripts/compiler/require_polyfill.js @@ -0,0 +1,36 @@ + + +/** + * Caches loaded modules + */ +let REQUIRE_CACHE = { } + +/** + * Used if the module is directly executed instead of being require'd for some reason + */ +let exports = { } + +/** + * Imports a module + * @param {*} path The path of the module + * @param {*} cwd The current working directory + */ +const require = (path) => { + let normalizedFilePath = FILE_RESOLUTION_getFilePath(path) + if(REQUIRE_CACHE[path]){ + return REQUIRE_CACHE[normalizedFilePath].exports + } else if(!!COMPILER_fileMap[normalizedFilePath]?.content) { + const code = COMPILER_fileMap[normalizedFilePath].moduleContent + let exports = new Function(code)() + //create module object + const module = { + exports: exports, + exportedValues: Object.keys(exports), + } + REQUIRE_CACHE[normalizedFilePath] = module + loggerScripts.INFO("[require] CREATE MODULE " + normalizedFilePath) + return module.exports + } else { + loggerScripts.WARNING("FAILED TO REQUIRE FILE " + normalizedFilePath) + } +} diff --git a/assets/Scripts/engine/engine-init.ts b/assets/Scripts/engine/engine-init.ts new file mode 100644 index 00000000..845ea452 --- /dev/null +++ b/assets/Scripts/engine/engine-init.ts @@ -0,0 +1,7 @@ + +/** + * Called when the script engine first initializes + */ +export const ENGINE_onInit = () => { + console.log('Script Engine Init') +} diff --git a/assets/Scripts/engine/engine-interface.ts b/assets/Scripts/engine/engine-interface.ts new file mode 100644 index 00000000..b265d8fc --- /dev/null +++ b/assets/Scripts/engine/engine-interface.ts @@ -0,0 +1,9 @@ + + +/** + * The host context that contains all core engine functions + */ +export interface Host { + classes: any, //the host's view of the scripting engine + singletons: any, //the singletons available to the script engine +} diff --git a/assets/Scripts/test.js b/assets/Scripts/test.js deleted file mode 100644 index d8ec2468..00000000 --- a/assets/Scripts/test.js +++ /dev/null @@ -1 +0,0 @@ -console.log("test") \ No newline at end of file diff --git a/docs/src/highlevel-design/locations/biomesindex.md b/docs/src/highlevel-design/locations/biomesindex.md index a5b9ca76..6b2cc65d 100644 --- a/docs/src/highlevel-design/locations/biomesindex.md +++ b/docs/src/highlevel-design/locations/biomesindex.md @@ -4,4 +4,5 @@ - @subpage biomeideas - @subpage largelocationideas - @subpage macrolocationideas - - @subpage smalllocations \ No newline at end of file + - @subpage smalllocations + - @subpage minidungeons \ No newline at end of file diff --git a/docs/src/highlevel-design/locations/minidungeons.md b/docs/src/highlevel-design/locations/minidungeons.md new file mode 100644 index 00000000..eac347cf --- /dev/null +++ b/docs/src/highlevel-design/locations/minidungeons.md @@ -0,0 +1,4 @@ +@page minidungeons Mini Dungeons + +In certain levels, you can find premade characters that can join your party. + diff --git a/docs/src/progress/currenttarget.md b/docs/src/progress/currenttarget.md index 193b9421..2a9a957f 100644 --- a/docs/src/progress/currenttarget.md +++ b/docs/src/progress/currenttarget.md @@ -21,7 +21,6 @@ Redo hitboxes to have capsules and also chaining between frames (but not between - Introduce block hitbox (blockbox) type - Sour spot, sweet spot for damage hitboxes and hurtboxes Enemy AI -better scaffolding for scriptig engine with hooks for equipping items, spawning entities, pausing/resuming play, etc Ability for private realms to have time start/stop based on the player's feedback <-- sync this up to tutorial ui via script Scene Message Service - Can send arbitrary events and messages diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 54c7b78f..ff4b523c 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -406,6 +406,8 @@ Audio - Sword Hit Metal - Sword Hit Flesh +(06/02/2024) +better scaffolding for scripting engine with hooks for equipping items, spawning entities, pausing/resuming play, etc # TODO @@ -413,7 +415,7 @@ Audio BIG BIG BIG BIG IMMEDIATE TO DO: always enforce opengl interface across all opengl calls jesus christ the bone uniform bug was impossible - +Fix not all grass tiles update when updating a nearby voxel (ie it doesn't go into negative coordinates to scan for foliage updates) diff --git a/src/main/java/electrosphere/engine/Globals.java b/src/main/java/electrosphere/engine/Globals.java index f1b95a1a..0d77b412 100644 --- a/src/main/java/electrosphere/engine/Globals.java +++ b/src/main/java/electrosphere/engine/Globals.java @@ -444,7 +444,6 @@ public class Globals { elementManager = new ElementManager(); //script engine scriptEngine = new ScriptEngine(); - scriptEngine.init(); //ai manager aiManager = new AIManager(); //realm & data cell manager diff --git a/src/main/java/electrosphere/engine/Main.java b/src/main/java/electrosphere/engine/Main.java index 2777bf5e..f8c8c96a 100644 --- a/src/main/java/electrosphere/engine/Main.java +++ b/src/main/java/electrosphere/engine/Main.java @@ -76,6 +76,9 @@ public class Main { //init global variables Globals.initGlobals(); + //init scripting engine + Globals.scriptEngine.init(); + //controls if(Globals.RUN_CLIENT){ initControlHandler(); diff --git a/src/main/java/electrosphere/entity/scene/SceneLoader.java b/src/main/java/electrosphere/entity/scene/SceneLoader.java index ec32d874..84b3b0c6 100644 --- a/src/main/java/electrosphere/entity/scene/SceneLoader.java +++ b/src/main/java/electrosphere/entity/scene/SceneLoader.java @@ -56,10 +56,11 @@ public class SceneLoader { } } //load scripts - for(String scriptPath : file.getScriptPaths()){ - Globals.scriptEngine.loadScript(scriptPath); - } - Globals.scriptEngine.runScript(file.getInitScriptPath()); + //TODO: integrate scripts for client side of scenes + // for(String scriptPath : file.getScriptPaths()){ + // Globals.scriptEngine.loadScript(scriptPath); + // } + // Globals.scriptEngine.runScript(file.getInitScriptPath()); return rVal; } diff --git a/src/main/java/electrosphere/logger/Logger.java b/src/main/java/electrosphere/logger/Logger.java index 65b0d4f7..08435c21 100644 --- a/src/main/java/electrosphere/logger/Logger.java +++ b/src/main/java/electrosphere/logger/Logger.java @@ -1,5 +1,7 @@ package electrosphere.logger; +import org.graalvm.polyglot.HostAccess.Export; + /** * A channel for logging messages */ @@ -56,6 +58,7 @@ public class Logger { * This should be used for messages that would have interest to someone running a server (ie specific network messages, account creation, etc) * @param message The message to report */ + @Export public void INFO(String message){ if(level == LogLevel.LOOP_DEBUG || level == LogLevel.DEBUG || level == LogLevel.INFO){ System.out.println(message); @@ -68,6 +71,7 @@ public class Logger { * This should be used for reporting events that happen in the engine that are concerning but don't mean the engine has failed to execute (ie a texture failed to load) * @param message The message to report */ + @Export public void WARNING(String message){ if(level == LogLevel.LOOP_DEBUG || level == LogLevel.DEBUG || level == LogLevel.INFO || level == LogLevel.WARNING){ System.out.println(message); diff --git a/src/main/java/electrosphere/logger/LoggerInterface.java b/src/main/java/electrosphere/logger/LoggerInterface.java index a57827cc..610d411c 100644 --- a/src/main/java/electrosphere/logger/LoggerInterface.java +++ b/src/main/java/electrosphere/logger/LoggerInterface.java @@ -20,6 +20,7 @@ public class LoggerInterface { public static Logger loggerDB; public static Logger loggerAudio; public static Logger loggerUI; + public static Logger loggerScripts; /** * Initializes all logic objects @@ -35,6 +36,7 @@ public class LoggerInterface { loggerDB = new Logger(LogLevel.WARNING); loggerAudio = new Logger(LogLevel.WARNING); loggerUI = new Logger(LogLevel.WARNING); + loggerScripts = new Logger(LogLevel.WARNING); loggerStartup.INFO("Initialized loggers"); } } diff --git a/src/main/java/electrosphere/script/ScriptEngine.java b/src/main/java/electrosphere/script/ScriptEngine.java index a3569e9d..ab3437db 100644 --- a/src/main/java/electrosphere/script/ScriptEngine.java +++ b/src/main/java/electrosphere/script/ScriptEngine.java @@ -7,11 +7,14 @@ import java.util.Map; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Engine; +import org.graalvm.polyglot.PolyglotException; import org.graalvm.polyglot.Source; import org.graalvm.polyglot.Value; +import electrosphere.engine.Globals; import electrosphere.logger.LoggerInterface; import electrosphere.util.FileUtils; +import electrosphere.util.MathUtils; /** * Interface for executing scripts in the game engine @@ -25,7 +28,37 @@ public class ScriptEngine { Map sourceMap; //the javascript object that stores values - Value jsBindingsObject; + Value topLevelValue; + + //the object that contains all host values accessible to javascript land + Value hostObject; + + //The files that are loaded on init to bootstrap the script engine + static final String[] filesToLoadOnInit = new String[]{ + //polyfills + "Scripts/compiler/require_polyfill.js", + + //main typescript engine + "Scripts/compiler/typescript.js", + + //compiler and utilities + "Scripts/compiler/file_resolution.js", + "Scripts/compiler/compiler.js", + "Scripts/compiler/host_access.js", + }; + + //The classes that will be provided to the scripting engine + //https://stackoverflow.com/a/65942034 + static final Object[][] staticClasses = new Object[][]{ + {"mathUtils",MathUtils.class}, + }; + + //singletons from the host that are provided to the javascript context + static final Object[][] hostSingletops = new Object[][]{ + {"timekeeper",Globals.timekeeper}, + {"currentPlayer",Globals.clientPlayer}, + {"loggerScripts",LoggerInterface.loggerScripts}, + }; /** * Initializes the engine @@ -36,11 +69,42 @@ public class ScriptEngine { //create engine with flag to disable warning Engine engine = Engine.newBuilder().option("engine.WarnInterpreterOnly", "false").build(); //create context - context = Context.newBuilder("js").engine(engine).build(); - //read scripts into source map - readScriptsDirectory("/src/main/sql", FileUtils.getAssetFile("/src/main/sql")); + context = Context.newBuilder("js") + .allowNativeAccess(false) + .engine(engine) + .build(); //save the js bindings object - jsBindingsObject = context.getBindings("js"); + topLevelValue = context.getBindings("js"); + + //put host members into environment + putTopLevelValue("loggerScripts",LoggerInterface.loggerScripts); + + //load all files required to start the engine + for(String fileToLoad : filesToLoadOnInit){ + loadDependency(fileToLoad); + } + + //define host members + defineHostMembers(); + + //register engine files + registerScriptDirectory("Scripts/engine",FileUtils.getAssetFile("Scripts/engine")); + + //compile + compile(); + + //run script for engine init + requireModule("/Scripts/engine/engine-init.ts"); + invokeModuleFunction("/Scripts/engine/engine-init.ts","ENGINE_onInit"); + + + //call the engine initialization function + // invokeFunction("ENGINE_onInit"); + + System.exit(0); + + //read scripts into source map + // readScriptsDirectory("/src/main/sql", FileUtils.getAssetFile("/src/main/sql")); //create bindings // try { // String content = FileUtils.getAssetFileAsString("/Scripts/test.js"); @@ -59,7 +123,7 @@ public class ScriptEngine { * @param value The value that is stored at that variable */ public void putTopLevelValue(String valueName, Object value){ - jsBindingsObject.putMember(valueName, value); + topLevelValue.putMember(valueName, value); } /** @@ -68,7 +132,16 @@ public class ScriptEngine { * @return The value of the variable */ public Value getTopLevelValue(String valueName){ - return jsBindingsObject.getMember(valueName); + return topLevelValue.getMember(valueName); + } + + /** + * Removes a top level member from the javascript context + * @param valueName The name of the top level member + * @return true if successfully removed, false otherwise + */ + public boolean removeTopLevelValue(String valueName){ + return topLevelValue.removeMember(valueName); } /** @@ -76,17 +149,18 @@ public class ScriptEngine { * @param path The * @param directory */ - void readScriptsDirectory(String path, File directory){ + void registerScriptDirectory(String path, File directory){ if(directory.exists() && directory.isDirectory()){ File[] children = directory.listFiles(); for(File childFile : children){ String qualifiedName = path + "/" + childFile.getName(); if(childFile.isDirectory()){ - readScriptsDirectory(qualifiedName,childFile); + registerScriptDirectory(qualifiedName,childFile); } else { //add to source map - String content = FileUtils.readFileToString(childFile); - sourceMap.put(qualifiedName,Source.create("js",content)); + registerFile(qualifiedName); + // String content = FileUtils.readFileToString(childFile); + // sourceMap.put(qualifiedName,Source.create("js",content)); } } } @@ -96,15 +170,17 @@ public class ScriptEngine { * Loads a script from disk * @param path The path to the script file */ - public void loadScript(String path){ + public void loadDependency(String path){ String content; try { content = FileUtils.getAssetFileAsString(path); sourceMap.put(path,Source.create("js",content)); + context.eval(sourceMap.get(path)); } catch (IOException e) { - // TODO Auto-generated catch block + LoggerInterface.loggerScripts.ERROR("FAILED TO LOAD SCRIPT", e); + } catch (PolyglotException e){ + LoggerInterface.loggerScripts.ERROR("Script error", e); e.printStackTrace(); - LoggerInterface.loggerGameLogic.ERROR("FAILED TO LOAD SCRIPT", e); } } @@ -113,12 +189,96 @@ public class ScriptEngine { * @param path The filepath of the script */ public void runScript(String path){ - Source source = sourceMap.get(path); - if(source != null){ - context.eval(source); + invokeFunction("COMPILER_runFile", path); + } + + /** + * Prints the content of a file + * @param path The filepath of the script + */ + public void printScriptSource(String path){ + invokeFunction("COMPILER_printSource", path); + } + + /** + * Registers a file with the scripting engine to be compiled into the full binary + * @param path The path to the script file + */ + private void registerFile(String path){ + String content; + try { + content = FileUtils.getAssetFileAsString(path); + sourceMap.put(path,Source.create("js",content)); + invokeFunction("COMPILER_registerFile",path,content); + } catch (IOException e) { + LoggerInterface.loggerScripts.ERROR("FAILED TO LOAD SCRIPT", e); } } + /** + * Compiles the project + */ + private void compile(){ + invokeFunction("COMPILER_run"); + Value compiledCode = topLevelValue.getMember("COMPILER_emitted_value"); + context.eval("js",compiledCode.asString()); + } + + + /** + * Calls a function defined in the global scope with the arguments provided + * @param functionName The function name + * @param args The arguments + */ + public Value invokeFunction(String functionName, Object... args){ + Value function = topLevelValue.getMember(functionName); + if(function != null){ + return function.execute(args); + } else { + LoggerInterface.loggerScripts.WARNING("Failed to invoke function " + functionName); + } + return null; + } + + /** + * Invokes a function defined in a file + * @param filePath The file the function is defined in + * @param functionName The function's name + * @param args The args to pass into the function + */ + public void invokeModuleFunction(String filePath, String functionName, Object ... args){ + Value filePathRaw = invokeFunction("FILE_RESOLUTION_getFilePath",filePath); + Value requireCache = topLevelValue.getMember("REQUIRE_CACHE"); + Value module = requireCache.getMember(filePathRaw.asString()); + Value exports = module.getMember("exports"); + Value function = exports.getMember(functionName); + if(function != null && function.canExecute()){ + function.execute(args); + } else { + LoggerInterface.loggerScripts.WARNING("Failed to invoke function " + functionName); + } + } + + /** + * Requires a module into the global space + * @param filePath The filepath of the module + */ + public void requireModule(String filePath){ + invokeFunction("require", filePath); + } + + /** + * Defines host members within javascript context + */ + private void defineHostMembers(){ + //remove top level members required for bootstrapping the engine + removeTopLevelValue("loggerScripts"); + //give guest access to static classes + Value classes = hostObject.getMember("classes"); + for(Object[] currentClass : staticClasses){ + classes.putMember((String)currentClass[0], currentClass[1]); + } + } } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..703c8288 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "paths" : { + "/*" : [ + "./assets/Scripts/*" + ], + } + } +} \ No newline at end of file