ChatState chat;
+ int time_skipped;
+ unsigned int packets_skipped;
+
};
}
public:
explicit NetworkedInput(World &, Player &, Client &);
+ bool UpdateImportant() const noexcept;
void Update(Entity &, float dt) override;
void PushPlayerUpdate(int dt);
void MergePlayerCorrection(std::uint16_t, const EntityState &);
};
std::list<PlayerHistory> player_hist;
+ glm::vec3 old_movement;
+
+ std::uint8_t old_actions;
std::uint8_t actions;
};
, stat_timer(1000)
, sky(master.GetEnv().loader.LoadCubeMap("skybox"))
, update_status()
-, chat(master.GetEnv(), *this, *this) {
+, chat(master.GetEnv(), *this, *this)
+, time_skipped(0)
+, packets_skipped(0) {
if (!save.Exists()) {
save.Write(master.GetWorldConf());
}
hud.FocusNone();
}
if (world_dt > 0) {
- input.PushPlayerUpdate(world_dt);
+ if (input.UpdateImportant() || packets_skipped >= master.NetStat().SuggestedPacketSkip()) {
+ input.PushPlayerUpdate(time_skipped + world_dt);
+ time_skipped = 0;
+ packets_skipped = 0;
+ } else {
+ time_skipped += world_dt;
+ ++packets_skipped;
+ }
}
hud.Display(res.block_types[player.GetInventorySlot() + 1]);
if (stat_timer.Hit()) {
: PlayerController(world, player)
, client(client)
, player_hist()
+, old_movement(0.0f)
+, old_actions(0)
, actions(0) {
}
+bool NetworkedInput::UpdateImportant() const noexcept {
+ return old_actions != actions || !iszero(old_movement - GetMovement());
+}
+
void NetworkedInput::Update(Entity &, float dt) {
Invalidate();
UpdatePlayer();
entry->packet = packet;
player_hist.splice(player_hist.end(), player_hist, entry);
}
+ old_movement = GetMovement();
+ old_actions = actions;
}
void NetworkedInput::MergePlayerCorrection(uint16_t seq, const EntityState &corrected_state) {
/// get recommended mode of operation
Mode GetMode() const noexcept { return mode; }
+ /// according to current mode, drop this many unimportant packets
+ unsigned int SuggestedPacketSkip() const noexcept { return (1 << mode) - 1; }
/// packet loss as factor
float PacketLoss() const noexcept { return packet_loss; }
void SendSpawn(SpawnStatus &);
void SendDespawn(SpawnStatus &);
+ /// true if updates are pushed to the client this frame
+ bool SendingUpdates() const noexcept;
void QueueUpdate(SpawnStatus &);
void SendUpdates();
unsigned int confirm_wait;
std::vector<SpawnStatus *> entity_updates;
+ unsigned int entity_updates_skipped;
EntityState player_update_state;
std::uint16_t player_update_pack;
, spawns()
, confirm_wait(0)
, entity_updates()
+, entity_updates_skipped(0)
, player_update_state()
, player_update_pack(0)
, player_update_timer(1500)
// they're the same
if (CanDespawn(*global_iter)) {
SendDespawn(*local_iter);
- } else {
+ } else if (SendingUpdates()) {
// update
QueueUpdate(*local_iter);
}
++confirm_wait;
}
+bool ClientConnection::SendingUpdates() const noexcept {
+ return entity_updates_skipped >= NetStat().SuggestedPacketSkip();
+}
+
void ClientConnection::QueueUpdate(SpawnStatus &status) {
// don't send updates while spawn not ack'd or despawn sent
if (status.spawn_pack == -1 && status.despawn_pack == -1) {
}
void ClientConnection::SendUpdates() {
+ if (!SendingUpdates()) {
+ entity_updates.clear();
+ ++entity_updates_skipped;
+ return;
+ }
auto base = PlayerChunks().Base();
auto pack = Prepare<Packet::EntityUpdate>();
pack.WriteChunkBase(base);
Send(Packet::EntityUpdate::GetSize(entity_pos));
}
entity_updates.clear();
+ entity_updates_skipped = 0;
}
void ClientConnection::CheckPlayerFix() {