mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-11-14 07:47:13 +00:00
fix: a proximity monitor row lists proximity types, not radii
LWOProximityMonitorComponent::LoadDataFromTemplate (0x00c2dfb0) reads the
row's Proximities as ids of ProximityTypes rows, and SendMessage
(0x00cbb930) makes, on AddedToWorld, a proximity under the type's name and
radius (30 when missing) for each type loaded on its side.
The ids were read as two radii: every launch pad ("7,8", the client's
RocketSign and WorldLauncher types) got a rocketSmall sphere of 7 and a
rocketLarge one of 8 that nothing used. Now the row's and the type's
LoadOnServer decide; of the 40 rows only a test object's has one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#include "ProximityMonitorComponent.h"
|
||||
#include "CDClientManager.h"
|
||||
#include "CDClientDatabase.h"
|
||||
#include "CDProximityMonitorComponentTable.h"
|
||||
#include "GameMessages.h"
|
||||
#include "dZoneManager.h"
|
||||
@@ -19,20 +20,29 @@ ProximityMonitorComponent::ProximityMonitorComponent(Entity* parent, const int32
|
||||
RegisterMsg(&ProximityMonitorComponent::OnGetObjectReportInfo);
|
||||
}
|
||||
|
||||
// The ProximityMonitorComponent row's radii, "small,large" (one value, as LOT 9833's "4", is both): the rocket
|
||||
// launch radii
|
||||
// The ProximityMonitorComponent row lists ProximityTypes ids ("7,8": RocketSign and WorldLauncher), not radii. Each
|
||||
// type has a name, a radius and where it is loaded: LWOProximityMonitorComponent::LoadDataFromTemplate (0x00c2dfb0)
|
||||
// keeps the ids and SendMessage (0x00cbb930), on AddedToWorld, sets a proximity up under the type's name for each one
|
||||
// that has LoadOnClient. The server's are the ones with LoadOnServer, of a row that has it too.
|
||||
void ProximityMonitorComponent::LoadDataFromTemplate() {
|
||||
if (m_ComponentID <= 0) return;
|
||||
const auto componentID = m_ComponentID;
|
||||
const auto proxCompData = CDClientManager::GetTable<CDProximityMonitorComponentTable>()->Query([componentID](const CDProximityMonitorComponent& entry) { return (entry.id == componentID); });
|
||||
if (proxCompData.empty()) return;
|
||||
if (proxCompData.empty() || !proxCompData[0].LoadOnServer) return;
|
||||
|
||||
const auto radii = GeneralUtils::SplitString(proxCompData[0].Proximities, ',');
|
||||
const auto small = radii.empty() ? std::nullopt : GeneralUtils::TryParse<int32_t>(radii[0]);
|
||||
const auto large = radii.size() > 1 ? GeneralUtils::TryParse<int32_t>(radii[1]) : small;
|
||||
if (!small || !large) return;
|
||||
SetProximityRadius(*small, "rocketSmall");
|
||||
SetProximityRadius(*large, "rocketLarge");
|
||||
for (const auto& typeString : GeneralUtils::SplitString(proxCompData[0].Proximities, ',')) {
|
||||
const auto typeID = GeneralUtils::TryParse<int32_t>(typeString);
|
||||
if (!typeID) continue;
|
||||
auto query = CDClientDatabase::CreatePreppedStmt("SELECT Name, Radius, LoadOnServer FROM ProximityTypes WHERE id = ?;");
|
||||
query.bind(1, *typeID);
|
||||
auto result = query.execQuery();
|
||||
if (result.eof() || result.getIntField("LoadOnServer", 0) == 0) continue;
|
||||
const std::string name = result.getStringField("Name", "");
|
||||
if (name.empty()) continue;
|
||||
// A missing or non-positive radius is 30, as the client takes it
|
||||
const auto radius = result.getIntField("Radius", 30);
|
||||
SetProximityRadius(static_cast<float>(radius > 0 ? radius : 30), name);
|
||||
}
|
||||
}
|
||||
|
||||
ProximityMonitorComponent::~ProximityMonitorComponent() {
|
||||
|
||||
@@ -4,6 +4,7 @@ set(DCOMPONENTS_TESTS
|
||||
"InventorySaveTests.cpp"
|
||||
"EquipMessagesTests.cpp"
|
||||
"DestroyableLevelConfigTests.cpp"
|
||||
"ProximityMonitorComponentTests.cpp"
|
||||
"RailActivatorComponentTests.cpp"
|
||||
"VendorBuybackTests.cpp"
|
||||
"RacingWrongWayTests.cpp"
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
#include "GameDependencies.h"
|
||||
|
||||
#include "CDClientDatabase.h"
|
||||
#include "CDClientManager.h"
|
||||
#include "CDProximityMonitorComponentTable.h"
|
||||
#include "Entity.h"
|
||||
#include "GameMessages.h"
|
||||
#include "ProximityMonitorComponent.h"
|
||||
#include "dpEntity.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// A ProximityMonitorComponent row lists ProximityTypes ids, as LWOProximityMonitorComponent::LoadDataFromTemplate
|
||||
// (0x00c2dfb0) reads it; the types say their name, radius and where they are loaded.
|
||||
class ProximityMonitorComponentTests : public GameDependenciesTest {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
SetUpDependencies();
|
||||
CDClientDatabase::Connect(":memory:");
|
||||
CDClientDatabase::ExecuteDML("CREATE TABLE ProximityTypes (id INTEGER, Name TEXT, Radius INTEGER, CollisionGroup INTEGER, PassiveChecks INTEGER, IconID INTEGER, LoadOnClient INTEGER, LoadOnServer INTEGER);");
|
||||
CDClientDatabase::ExecuteDML("INSERT INTO ProximityTypes VALUES (2, 'Test Proximity', 10, 1, 1, 1, 1, 0);");
|
||||
CDClientDatabase::ExecuteDML("INSERT INTO ProximityTypes VALUES (3, 'Test Prox Large', 20, 1, 1, 3, 1, 1);");
|
||||
CDClientDatabase::ExecuteDML("INSERT INTO ProximityTypes VALUES (7, 'RocketSign', 30, 1, 1, -1, 1, 0);");
|
||||
CDClientDatabase::ExecuteDML("INSERT INTO ProximityTypes VALUES (8, 'WorldLauncher', 80, 1, 1, 74, 1, 0);");
|
||||
CDClientDatabase::ExecuteDML("INSERT INTO ProximityTypes VALUES (11, 'NoRadius', 0, 1, 1, 0, 1, 1);");
|
||||
auto& rows = CDClientManager::GetEntriesMutable<CDProximityMonitorComponentTable>();
|
||||
rows.push_back({ 3, "2,3", true, true });
|
||||
rows.push_back({ 6, "7,8", true, false });
|
||||
rows.push_back({ 50, "3,11,99", true, true });
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
TearDownDependencies();
|
||||
}
|
||||
};
|
||||
|
||||
// A rocket launch pad's "7,8" are the client's sign and launch proximities, not radii of 7 and 8: nothing for the server
|
||||
TEST_F(ProximityMonitorComponentTests, ClientOnlyProximitiesAreNotMadeOnTheServer) {
|
||||
Entity launchpad(1, info);
|
||||
auto* const proximity = launchpad.AddComponent<ProximityMonitorComponent>(6);
|
||||
proximity->LoadDataFromTemplate();
|
||||
EXPECT_TRUE(proximity->GetProximitiesData().empty());
|
||||
}
|
||||
|
||||
TEST_F(ProximityMonitorComponentTests, ServerProximitiesTakeTheTypesNameAndRadius) {
|
||||
Entity object(2, info);
|
||||
auto* const proximity = object.AddComponent<ProximityMonitorComponent>(3);
|
||||
proximity->LoadDataFromTemplate();
|
||||
const auto& made = proximity->GetProximitiesData();
|
||||
ASSERT_EQ(made.size(), 1u);
|
||||
ASSERT_TRUE(made.contains("Test Prox Large"));
|
||||
|
||||
// A radius of 0 is 30, and a type that does not exist is skipped
|
||||
Entity other(3, info);
|
||||
auto* const otherProximity = other.AddComponent<ProximityMonitorComponent>(50);
|
||||
otherProximity->LoadDataFromTemplate();
|
||||
EXPECT_EQ(otherProximity->GetProximitiesData().size(), 2u);
|
||||
EXPECT_TRUE(otherProximity->GetProximitiesData().contains("NoRadius"));
|
||||
}
|
||||
Reference in New Issue
Block a user