DarkflameServer/dGame/dComponents/PropertyEntranceComponent.cpp
David Markowitz ec501831e6
fix: Remove database requirements for Property Entrance Component and greatly simplify logic (#1650)
* remove complex queries and move logic to dDatabase

remove unused code

Use correct id

fix arrows

use correct parameter

fix queries

Update Property.cpp

remove unused header

remove extra include

* fix tests

* Update dGame/dComponents/PropertyEntranceComponent.h

Co-authored-by: jadebenn <jadebenn@users.noreply.github.com>

* Update dGame/User.h

Co-authored-by: jadebenn <jadebenn@users.noreply.github.com>

---------

Co-authored-by: jadebenn <jadebenn@users.noreply.github.com>
2024-11-23 15:56:31 -06:00

179 lines
6.7 KiB
C++

#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<CDPropertyEntranceComponentTable>();
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<CharacterComponent>();
if (!characterComponent) return;
auto* rocket = entity->GetComponent<CharacterComponent>()->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<RocketLaunchpadControlComponent>();
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<ePropertySortType>(sortMethod);
propertyLookup.playerSort = static_cast<uint32_t>(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);
}