aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO.md12
-rw-r--r--reference/game.c1875
-rw-r--r--reference/types.hh45
-rw-r--r--src/containers.hh8
-rw-r--r--src/cr.hh18
-rw-r--r--src/crmain.cc2
-rw-r--r--src/crplayer.cc903
-rw-r--r--src/main.cc32
-rw-r--r--src/map.cc2
-rw-r--r--src/operate.cc2
-rw-r--r--src/query.cc3
-rw-r--r--src/query.hh43
-rw-r--r--src/stubs.hh7
-rw-r--r--src/thread.cc48
-rw-r--r--src/thread.hh2
15 files changed, 1052 insertions, 1950 deletions
diff --git a/TODO.md b/TODO.md
index 51efb7f..ecfef37 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,16 +1,15 @@
## TODO NEXT
-- OPERATE.CC
-- HOUSES.CC
- CRPLAYER.CC
+- QUERY.CC
+- COMMUNICATION.CC
+- HOUSES.CC
- CRNONPL.CC
- MOVEUSE.CC
- SENDING.CC
- RECEIVING.CC
- CONNECTIONS.CC
-- COMMUNICATION.CC
- READER.CC
- WRITER.CC
-- QUERY.CC
- DBFUNCS.CC
## Stack allocations
@@ -19,6 +18,11 @@ Any functions that use `alloca` or some other form of dynamic stack allocations
## Exceptions
I didn't dive into how exceptions are handled, but it seems that the ones related to creature actions have the outter most endpoint at `TCreature::Execute`. There can also be some checkpoints in between to modify a `RESULT` value or handle a failure.
+## Synchronization
+I'm not sure whether synchronization is done properly. The implementation of the first few `crplayer.cc` functions left me with a taste of race conditions although integer loads on x86 are generally atomic.
+
+I'm also under the impression that `getpid()` is used for retrieving the current thread id, so we'll have to wait and see how things unfold outside the main thread.
+
## Estimate
The decompiled file has ~115K lines of C. If we take ~15K lines to be rubbish, this can be round to ~100K. Considering a low estimate of 200 lines per day, the whole process could take up to 500 days which is quite a bit but not impossible. Now considering a high estimate of 1K lines per day, it could take 100 days which is also quite a bit.
diff --git a/reference/game.c b/reference/game.c
index 8baf67a..2b04018 100644
--- a/reference/game.c
+++ b/reference/game.c
@@ -8888,311 +8888,6 @@ void _GLOBAL__I_HouseArea(void)
return;
}
-void * ThreadStarter(void *Pointer)
-
-{
- char cVar1;
- code *pcVar2;
- undefined4 *__retval;
- undefined4 uVar3;
- bool Detach;
- void *Argument;
- undefined1 *Function;
-
- // WARNING: Load size is inaccurate
- pcVar2 = *Pointer;
- uVar3 = *(undefined4 *)((int)Pointer + 4);
- cVar1 = *(char *)((int)Pointer + 8);
- operator_delete(Pointer);
- if (cVar1 == '\0') {
- __retval = (undefined4 *)operator_new(4);
- uVar3 = (*pcVar2)(uVar3);
- *__retval = uVar3;
- }
- else {
- (*pcVar2)(uVar3);
- __retval = (undefined4 *)0x0;
- }
- // WARNING: Subroutine does not return
- pthread_exit(__retval);
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: thread
-
-Thread StartThread(undefined1 *Function,void *Argument,bool Detach)
-
-{
- TThreadStarter *Starter;
- undefined4 *__arg;
- int iVar1;
- Thread TStack_c;
- bool Detach_local;
- pthread_t thread;
-
- __arg = (undefined4 *)operator_new(0xc);
- *__arg = Function;
- *(bool *)(__arg + 2) = Detach;
- __arg[1] = Argument;
- iVar1 = pthread_create(&stack0xfffffff4,(pthread_attr_t *)0x0,ThreadStarter,__arg);
- if (iVar1 == 0) {
- if (Detach) {
- pthread_detach(TStack_c);
- }
- }
- else {
- error("StartThread: Kann Thread nicht anlegen; Fehlercode %d.\n",iVar1);
- TStack_c = 0;
- }
- return TStack_c;
-}
-
-
-
-Thread StartThread(undefined1 *Function,void *Argument,size_t StackSize,bool Detach)
-
-{
- undefined4 *__arg;
- int iVar1;
- TThreadStarter *Starter;
- Thread TStack_40;
- bool Detach_local;
- pthread_t thread;
- pthread_attr_t Attributes;
-
- __arg = (undefined4 *)operator_new(0xc);
- *__arg = Function;
- *(bool *)(__arg + 2) = Detach;
- __arg[1] = Argument;
- pthread_attr_init((pthread_attr_t *)&thread);
- pthread_attr_setstacksize((pthread_attr_t *)&thread,StackSize);
- iVar1 = pthread_create(&stack0xffffffc0,(pthread_attr_t *)&thread,ThreadStarter,__arg);
- pthread_attr_destroy((pthread_attr_t *)&thread);
- if (iVar1 == 0) {
- if (Detach) {
- pthread_detach(TStack_40);
- }
- }
- else {
- error("StartThread: Kann Thread nicht anlegen; Fehlercode %d.\n",iVar1);
- TStack_40 = 0;
- }
- return TStack_40;
-}
-
-
-
-Thread StartThread(undefined1 *Function,void *Argument,void *Stack,size_t StackSize,bool Detach)
-
-{
- undefined4 *__arg;
- int iVar1;
- TThreadStarter *Starter;
- Thread TStack_40;
- bool Detach_local;
- pthread_t thread;
- pthread_attr_t Attributes;
-
- __arg = (undefined4 *)operator_new(0xc);
- *__arg = Function;
- *(bool *)(__arg + 2) = Detach;
- __arg[1] = Argument;
- pthread_attr_init((pthread_attr_t *)&thread);
- pthread_attr_setstack((pthread_attr_t *)&thread,Stack,StackSize);
- iVar1 = pthread_create(&stack0xffffffc0,(pthread_attr_t *)&thread,ThreadStarter,__arg);
- pthread_attr_destroy((pthread_attr_t *)&thread);
- if (iVar1 == 0) {
- if (Detach) {
- pthread_detach(TStack_40);
- }
- }
- else {
- error("StartThread: Kann Thread nicht anlegen; Fehlercode %d.\n",iVar1);
- TStack_40 = 0;
- }
- return TStack_40;
-}
-
-
-
-void DelayThread(int Seconds,int MicroSeconds)
-
-{
- if (Seconds == 0) {
- if (MicroSeconds == 0) {
- sched_yield();
- return;
- }
- }
- else if (MicroSeconds == 0) {
- sleep(Seconds);
- return;
- }
- usleep(MicroSeconds + Seconds * 1000000);
- return;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: result
-
-int JoinThread(Thread OtherThread)
-
-{
- int iVar1;
- int value;
- int *local_c;
- int *result;
-
- local_c = (int *)0x0;
- pthread_join(OtherThread,&local_c);
- iVar1 = 0;
- if (local_c != (int *)0x0) {
- iVar1 = *local_c;
- operator_delete(local_c);
- }
- return iVar1;
-}
-
-
-
-// DWARF original prototype: void Semaphore(Semaphore * this, int initValue)
-
-void __thiscall Semaphore::Semaphore(Semaphore *this,int initValue)
-
-{
- int iVar1;
-
- this->value = initValue;
- iVar1 = pthread_mutex_init((pthread_mutex_t *)&this->mutex,(pthread_mutexattr_t *)0x0);
- if (iVar1 == -1) {
- this = (Semaphore *)s_Semaphore__Semaphore__Kann_Mutex_080f50a0;
- }
- else {
- iVar1 = pthread_cond_init((pthread_cond_t *)&this->condition,(pthread_condattr_t *)0x0);
- if (iVar1 != -1) {
- return;
- }
- this = (Semaphore *)s_Semaphore__Semaphore__Kann_Warte_080f5060;
- }
- error((char *)this);
- return;
-}
-
-
-
-// DWARF original prototype: void Semaphore(Semaphore * this, int initValue)
-
-void __thiscall Semaphore::Semaphore(Semaphore *this,int initValue)
-
-{
- int iVar1;
-
- this->value = initValue;
- iVar1 = pthread_mutex_init((pthread_mutex_t *)&this->mutex,(pthread_mutexattr_t *)0x0);
- if (iVar1 == -1) {
- this = (Semaphore *)s_Semaphore__Semaphore__Kann_Mutex_080f50a0;
- }
- else {
- iVar1 = pthread_cond_init((pthread_cond_t *)&this->condition,(pthread_condattr_t *)0x0);
- if (iVar1 != -1) {
- return;
- }
- this = (Semaphore *)s_Semaphore__Semaphore__Kann_Warte_080f5060;
- }
- error((char *)this);
- return;
-}
-
-
-
-// DWARF original prototype: void ~Semaphore(Semaphore * this, int __in_chrg)
-
-void __thiscall Semaphore::~Semaphore(Semaphore *this,int __in_chrg)
-
-{
- int iVar1;
-
- iVar1 = pthread_mutex_destroy((pthread_mutex_t *)&this->mutex);
- if (iVar1 == -1) {
- this = (Semaphore *)s_Semaphore___Semaphore__Kann_Mute_080f5120;
- }
- else {
- iVar1 = pthread_cond_destroy((pthread_cond_t *)&this->condition);
- if (iVar1 != -1) {
- return;
- }
- this = (Semaphore *)s_Semaphore___Semaphore__Kann_Wart_080f50e0;
- }
- error((char *)this);
- return;
-}
-
-
-
-// DWARF original prototype: void ~Semaphore(Semaphore * this, int __in_chrg)
-
-void __thiscall Semaphore::~Semaphore(Semaphore *this,int __in_chrg)
-
-{
- int iVar1;
-
- iVar1 = pthread_mutex_destroy((pthread_mutex_t *)&this->mutex);
- if (iVar1 == -1) {
- this = (Semaphore *)s_Semaphore___Semaphore__Kann_Mute_080f5120;
- }
- else {
- iVar1 = pthread_cond_destroy((pthread_cond_t *)&this->condition);
- if (iVar1 != -1) {
- return;
- }
- this = (Semaphore *)s_Semaphore___Semaphore__Kann_Wart_080f50e0;
- }
- error((char *)this);
- return;
-}
-
-
-
-// DWARF original prototype: void down(Semaphore * this)
-
-void __thiscall Semaphore::down(Semaphore *this)
-
-{
- pthread_mutex_t *__mutex;
- int iVar1;
-
- __mutex = &this->mutex;
- pthread_mutex_lock((pthread_mutex_t *)__mutex);
- iVar1 = this->value;
- if (iVar1 < 1) {
- do {
- pthread_cond_wait((pthread_cond_t *)&this->condition,(pthread_mutex_t *)__mutex);
- iVar1 = this->value;
- } while (iVar1 < 1);
- }
- this->value = iVar1 + -1;
- pthread_mutex_unlock((pthread_mutex_t *)__mutex);
- return;
-}
-
-
-
-// DWARF original prototype: void up(Semaphore * this)
-
-void __thiscall Semaphore::up(Semaphore *this)
-
-{
- pthread_mutex_lock((pthread_mutex_t *)&this->mutex);
- this->value = this->value + 1;
- pthread_mutex_unlock((pthread_mutex_t *)&this->mutex);
- pthread_cond_signal((pthread_cond_t *)&this->condition);
- return;
-}
-
-
-
void __static_initialization_and_destruction_0(int __initialize_p,int __priority)
{
@@ -18687,1576 +18382,6 @@ void __static_initialization_and_destruction_0(int __initialize_p,int __priority
return;
}
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-int GetNumberOfPlayers(void)
-
-{
- return FirstFreePlayer;
-}
-
-
-
-TPlayer * GetPlayer(char *Name)
-
-{
- TPlayer *pTVar1;
- TPlayer **ppTVar2;
- int iVar3;
- TPlayer *pl;
- int i;
- int i_00;
-
- i_00 = 0;
- if (0 < FirstFreePlayer) {
- do {
- ppTVar2 = vector<TPlayer*>::operator()(&PlayerList,i_00);
- pTVar1 = *ppTVar2;
- iVar3 = stricmp((pTVar1->super_TCreature).Name,Name,-1);
- if (iVar3 == 0) {
- return pTVar1;
- }
- i_00 = i_00 + 1;
- } while (i_00 < FirstFreePlayer);
- }
- return (TPlayer *)0x0;
-}
-
-
-
-TPlayer * GetPlayer(ulong CharacterID)
-
-{
- TPlayer *pTVar1;
- TPlayer *pTVar2;
-
- pTVar1 = (TPlayer *)GetCreature(CharacterID);
- pTVar2 = (TPlayer *)0x0;
- if ((pTVar1 != (TPlayer *)0x0) && (pTVar2 = pTVar1, (pTVar1->super_TCreature).Type != PLAYER)) {
- error("GetPlayer: Kreatur ist kein Spieler.\n");
- pTVar2 = (TPlayer *)0x0;
- }
- return pTVar2;
-}
-
-
-
-bool IsPlayerOnline(char *Name)
-
-{
- TPlayer **ppTVar1;
- int iVar2;
- TPlayer *pTVar3;
- TPlayer *pl;
- int i;
- int i_00;
-
- i_00 = 0;
- Semaphore::down(&PlayerMutex);
- if (0 < FirstFreePlayer) {
- do {
- ppTVar1 = vector<TPlayer*>::operator()(&PlayerList,i_00);
- pTVar3 = *ppTVar1;
- iVar2 = stricmp((pTVar3->super_TCreature).Name,Name,-1);
- if (iVar2 == 0) goto LAB_080a7244;
- i_00 = i_00 + 1;
- } while (i_00 < FirstFreePlayer);
- }
- pTVar3 = (TPlayer *)0x0;
-LAB_080a7244:
- Semaphore::up(&PlayerMutex);
- return pTVar3 != (TPlayer *)0x0;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: IgnoreGamemasters_local
-
-int IdentifyPlayer(char *Name,bool ExactMatch,bool IgnoreGamemasters,TPlayer **pl)
-
-{
- bool bVar1;
- size_t sVar2;
- TPlayer **ppTVar3;
- int iVar4;
- char *TestName;
- int i;
- int i_00;
- char *pcVar5;
- int local_18;
- int Hits;
- bool IgnoreGamemasters_local;
- bool ExactMatch_local;
-
- Hits._3_1_ = ExactMatch;
- if (Name == (char *)0x0) {
- pcVar5 = "IdentifyPlayer: Name ist NULL.\n";
- }
- else {
- if (*Name != '\0') {
- if (!ExactMatch) {
- sVar2 = strlen(Name);
- if (Name[sVar2 - 1] == '~') {
- Name[sVar2 - 1] = '\0';
- }
- else {
- Hits._3_1_ = '\x01';
- }
- }
- local_18 = 0;
- i_00 = 0;
- if (0 < FirstFreePlayer) {
- do {
- ppTVar3 = vector<TPlayer*>::operator()(&PlayerList,i_00);
- pcVar5 = ((*ppTVar3)->super_TCreature).Name;
- iVar4 = stricmp(pcVar5,Name,-1);
- if (iVar4 == 0) {
- ppTVar3 = vector<TPlayer*>::operator()(&PlayerList,i_00);
- *pl = *ppTVar3;
- return 0;
- }
- if (Hits._3_1_ == '\0') {
- sVar2 = strlen(Name);
- iVar4 = stricmp(pcVar5,Name,sVar2);
- if (iVar4 == 0) {
- if (IgnoreGamemasters) {
- ppTVar3 = vector<TPlayer*>::operator()(&PlayerList,i_00);
- bVar1 = CheckRight(((*ppTVar3)->super_TCreature).ID,NO_STATISTICS);
- if (bVar1) goto LAB_080a7356;
- }
- local_18 = local_18 + 1;
- ppTVar3 = vector<TPlayer*>::operator()(&PlayerList,i_00);
- *pl = *ppTVar3;
- }
- }
-LAB_080a7356:
- i_00 = i_00 + 1;
- } while (i_00 < FirstFreePlayer);
- }
- if (local_18 == 1) {
- return 0;
- }
- return (local_18 < 2) - 2;
- }
- pcVar5 = "IdentifyPlayer: Name ist leer.\n";
- }
- error(pcVar5);
- return -1;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void LogoutAllPlayers(void)
-
-{
- TPlayer *pTVar1;
- TPlayer **ppTVar2;
- TPlayer *pl;
- int i;
- int i_00;
- int iVar3;
-
- print();
- i_00 = 0;
- if (0 < FirstFreePlayer) {
- do {
- ppTVar2 = vector<TPlayer*>::operator()(&PlayerList,i_00);
- pTVar1 = *ppTVar2;
- if (pTVar1 == (TPlayer *)0x0) {
- iVar3 = i_00 + 1;
- error("LogoutAllPlayers: Eintrag %d in der Playerlist ist NULL.\n",i_00);
- }
- else {
- (*(pTVar1->super_TCreature)._vptr_TCreature[1])(pTVar1);
- iVar3 = i_00;
- }
- i_00 = iVar3;
- } while (iVar3 < FirstFreePlayer);
- }
- return;
-}
-
-
-
-void CloseProcessedRequests(ulong CharacterID)
-
-{
- TPlayer *pTVar1;
- TPlayer **ppTVar2;
- TPlayer *pl;
- int i;
- int i_00;
-
- i_00 = 0;
- if (0 < FirstFreePlayer) {
- do {
- ppTVar2 = vector<TPlayer*>::operator()(&PlayerList,i_00);
- pTVar1 = *ppTVar2;
- if (pTVar1 == (TPlayer *)0x0) {
- error("CloseProcessedRequests: Spieler %d existiert nicht.\n",i_00);
- }
- else if ((pTVar1->Request != 0) && (pTVar1->RequestProcessingGamemaster == CharacterID))
- {
- SendCloseRequest((pTVar1->super_TCreature).Connection);
- pTVar1->Request = 0;
- }
- i_00 = i_00 + 1;
- } while (i_00 < FirstFreePlayer);
- }
- return;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: CharacterID_local
-
-void NotifyBuddies(ulong CharacterID,char *Name,bool Login)
-
-{
- TPlayer *pTVar1;
- TConnection *Name_00;
- bool bVar2;
- bool bVar3;
- TPlayer **ppTVar4;
- int iVar5;
- TPlayerData *pTVar6;
- TPlayer *Player;
- int j;
- int iVar7;
- int iVar8;
- int local_20;
- int i;
- bool Hide;
- bool Login_local;
- char *Name_local;
- ulong CharacterID_local;
-
- if ((Name == (char *)0x0) || (*Name == '\0')) {
- error("NotifyBuddies: Name existiert nicht.\n");
- return;
- }
- bVar2 = CheckRight(CharacterID,NO_STATISTICS);
- local_20 = 0;
- if (0 < FirstFreePlayer) {
- do {
- ppTVar4 = vector<TPlayer*>::operator()(&PlayerList,local_20);
- pTVar1 = *ppTVar4;
- if (((pTVar1->super_TCreature).Connection != (TConnection *)0x0) &&
- (pTVar6 = pTVar1->PlayerData, pTVar6 != (TPlayerData *)0x0)) {
- if (bVar2) {
- bVar3 = CheckRight((pTVar1->super_TCreature).ID,READ_GAMEMASTER_CHANNEL);
- if (!bVar3) goto LAB_080a75da;
- pTVar6 = pTVar1->PlayerData;
- }
- if (0 < pTVar6->Buddies) {
- iVar8 = 0;
- iVar7 = 0;
- do {
- if (pTVar6->Buddy[iVar7] == CharacterID) {
- iVar5 = strcmp(pTVar6->BuddyName[0] + iVar8,Name);
- if (iVar5 == 0) {
- SendBuddyStatus((pTVar1->super_TCreature).Connection,CharacterID,
- Login);
- }
- else {
- Name_00 = (pTVar1->super_TCreature).Connection;
- SendBuddyData((TConnection *)CharacterID,(ulong)Name_00,
- (char *)Name_00,SUB41(CharacterID,0));
- strcpy(pTVar1->PlayerData->BuddyName[0] + iVar8,Name);
- }
- pTVar6 = pTVar1->PlayerData;
- }
- iVar7 = iVar7 + 1;
- iVar8 = iVar8 + 0x1e;
- } while (iVar7 < pTVar6->Buddies);
- }
- }
-LAB_080a75da:
- local_20 = local_20 + 1;
- } while (local_20 < FirstFreePlayer);
- }
- return;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: Online_local
-
-void CreatePlayerList(bool Online)
-
-{
- TPlayer *pTVar1;
- bool bVar2;
- byte bVar3;
- char *PlayerNames_00;
- int *PlayerLevels_00;
- int *PlayerProfessions_00;
- TPlayer **ppTVar4;
- time_t tVar5;
- int iVar6;
- TPlayer *Player;
- int NumberOfPlayers;
- int NumberOfPlayers_00;
- int i;
- int i_00;
- char *local_24;
- int *PlayerProfessions;
- int *PlayerLevels;
- char *PlayerNames;
- bool Online_local;
-
- PlayerNames_00 = (char *)operator_new__(FirstFreePlayer * 0x1e);
- PlayerLevels_00 = (int *)operator_new__(FirstFreePlayer << 2);
- PlayerProfessions_00 = (int *)operator_new__(FirstFreePlayer << 2);
- NumberOfPlayers_00 = Online - 1;
- if ((Online) && (i_00 = 0, 0 < FirstFreePlayer)) {
- local_24 = PlayerNames_00 + NumberOfPlayers_00 * 0x1e;
- do {
- ppTVar4 = vector<TPlayer*>::operator()(&PlayerList,i_00);
- pTVar1 = *ppTVar4;
- bVar2 = CheckRight((pTVar1->super_TCreature).ID,NO_STATISTICS);
- if (!bVar2) {
- strcpy(local_24,(pTVar1->super_TCreature).Name);
- iVar6 = TSkill::Get((pTVar1->super_TCreature).super_TSkillBase.Skills[0]);
- PlayerLevels_00[NumberOfPlayers_00] = iVar6;
- bVar2 = CheckRight((pTVar1->super_TCreature).ID,PREMIUM_ACCOUNT);
- if (bVar2) {
- bVar3 = (pTVar1->super_TCreature).Profession;
- }
- else {
- bVar3 = (pTVar1->super_TCreature).Profession;
- if (9 < bVar3) {
- bVar3 = bVar3 - 10;
- }
- }
- local_24 = local_24 + 0x1e;
- PlayerProfessions_00[NumberOfPlayers_00] = (uint)bVar3;
- NumberOfPlayers_00 = NumberOfPlayers_00 + 1;
- }
- i_00 = i_00 + 1;
- } while (i_00 < FirstFreePlayer);
- }
- PlayerlistOrder(NumberOfPlayers_00,PlayerNames_00,PlayerLevels_00,PlayerProfessions_00);
- if (Online) {
- tVar5 = time((time_t *)0x0);
- Log("load","%ld %d\n",tVar5,FirstFreePlayer);
- }
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void PrintPlayerPositions(void)
-
-{
- TPlayer *pTVar1;
- bool bVar2;
- byte bVar3;
- TPlayer **ppTVar4;
- int iVar5;
- TPlayer *Player;
- int i;
- int i_00;
-
- i_00 = 0;
- if (0 < FirstFreePlayer) {
- do {
- ppTVar4 = vector<TPlayer*>::operator()(&PlayerList,i_00);
- pTVar1 = *ppTVar4;
- bVar2 = CheckRight((pTVar1->super_TCreature).ID,PREMIUM_ACCOUNT);
- if (bVar2) {
- bVar3 = (pTVar1->super_TCreature).Profession;
- }
- else {
- bVar3 = (pTVar1->super_TCreature).Profession;
- if (9 < bVar3) {
- bVar3 = bVar3 - 10;
- }
- }
- i_00 = i_00 + 1;
- iVar5 = TSkill::Get((pTVar1->super_TCreature).super_TSkillBase.Skills[0]);
- Log("players","[%d,%d,%d] %d %d\n",(pTVar1->super_TCreature).posx,
- (pTVar1->super_TCreature).posy,(pTVar1->super_TCreature).posz,iVar5,(uint)bVar3);
- } while (i_00 < FirstFreePlayer);
- }
- return;
-}
-
-
-
-void LoadDepot(TPlayerData *PlayerData,int DepotNr,Object *Con)
-
-{
- bool bVar1;
- undefined4 *puVar2;
- char *Text;
- undefined1 local_4c [4];
- TReadBuffer Buffer;
- Object local_2c [7];
-
- if (PlayerData == (TPlayerData *)0x0) {
- Text = "LoadDepot: PlayerData ist NULL.\n";
- }
- else {
- // try { // try from 080a7923 to 080a79a9 has its CatchHandler @ 080a7ab8
- bVar1 = Object::exists(Con);
- if (bVar1) {
- Object::getObjectType(local_2c);
- bVar1 = ObjectType::getFlag((ObjectType *)local_2c,CONTAINER);
- if (bVar1) {
- if ((uint)DepotNr < 9) {
- if (PlayerData->Depot[DepotNr] == (uchar *)0x0) {
- GetSpecialObject((SPECIALMEANING)&Buffer.Position);
- local_4c = (undefined1 [4])Con->ObjectID;
- Create(local_2c,(ObjectType *)local_4c,(ulong)&Buffer.Position);
- }
- else {
- // try { // try from 080a79d6 to 080a79ee has its CatchHandler @ 080a7a4b
- TReadBuffer::TReadBuffer
- ((TReadBuffer *)local_4c,PlayerData->Depot[DepotNr],
- PlayerData->DepotSize[DepotNr]);
- Buffer.Position = Con->ObjectID;
- LoadObjects((TReadStream *)local_4c,(Object *)&Buffer.Position);
- }
- return;
- }
- // try { // try from 080a79fc to 080a7a36 has its CatchHandler @ 080a7ab8
- error(&DAT_08102c20,DepotNr);
- goto LAB_080a7a01;
- }
- Text = &DAT_08102c60;
- }
- else {
- Text = &DAT_08102ca0;
- }
- }
- error(Text);
-LAB_080a7a01:
- puVar2 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar2 = 0xffffffff;
- // WARNING: Subroutine does not return
- __cxa_throw(puVar2,&RESULT::typeinfo,0);
-}
-
-
-
-void SaveDepot(TPlayerData *PlayerData,int DepotNr,Object *Con)
-
-{
- bool bVar1;
- uchar *__dest;
- undefined4 *puVar2;
- char *Text;
- Object local_3c [4];
- undefined1 local_2c [4];
- TDynamicWriteBuffer HelpBuffer;
-
- if (PlayerData == (TPlayerData *)0x0) {
- Text = "SaveDepot: PlayerData ist NULL.\n";
- }
- else {
- // try { // try from 080a7af0 to 080a7b21 has its CatchHandler @ 080a7ce0
- bVar1 = Object::exists(Con);
- if (bVar1) {
- Object::getObjectType((Object *)local_2c);
- bVar1 = ObjectType::getFlag((ObjectType *)local_2c,CONTAINER);
- if (bVar1) {
- if ((uint)DepotNr < 9) {
- PlayerData->Dirty = true;
- if (PlayerData->Depot[DepotNr] != (uchar *)0x0) {
- operator_delete__(PlayerData->Depot[DepotNr]);
- PlayerData->Depot[DepotNr] = (uchar *)0x0;
- }
- // try { // try from 080a7b58 to 080a7b5c has its CatchHandler @ 080a7cc9
- TDynamicWriteBuffer::TDynamicWriteBuffer((TDynamicWriteBuffer *)local_2c,0x4000)
- ;
- // try { // try from 080a7b6f to 080a7ba2 has its CatchHandler @ 080a7c58
- GetFirstContainerObject(local_3c);
- SaveObjects(local_3c,(TWriteStream *)local_2c,false);
- PlayerData->DepotSize[DepotNr] = HelpBuffer.super_TWriteBuffer.Size;
- __dest = (uchar *)operator_new__(HelpBuffer.super_TWriteBuffer.Size);
- PlayerData->Depot[DepotNr] = __dest;
- memcpy(__dest,HelpBuffer.super_TWriteBuffer.super_TWriteStream.
- _vptr_TWriteStream,PlayerData->DepotSize[DepotNr]);
- // try { // try from 080a7bd0 to 080a7bd4 has its CatchHandler @ 080a7cc9
- TDynamicWriteBuffer::~TDynamicWriteBuffer
- ((TDynamicWriteBuffer *)local_2c,
- (int)HelpBuffer.super_TWriteBuffer.super_TWriteStream.
- _vptr_TWriteStream);
- return;
- }
- // try { // try from 080a7c09 to 080a7c43 has its CatchHandler @ 080a7ce0
- error(&DAT_08102d60,DepotNr);
- goto LAB_080a7c0e;
- }
- Text = &DAT_08102da0;
- }
- else {
- Text = &DAT_08102de0;
- }
- }
- error(Text);
-LAB_080a7c0e:
- puVar2 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar2 = 0xffffffff;
- // WARNING: Subroutine does not return
- __cxa_throw(puVar2,&RESULT::typeinfo,0);
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: Capitals_local
-
-void GetProfessionName(char *Buffer,int Profession,bool Article,bool Capitals)
-
-{
- char *__src;
- bool Capitals_local;
-
- if (Article) {
- if ((Profession == 0xb) || (Profession == 0xe)) {
- builtin_strncpy(Buffer,"an ",4);
- }
- else {
- Buffer[0] = 'a';
- Buffer[1] = ' ';
- Buffer[2] = '\0';
- }
- }
- else {
- *Buffer = '\0';
- }
- switch(Profession) {
- case 1:
- __src = "Knight";
- break;
- case 2:
- __src = "Paladin";
- break;
- case 3:
- __src = "Sorcerer";
- break;
- case 4:
- __src = "Druid";
- break;
- default:
- error("GetProfessionName: Unbekannter Beruf %d.\n",Profession);
- case 0:
- __src = "None";
- break;
- case 0xb:
- __src = "Elite Knight";
- break;
- case 0xc:
- __src = "Royal Paladin";
- break;
- case 0xd:
- __src = "Master Sorcerer";
- break;
- case 0xe:
- __src = "Elder Druid";
- }
- strcat(Buffer,__src);
- if (Capitals) {
- return;
- }
- strLower(Buffer);
- return;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: Requests
-
-void SendExistingRequests(TConnection *Connection)
-
-{
- int iVar1;
- TPlayer *pTVar2;
- int iVar3;
- TPlayer *pl;
- char *pcVar4;
- TPlayer **ppTVar5;
- int j;
- int iVar6;
- int i;
- int iVar7;
- TPlayer___0_ *Player;
- int i_1;
- ulong uStack_40;
- int local_20;
- int local_1c;
- undefined1 *local_18;
- int local_14;
- int Requests;
-
- local_18 = &stack0xffffffc4;
- if (Connection == (TConnection *)0x0) {
- uStack_40 = 0x80a7f50;
- error("SendExistingRequests: Verbindung ist NULL.\n");
- }
- else {
- local_14 = 0;
- iVar7 = 0;
- iVar3 = -(FirstFreePlayer * 4 + 0xfU & 0xfffffff0);
- if (0 < FirstFreePlayer) {
- do {
- *(int *)(&stack0xffffffc8 + iVar3) = iVar7;
- *(vector<TPlayer*> **)(&stack0xffffffc4 + iVar3) = &PlayerList;
- *(undefined4 *)((int)&uStack_40 + iVar3) = 0x80a7f00;
- ppTVar5 = vector<TPlayer*>::operator()
- (*(vector<TPlayer*> **)(&stack0xffffffc4 + iVar3),
- *(int *)(&stack0xffffffc8 + iVar3));
- pTVar2 = *ppTVar5;
- if (pTVar2 == (TPlayer *)0x0) {
- *(int *)(&stack0xffffffc8 + iVar3) = iVar7;
- *(char **)(&stack0xffffffc4 + iVar3) =
- "SendExistingRequests: Spieler %d existiert nicht.\n";
- *(undefined4 *)((int)&uStack_40 + iVar3) = 0x80a7f42;
- error(*(char **)(&stack0xffffffc4 + iVar3));
- }
- else if ((pTVar2->Request != 0) && (pTVar2->RequestProcessingGamemaster == 0)) {
- *(TPlayer **)(&stack0xffffffdc + local_14 * 4 + iVar3) = pTVar2;
- local_14 = local_14 + 1;
- }
- iVar7 = iVar7 + 1;
- } while (iVar7 < FirstFreePlayer);
- }
- iVar7 = 0;
- local_1c = local_14 + -1;
- if (0 < local_14 + -1) {
- do {
- iVar6 = iVar7 + 1;
- local_20 = iVar6;
- if (iVar6 < local_14) {
- do {
- iVar1 = *(int *)(&stack0xffffffdc + iVar7 * 4 + iVar3);
- if (*(int *)(*(int *)(&stack0xffffffdc + iVar6 * 4 + iVar3) + 0x3c4) <
- *(int *)(iVar1 + 0x3c4)) {
- *(int *)(&stack0xffffffdc + iVar7 * 4 + iVar3) =
- *(int *)(&stack0xffffffdc + iVar6 * 4 + iVar3);
- *(int *)(&stack0xffffffdc + iVar6 * 4 + iVar3) = iVar1;
- }
- iVar6 = iVar6 + 1;
- } while (iVar6 < local_14);
- }
- iVar7 = local_20;
- } while (local_20 < local_1c);
- }
- iVar7 = 0;
- if (0 < local_14) {
- do {
- *(undefined4 *)(&stack0xffffffc4 + iVar3) =
- *(undefined4 *)(*(int *)(&stack0xffffffdc + iVar7 * 4 + iVar3) + 0x3c0);
- *(undefined4 *)((int)&uStack_40 + iVar3) = 0x80a7ea1;
- pcVar4 = GetDynamicString(*(ulong *)(&stack0xffffffc4 + iVar3));
- iVar6 = *(int *)(*(int *)(&stack0xffffffdc + iVar7 * 4 + iVar3) + 0x3c4);
- *(undefined4 *)(&stack0xffffffd0 + iVar3) = 6;
- *(char **)(&stack0xffffffd4 + iVar3) = pcVar4;
- *(ulong *)(&stack0xffffffd8 + iVar3) = RoundNr - iVar6;
- iVar6 = *(int *)(&stack0xffffffdc + iVar7 * 4 + iVar3);
- iVar7 = iVar7 + 1;
- *(undefined4 *)(&stack0xffffffc8 + iVar3) = 0;
- *(int *)(&stack0xffffffcc + iVar3) = iVar6 + 0x214;
- *(TConnection **)(&stack0xffffffc4 + iVar3) = Connection;
- *(undefined4 *)((int)&uStack_40 + iVar3) = 0x80a7ee2;
- SendTalk(*(TConnection **)(&stack0xffffffc4 + iVar3),
- *(ulong *)(&stack0xffffffc8 + iVar3),*(char **)(&stack0xffffffcc + iVar3),
- *(int *)(&stack0xffffffd0 + iVar3),*(char **)(&stack0xffffffd4 + iVar3),
- *(int *)(&stack0xffffffd8 + iVar3));
- } while (iVar7 < local_14);
- }
- }
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void InitPlayerPool(void)
-
-{
- TPlayerData *pTVar1;
-
- pTVar1 = PlayerDataPool;
- do {
- pTVar1->CharacterID = 0;
- pTVar1 = pTVar1 + 1;
- } while ((int)pTVar1 < 0x907a435);
- return;
-}
-
-
-
-void SavePlayerPoolSlot(TPlayerData *Slot)
-
-{
- if (Slot != (TPlayerData *)0x0) {
- if (Slot->Dirty != false) {
- SavePlayerData(Slot);
- Slot->Dirty = false;
- }
- return;
- }
- error("SavePlayerPoolSlot: Slot existiert nicht.\n");
- return;
-}
-
-
-
-void FreePlayerPoolSlot(TPlayerData *Slot)
-
-{
- __pid_t _Var1;
- int i;
- int iVar2;
-
- if (Slot == (TPlayerData *)0x0) {
- Slot = (TPlayerData *)s_FreePlayerPoolSlot__Slot_ist_NUL_081030a0;
-LAB_080a8015:
- error((char *)Slot);
- return;
- }
- print();
- if (Slot->CharacterID != 0) {
- if (0 < Slot->Sticky) {
- Slot = (TPlayerData *)&DAT_08102fe0;
- goto LAB_080a8015;
- }
- if (Slot->Locked != 0) {
- _Var1 = getpid();
- if (Slot->Locked != _Var1) {
- Slot = (TPlayerData *)s_FreePlayerPoolSlot__Slot_ist_von_08103040;
- goto LAB_080a8015;
- }
- }
- if (Slot->Dirty != false) {
- SavePlayerData(Slot);
- Slot->Dirty = false;
- }
- if (Slot->Inventory != (uchar *)0x0) {
- operator_delete__(Slot->Inventory);
- }
- iVar2 = 0;
- do {
- if (Slot->Depot[iVar2] != (uchar *)0x0) {
- operator_delete__(Slot->Depot[iVar2]);
- }
- iVar2 = iVar2 + 1;
- } while (iVar2 < 9);
- Slot->CharacterID = 0;
- }
- return;
-}
-
-
-
-TPlayerData * GetPlayerPoolSlot(ulong CharacterID)
-
-{
- int iVar1;
- TPlayerData *pTVar2;
-
- if (CharacterID == 0) {
- error("GetPlayerPoolSlot: CharacterID ist Null.\n");
- }
- else {
- pTVar2 = PlayerDataPool;
- iVar1 = 0;
- do {
- if (pTVar2->CharacterID == CharacterID) {
- return (TPlayerData *)((int)PlayerDataPool[0].Actual + iVar1 + -0x4c);
- }
- pTVar2 = pTVar2 + 1;
- iVar1 = iVar1 + 0x1dcc;
- } while ((int)pTVar2 < 0x907a435);
- }
- return (TPlayerData *)0x0;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: DontWait_local
-// WARNING: Type propagation algorithm not settling
-
-TPlayerData * AssignPlayerPoolSlot(ulong CharacterID,bool DontWait)
-
-{
- bool bVar1;
- int i;
- TPlayerData *pTVar2;
- __pid_t _Var3;
- int iVar4;
- uint uVar5;
- TPlayerData *Slot;
- int iVar6;
- TPlayerData *pTVar7;
- TPlayerData *local_1c;
- bool DontWait_local;
-
- if (CharacterID == 0) {
- error("AssignPlayerPoolSlot: CharacterID ist Null.\n");
- return (TPlayerData *)0x0;
- }
- print();
- while( true ) {
- Semaphore::down(&PlayerDataPoolMutex);
- pTVar2 = GetPlayerPoolSlot(CharacterID);
- if (pTVar2 == (TPlayerData *)0x0) break;
- if (pTVar2->Locked == 0) {
- _Var3 = getpid();
- pTVar2->Locked = _Var3;
- Semaphore::up(&PlayerDataPoolMutex);
- return pTVar2;
- }
- if (DontWait) {
- pTVar2->Sticky = pTVar2->Sticky + 1;
- }
- Semaphore::up(&PlayerDataPoolMutex);
- if (DontWait) {
- return pTVar2;
- }
- DelayThread(0,100);
- }
- iVar4 = 0;
- iVar6 = 0;
- while (*(int *)((int)PlayerDataPool[0].Actual + iVar6 + -0x4c) != 0) {
- iVar4 = iVar4 + 1;
- iVar6 = iVar6 + 0x1dcc;
- pTVar2 = (TPlayerData *)0x0;
- if (1999 < iVar4) goto LAB_080a81ec;
- }
- pTVar2 = (TPlayerData *)((int)PlayerDataPool[0].Actual + iVar6 + -0x4c);
- uVar5 = 0x1dcc;
- pTVar7 = pTVar2;
- if (((uint)pTVar2 & 4) != 0) {
- pTVar7 = (TPlayerData *)((int)PlayerDataPool[0].Actual + iVar6 + -0x48);
- *(undefined4 *)((int)PlayerDataPool[0].Actual + iVar6 + -0x4c) = 0;
- uVar5 = 0x1dc8;
- }
- for (uVar5 = uVar5 >> 2; uVar5 != 0; uVar5 = uVar5 - 1) {
- pTVar7->CharacterID = 0;
- pTVar7 = (TPlayerData *)&pTVar7->Locked;
- }
- *(ulong *)((int)PlayerDataPool[0].Actual + iVar6 + -0x4c) = CharacterID;
- _Var3 = getpid();
- *(__pid_t *)((int)PlayerDataPool[0].Actual + iVar6 + -0x48) = _Var3;
- *(undefined1 *)((int)PlayerDataPool[0].Actual + iVar6 + -0x40) = 0;
- *(undefined4 *)((int)PlayerDataPool[0].Actual + iVar6 + -0x44) = 0;
- Semaphore::up(&PlayerDataPoolMutex);
-LAB_080a81ec:
- if (pTVar2 != (TPlayerData *)0x0) {
-LAB_080a81f0:
- print();
- bVar1 = PlayerDataExists(CharacterID);
- if (!bVar1) {
- Log("game","Spieler %ld loggt sich zum ersten Mal ein.\n",CharacterID);
- }
- bVar1 = LoadPlayerData(pTVar2);
- if (!bVar1) {
- pTVar2->CharacterID = 0;
- pTVar2->Locked = 0;
- return (TPlayerData *)0x0;
- }
- return pTVar2;
- }
- iVar4 = 0;
- iVar6 = 0;
- while (((*(int *)((int)PlayerDataPool[0].Actual + iVar6 + -0x44) != 0 ||
- (*(char *)((int)PlayerDataPool[0].Actual + iVar6 + -0x40) != '\0')) ||
- (*(int *)((int)PlayerDataPool[0].Actual + iVar6 + -0x48) != 0))) {
- iVar4 = iVar4 + 1;
- iVar6 = iVar6 + 0x1dcc;
- if (1999 < iVar4) goto LAB_080a8292;
- }
- pTVar2 = (TPlayerData *)((int)PlayerDataPool[0].Actual + iVar6 + -0x4c);
- FreePlayerPoolSlot(pTVar2);
- uVar5 = 0x1dcc;
- local_1c = pTVar2;
- if (((uint)pTVar2 & 4) != 0) {
- local_1c = (TPlayerData *)((int)PlayerDataPool[0].Actual + iVar6 + -0x48);
- uVar5 = 0x1dc8;
- *(undefined4 *)((int)PlayerDataPool[0].Actual + iVar6 + -0x4c) = 0;
- }
- for (uVar5 = uVar5 >> 2; uVar5 != 0; uVar5 = uVar5 - 1) {
- local_1c->CharacterID = 0;
- local_1c = (TPlayerData *)&local_1c->Locked;
- }
- *(ulong *)((int)PlayerDataPool[0].Actual + iVar6 + -0x4c) = CharacterID;
- _Var3 = getpid();
- *(__pid_t *)((int)PlayerDataPool[0].Actual + iVar6 + -0x48) = _Var3;
- Semaphore::up(&PlayerDataPoolMutex);
-LAB_080a8292:
- if (pTVar2 != (TPlayerData *)0x0) goto LAB_080a81f0;
- iVar4 = 0;
- iVar6 = 0;
- while ((*(int *)((int)PlayerDataPool[0].Actual + iVar6 + -0x44) != 0 ||
- (*(int *)((int)PlayerDataPool[0].Actual + iVar6 + -0x48) != 0))) {
- iVar4 = iVar4 + 1;
- iVar6 = iVar6 + 0x1dcc;
- if (1999 < iVar4) goto LAB_080a82c3;
- }
- pTVar2 = (TPlayerData *)((int)PlayerDataPool[0].Actual + iVar6 + -0x4c);
- FreePlayerPoolSlot(pTVar2);
- uVar5 = 0x1dcc;
- local_1c = pTVar2;
- if (((uint)pTVar2 & 4) != 0) {
- local_1c = (TPlayerData *)((int)PlayerDataPool[0].Actual + iVar6 + -0x48);
- uVar5 = 0x1dc8;
- *(undefined4 *)((int)PlayerDataPool[0].Actual + iVar6 + -0x4c) = 0;
- }
- for (uVar5 = uVar5 >> 2; uVar5 != 0; uVar5 = uVar5 - 1) {
- local_1c->CharacterID = 0;
- local_1c = (TPlayerData *)&local_1c->Locked;
- }
- *(ulong *)((int)PlayerDataPool[0].Actual + iVar6 + -0x4c) = CharacterID;
- _Var3 = getpid();
- *(__pid_t *)((int)PlayerDataPool[0].Actual + iVar6 + -0x48) = _Var3;
- Semaphore::up(&PlayerDataPoolMutex);
-LAB_080a82c3:
- if (pTVar2 == (TPlayerData *)0x0) {
- error("AssignPlayerPoolSlot: Kein Slot mehr frei.\n");
- Semaphore::up(&PlayerDataPoolMutex);
- return (TPlayerData *)0x0;
- }
- goto LAB_080a81f0;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: DontWait_local
-
-TPlayerData * AttachPlayerPoolSlot(ulong CharacterID,bool DontWait)
-
-{
- TPlayerData *pTVar1;
- __pid_t _Var2;
- TPlayerData *Slot;
- char *Text;
- bool DontWait_local;
-
- if (CharacterID == 0) {
- Text = "AttachPlayerPoolSlot: CharacterID ist Null.\n";
- }
- else {
- print();
- while( true ) {
- Semaphore::down(&PlayerDataPoolMutex);
- pTVar1 = GetPlayerPoolSlot(CharacterID);
- if (pTVar1 == (TPlayerData *)0x0) break;
- if (pTVar1->Locked == 0) {
- _Var2 = getpid();
- pTVar1->Locked = _Var2;
- Semaphore::up(&PlayerDataPoolMutex);
- return pTVar1;
- }
- Semaphore::up(&PlayerDataPoolMutex);
- if (DontWait) {
- return (TPlayerData *)0x0;
- }
- DelayThread(0,100);
- }
- Semaphore::up(&PlayerDataPoolMutex);
- Text = "AttachPlayerPoolSlot: Daten des Charakters sind nicht vorhanden.\n";
- }
- error(Text);
- return (TPlayerData *)0x0;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: DontWait_local
-
-void AttachPlayerPoolSlot(TPlayerData *Slot,bool DontWait)
-
-{
- __pid_t _Var1;
- bool DontWait_local;
-
- if (Slot == (TPlayerData *)0x0) {
- error("AttachPlayerPoolSlot: Slot ist NULL.\n");
- return;
- }
- print();
- while( true ) {
- Semaphore::down(&PlayerDataPoolMutex);
- if (Slot->Locked == 0) {
- _Var1 = getpid();
- Slot->Locked = _Var1;
- Semaphore::up(&PlayerDataPoolMutex);
- return;
- }
- Semaphore::up(&PlayerDataPoolMutex);
- if (DontWait) break;
- DelayThread(0,100);
- }
- return;
-}
-
-
-
-void IncreasePlayerPoolSlotSticky(TPlayerData *Slot)
-
-{
- if (Slot != (TPlayerData *)0x0) {
- Semaphore::down(&PlayerDataPoolMutex);
- Slot->Sticky = Slot->Sticky + 1;
- Semaphore::up(&PlayerDataPoolMutex);
- return;
- }
- error("IncreasePlayerPoolSlotSticky: Slot ist NULL.\n");
- return;
-}
-
-
-
-void DecreasePlayerPoolSlotSticky(TPlayerData *Slot)
-
-{
- if (Slot != (TPlayerData *)0x0) {
- Semaphore::down(&PlayerDataPoolMutex);
- Slot->Sticky = Slot->Sticky + -1;
- Semaphore::up(&PlayerDataPoolMutex);
- return;
- }
- error("DecreasePlayerPoolSlotSticky: Slot ist NULL.\n");
- return;
-}
-
-
-
-void DecreasePlayerPoolSlotSticky(ulong CharacterID)
-
-{
- TPlayerData *Slot;
- TPlayerData *pTVar1;
-
- if (CharacterID != 0) {
- Semaphore::down(&PlayerDataPoolMutex);
- pTVar1 = GetPlayerPoolSlot(CharacterID);
- if (pTVar1 == (TPlayerData *)0x0) {
- error("DecreasePlayerPoolSlotSticky: Slot von Spieler %ld nicht gefunden.\n",CharacterID
- );
- }
- else {
- pTVar1->Sticky = pTVar1->Sticky + -1;
- }
- Semaphore::up(&PlayerDataPoolMutex);
- return;
- }
- error("DecreasePlayerPoolSlotSticky: CharacterID ist Null.\n");
- return;
-}
-
-
-
-void ReleasePlayerPoolSlot(TPlayerData *Slot)
-
-{
- __pid_t _Var1;
-
- if (Slot == (TPlayerData *)0x0) {
- Slot = (TPlayerData *)s_ReleasePlayerPoolSlot__Slot_ist_N_08103520;
- }
- else {
- print();
- if (Slot->Locked == 0) {
- Slot = (TPlayerData *)s_ReleasePlayerPoolSlot__Slot_ist_n_081034e0;
- }
- else {
- _Var1 = getpid();
- if (Slot->Locked == _Var1) {
- Slot->Locked = 0;
- return;
- }
- Slot = (TPlayerData *)s_ReleasePlayerPoolSlot__Slot_ist_v_08103480;
- }
- }
- error((char *)Slot);
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void SavePlayerPoolSlots(void)
-
-{
- TPlayerData *Slot;
- time_t tVar1;
- __pid_t _Var2;
- int iVar3;
- TPlayerData *P;
- int i;
- int iVar4;
- char *Text;
- char *pcVar5;
-
- iVar3 = 0;
- print();
- iVar4 = 1999;
- do {
- Slot = (TPlayerData *)((int)PlayerDataPool[0].Actual + iVar3 + -0x4c);
- if ((((*(int *)((int)PlayerDataPool[0].Actual + iVar3 + -0x4c) != 0) &&
- (*(int *)((int)PlayerDataPool[0].Actual + iVar3 + -0x44) < 1)) &&
- (*(int *)((int)PlayerDataPool[0].Actual + iVar3 + -0x48) == 0)) &&
- (*(char *)((int)PlayerDataPool[0].Actual + iVar3 + -0x40) != '\0')) {
- tVar1 = time((time_t *)0x0);
- if (*(int *)((int)PlayerDataPool[0].Actual + iVar3 + -0x24) <= tVar1 + -900) {
- pcVar5 = (char *)0x1;
- AttachPlayerPoolSlot(Slot,true);
- _Var2 = getpid();
- if (*(int *)((int)PlayerDataPool[0].Actual + iVar3 + -0x48) == _Var2) {
- if (Slot == (TPlayerData *)0x0) {
- error("SavePlayerPoolSlot: Slot existiert nicht.\n");
- }
- else if (*(char *)((int)PlayerDataPool[0].Actual + iVar3 + -0x40) != '\0') {
- SavePlayerData(Slot);
- *(undefined1 *)((int)PlayerDataPool[0].Actual + iVar3 + -0x40) = 0;
- }
- if (Slot == (TPlayerData *)0x0) {
- Text = "ReleasePlayerPoolSlot: Slot ist NULL.\n";
- }
- else {
- pcVar5 = "Gebe Slot von Spieler %ld frei.\n";
- print();
- if (*(int *)((int)PlayerDataPool[0].Actual + iVar3 + -0x48) == 0) {
- Text = "ReleasePlayerPoolSlot: Slot ist nicht gesperrt.\n";
- }
- else {
- _Var2 = getpid();
- if (*(int *)((int)PlayerDataPool[0].Actual + iVar3 + -0x48) == _Var2) {
- *(undefined4 *)((int)PlayerDataPool[0].Actual + iVar3 + -0x48) = 0;
- goto LAB_080a875a;
- }
- Text =
- "ReleasePlayerPoolSlot: Slot ist von einem anderen Thread gesperrt.\n";
- }
- }
- error(Text,pcVar5);
- }
- }
- }
-LAB_080a875a:
- iVar3 = iVar3 + 0x1dcc;
- iVar4 = iVar4 + -1;
- if (iVar4 < 0) {
- return;
- }
- } while( true );
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: i
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void ExitPlayerPool(void)
-
-{
- int iVar1;
- __pid_t _Var2;
- TPlayerData *Slot;
- int iVar3;
- char *pcVar4;
- char *pcVar5;
- int local_14;
- int i;
-
- local_14 = 0;
- Slot = PlayerDataPool;
- iVar3 = 0;
- do {
- if (*(int *)((int)PlayerDataPool[0].Actual + iVar3 + -0x4c) != 0) {
- iVar1 = *(int *)((int)PlayerDataPool[0].Actual + iVar3 + -0x48);
- while (iVar1 != 0) {
- print();
- DelayThread(1,0);
- iVar1 = *(int *)((int)PlayerDataPool[0].Actual + iVar3 + -0x48);
- }
- iVar1 = *(int *)((int)PlayerDataPool[0].Actual + iVar3 + -0x44);
- while (0 < iVar1) {
- DelayThread(1,0);
- pcVar5 = (char *)0x0;
- AttachPlayerPoolSlot(Slot,false);
- SendMails(Slot);
- if (Slot == (TPlayerData *)0x0) {
- error("DecreasePlayerPoolSlotSticky: Slot ist NULL.\n");
- pcVar4 = "ReleasePlayerPoolSlot: Slot ist NULL.\n";
-LAB_080a8977:
- error(pcVar4,pcVar5);
- }
- else {
- Semaphore::down(&PlayerDataPoolMutex);
- Slot->Sticky = Slot->Sticky + -1;
- Semaphore::up(&PlayerDataPoolMutex);
- pcVar5 = "Gebe Slot von Spieler %ld frei.\n";
- print();
- if (Slot->Locked == 0) {
- pcVar4 = "ReleasePlayerPoolSlot: Slot ist nicht gesperrt.\n";
- goto LAB_080a8977;
- }
- _Var2 = getpid();
- if (Slot->Locked != _Var2) {
- pcVar4 =
- "ReleasePlayerPoolSlot: Slot ist von einem anderen Thread gesperrt.\n";
- goto LAB_080a8977;
- }
- Slot->Locked = 0;
- }
- iVar1 = *(int *)((int)PlayerDataPool[0].Actual + iVar3 + -0x44);
- }
- pcVar5 = (char *)0x0;
- AttachPlayerPoolSlot(Slot,false);
- FreePlayerPoolSlot(Slot);
- if (Slot == (TPlayerData *)0x0) {
- pcVar4 = "ReleasePlayerPoolSlot: Slot ist NULL.\n";
- }
- else {
- pcVar5 = "Gebe Slot von Spieler %ld frei.\n";
- print();
- if (Slot->Locked == 0) {
- pcVar4 = "ReleasePlayerPoolSlot: Slot ist nicht gesperrt.\n";
- }
- else {
- _Var2 = getpid();
- if (Slot->Locked == _Var2) {
- Slot->Locked = 0;
- goto LAB_080a89db;
- }
- pcVar4 = "ReleasePlayerPoolSlot: Slot ist von einem anderen Thread gesperrt.\n";
- }
- }
- error(pcVar4,pcVar5);
- }
-LAB_080a89db:
- local_14 = local_14 + 1;
- Slot = Slot + 1;
- iVar3 = iVar3 + 0x1dcc;
- if (1999 < local_14) {
- print();
- return;
- }
- } while( true );
-}
-
-
-
-int GetPlayerIndexEntryNumber(char *Name,int Position)
-
-{
- char cVar1;
- size_t sVar2;
- char c;
-
- if (Name == (char *)0x0) {
- error("GetPlayerIndexEntryNumber: Name ist NULL.\n");
- }
- else {
- sVar2 = strlen(Name);
- if ((int)sVar2 <= Position) {
- return 0;
- }
- cVar1 = Name[Position];
- if ((byte)(cVar1 + 0xbfU) < 0x1a) {
- return cVar1 + -0x40;
- }
- if ((byte)(cVar1 + 0x9fU) < 0x1a) {
- return cVar1 + -0x60;
- }
- }
- return 0;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: Node_local
-
-void InsertPlayerIndex(TPlayerIndexInternalNode *Node,int Position,char *Name,ulong CharacterID)
-
-{
- storeitem<> *psVar1;
- TPlayerIndexEntry *pTVar2;
- int i_1;
- int iVar3;
- int iVar4;
- TPlayerIndexInternalNode *Node_00;
- TPlayerIndexLeafNode *pTVar5;
- TPlayerIndexLeafNode *Leaf;
- TPlayerIndexEntry *pTVar6;
- storeitem<> *psVar7;
- int i;
- int iVar8;
- TPlayerIndexNode *Child;
- char *local_2c;
- int local_28;
- int i_2;
- int Number;
- ulong CharacterID_local;
- char *Name_local;
- int Position_local;
- TPlayerIndexInternalNode *Node_local;
-
- Position_local = (int)Node;
- Name_local = (char *)Position;
- do {
- if (Position_local == 0) {
- Node = (TPlayerIndexInternalNode *)s_InsertPlayerIndex__Node_ist_NULL_08103660;
-LAB_080a8cca:
- error((char *)Node);
- return;
- }
- if (Name == (char *)0x0) {
- Node = (TPlayerIndexInternalNode *)s_InsertPlayerIndex__Name_ist_NULL_08103620;
- goto LAB_080a8cca;
- }
- iVar3 = GetPlayerIndexEntryNumber(Name,(int)Name_local);
- psVar1 = *(storeitem<> **)(Position_local + 4 + iVar3 * 4);
- if (psVar1 == (storeitem<> *)0x0) {
- pTVar5 = store<>::getFreeItem(&PlayerIndexLeafNodes);
- (pTVar5->super_TPlayerIndexNode).InternalNode = false;
- strcpy(pTVar5->Entry[0].Name,Name);
- pTVar5->Count = 1;
- pTVar5->Entry[0].CharacterID = CharacterID;
- *(TPlayerIndexLeafNode **)(Position_local + 4 + iVar3 * 4) = pTVar5;
- return;
- }
- if ((psVar1->data).super_TPlayerIndexNode.InternalNode == false) {
- if ((psVar1->data).Count < 1) {
- iVar4 = (psVar1->data).Count;
- }
- else {
- pTVar6 = (psVar1->data).Entry;
- iVar8 = 0;
- do {
- iVar4 = strcmp(pTVar6->Name,Name);
- if (iVar4 == 0) {
- return;
- }
- iVar4 = (psVar1->data).Count;
- iVar8 = iVar8 + 1;
- pTVar6 = pTVar6 + 1;
- } while (iVar8 < iVar4);
- }
- if (iVar4 < 10) {
- strcpy((char *)((int)psVar1 + (psVar1->data).Count * 0x24 + 8),Name);
- *(ulong *)((int)psVar1 + (psVar1->data).Count * 0x24 + 0x28) = CharacterID;
- (psVar1->data).Count = (psVar1->data).Count + 1;
- return;
- }
- Node_00 = store<>::getFreeItem(&PlayerIndexInternalNodes);
- (Node_00->super_TPlayerIndexNode).InternalNode = true;
- iVar4 = 0;
- do {
- Node_00->Child[iVar4] = (TPlayerIndexNode *)0x0;
- iVar4 = iVar4 + 1;
- } while (iVar4 < 0x1b);
- *(TPlayerIndexInternalNode **)(Position_local + 4 + iVar3 * 4) = Node_00;
- local_28 = 0;
- if (0 < (psVar1->data).Count) {
- psVar7 = psVar1;
- do {
- pTVar2 = (psVar7->data).Entry;
- pTVar6 = (psVar7->data).Entry;
- psVar7 = (storeitem<> *)((psVar7->data).Entry[0].Name + 0x1c);
- InsertPlayerIndex(Node_00,(int)(Name_local + 1),pTVar6->Name,pTVar2->CharacterID
- );
- local_28 = local_28 + 1;
- } while (local_28 < (psVar1->data).Count);
- }
- local_2c = Name_local + 1;
- psVar1->next = PlayerIndexLeafNodes.firstFreeItem;
- Name_local = local_2c;
- PlayerIndexLeafNodes.firstFreeItem = psVar1;
- Position_local = (int)Node_00;
- }
- else {
- Name_local = Name_local + 1;
- Position_local = (int)psVar1;
- }
- } while( true );
-}
-
-
-
-TPlayerIndexEntry * SearchPlayerIndex(char *Name)
-
-{
- int iVar1;
- int Position;
- TPlayerIndexEntry *s1;
- TPlayerIndexNode *Node;
- TPlayerIndexInternalNode *pTVar2;
- int i;
- int iVar3;
-
- if (Name == (char *)0x0) {
- error("SearchPlayerIndex: Name ist NULL.\n");
- }
- else {
- pTVar2 = &PlayerIndexHead;
- iVar3 = 0;
- if (PlayerIndexHead.super_TPlayerIndexNode.InternalNode != false) {
- do {
- iVar1 = GetPlayerIndexEntryNumber(Name,iVar3);
- pTVar2 = (TPlayerIndexInternalNode *)pTVar2->Child[iVar1];
- if (pTVar2 == (TPlayerIndexInternalNode *)0x0) {
- return (TPlayerIndexEntry *)0x0;
- }
- iVar3 = iVar3 + 1;
- } while ((pTVar2->super_TPlayerIndexNode).InternalNode != false);
- }
- iVar3 = 0;
- if (0 < (int)pTVar2->Child[0]) {
- s1 = (TPlayerIndexEntry *)(pTVar2->Child + 1);
- do {
- iVar1 = stricmp(s1->Name,Name,-1);
- if (iVar1 == 0) {
- return s1;
- }
- iVar3 = iVar3 + 1;
- s1 = s1 + 1;
- } while (iVar3 < (int)pTVar2->Child[0]);
- }
- }
- return (TPlayerIndexEntry *)0x0;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void InitPlayerIndex(void)
-
-{
- int iVar1;
- ulong MinimumCharacterID;
- int iVar2;
- TQueryManagerConnection *this;
- char *MinimumCharacterID_00;
- ulong *Name;
- int i_1;
- int iStack_53040;
- int NumberOfPlayers;
- ulong CharacterIDs [10000];
- char Names [10000] [30];
-
- iVar2 = 0;
- PlayerIndexHead.super_TPlayerIndexNode.InternalNode = true;
- do {
- PlayerIndexHead.Child[iVar2] = (TPlayerIndexNode *)0x0;
- iVar2 = iVar2 + 1;
- } while (iVar2 < 0x1b);
- this = (TQueryManagerConnection *)operator_new(0x30);
- // try { // try from 080a8dc5 to 080a8dc9 has its CatchHandler @ 080a8ece
- TQueryManagerConnection::TQueryManagerConnection(this,0x57e47);
- if (this->Socket < 0) {
- error("InitPlayerIndex: Kann nicht zum Query-Manager verbinden.\n");
- }
- else {
- MinimumCharacterID_00 = (char *)0x0;
- while( true ) {
- iVar2 = TQueryManagerConnection::loadPlayers
- (this,(ulong)MinimumCharacterID_00,&iStack_53040,
- (char (*) [30])(CharacterIDs + 9999),(ulong *)&NumberOfPlayers);
- if (iVar2 != 0) break;
- if (0 < iStack_53040) {
- iVar2 = 0;
- Name = CharacterIDs + 9999;
- do {
- iVar1 = iVar2 + -1;
- iVar2 = iVar2 + 1;
- InsertPlayerIndex(&PlayerIndexHead,0,(char *)Name,CharacterIDs[iVar1]);
- Name = (ulong *)((int)Name + 0x1e);
- } while (iVar2 < iStack_53040);
- }
- MinimumCharacterID_00 = "%d Spielernamen geladen.\n";
- print();
- if (iStack_53040 < 10000) goto LAB_080a8e91;
- MinimumCharacterID_00 = (char *)(CharacterIDs[0x270e] + 1);
- }
- error("InitPlayerIndex: Kann Spielerdaten nicht ermitteln.\n");
-LAB_080a8e91:
- if (this != (TQueryManagerConnection *)0x0) {
- TQueryManagerConnection::~TQueryManagerConnection(this,(int)MinimumCharacterID_00);
- operator_delete(this);
- }
- }
- return;
-}
-
-
-
-bool PlayerExists(char *Name)
-
-{
- TPlayerIndexEntry *pTVar1;
- bool bVar2;
-
- if (Name == (char *)0x0) {
- error("PlayerExists: Name ist NULL.\n");
- bVar2 = false;
- }
- else {
- pTVar1 = SearchPlayerIndex(Name);
- bVar2 = pTVar1 != (TPlayerIndexEntry *)0x0;
- }
- return bVar2;
-}
-
-
-
-ulong GetCharacterID(char *Name)
-
-{
- TPlayerIndexEntry *pTVar1;
- ulong uVar2;
-
- if (Name == (char *)0x0) {
- error("GetCharacterID: Name ist NULL.\n");
- uVar2 = 0;
- }
- else {
- pTVar1 = SearchPlayerIndex(Name);
- uVar2 = 0;
- if (pTVar1 != (TPlayerIndexEntry *)0x0) {
- uVar2 = pTVar1->CharacterID;
- }
- }
- return uVar2;
-}
-
-
-
-char * GetCharacterName(char *Name)
-
-{
- TPlayerIndexEntry *pTVar1;
-
- if (Name == (char *)0x0) {
- error("GetCharacterName: Name ist NULL.\n");
- pTVar1 = (TPlayerIndexEntry *)0x0;
- }
- else {
- pTVar1 = SearchPlayerIndex(Name);
- if (pTVar1 == (TPlayerIndexEntry *)0x0) {
- error("GetCharacterName: Spieler existiert nicht.\n");
- pTVar1 = (TPlayerIndexEntry *)0x8107675;
- }
- }
- return pTVar1->Name;
-}
-
-
-
// DWARF original prototype: void TPlayer(TPlayer * this, TConnection * Connection, ulong
// CharacterID)
diff --git a/reference/types.hh b/reference/types.hh
index 5b900e6..ef66baf 100644
--- a/reference/types.hh
+++ b/reference/types.hh
@@ -30,26 +30,6 @@ struct TPreparedQuery {
char *Name;
};
-struct TPlayerIndexNode {
- bool InternalNode;
-};
-
-struct TPlayerIndexInternalNode {
- struct TPlayerIndexNode super_TPlayerIndexNode;
- struct TPlayerIndexNode *Child[27];
-};
-
-struct TPlayerIndexEntry {
- char Name[30];
- ulong CharacterID;
-};
-
-struct TPlayerIndexLeafNode {
- struct TPlayerIndexNode super_TPlayerIndexNode;
- int Count;
- struct TPlayerIndexEntry Entry[10];
-};
-
struct THouseGuest {
char Name[60];
};
@@ -245,31 +225,6 @@ struct TReaderThreadReply {
int Size;
};
-struct TQueryManagerConnection {
- int BufferSize;
- uchar *Buffer;
- struct TReadBuffer ReadBuffer;
- struct TWriteBuffer WriteBuffer;
- int Socket;
- bool QueryOk;
- undefined field6_0x2d;
- undefined field7_0x2e;
- undefined field8_0x2f;
-};
-
-struct TQueryManagerPoolConnection {
- struct TQueryManagerConnectionPool *QueryManagerConnectionPool;
- struct TQueryManagerConnection *QueryManagerConnection;
-};
-
-struct TQueryManagerConnectionPool {
- int NumberOfConnections;
- struct TQueryManagerConnection *QueryManagerConnection;
- bool *QueryManagerConnectionFree;
- struct Semaphore FreeQueryManagerConnections;
- struct Semaphore QueryManagerConnectionMutex;
-};
-
// NOTE(fusion): Probably bigint structures for RSA decoding.
struct vlong_flex_unit {
uint n;
diff --git a/src/containers.hh b/src/containers.hh
index ecbe6be..1ff9896 100644
--- a/src/containers.hh
+++ b/src/containers.hh
@@ -532,7 +532,9 @@ union storeitem{
// IMPORTANT(fusion): This will only work properly with POD structures. We
// could also manually handle `data` construction and destruction but I don't
// think we need it.
- STATIC_ASSERT(std::is_pod<T>::value);
+ STATIC_ASSERT(std::is_trivially_default_constructible<T>::value
+ && std::is_trivially_destructible<T>::value
+ && std::is_trivially_copyable<T>::value);
storeitem<T> *next;
T data;
};
@@ -560,7 +562,7 @@ struct store{
T *getFreeItem(void){
if(this->firstFreeItem == NULL){
- storeunit<T, N> *Unit = &this->Units.append()->data;
+ storeunit<T, N> *Unit = &this->Units->append()->data;
for(usize i = 0; i < (N - 1); i += 1){
Unit->item[i].next = &Unit->item[i + 1];
}
@@ -577,7 +579,7 @@ struct store{
// TODO(fusion): Not the safest thing to do.
ASSERT(Item != NULL);
((storeitem<T>*)Item)->next = this->firstFreeItem;
- this->firstfreeItem = (storeitem<T>*)Item;
+ this->firstFreeItem = (storeitem<T>*)Item;
}
// DATA
diff --git a/src/cr.hh b/src/cr.hh
index 0c7d373..20371ad 100644
--- a/src/cr.hh
+++ b/src/cr.hh
@@ -688,6 +688,24 @@ struct TMonster: TNonplayer {
// TPlayer
// =============================================================================
+struct TPlayerIndexNode {
+ bool InternalNode;
+};
+
+struct TPlayerIndexInternalNode: TPlayerIndexNode {
+ TPlayerIndexNode *Child[27];
+};
+
+struct TPlayerIndexEntry {
+ char Name[30];
+ uint32 CharacterID;
+};
+
+struct TPlayerIndexLeafNode: TPlayerIndexNode {
+ int Count;
+ TPlayerIndexEntry Entry[10];
+};
+
struct TPlayer: TCreature {
//TPlayer(void);
diff --git a/src/crmain.cc b/src/crmain.cc
index c6a8b74..f29a992 100644
--- a/src/crmain.cc
+++ b/src/crmain.cc
@@ -16,7 +16,7 @@ static uint32 NextCreatureID;
static int FirstFreeCreature;
static TCreature *HashList[1000];
static matrix<uint32> *FirstChainCreature;
-static vector<TCreature*> CreatureList(0, 10000, 1000);
+static vector<TCreature*> CreatureList(0, 10000, 1000, NULL);
static priority_queue<uint32, TAttackWave*> AttackWaveQueue(100, 100);
static int KilledCreatures[MAX_RACES];
static int KilledPlayers[MAX_RACES];
diff --git a/src/crplayer.cc b/src/crplayer.cc
index 8d962fb..3205e46 100644
--- a/src/crplayer.cc
+++ b/src/crplayer.cc
@@ -1,8 +1,24 @@
#include "cr.hh"
#include "info.hh"
+#include "operate.hh"
+#include "query.hh"
+#include "thread.hh"
#include "stubs.hh"
+static Semaphore PlayerMutex(1);
+static int FirstFreePlayer;
+static vector<TPlayer*> PlayerList(0, 100, 10, NULL);
+
+static Semaphore PlayerDataPoolMutex(1);
+static TPlayerData PlayerDataPool[2000];
+
+static TPlayerIndexInternalNode PlayerIndexHead;
+static store<TPlayerIndexInternalNode, 100> PlayerIndexInternalNodes;
+static store<TPlayerIndexLeafNode, 100> PlayerIndexLeafNodes;
+
+// TPlayer
+// =============================================================================
uint8 TPlayer::GetRealProfession(void){
return this->Profession;
}
@@ -74,3 +90,890 @@ void TPlayer::CheckState(void){
}
}
}
+
+// Player Utility
+// =============================================================================
+int GetNumberOfPlayers(void){
+ return FirstFreePlayer;
+}
+
+TPlayer *GetPlayer(uint32 CharacterID){
+ TCreature *Creature = GetCreature(CharacterID);
+ if(Creature != NULL && Creature->Type != PLAYER){
+ error("GetPlayer: Kreatur ist kein Spieler.\n");
+ Creature = NULL;
+ }
+ return (TPlayer*)Creature;
+}
+
+TPlayer *GetPlayer(const char *Name){
+ TPlayer *Result = NULL;
+ for(int Index = 0; Index < FirstFreePlayer; Index += 1){
+ TPlayer *Player = *PlayerList.at(Index);
+ if(stricmp(Player->Name, Name) == 0){
+ Result = Player;
+ break;
+ }
+ }
+ return Result;
+}
+
+bool IsPlayerOnline(const char *Name){
+ // TODO(fusion): What is `PlayerMutex` actually doing and where is it used?
+ bool Result;
+ PlayerMutex.down();
+ Result = (GetPlayer(Name) != NULL);
+ PlayerMutex.up();
+ return Result;
+}
+
+int IdentifyPlayer(const char *Name, bool ExactMatch, bool IgnoreGamemasters, TPlayer **OutPlayer){
+ if(Name == NULL){
+ error("IdentifyPlayer: Name ist NULL.\n");
+ return -1; // NOTFOUND ?
+ }
+
+ if(Name[0] == 0){
+ error("IdentifyPlayer: Name ist leer.\n");
+ return -1; // NOTFOUND ?
+ }
+
+ int NameLength = (int)strlen(Name);
+ if(!ExactMatch){
+ if(Name[NameLength - 1] != '~'){
+ ExactMatch = true;
+ }else{
+ NameLength -= 1;
+ }
+ }
+
+ int Hits = 0;
+ for(int Index = 0; Index < FirstFreePlayer; Index += 1){
+ TPlayer *Player = *PlayerList.at(Index);
+ if(stricmp(Player->Name, Name, NameLength) == 0){
+ if(NameLength == (int)strlen(Player->Name)){
+ *OutPlayer = Player;
+ return 0; // FOUND ?
+ }else if(!ExactMatch){
+ if(IgnoreGamemasters && CheckRight(Player->ID, NO_STATISTICS)){
+ continue;
+ }
+
+ *OutPlayer = Player;
+ Hits += 1;
+ }
+ }
+ }
+
+ if(Hits == 0){
+ return -1; // NOTFOUND ?
+ }else if(Hits > 1){
+ return -2; // AMBIGUOUS ?
+ }
+
+ return 0; // FOUND ?
+}
+
+void LogoutAllPlayers(void){
+ print(1, "LogoutAllPlayers: Werde alle Spieler ausloggen!\n");
+ for(int Index = 0; Index < FirstFreePlayer; Index += 1){
+ TPlayer *Player = *PlayerList.at(Index);
+
+ // TODO(fusion): Should we be checking if `Player` is NULL, because
+ // `GetPlayer` and `IdentifyPlayer` do not.
+ if(Player == NULL){
+ error("LogoutAllPlayers: Eintrag %d in der Playerlist ist NULL.\n", Index);
+ continue;
+ }
+
+ // TODO(fusion): Same thing as with `ProcessCreatures`. Players are removed
+ // from `PlayerList` by the player's destructor, in a swap and pop fashion.
+ // What a disaster.
+ delete Player;
+ Index -= 1;
+ }
+}
+
+void CloseProcessedRequests(uint32 CharacterID){
+ for(int Index = 0; Index < FirstFreePlayer; Index += 1){
+ TPlayer *Player = *PlayerList.at(Index);
+ if(Player == NULL){
+ error("CloseProcessedRequests: Spieler %d existiert nicht.\n", Index);
+ continue;
+ }
+
+ SendCloseRequest(Player->Connection);
+ Player->Request = 0;
+ }
+}
+
+void NotifyBuddies(uint32 CharacterID, const char *Name, bool Login){
+ if(Name == NULL || Name[0] == 0){
+ error("NotifyBuddies: Name existiert nicht.\n");
+ return;
+ }
+
+ bool Hide = CheckRight(CharacterID, NO_STATISTICS);
+ for(int Index = 0; Index < FirstFreePlayer; Index += 1){
+ TPlayer *Player = *PlayerList.at(Index);
+ if(Player->Connection == NULL || Player->PlayerData == NULL){
+ continue;
+ }
+
+ if(Hide && !CheckRight(Player->ID, READ_GAMEMASTER_CHANNEL)){
+ continue;
+ }
+
+ TPlayerData *PlayerData = Player->PlayerData;
+ for(int BuddyIndex = 0;
+ BuddyIndex < PlayerData->Buddies;
+ BuddyIndex += 1){
+ if(PlayerData->Buddy[BuddyIndex] == CharacterID){
+ if(strcmp(PlayerData->BuddyName[BuddyIndex], Name) == 0){
+ SendBuddyStatus(Player->Connection, CharacterID, Login);
+ }else{
+ SendBuddyData(Player->Connection, CharacterID, Name, Login);
+ strcpy(PlayerData->BuddyName[BuddyIndex], Name);
+ }
+ }
+ }
+ }
+}
+
+void CreatePlayerList(bool Online){
+ // TODO(fusion): Same as `WriteKillStatistics` for names.
+
+ // TODO(fusion): We can avoid allocating these buffers when `Online` is false.
+ // We'll be sure when we dive into `writer.cc` and `reader.cc` and learn more
+ // about these "orders".
+
+ char *PlayerNames = new char[FirstFreePlayer * 30];
+ int *PlayerLevels = new int[FirstFreePlayer];
+ int *PlayerProfessions = new int[FirstFreePlayer];
+ int NumberOfPlayers = -1;
+ if(Online){
+ NumberOfPlayers = 0;
+ for(int Index = 0; Index < FirstFreePlayer; Index += 1){
+ TPlayer *Player = *PlayerList.at(Index);
+ if(CheckRight(Player->ID, NO_STATISTICS)){
+ continue;
+ }
+
+ strcpy(&PlayerNames[Index * 30], Player->Name);
+ PlayerLevels[Index] = Player->Skills[SKILL_LEVEL]->Get();
+ PlayerProfessions[Index] = Player->GetActiveProfession();
+ NumberOfPlayers += 1;
+ }
+ Log("load", "%d %d\n", (int)time(NULL), FirstFreePlayer);
+ }
+
+ PlayerlistOrder(NumberOfPlayers, PlayerNames, PlayerLevels, PlayerProfessions);
+}
+
+void PrintPlayerPositions(void){
+ for(int Index = 0; Index < FirstFreePlayer; Index += 1){
+ TPlayer *Player = *PlayerList.at(Index);
+ Log("players", "[%d,%d,%d] %d %d\n",
+ Player->posx, Player->posy, Player->posz,
+ Player->Skills[SKILL_LEVEL]->Get(),
+ Player->GetActiveProfession());
+ }
+}
+
+void LoadDepot(TPlayerData *PlayerData, int DepotNr, Object Con){
+ if(PlayerData == NULL){
+ error("LoadDepot: PlayerData ist NULL.\n");
+ throw ERROR;
+ }
+
+ if(!Con.exists()){
+ error("LoadDepot: Übergebener Container existiert nicht.\n");
+ throw ERROR;
+ }
+
+ if(!Con.getObjectType().getFlag(CONTAINER)){
+ error("LoadDepot: Übergebenes Objekt ist kein Container.\n");
+ throw ERROR;
+ }
+
+ if(DepotNr < 0 || DepotNr >= 9){ // MAX_DEPOT ?
+ error("LoadDepot: Ungültige Depotnummer %d.\n", DepotNr);
+ throw ERROR;
+ }
+
+ if(PlayerData->Depot[DepotNr] == NULL){
+ Create(Con, GetSpecialObject(DEPOT_CHEST), 0);
+ }else{
+ try{
+ TReadBuffer ReadBuffer(
+ PlayerData->Depot[DepotNr],
+ PlayerData->DepotSize[DepotNr]);
+ LoadObjects(&ReadBuffer, Con);
+ }catch(const char *str){
+ error("LoadDepot: Kann Depot nicht lesen (%s).\n", str);
+ throw ERROR;
+ }
+ }
+}
+
+void SaveDepot(TPlayerData *PlayerData, int DepotNr, Object Con){
+ if(PlayerData == NULL){
+ error("SaveDepot: PlayerData ist NULL.\n");
+ throw ERROR;
+ }
+
+ if(!Con.exists()){
+ error("SaveDepot: Übergebener Container existiert nicht.\n");
+ throw ERROR;
+ }
+
+ if(!Con.getObjectType().getFlag(CONTAINER)){
+ error("SaveDepot: Übergebenes Objekt ist kein Container.\n");
+ throw ERROR;
+ }
+
+ if(DepotNr < 0 || DepotNr >= 9){ // MAX_DEPOT ?
+ error("SaveDepot: Ungültige Depotnummer %d.\n", DepotNr);
+ throw ERROR;
+ }
+
+ PlayerData->Dirty = true;
+ if(PlayerData->Depot[DepotNr] != NULL){
+ delete PlayerData->Depot[DepotNr];
+ PlayerData->Depot[DepotNr] = NULL;
+ }
+
+ try{
+ TDynamicWriteBuffer HelpBuffer(KB(16));
+ SaveObjects(GetFirstContainerObject(Con), &HelpBuffer, false);
+
+ PlayerData->Depot[DepotNr] = new uint8[HelpBuffer.Size];
+ PlayerData->DepotSize[DepotNr] = HelpBuffer.Size;
+ memcpy(PlayerData->Depot[DepotNr], HelpBuffer.Data, HelpBuffer.Size);
+ }catch(const char *str){
+ error("SaveDepot: Kann Depot nicht schreiben (%s).\n", str);
+ PlayerData->Depot[DepotNr] = NULL;
+ PlayerData->DepotSize[DepotNr] = 0;
+ }
+}
+
+void GetProfessionName(char *Buffer, int Profession, bool Article, bool Capitals){
+ Buffer[0] = 0;
+
+ if(Article){
+ if(Profession == PROFESSION_ELITE_KNIGHT
+ || Profession == PROFESSION_ELDER_DRUID){
+ strcat(Buffer, "an ");
+ }else{
+ strcat(Buffer, "a ");
+ }
+ }
+
+ switch(Profession){
+ case PROFESSION_NONE: strcat(Buffer, "None"); break;
+ case PROFESSION_KNIGHT: strcat(Buffer, "Knight"); break;
+ case PROFESSION_PALADIN: strcat(Buffer, "Paladin"); break;
+ case PROFESSION_SORCERER: strcat(Buffer, "Sorcerer"); break;
+ case PROFESSION_DRUID: strcat(Buffer, "Druid"); break;
+ case PROFESSION_ELITE_KNIGHT: strcat(Buffer, "Elite Knight"); break;
+ case PROFESSION_ROYAL_PALADIN: strcat(Buffer, "Royal Paladin"); break;
+ case PROFESSION_MASTER_SORCERER: strcat(Buffer, "Master Sorcerer"); break;
+ case PROFESSION_ELDER_DRUID: strcat(Buffer, "Elder Druid"); break;
+ // NOTE(fusion): Not in the original function but w/e.
+ default: strcat(Buffer, "Unknown"); break;
+ }
+
+ if(!Capitals){
+ strLower(Buffer);
+ }
+}
+
+void SendExistingRequests(TConnection *Connection){
+ if(Connection == NULL){
+ error("SendExistingRequests: Verbindung ist NULL.\n");
+ return;
+ }
+
+ // TODO(fusion): This function would originally use `alloca` to allocate
+ // the `Players` array.
+
+ int NumPlayers = 0;
+ TPlayer **Players = new TPlayer*[FirstFreePlayer];
+ for(int Index = 0; Index < FirstFreePlayer; Index += 1){
+ TPlayer *Player = *PlayerList.at(Index);
+ if(Player == NULL){
+ error("SendExistingRequests: Spieler %d existiert nicht.\n", Index);
+ continue;
+ }
+
+ if(Player->Request != 0 && Player->RequestProcessingGamemaster == 0){
+ Players[NumPlayers] = Player;
+ NumPlayers += 1;
+ }
+ }
+
+ // NOTE(fusion): Little selection sort by request timestamp.
+ for(int i = 0; i < (NumPlayers - 1); i += 1){
+ for(int j = i + 1; j < NumPlayers; j += 1){
+ if(Players[j]->RequestTimestamp < Players[i]->RequestTimestamp){
+ std::swap(Players[i], Players[j]);
+ }
+ }
+ }
+
+ for(int i = 0; i < NumPlayers; i += 1){
+ TPlayer *Player = Players[i];
+ SendTalk(Connection, 0, Player->Name, TALK_GAMEMASTER_REQUEST,
+ GetDynamicString(Player->Request),
+ (RoundNr - Player->RequestTimestamp));
+ }
+
+ delete []Players;
+}
+
+// Player Pool
+// =============================================================================
+void SavePlayerPoolSlot(TPlayerData *Slot){
+ if(Slot == NULL){
+ error("SavePlayerPoolSlot: Slot existiert nicht.\n");
+ return;
+ }
+
+ if(Slot->Dirty){
+ SavePlayerData(Slot);
+ Slot->Dirty = false;
+ }
+}
+
+void FreePlayerPoolSlot(TPlayerData *Slot){
+ if(Slot == NULL){
+ error("FreePlayerPoolSlot: Slot ist NULL.\n");
+ return;
+ }
+
+ print(3, "Gebe Slot von Charakter %u frei.\n", Slot->CharacterID);
+ if(Slot->CharacterID == 0){
+ return;
+ }
+
+ if(Slot->Sticky > 0){
+ error("FreePlayerPoolSlot: Slot wird noch benötigt; darf nicht freigegeben werden.\n");
+ return;
+ }
+
+ if(Slot->Locked != 0 && Slot->Locked != getpid()){
+ error("FreePlayerPoolSlot: Slot ist von einem anderen Thread gesperrt.\n");
+ return;
+ }
+
+ if(Slot->Dirty){
+ SavePlayerData(Slot);
+ Slot->Dirty = false;
+ }
+
+ delete[] Slot->Inventory;
+ for(int DepotNr = 0; DepotNr < 9; DepotNr += 1){ // MAX_DEPOT ?
+ delete[] Slot->Depot[DepotNr];
+ }
+
+ Slot->CharacterID = 0;
+}
+
+TPlayerData *GetPlayerPoolSlot(uint32 CharacterID){
+ if(CharacterID == 0){
+ error("GetPlayerPoolSlot: CharacterID ist Null.\n");
+ return NULL;
+ }
+
+ TPlayerData *Slot = NULL;
+ for(int i = 0; i < NARRAY(PlayerDataPool); i += 1){
+ if(PlayerDataPool[i].CharacterID == CharacterID){
+ Slot = &PlayerDataPool[i];
+ break;
+ }
+ }
+ return Slot;
+}
+
+TPlayerData *AssignPlayerPoolSlot(uint32 CharacterID, bool DontWait){
+ if(CharacterID == 0){
+ error("AssignPlayerPoolSlot: CharacterID ist Null.\n");
+ return NULL;
+ }
+
+ print(3, "Reserviere Slot für Charakter %u.\n", CharacterID);
+
+ // TODO(fusion): `PlayerDataPoolMutex` usage here could be improved, perhaps
+ // with some guard class.
+
+ TPlayerData *Slot = NULL;
+ while(true){
+ PlayerDataPoolMutex.down();
+ Slot = GetPlayerPoolSlot(CharacterID);
+ if(Slot == NULL){
+ break;
+ }
+
+ if(Slot->Locked == 0){
+ Slot->Locked = getpid();
+ PlayerDataPoolMutex.up();
+ return Slot;
+ }
+
+ if(DontWait){
+ Slot->Sticky += 1;
+ PlayerDataPoolMutex.up();
+ return Slot;
+ }
+
+ PlayerDataPoolMutex.up();
+ DelayThread(0, 100);
+ }
+
+ // NOTE(fusion): Player data for `CharacterID` isn't loaded so we need to
+ // assign it one slot and load it.
+ ASSERT(Slot == NULL);
+
+ // NOTE(fusion): Try to find an empty slot.
+ for(int i = 0; i < NARRAY(PlayerDataPool); i += 1){
+ if(PlayerDataPool[i].CharacterID == 0){
+ Slot = &PlayerDataPool[i];
+ break;
+ }
+ }
+
+ if(Slot == NULL){
+ // NOTE(fusion): Try to find a non-empty slot that is not being used and
+ // doesn't need to be saved.
+ for(int i = 0; i < NARRAY(PlayerDataPool); i += 1){
+ if(PlayerDataPool[i].Locked == 0
+ && PlayerDataPool[i].Sticky == 0
+ && !PlayerDataPool[i].Dirty){
+ Slot = &PlayerDataPool[i];
+ FreePlayerPoolSlot(Slot);
+ break;
+ }
+ }
+ }
+
+ if(Slot == NULL){
+ // NOTE(fusion): Try to find a non-empty slot that is not being used.
+ for(int i = 0; i < NARRAY(PlayerDataPool); i += 1){
+ if(PlayerDataPool[i].Locked == 0 && PlayerDataPool[i].Sticky == 0){
+ Slot = &PlayerDataPool[i];
+ FreePlayerPoolSlot(Slot);
+ break;
+ }
+ }
+ }
+
+ if(Slot == NULL){
+ PlayerDataPoolMutex.up();
+ error("AssignPlayerPoolSlot: Kein Slot mehr frei.\n");
+ return NULL;
+ }
+
+ memset(Slot, 0, sizeof(TPlayerData));
+ Slot->CharacterID = CharacterID;
+ Slot->Locked = getpid();
+ PlayerDataPoolMutex.up();
+
+ print(3, "Lade Daten für Spieler %u.\n", CharacterID);
+
+ if(!PlayerDataExists(CharacterID)){
+ Log("game", "Spieler %u loggt sich zum ersten Mal ein.\n", CharacterID);
+ }
+
+ if(!LoadPlayerData(Slot)){
+ Slot->CharacterID = 0;
+ Slot->Locked = 0;
+ Slot = NULL;
+ }
+
+ return Slot;
+}
+
+TPlayerData *AttachPlayerPoolSlot(uint32 CharacterID, bool DontWait){
+ if(CharacterID == 0){
+ error("AttachPlayerPoolSlot: CharacterID ist Null.\n");
+ return NULL;
+ }
+
+ print(3, "Attache Slot von Spieler %u.\n", CharacterID);
+
+ // TODO(fusion): Same as `AssignPlayerPoolSlot`.
+
+ while(true){
+ TPlayerData *Slot = NULL;
+ PlayerDataPoolMutex.down();
+ Slot = GetPlayerPoolSlot(CharacterID);
+ if(Slot == NULL){
+ PlayerDataPoolMutex.up();
+ error("AttachPlayerPoolSlot: Daten des Charakters sind nicht vorhanden.\n");
+ return NULL;
+ }
+
+ if(Slot->Locked == 0){
+ Slot->Locked = getpid();
+ PlayerDataPoolMutex.up();
+ return Slot;
+ }
+
+ if(DontWait){
+ PlayerDataPoolMutex.up();
+ return NULL;
+ }
+
+ PlayerDataPoolMutex.up();
+ DelayThread(0, 100);
+ }
+}
+
+void AttachPlayerPoolSlot(TPlayerData *Slot, bool DontWait){
+ if(Slot == NULL){
+ error("AttachPlayerPoolSlot: Slot ist NULL.\n");
+ return;
+ }
+
+ print(3, "Attache Slot von Spieler %u.\n", Slot->CharacterID);
+ while(true){
+ PlayerDataPoolMutex.down();
+ if(Slot->Locked == 0){
+ Slot->Locked = getpid();
+ PlayerDataPoolMutex.up();
+ return;
+ }
+
+ if(DontWait){
+ PlayerDataPoolMutex.up();
+ return;
+ }
+
+ PlayerDataPoolMutex.up();
+ DelayThread(0,100);
+ }
+}
+
+void IncreasePlayerPoolSlotSticky(TPlayerData *Slot){
+ if(Slot == NULL){
+ error("IncreasePlayerPoolSlotSticky: Slot ist NULL.\n");
+ return;
+ }
+
+ PlayerDataPoolMutex.down();
+ Slot->Sticky += 1;
+ PlayerDataPoolMutex.up();
+}
+
+void DecreasePlayerPoolSlotSticky(TPlayerData *Slot){
+ if(Slot == NULL){
+ error("DecreasePlayerPoolSlotSticky: Slot ist NULL.\n");
+ return;
+ }
+
+ PlayerDataPoolMutex.down();
+ Slot->Sticky -= 1;
+ PlayerDataPoolMutex.up();
+}
+
+void DecreasePlayerPoolSlotSticky(uint32 CharacterID){
+ if(CharacterID == 0){
+ error("DecreasePlayerPoolSlotSticky: CharacterID ist Null.\n");
+ return;
+ }
+
+ PlayerDataPoolMutex.down();
+ TPlayerData *Slot = GetPlayerPoolSlot(CharacterID);
+ if(Slot != NULL){
+ Slot->Sticky -= 1;
+ }else{
+ error("DecreasePlayerPoolSlotSticky: Slot von Spieler %u nicht gefunden.\n", CharacterID);
+ }
+ PlayerDataPoolMutex.up();
+}
+
+void ReleasePlayerPoolSlot(TPlayerData *Slot){
+ if(Slot == NULL){
+ error("ReleasePlayerPoolSlot: Slot ist NULL.\n");
+ return;
+ }
+
+ print(3, "Gebe Slot von Spieler %u frei.\n", Slot->CharacterID);
+ if(Slot->Locked == 0){
+ error("ReleasePlayerPoolSlot: Slot ist nicht gesperrt.\n");
+ return;
+ }
+
+ if(Slot->Locked != getpid()){
+ error("ReleasePlayerPoolSlot: Slot ist von einem anderen Thread gesperrt.\n");
+ return;
+ }
+
+ Slot->Locked = 0;
+}
+
+void SavePlayerPoolSlots(void){
+ time_t Now = time(NULL);
+ print(3, "Speichere alle Spielerdaten...\n");
+ for(int i = 0; i < NARRAY(PlayerDataPool); i += 1){
+ TPlayerData *Slot = &PlayerDataPool[i];
+ if(Slot->CharacterID == 0
+ || Slot->Locked != 0
+ || Slot->Sticky > 0
+ || !Slot->Dirty){
+ continue;
+ }
+
+ // TODO(fusion): Logged out for at least 15 minutes?
+ if((Now - Slot->LastLogoutTime) < 900){
+ continue;
+ }
+
+ AttachPlayerPoolSlot(Slot, true);
+ if(Slot->Locked == getpid()){
+ SavePlayerPoolSlot(Slot);
+ ReleasePlayerPoolSlot(Slot);
+ }
+ }
+}
+
+void InitPlayerPool(void){
+ memset(PlayerDataPool, 0, sizeof(PlayerDataPool));
+}
+
+void ExitPlayerPool(void){
+ // TODO(fusion): I assume the order in `ExitAll` is such to make this work?
+ for(int i = 0; i < NARRAY(PlayerDataPool); i += 1){
+ TPlayerData *Slot = &PlayerDataPool[i];
+ if(Slot->CharacterID == 0){
+ continue;
+ }
+
+ while(Slot->Locked != 0){
+ print(2, "Warte auf Freigabe von Slot %d...\n", i);
+ DelayThread(1, 0);
+ }
+
+ while(Slot->Sticky > 0){
+ DelayThread(1, 0);
+ AttachPlayerPoolSlot(Slot, false);
+ SendMails(Slot);
+ DecreasePlayerPoolSlotSticky(Slot);
+ ReleasePlayerPoolSlot(Slot);
+ }
+
+ AttachPlayerPoolSlot(Slot, false);
+ FreePlayerPoolSlot(Slot);
+ ReleasePlayerPoolSlot(Slot);
+ }
+ print(1, "Alle Spielerdaten gespeichert.\n");
+}
+
+// Player Index
+// =============================================================================
+int GetPlayerIndexEntryNumber(const char *Name, int Position){
+ if(Name == NULL){
+ error("GetPlayerIndexEntryNumber: Name ist NULL.\n");
+ return 0;
+ }
+
+ if(Position < (int)strlen(Name)){
+ int ch = Name[Position];
+ if(ch >= 'A' && ch <= 'Z'){
+ return ch - 'A';
+ }else if(ch >= 'a' && ch <= 'z'){
+ return ch - 'a';
+ }
+ }
+ return 0;
+}
+
+void InsertPlayerIndex(TPlayerIndexInternalNode *Node,
+ int Position, const char *Name, uint32 CharacterID){
+ while(true){
+ if(Node == NULL){
+ error("InsertPlayerIndex: Node ist NULL.\n");
+ return;
+ }
+
+ if(Name == NULL){
+ error("InsertPlayerIndex: Name ist NULL.\n");
+ return;
+ }
+
+ int ChildIndex = GetPlayerIndexEntryNumber(Name, Position);
+ TPlayerIndexNode *Child = Node->Child[ChildIndex];
+ if(Child == NULL){
+ TPlayerIndexLeafNode *Leaf = PlayerIndexLeafNodes.getFreeItem();
+ memset(Leaf, 0, sizeof(TPlayerIndexLeafNode));
+ Leaf->InternalNode = false;
+ Leaf->Count = 1;
+ strcpy(Leaf->Entry[0].Name, Name);
+ Leaf->Entry[0].CharacterID = CharacterID;
+ Node->Child[ChildIndex] = Leaf;
+ return;
+ }
+
+ if(Child->InternalNode){
+ Position += 1;
+ Node = (TPlayerIndexInternalNode*)Child;
+ continue;
+ }
+
+ TPlayerIndexLeafNode *ChildLeaf = (TPlayerIndexLeafNode*)Child;
+ for(int i = 0; i < ChildLeaf->Count; i += 1){
+ // NOTE(fusion): Check if entry is already in the index?
+ // TODO(fusion): We should probably be using `stricmp` here.
+ if(strcmp(ChildLeaf->Entry[i].Name, Name) == 0){
+ return;
+ }
+ }
+
+ if(ChildLeaf->Count < NARRAY(ChildLeaf->Entry)){
+ strcpy(ChildLeaf->Entry[ChildLeaf->Count].Name, Name);
+ ChildLeaf->Entry[ChildLeaf->Count].CharacterID = CharacterID;
+ ChildLeaf->Count += 1;
+ return;
+ }
+
+ // NOTE(fusion): Child leaf node is full so we need to create a new
+ // internal node and move all previous leaf entries to it. Note that
+ // the position is also increased here, so entries should get different
+ // child indices.
+ TPlayerIndexInternalNode *ChildInternal = PlayerIndexInternalNodes.getFreeItem();
+ memset(ChildInternal, 0, sizeof(TPlayerIndexInternalNode));
+ ChildInternal->InternalNode = true;
+ Node->Child[ChildIndex] = ChildInternal;
+
+ for(int i = 0; i < ChildLeaf->Count; i += 1){
+ InsertPlayerIndex(ChildInternal, Position + 1,
+ ChildLeaf->Entry[i].Name,
+ ChildLeaf->Entry[i].CharacterID);
+ }
+ PlayerIndexLeafNodes.putFreeItem(ChildLeaf);
+
+ Position += 1;
+ Node = ChildInternal;
+ }
+}
+
+TPlayerIndexEntry *SearchPlayerIndex(const char *Name){
+ if(Name == NULL){
+ error("SearchPlayerIndex: Name ist NULL.\n");
+ return NULL;
+ }
+
+ TPlayerIndexNode *Node = &PlayerIndexHead;
+ for(int Position = 0; Node->InternalNode; Position += 1){
+ int ChildIndex = GetPlayerIndexEntryNumber(Name, Position);
+ Node = ((TPlayerIndexInternalNode*)Node)->Child[ChildIndex];
+ if(Node == NULL){
+ return NULL;
+ }
+ }
+
+ ASSERT(!Node->InternalNode);
+ TPlayerIndexLeafNode *Leaf = (TPlayerIndexLeafNode*)Node;
+ for(int i = 0; i < Leaf->Count; i += 1){
+ if(stricmp(Leaf->Entry[i].Name, Name) == 0){
+ return &Leaf->Entry[i];
+ }
+ }
+
+ return NULL;
+}
+
+bool PlayerExists(const char *Name){
+ if(Name == NULL){
+ error("PlayerExists: Name ist NULL.\n");
+ return false;
+ }
+
+ return SearchPlayerIndex(Name) != NULL;
+}
+
+uint32 GetCharacterID(const char *Name){
+ if(Name == NULL){
+ error("GetCharacterID: Name ist NULL.\n");
+ return 0;
+ }
+
+ uint32 Result = 0;
+ TPlayerIndexEntry *Entry = SearchPlayerIndex(Name);
+ if(Entry != NULL){
+ Result = Entry->CharacterID;
+ }
+ return Result;
+}
+
+const char *GetCharacterName(const char *Name){
+ if(Name == NULL){
+ error("GetCharacterName: Name ist NULL.\n");
+ return NULL;
+ }
+
+ const char *Result = "Unknown";
+ TPlayerIndexEntry *Entry = SearchPlayerIndex(Name);
+ if(Entry != NULL){
+ Result = Entry->Name;
+ }
+ return Result;
+}
+
+void InitPlayerIndex(void){
+ memset(&PlayerIndexHead, 0, sizeof(TPlayerIndexInternalNode));
+ PlayerIndexHead.InternalNode = true;
+
+ // TODO(fusion): The `QueryBufferSize` parameter to `TQueryManagerConnection`
+ // is probably related to the size of both these arrays. There gotta be some
+ // type of limit per load query or we'd easily overflow these buffers. It may
+ // be hardcoded.
+ uint32 CharacterIDs[10000];
+ char Names[10000][30];
+ TQueryManagerConnection *QueryManager = new TQueryManagerConnection(360007);
+ if(!QueryManager->isConnected()){
+ error("InitPlayerIndex: Kann nicht zum Query-Manager verbinden.\n");
+ return;
+ }
+
+ int MinimumCharacterID = 0;
+ while(true){
+ int NumberOfPlayers;
+ int Ret = QueryManager->loadPlayers(MinimumCharacterID,
+ &NumberOfPlayers, Names, CharacterIDs);
+ if(Ret != 0){
+ error("InitPlayerIndex: Kann Spielerdaten nicht ermitteln.\n");
+ break;
+ }
+
+ for(int i = 0; i < NumberOfPlayers; i += 1){
+ InsertPlayerIndex(&PlayerIndexHead, 0, Names[i], CharacterIDs[i]);
+ }
+
+ if(NumberOfPlayers < 10000){
+ break;
+ }
+
+ MinimumCharacterID = CharacterIDs[9999] + 1;
+ }
+
+ delete QueryManager;
+}
+
+void ExitPlayerIndex(void){
+ // no-op
+}
+
+// Initialization
+// =============================================================================
+void InitPlayer(void){
+ InitPlayerPool();
+ CreatePlayerList(true);
+ InitPlayerIndex();
+}
+
+void ExitPlayer(void){
+ ExitPlayerPool();
+ CreatePlayerList(false);
+ ExitPlayerIndex();
+}
diff --git a/src/main.cc b/src/main.cc
index 7a804e0..c0180c2 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -5,6 +5,7 @@
#include "magic.hh"
#include "objects.hh"
#include "operate.hh"
+#include "query.hh"
#include "stubs.hh"
@@ -184,36 +185,27 @@ static void LockGame(void){
}
void LoadWorldConfig(void){
-#if 0
- // TODO(fusion): Whenever we implement query/database stuff.
- TQueryManagerConnection Connection(0x4000);
- if(Connection.WriteBuffer.Position < 0){
+ TQueryManagerConnection Connection(KB(16));
+ if(!Connection.isConnected()){
error("LoadWorldConfig: Kann nicht zum Query-Manager verbinden.\n");
throw "cannot connect to querymanager";
}
+ int HelpWorldType;
int HelpGameAddress[4];
- int Ret = Connection.loadWorldConfig(&WorldType, &RebootTime, HelpGameAddress,
- &Port, &MaxPlayers, &PremiumPlayerBuffer, &MaxNewbies, &PremiumNewbieBuffer);
- if(Ret != 0){ // TODO(fusion): Maybe `Ret != QUERY_OK` or something?
+ int Ret = Connection.loadWorldConfig(&HelpWorldType, &RebootTime,
+ HelpGameAddress, &GamePort,
+ &MaxPlayers, &PremiumPlayerBuffer,
+ &MaxNewbies, &PremiumNewbieBuffer);
+ if(Ret != 0){
error("LoadWorldConfig: Kann Konfigurationsdaten nicht holen.\n");
throw "cannot load world config";
}
- // NOTE(fusion): Ugh...
+ WorldType = (TWorldType)HelpWorldType;
snprintf(GameAddress, sizeof(GameAddress), "%d.%d.%d.%d",
- HelpGameAddress[0], HelpGameAddress[1],
- HelpGameAddress[2], HelpGameAddress[3]);
-#endif
-
- WorldType = NORMAL;
- RebootTime = 6 * 60; // minutes
- strcpy(GameAddress, "127.0.0.1"); // I KNOW
- GamePort = 7171;
- MaxPlayers = 1000;
- PremiumPlayerBuffer = 100;
- MaxNewbies = 200;
- PremiumNewbieBuffer = 50;
+ HelpGameAddress[0], HelpGameAddress[1],
+ HelpGameAddress[2], HelpGameAddress[3]);
}
static void InitAll(void){
diff --git a/src/map.cc b/src/map.cc
index 0329e20..9eb29cd 100644
--- a/src/map.cc
+++ b/src/map.cc
@@ -41,7 +41,7 @@ static vector<TDepotInfo> DepotInfo(0, 4, 5);
static vector<TMark> Mark(0, 4, 5);
static int Marks;
-static TDynamicWriteBuffer HelpBuffer(0x10000);
+static TDynamicWriteBuffer HelpBuffer(KB(64));
// Object
// =============================================================================
diff --git a/src/operate.cc b/src/operate.cc
index 07f3c50..18829a3 100644
--- a/src/operate.cc
+++ b/src/operate.cc
@@ -2886,7 +2886,7 @@ void RefreshSector(int SectorX, int SectorY, int SectorZ, const uint8 *Data, int
}
void RefreshMap(void){
- TDynamicWriteBuffer HelpBuffer(0x10000);
+ TDynamicWriteBuffer HelpBuffer(KB(64));
for(int SectorZ = SectorZMin; SectorZ <= SectorZMax; SectorZ += 1)
for(int SectorY = SectorYMin; SectorY <= SectorYMax; SectorY += 1)
for(int SectorX = SectorXMin; SectorX <= SectorXMax; SectorX += 1){
diff --git a/src/query.cc b/src/query.cc
new file mode 100644
index 0000000..697a3ce
--- /dev/null
+++ b/src/query.cc
@@ -0,0 +1,3 @@
+#include "query.hh"
+
+// TODO
diff --git a/src/query.hh b/src/query.hh
new file mode 100644
index 0000000..f9cd8de
--- /dev/null
+++ b/src/query.hh
@@ -0,0 +1,43 @@
+#ifndef TIBIA_QUERY_HH_
+#define TIBIA_QUERY_HH_ 1
+
+#include "common.hh"
+#include "thread.hh"
+
+struct TQueryManagerConnection{
+ TQueryManagerConnection(int QueryBufferSize);
+ int loadWorldConfig(int *WorldType, int *RebootTime,
+ int *IPAddress, int *Port,
+ int *MaxPlayers, int *PremiumPlayerBuffer,
+ int *MaxNewbies, int *PremiumNewbieBuffer);
+ int loadPlayers(uint32 MinimumCharacterID, int *NumberOfPlayers,
+ char (*Names)[30], uint32 *CharacterIDs);
+
+ bool isConnected(void){
+ return this->Socket >= 0;
+ }
+
+ // DATA
+ // =================
+ int BufferSize;
+ uint8 *Buffer;
+ TReadBuffer ReadBuffer;
+ TWriteBuffer WriteBuffer;
+ int Socket;
+ bool QueryOk;
+};
+
+struct TQueryManagerConnectionPool{
+ int NumberOfConnections;
+ TQueryManagerConnection *QueryManagerConnection;
+ bool *QueryManagerConnectionFree;
+ Semaphore FreeQueryManagerConnections;
+ Semaphore QueryManagerConnectionMutex;
+};
+
+struct TQueryManagerPoolConnection{
+ TQueryManagerConnectionPool *QueryManagerConnectionPool;
+ TQueryManagerConnection *QueryManagerConnection;
+};
+
+#endif //TIBIA_QUERY_HH_
diff --git a/src/stubs.hh b/src/stubs.hh
index bb68d1d..719f88d 100644
--- a/src/stubs.hh
+++ b/src/stubs.hh
@@ -45,18 +45,25 @@ extern void NetLoadCheck(void);
extern void NetLoadSummary(void);
extern void PrepareHouseCleanup(void);
extern void FinishHouseCleanup(void);
+extern void PlayerlistOrder(int NumberOfPlayers, char *PlayerNames, int *PlayerLevels, int *PlayerProfessions);
extern void ProcessConnections(void);
extern void ProcessMonsterhomes(void);
extern void ProcessReaderThreadReplies(TRefreshSectorFunction *RefreshSector, TSendMailsFunction *SendMails);
extern void ProcessWriterThreadReplies(void);
extern void ReceiveData(void);
+extern void SavePlayerData(TPlayerData *Slot);
+extern bool LoadPlayerData(TPlayerData *Slot);
+extern bool PlayerDataExists(uint32 CharacterID);
extern void SavePlayerDataOrder(void);
extern void SendAll(void);
extern void SendAmbiente(TConnection *Connection);
+extern void SendBuddyData(TConnection *Connection, uint32 CharacterID, const char *Name, bool Online);
+extern void SendBuddyStatus(TConnection *Connection, uint32 CharacterID, bool Online);
extern void SendClearTarget(TConnection *Connection);
extern void SendContainer(TConnection *Connection, int ContainerNr);
extern void SendCloseChannel(TConnection *Connection, int ChannelID);
extern void SendCloseContainer(TConnection *Connection, int ContainerNr);
+extern void SendCloseRequest(TConnection *Connection);
extern void SendCloseTrade(TConnection *Connection);
extern void SendCreatureHealth(TConnection *Connection, uint32 CreatureID);
extern void SendCreatureLight(TConnection *Connection, uint32 CreatureID);
diff --git a/src/thread.cc b/src/thread.cc
index 89dfc92..95ce1a6 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -46,6 +46,54 @@ ThreadHandle StartThread(ThreadFunction *Function, void *Argument, bool Detach){
return (ThreadHandle)Handle;
}
+ThreadHandle StartThread(ThreadFunction *Function, void *Argument, size_t StackSize, bool Detach){
+ TThreadStarter *Starter = new TThreadStarter;
+ Starter->Function = Function;
+ Starter->Argument = Argument;
+ Starter->Detach = Detach;
+
+ pthread_t Handle;
+ pthread_attr_t Attr;
+ pthread_attr_init(&Attr);
+ pthread_attr_setstacksize(&Attr, StackSize);
+ int err = pthread_create(&Handle, &Attr, ThreadStarter, Starter);
+ pthread_attr_destroy(&Attr);
+ if(err != 0){
+ error("StartThread: Kann Thread nicht anlegen; Fehlercode %d.\n", err);
+ return INVALID_THREAD_HANDLE;
+ }
+
+ if(Detach){
+ pthread_detach(Handle);
+ }
+
+ return (ThreadHandle)Handle;
+}
+
+ThreadHandle StartThread(ThreadFunction *Function, void *Argument, void *Stack, size_t StackSize, bool Detach){
+ TThreadStarter *Starter = new TThreadStarter;
+ Starter->Function = Function;
+ Starter->Argument = Argument;
+ Starter->Detach = Detach;
+
+ pthread_t Handle;
+ pthread_attr_t Attr;
+ pthread_attr_init(&Attr);
+ pthread_attr_setstack(&Attr, Stack, StackSize);
+ int err = pthread_create(&Handle, &Attr, ThreadStarter, Starter);
+ pthread_attr_destroy(&Attr);
+ if(err != 0){
+ error("StartThread: Kann Thread nicht anlegen; Fehlercode %d.\n", err);
+ return INVALID_THREAD_HANDLE;
+ }
+
+ if(Detach){
+ pthread_detach(Handle);
+ }
+
+ return (ThreadHandle)Handle;
+}
+
int JoinThread(ThreadHandle Handle){
int Result = 0;
int *ResultPointer;
diff --git a/src/thread.hh b/src/thread.hh
index cd8a881..17e46e9 100644
--- a/src/thread.hh
+++ b/src/thread.hh
@@ -12,6 +12,8 @@ typedef int (ThreadFunction)(void *);
constexpr ThreadHandle INVALID_THREAD_HANDLE = 0;
ThreadHandle StartThread(ThreadFunction *Function, void *Argument, bool Detach);
+ThreadHandle StartThread(ThreadFunction *Function, void *Argument, size_t StackSize, bool Detach);
+ThreadHandle StartThread(ThreadFunction *Function, void *Argument, void *Stack, size_t StackSize, bool Detach);
int JoinThread(ThreadHandle Handle);
void DelayThread(int Seconds, int MicroSeconds);