#include "playercomponent.h" #include "iconcomponent.h" #include "messages.h" #include #include #include #include #include #include #include #include #include #include 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 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(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(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(); } }