#ifndef PROTOCOL_H_INCLUDED #define PROTOCOL_H_INCLUDED #include #include #include #define PROTOCOL_PORT 29386 #define PROTOCOL_VERSION 3 #define PROTOCOL_F8FRAC (1 << 7) #define PACKED __attribute__((__packed__)) typedef enum { INVALID = 0, CL_INFO = 1, CL_KILL = 2, CL_DOES = 3, SV_INFO = 128, SV_KILL = 139, SV_SPLR = 130, SV_SBUL = 131, } MessageType; typedef union DoesBits { uint8_t bits; struct PACKED { uint8_t up : 1; uint8_t down : 1; uint8_t left : 1; uint8_t right : 1; uint8_t fire : 1; }; } DoesBits; typedef struct PACKED ClInfo { uint8_t type; uint8_t version; uint8_t name[32]; } ClInfo; typedef struct PACKED ClKill { uint8_t type; } ClKill; typedef struct PACKED ClDoes { uint8_t type; DoesBits code; } ClDoes; typedef struct PACKED SvInfo { uint8_t type; uint8_t version; uint8_t clientid; uint8_t maxclients; uint8_t name[32]; } SvInfo; typedef struct PACKED SvKill { uint8_t type; uint8_t message[256]; } SvKill; typedef struct PACKED SvSplr { uint8_t type; uint8_t clid; uint8_t live; uint8_t x, y, r; uint8_t vx, vy, vr; uint8_t shoot; } SvSplr; typedef struct PACKED SvSbul { uint8_t type; uint8_t id; uint8_t owner; uint8_t live; uint8_t x, y; uint8_t vx, vy; uint8_t tick; } SvSbul; typedef union ClMessage { uint8_t type; ClInfo info; ClKill kill; ClDoes does; } ClMessage; typedef union SvMessage { uint8_t type; SvInfo info; SvKill kill; SvSplr splr; SvSbul sbul; } SvMessage; typedef union ProtocolMessage { uint8_t type; ClMessage cl; SvMessage sv; } ProtocolMessage; static inline int8_t f2b(float x) { return x * PROTOCOL_F8FRAC; } static inline float b2f(int8_t x) { return (float) x / PROTOCOL_F8FRAC; } static inline int MessageTypeSize(MessageType type) { switch(type) { case CL_INFO: return sizeof(ClInfo); case CL_KILL: return sizeof(ClKill); case CL_DOES: return sizeof(ClDoes); case SV_INFO: return sizeof(SvInfo); case SV_KILL: return sizeof(SvKill); case SV_SPLR: return sizeof(SvSplr); case SV_SBUL: return sizeof(SvSbul); default: return sizeof(ProtocolMessage); } } static inline int MessageSize(ProtocolMessage m) { return MessageTypeSize(m.type); } static inline ProtocolMessage cl_info(const char * name) { ClInfo m = { .type = CL_INFO, .version = PROTOCOL_VERSION, }; strncpy((char*)m.name, name, sizeof(m.name)); return (ProtocolMessage) (ClMessage) m; } static inline ProtocolMessage cl_kill() { return (ProtocolMessage) (ClMessage) (ClKill) { .type = CL_KILL, }; } static inline ProtocolMessage cl_does(DoesBits code) { return (ProtocolMessage) (ClMessage) (ClDoes) { .type = CL_DOES, .code = code, }; } static inline ProtocolMessage sv_info(const char * name, int clientid, int maxclients) { SvInfo m = { .type = SV_INFO, .version = PROTOCOL_VERSION, .clientid = clientid, .maxclients = maxclients, }; strncpy((char*) m.name, name, sizeof(m.name)); return (ProtocolMessage) (SvMessage) m; } static inline ProtocolMessage sv_kill(const char * msg) { SvKill m = { .type = SV_KILL, }; strncpy((char*) m.message, msg, sizeof(m.message)); return (ProtocolMessage) (SvMessage) m; } static inline ProtocolMessage sv_splr(int clid, bool live, float x, float y, float r, float vx, float vy, float vr, int shoot) { return (ProtocolMessage) (SvMessage) (SvSplr) { .type = SV_SPLR, .clid = clid, .live = live, .x = f2b(x), .y = f2b(y), .r = f2b(r), .vx = f2b(vx), .vy = f2b(vy), .vr = f2b(vr), .shoot = shoot, }; } static inline ProtocolMessage sv_sbul(int id, int owner, bool live, float x, float y, float vx, float vy, int tick) { return (ProtocolMessage) (SvMessage) (SvSbul) { .type = SV_SBUL, .id = id, .owner = owner, .live = live, .x = f2b(x), .y = f2b(y), .vx = f2b(vx), .vy = f2b(vy), .tick = tick, }; } #undef PACKED #endif /* PROTOCOL_H_INCLUDED */