Destructible objects pt. 2
This commit is contained in:
parent
d6947a79d6
commit
986cbc12a6
@ -28,6 +28,7 @@ set(COMMON_SOURCES
|
||||
"src/game/character_anim_state.hpp"
|
||||
"src/game/character_anim_state.cpp"
|
||||
"src/game/player_input.hpp"
|
||||
"src/game/simple_entity_sync.hpp"
|
||||
"src/game/skeletoninstance.hpp"
|
||||
"src/game/skeletoninstance.cpp"
|
||||
"src/game/transform_node.hpp"
|
||||
@ -79,6 +80,8 @@ set(CLIENT_ONLY_SOURCES
|
||||
"src/gameview/entityview.cpp"
|
||||
"src/gameview/mapinstanceview.hpp"
|
||||
"src/gameview/mapinstanceview.cpp"
|
||||
"src/gameview/simple_entity_view.hpp"
|
||||
"src/gameview/simple_entity_view.cpp"
|
||||
"src/gameview/skinning_ubo.hpp"
|
||||
"src/gameview/skinning_ubo.cpp"
|
||||
"src/gameview/vehicleview.hpp"
|
||||
@ -116,6 +119,8 @@ set(SERVER_ONLY_SOURCES
|
||||
"src/game/character.cpp"
|
||||
"src/game/controllable_character.hpp"
|
||||
"src/game/controllable_character.cpp"
|
||||
"src/game/destroyed_object.hpp"
|
||||
"src/game/destroyed_object.cpp"
|
||||
"src/game/drivable_vehicle.hpp"
|
||||
"src/game/drivable_vehicle.cpp"
|
||||
"src/game/entity.hpp"
|
||||
@ -132,6 +137,8 @@ set(SERVER_ONLY_SOURCES
|
||||
"src/game/player_character.cpp"
|
||||
"src/game/player.hpp"
|
||||
"src/game/player.cpp"
|
||||
"src/game/simple_entity.hpp"
|
||||
"src/game/simple_entity.cpp"
|
||||
"src/game/usable.hpp"
|
||||
"src/game/vehicle.hpp"
|
||||
"src/game/vehicle.cpp"
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::string& filename)
|
||||
{
|
||||
auto model = std::make_shared<Model>();
|
||||
model->name_ = filename; // TODO: name not filename
|
||||
std::vector<glm::vec3> vert_pos; // rember for collision trimesh
|
||||
|
||||
CLIENT_ONLY(MeshBuilder mb(gfx::MF_NONE);)
|
||||
@ -45,7 +46,12 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
|
||||
vert_pos.emplace_back(pos);
|
||||
|
||||
if (temp_hull)
|
||||
temp_hull->addPoint(btVector3(pos.x, pos.y, pos.z), false);
|
||||
{
|
||||
auto offset_pos = pos - model->col_offset_;
|
||||
|
||||
temp_hull->addPoint(btVector3(offset_pos.x, offset_pos.y, offset_pos.z), false);
|
||||
|
||||
}
|
||||
|
||||
model->aabb_.AddPoint(pos);
|
||||
}
|
||||
@ -65,8 +71,17 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
|
||||
|
||||
if (model->cmesh_)
|
||||
{
|
||||
// FIXME: possible index segfault
|
||||
model->cmesh_->AddTriangle(vert_pos[indices[0]], vert_pos[indices[1]], vert_pos[indices[2]]);
|
||||
glm::vec3 p[3];
|
||||
for (size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
size_t index = indices[i];
|
||||
if (index >= vert_pos.size())
|
||||
throw std::runtime_error("Vertex index out of bounds in model");
|
||||
|
||||
p[i] = vert_pos[index] - model->col_offset_;
|
||||
}
|
||||
|
||||
model->cmesh_->AddTriangle(p[0], p[1], p[2]);
|
||||
}
|
||||
}
|
||||
else if (command == "surface")
|
||||
@ -141,6 +156,8 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
|
||||
glm::vec3 scale(trans.scale, sy, sz);
|
||||
trans.scale = 1.0f;
|
||||
|
||||
trans.position -= model->col_offset_; // apply offset
|
||||
|
||||
if (!compound)
|
||||
{
|
||||
compound = std::make_unique<btCompoundShape>();
|
||||
@ -157,6 +174,12 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
|
||||
throw std::runtime_error("Unknown collision shape type: " + shape_type);
|
||||
}
|
||||
}
|
||||
else if (command == "centerofmass")
|
||||
{
|
||||
glm::vec3 com;
|
||||
iss >> com.x >> com.y >> com.z;
|
||||
model->col_offset_ = com;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Unknown command in model file: " + command);
|
||||
|
||||
@ -41,6 +41,9 @@ public:
|
||||
Model() = default;
|
||||
static std::shared_ptr<const Model> LoadFromFile(const std::string& filename);
|
||||
|
||||
const std::string& GetName() const { return name_; }
|
||||
|
||||
const glm::vec3& GetColOffset() const { return col_offset_; }
|
||||
const collision::TriangleMesh* GetColMesh() const { return cmesh_.get(); }
|
||||
btCollisionShape* GetColShape() const { return cshape_.get(); }
|
||||
|
||||
@ -49,6 +52,8 @@ public:
|
||||
const AABB3& GetAABB() const { return aabb_; }
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
glm::vec3 col_offset_ = glm::vec3(0.0f);
|
||||
std::unique_ptr<collision::TriangleMesh> cmesh_;
|
||||
// std::vector<ModelCollisionShape> cshapes_;
|
||||
std::vector<std::unique_ptr<btCollisionShape>> subshapes_;
|
||||
|
||||
22
src/game/destroyed_object.cpp
Normal file
22
src/game/destroyed_object.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include "destroyed_object.hpp"
|
||||
|
||||
game::DestroyedObject::DestroyedObject(World& world, std::unique_ptr<MapObjectCollision> col)
|
||||
: Super(world, col->GetModel()->GetName()), col_(std::move(col))
|
||||
{
|
||||
// remove after 30s
|
||||
Schedule(30000, [this]()
|
||||
{
|
||||
Remove();
|
||||
});
|
||||
}
|
||||
|
||||
void game::DestroyedObject::UpdatePreSync()
|
||||
{
|
||||
if (!col_)
|
||||
return;
|
||||
|
||||
// sync transform with the physics body
|
||||
col_->GetModelTransform(root_.local);
|
||||
|
||||
root_.UpdateMatrix();
|
||||
}
|
||||
22
src/game/destroyed_object.hpp
Normal file
22
src/game/destroyed_object.hpp
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "simple_entity.hpp"
|
||||
#include "mapinstance.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
|
||||
class DestroyedObject : public SimpleEntity
|
||||
{
|
||||
public:
|
||||
using Super = SimpleEntity;
|
||||
|
||||
DestroyedObject(World& world, std::unique_ptr<MapObjectCollision> col);
|
||||
|
||||
virtual void UpdatePreSync() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<MapObjectCollision> col_;
|
||||
};
|
||||
|
||||
} // namespace game
|
||||
@ -89,7 +89,10 @@ game::MapObjectCollision::MapObjectCollision(collision::DynamicsWorld& world,
|
||||
btRigidBody::btRigidBodyConstructionInfo(mass, nullptr, cmesh->GetShape(), local_inertia));
|
||||
}
|
||||
|
||||
body_->setWorldTransform(trans.ToBtTransform());
|
||||
auto offset_trans = trans;
|
||||
offset_trans.position += trans.rotation * model_->GetColOffset();
|
||||
|
||||
body_->setWorldTransform(offset_trans.ToBtTransform());
|
||||
body_->setUserIndex(static_cast<int>(obj_type));
|
||||
body_->setUserPointer(this);
|
||||
|
||||
@ -102,17 +105,28 @@ void game::MapObjectCollision::Break()
|
||||
if (!body_)
|
||||
return;
|
||||
|
||||
// body_->setCollisionFlags(body_->getCollisionFlags() & ~btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||
|
||||
btCollisionShape* shape = body_->getCollisionShape();
|
||||
float mass = 10.0f;
|
||||
btVector3 local_inertia(0, 0, 0);
|
||||
body_->getCollisionShape()->calculateLocalInertia(mass, local_inertia);
|
||||
shape->calculateLocalInertia(mass, local_inertia);
|
||||
|
||||
body_->setMassProps(mass, local_inertia);
|
||||
body_->forceActivationState(ACTIVE_TAG);
|
||||
btTransform trans = body_->getWorldTransform();
|
||||
|
||||
// set to undefined to avoid breaking again
|
||||
// remove old
|
||||
world_.GetBtWorld().removeRigidBody(body_.get());
|
||||
body_.reset();
|
||||
|
||||
// make new
|
||||
body_ = std::make_unique<btRigidBody>(btRigidBody::btRigidBodyConstructionInfo(mass, nullptr, shape, local_inertia));
|
||||
body_->setWorldTransform(trans);
|
||||
body_->setUserIndex(static_cast<int>(collision::OT_UNDEFINED));
|
||||
world_.GetBtWorld().addRigidBody(body_.get());
|
||||
}
|
||||
|
||||
void game::MapObjectCollision::GetModelTransform(Transform& trans) const
|
||||
{
|
||||
trans.SetBtTransform(body_->getWorldTransform());
|
||||
trans.position -= trans.rotation * model_->GetColOffset(); // unapply offset
|
||||
}
|
||||
|
||||
game::MapObjectCollision::~MapObjectCollision()
|
||||
|
||||
@ -23,8 +23,12 @@ public:
|
||||
|
||||
void Break();
|
||||
|
||||
void GetModelTransform(Transform& trans) const;
|
||||
|
||||
const std::shared_ptr<const assets::Model>& GetModel() const { return model_; }
|
||||
btRigidBody& GetBtBody() { return *body_; }
|
||||
net::ObjNum GetNum() const { return num_; }
|
||||
|
||||
|
||||
~MapObjectCollision();
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include "player_character.hpp"
|
||||
#include "npc_character.hpp"
|
||||
#include "drivable_vehicle.hpp"
|
||||
#include "destroyed_object.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
@ -77,6 +78,16 @@ void game::OpenWorld::PlayerLeft(Player& player)
|
||||
RemovePlayerCharacter(player);
|
||||
}
|
||||
|
||||
void game::OpenWorld::DestructibleDestroyed(net::ObjNum num, std::unique_ptr<MapObjectCollision> col)
|
||||
{
|
||||
auto& destroyed_obj = Spawn<DestroyedObject>(std::move(col));
|
||||
|
||||
// Schedule(100000, [this, objnum = num]()
|
||||
// {
|
||||
// RespawnObj(objnum);
|
||||
// });
|
||||
}
|
||||
|
||||
std::optional<std::pair<game::Usable&, const game::UseTarget&>> game::OpenWorld::GetBestUseTarget(const glm::vec3& pos) const
|
||||
{
|
||||
std::optional<std::pair<Usable*, const UseTarget*>> best_target;
|
||||
|
||||
@ -25,6 +25,8 @@ public:
|
||||
virtual void PlayerViewAnglesChanged(Player& player, float yaw, float pitch) override;
|
||||
virtual void PlayerLeft(Player& player) override;
|
||||
|
||||
virtual void DestructibleDestroyed(net::ObjNum num, std::unique_ptr<MapObjectCollision> col) override;
|
||||
|
||||
std::optional<std::pair<Usable&, const UseTarget&>> GetBestUseTarget(const glm::vec3& pos) const;
|
||||
|
||||
private:
|
||||
|
||||
81
src/game/simple_entity.cpp
Normal file
81
src/game/simple_entity.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
#include "simple_entity.hpp"
|
||||
#include "net/utils.hpp"
|
||||
|
||||
game::SimpleEntity::SimpleEntity(World& world, const std::string& modelname) : Super(world, net::ET_SIMPLE), modelname_(modelname)
|
||||
{
|
||||
UpdateSyncState();
|
||||
}
|
||||
|
||||
void game::SimpleEntity::SendInitData(Player& player, net::OutMessage& msg) const
|
||||
{
|
||||
Super::SendInitData(player, msg);
|
||||
|
||||
msg.Write(net::ModelName(modelname_));
|
||||
|
||||
// write state against default
|
||||
static const SimpleEntitySyncState default_state;
|
||||
size_t fields_pos = msg.Reserve<SimpleEntitySyncFieldFlags>();
|
||||
auto fields = WriteState(msg, default_state);
|
||||
msg.WriteAt(fields_pos, fields);
|
||||
}
|
||||
|
||||
void game::SimpleEntity::Update()
|
||||
{
|
||||
Super::Update();
|
||||
|
||||
UpdatePreSync(); // chance to update state before sent
|
||||
|
||||
sync_current_ = 1 - sync_current_;
|
||||
UpdateSyncState();
|
||||
SendUpdateMsg();
|
||||
|
||||
}
|
||||
|
||||
void game::SimpleEntity::UpdateSyncState()
|
||||
{
|
||||
SimpleEntitySyncState& state = sync_[sync_current_];
|
||||
|
||||
net::EncodePosition(root_.local.position, state.pos);
|
||||
net::EncodeRotation(root_.local.rotation, state.rot);
|
||||
}
|
||||
|
||||
game::SimpleEntitySyncFieldFlags game::SimpleEntity::WriteState(net::OutMessage& msg, const SimpleEntitySyncState& base) const
|
||||
{
|
||||
SimpleEntitySyncFieldFlags fields = 0;
|
||||
const SimpleEntitySyncState& curr = sync_[sync_current_];
|
||||
|
||||
if (curr.pos.x.value != base.pos.x.value ||
|
||||
curr.pos.y.value != base.pos.y.value ||
|
||||
curr.pos.z.value != base.pos.z.value)
|
||||
{
|
||||
fields |= SESF_POSITION;
|
||||
|
||||
net::WriteDelta(msg, curr.pos.x, base.pos.x);
|
||||
net::WriteDelta(msg, curr.pos.y, base.pos.y);
|
||||
net::WriteDelta(msg, curr.pos.z, base.pos.z);
|
||||
}
|
||||
|
||||
if (curr.rot.x.value != base.rot.x.value ||
|
||||
curr.rot.y.value != base.rot.y.value ||
|
||||
curr.rot.z.value != base.rot.z.value)
|
||||
{
|
||||
fields |= SESF_ROTATION;
|
||||
|
||||
net::WriteDelta(msg, curr.rot.x, base.rot.x);
|
||||
net::WriteDelta(msg, curr.rot.y, base.rot.y);
|
||||
net::WriteDelta(msg, curr.rot.z, base.rot.z);
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
void game::SimpleEntity::SendUpdateMsg()
|
||||
{
|
||||
auto msg = BeginEntMsg(net::EMSG_UPDATE);
|
||||
|
||||
// write state against previous
|
||||
const SimpleEntitySyncState& prev = sync_[1 - sync_current_];
|
||||
size_t fields_pos = msg.Reserve<SimpleEntitySyncFieldFlags>();
|
||||
auto fields = WriteState(msg, prev);
|
||||
msg.WriteAt(fields_pos, fields);
|
||||
}
|
||||
32
src/game/simple_entity.hpp
Normal file
32
src/game/simple_entity.hpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include "entity.hpp"
|
||||
#include "simple_entity_sync.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
|
||||
class SimpleEntity : public Entity
|
||||
{
|
||||
public:
|
||||
using Super = Entity;
|
||||
|
||||
SimpleEntity(World& world, const std::string& modelname);
|
||||
|
||||
virtual void SendInitData(Player& player, net::OutMessage& msg) const override;
|
||||
virtual void Update() override;
|
||||
|
||||
virtual void UpdatePreSync() {}
|
||||
|
||||
private:
|
||||
void UpdateSyncState();
|
||||
SimpleEntitySyncFieldFlags WriteState(net::OutMessage& msg, const SimpleEntitySyncState& base) const;
|
||||
void SendUpdateMsg();
|
||||
|
||||
private:
|
||||
std::string modelname_;
|
||||
|
||||
SimpleEntitySyncState sync_[2];
|
||||
size_t sync_current_ = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace game
|
||||
23
src/game/simple_entity_sync.hpp
Normal file
23
src/game/simple_entity_sync.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "net/defs.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
|
||||
struct SimpleEntitySyncState
|
||||
{
|
||||
net::PositionQ pos;
|
||||
net::QuatQ rot;
|
||||
};
|
||||
|
||||
using SimpleEntitySyncFieldFlags = uint8_t;
|
||||
|
||||
enum SimpleEntitySyncFieldFlag
|
||||
{
|
||||
SESF_POSITION = 0x01,
|
||||
SESF_ROTATION = 0x02,
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@ -7,7 +7,7 @@
|
||||
#include "utils/allocnum.hpp"
|
||||
#include "collision/object_type.hpp"
|
||||
|
||||
game::World::World(std::string mapname) : map_(*this, std::move(mapname))
|
||||
game::World::World(std::string mapname) : Scheduler(time_ms_), map_(*this, std::move(mapname))
|
||||
{
|
||||
}
|
||||
|
||||
@ -51,6 +51,8 @@ void game::World::Update(int64_t delta_time)
|
||||
|
||||
DetectDestructibleCollisions();
|
||||
|
||||
RunTasks();
|
||||
|
||||
// update entities
|
||||
for (auto it = ents_.begin(); it != ents_.end();)
|
||||
{
|
||||
@ -61,10 +63,13 @@ void game::World::Update(int64_t delta_time)
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void game::World::FinishFrame()
|
||||
{
|
||||
ResetMsg();
|
||||
|
||||
// reset ent msgs
|
||||
for (auto& [entnum, ent] : ents_)
|
||||
{
|
||||
@ -82,6 +87,15 @@ game::Entity* game::World::GetEntity(net::EntNum entnum)
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
void game::World::RespawnObj(net::ObjNum objnum)
|
||||
{
|
||||
if (destroyed_objs_.erase(objnum) > 0)
|
||||
{
|
||||
map_.SpawnObj(objnum);
|
||||
SendObjRespawnedMsg(objnum);
|
||||
}
|
||||
}
|
||||
|
||||
void game::World::DetectDestructibleCollisions()
|
||||
{
|
||||
auto& bt_world = GetBtWorld();
|
||||
@ -110,7 +124,7 @@ void game::World::DetectDestructibleCollisions()
|
||||
|
||||
for (int j = 0; j < contactManifold->getNumContacts(); j++)
|
||||
{
|
||||
const float break_threshold = 3000.0f; // TODO: per-object threshold
|
||||
const float break_threshold = 100.0f; // TODO: per-object threshold
|
||||
|
||||
btManifoldPoint& pt = contactManifold->getContactPoint(j);
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
namespace game
|
||||
{
|
||||
|
||||
class World : public collision::DynamicsWorld, public net::MsgProducer
|
||||
class World : public collision::DynamicsWorld, public net::MsgProducer, public Scheduler
|
||||
{
|
||||
public:
|
||||
World(std::string mapname);
|
||||
@ -46,6 +46,8 @@ public:
|
||||
|
||||
Entity* GetEntity(net::EntNum entnum);
|
||||
|
||||
void RespawnObj(net::ObjNum objnum);
|
||||
|
||||
const assets::Map& GetMap() const { return map_.GetMap(); }
|
||||
const std::string& GetMapName() const { return map_.GetName(); }
|
||||
const std::map<net::EntNum, std::unique_ptr<Entity>>& GetEntities() const { return ents_; }
|
||||
|
||||
108
src/gameview/simple_entity_view.cpp
Normal file
108
src/gameview/simple_entity_view.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
#include "simple_entity_view.hpp"
|
||||
#include "net/defs.hpp"
|
||||
#include "assets/cache.hpp"
|
||||
#include "worldview.hpp"
|
||||
#include "net/utils.hpp"
|
||||
|
||||
game::view::SimpleEntityView::SimpleEntityView(WorldView& world, net::InMessage& msg) : Super(world, msg)
|
||||
{
|
||||
net::ModelName modelname;
|
||||
if (!msg.Read(modelname))
|
||||
throw EntityInitError();
|
||||
|
||||
if (modelname.len > 0)
|
||||
{
|
||||
model_ = assets::CacheManager::GetModel(std::string(modelname));
|
||||
if (!model_)
|
||||
throw EntityInitError();
|
||||
}
|
||||
|
||||
if (!ReadState(msg))
|
||||
throw EntityInitError();
|
||||
|
||||
states_[0] = states_[1]; // lerp from the read state to avoid jump
|
||||
|
||||
radius_ = 20.0f;
|
||||
}
|
||||
|
||||
bool game::view::SimpleEntityView::ProcessMsg(net::EntMsgType type, net::InMessage& msg)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case net::EMSG_UPDATE:
|
||||
return ProcessUpdateMsg(msg);
|
||||
|
||||
default:
|
||||
return Super::ProcessMsg(type, msg);
|
||||
}
|
||||
}
|
||||
|
||||
void game::view::SimpleEntityView::Update(const UpdateInfo& info)
|
||||
{
|
||||
Super::Update(info);
|
||||
|
||||
// interpolate states
|
||||
float tps = 25.0f;
|
||||
float t = (info.time - update_time_) * tps * 0.8f; // assume some jitter, interpolate for longer
|
||||
t = glm::clamp(t, 0.0f, 2.0f);
|
||||
|
||||
root_.local = Transform::Lerp(states_[0].trans, states_[1].trans, t);
|
||||
root_.UpdateMatrix();
|
||||
}
|
||||
|
||||
void game::view::SimpleEntityView::Draw(const DrawArgs& args)
|
||||
{
|
||||
Super::Draw(args);
|
||||
|
||||
if (!model_)
|
||||
return;
|
||||
|
||||
const auto& mesh = *model_->GetMesh();
|
||||
for (const auto& surface : mesh.surfaces)
|
||||
{
|
||||
gfx::DrawSurfaceCmd cmd;
|
||||
cmd.surface = &surface;
|
||||
cmd.matrices = &root_.matrix;
|
||||
args.dlist.AddSurface(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
bool game::view::SimpleEntityView::ReadState(net::InMessage& msg)
|
||||
{
|
||||
update_time_ = world_.GetTime();
|
||||
|
||||
// init lerp start state
|
||||
states_[0].trans = root_.local;
|
||||
|
||||
auto& new_state = states_[1];
|
||||
|
||||
// parse state delta
|
||||
SimpleEntitySyncFieldFlags fields;
|
||||
if (!msg.Read(fields))
|
||||
return false;
|
||||
|
||||
// pos
|
||||
if (fields & SESF_POSITION)
|
||||
{
|
||||
if (!net::ReadDelta(msg, sync_.pos.x) || !net::ReadDelta(msg, sync_.pos.y) || !net::ReadDelta(msg, sync_.pos.z))
|
||||
return false;
|
||||
|
||||
net::DecodePosition(sync_.pos, new_state.trans.position);
|
||||
}
|
||||
|
||||
// rot
|
||||
if (fields & SESF_ROTATION)
|
||||
{
|
||||
if (!net::ReadDelta(msg, sync_.rot.x) || !net::ReadDelta(msg, sync_.rot.y) || !net::ReadDelta(msg, sync_.rot.z))
|
||||
return false;
|
||||
|
||||
net::DecodeRotation(sync_.rot, new_state.trans.rotation);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool game::view::SimpleEntityView::ProcessUpdateMsg(net::InMessage& msg)
|
||||
{
|
||||
return ReadState(msg);
|
||||
}
|
||||
41
src/gameview/simple_entity_view.hpp
Normal file
41
src/gameview/simple_entity_view.hpp
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "assets/model.hpp"
|
||||
#include "entityview.hpp"
|
||||
#include "game/simple_entity_sync.hpp"
|
||||
|
||||
namespace game::view
|
||||
{
|
||||
|
||||
struct SimpleEntityViewState
|
||||
{
|
||||
Transform trans;
|
||||
};
|
||||
|
||||
class SimpleEntityView : public EntityView
|
||||
{
|
||||
public:
|
||||
using Super = EntityView;
|
||||
|
||||
SimpleEntityView(WorldView& world, net::InMessage& msg);
|
||||
|
||||
virtual bool ProcessMsg(net::EntMsgType type, net::InMessage& msg) override;
|
||||
virtual void Update(const UpdateInfo& info) override;
|
||||
virtual void Draw(const DrawArgs& args) override;
|
||||
|
||||
private:
|
||||
bool ReadState(net::InMessage& msg);
|
||||
|
||||
bool ProcessUpdateMsg(net::InMessage& msg);
|
||||
|
||||
private:
|
||||
std::shared_ptr<const assets::Model> model_;
|
||||
|
||||
SimpleEntitySyncState sync_;
|
||||
SimpleEntityViewState states_[2];
|
||||
float update_time_ = 0.0f;
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include "assets/cache.hpp"
|
||||
|
||||
#include "simple_entity_view.hpp"
|
||||
#include "characterview.hpp"
|
||||
#include "vehicleview.hpp"
|
||||
#include "client_session.hpp"
|
||||
@ -123,6 +124,10 @@ bool game::view::WorldView::ProcessEntSpawnMsg(net::InMessage& msg)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case net::ET_SIMPLE:
|
||||
entslot = std::make_unique<SimpleEntityView>(*this, msg);
|
||||
break;
|
||||
|
||||
case net::ET_CHARACTER:
|
||||
entslot = std::make_unique<CharacterView>(*this, msg);
|
||||
break;
|
||||
@ -132,6 +137,7 @@ bool game::view::WorldView::ProcessEntSpawnMsg(net::InMessage& msg)
|
||||
break;
|
||||
|
||||
default:
|
||||
ents_.erase(entnum);
|
||||
return false; // unknown type
|
||||
}
|
||||
|
||||
|
||||
@ -72,9 +72,10 @@ enum EntType : uint8_t
|
||||
{
|
||||
ET_NONE,
|
||||
|
||||
ET_SIMPLE,
|
||||
ET_CHARACTER,
|
||||
ET_VEHICLE,
|
||||
|
||||
|
||||
ET_COUNT,
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user