mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-17 14:29:20 +02:00
TTrain::id() numbers cabs with a local counter, in the order each peer happens to create them, so it cannot address a vehicle across the session. Neither was there any way for a player to see what is available to drive. - network/entities: PeerId (the host is peer 1, remote peers are numbered from 2, so it is a participant rather than a special case) and NetworkEntityId, plus a registry that numbers the drivable vehicles of the loaded scenario in name order and resolves ids back to TDynamicObject - the server owns the numbering and publishes it as VEHICLE_LIST - name, crew occupancy, crew capacity, AI state, availability - on every change and at least every 120 frames, out of band so it stays out of the replay backbuffer; a client binds the received ids to its own copy of the scenario by name - SERVER_HELLO hands the joining peer its PeerId - a multiplayer lobby listing that roster, with vehicles taken by other players shown as such rather than hidden; entering one goes through the existing entervehicle command, the vehicle is never moved The lobby lives inside the driver mode instead of a mode of its own: the world has to keep running while somebody is choosing (a client stops consuming the server's frames the moment its mode is not a command processor), and the same screen is what a player needs to change vehicles later on. Crew occupancy is still derived from the presence of a cab instance; the real crew model, claim handshake and AI takeover follow in stage 3.
129 lines
3.4 KiB
C++
129 lines
3.4 KiB
C++
#pragma once
|
|
#include <memory>
|
|
#include <functional>
|
|
#include <optional>
|
|
#include <queue>
|
|
#include <chrono>
|
|
#include "network/message.h"
|
|
#include "network/entities.h"
|
|
#include "input/command.h"
|
|
|
|
namespace network
|
|
{
|
|
//m7todo: separate client/server connection class?
|
|
class connection
|
|
{
|
|
friend class server;
|
|
friend class client;
|
|
|
|
private:
|
|
const int CATCHUP_PACKETS = 300;
|
|
|
|
bool is_client;
|
|
|
|
protected:
|
|
std::shared_ptr<std::istream> backbuffer;
|
|
size_t backbuffer_pos;
|
|
size_t packet_counter;
|
|
|
|
void send_complete(std::shared_ptr<std::string> buf);
|
|
void catch_up();
|
|
|
|
public:
|
|
std::function<void(const message &msg)> message_handler;
|
|
|
|
virtual void connected() = 0;
|
|
virtual void send_message(const message &msg) = 0;
|
|
virtual void send_messages(const std::vector<std::shared_ptr<message>> &messages) = 0;
|
|
|
|
connection(bool client = false, size_t counter = 0);
|
|
void set_handler(std::function<void(const message &msg)> handler);
|
|
|
|
virtual void disconnect() = 0;
|
|
|
|
enum peer_state {
|
|
AWAITING_HELLO,
|
|
CATCHING_UP,
|
|
ACTIVE,
|
|
DEAD
|
|
};
|
|
peer_state state;
|
|
|
|
// session identity of the peer on the other side of this connection
|
|
PeerId peer_id { PEER_NONE };
|
|
};
|
|
|
|
class server
|
|
{
|
|
private:
|
|
std::shared_ptr<std::istream> backbuffer;
|
|
|
|
protected:
|
|
void handle_message(std::shared_ptr<connection> conn, const message &msg);
|
|
|
|
std::vector<std::shared_ptr<connection>> clients;
|
|
|
|
command_queue::commands_map client_commands_queue;
|
|
|
|
public:
|
|
server(std::shared_ptr<std::istream> buf);
|
|
void push_delta(const frame_info &msg);
|
|
// sends an out of band message to every active peer. unlike push_delta this is not
|
|
// written to the backbuffer, so it does not become part of the replayed history
|
|
void push_message(const message &msg);
|
|
command_queue::commands_map pop_commands();
|
|
};
|
|
|
|
class client
|
|
{
|
|
protected:
|
|
virtual void connect() = 0;
|
|
void handle_message(std::shared_ptr<connection> conn, const message &msg);
|
|
std::shared_ptr<connection> conn;
|
|
size_t resume_frame_counter = 0;
|
|
size_t reconnect_delay = 0;
|
|
|
|
const size_t RECONNECT_DELAY_FRAMES = 60;
|
|
const float MAX_BUFFER_SIZE = 60.0f;
|
|
const float JITTERINESS_MIX = 0.998f;
|
|
const float TARGET_MIN = 2.0f;
|
|
const float TARGET_MIX = 0.98f;
|
|
const float JITTERINESS_MULTIPIER = 2.0f;
|
|
const float CONSUME_MULTIPIER = 0.05f;
|
|
|
|
std::queue<frame_info> delta_queue;
|
|
|
|
float last_target = 20.0f;
|
|
float jitteriness = 1.0f;
|
|
float consume_counter = 0.0f;
|
|
|
|
std::chrono::high_resolution_clock::time_point last_rcv;
|
|
std::chrono::high_resolution_clock::time_point last_frame;
|
|
std::chrono::high_resolution_clock::duration frame_time;
|
|
|
|
public:
|
|
void update();
|
|
std::tuple<double, double, command_queue::commands_map> get_next_delta(int counter);
|
|
void send_commands(command_queue::commands_map commands);
|
|
int get_frame_counter() {
|
|
return resume_frame_counter;
|
|
}
|
|
int get_awaiting_frames() {
|
|
return delta_queue.size();
|
|
}
|
|
};
|
|
|
|
class backend_manager
|
|
{
|
|
public:
|
|
virtual std::shared_ptr<server> create_server(std::shared_ptr<std::fstream>, const std::string &conf) = 0;
|
|
virtual std::shared_ptr<client> create_client(const std::string &conf) = 0;
|
|
virtual void update() = 0;
|
|
};
|
|
|
|
// HACK: static initialization order fiasco fix
|
|
// extern std::unordered_map<std::string, backend_manager*> backend_list;
|
|
using backend_list_t = std::unordered_map<std::string, backend_manager*>;
|
|
backend_list_t& backend_list();
|
|
}
|