diff options
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | src/communication.cc | 32 | ||||
| -rw-r--r-- | src/containers.hh | 4 | ||||
| -rw-r--r-- | src/crmain.cc | 11 | ||||
| -rw-r--r-- | src/crnonpl.cc | 31 | ||||
| -rw-r--r-- | src/crplayer.cc | 5 | ||||
| -rw-r--r-- | src/crypto.cc | 15 | ||||
| -rw-r--r-- | src/crypto.hh | 4 | ||||
| -rw-r--r-- | src/houses.cc | 40 | ||||
| -rw-r--r-- | src/map.cc | 34 | ||||
| -rw-r--r-- | src/moveuse.cc | 12 | ||||
| -rw-r--r-- | src/objects.cc | 4 | ||||
| -rw-r--r-- | src/operate.cc | 34 | ||||
| -rw-r--r-- | src/query.cc | 4 | ||||
| -rw-r--r-- | src/strings.cc | 11 | ||||
| -rw-r--r-- | src/threads.cc | 24 | ||||
| -rw-r--r-- | src/writer.cc | 12 |
17 files changed, 165 insertions, 114 deletions
@@ -137,5 +137,5 @@ $(BUILDDIR)/writer.obj: $(SRCDIR)/writer.cc $(HEADERS) .PHONY: clean clean: - @rm -r $(BUILDDIR) + @rm -rf $(BUILDDIR) diff --git a/src/communication.cc b/src/communication.cc index a15e20a..a2c4221 100644 --- a/src/communication.cc +++ b/src/communication.cc @@ -23,7 +23,7 @@ #define MAX_COMMUNICATION_THREADS 1100 #define COMMUNICATION_THREAD_STACK_SIZE ((int)KB(64)) -static int TERMINALVERSION[3] = {770, 770, 770}; +static int TERMINALVERSION[] = {770, 770, 770}; static int TCPSocket; static ThreadHandle AcceptorThread; static pid_t AcceptorThreadPID; @@ -710,12 +710,12 @@ TPlayerData *PerformRegistration(TConnection *Connection, char *PlayerName, char BuddyNames[100][30]; // MAX_BUDDIES, MAX_NAME_LENGTH ? uint8 Rights[12]; // MAX_RIGHT_BYTES ? bool PremiumAccountActivated; - int Status = QueryManagerConnection->loginGame(AccountID, PlayerName, + int LoginCode = QueryManagerConnection->loginGame(AccountID, PlayerName, PlayerPassword, Connection->GetIPAddress(), PrivateWorld, false, GamemasterClient, &CharacterID, &Sex, Guild, Rank, Title, &NumberOfBuddies, BuddyIDs, BuddyNames, Rights, &PremiumAccountActivated); - switch(Status){ + switch(LoginCode){ case 0:{ // NOTE(fusion): Login successful. break; @@ -845,6 +845,8 @@ TPlayerData *PerformRegistration(TConnection *Connection, char *PlayerName, return NULL; } + // TODO(fusion): This should probably checked beforehand or also dispatch + // `decrementIsOnline`. if(AccountID == 0){ error("PerformRegistration: Spieler %s wurde noch keinem Account zugewiesen.\n", PlayerName); SendLoginMessage(Connection, 20, @@ -925,22 +927,20 @@ bool HandleLogin(TConnection *Connection){ char PlayerName[30]; char PlayerPassword[30]; try{ - uint8 AssymmetricData[128]; - InputBuffer.readBytes(AssymmetricData, 128); + uint8 AsymmetricData[128]; + InputBuffer.readBytes(AsymmetricData, 128); RSAMutex.down(); - try{ - PrivateKey.decrypt(AssymmetricData); - }catch(const char *str){ + if(!PrivateKey.decrypt(AsymmetricData)){ RSAMutex.up(); - error("HandleLogin: Fehler beim Entschlüsseln (%s).\n", str); + error("HandleLogin: Fehler beim Entschlüsseln.\n"); SendLoginMessage(Connection, 20, "Login failed due to corrupt data.",-1); return false; } RSAMutex.up(); - TReadBuffer ReadBuffer(AssymmetricData, 128); - ReadBuffer.readByte(); + TReadBuffer ReadBuffer(AsymmetricData, 128); + ReadBuffer.readByte(); // always zero Connection->SymmetricKey.init(&ReadBuffer); TerminalType = (int)ReadBuffer.readWord(); TerminalVersion = (int)ReadBuffer.readWord(); @@ -1037,7 +1037,7 @@ bool HandleLogin(TConnection *Connection){ return false; } - bool SlotLocked = Slot->Locked == getpid(); + bool SlotLocked = (Slot->Locked == getpid()); // NOTE(fusion): These checks would have been already made if the player was // in the waiting list so they'd be redundant. @@ -1425,9 +1425,7 @@ int AcceptorThreadLoop(void *Unused){ AcceptorThreadPID = getpid(); print(1, "Warte auf Clients...\n"); while(GameRunning()){ - struct sockaddr_in RemoteAddr = {}; - socklen_t RemoteAddrLen = sizeof(RemoteAddr); - int Socket = accept(TCPSocket, (struct sockaddr*)&RemoteAddr, &RemoteAddrLen); + int Socket = accept(TCPSocket, NULL, NULL); if(Socket == -1){ error("AcceptorThreadLoop: Fehler %d beim Accept.\n", errno); continue; @@ -1525,7 +1523,9 @@ void InitCommunication(void){ QueryManagerConnectionPool.init(); // TODO(fusion): This is arbitrary, should probably be set in the config. - PrivateKey.initFromFile("tibia.pem"); + if(!PrivateKey.initFromFile("tibia.pem")){ + throw "cannot load RSA key"; + } OpenSocket(); if(TCPSocket == -1){ diff --git a/src/containers.hh b/src/containers.hh index 1ff9896..25a368f 100644 --- a/src/containers.hh +++ b/src/containers.hh @@ -323,9 +323,11 @@ struct matrix3d{ this->xmin = xmin; this->ymin = ymin; + this->zmin = zmin; this->dx = dx; this->dy = dy; - this->entry = new T[dx * dy]; + this->dz = dz; + this->entry = new T[dx * dy * dz]; } matrix3d(int xmin, int xmax, int ymin, int ymax, int zmin, int zmax, T init) diff --git a/src/crmain.cc b/src/crmain.cc index 96ccc92..1faee30 100644 --- a/src/crmain.cc +++ b/src/crmain.cc @@ -1140,7 +1140,6 @@ void AddKillStatistics(int AttackerRace, int DefenderRace){ KilledCreatures[DefenderRace] += 1; } - // NOTE(fusion): This seems to track how many players are killed by if(strcmp(RaceData[DefenderRace].Name, "human") == 0){ KilledPlayers[AttackerRace] += 1; } @@ -1458,7 +1457,7 @@ void LoadRace(const char *FileName){ }else if(strcmp(Identifier, "flags") == 0){ Script.readSymbol('{'); do{ - const char *Flag = Script.getIdentifier(); + const char *Flag = Script.readIdentifier(); if(strcmp(Flag, "kickboxes") == 0){ Race->KickBoxes = true; }else if(strcmp(Flag, "kickcreatures") == 0){ @@ -1800,17 +1799,17 @@ void LoadMonsterRaid(const char *FileName, int Start, Script.nextToken(); if(strcmp(Script.getIdentifier(), "date") == 0){ Script.readSymbol('='); - *Date = Script.getNumber(); + *Date = Script.readNumber(); }else if(strcmp(Script.getIdentifier(), "interval") == 0){ Script.readSymbol('='); - *Interval = Script.getNumber(); + *Interval = Script.readNumber(); }else{ Script.error("date or interval expected"); } Script.nextToken(); while(Script.Token != ENDOFFILE){ - if(strcmp(Script.getIdentifier(), "delay") == 0){ + if(strcmp(Script.getIdentifier(), "delay") != 0){ Script.error("delay expected"); } @@ -1928,7 +1927,7 @@ void LoadMonsterRaids(void){ SecondsToReboot += 86400; } - char BigRaidName[4096]; + char BigRaidName[4096] = {}; int BigRaidDuration = 0; int BigRaidTieBreaker = -1; diff --git a/src/crnonpl.cc b/src/crnonpl.cc index 277e2e6..b841d18 100644 --- a/src/crnonpl.cc +++ b/src/crnonpl.cc @@ -303,7 +303,6 @@ TBehaviourDatabase::TBehaviourDatabase(TReadScriptFile *Script) : if(!Ok){ TBehaviourNode *Left = this->readTerm(Script); - Script->nextToken(); if(Script->Token != SPECIAL){ Script->error("relational operator expected"); } @@ -326,9 +325,10 @@ TBehaviourDatabase::TBehaviourDatabase(TReadScriptFile *Script) : TBehaviourNode *Right = this->readTerm(Script); Behaviour->addCondition(BEHAVIOUR_CONDITION_EXPRESSION, NewBehaviourNode(Operator, Right, Left)); + }else{ + Script->nextToken(); } - Script->nextToken(); if(Script->Token == SPECIAL && Script->getSpecial() == ','){ Script->nextToken(); }else{ @@ -346,6 +346,7 @@ TBehaviourDatabase::TBehaviourDatabase(TReadScriptFile *Script) : while(true){ if(Script->Token == STRING){ Behaviour->addAction(BEHAVIOUR_ACTION_REPLY, Script->getString(), NULL, NULL, NULL); + Script->nextToken(); }else if(Script->Token == IDENTIFIER){ int Type = -1; int Data = 0; @@ -423,7 +424,7 @@ TBehaviourDatabase::TBehaviourDatabase(TReadScriptFile *Script) : switch(Type){ case BEHAVIOUR_ACTION_NONE:{ - // no-op + Script->nextToken(); break; } @@ -432,7 +433,6 @@ TBehaviourDatabase::TBehaviourDatabase(TReadScriptFile *Script) : Script->readSymbol('='); Script->nextToken(); TBehaviourNode *Value = this->readTerm(Script); - Behaviour->addAction(Type, &Data, Value, NULL, NULL); break; } @@ -444,7 +444,7 @@ TBehaviourDatabase::TBehaviourDatabase(TReadScriptFile *Script) : if(Script->Token != SPECIAL || Script->getSpecial() != ')'){ Script->error(") expected"); } - + Script->nextToken(); Behaviour->addAction(Type, &Data, Param, NULL, NULL); break; } @@ -452,50 +452,46 @@ TBehaviourDatabase::TBehaviourDatabase(TReadScriptFile *Script) : case BEHAVIOUR_ACTION_FUNCTION2: case BEHAVIOUR_ACTION_SET_SKILL_TIMER:{ Script->readSymbol('('); - Script->nextToken(); TBehaviourNode *Param1 = this->readTerm(Script); if(Script->Token != SPECIAL || Script->getSpecial() != ','){ Script->error(", expected"); } - Script->nextToken(); TBehaviourNode *Param2 = this->readTerm(Script); if(Script->Token != SPECIAL || Script->getSpecial() != ')'){ Script->error(") expected"); } - + Script->nextToken(); Behaviour->addAction(Type, &Data, Param1, Param2, NULL); break; } case BEHAVIOUR_ACTION_FUNCTION0: case BEHAVIOUR_ACTION_CHANGESTATE:{ + Script->nextToken(); Behaviour->addAction(Type, &Data, NULL, NULL, NULL); break; } case BEHAVIOUR_ACTION_FUNCTION3:{ Script->readSymbol('('); - Script->nextToken(); TBehaviourNode *Param1 = this->readTerm(Script); if(Script->Token != SPECIAL || Script->getSpecial() != ','){ Script->error(", expected"); } - Script->nextToken(); TBehaviourNode *Param2 = this->readTerm(Script); if(Script->Token != SPECIAL || Script->getSpecial() != ','){ Script->error(", expected"); } - Script->nextToken(); TBehaviourNode *Param3 = this->readTerm(Script); if(Script->Token != SPECIAL || Script->getSpecial() != ')'){ Script->error(") expected"); } - + Script->nextToken(); Behaviour->addAction(Type, &Data, Param1, Param2, Param3); break; } @@ -505,16 +501,17 @@ TBehaviourDatabase::TBehaviourDatabase(TReadScriptFile *Script) : break; } } + }else if(Script->Token == SPECIAL && Script->getSpecial() == '*'){ if(this->Behaviours == 0){ Script->error("no previous pattern"); } + Script->nextToken(); Behaviour->addAction(BEHAVIOUR_ACTION_REPEAT, NULL, NULL, NULL, NULL); }else{ Script->error("illegal action"); } - Script->nextToken(); if(Script->Token == SPECIAL && Script->getSpecial() == ','){ Script->nextToken(); }else{ @@ -529,7 +526,7 @@ TBehaviourDatabase::TBehaviourDatabase(TReadScriptFile *Script) : TBehaviourNode *TBehaviourDatabase::readValue(TReadScriptFile *Script){ TBehaviourNode *Node = NULL; if(Script->Token == NUMBER){ - Node = NewBehaviourNode(BEHAVIOUR_NODE_NUMBER, Script->readNumber()); + Node = NewBehaviourNode(BEHAVIOUR_NODE_NUMBER, Script->getNumber()); }else if(Script->Token == IDENTIFIER){ const char *Identifier = Script->getIdentifier(); if(strcmp(Identifier, "topic") == 0){ @@ -1597,7 +1594,7 @@ TNPC::TNPC(const char *FileName) : this->OrgOutfit = ReadOutfit(&Script); this->Outfit = this->OrgOutfit; }else if(strcmp(Identifier, "home") == 0){ - Script.readCoordinate(&this->startx, &this->starty, &this->startx); + Script.readCoordinate(&this->startx, &this->starty, &this->startz); this->posx = this->startx; this->posy = this->starty; this->posz = this->startz; @@ -2025,7 +2022,7 @@ TMonster::TMonster(int Race, int x, int y, int z, int Home, uint32 MasterID) : Object Bag = Create(GetBodyContainer(this->ID, INVENTORY_BAG), GetSpecialObject(DEFAULT_CONTAINER), 0); - for(int i = 0; i < RaceData[Race].Items; i += 1){ + for(int i = 1; i <= RaceData[Race].Items; i += 1){ TItemData *ItemData = RaceData[Race].Item.at(i); if(random(0, 999) > ItemData->Probability){ continue; @@ -2381,7 +2378,7 @@ void TMonster::IdleStimulus(void){ // NOTE(fusion): TALKING. if(RaceData[this->Race].Talks > 0 && (rand() % 50) == 0){ - int TalkNr = rand() % (RaceData[this->Race].Talks + 1); + int TalkNr = random(1, RaceData[this->Race].Talks); const char *Text = GetDynamicString(*RaceData[this->Race].Talk.at(TalkNr)); if(Text != 0 && Text[0] != 0){ // TODO(fusion): We were only checking for a `#` but it could be diff --git a/src/crplayer.cc b/src/crplayer.cc index e5874be..dce7ad2 100644 --- a/src/crplayer.cc +++ b/src/crplayer.cc @@ -2314,7 +2314,7 @@ bool LoadPlayerData(TPlayerData *Slot){ } } - int Position = Script.readNumber(); + int Position = Script.getNumber(); if(Position < INVENTORY_FIRST || Position > INVENTORY_LAST){ Script.error("illegal inventory position"); } @@ -2342,7 +2342,7 @@ bool LoadPlayerData(TPlayerData *Slot){ } } - int DepotNr = Script.readNumber(); + int DepotNr = Script.getNumber(); if(DepotNr < 0 || DepotNr >= NARRAY(Slot->Depot)){ Script.error("illegal depot number"); } @@ -2361,6 +2361,7 @@ bool LoadPlayerData(TPlayerData *Slot){ Script.error("end of file expected"); } + Script.close(); Result = true; }catch(const char *str){ error("LoadPlayerData: Kann Gegenstände des Spielers %u nicht laden.\n", diff --git a/src/crypto.cc b/src/crypto.cc index aa53dc3..1559999 100644 --- a/src/crypto.cc +++ b/src/crypto.cc @@ -27,16 +27,16 @@ TRSAPrivateKey::~TRSAPrivateKey(void){ } } -void TRSAPrivateKey::initFromFile(const char *FileName){ +bool TRSAPrivateKey::initFromFile(const char *FileName){ if(m_RSA != NULL){ error("TRSAPrivateKey::init: Key already initialized.\n"); - return; + return false; } FILE *File = fopen(FileName, "rb"); if(File == NULL){ error("TRSAPrivateKey::initFromFile: Failed to open \"%s\".\n", FileName); - return; + return false; } m_RSA = PEM_read_RSAPrivateKey(File, NULL, NULL, NULL); @@ -50,12 +50,14 @@ void TRSAPrivateKey::initFromFile(const char *FileName){ RSA_free(m_RSA); m_RSA = NULL; } + + return (m_RSA != NULL); } -void TRSAPrivateKey::decrypt(uint8 *Data){ +bool TRSAPrivateKey::decrypt(uint8 *Data){ if(m_RSA == NULL){ error("TRSAPrivateKey::decrypt: Key not initialized.\n"); - return; + return false; } // TODO(fusion): Pass in the length of `Data` for checking. @@ -63,7 +65,10 @@ void TRSAPrivateKey::decrypt(uint8 *Data){ if(RSA_private_decrypt(128, Data, Data, m_RSA, RSA_NO_PADDING) == -1){ DumpOpenSSLErrors("TRSAPrivateKey::decrypt", "RSA_private_decrypt"); + return false; } + + return true; } // TXTEASymmetricKey diff --git a/src/crypto.hh b/src/crypto.hh index b649ad8..4c89bf7 100644 --- a/src/crypto.hh +++ b/src/crypto.hh @@ -7,8 +7,8 @@ struct TRSAPrivateKey{ TRSAPrivateKey(void); ~TRSAPrivateKey(void); - void initFromFile(const char *FileName); - void decrypt(uint8 *Data); // single 128 bytes block + bool initFromFile(const char *FileName); + bool decrypt(uint8 *Data); // single 128 bytes block // DATA // ================= diff --git a/src/houses.cc b/src/houses.cc index 4c06419..a26ffbf 100644 --- a/src/houses.cc +++ b/src/houses.cc @@ -21,7 +21,27 @@ static TQueryManagerConnection *QueryManagerConnection; static int PaymentExtension; THouse::THouse(void) : Subowner(0, 4, 5), Guest(0, 9, 10) { - // no-op + this->ID = 0; + this->Name[0] = 0; + this->Description[0] = 0; + this->Size = 0; + this->Rent = 0; + this->DepotNr = 0; + this->NoAuction = 0; + this->GuildHouse = 0; + this->ExitX = 0; + this->ExitY = 0; + this->ExitZ = 0; + this->CenterX = 0; + this->CenterY = 0; + this->CenterZ = 0; + this->OwnerID = 0; + this->OwnerName[30] = 0; + this->LastTransition = 0; + this->PaidUntil = 0; + this->Subowners = 0; + this->Guests = 0; + this->Help = 0; } THouse::THouse(const THouse &Other) : THouse() { @@ -1121,7 +1141,7 @@ bool EvictFreeAccounts(void){ uint16 *HouseIDs = (uint16*)alloca(NumberOfEvictions * sizeof(uint16)); uint32 *OwnerIDs = (uint32*)alloca(NumberOfEvictions * sizeof(uint32)); int Ret = QueryManagerConnection->evictFreeAccounts(&NumberOfEvictions, HouseIDs, OwnerIDs); - if(Ret == 0){ + if(Ret != 0){ error("CollectRents: Kann Zahlungsdaten nicht ermitteln.\n"); return false; } @@ -1154,7 +1174,7 @@ bool EvictDeletedCharacters(void){ int NumberOfEvictions = Houses; uint16 *HouseIDs = (uint16*)alloca(NumberOfEvictions * sizeof(uint16)); int Ret = QueryManagerConnection->evictDeletedCharacters(&NumberOfEvictions, HouseIDs); - if(Ret == 0){ + if(Ret != 0){ error("CollectRents: Kann gelöschte Charaktere nicht ermitteln.\n"); return false; } @@ -1193,7 +1213,7 @@ bool EvictExGuildLeaders(void){ int NumberOfEvictions; int Ret = QueryManagerConnection->evictExGuildleaders( NumberOfGuildHouses, &NumberOfEvictions, HouseIDs, GuildLeaders); - if(Ret == 0){ + if(Ret != 0){ error("CollectRents: Kann Gildenränge nicht ermitteln.\n"); return false; } @@ -1311,7 +1331,6 @@ void ProcessRent(void){ CollectRent(); } - bool StartAuctions(void){ Log("houses", "Starte neue Versteigerungen...\n"); @@ -1533,7 +1552,7 @@ void LoadHouseAreas(void){ Script.readSymbol('('); Area->ID = (uint16)Script.readNumber(); Script.readSymbol(','); - Script.readNumber(); // area name + Script.readString(); // area name Script.readSymbol(','); Area->SQMPrice = Script.readNumber(); Script.readSymbol(','); @@ -1772,7 +1791,7 @@ void LoadOwners(void){ } } - strcpy(House->Guest.at(House->Guests)->Name, Script.readString()); + strcpy(House->Guest.at(House->Guests)->Name, Script.getString()); House->Guests += 1; } @@ -1789,7 +1808,7 @@ void LoadOwners(void){ } } - strcpy(House->Subowner.at(House->Subowners)->Name, Script.readString()); + strcpy(House->Subowner.at(House->Subowners)->Name, Script.getString()); House->Subowners += 1; } @@ -1924,9 +1943,8 @@ void SaveOwners(void){ void ProcessHouses(void){ FinishAuctions(); ProcessRent(); - if(StartAuctions()){ - UpdateHouseOwners(); - } + StartAuctions(); + UpdateHouseOwners(); } void InitHouses(void){ @@ -222,6 +222,7 @@ static void CronSet(Object Obj, uint32 Delay){ Entry->RoundNr = RoundNr + Delay; Entry->Previous = -1; Entry->Next = CronHashTable[Obj.ObjectID % NARRAY(CronHashTable)]; + CronHashTable[Obj.ObjectID % NARRAY(CronHashTable)] = Position; if(Entry->Next != -1){ CronEntry.at(Entry->Next)->Previous = Position; } @@ -370,7 +371,7 @@ static void ReadMapConfig(void){ } char Identifier[MAX_IDENT_LENGTH]; - strcpy(Identifier, Script.readIdentifier()); + strcpy(Identifier, Script.getIdentifier()); Script.readSymbol('='); if(strcmp(Identifier, "sectorxmin") == 0){ @@ -807,6 +808,7 @@ void LoadObjects(TReadScriptFile *Script, TWriteStream *Stream, bool Skip){ } Depth -= 1; + ProcessObjects = false; if(Depth <= 0){ break; } @@ -868,10 +870,6 @@ void LoadObjects(TReadStream *Stream, Object Con){ ObjectType ObjType(TypeID); if(ObjType.isBodyContainer()){ - // TODO(fusion): I couldn't find if a creature's body containers - // are properly initialized or if we need to create them here. - // Either way we should come back to this function to check it - // is working properly. Obj = GetContainerObject(Con, (TypeID - 1)); }else{ Obj = AppendObject(Con, ObjType); @@ -895,14 +893,14 @@ void LoadObjects(TReadStream *Stream, Object Con){ char String[4096]; Stream->readString(String, sizeof(String)); Obj.setAttribute((INSTANCEATTRIBUTE)Attribute, AddDynamicString(String)); - }else if(Attribute != REMAININGEXPIRETIME){ - uint32 Value = Stream->readQuad(); - Obj.setAttribute((INSTANCEATTRIBUTE)Attribute, Value); - }else{ + }else if(Attribute == REMAININGEXPIRETIME){ uint32 Value = Stream->readQuad(); if(Value != 0){ CronChange(Obj, (int)Value); } + }else{ + uint32 Value = Stream->readQuad(); + Obj.setAttribute((INSTANCEATTRIBUTE)Attribute, Value); } }else{ Obj = NONE; @@ -1037,7 +1035,7 @@ void LoadMap(void){ int SectorX, SectorY, SectorZ; if(sscanf(DirEntry->d_name, "%d-%d-%d.sec", &SectorX, &SectorY, &SectorZ) == 3){ - snprintf(FileName, sizeof(FileName), "%s/%s", SAVEPATH, DirEntry->d_name); + snprintf(FileName, sizeof(FileName), "%s/%s", MAPPATH, DirEntry->d_name); LoadSector(FileName, SectorX, SectorY, SectorZ); SectorCounter += 1; } @@ -1157,8 +1155,11 @@ void SaveObjects(TReadStream *Stream, TWriteScriptFile *Script){ Script->writeNumber(TypeID); }else{ - Depth -= 1; Script->writeText("}"); + Depth -= 1; + if(Depth <= 0){ + break; + } } ProcessObjects = false; @@ -1924,9 +1925,8 @@ void ChangeObject(Object Obj, ObjectType NewType){ } if(OldType.getFlag(EXPIRESTOP)){ - uint32 Value = Obj.getAttribute(SAVEDEXPIRETIME); - if(Value != 0){ - Delay = (int)Value; + if(Obj.getAttribute(SAVEDEXPIRETIME) != 0){ + Delay = (int)Obj.getAttribute(SAVEDEXPIRETIME); } } @@ -1938,7 +1938,7 @@ void ChangeObject(Object Obj, ObjectType NewType){ Obj.setObjectType(NewType); if(NewType.getFlag(CUMULATIVE)){ - if(Amount == 0){ + if(Amount <= 0){ Amount = 1; } Obj.setAttribute(AMOUNT, Amount); @@ -1952,7 +1952,7 @@ void ChangeObject(Object Obj, ObjectType NewType){ if(NewType.getFlag(LIQUIDPOOL)){ if(Obj.getAttribute(POOLLIQUIDTYPE) == 0){ - Obj.setAttribute(POOLLIQUIDTYPE, 1); // LIQUID_TYPE_NONE (?) + Obj.setAttribute(POOLLIQUIDTYPE, LIQUID_WATER); } } @@ -2014,7 +2014,7 @@ void PlaceObject(Object Obj, Object Con, bool Append){ } ObjectType ConType = Con.getObjectType(); - if(!ConType.getFlag(CONTAINER) || !ConType.getFlag(CHEST)){ + if(!ConType.getFlag(CONTAINER) && !ConType.getFlag(CHEST)){ error("PlaceObject: Con (%d) ist kein Container.\n", ConType.TypeID); return; } diff --git a/src/moveuse.cc b/src/moveuse.cc index 6c83dcc..cd03bd8 100644 --- a/src/moveuse.cc +++ b/src/moveuse.cc @@ -2543,7 +2543,7 @@ void LoadParameters(TReadScriptFile *Script, int *Parameters, int NumberOfParame } case MOVEUSE_PARAMETER_RIGHT:{ - const char *Right = Script->getIdentifier(); + const char *Right = Script->readIdentifier(); if(strcmp(Right, "premium_account") == 0){ Parameters[i] = PREMIUM_ACCOUNT; }else if(strcmp(Right, "special_moveuse") == 0){ @@ -2968,22 +2968,24 @@ void LoadDataBase(void){ if(strcmp(Identifier, "begin") == 0){ Script.readString(); + Script.nextToken(); continue; }else if(strcmp(Identifier, "end") == 0){ + Script.nextToken(); continue; } int EventType; if(strcmp(Identifier, "use") == 0){ - EventType = MOVEUSE_EVENT_MULTIUSE; + EventType = MOVEUSE_EVENT_USE; }else if(strcmp(Identifier, "multiuse") == 0){ EventType = MOVEUSE_EVENT_MULTIUSE; }else if(strcmp(Identifier, "movement") == 0){ - EventType = MOVEUSE_EVENT_MULTIUSE; + EventType = MOVEUSE_EVENT_MOVEMENT; }else if(strcmp(Identifier, "collision") == 0){ - EventType = MOVEUSE_EVENT_MULTIUSE; + EventType = MOVEUSE_EVENT_COLLISION; }else if(strcmp(Identifier, "separation") == 0){ - EventType = MOVEUSE_EVENT_MULTIUSE; + EventType = MOVEUSE_EVENT_SEPARATION; }else{ Script.error("Unknown event type"); } diff --git a/src/objects.cc b/src/objects.cc index 94edca4..18fe01c 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -98,8 +98,8 @@ static FLAG InstanceAttributeFlags[18] = { }; static const char FlagNames[66][30] = { - "Bank" // BANK - "Clip" // CLIP + "Bank", // BANK + "Clip", // CLIP "Bottom", // BOTTOM "Top", // TOP "Container", // CONTAINER diff --git a/src/operate.cc b/src/operate.cc index 7827d0d..14fab8a 100644 --- a/src/operate.cc +++ b/src/operate.cc @@ -1204,6 +1204,7 @@ Object Create(Object Con, ObjectType Type, uint32 Value){ SetObject(Obj, ObjectType(Position), 0); } + Creature->CrObject = Obj; Creature->NotifyCreate(); } @@ -1535,7 +1536,7 @@ void Merge(uint32 CreatureID, Object Obj, Object Dest, int Count, Object Ignore) } void Change(Object Obj, ObjectType NewType, uint32 Value){ - if(Obj.exists()){ + if(!Obj.exists()){ error("Change: Übergebenes Objekt existiert nicht.\n"); throw ERROR; } @@ -1563,7 +1564,7 @@ void Change(Object Obj, ObjectType NewType, uint32 Value){ if(NewType.getFlag(CONTAINER)){ int ObjectCount = CountObjectsInContainer(Obj); int NewCapacity = (int)NewType.getAttribute(CAPACITY); - if(ObjectCount < NewCapacity){ + if(ObjectCount > NewCapacity){ error("Change: Zielobjekt %d für %d ist kleinerer Container.\n", NewType.TypeID, OldType.TypeID); throw EMPTYCONTAINER; @@ -2751,18 +2752,29 @@ void ProcessCronSystem(void){ break; } - ObjectType ObjType = Obj.getObjectType(); - ObjectType ExpireTarget = (int)ObjType.getAttribute(EXPIRETARGET); - if(ObjType.getFlag(CONTAINER)){ - int Remainder = 0; - if(!ExpireTarget.isMapContainer() && ExpireTarget.getFlag(CONTAINER)){ - Remainder = (int)ExpireTarget.getAttribute(CAPACITY); + try{ + ObjectType ObjType = Obj.getObjectType(); + ObjectType ExpireTarget = (int)ObjType.getAttribute(EXPIRETARGET); + if(ObjType.getFlag(CONTAINER)){ + int Remainder = 0; + if(!ExpireTarget.isMapContainer() && ExpireTarget.getFlag(CONTAINER)){ + Remainder = (int)ExpireTarget.getAttribute(CAPACITY); + } + + Empty(Obj, Remainder); } - Empty(Obj, Remainder); - } + Change(Obj, ExpireTarget, 0); + }catch(RESULT r){ + error("ProcessCronSystem: Exception %d beim Verwesen von %d.\n", + r, Obj.getObjectType().TypeID); - Change(Obj, ExpireTarget, 0); + try{ + Delete(Obj, -1); + }catch(RESULT r){ + error("ProcessCronSystem: Kann Objekt nicht löschen - Exception %d.\n", r); + } + } } } diff --git a/src/query.cc b/src/query.cc index 5da269d..5384b79 100644 --- a/src/query.cc +++ b/src/query.cc @@ -846,7 +846,7 @@ int TQueryManagerConnection::reportStatement(uint32 ReporterID, const char *Play } } - this->sendQuad((uint32)NonZeroStatements); + this->sendWord((uint16)NonZeroStatements); for(int i = 0; i < NumberOfStatements; i += 1){ if(StatementIDs[i] != 0){ this->sendQuad(StatementIDs[i]); @@ -1253,7 +1253,7 @@ int TQueryManagerConnection::createPlayerlist(int NumberOfPlayers, const char ** } int TQueryManagerConnection::logKilledCreatures(int NumberOfRaces, const char **Names, - int *KilledPlayers,int *KilledCreatures){ + int *KilledPlayers, int *KilledCreatures){ this->prepareQuery(48); this->sendWord((uint16)NumberOfRaces); diff --git a/src/strings.cc b/src/strings.cc index d0bfe70..95471d6 100644 --- a/src/strings.cc +++ b/src/strings.cc @@ -183,8 +183,8 @@ void CleanupDynamicStrings(void){ if(Block->EntryType[i] == DYNAMIC_STRING_DELETED){ int StringOffset = Block->StringOffset[i]; char *String = &Block->Text[StringOffset]; - int StringLen = (int)strlen(String); - int StringEnd = StringOffset + StringLen + 1; + int StringSize = (int)strlen(String) + 1; + int StringEnd = StringOffset + StringSize; Block->EntryType[i] = DYNAMIC_STRING_FREE; if(StringEnd > DynamicBlockSize){ @@ -193,13 +193,14 @@ void CleanupDynamicStrings(void){ } if(StringEnd < DynamicBlockSize){ - memmove(String, String + StringEnd, DynamicBlockSize - StringEnd); + memmove(String, String + StringSize, DynamicBlockSize - StringEnd); } for(int j = 0; j < DynamicBlockEntries; j += 1){ if(Block->EntryType[j] != DYNAMIC_STRING_FREE - && Block->StringOffset[j] > StringOffset){ - Block->StringOffset[j] -= StringLen + 1; + && Block->StringOffset[j] > StringOffset){ + ASSERT(Block->StringOffset[j] >= StringEnd); + Block->StringOffset[j] -= StringSize; } } } diff --git a/src/threads.cc b/src/threads.cc index a7acb41..fbced09 100644 --- a/src/threads.cc +++ b/src/threads.cc @@ -132,12 +132,24 @@ Semaphore::Semaphore(int Value){ } Semaphore::~Semaphore(void){ - if(pthread_mutex_destroy(&this->mutex) != 0){ - error("Semaphore::~Semaphore: Kann Mutex nicht freigeben.\n"); - } - - if(pthread_cond_destroy(&this->condition) != 0){ - error("Semaphore::~Semaphore: Kann Wartebedingung nicht freigeben.\n"); + // IMPORTANT(fusion): Due to how initialization is rolled out, `exit` may be + // called after threads are spawned but before `ExitAll` is registered as an + // exit handler. This means such threads may still be running or left global + // semaphores in an inconsistent state if abruptly terminated. Either way, + // they are still considered "in use". + // In this case, calling `destroy` on either mutex or condition variable is + // undefined behaviour as per the manual but the actual implementation would + // fail on `mutex_destroy` with `EBUSY` and hang on `cond_destroy`. + // The temporary solution is to check the result from `mutex_destroy` before + // attempting to call `cond_destroy` to avoid hanging at exit. + + int ErrorCode; + if((ErrorCode = pthread_mutex_destroy(&this->mutex)) != 0){ + error("Semaphore::~Semaphore: Kann Mutex nicht freigeben: (%d) %s.\n", + ErrorCode, strerrordesc_np(ErrorCode)); + }else if((ErrorCode = pthread_cond_destroy(&this->condition)) != 0){ + error("Semaphore::~Semaphore: Kann Wartebedingung nicht freigeben: (%d) %s.\n", + ErrorCode, strerrordesc_np(ErrorCode)); } } diff --git a/src/writer.cc b/src/writer.cc index dbe0cb0..093711e 100644 --- a/src/writer.cc +++ b/src/writer.cc @@ -146,11 +146,13 @@ void Log(const char *ProtocolName, const char *Text, ...){ if(Line[0] != 0){ int LineEnd = (int)strlen(Line); - if(LineEnd < (int)(sizeof(Line) - 1)){ - Line[LineEnd] = '\n'; - Line[LineEnd + 1] = 0; - }else{ - Line[LineEnd - 1] = '\n'; + if(Line[LineEnd - 1] != '\n'){ + if(LineEnd < (int)(sizeof(Line) - 1)){ + Line[LineEnd] = '\n'; + Line[LineEnd + 1] = 0; + }else{ + Line[LineEnd - 1] = '\n'; + } } if(ProtocolThread != INVALID_THREAD_HANDLE){ |
