diff --git a/dCommon/dEnums/eCharacterVersion.h b/dCommon/dEnums/eCharacterVersion.h new file mode 100644 index 00000000..0fab4498 --- /dev/null +++ b/dCommon/dEnums/eCharacterVersion.h @@ -0,0 +1,21 @@ +#pragma once + +#ifndef __ECHARACTERVERSION__H__ +#define __ECHARACTERVERSION__H__ + +#include + +enum class eCharacterVersion : uint32_t { +// Versions from the live game + RELEASE = 0, // Initial release of the game + LIVE, // Fixes for the 1.9 release bug fixes for missions leading up to joining a faction +// New versions for DLU fixes + // Fixes the "Joined a faction" player flag not being set properly + PLAYER_FACTION_FLAGS, + // Fixes vault size value + VAULT_SIZE, + // Fixes speed base value in level component + UP_TO_DATE, // will become SPEED_BASE +}; + +#endif //!__ECHARACTERVERSION__H__ diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 1f094291..cbab87db 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -769,8 +769,8 @@ no_ghosting: auto* controllablePhysicsComponent = GetComponent(); auto* levelComponent = GetComponent(); - if (controllablePhysicsComponent != nullptr && levelComponent->GetLevel() >= 20) { - controllablePhysicsComponent->SetSpeedMultiplier(525.0f / 500.0f); + if (controllablePhysicsComponent && levelComponent) { + controllablePhysicsComponent->SetSpeedMultiplier(levelComponent->GetSpeedBase() / 500.0f); } } } diff --git a/dGame/TradingManager.cpp b/dGame/TradingManager.cpp index e49cca70..ed55f217 100644 --- a/dGame/TradingManager.cpp +++ b/dGame/TradingManager.cpp @@ -103,6 +103,7 @@ void Trade::SetAccepted(LWOOBJID participant, bool value) { } Complete(); + TradingManager::Instance()->CancelTrade(m_TradeId); } } @@ -121,33 +122,59 @@ void Trade::Complete() { if (inventoryA == nullptr || inventoryB == nullptr || characterA == nullptr || characterB == nullptr || missionsA == nullptr || missionsB == nullptr) return; + // First verify both players have the coins and items requested for the trade. + if (characterA->GetCoins() < m_CoinsA || characterB->GetCoins() < m_CoinsB) { + Game::logger->Log("TradingManager", "Possible coin trade cheating attempt! Aborting trade."); + return; + } + + for (const auto& tradeItem : m_ItemsA) { + auto* itemToRemove = inventoryA->FindItemById(tradeItem.itemId); + if (itemToRemove) { + if (itemToRemove->GetCount() < tradeItem.itemCount) { + Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading!!! Aborting trade", characterA->GetName().c_str()); + return; + } + } else { + Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading due to item not being available!!!", characterA->GetName().c_str()); + return; + } + } + + for (const auto& tradeItem : m_ItemsB) { + auto* itemToRemove = inventoryB->FindItemById(tradeItem.itemId); + if (itemToRemove) { + if (itemToRemove->GetCount() < tradeItem.itemCount) { + Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading!!! Aborting trade", characterB->GetName().c_str()); + return; + } + } else { + Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading due to item not being available!!! Aborting trade", characterB->GetName().c_str()); + return; + } + } + + // Now actually do the trade. characterA->SetCoins(characterA->GetCoins() - m_CoinsA + m_CoinsB, eLootSourceType::LOOT_SOURCE_TRADE); characterB->SetCoins(characterB->GetCoins() - m_CoinsB + m_CoinsA, eLootSourceType::LOOT_SOURCE_TRADE); for (const auto& tradeItem : m_ItemsA) { - inventoryA->RemoveItem(tradeItem.itemLot, tradeItem.itemCount, INVALID, true); - + auto* itemToRemove = inventoryA->FindItemById(tradeItem.itemId); + if (itemToRemove) itemToRemove->SetCount(itemToRemove->GetCount() - tradeItem.itemCount); missionsA->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, tradeItem.itemLot, LWOOBJID_EMPTY, "", -tradeItem.itemCount); - } - - for (const auto& tradeItem : m_ItemsB) { - inventoryB->RemoveItem(tradeItem.itemLot, tradeItem.itemCount, INVALID, true); - - missionsB->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, tradeItem.itemLot, LWOOBJID_EMPTY, "", -tradeItem.itemCount); - } - - for (const auto& tradeItem : m_ItemsA) { inventoryB->AddItem(tradeItem.itemLot, tradeItem.itemCount, eLootSourceType::LOOT_SOURCE_TRADE); } for (const auto& tradeItem : m_ItemsB) { + auto* itemToRemove = inventoryB->FindItemById(tradeItem.itemId); + if (itemToRemove) itemToRemove->SetCount(itemToRemove->GetCount() - tradeItem.itemCount); + missionsB->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, tradeItem.itemLot, LWOOBJID_EMPTY, "", -tradeItem.itemCount); inventoryA->AddItem(tradeItem.itemLot, tradeItem.itemCount, eLootSourceType::LOOT_SOURCE_TRADE); } - TradingManager::Instance()->CancelTrade(m_TradeId); - characterA->SaveXMLToDatabase(); characterB->SaveXMLToDatabase(); + return; } void Trade::Cancel() { diff --git a/dGame/dBehaviors/SpeedBehavior.cpp b/dGame/dBehaviors/SpeedBehavior.cpp index c7855557..bec2b1cb 100644 --- a/dGame/dBehaviors/SpeedBehavior.cpp +++ b/dGame/dBehaviors/SpeedBehavior.cpp @@ -7,85 +7,44 @@ void SpeedBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - if (m_AffectsCaster) { - branch.target = context->caster; - } + if (m_AffectsCaster) branch.target = context->caster; auto* target = EntityManager::Instance()->GetEntity(branch.target); - - if (target == nullptr) { - return; - } + if (!target) return; auto* controllablePhysicsComponent = target->GetComponent(); + if (!controllablePhysicsComponent) return; - if (controllablePhysicsComponent == nullptr) { - return; - } - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetSpeedMultiplier(current + ((m_RunSpeed - 500.0f) / 500.0f)); - + controllablePhysicsComponent->AddSpeedboost(m_RunSpeed); EntityManager::Instance()->SerializeEntity(target); if (branch.duration > 0.0f) { context->RegisterTimerBehavior(this, branch); } else if (branch.start > 0) { - controllablePhysicsComponent->SetIgnoreMultipliers(true); - context->RegisterEndBehavior(this, branch); } } -void SpeedBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { - auto* target = EntityManager::Instance()->GetEntity(branch.target); - - if (target == nullptr) { - return; - } - - auto* controllablePhysicsComponent = target->GetComponent(); - - if (controllablePhysicsComponent == nullptr) { - return; - } - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetSpeedMultiplier(current - ((m_RunSpeed - 500.0f) / 500.0f)); - - EntityManager::Instance()->SerializeEntity(target); +void SpeedBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + Handle(context, bitStream, branch); } void SpeedBehavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { auto* target = EntityManager::Instance()->GetEntity(branch.target); - - if (target == nullptr) { - return; - } + if (!target) return; auto* controllablePhysicsComponent = target->GetComponent(); + if (!controllablePhysicsComponent) return; - if (controllablePhysicsComponent == nullptr) { - return; - } - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetIgnoreMultipliers(false); - - controllablePhysicsComponent->SetSpeedMultiplier(current - ((m_RunSpeed - 500.0f) / 500.0f)); - + controllablePhysicsComponent->RemoveSpeedboost(m_RunSpeed); EntityManager::Instance()->SerializeEntity(target); } +void SpeedBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { + End(context, branch, second); +} + void SpeedBehavior::Load() { m_RunSpeed = GetFloat("run_speed"); - - if (m_RunSpeed < 500.0f) { - m_RunSpeed = 500.0f; - } - m_AffectsCaster = GetBoolean("affects_caster"); } diff --git a/dGame/dBehaviors/SpeedBehavior.h b/dGame/dBehaviors/SpeedBehavior.h index 04c0090f..57c46842 100644 --- a/dGame/dBehaviors/SpeedBehavior.h +++ b/dGame/dBehaviors/SpeedBehavior.h @@ -13,6 +13,8 @@ public: void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; diff --git a/dGame/dComponents/ControllablePhysicsComponent.cpp b/dGame/dComponents/ControllablePhysicsComponent.cpp index d7caf6a9..a5e447c8 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.cpp +++ b/dGame/dComponents/ControllablePhysicsComponent.cpp @@ -12,6 +12,7 @@ #include "EntityManager.h" #include "Character.h" #include "dZoneManager.h" +#include "LevelProgressionComponent.h" ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : Component(entity) { m_Position = {}; @@ -73,13 +74,7 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bo outBitStream->Write0(); //This contains info about immunities, but for now I'm leaving it out. } - if (m_SpeedMultiplier < 1.0f) { - m_DirtyCheats = false; - } - - if (m_IgnoreMultipliers) { - m_DirtyCheats = false; - } + if (m_IgnoreMultipliers) m_DirtyCheats = false; outBitStream->Write(m_DirtyCheats); if (m_DirtyCheats) { @@ -263,7 +258,7 @@ void ControllablePhysicsComponent::RemovePickupRadiusScale(float value) { if (pos != m_ActivePickupRadiusScales.end()) { m_ActivePickupRadiusScales.erase(pos); } else { - Game::logger->Log("ControllablePhysicsComponent", "Warning: Could not find pickup radius %f in list of active radii. List has %i active radii.", value, m_ActivePickupRadiusScales.size()); + Game::logger->LogDebug("ControllablePhysicsComponent", "Warning: Could not find pickup radius %f in list of active radii. List has %i active radii.", value, m_ActivePickupRadiusScales.size()); return; } @@ -276,3 +271,30 @@ void ControllablePhysicsComponent::RemovePickupRadiusScale(float value) { } EntityManager::Instance()->SerializeEntity(m_Parent); } + +void ControllablePhysicsComponent::AddSpeedboost(float value) { + m_ActiveSpeedBoosts.push_back(value); + m_SpeedBoost = value; + SetSpeedMultiplier(value / 500.0f); // 500 being the base speed +} + +void ControllablePhysicsComponent::RemoveSpeedboost(float value) { + const auto pos = std::find(m_ActiveSpeedBoosts.begin(), m_ActiveSpeedBoosts.end(), value); + if (pos != m_ActiveSpeedBoosts.end()) { + m_ActiveSpeedBoosts.erase(pos); + } else { + Game::logger->LogDebug("ControllablePhysicsComponent", "Warning: Could not find speedboost %f in list of active speedboosts. List has %i active speedboosts.", value, m_ActiveSpeedBoosts.size()); + return; + } + + // Recalculate speedboost since we removed one + m_SpeedBoost = 0.0f; + if (m_ActiveSpeedBoosts.size() == 0) { // no active speed boosts left, so return to base speed + auto* levelProgressionComponent = m_Parent->GetComponent(); + if (levelProgressionComponent) m_SpeedBoost = levelProgressionComponent->GetSpeedBase(); + } else { // Used the last applied speedboost + m_SpeedBoost = m_ActiveSpeedBoosts.back(); + } + SetSpeedMultiplier(m_SpeedBoost / 500.0f); // 500 being the base speed + EntityManager::Instance()->SerializeEntity(m_Parent); +} diff --git a/dGame/dComponents/ControllablePhysicsComponent.h b/dGame/dComponents/ControllablePhysicsComponent.h index ac481b9f..e029d607 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.h +++ b/dGame/dComponents/ControllablePhysicsComponent.h @@ -257,6 +257,13 @@ public: */ std::vector GetActivePickupRadiusScales() { return m_ActivePickupRadiusScales; }; + + void AddSpeedboost(float value); + + void RemoveSpeedboost(float value); + + std::vector GetActiveSpeedboosts() { return m_ActivePickupRadiusScales; }; + private: /** * The entity that owns this component @@ -372,6 +379,16 @@ private: * If the entity is teleporting */ bool m_IsTeleporting; + + /** + * The list of speed boosts for this entity + */ + std::vector m_ActiveSpeedBoosts; + + /** + * The active speed boost for this entity + */ + float m_SpeedBoost; }; #endif // CONTROLLABLEPHYSICSCOMPONENT_H diff --git a/dGame/dComponents/LevelProgressionComponent.cpp b/dGame/dComponents/LevelProgressionComponent.cpp index ee3cfc6b..6e6b823e 100644 --- a/dGame/dComponents/LevelProgressionComponent.cpp +++ b/dGame/dComponents/LevelProgressionComponent.cpp @@ -7,6 +7,8 @@ LevelProgressionComponent::LevelProgressionComponent(Entity* parent) : Component(parent) { m_Parent = parent; m_Level = 1; + m_SpeedBase = 500.0f; + m_CharacterVersion = eCharacterVersion::LIVE; } void LevelProgressionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { @@ -16,7 +18,8 @@ void LevelProgressionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { return; } level->SetAttribute("l", m_Level); - + level->SetAttribute("sb", m_SpeedBase); + level->SetAttribute("cv", static_cast(m_CharacterVersion)); } void LevelProgressionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { @@ -26,7 +29,10 @@ void LevelProgressionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { return; } level->QueryAttribute("l", &m_Level); - + level->QueryAttribute("sb", &m_SpeedBase); + uint32_t characterVersion; + level->QueryAttribute("cv", &characterVersion); + m_CharacterVersion = static_cast(characterVersion); } void LevelProgressionComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { @@ -60,7 +66,8 @@ void LevelProgressionComponent::HandleLevelUp() { } break; case 9: - controllablePhysicsComponent->SetSpeedMultiplier(static_cast(reward->value) / 500.0f); + SetSpeedBase(static_cast(reward->value) ); + controllablePhysicsComponent->SetSpeedMultiplier(GetSpeedBase() / 500.0f); break; case 11: case 12: @@ -72,3 +79,9 @@ void LevelProgressionComponent::HandleLevelUp() { // Tell the client we have finished sending level rewards. if (rewardingItem) GameMessages::NotifyLevelRewards(m_Parent->GetObjectID(), m_Parent->GetSystemAddress(), m_Level, !rewardingItem); } + +void LevelProgressionComponent::SetRetroactiveBaseSpeed(){ + if (m_Level >= 20) m_SpeedBase = 525.0f; + auto* controllablePhysicsComponent = m_Parent->GetComponent(); + if (controllablePhysicsComponent) controllablePhysicsComponent->SetSpeedMultiplier(m_SpeedBase / 500.0f); +} diff --git a/dGame/dComponents/LevelProgressionComponent.h b/dGame/dComponents/LevelProgressionComponent.h index 53f6693e..dd3fbfbb 100644 --- a/dGame/dComponents/LevelProgressionComponent.h +++ b/dGame/dComponents/LevelProgressionComponent.h @@ -3,11 +3,13 @@ #include "Entity.h" #include "GameMessages.h" #include "Component.h" +#include "eCharacterVersion.h" /** * Component that handles level progression and serilization. * */ + class LevelProgressionComponent : public Component { public: static const uint32_t ComponentType = eReplicaComponentType::COMPONENT_TYPE_LEVEL_PROGRESSION; @@ -44,11 +46,40 @@ public: */ void SetLevel(uint32_t level) { m_Level = level; m_DirtyLevelInfo = true; } + /** + * Gets the current Speed Base of the entity + * @return the current Speed Base of the entity + */ + const uint32_t GetSpeedBase() const { return m_SpeedBase; } + + /** + * Sets the Speed Base of the entity + * @param SpeedBase the Speed Base to set + */ + void SetSpeedBase(uint32_t SpeedBase) { m_SpeedBase = SpeedBase; } + /** * Gives the player rewards for the last level that they leveled up from */ void HandleLevelUp(); + /** + * Gets the current Character Version of the entity + * @return the current Character Version of the entity + */ + const eCharacterVersion GetCharacterVersion() const { return m_CharacterVersion; } + + /** + * Sets the Character Version of the entity + * @param CharacterVersion the Character Version to set + */ + void SetCharacterVersion(eCharacterVersion CharacterVersion) { m_CharacterVersion = CharacterVersion; } + + /** + * Set the Base Speed retroactively of the entity + */ + void SetRetroactiveBaseSpeed(); + private: /** * whether the level is dirty @@ -59,4 +90,15 @@ private: * Level of the entity */ uint32_t m_Level; + + /** + * The base speed of the entity + */ + float m_SpeedBase; + + /** + * The Character format version + */ + eCharacterVersion m_CharacterVersion; + }; diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 9aa8eda2..9753868d 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -5736,16 +5736,16 @@ void GameMessages::HandleClientItemConsumed(RakNet::BitStream* inStream, Entity* } auto* item = inventory->FindItemById(itemConsumed); - if (item == nullptr) { return; } + LOT itemLot = item->GetLot(); item->Consume(); auto* missions = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); if (missions != nullptr) { - missions->Progress(MissionTaskType::MISSION_TASK_TYPE_FOOD, item->GetLot()); + missions->Progress(MissionTaskType::MISSION_TASK_TYPE_FOOD, itemLot); } } diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index 594d3dc7..d204d5c9 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -56,6 +56,7 @@ #include "Player.h" #include "PropertyManagementComponent.h" #include "AssetManager.h" +#include "LevelProgressionComponent.h" #include "eBlueprintSaveResponseType.h" #include "ZCompression.h" @@ -993,9 +994,29 @@ void HandlePacket(Packet* packet) { player->GetComponent()->RocketUnEquip(player); } - c->SetRetroactiveFlags(); + // Do charxml fixes here + auto* levelComponent = player->GetComponent(); + if (!levelComponent) return; - player->RetroactiveVaultSize(); + auto version = levelComponent->GetCharacterVersion(); + switch(version) { + case eCharacterVersion::RELEASE: + // TODO: Implement, super low priority + case eCharacterVersion::LIVE: + Game::logger->Log("WorldServer", "Updating Character Flags"); + c->SetRetroactiveFlags(); + levelComponent->SetCharacterVersion(eCharacterVersion::PLAYER_FACTION_FLAGS); + case eCharacterVersion::PLAYER_FACTION_FLAGS: + Game::logger->Log("WorldServer", "Updating Vault Size"); + player->RetroactiveVaultSize(); + levelComponent->SetCharacterVersion(eCharacterVersion::VAULT_SIZE); + case eCharacterVersion::VAULT_SIZE: + Game::logger->Log("WorldServer", "Updaing Speedbase"); + levelComponent->SetRetroactiveBaseSpeed(); + levelComponent->SetCharacterVersion(eCharacterVersion::UP_TO_DATE); + case eCharacterVersion::UP_TO_DATE: + break; + } player->GetCharacter()->SetTargetScene("");