diff --git a/CMakeLists.txt b/CMakeLists.txt index 338ac29..8d38cd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ set(COMMON_SOURCES "src/net/msg_producer.cpp" "src/net/outmessage.hpp" "src/net/quantized.hpp" + "src/net/utils.hpp" "src/utils/allocnum.hpp" "src/utils/defs.hpp" "src/utils/files.hpp" diff --git a/src/client/app.cpp b/src/client/app.cpp index fd1d04b..a018083 100644 --- a/src/client/app.cpp +++ b/src/client/app.cpp @@ -16,22 +16,30 @@ App::App() void App::Frame() { - float delta_time = time_ - prev_time_; + delta_time_ = time_ - prev_time_; prev_time_ = time_; - if (delta_time < 0.0f) + if (delta_time_ < 0.0f) { - delta_time = 0.0f; // Prevent negative delta time + delta_time_ = 0.0f; // Prevent negative delta time } - else if (delta_time > 0.1f) + else if (delta_time_ > 0.1f) { - delta_time = 0.1f; // Cap delta time to avoid large jumps + delta_time_ = 0.1f; // Cap delta time to avoid large jumps } // detect inputs originating in this frame game::PlayerInputFlags new_input = input_ & ~prev_input_; prev_input_ = input_; + if (session_) + { + game::view::UpdateInfo updinfo; + updinfo.time = time_; + updinfo.delta_time = delta_time_; + session_->Update(updinfo); + } + float aspect = static_cast(viewport_size_.x) / static_cast(viewport_size_.y); renderer_.Begin(viewport_size_.x, viewport_size_.y); @@ -45,11 +53,11 @@ void App::Frame() { world->Draw(dlist_); - glm::mat4 view = glm::lookAt(glm::vec3(15.0f, 0.0f, 1.0f), glm::vec3(0.0f, 0.0f, -13.0f), glm::vec3(0.0f, 0.0f, 1.0f)); + // glm::mat4 view = glm::lookAt(glm::vec3(15.0f, 0.0f, 1.0f), glm::vec3(0.0f, 0.0f, -13.0f), glm::vec3(0.0f, 0.0f, 1.0f)); glm::mat4 proj = glm::perspective(glm::radians(45.0f), aspect, 0.1f, 3000.0f); gfx::DrawListParams params; - params.view_proj = proj * view; + params.view_proj = proj * session_->GetViewMatrix(); renderer_.DrawList(dlist_, params); } @@ -100,7 +108,8 @@ void App::MouseMove(const glm::vec2& delta) float delta_yaw = delta.x * sensitivity; float delta_pitch = -delta.y * sensitivity; - // TODO: rotate + if (session_) + session_->ProcessMouseMove(delta_yaw, delta_pitch); } App::~App() diff --git a/src/client/app.hpp b/src/client/app.hpp index 4a7b76e..9dcc40c 100644 --- a/src/client/app.hpp +++ b/src/client/app.hpp @@ -26,6 +26,9 @@ public: void SetInput(game::PlayerInputFlags input) { input_ = input; } void MouseMove(const glm::vec2& delta); + float GetTime() const { return delta_time_; } + float GetDeltaTime() const { return delta_time_; } + ~App(); private: @@ -39,6 +42,7 @@ private: game::PlayerInputFlags prev_input_ = 0; float prev_time_ = 0.0f; + float delta_time_ = 0.0f; gfx::Renderer renderer_; gfx::DrawList dlist_; diff --git a/src/client/main.cpp b/src/client/main.cpp index a01a5d1..f72ca01 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -240,6 +240,8 @@ static void Main() { } #endif + SDL_GL_SetSwapInterval(0); + { using namespace easywsclient; diff --git a/src/collision/dynamicsworld.cpp b/src/collision/dynamicsworld.cpp index 8b5909d..2bbe546 100644 --- a/src/collision/dynamicsworld.cpp +++ b/src/collision/dynamicsworld.cpp @@ -47,14 +47,14 @@ void collision::DynamicsWorld::AddModelInstance(const assets::Model& model, cons if (auto cmesh = model.GetColMesh(); cmesh) { // create trimesh object - auto obj = std::make_unique(); - obj->setCollisionShape(cmesh->GetShape()); + btRigidBody::btRigidBodyConstructionInfo rbInfo(0.0f, nullptr, cmesh->GetShape(), btVector3(0,0,0)); + auto obj = std::make_unique(rbInfo); // set transform obj->setWorldTransform(trans.ToBtTransform()); // add to world - bt_world_.addCollisionObject(obj.get()); + bt_world_.addRigidBody(obj.get()); static_objs_.emplace_back(std::move(obj)); } diff --git a/src/collision/dynamicsworld.hpp b/src/collision/dynamicsworld.hpp index c41fe7e..a7396a9 100644 --- a/src/collision/dynamicsworld.hpp +++ b/src/collision/dynamicsworld.hpp @@ -18,6 +18,9 @@ namespace collision // } + + + class DynamicsWorld { public: @@ -36,7 +39,7 @@ private: private: // this is BEFORE bt_world_!!! std::shared_ptr map_; - std::vector> static_objs_; + std::vector> static_objs_; // ^----- btDefaultCollisionConfiguration bt_cfg_; diff --git a/src/game/player.cpp b/src/game/player.cpp index 59cdc45..a40d83b 100644 --- a/src/game/player.cpp +++ b/src/game/player.cpp @@ -61,6 +61,8 @@ void game::Player::Control(Controllable* ctl) if (ctl_) ctl_->controller_ = this; + + SendControl(); } game::Player::~Player() @@ -76,6 +78,13 @@ void game::Player::SendWorldMsg() msg.Write(net::MapName(world_->GetMapName())); } +void game::Player::SendControl() +{ + auto msg = BeginMsg(net::MSG_CONTROL); + net::EntNum entnum = ctl_ ? ctl_->GetEntity().GetEntNum() : 0; + msg.Write(entnum); +} + void game::Player::SyncEntities() { const auto& ents = world_->GetEntities(); diff --git a/src/game/player.hpp b/src/game/player.hpp index b39f956..cfe3191 100644 --- a/src/game/player.hpp +++ b/src/game/player.hpp @@ -42,6 +42,7 @@ public: private: void SendWorldMsg(); + void SendControl(); // entities sync void SyncEntities(); diff --git a/src/game/vehicle.cpp b/src/game/vehicle.cpp index 54c4889..081bde9 100644 --- a/src/game/vehicle.cpp +++ b/src/game/vehicle.cpp @@ -1,9 +1,12 @@ #include "vehicle.hpp" #include "assets/cache.hpp" +#include "net/utils.hpp" #include "player.hpp" #include "player_input.hpp" +#include + static std::shared_ptr LoadVehicleModelByName(const std::string& model_name) { return assets::CacheManager::GetVehicleModel("data/" + model_name + ".veh"); @@ -14,7 +17,7 @@ struct Shape btBoxShape box; btCompoundShape compound; - Shape() : box(btVector3(1, 1, 1)) + Shape() : box(btVector3(1, 1, 0.1)) { btTransform t(btQuaternion(0, 0, 0), btVector3(0, 0, 2)); compound.addChildShape(t, &box); @@ -28,7 +31,7 @@ game::Vehicle::Vehicle(World& world, std::string model_name) root_.local.position.z = 10.0f; // setup chassis rigidbody - float mass = 300.0f; + float mass = 1300.0f; static Shape shape; btVector3 local_inertia(0, 0, 0); @@ -49,16 +52,23 @@ game::Vehicle::Vehicle(World& world, std::string model_name) btVector3 wheelDirectionCS0(0, 0, -1); btVector3 wheelAxleCS(1, 0, 0); - for (const auto& wheels = model_->GetWheels(); const auto& wheeldef : wheels) - { - float suspension_rest_length = 0.6f; + wheel_z_offset_ = 0.4f; + const auto& wheels = model_->GetWheels(); + + if (wheels.size() > MAX_WHEELS) + throw std::runtime_error("Max wheels exceeded"); + + num_wheels_ = wheels.size(); + + for (const auto& wheeldef : wheels) + { float wheelRadius = .35f; float friction = 5.0f; float suspensionStiffness = 60.0f; - //float suspensionDamping = 2.3f; - //float suspensionCompression = 4.4f; + // float suspensionDamping = 2.3f; + // float suspensionCompression = 4.4f; float suspensionRestLength = 0.6f; float rollInfluence = 0.01f; @@ -69,18 +79,18 @@ game::Vehicle::Vehicle(World& world, std::string model_name) const bool is_front = !(wheeldef.type & assets::WHEEL_REAR); - btVector3 wheel_pos(wheeldef.position.x, wheeldef.position.y, wheeldef.position.z); - auto& wi = vehicle_->addWheel(wheel_pos, wheelDirectionCS0, wheelAxleCS, suspension_rest_length, - wheelRadius, tuning, is_front); + btVector3 wheel_pos(wheeldef.position.x, wheeldef.position.y, wheeldef.position.z + wheel_z_offset_); + auto& wi = vehicle_->addWheel(wheel_pos, wheelDirectionCS0, wheelAxleCS, suspensionRestLength, wheelRadius, + tuning, is_front); wi.m_suspensionStiffness = suspensionStiffness; - wi.m_wheelsDampingCompression = k * 2.0 * btSqrt(suspensionStiffness); //vehicleTuning.suspensionCompression; - wi.m_wheelsDampingRelaxation = k * 3.3 * btSqrt(suspensionStiffness);//vehicleTuning.suspensionDamping; - + wi.m_wheelsDampingCompression = k * 2.0 * btSqrt(suspensionStiffness); // vehicleTuning.suspensionCompression; + wi.m_wheelsDampingRelaxation = k * 3.3 * btSqrt(suspensionStiffness); // vehicleTuning.suspensionDamping; + wi.m_frictionSlip = friction; - //if (wi.m_bIsFrontWheel) wi.m_frictionSlip = vehicleTuning.friction * 1.4f; - + // if (wi.m_bIsFrontWheel) wi.m_frictionSlip = vehicleTuning.friction * 1.4f; + wi.m_rollInfluence = rollInfluence; wi.m_maxSuspensionForce = maxSuspensionForce; wi.m_maxSuspensionTravelCm = maxSuspensionTravelCm; @@ -89,7 +99,6 @@ game::Vehicle::Vehicle(World& world, std::string model_name) auto& bt_world = world_.GetBtWorld(); bt_world.addRigidBody(body_.get()); bt_world.addAction(vehicle_.get()); - } void game::Vehicle::Update() @@ -97,13 +106,7 @@ void game::Vehicle::Update() Super::Update(); ProcessInput(); - - for (int j = 0; j < vehicle_->getNumWheels(); j++) - { - auto& wheel = vehicle_->getWheelInfo(j); - float sus_length = wheel.m_raycastInfo.m_suspensionLength; - // TODO: sync wheels - } + UpdateWheels(); SendUpdateMsg(); } @@ -139,7 +142,7 @@ void game::Vehicle::ProcessInput() if (in & IN_DEBUG1) { auto t = body_->getWorldTransform(); - t.setOrigin(btVector3(0, 0, 5)); + t.setOrigin(btVector3(100, 100, 5)); body_->setWorldTransform(t); } @@ -170,10 +173,10 @@ void game::Vehicle::ProcessInput() } // idle breaking - // if (in & (IN_FORWARD | IN_BACKWARD) == 0) - // { - // breakingForce = maxBreakingForce * 0.5f; - // } + if (!(in & IN_FORWARD) && !(in & IN_BACKWARD)) + { + breakingForce = maxBreakingForce * 0.05f; + } if (in & IN_LEFT) { @@ -215,42 +218,50 @@ void game::Vehicle::ProcessInput() vehicle_->setSteeringValue(steering_, 1); } +void game::Vehicle::UpdateWheels() +{ + for (size_t i = 0; i < num_wheels_; ++i) + { + auto& bt_wheel = vehicle_->getWheelInfo(i); + wheels_[i].speed = -(bt_wheel.m_rotation - wheels_[i].rotation) * 25.0f; + wheels_[i].rotation = bt_wheel.m_rotation; + wheels_[i].z_offset = wheel_z_offset_ - bt_wheel.m_raycastInfo.m_suspensionLength; + } +} + void game::Vehicle::SendUpdateMsg() { - const auto& trans = root_.local; + auto msg = BeginEntMsg(net::EMSG_UPDATE); + net::WriteTransform(msg, root_.local); - auto umsg = BeginEntMsg(net::EMSG_UPDATE); + // send wheel info + // msg.Write(static_cast(numwheels)); + msg.Write(steering_); - // write position - umsg.Write(trans.position.x); - umsg.Write(trans.position.y); - umsg.Write(trans.position.z); - - // write angles - glm::vec3 angles = glm::eulerAngles(trans.rotation); - umsg.Write(angles.x); - umsg.Write(angles.y); - umsg.Write(angles.z); + for (size_t i = 0; i < num_wheels_; ++i) + { + auto& wheel = wheels_[i]; + msg.Write(wheel.z_offset); + msg.Write(wheel.speed); + } // TEMP wheels // TODO: REMOVE - for (size_t i =0; i < vehicle_->getNumWheels(); ++i) - { - auto& wheel = vehicle_->getWheelInfo(i); - vehicle_->updateWheelTransformsWS(wheel); + // for (size_t i =0; i < vehicle_->getNumWheels(); ++i) + // { + // vehicle_->updateWheelTransform(i, true); + // btTransform tr = vehicle_->getWheelTransformWS(i); - Transform trans; - trans.SetBtTransform(wheel.m_worldTransform); + // Transform trans; + // trans.SetBtTransform(tr); - // write position - umsg.Write(trans.position.x); - umsg.Write(trans.position.y); - umsg.Write(trans.position.z); + // net::WriteTransform(msg, trans); - // write angles - glm::vec3 angles = glm::eulerAngles(trans.rotation); - umsg.Write(angles.x); - umsg.Write(angles.y); - umsg.Write(angles.z); - } + // // static glm::vec3 min_angles(1000.0f); + // // static glm::vec3 max_angles(-1000.0f); + // // min_angles = glm::min(min_angles, angles); + // // max_angles= glm::max(max_angles, angles); + + // // std::cout << angles.x << " " << angles.y << " " << angles.z << " | " < +#include + #include "assets/vehiclemdl.hpp" #include "collision/motionstate.hpp" +#include "controllable.hpp" +#include "entity.hpp" +#include "world.hpp" namespace game { +static constexpr size_t MAX_WHEELS = 4; + +struct VehicleWheelState +{ + float rotation = 0.0f; // [rad] + float speed = 0.0f; // [rad/s] + float z_offset = 0.0f; // [m] against model definition +}; + class Vehicle : public Entity, public Controllable { public: @@ -26,6 +38,7 @@ public: private: void ProcessInput(); + void UpdateWheels(); void SendUpdateMsg(); private: @@ -37,6 +50,10 @@ private: std::unique_ptr vehicle_; float steering_ = 0.0f; + float wheel_z_offset_ = 0.0f; + + size_t num_wheels_ = 0; + std::array wheels_; }; -} \ No newline at end of file +} // namespace game \ No newline at end of file diff --git a/src/game/world.cpp b/src/game/world.cpp index 90f3514..ac9f463 100644 --- a/src/game/world.cpp +++ b/src/game/world.cpp @@ -34,8 +34,8 @@ void game::World::RegisterEntity(std::unique_ptr ent) void game::World::Update(int64_t delta_time) { - time_ms_ += delta_time; - GetBtWorld().stepSimulation(static_cast(delta_time) * 1000.0f, 2, 1.0f / 100.0f); + time_ms_ += delta_time; + GetBtWorld().stepSimulation(static_cast(delta_time) * 0.001f, 10); // update entities for (auto it = ents_.begin(); it != ents_.end();) diff --git a/src/gameview/client_session.cpp b/src/gameview/client_session.cpp index 76be15b..e958242 100644 --- a/src/gameview/client_session.cpp +++ b/src/gameview/client_session.cpp @@ -1,6 +1,8 @@ #include "client_session.hpp" #include +#include "client/app.hpp" +// #include game::view::ClientSession::ClientSession(App& app) : app_(app) {} @@ -28,6 +30,9 @@ bool game::view::ClientSession::ProcessSingleMessage(net::MessageType type, net: case net::MSG_CHWORLD: return ProcessWorldMsg(msg); + case net::MSG_CONTROL: + return ProcessControlMsg(msg); + default: // try pass the msg to world if (world_ && world_->ProcessMsg(type, msg)) @@ -37,6 +42,50 @@ bool game::view::ClientSession::ProcessSingleMessage(net::MessageType type, net: } } +void game::view::ClientSession::ProcessMouseMove(float delta_yaw, float delta_pitch) +{ + yaw_ += delta_yaw; + // yaw_ = glm::fmod(yaw_, 2.0f * glm::pi()); + + pitch_ += delta_pitch; + // Clamp pitch to avoid gimbal lock + if (pitch_ > glm::radians(89.0f)) { + pitch_ = glm::radians(89.0f); + } else if (pitch_ < glm::radians(-89.0f)) { + pitch_ = glm::radians(-89.0f); + } +} + +void game::view::ClientSession::Update(const UpdateInfo& info) +{ + if (world_) + world_->Update(info); +} + +glm::mat4 game::view::ClientSession::GetViewMatrix() const +{ + glm::vec3 center(0, 0, 3); + + if (world_ && ctl_) + { + auto ent = world_->GetEntity(ctl_); + if (ent) + center += ent->GetRoot().local.position; + } + + float yaw_cos = glm::cos(yaw_); + float yaw_sin = glm::sin(yaw_); + float pitch_cos = glm::cos(pitch_); + float pitch_sin = glm::sin(pitch_); + glm::vec3 dir(yaw_sin * pitch_cos, yaw_cos * pitch_cos, pitch_sin); + + float distance = 10.0f; + + auto eye = center - dir * distance; + + return glm::lookAt(eye, center, glm::vec3(0, 0, 1)); +} + bool game::view::ClientSession::ProcessWorldMsg(net::InMessage& msg) { net::MapName mapname; @@ -44,7 +93,15 @@ bool game::view::ClientSession::ProcessWorldMsg(net::InMessage& msg) return false; // TODO: pass mapname - world_ = std::make_unique(); + world_ = std::make_unique(*this); + + return true; +} + +bool game::view::ClientSession::ProcessControlMsg(net::InMessage& msg) +{ + if (!msg.Read(ctl_)) + return false; return true; } diff --git a/src/gameview/client_session.hpp b/src/gameview/client_session.hpp index 257d8dc..a27042a 100644 --- a/src/gameview/client_session.hpp +++ b/src/gameview/client_session.hpp @@ -21,17 +21,27 @@ public: bool ProcessMessage(net::InMessage& msg); bool ProcessSingleMessage(net::MessageType type, net::InMessage& msg); + void ProcessMouseMove(float delta_yaw, float delta_pitch); + + void Update(const UpdateInfo& info); + const WorldView* GetWorld() const { return world_.get(); } + glm::mat4 GetViewMatrix() const; + private: // msg handlers bool ProcessWorldMsg(net::InMessage& msg); + bool ProcessControlMsg(net::InMessage& msg); private: App& app_; std::unique_ptr world_; + float yaw_ = 0.0f, pitch_ = 0.0f; + net::EntNum ctl_ = 0; + }; } // namespace game::view \ No newline at end of file diff --git a/src/gameview/entityview.hpp b/src/gameview/entityview.hpp index 79f8664..dd8a4ee 100644 --- a/src/gameview/entityview.hpp +++ b/src/gameview/entityview.hpp @@ -15,6 +15,12 @@ namespace game::view class WorldView; +struct UpdateInfo +{ + float time; + float delta_time; +}; + class EntityView { public: @@ -22,9 +28,11 @@ public: DELETE_COPY_MOVE(EntityView) virtual bool ProcessMsg(net::EntMsgType type, net::InMessage& msg) { return false; } - virtual void Update() {} + virtual void Update(const UpdateInfo& info) {} virtual void Draw(gfx::DrawList& dlist) {} + const TransformNode& GetRoot() const { return root_; } + virtual ~EntityView() = default; protected: diff --git a/src/gameview/vehicleview.cpp b/src/gameview/vehicleview.cpp index 07122ae..0495c3a 100644 --- a/src/gameview/vehicleview.cpp +++ b/src/gameview/vehicleview.cpp @@ -1,12 +1,21 @@ #include "vehicleview.hpp" #include "assets/cache.hpp" +#include "net/utils.hpp" +#include "worldview.hpp" #include game::view::VehicleView::VehicleView(WorldView& world, std::shared_ptr model) : EntityView(world), model_(std::move(model)) { + auto& modelwheels = model_->GetWheels(); + wheels_.resize(modelwheels.size()); + + for (size_t i = 0; i < wheels_.size(); ++i) + { + wheels_[i].node.parent = &root_; + } } std::unique_ptr game::view::VehicleView::InitFromMsg(WorldView& world, net::InMessage& msg) @@ -32,12 +41,37 @@ bool game::view::VehicleView::ProcessMsg(net::EntMsgType type, net::InMessage& m } } -void game::view::VehicleView::Update() {} +void game::view::VehicleView::Update(const UpdateInfo& info) +{ + 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(root_trans_[0], root_trans_[1], t); + + root_.UpdateMatrix(); + + const auto& wheels = model_->GetWheels(); + for (size_t i = 0; i < wheels.size(); ++i) + { + // update wheel transform + auto& wheelstate = wheels_[i]; + auto& wheeltrans = wheelstate.node.local; + wheeltrans.position = wheels[i].position; + wheeltrans.position.z += wheelstate.z_offset; + + // rotate + wheelstate.rotation += info.delta_time * wheelstate.speed; + + wheeltrans.rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f); + wheeltrans.rotation = glm::rotate(wheeltrans.rotation, wheelstate.steering, glm::vec3(0, 0, 1)); + wheeltrans.rotation = glm::rotate(wheeltrans.rotation, wheelstate.rotation, glm::vec3(1, 0, 0)); + + wheels_[i].node.UpdateMatrix(); + } +} void game::view::VehicleView::Draw(gfx::DrawList& dlist) { - root_.UpdateMatrix(); - // TOOD: chceck and fix const auto& model = *model_->GetModel(); const auto& mesh = *model.GetMesh(); @@ -51,17 +85,15 @@ void game::view::VehicleView::Draw(gfx::DrawList& dlist) } const auto& wheels = model_->GetWheels(); - for (size_t i = 0; i < 4; ++i) + for (size_t i = 0; i < wheels.size(); ++i) { - wheels_[i].UpdateMatrix(); - const auto& mesh = *wheels[i].model->GetMesh(); for (const auto& surface : mesh.surfaces) { gfx::DrawSurfaceCmd cmd; cmd.surface = &surface; - cmd.matrices = &wheels_[i].matrix; + cmd.matrices = &wheels_[i].node.matrix; dlist.AddSurface(cmd); } } @@ -69,27 +101,25 @@ void game::view::VehicleView::Draw(gfx::DrawList& dlist) bool game::view::VehicleView::ProcessUpdateMsg(net::InMessage& msg) { - auto& trans = root_.local; - glm::vec3 angles; + root_trans_[0] = root_.local; + auto& root_trans = root_trans_[1]; + update_time_ = world_.GetTime(); - if (!msg.Read(trans.position.x) || !msg.Read(trans.position.y) || - !msg.Read(trans.position.z) || !msg.Read(angles.x) || - !msg.Read(angles.y) || !msg.Read(angles.z)) + if (!net::ReadTransform(msg, root_trans)) return false; - trans.rotation = glm::quat(angles); + float steering; + if (!msg.Read(steering)) + return false; - for (size_t i = 0; i < 4; ++i) + const auto& wheels = model_->GetWheels(); + for (size_t i = 0; i < wheels_.size(); ++i) { - auto& trans = wheels_[i].local; - glm::vec3 angles; - - if (!msg.Read(trans.position.x) || !msg.Read(trans.position.y) || - !msg.Read(trans.position.z) || !msg.Read(angles.x) || - !msg.Read(angles.y) || !msg.Read(angles.z)) + auto& wheel = wheels_[i]; + if (!msg.Read(wheel.z_offset) || !msg.Read(wheel.speed)) return false; - trans.rotation = glm::quat(angles); + wheel.steering = i < 2 ? steering : 0.0f; } } diff --git a/src/gameview/vehicleview.hpp b/src/gameview/vehicleview.hpp index 1084405..8af613a 100644 --- a/src/gameview/vehicleview.hpp +++ b/src/gameview/vehicleview.hpp @@ -9,6 +9,15 @@ namespace game::view { +struct VehicleWheelViewInfo +{ + TransformNode node; + float steering = 0.0f; + float z_offset = 0.0f; + float speed = 0.0f; + float rotation = 0.0f; +}; + class VehicleView : public EntityView { public: @@ -16,7 +25,7 @@ public: static std::unique_ptr InitFromMsg(WorldView& world, net::InMessage& msg); virtual bool ProcessMsg(net::EntMsgType type, net::InMessage& msg) override; - virtual void Update() override; + virtual void Update(const UpdateInfo& info) override; virtual void Draw(gfx::DrawList& dlist) override; private: @@ -25,7 +34,10 @@ private: private: std::shared_ptr model_; - TransformNode wheels_[4]; + std::vector wheels_; + + float update_time_ = 0.0f; + Transform root_trans_[2]; }; diff --git a/src/gameview/worldview.cpp b/src/gameview/worldview.cpp index db71c59..9118573 100644 --- a/src/gameview/worldview.cpp +++ b/src/gameview/worldview.cpp @@ -3,8 +3,9 @@ #include "assets/cache.hpp" #include "vehicleview.hpp" +#include "client_session.hpp" -game::view::WorldView::WorldView() +game::view::WorldView::WorldView(ClientSession& session) : session_(session) { map_ = assets::CacheManager::GetMap("data/openworld.map"); } @@ -27,6 +28,16 @@ bool game::view::WorldView::ProcessMsg(net::MessageType type, net::InMessage& ms } } +void game::view::WorldView::Update(const UpdateInfo& info) +{ + time_ = info.time; + + for (const auto& [entnum, ent] : ents_) + { + ent->Update(info); + } +} + void game::view::WorldView::Draw(gfx::DrawList& dlist) const { if (map_) @@ -38,6 +49,15 @@ void game::view::WorldView::Draw(gfx::DrawList& dlist) const } } +game::view::EntityView* game::view::WorldView::GetEntity(net::EntNum entnum) +{ + auto it = ents_.find(entnum); + if (it != ents_.end()) + return it->second.get(); + + return nullptr; +} + bool game::view::WorldView::ProcessEntSpawnMsg(net::InMessage& msg) { net::EntNum entnum; diff --git a/src/gameview/worldview.hpp b/src/gameview/worldview.hpp index e72675a..9cb4967 100644 --- a/src/gameview/worldview.hpp +++ b/src/gameview/worldview.hpp @@ -10,15 +10,22 @@ namespace game::view { +class ClientSession; + class WorldView { public: - WorldView(); + WorldView(ClientSession& session); bool ProcessMsg(net::MessageType type, net::InMessage& msg); + void Update(const UpdateInfo& info); void Draw(gfx::DrawList& dlist) const; + EntityView* GetEntity(net::EntNum entnum); + + float GetTime() const { return time_; } + private: // msg handlers bool ProcessEntSpawnMsg(net::InMessage& msg); @@ -26,9 +33,12 @@ private: bool ProcessEntDestroyMsg(net::InMessage& msg); private: - std::shared_ptr map_; + ClientSession& session_; + std::shared_ptr map_; std::map> ents_; + + float time_ = 0.0f; }; diff --git a/src/gfx/shader_sources.cpp b/src/gfx/shader_sources.cpp index 628c278..fef383f 100644 --- a/src/gfx/shader_sources.cpp +++ b/src/gfx/shader_sources.cpp @@ -38,25 +38,37 @@ )GLSL" #define COMPUTE_LIGHTS_GLSL R"GLSL( - vec3 ComputeLights(in vec3 sector_pos, in vec3 sector_normal) - { - vec3 color = u_ambient_light; - for (int i = 0; i < u_num_lights; ++i) { - vec3 light_pos = u_light_positions[i]; - vec3 light_color = u_light_colors_rs[i].rgb; - float light_radius = u_light_colors_rs[i].a; - - vec3 to_light = light_pos - sector_pos.xyz; - float dist2 = dot(to_light, to_light); - if (dist2 < light_radius * light_radius) { - float dist = sqrt(dist2); - float attenuation = 1.0 - (dist / light_radius); - float dot = max(dot(sector_normal, normalize(to_light)), 0.0); - color += light_color * dot * attenuation; - } +// Example sun values (can later be uniforms) +vec3 u_sun_direction = normalize(vec3(0.3, 0.5, -0.8)); // direction from which sunlight comes +vec3 u_sun_color = vec3(1.0, 0.95, 0.7); // warm sunlight color + +vec3 ComputeLights(in vec3 sector_pos, in vec3 sector_normal) +{ + // Base ambient + vec3 color = vec3(0.5, 0.5, 0.5); // u_ambient_light + + // Sunlight contribution + float sun_dot = max(dot(sector_normal, -u_sun_direction), 0.0); + color += u_sun_color * sun_dot; + + // Point lights + for (int i = 0; i < u_num_lights; ++i) { + vec3 light_pos = u_light_positions[i]; + vec3 light_color = u_light_colors_rs[i].rgb; + float light_radius = u_light_colors_rs[i].a; + + vec3 to_light = light_pos - sector_pos; + float dist2 = dot(to_light, to_light); + if (dist2 < light_radius * light_radius) { + float dist = sqrt(dist2); + float attenuation = 1.0 - (dist / light_radius); + float dot_term = max(dot(sector_normal, normalize(to_light)), 0.0); + color += light_color * dot_term * attenuation; } - return color; } + + return color; +} )GLSL" // Zdrojove kody shaderu @@ -85,8 +97,7 @@ void main() { gl_Position = u_view_proj * world_pos; v_uv = vec2(a_uv.x, 1.0 - a_uv.y); - // v_color = ComputeLights(world_pos.xyz, world_normal) * a_color; - v_color = a_color; + v_color = ComputeLights(world_pos.xyz, world_normal) * a_color; } )GLSL", diff --git a/src/net/defs.hpp b/src/net/defs.hpp index aa2a494..bd4124f 100644 --- a/src/net/defs.hpp +++ b/src/net/defs.hpp @@ -31,6 +31,9 @@ enum MessageType : uint8_t MSG_ENTMSG, // ENTDESTROY MSG_ENTDESTROY, + + // CONTROL + MSG_CONTROL, /*~~~~~~~~~~~~~~~~*/ MSG_COUNT, @@ -68,5 +71,9 @@ enum EntMsgType : uint8_t using PositionQ = Quantized; using AngleQ = Quantized; +using QuatQ = Quantized; + +using WheelZOffsetQ = Quantized; +using RotationSpeedQ = Quantized; } // namespace net \ No newline at end of file diff --git a/src/net/utils.hpp b/src/net/utils.hpp new file mode 100644 index 0000000..d78e04a --- /dev/null +++ b/src/net/utils.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include "defs.hpp" +#include "outmessage.hpp" +#include "inmessage.hpp" +#include "utils/transform.hpp" + +namespace net +{ + +inline void WritePosition(OutMessage& msg, const glm::vec3& pos) +{ + msg.Write(pos.x); + msg.Write(pos.y); + msg.Write(pos.z); +} + +inline void WriteRotation(OutMessage& msg, const glm::quat& quat) +{ + auto q = glm::normalize(quat); + if (q.w < 0.0f) + q = -q; + + msg.Write(q.x); + msg.Write(q.y); + msg.Write(q.z); +} + +inline void WriteTransform(OutMessage& msg, const Transform& trans) +{ + WritePosition(msg, trans.position); + WriteRotation(msg, trans.rotation); +} + +inline bool ReadPosition(InMessage& msg, glm::vec3& pos) +{ + return msg.Read(pos.x) && msg.Read(pos.y) && msg.Read(pos.z); +} + +inline bool ReadRotation(InMessage& msg, glm::quat& q) +{ + glm::vec3 v; + if (!msg.Read(v.x) || !msg.Read(v.y) || !msg.Read(v.z)) + return false; + + float w = glm::sqrt(glm::max(0.0f, 1.0f - glm::dot(v, v))); + q = glm::quat(w, v.x, v.y, v.z); +} + +inline bool ReadTransform(InMessage& msg, Transform& trans) +{ + return ReadPosition(msg, trans.position) && ReadRotation(msg, trans.rotation); +} + +} \ No newline at end of file diff --git a/src/server/client.cpp b/src/server/client.cpp index d75e0c5..6b6d9bf 100644 --- a/src/server/client.cpp +++ b/src/server/client.cpp @@ -47,12 +47,14 @@ void sv::Client::Update() { if (player_) { - player_->ResetMsg(); player_->Update(); - + auto msg = player_->GetMsg(); if (!msg.empty()) + { Send(std::string(msg.data(), msg.size())); + player_->ResetMsg(); + } } } diff --git a/src/server/server.cpp b/src/server/server.cpp index 4ab354f..16c5db9 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -43,10 +43,10 @@ void sv::Server::Run() t_now = std::chrono::steady_clock::now(); } - auto t_diff = t_now - t_prev; - t_prev = t_now; + // auto t_diff = t_now - t_prev; + // t_prev = t_now; - std::cout << std::chrono::duration_cast(t_diff).count() <(t_diff).count() < lock(mtx_); + std::lock_guard lock(mtx_); + WSConnId conn_id = utils::AllocNum(id2conn_, last_id_); // register connection