402 lines
13 KiB
C++
Executable File
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();
|
|
}
|
|
|
|
}
|