Destructible objs pt. 1
This commit is contained in:
parent
0e7e80ee79
commit
d6947a79d6
@ -77,6 +77,8 @@ set(CLIENT_ONLY_SOURCES
|
|||||||
"src/gameview/client_session.cpp"
|
"src/gameview/client_session.cpp"
|
||||||
"src/gameview/entityview.hpp"
|
"src/gameview/entityview.hpp"
|
||||||
"src/gameview/entityview.cpp"
|
"src/gameview/entityview.cpp"
|
||||||
|
"src/gameview/mapinstanceview.hpp"
|
||||||
|
"src/gameview/mapinstanceview.cpp"
|
||||||
"src/gameview/skinning_ubo.hpp"
|
"src/gameview/skinning_ubo.hpp"
|
||||||
"src/gameview/skinning_ubo.cpp"
|
"src/gameview/skinning_ubo.cpp"
|
||||||
"src/gameview/vehicleview.hpp"
|
"src/gameview/vehicleview.hpp"
|
||||||
@ -120,6 +122,8 @@ set(SERVER_ONLY_SOURCES
|
|||||||
"src/game/entity.cpp"
|
"src/game/entity.cpp"
|
||||||
"src/game/game.hpp"
|
"src/game/game.hpp"
|
||||||
"src/game/game.cpp"
|
"src/game/game.cpp"
|
||||||
|
"src/game/mapinstance.hpp"
|
||||||
|
"src/game/mapinstance.cpp"
|
||||||
"src/game/npc_character.hpp"
|
"src/game/npc_character.hpp"
|
||||||
"src/game/npc_character.cpp"
|
"src/game/npc_character.cpp"
|
||||||
"src/game/openworld.hpp"
|
"src/game/openworld.hpp"
|
||||||
|
|||||||
@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#define GLM_ENABLE_EXPERIMENTAL
|
|
||||||
#include <glm/gtx/norm.hpp>
|
|
||||||
|
|
||||||
#include "cache.hpp"
|
#include "cache.hpp"
|
||||||
#include "cmdfile.hpp"
|
#include "cmdfile.hpp"
|
||||||
#include "utils/files.hpp"
|
#include "utils/files.hpp"
|
||||||
@ -65,7 +62,7 @@ std::shared_ptr<const assets::Map> assets::Map::LoadFromFile(const std::string&
|
|||||||
if (!chunk)
|
if (!chunk)
|
||||||
throw std::runtime_error("static in map without chunk");
|
throw std::runtime_error("static in map without chunk");
|
||||||
|
|
||||||
ChunkStaticObject obj;
|
MapStaticObject obj;
|
||||||
std::string model_name;
|
std::string model_name;
|
||||||
iss >> model_name;
|
iss >> model_name;
|
||||||
|
|
||||||
@ -90,7 +87,8 @@ std::shared_ptr<const assets::Map> assets::Map::LoadFromFile(const std::string&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk->objs.push_back(std::move(obj));
|
map->objs_.push_back(std::move(obj));
|
||||||
|
chunk->num_objs++;
|
||||||
}
|
}
|
||||||
else if (command == "chunk")
|
else if (command == "chunk")
|
||||||
{
|
{
|
||||||
@ -99,6 +97,8 @@ std::shared_ptr<const assets::Map> assets::Map::LoadFromFile(const std::string&
|
|||||||
iss >> coord.x >> coord.y;
|
iss >> coord.x >> coord.y;
|
||||||
iss >> chunk->aabb.min.x >> chunk->aabb.min.y >> chunk->aabb.min.z;
|
iss >> chunk->aabb.min.x >> chunk->aabb.min.y >> chunk->aabb.min.z;
|
||||||
iss >> chunk->aabb.max.x >> chunk->aabb.max.y >> chunk->aabb.max.z;
|
iss >> chunk->aabb.max.x >> chunk->aabb.max.y >> chunk->aabb.max.z;
|
||||||
|
|
||||||
|
chunk->first_obj = map->objs_.size();
|
||||||
}
|
}
|
||||||
else if (command == "surface")
|
else if (command == "surface")
|
||||||
{
|
{
|
||||||
@ -177,63 +177,3 @@ const assets::MapGraph* assets::Map::GetGraph(const std::string& name) const
|
|||||||
return &it->second;
|
return &it->second;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CLIENT
|
|
||||||
void assets::Map::Draw(const game::view::DrawArgs& args) const
|
|
||||||
{
|
|
||||||
if (!basemodel_ || !basemodel_->GetMesh())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const auto& mesh = *basemodel_->GetMesh();
|
|
||||||
|
|
||||||
const float max_dist = args.render_distance + 200.0f;
|
|
||||||
const float max_dist2 = max_dist * max_dist;
|
|
||||||
|
|
||||||
for (auto& chunk : chunks_)
|
|
||||||
{
|
|
||||||
glm::vec3 center = (chunk.aabb.min + chunk.aabb.max) * 0.5f;
|
|
||||||
if (glm::distance2(args.eye, center) > max_dist2)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!args.frustum.IsAABBVisible(chunk.aabb))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
DrawChunk(args, mesh, chunk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void assets::Map::DrawChunk(const game::view::DrawArgs& args, const Mesh& basemesh, const Chunk& chunk) const
|
|
||||||
{
|
|
||||||
for (const auto& surface_range : chunk.surfaces)
|
|
||||||
{
|
|
||||||
auto& surface = basemesh.surfaces[surface_range.idx];
|
|
||||||
|
|
||||||
gfx::DrawSurfaceCmd cmd;
|
|
||||||
cmd.surface = &surface;
|
|
||||||
cmd.first = surface_range.first;
|
|
||||||
cmd.count = surface_range.count;
|
|
||||||
args.dlist.AddSurface(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& obj : chunk.objs)
|
|
||||||
{
|
|
||||||
if (!obj.model || !obj.model->GetMesh())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!args.frustum.IsAABBVisible(obj.aabb))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const auto& surfaces = obj.model->GetMesh()->surfaces;
|
|
||||||
|
|
||||||
for (const auto& surface : surfaces)
|
|
||||||
{
|
|
||||||
gfx::DrawSurfaceCmd cmd;
|
|
||||||
cmd.surface = &surface;
|
|
||||||
cmd.matrices = &obj.node.matrix;
|
|
||||||
// cmd.color_mod = glm::vec4(obj.color, 1.0f);
|
|
||||||
args.dlist.AddSurface(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // CLIENT
|
|
||||||
|
|||||||
@ -9,14 +9,10 @@
|
|||||||
#include "model.hpp"
|
#include "model.hpp"
|
||||||
#include "utils/aabb.hpp"
|
#include "utils/aabb.hpp"
|
||||||
|
|
||||||
#ifdef CLIENT
|
|
||||||
#include "gameview/draw_args.hpp"
|
|
||||||
#endif // CLIENT
|
|
||||||
|
|
||||||
namespace assets
|
namespace assets
|
||||||
{
|
{
|
||||||
|
|
||||||
struct ChunkStaticObject
|
struct MapStaticObject
|
||||||
{
|
{
|
||||||
game::TransformNode node;
|
game::TransformNode node;
|
||||||
AABB3 aabb;
|
AABB3 aabb;
|
||||||
@ -37,7 +33,8 @@ struct Chunk
|
|||||||
{
|
{
|
||||||
AABB3 aabb;
|
AABB3 aabb;
|
||||||
std::vector<ChunkSurfaceRange> surfaces;
|
std::vector<ChunkSurfaceRange> surfaces;
|
||||||
std::vector<ChunkStaticObject> objs;
|
size_t first_obj = 0;
|
||||||
|
size_t num_objs = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MapGraphNode
|
struct MapGraphNode
|
||||||
@ -61,16 +58,13 @@ public:
|
|||||||
|
|
||||||
const std::shared_ptr<const Model>& GetBaseModel() const { return basemodel_; }
|
const std::shared_ptr<const Model>& GetBaseModel() const { return basemodel_; }
|
||||||
const std::vector<Chunk>& GetChunks() const { return chunks_; }
|
const std::vector<Chunk>& GetChunks() const { return chunks_; }
|
||||||
|
const std::vector<MapStaticObject>& GetStaticObjects() const { return objs_; }
|
||||||
const MapGraph* GetGraph(const std::string& name) const;
|
const MapGraph* GetGraph(const std::string& name) const;
|
||||||
|
|
||||||
CLIENT_ONLY(void Draw(const game::view::DrawArgs& args) const;)
|
|
||||||
|
|
||||||
private:
|
|
||||||
CLIENT_ONLY(void DrawChunk(const game::view::DrawArgs& args, const Mesh& basemesh, const Chunk& chunk) const;)
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<const Model> basemodel_;
|
std::shared_ptr<const Model> basemodel_;
|
||||||
std::vector<Chunk> chunks_;
|
std::vector<Chunk> chunks_;
|
||||||
|
std::vector<MapStaticObject> objs_;
|
||||||
std::map<std::string, MapGraph> graphs_;
|
std::map<std::string, MapGraph> graphs_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
|
|||||||
|
|
||||||
CLIENT_ONLY(MeshBuilder mb(gfx::MF_NONE);)
|
CLIENT_ONLY(MeshBuilder mb(gfx::MF_NONE);)
|
||||||
std::unique_ptr<btConvexHullShape> temp_hull;
|
std::unique_ptr<btConvexHullShape> temp_hull;
|
||||||
|
std::unique_ptr<btCompoundShape> compound;
|
||||||
|
|
||||||
LoadCMDFile(filename, [&](const std::string& command, std::istringstream& iss) {
|
LoadCMDFile(filename, [&](const std::string& command, std::istringstream& iss) {
|
||||||
if (command == "v")
|
if (command == "v")
|
||||||
@ -129,6 +130,33 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
|
|||||||
model->skeleton_ = CacheManager::GetSkeleton("data/" + skel_name + ".sk");
|
model->skeleton_ = CacheManager::GetSkeleton("data/" + skel_name + ".sk");
|
||||||
CLIENT_ONLY(mb.SetMeshFlag(gfx::MF_SKELETAL));
|
CLIENT_ONLY(mb.SetMeshFlag(gfx::MF_SKELETAL));
|
||||||
}
|
}
|
||||||
|
else if (command == "col")
|
||||||
|
{
|
||||||
|
std::string shape_type;
|
||||||
|
Transform trans;
|
||||||
|
float sy, sz;
|
||||||
|
iss >> shape_type;
|
||||||
|
ParseTransform(iss, trans);
|
||||||
|
iss >> sy >> sz;
|
||||||
|
glm::vec3 scale(trans.scale, sy, sz);
|
||||||
|
trans.scale = 1.0f;
|
||||||
|
|
||||||
|
if (!compound)
|
||||||
|
{
|
||||||
|
compound = std::make_unique<btCompoundShape>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shape_type == "box")
|
||||||
|
{
|
||||||
|
auto box_shape = std::make_unique<btBoxShape>(btVector3(scale.x, scale.y, scale.z));
|
||||||
|
compound->addChildShape(trans.ToBtTransform(), box_shape.get());
|
||||||
|
model->subshapes_.push_back(std::move(box_shape));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Unknown collision shape type: " + shape_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Unknown command in model file: " + command);
|
throw std::runtime_error("Unknown command in model file: " + command);
|
||||||
@ -157,6 +185,10 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
|
|||||||
|
|
||||||
model->cshape_ = std::make_unique<btConvexHullShape>((btScalar*)shape_hull->getVertexPointer(), shape_hull->numVertices(), sizeof(btVector3));
|
model->cshape_ = std::make_unique<btConvexHullShape>((btScalar*)shape_hull->getVertexPointer(), shape_hull->numVertices(), sizeof(btVector3));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
model->cshape_ = std::move(compound);
|
||||||
|
}
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,6 +51,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
std::unique_ptr<collision::TriangleMesh> cmesh_;
|
std::unique_ptr<collision::TriangleMesh> cmesh_;
|
||||||
// std::vector<ModelCollisionShape> cshapes_;
|
// std::vector<ModelCollisionShape> cshapes_;
|
||||||
|
std::vector<std::unique_ptr<btCollisionShape>> subshapes_;
|
||||||
std::unique_ptr<btCollisionShape> cshape_;
|
std::unique_ptr<btCollisionShape> cshape_;
|
||||||
|
|
||||||
std::shared_ptr<const Skeleton> skeleton_;
|
std::shared_ptr<const Skeleton> skeleton_;
|
||||||
|
|||||||
@ -10,47 +10,3 @@ collision::DynamicsWorld::DynamicsWorld()
|
|||||||
|
|
||||||
bt_broadphase_.getOverlappingPairCache()->setInternalGhostPairCallback(&bt_ghost_pair_cb_);
|
bt_broadphase_.getOverlappingPairCache()->setInternalGhostPairCallback(&bt_ghost_pair_cb_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void collision::DynamicsWorld::AddMapCollision(std::shared_ptr<const assets::Map> map)
|
|
||||||
{
|
|
||||||
if (!map)
|
|
||||||
return;
|
|
||||||
|
|
||||||
map_ = std::move(map);
|
|
||||||
|
|
||||||
// add basemodel
|
|
||||||
const auto& basemodel = map_->GetBaseModel();
|
|
||||||
if (basemodel)
|
|
||||||
{
|
|
||||||
Transform identity;
|
|
||||||
AddModelInstance(*basemodel, identity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add static objects
|
|
||||||
for (const auto& chunks = map_->GetChunks(); const auto& chunk : chunks)
|
|
||||||
{
|
|
||||||
for (const auto& obj : chunk.objs)
|
|
||||||
{
|
|
||||||
AddModelInstance(*obj.model, obj.node.local);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void collision::DynamicsWorld::AddModelInstance(const assets::Model& model, const Transform& trans)
|
|
||||||
{
|
|
||||||
if (auto cmesh = model.GetColMesh(); cmesh)
|
|
||||||
{
|
|
||||||
// create trimesh object
|
|
||||||
btRigidBody::btRigidBodyConstructionInfo rbInfo(0.0f, nullptr, cmesh->GetShape(), btVector3(0,0,0));
|
|
||||||
auto obj = std::make_unique<btRigidBody>(rbInfo);
|
|
||||||
|
|
||||||
// set transform
|
|
||||||
obj->setWorldTransform(trans.ToBtTransform());
|
|
||||||
|
|
||||||
// add to world
|
|
||||||
bt_world_.addRigidBody(obj.get());
|
|
||||||
static_objs_.emplace_back(std::move(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: add shape
|
|
||||||
}
|
|
||||||
|
|||||||
@ -10,38 +10,16 @@
|
|||||||
namespace collision
|
namespace collision
|
||||||
{
|
{
|
||||||
|
|
||||||
// struct StaticObjectInstance
|
|
||||||
// {
|
|
||||||
// std::unique_ptr<btCollisionShape> shape;
|
|
||||||
// btRigidBody body;
|
|
||||||
|
|
||||||
// StaticObjectInstance(std::unique_ptr<btCollisionShape> shape) : body()
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DynamicsWorld
|
class DynamicsWorld
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DynamicsWorld();
|
DynamicsWorld();
|
||||||
|
|
||||||
void AddMapCollision(std::shared_ptr<const assets::Map> map);
|
|
||||||
|
|
||||||
btDynamicsWorld& GetBtWorld() { return bt_world_; }
|
btDynamicsWorld& GetBtWorld() { return bt_world_; }
|
||||||
const btDynamicsWorld& GetBtWorld() const { return bt_world_; }
|
const btDynamicsWorld& GetBtWorld() const { return bt_world_; }
|
||||||
btVehicleRaycaster& GetVehicleRaycaster() { return bt_veh_raycaster_; }
|
btVehicleRaycaster& GetVehicleRaycaster() { return bt_veh_raycaster_; }
|
||||||
|
|
||||||
private:
|
|
||||||
void AddModelInstance(const assets::Model& model, const Transform& trans);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// this is BEFORE bt_world_!!!
|
|
||||||
std::shared_ptr<const assets::Map> map_;
|
|
||||||
std::vector<std::unique_ptr<btRigidBody>> static_objs_;
|
|
||||||
// ^-----
|
|
||||||
|
|
||||||
btDefaultCollisionConfiguration bt_cfg_;
|
btDefaultCollisionConfiguration bt_cfg_;
|
||||||
btCollisionDispatcher bt_dispatcher_;
|
btCollisionDispatcher bt_dispatcher_;
|
||||||
btGhostPairCallback bt_ghost_pair_cb_;
|
btGhostPairCallback bt_ghost_pair_cb_;
|
||||||
|
|||||||
16
src/collision/object_type.hpp
Normal file
16
src/collision/object_type.hpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace collision
|
||||||
|
{
|
||||||
|
|
||||||
|
enum ObjectType
|
||||||
|
{
|
||||||
|
OT_UNDEFINED = 0,
|
||||||
|
OT_MAP_STATIC = 1,
|
||||||
|
OT_MAP_DESTRUCTIBLE = 2,
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
122
src/game/mapinstance.cpp
Normal file
122
src/game/mapinstance.cpp
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
#include "mapinstance.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "assets/cache.hpp"
|
||||||
|
#include "collision/object_type.hpp"
|
||||||
|
|
||||||
|
game::MapInstance::MapInstance(collision::DynamicsWorld& world, std::string mapname)
|
||||||
|
: world_(world), mapname_(std::move(mapname))
|
||||||
|
{
|
||||||
|
map_ = assets::CacheManager::GetMap("data/" + mapname_ + ".map");
|
||||||
|
|
||||||
|
// add basemodel col
|
||||||
|
const auto& basemodel = map_->GetBaseModel();
|
||||||
|
if (basemodel)
|
||||||
|
{
|
||||||
|
Transform identity;
|
||||||
|
basemodel_col_ = std::make_unique<MapObjectCollision>(world_, basemodel, 0, identity, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add static objects
|
||||||
|
const auto& objs = map_->GetStaticObjects();
|
||||||
|
obj_cols_.resize(objs.size());
|
||||||
|
for (size_t i = 0; i < objs.size(); ++i)
|
||||||
|
{
|
||||||
|
SpawnObj(static_cast<net::ObjNum>(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void game::MapInstance::SpawnObj(net::ObjNum objnum)
|
||||||
|
{
|
||||||
|
if (objnum >= obj_cols_.size())
|
||||||
|
throw std::runtime_error("Invalid object number");
|
||||||
|
|
||||||
|
size_t i = static_cast<size_t>(objnum);
|
||||||
|
|
||||||
|
if (obj_cols_[i])
|
||||||
|
return; // already spawned
|
||||||
|
|
||||||
|
const auto& objs = map_->GetStaticObjects();
|
||||||
|
obj_cols_[i] = std::make_unique<MapObjectCollision>(world_, objs[i].model, static_cast<net::ObjNum>(i), objs[i].node.local, MAPOBJ_DESTRUCTIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<game::MapObjectCollision> game::MapInstance::DestroyObj(net::ObjNum objnum)
|
||||||
|
{
|
||||||
|
size_t i = static_cast<size_t>(objnum);
|
||||||
|
if (i >= obj_cols_.size())
|
||||||
|
throw std::runtime_error("Invalid object number");
|
||||||
|
|
||||||
|
auto obj = std::move(obj_cols_[i]);
|
||||||
|
|
||||||
|
if (obj)
|
||||||
|
{
|
||||||
|
obj->Break();
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
game::MapObjectCollision::MapObjectCollision(collision::DynamicsWorld& world,
|
||||||
|
std::shared_ptr<const assets::Model> model, net::ObjNum num,
|
||||||
|
const Transform& trans, MapObjectCollisionFlags flags)
|
||||||
|
: world_(world), model_(std::move(model)), num_(num)
|
||||||
|
{
|
||||||
|
auto cshape = model_->GetColShape();
|
||||||
|
auto cmesh = model_->GetColMesh();
|
||||||
|
|
||||||
|
const bool destructible = (flags & MAPOBJ_DESTRUCTIBLE) != 0 && cshape != nullptr;
|
||||||
|
|
||||||
|
collision::ObjectType obj_type = collision::OT_MAP_STATIC;
|
||||||
|
|
||||||
|
btVector3 local_inertia(0, 0, 0);
|
||||||
|
float mass = 0.0f;
|
||||||
|
|
||||||
|
if (destructible)
|
||||||
|
{
|
||||||
|
obj_type = collision::OT_MAP_DESTRUCTIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefer simple cshape which allow destruction
|
||||||
|
if (cshape)
|
||||||
|
{
|
||||||
|
body_ = std::make_unique<btRigidBody>(
|
||||||
|
btRigidBody::btRigidBodyConstructionInfo(mass, nullptr, cshape, local_inertia));
|
||||||
|
}
|
||||||
|
else if (cmesh)
|
||||||
|
{
|
||||||
|
body_ = std::make_unique<btRigidBody>(
|
||||||
|
btRigidBody::btRigidBodyConstructionInfo(mass, nullptr, cmesh->GetShape(), local_inertia));
|
||||||
|
}
|
||||||
|
|
||||||
|
body_->setWorldTransform(trans.ToBtTransform());
|
||||||
|
body_->setUserIndex(static_cast<int>(obj_type));
|
||||||
|
body_->setUserPointer(this);
|
||||||
|
|
||||||
|
// world_.GetBtWorld().addRigidBody(body_.get(), btBroadphaseProxy::StaticFilter, btBroadphaseProxy::AllFilter);
|
||||||
|
world_.GetBtWorld().addRigidBody(body_.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void game::MapObjectCollision::Break()
|
||||||
|
{
|
||||||
|
if (!body_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// body_->setCollisionFlags(body_->getCollisionFlags() & ~btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||||
|
|
||||||
|
float mass = 10.0f;
|
||||||
|
btVector3 local_inertia(0, 0, 0);
|
||||||
|
body_->getCollisionShape()->calculateLocalInertia(mass, local_inertia);
|
||||||
|
|
||||||
|
body_->setMassProps(mass, local_inertia);
|
||||||
|
body_->forceActivationState(ACTIVE_TAG);
|
||||||
|
|
||||||
|
// set to undefined to avoid breaking again
|
||||||
|
body_->setUserIndex(static_cast<int>(collision::OT_UNDEFINED));
|
||||||
|
}
|
||||||
|
|
||||||
|
game::MapObjectCollision::~MapObjectCollision()
|
||||||
|
{
|
||||||
|
if (body_)
|
||||||
|
world_.GetBtWorld().removeRigidBody(body_.get());
|
||||||
|
}
|
||||||
62
src/game/mapinstance.hpp
Normal file
62
src/game/mapinstance.hpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "assets/map.hpp"
|
||||||
|
#include "collision/dynamicsworld.hpp"
|
||||||
|
#include "net/defs.hpp"
|
||||||
|
|
||||||
|
namespace game
|
||||||
|
{
|
||||||
|
|
||||||
|
using MapObjectCollisionFlags = uint32_t;
|
||||||
|
|
||||||
|
enum MapObjectCollisionFlag : MapObjectCollisionFlags
|
||||||
|
{
|
||||||
|
MAPOBJ_DESTRUCTIBLE = 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
|
class MapObjectCollision
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MapObjectCollision(collision::DynamicsWorld& world, std::shared_ptr<const assets::Model> model,
|
||||||
|
net::ObjNum num, const Transform& trans, MapObjectCollisionFlags flags);
|
||||||
|
DELETE_COPY_MOVE(MapObjectCollision)
|
||||||
|
|
||||||
|
void Break();
|
||||||
|
|
||||||
|
btRigidBody& GetBtBody() { return *body_; }
|
||||||
|
net::ObjNum GetNum() const { return num_; }
|
||||||
|
|
||||||
|
~MapObjectCollision();
|
||||||
|
|
||||||
|
private:
|
||||||
|
collision::DynamicsWorld& world_;
|
||||||
|
std::shared_ptr<const assets::Model> model_;
|
||||||
|
net::ObjNum num_;
|
||||||
|
std::unique_ptr<btRigidBody> body_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MapInstance
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MapInstance(collision::DynamicsWorld& world, std::string mapname);
|
||||||
|
|
||||||
|
const assets::Map& GetMap() const { return *map_; }
|
||||||
|
const std::string& GetName() const { return mapname_; }
|
||||||
|
|
||||||
|
void SpawnObj(net::ObjNum objnum);
|
||||||
|
std::unique_ptr<MapObjectCollision> DestroyObj(net::ObjNum objnum);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
private:
|
||||||
|
collision::DynamicsWorld& world_;
|
||||||
|
std::string mapname_;
|
||||||
|
std::shared_ptr<const assets::Map> map_;
|
||||||
|
|
||||||
|
std::unique_ptr<MapObjectCollision> basemodel_col_;
|
||||||
|
std::vector<std::unique_ptr<MapObjectCollision>> obj_cols_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,6 +1,5 @@
|
|||||||
#include "openworld.hpp"
|
#include "openworld.hpp"
|
||||||
|
|
||||||
#include <coroutine>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "player.hpp"
|
#include "player.hpp"
|
||||||
@ -24,6 +23,9 @@ game::OpenWorld::OpenWorld() : World("openworld")
|
|||||||
{
|
{
|
||||||
SpawnBot();
|
SpawnBot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto& veh = Spawn<game::DrivableVehicle>("twingo", glm::vec3{0.8f, 0.1f, 0.1f});
|
||||||
|
veh.SetPosition({110.0f, 100.0f, 5.0f});
|
||||||
}
|
}
|
||||||
|
|
||||||
void game::OpenWorld::Update(int64_t delta_time)
|
void game::OpenWorld::Update(int64_t delta_time)
|
||||||
|
|||||||
@ -38,15 +38,7 @@ void game::Player::Update()
|
|||||||
|
|
||||||
if (world_)
|
if (world_)
|
||||||
{
|
{
|
||||||
if (cam_ent_)
|
SendWorldUpdateMsg();
|
||||||
{
|
|
||||||
auto cam_ent = world_->GetEntity(cam_ent_);
|
|
||||||
if (cam_ent)
|
|
||||||
{
|
|
||||||
cull_pos_ = cam_ent->GetRoot().GetGlobalPosition();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SyncEntities();
|
SyncEntities();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,11 +82,30 @@ void game::Player::SendWorldMsg()
|
|||||||
{
|
{
|
||||||
MSGDEBUG(std::cout << "seding CHWORLD" << std::endl;)
|
MSGDEBUG(std::cout << "seding CHWORLD" << std::endl;)
|
||||||
auto msg = BeginMsg(net::MSG_CHWORLD);
|
auto msg = BeginMsg(net::MSG_CHWORLD);
|
||||||
msg.Write(net::MapName(world_->GetMapName()));
|
world_->SendInitData(*this, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void game::Player::SendWorldUpdateMsg()
|
||||||
|
{
|
||||||
|
if (!world_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto msg = BeginMsg(); // no CMD here, included in world payload
|
||||||
|
msg.Write(world_->GetMsg());
|
||||||
}
|
}
|
||||||
|
|
||||||
void game::Player::SyncEntities()
|
void game::Player::SyncEntities()
|
||||||
{
|
{
|
||||||
|
// update cull pos
|
||||||
|
if (cam_ent_)
|
||||||
|
{
|
||||||
|
auto cam_ent = world_->GetEntity(cam_ent_);
|
||||||
|
if (cam_ent)
|
||||||
|
{
|
||||||
|
cull_pos_ = cam_ent->GetRoot().GetGlobalPosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const auto& ents = world_->GetEntities();
|
const auto& ents = world_->GetEntities();
|
||||||
|
|
||||||
auto ent_it = ents.begin();
|
auto ent_it = ents.begin();
|
||||||
|
|||||||
@ -37,7 +37,9 @@ public:
|
|||||||
~Player();
|
~Player();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// world sync
|
||||||
void SendWorldMsg();
|
void SendWorldMsg();
|
||||||
|
void SendWorldUpdateMsg();
|
||||||
|
|
||||||
// entities sync
|
// entities sync
|
||||||
void SyncEntities();
|
void SyncEntities();
|
||||||
|
|||||||
@ -89,7 +89,7 @@ game::Vehicle::Vehicle(World& world, std::string model_name, const glm::vec3& co
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto& bt_world = world_.GetBtWorld();
|
auto& bt_world = world_.GetBtWorld();
|
||||||
bt_world.addRigidBody(body_.get());
|
bt_world.addRigidBody(body_.get(), btBroadphaseProxy::DefaultFilter, btBroadphaseProxy::AllFilter);
|
||||||
bt_world.addAction(vehicle_.get());
|
bt_world.addAction(vehicle_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,25 @@
|
|||||||
#include "world.hpp"
|
#include "world.hpp"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "assets/cache.hpp"
|
#include "assets/cache.hpp"
|
||||||
#include "utils/allocnum.hpp"
|
#include "utils/allocnum.hpp"
|
||||||
|
#include "collision/object_type.hpp"
|
||||||
|
|
||||||
game::World::World(std::string mapname) : mapname_(std::move(mapname))
|
game::World::World(std::string mapname) : map_(*this, std::move(mapname))
|
||||||
{
|
{
|
||||||
map_ = assets::CacheManager::GetMap("data/" + mapname_ + ".map");
|
}
|
||||||
AddMapCollision(map_);
|
|
||||||
|
void game::World::SendInitData(Player& player, net::OutMessage& msg)
|
||||||
|
{
|
||||||
|
msg.Write(net::MapName(map_.GetName()));
|
||||||
|
|
||||||
|
msg.Write<net::ObjCount>(destroyed_objs_.size());
|
||||||
|
for (auto objnum : destroyed_objs_)
|
||||||
|
{
|
||||||
|
msg.Write(objnum);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
net::EntNum game::World::GetNewEntnum()
|
net::EntNum game::World::GetNewEntnum()
|
||||||
@ -38,6 +49,8 @@ void game::World::Update(int64_t delta_time)
|
|||||||
// GetBtWorld().stepSimulation(delta_s, 1, delta_s);
|
// GetBtWorld().stepSimulation(delta_s, 1, delta_s);
|
||||||
GetBtWorld().stepSimulation(delta_s, 2, delta_s * 0.5f);
|
GetBtWorld().stepSimulation(delta_s, 2, delta_s * 0.5f);
|
||||||
|
|
||||||
|
DetectDestructibleCollisions();
|
||||||
|
|
||||||
// update entities
|
// update entities
|
||||||
for (auto it = ents_.begin(); it != ents_.end();)
|
for (auto it = ents_.begin(); it != ents_.end();)
|
||||||
{
|
{
|
||||||
@ -68,3 +81,80 @@ game::Entity* game::World::GetEntity(net::EntNum entnum)
|
|||||||
|
|
||||||
return it->second.get();
|
return it->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void game::World::DetectDestructibleCollisions()
|
||||||
|
{
|
||||||
|
auto& bt_world = GetBtWorld();
|
||||||
|
int numManifolds = bt_world.getDispatcher()->getNumManifolds();
|
||||||
|
|
||||||
|
static std::vector<net::ObjNum> to_destroy;
|
||||||
|
to_destroy.clear();
|
||||||
|
|
||||||
|
// std::cout << "Checking " << numManifolds << " manifolds for destructible collisions..." << std::endl;
|
||||||
|
for (int i = 0; i < numManifolds; i++)
|
||||||
|
{
|
||||||
|
btPersistentManifold* contactManifold = bt_world.getDispatcher()->getManifoldByIndexInternal(i);
|
||||||
|
|
||||||
|
const btRigidBody* bodyA = static_cast<const btRigidBody*>(contactManifold->getBody0());
|
||||||
|
const btRigidBody* bodyB = static_cast<const btRigidBody*>(contactManifold->getBody1());
|
||||||
|
|
||||||
|
const btRigidBody* destructibleBody = nullptr;
|
||||||
|
|
||||||
|
if (bodyA->getUserIndex() == collision::OT_MAP_DESTRUCTIBLE)
|
||||||
|
destructibleBody = bodyA;
|
||||||
|
else if (bodyB->getUserIndex() == collision::OT_MAP_DESTRUCTIBLE)
|
||||||
|
destructibleBody = bodyB;
|
||||||
|
|
||||||
|
if (!destructibleBody)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int j = 0; j < contactManifold->getNumContacts(); j++)
|
||||||
|
{
|
||||||
|
const float break_threshold = 3000.0f; // TODO: per-object threshold
|
||||||
|
|
||||||
|
btManifoldPoint& pt = contactManifold->getContactPoint(j);
|
||||||
|
|
||||||
|
if (pt.getAppliedImpulse() > break_threshold)
|
||||||
|
{
|
||||||
|
std::cout << "Destructible collision detected: impulse = " << pt.getAppliedImpulse() << std::endl;
|
||||||
|
|
||||||
|
MapObjectCollision* obj_col = static_cast<MapObjectCollision*>(destructibleBody->getUserPointer());
|
||||||
|
to_destroy.push_back(obj_col->GetNum());
|
||||||
|
|
||||||
|
const btRigidBody* otherBody = (destructibleBody == bodyA) ? bodyB : bodyA;
|
||||||
|
btRigidBody* otherBodyNonConst = const_cast<btRigidBody*>(otherBody);
|
||||||
|
otherBodyNonConst->applyCentralImpulse(pt.m_normalWorldOnB * pt.getAppliedImpulse() * 0.5f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// destroy objs outside the loop to avoid corruption of the manifold list
|
||||||
|
for (auto objnum : to_destroy)
|
||||||
|
{
|
||||||
|
DestroyObject(objnum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void game::World::DestroyObject(net::ObjNum objnum)
|
||||||
|
{
|
||||||
|
SendObjDestroyedMsg(objnum);
|
||||||
|
destroyed_objs_.insert(objnum);
|
||||||
|
|
||||||
|
auto col = map_.DestroyObj(objnum);
|
||||||
|
if (col)
|
||||||
|
{
|
||||||
|
DestructibleDestroyed(objnum, std::move(col));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void game::World::SendObjDestroyedMsg(net::ObjNum objnum)
|
||||||
|
{
|
||||||
|
auto msg = BeginMsg(net::MSG_OBJDESTROY);
|
||||||
|
msg.Write(objnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void game::World::SendObjRespawnedMsg(net::ObjNum objnum)
|
||||||
|
{
|
||||||
|
auto msg = BeginMsg(net::MSG_OBJRESPAWN);
|
||||||
|
msg.Write(objnum);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <concepts>
|
#include <concepts>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include "assets/map.hpp"
|
#include "mapinstance.hpp"
|
||||||
#include "collision/dynamicsworld.hpp"
|
#include "collision/dynamicsworld.hpp"
|
||||||
#include "entity.hpp"
|
#include "entity.hpp"
|
||||||
#include "net/defs.hpp"
|
#include "net/defs.hpp"
|
||||||
@ -11,12 +12,14 @@
|
|||||||
namespace game
|
namespace game
|
||||||
{
|
{
|
||||||
|
|
||||||
class World : public collision::DynamicsWorld
|
class World : public collision::DynamicsWorld, public net::MsgProducer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
World(std::string mapname);
|
World(std::string mapname);
|
||||||
DELETE_COPY_MOVE(World)
|
DELETE_COPY_MOVE(World)
|
||||||
|
|
||||||
|
void SendInitData(Player& player, net::OutMessage& msg);
|
||||||
|
|
||||||
// spawn entity of type T
|
// spawn entity of type T
|
||||||
template <std::derived_from<Entity> T, typename... TArgs>
|
template <std::derived_from<Entity> T, typename... TArgs>
|
||||||
T& Spawn(TArgs&&... args)
|
T& Spawn(TArgs&&... args)
|
||||||
@ -39,18 +42,29 @@ public:
|
|||||||
virtual void PlayerViewAnglesChanged(Player& player, float yaw, float pitch) {}
|
virtual void PlayerViewAnglesChanged(Player& player, float yaw, float pitch) {}
|
||||||
virtual void PlayerLeft(Player& player) {}
|
virtual void PlayerLeft(Player& player) {}
|
||||||
|
|
||||||
|
virtual void DestructibleDestroyed(net::ObjNum num, std::unique_ptr<MapObjectCollision> col) {}
|
||||||
|
|
||||||
Entity* GetEntity(net::EntNum entnum);
|
Entity* GetEntity(net::EntNum entnum);
|
||||||
|
|
||||||
const assets::Map& GetMap() const { return *map_; }
|
const assets::Map& GetMap() const { return map_.GetMap(); }
|
||||||
const std::string& GetMapName() const { return mapname_; }
|
const std::string& GetMapName() const { return map_.GetName(); }
|
||||||
const std::map<net::EntNum, std::unique_ptr<Entity>>& GetEntities() const { return ents_; }
|
const std::map<net::EntNum, std::unique_ptr<Entity>>& GetEntities() const { return ents_; }
|
||||||
const int64_t& GetTime() const { return time_ms_; }
|
const int64_t& GetTime() const { return time_ms_; }
|
||||||
|
|
||||||
virtual ~World() = default;
|
virtual ~World() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<const assets::Map> map_;
|
void DetectDestructibleCollisions();
|
||||||
std::string mapname_;
|
|
||||||
|
void DestroyObject(net::ObjNum objnum);
|
||||||
|
|
||||||
|
void SendObjDestroyedMsg(net::ObjNum objnum);
|
||||||
|
void SendObjRespawnedMsg(net::ObjNum objnum);
|
||||||
|
|
||||||
|
private:
|
||||||
|
MapInstance map_;
|
||||||
|
std::set<net::ObjNum> destroyed_objs_;
|
||||||
|
|
||||||
std::map<net::EntNum, std::unique_ptr<Entity>> ents_;
|
std::map<net::EntNum, std::unique_ptr<Entity>> ents_;
|
||||||
net::EntNum last_entnum_ = 0;
|
net::EntNum last_entnum_ = 0;
|
||||||
|
|
||||||
|
|||||||
@ -117,12 +117,14 @@ audio::Master& game::view::ClientSession::GetAudioMaster() const
|
|||||||
|
|
||||||
bool game::view::ClientSession::ProcessWorldMsg(net::InMessage& msg)
|
bool game::view::ClientSession::ProcessWorldMsg(net::InMessage& msg)
|
||||||
{
|
{
|
||||||
net::MapName mapname;
|
try
|
||||||
if (!msg.Read(mapname))
|
{
|
||||||
|
world_ = std::make_unique<WorldView>(*this, msg);
|
||||||
|
}
|
||||||
|
catch (const EntityInitError&)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
// TODO: pass mapname
|
|
||||||
world_ = std::make_unique<WorldView>(*this);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
94
src/gameview/mapinstanceview.cpp
Normal file
94
src/gameview/mapinstanceview.cpp
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#include "mapinstanceview.hpp"
|
||||||
|
#include "assets/cache.hpp"
|
||||||
|
|
||||||
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
#include <glm/gtx/norm.hpp>
|
||||||
|
|
||||||
|
game::view::MapInstanceView::MapInstanceView(const std::string& map_name)
|
||||||
|
{
|
||||||
|
map_ = assets::CacheManager::GetMap("data/" + map_name + ".map");
|
||||||
|
|
||||||
|
objs_visible_.resize(map_->GetStaticObjects().size(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void game::view::MapInstanceView::Draw(const game::view::DrawArgs& args) const
|
||||||
|
{
|
||||||
|
const auto& basemodel = map_->GetBaseModel();
|
||||||
|
|
||||||
|
if (!basemodel || !basemodel->GetMesh())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto& mesh = *basemodel->GetMesh();
|
||||||
|
|
||||||
|
const float max_dist = args.render_distance + 200.0f;
|
||||||
|
const float max_dist2 = max_dist * max_dist;
|
||||||
|
|
||||||
|
for (const auto& chunks = map_->GetChunks(); const auto& chunk : chunks)
|
||||||
|
{
|
||||||
|
glm::vec3 center = (chunk.aabb.min + chunk.aabb.max) * 0.5f;
|
||||||
|
if (glm::distance2(args.eye, center) > max_dist2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!args.frustum.IsAABBVisible(chunk.aabb))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
DrawChunk(args, mesh, chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void game::view::MapInstanceView::EnableObj(net::ObjNum num, bool enable)
|
||||||
|
{
|
||||||
|
size_t i = static_cast<size_t>(num);
|
||||||
|
if (i >= objs_visible_.size())
|
||||||
|
return;
|
||||||
|
|
||||||
|
objs_visible_[i] = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void game::view::MapInstanceView::DrawChunk(const game::view::DrawArgs& args, const assets::Mesh& basemesh,
|
||||||
|
const assets::Chunk& chunk) const
|
||||||
|
{
|
||||||
|
for (const auto& surface_range : chunk.surfaces)
|
||||||
|
{
|
||||||
|
auto& surface = basemesh.surfaces[surface_range.idx];
|
||||||
|
|
||||||
|
gfx::DrawSurfaceCmd cmd;
|
||||||
|
cmd.surface = &surface;
|
||||||
|
cmd.first = surface_range.first;
|
||||||
|
cmd.count = surface_range.count;
|
||||||
|
args.dlist.AddSurface(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& objs = map_->GetStaticObjects();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < chunk.num_objs; ++i)
|
||||||
|
{
|
||||||
|
size_t abs_i = chunk.first_obj + i;
|
||||||
|
|
||||||
|
if (abs_i >= objs.size())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!objs_visible_[abs_i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto& obj = objs[abs_i];
|
||||||
|
|
||||||
|
if (!obj.model || !obj.model->GetMesh())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!args.frustum.IsAABBVisible(obj.aabb))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto& surfaces = obj.model->GetMesh()->surfaces;
|
||||||
|
|
||||||
|
for (const auto& surface : surfaces)
|
||||||
|
{
|
||||||
|
gfx::DrawSurfaceCmd cmd;
|
||||||
|
cmd.surface = &surface;
|
||||||
|
cmd.matrices = &obj.node.matrix;
|
||||||
|
// cmd.color_mod = glm::vec4(obj.color, 1.0f);
|
||||||
|
args.dlist.AddSurface(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/gameview/mapinstanceview.hpp
Normal file
30
src/gameview/mapinstanceview.hpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "assets/map.hpp"
|
||||||
|
#include "draw_args.hpp"
|
||||||
|
#include "net/defs.hpp"
|
||||||
|
|
||||||
|
namespace game::view
|
||||||
|
{
|
||||||
|
|
||||||
|
class MapInstanceView
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MapInstanceView(const std::string& map_name);
|
||||||
|
|
||||||
|
void Draw(const game::view::DrawArgs& args) const;
|
||||||
|
|
||||||
|
void EnableObj(net::ObjNum num, bool enable);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void DrawChunk(const game::view::DrawArgs& args, const assets::Mesh& basemesh, const assets::Chunk& chunk) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<const assets::Map> map_;
|
||||||
|
std::vector<bool> objs_visible_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -6,12 +6,26 @@
|
|||||||
#include "vehicleview.hpp"
|
#include "vehicleview.hpp"
|
||||||
#include "client_session.hpp"
|
#include "client_session.hpp"
|
||||||
|
|
||||||
game::view::WorldView::WorldView(ClientSession& session) :
|
game::view::WorldView::WorldView(ClientSession& session, net::InMessage& msg) :
|
||||||
session_(session),
|
session_(session), audiomaster_(session_.GetAudioMaster()), map_("openworld")
|
||||||
audiomaster_(session_.GetAudioMaster())
|
|
||||||
{
|
{
|
||||||
map_ = assets::CacheManager::GetMap("data/openworld.map");
|
net::MapName mapname;
|
||||||
AddMapCollision(map_);
|
if (!msg.Read(mapname))
|
||||||
|
throw EntityInitError();
|
||||||
|
|
||||||
|
// init destroyed objs
|
||||||
|
net::ObjCount objcount;
|
||||||
|
if (!msg.Read(objcount))
|
||||||
|
throw EntityInitError();
|
||||||
|
|
||||||
|
for (net::ObjCount i = 0; i < objcount; ++i)
|
||||||
|
{
|
||||||
|
net::ObjNum objnum;
|
||||||
|
if (!msg.Read(objnum))
|
||||||
|
throw EntityInitError();
|
||||||
|
|
||||||
|
map_.EnableObj(objnum, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool game::view::WorldView::ProcessMsg(net::MessageType type, net::InMessage& msg)
|
bool game::view::WorldView::ProcessMsg(net::MessageType type, net::InMessage& msg)
|
||||||
@ -27,6 +41,12 @@ bool game::view::WorldView::ProcessMsg(net::MessageType type, net::InMessage& ms
|
|||||||
case net::MSG_ENTDESTROY:
|
case net::MSG_ENTDESTROY:
|
||||||
return ProcessEntDestroyMsg(msg);
|
return ProcessEntDestroyMsg(msg);
|
||||||
|
|
||||||
|
case net::MSG_OBJDESTROY:
|
||||||
|
return ProcessObjDestroyOrRespawnMsg(msg, false);
|
||||||
|
|
||||||
|
case net::MSG_OBJRESPAWN:
|
||||||
|
return ProcessObjDestroyOrRespawnMsg(msg, true);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -44,8 +64,7 @@ void game::view::WorldView::Update(const UpdateInfo& info)
|
|||||||
|
|
||||||
void game::view::WorldView::Draw(const DrawArgs& args) const
|
void game::view::WorldView::Draw(const DrawArgs& args) const
|
||||||
{
|
{
|
||||||
if (map_)
|
map_.Draw(args);
|
||||||
map_->Draw(args);
|
|
||||||
|
|
||||||
for (const auto& [entnum, ent] : ents_)
|
for (const auto& [entnum, ent] : ents_)
|
||||||
{
|
{
|
||||||
@ -150,3 +169,13 @@ bool game::view::WorldView::ProcessEntDestroyMsg(net::InMessage& msg)
|
|||||||
ents_.erase(entnum);
|
ents_.erase(entnum);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool game::view::WorldView::ProcessObjDestroyOrRespawnMsg(net::InMessage& msg, bool enable)
|
||||||
|
{
|
||||||
|
net::ObjNum objnum;
|
||||||
|
if (!msg.Read(objnum))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
map_.EnableObj(objnum, enable);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "net/inmessage.hpp"
|
#include "net/inmessage.hpp"
|
||||||
#include "collision/dynamicsworld.hpp"
|
#include "collision/dynamicsworld.hpp"
|
||||||
#include "entityview.hpp"
|
#include "entityview.hpp"
|
||||||
|
#include "mapinstanceview.hpp"
|
||||||
|
|
||||||
namespace game::view
|
namespace game::view
|
||||||
{
|
{
|
||||||
@ -15,7 +16,7 @@ class ClientSession;
|
|||||||
class WorldView : public collision::DynamicsWorld
|
class WorldView : public collision::DynamicsWorld
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WorldView(ClientSession& session);
|
WorldView(ClientSession& session, net::InMessage& msg);
|
||||||
|
|
||||||
bool ProcessMsg(net::MessageType type, net::InMessage& msg);
|
bool ProcessMsg(net::MessageType type, net::InMessage& msg);
|
||||||
|
|
||||||
@ -35,10 +36,12 @@ private:
|
|||||||
bool ProcessEntMsgMsg(net::InMessage& msg);
|
bool ProcessEntMsgMsg(net::InMessage& msg);
|
||||||
bool ProcessEntDestroyMsg(net::InMessage& msg);
|
bool ProcessEntDestroyMsg(net::InMessage& msg);
|
||||||
|
|
||||||
|
bool ProcessObjDestroyOrRespawnMsg(net::InMessage& msg, bool enable);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ClientSession& session_;
|
ClientSession& session_;
|
||||||
|
|
||||||
std::shared_ptr<const assets::Map> map_;
|
MapInstanceView map_;
|
||||||
std::map<net::EntNum, std::unique_ptr<EntityView>> ents_;
|
std::map<net::EntNum, std::unique_ptr<EntityView>> ents_;
|
||||||
|
|
||||||
float time_ = 0.0f;
|
float time_ = 0.0f;
|
||||||
|
|||||||
@ -31,6 +31,9 @@ enum MessageType : uint8_t
|
|||||||
// CHWORLD <MapName>
|
// CHWORLD <MapName>
|
||||||
MSG_CHWORLD,
|
MSG_CHWORLD,
|
||||||
|
|
||||||
|
// CAM <EntNum>
|
||||||
|
MSG_CAM,
|
||||||
|
|
||||||
/*~~~~~~~~ Entity ~~~~~~~~*/
|
/*~~~~~~~~ Entity ~~~~~~~~*/
|
||||||
// ENTSPAWN <EntNum> <EntType> data...
|
// ENTSPAWN <EntNum> <EntType> data...
|
||||||
MSG_ENTSPAWN,
|
MSG_ENTSPAWN,
|
||||||
@ -39,8 +42,12 @@ enum MessageType : uint8_t
|
|||||||
// ENTDESTROY <EntNum>
|
// ENTDESTROY <EntNum>
|
||||||
MSG_ENTDESTROY,
|
MSG_ENTDESTROY,
|
||||||
|
|
||||||
// CAM <EntNum>
|
/*~~~~~~~~ Destructibles ~~~~~~~~*/
|
||||||
MSG_CAM,
|
// OBJDESTROY <ObjNum>
|
||||||
|
MSG_OBJDESTROY,
|
||||||
|
// OBJRESPAWN <ObjNum>
|
||||||
|
MSG_OBJRESPAWN,
|
||||||
|
|
||||||
|
|
||||||
/*~~~~~~~~~~~~~~~~*/
|
/*~~~~~~~~~~~~~~~~*/
|
||||||
MSG_COUNT,
|
MSG_COUNT,
|
||||||
@ -58,6 +65,7 @@ constexpr long long PI_D = 78256779;
|
|||||||
using ViewYawQ = Quantized<uint16_t, 0, 2 * PI_N, PI_D>;
|
using ViewYawQ = Quantized<uint16_t, 0, 2 * PI_N, PI_D>;
|
||||||
using ViewPitchQ = Quantized<uint16_t, -PI_N, PI_N, PI_D>;
|
using ViewPitchQ = Quantized<uint16_t, -PI_N, PI_N, PI_D>;
|
||||||
|
|
||||||
|
// entities
|
||||||
using EntNum = uint16_t;
|
using EntNum = uint16_t;
|
||||||
|
|
||||||
enum EntType : uint8_t
|
enum EntType : uint8_t
|
||||||
@ -107,4 +115,8 @@ using AnimTimeQ = Quantized<uint8_t, 0, 1>;
|
|||||||
using NumClothes = uint8_t;
|
using NumClothes = uint8_t;
|
||||||
using ClothesName = FixedStr<32>;
|
using ClothesName = FixedStr<32>;
|
||||||
|
|
||||||
|
// destructibles
|
||||||
|
using ObjNum = uint16_t;
|
||||||
|
using ObjCount = ObjNum;
|
||||||
|
|
||||||
} // namespace net
|
} // namespace net
|
||||||
Loading…
x
Reference in New Issue
Block a user