/** * @brief */ void Cl_Ping_f(void) { net_addr_t addr; cl_server_info_t *server; if (Cmd_Argc() != 2) { Com_Print("Usage: %s <address>\n", Cmd_Argv(0)); return; } server = NULL; if (!Net_StringToNetaddr(Cmd_Argv(1), &addr)) { Com_Print("Invalid address\n"); return; } if (!addr.port) { // use default addr.port = (uint16_t) htons(PORT_SERVER); } server = Cl_ServerForNetaddr(&addr); if (!server) { // add it server = Cl_AddServer(&addr); server->source = SERVER_SOURCE_USER; } server->ping_time = quetoo.ticks; server->ping = 999; Com_Print("Pinging %s\n", Net_NetaddrToString(&server->addr)); Netchan_OutOfBandPrint(NS_UDP_CLIENT, &server->addr, "info %i", PROTOCOL_MAJOR); }
/* * @brief A client issued an rcon command. Shift down the remaining args and * redirect all output to the invoking client. */ static void Svc_RemoteCommand(void) { const _Bool auth = Sv_RconAuthenticate(); const char *addr = Net_NetaddrToString(&net_from); // first print to the server console if (auth) Com_Print("Rcon from %s:\n%s\n", addr, net_message.data + 4); else Com_Print("Bad rcon from %s:\n%s\n", addr, net_message.data + 4); // then redirect the remaining output back to the client Com_BeginRedirect(RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, Sv_FlushRedirect); if (auth) { char remaining[MAX_STRING_CHARS]; int32_t i; remaining[0] = 0; for (i = 2; i < Cmd_Argc(); i++) { strcat(remaining, Cmd_Argv(i)); strcat(remaining, " "); } Cmd_ExecuteString(remaining); } else { Com_Print("Bad rcon_password\n"); } Com_EndRedirect(); }
/* * Cl_Ping_f */ void Cl_Ping_f(void) { net_addr_t addr; cl_server_info_t *server; if (Cmd_Argc() != 2) { Com_Print("Usage: %s <address>\n", Cmd_Argv(0)); return; } server = NULL; if (!Net_StringToNetaddr(Cmd_Argv(1), &addr)) { Com_Print("Invalid address\n"); return; } if (!addr.port) // use default addr.port = (unsigned short) BigShort(PORT_SERVER); server = Cl_ServerForNetaddr(&addr); if (!server) { // add it server = Cl_AddServer(&addr); server->source = SERVER_SOURCE_USER; } server->ping_time = cls.real_time; server->ping = 0; Com_Print("Pinging %s\n", Net_NetaddrToString(server->addr)); Netchan_OutOfBandPrint(NS_CLIENT, server->addr, "info %i", PROTOCOL); }
/* * @brief Creates the OpenGL context and initializes all GL state. */ void R_Init(void) { Com_Print("Video initialization...\n"); R_InitLocal(); R_InitContext(); R_InitConfig(); R_EnforceGlVersion(); R_InitGlExtensions(); R_InitState(); R_InitPrograms(); R_InitMedia(); R_InitImages(); R_InitDraw(); R_InitModels(); R_InitView(); Com_Print( "Video initialized %dx%dx%dbpp %s\n", r_context.width, r_context.height, (r_context.red_bits + r_context.green_bits + r_context.blue_bits + r_context.alpha_bits), (r_context.fullscreen ? "fullscreen" : "windowed")); }
/** * @brief record <demo name> * * Begin recording a demo from the current frame until `stop` is issued. */ void Cl_Record_f(void) { if (Cmd_Argc() != 2) { Com_Print("Usage: %s <demo name>\n", Cmd_Argv(0)); return; } if (cls.demo_file) { Com_Print("Already recording\n"); return; } if (cls.state != CL_ACTIVE) { Com_Print("You must be in a level to record\n"); return; } g_snprintf(cls.demo_filename, sizeof(cls.demo_filename), "demos/%s.demo", Cmd_Argv(1)); // open the demo file if (!(cls.demo_file = Fs_OpenWrite(cls.demo_filename))) { Com_Warn("Couldn't open %s\n", cls.demo_filename); return; } Com_Print("Recording to %s\n", cls.demo_filename); }
/* * Cl_Bind_f */ static void Cl_Bind_f(void) { int i, c, b; char cmd[1024]; c = Cmd_Argc(); if (c < 2) { Com_Print("Usage: %s <key> [command] : attach a command to a key\n", Cmd_Argv(0)); return; } b = Cl_StringToKeyNum(Cmd_Argv(1)); if (b == -1) { Com_Print("\"%s\" isn't a valid key\n", Cmd_Argv(1)); return; } if (c == 2) { if (ks->binds[b]) Com_Print("\"%s\" = \"%s\"\n", Cmd_Argv(1), ks->binds[b]); else Com_Print("\"%s\" is not bound\n", Cmd_Argv(1)); return; } // copy the rest of the command line cmd[0] = 0; // start out with a null string for (i = 2; i < c; i++) { strcat(cmd, Cmd_Argv(i)); if (i != (c - 1)) strcat(cmd, " "); } Cl_Bind(b, cmd); }
/* * Cl_Record_f * * record <demo name> * * Begin recording a demo from the current frame until `stop` is issued. */ void Cl_Record_f(void) { if (Cmd_Argc() != 2) { Com_Print("Usage: %s <demo name>\n", Cmd_Argv(0)); return; } if (cls.demo_file) { Com_Print("Already recording.\n"); return; } if (cls.state != CL_ACTIVE) { Com_Print("You must be in a level to record.\n"); return; } // open the demo file snprintf(cls.demo_path, sizeof(cls.demo_path), "%s/demos/%s.dem", Fs_Gamedir(), Cmd_Argv(1)); Fs_CreatePath(cls.demo_path); cls.demo_file = fopen(cls.demo_path, "wb"); if (!cls.demo_file) { Com_Warn("Cl_Record_f: couldn't open %s.\n", cls.demo_path); return; } // don't start saving messages until a non-delta compressed message is received cls.demo_waiting = true; // update user info var to inform server to send angles Cvar_ForceSet("recording", "1"); Com_Print("Requesting demo support from server...\n"); }
/* * @brief Adds the specified server to the master. */ static void Ms_AddServer(struct sockaddr_in *from) { struct sockaddr_in addr; if (Ms_GetServer(from)) { Com_Print("Duplicate ping from %s\n", inet_ntoa(from->sin_addr)); return; } if (Ms_BlacklistServer(from)) { Com_Print("Server %s has been blacklisted\n", inet_ntoa(from->sin_addr)); return; } ms_server_t *server = Z_Malloc(sizeof(*server)); server->ip = *from; server->last_heartbeat = time(0); server->port = from->sin_port; ms_servers = g_list_prepend(ms_servers, server); Com_Print("Server %s registered\n", inet_ntoa(from->sin_addr)); // send an acknowledgment addr.sin_addr = server->ip.sin_addr; addr.sin_family = AF_INET; addr.sin_port = server->port; memset(&addr.sin_zero, 0, sizeof(addr.sin_zero)); sendto(ms_sock, "\xFF\xFF\xFF\xFF" "ack", 7, 0, (struct sockaddr*) &addr, sizeof(addr)); }
/* * @brief */ static void CalcVis(void) { uint32_t i; RunThreadsOn(map_vis.num_portals * 2, true, BaseVis); SortPortals(); // fast vis just uses migh_tsee for a very loose bound if (fastvis) { for (i = 0; i < map_vis.num_portals * 2; i++) { map_vis.portals[i].vis = map_vis.portals[i].flood; map_vis.portals[i].status = stat_done; } } else { RunThreadsOn(map_vis.num_portals * 2, true, FinalVis); } // assemble the leaf vis lists by OR-ing and compressing the portal lists for (i = 0; i < map_vis.portal_clusters; i++) ClusterMerge(i); if (map_vis.portal_clusters) Com_Print("Average clusters visible: %i\n", visibility_count / map_vis.portal_clusters); else Com_Print("Average clusters visible: 0\n"); }
/* * S_Init */ void S_Init(void) { int freq, channels; unsigned short format; memset(&s_env, 0, sizeof(s_env)); if (Cvar_GetValue("s_disable")) { Com_Warn("Sound disabled.\n"); return; } Com_Print("Sound initialization...\n"); s_rate = Cvar_Get("s_rate", "44100", CVAR_ARCHIVE | CVAR_S_DEVICE, "Sound sampling rate in Hz."); s_reverse = Cvar_Get("s_reverse", "0", CVAR_ARCHIVE, "Reverse left and right channels."); s_volume = Cvar_Get("s_volume", "1.0", CVAR_ARCHIVE, "Global sound volume level."); Cmd_AddCommand("s_restart", S_Restart_f, "Restart the sound subsystem"); Cmd_AddCommand("s_play", S_Play_f, NULL); Cmd_AddCommand("s_stop", S_Stop_f, NULL); Cmd_AddCommand("s_list", S_List_f, NULL); if (SDL_WasInit(SDL_INIT_EVERYTHING) == 0) { if (SDL_Init(SDL_INIT_AUDIO) < 0) { Com_Warn("S_Init: %s.\n", SDL_GetError()); return; } } else if (SDL_WasInit(SDL_INIT_AUDIO) == 0) { if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { Com_Warn("S_Init: %s.\n", SDL_GetError()); return; } } if (Mix_OpenAudio(s_rate->integer, MIX_DEFAULT_FORMAT, 2, 1024) == -1) { Com_Warn("S_Init: %s\n", Mix_GetError()); return; } if (Mix_QuerySpec(&freq, &format, &channels) == 0) { Com_Warn("S_Init: %s\n", Mix_GetError()); return; } if (Mix_AllocateChannels(MAX_CHANNELS) != MAX_CHANNELS) { Com_Warn("S_Init: %s\n", Mix_GetError()); return; } Mix_ChannelFinished(S_FreeChannel); Com_Print("Sound initialized %dKHz %d channels.\n", freq, channels); s_env.initialized = true; S_InitMusic(); }
/* * @brief Generates ${bsp_name}.aas for AI navigation. */ int32_t AAS_Main(void) { Com_Print("\n----- AAS -----\n\n"); const time_t start = time(NULL); LoadBSPFile(bsp_name); if (d_bsp.num_nodes == 0) { Com_Error(ERR_FATAL, "No nodes"); } memset(&d_aas, 0, sizeof(d_aas)); CreateAASNodes(); PruneAASNodes(); WriteAASFile(); const time_t end = time(NULL); const time_t duration = end - start; Com_Print("\nAAS Time: "); if (duration > 59) Com_Print("%d Minutes ", (int32_t) (duration / 60)); Com_Print("%d Seconds\n", (int32_t) (duration % 60)); return 0; }
/** * @brief */ static void MemStats_f(void) { GArray *stats = Mem_Stats(); Com_Print("Memory stats:\n"); size_t sum = 0, reported_total = 0; for (size_t i = 0; i < stats->len; i++) { mem_stat_t *stat_i = &g_array_index(stats, mem_stat_t, i); const char *tag_name; if (stat_i->tag == -1) { Com_Print("total: %zd bytes\n", stat_i->size); reported_total = stat_i->size; continue; } else if (stat_i->tag < MEM_TAG_TOTAL) { tag_name = mem_tag_names[stat_i->tag]; } else { tag_name = va("#%d", stat_i->tag); } Com_Print(" [%s] %zd bytes - %zd blocks\n", tag_name, stat_i->size, stat_i->count); sum += stat_i->size; } if (sum != reported_total) { Com_Print("WARNING: %zd bytes summed vs %zd bytes reported!\n", sum, reported_total); } Com_Print(" [console] approx. %zd bytes - approx. %zd blocks\n", console_state.size, console_state.strings.length); g_array_free(stats, true); }
/* * Sv_UserInfoChanged * * Enforces safe user_info data before passing onto game module. */ void Sv_UserInfoChanged(sv_client_t *cl) { char *val; size_t i; if (*cl->user_info == '\0') { // catch empty user_info Com_Print("Empty user_info from %s\n", Sv_NetaddrToString(cl)); Sv_KickClient(cl, "Bad user info"); return; } if (strchr(cl->user_info, '\xFF')) { // catch end of message exploit Com_Print("Illegal user_info contained xFF from %s\n", Sv_NetaddrToString(cl)); Sv_KickClient(cl, "Bad user info"); return; } if (!ValidateUserInfo(cl->user_info)) { // catch otherwise invalid user_info Com_Print("Invalid user_info from %s\n", Sv_NetaddrToString(cl)); Sv_KickClient(cl, "Bad user info"); return; } val = GetUserInfo(cl->user_info, "skin"); if (strstr(val, "..")) // catch malformed skins SetUserInfo(cl->user_info, "skin", "enforcer/qforcer"); // call game code to allow overrides svs.game->ClientUserInfoChanged(cl->edict, cl->user_info); // name for C code, mask off high bit strncpy(cl->name, GetUserInfo(cl->user_info, "name"), sizeof(cl->name) - 1); for (i = 0; i < sizeof(cl->name); i++) { cl->name[i] &= 127; } // rate command val = GetUserInfo(cl->user_info, "rate"); if (*val != '\0') { cl->rate = atoi(val); if (cl->rate > CLIENT_RATE_MAX) cl->rate = CLIENT_RATE_MAX; else if (cl->rate < CLIENT_RATE_MIN) cl->rate = CLIENT_RATE_MIN; } // limit the print messages the client receives val = GetUserInfo(cl->user_info, "message_level"); if (*val != '\0') { cl->message_level = atoi(val); } // start/stop sending view angles for demo recording val = GetUserInfo(cl->user_info, "recording"); cl->recording = atoi(val) == 1; }
/* * @brief Calculate the PHS (Potentially Hearable Set) * by ORing together all the PVS visible from a leaf */ static void CalcPHS(void) { uint32_t i, j, k, l, index; int32_t bitbyte; long *dest, *src; byte *scan; int32_t count; byte uncompressed[MAX_BSP_LEAFS / 8]; byte compressed[MAX_BSP_LEAFS / 8]; Com_Verbose("Building PHS...\n"); count = 0; for (i = 0; i < map_vis.portal_clusters; i++) { scan = map_vis.uncompressed + i * map_vis.leaf_bytes; memcpy(uncompressed, scan, map_vis.leaf_bytes); for (j = 0; j < map_vis.leaf_bytes; j++) { bitbyte = scan[j]; if (!bitbyte) continue; for (k = 0; k < 8; k++) { if (!(bitbyte & (1 << k))) continue; // OR this pvs row into the phs index = ((j << 3) + k); if (index >= map_vis.portal_clusters) Com_Error(ERR_FATAL, "Bad bit vector in PVS\n"); // pad bits should be 0 src = (long *) (map_vis.uncompressed + index * map_vis.leaf_bytes); for (l = 0; l < map_vis.leaf_longs; l++) ((long *) uncompressed)[l] |= src[l]; } } for (j = 0; j < map_vis.portal_clusters; j++) if (uncompressed[j >> 3] & (1 << (j & 7))) count++; // compress the bit string j = CompressVis(uncompressed, compressed); dest = (long *) map_vis.pointer; map_vis.pointer += j; if (map_vis.pointer > map_vis.end) Com_Error(ERR_FATAL, "Overflow\n"); d_vis->bit_offsets[i][DVIS_PHS] = (byte *) dest - map_vis.base; memcpy(dest, compressed, j); } if (map_vis.portal_clusters) Com_Print("Average clusters hearable: %i\n", count / map_vis.portal_clusters); else Com_Print("Average clusters hearable: 0\n"); }
/* * BSP_Main */ int BSP_Main(void){ time_t start, end; char base[MAX_OSPATH]; int total_bsp_time; #ifdef _WIN32 char title[MAX_OSPATH]; sprintf(title, "Q2WMap [Compiling BSP]"); SetConsoleTitle(title); #endif Com_Print("\n----- BSP -----\n\n"); start = time(NULL); StripExtension(map_name, base); // clear the whole bsp structure memset(&d_bsp, 0, sizeof(d_bsp)); // delete portal and line files remove(va("%s.prt", base)); remove(va("%s.lin", base)); // if onlyents, just grab the entities and re-save if(onlyents){ LoadBSPFile(bsp_name); num_entities = 0; LoadMapFile(map_name); SetModelNumbers(); UnparseEntities(); WriteBSPFile(bsp_name); } else { // start from scratch LoadMapFile(map_name); SetModelNumbers(); ProcessModels(); } end = time(NULL); total_bsp_time = (int)(end - start); Com_Print("\nBSP Time: "); if(total_bsp_time > 59) Com_Print("%d Minutes ", total_bsp_time / 60); Com_Print("%d Seconds\n", total_bsp_time % 60); return 0; }
/* * @brief Prints information about all currently loaded media to the console. */ void S_ListMedia_f(void) { Com_Print("Loaded media:\n"); GList *key = s_media_state.keys; while (key) { s_media_t *media = g_hash_table_lookup(s_media_state.media, key->data); Com_Print("%s\n", media->name); key = key->next; } }
/* * @brief Removes the specified server. */ static void Ms_RemoveServer(struct sockaddr_in *from, ms_server_t *server) { if (!server) // resolve from address server = Ms_GetServer(from); if (!server) { Com_Print("Shutdown from unregistered server %s\n", inet_ntoa(from->sin_addr)); return; } Com_Print("Shutdown from %s\n", inet_ntoa(from->sin_addr)); Ms_DropServer(server); }
/** * @brief Stop recording a demo */ void Cl_Stop_f(void) { int32_t len = -1; if (!cls.demo_file) { Com_Print("Not recording a demo\n"); return; } // finish up Fs_Write(cls.demo_file, &len, sizeof(len), 1); Fs_Close(cls.demo_file); cls.demo_file = NULL; Com_Print("Stopped demo\n"); }
/* * @brief Entry point for spawning a new server or changing maps / demos. Brings any * connected clients along for the ride by broadcasting a reconnect before * clearing state. Special effort is made to ensure that a locally connected * client sees the reconnect message immediately. */ void Sv_InitServer(const char *server, sv_state_t state) { #ifdef BUILD_CLIENT extern void Cl_Disconnect(void); #endif char path[MAX_QPATH]; Com_Debug("Sv_InitServer: %s (%d)\n", server, state); Cbuf_CopyToDefer(); // ensure that the requested map or demo exists if (state == SV_ACTIVE_DEMO) g_snprintf(path, sizeof(path), "demos/%s.dem", server); else g_snprintf(path, sizeof(path), "maps/%s.bsp", server); if (!Fs_Exists(path)) { Com_Print("Couldn't open %s\n", path); return; } // inform any connected clients to reconnect to us Sv_ShutdownMessage("Server restarting...\n", true); #ifdef BUILD_CLIENT // disconnect any local client, they'll immediately reconnect Cl_Disconnect(); #endif // clear the sv_server_t structure Sv_ClearState(); Com_Print("Server initialization...\n"); // initialize the clients, loading the game module if we need it Sv_InitClients(); // load the map or demo and related media Sv_LoadMedia(server, state); sv.state = state; Sb_Init(&sv.multicast, sv.multicast_buffer, sizeof(sv.multicast_buffer)); Com_Print("Server initialized\n"); Com_InitSubsystem(Q2W_SERVER); svs.initialized = true; }
/* * @brief A connection-less packet has four leading 0xff bytes to distinguish * it from a game channel. Clients that are in the game can still send these, * and they will be handled here. */ static void Sv_ConnectionlessPacket(void) { Net_BeginReading(&net_message); Net_ReadLong(&net_message); // skip the -1 marker const char *s = Net_ReadStringLine(&net_message); Cmd_TokenizeString(s); const char *c = Cmd_Argv(0); const char *a = Net_NetaddrToString(&net_from); Com_Debug("Packet from %s: %s\n", a, c); if (!g_strcmp0(c, "ping")) Svc_Ping(); else if (!g_strcmp0(c, "ack")) Svc_Ack(); else if (!g_strcmp0(c, "status")) Svc_Status(); else if (!g_strcmp0(c, "info")) Svc_Info(); else if (!g_strcmp0(c, "get_challenge")) Svc_GetChallenge(); else if (!g_strcmp0(c, "connect")) Svc_Connect(); else if (!g_strcmp0(c, "rcon")) Svc_RemoteCommand(); else Com_Print("Bad connectionless packet from %s:\n%s\n", a, s); }
/** * @brief */ static void Ms_Frame(void) { const time_t now = time(NULL); GList *s = ms_servers; while (s) { ms_server_t *server = (ms_server_t *) s->data; if (now - server->last_heartbeat > 30) { if (server->queued_pings > 6) { Com_Print("Server %s timed out\n", stos(server)); Ms_DropServer(server); } else { if (now - server->last_ping >= 10) { server->queued_pings++; server->last_ping = now; Com_Verbose("Pinging %s\n", stos(server)); const char *ping = "\xFF\xFF\xFF\xFF" "ping"; sendto(ms_sock, ping, strlen(ping), 0, (struct sockaddr *) &server->addr, sizeof(server->addr)); } } } s = s->next; } }
/* * @brief */ static void Ms_SendServersList(struct sockaddr_in *from) { int32_t buflen; char buff[0xffff]; buflen = 0; memset(buff, 0, sizeof(buff)); memcpy(buff, "\xFF\xFF\xFF\xFF""servers ", 12); buflen += 12; GList *s = ms_servers; while (s) { const ms_server_t *server = (ms_server_t *) s->data; if (server->validated) { memcpy(buff + buflen, &server->ip.sin_addr, 4); buflen += 4; memcpy(buff + buflen, &server->port, 2); buflen += 2; } s = s->next; } if ((sendto(ms_sock, buff, buflen, 0, (struct sockaddr *) from, sizeof(*from))) == -1) Com_Warn("Socket error on send: %s.\n", strerror(errno)); else Com_Print("Sent server list to %s\n", inet_ntoa(from->sin_addr)); }
/* * Cl_Bindlist_f */ static void Cl_BindList_f(void) { unsigned short i; for (i = K_FIRST; i < K_LAST; i++) if (ks->binds[i] && ks->binds[i][0]) Com_Print("%s \"%s\"\n", Cl_KeyNumToString(i), ks->binds[i]); }
/* * @brief Populates the GL config structure by querying the implementation. */ static void R_InitConfig(void) { memset(&r_config, 0, sizeof(r_config)); r_config.renderer_string = (const char *) glGetString(GL_RENDERER); r_config.vendor_string = (const char *) glGetString(GL_VENDOR); r_config.version_string = (const char *) glGetString(GL_VERSION); r_config.extensions_string = (const char *) glGetString(GL_EXTENSIONS); glGetIntegerv(GL_MAX_TEXTURE_UNITS, &r_config.max_texunits); glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &r_config.max_teximage_units); Com_Print(" Renderer: ^2%s^7\n", r_config.renderer_string); Com_Print(" Vendor: ^2%s^7\n", r_config.vendor_string); Com_Print(" Version: ^2%s^7\n", r_config.version_string); }
/* * Cl_Unbind_f */ static void Cl_Unbind_f(void) { int b; if (Cmd_Argc() != 2) { Com_Print("Usage: %s <key> : remove commands from a key\n", Cmd_Argv(0)); return; } b = Cl_StringToKeyNum(Cmd_Argv(1)); if (b == -1) { Com_Print("\"%s\" isn't a valid key\n", Cmd_Argv(1)); return; } Cl_Bind(b, ""); }
/* * @brief Sends heartbeat messages to master servers every 300s. */ void Sv_HeartbeatMasters(void) { const char *string; int32_t i; if (!dedicated->value) return; // only dedicated servers report to masters if (!sv_public->value) return; // a private dedicated game if (!svs.initialized) // we're not up yet return; if (svs.next_heartbeat > quetoo.time) return; // not time to send yet svs.next_heartbeat = quetoo.time + HEARTBEAT_SECONDS * 1000; // send the same string that we would give for a status command string = Sv_StatusString(); // send to each master server for (i = 0; i < MAX_MASTERS; i++) { if (svs.masters[i].port) { Com_Print("Sending heartbeat to %s\n", Net_NetaddrToString(&svs.masters[i])); Netchan_OutOfBandPrint(NS_UDP_SERVER, &svs.masters[i], "heartbeat\n%s", string); } } }
/* * @brief */ void WriteAASFile(void) { char path[MAX_QPATH]; file_t *f; StripExtension(bsp_name, path); g_strlcat(path, ".aas", sizeof(path)); if (!(f = Fs_OpenWrite(path))) { Com_Error(ERR_FATAL, "Couldn't open %s for writing\n", path); } Com_Print("Writing %d AAS nodes..\n", d_aas.num_nodes); SwapAASFile(); d_bsp_header_t header; memset(&header, 0, sizeof(header)); header.ident = LittleLong(AAS_IDENT); header.version = LittleLong(AAS_VERSION); Fs_Write(f, &header, 1, sizeof(header)); d_bsp_lump_t *lump = &header.lumps[AAS_LUMP_NODES]; WriteLump(f, lump, d_aas.nodes, sizeof(d_aas_node_t) * d_aas.num_nodes); // rewrite the header with the populated lumps Fs_Seek(f, 0); Fs_Write(f, &header, 1, sizeof(header)); Fs_Close(f); }
/* * @brief Initializes the client console. */ void Cl_InitConsole(void) { memset(&cl_console, 0, sizeof(cl_console)); cl_console.Append = Cl_Print; Con_AddConsole(&cl_console); file_t *file = Fs_OpenRead("history"); if (file) { Con_ReadHistory(&cl_console, file); Fs_Close(file); } else { Com_Debug("Couldn't read history"); } memset(&cl_chat_console, 0, sizeof(cl_chat_console)); cl_chat_console.level = PRINT_CHAT | PRINT_TEAM_CHAT; cl_draw_chat = Cvar_Get("cl_draw_chat", "1", 0, "Draw recent chat messages"); cl_draw_notify = Cvar_Get("cl_draw_notify", "1", 0, "Draw recent console activity"); cl_notify_lines = Cvar_Get("cl_console_notify_lines", "3", CVAR_ARCHIVE, NULL); cl_notify_time = Cvar_Get("cl_notify_time", "3.0", CVAR_ARCHIVE, NULL); cl_chat_lines = Cvar_Get("cl_chat_lines", "3", CVAR_ARCHIVE, NULL); cl_chat_time = Cvar_Get("cl_chat_time", "10.0", CVAR_ARCHIVE, NULL); Cmd_Add("cl_toggle_console", Cl_ToggleConsole_f, CMD_SYSTEM | CMD_CLIENT, "Toggle the console"); Cmd_Add("cl_message_mode", Cl_MessageMode_f, CMD_CLIENT, "Activate chat"); Cmd_Add("cl_message_mode_2", Cl_MessageMode2_f, CMD_CLIENT, "Activate team chat"); Com_Print("Client console initialized\n"); }
/* * GetThreadWork * * Return an iteration of work, updating progress when appropriate. */ static int GetThreadWork(void){ int r; int f; ThreadLock(); if(thread_work.index == thread_work.count){ // done ThreadUnlock(); return -1; } // update work fraction and output progress if desired f = 10 * thread_work.index / thread_work.count; if(f != thread_work.fraction){ thread_work.fraction = f; if(thread_work.progress && !(verbose || debug)){ Com_Print("%i...", f); fflush(stdout); } } // assign the next work iteration r = thread_work.index; thread_work.index++; ThreadUnlock(); return r; }
/* * Cl_CheckPredictionError */ void Cl_CheckPredictionError(void) { int frame; short delta[3]; vec3_t fdelta; if (!cl_predict->value || (cl.frame.ps.pmove.pm_flags & PMF_NO_PREDICTION)) return; // calculate the last usercmd_t we sent that the server has processed frame = cls.netchan.incoming_acknowledged; frame &= CMD_MASK; // compare what the server returned with what we had predicted it to be VectorSubtract(cl.frame.ps.pmove.origin, cl.predicted_origins[frame], delta); VectorScale(delta, 0.125, fdelta); // denormalize back to floats if (VectorLength(fdelta) > 256.0) { // assume a teleport or something VectorClear(cl.prediction_error); } else { // save the prediction error for interpolation if (cl_show_prediction_misses->value && (delta[0] || delta[1] || delta[2])) Com_Print("Prediction miss on %i: %3.2f %3.2f %3.2f\n", cl.frame.server_frame, fdelta[0], fdelta[1], fdelta[2]); VectorCopy(cl.frame.ps.pmove.origin, cl.predicted_origins[frame]); VectorCopy(fdelta, cl.prediction_error); } }