1+ package funkin .scripting ;
2+
3+ #if ENABLE_LUA
4+ import llua .Lua ;
5+ import llua .LuaL ;
6+ import llua .State ;
7+ import llua .Convert ;
8+
9+ import openfl .utils .Assets ;
10+
11+ using llua .Lua ;
12+ using llua .LuaL ;
13+ using llua .Convert ;
14+
15+ class LuaScript extends Script {
16+ public var state : State = null ;
17+
18+ public var lastStackID : Int = 0 ;
19+ public var stack : Map <Int , Dynamic > = [];
20+
21+ public var luaCallbacks : Map <String , Dynamic > = [];
22+
23+ public override function onCreate (path : String ) {
24+ super .onCreate (path );
25+
26+ state = LuaL .newstate ();
27+ Lua .set_callbacks_function (cpp. Callable .fromStaticFunction (callback_handler ));
28+ LuaL .openlibs (state );
29+ Lua .register_hxtrace_func (cpp. Callable .fromStaticFunction (print_function ));
30+ state .register_hxtrace_lib ();
31+
32+ luaCallbacks [" __onPointerIndex" ] = onPointerIndex ;
33+ luaCallbacks [" __onPointerNewIndex" ] = onPointerNewIndex ;
34+ luaCallbacks [" __gc" ] = onGarbageCollection ;
35+
36+ state .newmetatable (" __funkinMetaTable" );
37+
38+ state .pushstring (' __index' );
39+ state .pushcfunction (cpp. Callable .fromStaticFunction (__index ));
40+ state .settable (- 3 );
41+
42+ state .pushstring (' __newindex' );
43+ state .pushcfunction (cpp. Callable .fromStaticFunction (__newindex ));
44+ state .settable (- 3 );
45+ }
46+
47+ public override function onLoad () {
48+ state .dostring (Assets .getText (path ));
49+ }
50+
51+ public static var callbackReturnVariables = [];
52+
53+ public override function onCall (funcName : String , args : Array <Dynamic >): Dynamic {
54+ state .settop (0 );
55+ state .getglobal (funcName );
56+
57+ if (state .type (- 1 ) != Lua .LUA_TFUNCTION )
58+ return null ;
59+
60+ for (k => val in args )
61+ pushArg (val );
62+
63+ if (state .pcall (args .length , 1 , 0 ) != 0 ) {
64+ this .error (' ${state .tostring (- 1 )}' );
65+ return null ;
66+ }
67+
68+ return fromLua (state .gettop ());
69+ }
70+
71+ public override function set (variable : String , value : Dynamic ) {
72+ pushArg (value );
73+ state .setglobal (variable );
74+ }
75+
76+ public override function onDestroy () {
77+ super .onDestroy ();
78+
79+ if (state != null ) {
80+ Lua .close (state );
81+ state = null ;
82+ }
83+ }
84+ public override function reload () {
85+ Logs .trace (' Hot-reloading is currently not supported on Lua.' , WARNING );
86+ }
87+
88+ // UTILS
89+ #if REGION
90+
91+ static inline function print_function (s : String ) : Int {
92+ if (Script .curScript != null )
93+ Script .curScript .trace (s );
94+ return 0 ;
95+ }
96+
97+ public function fromLua (stackPos : Int ): Dynamic {
98+ var v : Dynamic = state .fromLua (stackPos );
99+ if (v is Dynamic && Reflect .hasField (v , " __stack_id" )) {
100+ // is a "pointer"! convert it back.
101+ var pos : Int = Reflect .field (v , " __stack_id" );
102+ return stack [pos ];
103+ }
104+ return v ;
105+ }
106+ public function pushArg (val : Dynamic ) {
107+ switch (Type .typeof (val )) {
108+ case Type .ValueType. TNull :
109+ state .pushnil ();
110+ case Type .ValueType. TBool :
111+ state .pushboolean (val );
112+ case Type .ValueType. TInt :
113+ state .pushinteger (cast (val , Int ));
114+ case Type .ValueType. TFloat :
115+ state .pushnumber (val );
116+ case Type .ValueType. TClass (String ):
117+ state .pushstring (cast (val , String ));
118+ case Type .ValueType. TClass (Array ):
119+ state .arrayToLua (val );
120+ case Type .ValueType. TObject :
121+ @:privateAccess
122+ state .objectToLua (val ); // {}
123+ default :
124+
125+ var p = {
126+ __stack_id : lastStackID ++ ,
127+ };
128+ state .toLua (p );
129+ state .getmetatable (" __funkinMetaTable" );
130+ state .setmetatable (- 2 );
131+
132+ state .pushstring (' __gc' );
133+ state .pushcfunction (cpp. Callable .fromStaticFunction (__gc ));
134+ state .settable (- 3 );
135+
136+ stack [p .__stack_id ] = val ;
137+ }
138+ }
139+ public static function __index (state : StatePointer ): Int {
140+ return callback_handler (cast cpp. Pointer .fromRaw (state ).ref , " __onPointerIndex" );
141+ }
142+ public static function __newindex (state : StatePointer ): Int {
143+ return callback_handler (cast cpp. Pointer .fromRaw (state ).ref , " __onPointerNewIndex" );
144+ }
145+ public static function __gc (state : StatePointer ): Int {
146+ // callbackPreventAutoConvert = true;
147+ var v = callback_handler (cast cpp. Pointer .fromRaw (state ).ref , " __gc" );
148+ // callbackPreventAutoConvert = false;
149+ return v ;
150+ }
151+
152+ public function onPointerIndex (obj : Dynamic , key : String ) {
153+ if (obj != null )
154+ return Reflect .getProperty (obj , key );
155+ return null ;
156+ }
157+
158+ public function onPointerNewIndex (obj : Dynamic , key : String , val : Dynamic ) {
159+ if (obj != null )
160+ Reflect .setProperty (obj , key , val );
161+ }
162+
163+ public function onGarbageCollection (obj : Dynamic ) {
164+ trace (obj );
165+ if (Reflect .hasField (obj , " __stack_id" )) {
166+ trace (' Clearing item ID: ${obj .__stack_id } from stack due to garbage collection' );
167+ stack .remove (obj .__stack_id );
168+ }
169+ }
170+
171+ private static var callbackPreventAutoConvert : Bool = false ;
172+ public static inline function callback_handler (l : State , fname : String ): Int {
173+
174+ if (! (Script .curScript is LuaScript ))
175+ return 0 ;
176+ var curLua : LuaScript = cast Script .curScript ;
177+
178+ var cbf = curLua .luaCallbacks .get (fname );
179+ callbackReturnVariables = [];
180+
181+ if (cbf == null || ! Reflect .isFunction (cbf ))
182+ return 0 ;
183+
184+ var nparams : Int = Lua .gettop (l );
185+ var args : Array <Dynamic > = callbackPreventAutoConvert ? [for (i in 0 ... nparams ) l .fromLua (i + 1 )] : [for (i in 0 ... nparams ) curLua .fromLua (i + 1 )];
186+
187+ var ret : Dynamic = null ;
188+
189+ try {
190+ ret = (nparams > 0 ) ? Reflect .callMethod (null , cbf , args ) : cbf ();
191+ } catch (e ) {
192+ curLua .error (e .details ()); // for super cool mega logging!!!
193+ throw e ;
194+ }
195+ Lua .settop (l , 0 );
196+
197+ if (callbackReturnVariables .length <= 0 )
198+ callbackReturnVariables .push (ret );
199+ for (e in callbackReturnVariables )
200+ curLua .pushArg (e );
201+
202+ /* return the number of results */
203+ return callbackReturnVariables .length ;
204+
205+ }
206+ #end
207+ }
208+ #end
0 commit comments