diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 1865c679..b91a920d 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -18,6 +18,14 @@ body: - label: > I have pulled the latest version of the main branch of DarkflameServer and have confirmed that the issue exists there. required: true + - type: input + id: server-version + attributes: + label: DarkflameServer Version + description: > + DarkflameServer version or commit SHA (can be obtained with `git rev-parse --short HEAD`) + validations: + required: true - type: textarea id: problem attributes: @@ -29,7 +37,7 @@ body: - type: textarea id: reproduction attributes: - label: Reproduction steps + label: Reproduction Steps description: > Please provide a concise list of steps needed to reproduce this issue. validations: diff --git a/.github/ISSUE_TEMPLATE/installation_issue.yaml b/.github/ISSUE_TEMPLATE/installation_issue.yaml index 2fd9a84f..43211e62 100644 --- a/.github/ISSUE_TEMPLATE/installation_issue.yaml +++ b/.github/ISSUE_TEMPLATE/installation_issue.yaml @@ -12,6 +12,14 @@ body: - label: > I have read the [installation guide](https://github.com/DarkflameUniverse/DarkflameServer/blob/main/README.md). required: true + - type: input + id: server-version + attributes: + label: DarkflameServer Version + description: > + DarkflameServer version or commit SHA (can be obtained with `git rev-parse --short HEAD`) + validations: + required: true - type: dropdown id: platform attributes: diff --git a/.github/ISSUE_TEMPLATE/performance_issue.yaml b/.github/ISSUE_TEMPLATE/performance_issue.yaml index 420a5381..b5ec2bcb 100644 --- a/.github/ISSUE_TEMPLATE/performance_issue.yaml +++ b/.github/ISSUE_TEMPLATE/performance_issue.yaml @@ -15,6 +15,22 @@ body: - label: > I have pulled the latest version of the main branch of DarkflameServer and have confirmed that the issue exists there. required: true + - type: input + id: server-version + attributes: + label: DarkflameServer Version + description: > + DarkflameServer version or commit SHA (can be obtained with `git rev-parse --short HEAD`) + validations: + required: true + - type: textarea + id: environment + attributes: + label: Environment + description: > + Please include the environment you're running DarkflameServer on (for example: Windows, macOS, Ubuntu, WSL, etc), available memory, number of CPU cores. + validations: + required: true - type: textarea id: example attributes: diff --git a/CMakeLists.txt b/CMakeLists.txt index 1719a800..a6902a41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,7 +53,7 @@ FetchContent_Declare( FetchContent_Declare( zlib - URL http://github.com/madler/zlib/archive/refs/tags/v1.2.11.zip + URL https://github.com/madler/zlib/archive/refs/tags/v1.2.11.zip URL_HASH MD5=9d6a627693163bbbf3f26403a3a0b0b1 ) diff --git a/dAuthServer/AuthServer.cpp b/dAuthServer/AuthServer.cpp index 67590fa0..fef3124b 100644 --- a/dAuthServer/AuthServer.cpp +++ b/dAuthServer/AuthServer.cpp @@ -57,7 +57,7 @@ int main(int argc, char** argv) { Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); } catch (sql::SQLException& ex) { Game::logger->Log("AuthServer", "Got an error while connecting to the database: %s\n", ex.what()); - Database::Destroy(); + Database::Destroy("AuthServer"); delete Game::server; delete Game::logger; return 0; @@ -143,11 +143,12 @@ int main(int argc, char** argv) { } //Delete our objects here: - Database::Destroy(); + Database::Destroy("AuthServer"); delete Game::server; delete Game::logger; - return 0; + exit(EXIT_SUCCESS); + return EXIT_SUCCESS; } dLogger * SetupLogger() { diff --git a/dChatServer/ChatServer.cpp b/dChatServer/ChatServer.cpp index 81904d41..9ba3ba1b 100644 --- a/dChatServer/ChatServer.cpp +++ b/dChatServer/ChatServer.cpp @@ -61,7 +61,7 @@ int main(int argc, char** argv) { } catch (sql::SQLException& ex) { Game::logger->Log("ChatServer", "Got an error while connecting to the database: %s\n", ex.what()); - Database::Destroy(); + Database::Destroy("ChatServer"); delete Game::server; delete Game::logger; return 0; @@ -150,11 +150,12 @@ int main(int argc, char** argv) { } //Delete our objects here: - Database::Destroy(); + Database::Destroy("ChatServer"); delete Game::server; delete Game::logger; - return 0; + exit(EXIT_SUCCESS); + return EXIT_SUCCESS; } dLogger * SetupLogger() { diff --git a/dDatabase/Database.cpp b/dDatabase/Database.cpp index cdadbbaa..7ba138cf 100644 --- a/dDatabase/Database.cpp +++ b/dDatabase/Database.cpp @@ -26,9 +26,10 @@ void Database::Connect(const string& host, const string& database, const string& con->setClientOption("MYSQL_OPT_RECONNECT", &myTrue); } //Connect -void Database::Destroy() { +void Database::Destroy(std::string source) { if (!con) return; - Game::logger->Log("Database", "Destroying MySQL connection!\n"); + if (source != "") Game::logger->Log("Database", "Destroying MySQL connection from %s!\n", source.c_str()); + else Game::logger->Log("Database", "Destroying MySQL connection!\n"); con->close(); delete con; } //Destroy diff --git a/dDatabase/Database.h b/dDatabase/Database.h index 8e4cf5dc..6e458065 100644 --- a/dDatabase/Database.h +++ b/dDatabase/Database.h @@ -22,7 +22,7 @@ private: public: static void Connect(const std::string& host, const std::string& database, const std::string& username, const std::string& password); - static void Destroy(); + static void Destroy(std::string source=""); static sql::Statement* CreateStmt(); static sql::PreparedStatement* CreatePreppedStmt(const std::string& query); }; diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 6515b9b4..bca7ffa2 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -231,7 +231,8 @@ void Entity::Initialize() m_Components.insert(std::make_pair(COMPONENT_TYPE_RACING_STATS, nullptr)); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_ITEM) > 0) { + PetComponent* petComponent; + if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_ITEM) > 0 && !TryGetComponent(COMPONENT_TYPE_PET, petComponent)) { m_Components.insert(std::make_pair(COMPONENT_TYPE_ITEM, nullptr)); } diff --git a/dGame/TradingManager.cpp b/dGame/TradingManager.cpp index d0ec08d8..0963aa6f 100644 --- a/dGame/TradingManager.cpp +++ b/dGame/TradingManager.cpp @@ -60,7 +60,7 @@ void Trade::SetCoins(LWOOBJID participant, uint64_t coins) { m_CoinsA = coins; } - else if (participant = m_ParticipantB) + else if (participant == m_ParticipantB) { m_CoinsB = coins; } @@ -72,7 +72,7 @@ void Trade::SetItems(LWOOBJID participant, std::vector items) { m_ItemsA = items; } - else if (participant = m_ParticipantB) + else if (participant == m_ParticipantB) { m_ItemsB = items; } diff --git a/dGame/dComponents/BuffComponent.h b/dGame/dComponents/BuffComponent.h index 68cd5309..ba22c08b 100644 --- a/dGame/dComponents/BuffComponent.h +++ b/dGame/dComponents/BuffComponent.h @@ -51,7 +51,7 @@ public: void LoadFromXML(tinyxml2::XMLDocument* doc); - void UpdateXml(tinyxml2::XMLDocument* doc); + void UpdateXml(tinyxml2::XMLDocument* doc) override; void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); diff --git a/dGame/dComponents/ControllablePhysicsComponent.h b/dGame/dComponents/ControllablePhysicsComponent.h index 1c1a4f44..f0fe7461 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.h +++ b/dGame/dComponents/ControllablePhysicsComponent.h @@ -23,7 +23,7 @@ public: ControllablePhysicsComponent(Entity* entity); ~ControllablePhysicsComponent() override; - void Update(float deltaTime); + void Update(float deltaTime) override; void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); void LoadFromXML(tinyxml2::XMLDocument* doc); void ResetFlags(); diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index 56bf26d8..63080b2d 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -1229,19 +1229,19 @@ void InventoryComponent::AddItemSkills(const LOT lot) const auto index = m_Skills.find(slot); - if (index != m_Skills.end()) - { - const auto old = index->second; - - GameMessages::SendRemoveSkill(m_Parent, old); - } - const auto skill = FindSkill(lot); if (skill == 0) { return; } + + if (index != m_Skills.end()) + { + const auto old = index->second; + + GameMessages::SendRemoveSkill(m_Parent, old); + } GameMessages::SendAddSkill(m_Parent, skill, static_cast(slot)); diff --git a/dGame/dComponents/MissionComponent.h b/dGame/dComponents/MissionComponent.h index 6e54a6b0..13a812d2 100644 --- a/dGame/dComponents/MissionComponent.h +++ b/dGame/dComponents/MissionComponent.h @@ -29,8 +29,8 @@ public: explicit MissionComponent(Entity* parent); ~MissionComponent() override; void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void LoadFromXml(tinyxml2::XMLDocument* doc); - void UpdateXml(tinyxml2::XMLDocument* doc); + void LoadFromXml(tinyxml2::XMLDocument* doc) override; + void UpdateXml(tinyxml2::XMLDocument* doc) override; /** * Returns all the missions for this entity, mapped by mission ID diff --git a/dGame/dComponents/ModuleAssemblyComponent.h b/dGame/dComponents/ModuleAssemblyComponent.h index 28dcfa70..7153f30b 100644 --- a/dGame/dComponents/ModuleAssemblyComponent.h +++ b/dGame/dComponents/ModuleAssemblyComponent.h @@ -17,7 +17,7 @@ public: ~ModuleAssemblyComponent() override; void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void Update(float deltaTime); + void Update(float deltaTime) override; /** * Sets the subkey of this entity diff --git a/dGame/dComponents/MovementAIComponent.h b/dGame/dComponents/MovementAIComponent.h index 477c39f4..032732cc 100644 --- a/dGame/dComponents/MovementAIComponent.h +++ b/dGame/dComponents/MovementAIComponent.h @@ -61,7 +61,7 @@ public: MovementAIComponent(Entity* parentEntity, MovementAIInfo info); ~MovementAIComponent() override; - void Update(float deltaTime); + void Update(float deltaTime) override; /** * Returns the basic settings that this entity uses to move around diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index e605908f..a5c1168d 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -81,7 +81,7 @@ void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpd { const bool tamed = m_Owner != LWOOBJID_EMPTY; - outBitStream->Write1(); // Dirty? + outBitStream->Write1(); // Always serialize as dirty for now outBitStream->Write(static_cast(m_Status)); outBitStream->Write(static_cast(tamed ? m_Ability : PetAbilityType::Invalid)); // Something with the overhead icon? @@ -263,29 +263,12 @@ void PetComponent::OnUse(Entity* originator) auto position = originatorPosition; - NiPoint3 forward = NiQuaternion::LookAt(m_Parent->GetPosition(), originator->GetPosition()).GetForwardVector(); //m_Parent->GetRotation().GetForwardVector(); + NiPoint3 forward = NiQuaternion::LookAt(m_Parent->GetPosition(), originator->GetPosition()).GetForwardVector(); forward.y = 0; if (dpWorld::Instance().IsLoaded()) { - /* - if (interactionDistance > 2) - { - interactionDistance -= 1; - } - */ - NiPoint3 attempt = petPosition + forward * interactionDistance; - - /* - float deg = std::atan2(petPosition.z - originatorPosition.z, petPosition.x - originatorPosition.x); //* 180 / M_PI; - - auto position = NiPoint3( - petPosition.x + interactionDistance * std::cos(-deg), - petPosition.y, - petPosition.z + interactionDistance * std::sin(-deg) - ); - */ float y = dpWorld::Instance().GetHeightAtPoint(attempt); @@ -309,8 +292,6 @@ void PetComponent::OnUse(Entity* originator) auto rotation = NiQuaternion::LookAt(position, petPosition); - - //GameMessages::SendTeleport(originator->GetObjectID(), position, rotation, originator->GetSystemAddress(), true); GameMessages::SendNotifyPetTamingMinigame( originator->GetObjectID(), @@ -532,14 +513,12 @@ void PetComponent::Update(float deltaTime) m_Timer = 1; } -void PetComponent::TryBuild(std::vector& bricks, bool clientFailed) -{ +void PetComponent::TryBuild(uint32_t numBricks, bool clientFailed) { if (m_Tamer == LWOOBJID_EMPTY) return; auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); - if (tamer == nullptr) - { + if (tamer == nullptr) { m_Tamer = LWOOBJID_EMPTY; return; @@ -547,19 +526,11 @@ void PetComponent::TryBuild(std::vector& bricks, bool clientFailed) const auto& cached = buildCache.find(m_Parent->GetLOT()); - if (cached == buildCache.end()) - { - GameMessages::SendPetTamingTryBuildResult(m_Tamer, false, 0, tamer->GetSystemAddress()); - - return; - } + if (cached == buildCache.end()) return; auto* destroyableComponent = tamer->GetComponent(); - - if (destroyableComponent == nullptr) - { - return; - } + + if (destroyableComponent == nullptr) return; auto imagination = destroyableComponent->GetImagination(); @@ -569,59 +540,17 @@ void PetComponent::TryBuild(std::vector& bricks, bool clientFailed) EntityManager::Instance()->SerializeEntity(tamer); - const auto& trueBricks = BrickDatabase::Instance()->GetBricks(cached->second.buildFile); - - if (trueBricks.empty() || bricks.empty()) - { - GameMessages::SendPetTamingTryBuildResult(m_Tamer, false, 0, tamer->GetSystemAddress()); - - return; - } - - auto* brickIDTable = CDClientManager::Instance()->GetTable("BrickIDTable"); - - int32_t correct = 0; - - for (const auto& brick : bricks) - { - const auto brickEntries = brickIDTable->Query([brick](const CDBrickIDTable& entry) - { - return entry.NDObjectID == brick.designerID; - }); - - if (brickEntries.empty()) - { - continue; - } - - const auto designerID = brickEntries[0].LEGOBrickID; - - for (const auto& trueBrick : trueBricks) - { - if (designerID == trueBrick.designerID && brick.materialID == trueBrick.materialID) - { - correct++; - - break; - } - } - } - - const auto success = correct >= cached->second.numValidPieces; - - GameMessages::SendPetTamingTryBuildResult(m_Tamer, success, correct, tamer->GetSystemAddress()); - - if (!success) - { - if (imagination < cached->second.imaginationCost) - { + if (clientFailed) { + if (imagination < cached->second.imaginationCost) { ClientFailTamingMinigame(); } - } - else - { + } else { m_Timer = 0; } + + if (numBricks == 0) return; + + GameMessages::SendPetTamingTryBuildResult(m_Tamer, !clientFailed, numBricks, tamer->GetSystemAddress()); } void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) @@ -727,7 +656,6 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) if (missionComponent != nullptr) { - //missionComponent->ForceProgress(506, 768, 1, false); missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_PET_TAMING, m_Parent->GetLOT()); } diff --git a/dGame/dComponents/PetComponent.h b/dGame/dComponents/PetComponent.h index 76afaff6..845cfe31 100644 --- a/dGame/dComponents/PetComponent.h +++ b/dGame/dComponents/PetComponent.h @@ -39,7 +39,7 @@ public: * @param bricks the bricks to try to complete the minigame with * @param clientFailed unused */ - void TryBuild(std::vector& bricks, bool clientFailed); + void TryBuild(uint32_t numBricks, bool clientFailed); /** * Handles a notification from the client regarding the completion of the pet minigame, adding the pet to their diff --git a/dGame/dComponents/PropertyManagementComponent.h b/dGame/dComponents/PropertyManagementComponent.h index c37282e9..c03c4949 100644 --- a/dGame/dComponents/PropertyManagementComponent.h +++ b/dGame/dComponents/PropertyManagementComponent.h @@ -161,6 +161,8 @@ public: */ const std::map& GetModels() const; + LWOCLONEID GetCloneId() { return clone_Id; }; + private: /** * This diff --git a/dGame/dComponents/RebuildComponent.cpp b/dGame/dComponents/RebuildComponent.cpp index 7d4ae926..ef970d98 100644 --- a/dGame/dComponents/RebuildComponent.cpp +++ b/dGame/dComponents/RebuildComponent.cpp @@ -380,7 +380,7 @@ void RebuildComponent::StartRebuild(Entity* user) { EntityManager::Instance()->SerializeEntity(user); - GameMessages::SendRebuildNotifyState(m_Parent, m_State, eRebuildState::REBUILD_COMPLETED, user->GetObjectID()); + GameMessages::SendRebuildNotifyState(m_Parent, m_State, eRebuildState::REBUILD_BUILDING, user->GetObjectID()); GameMessages::SendEnableRebuild(m_Parent, true, false, false, eFailReason::REASON_NOT_GIVEN, 0.0f, user->GetObjectID()); m_State = eRebuildState::REBUILD_BUILDING; @@ -421,7 +421,10 @@ void RebuildComponent::CompleteRebuild(Entity* user) { EntityManager::Instance()->SerializeEntity(user); GameMessages::SendRebuildNotifyState(m_Parent, m_State, eRebuildState::REBUILD_COMPLETED, user->GetObjectID()); - GameMessages::SendEnableRebuild(m_Parent, false, true, false, eFailReason::REASON_NOT_GIVEN, m_ResetTime, user->GetObjectID()); + GameMessages::SendPlayFXEffect(m_Parent, 507, u"create", "BrickFadeUpVisCompleteEffect", LWOOBJID_EMPTY, 0.4f, 1.0f, true); + GameMessages::SendEnableRebuild(m_Parent, false, false, true, eFailReason::REASON_NOT_GIVEN, m_ResetTime, user->GetObjectID()); + GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); + m_State = eRebuildState::REBUILD_COMPLETED; m_Timer = 0.0f; @@ -429,9 +432,6 @@ void RebuildComponent::CompleteRebuild(Entity* user) { EntityManager::Instance()->SerializeEntity(m_Parent); - GameMessages::SendPlayFXEffect(m_Parent, 507, u"create", "BrickFadeUpVisCompleteEffect", LWOOBJID_EMPTY, 0.4f, 1.0f, true); - GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); - // Removes extra item requirements, isn't live accurate. // In live, all items were removed at the start of the quickbuild, then returned if it was cancelled. // TODO: fix? @@ -484,6 +484,7 @@ void RebuildComponent::CompleteRebuild(Entity* user) { character->SetPlayerFlag(flagNumber, true); } } + GameMessages::SendPlayAnimation(user, u"rebuild-celebrate", 1.09f); } void RebuildComponent::ResetRebuild(bool failed) { diff --git a/dGame/dComponents/VendorComponent.h b/dGame/dComponents/VendorComponent.h index 71297be9..fb9dbf6b 100644 --- a/dGame/dComponents/VendorComponent.h +++ b/dGame/dComponents/VendorComponent.h @@ -19,7 +19,7 @@ public: void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void OnUse(Entity* originator); + void OnUse(Entity* originator) override; /** * Gets the buy scaler diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index d2dcc54b..1ede443b 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -3238,12 +3238,12 @@ void GameMessages::HandleClientTradeRequest(RakNet::BitStream* inStream, Entity* void GameMessages::HandleClientTradeCancel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { - Game::logger->Log("GameMessages", "Trade canceled from (%llu)\n", entity->GetObjectID()); - auto* trade = TradingManager::Instance()->GetPlayerTrade(entity->GetObjectID()); if (trade == nullptr) return; + Game::logger->Log("GameMessages", "Trade canceled from (%llu)\n", entity->GetObjectID()); + TradingManager::Instance()->CancelTrade(trade->GetTradeId()); } @@ -3676,7 +3676,7 @@ void GameMessages::HandlePetTamingTryBuild(RakNet::BitStream* inStream, Entity* return; } - petComponent->TryBuild(bricks, clientFailed); + petComponent->TryBuild(bricks.size(), clientFailed); } void GameMessages::HandleNotifyTamingBuildSuccess(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index f307151f..e1e4728f 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -47,6 +47,7 @@ namespace Game { bool shutdownSequenceStarted = false; void ShutdownSequence(); +int FinalizeShutdown(); dLogger* SetupLogger(); void StartAuthServer(); void StartChatServer(); @@ -168,7 +169,7 @@ int main(int argc, char** argv) { std::cout << "Account created successfully!\n"; - Database::Destroy(); + Database::Destroy("MasterServer"); delete Game::logger; return EXIT_SUCCESS; @@ -318,13 +319,8 @@ int main(int argc, char** argv) { t += std::chrono::milliseconds(highFrameRate); std::this_thread::sleep_until(t); } - - //Delete our objects here: - Database::Destroy(); - delete Game::im; - delete Game::server; - delete Game::logger; - + FinalizeShutdown(); + exit(EXIT_SUCCESS); return EXIT_SUCCESS; } @@ -664,7 +660,7 @@ void HandlePacket(Packet* packet) { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); - auto* instance =Game::im->GetInstanceBySysAddr(packet->systemAddress); + auto* instance = Game::im->GetInstanceBySysAddr(packet->systemAddress); if (instance == nullptr) { return; @@ -745,12 +741,20 @@ void ShutdownSequence() { auto ticks = 0; if (!Game::im) { - exit(0); + exit(EXIT_SUCCESS); } Game::logger->Log("MasterServer", "Attempting to shutdown instances, max 60 seconds...\n"); while (true) { + + auto packet = Game::server->Receive(); + if (packet) { + HandlePacket(packet); + Game::server->DeallocatePacket(packet); + packet = nullptr; + } + auto done = true; for (auto* instance : Game::im->GetInstances()) { @@ -764,6 +768,7 @@ void ShutdownSequence() { } if (done) { + Game::logger->Log("MasterServer", "Finished shutting down MasterServer!\n"); break; } @@ -773,9 +778,21 @@ void ShutdownSequence() { ticks++; if (ticks == 600 * 6) { + Game::logger->Log("MasterServer", "Finished shutting down by timeout!\n"); break; } } - exit(0); + FinalizeShutdown(); } + +int FinalizeShutdown() { + //Delete our objects here: + Database::Destroy("MasterServer"); + delete Game::im; + delete Game::server; + delete Game::logger; + + exit(EXIT_SUCCESS); + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/dScripts/AmDrawBridge.h b/dScripts/AmDrawBridge.h index 1b00e2be..e7b801df 100644 --- a/dScripts/AmDrawBridge.h +++ b/dScripts/AmDrawBridge.h @@ -7,7 +7,7 @@ public: void OnStartup(Entity* self) override; void OnUse(Entity* self, Entity* user) override; void OnTimerDone(Entity* self, std::string timerName) override; - void OnNotifyObject(Entity *self, Entity *sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0); + void OnNotifyObject(Entity *self, Entity *sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0) override; void MoveBridgeDown(Entity* self, Entity* bridge, bool down); void NotifyDie(Entity* self, Entity* other); diff --git a/dScripts/BaseConsoleTeleportServer.cpp b/dScripts/BaseConsoleTeleportServer.cpp index b4e88af7..a9cd74e8 100644 --- a/dScripts/BaseConsoleTeleportServer.cpp +++ b/dScripts/BaseConsoleTeleportServer.cpp @@ -25,7 +25,7 @@ void BaseConsoleTeleportServer::BaseOnMessageBoxResponse(Entity* self, Entity* s if (rocketLaunchComponent == nullptr) { - rocketLaunchComponent; + return; } const auto& teleportZone = self->GetVar(u"transferZoneID"); diff --git a/dScripts/GfCampfire.h b/dScripts/GfCampfire.h index 668e7c1d..9e678419 100644 --- a/dScripts/GfCampfire.h +++ b/dScripts/GfCampfire.h @@ -4,11 +4,11 @@ class GfCampfire : public CppScripts::Script { public: - void OnStartup(Entity* self); + void OnStartup(Entity* self) override; void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3); - void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status); - void OnTimerDone(Entity* self, std::string timerName); + int32_t param3) override; + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; + void OnTimerDone(Entity* self, std::string timerName) override; void OnSkillEventFired(Entity *self, Entity *caster, const std::string &message) override; private: int32_t m_skillCastId = 43; diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index c8f2641e..a4056de9 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -77,6 +77,9 @@ bool chatConnected = false; bool worldShutdownSequenceStarted = false; bool worldShutdownSequenceComplete = false; void WorldShutdownSequence(); +void WorldShutdownProcess(uint32_t zoneId); +void FinalizeShutdown(); +void SendShutdownMessageToMaster(); dLogger* SetupLogger(int zoneID, int instanceID); void HandlePacketChat(Packet* packet); @@ -475,80 +478,16 @@ int main(int argc, char** argv) { } } - if (worldShutdownSequenceStarted && !worldShutdownSequenceComplete) - { - if (framesSinceShutdownSequence == 0) { - - ChatPackets::SendSystemMessage(UNASSIGNED_SYSTEM_ADDRESS, u"Server shutting down...", true); - - for (auto i = 0; i < Game::server->GetReplicaManager()->GetParticipantCount(); ++i) - { - const auto& player = Game::server->GetReplicaManager()->GetParticipantAtIndex(i); - - auto* entity = Player::GetPlayer(player); - - if (entity != nullptr && entity->GetCharacter() != nullptr) - { - auto* skillComponent = entity->GetComponent(); - - if (skillComponent != nullptr) - { - skillComponent->Reset(); - } - - entity->GetCharacter()->SaveXMLToDatabase(); - } - } - - if (PropertyManagementComponent::Instance() != nullptr) { - ChatPackets::SendSystemMessage(UNASSIGNED_SYSTEM_ADDRESS, u"Property data saved...", true); - PropertyManagementComponent::Instance()->Save(); - } - - ChatPackets::SendSystemMessage(UNASSIGNED_SYSTEM_ADDRESS, u"Character data saved...", true); - } - - framesSinceShutdownSequence++; - - if (framesSinceShutdownSequence == 100) - { - while (Game::server->GetReplicaManager()->GetParticipantCount() > 0) - { - const auto& player = Game::server->GetReplicaManager()->GetParticipantAtIndex(0); - - Game::server->Disconnect(player, SERVER_DISCON_KICK); - } - - CBITSTREAM; - PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_SHUTDOWN_RESPONSE); - Game::server->SendToMaster(&bitStream); - } - - if (framesSinceShutdownSequence == 300) - { - break; - } + if (worldShutdownSequenceStarted && !worldShutdownSequenceComplete) { + WorldShutdownProcess(zoneID); + break; } Metrics::AddMeasurement(MetricVariable::CPUTime, (1e6 * (1000.0 * (std::clock() - metricCPUTimeStart))) / CLOCKS_PER_SEC); Metrics::EndMeasurement(MetricVariable::Frame); } - - //Delete our objects here: - if (Game::physicsWorld) Game::physicsWorld = nullptr; - if (Game::zoneManager) delete Game::zoneManager; - - Game::logger->Log("WorldServer", "Shutdown complete, zone (%i), instance (%i)\n", Game::server->GetZoneID(), instanceID); - - Metrics::Clear(); - Database::Destroy(); - delete Game::chatFilter; - delete Game::server; - delete Game::logger; - - worldShutdownSequenceComplete = true; - - exit(0); + FinalizeShutdown(); + return EXIT_SUCCESS; } dLogger * SetupLogger(int zoneID, int instanceID) { @@ -1279,35 +1218,75 @@ void HandlePacket(Packet* packet) { } } -void WorldShutdownSequence() -{ - if (worldShutdownSequenceStarted || worldShutdownSequenceComplete) - { - return; - } +void WorldShutdownProcess(uint32_t zoneId) { + Game::logger->Log("WorldServer", "Saving map %i instance %i\n", zoneId, instanceID); + for (auto i = 0; i < Game::server->GetReplicaManager()->GetParticipantCount(); ++i) { + const auto& player = Game::server->GetReplicaManager()->GetParticipantAtIndex(i); - worldShutdownSequenceStarted = true; + auto* entity = Player::GetPlayer(player); + Game::logger->Log("WorldServer", "Saving data!\n"); + if (entity != nullptr && entity->GetCharacter() != nullptr) { + auto* skillComponent = entity->GetComponent(); - auto t = std::chrono::high_resolution_clock::now(); - auto ticks = 0; + if (skillComponent != nullptr) { + skillComponent->Reset(); + } + std::string message = "Saving character " + entity->GetCharacter()->GetName() + "...\n"; + Game::logger->Log("WorldServer", message); + entity->GetCharacter()->SaveXMLToDatabase(); + message = "Character data for " + entity->GetCharacter()->GetName() + " was saved!\n"; + Game::logger->Log("WorldServer", message); + } + } - Game::logger->Log("WorldServer", "Attempting to shutdown world, zone (%i), instance (%i), max 10 seconds...\n", Game::server->GetZoneID(), instanceID); + if (PropertyManagementComponent::Instance() != nullptr) { + Game::logger->Log("WorldServer", "Saving ALL property data for zone %i clone %i!\n", zoneId, PropertyManagementComponent::Instance()->GetCloneId()); + PropertyManagementComponent::Instance()->Save(); + Game::logger->Log("WorldServer", "ALL property data saved for zone %i clone %i!\n", zoneId, PropertyManagementComponent::Instance()->GetCloneId()); + } - while (true) - { - if (worldShutdownSequenceStarted) - { - break; - } + Game::logger->Log("WorldServer", "ALL DATA HAS BEEN SAVED FOR ZONE %i INSTANCE %i!\n", zoneId, instanceID); - t += std::chrono::milliseconds(highFrameRate); - std::this_thread::sleep_until(t); + while (Game::server->GetReplicaManager()->GetParticipantCount() > 0) { + const auto& player = Game::server->GetReplicaManager()->GetParticipantAtIndex(0); - ticks++; - - if (ticks == 600) - { - break; - } - } + Game::server->Disconnect(player, SERVER_DISCON_KICK); + } + SendShutdownMessageToMaster(); } + +void WorldShutdownSequence() { + if (worldShutdownSequenceStarted || worldShutdownSequenceComplete) { + return; + } + + worldShutdownSequenceStarted = true; + + Game::logger->Log("WorldServer", "Zone (%i) instance (%i) shutting down outside of main loop!\n", Game::server->GetZoneID(), instanceID); + WorldShutdownProcess(Game::server->GetZoneID()); + FinalizeShutdown(); +} + +void FinalizeShutdown() { + //Delete our objects here: + if (Game::physicsWorld) Game::physicsWorld = nullptr; + if (Game::zoneManager) delete Game::zoneManager; + + Game::logger->Log("WorldServer", "Shutdown complete, zone (%i), instance (%i)\n", Game::server->GetZoneID(), instanceID); + + Metrics::Clear(); + Database::Destroy("WorldServer"); + delete Game::chatFilter; + delete Game::server; + delete Game::logger; + + worldShutdownSequenceComplete = true; + + exit(EXIT_SUCCESS); +} + +void SendShutdownMessageToMaster() { + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_SHUTDOWN_RESPONSE); + Game::server->SendToMaster(&bitStream); +} \ No newline at end of file diff --git a/migrations/cdserver/3_plunger_gun_fix.sql b/migrations/cdserver/3_plunger_gun_fix.sql new file mode 100644 index 00000000..35654e8b --- /dev/null +++ b/migrations/cdserver/3_plunger_gun_fix.sql @@ -0,0 +1,2 @@ +-- File added April 9th, 2022 +UPDATE ItemComponent SET itemType = 5 where id = 7082; diff --git a/migrations/dlu/0_initial.sql b/migrations/dlu/0_initial.sql index 16cb3e7e..522e556f 100644 --- a/migrations/dlu/0_initial.sql +++ b/migrations/dlu/0_initial.sql @@ -1,5 +1,4 @@ -DROP TABLE IF EXISTS accounts; -CREATE TABLE accounts ( +CREATE TABLE IF NOT EXISTS accounts ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(35) NOT NULL UNIQUE, password TEXT NOT NULL, @@ -11,8 +10,7 @@ CREATE TABLE accounts ( mute_expire BIGINT UNSIGNED NOT NULL DEFAULT 0 ); -DROP TABLE IF EXISTS charinfo; -CREATE TABLE charinfo ( +CREATE TABLE IF NOT EXISTS charinfo ( id BIGINT NOT NULL PRIMARY KEY, account_id INT NOT NULL REFERENCES accounts(id), name VARCHAR(35) NOT NULL, @@ -23,21 +21,18 @@ CREATE TABLE charinfo ( permission_map BIGINT UNSIGNED NOT NULL DEFAULT 0 ); -DROP TABLE IF EXISTS charxml; -CREATE TABLE charxml ( +CREATE TABLE IF NOT EXISTS charxml ( id BIGINT NOT NULL PRIMARY KEY REFERENCES charinfo(id), xml_data LONGTEXT NOT NULL ); -DROP TABLE IF EXISTS command_log; -CREATE TABLE command_log ( +CREATE TABLE IF NOT EXISTS command_log ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, character_id BIGINT NOT NULL REFERENCES charinfo(id), command VARCHAR(256) NOT NULL ); -DROP TABLE IF EXISTS friends; -CREATE TABLE friends ( +CREATE TABLE IF NOT EXISTS friends ( player_id BIGINT NOT NULL REFERENCES charinfo(id), friend_id BIGINT NOT NULL REFERENCES charinfo(id), best_friend BOOLEAN NOT NULL DEFAULT FALSE, @@ -45,8 +40,7 @@ CREATE TABLE friends ( PRIMARY KEY (player_id, friend_id) ); -DROP TABLE IF EXISTS leaderboard; -CREATE TABLE leaderboard ( +CREATE TABLE IF NOT EXISTS leaderboard ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, game_id INT UNSIGNED NOT NULL DEFAULT 0, last_played TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP(), @@ -55,8 +49,7 @@ CREATE TABLE leaderboard ( score BIGINT UNSIGNED NOT NULL DEFAULT 0 ); -DROP TABLE IF EXISTS mail; -CREATE TABLE mail ( +CREATE TABLE IF NOT EXISTS mail ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, sender_id INT NOT NULL DEFAULT 0, sender_name VARCHAR(35) NOT NULL DEFAULT '', @@ -72,20 +65,17 @@ CREATE TABLE mail ( was_read BOOLEAN NOT NULL DEFAULT FALSE ); -DROP TABLE IF EXISTS object_id_tracker; -CREATE TABLE object_id_tracker ( +CREATE TABLE IF NOT EXISTS object_id_tracker ( last_object_id BIGINT UNSIGNED NOT NULL DEFAULT 0 PRIMARY KEY ); -DROP TABLE IF EXISTS pet_names; -CREATE TABLE pet_names ( +CREATE TABLE IF NOT EXISTS pet_names ( id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, pet_name TEXT NOT NULL, approved INT UNSIGNED NOT NULL ); -DROP TABLE IF EXISTS play_keys; -CREATE TABLE play_keys ( +CREATE TABLE IF NOT EXISTS play_keys ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, key_string CHAR(19) NOT NULL UNIQUE, key_uses INT NOT NULL DEFAULT 1, @@ -93,8 +83,7 @@ CREATE TABLE play_keys ( active BOOLEAN NOT NULL DEFAULT TRUE ); -DROP TABLE IF EXISTS properties; -CREATE TABLE properties ( +CREATE TABLE IF NOT EXISTS properties ( id BIGINT NOT NULL PRIMARY KEY, owner_id BIGINT NOT NULL REFERENCES charinfo(id), template_id INT UNSIGNED NOT NULL, @@ -112,8 +101,7 @@ CREATE TABLE properties ( zone_id INT NOT NULL ); -DROP TABLE IF EXISTS ugc; -CREATE TABLE ugc ( +CREATE TABLE IF NOT EXISTS ugc ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, account_id INT NOT NULL REFERENCES accounts(id), character_id BIGINT NOT NULL REFERENCES charinfo(id), @@ -123,8 +111,7 @@ CREATE TABLE ugc ( filename TEXT NOT NULL DEFAULT ('') ); -DROP TABLE IF EXISTS properties_contents; -CREATE TABLE properties_contents ( +CREATE TABLE IF NOT EXISTS properties_contents ( id BIGINT NOT NULL PRIMARY KEY, property_id BIGINT NOT NULL REFERENCES properties(id), ugc_id INT NULL REFERENCES ugc(id), @@ -138,8 +125,7 @@ CREATE TABLE properties_contents ( rw FLOAT NOT NULL ); -DROP TABLE IF EXISTS activity_log; -CREATE TABLE activity_log ( +CREATE TABLE IF NOT EXISTS activity_log ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, character_id BIGINT NOT NULL REFERENCES charinfo(id), activity INT NOT NULL, @@ -147,8 +133,7 @@ CREATE TABLE activity_log ( map_id INT NOT NULL ); -DROP TABLE IF EXISTS bug_reports; -CREATE TABLE bug_reports ( +CREATE TABLE IF NOT EXISTS bug_reports ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, body TEXT NOT NULL, client_version TEXT NOT NULL, @@ -157,8 +142,7 @@ CREATE TABLE bug_reports ( submitted TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP() ); -DROP TABLE IF EXISTS servers; -CREATE TABLE servers ( +CREATE TABLE IF NOT EXISTS servers ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name TEXT NOT NULL, ip TEXT NOT NULL,