From efeb10adcc606ad261782a260c8ef86e77ea0608 Mon Sep 17 00:00:00 2001 From: fusion32 Date: Sat, 21 Jun 2025 03:35:13 -0300 Subject: `connections.cc` --- Makefile | 6 +- TODO.md | 10 +- reference/game.c | 980 --------------------------------------------------- src/communication.cc | 98 ++++-- src/connections.cc | 575 ++++++++++++++++++++++++++++++ src/connections.hh | 65 ++-- src/main.cc | 8 +- src/stubs.hh | 6 +- 8 files changed, 691 insertions(+), 1057 deletions(-) create mode 100644 src/connections.cc diff --git a/Makefile b/Makefile index d4fb72a..c0632aa 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ endif HEADERS = $(SRCDIR)/common.hh $(SRCDIR)/communication.hh $(SRCDIR)/config.hh $(SRCDIR)/connections.hh $(SRCDIR)/containers.hh $(SRCDIR)/cr.hh $(SRCDIR)/crypto.hh $(SRCDIR)/enums.hh $(SRCDIR)/info.hh $(SRCDIR)/magic.hh $(SRCDIR)/map.hh $(SRCDIR)/moveuse.hh $(SRCDIR)/objects.hh $(SRCDIR)/operate.hh $(SRCDIR)/query.hh $(SRCDIR)/script.hh $(SRCDIR)/stubs.hh $(SRCDIR)/threads.hh -$(BUILDDIR)/$(OUTPUTEXE): $(BUILDDIR)/communication.obj $(BUILDDIR)/config.obj $(BUILDDIR)/cract.obj $(BUILDDIR)/crcombat.obj $(BUILDDIR)/crmain.obj $(BUILDDIR)/crplayer.obj $(BUILDDIR)/crskill.obj $(BUILDDIR)/crypto.obj $(BUILDDIR)/info.obj $(BUILDDIR)/magic.obj $(BUILDDIR)/main.obj $(BUILDDIR)/map.obj $(BUILDDIR)/moveuse.obj $(BUILDDIR)/objects.obj $(BUILDDIR)/operate.obj $(BUILDDIR)/query.obj $(BUILDDIR)/script.obj $(BUILDDIR)/shm.obj $(BUILDDIR)/strings.obj $(BUILDDIR)/threads.obj $(BUILDDIR)/time.obj $(BUILDDIR)/utils.obj +$(BUILDDIR)/$(OUTPUTEXE): $(BUILDDIR)/communication.obj $(BUILDDIR)/config.obj $(BUILDDIR)/connections.obj $(BUILDDIR)/cract.obj $(BUILDDIR)/crcombat.obj $(BUILDDIR)/crmain.obj $(BUILDDIR)/crplayer.obj $(BUILDDIR)/crskill.obj $(BUILDDIR)/crypto.obj $(BUILDDIR)/info.obj $(BUILDDIR)/magic.obj $(BUILDDIR)/main.obj $(BUILDDIR)/map.obj $(BUILDDIR)/moveuse.obj $(BUILDDIR)/objects.obj $(BUILDDIR)/operate.obj $(BUILDDIR)/query.obj $(BUILDDIR)/script.obj $(BUILDDIR)/shm.obj $(BUILDDIR)/strings.obj $(BUILDDIR)/threads.obj $(BUILDDIR)/time.obj $(BUILDDIR)/utils.obj @echo $(CC) $(CFLAGS) $(LFLAGS) -o $@ $^ $(BUILDDIR)/communication.obj: $(SRCDIR)/communication.cc $(HEADERS) @@ -26,6 +26,10 @@ $(BUILDDIR)/config.obj: $(SRCDIR)/config.cc $(HEADERS) @mkdir -p $(@D) $(CC) -c $(CFLAGS) -o $@ $< +$(BUILDDIR)/connections.obj: $(SRCDIR)/connections.cc $(HEADERS) + @mkdir -p $(@D) + $(CC) -c $(CFLAGS) -o $@ $< + $(BUILDDIR)/cract.obj: $(SRCDIR)/cract.cc $(HEADERS) @mkdir -p $(@D) $(CC) -c $(CFLAGS) -o $@ $< diff --git a/TODO.md b/TODO.md index b347d45..0c1c72f 100644 --- a/TODO.md +++ b/TODO.md @@ -1,12 +1,10 @@ ## TODO NEXT -- QUERY.CC -- COMMUNICATION.CC -- HOUSES.CC -- CRNONPL.CC -- MOVEUSE.CC - SENDING.CC - RECEIVING.CC -- CONNECTIONS.CC +- QUERY.CC +- HOUSES.CC <- GAME +- CRNONPL.CC <- GAME +- MOVEUSE.CC <- GAME - READER.CC - WRITER.CC - DBFUNCS.CC diff --git a/reference/game.c b/reference/game.c index c954698..7958431 100644 --- a/reference/game.c +++ b/reference/game.c @@ -26681,986 +26681,6 @@ void __static_initialization_and_destruction_0(int __initialize_p,int __priority return; } - - -// DWARF original prototype: void TConnection(TConnection * this) - -void __thiscall TConnection::TConnection(TConnection *this) - -{ - TXTEASymmetricKey::TXTEASymmetricKey(&this->SymmetricKey); - this->State = CONNECTION_FREE; - return; -} - - - -// DWARF original prototype: void TConnection(TConnection * this) - -void __thiscall TConnection::TConnection(TConnection *this) - -{ - TXTEASymmetricKey::TXTEASymmetricKey(&this->SymmetricKey); - this->State = CONNECTION_FREE; - return; -} - - - -// DWARF original prototype: void Process(TConnection * this) - -void __thiscall TConnection::Process(TConnection *this) - -{ - ulong uVar1; - bool bVar2; - CONNECTIONSTATE CVar3; - int Time; - int iVar4; - TPlayer *this_00; - TConnection *pTVar5; - int i; - - CVar3 = this->State; - if (CVar3 == CONNECTION_LOGIN) { - bVar2 = GameRunning(); - if ((!bVar2) || (this->ConnectionIsOk == false)) { - if (this->State < CONNECTION_CONNECTED) { - error(&DAT_08108420,this->State); - } - iVar4 = 0x95; - pTVar5 = this; - do { - if (pTVar5->KnownCreatureTable[0].State != KNOWNCREATURE_FREE) { - UnchainKnownCreature(this,pTVar5->KnownCreatureTable[0].CreatureID); - } - pTVar5->KnownCreatureTable[0].Connection = this; - pTVar5->KnownCreatureTable[0].State = KNOWNCREATURE_FREE; - pTVar5->KnownCreatureTable[0].CreatureID = 0; - pTVar5 = (TConnection *)(pTVar5->InData + 0x10); - iVar4 = iVar4 + -1; - } while (-1 < iVar4); - this->ConnectionIsOk = false; - this->State = CONNECTION_DISCONNECTED; - kill(this->PID,1); - } - CVar3 = this->State; - } - if (1 < CVar3 - CONNECTION_GAME) goto LAB_080cae41; - iVar4 = RoundNr - this->TimeStamp; - if (iVar4 == 0x1e) { - SendPing(this); - } - if (iVar4 == 0x3c) { - SendPing(this); - } - if ((RoundNr - 900 == this->TimeStampAction) && - (bVar2 = CheckRight(this->CharacterID,NO_LOGOUT_BLOCK), !bVar2)) { - SendMessage(this,0x12, - "You have been idle for %d minutes. You will be disconnected in one minute if you are still idle then." - ,0xf); - } - bVar2 = GameRunning(); - if ((bVar2) && - ((RoundNr - this->TimeStampAction < 0x3c0 || - (bVar2 = CheckRight(this->CharacterID,NO_LOGOUT_BLOCK), bVar2)))) { - if ((this->ConnectionIsOk == false) || (0x59 < iVar4)) { - if (2 < this->State - CONNECTION_GAME) { - error(&DAT_08108460,this->State); - } - this->State = CONNECTION_LOGOUT; - this_00 = (TPlayer *)0x0; - if (this->CharacterID != 0) { - this_00 = ::GetPlayer(this->CharacterID); - } - if (this_00 != (TPlayer *)0x0) { - TPlayer::ClearConnection(this_00); - bVar2 = false; - goto LAB_080cae11; - } - goto LAB_080cae21; - } - } - else { - if (2 < this->State - CONNECTION_GAME) { - error(&DAT_08108460,this->State); - } - this_00 = (TPlayer *)0x0; - this->State = CONNECTION_LOGOUT; - if (this->CharacterID != 0) { - this_00 = ::GetPlayer(this->CharacterID); - } - if (this_00 != (TPlayer *)0x0) { - TPlayer::ClearConnection(this_00); - bVar2 = true; -LAB_080cae11: - TCreature::StartLogout(&this_00->super_TCreature,false,bVar2); - } -LAB_080cae21: - uVar1 = RoundNr; - this->CharacterID = 0; - this->TimeStamp = uVar1; - this->ClosingIsDelayed = false; - } - CVar3 = this->State; -LAB_080cae41: - if ((CVar3 == CONNECTION_LOGOUT) && - (((bVar2 = GameRunning(), !bVar2 || (this->ConnectionIsOk == false)) || - (this->TimeStamp <= RoundNr)))) { - if (this->State < CONNECTION_CONNECTED) { - error(&DAT_08108420,this->State); - } - iVar4 = 0x95; - pTVar5 = this; - do { - if (pTVar5->KnownCreatureTable[0].State != KNOWNCREATURE_FREE) { - UnchainKnownCreature(this,pTVar5->KnownCreatureTable[0].CreatureID); - } - pTVar5->KnownCreatureTable[0].Connection = this; - pTVar5->KnownCreatureTable[0].State = KNOWNCREATURE_FREE; - pTVar5->KnownCreatureTable[0].CreatureID = 0; - pTVar5 = (TConnection *)(pTVar5->InData + 0x10); - iVar4 = iVar4 + -1; - } while (-1 < iVar4); - this->ConnectionIsOk = false; - this->State = CONNECTION_DISCONNECTED; - kill(this->PID,1); - } - return; -} - - - -// DWARF original prototype: void ResetTimer(TConnection * this, int Command) - -void __thiscall TConnection::ResetTimer(TConnection *this,int Command) - -{ - if ((((this->State - CONNECTION_GAME < 2) && (this->TimeStamp = RoundNr, Command != 0x69)) && - (Command != 0xbe)) && (((Command != 0xc9 && (Command != 0xca)) && (Command != 0x1e)))) { - this->TimeStampAction = RoundNr; - } - return; -} - - - -// DWARF original prototype: void EmergencyPing(TConnection * this) - -void __thiscall TConnection::EmergencyPing(TConnection *this) - -{ - if (this->State - CONNECTION_GAME < 2) { - if (RoundNr - this->TimeStamp < 0x50) { - this->TimeStamp = RoundNr - 100; - } - SendPing(this); - return; - } - return; -} - - - -// DWARF original prototype: pid_t GetPID(TConnection * this) - -pid_t __thiscall TConnection::GetPID(TConnection *this) - -{ - pid_t pVar1; - - if (this->State == CONNECTION_FREE) { - error("TConnection::GetPID: Verbindung ist nicht zugewiesen.\n"); - pVar1 = 0; - } - else { - pVar1 = this->PID; - } - return pVar1; -} - - - -// DWARF original prototype: int GetSocket(TConnection * this) - -int __thiscall TConnection::GetSocket(TConnection *this) - -{ - int iVar1; - - if (this->State < CONNECTION_CONNECTED) { - error("TConnection::GetSocket: Verbindung ist nicht angeschlossen.\n"); - iVar1 = -1; - } - else { - iVar1 = this->Socket; - } - return iVar1; -} - - - -// DWARF original prototype: char * GetIPAddress(TConnection * this) - -char * __thiscall TConnection::GetIPAddress(TConnection *this) - -{ - char *pcVar1; - - if (this->State < CONNECTION_CONNECTED) { - error("TConnection::GetIPAddress: Verbindung ist nicht angeschlossen.\n"); - pcVar1 = "Unknown"; - } - else { - pcVar1 = this->IPAddress; - } - return pcVar1; -} - - - -// DWARF original prototype: void Free(TConnection * this) - -void __thiscall TConnection::Free(TConnection *this) - -{ - this->State = CONNECTION_FREE; - return; -} - - - -// DWARF original prototype: void Assign(TConnection * this) - -void __thiscall TConnection::Assign(TConnection *this) - -{ - __pid_t _Var1; - - if (this->State != CONNECTION_FREE) { - error("TConnection::Assign: Verbindung ist nicht frei.\n"); - } - this->State = CONNECTION_ASSIGNED; - _Var1 = getpid(); - this->PID = _Var1; - return; -} - - - -// DWARF original prototype: void Connect(TConnection * this, int _Socket) - -void __thiscall TConnection::Connect(TConnection *this,int _Socket) - -{ - char *__src; - uint uVar1; - socklen_t local_30; - socklen_t addrlen; - sockaddr_in inaddr; - sockaddr peer; - - if (this->State != CONNECTION_ASSIGNED) { - error("TConnection::Connect: Verbindung ist keinem Thread zugewiesen .\n"); - } - this->State = CONNECTION_CONNECTED; - this->ConnectionIsOk = true; - this->ClosingIsDelayed = true; - this->Socket = _Socket; - local_30 = 0x10; - getpeername(this->Socket,(sockaddr *)(inaddr.sin_zero + 4),&local_30); - addrlen._0_1_ = inaddr.sin_zero[4]; - addrlen._1_1_ = inaddr.sin_zero[5]; - addrlen._2_1_ = inaddr.sin_zero[6]; - addrlen._3_1_ = inaddr.sin_zero[7]; - __src = inet_ntoa((in_addr)peer._0_4_); - strcpy(this->IPAddress,__src); - uVar1 = rand(); - this->RandomSeed = uVar1; - return; -} - - - -// DWARF original prototype: void Login(TConnection * this) - -void __thiscall TConnection::Login(TConnection *this) - -{ - if (this->State != CONNECTION_CONNECTED) { - error(&DAT_08108680,this->State); - } - this->State = CONNECTION_LOGIN; - return; -} - - - -// WARNING: Removing unreachable block (ram,0x080cb3a6) -// WARNING: Removing unreachable block (ram,0x080cb640) -// DWARF original prototype: bool JoinGame(TConnection * this, TReadBuffer * Buffer) - -bool __thiscall TConnection::JoinGame(TConnection *this,TReadBuffer *Buffer) - -{ - uint uVar1; - ulong uVar2; - TPlayer *this_00; - TPlayer *pl; - TConnection *pTVar3; - int i; - int iVar4; - char *Text; - TPlayer *local_14; - - if (this->State != CONNECTION_LOGIN) { - error(&DAT_081086c0,this->State); - } - iVar4 = 0x95; - pTVar3 = this; - do { - pTVar3->KnownCreatureTable[0].Connection = this; - pTVar3->KnownCreatureTable[0].State = KNOWNCREATURE_FREE; - pTVar3->KnownCreatureTable[0].CreatureID = 0; - pTVar3 = (TConnection *)(pTVar3->InData + 0x10); - iVar4 = iVar4 + -1; - } while (-1 < iVar4); - // try { // try from 080cb3d8 to 080cb3ee has its CatchHandler @ 080cb657 - uVar1 = (*(Buffer->super_TReadStream)._vptr_TReadStream[2])(Buffer); - this->TerminalType = uVar1 & 0xffff; - uVar1 = (*(Buffer->super_TReadStream)._vptr_TReadStream[2])(Buffer); - iVar4 = this->TerminalType; - this->TerminalVersion = uVar1 & 0xffff; - if ((iVar4 < 0) || ((1 < iVar4 && (iVar4 != 2)))) { - error("TConnection::JoinGame: Unbekannter Terminal-Typ %d.\n",iVar4); - } - else { - this->TerminalOffsetX = 8; - this->TerminalOffsetY = 6; - this->TerminalWidth = 0x12; - this->TerminalHeight = 0xe; - // try { // try from 080cb45a to 080cb45c has its CatchHandler @ 080cb687 - uVar2 = (*(Buffer->super_TReadStream)._vptr_TReadStream[3])(Buffer); - this->CharacterID = uVar2; - this_00 = ::GetPlayer(uVar2); - if (this_00 == (TPlayer *)0x0) { - this_00 = (TPlayer *)operator_new(0xde8); - // try { // try from 080cb60d to 080cb611 has its CatchHandler @ 080cb6a6 - TPlayer::TPlayer(this_00,this,this->CharacterID); - if (this_00 == (TPlayer *)0x0) { - return false; - } - if (this_00->ConstructError == NOERROR) { -LAB_080cb54c: - strcpy(this->Name,(this_00->super_TCreature).Name); - this->TimeStamp = RoundNr; - this->TimeStampAction = RoundNr; - return true; - } - (*(this_00->super_TCreature)._vptr_TCreature[1])(this_00); - } - else { - if ((this_00->super_TCreature).IsDead == false) { - if (((this_00->super_TCreature).LoggingOut == false) || - (iVar4 = TCreature::LogoutPossible(&this_00->super_TCreature), iVar4 != 0)) { - pTVar3 = (this_00->super_TCreature).Connection; - TPlayer::ClearConnection(this_00); - if (pTVar3 != (TConnection *)0x0) { - pTVar3->CharacterID = 0; - if (2 < pTVar3->State - CONNECTION_GAME) { - error(&DAT_08108460,pTVar3->State); - } - pTVar3->State = CONNECTION_LOGOUT; - local_14 = (TPlayer *)0x0; - if (pTVar3->CharacterID != 0) { - local_14 = ::GetPlayer(pTVar3->CharacterID); - } - if (local_14 != (TPlayer *)0x0) { - TPlayer::ClearConnection(local_14); - TCreature::StartLogout(&local_14->super_TCreature,false,true); - } - uVar2 = RoundNr; - pTVar3->CharacterID = 0; - pTVar3->TimeStamp = uVar2; - pTVar3->ClosingIsDelayed = false; - } - DecrementIsOnlineOrder(this->CharacterID); - TPlayer::TakeOver(this_00,this); - goto LAB_080cb54c; - } - Text = "Spieler %s loggt gerade aus - Einloggen gescheitert.\n"; - } - else { - Text = "Spieler %s ist gerade am Sterben - Einloggen gescheitert.\n"; - } - Log("game",Text,(this_00->super_TCreature).Name); - DecreasePlayerPoolSlotSticky(this->CharacterID); - } - } - return false; -} - - - -// DWARF original prototype: void EnterGame(TConnection * this) - -void __thiscall TConnection::EnterGame(TConnection *this) - -{ - if (this->State != CONNECTION_LOGIN) { - error(&DAT_08108800,this->State); - } - this->State = CONNECTION_GAME; - return; -} - - - -// DWARF original prototype: void Die(TConnection * this) - -void __thiscall TConnection::Die(TConnection *this) - -{ - if (this->State == CONNECTION_GAME) { - this->State = CONNECTION_DEAD; - } - return; -} - - - -// WARNING: Variable defined which should be unmapped: StopFight_local -// DWARF original prototype: void Logout(TConnection * this, int Delay, bool StopFight) - -void __thiscall TConnection::Logout(TConnection *this,int Delay,bool StopFight) - -{ - ulong uVar1; - TPlayer *this_00; - bool StopFight_local; - - if (2 < this->State - CONNECTION_GAME) { - error(&DAT_08108460,this->State); - } - this_00 = (TPlayer *)0x0; - this->State = CONNECTION_LOGOUT; - if (this->CharacterID != 0) { - this_00 = ::GetPlayer(this->CharacterID); - } - if (this_00 != (TPlayer *)0x0) { - TPlayer::ClearConnection(this_00); - TCreature::StartLogout(&this_00->super_TCreature,false,StopFight); - } - uVar1 = RoundNr; - this->CharacterID = 0; - this->TimeStamp = Delay + uVar1; - this->ClosingIsDelayed = false; - return; -} - - - -// DWARF original prototype: void Close(TConnection * this, bool Delay) - -void __thiscall TConnection::Close(TConnection *this,bool Delay) - -{ - CONNECTIONSTATE CVar1; - - CVar1 = this->State; - if (CVar1 < CONNECTION_CONNECTED) { - error(&DAT_08108420,CVar1); - CVar1 = this->State; - } - this->ConnectionIsOk = false; - this->ClosingIsDelayed = Delay; - if (CVar1 == CONNECTION_CONNECTED) { - this->State = CONNECTION_DISCONNECTED; - } - return; -} - - - -// DWARF original prototype: void Disconnect(TConnection * this) - -void __thiscall TConnection::Disconnect(TConnection *this) - -{ - TConnection *pTVar1; - int i; - int iVar2; - - if (this->State < CONNECTION_CONNECTED) { - error(&DAT_08108420,this->State); - } - iVar2 = 0x95; - pTVar1 = this; - do { - if (pTVar1->KnownCreatureTable[0].State != KNOWNCREATURE_FREE) { - UnchainKnownCreature(this,pTVar1->KnownCreatureTable[0].CreatureID); - } - pTVar1->KnownCreatureTable[0].Connection = this; - pTVar1->KnownCreatureTable[0].State = KNOWNCREATURE_FREE; - pTVar1->KnownCreatureTable[0].CreatureID = 0; - pTVar1 = (TConnection *)(pTVar1->InData + 0x10); - iVar2 = iVar2 + -1; - } while (-1 < iVar2); - this->ConnectionIsOk = false; - this->State = CONNECTION_DISCONNECTED; - kill(this->PID,1); - return; -} - - - -// DWARF original prototype: TPlayer * GetPlayer(TConnection * this) - -TPlayer * __thiscall TConnection::GetPlayer(TConnection *this) - -{ - TPlayer *pTVar1; - - if (this->State - CONNECTION_LOGIN < 4) { - if (this->CharacterID != 0) { - pTVar1 = ::GetPlayer(this->CharacterID); - return pTVar1; - } - } - else { - error(&DAT_08108840,this->State); - } - return (TPlayer *)0x0; -} - - - -// DWARF original prototype: char * GetName(TConnection * this) - -char * __thiscall TConnection::GetName(TConnection *this) - -{ - char *pcVar1; - - if (this->State - CONNECTION_LOGIN < 4) { - pcVar1 = this->Name; - } - else { - error(&DAT_08108880,this->State); - pcVar1 = ""; - } - return pcVar1; -} - - - -// DWARF original prototype: void GetPosition(TConnection * this, int * x, int * y, int * z) - -void __thiscall TConnection::GetPosition(TConnection *this,int *x,int *y,int *z) - -{ - TPlayer *pTVar1; - - if (this->State - CONNECTION_LOGIN < 4) { - pTVar1 = (TPlayer *)0x0; - if (this->CharacterID != 0) { - pTVar1 = ::GetPlayer(this->CharacterID); - } - } - else { - error(&DAT_08108840,this->State); - pTVar1 = (TPlayer *)0x0; - } - if (pTVar1 == (TPlayer *)0x0) { - *x = 0; - *y = 0; - *z = 0; - } - else { - *x = (pTVar1->super_TCreature).posx; - *y = (pTVar1->super_TCreature).posy; - *z = (pTVar1->super_TCreature).posz; - } - return; -} - - - -// WARNING: Variable defined which should be unmapped: posz -// DWARF original prototype: bool IsVisible(TConnection * this, int x, int y, int z) - -bool __thiscall TConnection::IsVisible(TConnection *this,int x,int y,int z) - -{ - bool bVar1; - int dz; - int iVar2; - int iVar3; - int local_1c; - int posx; - int posy; - int posz; - - GetPosition(this,&local_1c,&posx,&posy); - if (posy < 8) { - if (7 < z) { - return false; - } - if (posy < 8) goto LAB_080cba8a; - } - if (4 < (z - posy) + 2U) { - return false; - } -LAB_080cba8a: - iVar2 = ((y + this->TerminalOffsetY) - posx) - (posy - z); - iVar3 = ((x + this->TerminalOffsetX) - local_1c) - (posy - z); - if ((((iVar3 < 0) || (this->TerminalWidth <= iVar3)) || (iVar2 < 0)) || - (this->TerminalHeight <= iVar2)) { - bVar1 = false; - } - else { - bVar1 = true; - } - return bVar1; -} - - - -// DWARF original prototype: KNOWNCREATURESTATE KnownCreature(TConnection * this, ulong ID, bool -// UpdateFollows) - -KNOWNCREATURESTATE __thiscall -TConnection::KnownCreature(TConnection *this,ulong ID,bool UpdateFollows) - -{ - KNOWNCREATURESTATE KVar1; - int i; - int iVar2; - - iVar2 = 0; - while (this->KnownCreatureTable[0].CreatureID != ID) { - iVar2 = iVar2 + 1; - this = (TConnection *)(this->InData + 0x10); - if (0x95 < iVar2) { - return KNOWNCREATURE_FREE; - } - } - KVar1 = this->KnownCreatureTable[0].State; - if (KVar1 != KNOWNCREATURE_OUTDATED) { - return KVar1; - } - if (!UpdateFollows) { - return KNOWNCREATURE_OUTDATED; - } - this->KnownCreatureTable[0].State = KNOWNCREATURE_UPTODATE; - return KNOWNCREATURE_OUTDATED; -} - - - -// WARNING: Variable defined which should be unmapped: OldID -// WARNING: Variable defined which should be unmapped: FreeEntry -// DWARF original prototype: ulong NewKnownCreature(TConnection * this, ulong NewID) - -ulong __thiscall TConnection::NewKnownCreature(TConnection *this,ulong NewID) - -{ - int iVar1; - ulong uVar2; - bool bVar3; - ulong *puVar4; - TCreature *pTVar5; - TKnownCreature *pTVar6; - TCreature *cr; - int iVar7; - TConnection *pTVar8; - int i_1; - int local_1c; - int i_2; - int FreeEntry; - ulong OldID; - - iVar7 = 0; - i_2 = -1; - FreeEntry = 0; - puVar4 = &this->KnownCreatureTable[0].CreatureID; - do { - iVar1 = iVar7; - uVar2 = NewID; - if (*puVar4 == NewID) break; - iVar7 = iVar7 + 1; - puVar4 = puVar4 + 4; - iVar1 = i_2; - uVar2 = FreeEntry; - } while (iVar7 < 0x96); - FreeEntry = uVar2; - i_2 = iVar1; - if (i_2 == -1) { - iVar7 = 0; - pTVar6 = this->KnownCreatureTable; - pTVar8 = this; - do { - if (pTVar6->State == KNOWNCREATURE_FREE) { - FreeEntry = pTVar8->KnownCreatureTable[0].CreatureID; - i_2 = iVar7; - break; - } - iVar7 = iVar7 + 1; - pTVar6 = pTVar6 + 1; - pTVar8 = (TConnection *)(pTVar8->InData + 0x10); - } while (iVar7 < 0x96); - if (i_2 == -1) { - local_1c = 0; - puVar4 = &this->KnownCreatureTable[0].CreatureID; - do { - pTVar5 = GetCreature(*puVar4); - if (pTVar5 == (TCreature *)0x0) { - error("TUserCom::NewKnownCreature: Bekannte Kreatur existiert nicht.\n"); -LAB_080cbc81: - if ((pTVar5 == (TCreature *)0x0) || - (bVar3 = IsVisible(this,pTVar5->posx,pTVar5->posy,pTVar5->posz), !bVar3)) { - i_2 = local_1c; - FreeEntry = *puVar4; - UnchainKnownCreature(this,FreeEntry); - break; - } - } - else { - bVar3 = IsVisible(this,pTVar5->posx,pTVar5->posy,pTVar5->posz); - if (!bVar3) goto LAB_080cbc81; - } - local_1c = local_1c + 1; - puVar4 = puVar4 + 4; - } while (local_1c < 0x96); - if (i_2 == -1) { - print(); - return 0; - } - } - } - if (this->KnownCreatureTable[i_2].State != KNOWNCREATURE_FREE) { - error(&DAT_08108900); - } - this->KnownCreatureTable[i_2].CreatureID = NewID; - this->KnownCreatureTable[i_2].State = KNOWNCREATURE_UPTODATE; - pTVar5 = GetCreature(NewID); - if (pTVar5 == (TCreature *)0x0) { - error("TUserCom::NewKnownCreature: Kreatur %lu existiert nicht.\n",NewID); - } - else { - this->KnownCreatureTable[i_2].Next = pTVar5->FirstKnowingConnection; - pTVar5->FirstKnowingConnection = this->KnownCreatureTable + i_2; - } - return FreeEntry; -} - - - -// WARNING: Variable defined which should be unmapped: Unchain_local -// DWARF original prototype: void ClearKnownCreatureTable(TConnection * this, bool Unchain) - -void __thiscall TConnection::ClearKnownCreatureTable(TConnection *this,bool Unchain) - -{ - TConnection *pTVar1; - int i; - int iVar2; - bool Unchain_local; - - iVar2 = 0x95; - pTVar1 = this; - do { - if ((Unchain) && (pTVar1->KnownCreatureTable[0].State != KNOWNCREATURE_FREE)) { - UnchainKnownCreature(this,pTVar1->KnownCreatureTable[0].CreatureID); - } - pTVar1->KnownCreatureTable[0].Connection = this; - pTVar1->KnownCreatureTable[0].State = KNOWNCREATURE_FREE; - pTVar1->KnownCreatureTable[0].CreatureID = 0; - pTVar1 = (TConnection *)(pTVar1->InData + 0x10); - iVar2 = iVar2 + -1; - } while (-1 < iVar2); - return; -} - - - -// DWARF original prototype: void UnchainKnownCreature(TConnection * this, ulong ID) - -void __thiscall TConnection::UnchainKnownCreature(TConnection *this,ulong ID) - -{ - TKnownCreature *pTVar1; - TCreature *pTVar2; - TCreature *cr; - TKnownCreature *KnownCreature; - TKnownCreature *pTVar3; - - pTVar2 = GetCreature(ID); - if (pTVar2 == (TCreature *)0x0) { - this = (TConnection *)s_TUserCom__UnchainKnownCreature__K_08108a40; - } - else { - pTVar1 = pTVar2->FirstKnowingConnection; - if (pTVar1 != (TKnownCreature *)0x0) { - if (pTVar1->Connection == this) { - pTVar1->State = KNOWNCREATURE_FREE; - pTVar2->FirstKnowingConnection = pTVar1->Next; - } - else { - do { - pTVar3 = pTVar1; - pTVar1 = pTVar3->Next; - if (pTVar1 == (TKnownCreature *)0x0) { - this = (TConnection *)s_TUserCom__UnchainKnownCreature__K_081089c0; - goto LAB_080cbe0d; - } - } while (pTVar1->Connection != this); - pTVar1->State = KNOWNCREATURE_FREE; - pTVar3->Next = pTVar1->Next; - } - return; - } - this = (TConnection *)s_TUserCom__UnchainKnownCreature__K_08108a00; - } -LAB_080cbe0d: - error((char *)this); - return; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -TConnection * AssignFreeConnection(void) - -{ - int i; - int iVar1; - __pid_t _Var2; - TConnection *pTVar3; - - pTVar3 = Connections; - Semaphore::down(&ConnectionMutex); - iVar1 = 0; - do { - if (pTVar3->State == CONNECTION_FREE) { - pTVar3->State = CONNECTION_ASSIGNED; - _Var2 = getpid(); - pTVar3->PID = _Var2; - Semaphore::up(&ConnectionMutex); - return pTVar3; - } - iVar1 = iVar1 + 1; - pTVar3 = pTVar3 + 1; - } while (iVar1 < 0x44c); - Semaphore::up(&ConnectionMutex); - return (TConnection *)0x0; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -TConnection * GetFirstConnection(void) - -{ - TConnection *pTVar1; - - ConnectionIterator = -1; - pTVar1 = (TConnection *)(PlayerDataPool[0x7cd].QuestValues + 0x9a); - do { - ConnectionIterator = ConnectionIterator + 1; - if (pTVar1[1].State != CONNECTION_FREE) { - return pTVar1 + 1; - } - pTVar1 = pTVar1 + 1; - } while (ConnectionIterator < 1099); - return (TConnection *)0x0; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -TConnection * GetNextConnection(void) - -{ - TConnection *pTVar1; - - if (ConnectionIterator < 1099) { - pTVar1 = Connections + ConnectionIterator; - do { - ConnectionIterator = ConnectionIterator + 1; - if (pTVar1[1].State != CONNECTION_FREE) { - return pTVar1 + 1; - } - pTVar1 = pTVar1 + 1; - } while (ConnectionIterator < 1099); - } - return (TConnection *)0x0; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -void ProcessConnections(void) - -{ - TConnection *Connection; - TConnection *this; - TConnection *pTVar1; - - this = GetFirstConnection(); -joined_r0x080cbf6d: - do { - if (this == (TConnection *)0x0) { - return; - } - TConnection::Process(this); - if (ConnectionIterator < 1099) { - pTVar1 = Connections + ConnectionIterator; - do { - this = pTVar1 + 1; - ConnectionIterator = ConnectionIterator + 1; - if (pTVar1[1].State != CONNECTION_FREE) goto joined_r0x080cbf6d; - pTVar1 = this; - } while (ConnectionIterator < 1099); - } - this = (TConnection *)0x0; - } while( true ); -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -void InitConnections(void) - -{ - CONNECTIONSTATE *pCVar1; - - pCVar1 = &Connections[0].State; - do { - *pCVar1 = CONNECTION_FREE; - pCVar1 = pCVar1 + 0x147e; - } while ((int)pCVar1 < 0xa67ef89); - FirstSendingConnection = (TConnection *)0x0; - return; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -void ExitConnections(void) - -{ - return; -} - - - void __tcf_0(void *param_1) { diff --git a/src/communication.cc b/src/communication.cc index b959bb1..71a05d3 100644 --- a/src/communication.cc +++ b/src/communication.cc @@ -1366,7 +1366,18 @@ int HandleConnection(void *Data){ AttachCommunicationThreadStack(StackNumber); } - CommunicationThread(Socket); + try{ + CommunicationThread(Socket); + }catch(RESULT r){ + error("HandleConnection: Nicht abgefangene Exception %d.\n", r); + }catch(const char *str){ + error("HandleConnection: Nicht abgefangene Exception \"%s\".\n", str); + }catch(const std::exception &e){ + error("HandleConnection: Nicht abgefangene Exception %s.\n", e.what()); + }catch(...){ + error("HandleConnection: Nicht abgefangene Exception unbekannten Typs.\n"); + } + DecrementActiveConnections(); if(UseOwnStacks){ @@ -1390,13 +1401,13 @@ bool OpenSocket(void){ struct linger linger = {}; linger.l_onoff = 0; linger.l_linger = 0; - if(setsockopt(TCPSocket, SOL_SOCKET, SO_LINGER, &linger, sizeof(struct linger)) == -1){ + if(setsockopt(TCPSocket, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)) == -1){ error("LaunchServer: Socket wurde nicht auf LINGER=0 gesetzt.\n"); return false; } int reuseaddr = 1; - if(setsockopt(TCPSocket, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)) == -1){ + if(setsockopt(TCPSocket, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)) == -1){ error("LaunchServer: Fehler %d bei setsockopt.\n", errno); return false; } @@ -1405,10 +1416,10 @@ bool OpenSocket(void){ ServerAddress.sin_family = AF_INET; ServerAddress.sin_port = htons(GamePort); ServerAddress.sin_addr.s_addr = inet_addr(GameAddress); - if(bind(TCPSocket, (struct sockaddr*)&ServerAddress, sizeof(struct sockaddr_in)) == -1){ + if(bind(TCPSocket, (struct sockaddr*)&ServerAddress, sizeof(ServerAddress)) == -1){ error("LaunchServer: Fehler %d bei bind.\n", errno); print(1, "Bind Error Again -> Begin FloodBind :(\n"); - while(bind(TCPSocket, (struct sockaddr*)&ServerAddress, sizeof(struct sockaddr_in)) == -1){ + while(bind(TCPSocket, (struct sockaddr*)&ServerAddress, sizeof(ServerAddress)) == -1){ DelayThread(1, 0); } } @@ -1433,48 +1444,57 @@ int AcceptorThreadLoop(void *Unused){ continue; } - if(UseOwnStacks){ - int StackNumber; - void *Stack; - GetCommunicationThreadStack(&StackNumber, &Stack); - if(Stack == NULL){ - print(3,"Kein Stack-Bereich mehr frei.\n"); - if(close(Socket) == -1){ - error("AcceptorThreadLoop: Fehler %d beim Schließen der Socket (1).\n", errno); - } - }else{ - IncrementActiveConnections(); - void *Argument = (void*)(((uintptr)Socket & 0xFFFF) - | (((uintptr)StackNumber & 0xFFFF) << 16)); - ThreadHandle ConnectionThread = StartThread(HandleConnection, - Argument, Stack, COMMUNICATION_THREAD_STACK_SIZE, true); - if(ConnectionThread == INVALID_THREAD_HANDLE){ - DecrementActiveConnections(); - ReleaseCommunicationThreadStack(StackNumber); + // TODO(fusion): I don't think anything in here can throw any exception. + try{ + if(UseOwnStacks){ + int StackNumber; + void *Stack; + GetCommunicationThreadStack(&StackNumber, &Stack); + if(Stack == NULL){ + print(3,"Kein Stack-Bereich mehr frei.\n"); if(close(Socket) == -1){ - error("AcceptorThreadLoop: Fehler %d beim Schließen der Socket (2).\n", errno); + error("AcceptorThreadLoop: Fehler %d beim Schließen der Socket (1).\n", errno); + } + }else{ + IncrementActiveConnections(); + void *Argument = (void*)(((uintptr)Socket & 0xFFFF) + | (((uintptr)StackNumber & 0xFFFF) << 16)); + ThreadHandle ConnectionThread = StartThread(HandleConnection, + Argument, Stack, COMMUNICATION_THREAD_STACK_SIZE, true); + if(ConnectionThread == INVALID_THREAD_HANDLE){ + DecrementActiveConnections(); + ReleaseCommunicationThreadStack(StackNumber); + if(close(Socket) == -1){ + error("AcceptorThreadLoop: Fehler %d beim Schließen der Socket (2).\n", errno); + } } - } - } - }else{ - if(ActiveConnections >= MAX_COMMUNICATION_THREADS){ - print(3,"Keine Verbindung mehr frei.\n"); - if(close(Socket) == -1){ - error("AcceptorThreadLoop: Fehler %d beim Schließen der Socket (3).\n", errno); } }else{ - IncrementActiveConnections(); - void *Argument = (void*)((uintptr)Socket & 0xFFFF); - ThreadHandle ConnectionThread = StartThread(HandleConnection, - Argument, COMMUNICATION_THREAD_STACK_SIZE, true); - if(ConnectionThread == INVALID_THREAD_HANDLE){ - print(3, "Kann neuen Thread nicht anlegen.\n"); - DecrementActiveConnections(); + if(ActiveConnections >= MAX_COMMUNICATION_THREADS){ + print(3,"Keine Verbindung mehr frei.\n"); if(close(Socket) == -1){ - error("AcceptorThreadLoop: Fehler %d beim Schließen der Socket (4).\n", errno); + error("AcceptorThreadLoop: Fehler %d beim Schließen der Socket (3).\n", errno); + } + }else{ + IncrementActiveConnections(); + void *Argument = (void*)((uintptr)Socket & 0xFFFF); + ThreadHandle ConnectionThread = StartThread(HandleConnection, + Argument, COMMUNICATION_THREAD_STACK_SIZE, true); + if(ConnectionThread == INVALID_THREAD_HANDLE){ + print(3, "Kann neuen Thread nicht anlegen.\n"); + DecrementActiveConnections(); + if(close(Socket) == -1){ + error("AcceptorThreadLoop: Fehler %d beim Schließen der Socket (4).\n", errno); + } } } } + }catch(RESULT r){ + error("AcceptorThreadLoop: Nicht abgefangene Exception %d.\n", r); + }catch(const char *str){ + error("AcceptorThreadLoop: Nicht abgefangene Exception \"%s\".\n", str); + }catch(...){ + error("AcceptorThreadLoop: Nicht abgefangene Exception unbekannten Typs.\n"); } } diff --git a/src/connections.cc b/src/connections.cc new file mode 100644 index 0000000..2604a9e --- /dev/null +++ b/src/connections.cc @@ -0,0 +1,575 @@ +#include "connections.hh" +#include "cr.hh" +#include "info.hh" +#include "threads.hh" + +#include "stubs.hh" + +#include +#include +#include + +static Semaphore ConnectionMutex(1); +static int ConnectionIterator; +static TConnection *FirstSendingConnection; +static TConnection Connections[MAX_CONNECTIONS]; + +enum ClientCommand: int { + CL_CMD_LOGIN = 10, + CL_CMD_LOGIN_TREATED = 11, + CL_CMD_LOGOUT = 20, + CL_CMD_PING = 30, + CL_CMD_GO = 100, + CL_CMD_GO_NORTH = 101, + CL_CMD_GO_EAST = 102, + CL_CMD_GO_SOUTH = 103, + CL_CMD_GO_WEST = 104, + CL_CMD_GO_STOP = 105, + CL_CMD_GO_NORTHEAST = 106, + CL_CMD_GO_SOUTHEAST = 107, + CL_CMD_GO_SOUTHWEST = 108, + CL_CMD_GO_NORTHWEST = 109, + CL_CMD_ROTATE_NORTH = 111, + CL_CMD_ROTATE_EAST = 112, + CL_CMD_ROTATE_SOUTH = 113, + CL_CMD_ROTATE_WEST = 114, + CL_CMD_MOVE_OBJECT = 120, + CL_CMD_TRADE_OBJECT = 125, + CL_CMD_INSPECT_TRADE = 126, + CL_CMD_ACCEPT_TRADE = 127, + CL_CMD_REJECT_TRADE = 128, + CL_CMD_USE_OBJECT = 130, + CL_CMD_USE_TWO_OBJECTS = 131, + CL_CMD_USE_ON_CREATURE = 132, + CL_CMD_TURN_OBJECT = 133, + CL_CMD_CLOSE_CONTAINER = 135, + CL_CMD_UP_CONTAINER = 136, + CL_CMD_EDIT_TEXT = 137, + CL_CMD_EDIT_LIST = 138, + CL_CMD_LOOK_AT_POINT = 140, + CL_CMD_TALK = 150, + CL_CMD_GET_CHANNELS = 151, + CL_CMD_JOIN_CHANNEL = 152, + CL_CMD_LEAVE_CHANNEL = 153, + CL_CMD_PRIVATE_CHANNEL = 154, + CL_CMD_PROCESS_REQUEST = 155, + CL_CMD_REMOVE_REQUEST = 156, + CL_CMD_CANCEL_REQUEST = 157, + CL_CMD_SET_TACTICS = 160, + CL_CMD_ATTACK = 161, + CL_CMD_FOLLOW = 162, + CL_CMD_INVITE_TO_PARTY = 163, + CL_CMD_JOIN_PARTY = 164, + CL_CMD_REVOKE_INVITATION = 165, + CL_CMD_PASS_LEADERSHIP = 166, + CL_CMD_LEAVE_PARTY = 167, + CL_CMD_OPEN_CHANNEL = 170, + CL_CMD_INVITE_TO_CHANNEL = 171, + CL_CMD_EXCLUDE_FROM_CHANNEL = 172, + CL_CMD_CANCEL = 190, + CL_CMD_REFRESH_FIELD = 201, + CL_CMD_REFRESH_CONTAINER = 202, + CL_CMD_GET_OUTFIT = 210, + CL_CMD_SET_OUTFIT = 211, + CL_CMD_ADD_BUDDY = 220, + CL_CMD_REMOVE_BUDDY = 221, + CL_CMD_BUG_REPORT = 230, + CL_CMD_RULE_VIOLATION = 231, + CL_CMD_ERROR_FILE_ENTRY = 232, +}; + +enum ServerCommand: int { + SV_CMD_LOGIN_ERROR = 20, + SV_CMD_LOGIN_PREMIUM = 21, + SV_CMD_LOGIN_WAITINGLIST = 22, +}; + +// TConnection +// ============================================================================= +TConnection::TConnection(void){ + this->State = CONNECTION_FREE; +} + +void TConnection::Process(void){ + if(this->InGame()){ + uint32 LastCommand = (RoundNr - this->TimeStamp); + if(LastCommand == 30 || LastCommand == 60){ + SendPing(this); + } + + uint32 LastAction = (RoundNr - this->TimeStampAction); + if(LastAction == 900 && !CheckRight(this->CharacterID, NO_LOGOUT_BLOCK)){ + SendMessage(this, TALK_ADMIN_MESSAGE, + "You have been idle for %d minutes. You will be disconnected" + " in one minute if you are still idle then.", 15); + } + + if(LastAction >= 960 && !CheckRight(this->CharacterID, NO_LOGOUT_BLOCK)){ + this->Logout(0, true); + }else if(!GameRunning() || !this->ConnectionIsOk || (LastCommand >= 90)){ + this->Logout(0, false); + } + }else if(this->State == CONNECTION_LOGIN){ + if(!GameRunning() || !this->ConnectionIsOk){ + this->Disconnect(); + } + }else if(this->State == CONNECTION_LOGOUT){ + // NOTE(fusion): `TimeStamp` has the logout round which is set by + // `TConnection::Logout`. + if(!GameRunning() || !this->ConnectionIsOk || this->TimeStamp <= RoundNr){ + this->Disconnect(); + } + } +} + +void TConnection::ResetTimer(int Command){ + if(this->InGame()){ + this->TimeStamp = RoundNr; + if(Command != CL_CMD_PING + && Command != CL_CMD_GO_STOP + && Command != CL_CMD_CANCEL + && Command != CL_CMD_REFRESH_FIELD + && Command != CL_CMD_REFRESH_CONTAINER){ + this->TimeStampAction = RoundNr; + } + } +} + +void TConnection::EmergencyPing(void){ + if(this->InGame()){ + uint32 LastCommand = (RoundNr - this->TimeStamp); + if(LastCommand < 80){ + // TODO(fusion): This is only called by `NetLoadCheck`, when it detects + // lag, which can only happen after some set number of rounds, usually + // higher than 100. This is all to say this subtraction below is very + // unlikely to wrap. Nevertheless, we should also have some helper + // functions to do saturating addition or subtraction for both signed + // and unsigned integers. + this->TimeStamp = RoundNr - 100; + } + SendPing(this); + } +} + +pid_t TConnection::GetPID(void){ + if(this->State == CONNECTION_FREE){ + error("TConnection::GetPID: Verbindung ist nicht zugewiesen.\n"); + return 0; + } + + return this->PID; +} + +int TConnection::GetSocket(void){ + if(this->State == CONNECTION_FREE || this->State == CONNECTION_ASSIGNED){ + error("TConnection::GetSocket: Verbindung ist nicht angeschlossen.\n"); + return -1; + } + + return this->Socket; +} + +const char *TConnection::GetIPAddress(void){ + if(this->State == CONNECTION_FREE || this->State == CONNECTION_ASSIGNED){ + error("TConnection::GetIPAddress: Verbindung ist nicht angeschlossen.\n"); + return "Unknown"; + } + + return this->IPAddress; +} + +void TConnection::Free(void){ + this->State = CONNECTION_FREE; +} + +void TConnection::Assign(void){ + if(this->State != CONNECTION_FREE){ + error("TConnection::Assign: Verbindung ist nicht frei.\n"); + } + + this->State = CONNECTION_ASSIGNED; + this->PID = getpid(); +} + +void TConnection::Connect(int Socket){ + if(this->State != CONNECTION_ASSIGNED){ + error("TConnection::Connect: Verbindung ist keinem Thread zugewiesen.\n"); + } + + this->State = CONNECTION_CONNECTED; + this->Socket = Socket; + this->ConnectionIsOk = true; + this->ClosingIsDelayed = true; + this->RandomSeed = rand(); + + struct sockaddr_in RemoteAddr; + socklen_t RemoteAddrLen = sizeof(RemoteAddr); + getpeername(Socket, (struct sockaddr*)&RemoteAddr, &RemoteAddrLen); + strcpy(this->IPAddress, inet_ntoa(RemoteAddr.sin_addr)); +} + +void TConnection::Login(void){ + if(this->State != CONNECTION_CONNECTED){ + error("TConnection::Connect: Ungültiger Verbindungs-Zustand %d.\n", this->State); + } + + this->State = CONNECTION_LOGIN; +} + +bool TConnection::JoinGame(TReadBuffer *Buffer){ + if(this->State != CONNECTION_LOGIN){ + error("TConnection::JoinGame: Ungültiger Verbindungszustand %d.\n", this->State); + } + + this->ClearKnownCreatureTable(false); + + try{ + this->TerminalType = (int)Buffer->readWord(); + this->TerminalVersion = (int)Buffer->readWord(); + this->CharacterID = Buffer->readQuad(); + }catch(const char *str){ + error("TConnection::JoinGame: Fehler beim Auslesen des Puffers (%s).\n", str); + } + + if(this->TerminalType != 1 && this->TerminalType != 2){ + error("TConnection::JoinGame: Unbekannter Terminal-Typ %d.\n", this->TerminalType); + return false; + } + + this->TerminalOffsetX = 8; + this->TerminalOffsetY = 6; + this->TerminalWidth = 18; + this->TerminalHeight = 14; + + TPlayer *Player = ::GetPlayer(this->CharacterID); + if(Player == NULL){ + Player = new TPlayer(this, this->CharacterID); + if(Player->ConstructError != NOERROR){ + delete Player; + return false; + } + }else{ + if(Player->IsDead){ + Log("game", "Spieler %s ist gerade am Sterben - Einloggen gescheitert.\n", Player->Name); + DecreasePlayerPoolSlotSticky(this->CharacterID); + return false; + } + + if(Player->LoggingOut && Player->LogoutPossible() == 0){ + Log("game", "Spieler %s loggt gerade aus - Einloggen gescheitert.\n", Player->Name); + DecreasePlayerPoolSlotSticky(this->CharacterID); + return false; + } + + TConnection *OldConnection = Player->Connection; + Player->ClearConnection(); + if(OldConnection != NULL){ + OldConnection->CharacterID = 0; + OldConnection->Logout(0, true); + } + + DecrementIsOnlineOrder(this->CharacterID); + Player->TakeOver(this); + } + + strcpy(this->Name, Player->Name); + this->TimeStamp = RoundNr; + this->TimeStampAction = RoundNr; + return true; +} + +void TConnection::EnterGame(void){ + if(this->State != CONNECTION_LOGIN){ + error("TConnection::EnterGame: Ungültiger Verbindungszustand %d.\n", this->State); + } + + this->State = CONNECTION_GAME; +} + +void TConnection::Die(void){ + if(this->State == CONNECTION_GAME){ + this->State = CONNECTION_DEAD; + } +} + +void TConnection::Logout(int Delay, bool StopFight){ + if(!this->InGame() && this->State != CONNECTION_LOGOUT){ + error("TConnection::Logout: Ungültiger Verbindungszustand %d.\n", this->State); + } + + this->State = CONNECTION_LOGOUT; + if(this->CharacterID != 0){ + TPlayer *Player = ::GetPlayer(this->CharacterID); + if(Player != NULL){ + Player->ClearConnection(); + Player->StartLogout(false, StopFight); + } + } + + if(Delay < 0){ + Delay = 0; + } + + this->CharacterID = 0; + this->TimeStamp = RoundNr + (uint32)Delay; + this->ClosingIsDelayed = false; +} + +void TConnection::Close(bool Delay){ + if(this->State == CONNECTION_FREE || this->State == CONNECTION_ASSIGNED){ + error("TConnection::Close: Ungültiger Verbindungszustand %d.\n", this->State); + } + + if(this->State == CONNECTION_CONNECTED){ + this->State = CONNECTION_DISCONNECTED; + } + + this->ConnectionIsOk = false; + this->ClosingIsDelayed = Delay; +} + +void TConnection::Disconnect(void){ + if(this->State == CONNECTION_FREE || this->State == CONNECTION_ASSIGNED){ + error("TConnection::Close: Ungültiger Verbindungszustand %d.\n", this->State); + } + + this->ClearKnownCreatureTable(true); + this->ConnectionIsOk = false; + this->State = CONNECTION_DISCONNECTED; + kill(this->PID, SIGHUP); +} + +TPlayer *TConnection::GetPlayer(void){ + if(!this->Live()){ + error("TConnection::GetPlayer: Ungültiger Verbindungszustand %d.\n", this->State); + return NULL; + } + + TPlayer *Player = NULL; + if(this->CharacterID != 0){ + Player = ::GetPlayer(this->CharacterID); + } + return Player; +} + +const char *TConnection::GetName(void){ + if(!this->Live()){ + error("TConnection::GetName: Ungültiger Verbindungszustand %d.\n", this->State); + return ""; + } + + return this->Name; +} + +void TConnection::GetPosition(int *x, int *y, int *z){ + TPlayer *Player = this->GetPlayer(); + if(Player != NULL){ + *x = Player->posx; + *y = Player->posy; + *z = Player->posz; + }else{ + *x = 0; + *y = 0; + *z = 0; + } +} + +bool TConnection::IsVisible(int x, int y, int z){ + int PlayerX, PlayerY, PlayerZ; + this->GetPosition(&PlayerX, &PlayerY, &PlayerZ); + + // NOTE(fusion): The player can see only floors above ground when above + // ground, or two floors up and down when underground. + if(PlayerZ <= 7){ + if(z > 7){ + return false; + } + }else{ + if(std::abs(PlayerZ - z) > 2){ + return false; + } + } + + int MinX = (PlayerX - this->TerminalOffsetX) + (PlayerZ - z); + int MinY = (PlayerY - this->TerminalOffsetY) + (PlayerZ - z); + int MaxX = MinX + this->TerminalWidth - 1; + int MaxY = MinY + this->TerminalHeight - 1; + return x >= MinX && x <= MaxX + && y >= MinY && y <= MaxY; +} + +KNOWNCREATURESTATE TConnection::KnownCreature(uint32 ID, bool UpdateFollows){ + int EntryIndex = -1; + for(int i = 0; i < NARRAY(this->KnownCreatureTable); i += 1){ + if(this->KnownCreatureTable[i].CreatureID == ID){ + EntryIndex = i; + break; + } + } + + if(EntryIndex == -1){ + return KNOWNCREATURE_FREE; + } + + KNOWNCREATURESTATE Result = this->KnownCreatureTable[EntryIndex].State; + if(Result == KNOWNCREATURE_OUTDATED && UpdateFollows){ + this->KnownCreatureTable[EntryIndex].State = KNOWNCREATURE_UPTODATE; + } + return Result; +} + +uint32 TConnection::NewKnownCreature(uint32 NewID){ + uint32 OldID = 0; + int EntryIndex = -1; + for(int i = 0; i < NARRAY(this->KnownCreatureTable); i += 1){ + if(this->KnownCreatureTable[i].CreatureID == NewID){ + OldID = NewID; + EntryIndex = i; + break; + } + } + + if(EntryIndex == -1){ + for(int i = 0; i < NARRAY(this->KnownCreatureTable); i += 1){ + if(this->KnownCreatureTable[i].State == KNOWNCREATURE_FREE){ + OldID = this->KnownCreatureTable[i].CreatureID; + EntryIndex = i; + break; + } + } + } + + if(EntryIndex == -1){ + for(int i = 0; i < NARRAY(this->KnownCreatureTable); i += 1){ + TCreature *Creature = GetCreature(this->KnownCreatureTable[i].CreatureID); + if(Creature == NULL || !this->IsVisible(Creature->posx, Creature->posy, Creature->posz)){ + OldID = this->KnownCreatureTable[i].CreatureID; + EntryIndex = i; + this->UnchainKnownCreature(OldID); + break; + } + } + } + + if(EntryIndex == -1){ + print(3, "KnownCreatureTable ausgelastet.\n"); + return 0; + } + + if(this->KnownCreatureTable[EntryIndex].State != KNOWNCREATURE_FREE){ + error("TUserCom::NewKnownCreature: Slot ist nicht gelöscht.\n"); + } + + this->KnownCreatureTable[EntryIndex].State = KNOWNCREATURE_UPTODATE; + this->KnownCreatureTable[EntryIndex].CreatureID = NewID; + + TCreature *Creature = GetCreature(NewID); + if(Creature != NULL){ + this->KnownCreatureTable[EntryIndex].Next = Creature->FirstKnowingConnection; + Creature->FirstKnowingConnection = &this->KnownCreatureTable[EntryIndex]; + }else{ + error("TUserCom::NewKnownCreature: Kreatur %u existiert nicht.\n", NewID); + } + + return OldID; +} + +void TConnection::ClearKnownCreatureTable(bool Unchain){ + for(int i = 0; i < NARRAY(this->KnownCreatureTable); i += 1){ + if(Unchain && this->KnownCreatureTable[i].State != KNOWNCREATURE_FREE){ + this->UnchainKnownCreature(this->KnownCreatureTable[i].CreatureID); + } + this->KnownCreatureTable[i].State = KNOWNCREATURE_FREE; + this->KnownCreatureTable[i].CreatureID = 0; + this->KnownCreatureTable[i].Connection = this; + } +} + +void TConnection::UnchainKnownCreature(uint32 ID){ + TCreature *Creature = GetCreature(ID); + if(Creature == NULL){ + error("TUserCom::UnchainKnownCreature: Kreatur %u existiert nicht.\n", ID); + return; + } + + if(Creature->FirstKnowingConnection == NULL){ + error("TUserCom::UnchainKnownCreature: Kreatur %u kennt niemand.\n", ID); + return; + } + + TKnownCreature *Prev = NULL; + TKnownCreature *Cur = Creature->FirstKnowingConnection; + while(Cur != NULL){ + if(Cur->Connection == this){ + break; + } + Prev = Cur; + Cur = Cur->Next; + } + + if(Cur == NULL){ + error("TUserCom::UnchainKnownCreature: Kreatur %u ist nicht bekannt.\n", ID); + return; + } + + Cur->State = KNOWNCREATURE_FREE; + if(Prev == NULL){ + Creature->FirstKnowingConnection = Cur->Next; + }else{ + Prev->Next = Cur->Next; + } +} + +// Connection Utility +// ============================================================================= +TConnection *AssignFreeConnection(void){ + TConnection *Connection = NULL; + ConnectionMutex.down(); + for(int i = 0; i < MAX_CONNECTIONS; i += 1){ + if(Connections[i].State == CONNECTION_FREE){ + Connection = &Connections[i]; + Connection->Assign(); + break; + } + } + ConnectionMutex.up(); + return Connection; +} + +TConnection *GetFirstConnection(void){ + ConnectionIterator = 0; + return GetNextConnection(); +} + +TConnection *GetNextConnection(void){ + TConnection *NextConnection = NULL; + while(ConnectionIterator < MAX_CONNECTIONS){ + TConnection *Connection = &Connections[ConnectionIterator]; + ConnectionIterator += 1; + if(Connection->State != CONNECTION_FREE){ + NextConnection = Connection; + break; + } + } + return NextConnection; +} + +void ProcessConnections(void){ + TConnection *Connection = GetFirstConnection(); + while(Connection != NULL){ + Connection->Process(); + Connection = GetNextConnection(); + } +} + +void InitConnections(void){ + ConnectionIterator = 0; + FirstSendingConnection = NULL; + for(int i = 0; i < MAX_CONNECTIONS; i += 1){ + Connections[i].State = CONNECTION_FREE; + } +} + +void ExitConnections(void){ + // no-op +} diff --git a/src/connections.hh b/src/connections.hh index 79462c5..921a604 100644 --- a/src/connections.hh +++ b/src/connections.hh @@ -1,5 +1,5 @@ -#ifndef TIBIA_CONNECTION_HH_ -#define TIBIA_CONNECTION_HH_ 1 +#ifndef TIBIA_CONNECTIONS_HH_ +#define TIBIA_CONNECTIONS_HH_ 1 #include "common.hh" #include "crypto.hh" @@ -8,6 +8,11 @@ struct TConnection; struct TPlayer; +// TODO(fusion): The maximum number of connections should probably be kept in +// sync with the maximum number of communication threads, or maybe it is the +// same constant. +#define MAX_CONNECTIONS 1100 + struct TKnownCreature { KNOWNCREATURESTATE State; uint32 CreatureID; @@ -16,23 +21,37 @@ struct TKnownCreature { }; struct TConnection { - TPlayer *GetPlayer(void); - void Logout(int Delay, bool StopFight); - bool IsVisible(int x, int y, int z); - void EnterGame(void); - const char *GetIPAddress(void); - void Die(void); - KNOWNCREATURESTATE KnownCreature(uint32 CreatureID, bool UpdateFollows); - int GetSocket(void); + TConnection(void); + void Process(void); + void ResetTimer(int Command); void EmergencyPing(void); - void Login(void); - const char *GetName(void); + pid_t GetPID(void); + int GetSocket(void); + const char *GetIPAddress(void); + void Free(void); + void Assign(void); void Connect(int Socket); + void Login(void); + bool JoinGame(TReadBuffer *Buffer); + void EnterGame(void); + void Die(void); + void Logout(int Delay, bool StopFight); void Close(bool Delay); - void Free(void); - pid_t GetPID(void); + void Disconnect(void); + TPlayer *GetPlayer(void); + const char *GetName(void); + void GetPosition(int *x, int *y, int *z); + bool IsVisible(int x, int y, int z); + KNOWNCREATURESTATE KnownCreature(uint32 ID, bool UpdateFollows); + uint32 NewKnownCreature(uint32 NewID); + void ClearKnownCreatureTable(bool Unchain); + void UnchainKnownCreature(uint32 ID); + + bool InGame(void) const { + return this->State == CONNECTION_GAME + || this->State == CONNECTION_DEAD; + } - // TODO(fusion): Maybe rename this later? bool Live(void) const { return this->State == CONNECTION_LOGIN || this->State == CONNECTION_GAME @@ -47,15 +66,11 @@ struct TConnection { bool SigIOPending; bool WaitingForACK; uint8 OutData[16384]; - uint8 field5_0x4806; - uint8 field6_0x4807; int NextToSend; int NextToCommit; int NextToWrite; bool Overflow; bool WillingToSend; - uint8 field12_0x4816; - uint8 field13_0x4817; TConnection *NextSendingConnection; uint32 RandomSeed; CONNECTIONSTATE State; @@ -65,8 +80,6 @@ struct TConnection { TXTEASymmetricKey SymmetricKey; bool ConnectionIsOk; bool ClosingIsDelayed; - uint8 field23_0x4852; - uint8 field24_0x4853; uint32 TimeStamp; uint32 TimeStampAction; int TerminalType; @@ -77,8 +90,14 @@ struct TConnection { int TerminalHeight; uint32 CharacterID; char Name[31]; - uint8 field35_0x4897; TKnownCreature KnownCreatureTable[150]; }; -#endif // TIBIA_CONNECTION_HH_ +TConnection *AssignFreeConnection(void); +TConnection *GetFirstConnection(void); +TConnection *GetNextConnection(void); +void ProcessConnections(void); +void InitConnections(void); +void ExitConnections(void); + +#endif // TIBIA_CONNECTIONS_HH_ diff --git a/src/main.cc b/src/main.cc index 8d5fcf5..f4df04d 100644 --- a/src/main.cc +++ b/src/main.cc @@ -219,8 +219,8 @@ static void InitAll(void){ //InitLog("game"); srand(time(NULL)); InitSignalHandler(); - //InitConnections(); - //InitCommunication(); + InitConnections(); + InitCommunication(); InitStrings(); //InitWriter(); //InitReader(); @@ -254,8 +254,8 @@ static void ExitAll(void){ //ExitReader(); //ExitWriter(); ExitStrings(); - //ExitCommunication(); - //ExitConnections(); + ExitCommunication(); + ExitConnections(); ExitSignalHandler(); ExitSHM(); } diff --git a/src/stubs.hh b/src/stubs.hh index a749c8c..61114c4 100644 --- a/src/stubs.hh +++ b/src/stubs.hh @@ -17,7 +17,6 @@ typedef void TSendMailsFunction(TPlayerData *PlayerData); extern void AbortWriter(void); extern void AddBuddyOrder(TCreature *Creature, uint32 CharacterID); -extern TConnection *AssignFreeConnection(void); extern void RemoveBuddyOrder(TCreature *Creature, uint32 BuddyID); extern void BroadcastMessage(int Mode, const char *Text, ...) ATTR_PRINTF(2, 3); extern void ChangeNPCState(TCreature *Npc, int NewState, bool Stimulus); @@ -27,10 +26,9 @@ extern void CleanHouseField(int x, int y, int z); extern void ConvinceMonster(TCreature *Master, TCreature *Slave); extern void ChallengeMonster(TCreature *Challenger, TCreature *Monster); extern TCreature *CreateMonster(int Race, int x, int y, int z, int Home, uint32 Master, bool ShowEffect); +extern void DecrementIsOnlineOrder(uint32 CharacterID); extern void DeleteGamemasterRequest(const char *Name); extern void GetExitPosition(uint16 HouseID, int *x, int *y, int *z); -extern TConnection *GetFirstConnection(void); -extern TConnection *GetNextConnection(void); extern int GetOrderBufferSpace(void); extern const char *GetHouseName(uint16 HouseID); extern const char *GetHouseOwner(uint16 HouseID); @@ -44,7 +42,6 @@ extern void LogoutOrder(TPlayer *Player); 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); @@ -98,6 +95,7 @@ extern void SendMarkCreature(TConnection *Connection, uint32 CreatureID, int Col extern void SendMessage(TConnection *Connection, int Mode, const char *Text, ...) ATTR_PRINTF(3, 4); extern void SendMoveCreature(TConnection *Connection, uint32 CreatureID, int x, int y, int z); extern void SendOpenOwnChannel(TConnection *Connection, int Channel); +extern void SendPing(TConnection *Connection); extern void SendPlayerData(TConnection *Connection); extern void SendPlayerSkills(TConnection *Connection); extern void SendPlayerState(TConnection *Connection, uint8 State); -- cgit v1.2.3