From 7f5c651cf34e557d22eb148e08abc9dce8655780 Mon Sep 17 00:00:00 2001 From: whiteshark0 Date: Mon, 23 Mar 2009 14:51:13 +0000 Subject: new pluginloader library loading finished handshake missing sdk nearly finished git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/branches/experimental@1654 b956fd51-792f-4845-bead-9b4dfca2ff2c --- ServiceBasedPlugins/src/base/UMain.pas | 11 + ServiceBasedPlugins/src/base/UNote.pas | 3 +- ServiceBasedPlugins/src/base/UParty.pas | 207 +++++++++++++--- .../src/pluginsupport/UPartyDefines.pas | 38 +++ ServiceBasedPlugins/src/pluginsupport/UPlugin.pas | 137 +++++++++++ .../src/pluginsupport/UPluginDefines.pas | 273 +++++++++++++++++++++ .../src/pluginsupport/UPluginLoader_DLL.pas | 181 ++++++++++++++ .../src/pluginsupport/UPluginLoader_Included.pas | 38 +++ .../src/pluginsupport/UPluginManager.pas | 174 +++++++++++++ ServiceBasedPlugins/src/ultrastardx.dpr | 34 +-- 10 files changed, 1042 insertions(+), 54 deletions(-) create mode 100644 ServiceBasedPlugins/src/pluginsupport/UPartyDefines.pas create mode 100644 ServiceBasedPlugins/src/pluginsupport/UPlugin.pas create mode 100644 ServiceBasedPlugins/src/pluginsupport/UPluginDefines.pas create mode 100644 ServiceBasedPlugins/src/pluginsupport/UPluginLoader_DLL.pas create mode 100644 ServiceBasedPlugins/src/pluginsupport/UPluginLoader_Included.pas create mode 100644 ServiceBasedPlugins/src/pluginsupport/UPluginManager.pas diff --git a/ServiceBasedPlugins/src/base/UMain.pas b/ServiceBasedPlugins/src/base/UMain.pas index fec1903f..71d3885a 100644 --- a/ServiceBasedPlugins/src/base/UMain.pas +++ b/ServiceBasedPlugins/src/base/UMain.pas @@ -87,6 +87,9 @@ uses ULog, UPath, UPlaylist, + UPluginManager, + UPluginLoader_Dll, + UPluginLoader_Included, UMusic, UPlatform, USkins, @@ -233,6 +236,14 @@ begin Log.BenchmarkStart(1); Log.LogStatus('PluginManager', 'Initialization'); DLLMan := TDLLMan.Create; // Load PluginList + + PluginManager := TPluginManager.Create; + + //TPluginLoader_Included.Create; + TPluginLoader_DLL.Create(PluginPath); + + //PluginManager.Init; + Log.BenchmarkEnd(1); Log.LogBenchmark('Loading PluginManager', 1); diff --git a/ServiceBasedPlugins/src/base/UNote.pas b/ServiceBasedPlugins/src/base/UNote.pas index 5e70bfe1..41d3da36 100644 --- a/ServiceBasedPlugins/src/base/UNote.pas +++ b/ServiceBasedPlugins/src/base/UNote.pas @@ -126,12 +126,11 @@ uses UDLLManager, UParty, UConfig, - UCore, UCommon, UGraphic, UGraphicClasses, UPath, - UPluginDefs, + //UPluginDefs, UPlatform, UThemes; diff --git a/ServiceBasedPlugins/src/base/UParty.pas b/ServiceBasedPlugins/src/base/UParty.pas index 23012dfe..5b09c06d 100644 --- a/ServiceBasedPlugins/src/base/UParty.pas +++ b/ServiceBasedPlugins/src/base/UParty.pas @@ -33,10 +33,9 @@ interface {$I switches.inc} -uses - UPartyDefs, - UCoreModule, - UPluginDefs; +//uses + //UPartyDefs, + //UPluginDefs; type ARounds = array [0..252] of integer; //0..252 needed for @@ -54,13 +53,152 @@ type TeamOrderArray = array[0..5] of byte; + // some things copied from UPartyDefs, remove this later + + //---------------- + // TUS_Party_Proc_Init - Structure of the Party Init Proc + // This Function is called on SingScreen Init Everytime this Modi should be sung + // Return Non Zero to Abort Party Modi Loading... In this Case another Plugin will be loaded + //---------------- + TUS_Party_Proc_Init = Function (ID: Integer): integer; stdcall; + + //---------------- + // TUS_Party_Proc_Draw - Structure of the Party Draw Proc + // This Function is called on SingScreen Draw (Not when Paused). You should draw in this Proc + // Return Non Zero to Finish Song... In this Case Score Screen is loaded + //---------------- + TUS_Party_Proc_Draw = Function (ID: Integer): integer; stdcall; + + //---------------- + // TUS_Party_Proc_DeInit - Structure of the Party DeInit Proc + // This Function is called on SingScreen DeInit When Plugin abort Song or Song finishes + // Return Winner + //---------------- + TUS_Party_Proc_DeInit = Function (ID: Integer): integer; stdcall; + + //---------------- + // TUS_ModiInfo - Some Infos from Plugin to Partymode. + // Used to register party modi to Party manager + // --- + // Version Structure: + // First Byte: Head Revison + // Second Byte: Sub Revison + // Third Byte: Sub Revision 2 + // Fourth Byte: Letter (For Bug Fix releases. 0 or 'a' .. 'z') + //---------------- + TModiInfo_Name = Array [0..31] of Char; + TModiInfo_Desc = Array [0..63] of Char; + + PUS_ModiInfo = ^TUS_ModiInfo; + TUS_ModiInfo = record + //Size of this record (usefull if record will be extended in the future) + cbSize: Integer; //Don't forget to set this as Plugin! + + //Infos about the Modi + Name : TModiInfo_Name; //Modiname to Register for the Plugin + Description: TModiInfo_Desc; //Plugin Description + + //------------ + // Loading Settings + // --- + // Bit to Set | Triggered Option + // 1 | Song should be loaded + // 2 | Song has to be Non Duett + // 4 | Song has to be Duett (If 2 and 4 is set, both will be ignored) + // 8 | Only Playable with 2 and more players + // 16 | Restrict Background Loading + // 32 | Restrict Video Loading + // 64 | Increase TimesPlayed for Cur. Player + // 128 | Not in Use, Don't set it! + LoadingSettings: Byte; + + // SingScreen Settings + // --- + // Bit to Set | Triggered Option + // 1 | ShowNotes + // 2 | ShowScores + // 4 | ShowTime + // 8 | Start Audio Playback automaticaly + // 16 | Not in Use, Don't set it! + // 32 | Not in Use, Don't set it! + // 64 | Not in Use, Don't set it! + // 128 | Not in Use, Don't set it! + SingScreenSettings: Byte; + + // With which count of players can this modi be played + // --- + //Set different Bits + //1 -> One Player + //2 -> Two Players + //4 -> Three Players + //8 -> Four Players + //16-> Six Players + //e.g. : 10 -> Playable with 2 and 4 Players + NumPlayers: Byte; + + // ID that is given to the Party Procs when they are called + // If this Modi is running + // (e.g. to register Until 2000 and Until 5000 with the same Procs + // ID is the Max Point Count in this example) + ID: Integer; + + // Party Procs called on Party + // --- + // Set to nil(C: NULL) if u don't want to use this method + ModiInit: TUS_Party_Proc_Init; + ModiDraw: TUS_Party_Proc_Draw; + ModiDeInit: TUS_Party_Proc_DeInit; + end; + + //-------------- + // Team Info Record. Used by "Party/GetTeamInfo" and "Party/SetTeamInfo" + //-------------- + TTeamInfo = record + NumTeams: Byte; + Teaminfo: array[0..5] of record + Name: PChar; //Teamname + Score: Word; //TeamScore + Joker: Byte; //Team Jokers available + CurPlayer: Byte; //Id of Cur. Playing Player + NumPlayers: Byte; + Playerinfo: array[0..3] of record + Name: PChar; //Playername + TimesPlayed: Byte; //How often this Player has Sung + end; + end; + end; + +//---------------- +// Some Default Constants +//---------------- +const + // to use for TUS_ModiInfo.LoadingSettings + MLS_LoadSong = 1; //Song should be loaded + MLS_NotDuett = 2; //Song has to be Non Duett + MLS_ForceDuett = 4; //Song has to be Duett (If 2 and 4 is set, both will be ignored) + MLS_TeamOnly = 8; //Only Playable with 2 and more players + MLS_RestrictBG = 16; //Restrict Background Loading + MLS_RestrictVid = 32; //Restrict Video Loading + MLS_IncTP = 64; //Increase TimesPlayed for Cur. Player + + // to use with TUS_ModiInfo.SingScreenSettings + MSS_ShowNotes = 1; //ShowNotes + MSS_ShowScores = 2; //ShowScores + MSS_ShowTime = 4; //ShowTime + MSS_AutoPlayback= 8; //Start Audio Playback automaticaly + + //Standard (Duell) for TUS_ModiInfo.LoadingSettings and TUS_ModiInfo.SingScreenSettings + MLS_Standard = MLS_LoadSong or MLS_IncTP; + MSS_Standard = MSS_ShowNotes or MSS_ShowScores or MSS_ShowTime or MSS_AutoPlayback; + +type TUS_ModiInfoEx = record Info: TUS_ModiInfo; Owner: integer; TimesPlayed: byte; //Helper for setting round plugins end; - TPartySession = class (TCoreModule) + TPartySession = class private bPartyMode: boolean; //Is this party or single player CurRound: byte; @@ -77,14 +215,14 @@ type Rounds: array of TRoundInfo; //TCoreModule methods to inherit - constructor Create; override; - procedure Info(const pInfo: PModuleInfo); override; - function Load: boolean; override; - function Init: boolean; override; - procedure DeInit; override; - destructor Destroy; override; - - //Register modus service + constructor Create; + //procedure Info(const pInfo: PModuleInfo); + function Load: boolean; + function Init: boolean; + procedure DeInit; + destructor Destroy; + + {//Register modus service function RegisterModi(nothin: TwParam; pModiInfo: TlParam): integer; //Registers a new modus. wParam: Pointer to TUS_ModiInfo //Start new Party @@ -100,7 +238,7 @@ type function SetTeamInfo(wParam: TwParam; pTeamInfo: TlParam): integer; //Read TTeamInfo record from pointer at lParam. Returns zero on success function GetTeamOrder(wParam: TwParam; lParam: TlParam): integer; //Returns team order. Structure: Bits 1..3: Team at place1; Bits 4..6: Team at place2 ... - function GetWinnerString(wParam: TwParam; lParam: TlParam): integer; //wParam is roundnum. If (Pointer = nil) then return length of the string. Otherwise write the string to address at lParam + function GetWinnerString(wParam: TwParam; lParam: TlParam): integer; //wParam is roundnum. If (Pointer = nil) then return length of the string. Otherwise write the string to address at lParam} end; const @@ -109,7 +247,6 @@ const implementation uses - UCore, UGraphic, ULanguage, ULog, @@ -124,12 +261,12 @@ uses //------------- // function that gives some infos about the module to the core //------------- -procedure TPartySession.Info(const pInfo: PModuleInfo); +{rocedure TPartySession.Info(const pInfo: PModuleInfo); begin pInfo^.Name := 'TPartySession'; pInfo^.Version := MakeVersion(1,0,0,chr(0)); pInfo^.Description := 'Manages party modi and party game'; -end; +end; } //------------- // Just the constructor @@ -151,9 +288,9 @@ function TPartySession.Load: boolean; begin //Add register party modus service Result := true; - Core.Services.AddService('Party/RegisterModi', nil, Self.RegisterModi); + {Core.Services.AddService('Party/RegisterModi', nil, Self.RegisterModi); Core.Services.AddService('Party/StartParty', nil, Self.StartParty); - Core.Services.AddService('Party/GetCurModi', nil, Self.GetCurModi); + Core.Services.AddService('Party/GetCurModi', nil, Self.GetCurModi);} end; //------------- @@ -192,7 +329,7 @@ end; // Registers a new modus. wParam: Pointer to TUS_ModiInfo // Service for plugins //------------- -function TPartySession.RegisterModi(nothin: TwParam; pModiInfo: TlParam): integer; +{unction TPartySession.RegisterModi(nothin: TwParam; pModiInfo: TlParam): integer; var Len: integer; Info: PUS_ModiInfo; @@ -205,13 +342,13 @@ begin SetLength(Modis, Len + 1); Modis[Len].Info := Info^; - end - else - Core.ReportError(integer(PChar('Plugins try to register modus with wrong pointer, or wrong TUS_ModiInfo record.')), PChar('TPartySession')); + end; + {else + Core.ReportError(integer(PChar('Plugins try to register modus with wrong pointer, or wrong TUS_ModiInfo record.')), PChar('TPartySession'));} - // FIXME: return a valid result - Result := 0; -end; + // FIXME: return a valid result { + {esult := 0; +end; } //---------- // Returns a number of a random plugin @@ -265,7 +402,7 @@ end; //---------- // Starts new party mode. Returns non zero on success //---------- -function TPartySession.StartParty(NumRounds: TwParam; PAofIRounds: TlParam): integer; +{unction TPartySession.StartParty(NumRounds: TwParam; PAofIRounds: TlParam): integer; var I: integer; aiRounds: PARounds; @@ -305,7 +442,7 @@ begin Result := 1; except - Core.ReportError(integer(PChar('Can''t start party mode.')), PChar('TPartySession')); + //Core.ReportError(integer(PChar('Can''t start party mode.')), PChar('TPartySession')); end; end; end; @@ -340,7 +477,7 @@ begin end else Result := 0; -end; +end; } //---------- //GetRandomPlayer - gives back a random player to play next round @@ -392,7 +529,7 @@ end; //---------- // NextRound - Increases CurRound by 1; Returns num of round or -1 if last round is already played //---------- -function TPartySession.NextRound(wParam: TwParam; lParam: TlParam): integer; +{function TPartySession.NextRound(wParam: TwParam; lParam: TlParam): integer; var I: integer; begin @@ -409,7 +546,7 @@ begin end else Result := -1; -end; +end;} //---------- //IsWinner - returns true if the players bit is set in the winner byte @@ -440,7 +577,7 @@ end; //---------- // CallModiInit - calls CurModis Init Proc. If an error occurs, returns nonzero. In this case a new plugin was selected. Please renew loading //---------- -function TPartySession.CallModiInit(wParam: TwParam; lParam: TlParam): integer; +{function TPartySession.CallModiInit(wParam: TwParam; lParam: TlParam): integer; begin if (not bPartyMode) then begin //Set rounds if not in party mode @@ -455,10 +592,10 @@ begin except on E : Exception do begin - Core.ReportError(integer(PChar('Error starting modus: ' + Modis[Rounds[CurRound].Modi].Info.Name + ' ErrorStr: ' + E.Message)), PChar('TPartySession')); + //Core.ReportError(integer(PChar('Error starting modus: ' + Modis[Rounds[CurRound].Modi].Info.Name + ' ErrorStr: ' + E.Message)), PChar('TPartySession')); if (Rounds[CurRound].Modi = StandardModus) then begin - Core.ReportError(integer(PChar('Can''t start standard modus, will exit now!')), PChar('TPartySession')); + //Core.ReportError(integer(PChar('Can''t start standard modus, will exit now!')), PChar('TPartySession')); Halt; end else //Select standard modus @@ -660,6 +797,6 @@ begin end; end; -end; +end; } end. diff --git a/ServiceBasedPlugins/src/pluginsupport/UPartyDefines.pas b/ServiceBasedPlugins/src/pluginsupport/UPartyDefines.pas new file mode 100644 index 00000000..87e9531f --- /dev/null +++ b/ServiceBasedPlugins/src/pluginsupport/UPartyDefines.pas @@ -0,0 +1,38 @@ +{* 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: https://ultrastardx.svn.sourceforge.net/svnroot/ultrastardx/trunk/src/base/UMain.pas $ + * $Id: UMain.pas 1629 2009-03-07 22:30:04Z k-m_schindler $ + *} + +unit UPartyDefines; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +implementation + +end. \ No newline at end of file diff --git a/ServiceBasedPlugins/src/pluginsupport/UPlugin.pas b/ServiceBasedPlugins/src/pluginsupport/UPlugin.pas new file mode 100644 index 00000000..19c23999 --- /dev/null +++ b/ServiceBasedPlugins/src/pluginsupport/UPlugin.pas @@ -0,0 +1,137 @@ +{* 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: https://ultrastardx.svn.sourceforge.net/svnroot/ultrastardx/trunk/src/base/UMain.pas $ + * $Id: UMain.pas 1629 2009-03-07 22:30:04Z k-m_schindler $ + *} + +unit UPlugin; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses UPluginDefines; + +// a basic implementation of IPlugin +type + TPlugin = class(TInterfacedObject, IUS_Plugin) + protected + Status: TUS_PluginStatus; + Handle: TUS_Handle; + UniqueID: TUS_Handle; + Filename: WideString; + ErrorReason: WideString; + + procedure OnChangeStatus(Status: TUS_PluginStatus); virtual; + public + constructor Create(Handle: TUS_Handle; Filename: WideString); virtual; + + function GetStatus: TUS_PluginStatus; virtual; + procedure SetStatus(Status: TUS_PluginStatus); virtual; + + function GetHandle: TUS_Handle; virtual; + function GetUniqueID: TUS_Handle; virtual; + function GetFilename: WideString; virtual; + + procedure Init; virtual; + procedure DeInit; virtual; + + procedure SetError(Reason: WideString); virtual; + function GetErrorReason: WideString; virtual; + end; + +implementation +uses UPluginManager, ULog; + +constructor TPlugin.Create(Handle: TUS_Handle; Filename: WideString); +begin + inherited Create; + + Self.Handle := Handle; + Self.Filename := Filename; + Self.Status := psNone; + + Self.UniqueID := CalculateUSHash(Filename); //< this should be done another way ;) just for testing purposes +end; + +function TPlugin.GetStatus: TUS_PluginStatus; +begin + Result := Status; +end; + +procedure TPlugin.SetStatus(Status: TUS_PluginStatus); +begin + // OnChangeStatus has to change the status attribut + OnChangeStatus(Status); +end; + +function TPlugin.GetHandle: TUS_Handle; +begin + Result := Handle; +end; + +function TPlugin.GetUniqueID: TUS_Handle; +begin + Result := UniqueID; +end; + +function TPlugin.GetFilename: WideString; +begin + Result := Filename; +end; + +procedure TPlugin.Init; +begin + if (Status = psWaitingInit) then + SetStatus(psInited); +end; + +procedure TPlugin.DeInit; +begin + if (Status = psInited) then + SetStatus(psDeInited); +end; + +procedure TPlugin.SetError(Reason: WideString); +begin + ErrorReason := Reason; + SetStatus(psError); + PluginManager.ReportError(Handle); + Log.LogError(Filename + ': ' + Reason); +end; + +function TPlugin.GetErrorReason: WideString; +begin + Result := ErrorReason; +end; + +procedure TPlugin.OnChangeStatus(Status: TUS_PluginStatus); +begin + //do nothing here + //should be overwritten by the child classes +end; + +end. \ No newline at end of file diff --git a/ServiceBasedPlugins/src/pluginsupport/UPluginDefines.pas b/ServiceBasedPlugins/src/pluginsupport/UPluginDefines.pas new file mode 100644 index 00000000..5a042f1a --- /dev/null +++ b/ServiceBasedPlugins/src/pluginsupport/UPluginDefines.pas @@ -0,0 +1,273 @@ +{* 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: https://ultrastardx.svn.sourceforge.net/svnroot/ultrastardx/trunk/src/base/UMain.pas $ + * $Id: UMain.pas 1485 2008-10-28 20:16:05Z tobigun $ + *} +{* + some defines that are used by usdx and plugins +*} +unit UPluginDefines; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +const + SDK_Version = 0001000000000000; //< identifies the used SDK version (1.0.0.0) + +type + { this type is used for all version ints in this SDK } + TUS_Version = LongInt; + + { this type is used for all plugin handles in this SDK } + TUS_Handle = LongInt; + +const + US_HANDLE_CORE = 137; //handle of core, also first defined handle + US_HANDLE_UNDEFINED = 0; //undefined handle, used to indicate errors + + { this type is used for all id strings in this SDK } +const + MaxLength_TUS_Identifier = 32; //max length of identifier strings, has to be multiply of 4 + +type + TUS_Identifier = String[MaxLength_TUS_Identifier]; + + { this record is used to offer some information about this plugin to the core } + TUS_PluginInfo = packed record + Name : Array [1..32] of Char; //name of the plugin + Author : Array [1..32] of Char; //plugins author + PluginDesc : Array [1..64] of Char; //some further explentation + Version : TUS_Version; + end; + PUS_PluginInfo = ^TUS_PluginInfo; + + { this function reads the plugins information from a TUS_PluginInfo record, + and saves it. Can be called onced per plugin. + Version is the SDK_Version used by the plugin + BufferLength is the size of buffer in bytes } + TUS_Func_Identify = function (Handle: TUS_Handle; Version: TUS_Version; Buffer: PUS_PluginInfo; BufferLength: LongInt): LongInt; stdcall; + + { this plugin is used for selfshutdown by the plugin on an error + case. + Reason should be used to describe the reason for the shutdown + OnChangeStatus(psDeInited) is called when old status was psInited } + TUS_Func_Error = function (Handle: TUS_Handle; Reason: PWideChar): LongInt; stdcall; + + { this function writes the plugins filename including its path , + to buffer. A call with Buffer=nil or Len<=0 returns the actual + length of the path. + BufferLength is the size of buffer in bytes + Filename is used to identify duplicate load of one plugin + so it should even set when plugin is not loaded from file} + TUS_Func_GetFilename = function (Handle: TUS_Handle; Version: TUS_Version; Buffer: PWideChar; BufferLength: LongInt): LongInt; stdcall; + + { this function writes an interface, identified by 'ID', to the + buffer. + Version is the version of the interface that is used + BufferLength is the size of buffer in bytes} + TUS_Func_GetInterface = function (ID: TUS_Identifier; Version: TUS_Version; Buffer: Pointer; BufferLength: LongInt): LongInt; stdcall; + + { this function reads an interface, identified by 'ID', from the + buffer, to offer it to calls of GetInterface. + version is the version of the interface + BufferLength is the size of buffer in bytes } + TUS_Func_SetInterface = function (ID: TUS_Identifier; Version: TUS_Version; Buffer: Pointer; BufferLength: LongInt): LongInt; stdcall; + + { this function writes a record or some other data, + identified by 'ID', to the buffer. + Version is the version of the data that is used + BufferLength is the size of buffer in bytes} + TUS_Func_GetData = function (ID: TUS_Identifier; Version: TUS_Version; Buffer: Pointer; BufferLength: LongInt): LongInt; stdcall; + + { this function reads a record or some other data, + identified by 'ID', from the buffer, to offer it + to calls of GetData. + version is the version of the record + BufferLength is the size of buffer in bytes } + TUS_Func_SetData = function (ID: TUS_Identifier; Version: TUS_Version; Buffer: Pointer; BufferLength: LongInt): LongInt; stdcall; + + { a record w/ some useful methods for plugins } + TUS_PluginInterface = packed record + Version : TUS_Version; //SDK_Version + Handle : LongInt; //the plugins handle + + Identify : TUS_Func_Identify; + Error : TUS_Func_Error; + GetFilename : TUS_Func_GetFilename; + + GetInterface: TUS_Func_GetInterface; + SetInterface: TUS_Func_SetInterface; + + GetData : TUS_Func_GetData; + SetData : TUS_Func_SetData; + end; + PUS_PluginInterface = ^TUS_PluginInterface; + + { this function writes the PluginInterface to the buffer } + TUS_Func_InitInterface = function (Handle: TUS_Handle; Version: TUS_Version; Buffer: PUS_PluginInterface; BufferSize: LongInt): LongInt; + {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF} + + + { this function is called by core, in the WaitingInit status + it offers the plugin the possibility to load its plugininterface + and to check it's sdk version against the cores. + It has to be implemented by plugins loaded as library } + TUS_Plugin_Proc_Init = procedure (Handle: TUS_Handle; CoreVersion: TUS_Version; InitInterface: TUS_Func_InitInterface); + {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF} + + + TUS_PluginStatus = (psNone, psWaitingInit, psWaitingIdentify, psInited, psDeInited, psError); + + { this function is called everytime tbe plugins status changes + status is the new status. + it has to be implemented by plugins loaded as library } + TUS_Plugin_OnChangeStatus = procedure (Handle: TUS_Handle; Status: TUS_PluginStatus); + {$IFDEF MSWINDOWS} stdcall; {$ELSE} cdecl; {$ENDIF} + + + { this interface represents a loaded plugin, it eitber has to + be implemented by the pluginloader, e.g. for libs or by the + plugin itself in the case of integrated plugins } + IUS_Plugin = Interface + ['{23F7B722-D979-4402-9953-C6B229A6E888}'] + function GetStatus: TUS_PluginStatus; + procedure SetStatus(status: TUS_PluginStatus); + + function GetHandle: TUS_Handle; + function GetUniqueID: TUS_Handle; //< This ID is unique for the given plugin it may be a hash of the plugins code or s/t like that. used to identify plugins laoded twice + function GetFilename: WideString; + + Procedure Init; + Procedure DeInit; + + Procedure SetError(Reason: WideString); + Function GetErrorReason: WideString; + end; + + { this function will be called when a hookable event is spawn + data is a pointer to a struct that can contain any data + defined by the event creator. if there is no data this should + be nil. + breakable is true if the hook chain can be interupted by + returning US_HOOK_BREAK or US_HOOK_UNHOOKME_BREAK + by returning US_HOOK_UNHOOKME the callback will immediately + be removed from the chain } + TUS_Func_OnEvent = function(data: pointer; breakable: boolean): integer; + TUS_cFunc_OnEvent = function(data: pointer; breakable: boolean): integer of object; + + { this interface represents an event that can be hooked by + e.g. the core or other} + IUS_HookableEvent = Interface + // this GID has to be changed if we change this interface + ['{FFC6F09D-EC0B-41E2-87F6-70EC6F055C0E}'] + function GetIdentifier: TUS_Identifier; + function GetHash: LongInt; + + //adds the callback to the top of the events hook chain + //proc is the callback function + //parent is the plugins handle, or US_HANDLE_CORE if called by core + //returns hook-handle on succes or US_HANDLE_UNDEFINED on failure + function Hook(proc: TUS_Func_OnEvent; Parent: TUS_Handle): TUS_Handle; + function cHook(proc: TUS_cFunc_OnEvent; Parent: TUS_Handle): TUS_Handle; + + //removes a callback from the chain using the handle returned + //by the hook function + //returns an US_ERROR code + function UnHook(Handle: TUS_Handle): byte; + + //removes all callbacks of a specified parent (plugin) + procedure UnHookbyParent(Parent: TUS_Handle); + end; + + +const + { some errorcodes that are returned by functions using this SDK } + US_ERROR_None = 0; //< indicates success ;) + US_ERROR_VersionMismatch = 1; //< returned when the version the plugin wants to use is not supported + US_ERROR_SizeMismatch = 2; //< returned when the wanted data does not fit the buffersize + US_ERROR_WrongHandle = 3; //< returned when the given handle is not + US_ERROR_WrongID = 4; //< returned when the given id does not exist + US_ERROR_NameExists = 5; //< returned when the given name already exists + + US_ERROR_Unknown = 255; //< returned when an unknown error occured + + { return values for hook function } + US_HOOK_BREAK = High(integer); //this will break the hook chain + US_HOOK_UNHOOKME = High(integer) - 2; //this will remove the callback from the hooks chain + US_HOOK_UNHOOKME_BREAK = High(integer) - 1; //this will do both explained above + +{ this function converts an errorcode to its textual expression } +function USErrortoString(Code: LongInt): String; + +{ this funtion creates a hash for an TUS_Identifier + the hash is not guaranteed to be unique, it is just + for a fast search of an identifier } +function CalculateUSHash(Identifier: TUS_Identifier): LongInt; + +implementation + +{ this function converts an errorcode to its textual expression } +Function USErrortoString(Code: LongInt): String; +begin + Case Code of + US_Error_None: Result := 'success, no error occured'; + US_Error_VersionMismatch: Result := 'version mismatch'; + US_Error_SizeMismatch: Result := 'size mismatch'; + US_Error_WrongHandle: Result := 'handle does not exist'; + US_Error_WrongID: Result := 'id does not exist'; + US_Error_NameExists: Result := 'another item with this name does already exist'; + + Else Result := 'unknown error'; + end; +end; + +{ this funtion creates a hash for an TUS_Identifier + the hash is not guaranteed to be unique, it is just + for a fast search of an identifier } +function CalculateUSHash(Identifier: TUS_Identifier): LongInt; + var + L: Integer; + I: Integer; + + const + StartHash = -1337456101; +begin + // fill the unused chars of the identifier w/ zeros + L := Length(Identifier); + if (L < MaxLength_TUS_Identifier) then + FillChar(Identifier[L+1], MaxLength_TUS_Identifier - L, 0); + + // calculate the hash + // this is done by just adding respectively 4 bytes of the string + // to the hash (longint) + Result := StartHash; + for I := 1 to (MaxLength_TUS_Identifier div 4) do + Result := Result + LongInt(Identifier[I*4]); +end; + +end. + diff --git a/ServiceBasedPlugins/src/pluginsupport/UPluginLoader_DLL.pas b/ServiceBasedPlugins/src/pluginsupport/UPluginLoader_DLL.pas new file mode 100644 index 00000000..b143cd2a --- /dev/null +++ b/ServiceBasedPlugins/src/pluginsupport/UPluginLoader_DLL.pas @@ -0,0 +1,181 @@ +{* 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: https://ultrastardx.svn.sourceforge.net/svnroot/ultrastardx/trunk/src/base/UMain.pas $ + * $Id: UMain.pas 1629 2009-03-07 22:30:04Z k-m_schindler $ + *} + +unit UPluginLoader_DLL; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses UPluginDefines, UPlugin; + +type + TPluginLoader_DLL = class + protected + PluginDir: WideString; + public + constructor Create(PluginDir: WideString); + procedure Browse(Dir: WideString); + end; + + TPlugin_DLL = class (TPlugin) + protected + hLib: THandle; //< handle of loaded library + Lib_Proc_Init: TUS_Plugin_Proc_Init; + Lib_OnChangeStatus: TUS_Plugin_OnChangeStatus; + + procedure OnChangeStatus(Status: TUS_PluginStatus); override; + public + constructor Create(Handle: TUS_Handle; Filename: WideString); override; + destructor Destroy; override; + end; + +const + {$IF Defined(MSWINDOWS)} + DLLExt = '.dll'; + {$ELSEIF Defined(DARWIN)} + DLLExt = '.dylib'; + {$ELSEIF Defined(UNIX)} + DLLExt = '.so'; + {$IFEND} + +implementation +uses + {$IFDEF MSWINDOWS} + windows, + {$ELSE} + dynlibs, + {$ENDIF} + SysUtils, Dialogs, + UPluginManager, + UPlatform; + +{ implementation of TPluginLoader_DLL } +constructor TPluginLoader_DLL.Create(PluginDir: WideString); +begin + Self.PluginDir := PluginDir; + Browse(PluginDir); +end; + +procedure TPluginLoader_DLL.Browse(Dir: WideString); + var + Files: TDirectoryEntryArray; + I: Integer; +begin + Showmessage(Dir + ' - ' + DLLExt); + Files := Platform.DirectoryFindFiles(Dir, DLLExt, True); + + for I := 0 to High(Files) do + begin + ShowMessage(Dir + Files[I].Name); + if (Files[I].IsDirectory) then + Browse(Dir + Files[I].Name + PathDelim) + else if (Files[I].IsFile) then + PluginManager.AddPlugin(TPlugin_DLL.Create(PluginManager.GetHandle, Dir + Files[I].Name)); + end; +end; + +{ implementation of TPlugin_DLL } +constructor TPlugin_DLL.Create(Handle: TUS_Handle; Filename: WideString); +begin + inherited; + + hLib := 0; + Lib_Proc_Init := nil; + Lib_OnChangeStatus := nil; + + //try to load the library + SetStatus(psWaitingInit); +end; + +destructor TPlugin_DLL.Destroy; +begin + + inherited; +end; + +procedure TPlugin_DLL.OnChangeStatus(Status: TUS_PluginStatus); +begin + Case Status of + psWaitingInit: begin + //we have to try to load the plugin here + hLib := LoadLibrary(PChar(AnsiString(Filename))); + if (hlib <> 0) then + begin + @Lib_Proc_Init := GetProcAddress(hLib, PChar('Proc_Init')); + + If (not Assigned(Lib_Proc_Init)) then + begin + FreeLibrary(hLib); + + {$IFDEF MSWINDOWS} + SetError('Can''t export Proc_Init procedure from library. Windows reports: ' + SysErrorMessage(GetLastError)); + {$ELSE} + SetError('Can''t export Proc_Init procedure from library.'); + {$ENDIF} + Exit; + end; + + @Lib_OnChangeStatus := GetProcAddress(hLib, PChar('OnChangeStatus')); + + If (not Assigned(Lib_OnChangeStatus)) then + begin + FreeLibrary(hLib); + + {$IFDEF MSWINDOWS} + SetError('Can''t export OnChangeStatus procedure from library. Windows reports: ' + SysErrorMessage(GetLastError)); + {$ELSE} + SetError('Can''t export OnChangeStatus procedure from library.'); + {$ENDIF} + Exit; + end; + + end + else + begin + {$IFDEF MSWINDOWS} + SetError('Error loading library. Windows reports: ' + SysErrorMessage(GetLastError)); + {$ELSE} + SetError('Error loading library.'); + {$ENDIF} + Exit; + end; + + end; + + end; + + //call plugins OnChangeStatus procedure + If assigned(Lib_OnChangeStatus) then + Lib_OnChangeStatus(Self.Handle, Status); + + Self.Status := Status; +end; + +end. \ No newline at end of file diff --git a/ServiceBasedPlugins/src/pluginsupport/UPluginLoader_Included.pas b/ServiceBasedPlugins/src/pluginsupport/UPluginLoader_Included.pas new file mode 100644 index 00000000..df7b2f74 --- /dev/null +++ b/ServiceBasedPlugins/src/pluginsupport/UPluginLoader_Included.pas @@ -0,0 +1,38 @@ +{* 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: https://ultrastardx.svn.sourceforge.net/svnroot/ultrastardx/trunk/src/base/UMain.pas $ + * $Id: UMain.pas 1629 2009-03-07 22:30:04Z k-m_schindler $ + *} + +unit UPluginLoader_Included; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +implementation + +end. diff --git a/ServiceBasedPlugins/src/pluginsupport/UPluginManager.pas b/ServiceBasedPlugins/src/pluginsupport/UPluginManager.pas new file mode 100644 index 00000000..6c7f5056 --- /dev/null +++ b/ServiceBasedPlugins/src/pluginsupport/UPluginManager.pas @@ -0,0 +1,174 @@ +{* 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: https://ultrastardx.svn.sourceforge.net/svnroot/ultrastardx/trunk/src/base/UMain.pas $ + * $Id: UMain.pas 1629 2009-03-07 22:30:04Z k-m_schindler $ + *} +unit UPluginManager; + +{ this class manages all loaded plugins } + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +{$I switches.inc} + +uses Classes, UPluginDefines; + +type + TPluginManager = class + private + NextHandle: TUS_Handle; + + Plugins: TInterfaceList; + Events: TInterfaceList; + Interfaces: TInterfaceList; + + public + constructor Create; + + //returns a unique handle to use e.g. w/ a pluginloader + function GetHandle: TUS_Handle; + + //returns the plugin w/ the specified handle + function GetPluginbyHandle(Handle: TUS_Handle): IUS_Plugin; + + //just adds a plugin to the pluginlist + //it will be inited on next call of init + function AddPlugin(Plugin: IInterface): TUS_Handle; + + procedure Init; //< inits all plugins w/ status psWaitingInit + procedure DeInit; //< deinits all plugins w/ status psInited + + //called by plugins if they change to status psError + //removes all saved data and callbacks by this handle + procedure ReportError(Handle: TUS_Handle); + + destructor Destroy; + end; + +var + PluginManager: TPluginManager; + +implementation +uses SysUtils; + +constructor TPluginManager.Create; +begin + NextHandle := US_HANDLE_CORE + 1; + + Plugins := TInterfaceList.Create; + Events := TInterfaceList.Create; + Interfaces := TInterfaceList.Create; +end; + +destructor TPluginManager.Destroy; +begin + DeInit; + + Plugins.Destroy; + Events.Destroy; + Interfaces.Destroy; +end; + +// returns a unique handle to use e.g. w/ a pluginloader +function TPluginManager.GetHandle: TUS_Handle; +begin + Result := NextHandle; + Inc(NextHandle); +end; + +//returns the plugin w/ the specified handle +function TPluginManager.GetPluginbyHandle(Handle: TUS_Handle): IUS_Plugin; + var + I: integer; + Plugin: IUS_Plugin; +begin + Result := nil; + for I := 0 to Plugins.Count-1 do + begin + Plugin := IUS_Plugin(Plugins.Items[I]); + If (Plugin.GetHandle = Handle) then + begin + Result := Plugin; + Exit; + end; + end; +end; + +// just adds a plugin to the pluginlist +// it will be inited on next call of init +function TPluginManager.AddPlugin(Plugin: IInterface): TUS_Handle; +begin + If Supports(Plugin, IUS_Plugin) then + Plugins.Add(Plugin); +end; + +// inits all plugins w/ status psWaitingInit +procedure TPluginManager.Init; + var + I: integer; + Plugin: IUS_Plugin; +begin + for I := 0 to Plugins.Count-1 do + begin + Plugin := IUS_Plugin(Plugins.Items[I]); + If (Plugin.GetStatus = psWaitingInit) then + begin + Plugin.Init; + end; + end; +end; + +// deinits all plugins w/ status psInited +procedure TPluginManager.DeInit; + var + I: integer; + Plugin: IUS_Plugin; +begin + for I := 0 to Plugins.Count-1 do + begin + Plugin := IUS_Plugin(Plugins.Items[I]); + If (Plugin.GetStatus = psInited) then + begin + Plugin.DeInit; + end; + end; +end; + +//called by plugins if they change to errorstate +//removes all saved data and callbacks by this handle +procedure TPluginManager.ReportError(Handle: TUS_Handle); + var + I: integer; + Event: IUS_HookableEvent; +begin + for I := 0 to Events.Count-1 do + begin + Event := IUS_HookableEvent(Events.Items[I]); + Event.UnHookbyParent(Handle); + end; +end; + +end. \ No newline at end of file diff --git a/ServiceBasedPlugins/src/ultrastardx.dpr b/ServiceBasedPlugins/src/ultrastardx.dpr index f2896cd2..80d15e17 100644 --- a/ServiceBasedPlugins/src/ultrastardx.dpr +++ b/ServiceBasedPlugins/src/ultrastardx.dpr @@ -204,21 +204,21 @@ uses //------------------------------ //Includes - Plugin Support //------------------------------ - {UPluginDefines in 'pluginsupport\UPluginDefines.pas', - UPartyDefines in 'pluginsupport\UPartyDefines.pas', - - UPartyMode in 'pluginsupport\UPartyMode.pas', - UPartyManager in 'pluginsupport\UPartyManager.pas', - UPartyModePlugin in 'pluginsupport\UPartyModePlugin.pas', - UPluginLoader in 'pluginsupport\UPluginLoader.pas', } - - UModules in 'base\UModules.pas', //List of Modules to Load - UHooks in 'base\UHooks.pas', //Hook Managing - UServices in 'base\UServices.pas', //Service Managing - UCore in 'base\UCore.pas', //Core, Maybe remove this - UCoreModule in 'base\UCoreModule.pas', //^ - UPluginInterface in 'base\UPluginInterface.pas', //Interface offered by Core to Plugins - UPluginLoader in 'base\UPluginLoader.pas', //New Plugin Loader Module + UPluginDefines in 'pluginsupport\UPluginDefines.pas', + UPartyDefines in 'pluginsupport\UPartyDefines.pas', + + UPluginManager in 'pluginsupport\UPluginManager.pas', + UPlugin in 'pluginsupport\UPlugin.pas', + UPluginLoader_DLL in 'pluginsupport\UPluginLoader_DLL.pas', + UPluginLoader_Included in 'pluginsupport\UPluginLoader_Included.pas', + + //UModules in 'base\UModules.pas', //List of Modules to Load + //UHooks in 'base\UHooks.pas', //Hook Managing + //UServices in 'base\UServices.pas', //Service Managing + //UCore in 'base\UCore.pas', //Core, Maybe remove this + //UCoreModule in 'base\UCoreModule.pas', //^ + //UPluginInterface in 'base\UPluginInterface.pas', //Interface offered by Core to Plugins + //UPluginLoader in 'base\UPluginLoader.pas', //New Plugin Loader Module UParty in 'base\UParty.pas', // TODO: rewrite Party Manager as Module, reomplent ability to offer party Mody by Plugin @@ -331,8 +331,8 @@ uses //Includes - Modi SDK //------------------------------ ModiSDK in '..\plugins\SDK\ModiSDK.pas', //Old SDK, will be deleted soon - UPluginDefs in '..\plugins\SDK\UPluginDefs.pas', //New SDK, not only Modis - UPartyDefs in '..\plugins\SDK\UPartyDefs.pas', //Headers to register Party Modes + //UPluginDefs in '..\plugins\SDK\UPluginDefs.pas', //New SDK, not only Modis + //UPartyDefs in '..\plugins\SDK\UPartyDefs.pas', //Headers to register Party Modes SysUtils; -- cgit v1.2.3