Files
qt5-legatus-legacy/Lts/Plugins/BuildingViewer/Common/BgViewer/viewerCtrl/playercomponent.cpp
T
2026-08-13 18:33:10 +02:00

402 lines
13 KiB
C++
Executable File

#include "playercomponent.h"
#include "iconcomponent.h"
#include "messages.h"
#include <dtEntity/systemmessages.h>
#include <dtEntity/core.h>
#include <dtEntity/mapcomponent.h>
#include <dtEntity/profile.h>
#include <dtEntity/nodemasks.h>
#include <dtEntity/windowinterface.h>
#include <dtEntityOSG/positionattitudetransformcomponent.h>
#include <dtEntityOSG/shadercomponent.h>
#include <dtEntityOSG/transformcomponent.h>
#include <osgDB/ReadFile>
namespace VCtrl
{
////////////////////////////////////////////////////////////////////////////////
struct ShowHidePlayerCommand : public PlayerComponent::Command
{
bool mShow;
ShowHidePlayerCommand(double when, bool show)
: Command(when)
, mShow(show)
{
}
void Execute(PlayerComponent *component) override
{
dtEntityOSG::LayerComponent *lc;
if (component->GetEntity()->GetComponent(lc))
{
lc->SetVisible(mShow);
dtEntity::GetWindowInterface()->RequestRedraw(0);
}
IconComponent *ic;
if (component->GetEntity()->GetComponent(ic))
ic->SetVisible(mShow);
ShowHidePlayerMessage msg;
msg.SetAboutEntityId(component->GetEntity()->GetId());
msg.SetShow(mShow);
component->GetEntity()->GetEntityManager().EmitMessage(msg);
}
};
////////////////////////////////////////////////////////////////////////////////
struct TeleportToTargetCommand : public PlayerComponent::Command
{
osg::Vec3d mGoal;
VCtrl::OBB mOBB;
int mRoomNumber;
std::string mRoomname;
TeleportToTargetCommand(double when, const osg::Vec3d& goal, const VCtrl::OBB& obb, int roomNumber, const std::string& roomname)
: Command(when)
, mGoal(goal)
, mOBB(obb)
, mRoomNumber(roomNumber)
, mRoomname(roomname)
{
}
void Execute(PlayerComponent *component) override
{
dtEntityOSG::TransformComponent *tc = component->GetTransform();
if (tc)
{
tc->SetTranslation(mGoal);
tc->Finished();
}
else
LOG_ERROR("Cannot teleport: no transform component!");
component->PlaceAt(mGoal, mOBB, mRoomNumber, mRoomname);
}
};
////////////////////////////////////////////////////////////////////////////////
struct RemoveShootCommand : public PlayerComponent::Command
{
int mId;
RemoveShootCommand(double when, int32_t id)
: Command(when)
, mId(id)
{}
void Execute(PlayerComponent *component) override
{
dtEntity::EntityManager &em = component->GetEntity()->GetEntityManager();
RemoveShootMessage msg;
msg.SetId(mId);
em.EmitMessage(msg);
}
};
////////////////////////////////////////////////////////////////////////////////
struct ShootCommand : public PlayerComponent::Command
{
int mId;
Vec3d mShooterPos;
Vec3d mTargetPos;
dtEntity::EntityId mShooter;
dtEntity::EntityId mTarget;
int mBuildingIdSrc;
int mRoomNumberSrc;
int mBuildingIdDst;
int mRoomNumberDst;
int mLineType;
float mDuration;
double mSimTimeCreated;
ShootCommand(double when, int id, dtEntity::EntityId shooter, dtEntity::EntityId target,
const Vec3d &shooterPos, const Vec3d &targetPos,
int buildingIdSrc, int roomNumberSrc, int buildingIdDst, int roomNumberDst,
int lineType, float duration)
: Command(when)
, mId(id)
, mShooterPos(shooterPos)
, mTargetPos(targetPos)
, mShooter(shooter)
, mTarget(target)
, mBuildingIdSrc(buildingIdSrc)
, mRoomNumberSrc(roomNumberSrc)
, mBuildingIdDst(buildingIdDst)
, mRoomNumberDst(roomNumberDst)
, mLineType(lineType)
, mDuration(duration)
, mSimTimeCreated(when)
{
}
void Execute(PlayerComponent *component) override
{
dtEntity::EntityManager &em = component->GetEntity()->GetEntityManager();
// check if source/target is visible
dtEntity::Vec3d shooterpos(mShooterPos.x, mShooterPos.y, mShooterPos.z);
dtEntity::Vec3d targetpos(mTargetPos.x, mTargetPos.y, mTargetPos.z);
// draw an arrow
const osg::Vec4 shooterColor = component->GetColor();
dtEntity::GetDebugDrawInterface()->AddLine(shooterpos, targetpos, shooterColor, 2, mDuration, false);
osg::Vec3d edge = shooterpos - targetpos;
edge.normalize();
edge *= 0.5f;
osg::Quat q;
q.makeRotate(osg::PI / 4.0, 0, 0, 1);
osg::Vec3d result = q * edge;
dtEntity::GetDebugDrawInterface()->AddLine(targetpos, targetpos + result, shooterColor, 2, mDuration, false);
q.makeRotate(-osg::PI / 4.0, 0, 0, 1);
result = q * edge;
dtEntity::GetDebugDrawInterface()->AddLine(targetpos, targetpos + result, shooterColor, 2, mDuration, false);
osg::Vec3d left = edge ^ osg::Vec3d(0, 0, 1);
q.makeRotate(osg::PI / 4.0, left[0], left[1], left[2]);
result = q * edge;
dtEntity::GetDebugDrawInterface()->AddLine(targetpos, targetpos + result, shooterColor, 2, mDuration, false);
q.makeRotate(-osg::PI / 4.0, left[0], left[1], left[2]);
result = q * edge;
dtEntity::GetDebugDrawInterface()->AddLine(targetpos, targetpos + result, shooterColor, 2, mDuration, false);
ShootMessage msg;
msg.SetId(mId);
msg.SetShooter(mShooter);
msg.SetShooterPos(osg::Vec3d(mShooterPos.x, mShooterPos.y, mShooterPos.z));
msg.SetTarget(mTarget);
msg.SetTargetPos(osg::Vec3d(mTargetPos.x, mTargetPos.y, mTargetPos.z));
msg.SetBuildingIdSrc(mBuildingIdSrc);
msg.SetRoomNumberSrc(mRoomNumberSrc);
msg.SetBuildingIdDst(mBuildingIdDst);
msg.SetRoomNumberDst(mRoomNumberDst);
msg.SetLineType(mLineType);
msg.SetDuration(mDuration);
msg.SetSimTimeCreated(mSimTimeCreated);
em.EmitMessage(msg);
}
};
////////////////////////////////////////////////////////////////////////////////
const dtEntity::StringId PlayerComponent::TYPE(dtEntity::SID("Player"));
////////////////////////////////////////////////////////////////////////////////
void PlayerComponent::OnAddedToEntity(dtEntity::Entity &entity)
{
mEntity = &entity;
}
////////////////////////////////////////////////////////////////////////////////
void PlayerComponent::OnRemovedFromEntity(dtEntity::Entity &entity)
{
NavMeshGroupChangedMessage msg;
msg.SetPreviousGroupName(dtEntity::GetStringFromSID(mCurrentCellGroup));
msg.SetAboutEntityId(GetEntity()->GetId());
msg.SetGroupName("");
entity.GetEntityManager().EmitMessage(msg);
mEntity = nullptr;
}
////////////////////////////////////////////////////////////////////////////////
dtEntityOSG::TransformComponent *PlayerComponent::GetTransform()
{
assert(mEntity != nullptr);
if (mTransform == nullptr)
{
mEntity->GetComponent(mTransform, true);
assert(mTransform);
}
return mTransform;
}
////////////////////////////////////////////////////////////////////////////////
void PlayerComponent::ExecuteCommands(double timenow)
{
if (mCommands.empty())
return;
double nexttime = timenow;
osg::ref_ptr<Command> execcommand = nullptr;
for (const auto &command : mCommands)
{
if (command->mStartTime < nexttime)
{
execcommand = command;
nexttime = command->mStartTime;
}
}
if (execcommand.valid())
{
mCommands.erase(execcommand);
execcommand->Execute(this);
}
}
////////////////////////////////////////////////////////////////////////////////
void PlayerComponent::PositionOnMesh(const VCtrl::OBB& bb, osg::Vec3d& pos, const std::string& roomname)
{
GetTransform()->SetTranslation(pos);
mPreviousRoom = mCurrentRoom;
mCurrentRoom = dtEntity::SID(roomname);
if (bb.mBuilding != mCurrentCellGroup)
{
NavMeshGroupChangedMessage msg;
msg.SetPreviousGroupName(dtEntity::GetStringFromSID(mCurrentCellGroup));
msg.SetAboutEntityId(GetEntity()->GetId());
msg.SetGroupName(dtEntity::GetStringFromSID(bb.mBuilding));
mCurrentCellGroup = bb.mBuilding;
GetEntity()->GetEntityManager().EmitMessage(msg);
}
}
////////////////////////////////////////////////////////////////////////////////
void PlayerComponent::PlaceAt(const osg::Vec3d &_goal, const VCtrl::OBB &obb, int roomNumber, const std::string &roomname)
{
LOG_DEBUG("PlayerComponent::PlaceAt: " << "mEntity='"<< mEntity << "'"
<< ", _goal: x=" << _goal.x() << " y=" << _goal.y() << " z=" << _goal.z()
<< ", roomNumber="<< roomNumber
<< ", roomname='"<< roomname << "'");
osg::Vec3d pgoal = _goal;
PositionOnMesh(obb, pgoal, roomname);
dtEntity::GetWindowInterface()->RequestRedraw(0);
TransformSendMessage msg;
msg.SetAboutEntity(mEntity->GetId());
msg.SetPosition(pgoal);
msg.SetRoomNumber(roomNumber);
mEntity->GetEntityManager().EmitMessage(msg);
}
////////////////////////////////////////////////////////////////////////////////
void PlayerComponent::SetColor(const osg::Vec4f &color)
{
mColor = color;
}
////////////////////////////////////////////////////////////////////////////////
void PlayerComponent::DeleteQueuedCommands()
{
mCommands.clear();
}
////////////////////////////////////////////////////////////////////////////////
osg::Vec4f PlayerComponent::GetColor() const
{
return mColor;
}
////////////////////////////////////////////////////////////////////////////
const dtEntity::StringId PlayerSystem::TYPE(dtEntity::SID("Player"));
////////////////////////////////////////////////////////////////////////////
PlayerSystem::PlayerSystem(dtEntity::EntityManager &em)
: dtEntity::DefaultEntitySystem<PlayerComponent>(em)
{
mTickFunctor = dtEntity::MessageFunctor(this, &PlayerSystem::OnTick);
em.RegisterForMessages(dtEntity::TickMessage::TYPE, mTickFunctor, dtEntity::FilterOptions::ORDER_LATE, "PlayerSystem::OnTick");
}
////////////////////////////////////////////////////////////////////////////
void PlayerSystem::OnTick(const dtEntity::Message &m)
{
static const dtEntity::StringId PlayerSystemTick = dtEntity::SID("PlayerSystem Tick");
CProfileManager::Start_Profile(PlayerSystemTick);
const dtEntity::TickMessage &msg = static_cast<const dtEntity::TickMessage &>(m);
for (const auto &comp : mComponents)
comp.second->ExecuteCommands(msg.GetSimulationTime());
CProfileManager::Stop_Profile();
}
////////////////////////////////////////////////////////////////////////////
void PlayerSystem::PlayerShoot(int32_t id, dtEntity::EntityId shooterid, dtEntity::EntityId targetid,
const Vec3d &shooterPos, const Vec3d &targetPos,
int buildingIdSrc, int roomNumberSrc, int buildingIdDst, int roomNumberDst,
int lineType, double when, double duration)
{
ComponentStore::iterator shooter = mComponents.find(shooterid);
if (shooter == mComponents.end())
return;
// targetid may be a building
//if (mComponents.find(targetid) == mComponents.end())
// return;
PlayerComponent *shooterc = shooter->second;
shooterc->AddCommand(new ShootCommand(when, id, shooterid, targetid, shooterPos, targetPos, buildingIdSrc, roomNumberSrc, buildingIdDst, roomNumberDst, lineType, duration));
}
////////////////////////////////////////////////////////////////////////////
void PlayerSystem::RemovePlayerShoot(int32_t id, double when)
{
ComponentStore::iterator shooter = mComponents.find(id);
if (shooter == mComponents.end())
return;
PlayerComponent *shooterc = shooter->second;
shooterc->AddCommand(new RemoveShootCommand(when, id));
}
////////////////////////////////////////////////////////////////////////////
void PlayerSystem::ShowHidePlayer(dtEntity::EntityId eid, bool show, double when)
{
ComponentStore::iterator i = mComponents.find(eid);
if (i != mComponents.end())
{
PlayerComponent *player = i->second;
if (when <= 0)
{
IconComponent *ic;
if (player->GetEntity()->GetComponent(ic))
ic->SetVisible(show);
}
else
player->AddCommand(new ShowHidePlayerCommand(when, show));
}
}
////////////////////////////////////////////////////////////////////////////
void PlayerSystem::TeleportToTarget(dtEntity::EntityId id, double when, const osg::Vec3d &goal, const VCtrl::OBB &obb, int roomNumber, const std::string& roomname)
{
LOG_DEBUG("PlayerSystem::TeleportToTarget: " << "id='"<< id << "'"
<< ", when="<< when
<< ", goal: x=" << goal.x() << " y=" << goal.y() << " z=" << goal.z()
<< ", roomNumber="<< roomNumber
<< ", roomname='"<< roomname << "'");
ComponentStore::iterator i = mComponents.find(id);
if (i != mComponents.end())
{
PlayerComponent *player = i->second;
player->AddCommand(new TeleportToTargetCommand(when, goal, obb, roomNumber, roomname));
}
else
{
dtEntityOSG::TransformComponent *pat;
if (GetEntityManager().GetComponent(id, pat, true))
pat->SetTranslation(goal);
}
}
////////////////////////////////////////////////////////////////////////////
void PlayerSystem::DeleteQueuedCommands()
{
for (const auto &comp : mComponents)
comp.second->DeleteQueuedCommands();
}
}