My game uses your lua extension to add in game scripting for the users, recentley i noticed a memory leak, when i fixed it in my script i realised that when freeing lua corountine the game crashes
i was running a new corountine each frame
`extends Node
class_name Lua_Script
var timeStart
var ActiveCoroutines:Array[Dictionary]
var Lua:LuaState=LuaState.new()
var BaseFuncBinds:=[]
signal ScriptStop
signal ScriptStart
var MaxExecTime:=25
@export_enum("Client","Server") var runside:int=0
@export var script_enabled:=false:
set(val):
script_enabled=val
if val:
Start()
else:
isRunning=false
ScriptStop.emit()
@export_multiline var code:String
var isRunning:=false
var ISReady:=false
func _ready() -> void:
ISReady=true
if isRunning==false and script_enabled:
Start()
func Start():
if code=="":
if get_tree() == null:return
await get_tree().create_timer(.5).timeout
if code=="":return
Start()
return
if not ISReady:return
if isRunning==false and script_enabled and RunData.RunSide==runside:
isRunning=true
ActiveCoroutines.clear()
BaseFuncBinds.clear()
FinishedLastLoop=true
var setup = LuaSetUp.GetSetUpLua(self)
print(setup)
Lua = setup[0]
var env = setup[1]
var MainLuaF = Lua.load_string(code, "startup_"+name, env)
if MainLuaF is LuaError:
print("ErrorStart: "+MainLuaF.message)
return
elif MainLuaF is LuaFunction:
StartLuaCoroutine(MainLuaF)
ScriptStart.emit()
await get_tree().create_timer(1).timeout
#print(Lua.globals.to_dictionary())
func StartLuaCoroutine(LuaF:LuaFunction,StartArgs:=[],StartNow:bool=false):
var fn=LuaF
if fn == null:return
var LuaCr:LuaCoroutine=LuaCoroutine.create(fn)
LuaCr
LuaCr.set_hook(_coroutine_hook_func,LuaThread.HOOK_MASK_COUNT,100000)
if LuaCr == null:return
var CrData = {
"co": LuaCr,
"userdata": null,
"active": true,
"StartArgs":StartArgs,
"new":true,
}
#LuaCr.failed.connect(LuaFail.bind(CrData))
ActiveCoroutines.append(CrData)
if StartNow:
RunCoroutineByData(CrData)
func LuaFail(Data):
ActiveCoroutines.erase(Data)
func BindFunctionToBaseFunc(fun:LuaFunction,toBind:=""):
for x in BaseFuncBinds:
if x.Function == fun and x.Task==toBind:return
BaseFuncBinds.append({"Function"=fun,"Task"=toBind})
func RunBaseFunc(Name:String,Args:=[]):
if isRunning ==false or script_enabled==false:return
for i in BaseFuncBinds:
if i.Task == Name:
StartLuaCoroutine(i.Function,Args)
func _coroutine_hook_func(debug_info: LuaDebug):
if Time.get_ticks_msec()-LastYield > MaxExecTime:
return LuaThread.HOOK_YIELD
var LastYield:=Time.get_ticks_msec()
var FinishedLastLoop:=true
func _process(delta: float) -> void:
if not isRunning or not script_enabled or FinishedLastLoop==false : return
RunBaseFunc("process",[delta])
FinishedLastLoop=false
LastYield=Time.get_ticks_msec()
for Data in ActiveCoroutines:
if not isRunning or not script_enabled: continue
if Time.get_ticks_msec()-LastYield > MaxExecTime:
print("TookTooLong")
await get_tree().process_frame
LastYield=Time.get_ticks_msec()
RunCoroutineByData(Data)
FinishedLastLoop=true
Lua.collect_garbage()
func RunCoroutineByData(Data):
if Data["active"]==true:
if Data["co"]==null or not Data["co"] is LuaCoroutine:
EraseCor(Data)
return
if not Data["co"] is LuaCoroutine:
EraseCor(Data)
return
var Res
if Data["new"]:
if Data["StartArgs"] == []:
Res = Data["co"].resume()
else:
Res = Data["co"].resumev(Data["StartArgs"])
Data["new"]=false
else:
Res = Data["co"].resume()
if Res is LuaError:
print("ERROR "+Res.message)
EraseCor(Data)
return
if Data["co"].status == LuaCoroutine.STATUS_DEAD:
EraseCor(Data)
return
if Data["co"].status == LuaCoroutine.STATUS_YIELD:
Yielded(Data,Res)
return
else:
EraseCor(Data)
func EraseCor(CorData:Dictionary):
if ActiveCoroutines.has(CorData):
var CRx:LuaCoroutine=CorData.co
if CorData.has("co"):
#CorData.co=null
#CorData.co.free()
var CR:LuaCoroutine=CorData.co
print(CR.status)
#CR.failed.disconnect(LuaFail)
#await get_tree().process_frame
ActiveCoroutines.erase(CorData)
#await get_tree().process_frame
#print(CRx.get_reference_count())
func Yielded(Cor:Dictionary,Res):
if Res and Res.size()>1:
match Res[0]:
"sleep":
Cor["active"]=false
await get_tree().create_timer(float(Res[1])).timeout
Cor["active"]=true
`
My game uses your lua extension to add in game scripting for the users, recentley i noticed a memory leak, when i fixed it in my script i realised that when freeing lua corountine the game crashes
i was running a new corountine each frame
`extends Node
class_name Lua_Script
var timeStart
var ActiveCoroutines:Array[Dictionary]
var Lua:LuaState=LuaState.new()
var BaseFuncBinds:=[]
signal ScriptStop
signal ScriptStart
var MaxExecTime:=25
@export_enum("Client","Server") var runside:int=0
@export var script_enabled:=false:
set(val):
script_enabled=val
if val:
Start()
else:
isRunning=false
ScriptStop.emit()
@export_multiline var code:String
var isRunning:=false
var ISReady:=false
func _ready() -> void:
ISReady=true
if isRunning==false and script_enabled:
Start()
func Start():
func StartLuaCoroutine(LuaF:LuaFunction,StartArgs:=[],StartNow:bool=false):
var fn=LuaF
if fn == null:return
var LuaCr:LuaCoroutine=LuaCoroutine.create(fn)
LuaCr
func LuaFail(Data):
ActiveCoroutines.erase(Data)
func BindFunctionToBaseFunc(fun:LuaFunction,toBind:=""):
for x in BaseFuncBinds:
if x.Function == fun and x.Task==toBind:return
BaseFuncBinds.append({"Function"=fun,"Task"=toBind})
func RunBaseFunc(Name:String,Args:=[]):
if isRunning ==false or script_enabled==false:return
for i in BaseFuncBinds:
if i.Task == Name:
StartLuaCoroutine(i.Function,Args)
func _coroutine_hook_func(debug_info: LuaDebug):
if Time.get_ticks_msec()-LastYield > MaxExecTime:
return LuaThread.HOOK_YIELD
var LastYield:=Time.get_ticks_msec()
var FinishedLastLoop:=true
func _process(delta: float) -> void:
func RunCoroutineByData(Data):
if Data["active"]==true:
if Data["co"]==null or not Data["co"] is LuaCoroutine:
EraseCor(Data)
return
if not Data["co"] is LuaCoroutine:
EraseCor(Data)
return
func EraseCor(CorData:Dictionary):
func Yielded(Cor:Dictionary,Res):
if Res and Res.size()>1:
match Res[0]:
"sleep":
Cor["active"]=false
await get_tree().create_timer(float(Res[1])).timeout
Cor["active"]=true
`