diff --git a/dGame/dComponents/PropertyEntranceComponent.cpp b/dGame/dComponents/PropertyEntranceComponent.cpp index bba65322..df24daeb 100644 --- a/dGame/dComponents/PropertyEntranceComponent.cpp +++ b/dGame/dComponents/PropertyEntranceComponent.cpp @@ -1,6 +1,6 @@ #include "PropertyEntranceComponent.h" -#include +#include "CDPropertyEntranceComponentTable.h" #include "Character.h" #include "Database.h" @@ -16,7 +16,7 @@ #include "eGameMasterLevel.h" #include "DluAssert.h" -PropertyEntranceComponent::PropertyEntranceComponent(Entity* parent, uint32_t componentID) : Component(parent) { +PropertyEntranceComponent::PropertyEntranceComponent(Entity* parent, int32_t componentID) : Component(parent) { this->propertyQueries.clear(); m_ComponentId = componentID; } @@ -57,14 +57,14 @@ void PropertyEntranceComponent::OnEnterProperty(Entity* entity, uint32_t index, // 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()); + const auto& cachedQuery = propertyQueries.find(entity->GetObjectID()); - if (pair == propertyQueries.end()) { + if (cachedQuery == propertyQueries.end()) { Game::logger->Log("PropertyEntranceComponent", "Player %llu:%s did not have a property query open", entity->GetObjectID(), entity->GetCharacter()->GetName().c_str()); return; } - const auto& query = pair->second; + const auto& query = cachedQuery->second; if (index >= query.size()) return; @@ -80,11 +80,25 @@ void PropertyEntranceComponent::OnEnterProperty(Entity* entity, uint32_t index, launcher->Launch(entity, launcher->GetTargetZone(), cloneId); } -std::string PropertyEntranceComponent::BuildQuery(Entity* entity, int32_t sortMethod, Character* character, std::string customQuery, bool wantLimits) { +std::string PropertyEntranceComponent::BuildQuery(const ePropertySortType sortMethod, Character* character, const std::string& customQuery, const bool wantLimits) { + const std::string baseQueryForProperties = + R"QUERY( + SELECT p.* + FROM properties as p + JOIN charinfo as ci + ON ci.prop_clone_id = p.clone_id + WHERE p.zone_id = ? + AND ( + p.description LIKE ? + OR p.name LIKE ? + OR ci.name LIKE ? + ) + AND p.privacy_option >= ? + )QUERY"; DluAssert(character != nullptr); - std::string base = customQuery.empty() ? baseQueryForProperties : customQuery; - std::string orderBy; - if (sortMethod == SORT_TYPE_FEATURED || sortMethod == SORT_TYPE_FRIENDS) { + const std::string base = customQuery.empty() ? baseQueryForProperties : customQuery; + std::string orderBy = "ORDER BY p.last_updated DESC"; + if (sortMethod == ePropertySortType::SORT_TYPE_FEATURED || sortMethod == ePropertySortType::SORT_TYPE_FRIENDS) { std::stringstream friendsStream; friendsStream << " AND p.owner_id IN ("; @@ -98,32 +112,28 @@ std::string PropertyEntranceComponent::BuildQuery(Entity* entity, int32_t sortMe std::unique_ptr friendsListQueryResult(friendsListQuery->executeQuery()); if (friendsListQueryResult->next()) { - friendsStream << friendsListQueryResult->getInt(1); + friendsStream << friendsListQueryResult->getInt("requested_player"); while (friendsListQueryResult->next()) { - friendsStream << ',' << friendsListQueryResult->getInt(1); + friendsStream << ',' << friendsListQueryResult->getInt("requested_player"); } } - // Replace trailing comma with the closing parenthesis. // If we have no friends then use a -1 for the query. if (friendsListQueryResult->rowsCount() == 0) friendsStream << -1; friendsStream << ')'; orderBy += friendsStream.str() + " ORDER BY ci.name ASC"; - - } else if (sortMethod == SORT_TYPE_RECENT) { + } else if (sortMethod == ePropertySortType::SORT_TYPE_RECENT) { orderBy = "ORDER BY p.last_updated DESC"; - } else if (sortMethod == SORT_TYPE_REPUTATION) { + } else if (sortMethod == ePropertySortType::SORT_TYPE_REPUTATION) { orderBy = "ORDER BY p.reputation DESC, p.last_updated DESC"; - } else { - orderBy = "ORDER BY p.last_updated DESC"; } return base + orderBy + (wantLimits ? " LIMIT ? OFFSET ?;" : " ;"); } -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) { - std::vector entries; - PropertySelectQueryProperty playerEntry; +void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool includeNullAddress, bool includeNullDescription, bool playerOwn, bool updateUi, int32_t numResults, int32_t lReputationTime, ePropertySortType sortMethod, int32_t startIndex, std::string filterText, const SystemAddress& sysAddr) { + std::vector propertyPageEntries; + PropertySelectQueryProperty requestorEntry; auto character = entity->GetCharacter(); if (!character) return; @@ -139,42 +149,39 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl std::unique_ptr playerPropertyLookupResults(playerPropertyLookup->executeQuery()); // If the player has a property this query will have a single result. + requestorEntry.CloneId = character->GetPropertyCloneID(); + requestorEntry.OwnerName = character->GetName(); if (playerPropertyLookupResults->next()) { - playerEntry.CloneId = playerPropertyLookupResults->getUInt64(4);; - playerEntry.OwnerName = character->GetName(); - playerEntry.Name = playerPropertyLookupResults->getString(5).c_str(); - playerEntry.Description = playerPropertyLookupResults->getString(6).c_str(); - playerEntry.Reputation = playerPropertyLookupResults->getUInt(14); - playerEntry.IsBestFriend = true; - playerEntry.IsFriend = true; - playerEntry.IsModeratorApproved = playerPropertyLookupResults->getBoolean(10); - playerEntry.IsAlt = true; - playerEntry.IsOwned = true; - playerEntry.AccessType = playerPropertyLookupResults->getInt(9); - playerEntry.DateLastPublished = playerPropertyLookupResults->getInt64(11); - playerEntry.PerformanceCost = playerPropertyLookupResults->getDouble(16); - } else { - playerEntry.CloneId = character->GetPropertyCloneID(); - playerEntry.OwnerName = character->GetName(); - playerEntry.Description.clear(); - playerEntry.Name.clear(); - playerEntry.Reputation = 0.0f; - playerEntry.IsBestFriend = true; - playerEntry.IsFriend = true; + requestorEntry.Name = std::string(playerPropertyLookupResults->getString("name").c_str()); + requestorEntry.Description = std::string(playerPropertyLookupResults->getString("description").c_str()); + requestorEntry.Reputation = playerPropertyLookupResults->getUInt("reputation"); + requestorEntry.IsBestFriend = true; + requestorEntry.IsFriend = true; + requestorEntry.IsModeratorApproved = playerPropertyLookupResults->getBoolean("mod_approved"); + requestorEntry.IsAlt = true; + requestorEntry.IsOwned = true; + requestorEntry.AccessType = playerPropertyLookupResults->getInt("privacy_option"); + requestorEntry.DateLastPublished = playerPropertyLookupResults->getInt64("last_updated"); + requestorEntry.PerformanceCost = playerPropertyLookupResults->getDouble("performance_cost"); } - entries.push_back(playerEntry); + propertyPageEntries.push_back(requestorEntry); - const auto query = BuildQuery(entity, sortMethod, character); + const auto query = BuildQuery(sortMethod, character); std::unique_ptr propertyLookup(Database::CreatePreppedStmt(query)); const auto searchString = "%" + filterText + "%"; + PropertyPrivacyOption friendsLookup = + sortMethod == ePropertySortType::SORT_TYPE_FEATURED || sortMethod == ePropertySortType::SORT_TYPE_FRIENDS ? + PropertyPrivacyOption::Friends : + PropertyPrivacyOption::Public; + propertyLookup->setUInt(1, this->m_MapID); propertyLookup->setString(2, searchString.c_str()); propertyLookup->setString(3, searchString.c_str()); propertyLookup->setString(4, searchString.c_str()); - propertyLookup->setInt(5, sortMethod == SORT_TYPE_FEATURED || sortMethod == SORT_TYPE_FRIENDS ? (uint32_t)PropertyPrivacyOption::Friends : (uint32_t)PropertyPrivacyOption::Public); + propertyLookup->setInt(5, static_cast(friendsLookup)); propertyLookup->setInt(6, numResults); propertyLookup->setInt(7, startIndex); @@ -182,15 +189,15 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl while (propertyEntry->next()) { PropertySelectQueryProperty playerPropertyEntry; - const auto owner = propertyEntry->getInt(2); - playerPropertyEntry.CloneId = propertyEntry->getUInt64(4); - playerPropertyEntry.Name = std::string(propertyEntry->getString(5).c_str()); - playerPropertyEntry.Description = std::string(propertyEntry->getString(6).c_str()); - playerPropertyEntry.AccessType = propertyEntry->getInt(9); - playerPropertyEntry.IsModeratorApproved = propertyEntry->getBoolean(10); - playerPropertyEntry.DateLastPublished = propertyEntry->getInt(11); - playerPropertyEntry.Reputation = static_cast(propertyEntry->getInt(14)); - playerPropertyEntry.PerformanceCost = static_cast(propertyEntry->getDouble(16)); + const auto owner = propertyEntry->getInt("owner_id"); + playerPropertyEntry.CloneId = propertyEntry->getUInt64("clone_id"); + playerPropertyEntry.Name = std::string(propertyEntry->getString("name").c_str()); + playerPropertyEntry.Description = std::string(propertyEntry->getString("description").c_str()); + playerPropertyEntry.AccessType = propertyEntry->getInt("privacy_option"); + playerPropertyEntry.IsModeratorApproved = propertyEntry->getBoolean("mod_approved"); + playerPropertyEntry.DateLastPublished = propertyEntry->getInt("last_updated"); + playerPropertyEntry.Reputation = static_cast(propertyEntry->getInt("reputation")); + playerPropertyEntry.PerformanceCost = static_cast(propertyEntry->getDouble("performance_cost")); playerPropertyEntry.OwnerName = ""; playerPropertyEntry.IsBestFriend = false; playerPropertyEntry.IsFriend = false; @@ -209,7 +216,7 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl continue; } playerPropertyEntry.IsOwned = playerPropertyEntry.CloneId == character->GetPropertyCloneID(); - playerPropertyEntry.OwnerName = std::string(nameResult->getString(1).c_str()); + playerPropertyEntry.OwnerName = std::string(nameResult->getString("name").c_str()); // Query to get friend and best friend fields std::unique_ptr friendCheck( @@ -225,9 +232,9 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl // If we got a result than the two players are friends. playerPropertyEntry.IsFriend = friendResult->next(); - playerPropertyEntry.IsBestFriend = playerPropertyEntry.IsFriend && friendResult->getInt(1) == 3; + playerPropertyEntry.IsBestFriend = playerPropertyEntry.IsFriend && friendResult->getInt("best_friend") == 3; - playerPropertyEntry.IsModeratorApproved = propertyEntry->getBoolean(10); + playerPropertyEntry.IsModeratorApproved = propertyEntry->getBoolean("mod_approved"); // So lead moderators can visit the property but also see that it is still awaiting approval. if (!playerPropertyEntry.IsModeratorApproved && entity->GetGMLevel() >= eGameMasterLevel::LEAD_MODERATOR) { @@ -248,23 +255,38 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl if (isAltQueryResults->next()) playerPropertyEntry.IsAlt = true; - entries.push_back(playerPropertyEntry); + propertyPageEntries.push_back(playerPropertyEntry); } - propertyQueries[entity->GetObjectID()] = entries; + propertyQueries[entity->GetObjectID()] = propertyPageEntries; // Query here is to figure out whether or not to display the button to go to the next page or not. - auto buttonQuery = BuildQuery(entity, sortMethod, character, "SELECT COUNT(*) as numProperties FROM properties as p JOIN charinfo as ci ON ci.prop_clone_id = p.clone_id where p.zone_id = ? AND (p.description LIKE ? OR p.name LIKE ? OR ci.name LIKE ?) AND p.privacy_option >= ? ", false); + const std::string baseButtonQuery = + R"QUERY( + SELECT COUNT(*) as numProperties + FROM properties as p + JOIN charinfo as ci + ON ci.prop_clone_id = p.clone_id + WHERE p.zone_id = ? + AND ( + p.description LIKE ? + OR p.name LIKE ? + OR ci.name LIKE ? + ) + AND p.privacy_option >= ? + )QUERY"; + + auto buttonQuery = BuildQuery(sortMethod, character, baseButtonQuery, false); std::unique_ptr propertiesLeft(Database::CreatePreppedStmt(buttonQuery)); propertiesLeft->setUInt(1, this->m_MapID); propertiesLeft->setString(2, searchString.c_str()); propertiesLeft->setString(3, searchString.c_str()); propertiesLeft->setString(4, searchString.c_str()); - propertiesLeft->setInt(5, sortMethod == SORT_TYPE_FEATURED || sortMethod == SORT_TYPE_FRIENDS ? 1 : 2); + propertiesLeft->setInt(5, static_cast(friendsLookup)); std::unique_ptr result(propertiesLeft->executeQuery()); result->next(); int32_t numberOfProperties = result->getInt("numProperties"); - GameMessages::SendPropertySelectQuery(m_ParentEntity->GetObjectID(), startIndex, numberOfProperties - (startIndex + numResults) > 0, character->GetPropertyCloneID(), false, true, entries, sysAddr); + GameMessages::SendPropertySelectQuery(m_ParentEntity->GetObjectID(), startIndex, numberOfProperties - (startIndex + numResults) > 0, character->GetPropertyCloneID(), false, true, propertyPageEntries, sysAddr); } diff --git a/dGame/dComponents/PropertyEntranceComponent.h b/dGame/dComponents/PropertyEntranceComponent.h index 475954e9..488b8af5 100644 --- a/dGame/dComponents/PropertyEntranceComponent.h +++ b/dGame/dComponents/PropertyEntranceComponent.h @@ -6,13 +6,20 @@ #include "eReplicaComponentType.h" #include "PropertySelectQueryProperty.h" +enum class ePropertySortType : int32_t { + SORT_TYPE_FRIENDS = 0, + SORT_TYPE_REPUTATION = 1, + SORT_TYPE_RECENT = 3, + SORT_TYPE_FEATURED = 5 +}; + /** * Represents the launch pad that's used to select and browse properties */ -class PropertyEntranceComponent : public Component { +class PropertyEntranceComponent final : public Component { public: inline static const eReplicaComponentType ComponentType = eReplicaComponentType::PROPERTY_ENTRANCE; - explicit PropertyEntranceComponent(Entity* parent, uint32_t componentID); + explicit PropertyEntranceComponent(Entity* parent, int32_t componentID); void LoadTemplateData() override; @@ -45,7 +52,7 @@ public: * @param filterText property names to search for * @param sysAddr the address to send gamemessage responses to */ - void 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); + void OnPropertyEntranceSync(Entity* entity, bool includeNullAddress, bool includeNullDescription, bool playerOwn, bool updateUi, int32_t numResults, int32_t lReputationTime, ePropertySortType sortMethod, int32_t startIndex, std::string filterText, const SystemAddress& sysAddr); /** * Returns the name of this property @@ -59,7 +66,7 @@ public: */ [[nodiscard]] LWOMAPID GetMapID() const { return m_MapID; }; - std::string BuildQuery(Entity* entity, int32_t sortMethod, Character* character, std::string customQuery = "", bool wantLimits = true); + [[nodiscard]] static std::string BuildQuery(const ePropertySortType sortMethod, Character* character, const std::string& customQuery = "", const bool wantLimits = true); private: /** @@ -77,14 +84,5 @@ private: */ LWOMAPID m_MapID; - enum ePropertySortType : int32_t { - SORT_TYPE_FRIENDS = 0, - SORT_TYPE_REPUTATION = 1, - SORT_TYPE_RECENT = 3, - SORT_TYPE_FEATURED = 5 - }; - - std::string baseQueryForProperties = "SELECT p.* FROM properties as p JOIN charinfo as ci ON ci.prop_clone_id = p.clone_id where p.zone_id = ? AND (p.description LIKE ? OR p.name LIKE ? OR ci.name LIKE ?) AND p.privacy_option >= ? "; - int32_t m_ComponentId = -1; }; diff --git a/dGame/dComponents/PropertyManagementComponent.h b/dGame/dComponents/PropertyManagementComponent.h index 2f2deea4..080cc358 100644 --- a/dGame/dComponents/PropertyManagementComponent.h +++ b/dGame/dComponents/PropertyManagementComponent.h @@ -8,7 +8,7 @@ /** * Information regarding which players may visit this property */ -enum class PropertyPrivacyOption +enum class PropertyPrivacyOption : uint32_t { /** * Default, only you can visit your property @@ -18,12 +18,12 @@ enum class PropertyPrivacyOption /** * Your friends can visit your property */ - Friends = 1, + Friends = 1, - /** - * Requires Mythran approval, everyone can visit your property - */ - Public = 2 + /** + * Requires Mythran approval, everyone can visit your property + */ + Public = 2 }; /** diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 351df735..404db64d 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -2752,7 +2752,7 @@ void GameMessages::HandlePropertyEntranceSync(RakNet::BitStream* inStream, Entit bool updateUi{}; int32_t numResults{}; int32_t reputation{}; - int32_t sortMethod{}; + ePropertySortType sortMethod{}; int32_t startIndex{}; uint32_t filterTextLength{}; std::string filterText{}; @@ -2769,15 +2769,14 @@ void GameMessages::HandlePropertyEntranceSync(RakNet::BitStream* inStream, Entit for (auto i = 0u; i < filterTextLength; i++) { char c; - inStream->Read(c); - filterText.push_back(c); + if (inStream->Read(c)) filterText.push_back(c); } auto* player = Player::GetPlayer(sysAddr); auto* entranceComponent = entity->GetComponent(); - if (entranceComponent == nullptr) return; + if (!entranceComponent) return; entranceComponent->OnPropertyEntranceSync(player, includeNullAddress, diff --git a/dGame/dGameMessages/PropertySelectQueryProperty.cpp b/dGame/dGameMessages/PropertySelectQueryProperty.cpp index 6e975879..5f575a7c 100644 --- a/dGame/dGameMessages/PropertySelectQueryProperty.cpp +++ b/dGame/dGameMessages/PropertySelectQueryProperty.cpp @@ -3,22 +3,19 @@ void PropertySelectQueryProperty::Serialize(RakNet::BitStream& stream) const { stream.Write(CloneId); - const auto& owner = GeneralUtils::UTF8ToUTF16(OwnerName); - stream.Write(uint32_t(owner.size())); - for (uint32_t i = 0; i < owner.size(); ++i) { - stream.Write(static_cast(owner[i])); + stream.Write(OwnerName.size()); + for (const auto& c : OwnerName) { + stream.Write(c); } - const auto& name = GeneralUtils::UTF8ToUTF16(Name); - stream.Write(uint32_t(name.size())); - for (uint32_t i = 0; i < name.size(); ++i) { - stream.Write(static_cast(name[i])); + stream.Write(Name.size()); + for (const auto& c : Name) { + stream.Write(c); } - const auto& description = GeneralUtils::UTF8ToUTF16(Description); - stream.Write(uint32_t(description.size())); - for (uint32_t i = 0; i < description.size(); ++i) { - stream.Write(static_cast(description[i])); + stream.Write(Description.size()); + for (const auto& c : Description) { + stream.Write(c); } stream.Write(Reputation); @@ -32,7 +29,3 @@ void PropertySelectQueryProperty::Serialize(RakNet::BitStream& stream) const { stream.Write(PerformanceIndex); stream.Write(PerformanceCost); } - -void PropertySelectQueryProperty::Deserialize(RakNet::BitStream& stream) const { - // Do we need this? -} diff --git a/dGame/dGameMessages/PropertySelectQueryProperty.h b/dGame/dGameMessages/PropertySelectQueryProperty.h index 47d795a7..c3e5082e 100644 --- a/dGame/dGameMessages/PropertySelectQueryProperty.h +++ b/dGame/dGameMessages/PropertySelectQueryProperty.h @@ -1,7 +1,7 @@ #pragma once -#ifndef PROPERTYSELECTQUERY_H -#define PROPERTYSELECTQUERY_H +#ifndef __PROPERTYSELECTQUERY_H__ +#define __PROPERTYSELECTQUERY_H__ #include "Entity.h" @@ -10,12 +10,10 @@ class PropertySelectQueryProperty final public: void Serialize(RakNet::BitStream& stream) const; - void Deserialize(RakNet::BitStream& stream) const; - LWOCLONEID CloneId = LWOCLONEID_INVALID; // The cloneID of the property - std::string OwnerName = ""; // The property owners name - std::string Name = ""; // The property name - std::string Description = ""; // The property description + std::string OwnerName; // The property owners name + std::string Name; // The property name + std::string Description; // The property description float Reputation = 0; // The reputation of the property bool IsBestFriend = false; // Whether or not the property belongs to a best friend bool IsFriend = false; // Whether or not the property belongs to a friend @@ -28,4 +26,4 @@ public: uint32_t PerformanceIndex = 0; // The performance index of the property? Always 0? }; -#endif +#endif // __PROPERTYSELECTQUERY_H__