From ac1f8196a723e587f12ad355669d366f10e06f51 Mon Sep 17 00:00:00 2001 From: k-m_schindler Date: Sat, 22 Nov 2014 13:50:25 +0000 Subject: adjust eol and set svn property svn:eol-style native for all in lua git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@3087 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/lua/UHookableEvent.pas | 758 ++++++++++++++++++++++----------------------- 1 file changed, 379 insertions(+), 379 deletions(-) (limited to 'src/lua/UHookableEvent.pas') diff --git a/src/lua/UHookableEvent.pas b/src/lua/UHookableEvent.pas index 8ad7ea9c..7193654a 100644 --- a/src/lua/UHookableEvent.pas +++ b/src/lua/UHookableEvent.pas @@ -1,380 +1,380 @@ -{* UltraStar Deluxe - Karaoke Game - * - * UltraStar Deluxe is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - *} - -unit UHookableEvent; - -interface - -{$IFDEF FPC} - {$MODE Delphi} -{$ENDIF} - -{$I switches.inc} - -uses ULua; - -type - { Record holding information about a hook of an event } - PHook = ^THook; - THook = record - Handle: Integer; //< Handle to identify the hook, e.g. for unhooking by plugin - Parent: Integer; //< Lua Core Handle this hook belongs to - - Func: String; //< Name of the global that holds the function - - Next: PHook; //< Next Hook in list (nil for the first) - end; - - { procedure is called before each call to the hooking lua functions, to push values on stack - returns the number of pushed arguments} - PrepareStackProc = Function(L: PLua_State): Integer; - - { class representing a hookable event } - THookableEvent = class - private - iHandle: Integer; //< used to unregister at lua core - LastHook: PHook; //< last hook in hook list, first to be called - NextHookHandle: Integer; //< handle to identify next hook - - sName: String; //< the events name - - PrepareStack: PrepareStackProc; //< prepare stack procedure passed to constructor - CallinProcess: boolean; //< true if a chain call is in process, to prepare unhooking during calls - HooksToRemove: array of PHook; // hooks to delete after chaincall - - procedure RemoveWaitingHooks; - public - constructor Create(Name: String; const Proc: PrepareStackProc = nil); - - property Name: String read sName; //< returns the events name - property Handle: Integer read iHandle; //< returns the events name - - procedure Hook(L: Plua_State; Parent: Integer; Func: String); //< pushes hook object/table to the lua stack - procedure UnHook(L: Plua_State; hHook: Integer); //< unhook by plugin. push true or error string to lua stack - - procedure UnHookByParent(Parent: Integer); //< deletes all hooks by a specified parent (unhook by core) - - function CallHookChain(Breakable: Boolean): PLua_State; //< calls the events hookchain. if breakable, plugin can breake the chain by returning a value != 0 or false or nil - - destructor Destroy; override; - end; - -{ the default function for THookableEvent.PrepareStack it don't pass any arguments } -function PrepareStack_Dummy(L: PLua_State): Integer; - -{ function in resulting hook table. it calls the unhook command of the event on plugins demand } -function LuaHook_UnHook(L: Plua_State): Integer; cdecl; - -implementation -uses ULuaCore; - -constructor THookableEvent.Create(Name: String; const Proc: PrepareStackProc); -begin - inherited Create; - - Self.sName := Name; - - if (@Proc = nil) then - Self.PrepareStack := @PrepareStack_Dummy - else - Self.PrepareStack := Proc; - - //init LastHook pointer w/ nil - LastHook := nil; - NextHookHandle := 1; - - iHandle := LuaCore.RegisterEvent(Self); -end; - -destructor THookableEvent.Destroy; -var - Prev: PHook; - Cur: PHook; -begin - //delete all hooks - Cur := LastHook; - While (Cur <> nil) do - begin - Prev := Cur; - Cur := Prev.Next; - - Dispose(Prev); - end; - - //remove from luacores list - LuaCore.UnRegisterEvent(iHandle); - - inherited; -end; - -{ adds hook to events list and pushes hook object/table to the lua stack } -procedure THookableEvent.Hook(L: PLua_State; Parent: Integer; Func: String); - var - Item: PHook; - P: TLuaPlugin; -begin - P := LuaCore.GetPluginById(Parent); - if (P <> nil) then - begin - // get mem and fill it w/ data - New(Item); - Item.Handle := NextHookHandle; - Inc(NextHookHandle); - - Item.Parent := Parent; - Item.Func := Func; - - // add at front of the hook chain - Item.Next := LastHook; - LastHook := Item; - - //we need 2 free stack slots - lua_checkstack(L, 2); - - //create the hook table, we need 2 elements (event name and unhook function) - lua_createtable(L, 0, 2); - - //push events name - lua_pushstring(L, PAnsiChar(Name)); - - //add the name to the table - lua_setfield(L, -2, 'Event'); - - //push hook id to the stack - lua_pushinteger(L, Item.Handle); - - //create a c closure, append one value from stack(the id) - //this will pop both, the function and the id - lua_pushcclosure(L, LuaHook_UnHook, 1); - - //add the function to our table - lua_setfield(L, -2, 'Unhook'); - - //the table is left on the stack, it is our result - end; -end; - -{ removes hooks in HookstoRemove array from chain } -procedure THookableEvent.RemoveWaitingHooks; - function IsInArray(Cur: PHook): boolean; - var I: Integer; - begin - Result := false; - for I := 0 to high(HooksToRemove) do - if (HooksToRemove[I] = Cur) then - begin - Result := true; - Break; - end; - end; - - var - Cur, Prev: PHook; -begin - Prev := nil; - Cur := LastHook; - - while (Cur <> nil) do - begin - if (IsInArray(Cur)) then - begin //we found the hook - if (prev <> nil) then - Prev.Next := Cur.Next - else //last hook found - LastHook := Cur.Next; - - //free hooks memory - Dispose(Cur); - - if (prev <> nil) then - Cur := Prev.Next - else - Cur := LastHook; - end - else - begin - Prev := Cur; - Cur := Prev.Next; - end; - end; - - SetLength(HooksToRemove, 0); -end; - -{ unhook by plugin. push true or error string to lua stack } -procedure THookableEvent.UnHook(L: Plua_State; hHook: Integer); - var - Cur, Prev: PHook; - Len: integer; -begin - if (hHook < NextHookHandle) and (hHook > 0) then - begin - //Search for the Hook - Prev := nil; - Cur := LastHook; - - while (Cur <> nil) do - begin - if (Cur.Handle = hHook) then - begin //we found the hook - if not CallinProcess then - begin // => remove it - if (prev <> nil) then - Prev.Next := Cur.Next - else //last hook found - LastHook := Cur.Next; - - //free hooks memory - Dispose(Cur); - end - else - begin // add to list of hooks to remove - Len := Length(HooksToRemove); - SetLength(HooksToRemove, Len + 1); - HooksToRemove[Len] := Cur; - end; - - //indicate success - lua_pushboolean(L, True); - exit; //break the chain and exit the function - end; - Prev := Cur; - Cur := Prev.Next; - end; - - lua_pushstring(L, PAnsiChar('handle already unhooked')); //the error description - end - else - lua_pushstring(L, PAnsiChar('undefined hook handle')); //the error description -end; - -{ deletes all hooks by a specified parent (unhook by core) } -procedure THookableEvent.UnHookByParent(Parent: Integer); - var - Cur, Prev: PHook; -begin - Prev := nil; - Cur := LastHook; - - While (Cur <> nil) do - begin - if (Cur.Parent = Parent) then - begin //found a hook from parent => remove it - if (Prev <> nil) then - Prev.Next := Cur.Next - Else - LastHook := Cur.Next; - - Dispose(Cur); - - if (Prev <> nil) then - Cur := Prev.Next - else - Cur := LastHook; - end - else //move through the chain - begin - Prev := Cur; - Cur := Prev.Next; - end; - end; -end; - -{ calls the events hookchain. if breakable, plugin can breake the chain - by returning a value - breakable is pushed as the first parameter to the hooking functions - if chain is broken the LuaStack is returned, with all results left - you may call lua_clearstack } -function THookableEvent.CallHookChain(Breakable: Boolean): Plua_State; - var - Cur: PHook; - P: TLuaPlugin; -begin - Result := nil; - - CallinProcess := true; - - Cur := LastHook; - While (Cur <> nil) do - begin - P := LuaCore.GetPluginById(Cur.Parent); - lua_pushboolean(P.LuaState, Breakable); - - if (P.CallFunctionByName(Cur.Func, 1 + PrepareStack(P.LuaState), LUA_MULTRET)) - and Breakable - and (lua_gettop(P.LuaState) > 0) then - begin //Chain Broken - Result := P.LuaState; - Break; - end; - - Cur := Cur.Next; - end; - - RemoveWaitingHooks; - CallinProcess := false; -end; - -{ the default function for THookableEvent.PrepareStack it don't pass any arguments } -function PrepareStack_Dummy(L: PLua_State): Integer; -begin - Result := 0; -end; - -{ function in resulting hook table. it calls the unhook command of the event on plugins demand } -function LuaHook_UnHook(L: Plua_State): Integer; cdecl; - var - Name: string; - Event: THookableEvent; - hHook: integer; -begin - Result := 0; - - if not lua_isTable(L, 1) then - LuaL_Error(L, 'Can''t find hook table in LuaHook_Unhook. Please call Unhook with method seperator (colon) instead of a point.'); - - // get event name - Lua_GetField(L, 1, 'Event'); - if not lua_isString(L, -1) then - LuaL_Error(L, 'Can''t get event name in LuaHook_Unhook'); - - Name := Lua_ToString(L, -1); - - // get event by name - Event := LuaCore.GetEventbyName(Name); - - // free stack slots - Lua_pop(L, Lua_GetTop(L)); - - if (Event = nil) then - LuaL_Error(L, PAnsiChar('event ' + Name + ' does not exist (anymore?) in LuaHook_Unhook')); - - // get the hookid - hHook := lua_ToInteger(L, lua_upvalueindex(1)); - - Event.UnHook(L, hHook); -end; - +{* UltraStar Deluxe - Karaoke Game + * + * UltraStar Deluxe is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + *} + +unit UHookableEvent; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses ULua; + +type + { Record holding information about a hook of an event } + PHook = ^THook; + THook = record + Handle: Integer; //< Handle to identify the hook, e.g. for unhooking by plugin + Parent: Integer; //< Lua Core Handle this hook belongs to + + Func: String; //< Name of the global that holds the function + + Next: PHook; //< Next Hook in list (nil for the first) + end; + + { procedure is called before each call to the hooking lua functions, to push values on stack + returns the number of pushed arguments} + PrepareStackProc = Function(L: PLua_State): Integer; + + { class representing a hookable event } + THookableEvent = class + private + iHandle: Integer; //< used to unregister at lua core + LastHook: PHook; //< last hook in hook list, first to be called + NextHookHandle: Integer; //< handle to identify next hook + + sName: String; //< the events name + + PrepareStack: PrepareStackProc; //< prepare stack procedure passed to constructor + CallinProcess: boolean; //< true if a chain call is in process, to prepare unhooking during calls + HooksToRemove: array of PHook; // hooks to delete after chaincall + + procedure RemoveWaitingHooks; + public + constructor Create(Name: String; const Proc: PrepareStackProc = nil); + + property Name: String read sName; //< returns the events name + property Handle: Integer read iHandle; //< returns the events name + + procedure Hook(L: Plua_State; Parent: Integer; Func: String); //< pushes hook object/table to the lua stack + procedure UnHook(L: Plua_State; hHook: Integer); //< unhook by plugin. push true or error string to lua stack + + procedure UnHookByParent(Parent: Integer); //< deletes all hooks by a specified parent (unhook by core) + + function CallHookChain(Breakable: Boolean): PLua_State; //< calls the events hookchain. if breakable, plugin can breake the chain by returning a value != 0 or false or nil + + destructor Destroy; override; + end; + +{ the default function for THookableEvent.PrepareStack it don't pass any arguments } +function PrepareStack_Dummy(L: PLua_State): Integer; + +{ function in resulting hook table. it calls the unhook command of the event on plugins demand } +function LuaHook_UnHook(L: Plua_State): Integer; cdecl; + +implementation +uses ULuaCore; + +constructor THookableEvent.Create(Name: String; const Proc: PrepareStackProc); +begin + inherited Create; + + Self.sName := Name; + + if (@Proc = nil) then + Self.PrepareStack := @PrepareStack_Dummy + else + Self.PrepareStack := Proc; + + //init LastHook pointer w/ nil + LastHook := nil; + NextHookHandle := 1; + + iHandle := LuaCore.RegisterEvent(Self); +end; + +destructor THookableEvent.Destroy; +var + Prev: PHook; + Cur: PHook; +begin + //delete all hooks + Cur := LastHook; + While (Cur <> nil) do + begin + Prev := Cur; + Cur := Prev.Next; + + Dispose(Prev); + end; + + //remove from luacores list + LuaCore.UnRegisterEvent(iHandle); + + inherited; +end; + +{ adds hook to events list and pushes hook object/table to the lua stack } +procedure THookableEvent.Hook(L: PLua_State; Parent: Integer; Func: String); + var + Item: PHook; + P: TLuaPlugin; +begin + P := LuaCore.GetPluginById(Parent); + if (P <> nil) then + begin + // get mem and fill it w/ data + New(Item); + Item.Handle := NextHookHandle; + Inc(NextHookHandle); + + Item.Parent := Parent; + Item.Func := Func; + + // add at front of the hook chain + Item.Next := LastHook; + LastHook := Item; + + //we need 2 free stack slots + lua_checkstack(L, 2); + + //create the hook table, we need 2 elements (event name and unhook function) + lua_createtable(L, 0, 2); + + //push events name + lua_pushstring(L, PAnsiChar(Name)); + + //add the name to the table + lua_setfield(L, -2, 'Event'); + + //push hook id to the stack + lua_pushinteger(L, Item.Handle); + + //create a c closure, append one value from stack(the id) + //this will pop both, the function and the id + lua_pushcclosure(L, LuaHook_UnHook, 1); + + //add the function to our table + lua_setfield(L, -2, 'Unhook'); + + //the table is left on the stack, it is our result + end; +end; + +{ removes hooks in HookstoRemove array from chain } +procedure THookableEvent.RemoveWaitingHooks; + function IsInArray(Cur: PHook): boolean; + var I: Integer; + begin + Result := false; + for I := 0 to high(HooksToRemove) do + if (HooksToRemove[I] = Cur) then + begin + Result := true; + Break; + end; + end; + + var + Cur, Prev: PHook; +begin + Prev := nil; + Cur := LastHook; + + while (Cur <> nil) do + begin + if (IsInArray(Cur)) then + begin //we found the hook + if (prev <> nil) then + Prev.Next := Cur.Next + else //last hook found + LastHook := Cur.Next; + + //free hooks memory + Dispose(Cur); + + if (prev <> nil) then + Cur := Prev.Next + else + Cur := LastHook; + end + else + begin + Prev := Cur; + Cur := Prev.Next; + end; + end; + + SetLength(HooksToRemove, 0); +end; + +{ unhook by plugin. push true or error string to lua stack } +procedure THookableEvent.UnHook(L: Plua_State; hHook: Integer); + var + Cur, Prev: PHook; + Len: integer; +begin + if (hHook < NextHookHandle) and (hHook > 0) then + begin + //Search for the Hook + Prev := nil; + Cur := LastHook; + + while (Cur <> nil) do + begin + if (Cur.Handle = hHook) then + begin //we found the hook + if not CallinProcess then + begin // => remove it + if (prev <> nil) then + Prev.Next := Cur.Next + else //last hook found + LastHook := Cur.Next; + + //free hooks memory + Dispose(Cur); + end + else + begin // add to list of hooks to remove + Len := Length(HooksToRemove); + SetLength(HooksToRemove, Len + 1); + HooksToRemove[Len] := Cur; + end; + + //indicate success + lua_pushboolean(L, True); + exit; //break the chain and exit the function + end; + Prev := Cur; + Cur := Prev.Next; + end; + + lua_pushstring(L, PAnsiChar('handle already unhooked')); //the error description + end + else + lua_pushstring(L, PAnsiChar('undefined hook handle')); //the error description +end; + +{ deletes all hooks by a specified parent (unhook by core) } +procedure THookableEvent.UnHookByParent(Parent: Integer); + var + Cur, Prev: PHook; +begin + Prev := nil; + Cur := LastHook; + + While (Cur <> nil) do + begin + if (Cur.Parent = Parent) then + begin //found a hook from parent => remove it + if (Prev <> nil) then + Prev.Next := Cur.Next + Else + LastHook := Cur.Next; + + Dispose(Cur); + + if (Prev <> nil) then + Cur := Prev.Next + else + Cur := LastHook; + end + else //move through the chain + begin + Prev := Cur; + Cur := Prev.Next; + end; + end; +end; + +{ calls the events hookchain. if breakable, plugin can breake the chain + by returning a value + breakable is pushed as the first parameter to the hooking functions + if chain is broken the LuaStack is returned, with all results left + you may call lua_clearstack } +function THookableEvent.CallHookChain(Breakable: Boolean): Plua_State; + var + Cur: PHook; + P: TLuaPlugin; +begin + Result := nil; + + CallinProcess := true; + + Cur := LastHook; + While (Cur <> nil) do + begin + P := LuaCore.GetPluginById(Cur.Parent); + lua_pushboolean(P.LuaState, Breakable); + + if (P.CallFunctionByName(Cur.Func, 1 + PrepareStack(P.LuaState), LUA_MULTRET)) + and Breakable + and (lua_gettop(P.LuaState) > 0) then + begin //Chain Broken + Result := P.LuaState; + Break; + end; + + Cur := Cur.Next; + end; + + RemoveWaitingHooks; + CallinProcess := false; +end; + +{ the default function for THookableEvent.PrepareStack it don't pass any arguments } +function PrepareStack_Dummy(L: PLua_State): Integer; +begin + Result := 0; +end; + +{ function in resulting hook table. it calls the unhook command of the event on plugins demand } +function LuaHook_UnHook(L: Plua_State): Integer; cdecl; + var + Name: string; + Event: THookableEvent; + hHook: integer; +begin + Result := 0; + + if not lua_isTable(L, 1) then + LuaL_Error(L, 'Can''t find hook table in LuaHook_Unhook. Please call Unhook with method seperator (colon) instead of a point.'); + + // get event name + Lua_GetField(L, 1, 'Event'); + if not lua_isString(L, -1) then + LuaL_Error(L, 'Can''t get event name in LuaHook_Unhook'); + + Name := Lua_ToString(L, -1); + + // get event by name + Event := LuaCore.GetEventbyName(Name); + + // free stack slots + Lua_pop(L, Lua_GetTop(L)); + + if (Event = nil) then + LuaL_Error(L, PAnsiChar('event ' + Name + ' does not exist (anymore?) in LuaHook_Unhook')); + + // get the hookid + hHook := lua_ToInteger(L, lua_upvalueindex(1)); + + Event.UnHook(L, hHook); +end; + end. \ No newline at end of file -- cgit v1.2.3