395 lines
11 KiB
C++
395 lines
11 KiB
C++
|
// -----------------------------------------------------------------------------
|
|||
|
// This file is part of Broken Sword 2.5
|
|||
|
// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsd<73>rfer
|
|||
|
//
|
|||
|
// Broken Sword 2.5 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.
|
|||
|
//
|
|||
|
// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software
|
|||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
// -----------------------------------------------------------------------------
|
|||
|
|
|||
|
#define WIN32_LEAN_AND_MEAN
|
|||
|
#define NOMINMAX
|
|||
|
#include <windows.h>
|
|||
|
#include <psapi.h>
|
|||
|
#pragma comment(lib, "psapi.lib")
|
|||
|
|
|||
|
#include <math.h>
|
|||
|
#include <algorithm>
|
|||
|
|
|||
|
#include "kernel.h"
|
|||
|
#include "timer.h"
|
|||
|
#include "service_ids.h"
|
|||
|
|
|||
|
#include "gfx/graphicengine.h"
|
|||
|
#include "sfx/soundengine.h"
|
|||
|
#include "input/inputengine.h"
|
|||
|
#include "package/packagemanager.h"
|
|||
|
#include "script/script.h"
|
|||
|
#include "fmv/movieplayer.h"
|
|||
|
#include "persistenceservice.h"
|
|||
|
|
|||
|
#define BS_LOG_PREFIX "KERNEL"
|
|||
|
|
|||
|
BS_Kernel * BS_Kernel::_Instance = 0;
|
|||
|
|
|||
|
// Konstruktion / Destruktion
|
|||
|
// --------------------------
|
|||
|
BS_Kernel::BS_Kernel() :
|
|||
|
_pWindow(NULL),
|
|||
|
_Running(false),
|
|||
|
_pResourceManager(NULL),
|
|||
|
_InitSuccess(false)
|
|||
|
{
|
|||
|
// TODO:
|
|||
|
// Messagebox ausgeben wenn nicht gelogged werden kann -> log.txt schreibgesch<63>tzt
|
|||
|
BS_LOGLN("created.");
|
|||
|
|
|||
|
// Feststellen, ob der Timer unterst<73>tzt wird.
|
|||
|
if (!BS_Timer::IsTimerAvaliable())
|
|||
|
{
|
|||
|
BS_LOG_ERRORLN("This machine doesn't support a performance counter.");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Die BS_SERVICE_TABLE auslesen und kernelinterne Strukturen vorbereiten
|
|||
|
for (unsigned int i = 0; i < BS_SERVICE_COUNT; i++)
|
|||
|
{
|
|||
|
// Ist die Superclass schon registriert?
|
|||
|
Superclass* pCurSuperclass = NULL;
|
|||
|
std::vector<Superclass*>::iterator Iter;
|
|||
|
for (Iter = _SuperclassList.begin(); Iter != _SuperclassList.end(); ++Iter)
|
|||
|
if ((*Iter)->GetIdentifier() == BS_SERVICE_TABLE[i].SuperclassIdentifier)
|
|||
|
{
|
|||
|
pCurSuperclass = *Iter;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
// Falls die Superclass noch nicht registriert war, wird dies jetzt gemacht
|
|||
|
if (!pCurSuperclass)
|
|||
|
_SuperclassList.push_back(new Superclass(this, BS_SERVICE_TABLE[i].SuperclassIdentifier));
|
|||
|
}
|
|||
|
|
|||
|
// Fensterobjekt erstellen
|
|||
|
_pWindow = BS_Window::CreateBSWindow(0,0,0,0,false);
|
|||
|
if (!_pWindow)
|
|||
|
{
|
|||
|
BS_LOG_ERRORLN("Failed to create the window.");
|
|||
|
}
|
|||
|
else
|
|||
|
BS_LOGLN("Window created.");
|
|||
|
|
|||
|
// Resource-Manager erstellen
|
|||
|
_pResourceManager = new BS_ResourceManager(this);
|
|||
|
|
|||
|
// Random-Number-Generator initialisieren
|
|||
|
srand(GetMilliTicks());
|
|||
|
|
|||
|
// Die Skriptengine initialisieren
|
|||
|
// Die Skriptengine muss bereits von Kernel und nicht vom Benutzer gestartet werden, damit der Kernel seine Funktionen bei seiner Erzeugung
|
|||
|
// registrieren kann.
|
|||
|
BS_ScriptEngine * pScript = static_cast<BS_ScriptEngine *>(NewService("script", "lua"));
|
|||
|
if (!pScript || !pScript->Init())
|
|||
|
{
|
|||
|
_InitSuccess = false;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Scriptbindings des Kernels registrieren
|
|||
|
if (!_RegisterScriptBindings())
|
|||
|
{
|
|||
|
BS_LOG_ERRORLN("Script bindings could not be registered.");
|
|||
|
_InitSuccess = false;
|
|||
|
return;
|
|||
|
}
|
|||
|
BS_LOGLN("Script bindings registered.");
|
|||
|
|
|||
|
_InitSuccess = true;
|
|||
|
}
|
|||
|
|
|||
|
BS_Kernel::~BS_Kernel()
|
|||
|
{
|
|||
|
// Services in umgekehrter Reihenfolge der Erstellung endladen.
|
|||
|
while (!_ServiceCreationOrder.empty())
|
|||
|
{
|
|||
|
Superclass * superclass = GetSuperclassByIdentifier(_ServiceCreationOrder.top());
|
|||
|
if (superclass) superclass->DisconnectService();
|
|||
|
_ServiceCreationOrder.pop();
|
|||
|
}
|
|||
|
|
|||
|
// Superclasslist leeren
|
|||
|
while (_SuperclassList.size())
|
|||
|
{
|
|||
|
delete _SuperclassList.back();
|
|||
|
_SuperclassList.pop_back();
|
|||
|
}
|
|||
|
|
|||
|
// Fensterobjekt freigeben
|
|||
|
delete _pWindow;
|
|||
|
BS_LOGLN("Window destroyed.");
|
|||
|
|
|||
|
// Resource-Manager freigeben
|
|||
|
delete _pResourceManager;
|
|||
|
|
|||
|
BS_LOGLN("destroyed.");
|
|||
|
}
|
|||
|
|
|||
|
// Service Methoden
|
|||
|
// ----------------
|
|||
|
BS_Kernel::Superclass::Superclass (BS_Kernel* pKernel, const std::string& Identifier) :
|
|||
|
_pKernel(pKernel),
|
|||
|
_Identifier(Identifier),
|
|||
|
_ServiceCount(0),
|
|||
|
_ActiveService(NULL)
|
|||
|
{
|
|||
|
for (unsigned int i = 0; i < BS_SERVICE_COUNT; i++)
|
|||
|
if (BS_SERVICE_TABLE[i].SuperclassIdentifier == _Identifier)
|
|||
|
_ServiceCount++;
|
|||
|
}
|
|||
|
|
|||
|
BS_Kernel::Superclass::~Superclass()
|
|||
|
{
|
|||
|
DisconnectService();
|
|||
|
}
|
|||
|
|
|||
|
std::string BS_Kernel::Superclass::GetServiceIdentifier(unsigned int Number)
|
|||
|
{
|
|||
|
if (Number > _ServiceCount) return NULL;
|
|||
|
|
|||
|
unsigned int CurServiceOrd = 0;
|
|||
|
for (unsigned int i = 0; i < BS_SERVICE_COUNT; i++)
|
|||
|
{
|
|||
|
if (BS_SERVICE_TABLE[i].SuperclassIdentifier == _Identifier)
|
|||
|
if (Number == CurServiceOrd)
|
|||
|
return BS_SERVICE_TABLE[i].ServiceIdentifier;
|
|||
|
else
|
|||
|
CurServiceOrd++;
|
|||
|
}
|
|||
|
|
|||
|
return std::string("");
|
|||
|
}
|
|||
|
|
|||
|
BS_Service* BS_Kernel::Superclass::NewService(const std::string& ServiceIdentifier)
|
|||
|
{
|
|||
|
for (unsigned int i = 0; i < BS_SERVICE_COUNT; i++)
|
|||
|
if (BS_SERVICE_TABLE[i].SuperclassIdentifier == _Identifier &&
|
|||
|
BS_SERVICE_TABLE[i].ServiceIdentifier == ServiceIdentifier)
|
|||
|
{
|
|||
|
BS_Service* NewService = BS_SERVICE_TABLE[i].CreateMethod(_pKernel);
|
|||
|
|
|||
|
if (NewService)
|
|||
|
{
|
|||
|
DisconnectService();
|
|||
|
BS_LOGLN("Service '%s' created from superclass '%s'.", ServiceIdentifier.c_str(), _Identifier.c_str());
|
|||
|
_ActiveService = NewService;
|
|||
|
_ActiveServiceName = BS_SERVICE_TABLE[i].ServiceIdentifier;
|
|||
|
return _ActiveService;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
BS_LOG_ERRORLN("Failed to create service '%s' from superclass '%s'.", ServiceIdentifier.c_str(), _Identifier.c_str());
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
BS_LOG_ERRORLN("Service '%s' is not avaliable from superclass '%s'.", ServiceIdentifier.c_str(), _Identifier.c_str());
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
bool BS_Kernel::Superclass::DisconnectService()
|
|||
|
{
|
|||
|
if (_ActiveService)
|
|||
|
{
|
|||
|
delete _ActiveService;
|
|||
|
_ActiveService = 0;
|
|||
|
BS_LOGLN("Active service '%s' disconnected from superclass '%s'.", _ActiveServiceName.c_str(), _Identifier.c_str());
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
BS_Kernel::Superclass* BS_Kernel::GetSuperclassByIdentifier(const std::string & Identifier)
|
|||
|
{
|
|||
|
std::vector<Superclass*>::iterator Iter;
|
|||
|
for (Iter = _SuperclassList.begin(); Iter != _SuperclassList.end(); ++Iter)
|
|||
|
{
|
|||
|
if ((*Iter)->GetIdentifier() == Identifier)
|
|||
|
return *Iter;
|
|||
|
}
|
|||
|
|
|||
|
// BS_LOG_ERRORLN("Superclass '%s' does not exist.", Identifier.c_str());
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
unsigned int BS_Kernel::GetSuperclassCount()
|
|||
|
{
|
|||
|
return _SuperclassList.size();
|
|||
|
}
|
|||
|
|
|||
|
std::string BS_Kernel::GetSuperclassIdentifier(unsigned int Number)
|
|||
|
{
|
|||
|
if (Number > _SuperclassList.size()) return NULL;
|
|||
|
|
|||
|
unsigned int CurSuperclassOrd = 0;
|
|||
|
std::vector<Superclass*>::iterator Iter;
|
|||
|
for (Iter = _SuperclassList.begin(); Iter != _SuperclassList.end(); ++Iter)
|
|||
|
{
|
|||
|
if (CurSuperclassOrd == Number)
|
|||
|
return ((*Iter)->GetIdentifier());
|
|||
|
|
|||
|
CurSuperclassOrd++;
|
|||
|
}
|
|||
|
|
|||
|
return std::string("");
|
|||
|
}
|
|||
|
|
|||
|
unsigned int BS_Kernel::GetServiceCount(const std::string & SuperclassIdentifier)
|
|||
|
{
|
|||
|
Superclass* pSuperclass;
|
|||
|
if (!(pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier))) return 0;
|
|||
|
|
|||
|
return pSuperclass->GetServiceCount();
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
std::string BS_Kernel::GetServiceIdentifier(const std::string & SuperclassIdentifier, unsigned int Number)
|
|||
|
{
|
|||
|
Superclass* pSuperclass;
|
|||
|
if (!(pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier))) return NULL;
|
|||
|
|
|||
|
return (pSuperclass->GetServiceIdentifier(Number));
|
|||
|
}
|
|||
|
|
|||
|
BS_Service* BS_Kernel::NewService(const std::string& SuperclassIdentifier, const std::string& ServiceIdentifier)
|
|||
|
{
|
|||
|
Superclass* pSuperclass;
|
|||
|
if (!(pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier))) return NULL;
|
|||
|
|
|||
|
// Die Reihenfolge merken, in der Services erstellt werden, damit sie sp<73>ter in umgekehrter Reihenfolge entladen werden k<>nnen.
|
|||
|
_ServiceCreationOrder.push(SuperclassIdentifier);
|
|||
|
|
|||
|
return pSuperclass->NewService(ServiceIdentifier);
|
|||
|
}
|
|||
|
|
|||
|
bool BS_Kernel::DisconnectService(const std::string& SuperclassIdentifier)
|
|||
|
{
|
|||
|
Superclass* pSuperclass;
|
|||
|
if (!(pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier))) return false;
|
|||
|
|
|||
|
return pSuperclass->DisconnectService();
|
|||
|
}
|
|||
|
|
|||
|
BS_Service* BS_Kernel::GetService(const std::string& SuperclassIdentifier)
|
|||
|
{
|
|||
|
Superclass* pSuperclass;
|
|||
|
if (!(pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier))) return NULL;
|
|||
|
|
|||
|
return (pSuperclass->GetActiveService());
|
|||
|
}
|
|||
|
|
|||
|
std::string BS_Kernel::GetActiveServiceIdentifier(const std::string& SuperclassIdentifier)
|
|||
|
{
|
|||
|
Superclass * pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier);
|
|||
|
if (!pSuperclass) return std::string("");
|
|||
|
|
|||
|
return (pSuperclass->GetActiveServiceName());
|
|||
|
}
|
|||
|
|
|||
|
// -----------------------------------------------------------------------------
|
|||
|
|
|||
|
int BS_Kernel::GetRandomNumber(int Min, int Max)
|
|||
|
{
|
|||
|
BS_ASSERT(Min <= Max);
|
|||
|
unsigned int MaxInternal = (Min - Max + 1) < 0 ? - (Min - Max + 1) : (Min - Max + 1);
|
|||
|
return (rand() % MaxInternal) + Min;
|
|||
|
}
|
|||
|
|
|||
|
// Timer Methoden
|
|||
|
// --------------
|
|||
|
unsigned int BS_Kernel::GetMilliTicks()
|
|||
|
{
|
|||
|
return BS_Timer::GetMilliTicks();
|
|||
|
}
|
|||
|
|
|||
|
uint64_t BS_Kernel::GetMicroTicks()
|
|||
|
{
|
|||
|
return BS_Timer::GetMicroTicks();
|
|||
|
}
|
|||
|
|
|||
|
// Sonstige Methoden
|
|||
|
// -----------------
|
|||
|
|
|||
|
size_t BS_Kernel::GetUsedMemory()
|
|||
|
{
|
|||
|
PROCESS_MEMORY_COUNTERS pmc;
|
|||
|
pmc.cb = sizeof(pmc);
|
|||
|
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
|
|||
|
{
|
|||
|
return pmc.WorkingSetSize;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
BS_LOG_ERRORLN("Call to GetProcessMemoryInfo() failed. Error code: %d", GetLastError());
|
|||
|
return 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// -----------------------------------------------------------------------------
|
|||
|
|
|||
|
BS_GraphicEngine * BS_Kernel::GetGfx()
|
|||
|
{
|
|||
|
return static_cast<BS_GraphicEngine *>(GetService("gfx"));
|
|||
|
}
|
|||
|
|
|||
|
// -----------------------------------------------------------------------------
|
|||
|
|
|||
|
BS_SoundEngine * BS_Kernel::GetSfx()
|
|||
|
{
|
|||
|
return static_cast<BS_SoundEngine *>(GetService("sfx"));
|
|||
|
}
|
|||
|
|
|||
|
// -----------------------------------------------------------------------------
|
|||
|
|
|||
|
BS_InputEngine * BS_Kernel::GetInput()
|
|||
|
{
|
|||
|
return static_cast<BS_InputEngine *>(GetService("input"));
|
|||
|
}
|
|||
|
|
|||
|
// -----------------------------------------------------------------------------
|
|||
|
|
|||
|
BS_PackageManager * BS_Kernel::GetPackage()
|
|||
|
{
|
|||
|
return static_cast<BS_PackageManager *>(GetService("package"));
|
|||
|
}
|
|||
|
|
|||
|
// -----------------------------------------------------------------------------
|
|||
|
|
|||
|
BS_ScriptEngine * BS_Kernel::GetScript()
|
|||
|
{
|
|||
|
return static_cast<BS_ScriptEngine *>(GetService("script"));
|
|||
|
}
|
|||
|
|
|||
|
// -----------------------------------------------------------------------------
|
|||
|
|
|||
|
BS_MoviePlayer * BS_Kernel::GetFMV()
|
|||
|
{
|
|||
|
return static_cast<BS_MoviePlayer *>(GetService("fmv"));
|
|||
|
}
|
|||
|
|
|||
|
// -----------------------------------------------------------------------------
|
|||
|
|
|||
|
void BS_Kernel::Sleep(unsigned int Msecs) const
|
|||
|
{
|
|||
|
::Sleep(Msecs);
|
|||
|
}
|