/[LeafOK_CVS]/pvpgn-1.7.4/src/bnetd/anongame.c
ViewVC logotype

Contents of /pvpgn-1.7.4/src/bnetd/anongame.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (show annotations) (vendor branch)
Tue Jun 6 03:41:37 2006 UTC (19 years, 9 months ago) by sysadm
Branch: GNU, MAIN
CVS Tags: pvpgn_1-7-4-0_MIL, arelease, HEAD
Changes since 1.1: +0 -0 lines
Content type: text/x-csrc
no message

1 /*
2 * Copyright (C) 2004 CreepLord (creeplord@pvpgn.org)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #include "common/setup_before.h"
20
21 #ifdef WIN32_GUI
22 #include <win32/winmain.h>
23 #endif
24
25 #ifdef HAVE_STRING_H
26 # include <string.h>
27 #else
28 # ifdef HAVE_STRINGS_H
29 # include <strings.h>
30 # endif
31 # ifdef HAVE_MEMORY_H
32 # include <memory.h>
33 # endif
34 #endif
35 #ifdef STDC_HEADERS
36 # include <stdlib.h>
37 #else
38 # ifdef HAVE_MALLOC_H
39 # include <malloc.h>
40 # endif
41 #endif
42
43 #ifdef WIN32
44 # include "compat/socket.h" /* is this needed */
45 #endif
46
47 #include "compat/strdup.h"
48 #include "common/packet.h"
49 #include "common/eventlog.h"
50 #include "common/tag.h"
51 #include "team.h"
52 #include "account.h"
53 #include "account_wrap.h"
54 #include "connection.h"
55 #include "common/queue.h"
56 #include "prefs.h"
57 #include "common/bn_type.h"
58 #include "common/list.h"
59 #include "common/addr.h"
60 #include "common/xalloc.h"
61 #include "versioncheck.h"
62 #include "anongame.h"
63 #include "tournament.h"
64 #include "timer.h"
65 #include "ladder.h"
66 #include "server.h"
67 #include "anongame_maplists.h"
68 #include "anongame_gameresult.h"
69 #include "common/trans.h"
70 #include "common/setup_after.h"
71
72 #define MAX_LEVEL 100
73
74 /* [quetzal] 20020827 - this one get modified by anongame_queue player when there're enough
75 * players and map has been chosen based on their preferences. otherwise its NULL
76 */
77 static char *mapname = NULL;
78
79 static int players[ANONGAME_TYPES] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
80 static t_connection *player[ANONGAME_TYPES][ANONGAME_MAX_GAMECOUNT];
81
82 /* [quetzal] 20020815 - queue to hold matching players */
83 static t_list *matchlists[ANONGAME_TYPES][MAX_LEVEL];
84
85 long average_anongame_search_time = 30;
86 unsigned int anongame_search_count = 0;
87
88 /**********************************************************************************/
89 static t_connection *_connlist_find_connection_by_uid(int uid);
90 static char const *_conn_get_versiontag(t_connection * c);
91
92 static int _anongame_gametype_to_queue(int type, int gametype);
93 static int _anongame_level_by_queue(t_connection * c, int queue);
94 static char *_get_map_from_prefs(int queue, t_uint32 cur_prefs, t_clienttag clienttag);
95 static unsigned int _anongame_get_gametype_tab(int queue);
96
97 static int _anongame_totalplayers(int queue);
98 static int _anongame_totalteams(int queue);
99
100 static int _handle_anongame_search(t_connection * c, t_packet const *packet);
101 static int _anongame_queue(t_connection * c, int queue, t_uint32 map_prefs);
102 static int _anongame_compare_level(void const *a, void const *b);
103 static int _anongame_order_queue(int queue);
104 static int _anongame_match(t_connection * c, int queue);
105 static int _anongame_search_found(int queue);
106 /**********************************************************************************/
107
108 static t_connection *_connlist_find_connection_by_uid(int uid)
109 {
110 return connlist_find_connection_by_account(accountlist_find_account_by_uid(uid));
111 }
112
113 static char const *_conn_get_versiontag(t_connection * c)
114 {
115 return versioncheck_get_versiontag(conn_get_versioncheck(c));
116 }
117
118 /**********/
119
120 static char const *_anongame_queue_to_string(int queue)
121 {
122 switch (queue) {
123 case ANONGAME_TYPE_1V1:
124 return "PG 1v1";
125 case ANONGAME_TYPE_2V2:
126 return "PG 2v2";
127 case ANONGAME_TYPE_3V3:
128 return "PG 3v3";
129 case ANONGAME_TYPE_4V4:
130 return "PG 4v4";
131 case ANONGAME_TYPE_SMALL_FFA:
132 return "PG SFFA";
133 case ANONGAME_TYPE_AT_2V2:
134 return "AT 2v2";
135 case ANONGAME_TYPE_TEAM_FFA:
136 return "AT TFFA";
137 case ANONGAME_TYPE_AT_3V3:
138 return "AT 3v3";
139 case ANONGAME_TYPE_AT_4V4:
140 return "AT 4v4";
141 case ANONGAME_TYPE_TY:
142 return "TOURNEY";
143 case ANONGAME_TYPE_5V5:
144 return "PG 5v5";
145 case ANONGAME_TYPE_6V6:
146 return "PG 6v6";
147 case ANONGAME_TYPE_2V2V2:
148 return "PG 2v2v2";
149 case ANONGAME_TYPE_3V3V3:
150 return "PG 3v3v3";
151 case ANONGAME_TYPE_4V4V4:
152 return "PG 4v4v4";
153 case ANONGAME_TYPE_2V2V2V2:
154 return "PG 2v2v2v2";
155 case ANONGAME_TYPE_3V3V3V3:
156 return "PG 3v3v3v3";
157 case ANONGAME_TYPE_AT_2V2V2:
158 return "AT 2v2v2";
159 default:
160 eventlog(eventlog_level_error, __FUNCTION__, "invalid queue number %d", queue);
161 return "error";
162 }
163 }
164
165 static int _anongame_gametype_to_queue(int type, int gametype)
166 {
167 switch (type) {
168 case 0: /* PG */
169 switch (gametype) {
170 case 0:
171 return ANONGAME_TYPE_1V1;
172 case 1:
173 return ANONGAME_TYPE_2V2;
174 case 2:
175 return ANONGAME_TYPE_3V3;
176 case 3:
177 return ANONGAME_TYPE_4V4;
178 case 4:
179 return ANONGAME_TYPE_SMALL_FFA;
180 case 5:
181 return ANONGAME_TYPE_5V5;
182 case 6:
183 return ANONGAME_TYPE_6V6;
184 case 7:
185 return ANONGAME_TYPE_2V2V2;
186 case 8:
187 return ANONGAME_TYPE_3V3V3;
188 case 9:
189 return ANONGAME_TYPE_4V4V4;
190 case 10:
191 return ANONGAME_TYPE_2V2V2V2;
192 case 11:
193 return ANONGAME_TYPE_3V3V3V3;
194 default:
195 eventlog(eventlog_level_error, __FUNCTION__, "invalid PG game type: %d", gametype);
196 return -1;
197 }
198 case 1: /* AT */
199 switch (gametype) {
200 case 0:
201 return ANONGAME_TYPE_AT_2V2;
202 case 2:
203 return ANONGAME_TYPE_AT_3V3;
204 case 3:
205 return ANONGAME_TYPE_AT_4V4;
206 case 4:
207 return ANONGAME_TYPE_AT_2V2V2;
208 default:
209 eventlog(eventlog_level_error, __FUNCTION__, "invalid AT game type: %d", gametype);
210 return -1;
211 }
212 case 2: /* TY */
213 return ANONGAME_TYPE_TY;
214 default:
215 eventlog(eventlog_level_error, __FUNCTION__, "invalid type: %d", type);
216 return -1;
217 }
218 }
219
220 static int _anongame_level_by_queue(t_connection * c, int queue)
221 {
222 t_clienttag ct = conn_get_clienttag(c);
223
224 switch (queue) {
225 case ANONGAME_TYPE_1V1:
226 return account_get_ladder_level(conn_get_account(c), ct, ladder_id_solo);
227 case ANONGAME_TYPE_2V2:
228 case ANONGAME_TYPE_3V3:
229 case ANONGAME_TYPE_4V4:
230 case ANONGAME_TYPE_5V5:
231 case ANONGAME_TYPE_6V6:
232 case ANONGAME_TYPE_2V2V2:
233 case ANONGAME_TYPE_3V3V3:
234 case ANONGAME_TYPE_4V4V4:
235 case ANONGAME_TYPE_2V2V2V2:
236 case ANONGAME_TYPE_3V3V3V3:
237 return account_get_ladder_level(conn_get_account(c), ct, ladder_id_ffa);
238 case ANONGAME_TYPE_SMALL_FFA:
239 case ANONGAME_TYPE_TEAM_FFA:
240 return account_get_ladder_level(conn_get_account(c), ct, ladder_id_ffa);
241 case ANONGAME_TYPE_AT_2V2:
242 case ANONGAME_TYPE_AT_3V3:
243 case ANONGAME_TYPE_AT_4V4:
244 case ANONGAME_TYPE_AT_2V2V2:
245 return 0;
246 case ANONGAME_TYPE_TY: /* set to ((wins * 3) + ties - losses) ie. prelim score */
247 return tournament_get_player_score(conn_get_account(c));
248 default:
249 eventlog(eventlog_level_error, __FUNCTION__, "unknown queue: %d", queue);
250 return -1;
251 }
252 }
253
254 static char *_get_map_from_prefs(int queue, t_uint32 cur_prefs, t_clienttag clienttag)
255 {
256 int i, j = 0;
257 char *default_map, *selected;
258 char *res_maps[32];
259
260 if (clienttag == CLIENTTAG_WARCRAFT3_UINT)
261 default_map = "Maps\\(8)PlainsOfSnow.w3m";
262 else if (clienttag == CLIENTTAG_WAR3XP_UINT)
263 default_map = "Maps\\(8)PlainsOfSnow.w3m";
264 else {
265 eventlog(eventlog_level_error, __FUNCTION__, "invalid clienttag : %s", clienttag);
266 return "Maps\\(8)PlainsOfSnow.w3m";
267 }
268
269 for (i = 0; i < 32; i++)
270 res_maps[i] = NULL;
271
272 for (i = 0; i < 32; i++) {
273 if (cur_prefs & 1)
274 res_maps[j++] = maplists_get_map(queue, clienttag, i + 1);
275 cur_prefs >>= 1;
276 }
277
278 i = rand() % j;
279 if (res_maps[i])
280 selected = res_maps[i];
281 else
282 selected = default_map;
283
284 eventlog(eventlog_level_trace, __FUNCTION__, "got map %s from prefs", selected);
285 return selected;
286 }
287
288 static unsigned int _anongame_get_gametype_tab(int queue)
289 {
290 /* dizzy: this changed in 1.05 */
291 switch (queue) {
292 case ANONGAME_TYPE_1V1:
293 return SERVER_ANONGAME_SOLO_STR;
294 case ANONGAME_TYPE_2V2:
295 case ANONGAME_TYPE_3V3:
296 case ANONGAME_TYPE_4V4:
297 case ANONGAME_TYPE_5V5:
298 case ANONGAME_TYPE_6V6:
299 case ANONGAME_TYPE_2V2V2:
300 case ANONGAME_TYPE_3V3V3:
301 case ANONGAME_TYPE_4V4V4:
302 case ANONGAME_TYPE_2V2V2V2:
303 case ANONGAME_TYPE_3V3V3V3:
304 return SERVER_ANONGAME_TEAM_STR;
305 case ANONGAME_TYPE_SMALL_FFA:
306 return SERVER_ANONGAME_SFFA_STR;
307 case ANONGAME_TYPE_TEAM_FFA:
308 return 0; /* Team FFA is no longer supported */
309 case ANONGAME_TYPE_AT_2V2:
310 return SERVER_ANONGAME_AT2v2_STR;
311 case ANONGAME_TYPE_AT_3V3:
312 return SERVER_ANONGAME_AT3v3_STR;
313 case ANONGAME_TYPE_AT_4V4:
314 return SERVER_ANONGAME_AT4v4_STR;
315 case ANONGAME_TYPE_AT_2V2V2:
316 return SERVER_ANONGAME_AT2v2_STR; /* fixme */
317 case ANONGAME_TYPE_TY:
318 return SERVER_ANONGAME_TY_STR;
319 default:
320 eventlog(eventlog_level_error, __FUNCTION__, "invalid queue (%d)", queue);
321 return 0;
322 }
323 }
324
325 static int _anongame_totalplayers(int queue)
326 {
327 switch (queue) {
328 case ANONGAME_TYPE_1V1:
329 return 2;
330 case ANONGAME_TYPE_2V2:
331 case ANONGAME_TYPE_AT_2V2:
332 case ANONGAME_TYPE_SMALL_FFA: /* fixme: total players not always 4 */
333 return 4;
334 case ANONGAME_TYPE_3V3:
335 case ANONGAME_TYPE_AT_3V3:
336 case ANONGAME_TYPE_2V2V2:
337 case ANONGAME_TYPE_AT_2V2V2:
338 return 6;
339 case ANONGAME_TYPE_4V4:
340 case ANONGAME_TYPE_AT_4V4:
341 case ANONGAME_TYPE_TEAM_FFA:
342 case ANONGAME_TYPE_2V2V2V2:
343 return 8;
344 case ANONGAME_TYPE_3V3V3:
345 return 9;
346 case ANONGAME_TYPE_5V5:
347 return 10;
348 case ANONGAME_TYPE_6V6:
349 case ANONGAME_TYPE_4V4V4:
350 case ANONGAME_TYPE_3V3V3V3:
351 return 12;
352 case ANONGAME_TYPE_TY:
353 return tournament_get_totalplayers();
354 default:
355 eventlog(eventlog_level_error, __FUNCTION__, "unknown queue: %d", queue);
356 return 0;
357 }
358 }
359
360 static int _anongame_totalteams(int queue)
361 {
362 /* dont forget to change this if you make some game type with more teams */
363 #define ANONGAME_MAX_TEAMS 4
364 switch (queue) {
365 case ANONGAME_TYPE_1V1:
366 case ANONGAME_TYPE_SMALL_FFA:
367 return 0;
368 case ANONGAME_TYPE_2V2:
369 case ANONGAME_TYPE_3V3:
370 case ANONGAME_TYPE_4V4:
371 case ANONGAME_TYPE_5V5:
372 case ANONGAME_TYPE_6V6:
373 case ANONGAME_TYPE_AT_2V2:
374 case ANONGAME_TYPE_AT_3V3:
375 case ANONGAME_TYPE_AT_4V4:
376 return 2;
377 case ANONGAME_TYPE_2V2V2:
378 case ANONGAME_TYPE_3V3V3:
379 case ANONGAME_TYPE_4V4V4:
380 case ANONGAME_TYPE_AT_2V2V2:
381 return 3;
382 case ANONGAME_TYPE_TEAM_FFA: /* not even used */
383 case ANONGAME_TYPE_2V2V2V2:
384 case ANONGAME_TYPE_3V3V3V3:
385 return 4;
386 case ANONGAME_TYPE_TY:
387 return 2; /* fixme: does not support 2v2v2 - tournament_get_totalteams() */
388 default:
389 eventlog(eventlog_level_error, __FUNCTION__, "unknown queue: %d", queue);
390 return 0;
391 }
392 }
393
394 /**********/
395 static int _handle_anongame_search(t_connection * c, t_packet const *packet)
396 {
397 int i, j, temp, set = 1;
398 t_packet *rpacket;
399 t_connection *tc[6];
400 t_anongame *a, *ta;
401 t_uint8 teamsize = 0;
402 t_uint8 option = bn_byte_get(packet->u.client_findanongame.option);
403
404 if (!(a = conn_get_anongame(c))) {
405 if (!(a = conn_create_anongame(c))) {
406 eventlog(eventlog_level_error, __FUNCTION__, "[%d] conn_create_anongame failed", conn_get_socket(c));
407 return -1;
408 }
409 }
410
411 conn_set_anongame_search_starttime(c, now);
412
413 switch (option) {
414 case CLIENT_FINDANONGAME_AT_INVITER_SEARCH:
415 a->count = bn_int_get(packet->u.client_findanongame_at_inv.count);
416 a->id = bn_int_get(packet->u.client_findanongame_at_inv.id);
417 a->tid = bn_int_get(packet->u.client_findanongame_at_inv.tid);
418 a->race = bn_int_get(packet->u.client_findanongame_at_inv.race);
419 a->map_prefs = bn_int_get(packet->u.client_findanongame_at_inv.map_prefs);
420 a->type = bn_byte_get(packet->u.client_findanongame_at_inv.type);
421 a->gametype = bn_byte_get(packet->u.client_findanongame_at_inv.gametype);
422 teamsize = bn_byte_get(packet->u.client_findanongame_at_inv.teamsize);
423 break;
424 case CLIENT_FINDANONGAME_AT_SEARCH:
425 a->count = bn_int_get(packet->u.client_findanongame_at.count);
426 a->id = bn_int_get(packet->u.client_findanongame_at.id);
427 a->tid = bn_int_get(packet->u.client_findanongame_at.tid);
428 a->race = bn_int_get(packet->u.client_findanongame_at.race);
429 teamsize = bn_byte_get(packet->u.client_findanongame_at.teamsize);
430 break;
431 case CLIENT_FINDANONGAME_SEARCH:
432 a->count = bn_int_get(packet->u.client_findanongame.count);
433 a->id = bn_int_get(packet->u.client_findanongame.id);
434 a->race = bn_int_get(packet->u.client_findanongame.race);
435 a->map_prefs = bn_int_get(packet->u.client_findanongame.map_prefs);
436 a->type = bn_byte_get(packet->u.client_findanongame.type);
437 a->gametype = bn_byte_get(packet->u.client_findanongame.gametype);
438 break;
439 default:
440 eventlog(eventlog_level_error, __FUNCTION__, "invalid search option (%d)", option);
441 return -1;
442 }
443
444 if (option != CLIENT_FINDANONGAME_AT_SEARCH)
445 if ((a->queue = _anongame_gametype_to_queue(a->type, a->gametype)) < 0) {
446 eventlog(eventlog_level_error, __FUNCTION__, "invalid queue: %d", a->queue);
447 return -1;
448 }
449
450 account_set_w3pgrace(conn_get_account(c), conn_get_clienttag(c), a->race);
451
452 /* send search reply to client */
453 if (!(rpacket = packet_create(packet_class_bnet)))
454 return -1;
455 packet_set_size(rpacket, sizeof(t_server_anongame_search_reply));
456 packet_set_type(rpacket, SERVER_ANONGAME_SEARCH_REPLY);
457 bn_byte_set(&rpacket->u.server_anongame_search_reply.option, SERVER_FINDANONGAME_SEARCH);
458 bn_int_set(&rpacket->u.server_anongame_search_reply.count, a->count);
459 bn_int_set(&rpacket->u.server_anongame_search_reply.reply, 0);
460 temp = (int) average_anongame_search_time;
461 packet_append_data(rpacket, &temp, 2);
462 conn_push_outqueue(c, rpacket);
463 packet_del_ref(rpacket);
464 /* end search reply */
465
466 switch (option) {
467 case CLIENT_FINDANONGAME_AT_INVITER_SEARCH:
468 for (i = 0; i < teamsize; i++) { /* assign player conns to tc[] array */
469 if (!(tc[i] = _connlist_find_connection_by_uid(bn_int_get(packet->u.client_findanongame_at_inv.info[i])))) {
470 eventlog(eventlog_level_error, __FUNCTION__, "[%d] got NULL connection", conn_get_socket(tc[i]));
471 return -1;
472 }
473 }
474 for (i = 0; i < teamsize; i++) { /* assign info from inviter to other team players */
475 if (!(ta = conn_get_anongame(tc[i]))) {
476 if (!(ta = conn_create_anongame(tc[i]))) {
477 eventlog(eventlog_level_error, __FUNCTION__, "[%d] conn_create_anongame failed", conn_get_socket(tc[i]));
478 return -1;
479 }
480 }
481 for (j = 0; j < teamsize; j++) /* add each players conn to each anongame struct */
482 ta->tc[j] = tc[j];
483
484 ta->type = a->type;
485 ta->gametype = a->gametype;
486 ta->queue = a->queue;
487 ta->map_prefs = a->map_prefs;
488
489 if (ta->tid != a->tid)
490 set = 0;
491 }
492 if (!set) /* check if search packet has been recieved from each team member */
493 return 0;
494 break;
495 case CLIENT_FINDANONGAME_AT_SEARCH:
496 for (i = 0; i < teamsize; i++) { /* assign player conns to tc[] array */
497 if (!(tc[i] = _connlist_find_connection_by_uid(bn_int_get(packet->u.client_findanongame_at.info[i])))) {
498 eventlog(eventlog_level_error, __FUNCTION__, "[%d] got NULL connection", conn_get_socket(tc[i]));
499 return -1;
500 }
501 }
502 for (i = 0; i < teamsize; i++) { /* check if search packet has been recieved from each team member */
503 if (!(ta = conn_get_anongame(tc[i])))
504 return 0;
505 if (ta->tid != a->tid)
506 return 0;
507 }
508 break;
509 case CLIENT_FINDANONGAME_SEARCH:
510 tc[0] = c;
511 a->tc[0] = c;
512 break;
513 default:
514 eventlog(eventlog_level_error, __FUNCTION__, "invalid search option (%d)", option);
515 return -1;
516 }
517
518 if (_anongame_queue(tc[0], a->queue, a->map_prefs) < 0) {
519 eventlog(eventlog_level_error, __FUNCTION__, "queue failed");
520 return -1;
521 }
522
523 _anongame_match(c, a->queue);
524
525 /* if enough players are queued send found packet */
526 if (players[a->queue] == _anongame_totalplayers(a->queue))
527 if (_anongame_search_found(a->queue) < 0)
528 return -1;
529
530 return 0;
531 }
532
533 static int _anongame_queue(t_connection * c, int queue, t_uint32 map_prefs)
534 {
535 int level;
536 t_matchdata *md;
537
538 if (!c) {
539 eventlog(eventlog_level_error, __FUNCTION__, "got NULL connection");
540 }
541
542 if (queue >= ANONGAME_TYPES) {
543 eventlog(eventlog_level_error, __FUNCTION__, "unknown queue: %d", queue);
544 return -1;
545 }
546
547 level = _anongame_level_by_queue(c, queue);
548
549 if (!matchlists[queue][level])
550 matchlists[queue][level] = list_create();
551
552 md = xmalloc(sizeof(t_matchdata));
553 md->c = c;
554 md->map_prefs = map_prefs;
555 md->versiontag = _conn_get_versiontag(c);
556
557 list_append_data(matchlists[queue][level], md);
558
559 return 0;
560 }
561
562 static int _anongame_compare_level(void const *a, void const *b)
563 {
564 t_connection *ca = *(t_connection * const *) a;
565 t_connection *cb = *(t_connection * const *) b;
566
567 int level_a = _anongame_level_by_queue(ca, anongame_get_queue(conn_get_anongame(ca)));
568 int level_b = _anongame_level_by_queue(cb, anongame_get_queue(conn_get_anongame(cb)));
569
570 return (level_a > level_b) ? -1 : ((level_a < level_b) ? 1 : 0);
571 }
572
573 static int _anongame_order_queue(int queue)
574 {
575 if (_anongame_totalteams(queue) != 0 && !anongame_arranged(queue)) { /* no need to reorder 1v1, sffa, or AT queues */
576 int i, j;
577 t_connection *temp;
578 int level[ANONGAME_MAX_TEAMS];
579 int teams = _anongame_totalteams(queue); /* number of teams */
580 int ppt = players[queue] / teams; /* players per team */
581
582 for (i = 0; i < ANONGAME_MAX_TEAMS; i++)
583 level[i] = 0;
584
585 for (i = 0; i < ppt - 1; i++) { /* loop through the number of players per team */
586 for (j = 0; j < teams; j++) {
587 level[j] = level[j] + _anongame_level_by_queue(player[queue][i * ppt + j], queue);
588 }
589
590 if (teams == 2) {
591 /* 1 >= 2 */
592 if (level[i * teams] >= level[i * teams + 1]) {
593 temp = player[queue][(i + 1) * teams];
594 player[queue][(i + 1) * teams] = player[queue][(i + 1) * teams + 1];
595 player[queue][(i + 1) * teams + 1] = temp;
596 }
597 /* 2 >= 1 */
598 else if (level[i * teams + 1] >= level[i * teams]) {
599 ; /* nothing to do */
600 }
601 }
602 /* end 2 teams */
603 else if (teams == 3) {
604 /* 1 >= 2 >= 3 */
605 if (level[i * 3] >= level[i * 3 + 1] && level[i * 3 + 1] >= level[i * 3 + 2]) {
606 temp = player[queue][(i + 1) * 3];
607 player[queue][(i + 1) * 3] = player[queue][(i + 1) * 3 + 2];
608 player[queue][(i + 1) * 3 + 2] = temp;
609 }
610 /* 1 >= 3 >= 2 */
611 else if (level[i * 3] >= level[i * 3 + 2] && level[i * 3 + 2] >= level[i * 3 + 1]) {
612 temp = player[queue][(i + 1) * 3];
613 player[queue][(i + 1) * 3] = player[queue][(i + 1) * 3 + 2];
614 player[queue][(i + 1) * 3 + 2] = player[queue][(i + 1) * 3 + 1];
615 player[queue][(i + 1) * 3 + 1] = temp;
616 }
617 /* 2 >= 1 >= 3 */
618 else if (level[i * 3 + 1] >= level[i * 3] && level[i * 3] >= level[i * 3 + 2]) {
619 temp = player[queue][(i + 1) * 3];
620 player[queue][(i + 1) * 3] = player[queue][(i + 1) * 3 + 1];
621 player[queue][(i + 1) * 3 + 1] = player[queue][(i + 1) * 3 + 2];
622 player[queue][(i + 1) * 3 + 2] = temp;
623 }
624 /* 2 >= 3 >= 1 */
625 else if (level[i * 3 + 1] >= level[i * 3 + 2] && level[i * 3 + 2] >= level[i * 3]) {
626 temp = player[queue][(i + 1) * 3 + 1];
627 player[queue][(i + 1) * 3 + 1] = player[queue][(i + 1) * 3 + 2];
628 player[queue][(i + 1) * 3 + 2] = temp;
629 }
630 /* 3 >= 1 >= 2 */
631 else if (level[i * 3 + 2] >= level[i * 3] && level[i * 3] >= level[i * 3 + 1]) {
632 temp = player[queue][(i + 1) * 3];
633 player[queue][(i + 1) * 3] = player[queue][(i + 1) * 3 + 1];
634 player[queue][(i + 1) * 3 + 1] = temp;
635 }
636 /* 3 >= 2 >= 1 */
637 else if (level[i * 3 + 2] >= level[i * 3 + 1] && level[i * 3 + 1] >= level[i * 3]) {
638 ; /* nothing to do */
639 }
640 }
641 /* end 3 teams */
642 else if (teams == 4) {
643 /* 1234 */
644 if (level[i * 4] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4 + 3]) {
645 temp = player[queue][(i + 1) * 4];
646 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 3];
647 player[queue][(i + 1) * 4 + 3] = temp;
648 temp = player[queue][(i + 1) * 4 + 1];
649 player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 2];
650 player[queue][(i + 1) * 4 + 2] = temp;
651 }
652 /* 1243 */
653 else if (level[i * 4] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4 + 2] && level[i * 4 + 3] >= level[i * 4 + 2]) {
654 temp = player[queue][(i + 1) * 4];
655 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 3];
656 player[queue][(i + 1) * 4 + 3] = player[queue][(i + 1) * 4 + 1];
657 player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 2];
658 player[queue][(i + 1) * 4 + 2] = temp;
659 }
660 /* 1324 */
661 else if (level[i * 4] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4 + 3]) {
662 temp = player[queue][(i + 1) * 4];
663 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 3];
664 player[queue][(i + 1) * 4 + 3] = temp;
665 }
666 /* 1342 */
667 else if (level[i * 4] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4 + 1]) {
668 temp = player[queue][(i + 1) * 4];
669 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 3];
670 player[queue][(i + 1) * 4 + 3] = player[queue][(i + 1) * 4 + 1];
671 player[queue][(i + 1) * 4 + 1] = temp;
672 }
673 /* 1423 */
674 else if (level[i * 4] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4 + 2]) {
675 temp = player[queue][(i + 1) * 4];
676 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 3];
677 player[queue][(i + 1) * 4 + 3] = player[queue][(i + 1) * 4 + 2];
678 player[queue][(i + 1) * 4 + 2] = temp;
679 }
680 /* 1432 */
681 else if (level[i * 4] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4 + 1]) {
682 temp = player[queue][(i + 1) * 4];
683 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 3];
684 player[queue][(i + 1) * 4 + 3] = player[queue][(i + 1) * 4 + 2];
685 player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 1];
686 player[queue][(i + 1) * 4 + 1] = temp;
687 }
688 /* 2134 */
689 else if (level[i * 4 + 1] >= level[i * 4] && level[i * 4] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4 + 3]) {
690 temp = player[queue][(i + 1) * 4];
691 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 2];
692 player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 1];
693 player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 3];
694 player[queue][(i + 1) * 4 + 3] = temp;
695 }
696 /* 2143 */
697 else if (level[i * 4 + 1] >= level[i * 4] && level[i * 4] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4 + 2]) {
698 temp = player[queue][(i + 1) * 4];
699 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 2];
700 player[queue][(i + 1) * 4 + 2] = temp;
701 temp = player[queue][(i + 1) * 4 + 1];
702 player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 3];
703 player[queue][(i + 1) * 4 + 3] = temp;
704 }
705 /* 2314 */
706 else if (level[i * 4 + 1] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4] && level[i * 4] >= level[i * 4 + 3]) {
707 temp = player[queue][(i + 1) * 4];
708 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 3];
709 player[queue][(i + 1) * 4 + 3] = player[queue][(i + 1) * 4 + 1];
710 player[queue][(i + 1) * 4 + 1] = temp;
711 }
712 /* 2341 */
713 else if (level[i * 4 + 1] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4]) {
714 temp = player[queue][(i + 1) * 4 + 1];
715 player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 2];
716 player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 3];
717 player[queue][(i + 1) * 4 + 3] = temp;
718 }
719 /* 2413 */
720 else if (level[i * 4 + 1] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4] && level[i * 4] >= level[i * 4 + 2]) {
721 temp = player[queue][(i + 1) * 4];
722 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 1];
723 player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 3];
724 player[queue][(i + 1) * 4 + 3] = player[queue][(i + 1) * 4 + 2];
725 player[queue][(i + 1) * 4 + 2] = temp;
726 }
727 /* 2431 */
728 else if (level[i * 4 + 1] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4]) {
729 temp = player[queue][(i + 1) * 4 + 1];
730 player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 3];
731 player[queue][(i + 1) * 4 + 3] = player[queue][(i + 1) * 4 + 2];
732 player[queue][(i + 1) * 4 + 2] = temp;
733 }
734 /* 3124 */
735 else if (level[i * 4 + 2] >= level[i * 4] && level[i * 4] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4 + 3]) {
736 temp = player[queue][(i + 1) * 4];
737 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 2];
738 player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 3];
739 player[queue][(i + 1) * 4 + 3] = temp;
740 }
741 /* 3142 */
742 else if (level[i * 4 + 2] >= level[i * 4] && level[i * 4] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4 + 1]) {
743 temp = player[queue][(i + 1) * 4];
744 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 2];
745 player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 3];
746 player[queue][(i + 1) * 4 + 3] = player[queue][(i + 1) * 4 + 1];
747 player[queue][(i + 1) * 4 + 1] = temp;
748 }
749 /* 3214 */
750 else if (level[i * 4 + 2] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4] && level[i * 4] >= level[i * 4 + 3]) {
751 temp = player[queue][(i + 1) * 4];
752 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 1];
753 player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 2];
754 player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 3];
755 player[queue][(i + 1) * 4 + 3] = temp;
756 }
757 /* 3241 */
758 else if (level[i * 4 + 2] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4]) {
759 temp = player[queue][(i + 1) * 4 + 1];
760 player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 2];
761 player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 3];
762 player[queue][(i + 1) * 4 + 3] = temp;
763 }
764 /* 3412 */
765 else if (level[i * 4 + 2] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4] && level[i * 4] >= level[i * 4 + 1]) {
766 temp = player[queue][(i + 1) * 4];
767 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 1];
768 player[queue][(i + 1) * 4 + 1] = temp;
769 temp = player[queue][(i + 1) * 4 + 2];
770 player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 3];
771 player[queue][(i + 1) * 4 + 3] = temp;
772 }
773 /* 3421 */
774 else if (level[i * 4 + 2] >= level[i * 4 + 3] && level[i * 4 + 3] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4]) {
775 temp = player[queue][(i + 1) * 4 + 2];
776 player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 3];
777 player[queue][(i + 1) * 4 + 3] = temp;
778 }
779 /* 4123 */
780 else if (level[i * 4 + 3] >= level[i * 4] && level[i * 4] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4 + 2]) {
781 temp = player[queue][(i + 1) * 4];
782 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 2];
783 player[queue][(i + 1) * 4 + 2] = temp;
784 }
785 /* 4132 */
786 else if (level[i * 4 + 3] >= level[i * 4] && level[i * 4] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4 + 1]) {
787 temp = player[queue][(i + 1) * 4];
788 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 2];
789 player[queue][(i + 1) * 4 + 2] = player[queue][(i + 1) * 4 + 1];
790 player[queue][(i + 1) * 4 + 1] = temp;
791 }
792 /* 4213 */
793 else if (level[i * 4 + 3] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4] && level[i * 4] >= level[i * 4 + 2]) {
794 temp = player[queue][(i + 1) * 4];
795 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 1];
796 player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 2];
797 player[queue][(i + 1) * 4 + 2] = temp;
798 }
799 /* 4231 */
800 else if (level[i * 4 + 3] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4]) {
801 temp = player[queue][(i + 1) * 4 + 1];
802 player[queue][(i + 1) * 4 + 1] = player[queue][(i + 1) * 4 + 2];
803 player[queue][(i + 1) * 4 + 2] = temp;
804 }
805 /* 4312 */
806 else if (level[i * 4 + 3] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4] && level[i * 4] >= level[i * 4 + 1]) {
807 temp = player[queue][(i + 1) * 4];
808 player[queue][(i + 1) * 4] = player[queue][(i + 1) * 4 + 1];
809 player[queue][(i + 1) * 4 + 1] = temp;
810 }
811 /* 4321 */
812 else if (level[i * 4 + 3] >= level[i * 4 + 2] && level[i * 4 + 2] >= level[i * 4 + 1] && level[i * 4 + 1] >= level[i * 4]) {
813 ; /* nothing to do */
814 }
815 } /* end 4 teams */
816 } /* end ppt loop */
817 } /* end "if" statement */
818 return 0;
819 }
820
821 static int _anongame_match(t_connection * c, int queue)
822 {
823 int level = _anongame_level_by_queue(c, queue);
824 int delta = 0;
825 int i;
826 t_matchdata *md;
827 t_elem *curr;
828 int diff;
829 t_anongame *a = conn_get_anongame(c);
830 t_uint32 cur_prefs = a->map_prefs;
831 t_connection *inv_c[ANONGAME_MAX_TEAMS];
832 int maxlevel, minlevel;
833 int teams = 0;
834 players[queue] = 0;
835
836 eventlog(eventlog_level_trace, __FUNCTION__, "[%d] matching started for level %d player in queue %d", conn_get_socket(c), level, queue);
837
838 diff = war3_get_maxleveldiff();
839 maxlevel = level + diff;
840 minlevel = (level - diff < 0) ? 0 : level - diff;
841
842 while (abs(delta) < (diff + 1)) {
843 if ((level + delta <= maxlevel) && (level + delta >= minlevel)) {
844 eventlog(eventlog_level_trace, __FUNCTION__, "Traversing level %d players", level + delta);
845
846 LIST_TRAVERSE(matchlists[queue][level + delta], curr) {
847 md = elem_get_data(curr);
848 if (md->versiontag && _conn_get_versiontag(c) && !strcmp(md->versiontag, _conn_get_versiontag(c)) && (cur_prefs & md->map_prefs)) {
849 /* set maxlevel and minlevel to keep all players within 6 levels */
850 maxlevel = (level + delta + diff < maxlevel) ? level + delta + diff : maxlevel;
851 minlevel = (level + delta - diff > minlevel) ? level + delta - diff : minlevel;
852 cur_prefs &= md->map_prefs;
853
854 /* AT match */
855 if (anongame_arranged(queue)) {
856
857 /* set the inv_c for unqueueing later */
858 inv_c[teams] = md->c;
859
860 a = conn_get_anongame(md->c);
861
862 /* add all the players on the team to player[][] */
863 for (i = 0; i < _anongame_totalplayers(queue) / _anongame_totalteams(queue); i++) {
864 player[queue][teams + i * _anongame_totalteams(queue)] = a->tc[i];
865 players[queue]++;
866 }
867 teams++;
868
869 /* check for enough players */
870 if (players[queue] == _anongame_totalplayers(queue)) {
871
872 /* unqueue just the single team entry */
873 for (i = 0; i < teams; i++)
874 anongame_unqueue(inv_c[i], queue);
875
876 mapname = _get_map_from_prefs(queue, cur_prefs, conn_get_clienttag(c));
877 return 0;
878 }
879
880 /* PG match */
881 } else {
882 player[queue][players[queue]++] = md->c;
883
884 if (players[queue] == _anongame_totalplayers(queue)) {
885 /* first sort queue by level */
886 qsort(player[queue], players[queue], sizeof(t_connection *), _anongame_compare_level);
887 /* next call reodering function */
888 _anongame_order_queue(queue);
889 /* unqueue players */
890 for (i = 0; i < players[queue]; i++)
891 anongame_unqueue(player[queue][i], queue);
892
893 mapname = _get_map_from_prefs(queue, cur_prefs, conn_get_clienttag(c));
894 return 0;
895 }
896 }
897 }
898 }
899 }
900
901 if (delta <= 0 || level - delta < 0)
902 delta = abs(delta) + 1;
903 else
904 delta = -delta;
905
906 if (level + delta > MAX_LEVEL)
907 delta = -delta;
908
909 if (level + delta < 0)
910 break; /* cant really happen */
911
912 }
913 eventlog(eventlog_level_trace, __FUNCTION__, "[%d] Matching finished, not enough players (found %d)", conn_get_socket(c), players[queue]);
914 mapname = NULL;
915 return 0;
916 }
917
918 static int w3routeip = -1; /* changed by dizzy to show the w3routeshow addr if available */
919 static unsigned short w3routeport = BNETD_W3ROUTE_PORT;
920
921 static int _anongame_search_found(int queue)
922 {
923 t_packet *rpacket;
924 t_anongameinfo *info;
925 t_anongame *a;
926 int i, j;
927 t_saf_pt2 *pt2;
928
929 /* FIXME: maybe periodically lookup w3routeaddr to support dynamic ips?
930 * (or should dns lookup be even quick enough to do it everytime?)
931 */
932
933 if (w3routeip == -1) {
934 t_addr *routeraddr;
935
936 routeraddr = addr_create_str(prefs_get_w3route_addr(), 0, BNETD_W3ROUTE_PORT);
937
938 if (!routeraddr) {
939 eventlog(eventlog_level_error, __FUNCTION__, "error getting w3route_addr");
940 return -1;
941 }
942
943 w3routeip = addr_get_ip(routeraddr);
944 w3routeport = addr_get_port(routeraddr);
945 addr_destroy(routeraddr);
946 }
947
948 info = anongameinfo_create(_anongame_totalplayers(queue));
949
950 if (!info) {
951 eventlog(eventlog_level_error, __FUNCTION__, "anongameinfo_create failed");
952 return -1;
953 }
954
955 /* create data to be appended to end of packet */
956 pt2 = xmalloc(sizeof(t_saf_pt2));
957 bn_int_set(&pt2->unknown1, -1);
958 bn_int_set(&pt2->anongame_string, _anongame_get_gametype_tab(queue));
959 bn_byte_set(&pt2->totalplayers, _anongame_totalplayers(queue));
960 bn_byte_set(&pt2->totalteams, _anongame_totalteams(queue)); /* 1v1 & sffa are set to zero in _anongame_totalteams() */
961 bn_short_set(&pt2->unknown2, 0);
962 bn_byte_set(&pt2->visibility, 2); /* visibility. 0x01 - dark 0x02 - default */
963 bn_byte_set(&pt2->unknown3, 2);
964
965 /* send found packet to each of the players */
966 for (i = 0; i < players[queue]; i++) {
967 if (!(a = conn_get_anongame(player[queue][i]))) {
968 eventlog(eventlog_level_error, __FUNCTION__, "no anongame struct for queued player");
969 xfree(pt2);
970 return -1;
971 }
972
973 a->info = info;
974 a->playernum = i + 1;
975
976 for (j = 0; j < players[queue]; j++) {
977 a->info->player[j] = player[queue][j];
978 a->info->account[j] = conn_get_account(player[queue][j]);
979 }
980
981 if (!(rpacket = packet_create(packet_class_bnet))) {
982 xfree(pt2);
983 return -1;
984 }
985
986 packet_set_size(rpacket, sizeof(t_server_anongame_found));
987 packet_set_type(rpacket, SERVER_ANONGAME_FOUND);
988 bn_byte_set(&rpacket->u.server_anongame_found.option, 1);
989 bn_int_set(&rpacket->u.server_anongame_found.count, a->count);
990 bn_int_set(&rpacket->u.server_anongame_found.unknown1, 0);
991 { /* trans support */
992 unsigned int w3ip = w3routeip;
993 unsigned short w3port = w3routeport;
994
995 trans_net(conn_get_addr(player[queue][i]), &w3ip, &w3port);
996
997 /* if ip to send is 0.0.0.0 (which will not work anyway) try
998 * to guess the reachable IP of pvpgn by using the local
999 * endpoing address of the bnet class connection */
1000 if (!w3ip)
1001 w3ip = conn_get_real_local_addr(player[queue][i]);
1002
1003 bn_int_nset(&rpacket->u.server_anongame_found.ip, w3ip);
1004 bn_short_set(&rpacket->u.server_anongame_found.port, w3port);
1005 }
1006 bn_byte_set(&rpacket->u.server_anongame_found.unknown2, i + 1);
1007 bn_byte_set(&rpacket->u.server_anongame_found.unknown3, queue);
1008 bn_short_set(&rpacket->u.server_anongame_found.unknown4, 0);
1009 bn_int_set(&rpacket->u.server_anongame_found.id, 0xdeadbeef);
1010 bn_byte_set(&rpacket->u.server_anongame_found.unknown5, 6);
1011 bn_byte_set(&rpacket->u.server_anongame_found.type, a->type);
1012 bn_byte_set(&rpacket->u.server_anongame_found.gametype, a->gametype);
1013 packet_append_string(rpacket, mapname);
1014 packet_append_data(rpacket, pt2, sizeof(t_saf_pt2));
1015 conn_push_outqueue(player[queue][i], rpacket);
1016 packet_del_ref(rpacket);
1017 }
1018
1019 /* clear queue */
1020 players[queue] = 0;
1021 xfree(pt2);
1022 return 0;
1023 }
1024
1025 /**********************************************************************************/
1026 /* external functions */
1027 /**********************************************************************************/
1028 extern int anongame_matchlists_create()
1029 {
1030 int i, j;
1031
1032 for (i = 0; i < ANONGAME_TYPES; i++) {
1033 for (j = 0; j < MAX_LEVEL; j++) {
1034 matchlists[i][j] = NULL;
1035 }
1036 }
1037 return 0;
1038 }
1039
1040 extern int anongame_matchlists_destroy()
1041 {
1042 int i, j;
1043 for (i = 0; i < ANONGAME_TYPES; i++) {
1044 for (j = 0; j < MAX_LEVEL; j++) {
1045 if (matchlists[i][j]) {
1046 list_destroy(matchlists[i][j]);
1047 }
1048 }
1049 }
1050 return 0;
1051 }
1052
1053 /**********/
1054 extern int handle_anongame_search(t_connection * c, t_packet const *packet)
1055 {
1056 return _handle_anongame_search(c, packet);
1057 }
1058
1059 extern int anongame_unqueue(t_connection * c, int queue)
1060 {
1061 int i;
1062 t_elem *curr;
1063 t_matchdata *md;
1064
1065 if (queue < 0) {
1066 eventlog(eventlog_level_error, __FUNCTION__, "got negative queue id (%d)", queue);
1067 return -1;
1068 }
1069
1070 if (queue >= ANONGAME_TYPES) {
1071 eventlog(eventlog_level_error, __FUNCTION__, "unknown queue: %d", queue);
1072 return -1;
1073 }
1074
1075 if (conn_get_anongame_search_starttime(c) != ((time_t) 0)) {
1076 average_anongame_search_time *= anongame_search_count;
1077 average_anongame_search_time += (long) difftime(time(NULL), conn_get_anongame_search_starttime(c));
1078 anongame_search_count++;
1079 average_anongame_search_time /= anongame_search_count;
1080 if (anongame_search_count > 20000)
1081 anongame_search_count = anongame_search_count / 2; /* to prevent an overflow of the average time */
1082 conn_set_anongame_search_starttime(c, ((time_t) 0));
1083 }
1084
1085 for (i = 0; i < MAX_LEVEL; i++) {
1086 if (matchlists[queue][i] == NULL)
1087 continue;
1088
1089 LIST_TRAVERSE(matchlists[queue][i], curr) {
1090 md = elem_get_data(curr);
1091 if (md->c == c) {
1092 eventlog(eventlog_level_trace, __FUNCTION__, "unqueued player [%d] level %d", conn_get_socket(c), i);
1093 list_remove_elem(matchlists[queue][i], &curr);
1094 xfree(md);
1095 return 0;
1096 }
1097 }
1098 }
1099
1100 /* Output error to log for PG queues, AT players are queued with single
1101 * entry. Because anongame_unqueue() is called for each player, only the first
1102 * time called will the team be removed, the rest are therefore not an error.
1103 * [Omega]
1104 */
1105 if (anongame_arranged(queue) == 0) {
1106 eventlog(eventlog_level_trace, __FUNCTION__, "[%d] player not found in \"%s\" queue", conn_get_socket(c), _anongame_queue_to_string(queue));
1107 return -1;
1108 }
1109
1110 return 0;
1111 }
1112
1113 /**********/
1114 extern char anongame_arranged(int queue)
1115 {
1116 switch (queue) {
1117 case ANONGAME_TYPE_AT_2V2:
1118 case ANONGAME_TYPE_AT_3V3:
1119 case ANONGAME_TYPE_AT_4V4:
1120 case ANONGAME_TYPE_AT_2V2V2:
1121 return 1;
1122 case ANONGAME_TYPE_TY:
1123 return tournament_is_arranged();
1124 default:
1125 return 0;
1126 }
1127 }
1128
1129 extern int anongame_evaluate_results(t_anongame * anongame)
1130 {
1131 int i, j, number;
1132 int wins[ANONGAME_MAX_GAMECOUNT];
1133 int losses[ANONGAME_MAX_GAMECOUNT];
1134 int result;
1135 t_anongame_gameresult *results;
1136 t_anongameinfo *anoninfo = anongame->info;
1137
1138 for (i = 0; i < ANONGAME_MAX_GAMECOUNT; i++) {
1139 wins[i] = 0;
1140 losses[i] = 0;
1141 }
1142
1143 for (i = 0; i < anongame_get_totalplayers(anongame); i++) {
1144 if ((results = anoninfo->results[i])) {
1145 for (j = 0; j < gameresult_get_number_of_results(results); j++) {
1146 number = gameresult_get_player_number(results, j) - 1;
1147 result = gameresult_get_player_result(results, j);
1148
1149 if ((result == W3_GAMERESULT_WIN))
1150 wins[number]++;
1151 if ((result == W3_GAMERESULT_LOSS))
1152 losses[number]++;
1153 }
1154 }
1155 }
1156
1157 for (i = 0; i < anongame_get_totalplayers(anongame); i++) {
1158 if ((wins[i] > losses[i])) {
1159 if ((anoninfo->result[i] != W3_GAMERESULT_WIN)) {
1160 eventlog(eventlog_level_trace, __FUNCTION__, "player %d reported DISC/LOSS for self, but others agree on WIN", i + 1);
1161 anoninfo->result[i] = W3_GAMERESULT_WIN;
1162 }
1163 } else {
1164 if ((anoninfo->result[i] != W3_GAMERESULT_LOSS)) {
1165 eventlog(eventlog_level_trace, __FUNCTION__, "player %d reported DISC/WIN for self, but others agree on LOSS", i + 1);
1166 anoninfo->result[i] = W3_GAMERESULT_LOSS;
1167 }
1168 }
1169 }
1170
1171 return 0;
1172
1173 }
1174
1175 extern int anongame_stats(t_connection * c)
1176 {
1177 int i;
1178 int wins = 0, losses = 0, discs = 0;
1179 t_connection *gamec = conn_get_routeconn(c);
1180 t_anongame *a = conn_get_anongame(gamec);
1181 int tp = anongame_get_totalplayers(a);
1182 int oppon_level[ANONGAME_MAX_GAMECOUNT];
1183 t_uint8 gametype = a->queue;
1184 t_uint8 plnum = a->playernum;
1185 t_clienttag ct = conn_get_clienttag(c);
1186 int tt = _anongame_totalteams(gametype);
1187
1188 /* do nothing till all other players have w3route conn closed */
1189 for (i = 0; i < tp; i++)
1190 if (i + 1 != plnum && a->info->player[i])
1191 if (conn_get_routeconn(a->info->player[i]))
1192 return 0;
1193
1194 anongame_evaluate_results(a);
1195
1196 /* count wins, losses, discs */
1197 for (i = 0; i < tp; i++) {
1198 if (a->info->result[i] == W3_GAMERESULT_WIN)
1199 wins++;
1200 else if (a->info->result[i] == W3_GAMERESULT_LOSS)
1201 losses++;
1202 else
1203 discs++;
1204 }
1205
1206 /* do some sanity checking (hack prevention) */
1207 switch (gametype) {
1208 case ANONGAME_TYPE_SMALL_FFA:
1209 if (wins != 1) {
1210 eventlog(eventlog_level_info, __FUNCTION__, "bogus game result: wins != 1 in small ffa game");
1211 return -1;
1212 }
1213 break;
1214 case ANONGAME_TYPE_TEAM_FFA:
1215 if (!discs && wins != 2) {
1216 eventlog(eventlog_level_info, __FUNCTION__, "bogus game result: wins != 2 in team ffa game");
1217 return -1;
1218 }
1219 break;
1220 default:
1221 if (!discs && wins > losses) {
1222 eventlog(eventlog_level_info, __FUNCTION__, "bogus game result: wins > losses");
1223 return -1;
1224 }
1225 break;
1226 }
1227
1228 /* prevent users from getting loss if server is shutdown (does not prevent errors from crash) - [Omega] */
1229 if (discs == tp)
1230 if (!wins)
1231 return -1;
1232
1233 /* according to zap, order of players in anongame is:
1234 * for PG: t1_p1, t2_p1, t1_p2, t2_p2, ...
1235 * for AT: t1_p1, t1_p2, ..., t2_p1, t2_p2, ...
1236 *
1237 * (Not True.. follows same order as PG)
1238 * 4v4 = t1_p1, t2_p1, t1_p2, t2_p2, t1_p3, t2_p3, t1_p4, t2_p4
1239 * 3v3v3 = t1_p1, t2_p1, t3_p1, t1_p2, t2_p2, t3_p2, t1_p3, t2_p3, t3_p3
1240 * 2v2v2v2 = t1_p1, t2_p1, t3_p1, t4_p1, t1_p2, t2_p2, t3_p2, t4_p2
1241 */
1242
1243 /* opponent level calculation has to be done here, because later on, the level of other players
1244 * may allready be modified
1245 */
1246 for (i = 0; i < tp; i++) {
1247 int j, k, l;
1248 t_account *oacc;
1249 oppon_level[i] = 0;
1250 switch (gametype) {
1251 case ANONGAME_TYPE_TY:
1252 /* FIXME-TY: ADD TOURNAMENT STATS RECORDING (this part not required?) */
1253 break;
1254 case ANONGAME_TYPE_1V1:
1255 oppon_level[i] = account_get_ladder_level(a->info->account[(i + 1) % tp], ct, ladder_id_solo);
1256 break;
1257 case ANONGAME_TYPE_SMALL_FFA:
1258 /* oppon_level = average level of all other players */
1259 for (j = 0; j < tp; j++)
1260 if (i != j)
1261 oppon_level[i] += account_get_ladder_level(a->info->account[j], ct, ladder_id_ffa);
1262 oppon_level[i] /= (tp - 1);
1263 break;
1264 case ANONGAME_TYPE_AT_2V2:
1265 case ANONGAME_TYPE_AT_3V3:
1266 case ANONGAME_TYPE_AT_4V4:
1267 oacc = a->info->account[(i + 1) % tp];
1268 oppon_level[i] = team_get_level(account_find_team_by_teamid(oacc, account_get_currentatteam(oacc)));
1269 break;
1270 case ANONGAME_TYPE_AT_2V2V2:
1271 oacc = a->info->account[(i + 1) % tp];
1272 oppon_level[i] = team_get_level(account_find_team_by_teamid(oacc, account_get_currentatteam(oacc)));
1273 oacc = a->info->account[(i + 2) % tp];
1274 oppon_level[i] = team_get_level(account_find_team_by_teamid(oacc, account_get_currentatteam(oacc)));
1275 oppon_level[i] /= 2;
1276 break;
1277 default:
1278 /* oppon_level = average level of all opponents
1279 * this should work for all PG team games
1280 * [Omega] */
1281 k = i + 1;
1282 for (j = 0; j < (tp / tt); j++) {
1283 for (l = 0; l < (tt - 1); l++) {
1284 oppon_level[i] += account_get_ladder_level(a->info->account[k % tp], ct, ladder_id_team);
1285 k++;
1286 }
1287 k++;
1288 }
1289 oppon_level[i] /= (tp / tt * (tt - 1));
1290 }
1291 }
1292
1293 for (i = 0; i < tp; i++) {
1294 t_account *acc;
1295 t_team *team;
1296 unsigned int currteam;
1297 int result = a->info->result[i];
1298
1299 if (result == -1)
1300 result = W3_GAMERESULT_LOSS;
1301
1302 acc = a->info->account[i];
1303
1304 switch (gametype) {
1305 case ANONGAME_TYPE_TY:
1306 if (result == W3_GAMERESULT_WIN)
1307 tournament_add_stat(acc, 1);
1308 if (result == W3_GAMERESULT_LOSS)
1309 tournament_add_stat(acc, 2);
1310 /* FIXME-TY: how to do ties? */
1311 break;
1312 case ANONGAME_TYPE_AT_2V2:
1313 case ANONGAME_TYPE_AT_3V3:
1314 case ANONGAME_TYPE_AT_4V4:
1315 case ANONGAME_TYPE_AT_2V2V2:
1316
1317 if ((currteam = account_get_currentatteam(acc))) {
1318 team = account_find_team_by_teamid(acc, currteam);
1319 team_set_saveladderstats(team, gametype, result, oppon_level[i], ct);
1320 }
1321
1322 break;
1323 case ANONGAME_TYPE_1V1:
1324 case ANONGAME_TYPE_2V2:
1325 case ANONGAME_TYPE_3V3:
1326 case ANONGAME_TYPE_4V4:
1327 case ANONGAME_TYPE_SMALL_FFA:
1328 case ANONGAME_TYPE_5V5:
1329 case ANONGAME_TYPE_6V6:
1330 case ANONGAME_TYPE_2V2V2:
1331 case ANONGAME_TYPE_3V3V3:
1332 case ANONGAME_TYPE_4V4V4:
1333 case ANONGAME_TYPE_2V2V2V2:
1334 case ANONGAME_TYPE_3V3V3V3:
1335 if (result == W3_GAMERESULT_WIN)
1336 account_set_saveladderstats(acc, gametype, game_result_win, oppon_level[i], ct);
1337 if (result == W3_GAMERESULT_LOSS)
1338 account_set_saveladderstats(acc, gametype, game_result_loss, oppon_level[i], ct);
1339 break;
1340 default:
1341 break;
1342 }
1343 }
1344 /* aaron: now update war3 ladders */
1345 ladder_update_all_accounts();
1346 return 1;
1347 }
1348
1349 /**********/
1350 extern t_anongameinfo *anongameinfo_create(int totalplayers)
1351 {
1352 t_anongameinfo *temp;
1353 int i;
1354
1355 temp = xmalloc(sizeof(t_anongameinfo));
1356
1357 temp->totalplayers = temp->currentplayers = totalplayers;
1358 for (i = 0; i < ANONGAME_MAX_GAMECOUNT; i++) {
1359 temp->player[i] = NULL;
1360 temp->account[i] = NULL;
1361 temp->result[i] = -1; /* consider DISC default */
1362 temp->results[i] = NULL;
1363 }
1364
1365 return temp;
1366 }
1367
1368 extern void anongameinfo_destroy(t_anongameinfo * i)
1369 {
1370 int j;
1371
1372 if (!i) {
1373 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongameinfo");
1374 return;
1375 }
1376 for (j = 0; j < ANONGAME_MAX_GAMECOUNT; j++)
1377 if (i->results[j])
1378 gameresult_destroy(i->results[j]);
1379 xfree(i);
1380 }
1381
1382 /**********/
1383 extern t_anongameinfo *anongame_get_info(t_anongame * a)
1384 {
1385 if (!a) {
1386 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1387 return NULL;
1388 }
1389
1390 return a->info;
1391 }
1392
1393 extern int anongame_get_currentplayers(t_anongame * a)
1394 {
1395 if (!a) {
1396 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1397 return 0;
1398 }
1399 if (!a->info) {
1400 eventlog(eventlog_level_error, __FUNCTION__, "NULL anongameinfo");
1401 return 0;
1402 }
1403
1404 return a->info->currentplayers;
1405 }
1406
1407 extern int anongame_get_totalplayers(t_anongame * a)
1408 {
1409 if (!a) {
1410 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1411 return 0;
1412 }
1413 if (!a->info) {
1414 eventlog(eventlog_level_error, __FUNCTION__, "NULL anongameinfo");
1415 return 0;
1416 }
1417
1418 return a->info->totalplayers;
1419 }
1420
1421 extern t_connection *anongame_get_player(t_anongame * a, int plnum)
1422 {
1423 if (!a) {
1424 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1425 return NULL;
1426 }
1427 if (!a->info) {
1428 eventlog(eventlog_level_error, __FUNCTION__, "NULL anongameinfo");
1429 return NULL;
1430 }
1431
1432 if (plnum < 0 || plnum > 7 || plnum >= a->info->totalplayers) {
1433 eventlog(eventlog_level_error, __FUNCTION__, "invalid plnum: %d", plnum);
1434 return NULL;
1435 }
1436
1437 return a->info->player[plnum];
1438 }
1439
1440 extern int anongame_get_count(t_anongame * a)
1441 {
1442 if (!a) {
1443 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1444 return 0;
1445 }
1446 return a->count;
1447 }
1448
1449 extern t_uint32 anongame_get_id(t_anongame * a)
1450 {
1451 if (!a) {
1452 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1453 return 0;
1454 }
1455 return a->id;
1456 }
1457
1458 extern t_connection *anongame_get_tc(t_anongame * a, int tpnumber)
1459 {
1460 if (!a) {
1461 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1462 return 0;
1463 }
1464 return a->tc[tpnumber];
1465 }
1466
1467 extern t_uint32 anongame_get_race(t_anongame * a)
1468 {
1469 if (!a) {
1470 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1471 return 0;
1472 }
1473 return a->race;
1474 }
1475
1476 extern t_uint32 anongame_get_handle(t_anongame * a)
1477 {
1478 if (!a) {
1479 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1480 return 0;
1481 }
1482 return a->handle;
1483 }
1484
1485 extern unsigned int anongame_get_addr(t_anongame * a)
1486 {
1487 if (!a) {
1488 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1489 return 0;
1490 }
1491 return a->addr;
1492 }
1493
1494 extern char anongame_get_loaded(t_anongame * a)
1495 {
1496 if (!a) {
1497 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1498 return 0;
1499 }
1500 return a->loaded;
1501 }
1502
1503 extern char anongame_get_joined(t_anongame * a)
1504 {
1505 if (!a) {
1506 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1507 return 0;
1508 }
1509 return a->joined;
1510 }
1511
1512 extern t_uint8 anongame_get_playernum(t_anongame * a)
1513 {
1514 if (!a) {
1515 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1516 return 0;
1517 }
1518 return a->playernum;
1519 }
1520
1521 extern t_uint8 anongame_get_queue(t_anongame * a)
1522 {
1523 if (!a) {
1524 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1525 return 0;
1526 }
1527 return a->queue;
1528 }
1529
1530 /**********/
1531 extern void anongame_set_result(t_anongame * a, int result)
1532 {
1533 if (!a) {
1534 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1535 return;
1536 }
1537 if (!a->info) {
1538 eventlog(eventlog_level_error, __FUNCTION__, "NULL anongameinfo");
1539 return;
1540 }
1541
1542 if (a->playernum < 1 || a->playernum > ANONGAME_MAX_GAMECOUNT) {
1543 eventlog(eventlog_level_error, __FUNCTION__, "invalid playernum: %d", a->playernum);
1544 return;
1545 }
1546
1547 a->info->result[a->playernum - 1] = result;
1548 }
1549
1550 extern void anongame_set_gameresults(t_anongame * a, t_anongame_gameresult * results)
1551 {
1552 if (!a) {
1553 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1554 return;
1555 }
1556 if (!a->info) {
1557 eventlog(eventlog_level_error, __FUNCTION__, "NULL anongameinfo");
1558 return;
1559 }
1560
1561 if (a->playernum < 1 || a->playernum > ANONGAME_MAX_GAMECOUNT) {
1562 eventlog(eventlog_level_error, __FUNCTION__, "invalid playernum: %d", a->playernum);
1563 return;
1564 }
1565
1566 a->info->results[a->playernum - 1] = results;
1567 }
1568
1569 extern void anongame_set_handle(t_anongame * a, t_uint32 h)
1570 {
1571 if (!a) {
1572 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1573 return;
1574 }
1575
1576 a->handle = h;
1577 }
1578
1579 extern void anongame_set_addr(t_anongame * a, unsigned int addr)
1580 {
1581 if (!a) {
1582 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1583 return;
1584 }
1585
1586 a->addr = addr;
1587 }
1588
1589 extern void anongame_set_loaded(t_anongame * a, char loaded)
1590 {
1591 if (!a) {
1592 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1593 return;
1594 }
1595
1596 a->loaded = loaded;
1597 }
1598
1599 extern void anongame_set_joined(t_anongame * a, char joined)
1600 {
1601 if (!a) {
1602 eventlog(eventlog_level_error, __FUNCTION__, "got NULL anongame");
1603 return;
1604 }
1605
1606 a->joined = joined;
1607 }
1608
1609 /**********/
1610 /* move to own .c/.h file for handling w3route connections */
1611 extern int handle_w3route_packet(t_connection * c, t_packet const *const packet)
1612 {
1613 /* [smith] 20030427 fixed Big-Endian/Little-Endian conversion (Solaris bug) then
1614 * use packet_append_data for append platform dependent data types - like
1615 * "int", cos this code was broken for BE platforms. it's rewriten in platform
1616 * independent style whis usege bn_int and other bn_* like datatypes and
1617 * fuctions for wor with datatypes - bn_int_set(), what provide right
1618 * byteorder, not depended on LE/BE
1619 * fixed broken htonl() conversion for BE platforms - change it to
1620 * bn_int_nset(). i hope it's worked on intel too %) */
1621
1622 t_packet *rpacket;
1623 t_connection *gamec;
1624 char const *username;
1625 t_anongame *a = NULL;
1626 t_uint8 gametype, plnum;
1627 int tp, i;
1628
1629 if (!c) {
1630 eventlog(eventlog_level_error, __FUNCTION__, "[%d] got NULL connection", conn_get_socket(c));
1631 return -1;
1632 }
1633 if (!packet) {
1634 eventlog(eventlog_level_error, __FUNCTION__, "[%d] got NULL packet", conn_get_socket(c));
1635 return -1;
1636 }
1637 if (packet_get_class(packet) != packet_class_w3route) {
1638 eventlog(eventlog_level_error, __FUNCTION__, "[%d] got bad packet (class %d)", conn_get_socket(c), packet_get_class(packet));
1639 return -1;
1640 }
1641 if (conn_get_state(c) != conn_state_connected) {
1642 eventlog(eventlog_level_error, __FUNCTION__, "[%d] not connected", conn_get_socket(c));
1643 return -1;
1644 }
1645
1646 /* init route connection */
1647 if (packet_get_type(packet) == CLIENT_W3ROUTE_REQ) {
1648 t_connection *oldc;
1649
1650 eventlog(eventlog_level_trace, __FUNCTION__, "[%d] sizeof t_client_w3route_req %d", conn_get_socket(c), sizeof(t_client_w3route_req));
1651 username = packet_get_str_const(packet, sizeof(t_client_w3route_req), USER_NAME_MAX);
1652 eventlog(eventlog_level_info, __FUNCTION__, "[%d] got username '%s'", conn_get_socket(c), username);
1653 gamec = connlist_find_connection_by_accountname(username);
1654
1655 if (!gamec) {
1656 eventlog(eventlog_level_info, __FUNCTION__, "[%d] no game connection found for this w3route connection; closing", conn_get_socket(c));
1657 conn_set_state(c, conn_state_destroy);
1658 return 0;
1659 }
1660
1661 if (!(a = conn_get_anongame(gamec))) {
1662 eventlog(eventlog_level_info, __FUNCTION__, "[%d] no anongame struct for game connection", conn_get_socket(c));
1663 conn_set_state(c, conn_state_destroy);
1664 return 0;
1665 }
1666
1667 if (bn_int_get((unsigned char const *) packet->u.data + sizeof(t_client_w3route_req) + strlen(username) + 2) != anongame_get_id(a)) {
1668 eventlog(eventlog_level_info, __FUNCTION__, "[%d] client sent wrong id for user '%s', closing connection", conn_get_socket(c), username);
1669 conn_set_state(c, conn_state_destroy);
1670 return 0;
1671 }
1672
1673 oldc = conn_get_routeconn(gamec);
1674 if (oldc) {
1675 conn_set_routeconn(oldc, NULL);
1676 conn_set_state(oldc, conn_state_destroy);
1677 }
1678
1679 if (conn_set_routeconn(c, gamec) < 0 || conn_set_routeconn(gamec, c) < 0) {
1680 eventlog(eventlog_level_error, __FUNCTION__, "[%d] conn_set_routeconn failed", conn_get_socket(c));
1681 return -1;
1682 }
1683
1684 /* set clienttag for w3route connections; we can do conn_get_clienttag() on them */
1685 conn_set_clienttag(c, conn_get_clienttag(gamec));
1686
1687 anongame_set_addr(a, bn_int_get((unsigned char const *) packet->u.data + sizeof(t_client_w3route_req) + strlen(username) + 2 + 12));
1688 anongame_set_joined(a, 0);
1689 anongame_set_loaded(a, 0);
1690 anongame_set_result(a, -1);
1691 anongame_set_gameresults(a, NULL);
1692
1693 anongame_set_handle(a, bn_int_get(packet->u.client_w3route_req.handle));
1694
1695 if (!(rpacket = packet_create(packet_class_w3route))) {
1696 eventlog(eventlog_level_error, __FUNCTION__, "[%d] packet_create failed", conn_get_socket(c));
1697 return -1;
1698 }
1699
1700 packet_set_size(rpacket, sizeof(t_server_w3route_ack));
1701 packet_set_type(rpacket, SERVER_W3ROUTE_ACK);
1702 bn_byte_set(&rpacket->u.server_w3route_ack.unknown1, 7);
1703 bn_short_set(&rpacket->u.server_w3route_ack.unknown2, 0);
1704 bn_int_set(&rpacket->u.server_w3route_ack.unknown3, SERVER_W3ROUTE_ACK_UNKNOWN3);
1705
1706 bn_short_set(&rpacket->u.server_w3route_ack.unknown4, 0xcccc);
1707 bn_byte_set(&rpacket->u.server_w3route_ack.playernum, anongame_get_playernum(a));
1708 bn_short_set(&rpacket->u.server_w3route_ack.unknown5, 0x0002);
1709 bn_short_set(&rpacket->u.server_w3route_ack.port, conn_get_port(c));
1710 bn_int_nset(&rpacket->u.server_w3route_ack.ip, conn_get_addr(c));
1711 bn_int_set(&rpacket->u.server_w3route_ack.unknown7, 0);
1712 bn_int_set(&rpacket->u.server_w3route_ack.unknown8, 0);
1713 conn_push_outqueue(c, rpacket);
1714 packet_del_ref(rpacket);
1715
1716 return 0;
1717 } else {
1718 gamec = conn_get_routeconn(c);
1719 if (gamec)
1720 a = conn_get_anongame(gamec);
1721 }
1722
1723 if (!gamec) {
1724 eventlog(eventlog_level_info, __FUNCTION__, "[%d] no game connection found for this w3route connection", conn_get_socket(c));
1725 return 0;
1726 }
1727
1728 if (!a) {
1729 eventlog(eventlog_level_info, __FUNCTION__, "[%d] no anongame struct found for this w3route connection", conn_get_socket(c));
1730 return 0;
1731 }
1732
1733 gametype = anongame_get_queue(a);
1734 plnum = anongame_get_playernum(a);
1735 tp = anongame_get_totalplayers(a);
1736
1737 /* handle these packets _before_ checking for routeconn of other players */
1738 switch (packet_get_type(packet)) {
1739 case CLIENT_W3ROUTE_ECHOREPLY:
1740 return 0;
1741 case CLIENT_W3ROUTE_CONNECTED:
1742 return 0;
1743 case CLIENT_W3ROUTE_GAMERESULT:
1744 case CLIENT_W3ROUTE_GAMERESULT_W3XP:
1745 {
1746
1747 /* insert reading of whole packet into t_gameresult */
1748
1749 t_anongame_gameresult *gameresult;
1750 int result;
1751
1752 t_timer_data data;
1753 t_anongameinfo *inf = anongame_get_info(a);
1754 t_connection *ac;
1755
1756 data.p = NULL;
1757
1758 if (!(gameresult = anongame_gameresult_parse(packet)))
1759 result = -1;
1760 else /* own result is always stored as first result */
1761 result = gameresult_get_player_result(gameresult, 0);
1762
1763 eventlog(eventlog_level_trace, __FUNCTION__, "[%d] got W3ROUTE_GAMERESULT: %08x", conn_get_socket(c), result);
1764
1765 if (!inf) {
1766 eventlog(eventlog_level_error, __FUNCTION__, "[%d] NULL anongameinfo", conn_get_socket(c));
1767 return -1;
1768 }
1769
1770 anongame_set_gameresults(a, gameresult);
1771 anongame_set_result(a, result);
1772
1773 conn_set_state(c, conn_state_destroy);
1774
1775 /* activate timers on open w3route connectons */
1776 if (result == W3_GAMERESULT_WIN) {
1777 for (i = 0; i < tp; i++) {
1778 if (anongame_get_player(a, i)) {
1779 ac = conn_get_routeconn(anongame_get_player(a, i));
1780 if (ac) {
1781 /* 300 seconds or 5 minute timer */
1782 timerlist_add_timer(ac, now + (time_t) 300, conn_shutdown, data);
1783 eventlog(eventlog_level_trace, __FUNCTION__, "[%d] started timer to close w3route", conn_get_socket(ac));
1784 }
1785 }
1786 }
1787 }
1788
1789 return 0;
1790 }
1791 }
1792
1793 for (i = 0; i < tp; i++)
1794 if (i + 1 != plnum && anongame_get_player(a, i))
1795 if (!conn_get_routeconn(anongame_get_player(a, i)) || !conn_get_anongame(anongame_get_player(a, i))) {
1796 eventlog(eventlog_level_info, __FUNCTION__, "[%d] not all players have w3route connections up yet", conn_get_socket(c));
1797 return 0;
1798 }
1799
1800 /* handle these packets _after_ checking for routeconns of other players */
1801 switch (packet_get_type(packet)) {
1802 case CLIENT_W3ROUTE_LOADINGDONE:
1803 eventlog(eventlog_level_trace, __FUNCTION__, "[%d] got LOADINGDONE, playernum: %d", conn_get_socket(c), plnum);
1804
1805 anongame_set_loaded(a, 1);
1806
1807 for (i = 0; i < tp; i++) {
1808 if (!anongame_get_player(a, i)) /* ignore disconnected players */
1809 continue;
1810 if (!(rpacket = packet_create(packet_class_w3route))) {
1811 eventlog(eventlog_level_error, __FUNCTION__, "[%d] packet_create failed", conn_get_socket(c));
1812 return -1;
1813 }
1814 packet_set_size(rpacket, sizeof(t_server_w3route_loadingack));
1815 packet_set_type(rpacket, SERVER_W3ROUTE_LOADINGACK);
1816 bn_byte_set(&rpacket->u.server_w3route_loadingack.playernum, plnum);
1817 conn_push_outqueue(conn_get_routeconn(anongame_get_player(a, i)), rpacket);
1818 packet_del_ref(rpacket);
1819 }
1820
1821 /* have all players loaded? */
1822 for (i = 0; i < tp; i++)
1823 if (i + 1 != plnum && anongame_get_player(a, i) && !anongame_get_loaded(conn_get_anongame(anongame_get_player(a, i))))
1824 return 0;
1825
1826 for (i = 0; i < tp; i++) {
1827 if (!anongame_get_player(a, i))
1828 continue;
1829
1830 if (!(rpacket = packet_create(packet_class_w3route))) {
1831 eventlog(eventlog_level_error, __FUNCTION__, "[%d] packet_create failed", conn_get_socket(c));
1832 return -1;
1833 }
1834
1835 packet_set_size(rpacket, sizeof(t_server_w3route_ready));
1836 packet_set_type(rpacket, SERVER_W3ROUTE_READY);
1837 bn_byte_set(&rpacket->u.server_w3route_host.unknown1, 0);
1838 conn_push_outqueue(conn_get_routeconn(anongame_get_player(a, i)), rpacket);
1839 packet_del_ref(rpacket);
1840 }
1841
1842 break;
1843
1844 case CLIENT_W3ROUTE_ABORT:
1845 eventlog(eventlog_level_debug, __FUNCTION__, "[%d] got W3ROUTE_ABORT", conn_get_socket(c));
1846 break;
1847
1848 default:
1849 eventlog(eventlog_level_trace, __FUNCTION__, "[%d] default: got packet type: %04x", conn_get_socket(c), packet_get_type(packet));
1850 }
1851
1852 return 0;
1853 }
1854
1855 extern int handle_anongame_join(t_connection * c)
1856 {
1857 t_anongame *a, *ja, *oa;
1858 t_connection *jc, *o;
1859 t_packet *rpacket;
1860 int tp, level;
1861 char gametype;
1862 t_account *acct;
1863 t_clienttag ct = conn_get_clienttag(c);
1864
1865 static t_server_w3route_playerinfo2 pl2;
1866 static t_server_w3route_levelinfo2 li2;
1867 static t_server_w3route_playerinfo_addr pl_addr;
1868
1869 int i, j;
1870
1871 if (!c) {
1872 eventlog(eventlog_level_error, __FUNCTION__, "[%d] got NULL connection", conn_get_socket(c));
1873 return -1;
1874 }
1875 if (!(conn_get_routeconn(c))) {
1876 eventlog(eventlog_level_info, __FUNCTION__, "[%d] no route connection", conn_get_socket(c));
1877 return -1;
1878 }
1879 if (!(a = conn_get_anongame(c))) {
1880 eventlog(eventlog_level_error, __FUNCTION__, "[%d] no anongame struct", conn_get_socket(c));
1881 return -1;
1882 }
1883
1884 anongame_set_joined(a, 1);
1885 gametype = anongame_get_queue(a);
1886 tp = anongame_get_totalplayers(a);
1887
1888 /* wait till all players have w3route conns */
1889 for (i = 0; i < tp; i++)
1890 if (anongame_get_player(a, i) && (!conn_get_routeconn(anongame_get_player(a, i)) || !conn_get_anongame(anongame_get_player(a, i)) || !anongame_get_joined(conn_get_anongame(anongame_get_player(a, i))))) {
1891 eventlog(eventlog_level_info, __FUNCTION__, "[%d] not all players have joined game BNet yet", conn_get_socket(c));
1892 return 0;
1893 }
1894
1895 /* then send each player info about all others */
1896 for (j = 0; j < tp; j++) {
1897 jc = anongame_get_player(a, j);
1898 if (!jc) /* ignore disconnected players */
1899 continue;
1900 ja = conn_get_anongame(jc);
1901
1902 /* send a playerinfo packet for this player to each other player */
1903 for (i = 0; i < tp; i++) {
1904 if (i + 1 != anongame_get_playernum(ja)) {
1905 eventlog(eventlog_level_trace, __FUNCTION__, "i = %d", i);
1906
1907 if (!(o = anongame_get_player(ja, i))) {
1908 eventlog(eventlog_level_warn, __FUNCTION__, "[%d] player %d disconnected, ignoring", conn_get_socket(c), i);
1909 continue;
1910 }
1911
1912 if (!(rpacket = packet_create(packet_class_w3route))) {
1913 eventlog(eventlog_level_error, __FUNCTION__, "[%d] packet_create failed", conn_get_socket(c));
1914 return -1;
1915 }
1916
1917 packet_set_size(rpacket, sizeof(t_server_w3route_playerinfo));
1918 packet_set_type(rpacket, SERVER_W3ROUTE_PLAYERINFO);
1919
1920
1921 if (!(oa = conn_get_anongame(o))) {
1922 eventlog(eventlog_level_error, __FUNCTION__, "[%d] no anongame struct of player %d", conn_get_socket(c), i);
1923 return -1;
1924 }
1925
1926 bn_int_set(&rpacket->u.server_w3route_playerinfo.handle, anongame_get_handle(oa));
1927 bn_byte_set(&rpacket->u.server_w3route_playerinfo.playernum, anongame_get_playernum(oa));
1928
1929 packet_append_string(rpacket, conn_get_username(o));
1930
1931 /* playerinfo2 */
1932 bn_byte_set(&pl2.unknown1, 8);
1933 bn_int_set(&pl2.id, anongame_get_id(oa));
1934 bn_int_set(&pl2.race, anongame_get_race(oa));
1935 packet_append_data(rpacket, &pl2, sizeof(pl2));
1936
1937 /* external addr */
1938 bn_short_set(&pl_addr.unknown1, 2);
1939 { /* trans support */
1940 unsigned short port = conn_get_game_port(o);
1941 unsigned int addr = conn_get_game_addr(o);
1942
1943 trans_net(conn_get_game_addr(jc), &addr, &port);
1944
1945 bn_short_nset(&pl_addr.port, port);
1946 bn_int_nset(&pl_addr.ip, addr);
1947 }
1948 bn_int_set(&pl_addr.unknown2, 0);
1949 bn_int_set(&pl_addr.unknown3, 0);
1950 packet_append_data(rpacket, &pl_addr, sizeof(pl_addr));
1951
1952 /* local addr */
1953 bn_short_set(&pl_addr.unknown1, 2);
1954 bn_short_nset(&pl_addr.port, conn_get_game_port(o));
1955 bn_int_set(&pl_addr.ip, anongame_get_addr(oa));
1956 bn_int_set(&pl_addr.unknown2, 0);
1957 bn_int_set(&pl_addr.unknown3, 0);
1958 packet_append_data(rpacket, &pl_addr, sizeof(pl_addr));
1959
1960 conn_push_outqueue(conn_get_routeconn(jc), rpacket);
1961 packet_del_ref(rpacket);
1962 }
1963 }
1964
1965 /* levelinfo */
1966 if (!(rpacket = packet_create(packet_class_w3route))) {
1967 eventlog(eventlog_level_error, __FUNCTION__, "[%d] packet_create failed", conn_get_socket(c));
1968 return -1;
1969 }
1970
1971 packet_set_size(rpacket, sizeof(t_server_w3route_levelinfo));
1972 packet_set_type(rpacket, SERVER_W3ROUTE_LEVELINFO);
1973 bn_byte_set(&rpacket->u.server_w3route_levelinfo.numplayers, anongame_get_currentplayers(a));
1974
1975 for (i = 0; i < tp; i++) {
1976 if (!anongame_get_player(ja, i))
1977 continue;
1978
1979 bn_byte_set(&li2.plnum, i + 1);
1980 bn_byte_set(&li2.unknown1, 3);
1981
1982 switch (gametype) {
1983 case ANONGAME_TYPE_1V1:
1984 level = account_get_ladder_level(conn_get_account(anongame_get_player(ja, i)), ct, ladder_id_solo);
1985 break;
1986 case ANONGAME_TYPE_SMALL_FFA:
1987 case ANONGAME_TYPE_TEAM_FFA:
1988 level = account_get_ladder_level(conn_get_account(anongame_get_player(ja, i)), ct, ladder_id_ffa);
1989 break;
1990 case ANONGAME_TYPE_AT_2V2:
1991 case ANONGAME_TYPE_AT_3V3:
1992 case ANONGAME_TYPE_AT_4V4:
1993 case ANONGAME_TYPE_AT_2V2V2:
1994 acct = conn_get_account(anongame_get_player(ja, i));
1995 level = team_get_level(account_find_team_by_teamid(acct, account_get_currentatteam(acct)));
1996 break;
1997 case ANONGAME_TYPE_TY:
1998 level = 0; /* FIXME-TY: WHAT TO DO HERE */
1999 break;
2000 default:
2001 level = account_get_ladder_level(conn_get_account(anongame_get_player(ja, i)), ct, ladder_id_team);
2002 break;
2003 }
2004
2005 /* first anongame shows level 0 as level 1 */
2006 bn_byte_set(&li2.level, level ? level : 1);
2007
2008 bn_short_set(&li2.unknown2, 0);
2009 packet_append_data(rpacket, &li2, sizeof(li2));
2010 }
2011
2012 conn_push_outqueue(conn_get_routeconn(jc), rpacket);
2013 packet_del_ref(rpacket);
2014
2015 /* startgame1 */
2016 if (!(rpacket = packet_create(packet_class_w3route))) {
2017 eventlog(eventlog_level_error, __FUNCTION__, "[%d] packet_create failed", conn_get_socket(c));
2018 return -1;
2019 }
2020 packet_set_size(rpacket, sizeof(t_server_w3route_startgame1));
2021 packet_set_type(rpacket, SERVER_W3ROUTE_STARTGAME1);
2022 conn_push_outqueue(conn_get_routeconn(jc), rpacket);
2023 packet_del_ref(rpacket);
2024
2025 /* startgame2 */
2026 if (!(rpacket = packet_create(packet_class_w3route))) {
2027 eventlog(eventlog_level_error, __FUNCTION__, "[%d] packet_create failed", conn_get_socket(c));
2028 return -1;
2029 }
2030 packet_set_size(rpacket, sizeof(t_server_w3route_startgame2));
2031 packet_set_type(rpacket, SERVER_W3ROUTE_STARTGAME2);
2032 conn_push_outqueue(conn_get_routeconn(jc), rpacket);
2033 packet_del_ref(rpacket);
2034 }
2035 return 0;
2036 }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1