static void Handle_Key(unsigned char charcode, UInt32 mackeycode, qboolean keypressed) { unsigned int keycode = 0; char ascii = '\0'; switch (mackeycode) { case MK_ESCAPE: keycode = K_ESCAPE; break; case MK_F1: keycode = K_F1; break; case MK_F2: keycode = K_F2; break; case MK_F3: keycode = K_F3; break; case MK_F4: keycode = K_F4; break; case MK_F5: keycode = K_F5; break; case MK_F6: keycode = K_F6; break; case MK_F7: keycode = K_F7; break; case MK_F8: keycode = K_F8; break; case MK_F9: keycode = K_F9; break; case MK_F10: keycode = K_F10; break; case MK_F11: keycode = K_F11; break; case MK_F12: keycode = K_F12; break; case MK_SCROLLOCK: keycode = K_SCROLLOCK; break; case MK_PAUSE: keycode = K_PAUSE; break; case MK_BACKSPACE: keycode = K_BACKSPACE; break; case MK_INSERT: keycode = K_INS; break; case MK_HOME: keycode = K_HOME; break; case MK_PAGEUP: keycode = K_PGUP; break; case MK_NUMLOCK: keycode = K_NUMLOCK; break; case MK_KP_EQUALS: keycode = K_KP_EQUALS; break; case MK_KP_DIVIDE: keycode = K_KP_DIVIDE; break; case MK_KP_MULTIPLY: keycode = K_KP_MULTIPLY; break; case MK_TAB: keycode = K_TAB; break; case MK_DELETE: keycode = K_DEL; break; case MK_END: keycode = K_END; break; case MK_PAGEDOWN: keycode = K_PGDN; break; case MK_KP7: keycode = K_KP_7; break; case MK_KP8: keycode = K_KP_8; break; case MK_KP9: keycode = K_KP_9; break; case MK_KP_MINUS: keycode = K_KP_MINUS; break; case MK_CAPSLOCK: keycode = K_CAPSLOCK; break; case MK_RETURN: keycode = K_ENTER; break; case MK_KP4: keycode = K_KP_4; break; case MK_KP5: keycode = K_KP_5; break; case MK_KP6: keycode = K_KP_6; break; case MK_KP_PLUS: keycode = K_KP_PLUS; break; case MK_KP1: keycode = K_KP_1; break; case MK_KP2: keycode = K_KP_2; break; case MK_KP3: keycode = K_KP_3; break; case MK_KP_ENTER: case MK_IBOOK_ENTER: keycode = K_KP_ENTER; break; case MK_KP0: keycode = K_KP_0; break; case MK_KP_PERIOD: keycode = K_KP_PERIOD; break; default: switch(charcode) { case kUpArrowCharCode: keycode = K_UPARROW; break; case kLeftArrowCharCode: keycode = K_LEFTARROW; break; case kDownArrowCharCode: keycode = K_DOWNARROW; break; case kRightArrowCharCode: keycode = K_RIGHTARROW; break; case 0: case 191: // characters 0 and 191 are sent by the mouse buttons (?!) break; default: if ('A' <= charcode && charcode <= 'Z') { keycode = charcode + ('a' - 'A'); // lowercase it ascii = charcode; } else if (charcode >= 32) { keycode = charcode; ascii = charcode; } else Con_DPrintf(">> UNKNOWN char/keycode: %d/%u <<\n", charcode, (unsigned) mackeycode); } } if (keycode != 0) Key_Event(keycode, ascii, keypressed); }
/* ================ ED_LoadFromFile The entities are directly placed in the array, rather than allocated with ED_Alloc, because otherwise an error loading the map would have entity number references out of order. Creates a server's entity / program execution context by parsing textual entity definitions out of an ent file. Used for both fresh maps and savegame loads. A fresh map would also need to call ED_CallSpawnFunctions () to let the objects initialize themselves. ================ */ void ED_LoadFromFile (const char *data) { edict_t *ent; int inhibit; dfunction_t *func; ent = NULL; inhibit = 0; pr_global_struct->time = sv.time; // parse ents while (1) { // parse the opening brace data = COM_Parse (data); if (!data) break; if (com_token[0] != '{') Sys_Error ("ED_LoadFromFile: found %s when expecting {",com_token); if (!ent) ent = EDICT_NUM(0); else ent = ED_Alloc (); data = ED_ParseEdict (data, ent); // remove things from different skill levels or deathmatch if (deathmatch.to_bool()) { if (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH)) { ED_Free (ent); inhibit++; continue; } } else if ((current_skill == 0 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_EASY)) || (current_skill == 1 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_MEDIUM)) || (current_skill >= 2 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_HARD)) ) { ED_Free (ent); inhibit++; continue; } // // immediately call spawn function // if (!ent->v.classname) { Con_Printf ("No classname for:\n"); ED_Print (ent); ED_Free (ent); continue; } // look for the spawn function func = ED_FindFunction ( pr_strings + ent->v.classname ); if (!func) { Con_Printf ("No spawn function for:\n"); ED_Print (ent); ED_Free (ent); continue; } pr_global_struct->self = EDICT_TO_PROG(ent); PR_ExecuteProgram (func - pr_functions); } Con_DPrintf ("%i entities inhibited\n", inhibit); }
/** * Generate a list of trifans or strips for the model, which holds for all frames */ void BuildTris(void) { int startv; int len, bestlen, besttype; int bestverts[1024]; int besttris[1024]; // build tristrips numorder = 0; numcommands = 0; memset(used, 0, sizeof (used)); for (int i = 0; i < pheader->numtris; i++) { // pick an unused triangle and start the trifan if (used[i]) continue; bestlen = 0; for (int 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 (int j = 0; j < bestlen + 2; j++) bestverts[j] = stripverts[j]; for (int j = 0; j < bestlen; j++) besttris[j] = striptris[j]; } } } // mark the tris on the best strip as used for (int j = 0; j < bestlen; j++) used[besttris[j]] = 1; if (besttype == 1) commands[numcommands++] = (bestlen + 2); else commands[numcommands++] = -(bestlen + 2); for (int j = 0; j < bestlen + 2; j++) { // emit a vertex into the reorder buffer int k = bestverts[j]; vertexorder[numorder++] = k; // emit s/t coords into the commands stream float s = stverts[k].s; float 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; }
/* ================= Mod_LoadTextures ================= */ void Mod_LoadTextures (lump_t *l) { // 1999-12-28 OpenGL fullbright fix by Neal White III start // Neal White III - 12-28-1999 - OpenGL fullbright bugfix // [email protected] // http://home.telefragged.com/wally/ // // Problem: // // There was a problem in the original glquake with fullbright texels. // In the software renderer, fullbrights glow brightly in the dark. // Essentially, the fullbrights were ignored. I've fixed it by // adding another rendering pass and creating a new glowmap texture. // // Fix: // // When a texture with fullbright (FB) texels is loaded, a copy is made, // then the FB pixels are cleared to black in the original texture. In // the copy, all normal colors are cleared and only the FBs remain. When // it comes time to render the polygons, I do an additional pass and ADD // the glowmap on top of the current polygon. byte *ptexel; qboolean hasfullbrights; // qboolean noglow = COM_CheckParm("-noglow"); // int i, j, pixels, num, max, altmax; int i, num, max, altmax; unsigned long j, pixels; // 1999-12-28 OpenGL fullbright fix by Neal White III end miptex_t *mt; texture_t *tx, *tx2; texture_t *anims[10]; texture_t *altanims[10]; dmiptexlump_t *m; if (!l->filelen) { loadmodel->textures = NULL; return; } m = (dmiptexlump_t *)(mod_base + l->fileofs); m->nummiptex = LittleLong (m->nummiptex); loadmodel->numtextures = m->nummiptex; loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures) , loadname); for (i=0 ; i<m->nummiptex ; i++) { m->dataofs[i] = LittleLong(m->dataofs[i]); if (m->dataofs[i] == -1) continue; mt = (miptex_t *)((byte *)m + m->dataofs[i]); mt->width = LittleLong (mt->width); mt->height = LittleLong (mt->height); for (j=0 ; j<MIPLEVELS ; j++) mt->offsets[j] = LittleLong (mt->offsets[j]); if ( (mt->width & 15) || (mt->height & 15) ) Sys_Error ("Texture %s is not 16 aligned", mt->name); pixels = mt->width*mt->height/64*85; // 1999-12-28 OpenGL fullbright fix by Neal White III start hasfullbrights = false; if ((!strncmp(mt->name,"sky",3)) || (!strncmp(mt->name,"*",1)) || // turbulent (liquid) (!gl_glowmap->value) || (! gl_mtexable) ) { // sky has no lightmap, nor do liquids (so never needs a glowmap), // -noglow command line parameter, or no multi-texture support // // hasfullbrights is already false } else // check this texture for fullbright texels { ptexel = (byte *)(mt+1); for (j=0 ; j<pixels ; j++) { if (ptexel[j] >= 256-32) // 32 fullbright colors { hasfullbrights = true; break; } } } if (hasfullbrights) { tx = Hunk_AllocName (sizeof(texture_t) +pixels*2, loadname ); } else { // 1999-12-28 OpenGL fullbright fix by Neal White III end tx = Hunk_AllocName (sizeof(texture_t) +pixels, loadname ); } // 1999-12-28 OpenGL fullbright fix by Neal White III loadmodel->textures[i] = tx; memcpy (tx->name, mt->name, sizeof(tx->name)); tx->width = mt->width; tx->height = mt->height; for (j=0 ; j<MIPLEVELS ; j++) { // 1999-12-28 OpenGL fullbright fix by Neal White III tx->offsets[j] = mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t); // 1999-12-28 OpenGL fullbright fix by Neal White III start if (hasfullbrights) { tx->glowoffsets[j] = mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t) + pixels; } else { tx->glowoffsets[j] = 0; } } // 1999-12-28 OpenGL fullbright fix by Neal White III end // the pixels immediately follow the structures memcpy ( tx+1, mt+1, pixels); // 1999-12-28 OpenGL fullbright fix by Neal White III start if (hasfullbrights) { ptexel = (byte *)(tx+1); memcpy ( ptexel+pixels, mt+1, pixels); } tx->flags = 0; // 1999-12-28 OpenGL fullbright fix by Neal White III end if (!strncmp(mt->name,"sky",3)) // 2000-07-09 Dedicated server bug in GLQuake fix by Nathan Cline start { if (cls.state != ca_dedicated) { // 2000-07-09 Dedicated server bug in GLQuake fix by Nathan Cline end R_InitSky (tx); // 2000-07-09 Dedicated server bug in GLQuake fix by Nathan Cline start } } // 2000-07-09 Dedicated server bug in GLQuake fix by Nathan Cline end else { texture_mode = GL_LINEAR_MIPMAP_NEAREST; //_LINEAR; // 1999-12-28 OpenGL fullbright fix by Neal White III start // remove glowing fullbright colors from base texture (make black) if (hasfullbrights) { #ifdef _DEBUG qboolean bColorUsed[256]; Con_DPrintf ("*** Fullbright Texture: \"%s\", %dx%d, %d pixels\n", mt->name, mt->width, mt->height, pixels); for (j=0 ; j<256 ; j++) bColorUsed[j] = false; #endif ptexel = (byte *)(tx+1); for (j=0 ; j<pixels ; j++) { #ifdef _DEBUG bColorUsed[ptexel[j]] = true; #endif if (ptexel[j] >= 256-32) // 32 fullbright colors { ptexel[j] = 0; // make fullbrights black } } #ifdef _DEBUG Con_DPrintf ("*** Normal colors: "); for (j=0 ; j<256-32 ; j++) { if (bColorUsed[j]) Con_DPrintf ("%d ", j); } Con_DPrintf ("\n"); Con_DPrintf ("*** Fullbrights: "); for (j=256-32 ; j<256 ; j++) { if (bColorUsed[j]) Con_DPrintf ("%d ", j); } Con_DPrintf ("\n"); #endif } #ifdef _DEBUG else { Con_DPrintf ("*** Normal Texture: \"%s\", %dx%d\n", mt->name, mt->width, mt->height); } #endif // 1999-12-28 OpenGL fullbright fix by Neal White III end tx->gl_texturenum = GL_LoadTexture (mt->name, tx->width, tx->height, (byte *)(tx+1), true, false); // 1999-12-28 OpenGL fullbright fix by Neal White III start // create glowmap texture (all black except for glowing fullbright colors) if (hasfullbrights) { #ifdef _DEBUG qboolean bGlowDoubleCheck = false; #endif char glowname[32]; memcpy (glowname, mt->name, sizeof(mt->name)); glowname[16] = '\0'; for (j=0 ; glowname[j] != '\0'; j++) ; glowname[j++] = '<'; glowname[j++] = 'G'; glowname[j++] = 'L'; glowname[j++] = 'O'; glowname[j++] = 'W'; glowname[j++] = '>'; glowname[j++] = '\0'; ptexel = (byte *)(tx+1) + pixels; for (j=0 ; j<pixels ; j++) { if (ptexel[j] < 256-32) // build glowmap { ptexel[j] = 0; // make non-fullbrights black } #ifdef _DEBUG else { bGlowDoubleCheck = true; } #endif } tx->gl_glowtexnum = GL_LoadTexture (glowname, tx->width, tx->height, ptexel, true, false); tx->flags |= FLAG_HAS_GLOWMAP; #ifdef _DEBUG if (! bGlowDoubleCheck) Con_DPrintf ("INTERNAL ERROR: Mod_LoadTextures - FullBright texture \"%s\" has no FullBright colors!\n", glowname); #endif } // 1999-12-28 OpenGL fullbright fix by Neal White III end texture_mode = GL_LINEAR; } } // // sequence the animations // for (i=0 ; i<m->nummiptex ; i++) { tx = loadmodel->textures[i]; if (!tx || tx->name[0] != '+') continue; if (tx->anim_next) continue; // already sequenced // find the number of frames in the animation memset (anims, 0, sizeof(anims)); memset (altanims, 0, sizeof(altanims)); max = tx->name[1]; altmax = 0; if (max >= 'a' && max <= 'z') max -= 'a' - 'A'; if (max >= '0' && max <= '9') { max -= '0'; altmax = 0; anims[max] = tx; max++; } else if (max >= 'A' && max <= 'J') { altmax = max - 'A'; max = 0; altanims[altmax] = tx; altmax++; } else Sys_Error ("Bad animating texture %s", tx->name); for (j=i+1 ; j<m->nummiptex ; j++) { tx2 = loadmodel->textures[j]; if (!tx2 || tx2->name[0] != '+') continue; if (strcmp (tx2->name+2, tx->name+2)) continue; num = tx2->name[1]; if (num >= 'a' && num <= 'z') num -= 'a' - 'A'; if (num >= '0' && num <= '9') { num -= '0'; anims[num] = tx2; if (num+1 > max) max = num + 1; } else if (num >= 'A' && num <= 'J') { num = num - 'A'; altanims[num] = tx2; if (num+1 > altmax) altmax = num+1; } else Sys_Error ("Bad animating texture %s", tx->name); } #define ANIM_CYCLE 2 // link them all together for (j=0 ; j<max ; j++) { tx2 = anims[j]; if (!tx2) Sys_Error ("Missing frame %i of %s",j, tx->name); tx2->anim_total = max * ANIM_CYCLE; tx2->anim_min = j * ANIM_CYCLE; tx2->anim_max = (j+1) * ANIM_CYCLE; tx2->anim_next = anims[ (j+1)%max ]; if (altmax) tx2->alternate_anims = altanims[0]; } for (j=0 ; j<altmax ; j++) { tx2 = altanims[j]; if (!tx2) Sys_Error ("Missing frame %i of %s",j, tx->name); tx2->anim_total = altmax * ANIM_CYCLE; tx2->anim_min = j * ANIM_CYCLE; tx2->anim_max = (j+1) * ANIM_CYCLE; tx2->anim_next = altanims[ (j+1)%altmax ]; if (max) tx2->alternate_anims = anims[0]; } } }
/* ================ 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[1024]; int besttris[1024]; int type; int stripmax = 0; // // 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); // Save peak if (len > stripmax) stripmax = len; 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; ChkCmds ("BuildTris"); 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; ChkCmds ("BuildTris"); *(float *)&commands[numcommands++] = s; *(float *)&commands[numcommands++] = t; } } ChkCmds ("BuildTris"); commands[numcommands++] = 0; // end of list marker // Check old limit if (stripmax + 2 >= 128) { Con_Printf ("\002BuildTris: "); Con_Printf ("excessive stripcount (%d, normal max = %d) in %s\n", stripmax, 128 - 2, aliasmodel->name); } // Check old limit if (numcommands >= 8192) { Con_Printf ("\002BuildTris: "); Con_Printf ("excessive commands (%d, normal max = %d) in %s\n", numcommands, 8192, aliasmodel->name); } #ifndef NO_CACHE_MESH Con_DPrintf ("%3i tri %3i vert %3i cmd\n", pheader->numtris, numorder, numcommands); #endif }
int TCP_OpenListenSocket (unsigned short int port) { int newsocket; struct sockaddr_in address = { 0 }; unsigned long nonblocking = true; int i; if ((newsocket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) { Con_Printf ("TCP_OpenListenSocket: socket: (%i): %s\n", qerrno, strerror(qerrno)); return INVALID_SOCKET; } #ifndef _WIN32 if ((fcntl (newsocket, F_SETFL, O_NONBLOCK)) == -1) { // O'Rly?! @@@ Con_Printf ("TCP_OpenListenSocket: fcntl: (%i): %s\n", qerrno, strerror(qerrno)); closesocket(newsocket); return INVALID_SOCKET; } #endif if (ioctlsocket (newsocket, FIONBIO, &nonblocking) == -1) { // make asynchronous Con_Printf ("TCP_OpenListenSocket: ioctl: (%i): %s\n", qerrno, strerror(qerrno)); closesocket(newsocket); return INVALID_SOCKET; } #ifdef __APPLE__ address.sin_len = sizeof(address); // apple are special... #endif address.sin_family = AF_INET; // check for interface binding option if ((i = COM_CheckParm("-ip")) != 0 && i < COM_Argc()) { address.sin_addr.s_addr = inet_addr(COM_Argv(i+1)); Con_DPrintf ("Binding to IP Interface Address of %s\n", inet_ntoa(address.sin_addr)); } else { address.sin_addr.s_addr = INADDR_ANY; } if (port == PORT_ANY) { address.sin_port = 0; } else { address.sin_port = htons(port); } if (bind (newsocket, (void *)&address, sizeof(address)) == -1) { Con_Printf ("TCP_OpenListenSocket: bind: (%i): %s\n", qerrno, strerror(qerrno)); closesocket(newsocket); return INVALID_SOCKET; } if (listen (newsocket, TCP_LISTEN_BACKLOG) == INVALID_SOCKET) { Con_Printf ("TCP_OpenListenSocket: listen: (%i): %s\n", qerrno, strerror(qerrno)); closesocket(newsocket); return INVALID_SOCKET; } if (!TCP_Set_KEEPALIVE(newsocket)) { Con_Printf ("TCP_OpenListenSocket: TCP_Set_KEEPALIVE: failed\n"); closesocket(newsocket); return INVALID_SOCKET; } return newsocket; }
//jpg loading byte *LoadJPG (FILE *f) { struct jpeg_decompress_struct cinfo; JDIMENSION num_scanlines; JSAMPARRAY in; struct jpeg_error_mgr jerr; int numPixels; int row_stride; byte *out; int count; int i; //int r, g, b; byte *image_rgba; // set up the decompression. cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress (&cinfo); // inititalize the source jpeg_stdio_src (&cinfo, f); // initialize decompression (void) jpeg_read_header (&cinfo, TRUE); (void) jpeg_start_decompress (&cinfo); numPixels = cinfo.image_width * cinfo.image_height; // initialize the input buffer - we'll use the in-built memory management routines in the // JPEG library because it will automatically free the used memory for us when we destroy // the decompression structure. cool. row_stride = cinfo.output_width * cinfo.output_components; in = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); // bit of error checking if (cinfo.output_components != 3) goto error; // initialize the return data image_rgba = malloc ((numPixels * 4)); // read the jpeg count = 0; while (cinfo.output_scanline < cinfo.output_height) { num_scanlines = jpeg_read_scanlines(&cinfo, in, 1); out = in[0]; for (i = 0; i < row_stride;) { image_rgba[count++] = out[i++];//r image_rgba[count++] = out[i++];//g image_rgba[count++] = out[i++];//b image_rgba[count++] = 255; } } // finish decompression and destroy the jpeg image_width = cinfo.image_width; image_height = cinfo.image_height; (void) jpeg_finish_decompress (&cinfo); jpeg_destroy_decompress (&cinfo); fclose (f); return image_rgba; error: // this should rarely (if ever) happen, but just in case... Con_DPrintf ("Invalid JPEG Format\n"); jpeg_destroy_decompress (&cinfo); fclose (f); return NULL; }
int Datagram_GetMessage(qsocket_t *sock) { unsigned int length; unsigned int flags; int ret = 0; struct qsockaddr readaddr; unsigned int sequence; unsigned int count; if (!sock->canSend) if ((net_time - sock->lastSendTime) > 1.0) { ReSendMessage(sock); } while (1) { length = sfunc.Read(sock->socket, (byte *)&packetBuffer, NET_DATAGRAMSIZE, &readaddr); // if ((rand() & 255) > 220) // continue; if (length == 0) { break; } if (length == -1) { Con_Printf("Read error\n"); return -1; } if (sfunc.AddrCompare(&readaddr, &sock->addr) != 0) { #ifdef DEBUG Con_DPrintf("Forged packet received\n"); Con_DPrintf("Expected: %s\n", StrAddr(&sock->addr)); Con_DPrintf("Received: %s\n", StrAddr(&readaddr)); #endif continue; } if (length < NET_HEADERSIZE) { shortPacketCount++; continue; } length = BigLong(packetBuffer.length); flags = length & (~NETFLAG_LENGTH_MASK); length &= NETFLAG_LENGTH_MASK; if (flags & NETFLAG_CTL) { continue; } sequence = BigLong(packetBuffer.sequence); packetsReceived++; if (flags & NETFLAG_UNRELIABLE) { if (sequence < sock->unreliableReceiveSequence) { Con_DPrintf("Got a stale datagram\n"); ret = 0; break; } if (sequence != sock->unreliableReceiveSequence) { count = sequence - sock->unreliableReceiveSequence; droppedDatagrams += count; Con_DPrintf("Dropped %u datagram(s)\n", count); } sock->unreliableReceiveSequence = sequence + 1; length -= NET_HEADERSIZE; SZ_Clear(&net_message); SZ_Write(&net_message, packetBuffer.data, length); ret = 2; break; } if (flags & NETFLAG_ACK) { if (sequence != (sock->sendSequence - 1)) { Con_DPrintf("Stale ACK received\n"); continue; } if (sequence == sock->ackSequence) { sock->ackSequence++; if (sock->ackSequence != sock->sendSequence) { Con_DPrintf("ack sequencing error\n"); } } else { Con_DPrintf("Duplicate ACK received\n"); continue; } sock->sendMessageLength -= MAX_DATAGRAM; if (sock->sendMessageLength > 0) { Q_memcpy(sock->sendMessage, sock->sendMessage+MAX_DATAGRAM, sock->sendMessageLength); sock->sendNext = true; } else { sock->sendMessageLength = 0; sock->canSend = true; } continue; } if (flags & NETFLAG_DATA) { packetBuffer.length = BigLong(NET_HEADERSIZE | NETFLAG_ACK); packetBuffer.sequence = BigLong(sequence); sfunc.Write(sock->socket, (byte *)&packetBuffer, NET_HEADERSIZE, &readaddr); if (sequence != sock->receiveSequence) { receivedDuplicateCount++; continue; } sock->receiveSequence++; length -= NET_HEADERSIZE; if (flags & NETFLAG_EOM) { SZ_Clear(&net_message); SZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength); SZ_Write(&net_message, packetBuffer.data, length); sock->receiveMessageLength = 0; ret = 1; break; } Q_memcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length); sock->receiveMessageLength += length; continue; } } if (sock->sendNext) { SendMessageNext(sock); } return ret; }
int WINS_Init (void) { #ifdef ID_PC int i; char buff[MAXHOSTNAMELEN]; char *p; int r; WORD wVersionRequested; HINSTANCE hInst; // initialize the Winsock function vectors (we do this instead of statically linking // so we can run on Win 3.1, where there isn't necessarily Winsock) hInst = LoadLibrary("wsock32.dll"); if (hInst == NULL) { Con_SafePrintf ("Failed to load winsock.dll\n"); winsock_lib_initialized = false; return -1; } winsock_lib_initialized = true; pWSAStartup = (int (__stdcall *)(WORD,LPWSADATA))GetProcAddress(hInst, "WSAStartup"); pWSACleanup = (int (__stdcall *)(void))GetProcAddress(hInst, "WSACleanup"); pWSAGetLastError = (int (__stdcall *)(void))GetProcAddress(hInst, "WSAGetLastError"); psocket = (SOCKET (__stdcall *)(int,int,int))GetProcAddress(hInst, "socket"); pioctlsocket = (int (__stdcall *)(SOCKET,long,u_long *))GetProcAddress(hInst, "ioctlsocket"); psetsockopt = (int (__stdcall *)(SOCKET,int,int,const char *,int))GetProcAddress(hInst, "setsockopt"); precvfrom = (int (__stdcall *)(SOCKET,char *,int,int,sockaddr *,int *))GetProcAddress(hInst, "recvfrom"); psendto = (int (__stdcall *)(SOCKET,const char *,int,int,const sockaddr *,int))GetProcAddress(hInst, "sendto"); pclosesocket = (int (__stdcall *)(SOCKET))GetProcAddress(hInst, "closesocket"); pgethostname = (int (__stdcall *)(char *,int))GetProcAddress(hInst, "gethostname"); pgethostbyname = (hostent *(__stdcall *)(const char *))GetProcAddress(hInst, "gethostbyname"); pgethostbyaddr = (hostent *(__stdcall *)(const char *,int,int))GetProcAddress(hInst, "gethostbyaddr"); pgetsockname = (int (__stdcall *)(SOCKET,sockaddr *,int *))GetProcAddress(hInst, "getsockname"); if (!pWSAStartup || !pWSACleanup || !pWSAGetLastError || !psocket || !pioctlsocket || !psetsockopt || !precvfrom || !psendto || !pclosesocket || !pgethostname || !pgethostbyname || !pgethostbyaddr || !pgetsockname) { Con_SafePrintf ("Couldn't GetProcAddress from winsock.dll\n"); return -1; } if (COM_CheckParm ("-noudp")) return -1; if (winsock_initialized == 0) { wVersionRequested = MAKEWORD(1, 1); r = pWSAStartup (MAKEWORD(1, 1), &winsockdata); if (r) { Con_SafePrintf ("Winsock initialization failed.\n"); return -1; } } winsock_initialized++; // determine my name if (pgethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR) { Con_DPrintf ("Winsock TCP/IP Initialization failed.\n"); if (--winsock_initialized == 0) pWSACleanup (); return -1; } // if the quake hostname isn't set, set it to the machine name if (Q_strcmp(hostname.string, "UNNAMED") == 0) { // see if it's a text IP address (well, close enough) for (p = buff; *p; p++) if ((*p < '0' || *p > '9') && *p != '.') break; // if it is a real name, strip off the domain; we only want the host if (*p) { for (i = 0; i < 15; i++) if (buff[i] == '.') break; buff[i] = 0; } Cvar_Set ("hostname", buff); } i = COM_CheckParm ("-ip"); if (i) { if (i < com_argc-1) { myAddr = inet_addr(com_argv[i+1]); if (myAddr == INADDR_NONE) Sys_Error ("%s is not a valid IP address", com_argv[i+1]); strcpy(my_tcpip_address, com_argv[i+1]); } else { Sys_Error ("NET_Init: you must specify an IP address after -ip"); } } else { myAddr = INADDR_ANY; strcpy(my_tcpip_address, "INADDR_ANY"); } if ((net_controlsocket = WINS_OpenSocket (0)) == -1) { Con_Printf("WINS_Init: Unable to open control socket\n"); if (--winsock_initialized == 0) pWSACleanup (); return -1; } ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET; ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST; ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons((unsigned short)net_hostport); Con_Printf("Winsock TCP/IP Initialized\n"); tcpipAvailable = true; return net_controlsocket; #endif return 0; }
/* ================== CL_ParsePacketEntities An svc_packetentities has just been parsed, deal with the rest of the data stream. ================== */ void CL_ParsePacketEntities (qboolean delta) { int oldpacket, newpacket; packet_entities_t *oldp, *newp, dummy; int oldindex, newindex; int word, newnum, oldnum; qboolean full; byte from; newpacket = cls.netchan.incoming_sequence&UPDATE_MASK; newp = &cl.frames[newpacket].packet_entities; cl.frames[newpacket].invalid = false; if (delta) { from = MSG_ReadByte (); oldpacket = cl.frames[newpacket].delta_sequence; if ( (from&UPDATE_MASK) != (oldpacket&UPDATE_MASK) ) Con_DPrintf ("WARNING: from mismatch\n"); } else oldpacket = -1; full = false; if (oldpacket != -1) { if (cls.netchan.outgoing_sequence - oldpacket >= UPDATE_BACKUP-1) { // we can't use this, it is too old FlushEntityPacket (); return; } cl.validsequence = cls.netchan.incoming_sequence; oldp = &cl.frames[oldpacket&UPDATE_MASK].packet_entities; } else { // this is a full update that we can start delta compressing from now oldp = &dummy; dummy.num_entities = 0; cl.validsequence = cls.netchan.incoming_sequence; full = true; } oldindex = 0; newindex = 0; newp->num_entities = 0; while (1) { word = (unsigned short)MSG_ReadShort (); if (msg_badread) { // something didn't parse right... Host_EndGame ("msg_badread in packetentities"); return; } if (!word) { while (oldindex < oldp->num_entities) { // copy all the rest of the entities from the old packet //Con_Printf ("copy %i\n", oldp->entities[oldindex].number); if (newindex >= MAX_PACKET_ENTITIES) Host_EndGame ("CL_ParsePacketEntities: newindex == MAX_PACKET_ENTITIES"); newp->entities[newindex] = oldp->entities[oldindex]; newindex++; oldindex++; } break; } newnum = word&511; oldnum = oldindex >= oldp->num_entities ? 9999 : oldp->entities[oldindex].number; while (newnum > oldnum) { if (full) { Con_Printf ("WARNING: oldcopy on full update"); FlushEntityPacket (); return; } //Con_Printf ("copy %i\n", oldnum); // copy one of the old entities over to the new packet unchanged if (newindex >= MAX_PACKET_ENTITIES) Host_EndGame ("CL_ParsePacketEntities: newindex == MAX_PACKET_ENTITIES"); newp->entities[newindex] = oldp->entities[oldindex]; newindex++; oldindex++; oldnum = oldindex >= oldp->num_entities ? 9999 : oldp->entities[oldindex].number; } if (newnum < oldnum) { // new from baseline //Con_Printf ("baseline %i\n", newnum); if (word & U_REMOVE) { if (full) { cl.validsequence = 0; Con_Printf ("WARNING: U_REMOVE on full update\n"); FlushEntityPacket (); return; } continue; } if (newindex >= MAX_PACKET_ENTITIES) Host_EndGame ("CL_ParsePacketEntities: newindex == MAX_PACKET_ENTITIES"); CL_ParseDelta (&cl_baselines[newnum], &newp->entities[newindex], word); newindex++; continue; } if (newnum == oldnum) { // delta from previous if (full) { cl.validsequence = 0; Con_Printf ("WARNING: delta on full update"); } if (word & U_REMOVE) { oldindex++; continue; } //Con_Printf ("delta %i\n",newnum); CL_ParseDelta (&oldp->entities[oldindex], &newp->entities[newindex], word); newindex++; oldindex++; } } newp->num_entities = newindex; }
/* ============== S_LoadSound ============== */ sfxcache_t *S_LoadSound(sfx_t *s) { char namebuffer[256]; byte *data; wavinfo_t info; int len; float stepscale; sfxcache_t *sc; byte stackbuf[1*1024]; // avoid dirtying the cache heap loadedfile_t *fileinfo; // 2001-09-12 Returning information about loaded file by Maddes // see if still in memory sc = Cache_Check(&s->cache); if (sc) { return sc; } //Con_Printf ("S_LoadSound: %x\n", (int)stackbuf); // load it in Q_strcpy(namebuffer, "sound/"); Q_strcat(namebuffer, s->name); if (developer.value == 1) { Con_DPrintf("Loading %s\n",namebuffer); // Edited } // Con_Printf ("loading %s\n",namebuffer); // 2001-09-12 Returning information about loaded file by Maddes start /* data = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf)); if (!data) */ fileinfo = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf)); if (!fileinfo) // 2001-09-12 Returning information about loaded file by Maddes end { Con_Printf("Couldn't load %s\n", namebuffer); return NULL; } data = fileinfo->data; // 2001-09-12 Returning information about loaded file by Maddes info = GetWavinfo(s->name, data, com_filesize); if (info.channels != 1) { Con_Printf("%s is a stereo sample\n",s->name); return NULL; } stepscale = (float)info.rate / shm->speed; len = info.samples / stepscale; len = len * info.width * info.channels; sc = Cache_Alloc(&s->cache, len + sizeof(sfxcache_t), s->name); if (!sc) { return NULL; } sc->length = info.samples; sc->loopstart = info.loopstart; sc->speed = info.rate; sc->width = info.width; sc->stereo = info.channels; ResampleSfx(s, sc->speed, sc->width, data + info.dataofs); return sc; }
qboolean SND_FOpen (const char *name, qboolean midi, qboolean resume) { int len; char file[MAX_QPATH]; char filefull[MAX_QPATH]; FILE *f; if(resume == true) { strcpy(file, name); } else { if (midi == true) sprintf(file, "midi/%s", name); else sprintf(file, "mod/%s", name); } if(midi == true) { sprintf(filefull, "%s.mid", file); len = COM_FOpenFile ((char *)filefull, &f); } else { sprintf(filefull, "%s.ogg", file); len = COM_FOpenFile ((char *)filefull, &f); if(len < 1) { sprintf(filefull, "%s.mp3", file); len = COM_FOpenFile ((char *)filefull, &f); } if(len < 1) { sprintf(filefull, "%s.wav", file); len = COM_FOpenFile ((char *)filefull, &f); } } if(len < 1) { Con_Printf("SND_FOpen: Failed to open %s, file not found\n", filefull); return false; } if(!SND_File.length) { strcpy(SND_File.filename, filefull); SND_File.length = len; SND_File.data = COM_FReadFile(f, len); Con_DPrintf("SND_FOpen: Sucessfully opened %s\n", filefull); return true; } Con_SafePrintf("SND_FOpen: Failed to open %s, insufficient handles\n", filefull); return false; }
/* =================== SV_ReadClientMessage Returns false if the client should be killed =================== */ qboolean SV_ReadClientMessage (void) { int ret; int cmd; char *s; do { nextmsg: ret = NET_GetMessage (host_client->netconnection); if (ret == -1) { Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n"); return false; } if (!ret) return true; MSG_BeginReading (net_message); while (1) { if (!host_client->active) return false; // a command caused an error if (net_message->badread) { Sys_Printf ("SV_ReadClientMessage: badread\n"); return false; } cmd = MSG_ReadChar (net_message); switch (cmd) { case -1: goto nextmsg; // end of message default: Sys_Printf ("SV_ReadClientMessage: unknown command char\n"); return false; case clc_nop: // Sys_Printf ("SV_ReadClientMessage: clc_nop\n"); break; case clc_stringcmd: s = MSG_ReadString (net_message); ret = 0; if (nehahra) { if (strncasecmp(s, "max", 3) == 0) ret = 1; else if (strncasecmp(s, "monster", 7) == 0) ret = 1; else if (strncasecmp(s, "scrag", 5) == 0) ret = 1; else if (strncasecmp(s, "wraith", 6) == 0) ret = 1; else if (strncasecmp(s, "gimme", 5) == 0) ret = 1; } else { if (strncasecmp(s, "god", 3) == 0) ret = 1; else if (strncasecmp(s, "notarget", 8) == 0) ret = 1; else if (strncasecmp(s, "fly", 3) == 0) ret = 1; else if (strncasecmp(s, "noclip", 6) == 0) ret = 1; else if (strncasecmp(s, "give", 4) == 0) ret = 1; } if (strncasecmp(s, "status", 6) == 0) ret = 1; else if (strncasecmp(s, "freezeall", 9) == 0) ret = 1; else if (strncasecmp(s, "name", 4) == 0) ret = 1; else if (strncasecmp(s, "say", 3) == 0) ret = 1; else if (strncasecmp(s, "say_team", 8) == 0) ret = 1; else if (strncasecmp(s, "tell", 4) == 0) ret = 1; else if (strncasecmp(s, "color", 5) == 0) ret = 1; else if (strncasecmp(s, "kill", 4) == 0) ret = 1; else if (strncasecmp(s, "pause", 5) == 0) ret = 1; else if (strncasecmp(s, "spawn", 5) == 0) ret = 1; else if (strncasecmp(s, "begin", 5) == 0) ret = 1; else if (strncasecmp(s, "prespawn", 8) == 0) ret = 1; else if (strncasecmp(s, "kick", 4) == 0) ret = 1; else if (strncasecmp(s, "ping", 4) == 0) ret = 1; else if (strncasecmp(s, "ban", 3) == 0) ret = 1; else if (strncasecmp(s, "qcexec", 6) == 0) ret = 1; // qcexec command for qc testing if (ret == 1) Cmd_ExecuteString (s, src_client); else Con_DPrintf("%s tried to %s\n", host_client->name, s); break; case clc_disconnect: // Sys_Printf ("SV_ReadClientMessage: client disconnected\n"); return false; case clc_move: SV_ReadClientMove (&host_client->cmd); break; } } } while (ret == 1); return true; }
void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecursor) { if (!mouse_avail || !window) relative = hidecursor = false; if (relative) { if(vid_usingmouse && (vid_usingnoaccel != !!apple_mouse_noaccel.integer)) VID_SetMouse(false, false, false); // ungrab first! if (!vid_usingmouse) { Rect winBounds; CGPoint winCenter; SelectWindow(window); // Put the mouse cursor at the center of the window GetWindowBounds (window, kWindowContentRgn, &winBounds); winCenter.x = (winBounds.left + winBounds.right) / 2; winCenter.y = (winBounds.top + winBounds.bottom) / 2; CGWarpMouseCursorPosition(winCenter); // Lock the mouse pointer at its current position CGAssociateMouseAndMouseCursorPosition(false); // Save the status of mouse acceleration originalMouseSpeed = -1.0; // in case of error if(apple_mouse_noaccel.integer) { io_connect_t mouseDev = IN_GetIOHandle(); if(mouseDev != 0) { if(IOHIDGetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), &originalMouseSpeed) == kIOReturnSuccess) { Con_DPrintf("previous mouse acceleration: %f\n", originalMouseSpeed); if(IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), -1.0) != kIOReturnSuccess) { Con_Print("Could not disable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n"); Cvar_SetValueQuick(&apple_mouse_noaccel, 0); } } else { Con_Print("Could not disable mouse acceleration (failed at IOHIDGetAccelerationWithKey).\n"); Cvar_SetValueQuick(&apple_mouse_noaccel, 0); } IOServiceClose(mouseDev); } else { Con_Print("Could not disable mouse acceleration (failed at IO_GetIOHandle).\n"); Cvar_SetValueQuick(&apple_mouse_noaccel, 0); } } vid_usingmouse = true; vid_usingnoaccel = !!apple_mouse_noaccel.integer; } } else { if (vid_usingmouse) { if(originalMouseSpeed != -1.0) { io_connect_t mouseDev = IN_GetIOHandle(); if(mouseDev != 0) { Con_DPrintf("restoring mouse acceleration to: %f\n", originalMouseSpeed); if(IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), originalMouseSpeed) != kIOReturnSuccess) Con_Print("Could not re-enable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n"); IOServiceClose(mouseDev); } else Con_Print("Could not re-enable mouse acceleration (failed at IO_GetIOHandle).\n"); } CGAssociateMouseAndMouseCursorPosition(true); vid_usingmouse = false; } } if (vid_usinghidecursor != hidecursor) { vid_usinghidecursor = hidecursor; if (hidecursor) CGDisplayHideCursor(CGMainDisplayID()); else CGDisplayShowCursor(CGMainDisplayID()); } }
/* ===================== SV_DropClient Called when the player is getting totally kicked off the host if (crash = true), don't bother sending signofs ===================== */ void SV_DropClient(qboolean crash) { prvm_prog_t *prog = SVVM_prog; int i; Con_Printf("Client \"%s\" dropped\n", host_client->name); SV_StopDemoRecording(host_client); // make sure edict is not corrupt (from a level change for example) host_client->edict = PRVM_EDICT_NUM(host_client - svs.clients + 1); if (host_client->netconnection) { // tell the client to be gone if (!crash) { // LordHavoc: no opportunity for resending, so use unreliable 3 times unsigned char bufdata[8]; sizebuf_t buf; memset(&buf, 0, sizeof(buf)); buf.data = bufdata; buf.maxsize = sizeof(bufdata); MSG_WriteByte(&buf, svc_disconnect); NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, false); NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, false); NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, false); } } // call qc ClientDisconnect function // LordHavoc: don't call QC if server is dead (avoids recursive // Host_Error in some mods when they run out of edicts) if (host_client->clientconnectcalled && sv.active && host_client->edict) { // call the prog function for removing a client // this will set the body to a dead frame, among other things int saveSelf = PRVM_serverglobaledict(self); host_client->clientconnectcalled = false; PRVM_serverglobalfloat(time) = sv.time; PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict); prog->ExecuteProgram(prog, PRVM_serverfunction(ClientDisconnect), "QC function ClientDisconnect is missing"); PRVM_serverglobaledict(self) = saveSelf; } if (host_client->netconnection) { // break the net connection NetConn_Close(host_client->netconnection); host_client->netconnection = NULL; } // if a download is active, close it if (host_client->download_file) { Con_DPrintf("Download of %s aborted when %s dropped\n", host_client->download_name, host_client->name); FS_Close(host_client->download_file); host_client->download_file = NULL; host_client->download_name[0] = 0; host_client->download_expectedposition = 0; host_client->download_started = false; } // remove leaving player from scoreboard host_client->name[0] = 0; host_client->colors = 0; host_client->frags = 0; // send notification to all clients // get number of client manually just to make sure we get it right... i = host_client - svs.clients; MSG_WriteByte (&sv.reliable_datagram, svc_updatename); MSG_WriteByte (&sv.reliable_datagram, i); MSG_WriteString (&sv.reliable_datagram, host_client->name); MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors); MSG_WriteByte (&sv.reliable_datagram, i); MSG_WriteByte (&sv.reliable_datagram, host_client->colors); MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags); MSG_WriteByte (&sv.reliable_datagram, i); MSG_WriteShort (&sv.reliable_datagram, host_client->frags); // free the client now if (host_client->entitydatabase) EntityFrame_FreeDatabase(host_client->entitydatabase); if (host_client->entitydatabase4) EntityFrame4_FreeDatabase(host_client->entitydatabase4); if (host_client->entitydatabase5) EntityFrame5_FreeDatabase(host_client->entitydatabase5); if (sv.active) { // clear a fields that matter to DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS, and also frags PRVM_ED_ClearEdict(prog, host_client->edict); } // clear the client struct (this sets active to false) memset(host_client, 0, sizeof(*host_client)); // update server listing on the master because player count changed // (which the master uses for filtering empty/full servers) NetConn_Heartbeat(1); if (sv.loadgame) { for (i = 0;i < svs.maxclients;i++) if (svs.clients[i].active && !svs.clients[i].spawned) break; if (i == svs.maxclients) { Con_Printf("Loaded game, everyone rejoined - unpausing\n"); sv.paused = sv.loadgame = false; // we're basically done with loading now } } }
int LHNET_Read(lhnetsocket_t *lhnetsocket, void *content, int maxcontentlength, lhnetaddress_t *vaddress) { lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress; int value = 0; if (!lhnetsocket || !address || !content || maxcontentlength < 1) return -1; if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_LOOP) { time_t currenttime; lhnetpacket_t *p, *pnext; // scan for any old packets to timeout while searching for a packet // that is waiting to be delivered to this socket currenttime = time(NULL); for (p = lhnet_packetlist.next;p != &lhnet_packetlist;p = pnext) { pnext = p->next; if (p->timeout < currenttime) { // unlink and free p->next->prev = p->prev; p->prev->next = p->next; Z_Free(p); continue; } #ifndef STANDALONETEST if (cl_netlocalping.value && (realtime - cl_netlocalping.value * (1.0 / 2000.0)) < p->sentdoubletime) continue; #endif if (value == 0 && p->destinationport == lhnetsocket->address.port) { if (p->length <= maxcontentlength) { lhnetaddressnative_t *localaddress = (lhnetaddressnative_t *)&lhnetsocket->address; *address = *localaddress; address->port = p->sourceport; memcpy(content, p->data, p->length); value = p->length; } else value = -1; // unlink and free p->next->prev = p->prev; p->prev->next = p->next; Z_Free(p); } } } else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET4) { SOCKLEN_T inetaddresslength; address->addresstype = LHNETADDRESSTYPE_NONE; inetaddresslength = sizeof(address->addr.in); value = recvfrom(lhnetsocket->inetsocket, (char *)content, maxcontentlength, LHNET_RECVFROM_FLAGS, &address->addr.sock, &inetaddresslength); if (value > 0) { address->addresstype = LHNETADDRESSTYPE_INET4; address->port = ntohs(address->addr.in.sin_port); return value; } else if (value < 0) { int e = SOCKETERRNO; if (e == EWOULDBLOCK) return 0; switch (e) { case ECONNREFUSED: Con_Print("Connection refused\n"); return 0; } Con_DPrintf("LHNET_Read: recvfrom returned error: %s\n", LHNETPRIVATE_StrError()); } } #ifndef NOSUPPORTIPV6 else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET6) { SOCKLEN_T inetaddresslength; address->addresstype = LHNETADDRESSTYPE_NONE; inetaddresslength = sizeof(address->addr.in6); value = recvfrom(lhnetsocket->inetsocket, (char *)content, maxcontentlength, LHNET_RECVFROM_FLAGS, &address->addr.sock, &inetaddresslength); if (value > 0) { address->addresstype = LHNETADDRESSTYPE_INET6; address->port = ntohs(address->addr.in6.sin6_port); return value; } else if (value == -1) { int e = SOCKETERRNO; if (e == EWOULDBLOCK) return 0; switch (e) { case ECONNREFUSED: Con_Print("Connection refused\n"); return 0; } Con_DPrintf("LHNET_Read: recvfrom returned error: %s\n", LHNETPRIVATE_StrError()); } } #endif return value; }
void Host_Main(void) { double time1 = 0; double time2 = 0; double time3 = 0; double cl_timer = 0, sv_timer = 0; double clframetime, deltacleantime, olddirtytime, dirtytime; double wait; int pass1, pass2, pass3, i; char vabuf[1024]; qboolean playing; Host_Init(); realtime = 0; dirtytime = Sys_DirtyTime(); for (;;) { if (setjmp(host_abortframe)) { SCR_ClearLoadingScreen(false); continue; // something bad happened, or the server disconnected } olddirtytime = host_dirtytime; dirtytime = Sys_DirtyTime(); deltacleantime = dirtytime - olddirtytime; if (deltacleantime < 0) { // warn if it's significant if (deltacleantime < -0.01) Con_Printf("Host_Mingled: time stepped backwards (went from %f to %f, difference %f)\n", olddirtytime, dirtytime, deltacleantime); deltacleantime = 0; } else if (deltacleantime >= 1800) { Con_Printf("Host_Mingled: time stepped forward (went from %f to %f, difference %f)\n", olddirtytime, dirtytime, deltacleantime); deltacleantime = 0; } realtime += deltacleantime; host_dirtytime = dirtytime; cl_timer += deltacleantime; sv_timer += deltacleantime; if (!svs.threaded) { svs.perf_acc_realtime += deltacleantime; // Look for clients who have spawned playing = false; for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) if(host_client->spawned) if(host_client->netconnection) playing = true; if(sv.time < 10) { // don't accumulate time for the first 10 seconds of a match // so things can settle svs.perf_acc_realtime = svs.perf_acc_sleeptime = svs.perf_acc_lost = svs.perf_acc_offset = svs.perf_acc_offset_squared = svs.perf_acc_offset_max = svs.perf_acc_offset_samples = 0; } else if(svs.perf_acc_realtime > 5) { svs.perf_cpuload = 1 - svs.perf_acc_sleeptime / svs.perf_acc_realtime; svs.perf_lost = svs.perf_acc_lost / svs.perf_acc_realtime; if(svs.perf_acc_offset_samples > 0) { svs.perf_offset_max = svs.perf_acc_offset_max; svs.perf_offset_avg = svs.perf_acc_offset / svs.perf_acc_offset_samples; svs.perf_offset_sdev = sqrt(svs.perf_acc_offset_squared / svs.perf_acc_offset_samples - svs.perf_offset_avg * svs.perf_offset_avg); } if(svs.perf_lost > 0 && developer_extra.integer) if(playing) // only complain if anyone is looking Con_DPrintf("Server can't keep up: %s\n", Host_TimingReport(vabuf, sizeof(vabuf))); svs.perf_acc_realtime = svs.perf_acc_sleeptime = svs.perf_acc_lost = svs.perf_acc_offset = svs.perf_acc_offset_squared = svs.perf_acc_offset_max = svs.perf_acc_offset_samples = 0; } } if (slowmo.value < 0.00001 && slowmo.value != 0) Cvar_SetValue("slowmo", 0); if (host_framerate.value < 0.00001 && host_framerate.value != 0) Cvar_SetValue("host_framerate", 0); // keep the random time dependent, but not when playing demos/benchmarking if(!*sv_random_seed.string && !cls.demoplayback) rand(); // get new key events Key_EventQueue_Unblock(); SndSys_SendKeyEvents(); Sys_SendKeyEvents(); NetConn_UpdateSockets(); Log_DestBuffer_Flush(); // receive packets on each main loop iteration, as the main loop may // be undersleeping due to select() detecting a new packet if (sv.active && !svs.threaded) NetConn_ServerFrame(); Curl_Run(); // check for commands typed to the host Host_GetConsoleCommands(); // when a server is running we only execute console commands on server frames // (this mainly allows frikbot .way config files to work properly by staying in sync with the server qc) // otherwise we execute them on client frames if (sv.active ? sv_timer > 0 : cl_timer > 0) { // process console commands // R_TimeReport("preconsole"); CL_VM_PreventInformationLeaks(); Cbuf_Frame(); // R_TimeReport("console"); } //Con_Printf("%6.0f %6.0f\n", cl_timer * 1000000.0, sv_timer * 1000000.0); // if the accumulators haven't become positive yet, wait a while if (cls.state == ca_dedicated) wait = sv_timer * -1000000.0; else if (!sv.active || svs.threaded) wait = cl_timer * -1000000.0; else wait = max(cl_timer, sv_timer) * -1000000.0; if (!cls.timedemo && wait >= 1) { double time0, delta; if(host_maxwait.value <= 0) wait = min(wait, 1000000.0); else wait = min(wait, host_maxwait.value * 1000.0); if(wait < 1) wait = 1; // because we cast to int time0 = Sys_DirtyTime(); if (sv_checkforpacketsduringsleep.integer && !sys_usenoclockbutbenchmark.integer && !svs.threaded) NetConn_SleepMicroseconds((int)wait); else Sys_Sleep((int)wait); delta = Sys_DirtyTime() - time0; if (delta < 0 || delta >= 1800) delta = 0; if (!svs.threaded) svs.perf_acc_sleeptime += delta; // R_TimeReport("sleep"); continue; } // limit the frametime steps to no more than 100ms each if (cl_timer > 0.1) cl_timer = 0.1; if (sv_timer > 0.1) { if (!svs.threaded) svs.perf_acc_lost += (sv_timer - 0.1); sv_timer = 0.1; } R_TimeReport("---"); //------------------- // // server operations // //------------------- // limit the frametime steps to no more than 100ms each if (sv.active && sv_timer > 0 && !svs.threaded) { // execute one or more server frames, with an upper limit on how much // execution time to spend on server frames to avoid freezing the game if // the server is overloaded, this execution time limit means the game will // slow down if the server is taking too long. int framecount, framelimit = 1; double advancetime, aborttime = 0; float offset; prvm_prog_t *prog = SVVM_prog; // run the world state // don't allow simulation to run too fast or too slow or logic glitches can occur // stop running server frames if the wall time reaches this value if (sys_ticrate.value <= 0) advancetime = sv_timer; else if (cl.islocalgame && !sv_fixedframeratesingleplayer.integer) { // synchronize to the client frametime, but no less than 10ms and no more than 100ms advancetime = bound(0.01, cl_timer, 0.1); } else { advancetime = sys_ticrate.value; // listen servers can run multiple server frames per client frame framelimit = cl_maxphysicsframesperserverframe.integer; aborttime = Sys_DirtyTime() + 0.1; } if(slowmo.value > 0 && slowmo.value < 1) advancetime = min(advancetime, 0.1 / slowmo.value); else advancetime = min(advancetime, 0.1); if(advancetime > 0) { offset = Sys_DirtyTime() - dirtytime;if (offset < 0 || offset >= 1800) offset = 0; offset += sv_timer; ++svs.perf_acc_offset_samples; svs.perf_acc_offset += offset; svs.perf_acc_offset_squared += offset * offset; if(svs.perf_acc_offset_max < offset) svs.perf_acc_offset_max = offset; } // only advance time if not paused // the game also pauses in singleplayer when menu or console is used sv.frametime = advancetime * slowmo.value; if (host_framerate.value) sv.frametime = host_framerate.value; if (sv.paused || (cl.islocalgame && (key_dest != key_game || key_consoleactive || cl.csqc_paused))) sv.frametime = 0; for (framecount = 0;framecount < framelimit && sv_timer > 0;framecount++) { sv_timer -= advancetime; // move things around and think unless paused if (sv.frametime) SV_Physics(); // if this server frame took too long, break out of the loop if (framelimit > 1 && Sys_DirtyTime() >= aborttime) break; } R_TimeReport("serverphysics"); // send all messages to the clients SV_SendClientMessages(); if (sv.paused == 1 && realtime > sv.pausedstart && sv.pausedstart > 0) { prog->globals.generic[OFS_PARM0] = realtime - sv.pausedstart; PRVM_serverglobalfloat(time) = sv.time; prog->ExecuteProgram(prog, PRVM_serverfunction(SV_PausedTic), "QC function SV_PausedTic is missing"); } // send an heartbeat if enough time has passed since the last one NetConn_Heartbeat(0); R_TimeReport("servernetwork"); } else if (!svs.threaded) { // don't let r_speeds display jump around R_TimeReport("serverphysics"); R_TimeReport("servernetwork"); } //------------------- // // client operations // //------------------- if (cls.state != ca_dedicated && (cl_timer > 0 || cls.timedemo || ((vid_activewindow ? cl_maxfps : cl_maxidlefps).value < 1))) { R_TimeReport("---"); Collision_Cache_NewFrame(); R_TimeReport("collisioncache"); // decide the simulation time if (cls.capturevideo.active) { //*** if (cls.capturevideo.realtime) clframetime = cl.realframetime = max(cl_timer, 1.0 / cls.capturevideo.framerate); else { clframetime = 1.0 / cls.capturevideo.framerate; cl.realframetime = max(cl_timer, clframetime); } } else if (vid_activewindow && cl_maxfps.value >= 1 && !cls.timedemo) { clframetime = cl.realframetime = max(cl_timer, 1.0 / cl_maxfps.value); // when running slow, we need to sleep to keep input responsive wait = bound(0, cl_maxfps_alwayssleep.value * 1000, 100000); if (wait > 0) Sys_Sleep((int)wait); } else if (!vid_activewindow && cl_maxidlefps.value >= 1 && !cls.timedemo) clframetime = cl.realframetime = max(cl_timer, 1.0 / cl_maxidlefps.value); else clframetime = cl.realframetime = cl_timer; // apply slowmo scaling clframetime *= cl.movevars_timescale; // scale playback speed of demos by slowmo cvar if (cls.demoplayback) { clframetime *= slowmo.value; // if demo playback is paused, don't advance time at all if (cls.demopaused) clframetime = 0; } // host_framerate overrides all else if (host_framerate.value) clframetime = host_framerate.value; if (cl.paused || (cl.islocalgame && (key_dest != key_game || key_consoleactive || cl.csqc_paused))) clframetime = 0; if (cls.timedemo) clframetime = cl.realframetime = cl_timer; // deduct the frame time from the accumulator cl_timer -= cl.realframetime; cl.oldtime = cl.time; cl.time += clframetime; // update video if (host_speeds.integer) time1 = Sys_DirtyTime(); R_TimeReport("pre-input"); // Collect input into cmd CL_Input(); R_TimeReport("input"); // check for new packets NetConn_ClientFrame(); // read a new frame from a demo if needed CL_ReadDemoMessage(); R_TimeReport("clientnetwork"); // now that packets have been read, send input to server CL_SendMove(); R_TimeReport("sendmove"); // update client world (interpolate entities, create trails, etc) CL_UpdateWorld(); R_TimeReport("lerpworld"); CL_Video_Frame(); R_TimeReport("client"); CL_UpdateScreen(); R_TimeReport("render"); if (host_speeds.integer) time2 = Sys_DirtyTime(); // update audio if(cl.csqc_usecsqclistener) { S_Update(&cl.csqc_listenermatrix); cl.csqc_usecsqclistener = false; } else S_Update(&r_refdef.view.matrix); CDAudio_Update(); R_TimeReport("audio"); // reset gathering of mouse input in_mouse_x = in_mouse_y = 0; if (host_speeds.integer) { pass1 = (int)((time1 - time3)*1000000); time3 = Sys_DirtyTime(); pass2 = (int)((time2 - time1)*1000000); pass3 = (int)((time3 - time2)*1000000); Con_Printf("%6ius total %6ius server %6ius gfx %6ius snd\n", pass1+pass2+pass3, pass1, pass2, pass3); } } #if MEMPARANOIA Mem_CheckSentinelsGlobal(); #else if (developer_memorydebug.integer) Mem_CheckSentinelsGlobal(); #endif // if there is some time remaining from this frame, reset the timers if (cl_timer >= 0) cl_timer = 0; if (sv_timer >= 0) { if (!svs.threaded) svs.perf_acc_lost += sv_timer; sv_timer = 0; } host_framecount++; } }
lhnetsocket_t *LHNET_OpenSocket_Connectionless(lhnetaddress_t *address) { lhnetsocket_t *lhnetsocket, *s; if (!address) return NULL; lhnetsocket = (lhnetsocket_t *)Z_Malloc(sizeof(*lhnetsocket)); if (lhnetsocket) { memset(lhnetsocket, 0, sizeof(*lhnetsocket)); lhnetsocket->address = *address; switch(lhnetsocket->address.addresstype) { case LHNETADDRESSTYPE_LOOP: if (lhnetsocket->address.port == 0) { // allocate a port dynamically // this search will always terminate because there is never // an allocated socket with port 0, so if the number wraps it // will find the port is unused, and then refuse to use port // 0, causing an intentional failure condition lhnetsocket->address.port = 1024; for (;;) { for (s = lhnet_socketlist.next;s != &lhnet_socketlist;s = s->next) if (s->address.addresstype == lhnetsocket->address.addresstype && s->address.port == lhnetsocket->address.port) break; if (s == &lhnet_socketlist) break; lhnetsocket->address.port++; } } // check if the port is available for (s = lhnet_socketlist.next;s != &lhnet_socketlist;s = s->next) if (s->address.addresstype == lhnetsocket->address.addresstype && s->address.port == lhnetsocket->address.port) break; if (s == &lhnet_socketlist && lhnetsocket->address.port != 0) { lhnetsocket->next = &lhnet_socketlist; lhnetsocket->prev = lhnetsocket->next->prev; lhnetsocket->next->prev = lhnetsocket; lhnetsocket->prev->next = lhnetsocket; return lhnetsocket; } break; case LHNETADDRESSTYPE_INET4: #ifndef NOSUPPORTIPV6 case LHNETADDRESSTYPE_INET6: #endif #ifdef WIN32 if (lhnet_didWSAStartup) { #endif #ifndef NOSUPPORTIPV6 if ((lhnetsocket->inetsocket = socket(address->addresstype == LHNETADDRESSTYPE_INET6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1) #else if ((lhnetsocket->inetsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1) #endif { #ifdef WIN32 u_long _false = 0; #endif #ifdef MSG_DONTWAIT if (1) #else #ifdef WIN32 u_long _true = 1; #else char _true = 1; #endif if (ioctlsocket(lhnetsocket->inetsocket, FIONBIO, &_true) != -1) #endif { #ifdef IPV6_V6ONLY // We need to set this flag to tell the OS that we only listen on IPv6. If we don't // most OSes will create a dual-protocol socket that also listens on IPv4. In this case // if an IPv4 socket is already bound to the port we want, our bind() call will fail. int ipv6_only = 1; if (address->addresstype != LHNETADDRESSTYPE_INET6 || setsockopt (lhnetsocket->inetsocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&ipv6_only, sizeof(ipv6_only)) == 0 #ifdef WIN32 // The Win32 API only supports IPV6_V6ONLY since Windows Vista, but fortunately // the default value is what we want on Win32 anyway (IPV6_V6ONLY = true) || SOCKETERRNO == WSAENOPROTOOPT #endif ) #endif { lhnetaddressnative_t *localaddress = (lhnetaddressnative_t *)&lhnetsocket->address; SOCKLEN_T namelen; int bindresult; #if defined(SOL_RFC1149) && defined(RFC1149_1149ONLY) // we got reports of massive lags when this protocol was chosen as transport // so better turn it off { int rfc1149only = 0; int rfc1149enabled = 0; if(setsockopt(lhnetsocket->inetsocket, SOL_RFC1149, RFC1149_1149ONLY, &rfc1149only)) Con_Printf("LHNET_OpenSocket_Connectionless: warning: setsockopt(RFC1149_1149ONLY) returned error: %s\n", LHNETPRIVATE_StrError()); if(setsockopt(lhnetsocket->inetsocket, SOL_RFC1149, RFC1149_ENABLED, &rfc1149enabled)) Con_Printf("LHNET_OpenSocket_Connectionless: warning: setsockopt(RFC1149_ENABLED) returned error: %s\n", LHNETPRIVATE_StrError()); } #endif #ifndef NOSUPPORTIPV6 if (address->addresstype == LHNETADDRESSTYPE_INET6) { namelen = sizeof(localaddress->addr.in6); bindresult = bind(lhnetsocket->inetsocket, &localaddress->addr.sock, namelen); if (bindresult != -1) { if (getsockname(lhnetsocket->inetsocket, &localaddress->addr.sock, &namelen)) { // If getsockname failed, we can assume the bound socket is useless. bindresult = -1; } } } else #endif { namelen = sizeof(localaddress->addr.in); bindresult = bind(lhnetsocket->inetsocket, &localaddress->addr.sock, namelen); if (bindresult != -1) { if (getsockname(lhnetsocket->inetsocket, &localaddress->addr.sock, &namelen)) { // If getsockname failed, we can assume the bound socket is useless. bindresult = -1; } } } if (bindresult != -1) { int i = 1; // enable broadcast on this socket setsockopt(lhnetsocket->inetsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)); #ifdef IP_TOS { // enable DSCP for ToS support int tos = lhnet_default_dscp << 2; if (setsockopt(lhnetsocket->inetsocket, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(tos))) { // Error in setsockopt - fine, we'll simply set no TOS then. } } #endif lhnetsocket->next = &lhnet_socketlist; lhnetsocket->prev = lhnetsocket->next->prev; lhnetsocket->next->prev = lhnetsocket; lhnetsocket->prev->next = lhnetsocket; #ifdef WIN32 if (ioctlsocket(lhnetsocket->inetsocket, SIO_UDP_CONNRESET, &_false) == -1) Con_DPrintf("LHNET_OpenSocket_Connectionless: ioctlsocket SIO_UDP_CONNRESET returned error: %s\n", LHNETPRIVATE_StrError()); #endif return lhnetsocket; } else Con_Printf("LHNET_OpenSocket_Connectionless: bind returned error: %s\n", LHNETPRIVATE_StrError()); } #ifdef IPV6_V6ONLY else Con_Printf("LHNET_OpenSocket_Connectionless: setsockopt(IPV6_V6ONLY) returned error: %s\n", LHNETPRIVATE_StrError()); #endif } else Con_Printf("LHNET_OpenSocket_Connectionless: ioctlsocket returned error: %s\n", LHNETPRIVATE_StrError()); closesocket(lhnetsocket->inetsocket); } else Con_Printf("LHNET_OpenSocket_Connectionless: socket returned error: %s\n", LHNETPRIVATE_StrError()); #ifdef WIN32 } else Con_Print("LHNET_OpenSocket_Connectionless: can't open a socket (WSAStartup failed during LHNET_Init)\n"); #endif break; default: break; } Z_Free(lhnetsocket); } return NULL; }
qbool NET_GetTCPPacket_SV (netsrc_t netsrc, netadr_t *from, sizebuf_t *message) { int ret; float timeval = Sys_DoubleTime(); svtcpstream_t *st = NULL, *next = NULL; if (netsrc != NS_SERVER) return false; for (st = svs.tcpstreams; st; st = next) { next = st->next; *from = st->remoteaddr; if (st->socketnum == INVALID_SOCKET || st->drop) { sv_tcp_connection_free(st, true); // free and unlink continue; } //due to the above checks about invalid sockets, the socket is always open for st below. // check for client timeout if (st->timeouttime < timeval) { st->drop = true; continue; } ret = recv(st->socketnum, st->inbuffer+st->inlen, sizeof(st->inbuffer)-st->inlen, 0); if (ret == 0) { // connection closed st->drop = true; continue; } else if (ret == -1) { int err = qerrno; if (err == EWOULDBLOCK) { ret = 0; // it's OK } else { if (err == ECONNABORTED || err == ECONNRESET) { Con_DPrintf ("Connection lost or aborted\n"); //server died/connection lost. } else { Con_DPrintf ("NET_GetPacket: Error (%i): %s\n", err, strerror(err)); } st->drop = true; continue; } } else { // update timeout st->timeouttime = Sys_DoubleTime() + 10; } st->inlen += ret; if (st->waitingforprotocolconfirmation) { // not enough data if (st->inlen < 6) continue; if (strncmp(st->inbuffer, "qizmo\n", 6)) { Con_Printf ("Unknown TCP client\n"); st->drop = true; continue; } // remove leading 6 bytes memmove(st->inbuffer, st->inbuffer+6, st->inlen - (6)); st->inlen -= 6; // confirmed st->waitingforprotocolconfirmation = false; } // need two bytes for packet len if (st->inlen < 2) continue; message->cursize = BigShort(*(short*)st->inbuffer); if (message->cursize < 0) { message->cursize = 0; Con_Printf ("Warning: malformed message from %s\n", NET_AdrToString (*from)); st->drop = true; continue; } if (message->cursize >= message->maxsize) { Con_Printf ("Warning: Oversize packet from %s\n", NET_AdrToString (*from)); st->drop = true; continue; } if (message->cursize + 2 > st->inlen) { //not enough buffered to read a packet out of it. continue; } memcpy(message->data, st->inbuffer + 2, message->cursize); memmove(st->inbuffer, st->inbuffer + message->cursize + 2, st->inlen - (message->cursize + 2)); st->inlen -= message->cursize + 2; return true; // we got packet! } return false; // no packet received. }
/* =================== SV_ReadClientMessage Returns false if the client should be killed =================== */ qboolean SV_ReadClientMessage (void) { int ret; int cmd; char *s; do { nextmsg: ret = NET_GetMessage (host_client->netconnection); if (ret == -1) { Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n"); return false; } if (!ret) return true; MSG_BeginReading (); while (1) { if (!host_client->active) return false; // a command caused an error if (msg_badread) { Sys_Printf ("SV_ReadClientMessage: badread\n"); return false; } cmd = MSG_ReadChar (); switch (cmd) { case -1: goto nextmsg; // end of message default: Sys_Printf ("SV_ReadClientMessage: unknown command char\n"); return false; case clc_nop: // Sys_Printf ("clc_nop\n"); break; case clc_stringcmd: s = MSG_ReadString (); if (host_client->privileged) ret = 2; else ret = 0; if (Q_strncasecmp(s, "status", 6) == 0) ret = 1; else if (Q_strncasecmp(s, "god", 3) == 0) ret = 1; else if (Q_strncasecmp(s, "notarget", 8) == 0) ret = 1; else if (Q_strncasecmp(s, "fly", 3) == 0) ret = 1; else if (Q_strncasecmp(s, "name", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "noclip", 6) == 0) ret = 1; else if (Q_strncasecmp(s, "say", 3) == 0) ret = 1; else if (Q_strncasecmp(s, "say_team", 8) == 0) ret = 1; else if (Q_strncasecmp(s, "tell", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "color", 5) == 0) ret = 1; else if (Q_strncasecmp(s, "kill", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "pause", 5) == 0) ret = 1; else if (Q_strncasecmp(s, "spawn", 5) == 0) ret = 1; else if (Q_strncasecmp(s, "begin", 5) == 0) ret = 1; else if (Q_strncasecmp(s, "prespawn", 8) == 0) ret = 1; else if (Q_strncasecmp(s, "kick", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "ping", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "give", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "ban", 3) == 0) ret = 1; if (ret == 2) Cbuf_InsertText (s); else if (ret == 1) Cmd_ExecuteString (s, src_client); else Con_DPrintf("%s tried to %s\n", host_client->name, s); break; case clc_disconnect: // Sys_Printf ("SV_ReadClientMessage: client disconnected\n"); return false; case clc_move: SV_ReadClientMove (&host_client->cmd); break; } } } while (ret == 1); return true; }
void CDAudio_Play(byte track, qboolean looping) { struct cdrom_tocentry entry; struct cdrom_ti ti; if (cdfile == -1 || !enabled) return; if (!cdValid) { CDAudio_GetAudioDiskInfo(); if (!cdValid) return; } track = remap[track]; if (track < 1 || track > maxTrack) { Con_DPrintf("CDAudio: Bad track number %u.\n", track); return; } // don't try to play a non-audio track entry.cdte_track = track; entry.cdte_format = CDROM_MSF; if ( ioctl(cdfile, CDROMREADTOCENTRY, &entry) == -1 ) { Con_DPrintf("ioctl cdromreadtocentry failed\n"); return; } if (entry.cdte_ctrl == CDROM_DATA_TRACK) { Con_Printf("CDAudio: track %i is not audio\n", track); return; } if (playing) { if (playTrack == track) return; CDAudio_Stop(); } ti.cdti_trk0 = track; ti.cdti_trk1 = track; ti.cdti_ind0 = 1; ti.cdti_ind1 = 99; if ( ioctl(cdfile, CDROMPLAYTRKIND, &ti) == -1 ) { Con_DPrintf("ioctl cdromplaytrkind failed\n"); return; } if ( ioctl(cdfile, CDROMRESUME) == -1 ) Con_DPrintf("ioctl cdromresume failed\n"); playLooping = looping; playTrack = track; playing = true; if (cdvolume == 0.0) CDAudio_Pause (); }
int CDAudio_Play(byte track, qboolean looping) { DWORD dwReturn; MCI_PLAY_PARMS mciPlayParms; MCI_STATUS_PARMS mciStatusParms; if (!cd_enabled.value || !initialized) // Manoel Kasimier - CD player in menu - edited return 0; if (!cdValid) { CDAudio_GetAudioDiskInfo(); if (!cdValid) return 0; } track = remap[track]; if (track < 1 || track > maxTrack) { Con_DPrintf("CDAudio: Bad track number %u.\n", track); return 0; } // don't try to play a non-audio track mciStatusParms.dwItem = MCI_CDA_STATUS_TYPE_TRACK; mciStatusParms.dwTrack = track; dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms); if (dwReturn) { Con_DPrintf("MCI_STATUS failed (%i)\n", dwReturn); return 0; } if (mciStatusParms.dwReturn != MCI_CDA_TRACK_AUDIO) { Con_Printf("CDAudio: track %i is not audio\n", track); return 0; } // get the length of the track to be played mciStatusParms.dwItem = MCI_STATUS_LENGTH; mciStatusParms.dwTrack = track; dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms); if (dwReturn) { Con_DPrintf("MCI_STATUS failed (%i)\n", dwReturn); return 0; } if (playing) { if (playTrack == track) return 1; CDAudio_Stop(); } mciPlayParms.dwFrom = MCI_MAKE_TMSF(track, 0, 0, 0); mciPlayParms.dwTo = (mciStatusParms.dwReturn << 8) | track; mciPlayParms.dwCallback = (DWORD)mainwindow; dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY | MCI_FROM | MCI_TO, (DWORD)(LPVOID) &mciPlayParms); if (dwReturn) { Con_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", dwReturn); return 0; } playLooping = looping; playTrack = track; playing = true; if (cdvolume == 0.0) CDAudio_Pause (); return 1; }
/* ================= Mod_LoadLighting ================= */ void Mod_LoadLighting (lump_t *l) { // 2001-09-11 Colored lightning by LordHavoc/Sarcazm/Maddes start /* if (!l->filelen) { loadmodel->lightdata = NULL; return; } loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname); memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen); */ int i; byte *in, *out, *data; byte d; char litfilename[1024]; loadedfile_t *fileinfo; // 2001-09-12 Returning information about loaded file by Maddes loadmodel->lightdata = NULL; if (external_lit->value) { // check for a .LIT file strcpy(litfilename, loadmodel->name); COM_StripExtension(litfilename, litfilename); strcat(litfilename, ".lit"); // 2001-09-12 Returning information about loaded file by Maddes start /* data = (byte*) COM_LoadHunkFile(litfilename); if (data) */ fileinfo = COM_LoadHunkFile(litfilename); if (fileinfo) // 2001-09-12 Returning information about loaded file by Maddes end { Con_DPrintf("%s loaded from %s\n", litfilename, fileinfo->path->pack ? fileinfo->path->pack->filename : fileinfo->path->filename); // 2001-09-12 Displaying where .LIT file is loaded from by Maddes data = fileinfo->data; // 2001-09-12 Returning information about loaded file by Maddes if (data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T') { i = LittleLong(((int *)data)[1]); if (i == 1) { loadmodel->lightdata = data + 8; return; } else Con_Printf("Unknown .LIT file version (%d)\n", i); } else Con_Printf("Corrupt .LIT file (old version?), ignoring\n"); } // no .LIT found, expand the white lighting data to color } if (!l->filelen) return; loadmodel->lightdata = Hunk_AllocName ( l->filelen*3, loadname); in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write out = loadmodel->lightdata; memcpy (in, mod_base + l->fileofs, l->filelen); for (i = 0;i < l->filelen;i++) { d = *in++; *out++ = d; *out++ = d; *out++ = d; } // 2001-09-11 Colored lightning by LordHavoc/Sarcazm/Maddes end }
int CDAudio_Init(void) { DWORD dwReturn; MCI_OPEN_PARMS mciOpenParms; MCI_SET_PARMS mciSetParms; int n; static qboolean cd_initialized; // Manoel Kasimier - Windows XP fix // Manoel Kasimier - CD player in menu - begin cdValid = false; playing = false; wasPlaying = false; playLooping = false; // Manoel Kasimier - CD player in menu - end if (cls.state == ca_dedicated) return -1; if (COM_CheckParm("-nocdaudio")) return -1; mciOpenParms.lpstrDeviceType = "cdaudio"; if (dwReturn = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE, (DWORD) (LPVOID) &mciOpenParms)) { Con_Printf("CDAudio_Init: MCI_OPEN failed (%i)\n", dwReturn); return -1; } wDeviceID = mciOpenParms.wDeviceID; // Set the time format to track/minute/second/frame (TMSF). mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF; if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD)(LPVOID) &mciSetParms)) { Con_Printf("MCI_SET_TIME_FORMAT failed (%i)\n", dwReturn); mciSendCommand(wDeviceID, MCI_CLOSE, 0, (DWORD)NULL); return -1; } for (n = 0; n < 100; n++) remap[n] = n; initialized = true; if (CDAudio_GetAudioDiskInfo()) { Con_DPrintf("CDAudio_Init: No CD in player.\n"); // edited cdValid = false; } // Manoel Kasimier - Windows XP fix - begin if (!cd_initialized) { cd_initialized = true; Cvar_RegisterVariableWithCallback(&cd_enabled, cd_cvar_check); // Manoel Kasimier - Windows XP fix - end Cmd_AddCommand ("cd", CD_f); CD_FindCDAux(); // Hexen 2 } // Manoel Kasimier - Windows XP fix Con_DPrintf("CD Audio Initialized\n"); // edited return 0; }
/* ================= Mod_LoadQ3Model ================= */ void Mod_LoadQ3Model (model_t *mod, const void *buffer) { md3header_t *header; md3surface_t *surf; int i, j, picmip_flag; md3shader_t *shader; md3frame_t *frame; // md3ver_t *vert; byte *modeldata; const char **pathlist; const char *namelist[2]; char path[MAX_OSPATH]; header = (md3header_t *) buffer; if (header->version != 15) { Con_Printf ("\x02""ERROR: incorrect version of MD3 file %s\n", mod->name); return; } Con_DPrintf ("Loading md3 model...%s (%s)\n", header->filename, mod->name); frame = (md3frame_t *) ((byte *) header + header->frame_offs); for (i = 0; i < header->num_frames; i++, frame++) { VectorCopy (frame->pos, md3bboxmins); VectorCopy (frame->pos, md3bboxmaxs); for (j = 0; j < 3; j++) { if (frame->mins[j] < md3bboxmins[j]) md3bboxmins[j] = frame->mins[j]; if (frame->maxs[j] > md3bboxmaxs[j]) md3bboxmaxs[j] = frame->maxs[j]; } } #ifndef RQM_SV_ONLY picmip_flag = gl_picmip_all.value ? TEX_MIPMAP : 0; #else picmip_flag = 0; #endif surf = (md3surface_t *) ((byte *)header + header->surface_offs); for (i=0; i < header->num_surfaces; i++) { if (*(long *)surf->id != MD3IDHEADER) { Con_Printf ("\x02""MD3 bad surface for: %s\n", header->filename); break; } /*vert = (md3vert_t *) ((byte *) surf + surf->vert_offs); for (j=0; j < surf->num_surf_verts * surf->num_surf_frames; j++, vert++) { float lat; float lng; //convert verts from shorts to floats md3vert_mem_t *mem_vert = (md3vert_mem_t *)((byte *)mem_head + posn); md3vert_t *disk_vert = (md3vert_t *)((byte *)surf + surf->vert_offs + j * sizeof(md3vert_t)); mem_vert->vec[0] = (float)disk_vert->vec[0] / 64.0f; mem_vert->vec[1] = (float)disk_vert->vec[1] / 64.0f; mem_vert->vec[2] = (float)disk_vert->vec[2] / 64.0f; //work out normals lat = (disk_vert->normal + 255) * (2 * 3.141592654) / 255; lng = ((disk_vert->normal >> 8) & 255) * (2 * 3.141592654) / 255; mem_vert->normal[0] = cos (lat) * sin (lng); mem_vert->normal[1] = sin (lat) * sin (lng); mem_vert->normal[2] = cos (lng); } */ // load all the external textures: shader = (md3shader_t *)((byte *)surf + surf->shader_offs); for (j=0; j < surf->num_surf_shaders; j++, shader++) { #ifndef RQM_SV_ONLY //shader->index = GL_LoadTextureImage ("", shader->name, NULL, picmip_flag | TEX_BLEND, mod_loadpath->dir_level); namelist[0] = COM_SkipPath (shader->name); namelist[1] = NULL; if (namelist[0] != shader->name) { Q_strncpy (path, sizeof(path), shader->name, namelist[0]-shader->name); md3_paths[0] = path; pathlist = &md3_paths[0]; } else { pathlist = &md3_paths[1]; // no custom path } shader->index = GL_LoadTextureImage_MultiSource (pathlist, namelist, NULL, picmip_flag | TEX_BLEND, mod_loadpath->dir_level); if (!shader->index) { Con_Printf ("\x02""Model: %s Texture missing: %s\n", mod->name, shader->name); } #else shader->index = 0; #endif } surf = (md3surface_t *)((byte *)surf + surf->end_offs); } modeldata = Cache_Alloc (&mod->cache, header->end_offs, mod->name); if (!modeldata) { Con_DPrintf ("\x02""cache alloc failed...%s (%s)\n", header->filename, mod->name); return; //cache alloc failed } memcpy (modeldata, buffer, header->end_offs); mod->type = mod_md3; // mod->aliastype = MD3IDHEADER; mod->numframes = header->num_frames; mod->modhint = Mod_GetAliasHint (mod->name); mod->flags = header->flags; if (mod->modhint == MOD_HEAD) mod->flags |= EF_GIB; else mod->flags |= Mod_GetQ3ModelFlags (mod->name); VectorScale (md3bboxmaxs, 1.0/64.0, mod->maxs); VectorScale (md3bboxmins, 1.0/64.0, mod->mins); }
/* ==================== CheckPendingDownloads checks if there are free download slots to start new downloads in. To not start too many downloads at once, only one download is added at a time, up to a maximum number of cl_curl_maxdownloads are running. ==================== */ static void CheckPendingDownloads(void) { const char *h; char urlbuf[1024]; char vabuf[1024]; if(!curl_dll) return; if(numdownloads < cl_curl_maxdownloads.integer) { downloadinfo *di; for(di = downloads; di; di = di->next) { if(!di->started) { if(!di->buffer) { Con_Printf("Downloading %s -> %s", CleanURL(di->url, urlbuf, sizeof(urlbuf)), di->filename); di->stream = FS_OpenRealFile(di->filename, "ab", false); if(!di->stream) { Con_Printf("\nFAILED: Could not open output file %s\n", di->filename); Curl_EndDownload(di, CURL_DOWNLOAD_FAILED, CURLE_OK, NULL); return; } FS_Seek(di->stream, 0, SEEK_END); di->startpos = FS_Tell(di->stream); if(di->startpos > 0) Con_Printf(", resuming from position %ld", (long) di->startpos); Con_Print("...\n"); } else { Con_DPrintf("Downloading %s -> memory\n", CleanURL(di->url, urlbuf, sizeof(urlbuf))); di->startpos = 0; } di->curle = qcurl_easy_init(); di->slist = NULL; qcurl_easy_setopt(di->curle, CURLOPT_URL, di->url); if(cl_curl_useragent.integer) { const char *ua #ifdef HTTP_USER_AGENT = HTTP_USER_AGENT; #else = engineversion; #endif if(!ua) ua = ""; if(*cl_curl_useragent_append.string) ua = va(vabuf, sizeof(vabuf), "%s%s%s", ua, (ua[0] && ua[strlen(ua)-1] != ' ') ? " " : "", cl_curl_useragent_append.string); qcurl_easy_setopt(di->curle, CURLOPT_USERAGENT, ua); } else qcurl_easy_setopt(di->curle, CURLOPT_USERAGENT, ""); qcurl_easy_setopt(di->curle, CURLOPT_REFERER, di->referer); qcurl_easy_setopt(di->curle, CURLOPT_RESUME_FROM, (long) di->startpos); qcurl_easy_setopt(di->curle, CURLOPT_FOLLOWLOCATION, 1); qcurl_easy_setopt(di->curle, CURLOPT_WRITEFUNCTION, CURL_fwrite); qcurl_easy_setopt(di->curle, CURLOPT_LOW_SPEED_LIMIT, (long) 256); qcurl_easy_setopt(di->curle, CURLOPT_LOW_SPEED_TIME, (long) 45); qcurl_easy_setopt(di->curle, CURLOPT_WRITEDATA, (void *) di); qcurl_easy_setopt(di->curle, CURLOPT_PRIVATE, (void *) di); qcurl_easy_setopt(di->curle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP); if(qcurl_easy_setopt(di->curle, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP) != CURLE_OK) { Con_Printf("^1WARNING:^7 for security reasons, please upgrade to libcurl 7.19.4 or above. In a later version of DarkPlaces, HTTP redirect support will be disabled for this libcurl version.\n"); //qcurl_easy_setopt(di->curle, CURLOPT_FOLLOWLOCATION, 0); } if(di->post_content_type) { qcurl_easy_setopt(di->curle, CURLOPT_POST, 1); qcurl_easy_setopt(di->curle, CURLOPT_POSTFIELDS, di->postbuf); qcurl_easy_setopt(di->curle, CURLOPT_POSTFIELDSIZE, di->postbufsize); di->slist = qcurl_slist_append(di->slist, va(vabuf, sizeof(vabuf), "Content-Type: %s", di->post_content_type)); } // parse extra headers into slist // \n separated list! h = di->extraheaders; while(h) { const char *hh = strchr(h, '\n'); if(hh) { char *buf = (char *) Mem_Alloc(tempmempool, hh - h + 1); memcpy(buf, h, hh - h); buf[hh - h] = 0; di->slist = qcurl_slist_append(di->slist, buf); h = hh + 1; } else { di->slist = qcurl_slist_append(di->slist, h); h = NULL; } } qcurl_easy_setopt(di->curle, CURLOPT_HTTPHEADER, di->slist); qcurl_multi_add_handle(curlm, di->curle); di->started = true; ++numdownloads; if(numdownloads >= cl_curl_maxdownloads.integer) break; }
/* =============== PR_LoadProgs =============== */ void PR_LoadProgs (void) { int i; // flush the non-C variable lookup cache for (i=0 ; i<GEFV_CACHESIZE ; i++) gefvCache[i].field[0] = 0; CRC_Init (&pr_crc); progs = (dprograms_t *)COM_LoadHunkFile ("progs.dat"); if (!progs) Sys_Error ("PR_LoadProgs: couldn't load progs.dat"); Con_DPrintf ("Programs occupy %iK.\n", com_filesize/1024); for (i=0 ; i<com_filesize ; i++) CRC_ProcessByte (&pr_crc, ((byte *)progs)[i]); // byte swap the header for (i=0 ; i<sizeof(*progs)/4 ; i++) ((int *)progs)[i] = LittleLong ( ((int *)progs)[i] ); if (progs->version != PROG_VERSION) Sys_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION); if (progs->crc != PROGHEADER_CRC) Sys_Error ("progs.dat system vars have been modified, progdefs.h is out of date"); pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions); pr_strings = (char *)progs + progs->ofs_strings; pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs); pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs); pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements); pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals); pr_globals = (float *)pr_global_struct; pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t); // byte swap the lumps for (i=0 ; i<progs->numstatements ; i++) { pr_statements[i].op = LittleShort(pr_statements[i].op); pr_statements[i].a = LittleShort(pr_statements[i].a); pr_statements[i].b = LittleShort(pr_statements[i].b); pr_statements[i].c = LittleShort(pr_statements[i].c); } for (i=0 ; i<progs->numfunctions; i++) { pr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement); pr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start); pr_functions[i].s_name = LittleLong (pr_functions[i].s_name); pr_functions[i].s_file = LittleLong (pr_functions[i].s_file); pr_functions[i].numparms = LittleLong (pr_functions[i].numparms); pr_functions[i].locals = LittleLong (pr_functions[i].locals); } for (i=0 ; i<progs->numglobaldefs ; i++) { pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type); pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs); pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name); } for (i=0 ; i<progs->numfielddefs ; i++) { pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type); if (pr_fielddefs[i].type & DEF_SAVEGLOBAL) Sys_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL"); pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs); pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name); } for (i=0 ; i<progs->numglobals ; i++) ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]); }
/* ==================== Host_Init ==================== */ static void Host_Init (void) { int i; const char* os; char vabuf[1024]; if (COM_CheckParm("-profilegameonly")) Sys_AllowProfiling(false); // LordHavoc: quake never seeded the random number generator before... heh if (COM_CheckParm("-benchmark")) srand(0); // predictable random sequence for -benchmark else srand((unsigned int)time(NULL)); // FIXME: this is evil, but possibly temporary // LordHavoc: doesn't seem very temporary... // LordHavoc: made this a saved cvar // COMMANDLINEOPTION: Console: -developer enables warnings and other notices (RECOMMENDED for mod developers) if (COM_CheckParm("-developer")) { developer.value = developer.integer = 1; developer.string = "1"; } if (COM_CheckParm("-developer2") || COM_CheckParm("-developer3")) { developer.value = developer.integer = 1; developer.string = "1"; developer_extra.value = developer_extra.integer = 1; developer_extra.string = "1"; developer_insane.value = developer_insane.integer = 1; developer_insane.string = "1"; developer_memory.value = developer_memory.integer = 1; developer_memory.string = "1"; developer_memorydebug.value = developer_memorydebug.integer = 1; developer_memorydebug.string = "1"; } if (COM_CheckParm("-developer3")) { gl_paranoid.integer = 1;gl_paranoid.string = "1"; gl_printcheckerror.integer = 1;gl_printcheckerror.string = "1"; } // COMMANDLINEOPTION: Console: -nostdout disables text output to the terminal the game was launched from if (COM_CheckParm("-nostdout")) sys_nostdout = 1; // used by everything Memory_Init(); // initialize console command/cvar/alias/command execution systems Cmd_Init(); // initialize memory subsystem cvars/commands Memory_Init_Commands(); // initialize console and logging and its cvars/commands Con_Init(); // initialize various cvars that could not be initialized earlier u8_Init(); Curl_Init_Commands(); Cmd_Init_Commands(); Sys_Init_Commands(); COM_Init_Commands(); FS_Init_Commands(); // initialize console window (only used by sys_win.c) Sys_InitConsole(); // initialize the self-pack (must be before COM_InitGameType as it may add command line options) FS_Init_SelfPack(); // detect gamemode from commandline options or executable name COM_InitGameType(); // construct a version string for the corner of the console os = DP_OS_NAME; dpsnprintf (engineversion, sizeof (engineversion), "%s %s %s", gamename, os, buildstring); Con_Printf("%s\n", engineversion); // initialize process nice level Sys_InitProcessNice(); // initialize ixtable Mathlib_Init(); // initialize filesystem (including fs_basedir, fs_gamedir, -game, scr_screenshot_name) FS_Init(); // register the cvars for session locking Host_InitSession(); // must be after FS_Init Crypto_Init(); Crypto_Init_Commands(); NetConn_Init(); Curl_Init(); //PR_Init(); //PR_Cmd_Init(); PRVM_Init(); Mod_Init(); World_Init(); SV_Init(); V_Init(); // some cvars needed by server player physics (cl_rollangle etc) Host_InitCommands(); Host_InitLocal(); Host_ServerOptions(); Thread_Init(); if (cls.state == ca_dedicated) Cmd_AddCommand ("disconnect", CL_Disconnect_f, "disconnect from server (or disconnect all clients if running a server)"); else { Con_DPrintf("Initializing client\n"); R_Modules_Init(); Palette_Init(); MR_Init_Commands(); VID_Shared_Init(); VID_Init(); Render_Init(); S_Init(); CDAudio_Init(); Key_Init(); CL_Init(); } // save off current state of aliases, commands and cvars for later restore if FS_GameDir_f is called // NOTE: menu commands are freed by Cmd_RestoreInitState Cmd_SaveInitState(); // FIXME: put this into some neat design, but the menu should be allowed to crash // without crashing the whole game, so this should just be a short-time solution // here comes the not so critical stuff if (setjmp(host_abortframe)) { return; } Host_AddConfigText(); Cbuf_Execute(); // if stuffcmds wasn't run, then quake.rc is probably missing, use default if (!host_stuffcmdsrun) { Cbuf_AddText("exec default.cfg\nexec " CONFIGFILENAME "\nexec autoexec.cfg\nstuffcmds\n"); Cbuf_Execute(); } // put up the loading image so the user doesn't stare at a black screen... SCR_BeginLoadingPlaque(true); if (cls.state != ca_dedicated) { MR_Init(); } // check for special benchmark mode // COMMANDLINEOPTION: Client: -benchmark <demoname> runs a timedemo and quits, results of any timedemo can be found in gamedir/benchmark.log (for example id1/benchmark.log) i = COM_CheckParm("-benchmark"); if (i && i + 1 < com_argc) if (!sv.active && !cls.demoplayback && !cls.connect_trying) { Cbuf_AddText(va(vabuf, sizeof(vabuf), "timedemo %s\n", com_argv[i + 1])); Cbuf_Execute(); } // check for special demo mode // COMMANDLINEOPTION: Client: -demo <demoname> runs a playdemo and quits i = COM_CheckParm("-demo"); if (i && i + 1 < com_argc) if (!sv.active && !cls.demoplayback && !cls.connect_trying) { Cbuf_AddText(va(vabuf, sizeof(vabuf), "playdemo %s\n", com_argv[i + 1])); Cbuf_Execute(); } // COMMANDLINEOPTION: Client: -capturedemo <demoname> captures a playdemo and quits i = COM_CheckParm("-capturedemo"); if (i && i + 1 < com_argc) if (!sv.active && !cls.demoplayback && !cls.connect_trying) { Cbuf_AddText(va(vabuf, sizeof(vabuf), "playdemo %s\ncl_capturevideo 1\n", com_argv[i + 1])); Cbuf_Execute(); } if (cls.state == ca_dedicated || COM_CheckParm("-listen")) if (!sv.active && !cls.demoplayback && !cls.connect_trying) { Cbuf_AddText("startmap_dm\n"); Cbuf_Execute(); } if (!sv.active && !cls.demoplayback && !cls.connect_trying) { Cbuf_AddText("togglemenu 1\n"); Cbuf_Execute(); } Con_DPrint("========Initialized=========\n"); //Host_StartVideo(); if (cls.state != ca_dedicated) SV_StartThread(); }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. This is only called from the SV_Map_f() function. ================ */ void SV_SpawnServer (char *mapname, qbool devmap, char* entityfile) { extern func_t ED_FindFunctionOffset (char *name); edict_t *ent; int i; extern cvar_t sv_loadentfiles, sv_loadentfiles_dir; char *entitystring; char oldmap[MAP_NAME_LEN]; extern qbool sv_allow_cheats; extern cvar_t sv_cheats, sv_paused, sv_bigcoords; #ifndef SERVERONLY extern void CL_ClearState (void); #endif // store old map name snprintf (oldmap, MAP_NAME_LEN, "%s", sv.mapname); Con_DPrintf ("SpawnServer: %s\n",mapname); #ifndef SERVERONLY // As client+server we do it here. // As serveronly we do it in NET_Init(). NET_InitServer(); #endif SV_SaveSpawnparms (); SV_LoadAccounts(); #ifdef USE_PR2 // remove bot clients for (i = 0; i < MAX_CLIENTS; i++) { if( sv_vm && svs.clients[i].isBot ) { svs.clients[i].old_frags = 0; svs.clients[i].edict->v.frags = 0.0; svs.clients[i].name[0] = 0; svs.clients[i].state = cs_free; Info_RemoveAll(&svs.clients[i]._userinfo_ctx_); Info_RemoveAll(&svs.clients[i]._userinfoshort_ctx_); SV_FullClientUpdate(&svs.clients[i], &sv.reliable_datagram); svs.clients[i].isBot = 0; } } #endif // Shutdown game. PR_GameShutDown(); PR_UnLoadProgs(); svs.spawncount++; // any partially connected client will be restarted #ifndef SERVERONLY com_serveractive = false; #endif sv.state = ss_dead; sv.paused = false; Cvar_SetROM(&sv_paused, "0"); Host_ClearMemory(); #ifdef FTE_PEXT_FLOATCOORDS if (sv_bigcoords.value) { msg_coordsize = 4; msg_anglesize = 2; } else { msg_coordsize = 2; msg_anglesize = 1; } #endif if ((int)coop.value) Cvar_Set (&deathmatch, "0"); current_skill = (int) (skill.value + 0.5); if (current_skill < 0) current_skill = 0; Cvar_Set (&skill, va("%d", current_skill)); if (current_skill > 3) current_skill = 3; if ((sv_cheats.value || devmap) && !sv_allow_cheats) { sv_allow_cheats = true; Info_SetValueForStarKey (svs.info, "*cheats", "ON", MAX_SERVERINFO_STRING); } else if ((!sv_cheats.value && !devmap) && sv_allow_cheats) { sv_allow_cheats = false; Info_SetValueForStarKey (svs.info, "*cheats", "", MAX_SERVERINFO_STRING); } // wipe the entire per-level structure // NOTE: this also set sv.mvdrecording to false, so calling SV_MVD_Record() at end of function memset (&sv, 0, sizeof(sv)); sv.datagram.maxsize = sizeof(sv.datagram_buf); sv.datagram.data = sv.datagram_buf; sv.datagram.allowoverflow = true; sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf); sv.reliable_datagram.data = sv.reliable_datagram_buf; sv.multicast.maxsize = sizeof(sv.multicast_buf); sv.multicast.data = sv.multicast_buf; sv.signon.maxsize = sizeof(sv.signon_buffers[0]); sv.signon.data = sv.signon_buffers[0]; sv.num_signon_buffers = 1; sv.time = 1.0; // load progs to get entity field count // which determines how big each edict is // and allocate edicts PR_LoadProgs (); #ifdef WITH_NQPROGS PR_InitPatchTables(); #endif PR_InitProg(); for (i = 0; i < MAX_EDICTS; i++) { ent = EDICT_NUM(i); ent->e = &sv.sv_edicts[i]; // assigning ->e field in each edict_t ent->e->entnum = i; ent->e->area.ed = ent; // yeah, pretty funny, but this help to find which edict_t own this area (link_t) } fofs_items2 = ED_FindFieldOffset ("items2"); // ZQ_ITEMS2 extension fofs_maxspeed = ED_FindFieldOffset ("maxspeed"); fofs_gravity = ED_FindFieldOffset ("gravity"); fofs_movement = ED_FindFieldOffset ("movement"); fofs_vw_index = ED_FindFieldOffset ("vw_index"); fofs_hideentity = ED_FindFieldOffset ("hideentity"); fofs_trackent = ED_FindFieldOffset ("trackent"); // find optional QC-exported functions. // we have it here, so we set it to NULL in case of PR2 progs. mod_SpectatorConnect = ED_FindFunctionOffset ("SpectatorConnect"); mod_SpectatorThink = ED_FindFunctionOffset ("SpectatorThink"); mod_SpectatorDisconnect = ED_FindFunctionOffset ("SpectatorDisconnect"); mod_ChatMessage = ED_FindFunctionOffset ("ChatMessage"); mod_UserInfo_Changed = ED_FindFunctionOffset ("UserInfo_Changed"); mod_ConsoleCmd = ED_FindFunctionOffset ("ConsoleCmd"); mod_UserCmd = ED_FindFunctionOffset ("UserCmd"); mod_localinfoChanged = ED_FindFunctionOffset ("localinfoChanged"); GE_ClientCommand = ED_FindFunctionOffset ("GE_ClientCommand"); GE_PausedTic = ED_FindFunctionOffset ("GE_PausedTic"); GE_ShouldPause = ED_FindFunctionOffset ("GE_ShouldPause"); // leave slots at start for clients only sv.num_edicts = MAX_CLIENTS+1; for (i=0 ; i<MAX_CLIENTS ; i++) { ent = EDICT_NUM(i+1); // restore client name. ent->v.netname = PR_SetString(svs.clients[i].name); // reserve edict. svs.clients[i].edict = ent; //ZOID - make sure we update frags right svs.clients[i].old_frags = 0; } // fill sv.mapname and sv.modelname with new map name strlcpy (sv.mapname, mapname, sizeof(sv.mapname)); snprintf (sv.modelname, sizeof(sv.modelname), "maps/%s.bsp", sv.mapname); #ifndef SERVERONLY // set cvar Cvar_ForceSet (&host_mapname, mapname); #endif if (!(sv.worldmodel = CM_LoadMap (sv.modelname, false, &sv.map_checksum, &sv.map_checksum2))) // true if bad map { Con_Printf ("Cant load map %s, falling back to %s\n", mapname, oldmap); // fill mapname, sv.mapname and sv.modelname with old map name strlcpy (sv.mapname, oldmap, sizeof(sv.mapname)); snprintf (sv.modelname, sizeof(sv.modelname), "maps/%s.bsp", sv.mapname); mapname = oldmap; // and re-load old map sv.worldmodel = CM_LoadMap (sv.modelname, false, &sv.map_checksum, &sv.map_checksum2); // this should never happen if (!sv.worldmodel) SV_Error ("CM_LoadMap: bad map"); } sv.map_checksum2 = Com_TranslateMapChecksum (sv.mapname, sv.map_checksum2); SV_ClearWorld (); // clear physics interaction links #ifdef USE_PR2 if ( sv_vm ) { sv.sound_precache[0] = ""; sv.model_precache[0] = ""; } else #endif { sv.sound_precache[0] = pr_strings; sv.model_precache[0] = pr_strings; } sv.model_precache[1] = sv.modelname; sv.models[1] = sv.worldmodel; for (i=1 ; i< CM_NumInlineModels() ; i++) { sv.model_precache[1+i] = localmodels[i]; sv.models[i+1] = CM_InlineModel (localmodels[i]); } //check player/eyes models for hacks sv.model_player_checksum = SV_CheckModel("progs/player.mdl"); sv.eyes_player_checksum = SV_CheckModel("progs/eyes.mdl"); // // spawn the rest of the entities on the map // // precache and static commands can be issued during // map initialization sv.state = ss_loading; #ifndef SERVERONLY com_serveractive = true; #endif ent = EDICT_NUM(0); ent->e->free = false; ent->v.model = PR_SetString(sv.modelname); ent->v.modelindex = 1; // world model ent->v.solid = SOLID_BSP; ent->v.movetype = MOVETYPE_PUSH; // information about the server ent->v.netname = PR_SetString(VersionStringFull()); ent->v.targetname = PR_SetString(SERVER_NAME); ent->v.impulse = VERSION_NUM; ent->v.items = pr_numbuiltins - 1; PR_GLOBAL(mapname) = PR_SetString(sv.mapname); // serverflags are for cross level information (sigils) PR_GLOBAL(serverflags) = svs.serverflags; if (pr_nqprogs) { pr_globals[35] = deathmatch.value; pr_globals[36] = coop.value; pr_globals[37] = teamplay.value; NQP_Reset (); } if (pr_nqprogs) { // register the cvars that NetQuake provides for mod use const char **var, *nqcvars[] = {"gamecfg", "scratch1", "scratch2", "scratch3", "scratch4", "saved1", "saved2", "saved3", "saved4", "savedgamecfg", "temp1", NULL }; for (var = nqcvars; *var; var++) Cvar_Create((char *)/*stupid const warning*/ *var, "0", 0); } // run the frame start qc function to let progs check cvars if (!pr_nqprogs) SV_ProgStartFrame (); // ********* External Entity support (.ent file(s) in gamedir/maps) pinched from ZQuake ********* // load and spawn all other entities entitystring = NULL; if ((int)sv_loadentfiles.value) { char ent_path[1024] = {0}; if (!entityfile || !entityfile[0]) entityfile = sv.mapname; // first try maps/sv_loadentfiles_dir/ if (sv_loadentfiles_dir.string[0]) { snprintf(ent_path, sizeof(ent_path), "maps/%s/%s.ent", sv_loadentfiles_dir.string, entityfile); entitystring = (char *) FS_LoadHunkFile(ent_path, NULL); } // try maps/ if not loaded yet. if (!entitystring) { snprintf(ent_path, sizeof(ent_path), "maps/%s.ent", entityfile); entitystring = (char *) FS_LoadHunkFile(ent_path, NULL); } if (entitystring) { Con_DPrintf ("Using entfile %s\n", ent_path); } } if (!entitystring) { entitystring = CM_EntityString(); } PR_LoadEnts(entitystring); // ********* End of External Entity support code ********* // look up some model indexes for specialized message compression SV_FindModelNumbers (); // all spawning is completed, any further precache statements // or prog writes to the signon message are errors sv.state = ss_active; // run two frames to allow everything to settle SV_Physics (); sv.time += 0.1; SV_Physics (); sv.time += 0.1; sv.old_time = sv.time; // save movement vars SV_SetMoveVars(); // create a baseline for more efficient communications SV_CreateBaseline (); sv.signon_buffer_size[sv.num_signon_buffers-1] = sv.signon.cursize; Info_SetValueForKey (svs.info, "map", sv.mapname, MAX_SERVERINFO_STRING); // calltimeofday. { extern void PF_calltimeofday (void); pr_global_struct->time = sv.time; pr_global_struct->self = 0; PF_calltimeofday(); } Con_DPrintf ("Server spawned.\n"); // we change map - clear whole demo struct and sent initial state to all dest if any (for QTV only I thought) SV_MVD_Record(NULL, true); #ifndef SERVERONLY CL_ClearState (); #endif }
void VID_Finish (void) { qboolean vid_usevsync; // handle changes of the vsync option vid_usevsync = (vid_vsync.integer && !cls.timedemo); if (vid_usingvsync != vid_usevsync) { GLint sync = (vid_usevsync ? 1 : 0); if (qaglSetInteger(context, AGL_SWAP_INTERVAL, &sync) == GL_TRUE) { vid_usingvsync = vid_usevsync; Con_DPrintf("Vsync %s\n", vid_usevsync ? "activated" : "deactivated"); } else Con_Printf("ERROR: can't %s vsync\n", vid_usevsync ? "activate" : "deactivate"); } if (!vid_hidden) { if (r_speeds.integer == 2 || gl_finish.integer) GL_Finish(); qaglSwapBuffers(context); } VID_UpdateGamma(false, GAMMA_TABLE_SIZE); if (apple_multithreadedgl.integer) { if (!multithreadedgl) { if(qCGLGetCurrentContext && qCGLEnable && qCGLDisable) { CGLContextObj ctx = qCGLGetCurrentContext(); CGLError e = qCGLEnable(ctx, kCGLCEMPEngine); if(e == kCGLNoError) multithreadedgl = true; else { Con_Printf("WARNING: can't enable multithreaded GL, error %d\n", (int) e); Cvar_SetValueQuick(&apple_multithreadedgl, 0); } } else { Con_Printf("WARNING: can't enable multithreaded GL, CGL functions not present\n"); Cvar_SetValueQuick(&apple_multithreadedgl, 0); } } } else { if (multithreadedgl) { if(qCGLGetCurrentContext && qCGLEnable && qCGLDisable) { CGLContextObj ctx = qCGLGetCurrentContext(); qCGLDisable(ctx, kCGLCEMPEngine); multithreadedgl = false; } } } }