diff --git a/Project.xml b/Project.xml index 7f35ae53..bb3a0e4b 100644 --- a/Project.xml +++ b/Project.xml @@ -160,4 +160,7 @@ + + + diff --git a/buildnumber.txt b/buildnumber.txt index a0ce7199..6ea72f04 100644 --- a/buildnumber.txt +++ b/buildnumber.txt @@ -1 +1 @@ -1016 \ No newline at end of file +1032 \ No newline at end of file diff --git a/source/funkin/mods/ModsFolder.hx b/source/funkin/mods/ModsFolder.hx index 410feef8..8a65d4b4 100644 --- a/source/funkin/mods/ModsFolder.hx +++ b/source/funkin/mods/ModsFolder.hx @@ -1,9 +1,11 @@ package funkin.mods; +import flixel.util.FlxSignal.FlxTypedSignal; import openfl.utils.Assets; import openfl.utils.AssetManifest; import openfl.utils.AssetLibrary; import flixel.graphics.FlxGraphic; +import flixel.util.FlxSignal.FlxTypedSignal; #if MOD_SUPPORT import sys.FileSystem; @@ -16,13 +18,11 @@ import haxe.io.Path; using StringTools; class ModsFolder { - #if MOD_SUPPORT /** - * Last time the folder was modified. + * INTERNAL - Only use when editing source mods!! */ - public static var lastFolderEditTime:Date = null; - #end - + @:dox(hide) public static var onModSwitch:FlxTypedSignalVoid> = new FlxTypedSignalVoid>(); + /** * Current mod folder. Will affect `Paths`. */ @@ -49,6 +49,8 @@ class ModsFolder { * @param force Whenever the mod should be reloaded if it has already been loaded */ public static function loadMod(mod:String, force:Bool = false) { + if (mod == null) return null; // may be loading base game + if (FileSystem.exists('${modsPath}$mod.zip')) { var e = loadLibraryFromZip('mods/$mod'.toLowerCase(), '${modsPath}$mod.zip', force); loadedMods.push(mod); @@ -60,6 +62,23 @@ class ModsFolder { } } + /** + * Switches mod - unloads all the other mods, then load this one. + * @param libName + */ + public static function switchMod(mod:String) { + for(m in loadedMods) + unloadMod(m); + + loadMod(ModsFolder.currentModFolder = mod); + onModSwitch.dispatch(ModsFolder.currentModFolder); + FlxG.resetState(); + } + + public static function unloadMod(mod:String) { + Assets.unloadLibrary('mods/$mod'); + } + public static function prepareLibrary(libName:String, force:Bool = false) { if (Assets.hasLibrary(libName)) { if (force) diff --git a/source/funkin/scripting/GlobalScript.hx b/source/funkin/scripting/GlobalScript.hx new file mode 100644 index 00000000..70e2a076 --- /dev/null +++ b/source/funkin/scripting/GlobalScript.hx @@ -0,0 +1,100 @@ +package funkin.scripting; + +import flixel.FlxG; +import flixel.FlxState; +import funkin.mods.ModsFolder; +#if GLOBAL_SCRIPT +/** + * Class for THE Global Script, aka script that runs in the background at all times. + */ +class GlobalScript { + public static var script:Script; + + public static function init() { + #if MOD_SUPPORT + ModsFolder.onModSwitch.add(onModSwitch); + #end + FlxG.signals.focusGained.add(function() { + call("focusGained"); + }); + FlxG.signals.focusLost.add(function() { + call("focusLost"); + }); + FlxG.signals.gameResized.add(function(w:Int, h:Int) { + call("gameResized", [w, h]); + }); + FlxG.signals.postDraw.add(function() { + call("postDraw"); + }); + FlxG.signals.postGameReset.add(function() { + call("postGameReset"); + }); + FlxG.signals.postGameStart.add(function() { + }); + FlxG.signals.postStateSwitch.add(function() { + call("postStateSwitch"); + }); + FlxG.signals.postUpdate.add(function() { + call("postUpdate", [FlxG.elapsed]); + call("updatePost", [FlxG.elapsed]); + if (FlxG.keys.justPressed.F5) { + if (script != null && !(script is DummyScript)) { + Logs.trace('Reloading global script...', WARNING, YELLOW); + script.reload(); + Logs.trace('Global script successfully reloaded.', WARNING, GREEN); + } else { + Logs.trace('Loading global script...', WARNING, YELLOW); + onModSwitch(#if MOD_SUPPORT ModsFolder.currentModFolder #else null #end); + if (script is DummyScript) + Logs.trace('Global script not found. Are you sure "data/global.hx" exists?', ERROR, RED); + else + Logs.trace('Global script successfully loaded.', WARNING, GREEN); + } + } + }); + FlxG.signals.preDraw.add(function() { + call("preDraw"); + }); + FlxG.signals.preGameReset.add(function() { + call("preGameReset"); + }); + FlxG.signals.preGameStart.add(function() { + call("preGameStart"); + }); + FlxG.signals.preStateCreate.add(function(state:FlxState) { + call("preStateCreate", [state]); + }); + FlxG.signals.preStateSwitch.add(function() { + call("preStateSwitch", []); + }); + FlxG.signals.preUpdate.add(function() { + call("preUpdate", [FlxG.elapsed]); + call("update", [FlxG.elapsed]); + }); + + onModSwitch(#if MOD_SUPPORT ModsFolder.currentModFolder #else null #end); + } + + public static function call(name:String, ?args:Array) { + if (script == null) return; + script.call(name, args); + } + public static function onModSwitch(newMod:String) { + trace(newMod); + if (script != null) { + script.destroy(); + script = null; + } + script = Script.create(Paths.script('data/global')); + script.load(); + } + + public static function beatHit(curBeat:Int) { + call("beatHit", [curBeat]); + } + + public static function stepHit(curStep:Int) { + call("stepHit", [curStep]); + } +} +#end \ No newline at end of file diff --git a/source/funkin/system/Logs.hx b/source/funkin/system/Logs.hx index 041318aa..ddca2582 100644 --- a/source/funkin/system/Logs.hx +++ b/source/funkin/system/Logs.hx @@ -9,10 +9,6 @@ import funkin.windows.WindowsAPI.ConsoleColor; class Logs { private static var __showing:Bool = false; public static function init() { - __showInConsole([ - logText("Hello, World! ", CYAN), - logText("I am..."), - logText("COLORED!!", RED)]); Log.trace = function(v : Dynamic, ?infos : Null) { __showInConsole(prepareColoredTrace([ diff --git a/source/funkin/system/Main.hx b/source/funkin/system/Main.hx index adb56996..3fe29a33 100644 --- a/source/funkin/system/Main.hx +++ b/source/funkin/system/Main.hx @@ -106,13 +106,15 @@ class Main extends Sprite public function loadGameSettings() { - + Logs.init(); + // TODO: Mod switching ModsFolder.init(); - ModsFolder.loadMod("introMod"); - ModsFolder.currentModFolder = "introMod"; - - Logs.init(); + ModsFolder.switchMod("introMod"); + + #if GLOBAL_SCRIPT + funkin.scripting.GlobalScript.init(); + #end #if sys if (Sys.args().contains("-livereload")) { diff --git a/source/scripting/GlobalScript.hx b/source/scripting/GlobalScript.hx new file mode 100644 index 00000000..b2b04c5c --- /dev/null +++ b/source/scripting/GlobalScript.hx @@ -0,0 +1,87 @@ +package scripting; + +import flixel.FlxState; +/** + * A global script is a special kind of script that runs on everywhere on your mod: menus, game, etc... + * + * To create one, go to data and create a script named "global", then press F5 in game. + * + * All flixel signals are automatically binded, as shown below. + */ +interface GlobalScript { + /** + * Called whenever the game gains focus. + */ + public function focusGained():Void; + /** + * Called whenever the game loses focus. + */ + public function focusLost():Void; + /** + * Called whenever the game loses focus. + * @param width Width of the game + * @param height Height of the game + */ + public function gameResized(width:Int, height:Int):Void; + + /** + * Called after the screen has been drawn. + */ + public function postDraw():Void; + + /** + * Called after the game has been reset. + */ + public function postGameReset():Void; + + /** + * Called after the game has been started. + */ + public function postGameStart():Void; + + /** + * Called after the state has been switched. + */ + public function postStateSwitch():Void; + + /** + * Called after the game has been updated. + * + * Aliases: `postUpdate` + * + * @param elapsed Time elapsed since last frame + */ + public function updatePost(elapsed:Float):Void; + + /** + * Called before the game draws on screen. + */ + public function preDraw():Void; + + /** + * Called before the game resets. + */ + public function preGameReset():Void; + + /** + * Called before the game starts. + */ + public function preGameStart():Void; + + /** + * Called before the state creates. + */ + public function preStateCreate(state:FlxState):Void; + + /** + * Called before the state switches. + */ + public function preStateSwitch():Void; + + /** + * Called before the game updates. + * + * Aliases: `preUpdate` + */ + public function update(elapsed:Float):Void; +} \ No newline at end of file