diff --git a/source/funkin/backend/MusicBeatState.hx b/source/funkin/backend/MusicBeatState.hx index 5e679acd..eca0c466 100644 --- a/source/funkin/backend/MusicBeatState.hx +++ b/source/funkin/backend/MusicBeatState.hx @@ -9,7 +9,6 @@ import flixel.FlxState; import flixel.FlxSubState; import funkin.backend.scripting.events.*; import funkin.backend.scripting.Script; -import funkin.backend.scripting.ScriptPack; import funkin.backend.system.interfaces.IBeatReceiver; import funkin.backend.system.Conductor; import funkin.options.PlayerSettings; @@ -90,7 +89,7 @@ class MusicBeatState extends FlxState implements IBeatReceiver /** * Current injected script attached to the state. To add one, create a file at path "data/states/stateName" (ex: data/states/FreeplayState) */ - public var scripts:ScriptPack; + public var stateScript:Script; public var scriptsAllowed:Bool = true; @@ -112,50 +111,25 @@ class MusicBeatState extends FlxState implements IBeatReceiver this.scriptName = scriptName; } - public function addScript(file:String) - scripts.add(Script.create(Paths.script(file, null, true))); - function loadScript() { if (scriptsAllowed) { - if (scripts == null) { + if (stateScript == null || stateScript is DummyScript) { var className = Type.getClassName(Type.getClass(this)); var scriptName = this.scriptName != null ? this.scriptName : className.substr(className.lastIndexOf(".")+1); - var scriptPaths = []; - (scripts = new ScriptPack(scriptName)).setParent(this); - scriptPaths = Paths.getScriptPaths('assets/data/states/$scriptName'); - for (i in Paths.getScriptPaths('assets/data/states', '/$scriptName.')) - scriptPaths.push(i); - if (scriptPaths.length > 0) - for (i in scriptPaths) { - var old = Assets.forceAssetLibrary; - Assets.forceAssetLibrary = i.library; - addScript(i.file); - Assets.forceAssetLibrary = old; - } - if (Type.getClass(this) != PlayState) scripts.load(); - } - else - scripts.reload(); + stateScript = Script.create(Paths.script('data/states/${scriptName}')); + stateScript.setParent(this); + stateScript.load(); + } else + stateScript.reload(); } } - public function call(name:String, ?args:Array, ?defaultVal:Dynamic):Dynamic { - // calls the function on the assigned script - if (scripts == null) return defaultVal; - return scripts.call(name, args); - } - - public function event(name:String, event:T):T { - if (scripts == null) return event; - scripts.event(name, event); - return event; - } public override function tryUpdate(elapsed:Float):Void { if (persistentUpdate || subState == null) { - scripts.call("preUpdate", [elapsed]); + call("preUpdate", [elapsed]); update(elapsed); - scripts.call("postUpdate", [elapsed]); + call("postUpdate", [elapsed]); } if (_requestSubStateReset) @@ -170,31 +144,42 @@ class MusicBeatState extends FlxState implements IBeatReceiver } override function create() { - if (Type.getClass(this) != PlayState) loadScript(); + loadScript(); Framerate.offset.y = 0; super.create(); - scripts.call("create"); + call("create"); } public override function createPost() { super.createPost(); persistentUpdate = true; - scripts.call("postCreate"); + call("postCreate"); if (!skipTransIn) openSubState(new MusicBeatTransition(null)); skipTransIn = false; skipTransOut = false; } + public function call(name:String, ?args:Array, ?defaultVal:Dynamic):Dynamic { + // calls the function on the assigned script + if (stateScript == null) return defaultVal; + return stateScript.call(name, args); + } + + public function event(name:String, event:T):T { + if (stateScript == null) return event; + stateScript.call(name, [event]); + return event; + } override function update(elapsed:Float) { // TODO: DEBUG MODE!! if (FlxG.keys.justPressed.F5) { loadScript(); - if (scripts != null) + if (stateScript != null && !(stateScript is DummyScript)) Logs.trace('State script successfully reloaded', WARNING, GREEN); } - scripts.call("update", [elapsed]); + call("update", [elapsed]); super.update(elapsed); } @@ -202,19 +187,19 @@ class MusicBeatState extends FlxState implements IBeatReceiver @:dox(hide) public function stepHit(curStep:Int):Void { for(e in members) if (e != null && e is IBeatReceiver) cast(e, IBeatReceiver).stepHit(curStep); - scripts.call("stepHit", [curStep]); + call("stepHit", [curStep]); } @:dox(hide) public function beatHit(curBeat:Int):Void { for(e in members) if (e != null && e is IBeatReceiver) cast(e, IBeatReceiver).beatHit(curBeat); - scripts.call("beatHit", [curBeat]); + call("beatHit", [curBeat]); } @:dox(hide) public function measureHit(curMeasure:Int):Void { for(e in members) if (e != null && e is IBeatReceiver) cast(e, IBeatReceiver).measureHit(curMeasure); - scripts.call("measureHit", [curMeasure]); + call("measureHit", [curMeasure]); } /** @@ -235,34 +220,34 @@ class MusicBeatState extends FlxState implements IBeatReceiver * SCRIPTING STUFF */ public override function openSubState(subState:FlxSubState) { - var e = scripts.event("onOpenSubState", EventManager.get(StateEvent).recycle(subState)); + var e = event("onOpenSubState", EventManager.get(StateEvent).recycle(subState)); if (!e.cancelled) super.openSubState(subState); } public override function onResize(w:Int, h:Int) { super.onResize(w, h); - scripts.event("onResize", EventManager.get(ResizeEvent).recycle(w, h, null, null)); + event("onResize", EventManager.get(ResizeEvent).recycle(w, h, null, null)); } public override function destroy() { super.destroy(); graphicCache.destroy(); - scripts.call("onDestroy"); - scripts.call("destroy"); - scripts = FlxDestroyUtil.destroy(scripts); + call("onDestroy"); + if (stateScript != null) + stateScript.destroy(); } public override function draw() { graphicCache.draw(); - var e = scripts.event("draw", EventManager.get(DrawEvent).recycle()); + var e = event("draw", EventManager.get(DrawEvent).recycle()); if (!e.cancelled) super.draw(); - scripts.event("postDraw", e); + event("postDraw", e); } public override function switchTo(nextState:FlxState) { - var e = scripts.event("onStateSwitch", EventManager.get(StateEvent).recycle(nextState)); + var e = event("onStateSwitch", EventManager.get(StateEvent).recycle(nextState)); if (e.cancelled) return false; @@ -277,12 +262,12 @@ class MusicBeatState extends FlxState implements IBeatReceiver public override function onFocus() { super.onFocus(); - scripts.call("onFocus"); + call("onFocus"); } public override function onFocusLost() { super.onFocusLost(); - scripts.call("onFocusLost"); + call("onFocusLost"); } public override function resetSubState() { diff --git a/source/funkin/backend/MusicBeatSubstate.hx b/source/funkin/backend/MusicBeatSubstate.hx index 48171148..d1d96f43 100644 --- a/source/funkin/backend/MusicBeatSubstate.hx +++ b/source/funkin/backend/MusicBeatSubstate.hx @@ -3,7 +3,6 @@ package funkin.backend; import flixel.FlxState; import funkin.backend.scripting.events.*; import funkin.backend.scripting.Script; -import funkin.backend.scripting.ScriptPack; import funkin.backend.scripting.DummyScript; import funkin.backend.system.interfaces.IBeatReceiver; import funkin.backend.system.Conductor.BPMChangeEvent; @@ -64,7 +63,7 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver /** * Current injected script attached to the state. To add one, create a file at path "data/states/stateName" (ex: "data/states/PauseMenuSubstate.hx") */ - public var scripts:ScriptPack; + public var stateScript:Script; public var scriptsAllowed:Bool = true; @@ -98,49 +97,26 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver this.scriptsAllowed = #if SOFTCODED_STATES scriptsAllowed #else false #end; this.scriptName = scriptName; } - public function addScript(file:String) - scripts.add(Script.create(Paths.script(file, null, true))); function loadScript() { if (scriptsAllowed) { - if (scripts == null) { - (scripts = new ScriptPack(scriptName)).setParent(this); + if (stateScript == null || stateScript is DummyScript) { var className = Type.getClassName(Type.getClass(this)); var scriptName = this.scriptName != null ? this.scriptName : className.substr(className.lastIndexOf(".")+1); - var scriptPaths = []; - scriptPaths = Paths.getScriptPaths('assets/data/states/$scriptName'); - for (i in Paths.getScriptPaths('assets/data/states', '/$scriptName.')) - scriptPaths.push(i); - if (scriptPaths.length > 0) - for (i in scriptPaths) { - var old = Assets.forceAssetLibrary; - Assets.forceAssetLibrary = i.library; - addScript(i.file); - Assets.forceAssetLibrary = old; - } - scripts.load(); - } - else - scripts.reload(); + stateScript = Script.create(Paths.script('data/states/${scriptName}')); + stateScript.setParent(this); + stateScript.load(); + } else + stateScript.reload(); } } - public function call(name:String, ?args:Array, ?defaultVal:Dynamic):Dynamic { - // calls the function on the assigned script - if (scripts == null) return defaultVal; - return scripts.call(name, args); - } - public function event(name:String, event:T):T { - if (scripts == null) return event; - scripts.call(name, [event]); - return event; - } public override function tryUpdate(elapsed:Float):Void { if (persistentUpdate || subState == null) { - scripts.call("preUpdate", [elapsed]); + call("preUpdate", [elapsed]); update(elapsed); - scripts.call("postUpdate", [elapsed]); + call("postUpdate", [elapsed]); } if (_requestSubStateReset) @@ -155,26 +131,34 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver } override function close() { - if (scripts != null) { - var event = scripts.event("onClose", new CancellableEvent()); - if (!event.cancelled) { - super.close(); - scripts.call("onClosePost"); - } - } else + var event = event("onClose", new CancellableEvent()); + if (!event.cancelled) { super.close(); + call("onClosePost"); + } } override function create() { loadScript(); super.create(); - scripts.call("create"); + call("create"); } public override function createPost() { super.createPost(); - scripts.call("postCreate"); + call("postCreate"); + } + public function call(name:String, ?args:Array, ?defaultVal:Dynamic):Dynamic { + // calls the function on the assigned script + if (stateScript == null) return defaultVal; + return stateScript.call(name, args); + } + + public function event(name:String, event:T):T { + if (stateScript == null) return event; + stateScript.call(name, [event]); + return event; } override function update(elapsed:Float) @@ -182,28 +166,29 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver // TODO: DEBUG MODE!! if (FlxG.keys.justPressed.F5) { loadScript(); - Logs.trace('State script successfully reloaded', WARNING, GREEN); + if (stateScript != null && !(stateScript is DummyScript)) + Logs.trace('State script successfully reloaded', WARNING, GREEN); } - scripts.call("update", [elapsed]); + call("update", [elapsed]); super.update(elapsed); } @:dox(hide) public function stepHit(curStep:Int):Void { for(e in members) if (e is IBeatReceiver) cast(e, IBeatReceiver).stepHit(curStep); - scripts.call("stepHit", [curStep]); + call("stepHit", [curStep]); } @:dox(hide) public function beatHit(curBeat:Int):Void { for(e in members) if (e is IBeatReceiver) cast(e, IBeatReceiver).beatHit(curBeat); - scripts.call("beatHit", [curBeat]); + call("beatHit", [curBeat]); } @:dox(hide) public function measureHit(curMeasure:Int):Void { for(e in members) if (e is IBeatReceiver) cast(e, IBeatReceiver).measureHit(curMeasure); - scripts.call("measureHit", [curMeasure]); + call("measureHit", [curMeasure]); } /** @@ -224,25 +209,25 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver * SCRIPTING STUFF */ public override function openSubState(subState:FlxSubState) { - var e = scripts.event("onOpenSubState", EventManager.get(StateEvent).recycle(subState)); + var e = event("onOpenSubState", EventManager.get(StateEvent).recycle(subState)); if (!e.cancelled) super.openSubState(subState); } public override function onResize(w:Int, h:Int) { super.onResize(w, h); - scripts.event("onResize", EventManager.get(ResizeEvent).recycle(w, h, null, null)); + event("onResize", EventManager.get(ResizeEvent).recycle(w, h, null, null)); } public override function destroy() { super.destroy(); - scripts.call("onDestroy"); - scripts.call("destroy"); - scripts = FlxDestroyUtil.destroy(scripts); + call("onDestroy"); + if(stateScript != null) + stateScript.destroy(); } public override function switchTo(nextState:FlxState) { - var e = scripts.event("onStateSwitch", EventManager.get(StateEvent).recycle(nextState)); + var e = event("onStateSwitch", EventManager.get(StateEvent).recycle(nextState)); if (e.cancelled) return false; return super.switchTo(nextState); @@ -250,12 +235,12 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver public override function onFocus() { super.onFocus(); - scripts.call("onFocus"); + call("onFocus"); } public override function onFocusLost() { super.onFocusLost(); - scripts.call("onFocusLost"); + call("onFocusLost"); } public var parent:FlxState; diff --git a/source/funkin/backend/assets/Paths.hx b/source/funkin/backend/assets/Paths.hx index 26dd0e96..ef0b523f 100644 --- a/source/funkin/backend/assets/Paths.hx +++ b/source/funkin/backend/assets/Paths.hx @@ -98,35 +98,10 @@ class Paths } return getPath('images/$key.png', library); } - static public function getScriptPaths(key:String, excep:String = ""):Array { - var scriptsPaths:Array = []; - var reallib = assetsTree.libraries.copy(); - - key = key.replace("//", "/"); - - if (!key.endsWith("/")) key += "/"; - for (library in reallib) { - if (!library.exists(key, null)) continue; - - var path = library.getPath(key); - if(path == null) continue; - - for (i in sys.FileSystem.readDirectory(path)) { - var file = Path.withoutDirectory(i); - if (Script.scriptExtensions.contains(Path.extension(file))) { - var filepath = '${key}$file'.replace("//", "/"); - - if (filepath.contains(excep) || excep == "") - scriptsPaths.push(new ScriptPathInfo(filepath, library)); - } - } - } - return scriptsPaths; - } - + inline static public function script(key:String, ?library:String, isAssetsPath:Bool = false) { var scriptPath = isAssetsPath ? key : getPath(key, library); - if (!Script.scriptExtensions.contains(Path.extension(scriptPath))) { + if (!OpenFlAssets.exists(scriptPath)) { var p:String; for(ex in Script.scriptExtensions) { p = '$scriptPath.$ex'; diff --git a/source/funkin/backend/scripting/GlobalScript.hx b/source/funkin/backend/scripting/GlobalScript.hx index b741ee05..14803c8b 100644 --- a/source/funkin/backend/scripting/GlobalScript.hx +++ b/source/funkin/backend/scripting/GlobalScript.hx @@ -9,7 +9,7 @@ import funkin.backend.assets.ModsFolder; * Class for THE Global Script, aka script that runs in the background at all times. */ class GlobalScript { - public static var scripts:ScriptPack; + public static var script:Script; public static function init() { #if MOD_SUPPORT @@ -20,83 +20,92 @@ class GlobalScript { Conductor.onStepHit.add(stepHit); FlxG.signals.focusGained.add(function() { - scripts.call("focusGained"); + call("focusGained"); }); FlxG.signals.focusLost.add(function() { - scripts.call("focusLost"); + call("focusLost"); }); FlxG.signals.gameResized.add(function(w:Int, h:Int) { - scripts.call("gameResized", [w, h]); + call("gameResized", [w, h]); }); FlxG.signals.postDraw.add(function() { - scripts.call("postDraw"); + call("postDraw"); }); FlxG.signals.postGameReset.add(function() { - scripts.call("postGameReset"); + call("postGameReset"); }); FlxG.signals.postGameStart.add(function() { - scripts.call("postGameStart"); + call("postGameStart"); }); FlxG.signals.postStateSwitch.add(function() { - scripts.call("postStateSwitch"); + call("postStateSwitch"); }); FlxG.signals.postUpdate.add(function() { - scripts.call("postUpdate", [FlxG.elapsed]); + call("postUpdate", [FlxG.elapsed]); if (FlxG.keys.justPressed.F5) { - if (scripts != null) { + if (script != null && !(script is DummyScript)) { Logs.trace('Reloading global script...', WARNING, YELLOW); - scripts.reload(); + 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() { - scripts.call("preDraw"); + call("preDraw"); }); FlxG.signals.preGameReset.add(function() { - scripts.call("preGameReset"); + call("preGameReset"); }); FlxG.signals.preGameStart.add(function() { - scripts.call("preGameStart"); + call("preGameStart"); }); FlxG.signals.preStateCreate.add(function(state:FlxState) { - scripts.call("preStateCreate", [state]); + call("preStateCreate", [state]); }); FlxG.signals.preStateSwitch.add(function() { - scripts.call("preStateSwitch", []); + call("preStateSwitch", []); }); FlxG.signals.preUpdate.add(function() { - scripts.call("preUpdate", [FlxG.elapsed]); - scripts.call("update", [FlxG.elapsed]); + call("preUpdate", [FlxG.elapsed]); + call("update", [FlxG.elapsed]); }); onModSwitch(#if MOD_SUPPORT ModsFolder.currentModFolder #else null #end); } + public static function event(name:String, event:T):T { + if (script == null) return event; + script.call(name, [event]); + return event; + } + + public static function call(name:String, ?args:Array) { + if (script == null) return; + script.call(name, args); + } public static function onModSwitch(newMod:String) { - if (scripts != null) scripts.call("onDestroy"); - scripts = FlxDestroyUtil.destroy(scripts); - scripts = new ScriptPack("global"); - var scriptPaths = Paths.getScriptPaths("assets/data", "/global."); - for (i in Paths.getScriptPaths("assets/data/global")) scriptPaths.push(i); - var old = Assets.forceAssetLibrary; - for (i in scriptPaths) { - Assets.forceAssetLibrary = i.library; - scripts.add(Script.create(Paths.script(i.file, null, true))); + call("onDestroy"); + if (script != null) { + script.destroy(); + script = null; } - Assets.forceAssetLibrary = old; - scripts.load(); + script = Script.create(Paths.script('data/global')); + script.load(); } public static function beatHit(curBeat:Int) { - scripts.call("beatHit", [curBeat]); + call("beatHit", [curBeat]); } public static function stepHit(curStep:Int) { - scripts.call("stepHit", [curStep]); + call("stepHit", [curStep]); } } #end \ No newline at end of file diff --git a/source/funkin/backend/utils/DiscordUtil.hx b/source/funkin/backend/utils/DiscordUtil.hx index ad01f4a9..31ec1383 100644 --- a/source/funkin/backend/utils/DiscordUtil.hx +++ b/source/funkin/backend/utils/DiscordUtil.hx @@ -96,7 +96,7 @@ class DiscordUtil { data.largeImageText = DiscordUtil.data.logoText; #if GLOBAL_SCRIPT - var event = funkin.backend.scripting.GlobalScript.scripts.event("onDiscordPresenceUpdate", EventManager.get(DiscordPresenceUpdateEvent).recycle(data)); + var event = funkin.backend.scripting.GlobalScript.event("onDiscordPresenceUpdate", EventManager.get(DiscordPresenceUpdateEvent).recycle(data)); if (event.cancelled) return; #end diff --git a/source/funkin/game/PlayState.hx b/source/funkin/game/PlayState.hx index 005e38a2..1987c295 100644 --- a/source/funkin/game/PlayState.hx +++ b/source/funkin/game/PlayState.hx @@ -79,6 +79,11 @@ class PlayState extends MusicBeatState */ public static var coopMode:Bool = false; + /** + * Script Pack of all the scripts being ran. + */ + public var scripts:ScriptPack; + /** * Array of all the players in the stage. */ @@ -505,7 +510,7 @@ class PlayState extends MusicBeatState if (FlxG.sound.music != null) FlxG.sound.music.stop(); PauseSubState.script = ""; - loadScript(); + (scripts = new ScriptPack("PlayState")).setParent(this); camGame = camera; FlxG.cameras.add(camHUD = new HudCamera(), false); @@ -555,29 +560,19 @@ class PlayState extends MusicBeatState // case "": // ADD YOUR HARDCODED SCRIPTS HERE! default: - for(content in [Paths.getScriptPaths('assets/songs/${SONG.meta.name.toLowerCase()}/scripts'), Paths.getScriptPaths('assets/data/charts/')]) - for(file in content) { - var old = Assets.forceAssetLibrary; - Assets.forceAssetLibrary = file.library; - addScript(file.file); - Assets.forceAssetLibrary = old; - } - + for(content in [Paths.getFolderContent('songs/${SONG.meta.name.toLowerCase()}/scripts', true, fromMods ? MODS : BOTH), Paths.getFolderContent('data/charts/', true, fromMods ? MODS : BOTH)]) + for(file in content) addScript(file); var songEvents:Array = []; for (event in SONG.events) if (!songEvents.contains(event.name)) songEvents.push(event.name); - for (file in Paths.getScriptPaths('assets/data/events/')) { - var old = Assets.forceAssetLibrary; - Assets.forceAssetLibrary = file.library; - - var fileName:String = Path.withoutExtension(Path.withoutDirectory(file.file)); - if (EventsData.eventsList.contains(fileName) && songEvents.contains(fileName)) addScript(file.file); - - Assets.forceAssetLibrary = old; + for (file in Paths.getFolderContent('data/events/', true, fromMods ? MODS : BOTH)) { + var fileName:String = Path.withoutExtension(Path.withoutDirectory(file)); + if (EventsData.eventsList.contains(fileName) && songEvents.contains(fileName)) addScript(file); } } } + add(comboGroup); #end @@ -649,6 +644,7 @@ class PlayState extends MusicBeatState add(splashHandler); scripts.load(); + scripts.call("create"); #end // CAMERA & HUD INITIALISATION @@ -725,6 +721,7 @@ class PlayState extends MusicBeatState #end startingSong = true; + super.create(); for(s in introSprites) @@ -743,6 +740,8 @@ class PlayState extends MusicBeatState updateDiscordPresence(); __updateNote_event = EventManager.get(NoteUpdateEvent); + + scripts.call("postCreate"); } /** @@ -895,9 +894,11 @@ class PlayState extends MusicBeatState } public override function destroy() { + scripts.call("destroy"); for(g in __cachedGraphics) g.useCount--; super.destroy(); + scripts = FlxDestroyUtil.destroy(scripts); @:privateAccess { FlxG.sound.destroySound(inst); FlxG.sound.destroySound(vocals); @@ -1071,9 +1072,11 @@ class PlayState extends MusicBeatState @:dox(hide) override public function update(elapsed:Float) { + scripts.call("update", [elapsed]); if (inCutscene) { super.update(elapsed); + scripts.call("postUpdate", [elapsed]); return; } @@ -1191,6 +1194,13 @@ class PlayState extends MusicBeatState scripts.call("postUpdate", [elapsed]); } + override function draw() { + var e = scripts.event("draw", EventManager.get(DrawEvent).recycle()); + if (!e.cancelled) + super.draw(); + scripts.event("postDraw", e); + } + public function executeEvent(event:ChartEvent) { if (event == null) return; if (event.params == null) return; @@ -1614,6 +1624,12 @@ class PlayState extends MusicBeatState scripts.call("beatHit", [curBeat]); } + public function addScript(file:String) { + var ext = Path.extension(file).toLowerCase(); + if (Script.scriptExtensions.contains(ext)) + scripts.add(Script.create(file)); + } + // GETTERS & SETTERS #if REGION private inline function get_player():StrumLine