/* * @brief */ void Cl_ParseConfigString(void) { const uint16_t i = (uint16_t) Net_ReadShort(&net_message); if (i >= MAX_CONFIG_STRINGS) { Com_Error(ERR_DROP, "Invalid index %i\n", i); } strcpy(cl.config_strings[i], Net_ReadString(&net_message)); const char *s = cl.config_strings[i]; if (i > CS_MODELS && i < CS_MODELS + MAX_MODELS) { if (cls.state == CL_ACTIVE) { cl.model_precache[i - CS_MODELS] = R_LoadModel(s); if (cl.config_strings[i][0] == '*') { cl.model_clip[i - CS_MODELS] = Cm_Model(s); } else { cl.model_clip[i - CS_MODELS] = NULL; } } } else if (i >= CS_SOUNDS && i < CS_SOUNDS + MAX_SOUNDS) { if (cls.state == CL_ACTIVE) { cl.sound_precache[i - CS_SOUNDS] = S_LoadSample(s); } } else if (i >= CS_IMAGES && i < CS_IMAGES + MAX_IMAGES) { if (cls.state == CL_ACTIVE) { cl.image_precache[i - CS_IMAGES] = R_LoadImage(s, IT_PIC); } } cls.cgame->UpdateConfigString(i); }
/* * @brief */ static void Cl_ParseServerData(void) { char *str; int32_t i; // wipe the cl_client_t struct Cl_ClearState(); cls.state = CL_CONNECTED; cls.key_state.dest = KEY_CONSOLE; // parse protocol version number i = Net_ReadLong(&net_message); // ensure protocol matches if (i != PROTOCOL) { Com_Error(ERR_DROP, "Server is using unknown protocol %d\n", i); } // retrieve spawn count and packet rate cl.server_count = Net_ReadLong(&net_message); cl.server_hz = Net_ReadLong(&net_message); // determine if we're viewing a demo cl.demo_server = Net_ReadByte(&net_message); // game directory str = Net_ReadString(&net_message); if (g_strcmp0(Cvar_GetString("game"), str)) { Fs_SetGame(str); // reload the client game Cl_InitCgame(); } // parse player entity number cl.entity_num = Net_ReadShort(&net_message); // get the full level name str = Net_ReadString(&net_message); Com_Print("\n"); Com_Print("%c%s\n", 2, str); }
/** * @brief */ static void Cl_ParseServerData(void) { // wipe the cl_client_t struct Cl_ClearState(); Cl_SetKeyDest(KEY_CONSOLE); // parse protocol version number const uint16_t major = Net_ReadShort(&net_message); const uint16_t minor = Net_ReadShort(&net_message); // ensure protocol major matches if (major != PROTOCOL_MAJOR) { Com_Error(ERROR_DROP, "Server is using protocol major %d\n", major); } // determine if we're viewing a demo cl.demo_server = Net_ReadByte(&net_message); // game directory char *str = Net_ReadString(&net_message); if (g_strcmp0(Cvar_GetString("game"), str)) { Fs_SetGame(str); // reload the client game Cl_InitCgame(); } // ensure protocol minor matches if (minor != cls.cgame->protocol) { Com_Error(ERROR_DROP, "Server is using protocol minor %d\n", minor); } // parse client slot number, which is our entity number + 1 cl.client_num = Net_ReadShort(&net_message); // get the full level name str = Net_ReadString(&net_message); Com_Print("\n"); Com_Print("^2%s^7\n", str); }
/** * @brief Parses an incoming SVC_PRINT message. */ static void Cl_ParsePrint(void) { const byte level = Net_ReadByte(&net_message); const char *string = Net_ReadString(&net_message); // the server shouldn't have sent us anything below our level anyway if (level >= message_level->integer) { // check to see if we should ignore the message if (*cl_ignore->string) { char patterns[MAX_STRING_CHARS]; g_strlcpy(patterns, cl_ignore->string, sizeof(patterns)); const char *p = patterns; while (true) { const char *pattern = ParseToken(&p); if (pattern == NULL) { break; } if (GlobMatch(pattern, string)) { return; } } } char *sample = NULL; switch (level) { case PRINT_CHAT: case PRINT_TEAM_CHAT: if (level == PRINT_CHAT && *cl_chat_sound->string) { sample = cl_chat_sound->string; } else if (level == PRINT_TEAM_CHAT && *cl_team_chat_sound->string) { sample = cl_team_chat_sound->string; } break; default: break; } if (sample) { S_AddSample(&(const s_play_sample_t) { .sample = S_LoadSample(sample) }); } Con_Append(level, string); }
/** * @brief */ void Cl_ParseServerInfo(void) { char info[MAX_MSG_SIZE]; cl_server_info_t *server = Cl_ServerForNetaddr(&net_from); if (!server) { // unknown server, assumed response to broadcast server = Cl_AddServer(&net_from); server->source = SERVER_SOURCE_BCAST; server->ping_time = cls.broadcast_time; } // try to parse the info string g_strlcpy(info, Net_ReadString(&net_message), sizeof(info)); if (sscanf(info, "%63c\\%31c\\%31c\\%hu\\%hu", server->hostname, server->name, server->gameplay, &server->clients, &server->max_clients) != 5) { Com_Debug(DEBUG_CLIENT, "Failed to parse info \"%s\" for %s\n", info, Net_NetaddrToString(&server->addr)); server->hostname[0] = '\0'; server->name[0] = '\0'; server->gameplay[0] = '\0'; server->clients = 0; server->max_clients = 0; return; } g_strchomp(server->hostname); g_strchomp(server->name); g_strchomp(server->gameplay); server->hostname[sizeof(server->hostname) - 1] = '\0'; server->name[sizeof(server->name) - 1] = '\0'; server->gameplay[sizeof(server->name) - 1] = '\0'; server->ping = Clamp(quetoo.ticks - server->ping_time, 1u, 999u); Ui_UpdateBindings(); }
/* * @brief */ void Cl_ParseServerMessage(void) { int32_t cmd, old_cmd; char *s; int32_t i; if (cl_show_net_messages->integer == 1) Com_Print("%u ", (uint32_t) net_message.size); else if (cl_show_net_messages->integer >= 2) Com_Print("------------------\n"); cl.byte_counter += net_message.size; cmd = 0; // parse the message while (true) { if (net_message.read > net_message.size) { Com_Error(ERR_DROP, "Bad server message\n"); } old_cmd = cmd; cmd = Net_ReadByte(&net_message); if (cmd == -1) { Cl_ShowNet("END OF MESSAGE"); break; } if (cl_show_net_messages->integer >= 2 && sv_cmd_names[cmd]) Cl_ShowNet(sv_cmd_names[cmd]); switch (cmd) { case SV_CMD_BASELINE: Cl_ParseBaseline(); break; case SV_CMD_CBUF_TEXT: s = Net_ReadString(&net_message); Cbuf_AddText(s); break; case SV_CMD_CONFIG_STRING: Cl_ParseConfigString(); break; case SV_CMD_DISCONNECT: Com_Error(ERR_DROP, "Server disconnected\n"); break; case SV_CMD_DOWNLOAD: Cl_ParseDownload(); break; case SV_CMD_FRAME: Cl_ParseFrame(); break; case SV_CMD_PRINT: i = Net_ReadByte(&net_message); s = Net_ReadString(&net_message); if (i == PRINT_CHAT) { if (Cl_IgnoreChatMessage(s)) // filter /ignore'd chatters break; if (*cl_chat_sound->string) // trigger chat sound S_StartLocalSample(cl_chat_sound->string); } else if (i == PRINT_TEAMCHAT) { if (Cl_IgnoreChatMessage(s)) // filter /ignore'd chatters break; if (*cl_team_chat_sound->string) // trigger chat sound S_StartLocalSample(cl_team_chat_sound->string); } Com_Print("%s", s); break; case SV_CMD_RECONNECT: Com_Print("Server disconnected, reconnecting...\n"); // stop download if (cls.download.file) { if (cls.download.http) // clean up http downloads Cl_HttpDownload_Complete(); else // or just stop legacy ones Fs_Close(cls.download.file); cls.download.name[0] = '\0'; cls.download.file = NULL; } cls.state = CL_CONNECTING; cls.connect_time = 0; // fire immediately break; case SV_CMD_SERVER_DATA: Cl_ParseServerData(); break; case SV_CMD_SOUND: Cl_ParseSound(); break; default: // delegate to the client game module before failing if (!cls.cgame->ParseMessage(cmd)) { Com_Error(ERR_DROP, "Illegible server message:\n" " %d: last command was %s\n", cmd, sv_cmd_names[old_cmd]); } break; } } Cl_AddNetGraph(); Cl_WriteDemoMessage(); }
/** * @brief */ static void Cl_ParseCbufText(void) { const char *text = Net_ReadString(&net_message); Cbuf_AddText(text); }