#ifndef PROTOCOL_H_INCLUDED #define PROTOCOL_H_INCLUDED #include #include #include #define DEFAULT_PORT 29386 #define PROTOCOL_VERSION 0 #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, } MessageType; typedef enum { DOES_UP = 0, DOES_DOWN = 1, DOES_LEFT = 2, DOES_RIGHT = 3, DOES_FIRE = 4, } DoesCode; 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; uint8_t 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; } SvSplr; 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; } 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); 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(DoesCode 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) { 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), }; } #undef PACKED #endif /* PROTOCOL_H_INCLUDED */