This commit is contained in:
tovjemam 2026-01-06 14:48:38 +01:00
parent f2d9a02b6d
commit d158a2c371
24 changed files with 407 additions and 128 deletions

View File

@ -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"

View File

@ -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<float>(viewport_size_.x) / static_cast<float>(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()

View File

@ -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_;

View File

@ -240,6 +240,8 @@ static void Main() {
}
#endif
SDL_GL_SetSwapInterval(0);
{
using namespace easywsclient;

View File

@ -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<btCollisionObject>();
obj->setCollisionShape(cmesh->GetShape());
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_.addCollisionObject(obj.get());
bt_world_.addRigidBody(obj.get());
static_objs_.emplace_back(std::move(obj));
}

View File

@ -18,6 +18,9 @@ namespace collision
// }
class DynamicsWorld
{
public:
@ -36,7 +39,7 @@ private:
private:
// this is BEFORE bt_world_!!!
std::shared_ptr<const assets::Map> map_;
std::vector<std::unique_ptr<btCollisionObject>> static_objs_;
std::vector<std::unique_ptr<btRigidBody>> static_objs_;
// ^-----
btDefaultCollisionConfiguration bt_cfg_;

View File

@ -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();

View File

@ -42,6 +42,7 @@ public:
private:
void SendWorldMsg();
void SendControl();
// entities sync
void SyncEntities();

View File

@ -1,9 +1,12 @@
#include "vehicle.hpp"
#include "assets/cache.hpp"
#include "net/utils.hpp"
#include "player.hpp"
#include "player_input.hpp"
#include <iostream>
static std::shared_ptr<const assets::VehicleModel> 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<uint8_t>(static_cast<uint8_t>(numwheels));
msg.Write<net::AngleQ>(steering_);
// write position
umsg.Write<net::PositionQ>(trans.position.x);
umsg.Write<net::PositionQ>(trans.position.y);
umsg.Write<net::PositionQ>(trans.position.z);
// write angles
glm::vec3 angles = glm::eulerAngles(trans.rotation);
umsg.Write<net::AngleQ>(angles.x);
umsg.Write<net::AngleQ>(angles.y);
umsg.Write<net::AngleQ>(angles.z);
for (size_t i = 0; i < num_wheels_; ++i)
{
auto& wheel = wheels_[i];
msg.Write<net::WheelZOffsetQ>(wheel.z_offset);
msg.Write<net::RotationSpeedQ>(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<net::PositionQ>(trans.position.x);
umsg.Write<net::PositionQ>(trans.position.y);
umsg.Write<net::PositionQ>(trans.position.z);
// net::WriteTransform(msg, trans);
// write angles
glm::vec3 angles = glm::eulerAngles(trans.rotation);
umsg.Write<net::AngleQ>(angles.x);
umsg.Write<net::AngleQ>(angles.y);
umsg.Write<net::AngleQ>(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 << " | " <<std::endl;
// }
}

View File

@ -1,14 +1,26 @@
#pragma once
#include "entity.hpp"
#include "world.hpp"
#include "controllable.hpp"
#include <array>
#include <cstddef>
#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<btRaycastVehicle> vehicle_;
float steering_ = 0.0f;
float wheel_z_offset_ = 0.0f;
size_t num_wheels_ = 0;
std::array<VehicleWheelState, MAX_WHEELS> wheels_;
};
}
} // namespace game

View File

@ -34,8 +34,8 @@ void game::World::RegisterEntity(std::unique_ptr<Entity> ent)
void game::World::Update(int64_t delta_time)
{
time_ms_ += delta_time;
GetBtWorld().stepSimulation(static_cast<float>(delta_time) * 1000.0f, 2, 1.0f / 100.0f);
time_ms_ += delta_time;
GetBtWorld().stepSimulation(static_cast<float>(delta_time) * 0.001f, 10);
// update entities
for (auto it = ents_.begin(); it != ents_.end();)

View File

@ -1,6 +1,8 @@
#include "client_session.hpp"
#include <iostream>
#include "client/app.hpp"
// #include <glm/gtx/common.hpp>
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<float>());
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<WorldView>();
world_ = std::make_unique<WorldView>(*this);
return true;
}
bool game::view::ClientSession::ProcessControlMsg(net::InMessage& msg)
{
if (!msg.Read(ctl_))
return false;
return true;
}

View File

