diff --git a/dDatabase/CDClientDatabase/CDClientManager.cpp b/dDatabase/CDClientDatabase/CDClientManager.cpp index 6ecfb0ad..9aea0711 100644 --- a/dDatabase/CDClientDatabase/CDClientManager.cpp +++ b/dDatabase/CDClientDatabase/CDClientManager.cpp @@ -102,7 +102,6 @@ DEFINE_TABLE_STORAGE(CDScriptComponentTable); DEFINE_TABLE_STORAGE(CDSkillBehaviorTable); DEFINE_TABLE_STORAGE(CDTamingBuildPuzzleTable); DEFINE_TABLE_STORAGE(CDVendorComponentTable); -DEFINE_TABLE_STORAGE(CDZoneTableTable); void CDClientManager::LoadValuesFromDatabase() { if (!CDClientDatabase::isConnected) { @@ -149,7 +148,7 @@ void CDClientManager::LoadValuesFromDatabase() { CDSkillBehaviorTable::Instance().LoadValuesFromDatabase(); CDTamingBuildPuzzleTable::Instance().LoadValuesFromDatabase(); CDVendorComponentTable::Instance().LoadValuesFromDatabase(); - CDZoneTableTable::Instance().LoadValuesFromDatabase(); + CDZoneTableTable::LoadValuesFromDatabase(); } void CDClientManager::LoadValuesFromDefaults() { diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDZoneTableTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDZoneTableTable.cpp index 6aaeb854..a8837acb 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDZoneTableTable.cpp +++ b/dDatabase/CDClientDatabase/CDClientTables/CDZoneTableTable.cpp @@ -1,67 +1,53 @@ #include "CDZoneTableTable.h" -void CDZoneTableTable::LoadValuesFromDatabase() { +namespace CDZoneTableTable { + Table entries; - // First, get the size of the table - uint32_t size = 0; - auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ZoneTable"); - while (!tableSize.eof()) { - size = tableSize.getIntField(0, 0); + void LoadValuesFromDatabase() { + // Get the data from the database + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ZoneTable"); + while (!tableData.eof()) { + CDZoneTable entry; + entry.zoneID = tableData.getIntField("zoneID", -1); + entry.locStatus = tableData.getIntField("locStatus", -1); + entry.zoneName = tableData.getStringField("zoneName", ""); + entry.scriptID = tableData.getIntField("scriptID", -1); + entry.ghostdistance_min = tableData.getFloatField("ghostdistance_min", -1.0f); + entry.ghostdistance = tableData.getFloatField("ghostdistance", -1.0f); + entry.population_soft_cap = tableData.getIntField("population_soft_cap", -1); + entry.population_hard_cap = tableData.getIntField("population_hard_cap", -1); + UNUSED(entry.DisplayDescription = tableData.getStringField("DisplayDescription", "")); + UNUSED(entry.mapFolder = tableData.getStringField("mapFolder", "")); + entry.smashableMinDistance = tableData.getFloatField("smashableMinDistance", -1.0f); + entry.smashableMaxDistance = tableData.getFloatField("smashableMaxDistance", -1.0f); + UNUSED(entry.mixerProgram = tableData.getStringField("mixerProgram", "")); + UNUSED(entry.clientPhysicsFramerate = tableData.getStringField("clientPhysicsFramerate", "")); + entry.serverPhysicsFramerate = tableData.getStringField("serverPhysicsFramerate", ""); + entry.zoneControlTemplate = tableData.getIntField("zoneControlTemplate", -1); + entry.widthInChunks = tableData.getIntField("widthInChunks", -1); + entry.heightInChunks = tableData.getIntField("heightInChunks", -1); + entry.petsAllowed = tableData.getIntField("petsAllowed", -1) == 1 ? true : false; + entry.localize = tableData.getIntField("localize", -1) == 1 ? true : false; + entry.fZoneWeight = tableData.getFloatField("fZoneWeight", -1.0f); + UNUSED(entry.thumbnail = tableData.getStringField("thumbnail", "")); + entry.PlayerLoseCoinsOnDeath = tableData.getIntField("PlayerLoseCoinsOnDeath", -1) == 1 ? true : false; + entry.disableSaveLoc = tableData.getIntField("disableSaveLoc", -1) == 1 ? true : false; + entry.teamRadius = tableData.getFloatField("teamRadius", -1.0f); + UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); + entry.mountsAllowed = tableData.getIntField("mountsAllowed", -1) == 1 ? true : false; - tableSize.nextRow(); + entries[entry.zoneID] = entry; + tableData.nextRow(); + } } - tableSize.finalize(); + //! Queries the table with a zoneID to find. + const CDZoneTable* Query(uint32_t zoneID) { + const auto& iter = entries.find(zoneID); + if (iter != entries.end()) { + return &iter->second; + } - // Now get the data - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ZoneTable"); - auto& entries = GetEntriesMutable(); - while (!tableData.eof()) { - CDZoneTable entry; - entry.zoneID = tableData.getIntField("zoneID", -1); - entry.locStatus = tableData.getIntField("locStatus", -1); - entry.zoneName = tableData.getStringField("zoneName", ""); - entry.scriptID = tableData.getIntField("scriptID", -1); - entry.ghostdistance_min = tableData.getFloatField("ghostdistance_min", -1.0f); - entry.ghostdistance = tableData.getFloatField("ghostdistance", -1.0f); - entry.population_soft_cap = tableData.getIntField("population_soft_cap", -1); - entry.population_hard_cap = tableData.getIntField("population_hard_cap", -1); - UNUSED(entry.DisplayDescription = tableData.getStringField("DisplayDescription", "")); - UNUSED(entry.mapFolder = tableData.getStringField("mapFolder", "")); - entry.smashableMinDistance = tableData.getFloatField("smashableMinDistance", -1.0f); - entry.smashableMaxDistance = tableData.getFloatField("smashableMaxDistance", -1.0f); - UNUSED(entry.mixerProgram = tableData.getStringField("mixerProgram", "")); - UNUSED(entry.clientPhysicsFramerate = tableData.getStringField("clientPhysicsFramerate", "")); - entry.serverPhysicsFramerate = tableData.getStringField("serverPhysicsFramerate", ""); - entry.zoneControlTemplate = tableData.getIntField("zoneControlTemplate", -1); - entry.widthInChunks = tableData.getIntField("widthInChunks", -1); - entry.heightInChunks = tableData.getIntField("heightInChunks", -1); - entry.petsAllowed = tableData.getIntField("petsAllowed", -1) == 1 ? true : false; - entry.localize = tableData.getIntField("localize", -1) == 1 ? true : false; - entry.fZoneWeight = tableData.getFloatField("fZoneWeight", -1.0f); - UNUSED(entry.thumbnail = tableData.getStringField("thumbnail", "")); - entry.PlayerLoseCoinsOnDeath = tableData.getIntField("PlayerLoseCoinsOnDeath", -1) == 1 ? true : false; - entry.disableSaveLoc = tableData.getIntField("disableSaveLoc", -1) == 1 ? true : false; - entry.teamRadius = tableData.getFloatField("teamRadius", -1.0f); - UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); - entry.mountsAllowed = tableData.getIntField("mountsAllowed", -1) == 1 ? true : false; - - entries.insert(std::make_pair(entry.zoneID, entry)); - tableData.nextRow(); + return nullptr; } - - tableData.finalize(); } - -//! Queries the table with a zoneID to find. -const CDZoneTable* CDZoneTableTable::Query(uint32_t zoneID) { - auto& m_Entries = GetEntries(); - const auto& iter = m_Entries.find(zoneID); - - if (iter != m_Entries.end()) { - return &iter->second; - } - - return nullptr; -} - diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDZoneTableTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDZoneTableTable.h index b1e8b1ba..6d91242b 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDZoneTableTable.h +++ b/dDatabase/CDClientDatabase/CDClientTables/CDZoneTableTable.h @@ -33,8 +33,8 @@ struct CDZoneTable { bool mountsAllowed; //!< Whether or not mounts are allowed }; -class CDZoneTableTable : public CDTable> { -public: +namespace CDZoneTableTable { + using Table = std::map; void LoadValuesFromDatabase(); // Queries the table with a zoneID to find. diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 90bf7e76..35cd10fb 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -545,9 +545,8 @@ void Entity::Initialize() { // ZoneControl script if (m_TemplateID == 2365) { - CDZoneTableTable* zoneTable = CDClientManager::GetTable(); const auto zoneID = Game::zoneManager->GetZoneID(); - const CDZoneTable* zoneData = zoneTable->Query(zoneID.GetMapID()); + const CDZoneTable* zoneData = CDZoneTableTable::Query(zoneID.GetMapID()); if (zoneData != nullptr) { int zoneScriptID = zoneData->scriptID; diff --git a/dGame/dBehaviors/BasicAttackBehavior.cpp b/dGame/dBehaviors/BasicAttackBehavior.cpp index 97ceb846..41b02e7c 100644 --- a/dGame/dBehaviors/BasicAttackBehavior.cpp +++ b/dGame/dBehaviors/BasicAttackBehavior.cpp @@ -20,7 +20,7 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bi //Handle player damage cooldown if (entity->IsPlayer() && !this->m_DontApplyImmune) { - const float immunityTime = Game::zoneManager->GetWorldConfig()->globalImmunityTime; + const float immunityTime = Game::zoneManager->GetWorldConfig().globalImmunityTime; destroyableComponent->SetDamageCooldownTimer(immunityTime); } } @@ -214,7 +214,7 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet //Handle player damage cooldown if (isSuccess && targetEntity->IsPlayer() && !this->m_DontApplyImmune) { - destroyableComponent->SetDamageCooldownTimer(Game::zoneManager->GetWorldConfig()->globalImmunityTime); + destroyableComponent->SetDamageCooldownTimer(Game::zoneManager->GetWorldConfig().globalImmunityTime); } eBasicAttackSuccessTypes successState = eBasicAttackSuccessTypes::FAILIMMUNE; diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index cb8afd5a..cc67a9db 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -774,10 +774,10 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType if (Game::zoneManager->GetPlayerLoseCoinOnDeath()) { auto* character = m_Parent->GetCharacter(); uint64_t coinsTotal = character->GetCoins(); - const uint64_t minCoinsToLose = Game::zoneManager->GetWorldConfig()->coinsLostOnDeathMin; + const uint64_t minCoinsToLose = Game::zoneManager->GetWorldConfig().coinsLostOnDeathMin; if (coinsTotal >= minCoinsToLose) { - const uint64_t maxCoinsToLose = Game::zoneManager->GetWorldConfig()->coinsLostOnDeathMax; - const float coinPercentageToLose = Game::zoneManager->GetWorldConfig()->coinsLostOnDeathPercent; + const uint64_t maxCoinsToLose = Game::zoneManager->GetWorldConfig().coinsLostOnDeathMax; + const float coinPercentageToLose = Game::zoneManager->GetWorldConfig().coinsLostOnDeathPercent; uint64_t coinsToLose = std::max(static_cast(coinsTotal * coinPercentageToLose), minCoinsToLose); coinsToLose = std::min(maxCoinsToLose, coinsToLose); diff --git a/dGame/dComponents/VendorComponent.cpp b/dGame/dComponents/VendorComponent.cpp index b9286d25..b4a5f05c 100644 --- a/dGame/dComponents/VendorComponent.cpp +++ b/dGame/dComponents/VendorComponent.cpp @@ -101,7 +101,7 @@ void VendorComponent::SetupConstants() { std::vector vendorComps = vendorComponentTable->Query([=](CDVendorComponent entry) { return (entry.id == componentID); }); if (vendorComps.empty()) return; auto vendorData = vendorComps.at(0); - if (vendorData.buyScalar == 0.0) m_BuyScalar = Game::zoneManager->GetWorldConfig()->vendorBuyMultiplier; + if (vendorData.buyScalar == 0.0) m_BuyScalar = Game::zoneManager->GetWorldConfig().vendorBuyMultiplier; else m_BuyScalar = vendorData.buyScalar; m_SellScalar = vendorData.sellScalar; m_RefreshTimeSeconds = vendorData.refreshTimeSeconds; diff --git a/dGame/dMission/Mission.cpp b/dGame/dMission/Mission.cpp index 559193b7..b1ff4360 100644 --- a/dGame/dMission/Mission.cpp +++ b/dGame/dMission/Mission.cpp @@ -470,9 +470,9 @@ void Mission::YieldRewards() { int32_t coinsToSend = 0; if (info.LegoScore > 0) { eLootSourceType lootSource = info.isMission ? eLootSourceType::MISSION : eLootSourceType::ACHIEVEMENT; - if (levelComponent->GetLevel() >= Game::zoneManager->GetWorldConfig()->levelCap) { + if (levelComponent->GetLevel() >= Game::zoneManager->GetWorldConfig().levelCap) { // Since the character is at the level cap we reward them with coins instead of UScore. - coinsToSend += info.LegoScore * Game::zoneManager->GetWorldConfig()->levelCapCurrencyConversion; + coinsToSend += info.LegoScore * Game::zoneManager->GetWorldConfig().levelCapCurrencyConversion; } else { characterComponent->SetUScore(characterComponent->GetUScore() + info.LegoScore); GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), info.LegoScore, lootSource); diff --git a/dGame/dUtilities/Mail.cpp b/dGame/dUtilities/Mail.cpp index d3275b31..6791020e 100644 --- a/dGame/dUtilities/Mail.cpp +++ b/dGame/dUtilities/Mail.cpp @@ -81,7 +81,7 @@ namespace Mail { } else if (GeneralUtils::CaseInsensitiveStringCompare(mailInfo.recipient, character->GetName()) || receiverID->id == character->GetID()) { response.status = eSendResponse::CannotMailSelf; } else { - uint32_t mailCost = Game::zoneManager->GetWorldConfig()->mailBaseFee; + uint32_t mailCost = Game::zoneManager->GetWorldConfig().mailBaseFee; uint32_t stackSize = 0; auto inventoryComponent = player->GetComponent(); @@ -92,7 +92,7 @@ namespace Mail { if (hasAttachment) { item = inventoryComponent->FindItemById(mailInfo.itemID); if (item) { - mailCost += (item->GetInfo().baseValue * Game::zoneManager->GetWorldConfig()->mailPercentAttachmentFee); + mailCost += (item->GetInfo().baseValue * Game::zoneManager->GetWorldConfig().mailPercentAttachmentFee); mailInfo.itemLOT = item->GetLot(); } } diff --git a/dMasterServer/InstanceManager.cpp b/dMasterServer/InstanceManager.cpp index 3c40136c..be4283e7 100644 --- a/dMasterServer/InstanceManager.cpp +++ b/dMasterServer/InstanceManager.cpp @@ -37,9 +37,9 @@ Instance* InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, LW // If we are shutting down, return a nullptr so a new instance is not created. if (m_IsShuttingDown) { LOG("Tried to create a new instance map/instance/clone %i/%i/%i, but Master is shutting down.", - mapID, - m_LastInstanceID + 1, - cloneID); + mapID, + m_LastInstanceID + 1, + cloneID); return nullptr; } //TODO: Update this so that the IP is read from a configuration file instead @@ -292,9 +292,9 @@ Instance* InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID clon if (m_IsShuttingDown) { LOG("Tried to create a new private instance map/instance/clone %i/%i/%i, but Master is shutting down.", - mapID, - m_LastInstanceID + 1, - cloneID); + mapID, + m_LastInstanceID + 1, + cloneID); return nullptr; } @@ -333,29 +333,17 @@ Instance* InstanceManager::FindPrivateInstance(const std::string& password) { } int InstanceManager::GetSoftCap(LWOMAPID mapID) { - CDZoneTableTable* zoneTable = CDClientManager::GetTable(); - if (zoneTable) { - const CDZoneTable* zone = zoneTable->Query(mapID); + const CDZoneTable* zone = CDZoneTableTable::Query(mapID); - if (zone != nullptr) { - return zone->population_soft_cap; - } - } - - return 8; + // Default to 8 which is the cap for most worlds. + return zone ? zone->population_soft_cap : 8; } int InstanceManager::GetHardCap(LWOMAPID mapID) { - CDZoneTableTable* zoneTable = CDClientManager::GetTable(); - if (zoneTable) { - const CDZoneTable* zone = zoneTable->Query(mapID); + const CDZoneTable* zone = CDZoneTableTable::Query(mapID); - if (zone != nullptr) { - return zone->population_hard_cap; - } - } - - return 12; + // Default to 12 which is the cap for most worlds. + return zone ? zone->population_hard_cap : 12; } void Instance::SetShutdownComplete(const bool value) { diff --git a/dWorldServer/PerformanceManager.cpp b/dWorldServer/PerformanceManager.cpp index 052d075b..c54bf678 100644 --- a/dWorldServer/PerformanceManager.cpp +++ b/dWorldServer/PerformanceManager.cpp @@ -70,22 +70,19 @@ std::map PerformanceManager::m_Profiles = { void PerformanceManager::SelectProfile(LWOMAPID mapID) { // Try to get it from zoneTable - CDZoneTableTable* zoneTable = CDClientManager::GetTable(); - if (zoneTable) { - const CDZoneTable* zone = zoneTable->Query(mapID); - if (zone) { - if (zone->serverPhysicsFramerate == "high"){ - m_CurrentProfile = { highFrameDelta }; - return; - } - if (zone->serverPhysicsFramerate == "medium"){ - m_CurrentProfile = { mediumFrameDelta }; - return; - } - if (zone->serverPhysicsFramerate == "low"){ - m_CurrentProfile = { lowFrameDelta }; - return; - } + const CDZoneTable* zone = CDZoneTableTable::Query(mapID); + if (zone) { + if (zone->serverPhysicsFramerate == "high") { + m_CurrentProfile = { highFrameDelta }; + return; + } + if (zone->serverPhysicsFramerate == "medium") { + m_CurrentProfile = { mediumFrameDelta }; + return; + } + if (zone->serverPhysicsFramerate == "low") { + m_CurrentProfile = { lowFrameDelta }; + return; } } diff --git a/dZoneManager/Level.cpp b/dZoneManager/Level.cpp index d2b67b29..13c85c1a 100644 --- a/dZoneManager/Level.cpp +++ b/dZoneManager/Level.cpp @@ -253,8 +253,8 @@ void Level::ReadSceneObjectDataChunk(std::istream& file, Header& header) { //This is a little bit of a bodge, but because the alpha client (HF) doesn't store the //spawn position / rotation like the later versions do, we need to check the LOT for the spawn pos & set it. if (obj.lot == LOT_MARKER_PLAYER_START) { - Game::zoneManager->GetZone()->SetSpawnPos(obj.position); - Game::zoneManager->GetZone()->SetSpawnRot(obj.rotation); + Game::zoneManager->GetZoneMut()->SetSpawnPos(obj.position); + Game::zoneManager->GetZoneMut()->SetSpawnRot(obj.rotation); } std::string sData = GeneralUtils::UTF16ToWTF8(ldfString); diff --git a/dZoneManager/WorldConfig.h b/dZoneManager/WorldConfig.h index a98433a1..98085a48 100644 --- a/dZoneManager/WorldConfig.h +++ b/dZoneManager/WorldConfig.h @@ -5,7 +5,6 @@ #include struct WorldConfig { - int32_t worldConfigID{}; //! Primary key for WorlcConfig table float peGravityValue{}; //! Unknown float peBroadphaseWorldSize{}; //! Unknown float peGameObjScaleFactor{}; //! Unknown @@ -53,8 +52,8 @@ struct WorldConfig { float reputationPerVoteReceived{}; //! Unknown int32_t showcaseTopModelConsiderationBattles{}; //! Unknown float reputationPerBattlePromotion{}; //! Unknown - float coinsLostOnDeathMinTimeout{}; //! Unknown - float coinsLostOnDeathMaxTimeout{}; //! Unknown + float coinsLostOnDeathMinTimeout{}; //! Minimum amount of time coins lost on death will remain on the playfield. + float coinsLostOnDeathMaxTimeout{}; //! Maximum amount of time coins lost on death will remain on the playfield. int32_t mailBaseFee{}; //! The base fee to take when a player sends mail float mailPercentAttachmentFee{}; //! The scalar multiplied by an items base cost to determine how much that item costs to be mailed int32_t propertyReputationDelay{}; //! Unknown diff --git a/dZoneManager/Zone.cpp b/dZoneManager/Zone.cpp index 1d657075..282f4c45 100644 --- a/dZoneManager/Zone.cpp +++ b/dZoneManager/Zone.cpp @@ -2,6 +2,7 @@ #include "Level.h" #include #include +#include #include "Game.h" #include "Logger.h" #include "GeneralUtils.h" @@ -20,8 +21,8 @@ #include "eWaypointCommandType.h" #include "dNavMesh.h" -Zone::Zone(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) : - m_ZoneID(mapID, instanceID, cloneID) { +Zone::Zone(const LWOZONEID zoneID) : + m_ZoneID(zoneID) { m_NumberOfObjectsLoaded = 0; m_NumberOfSceneTransitionsLoaded = 0; m_CheckSum = 0; @@ -31,9 +32,6 @@ Zone::Zone(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLON Zone::~Zone() { LOG("Destroying zone %i", m_ZoneID.GetMapID()); - for (std::map::iterator it = m_Scenes.begin(); it != m_Scenes.end(); ++it) { - if (it->second.level != nullptr) delete it->second.level; - } } void Zone::Initalize() { @@ -153,23 +151,25 @@ void Zone::LoadZoneIntoMemory() { m_ZonePath = m_ZoneFilePath.substr(0, m_ZoneFilePath.rfind('/') + 1); } -std::string Zone::GetFilePathForZoneID() { +std::string Zone::GetFilePathForZoneID() const { //We're gonna go ahead and presume we've got the db loaded already: - CDZoneTableTable* zoneTable = CDClientManager::GetTable(); - const CDZoneTable* zone = zoneTable->Query(this->GetZoneID().GetMapID()); + const CDZoneTable* zone = CDZoneTableTable::Query(this->GetZoneID().GetMapID()); + std::string toReturn("ERR"); if (zone != nullptr) { - std::string toReturn = "maps/" + zone->zoneName; + toReturn = "maps/" + zone->zoneName; std::transform(toReturn.begin(), toReturn.end(), toReturn.begin(), ::tolower); + + /* Normalize to one slash type */ std::ranges::replace(toReturn, '\\', '/'); - return toReturn; } - return std::string("ERR"); + return toReturn; } //Based off code from: https://www.liquisearch.com/fletchers_checksum/implementation/optimizations -uint32_t Zone::CalculateChecksum() { - uint32_t sum1 = 0xffff, sum2 = 0xffff; +uint32_t Zone::CalculateChecksum() const { + uint32_t sum1 = 0xffff; + uint32_t sum2 = 0xffff; for (const auto& [scene, sceneRevision] : m_MapRevisions) { uint32_t sceneID = scene.GetSceneID(); @@ -194,7 +194,7 @@ uint32_t Zone::CalculateChecksum() { void Zone::LoadLevelsIntoMemory() { for (auto& [sceneID, scene] : m_Scenes) { if (scene.level) continue; - scene.level = new Level(this, m_ZonePath + scene.filename); + scene.level = std::make_unique(this, m_ZonePath + scene.filename); if (scene.level->m_ChunkHeaders.empty()) continue; @@ -241,7 +241,7 @@ void Zone::LoadScene(std::istream& file) { BinaryIO::BinaryRead(file, scene.color_g); } - m_Scenes.insert(std::make_pair(lwoSceneID, scene)); + m_Scenes[lwoSceneID] = std::move(scene); } void Zone::LoadLUTriggers(std::string triggerFile, SceneRef& scene) { @@ -299,7 +299,7 @@ void Zone::LoadLUTriggers(std::string triggerFile, SceneRef& scene) { } } -LUTriggers::Trigger* Zone::GetTrigger(uint32_t sceneID, uint32_t triggerID) { +LUTriggers::Trigger* Zone::GetTrigger(uint32_t sceneID, uint32_t triggerID) const { auto scene = m_Scenes.find(sceneID); if (scene == m_Scenes.end()) return nullptr; diff --git a/dZoneManager/Zone.h b/dZoneManager/Zone.h index 299d675b..206ad1f1 100644 --- a/dZoneManager/Zone.h +++ b/dZoneManager/Zone.h @@ -31,7 +31,7 @@ struct SceneRef { uint8_t color_r{}; uint8_t color_g{}; uint8_t color_b{}; - Level* level; + std::unique_ptr level; std::map triggers; }; @@ -203,18 +203,18 @@ public: }; public: - Zone(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID); + Zone(const LWOZONEID zoneID); ~Zone(); void Initalize(); void LoadZoneIntoMemory(); - std::string GetFilePathForZoneID(); - uint32_t CalculateChecksum(); + std::string GetFilePathForZoneID() const; + uint32_t CalculateChecksum() const; void LoadLevelsIntoMemory(); void AddRevision(LWOSCENEID sceneID, uint32_t revision); const LWOZONEID& GetZoneID() const { return m_ZoneID; } const uint32_t GetChecksum() const { return m_CheckSum; } - LUTriggers::Trigger* GetTrigger(uint32_t sceneID, uint32_t triggerID); + LUTriggers::Trigger* GetTrigger(uint32_t sceneID, uint32_t triggerID) const; const Path* GetPath(std::string name) const; uint32_t GetWorldID() const { return m_WorldID; } diff --git a/dZoneManager/dZoneManager.cpp b/dZoneManager/dZoneManager.cpp index 09baabed..ea19dc88 100644 --- a/dZoneManager/dZoneManager.cpp +++ b/dZoneManager/dZoneManager.cpp @@ -14,6 +14,7 @@ #include "eObjectBits.h" #include "CDZoneTableTable.h" #include "AssetManager.h" +#include #include "ObjectIDManager.h" @@ -29,21 +30,18 @@ void dZoneManager::Initialize(const LWOZONEID& zoneID) { LOT zoneControlTemplate = 2365; - CDZoneTableTable* zoneTable = CDClientManager::GetTable(); - if (zoneTable != nullptr) { - const CDZoneTable* zone = zoneTable->Query(zoneID.GetMapID()); + const CDZoneTable* zone = CDZoneTableTable::Query(zoneID.GetMapID()); - if (zone != nullptr) { - zoneControlTemplate = zone->zoneControlTemplate != -1 ? zone->zoneControlTemplate : 2365; - const auto min = zone->ghostdistance_min != -1.0f ? zone->ghostdistance_min : 100; - const auto max = zone->ghostdistance != -1.0f ? zone->ghostdistance : 100; - Game::entityManager->SetGhostDistanceMax(max + min); - Game::entityManager->SetGhostDistanceMin(max); - m_PlayerLoseCoinsOnDeath = zone->PlayerLoseCoinsOnDeath; - m_DisableSaveLocation = zone->disableSaveLoc; - m_MountsAllowed = zone->mountsAllowed; - m_PetsAllowed = zone->petsAllowed; - } + if (zone != nullptr) { + zoneControlTemplate = zone->zoneControlTemplate != -1 ? zone->zoneControlTemplate : 2365; + const auto min = zone->ghostdistance_min != -1.0f ? zone->ghostdistance_min : 100; + const auto max = zone->ghostdistance != -1.0f ? zone->ghostdistance : 100; + Game::entityManager->SetGhostDistanceMax(max + min); + Game::entityManager->SetGhostDistanceMin(max); + m_PlayerLoseCoinsOnDeath = zone->PlayerLoseCoinsOnDeath; + m_DisableSaveLocation = zone->disableSaveLoc; + m_MountsAllowed = zone->mountsAllowed; + m_PetsAllowed = zone->petsAllowed; } LOG("Creating zone control object %i", zoneControlTemplate); @@ -56,7 +54,9 @@ void dZoneManager::Initialize(const LWOZONEID& zoneID) { Game::entityManager->Initialize(); EntityInfo info; info.lot = zoneControlTemplate; - info.id = 70368744177662; + + /* Yep its hardcoded like this in the client too, this exact value. */ + info.id = 0x3FFF'FFFFFFFELL; Entity* zoneControl = Game::entityManager->CreateEntity(info, nullptr, nullptr, true); m_ZoneControlObject = zoneControl; @@ -74,16 +74,16 @@ void dZoneManager::Initialize(const LWOZONEID& zoneID) { dZoneManager::~dZoneManager() { if (m_pZone) delete m_pZone; - for (std::pair p : m_Spawners) { - if (p.second) { - delete p.second; - p.second = nullptr; + for (auto* spawner : m_Spawners | std::views::values) { + if (spawner) { + delete spawner; + spawner = nullptr; } } - if (m_WorldConfig) delete m_WorldConfig; } -Zone* dZoneManager::GetZone() { +Zone* dZoneManager::GetZoneMut() const { + DluAssert(m_pZone); return m_pZone; } @@ -91,20 +91,20 @@ void dZoneManager::LoadZone(const LWOZONEID& zoneID) { if (m_pZone) delete m_pZone; m_ZoneID = zoneID; - m_pZone = new Zone(zoneID.GetMapID(), zoneID.GetInstanceID(), zoneID.GetCloneID()); + m_pZone = new Zone(zoneID); } void dZoneManager::AddSpawner(LWOOBJID id, Spawner* spawner) { - m_Spawners.insert_or_assign(id, spawner); + m_Spawners[id] = spawner; } -LWOZONEID dZoneManager::GetZoneID() const { +const LWOZONEID& dZoneManager::GetZoneID() const { return m_ZoneID; } void dZoneManager::Update(float deltaTime) { - for (auto spawner : m_Spawners) { - spawner.second->Update(deltaTime); + for (auto spawner : m_Spawners | std::views::values) { + spawner->Update(deltaTime); } } @@ -136,12 +136,7 @@ LWOOBJID dZoneManager::MakeSpawner(SpawnerInfo info) { Spawner* dZoneManager::GetSpawner(const LWOOBJID id) { const auto& index = m_Spawners.find(id); - - if (index == m_Spawners.end()) { - return nullptr; - } - - return index->second; + return index != m_Spawners.end() ? index->second : nullptr; } void dZoneManager::RemoveSpawner(const LWOOBJID id) { @@ -154,10 +149,11 @@ void dZoneManager::RemoveSpawner(const LWOOBJID id) { auto* entity = Game::entityManager->GetEntity(id); + LOG("Destroying spawner (%llu)", id); + if (entity != nullptr) { entity->Kill(); } else { - LOG("Failed to find spawner entity (%llu)", id); } @@ -165,7 +161,7 @@ void dZoneManager::RemoveSpawner(const LWOOBJID id) { spawner->Deactivate(); - LOG("Destroying spawner (%llu)", id); + LOG("Destroyed spawner (%llu)", id); m_Spawners.erase(id); @@ -173,24 +169,23 @@ void dZoneManager::RemoveSpawner(const LWOOBJID id) { } -std::vector dZoneManager::GetSpawnersByName(std::string spawnerName) { +std::vector dZoneManager::GetSpawnersByName(const std::string& spawnerName) { std::vector spawners; - for (const auto& spawner : m_Spawners) { - if (spawner.second->GetName() == spawnerName) { - spawners.push_back(spawner.second); + for (const auto& spawner : m_Spawners | std::views::values) { + if (spawner->GetName() == spawnerName) { + spawners.push_back(spawner); } } return spawners; } -std::vector dZoneManager::GetSpawnersInGroup(std::string group) { +std::vector dZoneManager::GetSpawnersInGroup(const std::string& group) { std::vector spawnersInGroup; - for (auto spawner : m_Spawners) { - for (std::string entityGroup : spawner.second->m_Info.groups) { - if (entityGroup == group) { - spawnersInGroup.push_back(spawner.second); - } + for (auto spawner : m_Spawners | std::views::values) { + const auto& groups = spawner->m_Info.groups; + if (std::ranges::find(groups, group) != groups.end()) { + spawnersInGroup.push_back(spawner); } } @@ -200,71 +195,83 @@ std::vector dZoneManager::GetSpawnersInGroup(std::string group) { uint32_t dZoneManager::GetUniqueMissionIdStartingValue() { if (m_UniqueMissionIdStart == 0) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM Missions WHERE isMission = 0 GROUP BY isMission;"); - m_UniqueMissionIdStart = tableData.getIntField(0, -1); - tableData.finalize(); + m_UniqueMissionIdStart = tableData.getIntField(0, 1); } return m_UniqueMissionIdStart; } bool dZoneManager::CheckIfAccessibleZone(LWOMAPID zoneID) { - //We're gonna go ahead and presume we've got the db loaded already: - CDZoneTableTable* zoneTable = CDClientManager::GetTable(); - const CDZoneTable* zone = zoneTable->Query(zoneID); - if (zone != nullptr) { - return Game::assetManager->HasFile(("maps/" + zone->zoneName).c_str()); - } else { - return false; - } + const CDZoneTable* zone = CDZoneTableTable::Query(zoneID); + return zone && Game::assetManager->HasFile("maps/" + zone->zoneName); } void dZoneManager::LoadWorldConfig() { - LOG("Loading WorldConfig into memory"); + // Already loaded + if (m_WorldConfig) return; - auto worldConfig = CDClientDatabase::ExecuteQuery("SELECT * FROM WorldConfig;"); + LOG_DEBUG("Loading WorldConfig into memory"); - if (!m_WorldConfig) m_WorldConfig = new WorldConfig(); + // This table only has 1 row and only should have 1 row. + auto worldConfig = CDClientDatabase::ExecuteQuery("SELECT * FROM WorldConfig LIMIT 1;"); + + m_WorldConfig = WorldConfig(); if (worldConfig.eof()) { - LOG("WorldConfig table is empty. Is this intended?"); + LOG("WorldConfig table is empty. Is this intended?"); return; } // Now read in the giant table - m_WorldConfig->worldConfigID = worldConfig.getIntField("WorldConfigID"); m_WorldConfig->peGravityValue = worldConfig.getFloatField("pegravityvalue"); m_WorldConfig->peBroadphaseWorldSize = worldConfig.getFloatField("pebroadphaseworldsize"); m_WorldConfig->peGameObjScaleFactor = worldConfig.getFloatField("pegameobjscalefactor"); + m_WorldConfig->characterRotationSpeed = worldConfig.getFloatField("character_rotation_speed"); + m_WorldConfig->characterWalkForwardSpeed = worldConfig.getFloatField("character_walk_forward_speed"); m_WorldConfig->characterWalkBackwardSpeed = worldConfig.getFloatField("character_walk_backward_speed"); m_WorldConfig->characterWalkStrafeSpeed = worldConfig.getFloatField("character_walk_strafe_speed"); m_WorldConfig->characterWalkStrafeForwardSpeed = worldConfig.getFloatField("character_walk_strafe_forward_speed"); m_WorldConfig->characterWalkStrafeBackwardSpeed = worldConfig.getFloatField("character_walk_strafe_backward_speed"); + m_WorldConfig->characterRunBackwardSpeed = worldConfig.getFloatField("character_run_backward_speed"); m_WorldConfig->characterRunStrafeSpeed = worldConfig.getFloatField("character_run_strafe_speed"); m_WorldConfig->characterRunStrafeForwardSpeed = worldConfig.getFloatField("character_run_strafe_forward_speed"); m_WorldConfig->characterRunStrafeBackwardSpeed = worldConfig.getFloatField("character_run_strafe_backward_speed"); - m_WorldConfig->globalCooldown = worldConfig.getFloatField("global_cooldown"); + m_WorldConfig->characterGroundedTime = worldConfig.getFloatField("characterGroundedTime"); m_WorldConfig->characterGroundedSpeed = worldConfig.getFloatField("characterGroundedSpeed"); - m_WorldConfig->globalImmunityTime = worldConfig.getFloatField("globalImmunityTime"); + + m_WorldConfig->characterVersion = worldConfig.getIntField("CharacterVersion"); + m_WorldConfig->characterEyeHeight = worldConfig.getFloatField("character_eye_height"); m_WorldConfig->characterMaxSlope = worldConfig.getFloatField("character_max_slope"); + + m_WorldConfig->globalCooldown = worldConfig.getFloatField("global_cooldown"); + m_WorldConfig->globalImmunityTime = worldConfig.getFloatField("globalImmunityTime"); + m_WorldConfig->defaultRespawnTime = worldConfig.getFloatField("defaultrespawntime"); m_WorldConfig->missionTooltipTimeout = worldConfig.getFloatField("mission_tooltip_timeout"); m_WorldConfig->vendorBuyMultiplier = worldConfig.getFloatField("vendor_buy_multiplier", 0.1); m_WorldConfig->petFollowRadius = worldConfig.getFloatField("pet_follow_radius"); - m_WorldConfig->characterEyeHeight = worldConfig.getFloatField("character_eye_height"); + m_WorldConfig->flightVerticalVelocity = worldConfig.getFloatField("flight_vertical_velocity"); m_WorldConfig->flightAirspeed = worldConfig.getFloatField("flight_airspeed"); m_WorldConfig->flightFuelRatio = worldConfig.getFloatField("flight_fuel_ratio"); m_WorldConfig->flightMaxAirspeed = worldConfig.getFloatField("flight_max_airspeed"); - m_WorldConfig->fReputationPerVote = worldConfig.getFloatField("fReputationPerVote"); - m_WorldConfig->propertyCloneLimit = worldConfig.getIntField("nPropertyCloneLimit"); + m_WorldConfig->defaultHomespaceTemplate = worldConfig.getIntField("defaultHomespaceTemplate"); + m_WorldConfig->coinsLostOnDeathPercent = worldConfig.getFloatField("coins_lost_on_death_percent"); m_WorldConfig->coinsLostOnDeathMin = worldConfig.getIntField("coins_lost_on_death_min"); m_WorldConfig->coinsLostOnDeathMax = worldConfig.getIntField("coins_lost_on_death_max"); + m_WorldConfig->coinsLostOnDeathMinTimeout = worldConfig.getFloatField("coins_lost_on_death_min_timeout"); + m_WorldConfig->coinsLostOnDeathMaxTimeout = worldConfig.getFloatField("coins_lost_on_death_max_timeout"); + m_WorldConfig->characterVotesPerDay = worldConfig.getIntField("character_votes_per_day"); + + m_WorldConfig->defaultPropertyMaxHeight = worldConfig.getFloatField("defaultPropertyMaxHeight"); + m_WorldConfig->propertyCloneLimit = worldConfig.getIntField("nPropertyCloneLimit"); + m_WorldConfig->propertyReputationDelay = worldConfig.getIntField("propertyReputationDelay"); m_WorldConfig->propertyModerationRequestApprovalCost = worldConfig.getIntField("property_moderation_request_approval_cost"); m_WorldConfig->propertyModerationRequestReviewCost = worldConfig.getIntField("property_moderation_request_review_cost"); m_WorldConfig->propertyModRequestsAllowedSpike = worldConfig.getIntField("propertyModRequestsAllowedSpike"); @@ -272,21 +279,22 @@ void dZoneManager::LoadWorldConfig() { m_WorldConfig->propertyModRequestsAllowedTotal = worldConfig.getIntField("propertyModRequestsAllowedTotal"); m_WorldConfig->propertyModRequestsSpikeDuration = worldConfig.getIntField("propertyModRequestsSpikeDuration"); m_WorldConfig->propertyModRequestsIntervalDuration = worldConfig.getIntField("propertyModRequestsIntervalDuration"); + m_WorldConfig->modelModerateOnCreate = worldConfig.getIntField("modelModerateOnCreate") != 0; - m_WorldConfig->defaultPropertyMaxHeight = worldConfig.getFloatField("defaultPropertyMaxHeight"); + + m_WorldConfig->fReputationPerVote = worldConfig.getFloatField("fReputationPerVote"); m_WorldConfig->reputationPerVoteCast = worldConfig.getFloatField("reputationPerVoteCast"); m_WorldConfig->reputationPerVoteReceived = worldConfig.getFloatField("reputationPerVoteReceived"); - m_WorldConfig->showcaseTopModelConsiderationBattles = worldConfig.getIntField("showcaseTopModelConsiderationBattles"); m_WorldConfig->reputationPerBattlePromotion = worldConfig.getFloatField("reputationPerBattlePromotion"); - m_WorldConfig->coinsLostOnDeathMinTimeout = worldConfig.getFloatField("coins_lost_on_death_min_timeout"); - m_WorldConfig->coinsLostOnDeathMaxTimeout = worldConfig.getFloatField("coins_lost_on_death_max_timeout"); + + m_WorldConfig->showcaseTopModelConsiderationBattles = worldConfig.getIntField("showcaseTopModelConsiderationBattles"); + m_WorldConfig->mailBaseFee = worldConfig.getIntField("mail_base_fee"); m_WorldConfig->mailPercentAttachmentFee = worldConfig.getFloatField("mail_percent_attachment_fee"); - m_WorldConfig->propertyReputationDelay = worldConfig.getIntField("propertyReputationDelay"); + m_WorldConfig->levelCap = worldConfig.getIntField("LevelCap"); m_WorldConfig->levelUpBehaviorEffect = worldConfig.getStringField("LevelUpBehaviorEffect"); - m_WorldConfig->characterVersion = worldConfig.getIntField("CharacterVersion"); m_WorldConfig->levelCapCurrencyConversion = worldConfig.getIntField("LevelCapCurrencyConversion"); - worldConfig.finalize(); - LOG("Loaded WorldConfig into memory"); + + LOG_DEBUG("Loaded WorldConfig into memory"); } diff --git a/dZoneManager/dZoneManager.h b/dZoneManager/dZoneManager.h index 4e512d22..f9abee8c 100644 --- a/dZoneManager/dZoneManager.h +++ b/dZoneManager/dZoneManager.h @@ -1,11 +1,10 @@ #pragma once #include "dZMCommon.h" +#include "WorldConfig.h" #include "Zone.h" #include "Spawner.h" #include -class WorldConfig; - class dZoneManager { public: enum class dZoneNotifier { @@ -27,28 +26,36 @@ public: void Initialize(const LWOZONEID& zoneID); ~dZoneManager(); - Zone* GetZone(); //Gets a pointer to the currently loaded zone. + /* Gets a pointer to the currently loaded zone. */ + Zone* GetZoneMut() const; + const Zone* GetZone() const { return GetZoneMut(); }; void LoadZone(const LWOZONEID& zoneID); //Discard the current zone (if any) and loads a new zone. + + /* Adds a spawner to the zone with the specified ID. */ void AddSpawner(LWOOBJID id, Spawner* spawner); - LWOZONEID GetZoneID() const; + const LWOZONEID& GetZoneID() const; + + /* Creates a new spawner. Returns the finalized ID for the created spawner since some bits may be set to get it to function. */ LWOOBJID MakeSpawner(SpawnerInfo info); Spawner* GetSpawner(LWOOBJID id); void RemoveSpawner(LWOOBJID id); - std::vector GetSpawnersByName(std::string spawnerName); - std::vector GetSpawnersInGroup(std::string group); + std::vector GetSpawnersByName(const std::string& spawnerName); + std::vector GetSpawnersInGroup(const std::string& group); void Update(float deltaTime); Entity* GetZoneControlObject() { return m_ZoneControlObject; } bool GetPlayerLoseCoinOnDeath() { return m_PlayerLoseCoinsOnDeath; } bool GetDisableSaveLocation() { return m_DisableSaveLocation; } bool GetMountsAllowed() { return m_MountsAllowed; } bool GetPetsAllowed() { return m_PetsAllowed; } + + /* Gets the starting ID for missions in the player UI so they are ordered properly and show in the order accepted by the player. */ uint32_t GetUniqueMissionIdStartingValue(); bool CheckIfAccessibleZone(LWOMAPID zoneID); // The world config should not be modified by a caller. - const WorldConfig* GetWorldConfig() { + const WorldConfig& GetWorldConfig() { if (!m_WorldConfig) LoadWorldConfig(); - return m_WorldConfig; + return m_WorldConfig.value(); }; private: @@ -64,7 +71,7 @@ private: bool m_MountsAllowed = true; bool m_PetsAllowed = true; std::map m_Spawners; - WorldConfig* m_WorldConfig = nullptr; + std::optional m_WorldConfig = std::nullopt; Entity* m_ZoneControlObject = nullptr; };