/* =============== IN_InitJoystick =============== */ static void IN_InitJoystick( void ) { int i = 0; int total = 0; char buf[16384] = ""; if (stick != NULL) SDL_JoystickClose(stick); stick = NULL; memset(&stick_state, '\0', sizeof (stick_state)); if (!SDL_WasInit(SDL_INIT_JOYSTICK)) { Com_DPrintf("Calling SDL_Init(SDL_INIT_JOYSTICK)...\n"); if (SDL_Init(SDL_INIT_JOYSTICK) == -1) { Com_DPrintf("SDL_Init(SDL_INIT_JOYSTICK) failed: %s\n", SDL_GetError()); return; } Com_DPrintf("SDL_Init(SDL_INIT_JOYSTICK) passed.\n"); } total = SDL_NumJoysticks(); Com_DPrintf("%d possible joysticks\n", total); // Print list and build cvar to allow ui to select joystick. for (i = 0; i < total; i++) { Q_strcat(buf, sizeof(buf), SDL_JoystickNameForIndex(i)); Q_strcat(buf, sizeof(buf), "\n"); } Cvar_Get( "in_availableJoysticks", buf, CVAR_ROM ); if( !in_joystick->integer ) { Com_DPrintf( "Joystick is not active.\n" ); SDL_QuitSubSystem(SDL_INIT_JOYSTICK); return; } in_joystickNo = Cvar_Get( "in_joystickNo", "0", CVAR_ARCHIVE | CVAR_GLOBAL); if( in_joystickNo->integer < 0 || in_joystickNo->integer >= total ) Cvar_Set( "in_joystickNo", "0" ); in_joystickUseAnalog = Cvar_Get( "in_joystickUseAnalog", "0", CVAR_ARCHIVE | CVAR_GLOBAL); stick = SDL_JoystickOpen( in_joystickNo->integer ); if (stick == NULL) { Com_DPrintf( "No joystick opened.\n" ); return; } Com_DPrintf( "Joystick %d opened\n", in_joystickNo->integer ); Com_DPrintf( "Name: %s\n", SDL_JoystickNameForIndex(in_joystickNo->integer) ); Com_DPrintf( "Axes: %d\n", SDL_JoystickNumAxes(stick) ); Com_DPrintf( "Hats: %d\n", SDL_JoystickNumHats(stick) ); Com_DPrintf( "Buttons: %d\n", SDL_JoystickNumButtons(stick) ); Com_DPrintf( "Balls: %d\n", SDL_JoystickNumBalls(stick) ); Com_DPrintf( "Use Analog: %s\n", in_joystickUseAnalog->integer ? "Yes" : "No" ); SDL_JoystickEventState(SDL_QUERY); }
/* ==================== NET_IP6Socket ==================== */ int NET_IP6Socket(char *net_interface, int port, struct sockaddr_in6 *bindto, int *err) { SOCKET newsocket; struct sockaddr_in6 address; u_long _true = 1; *err = 0; if (net_interface) { // Print the name in brackets if there is a colon: if (Q_CountChar(net_interface, ':')) { Com_Printf("Opening IP6 socket: [%s]:%i\n", net_interface, port); } else { Com_Printf("Opening IP6 socket: %s:%i\n", net_interface, port); } } else { Com_Printf("Opening IP6 socket: [::]:%i\n", port); } if ((newsocket = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { *err = socketError; Com_Printf("WARNING: NET_IP6Socket: socket: %s\n", NET_ErrorString()); return newsocket; } // make it non-blocking if (ioctlsocket(newsocket, FIONBIO, &_true) == SOCKET_ERROR) { Com_Printf("WARNING: NET_IP6Socket: ioctl FIONBIO: %s\n", NET_ErrorString()); *err = socketError; closesocket(newsocket); return INVALID_SOCKET; } #ifdef IPV6_V6ONLY { int i = 1; // ipv4 addresses should not be allowed to connect via this socket. if (setsockopt(newsocket, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &i, sizeof(i)) == SOCKET_ERROR) { // win32 systems don't seem to support this anyways. Com_DPrintf("WARNING: NET_IP6Socket: setsockopt IPV6_V6ONLY: %s\n", NET_ErrorString()); } } #endif if (!net_interface || !net_interface[0]) { address.sin6_family = AF_INET6; address.sin6_addr = in6addr_any; } else { if (!Sys_StringToSockaddr(net_interface, (struct sockaddr *)&address, sizeof(address), AF_INET6)) { closesocket(newsocket); return INVALID_SOCKET; } } if (port == PORT_ANY) { address.sin6_port = 0; } else { address.sin6_port = htons((short)port); } if (bind(newsocket, (void *)&address, sizeof(address)) == SOCKET_ERROR) { Com_Printf("WARNING: NET_IP6Socket: bind: %s\n", NET_ErrorString()); *err = socketError; closesocket(newsocket); return INVALID_SOCKET; } if (bindto) { *bindto = address; } return newsocket; }
/* =============== SV_AddEntitiesVisibleFromPoint =============== */ static void SV_AddEntitiesVisibleFromPoint( int psIndex, int playerNum, vec3_t origin, clientSnapshot_t *frame, snapshotEntityNumbers_t *eNums, qboolean portal ) { int e, i; sharedEntity_t *ent; svEntity_t *svEnt; int l; int clientarea, clientcluster; int leafnum; byte *clientpvs; byte *bitvector; // during an error shutdown message we may need to transmit // the shutdown message after the server has shutdown, so // specfically check for it if ( !sv.state ) { return; } leafnum = CM_PointLeafnum (origin); clientarea = CM_LeafArea (leafnum); clientcluster = CM_LeafCluster (leafnum); // calculate the visible areas frame->areabytes[psIndex] = CM_WriteAreaBits( frame->areabits[psIndex], clientarea ); clientpvs = CM_ClusterPVS (clientcluster); for ( e = 0 ; e < sv.num_entities ; e++ ) { ent = SV_GentityNum(e); // never send entities that aren't linked in if ( !ent->r.linked ) { continue; } if (ent->s.number != e) { Com_DPrintf ("FIXING ENT->S.NUMBER!!!\n"); ent->s.number = e; } // entities can be flagged to explicitly not be sent to the client if ( ent->r.svFlags & SVF_NOCLIENT ) { continue; } // entities can be flagged to be sent to a given mask of clients if ( ent->r.svFlags & SVF_PLAYERMASK ) { if ( !Com_ClientListContains( &ent->r.sendPlayers, playerNum ) ) continue; } svEnt = SV_SvEntityForGentity( ent ); // don't double add an entity through portals if ( svEnt->snapshotCounter == sv.snapshotCounter ) { continue; } // limit based on distance if ( ent->r.cullDistance ) { vec3_t dir; VectorSubtract(ent->s.origin, origin, dir); if ( VectorLengthSquared(dir) > (float) ent->r.cullDistance * ent->r.cullDistance ) { continue; } } // broadcast entities are always sent if ( ent->r.svFlags & SVF_BROADCAST ) { SV_AddEntToSnapshot( frame, svEnt, ent, eNums ); continue; } // ignore if not touching a PV leaf // check area if ( !CM_AreasConnected( clientarea, svEnt->areanum ) ) { // doors can legally straddle two areas, so // we may need to check another one if ( !CM_AreasConnected( clientarea, svEnt->areanum2 ) ) { continue; // blocked by a door } } bitvector = clientpvs; // check individual leafs if ( !svEnt->numClusters ) { continue; } l = 0; for ( i=0 ; i < svEnt->numClusters ; i++ ) { l = svEnt->clusternums[i]; if ( bitvector[l >> 3] & (1 << (l&7) ) ) { break; } } // if we haven't found it to be visible, // check overflow clusters that coudln't be stored if ( i == svEnt->numClusters ) { if ( svEnt->lastCluster ) { for ( ; l <= svEnt->lastCluster ; l++ ) { if ( bitvector[l >> 3] & (1 << (l&7) ) ) { break; } } if ( l == svEnt->lastCluster ) { continue; // not visible } } else { continue; } } // visibility dummies if ( ent->r.svFlags & SVF_VISDUMMY ) { sharedEntity_t *ment = NULL; // find master ment = SV_GentityNum( ent->r.visDummyNum ); if ( ment ) { svEntity_t *master = NULL; master = SV_SvEntityForGentity( ment ); if ( master->snapshotCounter == sv.snapshotCounter || !ment->r.linked ) { continue; } SV_AddEntToSnapshot( frame, master, ment, eNums ); } // master needs to be added, but not this dummy ent continue; } else if ( ent->r.svFlags & SVF_VISDUMMY_MULTIPLE ) { int h; sharedEntity_t *ment = NULL; svEntity_t *master = NULL; for ( h = 0; h < sv.num_entities; h++ ) { ment = SV_GentityNum( h ); if ( ment == ent ) { continue; } if ( ment ) { master = SV_SvEntityForGentity( ment ); } else { continue; } if ( !ment->r.linked ) { continue; } if ( ment->s.number != h ) { Com_DPrintf( "FIXING vis dummy multiple ment->S.NUMBER!!!\n" ); ment->s.number = h; } if ( ment->r.svFlags & SVF_NOCLIENT ) { continue; } if ( master->snapshotCounter == sv.snapshotCounter ) { continue; } if ( ment->r.visDummyNum == ent->s.number ) { SV_AddEntToSnapshot( frame, master, ment, eNums ); } } // masters need to be added, but not this dummy ent continue; } // add it SV_AddEntToSnapshot( frame, svEnt, ent, eNums ); // if it's a portal entity, add everything visible from its camera position if ( ent->r.svFlags & SVF_PORTAL ) { if ( ent->r.portalCullDistance ) { vec3_t dir; VectorSubtract(ent->s.origin, origin, dir); if ( VectorLengthSquared(dir) > (float) ent->r.portalCullDistance * ent->r.portalCullDistance ) { continue; } } SV_AddEntitiesVisibleFromPoint( psIndex, playerNum, ent->s.origin2, frame, eNums, qtrue ); } }
/* =============== Cmd_Exec_f =============== */ void Cmd_Exec_f (void) { const char *path; char *f, *p; int len; char f2[COMMAND_BUFFER_SIZE+2]; if (Cmd_Argc () != 2) { Com_Printf ("exec <filename> : execute a config file\n", LOG_GENERAL); return; } path = Cmd_Argv(1); //r1: normalize while ((p = strchr (path, '\\'))) p[0] = '/'; //r1: deny traversing outside the q2 directory p = strstr (path, "../"); if (p) { p += 3; if (strstr (p, "../")) { Com_Printf ("WARNING: Illegal config path '%s'\n", LOG_GENERAL, path); return; } } //r1: sanity check length first so people don't exec pak0.pak and eat 300MB ram len = FS_LoadFile (path, NULL); if (len > COMMAND_BUFFER_SIZE - 2) { Com_Printf ("WARNING: %s exceeds maximum config file length\n", LOG_GENERAL, Cmd_Argv(1)); len = COMMAND_BUFFER_SIZE - 2; } len = FS_LoadFile (path, (void **)&f); if (!f || len <= 0) { //ugly hack to avoid printing missing config errors before startup finishes if (q2_initialized) Com_Printf ("couldn't exec %s\n", LOG_GENERAL, path); return; } #ifndef DEDICATED_ONLY if (Com_ServerState()) #endif Com_Printf ("execing %s\n", LOG_GENERAL, path); #ifndef DEDICATED_ONLY else Com_DPrintf ("execing %s\n",path); #endif // the file doesn't have a trailing 0, so we need to copy it off //f2 = Z_TagMalloc(len+2, TAGMALLOC_CMDBUFF); //f2 = alloca (len+2); memcpy (f2, f, len); //r1: fix for "no trailing newline = 'u or s'" bug. f2[len] = '\n'; f2[len+1] = 0; if ((p = strchr(f2, '\r')) && *(p+1) != '\n') Com_Printf ("WARNING: Raw \\r found in config file %s\n", LOG_GENERAL|LOG_WARNING, path); Cbuf_InsertText (f2); //Z_Free (f2); FS_FreeFile (f); }
static void SV_AddEntitiesVisibleFromPoint(vec3_t origin, clientSnapshot_t *frame, snapshotEntityNumbers_t *eNums) #endif { int e, i; sharedEntity_t *ent, *playerEnt, *ment; #ifdef FEATURE_ANTICHEAT sharedEntity_t *client; #endif svEntity_t *svEnt; int l; int clientarea, clientcluster; int leafnum; byte *clientpvs; byte *bitvector; // during an error shutdown message we may need to transmit // the shutdown message after the server has shutdown, so // specfically check for it if (!sv.state) { return; } leafnum = CM_PointLeafnum(origin); clientarea = CM_LeafArea(leafnum); clientcluster = CM_LeafCluster(leafnum); // calculate the visible areas frame->areabytes = CM_WriteAreaBits(frame->areabits, clientarea); clientpvs = CM_ClusterPVS(clientcluster); playerEnt = SV_GentityNum(frame->ps.clientNum); if (playerEnt->r.svFlags & SVF_SELF_PORTAL) { #ifdef FEATURE_ANTICHEAT SV_AddEntitiesVisibleFromPoint(playerEnt->s.origin2, frame, eNums, qtrue); // portal qtrue?! #else SV_AddEntitiesVisibleFromPoint(playerEnt->s.origin2, frame, eNums); #endif } for (e = 0 ; e < sv.num_entities ; e++) { ent = SV_GentityNum(e); // never send entities that aren't linked in if (!ent->r.linked) { continue; } if (ent->s.number != e) { Com_DPrintf("FIXING ENT->S.NUMBER!!!\n"); ent->s.number = e; } // entities can be flagged to explicitly not be sent to the client if (ent->r.svFlags & SVF_NOCLIENT) { continue; } // entities can be flagged to be sent to only one client if (ent->r.svFlags & SVF_SINGLECLIENT) { if (ent->r.singleClient != frame->ps.clientNum) { continue; } } // entities can be flagged to be sent to everyone but one client if (ent->r.svFlags & SVF_NOTSINGLECLIENT) { if (ent->r.singleClient == frame->ps.clientNum) { continue; } } svEnt = SV_SvEntityForGentity(ent); // don't double add an entity through portals if (svEnt->snapshotCounter == sv.snapshotCounter) { continue; } // broadcast entities are always sent if (ent->r.svFlags & SVF_BROADCAST) { SV_AddEntToSnapshot(playerEnt, svEnt, ent, eNums); continue; } bitvector = clientpvs; // just check origin for being in pvs, ignore bmodel extents if (ent->r.svFlags & SVF_IGNOREBMODELEXTENTS) { if (bitvector[svEnt->originCluster >> 3] & (1 << (svEnt->originCluster & 7))) { SV_AddEntToSnapshot(playerEnt, svEnt, ent, eNums); } continue; } // ignore if not touching a PV leaf // check area if (!CM_AreasConnected(clientarea, svEnt->areanum)) { // doors can legally straddle two areas, so // we may need to check another one if (!CM_AreasConnected(clientarea, svEnt->areanum2)) { continue; } } // check individual leafs if (!svEnt->numClusters) { continue; } l = 0; for (i = 0 ; i < svEnt->numClusters ; i++) { l = svEnt->clusternums[i]; if (bitvector[l >> 3] & (1 << (l & 7))) { break; } } // if we haven't found it to be visible, // check overflow clusters that coudln't be stored if (i == svEnt->numClusters) { if (svEnt->lastCluster) { for ( ; l <= svEnt->lastCluster ; l++) { if (bitvector[l >> 3] & (1 << (l & 7))) { break; } } if (l == svEnt->lastCluster) { continue; // not visible } } else { continue; } } // added "visibility dummies" if (ent->r.svFlags & SVF_VISDUMMY) { // find master; ment = SV_GentityNum(ent->s.otherEntityNum); if (ment) { svEntity_t *master = 0; master = SV_SvEntityForGentity(ment); if (master->snapshotCounter == sv.snapshotCounter || !ment->r.linked) { continue; } SV_AddEntToSnapshot(playerEnt, master, ment, eNums); } continue; // master needs to be added, but not this dummy ent } else if (ent->r.svFlags & SVF_VISDUMMY_MULTIPLE) { int h; sharedEntity_t *ment = 0; svEntity_t *master = 0; for (h = 0; h < sv.num_entities; h++) { ment = SV_GentityNum(h); if (ment == ent) { continue; } if (ment) { master = SV_SvEntityForGentity(ment); } else { continue; } if (!(ment->r.linked)) { continue; } if (ment->s.number != h) { Com_DPrintf("FIXING vis dummy multiple ment->S.NUMBER!!!\n"); ment->s.number = h; } if (ment->r.svFlags & SVF_NOCLIENT) { continue; } if (master->snapshotCounter == sv.snapshotCounter) { continue; } if (ment->s.otherEntityNum == ent->s.number) { SV_AddEntToSnapshot(playerEnt, master, ment, eNums); } } continue; } #ifdef FEATURE_ANTICHEAT if (sv_wh_active->integer > 0 && e < sv_maxclients->integer) // client { // note: !r.linked is already exclused - see above if (e == frame->ps.clientNum) { continue; } client = SV_GentityNum(frame->ps.clientNum); // exclude bots and free flying specs if (!portal && !(client->r.svFlags & SVF_BOT) && (frame->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR) && !(frame->ps.pm_flags & PMF_FOLLOW)) { if (!SV_CanSee(frame->ps.clientNum, e)) { SV_RandomizePos(frame->ps.clientNum, e); SV_AddEntToSnapshot(client, svEnt, ent, eNums); continue; } } } #endif // add it SV_AddEntToSnapshot(playerEnt, svEnt, ent, eNums); // if its a portal entity, add everything visible from its camera position if (ent->r.svFlags & SVF_PORTAL) { #ifdef FEATURE_ANTICHEAT SV_AddEntitiesVisibleFromPoint(ent->s.origin2, frame, eNums, qtrue /*localClient*/); #else SV_AddEntitiesVisibleFromPoint(ent->s.origin2, frame, eNums /*, qtrue, localClient*/); #endif } continue; }
/** * @brief Opens/closes a door * @note Use function for func_door * @todo Check if the door can be opened or closed - there should not be * anything in the way (e.g. an actor) */ static bool Door_Use (edict_t *door, edict_t *activator) { int opening = 1; if (door->doorState == STATE_CLOSED) { door->doorState = STATE_OPENED; opening = 1; } else if (door->doorState == STATE_OPENED) { door->doorState = STATE_CLOSED; opening = -1; } else return false; /* remember the old location */ AABB oldAABB; gi.GetInlineModelAABB(door->model, oldAABB); GridBox rerouteOldBox(oldAABB); /* change rotation and relink */ if (door->type == ET_DOOR) { if (door->dir & DOOR_OPEN_REVERSE) opening *= -1; door->angles[door->dir & 3] += DOOR_ROTATION_ANGLE * opening; } else if (door->type == ET_DOOR_SLIDING) { Door_SlidingUse(door); } gi.LinkEdict(door); /* maybe the server called this because the door starts opened */ if (G_MatchIsRunning()) { /* let everybody know, that the door moves */ if (door->doorState == STATE_OPENED) G_EventDoorOpen(door); else G_EventDoorClose(door); if (door->noise[0] != '\0') { const playermask_t playerMask = G_GetClosePlayerMask(door->origin, UNIT_SIZE * 10); G_EventSpawnSound(playerMask, false, door, door->origin, door->noise); } } /* Update model orientation */ gi.SetInlineModelOrientation(door->model, door->origin, door->angles); AABB newAabb; gi.GetInlineModelAABB(door->model, newAabb); GridBox rerouteNewBox(newAabb); Com_DPrintf(DEBUG_GAME, "Server processed door movement.\n"); /* Update path finding table for the new location of the model */ G_RecalcRouting(door->model, rerouteOldBox); /* Update path finding table */ G_RecalcRouting(door->model, rerouteNewBox); if (activator && G_IsLivingActor(activator)) { /* Check if the player appears/perishes, seen from other teams. */ G_CheckVis(activator); /* Calc new vis for the activator. */ G_CheckVisTeamAll(activator->team, 0, activator); } return true; }
/* ================ CL_ParseSnapshot If the snapshot is parsed properly, it will be copied to cl.snap and saved in cl.snapshots[]. If the snapshot is invalid for any reason, no changes to the state will be made at all. ================ */ void CL_ParseSnapshot( msg_t *msg ) { int len; clSnapshot_t *old; clSnapshot_t newSnap; int deltaNum; int oldMessageNum; int i, packetNum; // get the reliable sequence acknowledge number // NOTE: now sent with all server to client messages //clc.reliableAcknowledge = MSG_ReadLong( msg ); // read in the new snapshot to a temporary buffer // we will only copy to cl.snap if it is valid Com_Memset (&newSnap, 0, sizeof(newSnap)); // we will have read any new server commands in this // message before we got to svc_snapshot newSnap.serverCommandNum = clc.serverCommandSequence; newSnap.serverTime = MSG_ReadLong( msg ); // if we were just unpaused, we can only *now* really let the // change come into effect or the client hangs. cl_paused->modified = qfalse; newSnap.messageNum = clc.serverMessageSequence; deltaNum = MSG_ReadByte( msg ); if ( !deltaNum ) { newSnap.deltaNum = -1; } else { newSnap.deltaNum = newSnap.messageNum - deltaNum; } newSnap.snapFlags = MSG_ReadByte( msg ); // If the frame is delta compressed from data that we // no longer have available, we must suck up the rest of // the frame, but not use it, then ask for a non-compressed // message if ( newSnap.deltaNum <= 0 ) { newSnap.valid = qtrue; // uncompressed frame old = NULL; clc.demowaiting = qfalse; // we can start recording now } else { old = &cl.snapshots[newSnap.deltaNum & PACKET_MASK]; if ( !old->valid ) { // should never happen Com_Printf ("Delta from invalid frame (not supposed to happen!).\n"); while ( ( newSnap.deltaNum & PACKET_MASK ) != ( newSnap.messageNum & PACKET_MASK ) && !old->valid ) { newSnap.deltaNum++; old = &cl.snapshots[newSnap.deltaNum & PACKET_MASK]; } if ( old->valid ) { Com_Printf ("Found more recent frame to delta from.\n"); } } if ( !old->valid ) { Com_Printf ("Failed to find more recent frame to delta from.\n"); } else if ( old->messageNum != newSnap.deltaNum ) { // The frame that the server did the delta from // is too old, so we can't reconstruct it properly. Com_Printf ("Delta frame too old.\n"); } else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES-128 ) { Com_DPrintf ("Delta parseEntitiesNum too old.\n"); } else { newSnap.valid = qtrue; // valid delta parse } } // read areamask len = MSG_ReadByte( msg ); if((unsigned)len > sizeof(newSnap.areamask)) { Com_Error (ERR_DROP,"CL_ParseSnapshot: Invalid size %d for areamask", len); return; } MSG_ReadData( msg, &newSnap.areamask, len); // read playerinfo SHOWNET( msg, "playerstate" ); if ( old ) { MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps ); if (newSnap.ps.m_iVehicleNum) { //this means we must have written our vehicle's ps too MSG_ReadDeltaPlayerstate( msg, &old->vps, &newSnap.vps, qtrue ); } } else { MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps ); if (newSnap.ps.m_iVehicleNum) { //this means we must have written our vehicle's ps too MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.vps, qtrue ); } } // read packet entities SHOWNET( msg, "packet entities" ); CL_ParsePacketEntities( msg, old, &newSnap ); // if not valid, dump the entire thing now that it has // been properly read if ( !newSnap.valid ) { return; } // clear the valid flags of any snapshots between the last // received and this one, so if there was a dropped packet // it won't look like something valid to delta from next // time we wrap around in the buffer oldMessageNum = cl.snap.messageNum + 1; if ( newSnap.messageNum - oldMessageNum >= PACKET_BACKUP ) { oldMessageNum = newSnap.messageNum - ( PACKET_BACKUP - 1 ); } for ( ; oldMessageNum < newSnap.messageNum ; oldMessageNum++ ) { cl.snapshots[oldMessageNum & PACKET_MASK].valid = qfalse; } // copy to the current good spot cl.snap = newSnap; cl.snap.ping = 999; // calculate ping time for ( i = 0 ; i < PACKET_BACKUP ; i++ ) { packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK; if ( cl.snap.ps.commandTime >= cl.outPackets[ packetNum ].p_serverTime ) { cl.snap.ping = cls.realtime - cl.outPackets[ packetNum ].p_realtime; break; } } // save the frame off in the backup array for later delta comparisons cl.snapshots[cl.snap.messageNum & PACKET_MASK] = cl.snap; if (cl_shownet->integer == 3) { Com_Printf( " snapshot:%i delta:%i ping:%i\n", cl.snap.messageNum, cl.snap.deltaNum, cl.snap.ping ); } cl.newSnapshots = qtrue; }
/** * \brief Called by the system between frames for both key up and key down events. * \param[in] key Key mapping * \param[in] down Is key being pressed? * \param[in] time * \note Should NOT be called during an interrupt! */ PUBLIC void Key_Event( int key, _boolean down, unsigned time ) { char *kb; char cmd[ 1024 ]; // hack for modal presses if (key_waiting == -1) { if (down) { key_waiting = key; } return; } // update auto-repeat status if (down) { key_repeats[key]++; if (key != K_BACKSPACE && key != K_PAUSE && key != K_PGUP && key != K_KP_PGUP && key != K_PGDN && key != K_KP_PGDN && key_repeats[key] > 1) { return; // ignore most autorepeats } if (key >= 200 && !keybindings[key]) { Com_Printf ( "%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) ); } } else { key_repeats[ key ] = 0; } if( key == K_SHIFT ) { shift_down = down; } // console key is hardcoded, so the user can never unbind it if( key == '`' || key == '~' ) { if( ! down ) { return; } Con_ToggleConsole_f(); return; } // any key during the attract mode will bring up the menu // if (cl.attractloop && ClientStatic.key_dest != key_menu && // !(key >= K_F1 && key <= K_F12)) // key = K_ESCAPE; // menu key is hardcoded, so the user can never unbind it if( key == K_ESCAPE ) { if( ! down ) { return; } // if (cl.frame.playerstate.stats[STAT_LAYOUTS] && ClientStatic.key_dest == key_game) // { // put away help computer / inventory // Cbuf_AddText ("cmd putaway\n"); // return; // } switch( ClientStatic.key_dest ) { case key_message: Key_Message( key ); break; case KEY_AUTOMAP: automap_keydown( key ); break; case key_menu: M_Keydown( key ); break; case key_game: case key_console: M_Menu_Main_f(); break; default: Com_DPrintf( "Bad ClientStatic.key_dest\n" ); } return; } // track if any key is down for BUTTON_ANY keydown[key] = down; if (down) { if (key_repeats[key] == 1) { anykeydown++; } } else { anykeydown--; if (anykeydown < 0) { anykeydown = 0; } } // // key up events only generate commands if the game key binding is // a button command (leading + sign). These will occur even in console mode, // to keep the character from continuing an action started before a console // switch. Button commands include the kenum as a parameter, so multiple // downs can be matched with ups // if( ! down ) { kb = keybindings[key]; if (kb && kb[0] == '+') { com_snprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time); Cbuf_AddText (cmd); } if (keyshift[key] != key) { kb = keybindings[keyshift[key]]; if (kb && kb[0] == '+') { com_snprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time); Cbuf_AddText (cmd); } } return; } // // if not a consolekey, send to the interpreter no matter what mode is // if ( (ClientStatic.key_dest == key_menu && menubound[key]) || (ClientStatic.key_dest == key_console && !consolekeys[key]) || (ClientStatic.key_dest == key_game ) ) { kb = keybindings[key]; if (kb) { if (kb[0] == '+') { // button commands add keynum and time as a parm com_snprintf (cmd, sizeof(cmd), "%s %i %i\n", kb, key, time); Cbuf_AddText (cmd); } else { Cbuf_AddText (kb); Cbuf_AddText ("\n"); } } return; } if( ! down ) { return; // other systems only care about key down events } if (shift_down) { key = keyshift[ key ]; } switch (ClientStatic.key_dest) { case KEY_AUTOMAP: automap_keydown( key ); break; case key_message: Key_Message (key); break; case key_menu: M_Keydown (key); break; case key_game: case key_console: Key_Console (key); break; default: Com_DPrintf( "Bad ClientStatic.key_dest\n" ); } }
/* =================== CL_WritePacket Create and send the command packet to the server Including both the reliable commands and the usercmds During normal gameplay, a client packet will contain something like: 4 sequence number 2 qport 4 serverid 4 acknowledged sequence number 4 clc.serverCommandSequence <optional reliable commands> 1 clc_move or clc_moveNoDelta 1 command count <count * usercmds> =================== */ void CL_WritePacket( void ) { msg_t buf; byte data[MAX_MSGLEN]; int i, j; usercmd_t *cmd, *oldcmd; usercmd_t nullcmd; int packetNum; int oldPacketNum; int count, key; // don't send anything if playing back a demo if ( clc.demoplaying || cls.state == CA_CINEMATIC ) { return; } Com_Memset( &nullcmd, 0, sizeof(nullcmd) ); oldcmd = &nullcmd; MSG_Init( &buf, data, sizeof(data) ); MSG_Bitstream( &buf ); // write the current serverId so the server // can tell if this is from the current gameState MSG_WriteLong( &buf, cl.serverId ); // write the last message we received, which can // be used for delta compression, and is also used // to tell if we dropped a gamestate MSG_WriteLong( &buf, clc.serverMessageSequence ); // write the last reliable message we received MSG_WriteLong( &buf, clc.serverCommandSequence ); // write any unacknowledged clientCommands for ( i = clc.reliableAcknowledge + 1 ; i <= clc.reliableSequence ; i++ ) { MSG_WriteByte( &buf, clc_clientCommand ); MSG_WriteLong( &buf, i ); MSG_WriteString( &buf, clc.reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] ); } // we want to send all the usercmds that were generated in the last // few packet, so even if a couple packets are dropped in a row, // all the cmds will make it to the server if ( cl_packetdup->integer < 0 ) { Cvar_Set( "cl_packetdup", "0" ); } else if ( cl_packetdup->integer > 5 ) { Cvar_Set( "cl_packetdup", "5" ); } oldPacketNum = (clc.netchan.outgoingSequence - 1 - cl_packetdup->integer) & PACKET_MASK; count = cl.cmdNumber - cl.outPackets[ oldPacketNum ].p_cmdNumber; if ( count > MAX_PACKET_USERCMDS ) { count = MAX_PACKET_USERCMDS; Com_Printf("MAX_PACKET_USERCMDS\n"); } #ifdef USE_VOIP if (clc.voipOutgoingDataSize > 0) { // only send if data. MSG_WriteByte (&buf, clc_EOF); // placate legacy servers. MSG_WriteByte (&buf, clc_extension); MSG_WriteByte (&buf, clc_voip); MSG_WriteByte (&buf, clc.voipOutgoingGeneration); MSG_WriteLong (&buf, clc.voipOutgoingSequence); MSG_WriteByte (&buf, clc.voipOutgoingDataFrames); MSG_WriteLong (&buf, clc.voipTarget1); MSG_WriteLong (&buf, clc.voipTarget2); MSG_WriteLong (&buf, clc.voipTarget3); MSG_WriteShort (&buf, clc.voipOutgoingDataSize); MSG_WriteData (&buf, clc.voipOutgoingData, clc.voipOutgoingDataSize); // If we're recording a demo, we have to fake a server packet with // this VoIP data so it gets to disk; the server doesn't send it // back to us, and we might as well eliminate concerns about dropped // and misordered packets here. if ( clc.demorecording && !clc.demowaiting ) { const int voipSize = clc.voipOutgoingDataSize; msg_t fakemsg; byte fakedata[MAX_MSGLEN]; MSG_Init (&fakemsg, fakedata, sizeof (fakedata)); MSG_Bitstream (&fakemsg); MSG_WriteLong (&fakemsg, clc.reliableAcknowledge); MSG_WriteByte (&fakemsg, svc_EOF); MSG_WriteByte (&fakemsg, svc_extension); MSG_WriteByte (&fakemsg, svc_voip); MSG_WriteShort (&fakemsg, clc.clientNum); MSG_WriteByte (&fakemsg, clc.voipOutgoingGeneration); MSG_WriteLong (&fakemsg, clc.voipOutgoingSequence); MSG_WriteByte (&fakemsg, clc.voipOutgoingDataFrames); MSG_WriteShort (&fakemsg, clc.voipOutgoingDataSize ); MSG_WriteData (&fakemsg, clc.voipOutgoingData, voipSize); MSG_WriteByte (&fakemsg, svc_EOF); CL_WriteDemoMessage (&fakemsg, 0); } clc.voipOutgoingSequence += clc.voipOutgoingDataFrames; clc.voipOutgoingDataSize = 0; clc.voipOutgoingDataFrames = 0; } else #endif if ( count >= 1 ) { if ( cl_showSend->integer ) { Com_Printf( "(%i)", count ); } // begin a client move command if ( cl_nodelta->integer || !cl.snap.valid || clc.demowaiting || clc.serverMessageSequence != cl.snap.messageNum ) { MSG_WriteByte (&buf, clc_moveNoDelta); } else { MSG_WriteByte (&buf, clc_move); } // write the command count MSG_WriteByte( &buf, count ); // use the checksum feed in the key key = clc.checksumFeed; // also use the message acknowledge key ^= clc.serverMessageSequence; // also use the last acknowledged server command in the key key ^= MSG_HashKey(clc.serverCommands[ clc.serverCommandSequence & (MAX_RELIABLE_COMMANDS-1) ], 32); // write all the commands, including the predicted command for ( i = 0 ; i < count ; i++ ) { j = (cl.cmdNumber - count + i + 1) & CMD_MASK; cmd = &cl.cmds[j]; MSG_WriteDeltaUsercmdKey (&buf, key, oldcmd, cmd); oldcmd = cmd; } } // // deliver the message // packetNum = clc.netchan.outgoingSequence & PACKET_MASK; cl.outPackets[ packetNum ].p_realtime = cls.realtime; cl.outPackets[ packetNum ].p_serverTime = oldcmd->serverTime; cl.outPackets[ packetNum ].p_cmdNumber = cl.cmdNumber; clc.lastPacketSentTime = cls.realtime; if ( cl_showSend->integer ) { Com_Printf( "%i ", buf.cursize ); } CL_Netchan_Transmit (&clc.netchan, &buf); // clients never really should have messages large enough // to fragment, but in case they do, fire them all off // at once // TTimo: this causes a packet burst, which is bad karma for winsock // added a WARNING message, we'll see if there are legit situations where this happens while ( clc.netchan.unsentFragments ) { Com_DPrintf( "WARNING: #462 unsent fragments (not supposed to happen!)\n" ); CL_Netchan_TransmitNextFragment( &clc.netchan ); } }
/************************************************************************************************ * CRMBSPInstance::Spawn * spawns a bsp into the world using the previously aquired origin * * inputs: * none * * return: * none * ************************************************************************************************/ bool CRMBSPInstance::Spawn ( CRandomTerrain* terrain, qboolean IsServer) { #ifndef PRE_RELEASE_DEMO // TEntity* ent; float yaw; char temp[10000]; char *savePtr; vec3_t origin; vec3_t notmirrored; float water_level = terrain->GetLandScape()->GetWaterHeight(); const vec3_t& terxelSize = terrain->GetLandScape()->GetTerxelSize ( ); const vec3pair_t& bounds = terrain->GetLandScape()->GetBounds(); // If this entity somehow lost its collision flag then boot it if ( !GetArea().IsCollisionEnabled ( ) ) { return false; } // copy out the unmirrored version VectorCopy(GetOrigin(), notmirrored); // we want to mirror it before determining the Z value just in case the landscape isn't perfectly mirrored if (mMirror) { GetOrigin()[0] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][0] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][0] - GetOrigin()[0]; GetOrigin()[1] = TheRandomMissionManager->GetLandScape()->GetBounds()[0][1] + TheRandomMissionManager->GetLandScape()->GetBounds()[1][1] - GetOrigin()[1]; } // Align the instance to the center of a terxel GetOrigin ( )[0] = bounds[0][0] + (int)((GetOrigin ( )[0] - bounds[0][0] + terxelSize[0] / 2) / terxelSize[0]) * terxelSize[0]; GetOrigin ( )[1] = bounds[0][1] + (int)((GetOrigin ( )[1] - bounds[0][1] + terxelSize[1] / 2) / terxelSize[1]) * terxelSize[1]; // Make sure the bsp is resting on the ground, not below or above it // NOTE: This check is basically saying "is this instance not a bridge", because when instances are created they are all // placed above the world's Z boundary, EXCEPT FOR BRIDGES. So this call to GetWorldHeight will move all other instances down to // ground level except bridges if ( GetOrigin()[2] > terrain->GetBounds()[1][2] ) { if( GetFlattenRadius() ) { terrain->GetLandScape()->GetWorldHeight ( GetOrigin(), GetBounds ( ), false ); GetOrigin()[2] += 5; } else if (IsServer) { // if this instance does not flatten the ground around it, do a trace to more accurately determine its Z value trace_t tr; vec3_t end; vec3_t start; VectorCopy(GetOrigin(), end); VectorCopy(GetOrigin(), start); // start the trace below the top height of the landscape start[2] = TheRandomMissionManager->GetLandScape()->GetBounds()[1][2] - 1; // end the trace at the bottom of the world end[2] = MIN_WORLD_COORD; memset ( &tr, 0, sizeof ( tr ) ); SV_Trace( &tr, start, vec3_origin, vec3_origin, end, ENTITYNUM_NONE, CONTENTS_TERRAIN|CONTENTS_SOLID, G2_NOCOLLIDE, 0); //qfalse, 0, 10 ); if( !(tr.contents & CONTENTS_TERRAIN) || (tr.fraction == 1.0) ) { if ( 0 ) assert(0); // this should never happen // restore the unmirrored origin VectorCopy( notmirrored, GetOrigin() ); // don't spawn return false; } // assign the Z-value to wherever it hit the terrain GetOrigin()[2] = tr.endpos[2]; // lower it a little, otherwise the bottom of the instance might be exposed if on some weird sloped terrain GetOrigin()[2] -= 16; // FIXME: would it be better to use a number related to the instance itself like 1/5 it's height or something... } } else { terrain->GetLandScape()->GetWorldHeight ( GetOrigin(), GetBounds ( ), true ); } // save away the origin VectorCopy(GetOrigin(), origin); // make sure not to spawn if in water if (!HasObjective() && GetOrigin()[2] < water_level) return false; // restore the origin VectorCopy(origin, GetOrigin()); if (mMirror) { // change blue things to red for symmetric maps if (strlen(mFilter) > 0) { char * blue = strstr(mFilter,"blue"); if (blue) { blue[0] = (char) 0; strcat(mFilter, "red"); SetSide(SIDE_RED); } } if (strlen(mTeamFilter) > 0) { char * blue = strstr(mTeamFilter,"blue"); if (blue) { strcpy(mTeamFilter, "red"); SetSide(SIDE_RED); } } yaw = RAD2DEG(mArea->GetAngle() + mBaseAngle) + 180; } else { yaw = RAD2DEG(mArea->GetAngle() + mBaseAngle); } /* if( TheRandomMissionManager->GetMission()->GetSymmetric() ) { vec3_t diagonal; vec3_t lineToPoint; vec3_t mins; vec3_t maxs; vec3_t point; vec3_t vProj; vec3_t vec; float distance; VectorCopy( TheRandomMissionManager->GetLandScape()->GetBounds()[1], maxs ); VectorCopy( TheRandomMissionManager->GetLandScape()->GetBounds()[0], mins ); VectorCopy( GetOrigin(), point ); mins[2] = maxs[2] = point[2] = 0; VectorSubtract( point, mins, lineToPoint ); VectorSubtract( maxs, mins, diagonal); VectorNormalize(diagonal); VectorMA( mins, DotProduct(lineToPoint, diagonal), diagonal, vProj); VectorSubtract(point, vProj, vec ); distance = VectorLength(vec); // if an instance is too close to the imaginary diagonal that cuts the world in half, don't spawn it // otherwise you can get overlapping instances if( distance < GetSpacingRadius() ) { #ifdef _DEBUG mAutomapSymbol = AUTOMAP_END; #endif if( !HasObjective() ) { return false; } } } */ // Spawn in the bsp model sprintf(temp, "{\n" "\"classname\" \"misc_bsp\"\n" "\"bspmodel\" \"%s\"\n" "\"origin\" \"%f %f %f\"\n" "\"angles\" \"0 %f 0\"\n" "\"filter\" \"%s\"\n" "\"teamfilter\" \"%s\"\n" "\"spacing\" \"%d\"\n" "\"flatten\" \"%d\"\n" "}\n", mBsp, GetOrigin()[0], GetOrigin()[1], GetOrigin()[2], AngleNormalize360(yaw), mFilter, mTeamFilter, (int)GetSpacingRadius(), (int)GetFlattenRadius() ); if (IsServer) { // only allow for true spawning on the server savePtr = sv.entityParsePoint; sv.entityParsePoint = temp; // VM_Call( cgvm, GAME_SPAWN_RMG_ENTITY ); // char *s; int bufferSize = 1024; char buffer[1024]; // s = COM_Parse( (const char **)&sv.entityParsePoint ); Q_strncpyz( buffer, sv.entityParsePoint, bufferSize ); if ( sv.entityParsePoint && sv.entityParsePoint[0] ) { ge->GameSpawnRMGEntity(sv.entityParsePoint); } sv.entityParsePoint = savePtr; } #ifndef DEDICATED DrawAutomapSymbol(); #endif Com_DPrintf( "RMG: Building '%s' spawned at (%f %f %f)\n", mBsp, GetOrigin()[0], GetOrigin()[1], GetOrigin()[2] ); // now restore the instances un-mirrored origin // NOTE: all this origin flipping, setting the side etc... should be done when mMirror is set // because right after this function is called, mMirror is set to 0 but all the instance data is STILL MIRRORED -- not good VectorCopy(notmirrored, GetOrigin()); #endif // PRE_RELEASE_DEMO return true; }
/** * @brief Deals damage of a give type and amount to a target. * @param[in,out] target What we want to damage. * @param[in] fd The fire definition that defines what type of damage is dealt. * @param[in] damage The value of the damage. * @param[in] attacker The attacker. * @param[in] mock pseudo shooting - only for calculating mock values - nullptr for real shots * @param[in] impact impact location - @c nullptr for splash damage * @sa G_SplashDamage * @sa G_TakeDamage * @sa G_PrintActorStats */ static void G_Damage (Edict* target, const fireDef_t* fd, int damage, Edict* attacker, shot_mock_t* mock, const vec3_t impact) { const bool stunEl = (fd->obj->dmgtype == gi.csi->damStunElectro); const bool stunGas = (fd->obj->dmgtype == gi.csi->damStunGas); const bool shock = (fd->obj->dmgtype == gi.csi->damShock); const bool smoke = (fd->obj->dmgtype == gi.csi->damSmoke); bool isRobot; assert(target); /* Breakables */ if (G_IsBrushModel(target) && G_IsBreakable(target)) { /* Breakables are immune to stun & shock damage. */ if (stunEl || stunGas || shock || mock || smoke) return; if (damage >= target->HP) { /* don't reset the HP value here, this value is used to distinguish * between triggered destroy and a shoot */ assert(target->destroy); target->destroy(target); /* maybe the attacker is seeing something new? */ G_CheckVisTeamAll(attacker->team, 0, attacker); /* check if attacker appears/perishes for any other team */ G_CheckVis(attacker); } else { G_TakeDamage(target, damage); } return; } /* Actors don't die again. */ if (!G_IsLivingActor(target)) return; /* only actors after this point - and they must have a teamdef */ assert(target->chr.teamDef); isRobot = CHRSH_IsTeamDefRobot(target->chr.teamDef); /* Apply armour effects. */ if (damage > 0) { damage = G_ApplyProtection(target, fd->dmgweight, damage); } else if (damage < 0) { /* Robots can't be healed. */ if (isRobot) return; } Com_DPrintf(DEBUG_GAME, " Total damage: %d\n", damage); /* Apply difficulty settings. */ if (G_IsSinglePlayer()) { if (G_IsAlien(attacker) && !G_IsAlien(target)) damage *= pow(1.18, g_difficulty->value); else if (!G_IsAlien(attacker) && G_IsAlien(target)) damage *= pow(1.18, -g_difficulty->value); } assert(attacker->team >= 0 && attacker->team < MAX_TEAMS); assert(target->team >= 0 && target->team < MAX_TEAMS); if (g_nodamage != nullptr && !g_nodamage->integer) { /* hit */ if (mock) { G_UpdateShotMock(mock, attacker, target, damage); } else if (stunEl) { target->STUN += damage; } else if (stunGas) { if (!isRobot) /* Can't stun robots with gas */ target->STUN += damage; } else if (shock) { /* Only do this if it's not one from our own team ... they should have known that there was a flashbang coming. */ if (!isRobot && target->team != attacker->team) { /** @todo there should be a possible protection, too */ /* dazed entity wont reaction fire */ G_RemoveReaction(target); G_ActorReserveTUs(target, 0, target->chr.reservedTus.shot, target->chr.reservedTus.crouch); /* flashbangs kill TUs */ G_ActorSetTU(target, 0); G_SendStats(*target); /* entity is dazed */ G_SetDazed(target); G_ClientPrintf(target->getPlayer(), PRINT_HUD, _("Soldier is dazed!\nEnemy used flashbang!")); return; } } else { if (damage < 0) { /* The 'attacker' is healing the target. */ G_TreatActor(target, fd, damage, attacker->team); } else { /* Real damage was dealt. */ G_DamageActor(target, damage, impact); /* Update overall splash damage for stats/score. */ if (!mock && damage > 0 && fd->splrad) /**< Check for >0 and splrad to not count this as direct hit. */ G_UpdateHitScore(attacker, target, fd, damage); } } } if (mock) return; G_CheckDeathOrKnockout(target, attacker, fd, damage); }
/* ============ S_RawSamples Music streaming ============ */ void S_RawSamples( int samples, int rate, int width, int s_channels, const byte *data, float volume ) { int i; int src, dst; float scale; int intVolume; if ( !s_soundStarted || s_soundMuted ) { return; } intVolume = 256 * volume; if ( s_rawend < s_soundtime ) { Com_DPrintf( "S_RawSamples: resetting minimum: %i < %i\n", s_rawend, s_soundtime ); s_rawend = s_soundtime; } scale = (float)rate / dma.speed; //Com_Printf ("%i < %i < %i\n", s_soundtime, s_paintedtime, s_rawend); if (s_channels == 2 && width == 2) { if (scale == 1.0) { // optimized case for (i=0 ; i<samples ; i++) { dst = s_rawend&(MAX_RAW_SAMPLES-1); s_rawend++; s_rawsamples[dst].left = ((short *)data)[i*2] * intVolume; s_rawsamples[dst].right = ((short *)data)[i*2+1] * intVolume; } } else { for (i=0 ; ; i++) { src = i*scale; if (src >= samples) break; dst = s_rawend&(MAX_RAW_SAMPLES-1); s_rawend++; s_rawsamples[dst].left = ((short *)data)[src*2] * intVolume; s_rawsamples[dst].right = ((short *)data)[src*2+1] * intVolume; } } } else if (s_channels == 1 && width == 2) { for (i=0 ; ; i++) { src = i*scale; if (src >= samples) break; dst = s_rawend&(MAX_RAW_SAMPLES-1); s_rawend++; s_rawsamples[dst].left = ((short *)data)[src] * intVolume; s_rawsamples[dst].right = ((short *)data)[src] * intVolume; } } else if (s_channels == 2 && width == 1) { intVolume *= 256; for (i=0 ; ; i++) { src = i*scale; if (src >= samples) break; dst = s_rawend&(MAX_RAW_SAMPLES-1); s_rawend++; s_rawsamples[dst].left = ((char *)data)[src*2] * intVolume; s_rawsamples[dst].right = ((char *)data)[src*2+1] * intVolume; } } else if (s_channels == 1 && width == 1) { intVolume *= 256; for (i=0 ; ; i++) { src = i*scale; if (src >= samples) break; dst = s_rawend&(MAX_RAW_SAMPLES-1); s_rawend++; s_rawsamples[dst].left = (((byte *)data)[src]-128) * intVolume; s_rawsamples[dst].right = (((byte *)data)[src]-128) * intVolume; } } if ( s_rawend > s_soundtime + MAX_RAW_SAMPLES ) { Com_DPrintf( "S_RawSamples: overflowed %i > %i\n", s_rawend, s_soundtime ); } }
/* ====================== S_StartBackgroundTrack ====================== */ void S_StartBackgroundTrack( const char *intro, const char *loop ){ int len; char dump[16]; char name[MAX_QPATH]; if ( !intro ) { intro = ""; } if ( !loop || !loop[0] ) { loop = intro; } Com_DPrintf( "S_StartBackgroundTrack( %s, %s )\n", intro, loop ); Q_strncpyz( name, intro, sizeof( name ) - 4 ); COM_DefaultExtension( name, sizeof( name ), ".wav" ); if ( !intro[0] ) { return; } Q_strncpyz( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) ); // close the background track, but DON'T reset s_rawend // if restarting the same back ground track if ( s_backgroundFile ) { Sys_EndStreamedFile( s_backgroundFile ); FS_FCloseFile( s_backgroundFile ); s_backgroundFile = 0; } // // open up a wav file and get all the info // FS_FOpenFileRead( name, &s_backgroundFile, qtrue ); if ( !s_backgroundFile ) { Com_Printf( S_COLOR_YELLOW "WARNING: couldn't open music file %s\n", name ); return; } // skip the riff wav header FS_Read(dump, 12, s_backgroundFile); if ( !S_FindWavChunk( s_backgroundFile, "fmt " ) ) { Com_Printf( "No fmt chunk in %s\n", name ); FS_FCloseFile( s_backgroundFile ); s_backgroundFile = 0; return; } // save name for soundinfo s_backgroundInfo.format = FGetLittleShort( s_backgroundFile ); s_backgroundInfo.channels = FGetLittleShort( s_backgroundFile ); s_backgroundInfo.rate = FGetLittleLong( s_backgroundFile ); FGetLittleLong( s_backgroundFile ); FGetLittleShort( s_backgroundFile ); s_backgroundInfo.width = FGetLittleShort( s_backgroundFile ) / 8; if ( s_backgroundInfo.format != WAV_FORMAT_PCM ) { FS_FCloseFile( s_backgroundFile ); s_backgroundFile = 0; Com_Printf("Not a microsoft PCM format wav: %s\n", name); return; } if ( s_backgroundInfo.channels != 2 || s_backgroundInfo.rate != 22050 ) { Com_Printf(S_COLOR_YELLOW "WARNING: music file %s is not 22k stereo\n", name ); } if ( ( len = S_FindWavChunk( s_backgroundFile, "data" ) ) == 0 ) { FS_FCloseFile( s_backgroundFile ); s_backgroundFile = 0; Com_Printf("No data chunk in %s\n", name); return; } s_backgroundInfo.samples = len / (s_backgroundInfo.width * s_backgroundInfo.channels); s_backgroundSamples = s_backgroundInfo.samples; // // start the background streaming // Sys_BeginStreamedFile( s_backgroundFile, 0x10000 ); }
/* =============== IN_ProcessEvents =============== */ static void IN_ProcessEvents( void ) { SDL_Event e; fakeAscii_t key = A_NULL; if( !SDL_WasInit( SDL_INIT_VIDEO ) ) return; while( SDL_PollEvent( &e ) ) { switch( e.type ) { case SDL_KEYDOWN: if (e.key.keysym.scancode == SDL_SCANCODE_GRAVE) { Sys_QueEvent( 0, SE_KEY, A_CONSOLE, qtrue, 0, NULL ); } else { key = IN_TranslateSDLToJKKey( &e.key.keysym, qtrue ); if ( key != A_NULL ) { fakeAscii_t upperKey = key; if (e.key.keysym.sym >= A_LOW_A && e.key.keysym.sym <= A_LOW_Z) { upperKey = (fakeAscii_t)(A_CAP_A + (e.key.keysym.sym - A_LOW_A)); } else if (e.key.keysym.sym >= A_LOW_AGRAVE && e.key.keysym.sym <= A_LOW_THORN && e.key.keysym.sym != A_DIVIDE) { upperKey = (fakeAscii_t)(A_CAP_AGRAVE + (e.key.keysym.sym - A_LOW_AGRAVE)); } Sys_QueEvent( 0, SE_KEY, upperKey, qtrue, 0, NULL ); } if ( key == A_BACKSPACE ) Sys_QueEvent( 0, SE_CHAR, CTRL('h'), qfalse, 0, NULL); else if ( kg.keys[A_CTRL].down && key >= 'a' && key <= 'z' ) Sys_QueEvent( 0, SE_CHAR, CTRL(key), qfalse, 0, NULL ); } break; case SDL_KEYUP: if (e.key.keysym.scancode == SDL_SCANCODE_GRAVE) { Sys_QueEvent( 0, SE_KEY, A_CONSOLE, qfalse, 0, NULL ); } else { key = IN_TranslateSDLToJKKey( &e.key.keysym, qfalse ); if( key != A_NULL ) { fakeAscii_t upperKey = key; if (e.key.keysym.sym >= A_LOW_A && e.key.keysym.sym <= A_LOW_Z) { upperKey = (fakeAscii_t)(A_CAP_A + (e.key.keysym.sym - A_LOW_A)); } else if (e.key.keysym.sym >= A_LOW_AGRAVE && e.key.keysym.sym <= A_LOW_THORN && e.key.keysym.sym != A_DIVIDE) { upperKey = (fakeAscii_t)(A_CAP_AGRAVE + (e.key.keysym.sym - A_LOW_AGRAVE)); } Sys_QueEvent( 0, SE_KEY, upperKey, qfalse, 0, NULL ); } } if ( ( e.key.keysym.scancode == SDL_SCANCODE_LGUI || e.key.keysym.scancode == SDL_SCANCODE_RGUI ) && Cvar_VariableIntegerValue("r_fullscreen")) { SDL_MinimizeWindow(SDL_window); } break; case SDL_TEXTINPUT: { char *c = e.text.text; // Quick and dirty UTF-8 to UTF-32 conversion while( *c ) { int utf32 = 0; if( ( *c & 0x80 ) == 0 ) utf32 = *c++; else if( ( *c & 0xE0 ) == 0xC0 ) // 110x xxxx { utf32 |= ( *c++ & 0x1F ) << 6; utf32 |= ( *c++ & 0x3F ); } else if( ( *c & 0xF0 ) == 0xE0 ) // 1110 xxxx { utf32 |= ( *c++ & 0x0F ) << 12; utf32 |= ( *c++ & 0x3F ) << 6; utf32 |= ( *c++ & 0x3F ); } else if( ( *c & 0xF8 ) == 0xF0 ) // 1111 0xxx { utf32 |= ( *c++ & 0x07 ) << 18; utf32 |= ( *c++ & 0x3F ) << 12; utf32 |= ( *c++ & 0x3F ) << 6; utf32 |= ( *c++ & 0x3F ); } else { Com_DPrintf( "Unrecognised UTF-8 lead byte: 0x%x\n", (unsigned int)*c ); c++; } if( utf32 != 0 ) { Sys_QueEvent( 0, SE_CHAR, utf32, 0, 0, NULL ); } } break; } case SDL_MOUSEMOTION: if( mouseActive ) Sys_QueEvent( 0, SE_MOUSE, e.motion.xrel, e.motion.yrel, 0, NULL ); break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: { unsigned short b; switch( e.button.button ) { case SDL_BUTTON_LEFT: b = A_MOUSE1; break; case SDL_BUTTON_MIDDLE: b = A_MOUSE3; break; case SDL_BUTTON_RIGHT: b = A_MOUSE2; break; case SDL_BUTTON_X1: b = A_MOUSE4; break; case SDL_BUTTON_X2: b = A_MOUSE5; break; default: b = A_AUX0 + ( e.button.button - 6 ) % 32; break; } Sys_QueEvent( 0, SE_KEY, b, ( e.type == SDL_MOUSEBUTTONDOWN ? qtrue : qfalse ), 0, NULL ); } break; case SDL_MOUSEWHEEL: if( e.wheel.y > 0 ) { Sys_QueEvent( 0, SE_KEY, A_MWHEELUP, qtrue, 0, NULL ); Sys_QueEvent( 0, SE_KEY, A_MWHEELUP, qfalse, 0, NULL ); } else { Sys_QueEvent( 0, SE_KEY, A_MWHEELDOWN, qtrue, 0, NULL ); Sys_QueEvent( 0, SE_KEY, A_MWHEELDOWN, qfalse, 0, NULL ); } break; case SDL_QUIT: Cbuf_ExecuteText(EXEC_NOW, "quit Closed window\n"); break; case SDL_WINDOWEVENT: switch( e.window.event ) { case SDL_WINDOWEVENT_MINIMIZED: Cvar_SetValue( "com_minimized", 1 ); break; case SDL_WINDOWEVENT_RESTORED: case SDL_WINDOWEVENT_MAXIMIZED: Cvar_SetValue( "com_minimized", 0 ); break; case SDL_WINDOWEVENT_FOCUS_LOST: Cvar_SetValue( "com_unfocused", 1 ); S_MuteAllSounds(true); break; case SDL_WINDOWEVENT_FOCUS_GAINED: Cvar_SetValue( "com_unfocused", 0 ); S_MuteAllSounds(false); break; } default: break; } } }
/* ================= CL_ConnectionlessPacket Responses to broadcasts, etc ================= */ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { char *s; const char *c; MSG_BeginReading( msg ); MSG_ReadLong( msg ); // skip the -1 s = MSG_ReadStringLine( msg ); Cmd_TokenizeString( s ); c = Cmd_Argv(0); Com_DPrintf ("CL packet %s: %s\n", NET_AdrToString(from), c); // challenge from the server we are connecting to if ( !strcmp(c, "challengeResponse") ) { if ( cls.state != CA_CONNECTING ) { Com_Printf( "Unwanted challenge response received. Ignored.\n" ); } else { // start sending challenge repsonse instead of challenge request packets clc.challenge = atoi(Cmd_Argv(1)); cls.state = CA_CHALLENGING; clc.connectPacketCount = 0; clc.connectTime = -99999; // take this address as the new server address. This allows // a server proxy to hand off connections to multiple servers clc.serverAddress = from; } return; } // server connection if ( !strcmp(c, "connectResponse") ) { if ( cls.state >= CA_CONNECTED ) { Com_Printf ("Dup connect received. Ignored.\n"); return; } if ( cls.state != CA_CHALLENGING ) { Com_Printf ("connectResponse packet while not connecting. Ignored.\n"); return; } if ( !NET_CompareBaseAdr( from, clc.serverAddress ) ) { Com_Printf( "connectResponse from a different address. Ignored.\n" ); Com_Printf( "%s should have been %s\n", NET_AdrToString( from ), NET_AdrToString( clc.serverAddress ) ); return; } Netchan_Setup (NS_CLIENT, &clc.netchan, from, Cvar_VariableIntegerValue( "net_qport" ) ); cls.state = CA_CONNECTED; clc.lastPacketSentTime = -9999; // send first packet immediately return; } // a disconnect message from the server, which will happen if the server // dropped the connection but it is still getting packets from us if (!strcmp(c, "disconnect")) { CL_DisconnectPacket( from ); return; } // echo request from server if ( !strcmp(c, "echo") ) { NET_OutOfBandPrint( NS_CLIENT, from, "%s", Cmd_Argv(1) ); return; } // print request from server if ( !strcmp(c, "print") ) { s = MSG_ReadString( msg ); UI_UpdateConnectionMessageString( s ); Com_Printf( "%s", s ); return; } Com_DPrintf ("Unknown connectionless packet command.\n"); }
/* * CL_ParseServerData */ static void CL_ParseServerData( msg_t *msg ) { const char *str, *gamedir; int i, sv_bitflags, numpure; int http_portnum; Com_DPrintf( "Serverdata packet received.\n" ); // wipe the client_state_t struct CL_ClearState(); CL_SetClientState( CA_CONNECTED ); // parse protocol version number i = MSG_ReadLong( msg ); if( i != APP_PROTOCOL_VERSION && !(cls.demo.playing && i == APP_DEMO_PROTOCOL_VERSION) ) Com_Error( ERR_DROP, "Server returned version %i, not %i", i, APP_PROTOCOL_VERSION ); cl.servercount = MSG_ReadLong( msg ); cl.snapFrameTime = (unsigned int)MSG_ReadShort( msg ); cl.gamestart = true; // set extrapolation time to half snapshot time Cvar_ForceSet( "cl_extrapolationTime", va( "%i", (unsigned int)( cl.snapFrameTime * 0.5 ) ) ); cl_extrapolationTime->modified = false; // base game directory str = MSG_ReadString( msg ); if( !str || !str[0] ) Com_Error( ERR_DROP, "Server sent an empty base game directory" ); if( !COM_ValidateRelativeFilename( str ) || strchr( str, '/' ) ) Com_Error( ERR_DROP, "Server sent an invalid base game directory: %s", str ); if( strcmp( FS_BaseGameDirectory(), str ) ) { Com_Error( ERR_DROP, "Server has different base game directory (%s) than the client (%s)", str, FS_BaseGameDirectory() ); } // game directory str = MSG_ReadString( msg ); if( !str || !str[0] ) Com_Error( ERR_DROP, "Server sent an empty game directory" ); if( !COM_ValidateRelativeFilename( str ) || strchr( str, '/' ) ) Com_Error( ERR_DROP, "Server sent an invalid game directory: %s", str ); gamedir = FS_GameDirectory(); if( strcmp( str, gamedir ) ) { // shutdown the cgame module first in case it is running for whatever reason // (happens on wswtv in lobby), otherwise precaches that are going to follow // will probably f**k up (like models trying to load before the world model) CL_GameModule_Shutdown(); if( !FS_SetGameDirectory( str, true ) ) Com_Error( ERR_DROP, "Failed to load game directory set by server: %s", str ); ML_Restart( true ); } // parse player entity number cl.playernum = MSG_ReadShort( msg ); // get the full level name Q_strncpyz( cl.servermessage, MSG_ReadString( msg ), sizeof( cl.servermessage ) ); sv_bitflags = MSG_ReadByte( msg ); if( cls.demo.playing ) { cls.reliable = ( sv_bitflags & SV_BITFLAGS_RELIABLE ); } else { if( cls.reliable != ( ( sv_bitflags & SV_BITFLAGS_RELIABLE ) != 0 ) ) Com_Error( ERR_DROP, "Server and client disagree about connection reliability" ); } // builting HTTP server port if( cls.httpbaseurl ) { Mem_Free( cls.httpbaseurl ); cls.httpbaseurl = NULL; } if( ( sv_bitflags & SV_BITFLAGS_HTTP ) != 0 ) { if( ( sv_bitflags & SV_BITFLAGS_HTTP_BASEURL ) != 0 ) { // read base upstream url cls.httpbaseurl = ZoneCopyString( MSG_ReadString( msg ) ); } else { http_portnum = MSG_ReadShort( msg ) & 0xffff; cls.httpaddress = cls.serveraddress; if( cls.httpaddress.type == NA_IP6 ) { cls.httpaddress.address.ipv6.port = BigShort( http_portnum ); } else { cls.httpaddress.address.ipv4.port = BigShort( http_portnum ); } if( http_portnum ) { if( cls.httpaddress.type == NA_LOOPBACK ) { cls.httpbaseurl = ZoneCopyString( va( "http://localhost:%hu/", http_portnum ) ); } else { cls.httpbaseurl = ZoneCopyString( va( "http://%s/", NET_AddressToString( &cls.httpaddress ) ) ); } } } } // pure list // clean old, if necessary Com_FreePureList( &cls.purelist ); // add new numpure = MSG_ReadShort( msg ); while( numpure > 0 ) { const char *pakname = MSG_ReadString( msg ); const unsigned checksum = MSG_ReadLong( msg ); Com_AddPakToPureList( &cls.purelist, pakname, checksum, NULL ); numpure--; } //assert( numpure == 0 ); // get the configstrings request CL_AddReliableCommand( va( "configstrings %i 0", cl.servercount ) ); cls.sv_pure = ( sv_bitflags & SV_BITFLAGS_PURE ) != 0; cls.sv_tv = ( sv_bitflags & SV_BITFLAGS_TVSERVER ) != 0; #ifdef PURE_CHEAT cls.sv_pure = false; #endif cls.wakelock = Sys_AcquireWakeLock(); if( !cls.demo.playing && ( cls.serveraddress.type == NA_IP ) ) Steam_AdvertiseGame( cls.serveraddress.address.ipv4.ip, NET_GetAddressPort( &cls.serveraddress ) ); // separate the printfs so the server message can have a color Com_Printf( S_COLOR_WHITE "\n" "=====================================\n" ); Com_Printf( S_COLOR_WHITE "%s\n\n", cl.servermessage ); }
void SV_LinkEntity( sharedEntity_t *gEnt ) { worldSector_t *node; int leafs[MAX_TOTAL_ENT_LEAFS]; int cluster; int num_leafs; int i, j, k; int area; int lastLeaf; float *origin, *angles; svEntity_t *ent; ent = SV_SvEntityForGentity( gEnt ); if ( ent->worldSector ) { SV_UnlinkEntity( gEnt ); // unlink from old position } if(sv_antiblock->integer > 0){ if(gEnt->r.contents & CONTENTS_BODY){ if(gEnt->s.number >= 0 && gEnt->s.number < sv_maxclients->integer){ gEnt->r.contents &= ~CONTENTS_BODY; gEnt->r.contents |= CONTENTS_CORPSE; } } } // encode the size into the entityState_t for client prediction if ( gEnt->r.bmodel ) { gEnt->s.solid = SOLID_BMODEL; // a solid_box will never create this value } else if ( gEnt->r.contents & ( CONTENTS_SOLID | CONTENTS_BODY ) ) { // assume that x/y are equal and symetric i = gEnt->r.maxs[0]; if (i<1) i = 1; if (i>255) i = 255; // z is not symetric j = (-gEnt->r.mins[2]); if (j<1) j = 1; if (j>255) j = 255; // and z maxs can be negative... k = (gEnt->r.maxs[2]+32); if (k<1) k = 1; if (k>255) k = 255; gEnt->s.solid = (k<<16) | (j<<8) | i; } else { gEnt->s.solid = 0; } // get the position origin = gEnt->r.currentOrigin; angles = gEnt->r.currentAngles; // set the abs box if ( gEnt->r.bmodel && (angles[0] || angles[1] || angles[2]) ) { // expand for rotation float max; int i; max = RadiusFromBounds( gEnt->r.mins, gEnt->r.maxs ); for (i=0 ; i<3 ; i++) { gEnt->r.absmin[i] = origin[i] - max; gEnt->r.absmax[i] = origin[i] + max; } } else { // normal VectorAdd (origin, gEnt->r.mins, gEnt->r.absmin); VectorAdd (origin, gEnt->r.maxs, gEnt->r.absmax); } // because movement is clipped an epsilon away from an actual edge, // we must fully check even when bounding boxes don't quite touch gEnt->r.absmin[0] -= 1; gEnt->r.absmin[1] -= 1; gEnt->r.absmin[2] -= 1; gEnt->r.absmax[0] += 1; gEnt->r.absmax[1] += 1; gEnt->r.absmax[2] += 1; // link to PVS leafs ent->numClusters = 0; ent->lastCluster = 0; ent->areanum = -1; ent->areanum2 = -1; //get all leafs, including solids num_leafs = CM_BoxLeafnums( gEnt->r.absmin, gEnt->r.absmax, leafs, MAX_TOTAL_ENT_LEAFS, &lastLeaf ); // if none of the leafs were inside the map, the // entity is outside the world and can be considered unlinked if ( !num_leafs ) { return; } // set areas, even from clusters that don't fit in the entity array for (i=0 ; i<num_leafs ; i++) { area = CM_LeafArea (leafs[i]); if (area != -1) { // doors may legally straggle two areas, // but nothing should evern need more than that if (ent->areanum != -1 && ent->areanum != area) { if (ent->areanum2 != -1 && ent->areanum2 != area && sv.state == SS_LOADING) { Com_DPrintf ("Object %i touching 3 areas at %f %f %f\n", gEnt->s.number, gEnt->r.absmin[0], gEnt->r.absmin[1], gEnt->r.absmin[2]); } ent->areanum2 = area; } else { ent->areanum = area; } } } // store as many explicit clusters as we can ent->numClusters = 0; for (i=0 ; i < num_leafs ; i++) { cluster = CM_LeafCluster( leafs[i] ); if ( cluster != -1 ) { ent->clusternums[ent->numClusters++] = cluster; if ( ent->numClusters == MAX_ENT_CLUSTERS ) { break; } } } // store off a last cluster if we need to if ( i != num_leafs ) { ent->lastCluster = CM_LeafCluster( lastLeaf ); } gEnt->r.linkcount++; // find the first world sector node that the ent's box crosses node = sv_worldSectors; while (1) { if (node->axis == -1) break; if ( gEnt->r.absmin[node->axis] > node->dist) node = node->children[0]; else if ( gEnt->r.absmax[node->axis] < node->dist) node = node->children[1]; else break; // crosses the node } // link it in ent->worldSector = node; ent->nextEntityInWorldSector = node->entities; node->entities = ent; gEnt->r.linked = qtrue; }
void CRMLandScape::LoadMiscentDef(const char *td) { char miscentDef[MAX_QPATH]; CGenericParser2 parse; CGPGroup *basegroup, *classes, *items, *model; CGPValue *pair; Com_sprintf(miscentDef, MAX_QPATH, "ext_data/RMG/%s.miscents", Info_ValueForKey(td, "miscentDef")); Com_DPrintf("CG_Terrain: Loading and parsing miscentDef %s.....\n", Info_ValueForKey(td, "miscentDef")); if(!Com_ParseTextFile(miscentDef, parse)) { Com_sprintf(miscentDef, MAX_QPATH, "ext_data/arioche/%s.miscents", Info_ValueForKey(td, "miscentDef")); if(!Com_ParseTextFile(miscentDef, parse)) { Com_Printf("Could not open %s\n", miscentDef); return; } } // The whole file.... basegroup = parse.GetBaseParseGroup(); // The root { } struct classes = basegroup->GetSubGroups(); while(classes) { items = classes->GetSubGroups(); while(items) { if(!stricmp(items->GetName(), "miscent")) { int height, maxheight; // Height must exist - the rest are optional height = atol(items->FindPairValue("height", "0")); maxheight = atol(items->FindPairValue("maxheight", "255")); model = items->GetSubGroups(); while(model) { if(!stricmp(model->GetName(), "model")) { CRandomModel hd; // Set defaults hd.SetModel(""); hd.SetFrequency(1.0f); hd.SetMinScale(1.0f); hd.SetMaxScale(1.0f); pair = model->GetPairs(); while(pair) { if(!stricmp(pair->GetName(), "name")) { hd.SetModel(pair->GetTopValue()); } else if(!stricmp(pair->GetName(), "frequency")) { hd.SetFrequency((float)atof(pair->GetTopValue())); } else if(!stricmp(pair->GetName(), "minscale")) { hd.SetMinScale((float)atof(pair->GetTopValue())); } else if(!stricmp(pair->GetName(), "maxscale")) { hd.SetMaxScale((float)atof(pair->GetTopValue())); } pair = (CGPValue *)pair->GetNext(); } AddModel(height, maxheight, &hd); } model = (CGPGroup *)model->GetNext(); } } items = (CGPGroup *)items->GetNext(); } classes = (CGPGroup *)classes->GetNext(); } Com_ParseTextFileDestroy(parse); }
/* ================= S_CodecGetSound Opens/loads a sound, tries codec based on the sound's file extension then tries all supported codecs. ================= */ static void *S_CodecGetSound(const char *filename, snd_info_t *info) { snd_codec_t *codec; snd_codec_t *orgCodec = NULL; qboolean orgNameFailed = qfalse; char localName[ MAX_QPATH ]; const char *ext; char altName[ MAX_QPATH ]; void *rtn = NULL; Q_strncpyz(localName, filename, MAX_QPATH); ext = COM_GetExtension(localName); if( *ext ) { // Look for the correct loader and use it for( codec = codecs; codec; codec = codec->next ) { if( !Q_stricmp( ext, codec->ext ) ) { // Load if( info ) rtn = codec->load(localName, info); else rtn = codec->open(localName); break; } } // A loader was found if( codec ) { if( !rtn ) { // Loader failed, most likely because the file isn't there; // try again without the extension orgNameFailed = qtrue; orgCodec = codec; COM_StripExtension( filename, localName, MAX_QPATH ); } else { // Something loaded return rtn; } } } // Try and find a suitable match using all // the sound codecs supported for( codec = codecs; codec; codec = codec->next ) { if( codec == orgCodec ) continue; Com_sprintf( altName, sizeof (altName), "%s.%s", localName, codec->ext ); // Load if( info ) rtn = codec->load(altName, info); else rtn = codec->open(altName); if( rtn ) { if( orgNameFailed ) { Com_DPrintf(S_COLOR_YELLOW "WARNING: %s not present, using %s instead\n", filename, altName ); } return rtn; } } Com_Printf(S_COLOR_YELLOW "WARNING: Failed to %s sound %s!\n", info ? "load" : "open", filename); return NULL; }
static HINSTANCE Sys_RetrieveDLL( const char *gamename ) { char *basepath = Cvar_VariableString( "fs_basepath" ); char *homepath = Cvar_VariableString( "fs_homepath" ); char *cdpath = Cvar_VariableString( "fs_cdpath" ); char *gamedir = Cvar_VariableString( "fs_game" ); // Try basepath/fs_game char *fn = FS_BuildOSPath( basepath, gamedir, gamename ); HINSTANCE retVal = LoadLibrary( fn ); if(retVal) goto successful; if( homepath[0] ) { // Try homepath/fs_game fn = FS_BuildOSPath( homepath, gamedir, gamename ); retVal = LoadLibrary( fn ); if(retVal) goto successful; } if( cdpath[0] ) { // Try cdpath/fs_game fn = FS_BuildOSPath( cdpath, gamedir, gamename ); retVal = LoadLibrary( fn ); if(retVal) goto successful; } // Try base folder if mod is loaded but not found if (gamedir[0] ) { // Try basepath/base fn = FS_BuildOSPath( basepath, OPENJKGAME, gamename ); retVal = LoadLibrary( fn ); if(retVal) goto successful; if( homepath[0] ) { // Try homepath/base fn = FS_BuildOSPath( homepath, OPENJKGAME, gamename ); retVal = LoadLibrary( fn ); if(retVal) goto successful; } if( cdpath[0] ) { // Try cdpath/fs_game fn = FS_BuildOSPath( cdpath, OPENJKGAME, gamename ); retVal = LoadLibrary( fn ); if(retVal) goto successful; } } // Try basepath fn = va( "%s/%s", basepath, gamename ); retVal = LoadLibrary( fn ); if(retVal) goto successful; if( homepath[0] ) { // Try homepath fn = va( "%s/%s", homepath, gamename ); retVal = LoadLibrary( fn ); if(retVal) goto successful; } if( cdpath[0] ) { // Try cdpath/fs_game fn = va( "%s/%s", cdpath, gamename ); retVal = LoadLibrary( fn ); if(retVal) goto successful; } #ifdef _DEBUG // Try exepath (cwd) fn = NULL; retVal = LoadLibrary( gamename ); if(retVal) goto successful; #endif successful: Com_DPrintf("LoadLibrary (%s)\n", fn?fn:gamename); return retVal; }
/* ===================== CL_ParseDownload A download message has been received from the server ===================== */ void CL_ParseDownload ( msg_t *msg ) { int size; unsigned char data[MAX_MSGLEN]; uint16_t block; if (!*clc.downloadTempName) { Com_Printf("Server sending download, but no download was requested\n"); CL_AddReliableCommand("stopdl", qfalse); return; } // read the data block = MSG_ReadShort ( msg ); if ( !block && !clc.downloadBlock ) { // block zero is special, contains file size clc.downloadSize = MSG_ReadLong ( msg ); Cvar_SetValue( "cl_downloadSize", clc.downloadSize ); if (clc.downloadSize < 0) { Com_Error(ERR_DROP, "%s", MSG_ReadString( msg ) ); return; } } size = /*(unsigned short)*/MSG_ReadShort ( msg ); if (size < 0 || size > (int)sizeof(data)) { Com_Error(ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk", size); return; } MSG_ReadData( msg, data, size ); if((clc.downloadBlock & 0xFFFF) != block) { Com_DPrintf( "CL_ParseDownload: Expected block %d, got %d\n", (clc.downloadBlock & 0xFFFF), block); return; } // open the file if not opened yet if (!clc.download) { clc.download = FS_SV_FOpenFileWrite( clc.downloadTempName ); if (!clc.download) { Com_Printf( "Could not create %s\n", clc.downloadTempName ); CL_AddReliableCommand( "stopdl", qfalse ); CL_NextDownload(); return; } } if (size) FS_Write( data, size, clc.download ); CL_AddReliableCommand( va("nextdl %d", clc.downloadBlock), qfalse ); clc.downloadBlock++; clc.downloadCount += size; // So UI gets access to it Cvar_SetValue( "cl_downloadCount", clc.downloadCount ); if (!size) { // A zero length block means EOF if (clc.download) { FS_FCloseFile( clc.download ); clc.download = 0; // rename the file FS_SV_Rename ( clc.downloadTempName, clc.downloadName, qfalse ); } // send intentions now // We need this because without it, we would hold the last nextdl and then start // loading right away. If we take a while to load, the server is happily trying // to send us that last block over and over. // Write it twice to help make sure we acknowledge the download CL_WritePacket(); CL_WritePacket(); // get another file if needed CL_NextDownload (); } }
/* ============= RE_StretchRaw FIXME: not exactly backend Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle. Used for cinematics. ============= */ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const qbyte *data, int client, qboolean dirty) { int i, j; int start, end; if ( !tr.registered ) { return; } R_SyncRenderThread(); // we definately want to sync every frame for the cinematics qglFinish(); start = end = 0; if ( r_speeds->integer ) { start = ri.Milliseconds(); } // make sure rows and cols are powers of 2 for ( i = 0 ; ( 1 << i ) < cols ; i++ ) { } for ( j = 0 ; ( 1 << j ) < rows ; j++ ) { } if ( ( 1 << i ) != cols || ( 1 << j ) != rows) { ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows); } GL_Bind( tr.scratchImage[client] ); // if the scratchImage isn't in the format we want, specify it as a new texture if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; #ifdef IPHONE qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); #else qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); #endif // IPHONE qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); } else { if (dirty) { // otherwise, just subimage upload it so that drivers can tell we are going to be changing // it and don't try and do a texture compression qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); Com_DPrintf("blend = %d, lighting = %d\n", qglIsEnabled(GL_BLEND), qglIsEnabled(GL_LIGHTING)); } } if ( r_speeds->integer ) { end = ri.Milliseconds(); ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start ); } RB_SetGL2D(); qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); qglBegin (GL_QUADS); qglTexCoord2f ( 0.5f / cols, 0.5f / rows ); qglVertex2f (x, y); qglTexCoord2f ( ( cols - 0.5f ) / cols , 0.5f / rows ); qglVertex2f (x+w, y); qglTexCoord2f ( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows ); qglVertex2f (x+w, y+h); qglTexCoord2f ( 0.5f / cols, ( rows - 0.5f ) / rows ); qglVertex2f (x, y+h); qglEnd (); }
/* ================== SV_WriteSnapshotToClient ================== */ static void SV_WriteSnapshotToClient(client_t *client, msg_t *msg) { clientSnapshot_t *frame, *oldframe; int lastframe; int snapFlags; // this is the snapshot we are creating frame = &client->frames[client->netchan.outgoingSequence & PACKET_MASK]; // try to use a previous frame as the source for delta compressing the snapshot if (client->deltaMessage <= 0 || client->state != CS_ACTIVE) { // client is asking for a retransmit oldframe = NULL; lastframe = 0; } else if (client->netchan.outgoingSequence - client->deltaMessage >= (PACKET_BACKUP - 3)) { // client hasn't gotten a good message through in a long time Com_DPrintf("%s: Delta request from out of date packet.\n", client->name); oldframe = NULL; lastframe = 0; } else { // we have a valid snapshot to delta from oldframe = &client->frames[client->deltaMessage & PACKET_MASK]; lastframe = client->netchan.outgoingSequence - client->deltaMessage; // the snapshot's entities may still have rolled off the buffer, though if (oldframe->first_entity <= svs.nextSnapshotEntities - svs.numSnapshotEntities) { Com_DPrintf("%s: Delta request from out of date entities.\n", client->name); oldframe = NULL; lastframe = 0; } } MSG_WriteByte(msg, svc_snapshot); // NOTE, MRE: now sent at the start of every message from server to client // let the client know which reliable clientCommands we have received //MSG_WriteLong( msg, client->lastClientCommand ); // send over the current server time so the client can drift // its view of time to try to match MSG_WriteLong(msg, svs.time); // what we are delta'ing from MSG_WriteByte(msg, lastframe); snapFlags = svs.snapFlagServerBit; if (client->rateDelayed) { snapFlags |= SNAPFLAG_RATE_DELAYED; } if (client->state != CS_ACTIVE) { snapFlags |= SNAPFLAG_NOT_ACTIVE; } MSG_WriteByte(msg, snapFlags); // send over the areabits MSG_WriteByte(msg, frame->areabytes); MSG_WriteData(msg, frame->areabits, frame->areabytes); //{ //int sz = msg->cursize; //int usz = msg->uncompsize; // delta encode the playerstate if (oldframe) { MSG_WriteDeltaPlayerstate(msg, &oldframe->ps, &frame->ps); } else { MSG_WriteDeltaPlayerstate(msg, NULL, &frame->ps); } //Com_Printf( "Playerstate delta size: %f\n", ((msg->cursize - sz) * sv_fps->integer) / 8.f ); //} // delta encode the entities SV_EmitPacketEntities(oldframe, frame, msg); // padding for rate debugging if (sv_padPackets->integer) { int i; for (i = 0 ; i < sv_padPackets->integer ; i++) { MSG_WriteByte(msg, svc_nop); } } }
/* ===================== CL_ParseVoip A VoIP message has been received from the server ===================== */ static void CL_ParseVoip ( msg_t *msg, qboolean ignoreData ) { static short decoded[VOIP_MAX_PACKET_SAMPLES*4]; // !!! FIXME: don't hard code const int sender = MSG_ReadShort(msg); const int generation = MSG_ReadByte(msg); const int sequence = MSG_ReadLong(msg); const int frames = MSG_ReadByte(msg); const int packetsize = MSG_ReadShort(msg); const int flags = MSG_ReadBits(msg, VOIP_FLAGCNT); unsigned char encoded[4000]; int numSamples; int seqdiff; int written = 0; int i; Com_DPrintf("VoIP: %d-byte packet from client %d\n", packetsize, sender); if (sender < 0) return; // short/invalid packet, bail. else if (generation < 0) return; // short/invalid packet, bail. else if (sequence < 0) return; // short/invalid packet, bail. else if (frames < 0) return; // short/invalid packet, bail. else if (packetsize < 0) return; // short/invalid packet, bail. if (packetsize > sizeof (encoded)) { // overlarge packet? int bytesleft = packetsize; while (bytesleft) { int br = bytesleft; if (br > sizeof (encoded)) br = sizeof (encoded); MSG_ReadData(msg, encoded, br); bytesleft -= br; } return; // overlarge packet, bail. } MSG_ReadData(msg, encoded, packetsize); if (ignoreData) { return; // just ignore legacy speex voip data } else if (!clc.voipCodecInitialized) { return; // can't handle VoIP without libopus! } else if (sender >= MAX_CLIENTS) { return; // bogus sender. } else if (CL_ShouldIgnoreVoipSender(sender)) { return; // Channel is muted, bail. } // !!! FIXME: make sure data is narrowband? Does decoder handle this? Com_DPrintf("VoIP: packet accepted!\n"); seqdiff = sequence - clc.voipIncomingSequence[sender]; // This is a new "generation" ... a new recording started, reset the bits. if (generation != clc.voipIncomingGeneration[sender]) { Com_DPrintf("VoIP: new generation %d!\n", generation); opus_decoder_ctl(clc.opusDecoder[sender], OPUS_RESET_STATE); clc.voipIncomingGeneration[sender] = generation; seqdiff = 0; } else if (seqdiff < 0) { // we're ahead of the sequence?! // This shouldn't happen unless the packet is corrupted or something. Com_DPrintf("VoIP: misordered sequence! %d < %d!\n", sequence, clc.voipIncomingSequence[sender]); // reset the decoder just in case. opus_decoder_ctl(clc.opusDecoder[sender], OPUS_RESET_STATE); seqdiff = 0; } else if (seqdiff * VOIP_MAX_PACKET_SAMPLES*2 >= sizeof (decoded)) { // dropped more than we can handle? // just start over. Com_DPrintf("VoIP: Dropped way too many (%d) frames from client #%d\n", seqdiff, sender); opus_decoder_ctl(clc.opusDecoder[sender], OPUS_RESET_STATE); seqdiff = 0; } if (seqdiff != 0) { Com_DPrintf("VoIP: Dropped %d frames from client #%d\n", seqdiff, sender); // tell opus that we're missing frames... for (i = 0; i < seqdiff; i++) { assert((written + VOIP_MAX_PACKET_SAMPLES) * 2 < sizeof (decoded)); numSamples = opus_decode(clc.opusDecoder[sender], NULL, 0, decoded + written, VOIP_MAX_PACKET_SAMPLES, 0); if ( numSamples <= 0 ) { Com_DPrintf("VoIP: Error decoding frame %d from client #%d\n", i, sender); continue; } written += numSamples; } } numSamples = opus_decode(clc.opusDecoder[sender], encoded, packetsize, decoded + written, ARRAY_LEN(decoded) - written, 0); if ( numSamples <= 0 ) { Com_DPrintf("VoIP: Error decoding voip data from client #%d\n", sender); numSamples = 0; } #if 0 static FILE *encio = NULL; if (encio == NULL) encio = fopen("voip-incoming-encoded.bin", "wb"); if (encio != NULL) { fwrite(encoded, packetsize, 1, encio); fflush(encio); } static FILE *decio = NULL; if (decio == NULL) decio = fopen("voip-incoming-decoded.bin", "wb"); if (decio != NULL) { fwrite(decoded+written, numSamples*2, 1, decio); fflush(decio); } #endif written += numSamples; Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n", written * 2, written, frames); if(written > 0) CL_PlayVoip(sender, written, (const byte *) decoded, flags); clc.voipIncomingSequence[sender] = sequence + frames; }
/** * @brief Calculates the time the event should get executed. If two events return the same time, * they are going to be executed in the order the were parsed. * @param[in] eType The event type * @param[in,out] msg The message buffer that can be modified to get the event time * @param[in] dt Delta time in msec since the last event was parsed */ int CL_GetEventTime (const event_t eType, struct dbuffer *msg, const int dt) { const eventRegister_t *eventData = CL_GetEvent(eType); #ifdef OLDEVENTTIME /* the time the event should be executed. This value is used to sort the * event chain to determine which event must be executed at first. This * value also ensures, that the events are executed in the correct * order. E.g. @c impactTime is used to delay some events in case the * projectile needs some time to reach its target. */ int eventTime; if (eType == EV_RESET) { parsedDeath = qfalse; nextTime = 0; shootTime = 0; impactTime = 0; } else if (eType == EV_ACTOR_DIE) parsedDeath = qtrue; /* get event time */ if (nextTime < cl.time) nextTime = cl.time; if (impactTime < cl.time) impactTime = cl.time; if (eType == EV_ACTOR_DIE || eType == EV_MODEL_EXPLODE) eventTime = impactTime; else if (eType == EV_ACTOR_SHOOT || eType == EV_ACTOR_SHOOT_HIDDEN) eventTime = shootTime; else if (eType == EV_RESULTS) eventTime = nextTime + 1400; else eventTime = nextTime; if (eType == EV_ENT_APPEAR || eType == EV_INV_ADD || eType == EV_PARTICLE_APPEAR || eType == EV_PARTICLE_SPAWN) { if (parsedDeath) { /* drop items after death (caused by impact) */ eventTime = impactTime + 400; /* EV_INV_ADD messages are the last events sent after a death */ if (eType == EV_INV_ADD) parsedDeath = qfalse; } else if (impactTime > cl.time) { /* item thrown on the ground */ eventTime = impactTime + 75; } } /* calculate time interval before the next event */ switch (eType) { case EV_ACTOR_APPEAR: if (cl.actTeam != cls.team) nextTime += 600; break; case EV_INV_RELOAD: /* let the reload sound play */ nextTime += 600; break; case EV_ACTOR_START_SHOOT: nextTime += 300; shootTime = nextTime; break; case EV_ACTOR_SHOOT_HIDDEN: { int first; int objIdx; const objDef_t *obj; weaponFireDefIndex_t weapFdsIdx; fireDefIndex_t fireDefIndex; NET_ReadFormat(msg, eventData->formatString, &first, &objIdx, &weapFdsIdx, &fireDefIndex); obj = INVSH_GetItemByIDX(objIdx); if (first) { nextTime += 500; impactTime = shootTime = nextTime; } else { const fireDef_t *fd = FIRESH_GetFiredef(obj, weapFdsIdx, fireDefIndex); /* impact right away - we don't see it at all * bouncing is not needed here, too (we still don't see it) */ impactTime = shootTime; nextTime = shootTime + 1400; if (fd->delayBetweenShots > 0.0) shootTime += 1000 / fd->delayBetweenShots; } parsedDeath = qfalse; } break; case EV_ACTOR_MOVE: { le_t *le; int number, i; int time = 0; int pathLength; byte crouchingState; pos3_t pos, oldPos; number = NET_ReadShort(msg); /* get le */ le = LE_Get(number); if (!le) LE_NotFoundError(number); pathLength = NET_ReadByte(msg); /* Also skip the final position */ NET_ReadByte(msg); NET_ReadByte(msg); NET_ReadByte(msg); VectorCopy(le->pos, pos); crouchingState = LE_IsCrouched(le) ? 1 : 0; for (i = 0; i < pathLength; i++) { const dvec_t dvec = NET_ReadShort(msg); const byte dir = getDVdir(dvec); VectorCopy(pos, oldPos); PosAddDV(pos, crouchingState, dvec); time += LE_ActorGetStepTime(le, pos, oldPos, dir, NET_ReadShort(msg)); NET_ReadShort(msg); } nextTime += time + 400; } break; case EV_ACTOR_SHOOT: { const fireDef_t *fd; int flags, dummy; int objIdx, surfaceFlags; objDef_t *obj; int weap_fds_idx, fd_idx; shoot_types_t shootType; vec3_t muzzle, impact; /* read data */ NET_ReadFormat(msg, eventData->formatString, &dummy, &dummy, &dummy, &objIdx, &weap_fds_idx, &fd_idx, &shootType, &flags, &surfaceFlags, &muzzle, &impact, &dummy); obj = INVSH_GetItemByIDX(objIdx); fd = FIRESH_GetFiredef(obj, weap_fds_idx, fd_idx); if (!(flags & SF_BOUNCED)) { /* shooting */ if (fd->speed > 0.0 && !CL_OutsideMap(impact, UNIT_SIZE * 10)) { impactTime = shootTime + 1000 * VectorDist(muzzle, impact) / fd->speed; } else { impactTime = shootTime; } if (cl.actTeam != cls.team) nextTime = impactTime + 1400; else nextTime = impactTime + 400; if (fd->delayBetweenShots > 0.0) shootTime += 1000 / fd->delayBetweenShots; } else { /* only a bounced shot */ eventTime = impactTime; if (fd->speed > 0.0) { impactTime += 1000 * VectorDist(muzzle, impact) / fd->speed; nextTime = impactTime; } } parsedDeath = qfalse; } break; case EV_ACTOR_THROW: nextTime += NET_ReadShort(msg); impactTime = shootTime = nextTime; parsedDeath = qfalse; break; default: break; } Com_DPrintf(DEBUG_EVENTSYS, "%s => eventTime: %i, nextTime: %i, impactTime: %i, shootTime: %i\n", eventData->name, eventTime, nextTime, impactTime, shootTime); return eventTime; #else if (!eventData->timeCallback) return cl.time; return eventData->timeCallback(eventData, msg, dt); #endif }
void CL_cURL_BeginDownload(const char *localName, const char *remoteURL) { clc.curl.used = qtrue; Com_Printf("URL: %s\n", remoteURL); Com_DPrintf("***** CL_cURL_BeginDownload *****\n" "Localname: %s\n" "RemoteURL: %s\n" "****************************\n", localName, remoteURL); CL_cURL_Cleanup(); Q_strncpyz(clc.curl.downloadURL, remoteURL, sizeof(clc.curl.downloadURL)); Q_strncpyz(clc.downloadName, localName, sizeof(clc.downloadName)); Com_sprintf(clc.downloadTempName, sizeof(clc.downloadTempName), "%s.tmp", localName); // Set so UI gets access to it Cvar_Set("cl_downloadName", localName); Cvar_Set("cl_downloadSize", "0"); Cvar_Set("cl_downloadCount", "0"); Cvar_SetValue("cl_downloadTime", cls.realtime); clc.downloadBlock = 0; // Starting new file clc.downloadCount = 0; clc.curl.downloadCURL = qcurl_easy_init(); if(!clc.curl.downloadCURL) { Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_easy_init() failed"); return; } clc.download = FS_SV_FOpenFileWrite(clc.downloadTempName); if(!clc.download) { Com_Error(ERR_DROP, "CL_cURL_BeginDownload: failed to open %s for writing", clc.downloadTempName); return; } if(com_developer->integer) qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_VERBOSE, 1); qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_URL, clc.curl.downloadURL); qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_TRANSFERTEXT, 0); qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_REFERER, va("jka://%s", NET_AdrToString(clc.serverAddress))); qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_USERAGENT, va("%s %s", JK_VERSION, qcurl_version())); qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_WRITEFUNCTION, CL_cURL_CallbackWrite); qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_WRITEDATA, &clc.download); qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_NOPROGRESS, 0); qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_PROGRESSFUNCTION, CL_cURL_CallbackProgress); qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_SSL_VERIFYPEER, 0); qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_PROGRESSDATA, NULL); qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_FAILONERROR, 1); qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_FOLLOWLOCATION, 1); qcurl_easy_setopt(clc.curl.downloadCURL, CURLOPT_MAXREDIRS, 5); clc.curl.downloadCURLM = qcurl_multi_init(); if(!clc.curl.downloadCURLM) { qcurl_easy_cleanup(clc.curl.downloadCURL); clc.curl.downloadCURL = NULL; Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_multi_init() failed"); return; } qcurl_multi_add_handle(clc.curl.downloadCURLM, clc.curl.downloadCURL); if( // !(clc.sv_allowDownload & DLF_NO_DISCONNECT) && !clc.curl.disconnected) { CL_AddReliableCommand("disconnect", qtrue); CL_WritePacket(); CL_WritePacket(); CL_WritePacket(); clc.curl.disconnected = qtrue; } }
/* ================== SV_WriteSnapshotToClient ================== */ static void SV_WriteSnapshotToClient( client_t *client, msg_t *msg ) { clientSnapshot_t *frame, *oldframe; int lastframe; int i; int snapFlags; // this is the snapshot we are creating frame = &client->frames[ client->netchan.outgoingSequence & PACKET_MASK ]; // snapshot wasn't ever built if ( !frame->playerStates.pointer ) { return; } // try to use a previous frame as the source for delta compressing the snapshot if ( client->deltaMessage <= 0 || client->state != CS_ACTIVE ) { // client is asking for a retransmit oldframe = NULL; lastframe = 0; } else if ( client->netchan.outgoingSequence - client->deltaMessage >= (PACKET_BACKUP - 3) ) { // client hasn't gotten a good message through in a long time Com_DPrintf ("%s: Delta request from out of date packet.\n", SV_ClientName( client )); oldframe = NULL; lastframe = 0; } else { // we have a valid snapshot to delta from oldframe = &client->frames[ client->deltaMessage & PACKET_MASK ]; lastframe = client->netchan.outgoingSequence - client->deltaMessage; // the snapshot's entities may still have rolled off the buffer, though if ( oldframe->first_entity <= svs.nextSnapshotEntities - svs.numSnapshotEntities ) { Com_DPrintf ("%s: Delta request from out of date entities.\n", SV_ClientName( client )); oldframe = NULL; lastframe = 0; } } MSG_WriteByte (msg, svc_snapshot); // NOTE, MRE: now sent at the start of every message from server to client // let the client know which reliable clientCommands we have received //MSG_WriteLong( msg, client->lastClientCommand ); // send over the current server time so the client can drift // its view of time to try to match if( client->oldServerTime ) { // The server has not yet got an acknowledgement of the // new gamestate from this client, so continue to send it // a time as if the server has not restarted. Note from // the client's perspective this time is strictly speaking // incorrect, but since it'll be busy loading a map at // the time it doesn't really matter. MSG_WriteLong (msg, sv.time + client->oldServerTime); } else { MSG_WriteLong (msg, sv.time); } // what we are delta'ing from MSG_WriteByte (msg, lastframe); snapFlags = svs.snapFlagServerBit; if ( client->rateDelayed ) { snapFlags |= SNAPFLAG_RATE_DELAYED; } if ( client->state != CS_ACTIVE ) { snapFlags |= SNAPFLAG_NOT_ACTIVE; } MSG_WriteByte (msg, snapFlags); // send playerstates if (frame->numPSs > MAX_SPLITVIEW) { Com_DPrintf(S_COLOR_YELLOW "Warning: Almost sent numPSs as %d (max=%d)\n", frame->numPSs, MAX_SPLITVIEW); frame->numPSs = MAX_SPLITVIEW; } // send number of playerstates and local player indexes MSG_WriteByte (msg, frame->numPSs); for (i = 0; i < MAX_SPLITVIEW; i++) { MSG_WriteByte (msg, frame->localPlayerIndex[i]); MSG_WriteByte (msg, frame->playerNums[i]); // send over the areabits MSG_WriteByte (msg, frame->areabytes[i]); MSG_WriteData (msg, frame->areabits[i], frame->areabytes[i]); } for (i = 0; i < MAX_SPLITVIEW; i++) { if (frame->localPlayerIndex[i] == -1) { continue; } // delta encode the playerstate if ( oldframe && oldframe->localPlayerIndex[i] != -1) { MSG_WriteDeltaPlayerstate( msg, SV_SnapshotPlayer(oldframe, oldframe->localPlayerIndex[i]), SV_SnapshotPlayer(frame, frame->localPlayerIndex[i]) ); } else { MSG_WriteDeltaPlayerstate( msg, NULL, SV_SnapshotPlayer(frame, frame->localPlayerIndex[i]) ); } } // delta encode the entities SV_EmitPacketEntities (oldframe, frame, msg); // padding for rate debugging if ( sv_padPackets->integer ) { for ( i = 0 ; i < sv_padPackets->integer ; i++ ) { MSG_WriteByte (msg, svc_nop); } } }
void D_Init( void ) { qboolean started = qfalse; Com_Printf( "------ Initializing Database ------\n" ); db_enable = Cvar_Get( "db_enable", "1", CVAR_SERVERINFO | CVAR_ARCHIVE ); db_backend = Cvar_Get( "db_backend", "MySQL", CVAR_ARCHIVE ); db_statusmaster = Cvar_Get( "db_statusmaster", "0", CVAR_ARCHIVE ); db_statusslave = Cvar_Get( "db_statusslave", "0", CVAR_ARCHIVE ); // MySQL Master Server db_addressMaster = Cvar_Get( "db_addressmaster", "localhost", CVAR_ARCHIVE ); db_portMaster = Cvar_Get( "db_portmaster", "0", CVAR_ARCHIVE ); db_usernameMaster = Cvar_Get( "db_usernamemaster", "root", CVAR_ARCHIVE ); db_passwordMaster = Cvar_Get( "db_passwordmaster", "", CVAR_ARCHIVE ); db_databaseMaster = Cvar_Get( "db_databasemaster", "testdb", CVAR_ARCHIVE ); // MySQL Slave Server db_addressSlave = Cvar_Get( "db_addressslave", "localhost", CVAR_ARCHIVE ); db_portSlave = Cvar_Get( "db_portslave", "0", CVAR_ARCHIVE ); db_usernameSlave = Cvar_Get( "db_usernameslave", "root", CVAR_ARCHIVE ); db_passwordSlave = Cvar_Get( "db_passwordslave", "", CVAR_ARCHIVE ); db_databaseSlave = Cvar_Get( "db_databaseslave", "test", CVAR_ARCHIVE ); if ( db_enable->integer == 0 ) { Com_Printf( "Database Disabled.\n" ); } else { if ( strstr( db_backend->string, "MySQL" ) ) { started = D_MySQL_Init( &dbi ); } else { Cvar_Set( "db_enable", "0" ); Com_Printf( "Database was set enabled but no valid backend specified.\n" ); } if ( started ) { if ( !DB_ValidateInterface( &dbi ) ) { Com_Error( ERR_FATAL, "Database interface invalid." ); } } else { Com_Printf( "Database Initilisation Failed.\n" ); } } if ( dbi.DBConnectMaster ) { dbi.DBConnectMaster(); Cvar_Set( "db_statusmaster", "1" ); } if ( dbi.DBConnectSlave ) { dbi.DBConnectSlave(); Cvar_Set( "db_statusslave", "1" ); } if ( db_enable->integer == 1 ) { Com_DPrintf( "Master MySQL Database connected.\n" ); Com_DPrintf( "Slave MySQL Database connected.\n" ); } Com_Printf( "-----------------------------------\n" ); }
/** * @param[in] self The inventory interface pointer * @param[in] i The inventory the container is in. * @param[in] container The container where the item should be removed. * @param[in] fItem The item to be removed. * @return qtrue If removal was successful. * @return qfalse If nothing was removed or an error occurred. * @sa I_AddToInventory */ static qboolean I_RemoveFromInventory (inventoryInterface_t* self, inventory_t* const i, const invDef_t * container, invList_t *fItem) { invList_t *ic, *previous; assert(i); assert(container); assert(fItem); ic = i->c[container->id]; if (!ic) return qfalse; /** @todo the problem here is, that in case of a move inside the same container * the item don't just get updated x and y values but it is tried to remove * one of the items => crap - maybe we have to change the inventory move function * to check for this case of move and only update the x and y coordinates instead * of calling the add and remove functions */ if (container->single || ic == fItem) { self->cacheItem = ic->item; /* temp container like idEquip and idFloor */ if (container->temp && ic->item.amount > 1) { ic->item.amount--; Com_DPrintf(DEBUG_SHARED, "I_RemoveFromInventory: Amount of '%s': %i (%s)\n", ic->item.t->name, ic->item.amount, self->name); return qtrue; } if (container->single && ic->next) Com_Printf("I_RemoveFromInventory: Error: single container %s has many items. (%s)\n", container->name, self->name); /* An item in other containers than idFloor or idEquip should * always have an amount value of 1. * The other container types do not support stacking.*/ assert(ic->item.amount == 1); i->c[container->id] = ic->next; /* updated invUnused to be able to reuse this space later again */ I_RemoveInvList(self, ic); return qtrue; } for (previous = i->c[container->id]; ic; ic = ic->next) { if (ic == fItem) { self->cacheItem = ic->item; /* temp container like idEquip and idFloor */ if (ic->item.amount > 1 && container->temp) { ic->item.amount--; Com_DPrintf(DEBUG_SHARED, "I_RemoveFromInventory: Amount of '%s': %i (%s)\n", ic->item.t->name, ic->item.amount, self->name); return qtrue; } if (ic == i->c[container->id]) i->c[container->id] = i->c[container->id]->next; else previous->next = ic->next; I_RemoveInvList(self, ic); return qtrue; } previous = ic; } return qfalse; }
static int SNDDMA_InitDS () { HRESULT hresult; qboolean pauseTried; DSBUFFERDESC dsbuf; DSBCAPS dsbcaps; WAVEFORMATEX format; Com_Printf( "Initializing DirectSound\n"); if ( !hInstDS ) { Com_DPrintf( "...loading dsound.dll: " ); hInstDS = LoadLibrary("dsound.dll"); if ( hInstDS == NULL ) { Com_Printf ("failed\n"); return 0; } Com_DPrintf ("ok\n"); pDirectSoundCreate = (long (__stdcall *)(struct _GUID *,struct IDirectSound ** ,struct IUnknown *)) GetProcAddress(hInstDS,"DirectSoundCreate"); if ( !pDirectSoundCreate ) { Com_Printf ("*** couldn't get DS proc addr ***\n"); return 0; } } Com_DPrintf( "...creating DS object: " ); pauseTried = qfalse; while ( ( hresult = iDirectSoundCreate( NULL, &pDS, NULL ) ) != DS_OK ) { if ( hresult != DSERR_ALLOCATED ) { Com_Printf( "failed\n" ); return 0; } if ( pauseTried ) { Com_Printf ("failed, hardware already in use\n" ); return 0; } // first try just waiting five seconds and trying again // this will handle the case of a sysyem beep playing when the // game starts Com_DPrintf ("retrying...\n"); Sleep( 3000 ); pauseTried = qtrue; } Com_DPrintf( "ok\n" ); Com_DPrintf("...setting DSSCL_PRIORITY coop level: " ); if ( DS_OK != pDS->SetCooperativeLevel( g_wv.hWnd, DSSCL_PRIORITY ) ) { Com_Printf ("failed\n"); SNDDMA_Shutdown (); return qfalse; } Com_DPrintf("ok\n" ); // create the secondary buffer we'll actually work with dma.channels = 2; dma.samplebits = 16; if (s_khz->integer == 44) dma.speed = 44100; else if (s_khz->integer == 22) dma.speed = 22050; else dma.speed = 11025; memset (&format, 0, sizeof(format)); format.wFormatTag = WAVE_FORMAT_PCM; format.nChannels = dma.channels; format.wBitsPerSample = dma.samplebits; format.nSamplesPerSec = dma.speed; format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; format.cbSize = 0; format.nAvgBytesPerSec = format.nSamplesPerSec*format.nBlockAlign; memset (&dsbuf, 0, sizeof(dsbuf)); dsbuf.dwSize = sizeof(DSBUFFERDESC); #define idDSBCAPS_GETCURRENTPOSITION2 0x00010000 dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_LOCHARDWARE | idDSBCAPS_GETCURRENTPOSITION2; dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE; dsbuf.lpwfxFormat = &format; Com_DPrintf( "...creating secondary buffer: " ); if (DS_OK != pDS->CreateSoundBuffer(&dsbuf, &pDSBuf, NULL)) { dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY; hresult = pDS->CreateSoundBuffer(&dsbuf, &pDSBuf, NULL); if (hresult != DS_OK) { Com_Printf( "failed to create secondary buffer - %s\n", DSoundError( hresult ) ); SNDDMA_Shutdown (); return qfalse; } } Com_Printf( "locked hardware. ok\n" ); // Make sure mixer is active if ( DS_OK != pDSBuf->Play(0, 0, DSBPLAY_LOOPING) ) { Com_Printf ("*** Looped sound play failed ***\n"); SNDDMA_Shutdown (); return qfalse; } memset(&dsbcaps, 0, sizeof(dsbcaps)); dsbcaps.dwSize = sizeof(dsbcaps); // get the returned buffer size if ( DS_OK != pDSBuf->GetCaps (&dsbcaps) ) { Com_Printf ("*** GetCaps failed ***\n"); SNDDMA_Shutdown (); return qfalse; } gSndBufSize = dsbcaps.dwBufferBytes; dma.channels = format.nChannels; dma.samplebits = format.wBitsPerSample; dma.speed = format.nSamplesPerSec; dma.samples = gSndBufSize/(dma.samplebits/8); dma.submission_chunk = 1; dma.buffer = NULL; // must be locked first sample16 = (dma.samplebits/8) - 1; SNDDMA_BeginPainting (); if (dma.buffer) memset(dma.buffer, 0, dma.samples * dma.samplebits/8); SNDDMA_Submit (); return 1; }