DEADSOFTWARE

Изменены физические константы
[netwar.git] / server.c
1 #include <assert.h>
2 #include <SDL2/SDL_net.h>
4 #include "game.h"
5 #include "server.h"
6 #include "network.h"
7 #include "protocol.h"
9 #define MAX_NAMESIZE 32
11 typedef struct Client {
12 bool connected;
13 IPaddress address;
14 char name[MAX_NAMESIZE];
15 } Client;
17 static Uint32 lastTime;
18 static Uint32 currTime;
20 static UDPsocket sock;
21 static Client client[MAX_PLAYERS];
22 static char name[MAX_NAMESIZE] = "netwar! server";
23 static int clientlimit = 0;
25 static inline float randf() {
26 return (float) rand() / (float) RAND_MAX;
27 }
29 static inline float randfm() {
30 return (rand() % 2) ? (-randf()) : (+randf());
31 }
33 static inline bool cmpaddr(IPaddress a, IPaddress b) {
34 return (a.host == b.host) && (a.port == b.port);
35 }
37 static int sv_find_client(IPaddress address) {
38 for(int i = 0; i < clientlimit; i++)
39 if(client[i].connected && cmpaddr(client[i].address, address))
40 return i;
41 return -1;
42 }
44 static void sv_sync_client(int id, bool full) {
45 assert(id >= 0);
46 assert(client[id].connected);
48 for(int i = 0; i < clientlimit; i++)
49 if(full || g_player[i].updated)
50 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, g_player[i].shoot));
52 for(int i = 0; i < MAX_BULLETS; i++)
53 if(full || g_bullet[i].updated)
54 SendMessage(sock, client[id].address, sv_sbul(i, g_bullet[i].owner, g_bullet[i].live, g_bullet[i].x, g_bullet[i].y, g_bullet[i].vx, g_bullet[i].vy, g_bullet[i].tick));
55 }
57 static void sv_spawn_player(int id) {
58 assert(id >= 0);
59 g_player_set(id, true, randfm(), randfm(), randfm(), 0, 0, 0, PLAYER_SHOOT);
60 }
62 static void sv_kill_player(int id, bool send, const char * msg) {
63 assert(id >= 0);
64 assert(client[id].connected);
66 if(send)
67 SendMessage(sock, client[id].address, sv_kill(msg));
69 client[id].connected = false;
70 g_player_set(id, false, 0, 0, 0, 0, 0, 0, 0);
71 SDL_Log("Player %s (%i) disconnected: %s", client[id].name, id, msg);
72 }
74 static void sv_move_player(int id, ProtocolMessage m) {
75 assert(id >= 0);
76 assert(client[id].connected);
78 if(!g_player[id].live && m.cl.does.code.bits)
79 sv_spawn_player(id);
81 if(!g_player[id].live)
82 return;
84 g_player_does(id, m.cl.does.code);
85 }
87 static void sv_kill_address(IPaddress address, const char * msg) {
88 SDL_Log("sv_kill_address: %s", msg);
89 SendMessage(sock, address, sv_kill(msg));
90 }
92 static void sv_register_player(IPaddress address, ClInfo info) {
93 if(info.version != PROTOCOL_VERSION) {
94 sv_kill_address(address, "Uncompatible version");
95 return;
96 }
98 int i = 0;
99 while((i < clientlimit) && (client[i].connected))
100 ++i;
102 if(i >= clientlimit) {
103 sv_kill_address(address, "Too many clients");
104 return;
107 client[i].connected = true;
108 client[i].address = address;
109 strncpy(client[i].name, (char*) info.name, MAX_NAMESIZE);
110 client[i].name[MAX_NAMESIZE - 1] = 0;
112 SDL_Log("Player %s (%i) connected", client[i].name, i);
113 SendMessage(sock, address, sv_info(name, i, clientlimit));
115 sv_spawn_player(i);
116 sv_sync_client(i, true);
119 static void sv_recv_ipmsg(IPaddress address, ProtocolMessage m) {
120 int id = sv_find_client(address);
121 if(id < 0 && m.type != CL_INFO)
122 return;
124 switch(m.type) {
125 case CL_INFO: sv_register_player(address, m.cl.info); break;
126 case CL_KILL: sv_kill_player(id, false, ""); break;
127 case CL_DOES: sv_move_player(id, m); break;
128 default: sv_kill_address(address, "Invalid message");
132 static void sv_recv() {
133 IPaddress address;
134 ProtocolMessage m;
135 while(RecvMessage(sock, &address, &m))
136 sv_recv_ipmsg(address, m);
139 static void sv_send() {
140 for(int i = 0; i < clientlimit; i++)
141 if(client[i].connected)
142 sv_sync_client(i, false);
144 for(int i = 0; i < clientlimit; i++)
145 g_player[i].updated = false;
147 for(int i = 0; i < MAX_BULLETS; i++)
148 g_bullet[i].updated = false;
151 void sv_start(uint16_t port) {
152 g_init(true);
153 sock = OpenPort(port);
154 lastTime = SDL_GetTicks();
155 currTime = SDL_GetTicks();
158 void sv_stop() {
159 for(int i = 0; i < clientlimit; i++)
160 if(client[i].connected)
161 sv_kill_player(i, true, "Server shutdown");
162 ClosePort(sock);
165 void sv_setclientlimit(unsigned int maxclients) {
166 // TODO disconnect clients
167 clientlimit = (maxclients > MAX_PLAYERS) ? (MAX_PLAYERS) : (maxclients);
170 void sv_handle() {
171 if(currTime - lastTime >= TICK_DELAY) {
172 sv_recv();
173 g_update();
174 sv_send();
175 lastTime = SDL_GetTicks();
177 currTime = SDL_GetTicks();