2 #include <SDL2/SDL_net.h>
9 #define MAX_NAMESIZE 32
11 typedef struct Client
{
14 char name
[MAX_NAMESIZE
];
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
;
29 static inline float randfm() {
30 return (rand() % 2) ? (-randf()) : (+randf());
33 static inline bool cmpaddr(IPaddress a
, IPaddress b
) {
34 return (a
.host
== b
.host
) && (a
.port
== b
.port
);
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
))
44 static void sv_sync_client(int id
, bool full
) {
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
));
53 static void sv_kill_player(int id
, bool send
, const char * msg
) {
55 assert(client
[id
].connected
);
58 SendMessage(sock
, client
[id
].address
, sv_kill(msg
));
60 client
[id
].connected
= false;
61 g_player_set(id
, false, 0, 0, 0, 0, 0, 0);
62 SDL_Log("Player %s (%i) disconnected: %s", client
[id
].name
, id
, msg
);
65 static void sv_move_player(int id
, ProtocolMessage m
) {
67 assert(client
[id
].connected
);
69 g_player_does(id
, m
.cl
.does
.code
);
72 static void sv_register_player(IPaddress address
, ProtocolMessage m
) {
73 if(m
.cl
.info
.version
!= PROTOCOL_VERSION
)
74 SendMessage(sock
, address
, sv_kill("Uncompatible version"));
77 while((i
< clientlimit
) && (client
[i
].connected
))
80 int namesize
= sizeof(m
.cl
.info
.name
);
81 if(i
>= clientlimit
) {
82 SDL_Log("Too may clints, player %.*s disconnected", namesize
, m
.cl
.info
.name
);
83 SendMessage(sock
, address
, sv_kill("Too many clients"));
87 client
[i
].connected
= true;
88 client
[i
].address
= address
;
89 strncpy(client
[i
].name
, (char*) m
.cl
.info
.name
, MAX_NAMESIZE
);
90 client
[i
].name
[MAX_NAMESIZE
- 1] = 0;
92 SDL_Log("Player %s (%i) connected", client
[i
].name
, i
);
93 SendMessage(sock
, address
, sv_info(name
, i
, clientlimit
));
95 g_player_set(i
, true, randfm(), randfm(), randfm(), 0, 0, 0);
96 sv_sync_client(i
, true);
99 static void sv_recv() {
102 if(!RecvMessage(sock
, &address
, &m
))
106 case CL_INFO
: sv_register_player(address
, m
); break;
107 case CL_KILL
: sv_kill_player(sv_find_client(address
), false, ""); break;
108 case CL_DOES
: sv_move_player(sv_find_client(address
), m
); break;
109 default: SDL_Log("invalid message %i", m
.type
);
113 static void sv_send() {
114 for(int i
= 0; i
< clientlimit
; i
++)
115 if(client
[i
].connected
)
116 sv_sync_client(i
, false);
118 for(int i
= 0; i
< clientlimit
; i
++)
119 g_player
[i
].updated
= false;
122 void sv_start(uint16_t port
) {
123 sock
= OpenPort(port
);
124 lastTime
= SDL_GetTicks();
125 currTime
= SDL_GetTicks();
129 for(int i
= 0; i
< clientlimit
; i
++)
130 if(client
[i
].connected
)
131 sv_kill_player(i
, true, "Server shutdown");
135 void sv_setclientlimit(unsigned int maxclients
) {
136 // TODO disconnect clients
137 clientlimit
= (maxclients
> MAX_PLAYERS
) ? (MAX_PLAYERS
) : (maxclients
);
141 if(currTime
- lastTime
>= TICK_DELAY
) {
145 lastTime
= SDL_GetTicks();
147 currTime
= SDL_GetTicks();