/* ================== CL_KeepaliveMessage When the client is taking a long time to load stuff, send keepalive messages so the server doesn't disconnect. ================== */ void CL_KeepaliveMessage (void) { float time; static float lastmsg; int ret; sizebuf_t old; byte* olddata; if (sv.active) return; // no need if server is local if (cls.demoplayback) return; // read messages from server, should just be nops old = net_message; olddata = Sys_BigStackAlloc(8192 * sizeof(byte), "CL_KeepaliveMessage"); memcpy (olddata, net_message.data, net_message.cursize); do { ret = CL_GetMessage (); switch (ret) { default: Host_Error ("CL_KeepaliveMessage: CL_GetMessage failed"); case 0: break; // nothing waiting case 1: Host_Error ("CL_KeepaliveMessage: received a message"); break; case 2: if (MSG_ReadByte() != svc_nop) Host_Error ("CL_KeepaliveMessage: datagram wasn't a nop"); break; } } while (ret); net_message = old; memcpy (net_message.data, olddata, net_message.cursize); // check time time = Sys_FloatTime (); if (time - lastmsg < 5) { Sys_BigStackFree(8192 * sizeof(byte), "CL_KeepaliveMessage"); return; } lastmsg = time; // write out a nop Con_Printf ("--> client to server keepalive\n"); MSG_WriteByte (&cls.message, clc_nop); NET_SendMessage (cls.netcon, &cls.message); SZ_Clear (&cls.message); Sys_BigStackFree(8192 * sizeof(byte), "CL_KeepaliveMessage"); }
/* ================ Host_EndGame ================ */ void Host_EndGame (char *message, ...) { va_list argptr; char* string = Sys_BigStackAlloc(1024, "Host_EndGame"); va_start (argptr,message); vsprintf (string,message,argptr); va_end (argptr); Con_DPrintf ("Host_EndGame: %s\n",string); if (sv.active) Host_ShutdownServer (false); if (cls.state == ca_dedicated) Sys_Error ("Host_EndGame: %s\n",string); // dedicated servers exit Sys_BigStackFree(1024, "Host_EndGame"); if (cls.demonum != -1) { CL_StopPlayback(); CL_NextDemo(); } else CL_Disconnect (); longjmp (host_abortserver, 1); }
/* ================ Host_Error This shuts down both the client and server ================ */ void Host_Error (char *error, ...) { va_list argptr; char* string; static bool inerror = false; if (inerror) Sys_Error ("Host_Error: recursively entered"); inerror = true; SCR_EndLoadingPlaque (); // reenable screen updates string = Sys_BigStackAlloc(1024, "Host_Error"); va_start (argptr,error); vsprintf (string,error,argptr); va_end (argptr); Con_Printf ("Host_Error: %s\n",string); if (sv.active) Host_ShutdownServer (false); if (cls.state == ca_dedicated) Sys_Error ("Host_Error: %s\n",string); // dedicated servers exit Sys_BigStackFree(1024, "Host_Error"); CL_Disconnect (); cls.demonum = -1; inerror = false; longjmp (host_abortserver, 1); }
/* ================ SV_SendServerinfo Sends the first message from the server to a connected client. This will be sent on the initial connection and upon each server load. ================ */ void SV_SendServerinfo (client_t *client) { char **s; char* message = Sys_BigStackAlloc(2048, "SV_SendServerinfo"); if (svs.maxclients > 1) { MSG_WriteByte(&client->message, svc_print); snprintf(message, sizeof(message), "\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n" "\n \01\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\03"); MSG_WriteString(&client->message, message); MSG_WriteByte(&client->message, svc_print); snprintf(message, sizeof(message), "\02\n \04ProQuake Server Version %4.2f\06" "\n \07\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\10\11", VERSION_PROQUAKE); MSG_WriteString(&client->message, message); } MSG_WriteByte (&client->message, svc_serverinfo); MSG_WriteLong (&client->message, PROTOCOL_NETQUAKE); MSG_WriteByte (&client->message, svs.maxclients); if (!coop.value && deathmatch.value) MSG_WriteByte (&client->message, GAME_DEATHMATCH); else MSG_WriteByte (&client->message, GAME_COOP); sprintf (message, pr_strings+sv.edicts->v.message); MSG_WriteString (&client->message,message); for (s = sv.model_precache+1 ; *s ; s++) MSG_WriteString (&client->message, *s); MSG_WriteByte (&client->message, 0); for (s = sv.sound_precache+1 ; *s ; s++) MSG_WriteString (&client->message, *s); MSG_WriteByte (&client->message, 0); // send music MSG_WriteByte (&client->message, svc_cdtrack); MSG_WriteByte (&client->message, sv.edicts->v.sounds); MSG_WriteByte (&client->message, sv.edicts->v.sounds); // set view MSG_WriteByte (&client->message, svc_setview); MSG_WriteShort (&client->message, NUM_FOR_EDICT(client->edict)); if (!pq_fullpitch.value && client->netconnection->proquake_connection != MOD_QSMACK) { // Ch0wW: Re-add it MSG_WriteByte(&client->message, svc_stufftext); MSG_WriteString(&client->message, "pq_fullpitch 0; cl_fullpitch 0\n"); } MSG_WriteByte (&client->message, svc_signonnum); MSG_WriteByte (&client->message, 1); client->sendsignon = true; client->spawned = false; // need prespawn, spawn, etc Sys_BigStackFree(2048, "SV_SendServerinfo"); }
/* ================ SV_SendServerinfo Sends the first message from the server to a connected client. This will be sent on the initial connection and upon each server load. ================ */ void SV_SendServerinfo (client_t *client) { char **s; // >>> FIX: For Nintendo Wii using devkitPPC / libogc // Allocating in big stack. Stack in this device is pretty small: //char message[2048]; char* message = Sys_BigStackAlloc(2048, "SV_SendServerinfo"); // <<< FIX MSG_WriteByte (&client->message, svc_print); sprintf (message, "%c\nVERSION %4.2f SERVER (%i CRC)", 2, VERSION, pr_crc); MSG_WriteString (&client->message,message); MSG_WriteByte (&client->message, svc_serverinfo); MSG_WriteLong (&client->message, PROTOCOL_VERSION); MSG_WriteByte (&client->message, svs.maxclients); if (!coop.value && deathmatch.value) MSG_WriteByte (&client->message, GAME_DEATHMATCH); else MSG_WriteByte (&client->message, GAME_COOP); sprintf (message, pr_strings+sv.edicts->v.message); MSG_WriteString (&client->message,message); for (s = sv.model_precache+1 ; *s ; s++) MSG_WriteString (&client->message, *s); MSG_WriteByte (&client->message, 0); for (s = sv.sound_precache+1 ; *s ; s++) MSG_WriteString (&client->message, *s); MSG_WriteByte (&client->message, 0); // send music MSG_WriteByte (&client->message, svc_cdtrack); MSG_WriteByte (&client->message, sv.edicts->v.sounds); MSG_WriteByte (&client->message, sv.edicts->v.sounds); // set view MSG_WriteByte (&client->message, svc_setview); MSG_WriteShort (&client->message, NUM_FOR_EDICT(client->edict)); MSG_WriteByte (&client->message, svc_signonnum); MSG_WriteByte (&client->message, 1); client->sendsignon = true; client->spawned = false; // need prespawn, spawn, etc // >>> FIX: For Nintendo Wii using devkitPPC / libogc // Deallocating from previous fix: Sys_BigStackFree(2048, "SV_SendServerinfo"); // <<< FIX }
/* ================= Host_ClientCommands Send text over to the client to be executed ================= */ void Host_ClientCommands (char *fmt, ...) { va_list argptr; char* string = Sys_BigStackAlloc(1024, "Host_ClientCommands"); va_start (argptr,fmt); vsprintf (string, fmt,argptr); va_end (argptr); MSG_WriteByte (&host_client->message, svc_stufftext); MSG_WriteString (&host_client->message, string); Sys_BigStackFree(1024, "Host_ClientCommands"); }
/* ================= SV_ClientPrintf Sends text across to be displayed FIXME: make this just a stuffed echo? ================= */ void SV_ClientPrintf (char *fmt, ...) { va_list argptr; char* string = Sys_BigStackAlloc(1024, "SV_ClientPrintf"); va_start (argptr,fmt); vsprintf (string, fmt,argptr); va_end (argptr); MSG_WriteByte (&host_client->message, svc_print); MSG_WriteString (&host_client->message, string); Sys_BigStackFree(1024, "SV_ClientPrintf"); }
void Mod_FloodFillSkin( byte *skin, int skinwidth, int skinheight ) { byte fillcolor = *skin; // assume this is the pixel to fill floodfill_t* fifo; int inpt = 0, outpt = 0; int filledcolor = -1; int i; if (filledcolor == -1) { filledcolor = 0; // attempt to find opaque black for (i = 0; i < 256; ++i) if (d_8to24table[i] == (255 << 0)) // alpha 1.0 { filledcolor = i; break; } } // can't fill to filled color or to transparent color (used as visited marker) if ((fillcolor == filledcolor) || (fillcolor == 255)) { //printf( "not filling skin from %d to %d\n", fillcolor, filledcolor ); return; } fifo = Sys_BigStackAlloc(FLOODFILL_FIFO_SIZE * sizeof(floodfill_t), "Mod_FloodFillSkin"); fifo[inpt].x = 0, fifo[inpt].y = 0; inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; while (outpt != inpt) { int x = fifo[outpt].x, y = fifo[outpt].y; int fdc = filledcolor; byte *pos = &skin[x + skinwidth * y]; outpt = (outpt + 1) & FLOODFILL_FIFO_MASK; if (x > 0) FLOODFILL_STEP( -1, -1, 0 ); if (x < skinwidth - 1) FLOODFILL_STEP( 1, 1, 0 ); if (y > 0) FLOODFILL_STEP( -skinwidth, 0, -1 ); if (y < skinheight - 1) FLOODFILL_STEP( skinwidth, 0, 1 ); skin[x + skinwidth * y] = fdc; } Sys_BigStackFree(FLOODFILL_FIFO_SIZE * sizeof(floodfill_t), "Mod_FloodFillSkin"); }
/* ================= SV_BroadcastPrintf Sends text to all active clients ================= */ void SV_BroadcastPrintf (char *fmt, ...) { va_list argptr; char* string = Sys_BigStackAlloc(1024, "SV_BroadcastPrintf"); int i; va_start (argptr,fmt); vsprintf (string, fmt,argptr); va_end (argptr); for (i = 0; i < svs.maxclients; i++) { if (svs.clients[i].active && svs.clients[i].spawned) { MSG_WriteByte(&svs.clients[i].message, svc_print); MSG_WriteString(&svs.clients[i].message, string); } } Sys_BigStackFree(1024, "SV_BroadcastPrintf"); }
/* ================== R_ScreenShot_f ================== */ void R_ScreenShot_f (void) { int i; // >>> FIX: For Nintendo Wii using devkitPPC / libogc // Allocating in big stack. Stack in this device is pretty small: //char pcxname[80]; //char checkname[MAX_OSPATH]; //FILE *f; //byte palette[768]; FILE *f; char* pcxname = Sys_BigStackAlloc(80, "R_ScreenShot_f"); char* checkname = Sys_BigStackAlloc(MAX_OSPATH, "R_ScreenShot_f"); byte* palette = Sys_BigStackAlloc(768, "R_ScreenShot_f"); // <<< FIX // create the scrnshots directory if it doesn't exist // >>> FIX: For Nintendo Wii using devkitPPC / libogc // Adjusting for previous fix: //Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir()); Com_sprintf (checkname, MAX_OSPATH, "%s/scrnshot", ri.FS_Gamedir()); // <<< FIX Sys_Mkdir (checkname); // // find a file name to save it to // strcpy(pcxname,"quake00.pcx"); for (i=0 ; i<=99 ; i++) { pcxname[5] = i/10 + '0'; pcxname[6] = i%10 + '0'; // >>> FIX: For Nintendo Wii using devkitPPC / libogc // Adjusting for previous fix: //Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), pcxname); Com_sprintf (checkname, MAX_OSPATH, "%s/scrnshot/%s", ri.FS_Gamedir(), pcxname); // <<< FIX f = fopen (checkname, "r"); if (!f) break; // file doesn't exist fclose (f); } if (i==100) { ri.Con_Printf (PRINT_ALL, "R_ScreenShot_f: Couldn't create a PCX"); // >>> FIX: For Nintendo Wii using devkitPPC / libogc // Deallocating from previous fix: Sys_BigStackFree(80 + MAX_OSPATH + 768, "R_ScreenShot_f"); // <<< FIX return; } // turn the current 32 bit palette into a 24 bit palette for (i=0 ; i<256 ; i++) { palette[i*3+0] = sw_state.currentpalette[i*4+0]; palette[i*3+1] = sw_state.currentpalette[i*4+1]; palette[i*3+2] = sw_state.currentpalette[i*4+2]; } // // save the pcx file // WritePCXfile (checkname, vid.buffer, vid.width, vid.height, vid.rowbytes, palette); ri.Con_Printf (PRINT_ALL, "Wrote %s\n", checkname); // >>> FIX: For Nintendo Wii using devkitPPC / libogc // Deallocating from previous fix: Sys_BigStackFree(80 + MAX_OSPATH + 768, "R_ScreenShot_f"); // <<< FIX }
/* ================ BuildTris Generate a list of trifans or strips for the model, which holds for all frames ================ */ void BuildTris (void) { int i, j, k; int startv; mtriangle_t *last, *check; int m1, m2; int striplength; trivertx_t *v; mtriangle_t *tv; float s, t; int index; int len, bestlen, besttype; int* bestverts = Sys_BigStackAlloc(1024 * sizeof(int), "BuildTris"); int* besttris = Sys_BigStackAlloc(1024 * sizeof(int), "BuildTris"); int type; // // build tristrips // numorder = 0; numcommands = 0; memset (used, 0, sizeof(used)); for (i=0 ; i<pheader->numtris ; i++) { // pick an unused triangle and start the trifan if (used[i]) continue; bestlen = 0; for (type = 0 ; type < 2 ; type++) // type = 1; { for (startv =0 ; startv < 3 ; startv++) { if (type == 1) len = StripLength (i, startv); else len = FanLength (i, startv); if (len > bestlen) { besttype = type; bestlen = len; for (j=0 ; j<bestlen+2 ; j++) bestverts[j] = stripverts[j]; for (j=0 ; j<bestlen ; j++) besttris[j] = striptris[j]; } } } // mark the tris on the best strip as used for (j=0 ; j<bestlen ; j++) used[besttris[j]] = 1; if (besttype == 1) commands[numcommands++] = (bestlen+2); else commands[numcommands++] = -(bestlen+2); for (j=0 ; j<bestlen+2 ; j++) { // emit a vertex into the reorder buffer k = bestverts[j]; vertexorder[numorder++] = k; // emit s/t coords into the commands stream s = stverts[k].s; t = stverts[k].t; if (!triangles[besttris[0]].facesfront && stverts[k].onseam) s += pheader->skinwidth / 2; // on back side s = (s + 0.5) / pheader->skinwidth; t = (t + 0.5) / pheader->skinheight; *(float *)&commands[numcommands++] = s; *(float *)&commands[numcommands++] = t; } } commands[numcommands++] = 0; // end of list marker Con_DPrintf ("%3i tri %3i vert %3i cmd\n", pheader->numtris, numorder, numcommands); allverts += numorder; alltris += pheader->numtris; Sys_BigStackFree(1024 * sizeof(int) + 1024 * sizeof(int), "BuildTris"); }
/* ================== Mod_LoadModel Loads a model into the cache ================== */ model_t *Mod_LoadModel (model_t *mod, qboolean crash) { unsigned *buf; // >>> FIX: For Nintendo Wii using devkitPPC / libogc // Deferring allocation. Stack in this device is pretty small: //byte stackbuf[1024]; // avoid dirtying the cache heap byte* stackbuf; // avoid dirtying the cache heap // <<< FIX if (mod->type == mod_alias) { if (Cache_Check (&mod->cache)) { mod->needload = NL_PRESENT; return mod; } } else { if (mod->needload == NL_PRESENT) return mod; } // // because the world is so huge, load it one piece at a time // // // load the file // // >>> FIX: For Nintendo Wii using devkitPPC / libogc // Allocating for previous fixes (and, this time, expanding the allocated size), in big stack: stackbuf = Sys_BigStackAlloc(4096 * sizeof(byte), "Mod_LoadModel"); // <<< FIX // >>> FIX: For Nintendo Wii using devkitPPC / libogc // Adjusting for previous fix: //buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf)); buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, 4096); // <<< FIX if (!buf) { if (crash) Sys_Error ("Mod_NumForName: %s not found", mod->name); // >>> FIX: For Nintendo Wii using devkitPPC / libogc // Deallocating from previous fixes: Sys_BigStackFree(4096 * sizeof(byte), "Mod_LoadModel"); // <<< FIX return NULL; } // // allocate a new model // COM_FileBase (mod->name, loadname); loadmodel = mod; // // fill it in // // call the apropriate loader mod->needload = NL_PRESENT; switch (LittleLong(*(unsigned *)buf)) { case IDPOLYHEADER: Mod_LoadAliasModel (mod, buf); break; case IDSPRITEHEADER: Mod_LoadSpriteModel (mod, buf); break; default: Mod_LoadBrushModel (mod, buf); break; } // >>> FIX: For Nintendo Wii using devkitPPC / libogc // Deallocating from previous fixes: Sys_BigStackFree(4096 * sizeof(byte), "Mod_LoadModel"); // <<< FIX return mod; }
/* ================== Mod_LoadModel Loads a model into the cache ================== */ model_t *Mod_LoadModel (model_t *mod, qboolean crash) { void *d; unsigned *buf; byte* stackbuf; if (!mod->needload) { if (mod->type == mod_alias) { d = Cache_Check (&mod->cache); if (d) return mod; } else return mod; // not cached at all } // // because the world is so huge, load it one piece at a time // if (!crash) { } // // load the file // stackbuf = Sys_BigStackAlloc(1024 * sizeof(byte), "Mod_LoadModel"); buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, 1024); if (!buf) { if (crash) Sys_Error ("Mod_NumForName: %s not found", mod->name); return NULL; } // // allocate a new model // COM_FileBase (mod->name, loadname); loadmodel = mod; // // fill it in // // call the apropriate loader mod->needload = false; switch (LittleLong(*(unsigned *)buf)) { case IDPOLYHEADER: Mod_LoadAliasModel (mod, buf); break; case IDSPRITEHEADER: Mod_LoadSpriteModel (mod, buf); break; default: Mod_LoadBrushModel (mod, buf); break; } Sys_BigStackFree(1024 * sizeof(byte), "Mod_LoadModel"); return mod; }
/* ================== CL_ParseServerInfo ================== */ void CL_ParseServerInfo (void) { char *str; int i, maxlen; int nummodels, numsounds; char** sound_precache; char** model_precache; char tempname[MAX_QPATH]; Con_DPrintf ("Serverinfo packet received.\n"); // // wipe the client_state_t struct // CL_ClearState (); // parse protocol version number i = MSG_ReadLong (); if (i != PROTOCOL_NETQUAKE && i != PROTOCOL_FITZQUAKE) { Host_Error("Server returned version %i, not %i (Net/ProQuake) or %i (FitzQuake)", i, PROTOCOL_NETQUAKE, PROTOCOL_FITZQUAKE); Con_Printf ("Server returned version %i, not %i", i, PROTOCOL_NETQUAKE); return; } // parse maxclients cl.maxclients = MSG_ReadByte (); if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD) { Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients); return; } cl.scores = Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), "scores"); // parse gametype cl.gametype = MSG_ReadByte (); // parse signon message str = MSG_ReadString (); strncpy (cl.levelname, str, sizeof(cl.levelname)-1); // seperate the printfs so the server message can have a color Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"); Con_Printf ("%c%s\n", 2, str); // // first we go through and touch all of the precache data that still // happens to be in the cache, so precaching something else doesn't // needlessly purge it // model_precache = Sys_BigStackAlloc(MAX_MODELS * sizeof(char*), "CL_ParseServerInfo"); for (i = 0; i < MAX_MODELS; i++) { model_precache[i] = Sys_BigStackAlloc(MAX_QPATH, "CL_ParseServerInfo"); }; // precache models memset (cl.model_precache, 0, sizeof(cl.model_precache)); for (nummodels=1 ; ; nummodels++) { str = MSG_ReadString (); if (!str[0]) break; if (nummodels == MAX_MODELS) { Con_Printf("Server sent too many model precaches\n"); for (i = MAX_MODELS - 1; i >= 0; i--) { free(model_precache[i]); }; free(model_precache); return; } strcpy (model_precache[nummodels], str); Mod_TouchModel (str); } // precache sounds sound_precache = Sys_BigStackAlloc(MAX_SOUNDS * sizeof(char*), "CL_ParseServerInfo"); for (i = 0; i < MAX_SOUNDS; i++) { sound_precache[i] = Sys_BigStackAlloc(MAX_QPATH, "CL_ParseServerInfo"); }; memset (cl.sound_precache, 0, sizeof(cl.sound_precache)); for (numsounds=1 ; ; numsounds++) { str = MSG_ReadString (); if (!str[0]) break; if (numsounds == MAX_SOUNDS) { Con_Printf("Server sent too many sound precaches\n"); Sys_BigStackFree(MAX_MODELS * sizeof(char*) + MAX_MODELS * MAX_QPATH + MAX_SOUNDS * sizeof(char*) + MAX_SOUNDS * MAX_QPATH, "CL_ParseServerInfo"); return; } strcpy (sound_precache[numsounds], str); S_TouchSound (str); } // // now we try to load everything else until a cache allocation fails // for (i=1 ; i<nummodels ; i++) { cl.model_precache[i] = Mod_ForName (model_precache[i], false); if (cl.model_precache[i] == NULL) { Con_Printf("Model %s not found\n", model_precache[i]); Sys_BigStackFree(MAX_MODELS * sizeof(char*) + MAX_MODELS * MAX_QPATH + MAX_SOUNDS * sizeof(char*) + MAX_SOUNDS * MAX_QPATH, "CL_ParseServerInfo"); return; } CL_KeepaliveMessage (); } S_BeginPrecaching (); for (i=1 ; i<numsounds ; i++) { cl.sound_precache[i] = S_PrecacheSound (sound_precache[i]); CL_KeepaliveMessage (); } S_EndPrecaching (); // local state cl_entities[0].model = cl.worldmodel = cl.model_precache[1]; R_NewMap (); Hunk_Check (); // make sure nothing is hurt noclip_anglehack = false; // noclip is turned off at start Sys_BigStackFree(MAX_MODELS * sizeof(char*) + MAX_MODELS * MAX_QPATH + MAX_SOUNDS * sizeof(char*) + MAX_SOUNDS * MAX_QPATH, "CL_ParseServerInfo"); }