mpfw/mpfw_server/NetQuake.h
2025-07-26 16:27:54 -04:00

259 lines
5.4 KiB
C++

#pragma once
#include <iostream>
#include "Config.h"
#include <asio/ts/internet.hpp>
#include <asio.hpp>
#include <map>
#include <vector>
#include <thread>
namespace NetQuake {
struct NetworkGenericPacket { // generic packet straight from server
char type[2];
char length[2];
std::string remainder;
};
enum PacketType {
NQ_CONTROL_PACKET = 0x8000,
NQ_MESSAGE_BLOCK_CHUNK = 0x0001,
NQ_MESSAGE_BLOCK_END = 0x0009,
NQ_ACK = 0x0002,
NQ_UNRELIABLE = 0x0010,
NQ_UNKNOWN_PACKET
};
struct SerializedGenericPacket {
PacketType type;
int length;
std::string remainder;
};
SerializedGenericPacket Serialize(NetworkGenericPacket ngp);
enum ClientMessageType {
CLIENT_MESSAGE_NOOP = 0x00,
CLIENT_MESSAGE_KEEPALIVE = 0x01,
CLIENT_MESSAGE_DISCONNECT = 0x02,
CLIENT_MESSAGE_MOVEMENT = 0x03,
CLIENT_MESSAGE_CONSOLE = 0x04,
CLIENT_MESSAGE_UNKNOWN
};
struct ClientMessage {
ClientMessageType type;
std::string data;
};
struct ClientMessageBlock {
std::vector<ClientMessage> messages;
};
struct GenericGamePacket {
PacketType type;
int length;
long packetNumber;
ClientMessageBlock messageBlock;
bool valid = false;
};
GenericGamePacket toGenericGamePacket(SerializedGenericPacket sgp);
enum DemoMessageType {
DEM_BAD = 0x00,
DEM_NOP = 0x01,
DEM_DISCONNECT = 0x02,
DEM_UPDATESTAT = 0x03,
DEM_VERSION = 0x04,
DEM_SETVIEW = 0x05,
DEM_SOUND = 0x06,
DEM_TIME = 0x07,
DEM_PRINT = 0x08,
DEM_STUFFTEXT = 0x09,
DEM_SETANGLE = 0x0A,
DEM_SERVERINFO = 0x0B,
DEM_LIGHTSTYLE = 0x0C,
DEM_UPDATENAME = 0x0D,
DEM_UPDATEFRAGS = 0x0E,
DEM_CLIENTDATA = 0x0F,
DEM_STOPSOUND = 0x10,
DEM_UPDATECOLORS = 0x11,
DEM_PARTICLE = 0x12,
DEM_DAMAGE = 0x13,
DEM_SPAWNSTATIC = 0x14,
DEM_SPAWNBINARY = 0x15,
DEM_SPAWNBASELINE = 0x16,
DEM_TEMP_ENTITY = 0x17,
DEM_SETPAUSE = 0x18,
DEM_SIGNONUM = 0x19,
DEM_CENTERPRINT = 0x1A,
DEM_KILLEDMONSTER = 0x1B,
DEM_FOUNDSECRET = 0x1C,
DEM_SPAWNSTATICSOUND = 0x1D,
DEM_INTERMISSION = 0x1E,
DEM_FINALE = 0x1F,
DEM_CDTRACK = 0x20,
DEM_SELLSCREEN = 0x21,
DEM_CUTSCENE = 0x22,
DEM_UPDATEENTITY = 0x80
};
class GenericServerMessage {
public:
DemoMessageType type;
virtual std::string Serialize() = 0;
};
namespace ServerMessages {
class Print : public GenericServerMessage { // 0x08
public:
std::string text = "";
Print() { this->type = DEM_PRINT; }
std::string Serialize();
};
class ServerInfo : public GenericServerMessage { // 0x0B
public:
long serverVersion = 15;
long maxClients;
long multi;
std::string mapName;
std::vector<std::string> precacheModels;
long numModels;
std::vector<std::string> precacheSounds;
long numSounds;
ServerInfo() {
this->type = DEM_SERVERINFO;
precacheModels = std::vector<std::string>(256);
precacheSounds = std::vector<std::string>(256);
}
std::string Serialize();
};
class SignOn : public GenericServerMessage {
public:
long signon;
SignOn() { type = DEM_SIGNONUM; }
std::string Serialize();
};
}
class ServerMessageBlock{
public:
PacketType type;
int order;
std::vector<GenericServerMessage*> serverMessages;
std::string Serialize();
};
enum Control_OpCode {
CONTROL_CONNECTION_REQUEST = 0x01,
CONTROL_SERVER_INFO_REQUEST = 0x02,
CONTROL_PLAYER_INFO_REQUEST = 0x03,
CONTROL_RULE_INFO_REQUEST = 0x04,
CONTROL_SERVER_INFO_REPLY = 0x83
};
struct GenericControlPacket {
Control_OpCode opcode;
std::string remainder;
GenericControlPacket(SerializedGenericPacket sgp);
};
enum NetProtocolVersion {
QTEST1 = 0x01,
QUNKNOWN = 0x02,
QGOLD = 0x03
};
struct ServerInfoRequest {
std::string gameName;
NetProtocolVersion netVersion;
ServerInfoRequest(GenericControlPacket gcp);
};
struct Address {
std::string ip;
int port;
};
struct ServerInfoReply {
Address address;
std::string hostname;
std::string levelname;
char currentPlayers;
char maxPlayers;
NetProtocolVersion netVersion;
};
std::string Serialize(ServerInfoReply sirp);
struct ConnectionRequest {
std::string gameName;
NetProtocolVersion netVersion;
ConnectionRequest(GenericControlPacket gcp);
};
struct ConnectionRequestReply {
bool reject;
short port; // LITTLE-ENDIAN (!)(!)(!)(!)(!)
char unknown[2]; // [ have fun :) ]
std::string reason;
};
::std::string Serialize(ConnectionRequestReply crr);
class GameEndpoint {
std::thread internalThread;
public:
GameEndpoint();
GameEndpoint(Config::Config* config, int port, asio::ip::udp::endpoint startRemote);
~GameEndpoint();
};
namespace Internal {
struct NewEndpointRequestReply {
bool ready = false;
bool error = false;
std::string reason;
int port;
asio::ip::udp::endpoint startRemote;
};
class InternalRequestConsole {
std::vector<NewEndpointRequestReply> newEndpointRequests;
int lastEndpointRequestTreated = 0;
public:
InternalRequestConsole();
int newEndpointRequest(asio::ip::udp::endpoint ep);
NewEndpointRequestReply getEndpointRequest(int id);
void Update(Config::Config *config, std::vector<GameEndpoint>* gameEndpointsVector);
~InternalRequestConsole();
};
}
std::string AcknowledgePacket(int packet);
void NetQuake_ControlServer(Internal::InternalRequestConsole* internalRequestConsole, Config::Config* config, bool* serverRunning);
void NetQuake_EndpointServer(Config::Config* config, int port, asio::ip::udp::endpoint startRemote);
}