diff --git a/src/game/character.cpp b/src/game/character.cpp index 1448af1..8a5833c 100644 --- a/src/game/character.cpp +++ b/src/game/character.cpp @@ -220,16 +220,15 @@ void game::Character::UpdateSyncState() void game::Character::SendUpdateMsg() { - auto msg = BeginEntMsg(net::EMSG_UPDATE); + auto msg = BeginUpdateMsg(); auto fields_pos = msg.Reserve(); auto fields = WriteState(msg, sync_[1 - sync_current_]); - // TODO: allow this - // if (fields == 0) - // { - // DiscardMsg(); - // return; - // } + if (fields == 0) + { + DiscardUpdateMsg(); + return; + } msg.WriteAt(fields_pos, fields); } diff --git a/src/game/entity.cpp b/src/game/entity.cpp index 2aef0c7..276fa5c 100644 --- a/src/game/entity.cpp +++ b/src/game/entity.cpp @@ -40,6 +40,12 @@ bool game::Entity::TryUpdate() return true; } +void game::Entity::FinalizeFrame() +{ + ResetMsg(); + DiscardUpdateMsg(); +} + void game::Entity::SetNametag(const std::string& nametag) { nametag_ = nametag; @@ -89,3 +95,14 @@ net::OutMessage game::Entity::BeginEntMsg(net::EntMsgType type) msg.Write(type); return msg; } + +net::OutMessage game::Entity::BeginUpdateMsg() +{ + update_msg_buf_.clear(); // make sure + return net::OutMessage(update_msg_buf_); +} + +void game::Entity::DiscardUpdateMsg() +{ + update_msg_buf_.clear(); +} diff --git a/src/game/entity.hpp b/src/game/entity.hpp index c5c4821..166469e 100644 --- a/src/game/entity.hpp +++ b/src/game/entity.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include "net/msg_producer.hpp" #include "transform_node.hpp" @@ -28,6 +29,10 @@ public: virtual void Update(); bool TryUpdate(); // if not already updated int64_t GetUpdateTime() const { return upd_time_; } + + std::span GetUpdateMsg() const { return update_msg_buf_; } + + void FinalizeFrame(); void SetNametag(const std::string& nametag); @@ -55,6 +60,8 @@ private: protected: net::OutMessage BeginEntMsg(net::EntMsgType type); + net::OutMessage BeginUpdateMsg(); + void DiscardUpdateMsg(); protected: World& world_; @@ -70,6 +77,9 @@ protected: private: int64_t upd_time_ = -1; + + std::vector update_msg_buf_; + std::string nametag_; net::EntNum parentnum_ = 0; }; diff --git a/src/game/player.cpp b/src/game/player.cpp index 78f24c8..4375b6a 100644 --- a/src/game/player.cpp +++ b/src/game/player.cpp @@ -106,6 +106,10 @@ void game::Player::SyncEntities() } } + // list of entities to send update and messages of + static std::vector upd_ents; + upd_ents.clear(); + const auto& ents = world_->GetEntities(); auto ent_it = ents.begin(); @@ -116,36 +120,73 @@ void game::Player::SyncEntities() const net::EntNum entnum = (ent_it != ents.end() ? ent_it->first : std::numeric_limits::max()); const net::EntNum knownum = (know_it != known_ents_.end() ? *know_it : std::numeric_limits::max()); - if (entnum == knownum) // ----- entity exists and is currently known ----- + if (entnum == knownum) // entity exists and is currently known { const Entity& e = *ent_it->second; if (ShouldSeeEntity(e)) // still visible? { - SendUpdateEntity(e); // 2) update + upd_ents.push_back(&e); ++ent_it; ++know_it; } - else // vanished for player + else // not longed visible for player { - SendDestroyEntity(knownum); // 3) destroy - know_it = known_ents_.erase(know_it); // remove from known + SendDestroyEntity(knownum); + know_it = known_ents_.erase(know_it); ++ent_it; } } - else if (entnum < knownum) // ----- entity exists, player does NOT know it ----- + else if (entnum < knownum) // entity exists, player does NOT know it { const Entity& e = *ent_it->second; - if (ShouldSeeEntity(e)) // 1) become visible + if (ShouldSeeEntity(e)) { SendInitEntity(e); - known_ents_.insert(entnum); // add to known - } // else: stays invisible, nothing to do + known_ents_.insert(entnum); + } ++ent_it; } - else // ----- player knows it, but it no longer exists ----- + else // player knows it, but it no longer exists { - SendDestroyEntity(knownum); // 3) destroy - know_it = known_ents_.erase(know_it); // remove from known + SendDestroyEntity(knownum); + know_it = known_ents_.erase(know_it); + } + } + + // write update payload + { + auto msg = BeginMsg(net::MSG_UPDATEENTS); + size_t count_pos = msg.Reserve(); + + net::EntCount count = 0; + net::EntNum lastnum = 0; + + for (auto ent : upd_ents) + { + auto ent_upd = ent->GetUpdateMsg(); + if (!ent_upd.empty()) + { + auto numdiff = ent->GetEntNum() - lastnum; + + msg.WriteVarInt(numdiff); + msg.Write(ent_upd); + + ++count; + lastnum = ent->GetEntNum(); + } + } + + msg.WriteAt(count_pos, count); + } + + // write other entity msgs + for (auto ent : upd_ents) + { + auto ent_msg = ent->GetMsg(); + if (!ent_msg.empty()) + { + auto msg = BeginMsg(); + msg.Write(ent_msg); } } } @@ -171,13 +212,6 @@ void game::Player::SendInitEntity(const Entity& entity) entity.SendInitData(*this, msg); } -void game::Player::SendUpdateEntity(const Entity& entity) -{ - MSGDEBUG(std::cout << "seding update ent " << entity.GetEntNum() << std::endl;) - auto msg = BeginMsg(); // no CMD here, these are already included in entity message payload! - msg.Write(entity.GetMsg()); -} - void game::Player::SendDestroyEntity(net::EntNum entnum) { MSGDEBUG(std::cout << "seding ENTDESTROY " << entnum << std::endl;) diff --git a/src/game/player.hpp b/src/game/player.hpp index b0e046a..de72609 100644 --- a/src/game/player.hpp +++ b/src/game/player.hpp @@ -45,7 +45,6 @@ private: void SyncEntities(); bool ShouldSeeEntity(const Entity& entity) const; void SendInitEntity(const Entity& entity); - void SendUpdateEntity(const Entity& entity); void SendDestroyEntity(net::EntNum entnum); // msg handlers diff --git a/src/game/simple_entity.cpp b/src/game/simple_entity.cpp index 9a880d3..51ca76f 100644 --- a/src/game/simple_entity.cpp +++ b/src/game/simple_entity.cpp @@ -71,11 +71,18 @@ game::SimpleEntitySyncFieldFlags game::SimpleEntity::WriteState(net::OutMessage& void game::SimpleEntity::SendUpdateMsg() { - auto msg = BeginEntMsg(net::EMSG_UPDATE); + auto msg = BeginUpdateMsg(); // write state against previous const SimpleEntitySyncState& prev = sync_[1 - sync_current_]; size_t fields_pos = msg.Reserve(); auto fields = WriteState(msg, prev); + + if (fields == 0) + { + DiscardUpdateMsg(); + return; + } + msg.WriteAt(fields_pos, fields); } diff --git a/src/game/vehicle.cpp b/src/game/vehicle.cpp index f5aa547..f779716 100644 --- a/src/game/vehicle.cpp +++ b/src/game/vehicle.cpp @@ -456,16 +456,15 @@ game::VehicleSyncFieldFlags game::Vehicle::WriteState(net::OutMessage& msg, cons void game::Vehicle::SendUpdateMsg() { - auto msg = BeginEntMsg(net::EMSG_UPDATE); + auto msg = BeginUpdateMsg(); auto fields_pos = msg.Reserve(); auto fields = WriteState(msg, sync_[1 - sync_current_]); - // TODO: allow this - // if (fields == 0) - // { - // DiscardMsg(); - // return; - // } + if (fields == 0) + { + DiscardUpdateMsg(); + return; + } msg.WriteAt(fields_pos, fields); } diff --git a/src/game/world.cpp b/src/game/world.cpp index aac2f52..4c300c0 100644 --- a/src/game/world.cpp +++ b/src/game/world.cpp @@ -73,7 +73,7 @@ void game::World::FinishFrame() // reset ent msgs for (auto& [entnum, ent] : ents_) { - ent->ResetMsg(); + ent->FinalizeFrame(); } } diff --git a/src/gameview/characterview.cpp b/src/gameview/characterview.cpp index b894e0b..6c69e5f 100644 --- a/src/gameview/characterview.cpp +++ b/src/gameview/characterview.cpp @@ -30,11 +30,10 @@ game::view::CharacterView::CharacterView(WorldView& world, net::InMessage& msg) UpdateSurfaceMask(); // read initial state - if (!ReadState(msg)) + if (!ReadState(&msg)) throw EntityInitError(); - states_[0] = states_[1]; // lerp from the read state to avoid jump - + OnAttach(); radius_ = 2.0f; } @@ -43,18 +42,16 @@ bool game::view::CharacterView::ProcessMsg(net::EntMsgType type, net::InMessage& { switch (type) { - case net::EMSG_UPDATE: - return ProcessUpdateMsg(msg); - - case net::EMSG_ATTACH: - skip_lerps_ = 1; - return Super::ProcessMsg(type, msg); - default: return Super::ProcessMsg(type, msg); } } +bool game::view::CharacterView::ProcessUpdateMsg(net::InMessage* msg) +{ + return ReadState(msg); +} + void game::view::CharacterView::Update(const UpdateInfo& info) { Super::Update(info); @@ -66,7 +63,12 @@ void game::view::CharacterView::Update(const UpdateInfo& info) root_.local = Transform::Lerp(states_[0].trans, states_[1].trans, t); animstate_.loco_blend = glm::mix(states_[0].loco_blend, states_[1].loco_blend, t); - animstate_.loco_phase = glm::mod(glm::mix(states_[0].loco_phase, states_[1].loco_phase, t), 1.0f); + + float loco_phase0 = states_[0].loco_phase; + float loco_phase1 = states_[1].loco_phase; + if (loco_phase0 > loco_phase1) + loco_phase0 -= 1.0f; + animstate_.loco_phase = glm::mod(glm::mix(loco_phase0, loco_phase1, t), 1.0f); animstate_.ApplyToSkeleton(sk_); @@ -137,7 +139,17 @@ void game::view::CharacterView::Draw(const DrawArgs& args) } } -bool game::view::CharacterView::ReadState(net::InMessage& msg) +void game::view::CharacterView::OnAttach() +{ + states_[0] = states_[1]; // lerp from the read state to avoid jump + + // init view state + root_.local = states_[0].trans; + animstate_.loco_blend = states_[0].loco_blend; + animstate_.loco_phase = states_[0].loco_phase; +} + +bool game::view::CharacterView::ReadState(net::InMessage* msg) { update_time_ = world_.GetTime(); @@ -148,66 +160,55 @@ bool game::view::CharacterView::ReadState(net::InMessage& msg) auto& new_state = states_[1]; - // parse state delta - CharacterSyncFieldFlags fields; - if (!msg.Read(fields)) - return false; - - // transform - if (fields & CSF_TRANSFORM) + if (msg) { - if (!net::ReadDelta(msg, sync_.pos.x) || !net::ReadDelta(msg, sync_.pos.y) || - !net::ReadDelta(msg, sync_.pos.z) || !net::ReadDelta(msg, sync_.yaw)) + // parse state delta + CharacterSyncFieldFlags fields; + if (!msg->Read(fields)) return false; - net::DecodePosition(sync_.pos, new_state.trans.position); - new_state.trans.rotation = glm::rotate(glm::quat(1.0f, 0.0f, 0.0f, 0.0f), - sync_.yaw.Decode() + glm::pi() * 0.5f, glm::vec3(0, 0, 1)); - } + // transform + if (fields & CSF_TRANSFORM) + { + if (!net::ReadDelta(*msg, sync_.pos.x) || !net::ReadDelta(*msg, sync_.pos.y) || + !net::ReadDelta(*msg, sync_.pos.z) || !net::ReadDelta(*msg, sync_.yaw)) + return false; - if (fields & CSF_IDLE_ANIM) - { - if (!msg.Read(sync_.idle_anim)) - return false; + net::DecodePosition(sync_.pos, new_state.trans.position); + new_state.trans.rotation = glm::rotate(glm::quat(1.0f, 0.0f, 0.0f, 0.0f), + sync_.yaw.Decode() + glm::pi() * 0.5f, glm::vec3(0, 0, 1)); + } - animstate_.idle_anim_idx = sync_.idle_anim; - } + if (fields & CSF_IDLE_ANIM) + { + if (!msg->Read(sync_.idle_anim)) + return false; - if (fields & CSF_LOCO_ANIMS) - { - if (!msg.Read(sync_.walk_anim) || !msg.Read(sync_.run_anim)) - return false; + animstate_.idle_anim_idx = sync_.idle_anim; + } - animstate_.walk_anim_idx = sync_.walk_anim; - animstate_.run_anim_idx = sync_.run_anim; - } + if (fields & CSF_LOCO_ANIMS) + { + if (!msg->Read(sync_.walk_anim) || !msg->Read(sync_.run_anim)) + return false; - if (fields & CSF_LOCO_VALS) - { - if (!net::ReadDelta(msg, sync_.loco_blend) || !net::ReadDelta(msg, sync_.loco_phase)) - return false; + animstate_.walk_anim_idx = sync_.walk_anim; + animstate_.run_anim_idx = sync_.run_anim; + } - new_state.loco_blend = sync_.loco_blend.Decode(); - new_state.loco_phase = sync_.loco_phase.Decode(); + if (fields & CSF_LOCO_VALS) + { + if (!net::ReadDelta(*msg, sync_.loco_blend) || !net::ReadDelta(*msg, sync_.loco_phase)) + return false; - if (new_state.loco_phase < states_[0].loco_phase) - states_[0].loco_phase -= 1.0f; - } - - if (skip_lerps_ > 0) - { - states_[0] = states_[1]; - skip_lerps_--; + new_state.loco_blend = sync_.loco_blend.Decode(); + new_state.loco_phase = sync_.loco_phase.Decode(); + } } return true; } -bool game::view::CharacterView::ProcessUpdateMsg(net::InMessage& msg) -{ - return ReadState(msg); -} - game::view::CharacterView::SurfaceMask game::view::CharacterView::GetSurfaceMask(const std::string& name) { const auto& surface_names = basemodel_->GetMesh()->surface_names; diff --git a/src/gameview/characterview.hpp b/src/gameview/characterview.hpp index f66a1e8..e9e1371 100644 --- a/src/gameview/characterview.hpp +++ b/src/gameview/characterview.hpp @@ -34,12 +34,15 @@ public: DELETE_COPY_MOVE(CharacterView) virtual bool ProcessMsg(net::EntMsgType type, net::InMessage& msg) override; + virtual bool ProcessUpdateMsg(net::InMessage* msg) override; virtual void Update(const UpdateInfo& info) override; virtual void Draw(const DrawArgs& args) override; +protected: + virtual void OnAttach() override; + private: - bool ReadState(net::InMessage& msg); - bool ProcessUpdateMsg(net::InMessage& msg); + bool ReadState(net::InMessage* msg); SurfaceMask GetSurfaceMask(const std::string& name); void UpdateSurfaceMask(); @@ -63,7 +66,6 @@ private: CharacterSyncState sync_; CharacterViewState states_[2]; float update_time_ = 0.0f; - size_t skip_lerps_ = 0; }; } diff --git a/src/gameview/entityview.cpp b/src/gameview/entityview.cpp index 04af451..1aac7b7 100644 --- a/src/gameview/entityview.cpp +++ b/src/gameview/entityview.cpp @@ -30,6 +30,11 @@ bool game::view::EntityView::ProcessMsg(net::EntMsgType type, net::InMessage& ms } } +bool game::view::EntityView::ProcessUpdateMsg(net::InMessage* msg) +{ + return true; +} + bool game::view::EntityView::TryUpdate(const UpdateInfo& info) { float time = world_.GetTime(); @@ -81,7 +86,12 @@ bool game::view::EntityView::ReadNametag(net::InMessage& msg) bool game::view::EntityView::ReadAttach(net::InMessage& msg) { - return msg.Read(parentnum_); + if (!msg.Read(parentnum_)) + return false; + + OnAttach(); + + return true; } bool game::view::EntityView::ProcessPlaySoundMsg(net::InMessage& msg) diff --git a/src/gameview/entityview.hpp b/src/gameview/entityview.hpp index dc5a973..0cd8cbd 100644 --- a/src/gameview/entityview.hpp +++ b/src/gameview/entityview.hpp @@ -36,6 +36,7 @@ public: DELETE_COPY_MOVE(EntityView) virtual bool ProcessMsg(net::EntMsgType type, net::InMessage& msg); + virtual bool ProcessUpdateMsg(net::InMessage* msg); bool TryUpdate(const UpdateInfo& info); // if not updated already virtual void Update(const UpdateInfo& info); @@ -47,6 +48,9 @@ public: virtual ~EntityView() = default; +protected: + virtual void OnAttach() {} + private: bool ReadNametag(net::InMessage& msg); bool ReadAttach(net::InMessage& msg); diff --git a/src/gameview/simple_entity_view.cpp b/src/gameview/simple_entity_view.cpp index b4681e4..97518f2 100644 --- a/src/gameview/simple_entity_view.cpp +++ b/src/gameview/simple_entity_view.cpp @@ -17,10 +17,11 @@ game::view::SimpleEntityView::SimpleEntityView(WorldView& world, net::InMessage& throw EntityInitError(); } - if (!ReadState(msg)) + if (!ReadState(&msg)) throw EntityInitError(); states_[0] = states_[1]; // lerp from the read state to avoid jump + root_.local = states_[0].trans; radius_ = 20.0f; } @@ -29,14 +30,16 @@ bool game::view::SimpleEntityView::ProcessMsg(net::EntMsgType type, net::InMessa { switch (type) { - case net::EMSG_UPDATE: - return ProcessUpdateMsg(msg); - default: return Super::ProcessMsg(type, msg); } } +bool game::view::SimpleEntityView::ProcessUpdateMsg(net::InMessage* msg) +{ + return ReadState(msg); +} + void game::view::SimpleEntityView::Update(const UpdateInfo& info) { Super::Update(info); @@ -67,7 +70,7 @@ void game::view::SimpleEntityView::Draw(const DrawArgs& args) } } -bool game::view::SimpleEntityView::ReadState(net::InMessage& msg) +bool game::view::SimpleEntityView::ReadState(net::InMessage* msg) { update_time_ = world_.GetTime(); @@ -76,33 +79,31 @@ bool game::view::SimpleEntityView::ReadState(net::InMessage& msg) auto& new_state = states_[1]; - // parse state delta - SimpleEntitySyncFieldFlags fields; - if (!msg.Read(fields)) - return false; - - // pos - if (fields & SESF_POSITION) + if (msg) { - if (!net::ReadDelta(msg, sync_.pos.x) || !net::ReadDelta(msg, sync_.pos.y) || !net::ReadDelta(msg, sync_.pos.z)) + // parse state delta + SimpleEntitySyncFieldFlags fields; + if (!msg->Read(fields)) return false; - net::DecodePosition(sync_.pos, new_state.trans.position); - } + // pos + if (fields & SESF_POSITION) + { + if (!net::ReadDelta(*msg, sync_.pos.x) || !net::ReadDelta(*msg, sync_.pos.y) || !net::ReadDelta(*msg, sync_.pos.z)) + return false; - // rot - if (fields & SESF_ROTATION) - { - if (!net::ReadDelta(msg, sync_.rot.x) || !net::ReadDelta(msg, sync_.rot.y) || !net::ReadDelta(msg, sync_.rot.z)) - return false; + net::DecodePosition(sync_.pos, new_state.trans.position); + } - net::DecodeRotation(sync_.rot, new_state.trans.rotation); + // rot + if (fields & SESF_ROTATION) + { + if (!net::ReadDelta(*msg, sync_.rot.x) || !net::ReadDelta(*msg, sync_.rot.y) || !net::ReadDelta(*msg, sync_.rot.z)) + return false; + + net::DecodeRotation(sync_.rot, new_state.trans.rotation); + } } return true; } - -bool game::view::SimpleEntityView::ProcessUpdateMsg(net::InMessage& msg) -{ - return ReadState(msg); -} diff --git a/src/gameview/simple_entity_view.hpp b/src/gameview/simple_entity_view.hpp index 2f557ab..edc3a4d 100644 --- a/src/gameview/simple_entity_view.hpp +++ b/src/gameview/simple_entity_view.hpp @@ -20,13 +20,12 @@ public: SimpleEntityView(WorldView& world, net::InMessage& msg); virtual bool ProcessMsg(net::EntMsgType type, net::InMessage& msg) override; + virtual bool ProcessUpdateMsg(net::InMessage* msg) override; virtual void Update(const UpdateInfo& info) override; virtual void Draw(const DrawArgs& args) override; private: - bool ReadState(net::InMessage& msg); - - bool ProcessUpdateMsg(net::InMessage& msg); + bool ReadState(net::InMessage* msg); private: std::shared_ptr model_; diff --git a/src/gameview/vehicleview.cpp b/src/gameview/vehicleview.cpp index 8af44f4..de391c7 100644 --- a/src/gameview/vehicleview.cpp +++ b/src/gameview/vehicleview.cpp @@ -27,18 +27,14 @@ game::view::VehicleView::VehicleView(WorldView& world, net::InMessage& msg) color_ = glm::vec4(color, 1.0f); - if (!ReadState(msg)) + if (!ReadState(&msg)) throw EntityInitError(); // init the other transform to identical root_trans_[0] = root_trans_[1]; - - snd_accel_ = assets::CacheManager::GetSound("data/auto.snd"); - - // sync state - net::DecodePosition(sync_.pos, root_.local.position); - net::DecodeRotation(sync_.rot, root_.local.rotation); + root_.local = root_trans_[0]; + snd_accel_ = assets::CacheManager::GetSound("data/auto.snd"); radius_ = 3.0f; } @@ -47,14 +43,16 @@ bool game::view::VehicleView::ProcessMsg(net::EntMsgType type, net::InMessage& m { switch (type) { - case net::EMSG_UPDATE: - return ProcessUpdateMsg(msg); - default: return Super::ProcessMsg(type, msg); } } +bool game::view::VehicleView::ProcessUpdateMsg(net::InMessage* msg) +{ + return ReadState(msg); +} + void game::view::VehicleView::Update(const UpdateInfo& info) { Super::Update(info); @@ -145,81 +143,78 @@ void game::view::VehicleView::Draw(const DrawArgs& args) } } -bool game::view::VehicleView::ReadState(net::InMessage& msg) +bool game::view::VehicleView::ReadState(net::InMessage* msg) { root_trans_[0] = root_.local; auto& root_trans = root_trans_[1]; update_time_ = world_.GetTime(); - // parse state delta - VehicleSyncFieldFlags fields; - if (!msg.Read(fields)) - return false; - - // flags - if (fields & VSF_FLAGS) + if (msg) { - if (!msg.Read(flags_)) - return false; - } - - // pos - if (fields & VSF_POSITION) - { - if (!net::ReadDelta(msg, sync_.pos.x) || - !net::ReadDelta(msg, sync_.pos.y) || - !net::ReadDelta(msg, sync_.pos.z)) + // parse state delta + VehicleSyncFieldFlags fields; + if (!msg->Read(fields)) return false; - net::DecodePosition(sync_.pos, root_trans.position); - } - - // rot - if (fields & VSF_ROTATION) - { - if (!net::ReadDelta(msg, sync_.rot.x) || - !net::ReadDelta(msg, sync_.rot.y) || - !net::ReadDelta(msg, sync_.rot.z)) - return false; - - net::DecodeRotation(sync_.rot, root_trans.rotation); - } - - // steering - if (fields & VSF_STEERING) - { - if (!net::ReadDelta(msg, sync_.steering)) - return false; - - } - - float steering = sync_.steering.Decode(); - - // wheels - if (fields & VSF_WHEELS) - { - for (size_t i = 0; i < wheels_.size(); ++i) + // flags + if (fields & VSF_FLAGS) { - if (!net::ReadDelta(msg, sync_.wheels[i].z_offset) || - !net::ReadDelta(msg, sync_.wheels[i].speed)) + if (!msg->Read(flags_)) return false; } + + // pos + if (fields & VSF_POSITION) + { + if (!net::ReadDelta(*msg, sync_.pos.x) || + !net::ReadDelta(*msg, sync_.pos.y) || + !net::ReadDelta(*msg, sync_.pos.z)) + return false; + + net::DecodePosition(sync_.pos, root_trans.position); + } + + // rot + if (fields & VSF_ROTATION) + { + if (!net::ReadDelta(*msg, sync_.rot.x) || + !net::ReadDelta(*msg, sync_.rot.y) || + !net::ReadDelta(*msg, sync_.rot.z)) + return false; + + net::DecodeRotation(sync_.rot, root_trans.rotation); + } + + // steering + if (fields & VSF_STEERING) + { + if (!net::ReadDelta(*msg, sync_.steering)) + return false; + + } + + float steering = sync_.steering.Decode(); + + // wheels + if (fields & VSF_WHEELS) + { + for (size_t i = 0; i < wheels_.size(); ++i) + { + if (!net::ReadDelta(*msg, sync_.wheels[i].z_offset) || + !net::ReadDelta(*msg, sync_.wheels[i].speed)) + return false; + } + } + + const auto& wheels = model_->GetWheels(); + for (size_t i = 0; i < wheels_.size(); ++i) + { + auto& wheel = wheels_[i]; + wheel.z_offset = sync_.wheels[i].z_offset.Decode(); + wheel.speed = sync_.wheels[i].speed.Decode(); + + wheel.steering = i < 2 ? steering : 0.0f; + } } - - const auto& wheels = model_->GetWheels(); - for (size_t i = 0; i < wheels_.size(); ++i) - { - auto& wheel = wheels_[i]; - wheel.z_offset = sync_.wheels[i].z_offset.Decode(); - wheel.speed = sync_.wheels[i].speed.Decode(); - - wheel.steering = i < 2 ? steering : 0.0f; - } - return true; } - -bool game::view::VehicleView::ProcessUpdateMsg(net::InMessage& msg) -{ - return ReadState(msg); -} diff --git a/src/gameview/vehicleview.hpp b/src/gameview/vehicleview.hpp index ce8aa59..d6d76ca 100644 --- a/src/gameview/vehicleview.hpp +++ b/src/gameview/vehicleview.hpp @@ -27,12 +27,12 @@ public: DELETE_COPY_MOVE(VehicleView) virtual bool ProcessMsg(net::EntMsgType type, net::InMessage& msg) override; + virtual bool ProcessUpdateMsg(net::InMessage* msg) override; virtual void Update(const UpdateInfo& info) override; virtual void Draw(const DrawArgs& args) override; private: - bool ReadState(net::InMessage& msg); - bool ProcessUpdateMsg(net::InMessage& msg); + bool ReadState(net::InMessage* msg); private: std::shared_ptr model_; diff --git a/src/gameview/worldview.cpp b/src/gameview/worldview.cpp index e0170d8..3c97e2f 100644 --- a/src/gameview/worldview.cpp +++ b/src/gameview/worldview.cpp @@ -31,8 +31,9 @@ game::view::WorldView::WorldView(ClientSession& session, net::InMessage& msg) : // cache common snds and stuff Cache(assets::CacheManager::GetSound("data/breaksign.snd")); Cache(assets::CacheManager::GetSound("data/breakpatnik.snd")); + Cache(assets::CacheManager::GetSound("data/breakwood.snd")); + Cache(assets::CacheManager::GetSound("data/cardoor.snd")); Cache(assets::CacheManager::GetSound("data/crash.snd")); - Cache(assets::CacheManager::GetSound("data/breakwindow.snd")); } bool game::view::WorldView::ProcessMsg(net::MessageType type, net::InMessage& msg) @@ -44,6 +45,9 @@ bool game::view::WorldView::ProcessMsg(net::MessageType type, net::InMessage& ms case net::MSG_ENTMSG: return ProcessEntMsgMsg(msg); + + case net::MSG_UPDATEENTS: + return ProcessUpdateEntsMsg(msg); case net::MSG_ENTDESTROY: return ProcessEntDestroyMsg(msg); @@ -172,6 +176,49 @@ bool game::view::WorldView::ProcessEntMsgMsg(net::InMessage& msg) return ent_it->second->ProcessMsg(type, msg); } +bool game::view::WorldView::ProcessUpdateEntsMsg(net::InMessage& msg) +{ + net::EntCount count; + if (!msg.Read(count)) + return false; + + net::EntNum current = 0; + auto it = ents_.begin(); + + for (net::EntNum i = 0; i < count; ++i) + { + int64_t diff; + if (!msg.ReadVarInt(diff)) + return false; + + current += static_cast(diff); + + while (it->first < current) + { + it->second->ProcessUpdateMsg(nullptr); // blank update + ++it; + if (it == ents_.end()) + return false; + } + + if (it->first != current) + { + return false; // exact num wasnt found and it overrun + } + + if (!it->second->ProcessUpdateMsg(&msg)) + return false; + } + + // process remaining + for (; it != ents_.end(); ++it) + { + it->second->ProcessUpdateMsg(nullptr); + } + + return true; +} + bool game::view::WorldView::ProcessEntDestroyMsg(net::InMessage& msg) { net::EntNum entnum; diff --git a/src/gameview/worldview.hpp b/src/gameview/worldview.hpp index 930e96d..b15b33a 100644 --- a/src/gameview/worldview.hpp +++ b/src/gameview/worldview.hpp @@ -36,6 +36,7 @@ private: // msg handlers bool ProcessEntSpawnMsg(net::InMessage& msg); bool ProcessEntMsgMsg(net::InMessage& msg); + bool ProcessUpdateEntsMsg(net::InMessage& msg); bool ProcessEntDestroyMsg(net::InMessage& msg); bool ProcessObjDestroyOrRespawnMsg(net::InMessage& msg, bool enable); diff --git a/src/net/defs.hpp b/src/net/defs.hpp index 972fa5e..d90b8bc 100644 --- a/src/net/defs.hpp +++ b/src/net/defs.hpp @@ -39,6 +39,8 @@ enum MessageType : uint8_t MSG_ENTSPAWN, // ENTMSG data... MSG_ENTMSG, + // UPDATEENTS ... + MSG_UPDATEENTS, // ENTDESTROY MSG_ENTDESTROY, @@ -67,6 +69,7 @@ using ViewPitchQ = Quantized; // entities using EntNum = uint16_t; +using EntCount = EntNum; enum EntType : uint8_t { @@ -85,7 +88,7 @@ enum EntMsgType : uint8_t EMSG_NAMETAG, EMSG_ATTACH, - EMSG_UPDATE, + // EMSG_UPDATE, // deprecated EMSG_PLAYSOUND, };