From: DeaDDooMER Date: Thu, 30 Mar 2017 20:05:35 +0000 (+0300) Subject: Первая версия протестированная на сервере X-Git-Url: http://deadsoftware.ru/gitweb?p=netwar.git;a=commitdiff_plain;h=c4b04d12861ae0eac6315b1c2170013422136f80 Первая версия протестированная на сервере --- c4b04d12861ae0eac6315b1c2170013422136f80 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cbac3ed --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.exe +*.dll +netwar +dedicated diff --git a/bsdmake.sh b/bsdmake.sh new file mode 100755 index 0000000..ad58d29 --- /dev/null +++ b/bsdmake.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +exec cc -o dedicated -lSDL2 -lSDL2_net -lm dedicated.c game.c server.c network.c -I/usr/local/include -L/usr/local/lib diff --git a/client.c b/client.c new file mode 100644 index 0000000..defe5ec --- /dev/null +++ b/client.c @@ -0,0 +1,101 @@ +#include +#include + +#include "game.h" +#include "client.h" +#include "network.h" +#include "protocol.h" + +int cl_playerid; + +static bool run; +static IPaddress addr; +static UDPsocket sock; +static char nickname[32] = "Anonymous"; + +static void cl_kill_client(ProtocolMessage m) { + SDL_Log("Connection refused by server: %.*s\n", (int) sizeof(m.sv.kill.message), m.sv.kill.message); + cl_disconnect(true); +} + +static void cl_update_svinfo(ProtocolMessage m) { + SDL_Log("Connected to server %.*s\n", (int) sizeof(m.sv.info.name), m.sv.info.name); + cl_playerid = m.sv.info.clientid; + assert(cl_playerid < MAX_PLAYERS); + SDL_Log("Player id%i\n", cl_playerid); +} + +static void cl_update_svplayer(ProtocolMessage m) { + g_player_set( + m.sv.splr.clid, + m.sv.splr.live, + b2f(m.sv.splr.x), + b2f(m.sv.splr.y), + b2f(m.sv.splr.r), + b2f(m.sv.splr.vx), + b2f(m.sv.splr.vy), + b2f(m.sv.splr.vr) + ); +} + +void cl_connect(const char * host, uint16_t port) { + if(SDLNet_ResolveHost(&addr, host, (port) ? (port) : (DEFAULT_PORT)) != 0) { + SDL_Log("Unable to resolve host: %s\n", SDLNet_GetError()); + exit(1); + } + + sock = OpenPort(0); + SendMessage(sock, addr, cl_info(nickname)); + + ProtocolMessage m; + bool received = WaitMessage(sock, NULL, &m, 10000); + if(!received) { + SDL_Log("Connection timeout"); + exit(1); + } + + run = true; + if(m.type == SV_KILL) { + cl_kill_client(m); + } else if(m.type == SV_INFO) { + cl_update_svinfo(m); + } else { + SDL_Log("Invalid first message %i\n", m.type); + run = false; + } +} + +void cl_move(DoesCode code) { + g_player_does(cl_playerid, code); + SendMessage(sock, addr, cl_does(code)); +} + +void cl_recv() { + IPaddress address; + ProtocolMessage m; + if(!RecvMessage(sock, &address, &m)) + return; + + switch(m.type) { + case SV_INFO: cl_update_svinfo(m); break; + case SV_KILL: cl_kill_client(m); break; + case SV_SPLR: cl_update_svplayer(m); break; + default: SDL_Log("invalid message %i", m.type); + } +} + +void cl_disconnect(bool force) { + if(!run) + return; + + if(!force) + SendMessage(sock, addr, cl_kill()); + + ClosePort(sock); + + run = false; +} + +bool cl_isrun() { + return run; +} diff --git a/client.h b/client.h new file mode 100644 index 0000000..1a85a23 --- /dev/null +++ b/client.h @@ -0,0 +1,9 @@ +#include + +extern int cl_playerid; + +void cl_connect(const char * host, uint16_t port); +void cl_disconnect(bool force); +void cl_move(DoesCode code); +void cl_recv(); +bool cl_isrun(); diff --git a/dedicated.c b/dedicated.c new file mode 100644 index 0000000..bef813c --- /dev/null +++ b/dedicated.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include + +#include "server.h" +#include "protocol.h" + +static uint16_t port = DEFAULT_PORT; + +static void argverr() { + SDL_Log("Invalid argument\n"); + exit(1); +} + +static void useargs(char ** argv) { + int i = 1; + while(argv[i]) { + if(strcmp(argv[i], "-p") == 0) { + if(argv[++i]) + port = atoi(argv[i++]); + else + argverr(); + } else { + argverr(); + } + } +} + +static void sysinit() { + if(SDL_Init(SDL_INIT_EVENTS) != 0) { + SDL_Log("Unable to initialize SDL: %s\n", SDL_GetError()); + exit(1); + } + atexit(SDL_Quit); + + if(SDLNet_Init() != 0) { + SDL_Log("Unable to initialize SDLNet: %s\n", SDLNet_GetError()); + exit(1); + } + atexit(SDLNet_Quit); +} + +int main(int argc, char ** argv) { + sysinit(); + useargs(argv); + + sv_start(port); + sv_setclientlimit(32); + + bool run = true; + while(run) { + SDL_Event event; + while(SDL_PollEvent(&event)) + if(event.type == SDL_QUIT) + run = false; + + sv_handle(); + + SDL_Delay(1); + } + + sv_stop(); + + return 0; +} diff --git a/game.c b/game.c new file mode 100644 index 0000000..cbc8e15 --- /dev/null +++ b/game.c @@ -0,0 +1,65 @@ +#include + +#include +#include +#include + +#include "game.h" + +#define SPEED 0.00006 +#define ROTATE 0.00004 + +Player g_player[MAX_PLAYERS]; + +static void moveplayer(int id, float speed) { + g_player[id].vx += speed * cos(g_player[id].r * 2 * M_PI); + g_player[id].vy += speed * sin(g_player[id].r * 2 * M_PI); +} + +static void checkspacebound(float * a) { + float x = *a; + if(x < -1) + x = abs(x); + else if(x > 1) + x = -x; + *a = x; +} + +void g_player_set(unsigned int id, bool live, float x, float y, float r, float vx, float vy, float vr) { + assert(id < MAX_PLAYERS); + g_player[id] = (Player) { + .updated = true, + .live = live, + .x = x, + .y = y, + .r = r, + .vx = vx, + .vy = vy, + .vr = vr, + }; +} + +void g_player_does(unsigned int id, DoesCode code) { + assert(id < MAX_PLAYERS); + g_player[id].updated = true; + switch(code) { + case DOES_UP: moveplayer(id, SPEED); break; + case DOES_DOWN: moveplayer(id, -SPEED); break; + case DOES_LEFT: g_player[id].vr -= ROTATE; break; + case DOES_RIGHT: g_player[id].vr += ROTATE; break; + case DOES_FIRE: break; + } +} + +void g_update() { + for(int i = 0; i < MAX_PLAYERS; i++) { + if(g_player[i].live) { + g_player[i].updated = true; + g_player[i].x += g_player[i].vx; + g_player[i].y += g_player[i].vy; + g_player[i].r += g_player[i].vr; + checkspacebound(&g_player[i].x); + checkspacebound(&g_player[i].y); + } + } +} diff --git a/game.h b/game.h new file mode 100644 index 0000000..17c2b68 --- /dev/null +++ b/game.h @@ -0,0 +1,23 @@ +#include + +#include "protocol.h" + +#define MAX_PLAYERS 64 +#define TICK_DELAY (1000 / 60) +#define PLAYER_SIZE 0.01785 + +typedef struct Player { + /* public */ + bool live; + float x, y, r; + float vx, vy, vr; + + /* internal */ + bool updated; +} Player; + +extern Player g_player[MAX_PLAYERS]; + +void g_player_set(unsigned int id, bool live, float x, float y, float r, float vx, float vy, float vr); +void g_player_does(unsigned int id, DoesCode code); +void g_update(); diff --git a/makefile b/makefile new file mode 100644 index 0000000..973189b --- /dev/null +++ b/makefile @@ -0,0 +1,18 @@ +ifdef WIN32 + CC := x86_64-w64-mingw32-gcc + CFLAGS := -g -std=gnu11 -Wall + LDFLAGS := -lmingw32 -lSDL2main -lSDL2 -lSDL2_net -lm + OUTPOSTFIX := .exe +else + CC := gcc + CFLAGS := -g -std=gnu11 -Wall + LDFLAGS := -lSDL2_net -lSDL2 -lm +endif + +all: dedicated.o netwar.o + +netwar.o: + $(CC) $(CFLAGS) -o netwar$(OUTPOSTFIX) netwar.c client.c network.c game.c $(LDFLAGS) + +dedicated.o: + $(CC) $(CFLAGS) -o dedicated$(OUTPOSTFIX) dedicated.c server.c network.c game.c $(LDFLAGS) diff --git a/netwar.c b/netwar.c new file mode 100644 index 0000000..2419456 --- /dev/null +++ b/netwar.c @@ -0,0 +1,165 @@ +#include +#include +#include +#include +#include + +#include "game.h" +#include "client.h" +#include "protocol.h" + +#define WIDTH 640 +#define HEIGHT 480 + +static const float ship[] = { + +1.0, +0.0, -1.0, -1.0, + -1.0, -1.0, +0.0, +0.0, + +0.0, +0.0, -1.0, +1.0, + -1.0, +1.0, +1.0, +0.0, +}; + +static char * host = "localhost"; +static char * nick = "Anonymous"; +static uint16_t port = DEFAULT_PORT; + +static SDL_Window * window; +static SDL_Renderer * renderer; + +static void argverr() { + SDL_Log("Invalid argument\n"); + exit(1); +} + +static void useargs(char ** argv) { + int i = 1; + while(argv[i]) { + if(strcmp(argv[i], "-h") == 0) { + if(argv[++i]) + host = argv[i++]; + else + argverr(); + } else if(strcmp(argv[i], "-p") == 0) { + if(argv[++i]) + port = atoi(argv[i++]); + else + argverr(); + } else if(strcmp(argv[i], "-l") == 0) { + if(argv[++i]) + nick = argv[i++]; + else + argverr(); + } else { + argverr(); + } + } +} + +static void sysinit() { + if(SDL_Init(SDL_INIT_EVERYTHING) != 0) { + SDL_Log("Unable to initialize SDL: %s\n", SDL_GetError()); + exit(1); + } + atexit(SDL_Quit); + + if(SDLNet_Init() != 0) { + SDL_Log("Unable to initialize SDLNet: %s\n", SDLNet_GetError()); + exit(1); + } + atexit(SDLNet_Quit); +} + +static void openwindow() { + SDL_CreateWindowAndRenderer(WIDTH, HEIGHT, 0, &window, &renderer); + SDL_RenderPresent(renderer); +} + +static void closewindow() { + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); +} + +static void paintwindow() { + SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00); + SDL_RenderClear(renderer); + + int cx = WIDTH / 2; + int cy = HEIGHT / 2; + int shipsz = (WIDTH + HEIGHT) / 2 * PLAYER_SIZE; + + for(int i = 0; i < MAX_PLAYERS; i++) { + if(i == cl_playerid) + SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0x00); + else + SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0x00, 0x00); + + int count = sizeof(ship) / sizeof(ship[0]) / 2; + int x = g_player[i].x * WIDTH / 2; + int y = g_player[i].y * HEIGHT / 2; + + SDL_Point pixship[count]; + for(int j = 0; j < count * 2; j += 2) { + float c = cos(g_player[i].r * 2 * M_PI); + float s = sin(g_player[i].r * 2 * M_PI); + float rx = ship[j + 0] * shipsz; + float ry = ship[j + 1] * shipsz; + pixship[j / 2].x = cx + x + (c * rx - s * ry); + pixship[j / 2].y = cy + y + (s * rx + c * ry); + } + + if(g_player[i].live) + SDL_RenderDrawLines(renderer, pixship, count); + } + + SDL_RenderPresent(renderer); +} + +static void keyboardhandle() { + SDL_PumpEvents(); + const Uint8 * key = SDL_GetKeyboardState(NULL); + if(key[SDL_SCANCODE_UP]) + cl_move(DOES_UP); + if(key[SDL_SCANCODE_DOWN]) + cl_move(DOES_DOWN); + if(key[SDL_SCANCODE_LEFT]) + cl_move(DOES_LEFT); + if(key[SDL_SCANCODE_RIGHT]) + cl_move(DOES_RIGHT); + if(key[SDL_SCANCODE_LCTRL]) + cl_move(DOES_FIRE); +} + +int main(int argc, char ** argv) { + sysinit(); + useargs(argv); + openwindow(); + + cl_connect(host, port); + + Uint32 lastTime = SDL_GetTicks(); + Uint32 currTime = SDL_GetTicks(); + + while(cl_isrun()) { + SDL_Event event; + while(SDL_PollEvent(&event)) + if(event.type == SDL_QUIT) + goto cleanup; + + if(currTime - lastTime >= TICK_DELAY) { + keyboardhandle(); + g_update(); + lastTime = SDL_GetTicks(); + } + currTime = SDL_GetTicks(); + + cl_recv(); + + paintwindow(); + + SDL_Delay(1); + } + +cleanup: + closewindow(); + cl_disconnect(false); + return 0; +} diff --git a/network.c b/network.c new file mode 100644 index 0000000..45adb04 --- /dev/null +++ b/network.c @@ -0,0 +1,56 @@ +#include "network.h" + +void SendMessage(UDPsocket sock, IPaddress address, ProtocolMessage m) { + UDPpacket packet = { + .channel = -1, + .data = (void *) &m, + .len = MessageSize(m), + .maxlen = sizeof(ProtocolMessage), + .status = 0, + .address = address, + }; + + if(!SDLNet_UDP_Send(sock, -1, &packet)) { + SDL_Log("Messge not sended: %s\n", SDLNet_GetError()); + exit(1); + } +} + +bool RecvMessage(UDPsocket sock, IPaddress * address, ProtocolMessage * m) { + UDPpacket packet = { + .channel = -1, + .data = (void *) m, + .len = sizeof(ProtocolMessage), + .maxlen = sizeof(ProtocolMessage), + .status = 0, + .address = (IPaddress) { 0, 0 }, + }; + + int status; + status = SDLNet_UDP_Recv(sock, &packet); + if(status < 0) + goto error_recv; + else if(status == 0) + goto error_norecv; + + if(address) + *address = packet.address; + + return true; + +error_recv: + SDL_Log("Messge not received: %s\n", SDLNet_GetError()); + exit(1); +error_norecv: + return false; +} + +bool WaitMessage(UDPsocket sock, IPaddress * address, ProtocolMessage * m, uint32_t timeout) { + uint32_t lastTime = SDL_GetTicks(); + while(SDL_GetTicks() - lastTime < timeout) { + if(RecvMessage(sock, address, m)) + return true; + SDL_Delay(1); + } + return false; +} diff --git a/network.h b/network.h new file mode 100644 index 0000000..3dbcc65 --- /dev/null +++ b/network.h @@ -0,0 +1,26 @@ +#ifndef NETWORK_H_INCLUDED +#define NETWORK_H_INCLUDED + +#include +#include + +#include "protocol.h" + +static inline UDPsocket OpenPort(uint16_t port) { + UDPsocket sock = SDLNet_UDP_Open(SDL_SwapLE16(port)); + if(!sock) { + SDL_Log("SDLNet_UDP_Open: %s\n", SDLNet_GetError()); + exit(1); + } + return sock; +} + +static inline void ClosePort(UDPsocket sock) { + SDLNet_UDP_Close(sock); +} + +void SendMessage(UDPsocket sock, IPaddress address, ProtocolMessage m); +bool RecvMessage(UDPsocket sock, IPaddress * address, ProtocolMessage * m); +bool WaitMessage(UDPsocket sock, IPaddress * address, ProtocolMessage * m, uint32_t timeout); + +#endif /* NETWORK_H_INCLUDED */ diff --git a/protocol.h b/protocol.h new file mode 100644 index 0000000..2681553 --- /dev/null +++ b/protocol.h @@ -0,0 +1,167 @@ +#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 */ diff --git a/server.c b/server.c new file mode 100644 index 0000000..ea28583 --- /dev/null +++ b/server.c @@ -0,0 +1,148 @@ +#include +#include + +#include "game.h" +#include "server.h" +#include "network.h" +#include "protocol.h" + +#define MAX_NAMESIZE 32 + +typedef struct Client { + bool connected; + IPaddress address; + char name[MAX_NAMESIZE]; +} Client; + +static Uint32 lastTime; +static Uint32 currTime; + +static UDPsocket sock; +static Client client[MAX_PLAYERS]; +static char name[MAX_NAMESIZE] = "netwar! server"; +static int clientlimit = 0; + +static inline float randf() { + return (float) rand() / (float) RAND_MAX; +} + +static inline float randfm() { + return (rand() % 2) ? (-randf()) : (+randf()); +} + +static inline bool cmpaddr(IPaddress a, IPaddress b) { + return (a.host == b.host) && (a.port == b.port); +} + +static int sv_find_client(IPaddress address) { + for(int i = 0; i < clientlimit; i++) + if(client[i].connected && cmpaddr(client[i].address, address)) + return i; + return -1; +} + +static void sv_sync_client(int id, bool full) { + assert(id >= 0); + assert(client[id].connected); + + for(int i = 0; i < clientlimit; i++) + if(full || g_player[i].updated) + SendMessage(sock, client[id].address, sv_splr(i, g_player[i].live, g_player[i].x, g_player[i].y, g_player[i].r, g_player[i].vx, g_player[i].vy, g_player[i].vr)); +} + +static void sv_kill_player(int id, bool send, const char * msg) { + assert(id >= 0); + assert(client[id].connected); + + if(send) + SendMessage(sock, client[id].address, sv_kill(msg)); + + client[id].connected = false; + g_player_set(id, false, 0, 0, 0, 0, 0, 0); + SDL_Log("Player %s (%i) disconnected: %s", client[id].name, id, msg); +} + +static void sv_move_player(int id, ProtocolMessage m) { + assert(id >= 0); + assert(client[id].connected); + + g_player_does(id, m.cl.does.code); +} + +static void sv_register_player(IPaddress address, ProtocolMessage m) { + if(m.cl.info.version != PROTOCOL_VERSION) + SendMessage(sock, address, sv_kill("Uncompatible version")); + + int i = 0; + while((i < clientlimit) && (client[i].connected)) + ++i; + + int namesize = sizeof(m.cl.info.name); + if(i >= clientlimit) { + SDL_Log("Too may clints, player %.*s disconnected", namesize, m.cl.info.name); + SendMessage(sock, address, sv_kill("Too many clients")); + return; + } + + client[i].connected = true; + client[i].address = address; + strncpy(client[i].name, (char*) m.cl.info.name, MAX_NAMESIZE); + client[i].name[MAX_NAMESIZE - 1] = 0; + + SDL_Log("Player %s (%i) connected", client[i].name, i); + SendMessage(sock, address, sv_info(name, i, clientlimit)); + + g_player_set(i, true, randfm(), randfm(), randfm(), 0, 0, 0); + sv_sync_client(i, true); +} + +static void sv_recv() { + IPaddress address; + ProtocolMessage m; + if(!RecvMessage(sock, &address, &m)) + return; + + switch(m.type) { + case CL_INFO: sv_register_player(address, m); break; + case CL_KILL: sv_kill_player(sv_find_client(address), false, ""); break; + case CL_DOES: sv_move_player(sv_find_client(address), m); break; + default: SDL_Log("invalid message %i", m.type); + } +} + +static void sv_send() { + for(int i = 0; i < clientlimit; i++) + if(client[i].connected) + sv_sync_client(i, false); + + for(int i = 0; i < clientlimit; i++) + g_player[i].updated = false; +} + +void sv_start(uint16_t port) { + sock = OpenPort(port); + lastTime = SDL_GetTicks(); + currTime = SDL_GetTicks(); +} + +void sv_stop() { + for(int i = 0; i < clientlimit; i++) + if(client[i].connected) + sv_kill_player(i, true, "Server shutdown"); + ClosePort(sock); +} + +void sv_setclientlimit(unsigned int maxclients) { + // TODO disconnect clients + clientlimit = (maxclients > MAX_PLAYERS) ? (MAX_PLAYERS) : (maxclients); +} + +void sv_handle() { + if(currTime - lastTime >= TICK_DELAY) { + sv_recv(); + g_update(); + sv_send(); + lastTime = SDL_GetTicks(); + } + currTime = SDL_GetTicks(); +} diff --git a/server.h b/server.h new file mode 100644 index 0000000..895062c --- /dev/null +++ b/server.h @@ -0,0 +1,7 @@ +#include + +void sv_start (uint16_t port); +void sv_stop (); +void sv_handle (); + +void sv_setclientlimit(unsigned int maxclients); diff --git a/start.bat b/start.bat new file mode 100644 index 0000000..3689d29 --- /dev/null +++ b/start.bat @@ -0,0 +1 @@ +netwar.exe -h succubus.deadsoftware.ru