mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-11-14 07:47:13 +00:00
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>
148 lines
5.8 KiB
C++
148 lines
5.8 KiB
C++
#include "ProximityMonitorComponent.h"
|
|
#include "CDClientManager.h"
|
|
#include "CDClientDatabase.h"
|
|
#include "CDProximityMonitorComponentTable.h"
|
|
#include "GameMessages.h"
|
|
#include "dZoneManager.h"
|
|
#include "ControllablePhysicsComponent.h"
|
|
#include "EntityManager.h"
|
|
#include "SimplePhysicsComponent.h"
|
|
#include "Amf3.h"
|
|
#include "dpShapeSphere.h"
|
|
|
|
const std::unordered_set<LWOOBJID> ProximityMonitorComponent::m_EmptyObjectSet = {};
|
|
|
|
ProximityMonitorComponent::ProximityMonitorComponent(Entity* parent, const int32_t componentID, int radiusSmall, int radiusLarge) : Component(parent, componentID) {
|
|
if (radiusSmall != -1 && radiusLarge != -1) {
|
|
SetProximityRadius(radiusSmall, "rocketSmall");
|
|
SetProximityRadius(radiusLarge, "rocketLarge");
|
|
}
|
|
RegisterMsg(&ProximityMonitorComponent::OnGetObjectReportInfo);
|
|
}
|
|
|
|
// 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() || !proxCompData[0].LoadOnServer) return;
|
|
|
|
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() {
|
|
for (const auto& en : m_ProximitiesData) {
|
|
if (!en.second) continue;
|
|
|
|
dpWorld::RemoveEntity(en.second);
|
|
}
|
|
|
|
m_ProximitiesData.clear();
|
|
}
|
|
|
|
void ProximityMonitorComponent::SetProximityRadius(float proxRadius, const std::string& name, const uint32_t collisionGroup) {
|
|
// A proximity set again under its name replaces the old one
|
|
UnsetProximityRadius(name);
|
|
dpEntity* en = new dpEntity(m_Parent->GetObjectID(), proxRadius);
|
|
en->SetCollisionGroup(collisionGroup);
|
|
en->SetPosition(m_Parent->GetPosition());
|
|
|
|
dpWorld::AddEntity(en);
|
|
m_ProximitiesData.insert(std::make_pair(name, en));
|
|
}
|
|
|
|
void ProximityMonitorComponent::SetProximityRadius(dpEntity* entity, const std::string& name) {
|
|
UnsetProximityRadius(name);
|
|
dpWorld::AddEntity(entity);
|
|
entity->SetPosition(m_Parent->GetPosition());
|
|
m_ProximitiesData.insert(std::make_pair(name, entity));
|
|
}
|
|
|
|
void ProximityMonitorComponent::UnsetProximityRadius(const std::string& name) {
|
|
const auto iter = m_ProximitiesData.find(name);
|
|
if (iter == m_ProximitiesData.end()) return;
|
|
if (iter->second) dpWorld::RemoveEntity(iter->second);
|
|
m_ProximitiesData.erase(iter);
|
|
}
|
|
|
|
const std::unordered_set<LWOOBJID>& ProximityMonitorComponent::GetProximityObjects(const std::string& name) const {
|
|
const auto iter = m_ProximitiesData.find(name);
|
|
|
|
if (iter == m_ProximitiesData.cend()) {
|
|
return m_EmptyObjectSet;
|
|
}
|
|
|
|
return iter->second->GetCurrentlyCollidingObjects();
|
|
}
|
|
|
|
bool ProximityMonitorComponent::IsInProximity(const std::string& name, LWOOBJID objectID) {
|
|
const auto iter = m_ProximitiesData.find(name);
|
|
|
|
if (iter == m_ProximitiesData.cend()) {
|
|
return false;
|
|
}
|
|
|
|
const auto& collisions = iter->second->GetCurrentlyCollidingObjects();
|
|
|
|
return collisions.contains(objectID);
|
|
}
|
|
|
|
bool ProximityMonitorComponent::OnGetObjectReportInfo(GameMessages::GetObjectReportInfo& reportInfo) {
|
|
auto& proxInfo = reportInfo.info->PushDebug("Proximity Monitor");
|
|
for (const auto& [name, entity] : m_ProximitiesData) {
|
|
if (!entity) continue;
|
|
auto& proxAmf = proxInfo.PushDebug(name);
|
|
const auto* const shape = entity->GetShape();
|
|
if (shape && shape->GetShapeType() == dpShapeType::Sphere) {
|
|
const auto* const sphere = static_cast<const dpShapeSphere*>(shape);
|
|
proxAmf.PushDebug<AMFDoubleValue>("Radius") = sphere->GetRadius();
|
|
}
|
|
proxAmf.PushDebug<AMFBoolValue>("Sleeping") = entity->GetSleeping();
|
|
proxAmf.PushDebug<AMFDoubleValue>("Scale") = entity->GetScale();
|
|
proxAmf.PushDebug<AMFBoolValue>("Gargantuan") = entity->GetIsGargantuan();
|
|
proxAmf.PushDebug<AMFBoolValue>("Static") = entity->GetIsStatic();
|
|
proxAmf.PushDebug("Position").PushDebug(entity->GetPosition());
|
|
proxAmf.PushDebug("Rotation").PushDebug(entity->GetRotation());
|
|
auto& collidingAmf = proxAmf.PushDebug("Colliding Objects");
|
|
int i = 1;
|
|
for (const auto& colliding : entity->GetCurrentlyCollidingObjects()) {
|
|
collidingAmf.PushDebug<AMFStringValue>(std::to_string(i++), "LWOOBJID") = std::to_string(colliding);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ProximityMonitorComponent::Run(float deltaTime) {
|
|
for (const auto& prox : m_ProximitiesData) {
|
|
if (!prox.second) continue;
|
|
|
|
prox.second->SetPosition(m_Parent->GetPosition());
|
|
//Process enter events
|
|
for (const auto id : prox.second->GetNewObjects()) {
|
|
m_Parent->OnCollisionProximity(id, prox.first, "ENTER");
|
|
}
|
|
|
|
//Process exit events
|
|
for (const auto id : prox.second->GetRemovedObjects()) {
|
|
m_Parent->OnCollisionProximity(id, prox.first, "LEAVE");
|
|
}
|
|
}
|
|
}
|
|
|