unit UCore;
interface
{$IFDEF FPC}
{$MODE Delphi}
{$ENDIF}
{$I switches.inc}
uses uPluginDefs,
uCoreModule,
UHooks,
UServices,
UModules;
{*********************
TCore
Class manages all CoreModules, teh StartUp, teh MainLoop and the shutdown process
Also it does some Error Handling, and maybe sometime multithreaded Loading ;)
*********************}
type
TModuleListItem = record
Module: TCoreModule; //Instance of the Modules Class
Info: TModuleInfo; //ModuleInfo returned by Modules Modulinfo Proc
NeedsDeInit: Boolean; //True if Module was succesful inited
end;
TCore = class
private
//Some Hook Handles. See Plugin SDKs Hooks.txt for Infos
hLoadingFinished: THandle;
hMainLoop: THandle;
hTranslate: THandle;
hLoadTextures: THandle;
hExitQuery: THandle;
hExit: THandle;
hDebug: THandle;
hError: THandle;
sReportError: THandle;
sReportDebug: THandle;
sShowMessage: THandle;
sRetranslate: THandle;
sReloadTextures: THandle;
sGetModuleInfo: THandle;
sGetApplicationHandle: THandle;
Modules: Array [0..High(CORE_MODULES_TO_LOAD)] of TModuleListItem;
//Cur + Last Executed Setting and Getting ;)
iCurExecuted: Integer;
iLastExecuted: Integer;
Procedure SetCurExecuted(Value: Integer);
//Function Get all Modules and Creates them
Function GetModules: Boolean;
//Loads Core and all Modules
Function Load: Boolean;
//Inits Core and all Modules
Function Init: Boolean;
//DeInits Core and all Modules
Function DeInit: Boolean;
//Load the Core
Function LoadCore: Boolean;
//Init the Core
Function InitCore: Boolean;
//DeInit the Core
Function DeInitCore: Boolean;
//Called one Time per Frame
Function MainLoop: Boolean;
public
Hooks: THookManager; //Teh Hook Manager ;)
Services: TServiceManager;//The Service Manager
Name: String; //Name of this Application
Version: LongWord; //Version of this ". For Info Look PluginDefs Functions
LastErrorReporter:String; //Who Reported the Last Error String
LastErrorString: String; //Last Error String reported
property CurExecuted: Integer read iCurExecuted write SetCurExecuted; //ID of Plugin or Module curently Executed
property LastExecuted: Integer read iLastExecuted;
//---------------
//Main Methods to control the Core:
//---------------
Constructor Create(const cName: String; const cVersion: LongWord);
//Starts Loading and Init Process. Then Runs MainLoop. DeInits on Shutdown
Procedure Run;
//Method for other Classes to get Pointer to a specific Module
Function GetModulebyName(const Name: String): PCoreModule;
//--------------
// Hook and Service Procs:
//--------------
Function ShowMessage(wParam: TwParam; lParam: TlParam): integer; //Shows a Message (lParam: PChar Text, wParam: Symbol)
Function ReportError(wParam: TwParam; lParam: TlParam): integer; //Shows a Message (wParam: Pchar(Message), lParam: PChar(Reportername))
Function ReportDebug(wParam: TwParam; lParam: TlParam): integer; //Shows a Message (wParam: Pchar(Message), lParam: PChar(Reportername))
Function Retranslate(wParam: TwParam; lParam: TlParam): integer; //Calls Translate hook
Function ReloadTextures(wParam: TwParam; lParam: TlParam): integer; //Calls LoadTextures hook
Function GetModuleInfo(wParam: TwParam; lParam: TlParam): integer; //If lParam = nil then get length of Moduleinfo Array. If lparam <> nil then write array of TModuleInfo to address at lparam
Function GetApplicationHandle(wParam: TwParam; lParam: TlParam): integer; //Returns Application Handle
end;
var
Core: TCore;
implementation
uses {$IFDEF win32}
Windows,
{$ENDIF}
SysUtils;
//-------------
// Create - Creates Class + Hook and Service Manager
//-------------
Constructor TCore.Create(const cName: String; const cVersion: LongWord);
begin
inherited Create;
Name := cName;
Version := cVersion;
iLastExecuted := 0;
iCurExecuted := 0;
LastErrorReporter := '';
LastErrorString := '';
Hooks := THookManager.Create(50);
Services := TServiceManager.Create;
end;
//-------------
//Starts Loading and Init Process. Then Runs MainLoop. DeInits on Shutdown
//-------------
Procedure TCore.Run;
var
noError: Boolean;
begin
//Get Modules
Try
noError := GetModules;
Except
noError := False;
end;
//Loading
if (noError) then
begin
Try
noError := Load;
Except
noError := False;
end;
if (noError) then
begin //Init
Try
noError := Init;
Except
noError := False;
end;
If noError then
begin
//Call Translate Hook
noError := (Hooks.CallEventChain(hTranslate, 0, nil) = 0);
If noError then
begin //Calls LoadTextures Hook
noError := (Hooks.CallEventChain(hLoadTextures, 0, nil) = 0);
if noError then
begin //Calls Loading Finished Hook
noError := (Hooks.CallEventChain(hLoadingFinished, 0, nil) = 0);
If noError then
begin
//Start MainLoop
While noError do
begin
noError := MainLoop;
// to-do : Call Display Draw here
end;
end
else
begin
If (LastErrorString <> '') then
Self.ShowMessage(CORE_SM_ERROR, PChar('Error calling LoadingFinished Hook: ' + LastErrorString))
else
Self.ShowMessage(CORE_SM_ERROR, PChar('Error calling LoadingFinished Hook'));
end;
end
else
begin
If (LastErrorString <> '') then
Self.ShowMessage(CORE_SM_ERROR, PChar('Error loading textures: ' + LastErrorString))
else
Self.ShowMessage(CORE_SM_ERROR, PChar('Error loading textures'));
end;
end
else
begin
If (LastErrorString <> '') then
Self.ShowMessage(CORE_SM_ERROR, PChar('Error translating: ' + LastErrorString))
else
Self.ShowMessage(CORE_SM_ERROR, PChar('Error translating'));
end;
end
else
begin
If (LastErrorString <> '') then
Self.ShowMessage(CORE_SM_ERROR, PChar('Error initing Modules: ' + LastErrorString))
else
Self.ShowMessage(CORE_SM_ERROR, PChar('Error initing Modules'));
end;
end
else
begin
If (LastErrorString <> '') then
Self.ShowMessage(CORE_SM_ERROR, PChar('Error loading Modules: ' + LastErrorString))
else
Self.ShowMessage(CORE_SM_ERROR, PChar('Error loading Modules'));
end;
end
else
begin
If (LastErrorString <> '') then
Self.ShowMessage(CORE_SM_ERROR, PChar('Error Getting Modules: ' + LastErrorString))
else
Self.ShowMessage(CORE_SM_ERROR, PChar('Error Getting Modules'));
end;
//DeInit
DeInit;
end;
//-------------
//Called one Time per Frame
//-------------
Function TCore.MainLoop: Boolean;
begin
Result := False;
end;
//-------------
//Function Get all Modules and Creates them
//-------------
Function TCore.GetModules: Boolean;
var
I: Integer;
begin
Result := False;
for I := 0 to high(Modules) do
begin
try
Modules[I].NeedsDeInit := False;
Modules[I].Module := CORE_MODULES_TO_LOAD[I].Create;
Modules[I].Module.Info(@Modules[I].Info);
except
ReportError(Integer(PChar('Can''t get module #' + InttoStr(I) + ' "' + Modules[I].Info.Name + '"')), PChar('Core'));
Exit;
end;
end;
Result := True;
end;
//-------------
//Loads Core and all Modules
//-------------
Function TCore.Load: Boolean;
var
I: Integer;
begin
Result := LoadCore;
I := 0;
While ((Result = True) AND (I <= High(CORE_MODULES_TO_LOAD))) do
begin
try
Result := Modules[I].Module.Load;
except
Result := False;
ReportError(Integer(PChar('Error loading module #' + InttoStr(I) + ' "' + Modules[I].Info.Name + '"')), PChar('Core'));
end;
Inc(I);
end;
end;
//-------------
//Inits Core and all Modules
//-------------
Function TCore.Init: Boolean;
var
I: Integer;
begin
Result := InitCore;
I := 0;
While ((Result = True) AND (I <= High(CORE_MODULES_TO_LOAD))) do
begin
try
Result := Modules[I].Module.Init;
except
Result := False;
ReportError(Integer(PChar('Error initing module #' + InttoStr(I) + ' "' + Modules[I].Info.Name + '"')), PChar('Core'));
end;
Modules[I].NeedsDeInit := Result;
Inc(I);
end;
end;
//-------------
//DeInits Core and all Modules
//-------------
Function TCore.DeInit: boolean;
var
i: integer;
begin
for i := High(CORE_MODULES_TO_LOAD) downto 0 do
try
if (Modules[i].NeedsDeInit) then
Modules[i].Module.DeInit;
except
end;
end;
DeInitCore;
Result := true;
end;
//-------------
//Load the Core
//-------------
Function TCore.LoadCore: Boolean;
begin
hLoadingFinished := Hooks.AddEvent('Core/LoadingFinished');
hMainLoop := Hooks.AddEvent('Core/MainLoop');
hTranslate := Hooks.AddEvent('Core/Translate');
hLoadTextures := Hooks.AddEvent('Core/LoadTextures');
hExitQuery := Hooks.AddEvent('Core/ExitQuery');
hExit := Hooks.AddEvent('Core/Exit');
hDebug := Hooks.AddEvent('Core/NewDebugInfo');
hError := Hooks.AddEvent('Core/NewError');
sReportError := Services.AddService('Core/ReportError', nil, Self.ReportError);
sReportDebug := Services.AddService('Core/ReportDebug', nil, Self.ReportDebug);
sShowMessage := Services.AddService('Core/ShowMessage', nil, Self.ShowMessage);
sRetranslate := Services.AddService('Core/Retranslate', nil, Self.Retranslate);
sReloadTextures := Services.AddService('Core/ReloadTextures', nil, Self.ReloadTextures);
sGetModuleInfo := Services.AddService('Core/GetModuleInfo', nil, Self.GetModuleInfo);
sGetApplicationHandle := Services.AddService('Core/GetApplicationHandle', nil, Self.GetApplicationHandle);
//A little Test
Hooks.AddSubscriber('Core/NewError', HookTest);
result := true;
end;
//-------------
//Init the Core
//-------------
Function TCore.InitCore: Boolean;
begin
//Dont Init s.th. atm.
result := true;
end;
//-------------
//DeInit the Core
//-------------
Function TCore.DeInitCore: Boolean;
begin
// to-do : write TService-/HookManager.Free and call it here
Result := true;
end;
//-------------
//Method for other Classes to get Pointer to a specific Module
//-------------
Function TCore.GetModulebyName(const Name: String): PCoreModule;
var I: Integer;
begin
Result := nil;
For I := 0 to high(Modules) do
If (Modules[I].Info.Name = Name) then
begin
Result := @Modules[I].Module;
Break;
end;
end;
//-------------
// Shows a MessageDialog (lParam: PChar Text, wParam: Symbol)
//-------------
Function TCore.ShowMessage(wParam: TwParam; lParam: TlParam): integer;
{$IFDEF MSWINDOWS}
var Params: Cardinal; // Auto Removed, Unused Variable
{$ENDIF}
begin
Result := -1;
{$IFDEF MSWINDOWS}
If (lParam<>nil) then
begin
Params := MB_OK;
Case wParam of
CORE_SM_ERROR: Params := Params or MB_ICONERROR;
CORE_SM_WARNING: Params := Params or MB_ICONWARNING;
CORE_SM_INFO: Params := Params or MB_ICONINFORMATION;
end;
//Show:
Result := Messagebox(0, lParam, PChar(Name), Params);
end;
{$ENDIF}
// to-do : write ShowMessage for other OSes
end;
//-------------
// Calls NewError HookChain (wParam: Pchar(Message), lParam: PChar(Reportername))
//-------------
Function TCore.ReportError(wParam: TwParam; lParam: TlParam): integer;
begin
//Update LastErrorReporter and LastErrorString
LastErrorReporter := String(PChar(lParam));
LastErrorString := String(PChar(Pointer(wParam)));
Hooks.CallEventChain(hError, wParam, lParam);
end;
//-------------
// Calls NewDebugInfo HookChain (wParam: Pchar(Message), lParam: PChar(Reportername))
//-------------
Function TCore.ReportDebug(wParam: TwParam; lParam: TlParam): integer;
begin
Hooks.CallEventChain(hDebug, wParam, lParam);
end;
//-------------
// Calls Translate hook
//-------------
Function TCore.Retranslate(wParam: TwParam; lParam: TlParam): integer;
begin
Hooks.CallEventChain(hTranslate, 1, nil);
end;
//-------------
// Calls LoadTextures hook
//-------------
Function TCore.ReloadTextures(wParam: TwParam; lParam: TlParam): integer;
begin
Hooks.CallEventChain(hLoadTextures, 1, nil);
end;
//-------------
// If lParam = nil then get length of Moduleinfo Array. If lparam <> nil then write array of TModuleInfo to address at lparam
//-------------
Function TCore.GetModuleInfo(wParam: TwParam; lParam: TlParam): integer;
begin
if (Pointer(lParam) = nil) then
begin
Result := Length(Modules);
end
else
begin
Try
For Result := 0 to High(Modules) do
begin
AModuleInfo(Pointer(lParam))[Result].Name := Modules[Result].Info.Name;
AModuleInfo(Pointer(lParam))[Result].Version := Modules[Result].Info.Version;
AModuleInfo(Pointer(lParam))[Result].Description := Modules[Result].Info.Description;
end;
Except
Result := -1;
end;
end;
end;
//-------------
// Returns Application Handle
//-------------
Function TCore.GetApplicationHandle(wParam: TwParam; lParam: TlParam): integer;
begin
Result := hInstance;
end;
//-------------
// Called when setting CurExecuted
//-------------
Procedure TCore.SetCurExecuted(Value: Integer);
begin
//Set Last Executed
iLastExecuted := iCurExecuted;
//Set Cur Executed
iCurExecuted := Value;
end;
end.