mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-11-15 08:17:13 +00:00
feat: save the mount item as live did
Every live save had <mnt a="..."/>, which LWOMountControlComponent::LoadFromSaveData (0x00bf99c0) reads as the character's mount item (0 on the 450 saves looked at). The server wrote no such element. MountControlComponent now writes it: the item of the mount being ridden, 0 on foot. The saved value is read and kept; nothing is mounted from it, as riding does not go on over a world change. A save from before gains <mnt a="0"/> and nothing else in it changes. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@ set(DGAME_DCOMPONENTS_SOURCES
|
||||
"Character/LevelProgressionComponent.cpp"
|
||||
"LUPExhibitComponent.cpp"
|
||||
"Character/MissionComponent.cpp"
|
||||
"Character/MountControlComponent.cpp"
|
||||
"MissionOfferComponent.cpp"
|
||||
"ModelComponent.cpp"
|
||||
"ModuleAssemblyComponent.cpp"
|
||||
|
||||
23
dGame/dComponents/Character/MountControlComponent.cpp
Normal file
23
dGame/dComponents/Character/MountControlComponent.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "MountControlComponent.h"
|
||||
|
||||
#include "Entity.h"
|
||||
#include "PossessorComponent.h"
|
||||
|
||||
#include "tinyxml2.h"
|
||||
|
||||
void MountControlComponent::LoadFromSaveData(const tinyxml2::XMLDocument& doc) {
|
||||
const auto* const obj = doc.FirstChildElement("obj");
|
||||
const auto* const mount = obj ? obj->FirstChildElement("mnt") : nullptr;
|
||||
if (mount) mount->QueryInt64Attribute("a", &m_SavedMountItemID);
|
||||
}
|
||||
|
||||
void MountControlComponent::WriteSaveData(tinyxml2::XMLDocument& doc) {
|
||||
auto* const obj = doc.FirstChildElement("obj");
|
||||
if (!obj) return;
|
||||
|
||||
auto* mount = obj->FirstChildElement("mnt");
|
||||
if (!mount) mount = obj->InsertNewChildElement("mnt");
|
||||
|
||||
const auto* const possessor = m_Parent->GetComponent<PossessorComponent>();
|
||||
mount->SetAttribute("a", possessor ? possessor->GetMountItemID() : LWOOBJID_EMPTY);
|
||||
}
|
||||
@@ -2,17 +2,31 @@
|
||||
#define MOUNTCONTROLCOMPONENT_H
|
||||
|
||||
#include "Component.h"
|
||||
#include "dCommonVars.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
|
||||
/**
|
||||
* Mount control (111): the character's riding of mounts, as the client's LWOMountControlComponent: the client makes it (componentID -1) with every character
|
||||
* (LWOCharacterComponent::Factory). Nothing of it is sent or done on the server yet.
|
||||
* (LWOCharacterComponent::Factory). It keeps the mount item in the character's save, as live did (<mnt a="item id"/>,
|
||||
* 0 when not riding: all 450 live saves looked at were 0).
|
||||
*/
|
||||
class MountControlComponent final : public Component {
|
||||
public:
|
||||
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::MOUNT_CONTROL;
|
||||
|
||||
MountControlComponent(Entity* parent, const int32_t componentID) : Component(parent, componentID) {}
|
||||
|
||||
// LWOMountControlComponent::LoadFromSaveData (0x00bf99c0): <mnt a>, the mount item of the save
|
||||
void LoadFromSaveData(const tinyxml2::XMLDocument& doc) override;
|
||||
|
||||
// Writes <mnt a>: the item of the mount being ridden (PossessorComponent's), 0 when on foot
|
||||
void WriteSaveData(tinyxml2::XMLDocument& doc) override;
|
||||
|
||||
// The mount item the save named. Riding does not go on over a world change, so nothing is mounted from it.
|
||||
LWOOBJID GetSavedMountItemID() const { return m_SavedMountItemID; }
|
||||
|
||||
private:
|
||||
LWOOBJID m_SavedMountItemID = LWOOBJID_EMPTY;
|
||||
};
|
||||
|
||||
#endif // MOUNTCONTROLCOMPONENT_H
|
||||
|
||||
@@ -6,6 +6,7 @@ set(DCOMPONENTS_TESTS
|
||||
"DestroyableLevelConfigTests.cpp"
|
||||
"ProximityMonitorComponentTests.cpp"
|
||||
"RailActivatorComponentTests.cpp"
|
||||
"MountControlComponentTests.cpp"
|
||||
"ConstructionOnlyComponentTests.cpp"
|
||||
"PropertyVendorComponentTests.cpp"
|
||||
"VendorBuybackTests.cpp"
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// The mount item in a character's save: LWOMountControlComponent::LoadFromSaveData (0x00bf99c0) reads <mnt a>, and
|
||||
// every live save had the element (<mnt a="0"/> on the 450 looked at).
|
||||
#include "GameDependencies.h"
|
||||
|
||||
#include "Entity.h"
|
||||
#include "MountControlComponent.h"
|
||||
#include "PossessorComponent.h"
|
||||
|
||||
#include "tinyxml2.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <string>
|
||||
|
||||
class MountControlComponentTests : public GameDependenciesTest {
|
||||
protected:
|
||||
void SetUp() override { SetUpDependencies(); }
|
||||
void TearDown() override { TearDownDependencies(); }
|
||||
|
||||
static std::string Print(const tinyxml2::XMLDocument& doc) {
|
||||
tinyxml2::XMLPrinter printer(nullptr, true);
|
||||
doc.Print(&printer);
|
||||
return printer.CStr();
|
||||
}
|
||||
};
|
||||
|
||||
// A save from before the element was written gains it, and nothing else changes
|
||||
TEST_F(MountControlComponentTests, OldSaveGainsTheElement) {
|
||||
tinyxml2::XMLDocument doc;
|
||||
ASSERT_EQ(doc.Parse(R"(<obj v="1"><mf hc="1"/><char cc="5"/><dest hm="4"/></obj>)"), tinyxml2::XML_SUCCESS);
|
||||
Entity player(70, info);
|
||||
auto* const mountControl = player.AddComponent<MountControlComponent>(-1);
|
||||
mountControl->LoadFromSaveData(doc);
|
||||
EXPECT_EQ(mountControl->GetSavedMountItemID(), LWOOBJID_EMPTY);
|
||||
mountControl->WriteSaveData(doc);
|
||||
EXPECT_EQ(Print(doc), R"(<obj v="1"><mf hc="1"/><char cc="5"/><dest hm="4"/><mnt a="0"/></obj>)");
|
||||
// Saving again changes nothing
|
||||
mountControl->WriteSaveData(doc);
|
||||
EXPECT_EQ(Print(doc), R"(<obj v="1"><mf hc="1"/><char cc="5"/><dest hm="4"/><mnt a="0"/></obj>)");
|
||||
}
|
||||
|
||||
// The item of the mount being ridden is saved, in the element's own place; on foot it is 0 again
|
||||
TEST_F(MountControlComponentTests, TheRiddenMountIsSaved) {
|
||||
tinyxml2::XMLDocument doc;
|
||||
ASSERT_EQ(doc.Parse(R"(<obj v="1"><mis/><mnt a="1152921510436607007"/><dest hm="4"/></obj>)"), tinyxml2::XML_SUCCESS);
|
||||
Entity player(71, info);
|
||||
auto* const possessor = player.AddComponent<PossessorComponent>(-1);
|
||||
auto* const mountControl = player.AddComponent<MountControlComponent>(-1);
|
||||
mountControl->LoadFromSaveData(doc);
|
||||
EXPECT_EQ(mountControl->GetSavedMountItemID(), 1152921510436607007LL);
|
||||
|
||||
// Nothing is ridden after a load
|
||||
mountControl->WriteSaveData(doc);
|
||||
EXPECT_EQ(Print(doc), R"(<obj v="1"><mis/><mnt a="0"/><dest hm="4"/></obj>)");
|
||||
|
||||
possessor->SetMountItemID(1152921510436607123LL);
|
||||
mountControl->WriteSaveData(doc);
|
||||
EXPECT_EQ(Print(doc), R"(<obj v="1"><mis/><mnt a="1152921510436607123"/><dest hm="4"/></obj>)");
|
||||
|
||||
possessor->SetMountItemID(LWOOBJID_EMPTY);
|
||||
mountControl->WriteSaveData(doc);
|
||||
EXPECT_EQ(Print(doc), R"(<obj v="1"><mis/><mnt a="0"/><dest hm="4"/></obj>)");
|
||||
}
|
||||
Reference in New Issue
Block a user