mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-30 16:37:14 +00:00
fix(ugc): give old cars and rockets a build id when a character loads
Cars and rockets built before builds were recorded have no subkey and no ugc_modular_build row, so the client has no blueprint id to ask for their icon with. When a character loads, such an item (a ModularBuildComponent createdLOT with assemblyPartLOTs but no subkey) gets what a new build gets: a persistent id as its subkey and a ugc_modular_build row with its modules and owner. The next save keeps the subkey; nothing is dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
#include "CDModularBuildComponentTable.h"
|
#include "CDModularBuildComponentTable.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -55,3 +57,8 @@ std::optional<CDModularBuildComponent> CDModularBuildComponentTable::FindByNumbe
|
|||||||
std::optional<CDModularBuildComponent> CDModularBuildComponentTable::GetByNumberOfParts(const uint32_t numberOfParts) const {
|
std::optional<CDModularBuildComponent> CDModularBuildComponentTable::GetByNumberOfParts(const uint32_t numberOfParts) const {
|
||||||
return FindByNumberOfParts(GetEntries(), numberOfParts);
|
return FindByNumberOfParts(GetEntries(), numberOfParts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CDModularBuildComponentTable::IsCreatedLot(LOT lot) const {
|
||||||
|
const auto& entries = GetEntries();
|
||||||
|
return std::any_of(entries.begin(), entries.end(), [lot](const CDModularBuildComponent& build) { return build.createdLOT == lot; });
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ public:
|
|||||||
// The first build made of this many parts
|
// The first build made of this many parts
|
||||||
std::optional<CDModularBuildComponent> GetByNumberOfParts(uint32_t numberOfParts) const;
|
std::optional<CDModularBuildComponent> GetByNumberOfParts(uint32_t numberOfParts) const;
|
||||||
|
|
||||||
|
// Whether a LOT is the item some build becomes (a car or rocket)
|
||||||
|
bool IsCreatedLot(LOT lot) const;
|
||||||
|
|
||||||
// Fills numberOfParts and rootPartExampleLOT from a ModularBuildComponent.xml
|
// Fills numberOfParts and rootPartExampleLOT from a ModularBuildComponent.xml
|
||||||
static void ParseXml(std::string_view xml, CDModularBuildComponent& build);
|
static void ParseXml(std::string_view xml, CDModularBuildComponent& build);
|
||||||
static std::optional<CDModularBuildComponent> FindByNumberOfParts(const std::vector<CDModularBuildComponent>& builds, uint32_t numberOfParts);
|
static std::optional<CDModularBuildComponent> FindByNumberOfParts(const std::vector<CDModularBuildComponent>& builds, uint32_t numberOfParts);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "GameMessages.h"
|
#include "GameMessages.h"
|
||||||
#include "InventoryMessages.h"
|
#include "InventoryMessages.h"
|
||||||
#include "Database.h"
|
#include "Database.h"
|
||||||
|
#include "CDModularBuildComponentTable.h"
|
||||||
#include "SkillMessages.h"
|
#include "SkillMessages.h"
|
||||||
#include "MovementMessages.h"
|
#include "MovementMessages.h"
|
||||||
#include "SkillComponent.h"
|
#include "SkillComponent.h"
|
||||||
@@ -610,6 +611,27 @@ bool InventoryComponent::HasSpaceForLoot(const Loot::Return& loot) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
/**
|
||||||
|
* Cars and rockets built before builds were recorded have no subkey, so the client has no blueprint id to ask for
|
||||||
|
* their icon with. Give such an item what a new build gets (ModularBuildFinish): a persistent id as its subkey and a
|
||||||
|
* ugc_modular_build row with its modules. The next save keeps the subkey. Main thread (character load).
|
||||||
|
*/
|
||||||
|
void AssignModularBuildId(Item& item, Entity* owner) {
|
||||||
|
if (item.GetSubKey() != LWOOBJID_EMPTY || !CDClientManager::GetTable<CDModularBuildComponentTable>()->IsCreatedLot(item.GetLot())) return;
|
||||||
|
const auto& config = item.GetConfig();
|
||||||
|
const auto modules = config.find(u"assemblyPartLOTs");
|
||||||
|
if (modules == config.values.end() || !modules->second) return;
|
||||||
|
const auto modulesText = modules->second->GetValueAsString();
|
||||||
|
if (modulesText.empty()) return;
|
||||||
|
const auto id = ObjectIDManager::GetPersistentID();
|
||||||
|
auto* character = owner ? owner->GetCharacter() : nullptr;
|
||||||
|
Database::Get()->InsertUgcBuild(modulesText, id, character ? std::optional(character->GetID()) : std::nullopt);
|
||||||
|
item.SetSubKey(id);
|
||||||
|
LOG("Gave the %i build %llu (made before builds were recorded) the build id %llu", item.GetLot(), item.GetId(), id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void InventoryComponent::LoadXml(const tinyxml2::XMLDocument& document) {
|
void InventoryComponent::LoadXml(const tinyxml2::XMLDocument& document) {
|
||||||
LoadPetXml(document);
|
LoadPetXml(document);
|
||||||
|
|
||||||
@@ -712,6 +734,7 @@ void InventoryComponent::LoadXml(const tinyxml2::XMLDocument& document) {
|
|||||||
auto* item = new Item(id, lot, inventory, slot, count, bound, {}, parent, subKey);
|
auto* item = new Item(id, lot, inventory, slot, count, bound, {}, parent, subKey);
|
||||||
|
|
||||||
item->LoadConfigXml(*itemElement);
|
item->LoadConfigXml(*itemElement);
|
||||||
|
AssignModularBuildId(*item, m_Parent);
|
||||||
|
|
||||||
if (equipped) {
|
if (equipped) {
|
||||||
const auto info = Inventory::FindItemComponent(lot);
|
const auto info = Inventory::FindItemComponent(lot);
|
||||||
|
|||||||
Reference in New Issue
Block a user