mirror of
https://github.com/DarkflameUniverse/DarkflameServer
synced 2024-08-30 18:43:58 +00:00
36f7b8a928
Removes the singleton inheritance from dpWorld. Tested that crux prime, nimbus station, avant gardens and nexus tower still use navmeshes and physics and that physics volumes are still collided with.
453 lines
14 KiB
C++
453 lines
14 KiB
C++
/*
|
|
* Darkflame Universe
|
|
* Copyright 2018
|
|
*/
|
|
|
|
#include <sstream>
|
|
#include <iostream>
|
|
|
|
#include "PhantomPhysicsComponent.h"
|
|
#include "Game.h"
|
|
#include "LDFFormat.h"
|
|
#include "Logger.h"
|
|
#include "Entity.h"
|
|
#include "EntityManager.h"
|
|
#include "ControllablePhysicsComponent.h"
|
|
#include "GameMessages.h"
|
|
#include "ePhysicsEffectType.h"
|
|
|
|
#include "CDClientManager.h"
|
|
#include "CDComponentsRegistryTable.h"
|
|
#include "CDPhysicsComponentTable.h"
|
|
#include "dServer.h"
|
|
#include "EntityInfo.h"
|
|
|
|
#include "dpWorld.h"
|
|
#include "dpEntity.h"
|
|
#include "dpShapeBox.h"
|
|
#include "dpShapeSphere.h"
|
|
|
|
PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : PhysicsComponent(parent) {
|
|
m_Position = m_Parent->GetDefaultPosition();
|
|
m_Rotation = m_Parent->GetDefaultRotation();
|
|
m_Scale = m_Parent->GetDefaultScale();
|
|
m_dpEntity = nullptr;
|
|
|
|
m_EffectInfoDirty = false;
|
|
|
|
m_IsPhysicsEffectActive = false;
|
|
m_EffectType = ePhysicsEffectType::PUSH;
|
|
m_DirectionalMultiplier = 0.0f;
|
|
|
|
m_MinMax = false;
|
|
m_Min = 0;
|
|
m_Max = 1;
|
|
|
|
m_IsDirectional = false;
|
|
m_Direction = NiPoint3(); // * m_DirectionalMultiplier
|
|
|
|
if (m_Parent->GetVar<bool>(u"create_physics")) {
|
|
CreatePhysics();
|
|
}
|
|
|
|
if (m_Parent->GetVar<bool>(u"respawnVol")) {
|
|
m_IsRespawnVolume = true;
|
|
}
|
|
|
|
if (m_IsRespawnVolume) {
|
|
{
|
|
auto respawnString = std::stringstream(m_Parent->GetVarAsString(u"rspPos"));
|
|
|
|
std::string segment;
|
|
std::vector<std::string> seglist;
|
|
|
|
while (std::getline(respawnString, segment, '\x1f')) {
|
|
seglist.push_back(segment);
|
|
}
|
|
|
|
m_RespawnPos = NiPoint3(std::stof(seglist[0]), std::stof(seglist[1]), std::stof(seglist[2]));
|
|
}
|
|
|
|
{
|
|
auto respawnString = std::stringstream(m_Parent->GetVarAsString(u"rspRot"));
|
|
|
|
std::string segment;
|
|
std::vector<std::string> seglist;
|
|
|
|
while (std::getline(respawnString, segment, '\x1f')) {
|
|
seglist.push_back(segment);
|
|
}
|
|
|
|
m_RespawnRot = NiQuaternion(std::stof(seglist[0]), std::stof(seglist[1]), std::stof(seglist[2]), std::stof(seglist[3]));
|
|
}
|
|
}
|
|
|
|
// HF - RespawnPoints. Legacy respawn entity.
|
|
if (m_Parent->GetLOT() == 4945) {
|
|
m_IsRespawnVolume = true;
|
|
m_RespawnPos = m_Position;
|
|
m_RespawnRot = m_Rotation;
|
|
}
|
|
|
|
/*
|
|
for (LDFBaseData* data : settings) {
|
|
if (data) {
|
|
if (data->GetKey() == u"create_physics") {
|
|
if (bool(std::stoi(data->GetValueAsString()))) {
|
|
CreatePhysics(settings);
|
|
}
|
|
}
|
|
|
|
if (data->GetKey() == u"respawnVol") {
|
|
if (bool(std::stoi(data->GetValueAsString()))) {
|
|
m_IsRespawnVolume = true;
|
|
}
|
|
}
|
|
|
|
if (m_IsRespawnVolume) {
|
|
if (data->GetKey() == u"rspPos") {
|
|
//Joy, we get to split strings!
|
|
std::stringstream test(data->GetValueAsString());
|
|
std::string segment;
|
|
std::vector<std::string> seglist;
|
|
|
|
while (std::getline(test, segment, '\x1f')) {
|
|
seglist.push_back(segment);
|
|
}
|
|
|
|
m_RespawnPos = NiPoint3(std::stof(seglist[0]), std::stof(seglist[1]), std::stof(seglist[2]));
|
|
}
|
|
|
|
if (data->GetKey() == u"rspRot") {
|
|
//Joy, we get to split strings!
|
|
std::stringstream test(data->GetValueAsString());
|
|
std::string segment;
|
|
std::vector<std::string> seglist;
|
|
|
|
while (std::getline(test, segment, '\x1f')) {
|
|
seglist.push_back(segment);
|
|
}
|
|
|
|
m_RespawnRot = NiQuaternion(std::stof(seglist[0]), std::stof(seglist[1]), std::stof(seglist[2]), std::stof(seglist[3]));
|
|
}
|
|
}
|
|
|
|
if (m_Parent->GetLOT() == 4945) // HF - RespawnPoints
|
|
{
|
|
m_IsRespawnVolume = true;
|
|
m_RespawnPos = m_Position;
|
|
m_RespawnRot = m_Rotation;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
if (!m_HasCreatedPhysics) {
|
|
CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
|
|
auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), eReplicaComponentType::PHANTOM_PHYSICS);
|
|
|
|
CDPhysicsComponentTable* physComp = CDClientManager::Instance().GetTable<CDPhysicsComponentTable>();
|
|
|
|
if (physComp == nullptr) return;
|
|
|
|
auto* info = physComp->GetByID(componentID);
|
|
if (info == nullptr || info->physicsAsset == "" || info->physicsAsset == "NO_PHYSICS") return;
|
|
|
|
//temp test
|
|
if (info->physicsAsset == "miscellaneous\\misc_phys_10x1x5.hkx") {
|
|
m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 10.0f, 5.0f, 1.0f);
|
|
|
|
m_dpEntity->SetScale(m_Scale);
|
|
m_dpEntity->SetRotation(m_Rotation);
|
|
m_dpEntity->SetPosition(m_Position);
|
|
|
|
dpWorld::AddEntity(m_dpEntity);
|
|
} else if (info->physicsAsset == "miscellaneous\\misc_phys_640x640.hkx") {
|
|
// Move this down by 13.521004 units so it is still effectively at the same height as before
|
|
m_Position = m_Position - NiPoint3::UNIT_Y * 13.521004f;
|
|
// TODO Fix physics simulation to do simulation at high velocities due to bullet through paper problem...
|
|
m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 1638.4f, 13.521004f * 2.0f, 1638.4f);
|
|
|
|
m_dpEntity->SetScale(m_Scale);
|
|
m_dpEntity->SetRotation(m_Rotation);
|
|
m_dpEntity->SetPosition(m_Position);
|
|
|
|
dpWorld::AddEntity(m_dpEntity);
|
|
} else if (info->physicsAsset == "env\\trigger_wall_tall.hkx") {
|
|
m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 10.0f, 25.0f, 1.0f);
|
|
m_dpEntity->SetScale(m_Scale);
|
|
m_dpEntity->SetRotation(m_Rotation);
|
|
m_dpEntity->SetPosition(m_Position);
|
|
dpWorld::AddEntity(m_dpEntity);
|
|
} else if (info->physicsAsset == "env\\env_gen_placeholderphysics.hkx") {
|
|
m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 20.0f, 20.0f, 20.0f);
|
|
m_dpEntity->SetScale(m_Scale);
|
|
m_dpEntity->SetRotation(m_Rotation);
|
|
m_dpEntity->SetPosition(m_Position);
|
|
dpWorld::AddEntity(m_dpEntity);
|
|
} else if (info->physicsAsset == "env\\POI_trigger_wall.hkx") {
|
|
m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 1.0f, 12.5f, 20.0f); // Not sure what the real size is
|
|
m_dpEntity->SetScale(m_Scale);
|
|
m_dpEntity->SetRotation(m_Rotation);
|
|
m_dpEntity->SetPosition(m_Position);
|
|
dpWorld::AddEntity(m_dpEntity);
|
|
} else if (info->physicsAsset == "env\\NG_NinjaGo\\env_ng_gen_gate_chamber_puzzle_ceiling_tile_falling_phantom.hkx") {
|
|
m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 18.0f, 5.0f, 15.0f);
|
|
m_dpEntity->SetScale(m_Scale);
|
|
m_dpEntity->SetRotation(m_Rotation);
|
|
m_dpEntity->SetPosition(m_Position + m_Rotation.GetForwardVector() * 7.5f);
|
|
dpWorld::AddEntity(m_dpEntity);
|
|
} else if (info->physicsAsset == "env\\NG_NinjaGo\\ng_flamejet_brick_phantom.HKX") {
|
|
m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 1.0f, 1.0f, 12.0f);
|
|
m_dpEntity->SetScale(m_Scale);
|
|
m_dpEntity->SetRotation(m_Rotation);
|
|
m_dpEntity->SetPosition(m_Position + m_Rotation.GetForwardVector() * 6.0f);
|
|
dpWorld::AddEntity(m_dpEntity);
|
|
} else if (info->physicsAsset == "env\\Ring_Trigger.hkx") {
|
|
m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 6.0f, 6.0f, 6.0f);
|
|
m_dpEntity->SetScale(m_Scale);
|
|
m_dpEntity->SetRotation(m_Rotation);
|
|
m_dpEntity->SetPosition(m_Position);
|
|
dpWorld::AddEntity(m_dpEntity);
|
|
} else if (info->physicsAsset == "env\\vfx_propertyImaginationBall.hkx") {
|
|
m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 4.5f);
|
|
m_dpEntity->SetScale(m_Scale);
|
|
m_dpEntity->SetRotation(m_Rotation);
|
|
m_dpEntity->SetPosition(m_Position);
|
|
dpWorld::AddEntity(m_dpEntity);
|
|
} else if (info->physicsAsset == "env\\env_won_fv_gas-blocking-volume.hkx") {
|
|
m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 390.496826f, 111.467964f, 600.821534f, true);
|
|
m_dpEntity->SetScale(m_Scale);
|
|
m_dpEntity->SetRotation(m_Rotation);
|
|
m_Position.y -= (111.467964f * m_Scale) / 2;
|
|
m_dpEntity->SetPosition(m_Position);
|
|
dpWorld::AddEntity(m_dpEntity);
|
|
} else {
|
|
//LOG("This one is supposed to have %s", info->physicsAsset.c_str());
|
|
|
|
//add fallback cube:
|
|
m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 2.0f, 2.0f, 2.0f);
|
|
m_dpEntity->SetScale(m_Scale);
|
|
m_dpEntity->SetRotation(m_Rotation);
|
|
m_dpEntity->SetPosition(m_Position);
|
|
dpWorld::AddEntity(m_dpEntity);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
PhantomPhysicsComponent::~PhantomPhysicsComponent() {
|
|
if (m_dpEntity) {
|
|
dpWorld::RemoveEntity(m_dpEntity);
|
|
}
|
|
}
|
|
|
|
void PhantomPhysicsComponent::CreatePhysics() {
|
|
unsigned char alpha;
|
|
unsigned char red;
|
|
unsigned char green;
|
|
unsigned char blue;
|
|
int type = -1;
|
|
float x = 0.0f;
|
|
float y = 0.0f;
|
|
float z = 0.0f;
|
|
float width = 0.0f; //aka "radius"
|
|
float height = 0.0f;
|
|
|
|
if (m_Parent->HasVar(u"primitiveModelType")) {
|
|
type = m_Parent->GetVar<int32_t>(u"primitiveModelType");
|
|
x = m_Parent->GetVar<float>(u"primitiveModelValueX");
|
|
y = m_Parent->GetVar<float>(u"primitiveModelValueY");
|
|
z = m_Parent->GetVar<float>(u"primitiveModelValueZ");
|
|
} else {
|
|
CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
|
|
auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), eReplicaComponentType::PHANTOM_PHYSICS);
|
|
|
|
CDPhysicsComponentTable* physComp = CDClientManager::Instance().GetTable<CDPhysicsComponentTable>();
|
|
|
|
if (physComp == nullptr) return;
|
|
|
|
auto info = physComp->GetByID(componentID);
|
|
|
|
if (info == nullptr) return;
|
|
|
|
type = info->pcShapeType;
|
|
width = info->playerRadius;
|
|
height = info->playerHeight;
|
|
}
|
|
|
|
switch (type) {
|
|
case 1: { //Make a new box shape
|
|
NiPoint3 boxSize(x, y, z);
|
|
if (x == 0.0f) {
|
|
//LU has some weird values, so I think it's best to scale them down a bit
|
|
if (height < 0.5f) height = 2.0f;
|
|
if (width < 0.5f) width = 2.0f;
|
|
|
|
//Scale them:
|
|
width = width * m_Scale;
|
|
height = height * m_Scale;
|
|
|
|
boxSize = NiPoint3(width, height, width);
|
|
}
|
|
|
|
m_dpEntity = new dpEntity(m_Parent->GetObjectID(), boxSize);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!m_dpEntity) return;
|
|
|
|
m_dpEntity->SetPosition({ m_Position.x, m_Position.y - (height / 2), m_Position.z });
|
|
|
|
dpWorld::AddEntity(m_dpEntity);
|
|
|
|
m_HasCreatedPhysics = true;
|
|
}
|
|
|
|
void PhantomPhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
|
PhysicsComponent::Serialize(outBitStream, bIsInitialUpdate);
|
|
|
|
outBitStream->Write(m_EffectInfoDirty || bIsInitialUpdate);
|
|
if (m_EffectInfoDirty || bIsInitialUpdate) {
|
|
outBitStream->Write(m_IsPhysicsEffectActive);
|
|
|
|
if (m_IsPhysicsEffectActive) {
|
|
outBitStream->Write(m_EffectType);
|
|
outBitStream->Write(m_DirectionalMultiplier);
|
|
|
|
// forgive me father for i have sinned
|
|
outBitStream->Write0();
|
|
//outBitStream->Write(m_MinMax);
|
|
//if (m_MinMax) {
|
|
//outBitStream->Write(m_Min);
|
|
//outBitStream->Write(m_Max);
|
|
//}
|
|
|
|
outBitStream->Write(m_IsDirectional);
|
|
if (m_IsDirectional) {
|
|
outBitStream->Write(m_Direction.x);
|
|
outBitStream->Write(m_Direction.y);
|
|
outBitStream->Write(m_Direction.z);
|
|
}
|
|
}
|
|
|
|
m_EffectInfoDirty = false;
|
|
}
|
|
}
|
|
|
|
// Even if we were to implement Friction server side,
|
|
// it also defaults to 1.0f in the last argument, so we dont need two functions to do the same thing.
|
|
void ApplyCollisionEffect(const LWOOBJID& target, const ePhysicsEffectType effectType, const float effectScale) {
|
|
switch (effectType) {
|
|
case ePhysicsEffectType::GRAVITY_SCALE: {
|
|
auto* targetEntity = Game::entityManager->GetEntity(target);
|
|
if (targetEntity) {
|
|
auto* controllablePhysicsComponent = targetEntity->GetComponent<ControllablePhysicsComponent>();
|
|
// dont want to apply an effect to nothing.
|
|
if (!controllablePhysicsComponent) return;
|
|
controllablePhysicsComponent->SetGravityScale(effectScale);
|
|
GameMessages::SendSetGravityScale(target, effectScale, targetEntity->GetSystemAddress());
|
|
}
|
|
}
|
|
// The other types are not handled by the server
|
|
case ePhysicsEffectType::ATTRACT:
|
|
case ePhysicsEffectType::FRICTION:
|
|
case ePhysicsEffectType::PUSH:
|
|
case ePhysicsEffectType::REPULSE:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void PhantomPhysicsComponent::Update(float deltaTime) {
|
|
if (!m_dpEntity) return;
|
|
|
|
//Process enter events
|
|
for (auto en : m_dpEntity->GetNewObjects()) {
|
|
if (!en) continue;
|
|
ApplyCollisionEffect(en->GetObjectID(), m_EffectType, m_DirectionalMultiplier);
|
|
m_Parent->OnCollisionPhantom(en->GetObjectID());
|
|
|
|
//If we are a respawn volume, inform the client:
|
|
if (m_IsRespawnVolume) {
|
|
auto entity = Game::entityManager->GetEntity(en->GetObjectID());
|
|
|
|
if (entity) {
|
|
GameMessages::SendPlayerReachedRespawnCheckpoint(entity, m_RespawnPos, m_RespawnRot);
|
|
entity->SetRespawnPos(m_RespawnPos);
|
|
entity->SetRespawnRot(m_RespawnRot);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Process exit events
|
|
for (auto en : m_dpEntity->GetRemovedObjects()) {
|
|
if (!en) continue;
|
|
ApplyCollisionEffect(en->GetObjectID(), m_EffectType, 1.0f);
|
|
m_Parent->OnCollisionLeavePhantom(en->GetObjectID());
|
|
}
|
|
}
|
|
|
|
void PhantomPhysicsComponent::SetDirection(const NiPoint3& pos) {
|
|
m_Direction = pos;
|
|
m_Direction.x *= m_DirectionalMultiplier;
|
|
m_Direction.y *= m_DirectionalMultiplier;
|
|
m_Direction.z *= m_DirectionalMultiplier;
|
|
|
|
m_EffectInfoDirty = true;
|
|
m_IsDirectional = true;
|
|
}
|
|
|
|
void PhantomPhysicsComponent::SpawnVertices() {
|
|
if (!m_dpEntity) return;
|
|
|
|
LOG("%llu", m_Parent->GetObjectID());
|
|
auto box = static_cast<dpShapeBox*>(m_dpEntity->GetShape());
|
|
for (auto vert : box->GetVertices()) {
|
|
LOG("%f, %f, %f", vert.x, vert.y, vert.z);
|
|
|
|
EntityInfo info;
|
|
info.lot = 33;
|
|
info.pos = vert;
|
|
info.spawner = nullptr;
|
|
info.spawnerID = m_Parent->GetObjectID();
|
|
info.spawnerNodeID = 0;
|
|
|
|
Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr);
|
|
Game::entityManager->ConstructEntity(newEntity);
|
|
}
|
|
}
|
|
|
|
void PhantomPhysicsComponent::SetDirectionalMultiplier(float mul) {
|
|
m_DirectionalMultiplier = mul;
|
|
m_EffectInfoDirty = true;
|
|
}
|
|
|
|
void PhantomPhysicsComponent::SetEffectType(ePhysicsEffectType type) {
|
|
m_EffectType = type;
|
|
m_EffectInfoDirty = true;
|
|
}
|
|
|
|
void PhantomPhysicsComponent::SetMin(uint32_t min) {
|
|
m_Min = min;
|
|
m_MinMax = true;
|
|
m_EffectInfoDirty = true;
|
|
}
|
|
|
|
void PhantomPhysicsComponent::SetMax(uint32_t max) {
|
|
m_Max = max;
|
|
m_MinMax = true;
|
|
m_EffectInfoDirty = true;
|
|
}
|
|
|
|
void PhantomPhysicsComponent::SetPosition(const NiPoint3& pos) {
|
|
PhysicsComponent::SetPosition(pos);
|
|
if (m_dpEntity) m_dpEntity->SetPosition(pos);
|
|
}
|
|
|
|
void PhantomPhysicsComponent::SetRotation(const NiQuaternion& rot) {
|
|
PhysicsComponent::SetRotation(rot);
|
|
if (m_dpEntity) m_dpEntity->SetRotation(rot);
|
|
}
|