/** * @brief Ensures client-side prediction has the current collision model at its * disposal. */ void Cl_UpdatePrediction(void) { // ensure the world model is loaded if (!Com_WasInit(QUETOO_SERVER) || cl.demo_server || !Cm_NumModels()) { int64_t bs; const char *bsp_name = cl.config_strings[CS_MODELS]; const int64_t bsp_size = strtoll(cl.config_strings[CS_BSP_SIZE], NULL, 10); Cm_LoadBspModel(bsp_name, &bs); if (bs != bsp_size) { Com_Error(ERROR_DROP, "Local map version differs from server: " "%" PRId64 " != %" PRId64 "\n", bs, bsp_size); } } // load the BSP models for prediction as well for (uint16_t i = 1; i < MAX_MODELS; i++) { const char *s = cl.config_strings[CS_MODELS + i]; if (*s == '*') { cl.cm_models[i] = Cm_Model(cl.config_strings[CS_MODELS + i]); } else { cl.cm_models[i] = NULL; } } }
/* * @brief */ void Cl_ClearState(void) { if (Com_WasInit(QUETOO_CGAME)) cls.cgame->ClearState(); Cl_ClearInput(); // wipe the entire cl_client_t structure memset(&cl, 0, sizeof(cl)); Com_QuitSubsystem(QUETOO_CLIENT); Mem_ClearBuffer(&cls.net_chan.message); }
/* * @brief Re-send a connect message if the last one has timed out. */ static void Cl_CheckForResend(void) { // if the local server is running and we aren't then connect if (Com_WasInit(QUETOO_SERVER) && g_strcmp0(cls.server_name, "localhost")) { if (cls.state > CL_DISCONNECTED) { Cl_Disconnect(); } g_strlcpy(cls.server_name, "localhost", sizeof(cls.server_name)); cls.state = CL_CONNECTING; cls.connect_time = 0; } // re-send if we haven't received a reply yet if (cls.state != CL_CONNECTING) return; // don't flood connection packets if (cls.connect_time && (quetoo.time - cls.connect_time < 1000)) return; net_addr_t addr; if (!Net_StringToNetaddr(cls.server_name, &addr)) { Com_Print("Bad server address\n"); cls.state = CL_DISCONNECTED; return; } if (addr.port == 0) addr.port = htons(PORT_SERVER); cls.connect_time = quetoo.time; // for retransmit requests const char *s = Net_NetaddrToString(&addr); if (g_strcmp0(cls.server_name, s)) { Com_Print("Connecting to %s (%s)...\n", cls.server_name, s); } else { Com_Print("Connecting to %s...\n", cls.server_name); } Netchan_OutOfBandPrint(NS_UDP_CLIENT, &addr, "get_challenge\n"); }
/* * @brief */ static void Cl_Connect_f(void) { if (Cmd_Argc() != 2) { Com_Print("Usage: %s <address>\n", Cmd_Argv(0)); return; } if (Com_WasInit(QUETOO_SERVER)) { // if running a local server, kill it Sv_ShutdownServer("Server quit\n"); } Cl_Disconnect(); strncpy(cls.server_name, Cmd_Argv(1), sizeof(cls.server_name)); cls.server_name[sizeof(cls.server_name) - 1] = '\0'; cls.state = CL_CONNECTING; cls.connect_time = 0; // fire immediately }
/* * R_BeginLoading * * Loads the specified level after resetting all model data. */ void R_BeginLoading(const char *bsp_name, int bsp_size) { R_FreeModels(); // free all models // load bsp for collision detection (prediction) if (!Com_WasInit(Q2W_SERVER)) { int bs; Cm_LoadBsp(bsp_name, &bs); if (bs != bsp_size) { Com_Error(ERR_DROP, "Local map version differs from server: " "%i != %i.", bs, bsp_size); } } // then load materials R_LoadMaterials(bsp_name); // finally load the bsp for rendering (surface arrays) r_world_model = R_LoadModel(bsp_name); }
/** * @brief */ static cvar_t *Cvar_Set_(const char *name, const char *value, int32_t flags, _Bool force) { cvar_t *var = Cvar_Get(name); if (!var) { // create it return Cvar_Add(name, value, flags, NULL); } if (var->flags & (CVAR_USER_INFO | CVAR_SERVER_INFO)) { if (!Cvar_InfoValidate(value)) { Com_Print("Invalid info value for %s: %s\n", var->name, value); return var; } } // if not forced, honor flags-based logic if (!force) { // command line variables retain their value through initialization if (var->flags & CVAR_CLI) { if (!Com_WasInit(QUETOO_CLIENT) && !Com_WasInit(QUETOO_SERVER)) { Com_Debug(DEBUG_CONSOLE, "%s: retaining value \"%s\" from command line.\n", name, var->string); return var; } } // developer variables can not be modified when in multiplayer mode if (var->flags & CVAR_DEVELOPER) { if (!Com_WasInit(QUETOO_SERVER)) { Com_Print("%s is only available offline.\n", name); return var; } } // write-protected variables can never be modified if (var->flags & CVAR_NO_SET) { Com_Print("%s is write protected.\n", name); return var; } // while latched variables can only be changed on map load if (var->flags & CVAR_LATCH) { if (var->latched_string) { if (!g_strcmp0(value, var->latched_string)) { return var; } Mem_Free(var->latched_string); } else { if (!g_strcmp0(value, var->string)) { return var; } } if (Com_WasInit(QUETOO_SERVER)) { Com_Print("%s will be changed for next game.\n", name); var->latched_string = Mem_Link(Mem_TagCopyString(value, MEM_TAG_CVAR), var); } else { if (var->string) { Mem_Free(var->string); } var->string = Mem_Link(Mem_TagCopyString(value, MEM_TAG_CVAR), var); var->value = strtof(var->string, NULL); var->integer = (int32_t) strtol(var->string, NULL, 0); var->modified = true; } return var; } } else { if (var->latched_string) { Mem_Free(var->latched_string); var->latched_string = NULL; } } if (!g_strcmp0(var->string, value)) { return var; // not changed } if (!force) { if (var->flags & CVAR_R_MASK) { Com_Print("%s will be changed on ^3r_restart^7.\n", name); } if (var->flags & CVAR_S_MASK) { Com_Print("%s will be changed on ^3s_restart^7.\n", name); } } if (var->flags & CVAR_USER_INFO) { cvar_user_info_modified = true; // transmit at next opportunity } Mem_Free(var->string); var->string = Mem_Link(Mem_CopyString(value), var); var->value = strtof(var->string, NULL); var->integer = (int32_t) strtol(var->string, NULL, 0); var->modified = true; return var; }
/** * @brief */ static void Init(void) { SDL_Init(SDL_INIT_TIMER); Mem_Init(); Cmd_Init(); Cvar_Init(); verbose = Cvar_Add("verbose", "0", 0, "Print verbose debugging information"); dedicated = Cvar_Add("dedicated", "0", CVAR_NO_SET, "Run a dedicated server"); if (strstr(Sys_ExecutablePath(), "-dedicated")) { Cvar_ForceSet("dedicated", "1"); } if (dedicated->value) { Cvar_ForceSet("threads", "0"); } game = Cvar_Add("game", DEFAULT_GAME, CVAR_LATCH | CVAR_SERVER_INFO, "The game module name"); game->modified = g_strcmp0(game->string, DEFAULT_GAME); threads = Cvar_Add("threads", "0", CVAR_ARCHIVE, "Specifies the number of threads to create"); threads->modified = false; time_demo = Cvar_Add("time_demo", "0", CVAR_LO_ONLY, "Benchmark and stress test"); time_scale = Cvar_Add("time_scale", "1.0", CVAR_LO_ONLY, "Controls time lapse"); const char *s = va("Quetoo %s %s %s", VERSION, __DATE__, BUILD_HOST); Cvar_Add("version", s, CVAR_SERVER_INFO | CVAR_NO_SET, NULL); quetoo.Debug = Debug; quetoo.Error = Error; quetoo.Print = Print; quetoo.Verbose = Verbose; quetoo.Warn = Warn; Fs_Init(true); Thread_Init(threads->integer); Con_Init(); Cmd_Add("mem_stats", MemStats_f, CMD_SYSTEM, "Print memory stats"); Cmd_Add("debug", Debug_f, CMD_SYSTEM, "Control debugging output"); Cmd_Add("quit", Quit_f, CMD_SYSTEM, "Quit Quetoo"); Netchan_Init(); Sv_Init(); Cl_Init(); Com_Print("Quetoo %s %s %s initialized\n", VERSION, __DATE__, BUILD_HOST); // reset debug value since Cbuf may change it from Com's "all" init Com_SetDebug("0"); // execute any +commands specified on the command line Cbuf_InsertFromDefer(); Cbuf_Execute(); // dedicated server, nothing specified, use Edge if (dedicated->value && !Com_WasInit(QUETOO_SERVER)) { Cbuf_AddText("map edge\n"); Cbuf_Execute(); } }