Start of property entrance component rewrite

This is very WIP
This commit is contained in:
Jett 2023-10-27 02:17:10 +01:00
parent e4cae35edb
commit 2b1ae4c577
8 changed files with 269 additions and 318 deletions

View File

@ -6,7 +6,7 @@
#include "Database.h" #include "Database.h"
#include "GameMessages.h" #include "GameMessages.h"
#include "PropertyManagementComponent.h" #include "PropertyManagementComponent.h"
#include "PropertySelectQueryProperty.h" #include "PropertyData.h"
#include "RocketLaunchpadControlComponent.h" #include "RocketLaunchpadControlComponent.h"
#include "CharacterComponent.h" #include "CharacterComponent.h"
#include "UserManager.h" #include "UserManager.h"
@ -14,10 +14,9 @@
#include "Amf3.h" #include "Amf3.h"
#include "eObjectBits.h" #include "eObjectBits.h"
#include "eGameMasterLevel.h" #include "eGameMasterLevel.h"
#include "User.h"
PropertyEntranceComponent::PropertyEntranceComponent(uint32_t componentID, Entity* parent) : Component(parent) { PropertyEntranceComponent::PropertyEntranceComponent(uint32_t componentID, Entity* parent) : Component(parent), m_UserRequestedCloneMap() {
this->propertyQueries = {};
auto table = CDClientManager::Instance().GetTable<CDPropertyEntranceComponentTable>(); auto table = CDClientManager::Instance().GetTable<CDPropertyEntranceComponentTable>();
const auto& entry = table->GetByID(componentID); const auto& entry = table->GetByID(componentID);
@ -52,15 +51,12 @@ 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. // Increment index once here because the first index of other player properties is 2 in the propertyQueries cache.
index++; index++;
const auto& pair = propertyQueries.find(entity->GetObjectID()); const auto& item = m_UserRequestedCloneMap.find(entity->GetObjectID());
if (item == m_UserRequestedCloneMap.end()) return;
if (pair == propertyQueries.end()) return; if (index >= m_UserRequestedCloneMap[entity->GetObjectID()].size()) return;
const auto& query = pair->second; cloneId = m_UserRequestedCloneMap[entity->GetObjectID()][index];
if (index >= query.size()) return;
cloneId = query[index].CloneId;
} }
auto* launcher = m_Parent->GetComponent<RocketLaunchpadControlComponent>(); auto* launcher = m_Parent->GetComponent<RocketLaunchpadControlComponent>();
@ -74,261 +70,214 @@ void PropertyEntranceComponent::OnEnterProperty(Entity* entity, uint32_t index,
launcher->Launch(entity, launcher->GetTargetZone(), cloneId); launcher->Launch(entity, launcher->GetTargetZone(), cloneId);
} }
PropertySelectQueryProperty PropertyEntranceComponent::SetPropertyValues(PropertySelectQueryProperty property, LWOCLONEID cloneId, std::string ownerName, std::string propertyName, std::string propertyDescription, float reputation, bool isBFF, bool isFriend, bool isModeratorApproved, bool isAlt, bool isOwned, uint32_t privacyOption, uint32_t timeLastUpdated, float performanceCost) { void PropertyEntranceComponent::PopulateUserFriendMap(uint32_t user) {
property.CloneId = cloneId; this->m_UserFriendMap[user] = {};
property.OwnerName = ownerName;
property.Name = propertyName;
property.Description = propertyDescription;
property.Reputation = reputation;
property.IsBestFriend = isBFF;
property.IsFriend = isFriend;
property.IsModeratorApproved = isModeratorApproved;
property.IsAlt = isAlt;
property.IsOwned = isOwned;
property.AccessType = privacyOption;
property.DateLastPublished = timeLastUpdated;
property.PerformanceCost = performanceCost;
return property; auto friendQuery = Database::CreatePreppedStmt("SELECT * FROM friends WHERE friend_id = ? OR player_id = ?;");
} friendQuery->setUInt(1, user);
friendQuery->setUInt(2, user);
std::string PropertyEntranceComponent::BuildQuery(Entity* entity, int32_t sortMethod, Character* character, std::string customQuery, bool wantLimits) { auto friendRes = friendQuery->executeQuery();
std::string base;
if (customQuery == "") {
base = baseQueryForProperties;
} else {
base = customQuery;
}
std::string orderBy = "";
if (sortMethod == SORT_TYPE_FEATURED || sortMethod == SORT_TYPE_FRIENDS) {
std::string friendsList = " AND p.owner_id IN (";
auto friendsListQuery = Database::CreatePreppedStmt("SELECT * FROM (SELECT CASE WHEN player_id = ? THEN friend_id WHEN friend_id = ? THEN player_id END AS requested_player FROM friends ) AS fr WHERE requested_player IS NOT NULL ORDER BY requested_player DESC;"); while (friendRes->next()) {
auto friendId = friendRes->getUInt(2);
auto playerId = friendRes->getUInt(1);
auto bestFriend = friendRes->getUInt(3) == 3;
friendsListQuery->setUInt(1, character->GetID()); if (friendId == user) {
friendsListQuery->setUInt(2, character->GetID()); this->m_UserFriendMap[user][playerId] = bestFriend;
} else {
auto friendsListQueryResult = friendsListQuery->executeQuery(); this->m_UserFriendMap[user][friendId] = bestFriend;
while (friendsListQueryResult->next()) {
auto playerIDToConvert = friendsListQueryResult->getInt(1);
friendsList = friendsList + std::to_string(playerIDToConvert) + ",";
} }
// Replace trailing comma with the closing parenthesis.
if (friendsList.at(friendsList.size() - 1) == ',') friendsList.erase(friendsList.size() - 1, 1);
friendsList += ") ";
// If we have no friends then use a -1 for the query.
if (friendsList.find("()") != std::string::npos) friendsList = " AND p.owner_id IN (-1) ";
orderBy += friendsList + "ORDER BY ci.name ASC ";
delete friendsListQueryResult;
friendsListQueryResult = nullptr;
delete friendsListQuery;
friendsListQuery = nullptr;
} else if (sortMethod == SORT_TYPE_RECENT) {
orderBy = "ORDER BY p.last_updated DESC ";
} else if (sortMethod == 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 ?;" : ";");
delete friendRes;
friendRes = nullptr;
delete friendQuery;
friendQuery = nullptr;
} }
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<uint32_t> PropertyEntranceComponent::GetPropertyIDsBasedOnParams(const std::string& searchText, uint32_t sortMethod) {
std::string query = "SELECT id, last_updated, reputation FROM properties WHERE zone_id = ? AND (description LIKE ? OR name LIKE ? OR name LIKE ?) AND privacy_option >= ? ";
std::vector<PropertySelectQueryProperty> entries{}; if (sortMethod == SORT_TYPE_RECENT) {
PropertySelectQueryProperty playerEntry{}; query += "ORDER BY last_updated DESC;";
} else if (sortMethod == SORT_TYPE_REPUTATION) {
auto character = entity->GetCharacter(); query += "ORDER BY reputation DESC, last_updated DESC;";
if (!character) return;
// Player property goes in index 1 of the vector. This is how the client expects it.
auto playerPropertyLookup = Database::CreatePreppedStmt("SELECT * FROM properties WHERE owner_id = ? AND zone_id = ?");
playerPropertyLookup->setInt(1, character->GetID());
playerPropertyLookup->setInt(2, this->m_MapID);
auto playerPropertyLookupResults = playerPropertyLookup->executeQuery();
// If the player has a property this query will have a single result.
if (playerPropertyLookupResults->next()) {
const auto cloneId = playerPropertyLookupResults->getUInt64(4);
const auto propertyName = std::string(playerPropertyLookupResults->getString(5).c_str());
const auto propertyDescription = std::string(playerPropertyLookupResults->getString(6).c_str());
const auto privacyOption = playerPropertyLookupResults->getInt(9);
const auto modApproved = playerPropertyLookupResults->getBoolean(10);
const auto dateLastUpdated = playerPropertyLookupResults->getInt64(11);
const auto reputation = playerPropertyLookupResults->getUInt(14);
const auto performanceCost = (float)playerPropertyLookupResults->getDouble(16);
playerEntry = SetPropertyValues(playerEntry, cloneId, character->GetName(), propertyName, propertyDescription, reputation, true, true, modApproved, true, true, privacyOption, dateLastUpdated, performanceCost);
} else { } else {
playerEntry = SetPropertyValues(playerEntry, character->GetPropertyCloneID(), character->GetName(), "", "", 0, true, true); query += "ORDER BY last_updated DESC;";
} }
delete playerPropertyLookupResults;
playerPropertyLookupResults = nullptr;
delete playerPropertyLookup;
playerPropertyLookup = nullptr;
entries.push_back(playerEntry);
const auto query = BuildQuery(entity, sortMethod, character);
auto propertyLookup = Database::CreatePreppedStmt(query); auto propertyLookup = Database::CreatePreppedStmt(query);
const auto searchString = "%" + filterText + "%"; const auto searchString = "%" + searchText + "%";
propertyLookup->setUInt(1, this->m_MapID); propertyLookup->setUInt(1, this->m_MapID);
propertyLookup->setString(2, searchString.c_str()); propertyLookup->setString(2, searchString.c_str());
propertyLookup->setString(3, searchString.c_str()); propertyLookup->setString(3, searchString.c_str());
propertyLookup->setString(4, 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, sortMethod == SORT_TYPE_FEATURED || sortMethod == SORT_TYPE_FRIENDS ? (uint32_t)PropertyPrivacyOption::Friends : (uint32_t)PropertyPrivacyOption::Public);
propertyLookup->setInt(6, numResults);
propertyLookup->setInt(7, startIndex);
auto propertyEntry = propertyLookup->executeQuery(); auto propertyIdRes = propertyLookup->executeQuery();
while (propertyEntry->next()) { std::vector<uint32_t> propertyIds{};
const auto propertyId = propertyEntry->getUInt64(1);
const auto owner = propertyEntry->getInt(2);
const auto cloneId = propertyEntry->getUInt64(4);
const auto propertyNameFromDb = std::string(propertyEntry->getString(5).c_str());
const auto propertyDescriptionFromDb = std::string(propertyEntry->getString(6).c_str());
const auto privacyOption = propertyEntry->getInt(9);
const auto modApproved = propertyEntry->getBoolean(10);
const auto dateLastUpdated = propertyEntry->getInt(11);
const float reputation = propertyEntry->getInt(14);
const auto performanceCost = (float)propertyEntry->getDouble(16);
PropertySelectQueryProperty entry{}; while (propertyIdRes->next()) {
propertyIds.push_back(propertyIdRes->getUInt(1));
std::string ownerName = "";
bool isOwned = true;
auto nameLookup = Database::CreatePreppedStmt("SELECT name FROM charinfo WHERE prop_clone_id = ?;");
nameLookup->setUInt64(1, cloneId);
auto nameResult = nameLookup->executeQuery();
if (!nameResult->next()) {
delete nameLookup;
nameLookup = nullptr;
Game::logger->Log("PropertyEntranceComponent", "Failed to find property owner name for %llu!", cloneId);
continue;
} else {
isOwned = cloneId == character->GetPropertyCloneID();
ownerName = std::string(nameResult->getString(1).c_str());
}
delete nameResult;
nameResult = nullptr;
delete nameLookup;
nameLookup = nullptr;
std::string propertyName = propertyNameFromDb;
std::string propertyDescription = propertyDescriptionFromDb;
bool isBestFriend = false;
bool isFriend = false;
// Convert owner char id to LWOOBJID
LWOOBJID ownerObjId = owner;
GeneralUtils::SetBit(ownerObjId, eObjectBits::CHARACTER);
GeneralUtils::SetBit(ownerObjId, eObjectBits::PERSISTENT);
// Query to get friend and best friend fields
auto friendCheck = Database::CreatePreppedStmt("SELECT best_friend FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?)");
friendCheck->setUInt(1, character->GetID());
friendCheck->setUInt(2, ownerObjId);
friendCheck->setUInt(3, ownerObjId);
friendCheck->setUInt(4, character->GetID());
auto friendResult = friendCheck->executeQuery();
// If we got a result than the two players are friends.
if (friendResult->next()) {
isFriend = true;
if (friendResult->getInt(1) == 3) {
isBestFriend = true;
}
}
delete friendCheck;
friendCheck = nullptr;
delete friendResult;
friendResult = nullptr;
bool isModeratorApproved = propertyEntry->getBoolean(10);
if (!isModeratorApproved && entity->GetGMLevel() >= eGameMasterLevel::LEAD_MODERATOR) {
propertyName = "[AWAITING APPROVAL]";
propertyDescription = "[AWAITING APPROVAL]";
isModeratorApproved = true;
}
bool isAlt = false;
// Query to determine whether this property is an alt character of the entity.
auto isAltQuery = Database::CreatePreppedStmt("SELECT id FROM charinfo where account_id in (SELECT account_id from charinfo WHERE id = ?) AND id = ?;");
isAltQuery->setInt(1, character->GetID());
isAltQuery->setInt(2, owner);
auto isAltQueryResults = isAltQuery->executeQuery();
if (isAltQueryResults->next()) {
isAlt = true;
}
delete isAltQueryResults;
isAltQueryResults = nullptr;
delete isAltQuery;
isAltQuery = nullptr;
entry = SetPropertyValues(entry, cloneId, ownerName, propertyName, propertyDescription, reputation, isBestFriend, isFriend, isModeratorApproved, isAlt, isOwned, privacyOption, dateLastUpdated, performanceCost);
entries.push_back(entry);
} }
delete propertyEntry; delete propertyIdRes;
propertyEntry = nullptr; propertyIdRes = nullptr;
delete propertyLookup; delete propertyLookup;
propertyLookup = nullptr; propertyLookup = nullptr;
propertyQueries[entity->GetObjectID()] = entries; return propertyIds;
}
// Query here is to figure out whether or not to display the button to go to the next page or not.
int32_t numberOfProperties = 0;
auto buttonQuery = BuildQuery(entity, sortMethod, character, "SELECT COUNT(*) 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); 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) {
auto propertiesLeft = Database::CreatePreppedStmt(buttonQuery); std::vector<PropertyData> entries{};
propertiesLeft->setUInt(1, this->m_MapID); if (m_UserFriendMap.find((uint32_t)entity->GetObjectID()) == m_UserFriendMap.end()) {
propertiesLeft->setString(2, searchString.c_str()); this->PopulateUserFriendMap((uint32_t)entity->GetObjectID());
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);
auto result = propertiesLeft->executeQuery(); auto character = entity->GetCharacter();
result->next(); if (!character) return;
numberOfProperties = result->getInt(1);
auto playerEntry = this->GetPropertyData(character->GetPropertyCloneID());
if (playerEntry.CloneID == 0) {
playerEntry.CloneID = character->GetPropertyCloneID();
playerEntry.PrimaryData.Name = character->GetName();
playerEntry.PersonalData.IsFriend = true;
playerEntry.PersonalData.IsBestFriend = true;
} else {
playerEntry.PersonalData = this->GetPropertyPersonalData(playerEntry, entity, true);
}
entries.push_back(playerEntry);
auto propertyIds = this->GetPropertyIDsBasedOnParams(filterText, sortMethod);
std::vector<uint32_t> propertyIdsSlice(propertyIds.begin() + startIndex, propertyIds.begin() + startIndex + numResults);
for (const auto& id : propertyIdsSlice) {
auto prop = this->GetPropertyData(id);
if (prop.CloneID != 0) {
prop.PersonalData = this->GetPropertyPersonalData(prop, entity, true);
entries.push_back(prop);
}
}
this->m_UserRequestedCloneMap[entity->GetObjectID()] = propertyIdsSlice;
GameMessages::SendPropertySelectQuery(m_Parent->GetObjectID(), startIndex, propertyIds.size() - (startIndex + numResults) > 0, character->GetPropertyCloneID(), false, true, entries, sysAddr);
}
PropertyData PropertyEntranceComponent::GetPropertyData(uint32_t propertyID) {
if (m_PropertyDataCache.find(propertyID) != m_PropertyDataCache.end()) {
return m_PropertyDataCache[propertyID];
}
auto propQuery = Database::CreatePreppedStmt("SELECT * FROM properties WHERE id = ?;");
propQuery->setUInt64(1, propertyID);
auto result = propQuery->executeQuery();
if (!result->next()) {
delete result;
result = nullptr;
delete propQuery;
propQuery = nullptr;
return PropertyData{};
}
PropertyData entry{};
entry.CloneID = result->getUInt64(4);
auto charQuery = Database::CreatePreppedStmt("SELECT name FROM charinfo WHERE prop_clone_id = ?;");
charQuery->setUInt64(1, entry.CloneID);
auto charResult = charQuery->executeQuery();
if (charResult->next()) {
entry.PrimaryData.OwnerName = std::string(charResult->getString(1).c_str());
}
delete charResult;
charResult = nullptr;
delete charQuery;
charQuery = nullptr;
entry.PrimaryData.OwnerID = result->getInt(2);
entry.PrimaryData.IsModeratorApproved = result->getBoolean(10);
entry.PrimaryData.Name = std::string(result->getString(5).c_str());
entry.PrimaryData.Description = std::string(result->getString(6).c_str());
entry.PrimaryData.Reputation = result->getUInt(14);
entry.MetaData.AccessType = result->getInt(9);
entry.MetaData.DateLastPublished = result->getInt64(11);
entry.MetaData.PerformanceCost = result->getFloat(16);
delete result; delete result;
result = nullptr; result = nullptr;
delete propertiesLeft; delete propQuery;
propertiesLeft = nullptr; propQuery = nullptr;
GameMessages::SendPropertySelectQuery(m_Parent->GetObjectID(), startIndex, numberOfProperties - (startIndex + numResults) > 0, character->GetPropertyCloneID(), false, true, entries, sysAddr); this->m_PropertyDataCache[entry.CloneID] = entry;
return entry;
}
PropertyPersonalData PropertyEntranceComponent::GetPropertyPersonalData(PropertyData& propertyData, Entity* queryingUser, bool updatePropertyDataStructure) {
PropertyPersonalData personalData{};
personalData.IsFriend = m_UserFriendMap[(uint32_t)queryingUser].find(propertyData.PrimaryData.OwnerID) != m_UserFriendMap[(uint32_t)queryingUser].end();
if (personalData.IsFriend) {
personalData.IsBestFriend = m_UserFriendMap[(uint32_t)queryingUser][propertyData.PrimaryData.OwnerID];
}
personalData.IsModeratorApproved = propertyData.PrimaryData.IsModeratorApproved;
if (!personalData.IsModeratorApproved && queryingUser->GetGMLevel() >= eGameMasterLevel::LEAD_MODERATOR && updatePropertyDataStructure) {
propertyData.PrimaryData.Name = "[AWAITING APPROVAL]";
propertyData.PrimaryData.Description = "[AWAITING APPROVAL]";
propertyData.PrimaryData.IsModeratorApproved = true;
}
auto* user = UserManager::Instance()->GetUser(queryingUser->GetSystemAddress());
auto isAltQuery = Database::CreatePreppedStmt("SELECT id, prop_clone_id FROM charinfo where account_id = ?;");
isAltQuery->setInt(1, user->GetAccountID());
auto isAltQueryResults = isAltQuery->executeQuery();
bool ownerIsOurAccount = false;
while (isAltQueryResults->next()) {
if (queryingUser->GetCharacter()->GetPropertyCloneID() == isAltQueryResults->getInt(2)) {
if (isAltQueryResults->getInt(1) == propertyData.PrimaryData.OwnerID) {
personalData.IsOwned = true;
}
ownerIsOurAccount = true;
}
}
personalData.IsAlt = ownerIsOurAccount && !personalData.IsOwned;
delete isAltQueryResults;
isAltQueryResults = nullptr;
return personalData;
} }

View File

@ -8,6 +8,8 @@
#include "GameMessages.h" #include "GameMessages.h"
#include "eReplicaComponentType.h" #include "eReplicaComponentType.h"
#include "PropertyData.h"
/** /**
* Represents the launch pad that's used to select and browse properties * Represents the launch pad that's used to select and browse properties
*/ */
@ -59,15 +61,17 @@ public:
*/ */
[[nodiscard]] LWOMAPID GetMapID() const { return m_MapID; }; [[nodiscard]] LWOMAPID GetMapID() const { return m_MapID; };
PropertySelectQueryProperty SetPropertyValues(PropertySelectQueryProperty property, LWOCLONEID cloneId = LWOCLONEID_INVALID, std::string ownerName = "", std::string propertyName = "", std::string propertyDescription = "", float reputation = 0, bool isBFF = false, bool isFriend = false, bool isModeratorApproved = false, bool isAlt = false, bool isOwned = false, uint32_t privacyOption = 0, uint32_t timeLastUpdated = 0, float performanceCost = 0.0f); void PopulateUserFriendMap(uint32_t user);
std::string BuildQuery(Entity* entity, int32_t sortMethod, Character* character, std::string customQuery = "", bool wantLimits = true);
std::vector<uint32_t> GetPropertyIDsBasedOnParams(const std::string& searchText, uint32_t sortMethod);
PropertyData GetPropertyData(uint32_t propertyID);
PropertyPersonalData GetPropertyPersonalData(PropertyData& propertyData, Entity* queryingUser, bool updatePropertyDataStructure = false);
private: private:
/** std::unordered_map<LWOOBJID, std::vector<uint32_t>> m_UserRequestedCloneMap;
* Cache of property information that was queried for property launched, indexed by property ID std::unordered_map<uint32_t, PropertyData> m_PropertyDataCache;
*/
std::map<LWOOBJID, std::vector<PropertySelectQueryProperty>> propertyQueries; std::unordered_map<LWOOBJID, std::unordered_map<LWOOBJID, bool>> m_UserFriendMap;
/** /**
* The custom name for this property * The custom name for this property
@ -85,6 +89,4 @@ private:
SORT_TYPE_RECENT = 3, SORT_TYPE_RECENT = 3,
SORT_TYPE_FEATURED = 5 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 >= ? ";
}; };

View File

@ -1,4 +1,3 @@
set(DGAME_DGAMEMESSAGES_SOURCES "GameMessageHandler.cpp" set(DGAME_DGAMEMESSAGES_SOURCES "GameMessageHandler.cpp"
"GameMessages.cpp" "GameMessages.cpp"
"PropertyDataMessage.cpp" "PropertyDataMessage.cpp" PARENT_SCOPE)
"PropertySelectQueryProperty.cpp" PARENT_SCOPE)

View File

@ -84,7 +84,7 @@
#include "PropertyDataMessage.h" #include "PropertyDataMessage.h"
#include "PropertyManagementComponent.h" #include "PropertyManagementComponent.h"
#include "PropertyVendorComponent.h" #include "PropertyVendorComponent.h"
#include "PropertySelectQueryProperty.h" #include "PropertyData.h"
#include "TradingManager.h" #include "TradingManager.h"
#include "ControlBehaviors.h" #include "ControlBehaviors.h"
#include "AMFDeserialize.h" #include "AMFDeserialize.h"
@ -3084,7 +3084,7 @@ void GameMessages::SendPropertyEntranceBegin(LWOOBJID objectId, const SystemAddr
SEND_PACKET; SEND_PACKET;
} }
void GameMessages::SendPropertySelectQuery(LWOOBJID objectId, int32_t navOffset, bool thereAreMore, int32_t cloneId, bool hasFeaturedProperty, bool wasFriends, const std::vector<PropertySelectQueryProperty>& entries, const SystemAddress& sysAddr) { void GameMessages::SendPropertySelectQuery(LWOOBJID objectId, int32_t navOffset, bool thereAreMore, int32_t cloneId, bool hasFeaturedProperty, bool wasFriends, const std::vector<PropertyData>& entries, const SystemAddress& sysAddr) {
CBITSTREAM; CBITSTREAM;
CMSGHEADER; CMSGHEADER;
@ -3099,10 +3099,41 @@ void GameMessages::SendPropertySelectQuery(LWOOBJID objectId, int32_t navOffset,
bitStream.Write<uint32_t>(entries.size()); bitStream.Write<uint32_t>(entries.size());
for (auto& entry : entries) { for (const auto& item : entries) {
entry.Serialize(bitStream); bitStream.Write(item.CloneID);
}
const auto& owner = GeneralUtils::UTF8ToUTF16(item.PrimaryData.OwnerName);
bitStream.Write(uint32_t(owner.size()));
for (uint32_t i = 0; i < owner.size(); ++i) {
bitStream.Write(static_cast<uint16_t>(owner[i]));
}
const auto& name = GeneralUtils::UTF8ToUTF16(item.PrimaryData.Name);
bitStream.Write(uint32_t(name.size()));
for (uint32_t i = 0; i < name.size(); ++i) {
bitStream.Write(static_cast<uint16_t>(name[i]));
}
const auto& description = GeneralUtils::UTF8ToUTF16(item.PrimaryData.Description);
bitStream.Write(uint32_t(description.size()));
for (uint32_t i = 0; i < description.size(); ++i) {
bitStream.Write(static_cast<uint16_t>(description[i]));
}
bitStream.Write(item.PrimaryData.Reputation);
bitStream.Write(item.PersonalData.IsBestFriend);
bitStream.Write(item.PersonalData.IsFriend);
bitStream.Write(item.PersonalData.IsModeratorApproved);
bitStream.Write(item.PersonalData.IsAlt);
bitStream.Write(item.PersonalData.IsOwned);
bitStream.Write(item.MetaData.AccessType);
bitStream.Write(item.MetaData.DateLastPublished);
bitStream.Write(item.MetaData.PerformanceIndex);
bitStream.Write(item.MetaData.PerformanceCost);
}
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
SEND_PACKET; SEND_PACKET;
} }

View File

@ -18,7 +18,7 @@ class Item;
class NiQuaternion; class NiQuaternion;
class User; class User;
class Leaderboard; class Leaderboard;
class PropertySelectQueryProperty; class PropertyData;
class TradeItem; class TradeItem;
enum class eAnimationFlags : uint32_t; enum class eAnimationFlags : uint32_t;
@ -335,7 +335,7 @@ namespace GameMessages {
void SendPropertyEntranceBegin(LWOOBJID objectId, const SystemAddress& sysAddr); void SendPropertyEntranceBegin(LWOOBJID objectId, const SystemAddress& sysAddr);
void SendPropertySelectQuery(LWOOBJID objectId, int32_t navOffset, bool thereAreMore, int32_t cloneId, bool hasFeaturedProperty, bool wasFriends, const std::vector<PropertySelectQueryProperty>& entries, const SystemAddress& sysAddr); void SendPropertySelectQuery(LWOOBJID objectId, int32_t navOffset, bool thereAreMore, int32_t cloneId, bool hasFeaturedProperty, bool wasFriends, const std::vector<PropertyData>& entries, const SystemAddress& sysAddr);
void SendNotifyObject(LWOOBJID objectId, LWOOBJID objIDSender, std::u16string name, const SystemAddress& sysAddr, int param1 = 0, int param2 = 0); void SendNotifyObject(LWOOBJID objectId, LWOOBJID objIDSender, std::u16string name, const SystemAddress& sysAddr, int param1 = 0, int param2 = 0);

View File

@ -0,0 +1,39 @@
#pragma once
#include "Entity.h"
struct PropertyPersonalData final {
bool IsBestFriend;
bool IsFriend;
bool IsModeratorApproved;
bool IsAlt;
bool IsOwned;
};
struct PropertyMetaData final {
uint32_t AccessType;
uint32_t DateLastPublished;
float PerformanceCost;
uint32_t PerformanceIndex;
};
struct PropertyPrimaryData final {
// The below two objects are not serialized with this struct however are used to gather the relative/Personal data of the property.
LWOOBJID OwnerID;
bool IsModeratorApproved;
std::string OwnerName;
std::string Name;
std::string Description;
float Reputation;
};
struct PropertyData {
LWOCLONEID CloneID;
PropertyPrimaryData PrimaryData;
PropertyPersonalData PersonalData;
PropertyMetaData MetaData;
};

View File

@ -1,38 +0,0 @@
#include "PropertySelectQueryProperty.h"
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<uint16_t>(owner[i]));
}
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<uint16_t>(name[i]));
}
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<uint16_t>(description[i]));
}
stream.Write(Reputation);
stream.Write(IsBestFriend);
stream.Write(IsFriend);
stream.Write(IsModeratorApproved);
stream.Write(IsAlt);
stream.Write(IsOwned);
stream.Write(AccessType);
stream.Write(DateLastPublished);
stream.Write(PerformanceIndex);
stream.Write(PerformanceCost);
}
void PropertySelectQueryProperty::Deserialize(RakNet::BitStream& stream) const {
// Do we need this?
}

View File

@ -1,31 +0,0 @@
#pragma once
#ifndef PROPERTYSELECTQUERY_H
#define PROPERTYSELECTQUERY_H
#include "Entity.h"
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
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
bool IsModeratorApproved = false; // Whether or not a moderator has approved this property
bool IsAlt = false; // Whether or not the property is owned by an alt of the account owner
bool IsOwned = false; // Whether or not the property is owned
uint32_t AccessType = 0; // The privacy option of the property
uint32_t DateLastPublished = 0; // The last day the property was published
float PerformanceCost = 0; // The performance cost of the property
uint32_t PerformanceIndex = 0; // The performance index of the property? Always 0?
};
#endif