mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-18 02:00:27 +02:00
2299 lines
64 KiB
C
2299 lines
64 KiB
C
/*
|
|
NETWORK_SERVER_MESSAGE_HANDLER.C
|
|
|
|
symbols in this file:
|
|
0011E890 0090:
|
|
_code_0011e890 (0000)
|
|
0011E920 00a0:
|
|
_code_0011e920 (0000)
|
|
0011E9C0 0090:
|
|
_code_0011e9c0 (0000)
|
|
0011EA50 0090:
|
|
_code_0011ea50 (0000)
|
|
0011EAE0 00a0:
|
|
_code_0011eae0 (0000)
|
|
0011EB80 00a0:
|
|
_code_0011eb80 (0000)
|
|
0011EC20 0020:
|
|
_code_0011ec20 (0000)
|
|
0011EC40 0040:
|
|
_network_game_server_send_message_to_machine (0000)
|
|
0011EC80 0110:
|
|
_network_game_server_send_message_to_all_machines (0000)
|
|
0011ED90 0090:
|
|
_network_game_server_send_player_joined_info_ingame (0000)
|
|
0011EE20 00c0:
|
|
_network_game_server_send_game_data_pregame (0000)
|
|
0011EEE0 0240:
|
|
_code_0011eee0 (0000)
|
|
0011F120 00c0:
|
|
_code_0011f120 (0000)
|
|
0011F1E0 03f0:
|
|
_code_0011f1e0 (0000)
|
|
0011F5D0 00c0:
|
|
_code_0011f5d0 (0000)
|
|
0011F690 00c0:
|
|
_code_0011f690 (0000)
|
|
0011F750 00e0:
|
|
_code_0011f750 (0000)
|
|
0011F830 00d0:
|
|
_code_0011f830 (0000)
|
|
0011F900 00d0:
|
|
_code_0011f900 (0000)
|
|
0011F9D0 00f0:
|
|
_code_0011f9d0 (0000)
|
|
0011FAC0 0310:
|
|
_network_game_server_handle_datagram (0000)
|
|
0011FDD0 0400:
|
|
_network_game_server_handle_client_message (0000)
|
|
00286F00 005a:
|
|
??_C@_0FK@KMJJAKFL@failed?5to?5handle?5a?5message_clien@ (0000)
|
|
00286F60 0043:
|
|
??_C@_0ED@BONJCMOD@server?5failed?5to?5decode?5a?5messag@ (0000)
|
|
00286FA8 0065:
|
|
??_C@_0GF@BGPKJGEH@failed?5to?5handle?5a?5message_type_@ (0000)
|
|
00287010 004e:
|
|
??_C@_0EO@HMJBCLNP@server?5failed?5to?5decode?5a?5messag@ (0000)
|
|
00287060 0056:
|
|
??_C@_0FG@LPGCCINN@failed?5to?5handle?5a?5message_clien@ (0000)
|
|
002870B8 0037:
|
|
??_C@_0DH@MMOKOPCN@server?5failed?5to?5decode?5a?5messag@ (0000)
|
|
002870F0 005e:
|
|
??_C@_0FO@NHCIMMDF@failed?5to?5handle?5a?5message_clien@ (0000)
|
|
00287150 004a:
|
|
??_C@_0EK@ONPDOJKK@server?5failed?5to?5decode?5a?5messag@ (0000)
|
|
002871A0 0068:
|
|
??_C@_0GI@DLKCJODI@failed?5to?5handle?5a?5message_clien@ (0000)
|
|
00287208 004f:
|
|
??_C@_0EP@DAOANLDM@server?5failed?5to?5decode?5a?5messag@ (0000)
|
|
00287258 0033:
|
|
??_C@_0DD@FJKDMFNA@server?5failed?5to?5remove?5a?5networ@ (0000)
|
|
00287290 005b:
|
|
??_C@_0FL@NDHDFCNK@failed?5to?5handle?5a?5message_clien@ (0000)
|
|
002872F0 0045:
|
|
??_C@_0EF@MJLJMBIP@network_game_server_switch_machi@ (0000)
|
|
00287338 0059:
|
|
??_C@_0FJ@PEAAKLFN@network_game_server_write?$CI?$CJ?5fail@ (0000)
|
|
00287394 0027:
|
|
??_C@_0CH@EEEHHOGO@message_length?$DM?$DNsizeof?$CImessage_b@ (0000)
|
|
002873BC 0012:
|
|
??_C@_0BC@FDHBPMJE@server?5?$CG?$CG?5message?$AA@ (0000)
|
|
002873D0 003b:
|
|
??_C@_0DL@ICDCPLFI@c?3?2halo?2SOURCE?2networking?2networ@ (0000)
|
|
0028740C 003c:
|
|
??_C@_0DM@MOMFHJIG@failed?5to?5create?5a?5message_serve@ (0000)
|
|
00287448 0072:
|
|
??_C@_0HC@FGJDKKLC@network_game_server_send_message@ (0000)
|
|
002874C0 0058:
|
|
??_C@_0FI@LBJCENJB@failed?5to?5handle?5a?5message_serve@ (0000)
|
|
00287518 003f:
|
|
??_C@_0DP@CCCLFFGC@failed?5to?5create?5a?5message_serve@ (0000)
|
|
00287558 004b:
|
|
??_C@_0EL@NFHCHAEG@failed?5to?5send?5message_server_ga@ (0000)
|
|
002875A4 0039:
|
|
??_C@_0DJ@PCNJDMDI@failed?5to?5create?5a?5message_serve@ (0000)
|
|
002875E0 0054:
|
|
??_C@_0FE@HMKEDIDF@network_game_server_write?$CI?$CJ?5fail@ (0000)
|
|
00287634 002b:
|
|
??_C@_0CL@FOJJMNII@server?5?$CG?$CG?5source_address?5?$CG?$CG?5clie@ (0000)
|
|
00287660 002f:
|
|
??_C@_0CP@JCCANCCC@failed?5to?5create?5a?5message_serve@ (0000)
|
|
00287690 0043:
|
|
??_C@_0ED@LGNNJLKJ@network_game_server_write?$CI?$CJ?5fail@ (0000)
|
|
002876D8 0042:
|
|
??_C@_0EC@MGMKMMHI@server?5failed?5to?5decode?5a?5messag@ (0000)
|
|
0028771C 003b:
|
|
??_C@_0DL@JAHACCAG@failed?5to?5create?5a?5message_serve@ (0000)
|
|
00287758 0043:
|
|
??_C@_0ED@PLLDKIEI@client?5machine?5?8?$CFs?8?5?$EA?$CFs?5tried?5to@ (0000)
|
|
002877A0 0041:
|
|
??_C@_0EB@ONCPMINI@client?5machine?5?8?$CFs?8?5?$EA?$CFs?5tried?5to@ (0000)
|
|
002877E8 0043:
|
|
??_C@_0ED@DKNIPKFL@network_game_server_write?$CI?$CJ?5fail@ (0000)
|
|
00287830 0044:
|
|
??_C@_0EE@MGEHHOCB@server?5failed?5to?5accept?5valid?5cl@ (0000)
|
|
00287878 0075:
|
|
??_C@_0HF@HFOMEJBD@network_game_server_send_game_da@ (0000)
|
|
002878F0 0039:
|
|
??_C@_0DJ@CKOCAMEF@sent?5_message_type_server_machin@ (0000)
|
|
00287930 0064:
|
|
??_C@_0GE@MLODGBHN@network_game_server_write?$CI?$CJ?5fail@ (0000)
|
|
00287994 0029:
|
|
??_C@_0CJ@EPMEBAJK@network_machine_is_valid?$CIclient_@ (0000)
|
|
002879C0 0040:
|
|
??_C@_0EA@HPKAIHHK@server?5refused?5client?5?8?$CFs?8?5becau@ (0000)
|
|
00287A00 000d:
|
|
??_C@_0N@MPMCKMFC@d?3?2hosts?4txt?$AA@ (0000)
|
|
00287A10 002d:
|
|
??_C@_0CN@LBHCOBFK@ignoring?5redundant?5join?5request?5@ (0000)
|
|
00287A40 0062:
|
|
??_C@_0GC@IBIEHGFG@failed?5to?5handle?5a?5message_clien@ (0000)
|
|
00287AA8 004b:
|
|
??_C@_0EL@BFEPJEFO@server?5failed?5to?5decode?5a?5messag@ (0000)
|
|
00287AF8 0070:
|
|
??_C@_0HA@DHHGOECG@server?5failed?5to?5add?5a?5network?5p@ (0000)
|
|
00287B68 0072:
|
|
??_C@_0HC@LODCIJJJ@server?5failed?5to?5send?5pregame?5ga@ (0000)
|
|
00287BE0 0065:
|
|
??_C@_0GF@EKICMCEL@failed?5to?5handle?5a?5message_clien@ (0000)
|
|
00287C48 004e:
|
|
??_C@_0EO@JJCAGDLG@server?5failed?5to?5decode?5a?5messag@ (0000)
|
|
00287C98 0076:
|
|
??_C@_0HG@LNIKCCLC@server?5failed?5to?5remove?5a?5networ@ (0000)
|
|
00287D10 0075:
|
|
??_C@_0HF@KPAHGLDA@server?5failed?5to?5send?5pregame?5ga@ (0000)
|
|
00287D88 0058:
|
|
??_C@_0FI@HEMIANGD@failed?5to?5handle?5a?5message_clien@ (0000)
|
|
00287DE0 0041:
|
|
??_C@_0EB@EACNFEBF@server?5failed?5to?5decode?5a?5messag@ (0000)
|
|
00287E28 0075:
|
|
??_C@_0HF@CJBDOMOO@network_game_server_adjust_machi@ (0000)
|
|
00287EA0 0068:
|
|
??_C@_0GI@IHEHKNKB@server?5failed?5to?5send?5pregame?5ga@ (0000)
|
|
00287F08 0036:
|
|
??_C@_0DG@ECGMMKBK@server?5received?5machine?5settings@ (0000)
|
|
00287F40 005f:
|
|
??_C@_0FP@BKMGBKPC@failed?5to?5handle?5a?5message_clien@ (0000)
|
|
00287FA0 0048:
|
|
??_C@_0EI@NDLJFMCJ@server?5failed?5to?5decode?5a?5messag@ (0000)
|
|
00287FE8 006b:
|
|
??_C@_0GL@MGDAOAGD@network_game_update_player?$CI?$CJ?5fai@ (0000)
|
|
00288058 006f:
|
|
??_C@_0GP@IGEJNGEG@server?5failed?5to?5send?5pregame?5ga@ (0000)
|
|
002880C8 0028:
|
|
??_C@_0CI@NAMNDBJF@server?5received?5updated?5player?5s@ (0000)
|
|
002880F0 006a:
|
|
??_C@_0GK@PIEMGCFK@failed?5to?5handle?5a?5message_clien@ (0000)
|
|
00288160 004b:
|
|
??_C@_0EL@FGPNNAHJ@server?5failed?5to?5decode?5a?5messag@ (0000)
|
|
002881B0 0080:
|
|
??_C@_0IA@GMAELFDC@network_game_server_remove_machi@ (0000)
|
|
00288230 0072:
|
|
??_C@_0HC@JPOEIOK@server?5failed?5to?5send?5pregame?5ga@ (0000)
|
|
002882A8 0061:
|
|
??_C@_0GB@BICEKEIA@failed?5to?5handle?5a?5message_clien@ (0000)
|
|
00288310 004d:
|
|
??_C@_0EN@FBHIPCPE@server?5failed?5to?5decode?5a?5messag@ (0000)
|
|
00288360 003a:
|
|
??_C@_0DK@HGNCDCGJ@server?5received?5a?5malformed?1dama@ (0000)
|
|
002883A0 0047:
|
|
??_C@_0EH@HDCJJGCF@server?5received?5low?9level?5error?5@ (0000)
|
|
002883E8 0046:
|
|
??_C@_0EG@NGIBKKFK@server?5received?5a?5bad?5message?5ty@ (0000)
|
|
00288430 003f:
|
|
??_C@_0DP@DJCDAEKP@failed?5to?5decode?5a?5message_clien@ (0000)
|
|
00288470 003e:
|
|
??_C@_0DO@EMEMPFEN@server?5failed?5to?5advertise?5game?5@ (0000)
|
|
002884B0 002e:
|
|
??_C@_0CO@IFNMPAGP@failed?5to?5decode?5a?5message_clien@ (0000)
|
|
002884E0 0026:
|
|
??_C@_0CG@PBGOHBCL@server?5failed?5to?5handle?5a?5client@ (0000)
|
|
00288508 0042:
|
|
??_C@_0EC@OIEIALKJ@ignoring?5a?5message_client_game_u@ (0000)
|
|
00288550 0062:
|
|
??_C@_0GC@EMAKPFP@failed?5to?5handle?5a?5message_clien@ (0000)
|
|
002885B4 0035:
|
|
??_C@_0DF@NPLDDCCG@failed?5to?5decode?5a?5message_clien@ (0000)
|
|
002885F0 0046:
|
|
??_C@_0EG@DEJFBBLL@server?5received?5datagram?5with?5an@ (0000)
|
|
00288638 004c:
|
|
??_C@_0EM@NPFBANHI@server?5received?5a?5datagram?5with?5@ (0000)
|
|
00288684 003c:
|
|
??_C@_0DM@HFFMPMPG@server?5received?5a?5datagram?5with?5@ (0000)
|
|
002886C0 0081:
|
|
??_C@_0IB@OPFACLKA@server?5?$CG?$CG?5message?5?$CG?$CG?5source_addr@ (0000)
|
|
00288744 003a:
|
|
??_C@_0DK@NEANDKEL@server?5received?5a?5malformed?1dama@ (0000)
|
|
00288780 0047:
|
|
??_C@_0EH@PCKBOEPO@server?5received?5low?9level?5error?5@ (0000)
|
|
002887C8 0046:
|
|
??_C@_0EG@GPPJDFA@server?5received?5a?5bad?5message?5ty@ (0000)
|
|
00288810 003e:
|
|
??_C@_0DO@LBJNGIAJ@bad?5or?5inappropriate?5packet?5type@ (0000)
|
|
00288850 004e:
|
|
??_C@_0EO@OPDINPHL@network_game_server_handle_messa@ (0000)
|
|
002888A0 0045:
|
|
??_C@_0EF@FHPBCOMI@network_game_server_handle_messa@ (0000)
|
|
002888E8 0052:
|
|
??_C@_0FC@HBMALEKE@network_game_server_handle_messa@ (0000)
|
|
00288940 0050:
|
|
??_C@_0FA@OHGBEJHJ@network_game_server_handle_messa@ (0000)
|
|
00288990 004d:
|
|
??_C@_0EN@IOBKAAMM@network_game_server_handle_messa@ (0000)
|
|
002889E0 003a:
|
|
??_C@_0DK@DJBGFGMF@network_game_server_handle_messa@ (0000)
|
|
00288A20 0046:
|
|
??_C@_0EG@KNLLMEKN@network_game_server_handle_messa@ (0000)
|
|
00288A68 004b:
|
|
??_C@_0EL@IBNDPBLB@network_game_server_handle_messa@ (0000)
|
|
00288AB8 0044:
|
|
??_C@_0EE@KLMGADOJ@network_game_server_handle_messa@ (0000)
|
|
00288B00 0051:
|
|
??_C@_0FB@PPCOJHGP@network_game_server_handle_messa@ (0000)
|
|
00288B58 004e:
|
|
??_C@_0EO@EEEMKLCF@network_game_server_handle_messa@ (0000)
|
|
00288BA8 0045:
|
|
??_C@_0EF@FHABLMKA@network_game_server_handle_messa@ (0000)
|
|
00288BF0 0048:
|
|
??_C@_0EI@INBBOEGP@an?5un?9validated?5client?5sent?5some@ (0000)
|
|
00288C38 0044:
|
|
??_C@_0EE@EPDDKPMF@server?5received?5a?5client?5message@ (0000)
|
|
00288C7C 0032:
|
|
??_C@_0DC@DAGHEIED@server?5received?5client?5message?5w@ (0000)
|
|
00288CB0 0054:
|
|
??_C@_0FE@BPJHKGCF@server?5?$CG?$CG?5machine?5?$CG?$CG?5message?5?$CG?$CG?5@ (0000)
|
|
*/
|
|
|
|
|
|
/* ---------- headers */
|
|
|
|
#include "cseries.h"
|
|
#include "bungie_net/common/message_header.h"
|
|
#include "bungie_net/network/transport.h"
|
|
#include "bungie_net/network/transport_endpoint_winsock.h"
|
|
#include "game/game.h"
|
|
#include "game/game_engine.h"
|
|
#include "game/players.h"
|
|
#include "networking/network_connection.h"
|
|
#include "networking/network_game_globals.h"
|
|
#include "networking/network_game_manager.h"
|
|
#include "networking/network_game_protocol.h"
|
|
#include "networking/network_messages.h"
|
|
#include "networking/network_server_manager_internal.h"
|
|
#include "networking/network_server_message_handler.h"
|
|
#include "text/unicode.h"
|
|
#ifdef HALO_LINUX
|
|
/* system_milliseconds(), for the settings update interval */
|
|
#include "cseries/cseries_windows.h"
|
|
#endif
|
|
|
|
/* ---------- constants */
|
|
|
|
enum
|
|
{
|
|
#ifdef HALO_LINUX
|
|
/* the native builds' session limits and protocol
|
|
(port/linux/include/halo_port_limits.h) */
|
|
MAXIMUM_NETWORK_MACHINE_COUNT = HALO_PORT_MAXIMUM_NETWORK_MACHINES,
|
|
NETWORK_MESSAGE_BUFFER_SIZE = HALO_PORT_MAXIMUM_NETWORK_MESSAGE_SIZE,
|
|
NETWORK_GAME_MESSAGE_VERSION = HALO_PORT_NETWORK_GAME_MESSAGE_VERSION,
|
|
#else
|
|
MAXIMUM_NETWORK_MACHINE_COUNT = 4,
|
|
NETWORK_MESSAGE_BUFFER_SIZE = 0x600,
|
|
NETWORK_GAME_MESSAGE_VERSION = 1,
|
|
#endif
|
|
MAXIMUM_MACHINE_NAME_LENGTH = 32,
|
|
NETWORK_GAME_MAP_NAME_LENGTH = 0x100,
|
|
JOIN_GAME_TOKEN_LENGTH = 16,
|
|
MAXIMUM_HOSTS_FILE_LINE_LENGTH = 32,
|
|
TRANSPORT_ERROR_MESSAGE_TEXT_LENGTH = 0x80,
|
|
REMOVE_PLAYER_INGAME_GAME_TIME_DELAY = 33,
|
|
TRANSPORT_NONCE_LENGTH = 8,
|
|
NETWORK_GAME_NAME_LENGTH = 16,
|
|
#ifdef HALO_LINUX
|
|
MAXIMUM_NUMBER_OF_PLAYERS = HALO_PORT_MAXIMUM_NETWORK_PLAYERS,
|
|
#else
|
|
MAXIMUM_NUMBER_OF_PLAYERS = 16,
|
|
#endif
|
|
};
|
|
|
|
enum
|
|
{
|
|
_game_advertisement_open_bit = 1,
|
|
_game_advertisement_has_teams_bit,
|
|
_game_advertisement_oddball_variant_bit,
|
|
};
|
|
|
|
#define MINIMUM_TRANSPORT_ERROR_MESSAGE_SIZE (sizeof(word) + TRANSPORT_ERROR_MESSAGE_TEXT_LENGTH + sizeof(byte))
|
|
|
|
enum
|
|
{
|
|
_message_type_error = 1,
|
|
_message_type_data = 2,
|
|
};
|
|
|
|
enum network_game_server_state
|
|
{
|
|
_network_game_server_state_pregame = 0,
|
|
_network_game_server_state_ingame,
|
|
_network_game_server_state_postgame,
|
|
};
|
|
|
|
enum network_game_packet_class
|
|
{
|
|
_network_game_packet_class_client_search = 0,
|
|
_network_game_packet_class_client_pregame = 3,
|
|
_network_game_packet_class_client_ingame = 5,
|
|
_network_game_packet_class_client_postgame = 7,
|
|
};
|
|
|
|
enum network_game_server_rejection_reason
|
|
{
|
|
_network_game_server_rejection_reason_bad_join_token = 2,
|
|
_network_game_server_rejection_reason_game_not_open = 5,
|
|
_network_game_server_rejection_reason_not_in_hosts_file = 6,
|
|
};
|
|
|
|
/* ---------- macros */
|
|
|
|
#define network_machine_is_valid(machine) \
|
|
((machine) && (machine)->machine_index >= 0 && \
|
|
(machine)->machine_index < MAXIMUM_NETWORK_MACHINE_COUNT)
|
|
|
|
/* ---------- structures */
|
|
|
|
struct network_connection;
|
|
struct network_game_server;
|
|
struct network_game_server_client_machine;
|
|
|
|
struct network_machine
|
|
{
|
|
wchar_t name[MAXIMUM_MACHINE_NAME_LENGTH];
|
|
char machine_index;
|
|
byte padding41[3];
|
|
};
|
|
|
|
struct network_game_map
|
|
{
|
|
long unknown;
|
|
char name[0x80];
|
|
};
|
|
|
|
struct network_game_local_data
|
|
{
|
|
boolean game_objects_loaded;
|
|
byte padding[3];
|
|
};
|
|
|
|
struct network_game
|
|
{
|
|
wchar_t name[NETWORK_GAME_NAME_LENGTH];
|
|
struct network_game_map map;
|
|
struct game_variant variant;
|
|
byte unknown;
|
|
char minimum_player_count;
|
|
#ifdef HALO_LINUX
|
|
/* 128 does not fit a signed char */
|
|
byte maximum_player_count;
|
|
#else
|
|
char maximum_player_count;
|
|
#endif
|
|
byte team_count;
|
|
short difficulty;
|
|
short machine_count;
|
|
struct network_machine machines[MAXIMUM_NETWORK_MACHINE_COUNT];
|
|
short player_count;
|
|
struct network_player players[MAXIMUM_NUMBER_OF_PLAYERS];
|
|
word reserved_after_players;
|
|
unsigned long random_seed;
|
|
long number_of_games_played;
|
|
struct network_game_local_data local_data;
|
|
};
|
|
|
|
#ifdef HALO_LINUX
|
|
typedef char network_game_players_offset_assert[
|
|
offsetof(struct network_game, players) == HALO_PORT_NETWORK_GAME_PLAYERS_OFFSET ? 1 : -1];
|
|
typedef char network_game_size_assert[
|
|
sizeof(struct network_game) == HALO_PORT_NETWORK_GAME_SIZE ? 1 : -1];
|
|
#endif
|
|
|
|
struct network_message
|
|
{
|
|
word header;
|
|
};
|
|
|
|
struct message_client_broadcast_game_search
|
|
{
|
|
word port;
|
|
short version;
|
|
byte nonce[TRANSPORT_NONCE_LENGTH];
|
|
};
|
|
|
|
struct message_client_ping
|
|
{
|
|
long timestamp;
|
|
short port;
|
|
byte padding[2];
|
|
};
|
|
|
|
struct message_client_game_update
|
|
{
|
|
unsigned long update_number;
|
|
short unknown;
|
|
short player_count;
|
|
#ifdef HALO_LINUX
|
|
/* a machine's players, which 16 players / 4 machines only happened to give */
|
|
struct player_action actions[MAXIMUM_LOCAL_PLAYERS];
|
|
#else
|
|
struct player_action actions[MAXIMUM_NUMBER_OF_PLAYERS / MAXIMUM_NETWORK_MACHINE_COUNT];
|
|
#endif
|
|
};
|
|
|
|
struct message_server_pong
|
|
{
|
|
long timestamp;
|
|
};
|
|
|
|
struct message_server_game_advertise
|
|
{
|
|
byte client_nonce[TRANSPORT_NONCE_LENGTH];
|
|
byte nonce[TRANSPORT_NONCE_LENGTH];
|
|
XNKID key_id;
|
|
XNKEY key;
|
|
XNADDR xnaddr;
|
|
word port;
|
|
word version;
|
|
word platform;
|
|
wchar_t game_name[NETWORK_GAME_NAME_LENGTH];
|
|
byte reserved[0x1A];
|
|
struct network_game_map map;
|
|
short engine_type;
|
|
short machine_count;
|
|
short player_count;
|
|
short maximum_player_count;
|
|
short variant_setting;
|
|
word flags;
|
|
byte join_game_token[JOIN_GAME_TOKEN_LENGTH];
|
|
};
|
|
|
|
struct message_client_join_game_request
|
|
{
|
|
wchar_t machine_name[MAXIMUM_MACHINE_NAME_LENGTH];
|
|
byte join_game_token[JOIN_GAME_TOKEN_LENGTH];
|
|
};
|
|
|
|
struct message_client_settings_request
|
|
{
|
|
wchar_t machine_name[MAXIMUM_MACHINE_NAME_LENGTH];
|
|
char machine_index;
|
|
byte padding[3];
|
|
};
|
|
|
|
struct message_client_game_start_request
|
|
{
|
|
long countdown_time;
|
|
};
|
|
|
|
struct message_client_graceful_game_exit_pregame
|
|
{
|
|
long unused;
|
|
};
|
|
|
|
struct message_client_map_is_precached_pregame
|
|
{
|
|
char map_name[NETWORK_GAME_MAP_NAME_LENGTH];
|
|
};
|
|
|
|
struct message_client_loaded
|
|
{
|
|
long unused;
|
|
};
|
|
|
|
struct message_client_switch_to_pregame
|
|
{
|
|
long unused;
|
|
};
|
|
|
|
struct message_server_machine_accepted
|
|
{
|
|
long random_seed;
|
|
short machine_index;
|
|
byte padding[2];
|
|
};
|
|
|
|
struct message_server_machine_rejected
|
|
{
|
|
short reason;
|
|
};
|
|
|
|
#ifdef HALO_LINUX
|
|
/* the game settings record no longer fits one message: it goes out as
|
|
consecutive pieces, which the clients put back together */
|
|
struct message_server_game_settings_update
|
|
{
|
|
word total_size;
|
|
word offset;
|
|
word length;
|
|
word pad;
|
|
byte data[HALO_PORT_NETWORK_GAME_SETTINGS_FRAGMENT_SIZE];
|
|
};
|
|
#else
|
|
struct message_server_game_settings_update
|
|
{
|
|
struct network_game game;
|
|
};
|
|
#endif
|
|
|
|
struct message_server_remove_player_ingame
|
|
{
|
|
struct network_player player;
|
|
long game_time;
|
|
};
|
|
|
|
/* ---------- prototypes */
|
|
|
|
static boolean network_game_server_handle_message_client_broadcast_game_search(
|
|
struct network_game_server *server,
|
|
struct transport_address *source_address,
|
|
struct message_client_broadcast_game_search *client_message);
|
|
static boolean network_game_server_handle_message_client_ping(
|
|
struct network_game_server *server,
|
|
struct transport_address *source_address,
|
|
struct message_client_ping *client_message);
|
|
static boolean network_game_server_handle_message_client_join_game_request(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size);
|
|
static boolean network_game_server_handle_message_client_add_player_request_pregame(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size);
|
|
static boolean network_game_server_handle_message_client_remove_player_request_pregame(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size);
|
|
static boolean network_game_server_handle_message_client_settings_request(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size);
|
|
static boolean network_game_server_handle_message_client_player_settings_request(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size);
|
|
static boolean network_game_server_handle_message_client_game_start_request(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size);
|
|
static boolean network_game_server_handle_message_client_graceful_game_exit_pregame(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size);
|
|
static boolean network_game_server_handle_message_client_map_is_precached_pregame(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size);
|
|
static boolean network_game_server_handle_message_client_loaded(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size);
|
|
static boolean network_game_server_handle_message_client_add_player_request_ingame(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size);
|
|
static boolean network_game_server_handle_message_client_remove_player_request_ingame(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size);
|
|
static boolean network_game_server_handle_message_client_remove_player_request_postgame(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size);
|
|
static boolean network_game_server_handle_message_client_switch_to_pregame(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size);
|
|
|
|
/* ---------- globals */
|
|
|
|
/* ---------- private code */
|
|
|
|
static boolean network_game_server_write(
|
|
struct network_connection *connection,
|
|
void *message,
|
|
word buffer_size,
|
|
struct transport_address *destination_address,
|
|
boolean reliable)
|
|
{
|
|
return network_connection_write(
|
|
connection,
|
|
message,
|
|
buffer_size,
|
|
destination_address,
|
|
reliable);
|
|
}
|
|
|
|
/* ---------- public code */
|
|
|
|
boolean network_game_server_send_message_to_machine(
|
|
struct network_game_server *server,
|
|
struct network_machine *machine,
|
|
struct network_message *message)
|
|
{
|
|
boolean result = FALSE;
|
|
struct network_connection *connection =
|
|
network_game_server_get_machine_connection(server, machine);
|
|
|
|
if (connection)
|
|
{
|
|
word message_size = GET_MESSAGE_SIZE(message->header);
|
|
|
|
result = network_game_server_write(
|
|
connection,
|
|
message,
|
|
message_size,
|
|
NULL,
|
|
1);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
boolean network_game_server_send_message_to_all_machines(
|
|
struct network_game_server *server,
|
|
struct network_message *message)
|
|
{
|
|
byte message_buffer[NETWORK_MESSAGE_BUFFER_SIZE];
|
|
boolean result = TRUE;
|
|
word message_length;
|
|
long machine_index;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_server_message_handler.c",
|
|
0x187,
|
|
server && message);
|
|
|
|
message_length = GET_MESSAGE_SIZE(message->header);
|
|
for (machine_index = 0; machine_index < MAXIMUM_NETWORK_MACHINE_COUNT; machine_index++)
|
|
{
|
|
struct network_game_server_client_machine *machine =
|
|
network_game_server_get_client_machine_at_index(server, machine_index);
|
|
|
|
if (network_game_server_client_machine_is_joined_to_game(server, machine))
|
|
{
|
|
struct network_connection *connection =
|
|
network_game_server_get_client_connection(machine);
|
|
|
|
if (connection && network_connection_active(connection))
|
|
{
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_server_message_handler.c",
|
|
0x19A,
|
|
message_length<=sizeof(message_buffer));
|
|
|
|
csmemcpy(message_buffer, message, message_length);
|
|
if (!network_game_server_write(
|
|
connection,
|
|
message_buffer,
|
|
message_length,
|
|
NULL,
|
|
1))
|
|
{
|
|
network_event(
|
|
"network_game_server_write() failed in network_game_server_send_message_to_all_machines()");
|
|
result = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
boolean network_game_server_send_player_joined_info_ingame(
|
|
struct network_game_server *server,
|
|
struct network_player *player)
|
|
{
|
|
struct network_player message;
|
|
void *encoded_message;
|
|
boolean result;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_server_message_handler.c",
|
|
0x1B0,
|
|
server && player);
|
|
|
|
message = *player;
|
|
encoded_message = create_network_game_message(
|
|
_message_server_add_player_ingame,
|
|
&message,
|
|
sizeof(message));
|
|
if (encoded_message)
|
|
{
|
|
result = network_game_server_send_message_to_all_machines(server, encoded_message);
|
|
if (!result)
|
|
{
|
|
network_event(
|
|
"network_game_server_send_message_to_all_machines() failed in network_game_server_send_player_joined_info_ingame()");
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
network_event("failed to create a message_server_add_player_ingame message");
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef HALO_LINUX
|
|
/* With up to 128 machines, sending the whole settings record (13 KB) to every
|
|
machine on each lobby change would flood the network while a lobby fills, so
|
|
changes are collected and sent at most this often; the server's pregame idle
|
|
sends what is pending. */
|
|
enum
|
|
{
|
|
NETWORK_GAME_SETTINGS_UPDATE_INTERVAL = MILLISECONDS_PER_SECOND / 4,
|
|
};
|
|
|
|
static boolean network_game_settings_update_pending = FALSE;
|
|
static unsigned long network_game_settings_update_time = 0;
|
|
|
|
boolean network_game_server_send_game_settings_to_all_machines(
|
|
struct network_game_server *server,
|
|
void const *game,
|
|
long game_size)
|
|
{
|
|
struct message_server_game_settings_update message;
|
|
long offset;
|
|
boolean result = TRUE;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_server_message_handler.c",
|
|
0x1C8,
|
|
server);
|
|
|
|
/* every piece goes out even if one fails for a machine: the others
|
|
would otherwise keep the old settings (a machine whose connection failed
|
|
is closed, and is skipped when the update is sent again) */
|
|
for (offset = 0; offset < game_size; offset += sizeof(message.data))
|
|
{
|
|
void *encoded_message;
|
|
|
|
message.total_size = (word)game_size;
|
|
message.offset = (word)offset;
|
|
message.length = (word)MIN((long)sizeof(message.data), game_size - offset);
|
|
message.pad = 0;
|
|
csmemset(message.data, 0, sizeof(message.data));
|
|
csmemcpy(message.data, (byte const *)game + offset, message.length);
|
|
encoded_message = create_network_game_message(
|
|
_message_server_game_settings_update,
|
|
&message,
|
|
sizeof(message));
|
|
if (encoded_message)
|
|
{
|
|
result = network_game_server_send_message_to_all_machines(server, encoded_message);
|
|
if (!result)
|
|
{
|
|
network_event(
|
|
"failed to send message_server_game_settings_update message to all machines");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("failed to create a message_server_game_settings_update message");
|
|
result = FALSE;
|
|
}
|
|
}
|
|
|
|
network_game_settings_update_pending = !result;
|
|
network_game_settings_update_time = system_milliseconds();
|
|
|
|
return result;
|
|
}
|
|
|
|
boolean network_game_server_flush_game_data_pregame(
|
|
struct network_game_server *server)
|
|
{
|
|
boolean result = TRUE;
|
|
|
|
if (network_game_settings_update_pending &&
|
|
system_milliseconds() - network_game_settings_update_time >= NETWORK_GAME_SETTINGS_UPDATE_INTERVAL)
|
|
{
|
|
struct network_game *game = network_game_server_get_game(server);
|
|
|
|
if (game)
|
|
{
|
|
result = network_game_server_send_game_settings_to_all_machines(server, game, sizeof(*game));
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"failed to handle a message_server_game_settings_update because their was no server game");
|
|
network_game_settings_update_pending = FALSE;
|
|
result = FALSE;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
boolean network_game_server_send_game_data_pregame(
|
|
struct network_game_server *server)
|
|
{
|
|
network_game_settings_update_pending = TRUE;
|
|
|
|
return network_game_server_flush_game_data_pregame(server);
|
|
}
|
|
#else
|
|
boolean network_game_server_send_game_data_pregame(
|
|
struct network_game_server *server)
|
|
{
|
|
struct message_server_game_settings_update message;
|
|
struct network_game *game;
|
|
void *encoded_message;
|
|
boolean result = FALSE;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_server_message_handler.c",
|
|
0x1C8,
|
|
server);
|
|
|
|
game = network_game_server_get_game(server);
|
|
if (game)
|
|
{
|
|
csmemcpy(&message, game, sizeof(message));
|
|
encoded_message = create_network_game_message(
|
|
_message_server_game_settings_update,
|
|
&message,
|
|
sizeof(message));
|
|
if (encoded_message)
|
|
{
|
|
result = network_game_server_send_message_to_all_machines(server, encoded_message);
|
|
if (!result)
|
|
{
|
|
network_event(
|
|
"failed to send message_server_game_settings_update message to all machines");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("failed to create a message_server_game_settings_update message");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"failed to handle a message_server_game_settings_update because their was no server game");
|
|
}
|
|
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
boolean network_game_server_handle_client_message(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *machine,
|
|
word *message,
|
|
short message_buffer_size)
|
|
{
|
|
boolean result = TRUE;
|
|
word message_type;
|
|
byte packet_type;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_server_message_handler.c",
|
|
0xCF,
|
|
server && machine && message && (message_buffer_size == GET_MESSAGE_SIZE(*message)));
|
|
|
|
message_type = (byte)GET_MESSAGE_TYPE(*message);
|
|
if (GET_MESSAGE_FLAGS(*message))
|
|
{
|
|
network_event("server received client message with invalid flags");
|
|
}
|
|
else
|
|
{
|
|
switch (message_type)
|
|
{
|
|
case _message_type_packet:
|
|
packet_type = ((byte *)message)[message_buffer_size - 1];
|
|
if (network_game_server_client_machine_is_joined_to_game(server, machine) ||
|
|
packet_type == _message_client_join_game_request)
|
|
{
|
|
switch (packet_type)
|
|
{
|
|
case _message_client_join_game_request:
|
|
result = network_game_server_handle_message_client_join_game_request(
|
|
server,
|
|
machine,
|
|
message,
|
|
message_buffer_size);
|
|
if (!result)
|
|
{
|
|
network_event("network_game_server_handle_message_client_join_game_request() failed");
|
|
}
|
|
break;
|
|
|
|
case _message_client_add_player_request_pregame:
|
|
result = network_game_server_handle_message_client_add_player_request_pregame(
|
|
server,
|
|
machine,
|
|
message,
|
|
message_buffer_size);
|
|
if (!result)
|
|
{
|
|
network_event("network_game_server_handle_message_client_add_player_request_pregame() failed");
|
|
}
|
|
break;
|
|
|
|
case _message_client_remove_player_request_pregame:
|
|
result = network_game_server_handle_message_client_remove_player_request_pregame(
|
|
server,
|
|
machine,
|
|
message,
|
|
message_buffer_size);
|
|
if (!result)
|
|
{
|
|
network_event("network_game_server_handle_message_client_remove_player_request_pregame() failed");
|
|
}
|
|
break;
|
|
|
|
case _message_client_settings_request:
|
|
result = network_game_server_handle_message_client_settings_request(
|
|
server,
|
|
machine,
|
|
message,
|
|
message_buffer_size);
|
|
if (!result)
|
|
{
|
|
network_event("network_game_server_handle_message_client_settings_request() failed");
|
|
}
|
|
break;
|
|
|
|
case _message_client_player_settings_request:
|
|
result = network_game_server_handle_message_client_player_settings_request(
|
|
server,
|
|
machine,
|
|
message,
|
|
message_buffer_size);
|
|
if (!result)
|
|
{
|
|
network_event("network_game_server_handle_message_client_player_settings_request() failed");
|
|
}
|
|
break;
|
|
|
|
case _message_client_game_start_request:
|
|
result = network_game_server_handle_message_client_game_start_request(
|
|
server,
|
|
machine,
|
|
message,
|
|
message_buffer_size);
|
|
if (!result)
|
|
{
|
|
network_event("network_game_server_handle_message_client_game_start_request() failed");
|
|
}
|
|
break;
|
|
|
|
case _message_client_graceful_game_exit_pregame:
|
|
result = network_game_server_handle_message_client_graceful_game_exit_pregame(
|
|
server,
|
|
machine,
|
|
message,
|
|
message_buffer_size);
|
|
if (!result)
|
|
{
|
|
network_event("network_game_server_handle_message_client_graceful_game_exit_pregame() failed");
|
|
}
|
|
break;
|
|
|
|
case _message_client_map_is_precached_pregame:
|
|
result = network_game_server_handle_message_client_map_is_precached_pregame(
|
|
server,
|
|
machine,
|
|
message,
|
|
message_buffer_size);
|
|
if (!result)
|
|
{
|
|
network_event("network_game_server_handle_message_client_graceful_game_exit_pregame() failed");
|
|
}
|
|
break;
|
|
|
|
case _message_client_loaded:
|
|
result = network_game_server_handle_message_client_loaded(
|
|
server,
|
|
machine,
|
|
message,
|
|
message_buffer_size);
|
|
if (!result)
|
|
{
|
|
network_event("network_game_server_handle_message_client_loaded() failed");
|
|
}
|
|
break;
|
|
|
|
case _message_client_add_player_request_ingame:
|
|
result = network_game_server_handle_message_client_add_player_request_ingame(
|
|
server,
|
|
machine,
|
|
message,
|
|
message_buffer_size);
|
|
if (!result)
|
|
{
|
|
network_event("network_game_server_handle_message_client_add_player_request_ingame() failed");
|
|
}
|
|
break;
|
|
|
|
case _message_client_remove_player_request_ingame:
|
|
result = network_game_server_handle_message_client_remove_player_request_ingame(
|
|
server,
|
|
machine,
|
|
message,
|
|
message_buffer_size);
|
|
if (!result)
|
|
{
|
|
network_event("network_game_server_handle_message_client_remove_player_request_ingame() failed");
|
|
}
|
|
break;
|
|
|
|
case _message_client_remove_player_request_postgame:
|
|
result = network_game_server_handle_message_client_remove_player_request_postgame(
|
|
server,
|
|
machine,
|
|
message,
|
|
message_buffer_size);
|
|
if (!result)
|
|
{
|
|
network_event("network_game_server_handle_message_client_remove_player_request_postgame() failed");
|
|
}
|
|
break;
|
|
|
|
case _message_client_switch_to_pregame:
|
|
result = network_game_server_handle_message_client_switch_to_pregame(
|
|
server,
|
|
machine,
|
|
message,
|
|
message_buffer_size);
|
|
if (!result)
|
|
{
|
|
network_event("network_game_server_handle_message_client_switch_to_pregame() failed");
|
|
}
|
|
break;
|
|
|
|
case _message_client_graceful_game_exit_postgame:
|
|
result = network_game_server_handle_message_client_graceful_game_exit_pregame(
|
|
server,
|
|
machine,
|
|
message,
|
|
message_buffer_size);
|
|
if (!result)
|
|
{
|
|
network_event("network_game_server_handle_message_client_graceful_game_exit_pregame() failed");
|
|
}
|
|
break;
|
|
|
|
default:
|
|
network_event(
|
|
"bad or inappropriate packet type received from a client (#%d)",
|
|
packet_type);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("an un-validated client sent something other than a join request message");
|
|
}
|
|
break;
|
|
|
|
case _message_type_data:
|
|
network_event("server received a bad message type from a client (_message_type_data)");
|
|
break;
|
|
|
|
case _message_type_error:
|
|
if (message_buffer_size >= MINIMUM_TRANSPORT_ERROR_MESSAGE_SIZE)
|
|
{
|
|
byte *error_message = (byte *)(message + 1);
|
|
|
|
network_event(
|
|
"server received low-level error message from a client: error= #%d (%s)",
|
|
error_message[TRANSPORT_ERROR_MESSAGE_TEXT_LENGTH],
|
|
error_message);
|
|
}
|
|
else
|
|
{
|
|
network_event("server received a malformed/damaged message from a client");
|
|
}
|
|
break;
|
|
|
|
default:
|
|
network_event(
|
|
"server received a client message with an unknown message type (#%d)",
|
|
message_type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
boolean network_game_server_handle_datagram(
|
|
struct network_game_server *server,
|
|
word *message,
|
|
short datagram_size,
|
|
struct transport_address *source_address)
|
|
{
|
|
word message_type;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_server_message_handler.c",
|
|
0x40,
|
|
server && message && source_address &&
|
|
(datagram_size > sizeof(message_header)) &&
|
|
(datagram_size == GET_MESSAGE_SIZE(*message)));
|
|
|
|
message_type = (byte)GET_MESSAGE_TYPE(*message);
|
|
if (GET_MESSAGE_FLAGS(*message))
|
|
{
|
|
network_event(
|
|
"server received a datagram with invalid flags; sender= '%s'",
|
|
transport_address_to_string(source_address));
|
|
}
|
|
else
|
|
{
|
|
switch (message_type)
|
|
{
|
|
case _message_type_packet:
|
|
{
|
|
short packet_version = NETWORK_GAME_MESSAGE_VERSION;
|
|
short packet_type = ((byte *)message)[datagram_size - 1];
|
|
|
|
datagram_size -= sizeof(word);
|
|
switch (packet_type)
|
|
{
|
|
case _message_client_broadcast_game_search:
|
|
if (network_game_should_accept_remote_connections())
|
|
{
|
|
struct message_client_broadcast_game_search game_search;
|
|
|
|
if (decode_network_game_message(
|
|
&game_search,
|
|
message + 1,
|
|
&datagram_size,
|
|
&packet_type,
|
|
&packet_version,
|
|
_network_game_packet_class_client_search))
|
|
{
|
|
if (!network_game_server_handle_message_client_broadcast_game_search(
|
|
server,
|
|
source_address,
|
|
&game_search))
|
|
{
|
|
network_event(
|
|
"server failed to advertise game to prospective client at '%s'",
|
|
transport_address_to_string(source_address));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("failed to decode a message_client_broadcast_game_search packet");
|
|
}
|
|
}
|
|
break;
|
|
|
|
case _message_client_ping:
|
|
if (network_game_should_accept_remote_connections())
|
|
{
|
|
struct message_client_ping ping;
|
|
|
|
if (decode_network_game_message(
|
|
&ping,
|
|
message + 1,
|
|
&datagram_size,
|
|
&packet_type,
|
|
&packet_version,
|
|
_network_game_packet_class_client_search))
|
|
{
|
|
if (!network_game_server_handle_message_client_ping(
|
|
server,
|
|
source_address,
|
|
&ping))
|
|
{
|
|
network_event("server failed to handle a client ping");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("failed to decode a message_client_ping packet");
|
|
}
|
|
}
|
|
break;
|
|
|
|
case _message_client_game_update:
|
|
if (network_game_server_get_state(server, NULL) == _network_game_server_state_ingame)
|
|
{
|
|
struct network_game_server_client_machine *client_machine =
|
|
network_game_server_get_client_machine_at_address(
|
|
server,
|
|
source_address->address.long_words[0]);
|
|
|
|
if (client_machine)
|
|
{
|
|
struct message_client_game_update game_update;
|
|
|
|
if (decode_network_game_message(
|
|
&game_update,
|
|
message + 1,
|
|
&datagram_size,
|
|
&packet_type,
|
|
&packet_version,
|
|
_network_game_packet_class_client_ingame))
|
|
{
|
|
network_game_server_handle_client_update_packet(
|
|
server,
|
|
client_machine,
|
|
&game_update);
|
|
}
|
|
else
|
|
{
|
|
network_event("failed to decode a message_client_game_update packet");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"failed to handle a message_client_game_update message; this client doesn't seem to be in the game");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("ignoring a message_client_game_update message; we are not in game");
|
|
}
|
|
break;
|
|
|
|
default:
|
|
network_event(
|
|
"server received datagram with an unexpected packet type; sender= '%s'",
|
|
transport_address_to_string(source_address));
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case _message_type_data:
|
|
network_event(
|
|
"server received a bad message type (_message_type_data); sender= '%s'",
|
|
transport_address_to_string(source_address));
|
|
break;
|
|
|
|
case _message_type_error:
|
|
if (datagram_size >= MINIMUM_TRANSPORT_ERROR_MESSAGE_SIZE)
|
|
{
|
|
byte *error_message = (byte *)(message + 1);
|
|
|
|
network_event(
|
|
"server received low-level error message: error= #%d (%s); sender= '%s'",
|
|
error_message[TRANSPORT_ERROR_MESSAGE_TEXT_LENGTH],
|
|
error_message,
|
|
transport_address_to_string(source_address));
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"server received a malformed/damaged message; sender= '%s'",
|
|
transport_address_to_string(source_address));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
network_event(
|
|
"server received a datagram with an unknown message type (#%d); sender= '%s'",
|
|
message_type,
|
|
transport_address_to_string(source_address));
|
|
break;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* ---------- private code */
|
|
|
|
static boolean network_game_server_handle_message_client_broadcast_game_search(
|
|
struct network_game_server *server,
|
|
struct transport_address *source_address,
|
|
struct message_client_broadcast_game_search *client_message)
|
|
{
|
|
boolean result = TRUE;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_server_message_handler.c",
|
|
0x21F,
|
|
server && source_address && client_message);
|
|
|
|
if (client_message->version == NETWORK_GAME_MESSAGE_VERSION)
|
|
{
|
|
struct network_game *game = network_game_server_get_game(server);
|
|
|
|
if (game)
|
|
{
|
|
struct message_server_game_advertise advertisement = {0};
|
|
struct transport_address address;
|
|
struct network_message *reply;
|
|
|
|
address.address_length = IPV4_ADDRESS_LENGTH;
|
|
address.address.long_words[0] = NONE;
|
|
address.port = NETWORK_GAME_CLIENT_PORT;
|
|
|
|
csmemcpy(
|
|
advertisement.client_nonce,
|
|
client_message->nonce,
|
|
sizeof(client_message->nonce));
|
|
transport_get_nonce(advertisement.nonce, TRANSPORT_NONCE_LENGTH);
|
|
advertisement.key_id = transport_get_key_id();
|
|
advertisement.key = transport_get_key();
|
|
|
|
{
|
|
XNADDR xnaddr;
|
|
|
|
advertisement.xnaddr = *transport_get_xnaddr(&xnaddr);
|
|
}
|
|
|
|
advertisement.port = NETWORK_GAME_SERVER_PORT;
|
|
advertisement.version = NETWORK_GAME_MESSAGE_VERSION;
|
|
advertisement.platform = 0;
|
|
ustrncpy(advertisement.game_name, game->name, NETWORK_GAME_NAME_LENGTH - 1);
|
|
advertisement.engine_type = (short)game->variant.game_engine_index;
|
|
csmemcpy(&advertisement.map, &game->map, sizeof(game->map));
|
|
advertisement.machine_count = game->machine_count;
|
|
advertisement.player_count = game->player_count;
|
|
advertisement.maximum_player_count = game->maximum_player_count;
|
|
advertisement.variant_setting = (short)game->variant.universal_variant.score_to_win;
|
|
advertisement.flags = 0;
|
|
if (game->variant.universal_variant.teams == TRUE)
|
|
{
|
|
advertisement.flags = FLAG(_game_advertisement_has_teams_bit);
|
|
}
|
|
|
|
if (game->variant.game_engine_index == game_engine_oddball &&
|
|
game->variant.game_engine_variant.oddball.oddball_ball_type == 2)
|
|
{
|
|
advertisement.flags |= FLAG(_game_advertisement_oddball_variant_bit);
|
|
}
|
|
|
|
if (network_game_server_game_is_open(server))
|
|
{
|
|
advertisement.flags |= FLAG(_game_advertisement_open_bit);
|
|
}
|
|
|
|
network_game_generate_join_game_token(advertisement.join_game_token);
|
|
reply = create_network_game_message(
|
|
_message_server_game_advertise,
|
|
&advertisement,
|
|
sizeof(advertisement));
|
|
if (reply)
|
|
{
|
|
word message_size = GET_MESSAGE_SIZE(reply->header);
|
|
struct network_connection *connection =
|
|
network_game_server_get_connection(server);
|
|
|
|
result = network_game_server_write(
|
|
connection,
|
|
reply,
|
|
message_size,
|
|
&address,
|
|
0);
|
|
if (!result)
|
|
{
|
|
network_event(
|
|
"network_game_server_write() failed in handle_message_client_broadcast_game_search()");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("failed to create a message_server_game_advertise message");
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static boolean network_game_server_handle_message_client_ping(
|
|
struct network_game_server *server,
|
|
struct transport_address *source_address,
|
|
struct message_client_ping *client_message)
|
|
{
|
|
struct message_server_pong pong;
|
|
struct network_message *reply;
|
|
boolean result = FALSE;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_server_message_handler.c",
|
|
0x26A,
|
|
server && source_address && client_message);
|
|
|
|
pong.timestamp = client_message->timestamp;
|
|
reply = create_network_game_message(
|
|
_message_server_pong,
|
|
&pong,
|
|
sizeof(pong));
|
|
if (reply)
|
|
{
|
|
struct transport_address address;
|
|
address.address_length = IPV4_ADDRESS_LENGTH;
|
|
address.address.long_words[0] = source_address->address.long_words[0];
|
|
address.port = client_message->port;
|
|
result = network_game_server_write(
|
|
network_game_server_get_connection(server),
|
|
reply,
|
|
GET_MESSAGE_SIZE(reply->header),
|
|
&address,
|
|
0);
|
|
if (!result)
|
|
{
|
|
network_event(
|
|
"network_game_server_write() failed in handle_message_client_ping()");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("failed to create a message_server_pong message");
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static boolean network_game_server_handle_message_client_join_game_request(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *server_client_machine,
|
|
word *message,
|
|
short message_size)
|
|
{
|
|
boolean result = TRUE;
|
|
|
|
if (network_game_server_get_state(server, NULL) == _network_game_server_state_pregame)
|
|
{
|
|
struct message_client_join_game_request join_game_request;
|
|
short packet_type = _message_client_join_game_request;
|
|
short packet_version = NETWORK_GAME_MESSAGE_VERSION;
|
|
|
|
message_size -= sizeof(word);
|
|
if (network_game_server_client_machine_is_joined_to_game(server, server_client_machine))
|
|
{
|
|
network_event("ignoring redundant join request from machine");
|
|
}
|
|
else if (decode_network_game_message(
|
|
&join_game_request,
|
|
message + 1,
|
|
&message_size,
|
|
&packet_type,
|
|
&packet_version,
|
|
_network_game_packet_class_client_pregame))
|
|
{
|
|
struct transport_address source_address;
|
|
|
|
network_connection_get_address(
|
|
network_game_server_get_client_connection(server_client_machine),
|
|
&source_address,
|
|
FALSE);
|
|
if (network_game_server_get_state(server, NULL) == _network_game_server_state_pregame &&
|
|
network_game_server_game_is_open(server))
|
|
{
|
|
byte join_game_token[JOIN_GAME_TOKEN_LENGTH];
|
|
|
|
network_game_generate_join_game_token(join_game_token);
|
|
if (!csmemcmp(
|
|
join_game_request.join_game_token,
|
|
join_game_token,
|
|
sizeof(join_game_token)))
|
|
{
|
|
boolean machine_is_in_hosts_file = TRUE;
|
|
FILE *hosts_file;
|
|
|
|
wide_to_ascii(
|
|
join_game_request.machine_name,
|
|
(char *)join_game_request.machine_name,
|
|
sizeof(join_game_request.machine_name));
|
|
hosts_file = fopen("d:\\hosts.txt", "r");
|
|
if (hosts_file)
|
|
{
|
|
char host_line[MAXIMUM_HOSTS_FILE_LINE_LENGTH] = "";
|
|
|
|
machine_is_in_hosts_file = FALSE;
|
|
while (fgets(host_line, sizeof(host_line), hosts_file))
|
|
{
|
|
if (!csstrncmp(
|
|
(char *)join_game_request.machine_name,
|
|
host_line,
|
|
csstrlen((char *)join_game_request.machine_name)))
|
|
{
|
|
machine_is_in_hosts_file = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
fclose(hosts_file);
|
|
}
|
|
|
|
if (!machine_is_in_hosts_file)
|
|
{
|
|
struct message_server_machine_rejected rejection;
|
|
struct network_message *reply;
|
|
|
|
rejection.reason = _network_game_server_rejection_reason_not_in_hosts_file;
|
|
network_event(
|
|
"server refused client '%s' because it is not in your hosts file",
|
|
join_game_request.machine_name);
|
|
reply = create_network_game_message(
|
|
_message_server_machine_rejected,
|
|
&rejection,
|
|
sizeof(rejection));
|
|
if (reply)
|
|
{
|
|
word message_size = GET_MESSAGE_SIZE(reply->header);
|
|
struct network_connection *connection =
|
|
network_game_server_get_client_connection(server_client_machine);
|
|
|
|
network_game_server_write(
|
|
connection,
|
|
reply,
|
|
message_size,
|
|
NULL,
|
|
1);
|
|
}
|
|
|
|
result = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (network_game_server_accept_client_machine_into_game(server, server_client_machine))
|
|
{
|
|
struct message_server_machine_accepted acceptance;
|
|
struct network_message *reply;
|
|
struct network_machine *client_machine;
|
|
long machine_index = NONE;
|
|
|
|
client_machine = network_game_server_get_client_machine(
|
|
server,
|
|
server_client_machine,
|
|
&machine_index);
|
|
network_game_server_get_game(server);
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\networking\\network_server_message_handler.c",
|
|
0x2CE,
|
|
network_machine_is_valid(client_machine));
|
|
|
|
acceptance.machine_index = (short)machine_index;
|
|
acceptance.random_seed = network_game_get_random_seed();
|
|
reply = create_network_game_message(
|
|
_message_server_machine_accepted,
|
|
&acceptance,
|
|
sizeof(acceptance));
|
|
if (reply)
|
|
{
|
|
word message_size = GET_MESSAGE_SIZE(reply->header);
|
|
struct network_connection *connection =
|
|
network_game_server_get_client_connection(server_client_machine);
|
|
|
|
result = network_game_server_write(
|
|
connection,
|
|
reply,
|
|
message_size,
|
|
NULL,
|
|
1);
|
|
if (!result)
|
|
{
|
|
network_event(
|
|
"network_game_server_write() failed in network_game_server_handle_message_client_join_game_request()");
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"sent _message_type_server_machine_accepted message to %d",
|
|
machine_index);
|
|
}
|
|
|
|
if (result == TRUE)
|
|
{
|
|
result = network_game_server_send_game_data_pregame(server);
|
|
if (!result)
|
|
{
|
|
network_event(
|
|
"network_game_server_send_game_data_pregame() failed in network_game_server_handle_message_client_join_game_request()");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
struct message_server_machine_rejected rejection;
|
|
struct network_message *reply;
|
|
|
|
rejection.reason = _network_game_server_rejection_reason_game_not_open;
|
|
network_event(
|
|
"server failed to accept valid client machine '%s' @%s into the game",
|
|
join_game_request.machine_name,
|
|
transport_address_to_string(&source_address));
|
|
reply = create_network_game_message(
|
|
_message_server_machine_rejected,
|
|
&rejection,
|
|
sizeof(rejection));
|
|
if (reply)
|
|
{
|
|
word message_size = GET_MESSAGE_SIZE(reply->header);
|
|
struct network_connection *connection =
|
|
network_game_server_get_client_connection(server_client_machine);
|
|
|
|
if (!network_game_server_write(
|
|
connection,
|
|
reply,
|
|
message_size,
|
|
NULL,
|
|
1))
|
|
{
|
|
network_event(
|
|
"network_game_server_write() failed while sending a rejection reply");
|
|
}
|
|
}
|
|
|
|
result = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
struct message_server_machine_rejected rejection;
|
|
struct network_message *reply;
|
|
|
|
rejection.reason = _network_game_server_rejection_reason_bad_join_token;
|
|
network_event(
|
|
"client machine '%s' @%s tried to join game with a bad join token",
|
|
join_game_request.machine_name,
|
|
transport_address_to_string(&source_address));
|
|
reply = create_network_game_message(
|
|
_message_server_machine_rejected,
|
|
&rejection,
|
|
sizeof(rejection));
|
|
if (reply)
|
|
{
|
|
word message_size = GET_MESSAGE_SIZE(reply->header);
|
|
struct network_connection *connection =
|
|
network_game_server_get_client_connection(server_client_machine);
|
|
|
|
if (!network_game_server_write(
|
|
connection,
|
|
reply,
|
|
message_size,
|
|
NULL,
|
|
1))
|
|
{
|
|
network_event(
|
|
"network_game_server_write() failed while sending a rejection reply");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("failed to create a message_server_machine_rejected message");
|
|
}
|
|
|
|
result = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
struct message_server_machine_rejected rejection;
|
|
struct network_message *reply;
|
|
|
|
rejection.reason = _network_game_server_rejection_reason_game_not_open;
|
|
network_event(
|
|
"client machine '%s' @%s tried to join game when they should not be",
|
|
join_game_request.machine_name,
|
|
transport_address_to_string(&source_address));
|
|
reply = create_network_game_message(
|
|
_message_server_machine_rejected,
|
|
&rejection,
|
|
sizeof(rejection));
|
|
if (reply)
|
|
{
|
|
word message_size = GET_MESSAGE_SIZE(reply->header);
|
|
struct network_connection *connection =
|
|
network_game_server_get_client_connection(server_client_machine);
|
|
|
|
if (!network_game_server_write(
|
|
connection,
|
|
reply,
|
|
message_size,
|
|
NULL,
|
|
1))
|
|
{
|
|
network_event(
|
|
"network_game_server_write() failed while sending a rejection reply");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("failed to create a message_server_machine_rejected message");
|
|
}
|
|
|
|
result = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("server failed to decode a message_client_join_game_request packet");
|
|
result = FALSE;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static boolean network_game_server_handle_message_client_add_player_request_pregame(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size)
|
|
{
|
|
if (network_game_server_get_state(server, NULL) == _network_game_server_state_pregame)
|
|
{
|
|
struct network_player player;
|
|
short packet_type = _message_client_add_player_request_pregame;
|
|
short packet_version = NETWORK_GAME_MESSAGE_VERSION;
|
|
|
|
message_size -= sizeof(word);
|
|
if (decode_network_game_message(
|
|
&player,
|
|
message + 1,
|
|
&message_size,
|
|
&packet_type,
|
|
&packet_version,
|
|
_network_game_packet_class_client_pregame))
|
|
{
|
|
if (network_game_server_add_player_to_game(server, client_machine, &player))
|
|
{
|
|
if (!network_game_server_send_game_data_pregame(server))
|
|
{
|
|
network_event(
|
|
"server failed to send pregame game data in network_game_server_handle_message_client_add_player_request_pregame()");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"server failed to add a network player in network_game_server_handle_message_client_add_player_request_pregame()");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("server failed to decode a message_client_add_player_request_pregame packet");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"failed to handle a message_client_add_player_request_pregame because the server is not in pregame");
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static boolean network_game_server_handle_message_client_remove_player_request_pregame(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size)
|
|
{
|
|
if (network_game_server_get_state(server, NULL) == _network_game_server_state_pregame)
|
|
{
|
|
struct network_player player;
|
|
short packet_type = _message_client_remove_player_request_pregame;
|
|
short packet_version = NETWORK_GAME_MESSAGE_VERSION;
|
|
|
|
message_size -= sizeof(word);
|
|
if (decode_network_game_message(
|
|
&player,
|
|
message + 1,
|
|
&message_size,
|
|
&packet_type,
|
|
&packet_version,
|
|
_network_game_packet_class_client_pregame))
|
|
{
|
|
if (network_game_server_remove_player_from_game(server, client_machine, &player))
|
|
{
|
|
if (!network_game_server_send_game_data_pregame(server))
|
|
{
|
|
network_event(
|
|
"server failed to send pregame game data in network_game_server_handle_message_client_remove_player_request_pregame()");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"server failed to remove a network player in network_game_server_handle_message_client_remove_player_request_pregame()");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("server failed to decode a message_client_remove_player_request_pregame packet");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"failed to handle a message_client_remove_player_request_pregame because the server is not in pregame");
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static boolean network_game_server_handle_message_client_settings_request(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size)
|
|
{
|
|
if (network_game_server_get_state(server, NULL) == _network_game_server_state_pregame)
|
|
{
|
|
struct network_machine machine_settings;
|
|
short packet_type = _message_client_settings_request;
|
|
short packet_version = NETWORK_GAME_MESSAGE_VERSION;
|
|
|
|
message_size -= sizeof(word);
|
|
if (decode_network_game_message(
|
|
&machine_settings,
|
|
message + 1,
|
|
&message_size,
|
|
&packet_type,
|
|
&packet_version,
|
|
_network_game_packet_class_client_pregame))
|
|
{
|
|
if (network_game_server_adjust_machine_settings(server, client_machine, &machine_settings))
|
|
{
|
|
network_event(
|
|
"server received machine settings for machine #%d/'%s'",
|
|
machine_settings.machine_index,
|
|
wide_to_ascii(
|
|
machine_settings.name,
|
|
(char *)machine_settings.name,
|
|
sizeof(machine_settings.name)));
|
|
if (!network_game_server_send_game_data_pregame(server))
|
|
{
|
|
network_event(
|
|
"server failed to send pregame game data in network_game_server_handle_message_client_settings_request()");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"network_game_server_adjust_machine_settings() failed in network_game_server_handle_message_client_settings_request()");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("server failed to decode a message_client_settings_request packet");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"failed to handle a message_client_settings_request because the server is not in pregame");
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static boolean network_game_server_handle_message_client_player_settings_request(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size)
|
|
{
|
|
if (network_game_server_get_state(server, NULL) == _network_game_server_state_pregame)
|
|
{
|
|
struct network_player player;
|
|
short packet_type = _message_client_player_settings_request;
|
|
short packet_version = NETWORK_GAME_MESSAGE_VERSION;
|
|
|
|
message_size -= sizeof(word);
|
|
if (decode_network_game_message(
|
|
&player,
|
|
message + 1,
|
|
&message_size,
|
|
&packet_type,
|
|
&packet_version,
|
|
_network_game_packet_class_client_pregame))
|
|
{
|
|
if (network_game_update_player(network_game_server_get_game(server), &player))
|
|
{
|
|
network_event("server received updated player settings");
|
|
if (!network_game_server_send_game_data_pregame(server))
|
|
{
|
|
network_event(
|
|
"server failed to send pregame game data in network_game_server_handle_message_client_player_settings_request()");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"network_game_update_player() failed in network_game_server_handle_message_client_player_settings_request()");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("server failed to decode a message_client_player_settings_request packet");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"failed to handle a message_client_player_settings_request because the server is not in pregame");
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static boolean network_game_server_handle_message_client_game_start_request(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size)
|
|
{
|
|
if (network_game_server_get_state(server, NULL) == _network_game_server_state_pregame)
|
|
{
|
|
struct message_client_game_start_request game_start_request;
|
|
short packet_type = _message_client_player_settings_request;
|
|
short packet_version = NETWORK_GAME_MESSAGE_VERSION;
|
|
|
|
message_size -= sizeof(word);
|
|
if (decode_network_game_message(
|
|
&game_start_request,
|
|
message + 1,
|
|
&message_size,
|
|
&packet_type,
|
|
&packet_version,
|
|
_network_game_packet_class_client_pregame))
|
|
{
|
|
network_game_server_update_countdown(server, game_start_request.countdown_time);
|
|
}
|
|
else
|
|
{
|
|
network_event("server failed to decode a message_client_game_start_request packet");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"failed to handle a message_client_game_start_request because the server is not in pregame");
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static boolean network_game_server_handle_message_client_graceful_game_exit_pregame(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size)
|
|
{
|
|
if (network_game_server_get_state(server, NULL) == _network_game_server_state_pregame)
|
|
{
|
|
struct message_client_graceful_game_exit_pregame graceful_game_exit;
|
|
short packet_type = _message_client_graceful_game_exit_pregame;
|
|
short packet_version = NETWORK_GAME_MESSAGE_VERSION;
|
|
|
|
message_size -= sizeof(word);
|
|
if (decode_network_game_message(
|
|
&graceful_game_exit,
|
|
message + 1,
|
|
&message_size,
|
|
&packet_type,
|
|
&packet_version,
|
|
_network_game_packet_class_client_pregame))
|
|
{
|
|
if (network_game_server_remove_machine_from_game(
|
|
server,
|
|
network_game_server_get_client_machine(server, client_machine, NULL)))
|
|
{
|
|
if (!network_game_server_send_game_data_pregame(server))
|
|
{
|
|
network_event(
|
|
"server failed to send pregame game data in network_game_server_handle_message_client_graceful_game_exit_pregame()");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"network_game_server_remove_machine_from_game() failed in network_game_server_handle_message_client_graceful_game_exit_pregame()");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("server failed to decode a message_client_graceful_game_exit_pregame packet");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"failed to handle a message_client_graceful_game_exit_pregame message because the server is not in pregame");
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static boolean network_game_server_handle_message_client_map_is_precached_pregame(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size)
|
|
{
|
|
if (network_game_server_get_state(server, NULL) == _network_game_server_state_pregame)
|
|
{
|
|
struct message_client_map_is_precached_pregame map_is_precached;
|
|
short packet_type = _message_client_map_is_precached_pregame;
|
|
short packet_version = NETWORK_GAME_MESSAGE_VERSION;
|
|
|
|
message_size -= sizeof(word);
|
|
if (decode_network_game_message(
|
|
&map_is_precached,
|
|
message + 1,
|
|
&message_size,
|
|
&packet_type,
|
|
&packet_version,
|
|
_network_game_packet_class_client_pregame))
|
|
{
|
|
network_game_server_client_machine_is_precached(
|
|
server,
|
|
client_machine,
|
|
map_is_precached.map_name);
|
|
}
|
|
else
|
|
{
|
|
network_event("server failed to decode a message_type_client_map_is_precached_pregame packet");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"failed to handle a message_type_client_map_is_precached_pregame because the server is not in pregame");
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static boolean network_game_server_handle_message_client_loaded(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size)
|
|
{
|
|
boolean result = TRUE;
|
|
|
|
if (network_game_server_get_state(server, NULL) == _network_game_server_state_pregame)
|
|
{
|
|
struct message_client_loaded loaded;
|
|
short packet_type = _message_client_loaded;
|
|
short packet_version = NETWORK_GAME_MESSAGE_VERSION;
|
|
|
|
message_size -= sizeof(word);
|
|
if (decode_network_game_message(
|
|
&loaded,
|
|
message + 1,
|
|
&message_size,
|
|
&packet_type,
|
|
&packet_version,
|
|
_network_game_packet_class_client_ingame))
|
|
{
|
|
network_game_server_client_machine_game_loading_complete(server, client_machine);
|
|
}
|
|
else
|
|
{
|
|
network_event("server failed to decode a message_client_loaded packet");
|
|
result = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"failed to handle a message_client_loaded message because the server is not in pregame");
|
|
result = FALSE;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static boolean network_game_server_handle_message_client_add_player_request_ingame(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size)
|
|
{
|
|
if (network_game_server_get_state(server, NULL) == _network_game_server_state_ingame)
|
|
{
|
|
struct network_player player;
|
|
short packet_type = _message_client_add_player_request_ingame;
|
|
short packet_version = NETWORK_GAME_MESSAGE_VERSION;
|
|
|
|
message_size -= sizeof(word);
|
|
if (decode_network_game_message(
|
|
&player,
|
|
message + 1,
|
|
&message_size,
|
|
&packet_type,
|
|
&packet_version,
|
|
_network_game_packet_class_client_ingame))
|
|
{
|
|
network_game_server_queue_player_for_addition(server, &player);
|
|
}
|
|
else
|
|
{
|
|
network_event("server failed to decode a message_client_add_player_request_ingame packet");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"failed to handle a message_client_add_player_request_ingame because the server is not in game");
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static boolean network_game_server_handle_message_client_remove_player_request_ingame(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size)
|
|
{
|
|
boolean result = TRUE;
|
|
|
|
if (network_game_server_get_state(server, NULL) == _network_game_server_state_ingame)
|
|
{
|
|
struct network_player player;
|
|
short packet_type = _message_client_add_player_request_ingame;
|
|
short packet_version = NETWORK_GAME_MESSAGE_VERSION;
|
|
|
|
message_size -= sizeof(word);
|
|
if (decode_network_game_message(
|
|
&player,
|
|
message + 1,
|
|
&message_size,
|
|
&packet_type,
|
|
&packet_version,
|
|
_network_game_packet_class_client_ingame))
|
|
{
|
|
struct network_game *game = network_game_server_get_game(server);
|
|
|
|
if (network_game_remove_player(game, &player))
|
|
{
|
|
struct message_server_remove_player_ingame remove_player;
|
|
void *encoded_message;
|
|
|
|
remove_player.player = player;
|
|
remove_player.game_time = game_time_get() + REMOVE_PLAYER_INGAME_GAME_TIME_DELAY;
|
|
encoded_message = create_network_game_message(
|
|
_message_server_remove_player_ingame,
|
|
&remove_player,
|
|
sizeof(remove_player));
|
|
if (encoded_message)
|
|
{
|
|
result = network_game_server_send_message_to_all_machines(server, encoded_message);
|
|
if (!result)
|
|
{
|
|
network_event(
|
|
"network_game_server_send_message_to_all_machines() failed in network_game_server_handle_message_client_remove_player_request_ingame()");
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("server failed to decode a message_client_remove_player_request_ingame packet");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"failed to handle a message_client_remove_player_request_ingame because the server is not in game");
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static boolean network_game_server_handle_message_client_remove_player_request_postgame(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size)
|
|
{
|
|
if (network_game_server_get_state(server, NULL) == _network_game_server_state_postgame)
|
|
{
|
|
struct network_player player;
|
|
short packet_type = _message_client_remove_player_request_postgame;
|
|
short packet_version = NETWORK_GAME_MESSAGE_VERSION;
|
|
|
|
message_size -= sizeof(word);
|
|
if (decode_network_game_message(
|
|
&player,
|
|
message + 1,
|
|
&message_size,
|
|
&packet_type,
|
|
&packet_version,
|
|
_network_game_packet_class_client_postgame))
|
|
{
|
|
if (!network_game_server_remove_player_from_game(server, client_machine, &player))
|
|
{
|
|
network_event("server failed to remove a network player post-game");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("server failed to decode a message_client_remove_player_request_postgame packet");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"failed to handle a message_client_remove_player_request_postgame because the server is not in post-game");
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static boolean network_game_server_handle_message_client_switch_to_pregame(
|
|
struct network_game_server *server,
|
|
struct network_game_server_client_machine *client_machine,
|
|
word *message,
|
|
short message_size)
|
|
{
|
|
boolean result = TRUE;
|
|
|
|
if (network_game_server_get_state(server, NULL) == _network_game_server_state_postgame)
|
|
{
|
|
struct message_client_switch_to_pregame switch_to_pregame;
|
|
short packet_type = _message_client_switch_to_pregame;
|
|
short packet_version = NETWORK_GAME_MESSAGE_VERSION;
|
|
|
|
message_size -= sizeof(word);
|
|
if (decode_network_game_message(
|
|
&switch_to_pregame,
|
|
message + 1,
|
|
&message_size,
|
|
&packet_type,
|
|
&packet_version,
|
|
_network_game_packet_class_client_postgame))
|
|
{
|
|
result = network_game_server_switch_machine_from_postgame_to_pregame(server, client_machine);
|
|
if (!result)
|
|
{
|
|
network_event("network_game_server_switch_machine_from_postgame_to_pregame() failed");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event("server failed to decode a message_client_remove_player_request_postgame packet");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
network_event(
|
|
"failed to handle a message_client_switch_to_pregame because the server is not in post-game");
|
|
}
|
|
|
|
return result;
|
|
}
|