#include "PropertyEntranceComponent.h" #include "CDPropertyEntranceComponentTable.h" #include "Character.h" #include "Database.h" #include "GameMessages.h" #include "PropertyManagementComponent.h" #include "PropertySelectQueryProperty.h" #include "RocketLaunchpadControlComponent.h" #include "CharacterComponent.h" #include "UserManager.h" #include "Logger.h" #include "Amf3.h" #include "eObjectBits.h" #include "eGameMasterLevel.h" #include "ePropertySortType.h" #include "User.h" PropertyEntranceComponent::PropertyEntranceComponent(Entity* parent, uint32_t componentID) : Component(parent) { this->propertyQueries = {}; auto table = CDClientManager::GetTable(); const auto& entry = table->GetByID(componentID); this->m_MapID = entry.mapID; this->m_PropertyName = entry.propertyName; } void PropertyEntranceComponent::OnUse(Entity* entity) { auto* characterComponent = entity->GetComponent(); if (!characterComponent) return; auto* rocket = entity->GetComponent()->RocketEquip(entity); if (!rocket) return; GameMessages::SendPropertyEntranceBegin(m_Parent->GetObjectID(), entity->GetSystemAddress()); AMFArrayValue args; args.Insert("state", "property_menu"); GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", args); } void PropertyEntranceComponent::OnEnterProperty(Entity* entity, uint32_t index, bool returnToZone, const SystemAddress& sysAddr) { LWOCLONEID cloneId = 0; if (index == -1 && !returnToZone) { cloneId = entity->GetCharacter()->GetPropertyCloneID(); } else if (index == -1 && returnToZone) { cloneId = 0; } else if (index >= 0) { // Increment index once here because the first index of other player properties is 2 in the propertyQueries cache. index++; const auto& pair = propertyQueries.find(entity->GetObjectID()); if (pair == propertyQueries.end()) return; const auto& query = pair->second; if (index >= query.size()) return; cloneId = query[index].CloneId; } auto* launcher = m_Parent->GetComponent(); if (launcher == nullptr) { return; } launcher->SetSelectedCloneId(entity->GetObjectID(), cloneId); launcher->Launch(entity, launcher->GetTargetZone(), cloneId); } void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool includeNullAddress, bool includeNullDescription, bool playerOwn, bool updateUi, int32_t numResults, int32_t lReputationTime, int32_t sortMethod, int32_t startIndex, std::string filterText, const SystemAddress& sysAddr) { const auto* const character = entity->GetCharacter(); if (!character) return; const auto* const user = character->GetParentUser(); if (!user) return; auto& entries = propertyQueries[entity->GetObjectID()]; entries.clear(); // Player property goes in index 1 of the vector. This is how the client expects it. const auto playerProperty = Database::Get()->GetPropertyInfo(m_MapID, character->GetPropertyCloneID()); // If the player has a property this query will have a single result. auto& playerEntry = entries.emplace_back(); if (playerProperty.has_value()) { playerEntry.OwnerName = character->GetName(); playerEntry.IsBestFriend = true; playerEntry.IsFriend = true; playerEntry.IsAlt = true; playerEntry.IsOwned = true; playerEntry.CloneId = playerProperty->cloneId; playerEntry.Name = playerProperty->name; playerEntry.Description = playerProperty->description; playerEntry.AccessType = playerProperty->privacyOption; playerEntry.IsModeratorApproved = playerProperty->modApproved; playerEntry.DateLastPublished = playerProperty->lastUpdatedTime; playerEntry.Reputation = playerProperty->reputation; playerEntry.PerformanceCost = playerProperty->performanceCost; auto& entry = playerEntry; } else { playerEntry.OwnerName = character->GetName(); playerEntry.IsBestFriend = true; playerEntry.IsFriend = true; playerEntry.IsAlt = false; playerEntry.IsOwned = false; playerEntry.CloneId = character->GetPropertyCloneID(); playerEntry.Name = ""; playerEntry.Description = ""; playerEntry.AccessType = 0; playerEntry.IsModeratorApproved = false; playerEntry.DateLastPublished = 0; playerEntry.Reputation = 0; playerEntry.PerformanceCost = 0.0f; } IProperty::PropertyLookup propertyLookup; propertyLookup.mapId = m_MapID; propertyLookup.searchString = filterText; propertyLookup.sortChoice = static_cast(sortMethod); propertyLookup.playerSort = static_cast(sortMethod == SORT_TYPE_FEATURED || sortMethod == SORT_TYPE_FRIENDS ? PropertyPrivacyOption::Friends : PropertyPrivacyOption::Public); propertyLookup.playerId = character->GetID(); propertyLookup.numResults = numResults; propertyLookup.startIndex = startIndex; const auto lookupResult = Database::Get()->GetProperties(propertyLookup); for (const auto& propertyEntry : lookupResult->entries) { const auto owner = propertyEntry.ownerId; const auto otherCharacter = Database::Get()->GetCharacterInfo(owner); if (!otherCharacter.has_value()) { LOG("Failed to find property owner name for %u!", owner); continue; } auto& entry = entries.emplace_back(); entry.IsOwned = entry.CloneId == otherCharacter->cloneId; entry.OwnerName = otherCharacter->name; entry.CloneId = propertyEntry.cloneId; entry.Name = propertyEntry.name; entry.Description = propertyEntry.description; entry.AccessType = propertyEntry.privacyOption; entry.IsModeratorApproved = propertyEntry.modApproved; entry.DateLastPublished = propertyEntry.lastUpdatedTime; entry.Reputation = propertyEntry.reputation; entry.PerformanceCost = propertyEntry.performanceCost; entry.IsBestFriend = false; entry.IsFriend = false; // Query to get friend and best friend fields const auto friendCheck = Database::Get()->GetBestFriendStatus(character->GetID(), owner); // If we got a result than the two players are friends. if (friendCheck.has_value()) { entry.IsFriend = true; entry.IsBestFriend = friendCheck->bestFriendStatus == 3; } if (!entry.IsModeratorApproved && entity->GetGMLevel() >= eGameMasterLevel::LEAD_MODERATOR) { entry.Name = "[AWAITING APPROVAL]"; entry.Description = "[AWAITING APPROVAL]"; entry.IsModeratorApproved = true; } // Query to determine whether this property is an alt character of the entity. for (const auto charid : Database::Get()->GetAccountCharacterIds(user->GetAccountID())) { entry.IsAlt = charid == owner; if (entry.IsAlt) break; } } // Query here is to figure out whether or not to display the button to go to the next page or not. GameMessages::SendPropertySelectQuery(m_Parent->GetObjectID(), startIndex, lookupResult->totalEntriesMatchingQuery - (startIndex + numResults) > 0, character->GetPropertyCloneID(), false, true, entries, sysAddr); }