From 1b2346740c8b23f56a29bcbb646266667a911f6b Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Sat, 16 May 2009 13:06:57 +0000 Subject: add Lua_GetOwner to ULuaUtils (function returns plugin by lua state) use new function in ULuaParty and ULuaUsdx new lua function: Usdx.ShutMeDown to give plugins the ability to unload git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/branches/experimental@1732 b956fd51-792f-4845-bead-9b4dfca2ff2c --- Lua/src/lua/ULuaCore.pas | 90 ++++++++++++++++++++++++++++++----------------- Lua/src/lua/ULuaParty.pas | 8 ++--- Lua/src/lua/ULuaUsdx.pas | 42 +++++++++++++++------- Lua/src/lua/ULuaUtils.pas | 35 ++++++++++++++++-- 4 files changed, 121 insertions(+), 54 deletions(-) (limited to 'Lua/src') diff --git a/Lua/src/lua/ULuaCore.pas b/Lua/src/lua/ULuaCore.pas index cdb41f22..986974bb 100644 --- a/Lua/src/lua/ULuaCore.pas +++ b/Lua/src/lua/ULuaCore.pas @@ -63,6 +63,7 @@ type State: Plua_State; //< all functions of this plugin are called with this Lua state bPaused: Boolean; //< If true no lua functions from this state are called ErrorCount: Integer; //< counts the errors that occured during function calls of this plugin + ShutDown: Boolean; //< for self shutdown by plugin. true if plugin wants to be unloaded after execution of current function sName: String; sVersion: String; @@ -92,6 +93,8 @@ type procedure PausePlugin(doPause: Boolean); property Paused: boolean read bPaused write PausePlugin; + procedure ShutMeDown; + { calls the lua function in the global w/ the given name. the arguments to the function have to be pushed to the stack before calling this function. @@ -183,7 +186,7 @@ var LuaCore: TLuaCore; implementation -uses ULog, UPlatform, ULuaUsdx, UMain; +uses ULog, UPlatform, ULuaUsdx, UMain, StrUtils; constructor TLuaCore.Create; begin @@ -664,6 +667,7 @@ begin Self.ErrorCount := 0; Self.sName := 'not registred'; Self.sStatus := psNone; + Self.ShutDown := False; State := nil; //< to prevent calls to unopened state end; @@ -714,7 +718,7 @@ begin // plugin_init() if false or nothing is returned plugin init is aborted if (CallFunctionByName('plugin_init', 0, 1)) then begin - If (HasRegistred) AND (lua_toBoolean(State, 1)) then + If (HasRegistred) AND (sStatus = psNone) AND (lua_toBoolean(State, 1)) then begin sStatus := psRunning; ClearStack; @@ -764,6 +768,12 @@ begin bPaused := doPause; end; +{ unload plugin after execution of the current function } +procedure TLuaPlugin.ShutMeDown; +begin + ShutDown := True; +end; + { calls the lua function in the global w/ the given name. the arguments to the function have to be pushed to the stack before calling this function. @@ -775,59 +785,73 @@ end; function TLuaPlugin.CallFunctionByName(Name: String; const nArgs: Integer; const nResults: Integer; const ReportErrors: Boolean): Boolean; begin Result := false; - if (not bPaused) and (State <> nil) then + if (State <> nil) then begin - // we need at least one stack slot free - lua_checkstack(State, 1); - - // lua_getglobal(State, PChar(Name)); //this is just a macro: - lua_getfield(State, LUA_GLOBALSINDEX, PChar(Name)); - - If (lua_isfunction(State, -1)) then - begin //we got a function - // move function in front of the arguments (if any) - if (nArgs > 0) then - lua_insert(State, -(nArgs + 1)); - - // call it! - if (lua_pcall(State, nArgs, nResults, 0) = 0) then - Result := true //called w/o errors - else //increase error counter - Inc (ErrorCount); + if (not bPaused) then + begin + // we need at least one stack slot free + lua_checkstack(State, 1); + + // lua_getglobal(State, PChar(Name)); //this is just a macro: + lua_getfield(State, LUA_GLOBALSINDEX, PChar(Name)); + + if (lua_isfunction(State, -1)) then + begin //we got a function + // move function in front of the arguments (if any) + if (nArgs > 0) then + lua_insert(State, -(nArgs + 1)); + + // call it! + if (lua_pcall(State, nArgs, nResults, 0) = 0) then + Result := true //called w/o errors + else //increase error counter + Inc (ErrorCount); + end + else + begin //we have to pop the args and the field we pushed from stack + lua_pop(State, nArgs + 1); + //leave an errormessage on stack + lua_pushstring(State, Pchar('could not find function named ' + Name)); + end; end else - begin //we have to pop the args and the field we pushed from stack - lua_pop(State, nArgs + 1); + begin //we have to pop the args from stack + lua_pop(State, nArgs); //leave an errormessage on stack - lua_pushstring(State, Pchar('could not find function named ' + Name)); + lua_pushstring(State, PChar('plugin paused')); end; + + if (not Result) AND (ReportErrors) then + Log.LogError(lua_toString(State, -1), 'lua/' + sName); + + if ShutDown then + begin // plugin indicates self shutdown + ShutDown := False; + Unload; + Result := False; + end end else - begin //we have to pop the args from stack - lua_pop(State, nArgs); - //leave an errormessage on stack - lua_pushstring(State, PChar('plugin paused')); + begin + Log.LogError('trying to call function of closed or not opened lua state', IfThen(HasRegistred, Name, Filename)); end; - - if (not Result) AND (ReportErrors) then - Log.LogError(lua_toString(State, -1), 'lua/' + sName); end; { removes all values from stack } procedure TLuaPlugin.ClearStack; begin - if (lua_gettop(State) > 0) then + if (State <> nil) and (lua_gettop(State) > 0) then lua_pop(State, lua_gettop(State)); end; -{ Destroys the Luastate, and frees as much mem as possible, +{ destroys the lua state, and frees as much mem as possible, w/o destroying the class and important information } procedure TLuaPlugin.Unload; begin if (State <> nil) then begin if (Status in [psRunning, psErrorOnRun]) then - CallFunctionByName('plugin_unload', 1, 0, False); + CallFunctionByName('plugin_unload'); ClearStack; lua_close(State); diff --git a/Lua/src/lua/ULuaParty.pas b/Lua/src/lua/ULuaParty.pas index 41a0d2ae..25cfce94 100644 --- a/Lua/src/lua/ULuaParty.pas +++ b/Lua/src/lua/ULuaParty.pas @@ -101,14 +101,13 @@ function ULuaParty_Register(L: Plua_State): Integer; cdecl; var Info: TParty_ModeInfo; Key: String; + P: TLuaPlugin; begin // check for table on stack luaL_checkType(L, 1, LUA_TTABLE); // get parent id - lua_getfield (L, LUA_REGISTRYINDEX, '_USDX_STATE_ID'); - if (not lua_isNumber(L, -1)) then - luaL_error(L, 'unable to get _USDX_STATE_ID in ULuaParty_Register'); + P := Lua_GetOwner(L); // set mode info to default @@ -116,8 +115,7 @@ begin // set parent in info rec and pop it from stack - Info.Parent := lua_toInteger(L, -1); - lua_pop(L, 1); + Info.Parent := P.Id; // go through table elements lua_pushNil(L); diff --git a/Lua/src/lua/ULuaUsdx.pas b/Lua/src/lua/ULuaUsdx.pas index d5277161..c38eec4c 100644 --- a/Lua/src/lua/ULuaUsdx.pas +++ b/Lua/src/lua/ULuaUsdx.pas @@ -49,16 +49,20 @@ function ULuaUsdx_Version(L: Plua_State): Integer; cdecl; arguments: event_name: string } function ULuaUsdx_Hook(L: Plua_State): Integer; cdecl; +{ Usdx.ShutMeDown - no results, no arguments + unloads the calling plugin } +function ULuaUsdx_ShutMeDown(L: Plua_State): Integer; cdecl; + const ULuaUsdx_Lib_f: array [0..3] of lual_reg = ( (name:'Version'; func:ULuaUsdx_Version), (name:'Time'; func:ULuaUsdx_Time), (name:'Hook'; func:ULuaUsdx_Hook), - (name:nil; func:nil) + (name:'ShutMeDown'; func:ULuaUsdx_ShutMeDown) ); implementation -uses SDL, ULuaCore, UHookableEvent, UConfig; +uses SDL, ULuaCore, ULuaUtils, UHookableEvent, UConfig; { Usdx.Time - returns sdl_time to have time numbers comparable with ultrastar deluxe ones. no arguments } @@ -68,7 +72,7 @@ begin //remove arguments (if any) top := lua_gettop(L); - If (top > 0) then + if (top > 0) then lua_pop(L, top); //push result @@ -84,7 +88,7 @@ begin //remove arguments (if any) top := lua_gettop(L); - If (top > 0) then + if (top > 0) then lua_pop(L, top); //push result @@ -98,19 +102,13 @@ function ULuaUsdx_Hook(L: Plua_State): Integer; cdecl; var EventName: String; FunctionName: String; - ParentId: Integer; + P: TLuaPlugin; Event: THookableEvent; begin EventName := luaL_checkstring(L, 1); FunctionName := luaL_checkstring(L, 2); - lua_checkstack(L, 1); - - lua_getfield (L, LUA_REGISTRYINDEX, '_USDX_STATE_ID'); - if (not lua_isNumber(L, -1)) then - luaL_error(L, 'unable to get _USDX_STATE_ID in ULuaUsdx_Hook'); - - ParentId := lua_toInteger(L, -1); + P := Lua_GetOwner(L); lua_pop(L, lua_gettop(L)); //clear stack @@ -119,10 +117,28 @@ begin Event := LuaCore.GetEventByName(EventName); if (Event <> nil) then begin - Event.Hook(L, ParentId, FunctionName); + Event.Hook(L, P.Id, FunctionName); end else luaL_error(L, PChar('event does not exist: ' + EventName)); end; +function ULuaUsdx_ShutMeDown(L: Plua_State): Integer; cdecl; + var + top: Integer; + P: TLuaPlugin; +begin + Result := 0; + + //remove arguments (if any) + top := lua_gettop(L); + + if (top > 0) then + lua_pop(L, top); + + P := Lua_GetOwner(L); + + P.ShutMeDown; +end; + end. \ No newline at end of file diff --git a/Lua/src/lua/ULuaUtils.pas b/Lua/src/lua/ULuaUtils.pas index 2bcfea68..de3bd15f 100644 --- a/Lua/src/lua/ULuaUtils.pas +++ b/Lua/src/lua/ULuaUtils.pas @@ -33,7 +33,7 @@ interface {$I switches.inc} -uses ULua; +uses ULua, ULuaCore; { converts a lua table with a structure like: * = 1 , * = 4 , * = 5 @@ -42,6 +42,13 @@ uses ULua; does not pop anything } function Lua_ToBinInt(L: PLua_State; idx: Integer): Integer; +{ returns plugin that is the owner of the given state + may raise a lua error if the parent id is not found + in states registry, if state owner does not exists + or is not loaded. So a check for a nil value is not + necessary } +function Lua_GetOwner(L: PLua_State): TLuaPlugin; + { this is a helper in case an evenet owner don't has no use for the results returns number of popped elements } function Lua_ClearStack(L: Plua_State): Integer; @@ -61,7 +68,7 @@ begin // default: no bits set Result := 0; - lua_checkstack(L, 3); + lua_checkstack(L, 2); if (idx < 0) then dec(idx); // we will push one value before using this @@ -81,10 +88,32 @@ begin end; end; +{ returns plugin that is the owner of the given state + may raise a lua error if the parent id is not found + in states registry, if state owner does not exists + or is not loaded. So a check for a nil value is not + necessary } +function Lua_GetOwner(L: PLua_State): TLuaPlugin; +begin + lua_checkstack(L, 1); + + lua_getfield (L, LUA_REGISTRYINDEX, '_USDX_STATE_ID'); + if (not lua_isNumber(L, -1)) then + luaL_error(L, 'unable to get _USDX_STATE_ID'); + + Result := LuaCore.GetPluginById(lua_toInteger(L, -1)); + + lua_pop(L, 1); //< remove state id from stack + + if (Result = nil) then + luaL_error(L, '_USDX_STATE_ID has invalid value') + else if (Result.Status > psRunning) then + luaL_error(L, 'owning plugin is not loaded or already unloaded in Lua_GetOwner'); +end; + { this is a helper in case an evenet owner don't has no use for the results returns number of popped elements } function Lua_ClearStack(L: Plua_State): Integer; - var I: Integer; begin Result := lua_gettop(L); lua_pop(L, Result); -- cgit v1.2.3