diff --git a/Project.xml b/Project.xml index f60790e76c2..7686581b716 100644 --- a/Project.xml +++ b/Project.xml @@ -124,10 +124,8 @@ - + - - diff --git a/hmm.json b/hmm.json index 5d92add16c9..354ea150ac0 100644 --- a/hmm.json +++ b/hmm.json @@ -75,11 +75,11 @@ "url": "https://github.com/MAJigsaw77/hxdiscord_rpc" }, { - "name": "linc_luajit", + "name": "hxluajit", "type": "git", "dir": null, "ref": "master", - "url": "https://github.com/JS-Engine-things/linc_luajit" + "url": "https://github.com/JS-Engine-things/hxluajit" }, { "name": "funkin.vis", diff --git a/setup/unix.sh b/setup/unix.sh index 8bc2e0cbd8a..3e7d7a5a451 100644 --- a/setup/unix.sh +++ b/setup/unix.sh @@ -18,7 +18,7 @@ haxelib git away3d https://github.com/moxie-coder/away3d --quiet haxelib git tjson https://github.com/moxie-coder/tjson --quiet haxelib git hxcpp https://github.com/FunkinCrew/hxcpp --quiet haxelib git flxanimate https://github.com/Dot-Stuff/flxanimate 768740a56b26aa0c072720e0d1236b94afe68e3e --quiet -haxelib git linc_luajit https://github.com/JS-Engine-things/linc_luajit --quiet +haxelib git hxluajit https://github.com/JS-Engine-things/hxluajit --quiet haxelib git funkin.vis https://github.com/JS-Engine-things/funkVis-FrequencyFixed --quiet haxelib git grig.audio https://github.com/JS-Engine-things/grig.audio --quiet haxelib git hxdiscord_rpc https://github.com/MAJigsaw77/hxdiscord_rpc --quiet --skip-dependencies diff --git a/setup/windows.bat b/setup/windows.bat index c8f5ba4b92a..6efa93cb477 100644 --- a/setup/windows.bat +++ b/setup/windows.bat @@ -16,7 +16,7 @@ haxelib git away3d https://github.com/moxie-coder/away3d --quiet haxelib git tjson https://github.com/moxie-coder/tjson --quiet haxelib git hxcpp https://github.com/FunkinCrew/hxcpp --quiet haxelib git flxanimate https://github.com/Dot-Stuff/flxanimate 768740a56b26aa0c072720e0d1236b94afe68e3e --quiet -haxelib git linc_luajit https://github.com/JS-Engine-things/linc_luajit --quiet +haxelib git hxluajit https://github.com/JS-Engine-things/hxluajit --quiet haxelib git funkin.vis https://github.com/JS-Engine-things/funkVis-FrequencyFixed --quiet haxelib git grig.audio https://github.com/JS-Engine-things/grig.audio --quiet haxelib git hxdiscord_rpc https://github.com/MAJigsaw77/hxdiscord_rpc --quiet --skip-dependencies diff --git a/source/Achievements.hx b/source/Achievements.hx index 2195a731c6e..a9c9539f433 100644 --- a/source/Achievements.hx +++ b/source/Achievements.hx @@ -3,6 +3,9 @@ import flixel.FlxCamera; #if ACHIEVEMENTS_ALLOWED import haxe.Exception; import objects.AchievementPopup; +#if LUA_ALLOWED +import psychlua.FunkinLua.State; +#end typedef Achievement = { @@ -261,7 +264,7 @@ class Achievements { #if LUA_ALLOWED public static function addLuaCallbacks(lua:State) { - Lua_helper.add_callback(lua, "getAchievementScore", function(name:String):Float + Convert.addCallback(lua, "getAchievementScore", function(name:String):Float { if(!achievements.exists(name)) { @@ -270,7 +273,7 @@ class Achievements { } return getScore(name); }); - Lua_helper.add_callback(lua, "setAchievementScore", function(name:String, ?value:Float = 1, ?saveIfNotUnlocked:Bool = true):Float + Convert.addCallback(lua, "setAchievementScore", function(name:String, ?value:Float = 1, ?saveIfNotUnlocked:Bool = true):Float { if(!achievements.exists(name)) { @@ -279,7 +282,7 @@ class Achievements { } return setScore(name, value, saveIfNotUnlocked); }); - Lua_helper.add_callback(lua, "addAchievementScore", function(name:String, ?value:Float = 1, ?saveIfNotUnlocked:Bool = true):Float + Convert.addCallback(lua, "addAchievementScore", function(name:String, ?value:Float = 1, ?saveIfNotUnlocked:Bool = true):Float { if(!achievements.exists(name)) { @@ -288,7 +291,7 @@ class Achievements { } return addScore(name, value, saveIfNotUnlocked); }); - Lua_helper.add_callback(lua, "unlockAchievement", function(name:String):Dynamic + Convert.addCallback(lua, "unlockAchievement", function(name:String):Dynamic { if(!achievements.exists(name)) { @@ -297,7 +300,7 @@ class Achievements { } return unlock(name); }); - Lua_helper.add_callback(lua, "isAchievementUnlocked", function(name:String):Dynamic + Convert.addCallback(lua, "isAchievementUnlocked", function(name:String):Dynamic { if(!achievements.exists(name)) { @@ -306,7 +309,7 @@ class Achievements { } return isUnlocked(name); }); - Lua_helper.add_callback(lua, "achievementExists", function(name:String) return achievements.exists(name)); + Convert.addCallback(lua, "achievementExists", function(name:String) return achievements.exists(name)); } #end #end diff --git a/source/DiscordClient.hx b/source/DiscordClient.hx index 88b5b94373a..e560476aaa9 100644 --- a/source/DiscordClient.hx +++ b/source/DiscordClient.hx @@ -6,6 +6,9 @@ import cpp.ConstCharStar; import cpp.Function; import cpp.RawConstPointer; #end +#if LUA_ALLOWED +import psychlua.FunkinLua.State; +#end import hxdiscord_rpc.Discord; import hxdiscord_rpc.Types; @@ -150,8 +153,8 @@ class DiscordClient #if LUA_ALLOWED public static function addLuaCallbacks(lua:State) { - Lua_helper.add_callback(lua, "changeDiscordPresence", changePresence); - Lua_helper.add_callback(lua, "changeDiscordClientID", function(?newID:String) { + Convert.addCallback(lua, "changeDiscordPresence", changePresence); + Convert.addCallback(lua, "changeDiscordClientID", function(?newID:String) { if(newID == null) newID = _defaultID; clientID = newID; }); diff --git a/source/Main.hx b/source/Main.hx index 9f7e6cbde75..32afc2e02f0 100644 --- a/source/Main.hx +++ b/source/Main.hx @@ -78,8 +78,6 @@ class Main extends Sprite { FlxG.sound = soundFrontEnd; funkinGame._customSoundTray = objects.CustomSoundTray.CustomSoundTray; } - // turns out I forgot this, I'm a bit dumb for that - #if LUA_ALLOWED Lua.set_callbacks_function(cpp.Callable.fromStaticFunction(psychlua.CallbackHandler.call)); #end addChild(funkinGame); diff --git a/source/import.hx b/source/import.hx index 53a88efb676..6f3748d47f9 100644 --- a/source/import.hx +++ b/source/import.hx @@ -8,8 +8,8 @@ import sys.io.*; #end #if LUA_ALLOWED -import llua.*; -import llua.Lua; +import hxluajit.*; +import hxluajit.Types; import psychlua.*; #else import psychlua.FunkinLua; // TODO: test and seperate this into LuaUtils diff --git a/source/psychlua/CallbackHandler.hx b/source/psychlua/CallbackHandler.hx deleted file mode 100644 index 82df5876d8d..00000000000 --- a/source/psychlua/CallbackHandler.hx +++ /dev/null @@ -1,54 +0,0 @@ -package psychlua; - -class CallbackHandler -{ - public static inline function call(l:State, fname:String):Int - { - try - { - //trace('calling $fname'); - var cbf:Dynamic = Lua_helper.callbacks.get(fname); - - //Local functions have the lowest priority - //This is to prevent a "for" loop being called in every single operation, - //so that it only loops on reserved/special functions - if(cbf == null) - { - //trace('looping thru scripts'); - for (script in PlayState.instance.luaArray) - if(script != null && script.lua == l) - { - //trace('found script'); - cbf = script.callbacks.get(fname); - break; - } - } - - if(cbf == null) return 0; - - var nparams:Int = Lua.gettop(l); - var args:Array = []; - - for (i in 0...nparams) { - args[i] = Convert.fromLua(l, i + 1); - } - - var ret:Dynamic = null; - /* return the number of results */ - - ret = Reflect.callMethod(null,cbf,args); - - if(ret != null){ - Convert.toLua(l, ret); - return 1; - } - } - catch(e:Dynamic) - { - if(Lua_helper.sendErrorsToLua) {LuaL.error(l, 'CALLBACK ERROR! ${if(e.message != null) e.message else e}');return 0;} - trace(e); - throw(e); - } - return 0; - } -} \ No newline at end of file diff --git a/source/psychlua/Convert.hx b/source/psychlua/Convert.hx new file mode 100644 index 00000000000..7726b925ccd --- /dev/null +++ b/source/psychlua/Convert.hx @@ -0,0 +1,304 @@ +package psychlua; + +import haxe.ds.*; +import psychlua.FunkinLua.State; +import hxluajit.Types; + + +/** + * Some borrowed code from hxluajit-wrapper. + * @see https://github.com/MAJigsaw77/hxluajit-wrapper/blob/main/hxluajit/wrapper/LuaConverter.hx + * + * We didn't use hxluajit-wrapper because we wanted to have our functions and methods as similar as possible to linc_luajit + */ +class Convert +{ + public static function addCallback(l:State, name:String, func:Dynamic) + { + // PsychLua expects the function to be null for local callbacks so if func is not TFunction we don't add the callback here + if (Type.typeof(func) == TFunction) + callbacks.set(name, func); + + Lua.pushstring(l, name); + Lua.pushcclosure(l, cpp.Callable.fromStaticFunction(handleCallback), 1); + Lua.setglobal(l, name); + } + + public static function removeCallback(l:State, name:String) + { + if (!callbacks.exists(name)) + return; + + callbacks.remove(name); + + Lua.pushnil(l); + Lua.setglobal(l, name); + } + + public static function toLua(l:State, v:Dynamic):Bool + { + switch (Type.typeof(v)) + { + case TInt: + Lua.pushinteger(l, cast(v, Int)); + case TFloat: + Lua.pushnumber(l, cast(v, Float)); + case TBool: + Lua.pushboolean(l, v == true ? 1 : 0); + case TObject: + final fields:Array = Reflect.fields(v); + + Lua.createtable(l, fields.length, 0); + + for (field in fields) + { + Lua.pushstring(l, field); + toLua(l, Reflect.field(v, field)); + Lua.settable(l, -3); + } + case TClass(String): + Lua.pushstring(l, cast(v, String)); + case TClass(Array): + final elements:Array = v; + + Lua.createtable(l, elements.length, 0); + + for (i in 0...elements.length) + { + Lua.pushinteger(l, i + 1); + toLua(l, elements[i]); + Lua.settable(l, -3); + } + case TClass(IntMap) | TClass(StringMap) | TClass(ObjectMap): + final values:Map = v; + + Lua.createtable(l, Lambda.count(values), 0); + + for (key => value in values) + { + Lua.pushstring(l, key); + toLua(l, value); + Lua.settable(l, -3); + } + case TNull: + Lua.pushnil(l); + default: + Lua.pushnil(l); + return false; + } + return true; + } + + public static function fromLua(l:State, idx:Int):Dynamic + { + var ret:Dynamic = null; + + switch (Lua.type(l, idx)) + { + case type if (type == Lua.TNUMBER): + ret = Lua.tonumber(l, idx); + case type if (type == Lua.TSTRING): + ret = Lua.tostring(l, idx).toString(); + case type if (type == Lua.TBOOLEAN): + ret = Lua.toboolean(l, idx) == 1; + case type if (type == Lua.TTABLE): + ret = convertTable(l, idx); + case type if (type == Lua.TFUNCTION): + ret = new LuaFunction(cpp.Pointer.fromRaw(l), LuaL.ref(l, Lua.REGISTRYINDEX)); + case type if (type == Lua.TUSERDATA || type == Lua.TLIGHTUSERDATA): + ret = cpp.Pointer.fromRaw(Lua.touserdata(l, idx)); + default: + ret = null; + } + + return ret; + } + + public static function callFunctionWithoutName(l:State, args:Array):Array + { + for (arg in args) + toLua(l, arg); + + final status:Int = Lua.pcall(l, args.length, Lua.MULTRET, 0); + + if (status != Lua.OK) + { + var error = Lua.tostring(l, -1); + trace('Error calling a function without name: $error'); + Lua.pop(l, 1); + + return []; + } + + final args:Array = []; + + { + final count:Int = Lua.gettop(l); + + for (i in 0...count) + args.push(fromLua(l, i + 1)); + + Lua.pop(l, count); + } + + return args; + } + + @:noCompletion + private static function convertTable(l:State, idx:Int):Dynamic + { + var isArray:Bool = true; + + var count:Int = 0; + + iterateTable(l, idx, function():Void + { + if (isArray) + { + if (Lua.type(l, -2) == Lua.TNUMBER) + { + final index:Lua_Integer = Lua.tointeger(l, -2); + + if (index < 0) + isArray = false; + } + else + isArray = false; + } + + count++; + }); + + if (count == 0) + return {}; + + if (isArray) + { + final obj:Array = []; + + iterateTable(l, idx, function():Void + { + obj[Lua.tointeger(l, -2) - 1] = fromLua(l, -1); + }); + + return obj; + } + else + { + final obj:haxe.DynamicAccess = {}; + + iterateTable(l, idx, function():Void + { + obj.set(Std.string(fromLua(l, -2)), fromLua(l, -1)); + }); + + return obj; + } + } + + @:noCompletion + private static function iterateTable(l:State, idx:Int, fn:Void->Void):Void + { + Lua.pushnil(l); + + while (Lua.next(l, idx < 0 ? idx - 1 : idx) != 0) + { + fn(); + + Lua.pop(l, 1); + } + } + + @:noCompletion + private static var funcs = []; + + @:noCompletion + private static function handleMethod(l:State):Int + { + var argsLength:Int = Lua.gettop(l); + var method = funcs[cast Lua.tonumber(l, Lua.upvalueindex(1))]; + var args = []; + + for (i in 0...argsLength) + args[i] = fromLua(l, i + 1); + + try + { + var result = Reflect.callMethod(null, method, args); + if (result != null) + return toLua(l, result) ? 1 : 0; + else + return 0; + } + catch (e) + { + LuaL.error(l, 'METHOD ERROR!\n${e.stack}'); + return 0; + } + } + + @:noCompletion + private static var callbacks:Map = new Map(); + + @:noCompletion + private static function handleCallback(l:State):Int + { + try + { + var callbackName:String = Lua.tostring(l, Lua.upvalueindex(1)); + var callbackMethod:Dynamic = callbacks.get(callbackName); + + if (callbackMethod == null) + { + // trace('checking last script'); + var last:FunkinLua = FunkinLua.lastCalledScript; + if (last == null || last.lua != l) + { + // trace('looping thru scripts'); + for (script in PlayState.instance.luaArray) + { + if (script != FunkinLua.lastCalledScript && script != null && script.lua == l) + { + // trace('found script'); + callbackMethod = script.callbacks.get(callbackName); + break; + } + } + } + else + { + callbackMethod = last.callbacks.get(callbackName); + } + } + + if (callbackMethod == null) + return 0; + + var nparams:Int = Lua.gettop(l); + var args:Array = []; + + for (i in 0...nparams) + { + args[i] = fromLua(l, i + 1); + } + + var ret:Dynamic = null; + /* return the number of results */ + + ret = Reflect.callMethod(null, callbackMethod, args); + + if (ret != null) + { + toLua(l, ret); + return 1; + } + } + catch (e:Dynamic) + { + LuaL.error(l, 'CALLBACK ERROR! ${if (e.message != null) e.message else e}'); + return 0; + } + + return 0; + } +} diff --git a/source/psychlua/CustomSubstate.hx b/source/psychlua/CustomSubstate.hx index 22032221c02..c8afd44c8e3 100644 --- a/source/psychlua/CustomSubstate.hx +++ b/source/psychlua/CustomSubstate.hx @@ -11,9 +11,9 @@ class CustomSubstate extends MusicBeatSubstate public static function implement(funk:FunkinLua) { var lua = funk.lua; - Lua_helper.add_callback(lua, "openCustomSubstate", openCustomSubstate); - Lua_helper.add_callback(lua, "closeCustomSubstate", closeCustomSubstate); - Lua_helper.add_callback(lua, "insertToCustomSubstate", insertToCustomSubstate); + Convert.addCallback(lua, "openCustomSubstate", openCustomSubstate); + Convert.addCallback(lua, "closeCustomSubstate", closeCustomSubstate); + Convert.addCallback(lua, "insertToCustomSubstate", insertToCustomSubstate); } #end diff --git a/source/psychlua/FlxAnimateFunctions.hx b/source/psychlua/FlxAnimateFunctions.hx index 565ef3c3493..24a4f937a07 100644 --- a/source/psychlua/FlxAnimateFunctions.hx +++ b/source/psychlua/FlxAnimateFunctions.hx @@ -2,13 +2,17 @@ package psychlua; import openfl.utils.Assets; +#if LUA_ALLOWED +import psychlua.FunkinLua.State; +#end + #if (LUA_ALLOWED && flxanimate) class FlxAnimateFunctions { public static function implement(funk:FunkinLua) { final lua:State = funk.lua; - Lua_helper.add_callback(lua, "makeFlxAnimateSprite", function(tag:String, ?x:Float = 0, ?y:Float = 0, ?loadFolder:String = null) { + Convert.addCallback(lua, "makeFlxAnimateSprite", function(tag:String, ?x:Float = 0, ?y:Float = 0, ?loadFolder:String = null) { tag = tag.replace('.', ''); var lastSprite = MusicBeatState.getVariables().get(tag); if(lastSprite != null) @@ -24,12 +28,12 @@ class FlxAnimateFunctions mySprite.active = true; }); - Lua_helper.add_callback(lua, "loadAnimateAtlas", function(tag:String, folderOrImg:String, ?spriteJson:String = null, ?animationJson:String = null) { + Convert.addCallback(lua, "loadAnimateAtlas", function(tag:String, folderOrImg:String, ?spriteJson:String = null, ?animationJson:String = null) { var spr:FlxAnimate = MusicBeatState.getVariables().get(tag); if(spr != null) Paths.loadAnimateAtlas(spr, folderOrImg, spriteJson, animationJson); }); - Lua_helper.add_callback(lua, "addAnimationBySymbol", function(tag:String, name:String, symbol:String, ?framerate:Float = 24, ?loop:Bool = false, ?matX:Float = 0, ?matY:Float = 0) + Convert.addCallback(lua, "addAnimationBySymbol", function(tag:String, name:String, symbol:String, ?framerate:Float = 24, ?loop:Bool = false, ?matX:Float = 0, ?matY:Float = 0) { var obj:FlxAnimate = cast MusicBeatState.getVariables().get(tag); if(obj == null) return false; @@ -44,7 +48,7 @@ class FlxAnimateFunctions return true; }); - Lua_helper.add_callback(lua, "addAnimationBySymbolIndices", function(tag:String, name:String, symbol:String, ?indices:Any = null, ?framerate:Float = 24, ?loop:Bool = false, ?matX:Float = 0, ?matY:Float = 0) + Convert.addCallback(lua, "addAnimationBySymbolIndices", function(tag:String, name:String, symbol:String, ?indices:Any = null, ?framerate:Float = 24, ?loop:Bool = false, ?matX:Float = 0, ?matY:Float = 0) { var obj:FlxAnimate = cast MusicBeatState.getVariables().get(tag); if(obj == null) return false; diff --git a/source/psychlua/FunkinLua.hx b/source/psychlua/FunkinLua.hx index b0f800b4748..a83b9ac332d 100644 --- a/source/psychlua/FunkinLua.hx +++ b/source/psychlua/FunkinLua.hx @@ -211,7 +211,7 @@ class FunkinLua { for (name => func in customFunctions) { if (func != null) - Lua_helper.add_callback(lua, name, func); + Convert.addCallback(lua, name, func); } // shader shit @@ -605,11 +605,11 @@ class FunkinLua { if(luaInstance.scriptName == cervix) { Lua.getglobal(luaInstance.lua, global); - if(Lua.isnumber(luaInstance.lua,-1)){ + if(Lua.isnumber(luaInstance.lua,-1) == 1){ Lua.pushnumber(lua, Lua.tonumber(luaInstance.lua, -1)); - }else if(Lua.isstring(luaInstance.lua,-1)){ + }else if(Lua.isstring(luaInstance.lua,-1) == 1){ Lua.pushstring(lua, Lua.tostring(luaInstance.lua, -1)); - }else if(Lua.isboolean(luaInstance.lua,-1)){ + }else if(Lua.isboolean(luaInstance.lua,-1) == 1){ Lua.pushboolean(lua, Lua.toboolean(luaInstance.lua, -1)); }else{ Lua.pushnil(lua); @@ -2259,7 +2259,7 @@ class FunkinLua { }); for (name => func in registeredFunctions) { if (func != null) - Lua_helper.add_callback(lua, name, func); + Convert.addCallback(lua, name, func); } #if ACHIEVEMENTS_ALLOWED Achievements.addLuaCallbacks(lua); #end #if HSCRIPT_ALLOWED HScript.implement(this); #end @@ -2890,7 +2890,7 @@ class FunkinLua { public function addLocalCallback(name:String, myFunction:Dynamic) { callbacks.set(name, myFunction); - Lua_helper.add_callback(lua, name, null); // just so that it gets called + Convert.addCallback(lua, name, null); // just so that it gets called } public static function registerFunction(name:String, func:Dynamic):Void @@ -3185,8 +3185,8 @@ class FunkinLua { Lua.getglobal(lua, func); var type:Int = Lua.type(lua, -1); - if (type != Lua.LUA_TFUNCTION) { - if (type > Lua.LUA_TNIL) + if (type != Lua.TFUNCTION) { + if (type > Lua.TNIL) LuaUtils.luaTrace(lua, "ERROR (" + func + "): attempt to call a " + typeToString(type) + " value", false, false, FlxColor.RED); Lua.pop(lua, 1); @@ -3197,7 +3197,7 @@ class FunkinLua { var status:Int = Lua.pcall(lua, args.length, 1, 0); // Checks if it's not successful, then show a error. - if (status != Lua.LUA_OK) { + if (status != Lua.OK) { var error:String = LuaUtils.getErrorMessage(lua, status); LuaUtils.luaTrace(lua, "ERROR (" + func + "): " + error, false, false, FlxColor.RED); return Function_Continue; @@ -3266,16 +3266,24 @@ class FunkinLua { return coverMeInPiss; } - function typeToString(type:Int):String { + public static function typeToString(type:Int):String + { #if LUA_ALLOWED - switch(type) { - case Lua.LUA_TBOOLEAN: return "boolean"; - case Lua.LUA_TNUMBER: return "number"; - case Lua.LUA_TSTRING: return "string"; - case Lua.LUA_TTABLE: return "table"; - case Lua.LUA_TFUNCTION: return "function"; + switch (type) + { + case type if (type == Lua.TBOOLEAN): + return "boolean"; + case type if (type == Lua.TNUMBER): + return "number"; + case type if (type == Lua.TSTRING): + return "string"; + case type if (type == Lua.TTABLE): + return "table"; + case type if (type == Lua.TFUNCTION): + return "function"; + case type if (type <= Lua.TNIL): + return "nil"; } - if (type <= Lua.LUA_TNIL) return "nil"; #end return "unknown"; } @@ -3287,7 +3295,7 @@ class FunkinLua { if (Reflect.isFunction(data)) { // Bind as a callable Lua function - Lua_helper.add_callback(lua, variable, data); + Convert.addCallback(lua, variable, data); return; } @@ -3317,4 +3325,5 @@ class FunkinLua { return PlayState.instance.isDead ? GameOverSubstate.instance : PlayState.instance; } } +typedef State = cpp.RawPointer; // hi guys, my name is "secret"! diff --git a/source/psychlua/HScript.hx b/source/psychlua/HScript.hx index 149f15c4fb2..d2cf43c2b12 100644 --- a/source/psychlua/HScript.hx +++ b/source/psychlua/HScript.hx @@ -95,7 +95,7 @@ class HScript #if HSCRIPT_ALLOWED for (script in PlayState.instance.luaArray) if(script != null && script.lua != null && !script.closed) - Lua_helper.add_callback(script.lua, name, func); + Convert.addCallback(script.lua, name, func); #end FunkinLua.customFunctions.set(name, func); }); diff --git a/source/psychlua/LuaFunction.hx b/source/psychlua/LuaFunction.hx new file mode 100644 index 00000000000..4bd988f3a2a --- /dev/null +++ b/source/psychlua/LuaFunction.hx @@ -0,0 +1,62 @@ +package psychlua; + +import hxluajit.Types; + +/** + * Holds a Lua function that can be called from Haxe. + * + * @see https://github.com/DragShot/linc_luajit/blob/master/llua/LuaCallback.hx + * + * @author DragShot + */ +@:allow(psychlua.Convert) +class LuaFunction +{ + @:noCompletion + private var l:Null>; + + @:noCompletion + private var ref:Int; + + /** + * Creates a new LuaFunction instance. + * + * @param l The Lua state pointer. + * @param ref The Lua function reference. + */ + private function new(l:cpp.Pointer, ref:Int):Void + { + this.l = l; + this.ref = ref; + } + + /** + * Calls the Lua function. + * + * @param args The function arguments. + * @return The function results as a Haxe array. + */ + public function call(args:Array):Array + { + if (l != null) + { + Lua.rawgeti(l.raw, Lua.REGISTRYINDEX, ref); + + return Convert.callFunctionWithoutName(l.raw, args); + } + + return []; + } + + /** + * Disposes of the Lua function reference. + */ + public function dispose():Void + { + if (l != null) + { + LuaL.unref(l.raw, Lua.REGISTRYINDEX, ref); + l = null; + } + } +} \ No newline at end of file diff --git a/source/psychlua/LuaUtils.hx b/source/psychlua/LuaUtils.hx index f168d49d88b..4b90a30a6c6 100644 --- a/source/psychlua/LuaUtils.hx +++ b/source/psychlua/LuaUtils.hx @@ -6,6 +6,10 @@ import flixel.util.FlxColor; import openfl.display.BlendMode; +#if LUA_ALLOWED +import psychlua.FunkinLua.State; +#end + using StringTools; @:allow(psychlua.FunkinLua) @@ -106,13 +110,18 @@ class LuaUtils { Lua.pop(lua, 1); if (v != null) v = v.trim(); - if (v == null || v == "") { - return switch(status) { - case Lua.LUA_ERRRUN: return "Runtime Error"; - case Lua.LUA_ERRMEM: return "Memory Allocation Error"; - case Lua.LUA_ERRERR: return "Critical Error"; - case _: return "Unknown Error"; + if (v == null || v == "") + { + switch (status) + { + case type if (type == Lua.ERRRUN): + return "Runtime Error"; + case type if (type == Lua.ERRMEM): + return "Memory Allocation Error"; + case type if (type == Lua.ERRERR): + return "Critical Error"; } + return "Unknown Error"; } return v;