Optimize entity updates
This commit is contained in:
parent
02e779fc70
commit
84a8d269de
@ -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<CharacterSyncFieldFlags>();
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <span>
|
||||
|
||||
#include "net/msg_producer.hpp"
|
||||
#include "transform_node.hpp"
|
||||
@ -29,6 +30,10 @@ public:
|
||||
bool TryUpdate(); // if not already updated
|
||||
int64_t GetUpdateTime() const { return upd_time_; }
|
||||
|
||||
std::span<const char> GetUpdateMsg() const { return update_msg_buf_; }
|
||||
|
||||
void FinalizeFrame();
|
||||
|
||||
void SetNametag(const std::string& nametag);
|
||||
|
||||
void Attach(net::EntNum parentnum);
|
||||
@ -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<char> update_msg_buf_;
|
||||
|
||||
std::string nametag_;
|
||||
net::EntNum parentnum_ = 0;
|
||||
};
|
||||
|
||||
@ -106,6 +106,10 @@ void game::Player::SyncEntities()
|
||||
}
|
||||
}
|
||||
|
||||
// list of entities to send update and messages of
|
||||
static std::vector<const Entity*> 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<net::EntNum>::max());
|
||||
const net::EntNum knownum = (know_it != known_ents_.end() ? *know_it : std::numeric_limits<net::EntNum>::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>();
|
||||
|
||||
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;)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<SimpleEntitySyncFieldFlags>();
|
||||
auto fields = WriteState(msg, prev);
|
||||
|
||||
if (fields == 0)
|
||||
{
|
||||
DiscardUpdateMsg();
|
||||
return;
|
||||
}
|
||||
|
||||
msg.WriteAt(fields_pos, fields);
|
||||
}
|
||||
|
||||
@ -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<VehicleSyncFieldFlags>();
|
||||
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);
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ void game::World::FinishFrame()
|
||||
// reset ent msgs
|
||||
for (auto& [entnum, ent] : ents_)
|
||||
{
|
||||
ent->ResetMsg();
|
||||
ent->FinalizeFrame();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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,16 +160,18 @@ bool game::view::CharacterView::ReadState(net::InMessage& msg)
|
||||
|
||||
auto& new_state = states_[1];
|
||||
|
||||
if (msg)
|
||||
{
|
||||
// parse state delta
|
||||
CharacterSyncFieldFlags fields;
|
||||
if (!msg.Read(fields))
|
||||
if (!msg->Read(fields))
|
||||
return false;
|
||||
|
||||
// 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))
|
||||
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;
|
||||
|
||||
net::DecodePosition(sync_.pos, new_state.trans.position);
|
||||
@ -167,7 +181,7 @@ bool game::view::CharacterView::ReadState(net::InMessage& msg)
|
||||
|
||||
if (fields & CSF_IDLE_ANIM)
|
||||
{
|
||||
if (!msg.Read(sync_.idle_anim))
|
||||
if (!msg->Read(sync_.idle_anim))
|
||||
return false;
|
||||
|
||||
animstate_.idle_anim_idx = sync_.idle_anim;
|
||||
@ -175,7 +189,7 @@ bool game::view::CharacterView::ReadState(net::InMessage& msg)
|
||||
|
||||
if (fields & CSF_LOCO_ANIMS)
|
||||
{
|
||||
if (!msg.Read(sync_.walk_anim) || !msg.Read(sync_.run_anim))
|
||||
if (!msg->Read(sync_.walk_anim) || !msg->Read(sync_.run_anim))
|
||||
return false;
|
||||
|
||||
animstate_.walk_anim_idx = sync_.walk_anim;
|
||||
@ -184,30 +198,17 @@ bool game::view::CharacterView::ReadState(net::InMessage& msg)
|
||||
|
||||
if (fields & CSF_LOCO_VALS)
|
||||
{
|
||||
if (!net::ReadDelta(msg, sync_.loco_blend) || !net::ReadDelta(msg, sync_.loco_phase))
|
||||
if (!net::ReadDelta(*msg, sync_.loco_blend) || !net::ReadDelta(*msg, sync_.loco_phase))
|
||||
return false;
|
||||
|
||||
new_state.loco_blend = sync_.loco_blend.Decode();
|
||||
new_state.loco_phase = sync_.loco_phase.Decode();
|
||||
|
||||
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_--;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,15 +79,17 @@ bool game::view::SimpleEntityView::ReadState(net::InMessage& msg)
|
||||
|
||||
auto& new_state = states_[1];
|
||||
|
||||
if (msg)
|
||||
{
|
||||
// parse state delta
|
||||
SimpleEntitySyncFieldFlags fields;
|
||||
if (!msg.Read(fields))
|
||||
if (!msg->Read(fields))
|
||||
return false;
|
||||
|
||||
// pos
|
||||
if (fields & SESF_POSITION)
|
||||
{
|
||||
if (!net::ReadDelta(msg, sync_.pos.x) || !net::ReadDelta(msg, sync_.pos.y) || !net::ReadDelta(msg, sync_.pos.z))
|
||||
if (!net::ReadDelta(*msg, sync_.pos.x) || !net::ReadDelta(*msg, sync_.pos.y) || !net::ReadDelta(*msg, sync_.pos.z))
|
||||
return false;
|
||||
|
||||
net::DecodePosition(sync_.pos, new_state.trans.position);
|
||||
@ -93,16 +98,12 @@ bool game::view::SimpleEntityView::ReadState(net::InMessage& msg)
|
||||
// rot
|
||||
if (fields & SESF_ROTATION)
|
||||
{
|
||||
if (!net::ReadDelta(msg, sync_.rot.x) || !net::ReadDelta(msg, sync_.rot.y) || !net::ReadDelta(msg, sync_.rot.z))
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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<const assets::Model> model_;
|
||||
|
||||
@ -27,19 +27,15 @@ 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];
|
||||
root_.local = root_trans_[0];
|
||||
|
||||
snd_accel_ = assets::CacheManager::GetSound("data/auto.snd");
|
||||
|
||||
// sync state
|
||||
net::DecodePosition(sync_.pos, root_.local.position);
|
||||
net::DecodeRotation(sync_.rot, root_.local.rotation);
|
||||
|
||||
|
||||
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,30 +143,32 @@ 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();
|
||||
|
||||
if (msg)
|
||||
{
|
||||
// parse state delta
|
||||
VehicleSyncFieldFlags fields;
|
||||
if (!msg.Read(fields))
|
||||
if (!msg->Read(fields))
|
||||
return false;
|
||||
|
||||
// flags
|
||||
if (fields & VSF_FLAGS)
|
||||
{
|
||||
if (!msg.Read(flags_))
|
||||
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))
|
||||
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);
|
||||
@ -177,9 +177,9 @@ bool game::view::VehicleView::ReadState(net::InMessage& msg)
|
||||
// rot
|
||||
if (fields & VSF_ROTATION)
|
||||
{
|
||||
if (!net::ReadDelta(msg, sync_.rot.x) ||
|
||||
!net::ReadDelta(msg, sync_.rot.y) ||
|
||||
!net::ReadDelta(msg, sync_.rot.z))
|
||||
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);
|
||||
@ -188,7 +188,7 @@ bool game::view::VehicleView::ReadState(net::InMessage& msg)
|
||||
// steering
|
||||
if (fields & VSF_STEERING)
|
||||
{
|
||||
if (!net::ReadDelta(msg, sync_.steering))
|
||||
if (!net::ReadDelta(*msg, sync_.steering))
|
||||
return false;
|
||||
|
||||
}
|
||||
@ -200,8 +200,8 @@ bool game::view::VehicleView::ReadState(net::InMessage& msg)
|
||||
{
|
||||
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))
|
||||
if (!net::ReadDelta(*msg, sync_.wheels[i].z_offset) ||
|
||||
!net::ReadDelta(*msg, sync_.wheels[i].speed))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -215,11 +215,6 @@ bool game::view::VehicleView::ReadState(net::InMessage& msg)
|
||||
|
||||
wheel.steering = i < 2 ? steering : 0.0f;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool game::view::VehicleView::ProcessUpdateMsg(net::InMessage& msg)
|
||||
{
|
||||
return ReadState(msg);
|
||||
}
|
||||
|
||||
@ -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<const assets::VehicleModel> model_;
|
||||
|
||||
@ -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)
|
||||
@ -45,6 +46,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<net::EntNum>(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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -39,6 +39,8 @@ enum MessageType : uint8_t
|
||||
MSG_ENTSPAWN,
|
||||
// ENTMSG <EntNum> data...
|
||||
MSG_ENTMSG,
|
||||
// UPDATEENTS <EntCount> ...
|
||||
MSG_UPDATEENTS,
|
||||
// ENTDESTROY <EntNum>
|
||||
MSG_ENTDESTROY,
|
||||
|
||||
@ -67,6 +69,7 @@ using ViewPitchQ = Quantized<uint16_t, -PI_N, PI_N, PI_D>;
|
||||
|
||||
// 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,
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user