diff --git a/dCommon/dEnums/dCommonVars.h b/dCommon/dEnums/dCommonVars.h index 085fed2e..75dcc73d 100644 --- a/dCommon/dEnums/dCommonVars.h +++ b/dCommon/dEnums/dCommonVars.h @@ -3,13 +3,14 @@ #ifndef __DCOMMONVARS__H__ #define __DCOMMONVARS__H__ +#include #include -#include #include +#include #include "BitStream.h" -#include "eConnectionType.h" -#include "MessageType/Client.h" #include "BitStreamUtils.h" +#include "MessageType/Client.h" +#include "eConnectionType.h" #pragma warning (disable:4251) //Disables SQL warnings @@ -99,6 +100,7 @@ public: constexpr LWOZONEID(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) noexcept { m_MapID = mapID; m_InstanceID = instanceID; m_CloneID = cloneID; } constexpr LWOZONEID(const LWOZONEID& replacement) noexcept { *this = replacement; } constexpr bool operator==(const LWOZONEID&) const = default; + constexpr auto operator<=>(const LWOZONEID&) const = default; private: LWOMAPID m_MapID = LWOMAPID_INVALID; //1000 for VE, 1100 for AG, etc... diff --git a/dGame/UserManager.cpp b/dGame/UserManager.cpp index 1cd9bbe5..85757ec1 100644 --- a/dGame/UserManager.cpp +++ b/dGame/UserManager.cpp @@ -29,6 +29,7 @@ #include "MessageType/Chat.h" #include "BitStreamUtils.h" #include "CheatDetection.h" +#include "CharacterComponent.h" UserManager* UserManager::m_Address = nullptr; @@ -340,7 +341,10 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet) xml << "GetAccountID() << "\" cc=\"0\" gm=\"0\" ft=\"0\" llog=\"" << time(NULL) << "\" "; xml << "ls=\"0\" lzx=\"-626.5847\" lzy=\"613.3515\" lzz=\"-28.6374\" lzrx=\"0.0\" lzry=\"0.7015\" lzrz=\"0.0\" lzrw=\"0.7126\" "; - xml << "stt=\"0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;\">"; + xml << "stt=\"0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;\">"; + xml << ""; + + xml << ""; xml << ""; @@ -522,6 +526,13 @@ void UserManager::LoginCharacter(const SystemAddress& sysAddr, uint32_t playerID ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, zoneID, character->GetZoneClone(), false, [=](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", character->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); if (character) { + auto* entity = character->GetEntity(); + if (entity) { + auto* characterComponent = entity->GetComponent(); + if (characterComponent) { + characterComponent->AddVisitedLevel(LWOZONEID(zoneID, LWOINSTANCEID_INVALID, zoneClone)); + } + } character->SetZoneID(zoneID); character->SetZoneInstance(zoneInstance); character->SetZoneClone(zoneClone); diff --git a/dGame/dBehaviors/PropertyTeleportBehavior.cpp b/dGame/dBehaviors/PropertyTeleportBehavior.cpp index 7e9ecee0..bfbcd163 100644 --- a/dGame/dBehaviors/PropertyTeleportBehavior.cpp +++ b/dGame/dBehaviors/PropertyTeleportBehavior.cpp @@ -42,10 +42,15 @@ void PropertyTeleportBehavior::Handle(BehaviorContext* context, RakNet::BitStrea LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); if (entity->GetCharacter()) { + auto* characterComponent = entity->GetComponent(); + if (characterComponent) { + characterComponent->AddVisitedLevel(LWOZONEID(zoneID, LWOINSTANCEID_INVALID, zoneClone)); + characterComponent->SetLastRocketConfig(u""); + } + entity->GetCharacter()->SetZoneID(zoneID); entity->GetCharacter()->SetZoneInstance(zoneInstance); entity->GetCharacter()->SetZoneClone(zoneClone); - entity->GetComponent()->SetLastRocketConfig(u""); } entity->GetCharacter()->SaveXMLToDatabase(); diff --git a/dGame/dComponents/ActivityComponent.cpp b/dGame/dComponents/ActivityComponent.cpp index 54c7101b..0e6778b0 100644 --- a/dGame/dComponents/ActivityComponent.cpp +++ b/dGame/dComponents/ActivityComponent.cpp @@ -27,6 +27,7 @@ #include "CDActivityRewardsTable.h" #include "CDActivitiesTable.h" #include "LeaderboardManager.h" +#include "CharacterComponent.h" ActivityComponent::ActivityComponent(Entity* parent, int32_t activityID) : Component(parent) { /* @@ -526,6 +527,11 @@ void ActivityInstance::StartZone() { LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", player->GetCharacter()->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); if (player->GetCharacter()) { + auto* characterComponent = player->GetComponent(); + if (characterComponent) { + characterComponent->AddVisitedLevel(LWOZONEID(zoneID, LWOINSTANCEID_INVALID, zoneClone)); + } + player->GetCharacter()->SetZoneID(zoneID); player->GetCharacter()->SetZoneInstance(zoneInstance); player->GetCharacter()->SetZoneClone(zoneClone); diff --git a/dGame/dComponents/CharacterComponent.cpp b/dGame/dComponents/CharacterComponent.cpp index 90c992f1..0659e743 100644 --- a/dGame/dComponents/CharacterComponent.cpp +++ b/dGame/dComponents/CharacterComponent.cpp @@ -245,6 +245,8 @@ void CharacterComponent::LoadFromXml(const tinyxml2::XMLDocument& doc) { SetReputation(0); } + auto* vl = character->FirstChildElement("vl"); + if (vl) LoadVisitedLevelsXml(*vl); character->QueryUnsigned64Attribute("co", &m_ClaimCodes[0]); character->QueryUnsigned64Attribute("co1", &m_ClaimCodes[1]); character->QueryUnsigned64Attribute("co2", &m_ClaimCodes[2]); @@ -374,6 +376,10 @@ void CharacterComponent::UpdateXml(tinyxml2::XMLDocument& doc) { return; } + auto* vl = character->FirstChildElement("vl"); + if (!vl) vl = character->InsertNewChildElement("vl"); + UpdateVisitedLevelsXml(*vl); + if (m_ClaimCodes[0] != 0) character->SetAttribute("co", m_ClaimCodes[0]); if (m_ClaimCodes[1] != 0) character->SetAttribute("co1", m_ClaimCodes[1]); if (m_ClaimCodes[2] != 0) character->SetAttribute("co2", m_ClaimCodes[2]); @@ -855,8 +861,9 @@ void CharacterComponent::SendToZone(LWOMAPID zoneId, LWOCLONEID cloneId) const { character->SetZoneID(zoneID); character->SetZoneInstance(zoneInstance); character->SetZoneClone(zoneClone); - + characterComponent->SetLastRocketConfig(u""); + characterComponent->AddVisitedLevel(LWOZONEID(zoneID, LWOINSTANCEID_INVALID, zoneClone)); character->SaveXMLToDatabase(); } @@ -883,3 +890,30 @@ void CharacterComponent::SetRespawnPos(const NiPoint3& position) { void CharacterComponent::SetRespawnRot(const NiQuaternion& rotation) { m_respawnRot = rotation; } + +void CharacterComponent::AddVisitedLevel(const LWOZONEID zoneID) { + LWOZONEID toInsert(zoneID.GetMapID(), LWOINSTANCEID_INVALID, zoneID.GetCloneID()); + m_VisitedLevels.insert(toInsert); +} + +void CharacterComponent::UpdateVisitedLevelsXml(tinyxml2::XMLElement& vl) { + vl.DeleteChildren(); + // + for (const auto zoneID : m_VisitedLevels) { + // + auto* l = vl.InsertNewChildElement("l"); + l->SetAttribute("id", zoneID.GetMapID()); + l->SetAttribute("cid", zoneID.GetCloneID()); + } + // +} + +void CharacterComponent::LoadVisitedLevelsXml(const tinyxml2::XMLElement& vl) { + // + for (const auto* l = vl.FirstChildElement("l"); l != nullptr; l = l->NextSiblingElement("l")) { + // + LWOZONEID toInsert(l->IntAttribute("id"), LWOINSTANCEID_INVALID, l->IntAttribute("cid")); + m_VisitedLevels.insert(toInsert); + } + // +} diff --git a/dGame/dComponents/CharacterComponent.h b/dGame/dComponents/CharacterComponent.h index cb6027b5..6336a6d1 100644 --- a/dGame/dComponents/CharacterComponent.h +++ b/dGame/dComponents/CharacterComponent.h @@ -10,6 +10,7 @@ #include "tinyxml2.h" #include "eReplicaComponentType.h" #include +#include #include "Loot.h" enum class eGameActivity : uint32_t; @@ -321,6 +322,13 @@ public: * Character info regarding this character, including clothing styles, etc. */ Character* m_Character; + + /* Saves the provided zoneID as a visited level. Ignores InstanceID */ + void AddVisitedLevel(const LWOZONEID zoneID); + /* Updates the VisitedLevels (vl) node of the charxml */ + void UpdateVisitedLevelsXml(tinyxml2::XMLElement& doc); + /* Reads the VisitedLevels (vl) node of the charxml */ + void LoadVisitedLevelsXml(const tinyxml2::XMLElement& doc); private: bool OnRequestServerObjectInfo(GameMessages::GameMsg& msg); @@ -619,6 +627,8 @@ private: std::map m_DroppedLoot; uint64_t m_DroppedCoins = 0; + + std::set m_VisitedLevels; }; #endif // CHARACTERCOMPONENT_H diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 3008fbdd..94bacfcf 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -4926,6 +4926,11 @@ void GameMessages::HandleFireEventServerSide(RakNet::BitStream& inStream, Entity LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", character->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); if (character) { + auto* characterComponent = player->GetComponent(); + if (characterComponent) { + characterComponent->AddVisitedLevel(LWOZONEID(zoneID, LWOINSTANCEID_INVALID, zoneClone)); + } + character->SetZoneID(zoneID); character->SetZoneInstance(zoneInstance); character->SetZoneClone(zoneClone); diff --git a/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp b/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp index 33cbe70a..1ea1f8ed 100644 --- a/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp +++ b/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp @@ -1049,6 +1049,10 @@ namespace DEVGMCommands { LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); if (entity->GetCharacter()) { + auto* characterComponent = entity->GetComponent(); + if (characterComponent) { + characterComponent->AddVisitedLevel(LWOZONEID(zoneID, LWOINSTANCEID_INVALID, zoneClone)); + } entity->GetCharacter()->SetZoneID(zoneID); entity->GetCharacter()->SetZoneInstance(zoneInstance); entity->GetCharacter()->SetZoneClone(zoneClone); diff --git a/dGame/dUtilities/SlashCommands/GMZeroCommands.cpp b/dGame/dUtilities/SlashCommands/GMZeroCommands.cpp index f80f3280..9e0bb475 100644 --- a/dGame/dUtilities/SlashCommands/GMZeroCommands.cpp +++ b/dGame/dUtilities/SlashCommands/GMZeroCommands.cpp @@ -168,6 +168,10 @@ namespace GMZeroCommands { LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", entity->GetCharacter()->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); if (entity->GetCharacter()) { + auto* characterComponent = entity->GetComponent(); + if (characterComponent) { + characterComponent->AddVisitedLevel(LWOZONEID(zoneID, LWOINSTANCEID_INVALID, zoneClone)); + } entity->GetCharacter()->SetZoneID(zoneID); entity->GetCharacter()->SetZoneInstance(zoneInstance); entity->GetCharacter()->SetZoneClone(zoneClone); @@ -190,6 +194,10 @@ namespace GMZeroCommands { LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); if (entity->GetCharacter()) { + auto* characterComponent = entity->GetComponent(); + if (characterComponent) { + characterComponent->AddVisitedLevel(LWOZONEID(zoneID, LWOINSTANCEID_INVALID, zoneClone)); + } entity->GetCharacter()->SetZoneID(zoneID); entity->GetCharacter()->SetZoneInstance(zoneInstance); entity->GetCharacter()->SetZoneClone(zoneClone);