#pragma once #include "network/multi_time_manager.h" struct physics_info; constexpr int PACKET_INFO_LIMIT = 4; // we should never need more than 4 packets to do interpolation. Overwrite the oldest ones if we do. typedef struct packet_info { int frame; // this allows us to directly compare one packet to another. int remote_missiontime; // the remote timestamp that matches this packet. vec3d position; // what it says on the tin vec3d velocity; // what it says on the tin vec3d rotational_velocity; // what it says on the tin vec3d desired_velocity; // what it says on the tin vec3d desired_rotational_velocity; // this one is only actually from the packet when we are dealing with a player ship. angles angle; // what it says on the tin, this is kept in angles so we can directly slerp later. packet_info(int frame_in = 0, int time_in = 0, const vec3d* position_in = &vmd_zero_vector, const vec3d* velocity_in = &vmd_zero_vector, const vec3d* rotational_velocity_in = &vmd_zero_vector, const vec3d* desired_velocity_in = &vmd_zero_vector, const vec3d* desired_rotational_velocity_in = &vmd_zero_vector, const angles* angles_in = &vmd_zero_angles) { frame = frame_in; remote_missiontime = time_in; position = *position_in; velocity = *velocity_in; rotational_velocity = *rotational_velocity_in; desired_velocity = *desired_velocity_in; desired_rotational_velocity = *desired_rotational_velocity_in; angle = *angles_in; } }packet_info; // the real center of the new interpolation code. When a packet is received, its frame is used as the key in the unordered_map _packets // those keys are kept in _received_frames class interpolation_manager { private: int _upcoming_packet_index; // what packet should we look at as the next packet. -1 if we do not yet have enough packets. int _prev_packet_index; // what was the last packet? This and Upcoming are both idices into the _packets vector. int _local_skip_forward; // TODO: Use this? Used on the server if a client is inexplicably ahead of us. bool _simulation_mode; // are we currently simulating as if this were a normal ship? bool _packets_expended; // have we used up all packets while interpolating? SCP_vector _packets; // all the info from the position/orientation portion of packets that we care to keep int _source_player_index; void reassess_packet_index(vec3d* pos, matrix* ori, physics_info* pip); // for finding which packets from within _packets we should use void replace_packet(int index, vec3d* pos, matrix* orient, physics_info* pip); // a function that acts as a workaround, when coming out of simulation_mode // Frame numbers that helps us figure out if we should ignore new information coming from the server because // we already received a newer packet than this one for that type of info. int _hull_comparison_frame; // what frame was the last hull information received? int _shields_comparison_frame; // what frame was the last shield information received? SCP_vector _subsystems_comparison_frame; // what frame was the last subsystem information received? (for each subsystem) int _ai_comparison_frame; // what frame was the last ai information received? public: // adds a new packet, whilst also manually sorting the relevant entries void add_packet(int frame, int time_delta, vec3d* position, vec3d* velocity, vec3d* rotational_velocity, vec3d* desired_velocity, vec3d* desired_rotational_velocity, angles* angles, int player_index); void interpolate(vec3d* pos, matrix* ori, physics_info* pip, bool player_ship); int get_hull_comparison_frame() { return _hull_comparison_frame; } int get_shields_comparison_frame() { return _shields_comparison_frame; } int get_subsystem_comparison_frame(int i) { if (i < static_cast(_subsystems_comparison_frame.size()) && i >= 0) { return _subsystems_comparison_frame[i]; } // if it somehow got passed nonsense, chances are what it is is trying to read is nonsense, and INT_MAX will keep it from doing anything crazy. else { return INT_MAX; } } int get_ai_comparison_frame() { return _ai_comparison_frame; } void set_hull_comparison_frame(int frame) { _hull_comparison_frame = frame; } void set_shields_comparison_frame(int frame) { _shields_comparison_frame = frame; } void set_subsystem_comparison_frames(int i, int frame) { if (i < static_cast(_subsystems_comparison_frame.size()) && i >= 0) { _subsystems_comparison_frame[i] = frame; } } void set_ai_comparison_frame(int frame) { _ai_comparison_frame = frame; } void force_interpolation_mode() { _simulation_mode = true; } void reset() { if (!(Game_mode & GM_MULTIPLAYER)){ return; } _packets.clear(); _packets.reserve(PACKET_INFO_LIMIT * 2); _upcoming_packet_index = -1; _prev_packet_index = -1; _simulation_mode = false; _packets_expended = false; _local_skip_forward = 0; _hull_comparison_frame = -1; _shields_comparison_frame = -1; _source_player_index = -1; // if we are resetting, that means that the ship may be respawning, so don't clear it out, just set the values to invalid. for (auto& frame : _subsystems_comparison_frame) { frame = -1; } _ai_comparison_frame = -1; } void clean_up() { _packets.clear(); _packets.shrink_to_fit(); _subsystems_comparison_frame.clear(); _subsystems_comparison_frame.shrink_to_fit(); } interpolation_manager() { _upcoming_packet_index = -1; _prev_packet_index = -1; _simulation_mode = false; _packets_expended = false; _local_skip_forward = 0; _hull_comparison_frame = -1; _shields_comparison_frame = -1; _ai_comparison_frame = -1; _source_player_index = -1; } };