@ -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<WorldView> world_;
float yaw_ = 0.0f, pitch_ = 0.0f;
net::EntNum ctl_ = 0;
};
} // namespace game::view

View File

@ -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:

View File

@ -1,12 +1,21 @@
#include "vehicleview.hpp"
#include "assets/cache.hpp"
#include "net/utils.hpp"
#include "worldview.hpp"
#include <iostream>
game::view::VehicleView::VehicleView(WorldView& world, std::shared_ptr<const assets::VehicleModel> 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> 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<net::PositionQ>(trans.position.x) || !msg.Read<net::PositionQ>(trans.position.y) ||
!msg.Read<net::PositionQ>(trans.position.z) || !msg.Read<net::AngleQ>(angles.x) ||
!msg.Read<net::AngleQ>(angles.y) || !msg.Read<net::AngleQ>(angles.z))
if (!net::ReadTransform(msg, root_trans))
return false;
trans.rotation = glm::quat(angles);
float steering;
if (!msg.Read<net::AngleQ>(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<net::PositionQ>(trans.position.x) || !msg.Read<net::PositionQ>(trans.position.y) ||
!msg.Read<net::PositionQ>(trans.position.z) || !msg.Read<net::AngleQ>(angles.x) ||
!msg.Read<net::AngleQ>(angles.y) || !msg.Read<net::AngleQ>(angles.z))
auto& wheel = wheels_[i];
if (!msg.Read<net::WheelZOffsetQ>(wheel.z_offset) || !msg.Read<net::RotationSpeedQ>(wheel.speed))
return false;
trans.rotation = glm::quat(angles);
wheel.steering = i < 2 ? steering : 0.0f;
}
}

View File

@ -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<VehicleView> 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<const assets::VehicleModel> model_;
TransformNode wheels_[4];
std::vector<VehicleWheelViewInfo> wheels_;
float update_time_ = 0.0f;
Transform root_trans_[2];
};

View File

@ -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;

View File

@ -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<const assets::Map> map_;
ClientSession& session_;
std::shared_ptr<const assets::Map> map_;
std::map<net::EntNum, std::unique_ptr<EntityView>> ents_;
float time_ = 0.0f;
};

View File

@ -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",

View File

@ -31,6 +31,9 @@ enum MessageType : uint8_t
MSG_ENTMSG,
// ENTDESTROY <EntNum>
MSG_ENTDESTROY,
// CONTROL <EntNum>
MSG_CONTROL,
/*~~~~~~~~~~~~~~~~*/
MSG_COUNT,
@ -68,5 +71,9 @@ enum EntMsgType : uint8_t
using PositionQ = Quantized<uint32_t, -10000, 10000, 1>;
using AngleQ = Quantized<uint16_t, -PI_N, PI_N, PI_D>;
using QuatQ = Quantized<uint16_t, -1, 1, 1>;
using WheelZOffsetQ = Quantized<uint8_t, -1, 1, 1>;
using RotationSpeedQ = Quantized<uint16_t, -300, 300, 1>;
} // namespace net

55
src/net/utils.hpp Normal file
View File

@ -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<PositionQ>(pos.x);
msg.Write<PositionQ>(pos.y);
msg.Write<PositionQ>(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<QuatQ>(q.x);
msg.Write<QuatQ>(q.y);
msg.Write<QuatQ>(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<PositionQ>(pos.x) && msg.Read<PositionQ>(pos.y) && msg.Read<PositionQ>(pos.z);
}
inline bool ReadRotation(InMessage& msg, glm::quat& q)
{
glm::vec3 v;
if (!msg.Read<QuatQ>(v.x) || !msg.Read<QuatQ>(v.y) || !msg.Read<QuatQ>(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);
}
}

View File

@ -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();
}
}
}

View File

@ -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<std::chrono::milliseconds>(t_diff).count() <<std::endl;
// std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(t_diff).count() <<std::endl;
}
}

View File

@ -13,9 +13,9 @@ sv::WSServer::WSServer(uint16_t port)
CROW_WEBSOCKET_ROUTE(app, "/ws")
.onopen([&](crow::websocket::connection& conn) {
CROW_LOG_INFO << "new websocket connection from " << conn.get_remote_ip();
std::lock_guard<std::mutex> lock(mtx_);
std::lock_guard<std::mutex> lock(mtx_);
WSConnId conn_id = utils::AllocNum(id2conn_, last_id_);
// register connection