diff --git a/dGame/dComponents/DestroyableComponent.h b/dGame/dComponents/DestroyableComponent.h index 011ab795..8c4d1127 100644 --- a/dGame/dComponents/DestroyableComponent.h +++ b/dGame/dComponents/DestroyableComponent.h @@ -17,7 +17,7 @@ enum class eStateChangeType : uint32_t; * Represents the stats of an entity, for example its health, imagination and armor. Also handles factions, which * indicate which enemies this entity has. */ -class DestroyableComponent : public Component { +class DestroyableComponent final : public Component { public: inline static const eReplicaComponentType ComponentType = eReplicaComponentType::DESTROYABLE; diff --git a/dGame/dComponents/DonationVendorComponent.h b/dGame/dComponents/DonationVendorComponent.h index df6d3562..22832f14 100644 --- a/dGame/dComponents/DonationVendorComponent.h +++ b/dGame/dComponents/DonationVendorComponent.h @@ -6,7 +6,7 @@ class Entity; -class DonationVendorComponent : public VendorComponent { +class DonationVendorComponent final : public VendorComponent { public: inline static const eReplicaComponentType ComponentType = eReplicaComponentType::DONATION_VENDOR; DonationVendorComponent(Entity* parent); diff --git a/dGame/dComponents/GateRushComponent.h b/dGame/dComponents/GateRushComponent.h index 8680e2d7..baf96765 100644 --- a/dGame/dComponents/GateRushComponent.h +++ b/dGame/dComponents/GateRushComponent.h @@ -6,7 +6,7 @@ class Entity; -class GateRushComponent : public RacingControlComponent { +class GateRushComponent final : public RacingControlComponent { public: inline static const eReplicaComponentType ComponentType = eReplicaComponentType::GATE_RUSH_CONTROL; GateRushComponent(Entity* parent, int32_t componentId); diff --git a/dGame/dComponents/HavokVehiclePhysicsComponent.h b/dGame/dComponents/HavokVehiclePhysicsComponent.h index fd730f17..dfaa10b0 100644 --- a/dGame/dComponents/HavokVehiclePhysicsComponent.h +++ b/dGame/dComponents/HavokVehiclePhysicsComponent.h @@ -26,7 +26,7 @@ struct RemoteInputInfo { /** * Physics component for vehicles. */ -class HavokVehiclePhysicsComponent : public Component { +class HavokVehiclePhysicsComponent final : public Component { public: inline static const eReplicaComponentType ComponentType = eReplicaComponentType::HAVOK_VEHICLE_PHYSICS; diff --git a/dGame/dComponents/InventoryComponent.h b/dGame/dComponents/InventoryComponent.h index fc4b4921..864f07a4 100644 --- a/dGame/dComponents/InventoryComponent.h +++ b/dGame/dComponents/InventoryComponent.h @@ -35,7 +35,7 @@ enum class eItemType : int32_t; * of different types, each type representing a different group of items, see `eInventoryType` for a list of * inventories. */ -class InventoryComponent : public Component +class InventoryComponent final : public Component { public: inline static const eReplicaComponentType ComponentType = eReplicaComponentType::INVENTORY; diff --git a/dGame/dComponents/ItemComponent.cpp b/dGame/dComponents/ItemComponent.cpp index bb201b00..fb7133dc 100644 --- a/dGame/dComponents/ItemComponent.cpp +++ b/dGame/dComponents/ItemComponent.cpp @@ -2,7 +2,6 @@ #include "Entity.h" #include "eUgcModerationStatus.h" - ItemComponent::ItemComponent(Entity* parent) : Component(parent) { m_ParentEntity = parent; @@ -19,13 +18,13 @@ ItemComponent::ItemComponent(Entity* parent) : Component(parent) { void ItemComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { outBitStream->Write(m_DirtyItemInfo || bIsInitialUpdate); - if (m_DirtyItemInfo || bIsInitialUpdate){ + if (m_DirtyItemInfo || bIsInitialUpdate) { outBitStream->Write(m_UgId); outBitStream->Write(m_UgModerationStatus); - outBitStream->Write(m_UgDescription != u""); - if (m_UgDescription != u""){ + outBitStream->Write(!m_UgDescription.empty()); + if (!m_UgDescription.empty()){ outBitStream->Write(m_UgDescription.length()); - for (uint16_t character : m_UgDescription) outBitStream->Write(character); + outBitStream->Write(reinterpret_cast(m_UgDescription.c_str()), m_UgDescription.length() * sizeof(uint16_t)); } m_DirtyItemInfo = false; } diff --git a/dGame/dComponents/ItemComponent.h b/dGame/dComponents/ItemComponent.h index ccfa63a8..75c36897 100644 --- a/dGame/dComponents/ItemComponent.h +++ b/dGame/dComponents/ItemComponent.h @@ -1,4 +1,7 @@ +#ifndef __ITEMCOMPONENT__H__ +#define __ITEMCOMPONENT__H__ #pragma once + #include "dCommonVars.h" #include "RakNetTypes.h" #include "NiPoint3.h" @@ -9,7 +12,7 @@ class Entity; enum class eUgcModerationStatus : uint32_t; -class ItemComponent : public Component { +class ItemComponent final : public Component { public: static const eReplicaComponentType ComponentType = eReplicaComponentType::ITEM; @@ -39,7 +42,7 @@ private: LWOOBJID m_UgId; /** - * + * Whether or not the description of this item is approved. */ eUgcModerationStatus m_UgModerationStatus; @@ -48,3 +51,5 @@ private: */ std::u16string m_UgDescription; }; + +#endif //!__ITEMCOMPONENT__H__ diff --git a/dGame/dComponents/LUPExhibitComponent.cpp b/dGame/dComponents/LUPExhibitComponent.cpp index 67014bbc..9034d7aa 100644 --- a/dGame/dComponents/LUPExhibitComponent.cpp +++ b/dGame/dComponents/LUPExhibitComponent.cpp @@ -3,42 +3,32 @@ #include "EntityManager.h" LUPExhibitComponent::LUPExhibitComponent(Entity* parent) : Component(parent) { - m_Exhibits = { 11121, 11295, 11423, 11979 }; - m_ExhibitIndex = 0; - - m_Exhibit = m_Exhibits[m_ExhibitIndex]; - - -} - -LUPExhibitComponent::~LUPExhibitComponent() { - + m_UpdateTimer = 0.0f; + m_Exhibit = m_Exhibits.front(); + m_DirtyExhibitInfo = true; } void LUPExhibitComponent::Update(float deltaTime) { m_UpdateTimer += deltaTime; + if (m_UpdateTimer < 20.0f) return; - if (m_UpdateTimer > 20.0f) { - NextExhibit(); - - m_UpdateTimer = 0.0f; - } + NextExhibit(); + m_UpdateTimer = 0.0f; } void LUPExhibitComponent::NextExhibit() { m_ExhibitIndex++; - if (m_ExhibitIndex >= m_Exhibits.size()) { - m_ExhibitIndex = 0; - } - - m_Exhibit = m_Exhibits[m_ExhibitIndex]; - + // After 1361 years, this will skip exhibit 4 one time. I think modulo is ok here. + m_Exhibit = m_Exhibits.at(m_ExhibitIndex % m_Exhibits.size()); EntityManager::Instance()->SerializeEntity(m_ParentEntity); } void LUPExhibitComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags) { - outBitStream->Write1(); // Dirty flag? - outBitStream->Write(m_Exhibit); + outBitStream->Write(bIsInitialUpdate || m_DirtyExhibitInfo); + if (bIsInitialUpdate || m_DirtyExhibitInfo) { + outBitStream->Write(m_Exhibit); + if (!bIsInitialUpdate) m_DirtyExhibitInfo = false; + } } diff --git a/dGame/dComponents/LUPExhibitComponent.h b/dGame/dComponents/LUPExhibitComponent.h index e8db875b..bfa86b48 100644 --- a/dGame/dComponents/LUPExhibitComponent.h +++ b/dGame/dComponents/LUPExhibitComponent.h @@ -8,13 +8,12 @@ * Component that handles the LOT that is shown in the LUP exhibit in the LUP world. Works by setting a timer and * switching the LOTs around that we'd like to display. */ -class LUPExhibitComponent : public Component +class LUPExhibitComponent final : public Component { public: inline static const eReplicaComponentType ComponentType = eReplicaComponentType::EXHIBIT; LUPExhibitComponent(Entity* parent); - ~LUPExhibitComponent(); void Update(float deltaTime) override; void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags); @@ -36,10 +35,13 @@ private: /** * The list of possible exhibits to show */ - std::vector m_Exhibits; + const std::vector m_Exhibits = { 11121, 11295, 11423, 11979 }; /** * The current index in the exhibit list */ size_t m_ExhibitIndex; + + // Whether or not to notify clients of a change in the visible exhibit + bool m_DirtyExhibitInfo; }; diff --git a/dGame/dComponents/LevelProgressionComponent.cpp b/dGame/dComponents/LevelProgressionComponent.cpp index 07fa9dca..4c08fe20 100644 --- a/dGame/dComponents/LevelProgressionComponent.cpp +++ b/dGame/dComponents/LevelProgressionComponent.cpp @@ -43,47 +43,48 @@ void LevelProgressionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { void LevelProgressionComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { outBitStream->Write(bIsInitialUpdate || m_DirtyLevelInfo); - if (bIsInitialUpdate || m_DirtyLevelInfo) outBitStream->Write(m_Level); - m_DirtyLevelInfo = false; + if (bIsInitialUpdate || m_DirtyLevelInfo) { + outBitStream->Write(m_Level); + if (!bIsInitialUpdate) m_DirtyLevelInfo = false; + } } void LevelProgressionComponent::HandleLevelUp() { auto* rewardsTable = CDClientManager::Instance().GetTable(); const auto& rewards = rewardsTable->GetByLevelID(m_Level); - bool rewardingItem = rewards.size() > 0; + if (rewards.empty()) return; auto* inventoryComponent = m_ParentEntity->GetComponent(); auto* controllablePhysicsComponent = m_ParentEntity->GetComponent(); if (!inventoryComponent || !controllablePhysicsComponent) return; // Tell the client we beginning to send level rewards. - if (rewardingItem) GameMessages::NotifyLevelRewards(m_ParentEntity->GetObjectID(), m_ParentEntity->GetSystemAddress(), m_Level, rewardingItem); + GameMessages::NotifyLevelRewards(m_ParentEntity->GetObjectID(), m_ParentEntity->GetSystemAddress(), m_Level, true); for (auto* reward : rewards) { switch (reward->rewardType) { case 0: inventoryComponent->AddItem(reward->value, reward->count, eLootSourceType::LEVEL_REWARD); break; - case 4: - { + case 4: { auto* items = inventoryComponent->GetInventory(eInventoryType::ITEMS); + if (!items) continue; items->SetSize(items->GetSize() + reward->value); + break; } - break; case 9: SetSpeedBase(static_cast(reward->value)); controllablePhysicsComponent->SetSpeedMultiplier(GetSpeedBase() / 500.0f); break; case 11: case 12: - break; default: break; } } // Tell the client we have finished sending level rewards. - if (rewardingItem) GameMessages::NotifyLevelRewards(m_ParentEntity->GetObjectID(), m_ParentEntity->GetSystemAddress(), m_Level, !rewardingItem); + GameMessages::NotifyLevelRewards(m_ParentEntity->GetObjectID(), m_ParentEntity->GetSystemAddress(), m_Level, false); } void LevelProgressionComponent::SetRetroactiveBaseSpeed() { diff --git a/dGame/dComponents/LevelProgressionComponent.h b/dGame/dComponents/LevelProgressionComponent.h index 033e54e5..5be9756a 100644 --- a/dGame/dComponents/LevelProgressionComponent.h +++ b/dGame/dComponents/LevelProgressionComponent.h @@ -11,7 +11,7 @@ * */ -class LevelProgressionComponent : public Component { +class LevelProgressionComponent final : public Component { public: inline static const eReplicaComponentType ComponentType = eReplicaComponentType::LEVEL_PROGRESSION; @@ -45,7 +45,11 @@ public: * Sets the level of the entity * @param level the level to set */ - void SetLevel(uint32_t level) { m_Level = level; m_DirtyLevelInfo = true; } + void SetLevel(uint32_t level) { + if (m_Level == level) return; + m_Level = level; + m_DirtyLevelInfo = true; + } /** * Gets the current Speed Base of the entity @@ -98,7 +102,7 @@ private: float m_SpeedBase; /** - * The Character format version + * The Character format version. Certain bug fixes increment this version number. */ eCharacterVersion m_CharacterVersion; diff --git a/dGame/dComponents/MissionComponent.cpp b/dGame/dComponents/MissionComponent.cpp index 221a0f89..315d9f72 100644 --- a/dGame/dComponents/MissionComponent.cpp +++ b/dGame/dComponents/MissionComponent.cpp @@ -1,9 +1,8 @@ /* * Darkflame Universe - * Copyright 2019 + * Copyright 2023 */ -#include #include #include "MissionComponent.h" @@ -19,62 +18,40 @@ #include "MissionPrerequisites.h" #include "AchievementCacheKey.h" #include "eMissionState.h" - - // MARK: Mission Component +#include "GeneralUtils.h" std::unordered_map> MissionComponent::m_AchievementCache = {}; -//! Initializer MissionComponent::MissionComponent(Entity* parent) : Component(parent) { m_LastUsedMissionOrderUID = dZoneManager::Instance()->GetUniqueMissionIdStartingValue(); } -//! Destructor MissionComponent::~MissionComponent() { - for (const auto& mission : m_Missions) { - delete mission.second; + for (const auto& [missionId, mission] : m_Missions) { + delete mission; } - - this->m_Missions.clear(); } - Mission* MissionComponent::GetMission(const uint32_t missionId) const { - if (m_Missions.count(missionId) == 0) { - return nullptr; - } + if (m_Missions.count(missionId) == 0) return nullptr; const auto& index = m_Missions.find(missionId); - if (index == m_Missions.end()) { - return nullptr; - } - - return index->second; + return index == m_Missions.end() ? nullptr : index->second; } - eMissionState MissionComponent::GetMissionState(const uint32_t missionId) const { auto* mission = GetMission(missionId); - if (mission == nullptr) { - return CanAccept(missionId) ? eMissionState::AVAILABLE : eMissionState::UNKNOWN; - } + if (!mission) return CanAccept(missionId) ? eMissionState::AVAILABLE : eMissionState::UNKNOWN; return mission->GetMissionState(); } - -const std::unordered_map& MissionComponent::GetMissions() const { - return m_Missions; -} - - bool MissionComponent::CanAccept(const uint32_t missionId) const { return MissionPrerequisites::CanAccept(missionId, m_Missions); } - void MissionComponent::AcceptMission(const uint32_t missionId, const bool skipChecks) { if (!skipChecks && !CanAccept(missionId)) { return; @@ -83,7 +60,7 @@ void MissionComponent::AcceptMission(const uint32_t missionId, const bool skipCh // If this is a daily mission, it may already be "accepted" auto* mission = this->GetMission(missionId); - if (mission != nullptr) { + if (mission) { if (mission->GetClientInfo().repeatable) { mission->Accept(); if (mission->IsMission()) mission->SetUniqueMissionOrderID(++m_LastUsedMissionOrderUID); @@ -100,54 +77,41 @@ void MissionComponent::AcceptMission(const uint32_t missionId, const bool skipCh this->m_Missions.insert_or_assign(missionId, mission); - if (missionId == 1728) { - //Needs to send a mail - - auto address = m_ParentEntity->GetSystemAddress(); - - Mail::HandleNotificationRequest(address, m_ParentEntity->GetObjectID()); - } + //Needs to send a mail + if (missionId == 1728) Mail::HandleNotificationRequest(m_ParentEntity->GetSystemAddress(), m_ParentEntity->GetObjectID()); } - void MissionComponent::CompleteMission(const uint32_t missionId, const bool skipChecks, const bool yieldRewards) { // Get the mission first auto* mission = this->GetMission(missionId); - if (mission == nullptr) { + if (!mission) { AcceptMission(missionId, skipChecks); mission = this->GetMission(missionId); - if (mission == nullptr) { - return; - } + if (!mission) return; } //If this mission is not repeatable, and already completed, we stop here. - if (mission->IsComplete() && !mission->IsRepeatable()) { - return; - } + if (mission->IsComplete() && !mission->IsRepeatable()) return; mission->Complete(yieldRewards); } -void MissionComponent::RemoveMission(uint32_t missionId) { - auto* mission = this->GetMission(missionId); +void MissionComponent::RemoveMission(const uint32_t missionId) { + auto missionItr = m_Missions.find(missionId); - if (mission == nullptr) { - return; - } + if (missionItr == m_Missions.end()) return; - delete mission; + delete missionItr->second; - m_Missions.erase(missionId); + m_Missions.erase(missionItr); } -void MissionComponent::Progress(eMissionTaskType type, int32_t value, LWOOBJID associate, const std::string& targets, int32_t count, bool ignoreAchievements) { - for (const auto& pair : m_Missions) { - auto* mission = pair.second; - +void MissionComponent::Progress(const eMissionTaskType type, const int32_t value, const LWOOBJID& associate, const std::string& targets, const int32_t count, const bool ignoreAchievements) { + for (const auto& [missionId, mission] : m_Missions) { + if (!mission) continue; if (mission->IsAchievement() && ignoreAchievements) continue; if (mission->IsComplete()) continue; @@ -163,73 +127,57 @@ void MissionComponent::Progress(eMissionTaskType type, int32_t value, LWOOBJID a void MissionComponent::ForceProgress(const uint32_t missionId, const uint32_t taskId, const int32_t value, const bool acceptMission) { auto* mission = GetMission(missionId); - if (mission == nullptr) { - if (!acceptMission) { - return; - } + if (!mission) { + if (!acceptMission) return; AcceptMission(missionId); mission = GetMission(missionId); - if (mission == nullptr) { - return; - } + if (!mission) return; } - for (auto* element : mission->GetTasks()) { - if (element->GetClientInfo().uid != taskId) continue; + std::for_each(mission->GetTasks().begin(), mission->GetTasks().end(), [value, taskId](MissionTask* element) { + if (element->GetClientInfo().uid != taskId) return; element->AddProgress(value); - } + }); - if (!mission->IsComplete()) { - mission->CheckCompletion(); - } + if (!mission->IsComplete()) mission->CheckCompletion(); } void MissionComponent::ForceProgressTaskType(const uint32_t missionId, const uint32_t taskType, const int32_t value, const bool acceptMission) { auto* mission = GetMission(missionId); - if (mission == nullptr) { - if (!acceptMission) { - return; - } + if (!mission) { + if (!acceptMission) return; CDMissions missionInfo; - if (!GetMissionInfo(missionId, missionInfo)) { - return; - } + if (!GetMissionInfo(missionId, missionInfo)) return; - if (missionInfo.isMission) { - return; - } + if (missionInfo.isMission) return; AcceptMission(missionId); mission = GetMission(missionId); - if (mission == nullptr) { - return; - } + if (!mission) return; } - for (auto* element : mission->GetTasks()) { - if (element->GetType() != static_cast(taskType)) continue; + std::for_each(mission->GetTasks().begin(), mission->GetTasks().end(), [value, taskType](MissionTask* element) { + if (element->GetType() != static_cast(taskType)) return; element->AddProgress(value); - } + }); - if (!mission->IsComplete()) { - mission->CheckCompletion(); - } + if (!mission->IsComplete()) mission->CheckCompletion(); } -void MissionComponent::ForceProgressValue(uint32_t missionId, uint32_t taskType, int32_t value, bool acceptMission) { +void MissionComponent::ForceProgressValue(const uint32_t missionId, const uint32_t taskType, const int32_t value, const bool acceptMission) { auto* mission = GetMission(missionId); - if (mission == nullptr) { + if (!mission) { if (!acceptMission) { return; } @@ -264,11 +212,11 @@ void MissionComponent::ForceProgressValue(uint32_t missionId, uint32_t taskType, } } -bool MissionComponent::GetMissionInfo(uint32_t missionId, CDMissions& result) { +bool MissionComponent::GetMissionInfo(const uint32_t missionId, CDMissions& result) const { auto* missionsTable = CDClientManager::Instance().GetTable(); const auto missions = missionsTable->Query([=](const CDMissions& entry) { - return entry.id == static_cast(missionId); + return entry.id == static_cast(missionId); }); if (missions.empty()) { @@ -280,10 +228,7 @@ bool MissionComponent::GetMissionInfo(uint32_t missionId, CDMissions& result) { return true; } -#define MISSION_NEW_METHOD - -bool MissionComponent::LookForAchievements(eMissionTaskType type, int32_t value, bool progress, LWOOBJID associate, const std::string& targets, int32_t count) { -#ifdef MISSION_NEW_METHOD +bool MissionComponent::LookForAchievements(const eMissionTaskType type, const int32_t value, const bool progress, const LWOOBJID& associate, const std::string& targets, const int32_t count) { // Query for achievments, using the cache const auto& result = QueryAchievements(type, value, targets); @@ -291,9 +236,7 @@ bool MissionComponent::LookForAchievements(eMissionTaskType type, int32_t value, for (const uint32_t missionID : result) { // Check if we already have this achievement - if (GetMission(missionID) != nullptr) { - continue; - } + if (GetMission(missionID)) continue; // Check if we can accept this achievement if (!MissionPrerequisites::CanAccept(missionID, m_Missions)) { @@ -311,87 +254,15 @@ bool MissionComponent::LookForAchievements(eMissionTaskType type, int32_t value, any = true; - if (progress) { - // Progress mission to bring it up to speed - instance->Progress(type, value, associate, targets, count); - } + if (!progress) continue; + // Progress mission to bring it up to speed + instance->Progress(type, value, associate, targets, count); } return any; -#else - auto* missionTasksTable = CDClientManager::Instance().GetTable(); - auto* missionsTable = CDClientManager::Instance().GetTable(); - - auto tasks = missionTasksTable->Query([=](const CDMissionTasks& entry) { - return entry.taskType == static_cast(type); - }); - - auto any = false; - - for (const auto& task : tasks) { - if (GetMission(task.id) != nullptr) { - continue; - } - - const auto missionEntries = missionsTable->Query([=](const CDMissions& entry) { - return entry.id == static_cast(task.id) && !entry.isMission; - }); - - if (missionEntries.empty()) { - continue; - } - - const auto mission = missionEntries[0]; - - if (mission.isMission || !MissionPrerequisites::CanAccept(mission.id, m_Missions)) { - continue; - } - - if (task.target != value && task.targetGroup != targets) { - auto stream = std::istringstream(task.targetGroup); - std::string token; - - auto found = false; - - while (std::getline(stream, token, ',')) { - try { - const auto target = std::stoul(token); - - found = target == value; - - if (found) { - break; - } - } catch (std::invalid_argument& exception) { - Game::logger->Log("MissionComponent", "Failed to parse target (%s): (%s)!", token.c_str(), exception.what()); - } - } - - if (!found) { - continue; - } - } - - auto* instance = new Mission(this, mission.id); - - m_Missions.insert_or_assign(mission.id, instance); - - if (instance->IsMission()) instance->SetUniqueMissionOrderID(++m_LastUsedMissionOrderUID); - - instance->Accept(); - - any = true; - - if (progress) { - instance->Progress(type, value, associate, targets, count); - } - } - - return any; -#endif } -const std::vector& MissionComponent::QueryAchievements(eMissionTaskType type, int32_t value, const std::string targets) { +const std::vector& MissionComponent::QueryAchievements(const eMissionTaskType type, const int32_t value, const std::string& targets) { // Create a hash which represent this query for achievements AchievementCacheKey toFind; toFind.SetType(type); @@ -420,95 +291,68 @@ const std::vector& MissionComponent::QueryAchievements(eMissionTaskTyp // Seek the assosicated mission auto foundMission = false; - const auto& mission = missionsTable->GetByMissionID(task.id, foundMission); + const auto& cdMission = missionsTable->GetByMissionID(task.id, foundMission); - if (!foundMission || mission.isMission) { - continue; - } + if (!foundMission || cdMission.isMission) continue; // Compare the easy values if (task.target == value || task.targetGroup == targets) { - result.push_back(mission.id); + result.push_back(cdMission.id); continue; } // Compare the target group, array separated by ',' - auto stream = std::istringstream(task.targetGroup); - std::string token; + for (const auto& possibleMissionStr : GeneralUtils::SplitString(task.targetGroup, ',')) { + uint32_t possibleMission; + if (GeneralUtils::TryParse(possibleMissionStr, possibleMission) && possibleMission == value) { + result.push_back(cdMission.id); - while (std::getline(stream, token, ',')) { - try { - if (std::stoi(token) == value) { - result.push_back(mission.id); - - continue; - } - } catch (std::invalid_argument& exception) { - // Ignored + break; } } } - // Insert into cache - m_AchievementCache.insert_or_assign(toFind, result); - return m_AchievementCache.find(toFind)->second; + // Insert into cache and return the inserted value. + return m_AchievementCache.insert_or_assign(toFind, result).first->second; } bool MissionComponent::RequiresItem(const LOT lot) { - auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT type FROM Objects WHERE id = ?;"); - query.bind(1, (int)lot); + auto query = CDClientDatabase::CreatePreppedStmt("SELECT type FROM Objects WHERE id = ?;"); + query.bind(1, static_cast(lot)); auto result = query.execQuery(); - if (result.eof()) { - return false; - } + if (result.eof()) return false; if (!result.fieldIsNull(0)) { const auto type = std::string(result.getStringField(0)); - result.finalize(); - - if (type == "Powerup") { - return true; - } + if (type == "Powerup") return true; } - result.finalize(); - - for (const auto& pair : m_Missions) { - auto* mission = pair.second; - - if (mission->IsComplete()) { - continue; - } + for (const auto& [missionId, mission] : m_Missions) { + if (mission->IsComplete()) continue; for (auto* task : mission->GetTasks()) { if (task->IsComplete() || task->GetType() != eMissionTaskType::GATHER) { continue; } - if (!task->InAllTargets(lot)) { - continue; - } + if (!task->InAllTargets(lot)) continue; return true; } } - - const auto required = LookForAchievements(eMissionTaskType::GATHER, lot, false); - - return required; + return LookForAchievements(eMissionTaskType::GATHER, lot, false); } void MissionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { - if (doc == nullptr) return; + if (!doc) return; auto* mis = doc->FirstChildElement("obj")->FirstChildElement("mis"); - if (mis == nullptr) return; + if (!mis) return; auto* cur = mis->FirstChildElement("cur"); auto* done = mis->FirstChildElement("done"); @@ -516,7 +360,7 @@ void MissionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { auto* doneM = done->FirstChildElement(); while (doneM) { - int missionId; + uint32_t missionId; doneM->QueryAttribute("id", &missionId); @@ -533,7 +377,7 @@ void MissionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { uint32_t missionOrder{}; while (currentM) { - int missionId; + uint32_t missionId; currentM->QueryAttribute("id", &missionId); @@ -543,7 +387,7 @@ void MissionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { if (currentM->QueryAttribute("o", &missionOrder) == tinyxml2::XML_SUCCESS && mission->IsMission()) { mission->SetUniqueMissionOrderID(missionOrder); - if (missionOrder > m_LastUsedMissionOrderUID) m_LastUsedMissionOrderUID = missionOrder; + m_LastUsedMissionOrderUID = std::max(missionOrder, m_LastUsedMissionOrderUID); } currentM = currentM->NextSiblingElement(); @@ -554,7 +398,7 @@ void MissionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { void MissionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { - if (doc == nullptr) return; + if (!doc) return; auto shouldInsertMis = false; @@ -562,7 +406,7 @@ void MissionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { auto* mis = obj->FirstChildElement("mis"); - if (mis == nullptr) { + if (!mis) { mis = doc->NewElement("mis"); shouldInsertMis = true; @@ -573,50 +417,33 @@ void MissionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { auto* done = doc->NewElement("done"); auto* cur = doc->NewElement("cur"); - for (const auto& pair : m_Missions) { - auto* mission = pair.second; + for (const auto& [missionId, mission] : m_Missions) { + if (!mission) continue; + const auto complete = mission->IsComplete(); - if (mission) { - const auto complete = mission->IsComplete(); + auto* missionElement = doc->NewElement("m"); - auto* m = doc->NewElement("m"); + if (!complete && mission->IsMission()) missionElement->SetAttribute("o", mission->GetUniqueMissionOrderID()); - if (complete) { - mission->UpdateXml(m); + mission->UpdateXml(missionElement); - done->LinkEndChild(m); - - continue; - } - if (mission->IsMission()) m->SetAttribute("o", mission->GetUniqueMissionOrderID()); - - mission->UpdateXml(m); - - cur->LinkEndChild(m); - } + cur->LinkEndChild(missionElement); } mis->InsertFirstChild(done); mis->InsertEndChild(cur); - if (shouldInsertMis) { - obj->LinkEndChild(mis); - } + if (shouldInsertMis) obj->LinkEndChild(mis); } -void MissionComponent::AddCollectible(int32_t collectibleID) { - // Check if this collectible is already in the list - if (HasCollectible(collectibleID)) { - return; - } - - m_Collectibles.push_back(collectibleID); +void MissionComponent::AddCollectible(const int32_t collectibleID) { + if (!HasCollectible(collectibleID)) m_Collectibles.push_back(collectibleID); } -bool MissionComponent::HasCollectible(int32_t collectibleID) { +bool MissionComponent::HasCollectible(const int32_t collectibleID) const { return std::find(m_Collectibles.begin(), m_Collectibles.end(), collectibleID) != m_Collectibles.end(); } -bool MissionComponent::HasMission(uint32_t missionId) { +bool MissionComponent::HasMission(const uint32_t missionId) const { return GetMission(missionId) != nullptr; } diff --git a/dGame/dComponents/MissionComponent.h b/dGame/dComponents/MissionComponent.h index e82b5b67..b49f19d9 100644 --- a/dGame/dComponents/MissionComponent.h +++ b/dGame/dComponents/MissionComponent.h @@ -39,35 +39,35 @@ public: * Returns all the missions for this entity, mapped by mission ID * @return the missions for this entity, mapped by mission ID */ - const std::unordered_map& GetMissions() const; + const std::unordered_map& GetMissions() const { return m_Missions; }; /** * Returns the mission for the given mission ID, if it exists * @param missionId the id of the mission to get * @return the mission for the given mission ID */ - Mission* GetMission(uint32_t missionId) const; + Mission* GetMission(const uint32_t missionId) const; /** * Returns the current state of the entities progression for the mission of the specified ID * @param missionId the ID of the mission to get the mission state for * @return the mission state of the mission specified by the ID */ - eMissionState GetMissionState(uint32_t missionId) const; + eMissionState GetMissionState(const uint32_t missionId) const; /** * Checks if the entity has all the requirements for accepting the mission specified by the ID. * @param missionId the mission ID to check for if the character may accept it * @return whether this entity can accept the mission represented by the given mission ID */ - bool CanAccept(uint32_t missionId) const; + bool CanAccept(const uint32_t missionId) const; /** * Accepts the mission specified by the ID, if the entity may accept it. Also stores it in the mission inventory. * @param missionId the ID of the mission to accept * @param skipChecks skips the checks for the mission prerequisites */ - void AcceptMission(uint32_t missionId, bool skipChecks = false); + void AcceptMission(const uint32_t missionId, const bool skipChecks = false); /** * Completes the mission specified by the given ID, if the entity has fulfilled all progress requirements. @@ -75,13 +75,13 @@ public: * @param skipChecks skips the checks for having completed all of the mission tasks * @param yieldRewards whether to yield mission rewards, currently unused */ - void CompleteMission(uint32_t missionId, bool skipChecks = false, bool yieldRewards = true); + void CompleteMission(const uint32_t missionId, const bool skipChecks = false, const bool yieldRewards = true); /** * Removes the mission from the entities' mission chain. Not used for normal gameplay but useful for debugging. * @param missionId the ID of the mission to remove */ - void RemoveMission(uint32_t missionId); + void RemoveMission(const uint32_t missionId); /** * Attempts to progress mission tasks for a given type using parameters to progress. Note that this function is @@ -94,7 +94,7 @@ public: * @param count the number to progress by, for example the number of items * @param ignoreAchievements do not progress achievements */ - void Progress(eMissionTaskType type, int32_t value, LWOOBJID associate = 0, const std::string& targets = "", int32_t count = 1, bool ignoreAchievements = false); + void Progress(const eMissionTaskType type, const int32_t value, const LWOOBJID& associate = 0, const std::string& targets = "", const int32_t count = 1, const bool ignoreAchievements = false); /** * Forces progression for a mission and task, ignoring checks @@ -103,7 +103,7 @@ public: * @param value the value to progress with * @param acceptMission accept the mission if it was not already accepted */ - void ForceProgress(uint32_t missionId, uint32_t taskId, int32_t value, bool acceptMission = true); + void ForceProgress(const uint32_t missionId, const uint32_t taskId, const int32_t value, const bool acceptMission = true); /** * Forces progress for all tasks of a certain type that belong to the same mission @@ -112,7 +112,7 @@ public: * @param value the value to progress with * @param acceptMission accept the mission if it wasn't already */ - void ForceProgressTaskType(uint32_t missionId, uint32_t taskType, int32_t value, bool acceptMission = true); + void ForceProgressTaskType(const uint32_t missionId, const uint32_t taskType, const int32_t value, const bool acceptMission = true); /** * Force progresses by checking the value and progressing by 1 @@ -121,7 +121,7 @@ public: * @param value the value to check the mission values before progressing * @param acceptMission accept the mission if it wasn't already */ - void ForceProgressValue(uint32_t missionId, uint32_t taskType, int32_t value, bool acceptMission = true); + void ForceProgressValue(const uint32_t missionId, const uint32_t taskType, const int32_t value, const bool acceptMission = true); /** * Returns client database mission information for a mission @@ -129,7 +129,7 @@ public: * @param result the result to store the information in * @return true if the information was succesfully retrieved, false otherwise */ - bool GetMissionInfo(uint32_t missionId, CDMissions& result); + bool GetMissionInfo(const uint32_t missionId, CDMissions& result) const; /** * Checks if there's any achievements we might be able to accept for the given parameters @@ -141,34 +141,34 @@ public: * @param count the number of values to progress by (differs by task type) * @return true if a achievement was accepted, false otherwise */ - bool LookForAchievements(eMissionTaskType type, int32_t value, bool progress = true, LWOOBJID associate = LWOOBJID_EMPTY, const std::string& targets = "", int32_t count = 1); + bool LookForAchievements(const eMissionTaskType type, const int32_t value, const bool progress = true, const LWOOBJID& associate = LWOOBJID_EMPTY, const std::string& targets = "", const int32_t count = 1); /** * Checks if there's a mission active that requires the collection of the specified LOT * @param lot the LOT to check for * @return if there's a mission active that requires the collection of the specified LOT */ - bool RequiresItem(LOT lot); + bool RequiresItem(const LOT lot); /** * Collects a collectable for the entity, unrendering it for the entity * @param collectibleID the ID of the collectable to add */ - void AddCollectible(int32_t collectibleID); + void AddCollectible(const int32_t collectibleID); /** * Checks if the entity already has a collectible of the specified ID * @param collectibleID the ID of the collectible to check * @return if the entity already has a collectible of the specified ID */ - bool HasCollectible(int32_t collectibleID); + bool HasCollectible(const int32_t collectibleID) const; /** * Checks if the entity has a certain mission in its inventory * @param missionId the ID of the mission to check * @return if the entity has a certain mission in its inventory */ - bool HasMission(uint32_t missionId); + bool HasMission(const uint32_t missionId) const; private: /** @@ -189,7 +189,7 @@ private: * @param targets optional targets to progress with * @return list of mission IDs (achievements) that can be progressed for the given parameters */ - static const std::vector& QueryAchievements(eMissionTaskType type, int32_t value, const std::string targets); + static const std::vector& QueryAchievements(const eMissionTaskType type, const int32_t value, const std::string& targets); /** * As achievements can be hard to query, we here store a list of all the mission IDs that can be unlocked for a diff --git a/dGame/dComponents/MissionOfferComponent.cpp b/dGame/dComponents/MissionOfferComponent.cpp index 774de1c7..7dbaecdc 100644 --- a/dGame/dComponents/MissionOfferComponent.cpp +++ b/dGame/dComponents/MissionOfferComponent.cpp @@ -1,6 +1,6 @@ /* * Darkflame Universe - * Copyright 2019 + * Copyright 2023 */ #include @@ -18,61 +18,26 @@ #include "CDComponentsRegistryTable.h" -OfferedMission::OfferedMission(const uint32_t missionId, const bool offersMission, const bool acceptsMission) { - this->missionId = missionId; - this->offersMission = offersMission; - this->acceptsMission = acceptsMission; +MissionOfferComponent::MissionOfferComponent(Entity* parent, const int32_t componentId) : Component(parent) { + m_ComponentId = componentId; } +void MissionOfferComponent::LoadTemplateData() { + if (m_ComponentId == -1) return; + // Now lookup the missions in the MissionNPCComponent table + auto* missionNpcComponentTable = CDClientManager::Instance().GetTable(); -uint32_t OfferedMission::GetMissionId() const { - return this->missionId; -} + auto missions = missionNpcComponentTable->Query([=](const CDMissionNPCComponent& entry) { + return entry.id == static_cast(m_ComponentId); + }); -bool OfferedMission::GetOfferMission() const { - return this->offersMission; -} - -bool OfferedMission::GetAcceptMission() const { - return this->acceptsMission; -} - -//------------------------ MissionOfferComponent below ------------------------ - -MissionOfferComponent::MissionOfferComponent(Entity* parent, const LOT parentLot) : Component(parent) { - auto* compRegistryTable = CDClientManager::Instance().GetTable(); - - auto value = compRegistryTable->GetByIDAndType(parentLot, eReplicaComponentType::MISSION_OFFER, -1); - - if (value != -1) { - const uint32_t componentId = value; - - // Now lookup the missions in the MissionNPCComponent table - auto* missionNpcComponentTable = CDClientManager::Instance().GetTable(); - - auto missions = missionNpcComponentTable->Query([=](const CDMissionNPCComponent& entry) { - return entry.id == static_cast(componentId); - }); - - for (auto& mission : missions) { - auto* offeredMission = new OfferedMission(mission.missionID, mission.offersMission, mission.acceptsMission); - this->offeredMissions.push_back(offeredMission); - } + for (const auto& mission : missions) { + this->offeredMissions.emplace_back( + std::make_unique(mission.missionID, mission.offersMission, mission.acceptsMission) + ); } } - -MissionOfferComponent::~MissionOfferComponent() { - for (auto* mission : this->offeredMissions) { - if (mission) { - delete mission; - mission = nullptr; - } - } - - offeredMissions.clear(); -} - void MissionOfferComponent::OnUse(Entity* originator) { OfferMissions(originator); } @@ -88,17 +53,15 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi std::vector offered{}; - CDMissions info{}; + CDMissions missionInfo{}; - if (specifiedMissionId > 0 && !Mission::IsValidMission(specifiedMissionId, info)) { + if (specifiedMissionId > 0 && !Mission::IsValidMission(specifiedMissionId, missionInfo)) { return; } - for (auto* offeredMission : this->offeredMissions) { - if (specifiedMissionId > 0) { - if (offeredMission->GetMissionId() != specifiedMissionId && !info.isRandom) { - continue; - } + for (const auto& offeredMission : offeredMissions) { + if (specifiedMissionId > 0 && (offeredMission->GetMissionId() != specifiedMissionId && !missionInfo.isRandom)) { + continue; } // First, check if we already have the mission @@ -106,10 +69,13 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi auto* mission = missionComponent->GetMission(missionId); - if (mission != nullptr) { + if (mission) { if (specifiedMissionId <= 0) { // Handles the odd case where the offer object should not display the mission again - if (!mission->IsComplete() && mission->GetClientInfo().offer_objectID == m_ParentEntity->GetLOT() && mission->GetClientInfo().target_objectID != m_ParentEntity->GetLOT() && mission->IsFetchMission()) { + if (!mission->IsComplete() && + mission->GetClientInfo().offer_objectID == m_ParentEntity->GetLOT() && + mission->GetClientInfo().target_objectID != m_ParentEntity->GetLOT() && + mission->IsFetchMission()) { continue; } } @@ -127,50 +93,30 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi const auto canAccept = MissionPrerequisites::CanAccept(missionId, missionComponent->GetMissions()); // Mission has not yet been accepted - check the prereqs - if (!canAccept) - continue; + if (!canAccept || !Mission::IsValidMission(missionId, missionInfo)) continue; - if (!Mission::IsValidMission(missionId, info)) { - continue; - } + // This means the mission is part of a random pool of missions. + if (missionInfo.isRandom && missionInfo.randomPool.empty()) continue; - const auto& randomPool = info.randomPool; - const auto isRandom = info.isRandom; + if (missionInfo.isRandom && !missionInfo.randomPool.empty()) { + auto randomMissionPoolStr = GeneralUtils::SplitString(missionInfo.randomPool, ','); - if (isRandom && randomPool.empty()) // This means the mission is part of a random pool of missions. - { - continue; - } - - if (isRandom && !randomPool.empty()) { - std::istringstream stream(randomPool); - std::string token; - - std::vector randomMissionPool; - - while (std::getline(stream, token, ',')) { - try { - const auto value = std::stoul(token); - - randomMissionPool.push_back(value); - } catch (std::invalid_argument& exception) { - Game::logger->Log("MissionOfferComponent", "Failed to parse value (%s): (%s)!", token.c_str(), exception.what()); - } + std::vector randomMissions; + for (const auto& randomMissionStr : randomMissionPoolStr) { + uint32_t randomMission; + if (GeneralUtils::TryParse(randomMissionStr, randomMission)) randomMissions.push_back(randomMission); } if (specifiedMissionId > 0) { - const auto& iter = std::find(randomMissionPool.begin(), randomMissionPool.end(), specifiedMissionId); - - if (iter != randomMissionPool.end() && MissionPrerequisites::CanAccept(specifiedMissionId, missionComponent->GetMissions())) { + if (std::find(randomMissions.begin(), randomMissions.end(), specifiedMissionId) != randomMissions.end() && + MissionPrerequisites::CanAccept(specifiedMissionId, missionComponent->GetMissions())) { GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), specifiedMissionId, m_ParentEntity->GetObjectID()); - return; } } std::vector canAcceptPool; - - for (const auto sample : randomMissionPool) { + for (const auto& sample : randomMissions) { const auto state = missionComponent->GetMissionState(sample); if (state == eMissionState::ACTIVE || @@ -180,9 +126,7 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi sample == specifiedMissionId) { mission = missionComponent->GetMission(sample); - if (mission == nullptr || mission->IsAchievement()) { - continue; - } + if (!mission || mission->IsAchievement()) continue; GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), sample, m_ParentEntity->GetObjectID()); @@ -191,16 +135,16 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi break; } - if (std::find(offered.begin(), offered.end(), sample) == offered.end() && MissionPrerequisites::CanAccept(sample, missionComponent->GetMissions())) { + if (std::find(offered.begin(), offered.end(), sample) == offered.end() && + MissionPrerequisites::CanAccept(sample, missionComponent->GetMissions())) { canAcceptPool.push_back(sample); } } // If the mission is already active or we already completed one of them today - if (canAcceptPool.empty()) - continue; + if (canAcceptPool.empty()) continue; - const auto selected = canAcceptPool[GeneralUtils::GenerateRandomNumber(0, canAcceptPool.size() - 1)]; + const auto selected = canAcceptPool[GeneralUtils::GenerateRandomNumber(0, canAcceptPool.size() - 1)]; GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), selected, m_ParentEntity->GetObjectID()); } else if (std::find(offered.begin(), offered.end(), missionId) == offered.end() && offeredMission->GetOfferMission()) { diff --git a/dGame/dComponents/MissionOfferComponent.h b/dGame/dComponents/MissionOfferComponent.h index ad5f83bc..78da8fd9 100644 --- a/dGame/dComponents/MissionOfferComponent.h +++ b/dGame/dComponents/MissionOfferComponent.h @@ -1,15 +1,18 @@ /* * Darkflame Universe - * Copyright 2019 + * Copyright 2023 */ -#ifndef MISSIONOFFERCOMPONENT_H -#define MISSIONOFFERCOMPONENT_H +#ifndef __MISSIONOFFERCOMPONENT_H__ +#define __MISSIONOFFERCOMPONENT_H__ +#pragma once + +#include +#include +#include #include "dCommonVars.h" #include "Component.h" -#include -#include #include "eReplicaComponentType.h" class Entity; @@ -18,25 +21,29 @@ class Entity; * Light wrapper around missions that may be offered by an entity */ struct OfferedMission { - OfferedMission(uint32_t missionId, bool offersMission, bool acceptsMission); + OfferedMission(const uint32_t missionId, const bool offersMission, const bool acceptsMission) { + this->missionId = missionId; + this->offersMission = offersMission; + this->acceptsMission = acceptsMission; + }; /** * Returns the ID of the mission * @return the ID of the mission */ - uint32_t GetMissionId() const; + uint32_t GetMissionId() const { return missionId; }; /** * Returns if this mission is offered by the entity * @return true if this mission is offered by the entity, false otherwise */ - bool GetOfferMission() const; + bool GetOfferMission() const { return offersMission; }; /** * Returns if this mission may be accepted by the entity (currently unused) * @return true if this mission may be accepted by the entity, false otherwise */ - bool GetAcceptMission() const; + bool GetAcceptMission() const { return acceptsMission; }; private: @@ -63,8 +70,9 @@ class MissionOfferComponent : public Component { public: inline static const eReplicaComponentType ComponentType = eReplicaComponentType::MISSION_OFFER; - MissionOfferComponent(Entity* parent, LOT parentLot); - ~MissionOfferComponent() override; + MissionOfferComponent(Entity* parent, const int32_t componentId = -1); + + void LoadTemplateData() override; /** * Handles the OnUse event triggered by some entity, determines which missions to show based on what they may @@ -85,7 +93,9 @@ private: /** * The missions this entity has to offer */ - std::vector offeredMissions; + std::vector> offeredMissions; + + int32_t m_ComponentId; }; -#endif // MISSIONOFFERCOMPONENT_H +#endif // __MISSIONOFFERCOMPONENT_H__ diff --git a/dGame/dComponents/ModelBehaviorComponent.cpp b/dGame/dComponents/ModelBehaviorComponent.cpp index e7493250..634724c1 100644 --- a/dGame/dComponents/ModelBehaviorComponent.cpp +++ b/dGame/dComponents/ModelBehaviorComponent.cpp @@ -3,7 +3,7 @@ #include "ePhysicsBehaviorType.h" ModelBehaviorComponent::ModelBehaviorComponent(Entity* parent) : Component(parent) { - m_DirtyModelInfo = false; + m_DirtyModelInfo = true; m_IsPickable = false; m_PhysicsType = ePhysicsBehaviorType::STANDARD; m_OriginalPosition = m_ParentEntity->GetDefaultPosition(); @@ -17,7 +17,7 @@ void ModelBehaviorComponent::Serialize(RakNet::BitStream* outBitStream, bool bIs outBitStream->Write(m_PhysicsType); outBitStream->Write(m_OriginalPosition); outBitStream->Write(m_OriginalRotation); - m_DirtyModelInfo = false; + if (!bIsInitialUpdate) m_DirtyModelInfo = false; } } diff --git a/dGame/dComponents/ModelBehaviorComponent.h b/dGame/dComponents/ModelBehaviorComponent.h index 09b3ff3a..a85ec2e3 100644 --- a/dGame/dComponents/ModelBehaviorComponent.h +++ b/dGame/dComponents/ModelBehaviorComponent.h @@ -30,7 +30,11 @@ public: * Sets the original position of the model * @param pos the original position to set */ - void SetPosition(const NiPoint3& pos) { m_OriginalPosition = pos; m_DirtyModelInfo = true; } + void SetPosition(const NiPoint3& pos) { + if (m_OriginalPosition == pos) return; + m_OriginalPosition = pos; + m_DirtyModelInfo = true; + } /** * Returns the original rotation of the model @@ -42,7 +46,11 @@ public: * Sets the original rotation of the model * @param rot the original rotation to set */ - void SetRotation(const NiQuaternion& rot) { m_OriginalRotation = rot; m_DirtyModelInfo = true; } + void SetRotation(const NiQuaternion& rot) { + if (m_OriginalRotation == rot) return; + m_OriginalRotation = rot; + m_DirtyModelInfo = true; + } private: diff --git a/dGame/dComponents/ModuleAssemblyComponent.cpp b/dGame/dComponents/ModuleAssemblyComponent.cpp index 8e197f0c..f00bc880 100644 --- a/dGame/dComponents/ModuleAssemblyComponent.cpp +++ b/dGame/dComponents/ModuleAssemblyComponent.cpp @@ -1,70 +1,31 @@ #include "ModuleAssemblyComponent.h" +#include "Entity.h" + ModuleAssemblyComponent::ModuleAssemblyComponent(Entity* parent) : Component(parent) { m_SubKey = LWOOBJID_EMPTY; m_UseOptionalParts = false; - m_AssemblyPartsLOTs = u""; -} - -ModuleAssemblyComponent::~ModuleAssemblyComponent() { - -} - -void ModuleAssemblyComponent::SetSubKey(LWOOBJID value) { - m_SubKey = value; -} - -LWOOBJID ModuleAssemblyComponent::GetSubKey() const { - return m_SubKey; -} - -void ModuleAssemblyComponent::SetUseOptionalParts(bool value) { - m_UseOptionalParts = value; -} - -bool ModuleAssemblyComponent::GetUseOptionalParts() const { - return m_UseOptionalParts; } void ModuleAssemblyComponent::SetAssemblyPartsLOTs(const std::u16string& value) { - std::u16string val{}; - - val.reserve(value.size() + 1); - - for (auto character : value) { - if (character == '+') character = ';'; - - val.push_back(character); - } - - val.push_back(';'); - - m_AssemblyPartsLOTs = val; -} - -const std::u16string& ModuleAssemblyComponent::GetAssemblyPartsLOTs() const { - return m_AssemblyPartsLOTs; + m_AssemblyPartsLOTs = value; + std::replace(m_AssemblyPartsLOTs.begin(), m_AssemblyPartsLOTs.end(), u'+', u';'); + // doesn't matter if we push back a ; or a +. The client splits on either of them. + // For congruency however, maintain one or the other. + m_AssemblyPartsLOTs.push_back(u';'); } void ModuleAssemblyComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - if (bIsInitialUpdate) { - outBitStream->Write1(); + if (!bIsInitialUpdate) return; + outBitStream->Write(bIsInitialUpdate); - outBitStream->Write(m_SubKey != LWOOBJID_EMPTY); - if (m_SubKey != LWOOBJID_EMPTY) { - outBitStream->Write(m_SubKey); - } + outBitStream->Write(m_SubKey != LWOOBJID_EMPTY); + if (m_SubKey != LWOOBJID_EMPTY) outBitStream->Write(m_SubKey); - outBitStream->Write(m_UseOptionalParts); + outBitStream->Write(m_UseOptionalParts); - outBitStream->Write(static_cast(m_AssemblyPartsLOTs.size())); - for (char16_t character : m_AssemblyPartsLOTs) { - outBitStream->Write(character); - } + outBitStream->Write(m_AssemblyPartsLOTs.size()); + for (const char16_t character : m_AssemblyPartsLOTs) { + outBitStream->Write(character); } } - -void ModuleAssemblyComponent::Update(float deltaTime) { - -} - diff --git a/dGame/dComponents/ModuleAssemblyComponent.h b/dGame/dComponents/ModuleAssemblyComponent.h index 89498dc5..7845fc19 100644 --- a/dGame/dComponents/ModuleAssemblyComponent.h +++ b/dGame/dComponents/ModuleAssemblyComponent.h @@ -1,10 +1,15 @@ +#ifndef __MODULEASSEMBLYCOMPONENT__H__ +#define __MODULEASSEMBLYCOMPONENT__H__ + #pragma once -#include "BitStream.h" -#include "Entity.h" #include "Component.h" #include "eReplicaComponentType.h" +namespace RakNet { + class BitStream; +}; + /** * Component that belongs to an object that may be modularly built, like cars and rockets. Note that this is not the * same as having said items in your inventory (the subkey for this component) this component is the one that @@ -15,35 +20,32 @@ public: inline static const eReplicaComponentType ComponentType = eReplicaComponentType::MODULE_ASSEMBLY; ModuleAssemblyComponent(Entity* parent); - ~ModuleAssemblyComponent() override; void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void Update(float deltaTime) override; /** * Sets the subkey of this entity * @param value the subkey to set */ - void SetSubKey(LWOOBJID value); + void SetSubKey(const LWOOBJID& value) { m_SubKey = value; }; /** * Returns the subkey for this entity * @return the subkey for this entity */ - LWOOBJID GetSubKey() const; - + LWOOBJID GetSubKey() const { return m_SubKey; }; /** * Sets the optional parts value * @param value the value to set */ - void SetUseOptionalParts(bool value); + void SetUseOptionalParts(bool value) { m_UseOptionalParts = value; }; /** * Returns the optional parts value * @return the value to set */ - bool GetUseOptionalParts() const; + bool GetUseOptionalParts() const { return m_UseOptionalParts; }; /** * Sets the assembly part lots (the subsections of this modular build) @@ -55,7 +57,7 @@ public: * Returns the assembly part lots (the subsections of this modular build) * @return */ - const std::u16string& GetAssemblyPartsLOTs() const; + const std::u16string& GetAssemblyPartsLOTs() const { return m_AssemblyPartsLOTs; }; private: @@ -75,3 +77,5 @@ private: */ std::u16string m_AssemblyPartsLOTs; }; + +#endif //!__MODULEASSEMBLYCOMPONENT__H__ diff --git a/dGame/dEntity/Entity.cpp b/dGame/dEntity/Entity.cpp index fbd1ac41..5aee112d 100644 --- a/dGame/dEntity/Entity.cpp +++ b/dGame/dEntity/Entity.cpp @@ -517,7 +517,7 @@ void Entity::Initialize() { m_IsGhostingCandidate = false; break; case eReplicaComponentType::MISSION_OFFER: - AddComponent(GetLOT()); + AddComponent(componentId); break; case eReplicaComponentType::RACING_STATS: AddComponent();