aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--TODO.md10
-rw-r--r--reference/game.c980
-rw-r--r--src/communication.cc98
-rw-r--r--src/connections.cc575
-rw-r--r--src/connections.hh65
-rw-r--r--src/main.cc8
-rw-r--r--src/stubs.hh6
8 files changed, 691 insertions, 1057 deletions
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 <arpa/inet.h>
+#include <netinet/in.h>
+#include <signal.h>
+
+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);