/* ================== SV_BotAllocateClient ================== */ int SV_BotAllocateClient(void) { int i; client_t *cl; // find a client slot for ( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { if ( cl->state == CS_FREE ) { break; } } if ( i == sv_maxclients->integer ) { return -1; } cl->gentity = SV_GentityNum( i ); cl->gentity->s.number = i; cl->state = CS_ACTIVE; cl->lastPacketTime = svs.time; cl->netchan.remoteAddress.type = NA_BOT; cl->rate = 16384; // cannot start recording auto demos here since bot's name is not set yet return i; }
/* ================== SV_BotAllocateClient ================== */ int SV_BotAllocateClient( void ) { int i; client_t *cl; // find a client slot for ( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { // Wolfenstein, never use the first slot, otherwise if a bot connects before the first client on a listen server, game won't start if ( i < 1 ) { continue; } // done. if ( cl->state == CS_FREE ) { break; } } if ( i == sv_maxclients->integer ) { return -1; } cl->gentity = SV_GentityNum( i ); cl->gentity->s.number = i; cl->state = CS_ACTIVE; cl->lastPacketTime = svs.time; cl->netchan.remoteAddress.type = NA_BOT; cl->rate = 16384; return i; }
//--------------------------------------------------------------------------- // CROFFSystem::Play // Start roff playback on an entity // // INPUTS: // the id of the entity that will be roffed // the id of the roff to play // // RETURN: // success or failure of add operation //--------------------------------------------------------------------------- qboolean CROFFSystem::Play( int entID, int id, qboolean doTranslation, qboolean isClient ) { sharedEntity_t *ent = SV_GentityNum( entID ); ent->r.mIsRoffing = qtrue; /*rjr if(ent->GetPhysics() == PHYSICS_TYPE_NONE) { ent->SetPhysics(PHYSICS_TYPE_BRUSHMODEL); }*/ //bjg TODO: reset this latter? if ( ent == 0 ) { // shame on you.. return qfalse; } SROFFEntity *roffing_ent = new SROFFEntity; roffing_ent->mEntID = entID; roffing_ent->mROFFID = id; roffing_ent->mNextROFFTime = svs.time; roffing_ent->mROFFFrame = 0; roffing_ent->mKill = qfalse; roffing_ent->mSignal = qtrue; // TODO: hook up the real signal code roffing_ent->mTranslated = doTranslation; roffing_ent->mIsClient = isClient; VectorCopy(ent->s.apos.trBase, roffing_ent->mStartAngles); mROFFEntList.push_back( roffing_ent ); return qtrue; }
/* ======================================================================================================================================= SV_PointContents ======================================================================================================================================= */ int SV_PointContents(const vec3_t p, int passEntityNum) { int touch[MAX_GENTITIES]; sharedEntity_t *hit; int i, num; int contents, c2; clipHandle_t clipHandle; // get base contents from world contents = CM_PointContents(p, 0); // or in contents from all the other entities num = SV_AreaEntities(p, p, touch, MAX_GENTITIES); for (i = 0; i < num; i++) { if (touch[i] == passEntityNum) { continue; } hit = SV_GentityNum(touch[i]); // might intersect, so do an exact clip clipHandle = SV_ClipHandleForEntity(hit); // non - worldspawn entities must not use world as clip model! if (clipHandle == 0) { continue; } c2 = CM_TransformedPointContents(p, clipHandle, hit->r.currentOrigin, hit->r.currentAngles); // s.origin/angles is base origin/angles, need to use the current origin/angles for moving entity based water, or water locks in movement start position. //c2 = CM_TransformedPointContents(p, clipHandle, hit->s.origin, hit->s.angles); contents |= c2; } return contents; }
/* ================== SV_ClientEnterWorld ================== */ void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd ) { int clientNum; sharedEntity_t *ent; Com_DPrintf( "Going from CS_PRIMED to CS_ACTIVE for %s\n", client->name ); client->state = CS_ACTIVE; // resend all configstrings using the cs commands since these are // no longer sent when the client is CS_PRIMED SV_UpdateConfigstrings( client ); // set up the entity for the client clientNum = client - svs.clients; ent = SV_GentityNum( clientNum ); ent->s.number = clientNum; client->gentity = ent; client->lastUserInfoChange = 0; //reset the delay client->lastUserInfoCount = 0; //reset the count client->deltaMessage = -1; client->nextSnapshotTime = svs.time; // generate a snapshot immediately if(cmd) memcpy(&client->lastUsercmd, cmd, sizeof(client->lastUsercmd)); else memset(&client->lastUsercmd, '\0', sizeof(client->lastUsercmd)); // call the game begin function GVM_ClientBegin( client - svs.clients ); SV_BeginAutoRecordDemos(); }
/* ================== SV_ClientEnterWorld ================== */ void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd ) { int clientNum; sharedEntity_t *ent; Com_DPrintf( "Going from CS_PRIMED to CS_ACTIVE for %s\n", client->name ); client->state = CS_ACTIVE; SVC_WhitelistAdr( client->netchan.remoteAddress ); // set up the entity for the client clientNum = client - svs.clients; ent = SV_GentityNum( clientNum ); ent->s.number = clientNum; client->gentity = ent; client->lastUserInfoChange = 0; //reset the delay client->lastUserInfoCount = 0; //reset the count client->deltaMessage = -1; client->nextSnapshotTime = svs.time; // generate a snapshot immediately client->lastUsercmd = *cmd; // call the game begin function VM_Call( gvm, GAME_CLIENT_BEGIN, client - svs.clients ); }
/* ================== SV_BotAllocateClient ================== */ int SV_BotAllocateClient(int clientNum) { int i; client_t *cl; // added possibility to request a clientnum if (clientNum > 0) { if (clientNum >= sv_maxclients->integer) { return -1; } cl = &svs.clients[clientNum]; if (cl->state != CS_FREE) { return -1; } else { i = clientNum; } } else { // find a client slot for (i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++) { // Wolfenstein, never use the first slot, otherwise if a bot connects before the first client on a listen server, game won't start if (i < 1) { continue; } if (cl->state == CS_FREE) { break; // done. } } } if (i == sv_maxclients->integer) { Com_DPrintf("SV_BotAllocateClient: can't allocate a bot client.\n"); return -1; } cl->gentity = SV_GentityNum(i); cl->gentity->s.number = i; cl->state = CS_ACTIVE; cl->lastPacketTime = svs.time; cl->netchan.remoteAddress.type = NA_BOT; cl->rate = 16384; #ifdef FEATURE_TRACKER Tracker_catchBotConnect(cl - svs.clients); #endif return i; }
/* ==================== SV_ClipToEntity ==================== */ void SV_ClipToEntity( trace_t *trace, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int entityNum, int contentmask, int capsule ) { sharedEntity_t *touch; clipHandle_t clipHandle; float *origin, *angles; touch = SV_GentityNum( entityNum ); Com_Memset(trace, 0, sizeof(trace_t)); // if it doesn't have any brushes of a type we // are looking for, ignore it if ( ! ( contentmask & touch->r.contents ) ) { trace->fraction = 1.0; return; } // might intersect, so do an exact clip clipHandle = SV_ClipHandleForEntity (touch); origin = touch->r.currentOrigin; angles = touch->r.currentAngles; if ( !touch->r.bmodel ) { angles = vec3_origin; // boxes don't rotate } CM_TransformedBoxTrace ( trace, (float *)start, (float *)end, (float *)mins, (float *)maxs, clipHandle, contentmask, origin, angles, capsule); if ( trace->fraction < 1 ) { trace->entityNum = touch->s.number; } }
/* ================== SV_BotAllocateClient ================== */ int SV_BotAllocateClient(void) { int i = 0; client_t *cl; // Find a client slot - skip the first two for split screen, humans // MUST be the first two clients! extern bool SplitScreenModeActive( void ); if( SplitScreenModeActive() ) i = 2; // Likewise, for a listen server, we want the local client to be #0: else if( !com_dedicated->integer ) i = 1; for ( cl = svs.clients + i; i < sv_maxclients->integer; i++, cl++ ) { if ( cl->state == CS_FREE ) { break; } } if ( i == sv_maxclients->integer ) { return -1; } cl->gentity = SV_GentityNum( i ); cl->gentity->s.number = i; cl->state = CS_ACTIVE; cl->lastPacketTime = svs.time; cl->netchan.remoteAddress.type = NA_BOT; cl->rate = 16384; return i; }
/* ============= SV_PointContents ============= */ int SV_PointContents( const vec3_t p, int passEntityNum ) { int touch[MAX_GENTITIES]; sharedEntity_t *hit; int i, num; int contents, c2; clipHandle_t clipHandle; float *angles; // get base contents from world contents = CM_PointContents( p, 0 ); // or in contents from all the other entities num = SV_AreaEntities( p, p, touch, MAX_GENTITIES ); for ( i=0 ; i<num ; i++ ) { if ( touch[i] == passEntityNum ) { continue; } hit = SV_GentityNum( touch[i] ); // might intersect, so do an exact clip clipHandle = SV_ClipHandleForEntity( hit ); angles = hit->r.currentAngles; if ( !hit->r.bmodel ) { angles = vec3_origin; // boxes don't rotate } c2 = CM_TransformedPointContents (p, clipHandle, hit->r.currentOrigin, angles); contents |= c2; } return contents; }
edict_s* SV_GEntityForSvEntity( svEntity_t* svEnt ) { int num; num = svEnt - sv.svEntities; return SV_GentityNum( num ); }
/* ============= Q3_GetEntityByName Returns the sequencer of the entity by the given name ============= */ static sharedEntity_t *Q3_GetEntityByName( const char *name ) { sharedEntity_t *ent; entlist_t::iterator ei; char temp[1024]; if ( name == NULL || name[0] == '\0' ) return NULL; strncpy( (char *) temp, name, sizeof(temp) ); temp[sizeof(temp)-1] = 0; ei = ICARUS_EntList.find( Q_strupr( (char *) temp ) ); if ( ei == ICARUS_EntList.end() ) return NULL; ent = SV_GentityNum((*ei).second); return ent; // this now returns the ent instead of the sequencer -- dmv 06/27/01 // if (ent == NULL) // return NULL; // return gSequencers[ent->s.number]; }
void SV_RestorePos(int cli) { sharedEntity_t *ent; ent = SV_GentityNum(cli); VectorCopy(old_origin[cli], ent->s.pos.trBase); origin_changed[cli] = 0; }
void BotFindRandomPoint( int botClientNum, vec3_t point ) { qVec origin = SV_GentityNum( botClientNum )->s.origin; if ( !BotFindRandomPointInRadius( botClientNum, origin, point, 2000 ) ) { VectorCopy( origin, point ); } }
/** * @brief Changes the position of client 'other' so that it is directly * below 'player'. The distance is maintained so that sound scaling * will work correctly. */ void SV_RandomizePos(int player, int other) { sharedEntity_t *pent, *oent; vec3_t los; float dist; pent = SV_GentityNum(player); oent = SV_GentityNum(other); VectorCopy(oent->s.pos.trBase, old_origin[other]); origin_changed[other] = 1; // get distance (we need it for correct sound scaling) VectorSubtract(oent->s.pos.trBase, pent->s.pos.trBase, los); dist = vec3_length(los); // set the opponent's position directly below the player VectorCopy(pent->s.pos.trBase, oent->s.pos.trBase); oent->s.pos.trBase[2] -= dist; }
/* ------------------------- Q3_DebugPrint ------------------------- */ void Q3_DebugPrint( int level, const char *format, ... ) { //Don't print messages they don't want to see //if ( g_ICARUSDebug->integer < level ) if (!com_developer || !com_developer->integer) return; va_list argptr; char text[1024]; va_start (argptr, format); Q_vsnprintf(text, sizeof(text), format, argptr); va_end (argptr); //Add the color formatting switch ( level ) { case WL_ERROR: Com_Printf ( S_COLOR_RED"ERROR: %s", text ); break; case WL_WARNING: Com_Printf ( S_COLOR_YELLOW"WARNING: %s", text ); break; case WL_DEBUG: { int entNum; char *buffer; sscanf( text, "%d", &entNum ); if ( ( ICARUS_entFilter >= 0 ) && ( ICARUS_entFilter != entNum ) ) return; buffer = (char *) text; buffer += 5; if ( ( entNum < 0 ) || ( entNum >= MAX_GENTITIES ) ) entNum = 0; Com_Printf ( S_COLOR_BLUE"DEBUG: %s(%d): %s\n", SV_GentityNum(entNum)->script_targetname, entNum, buffer ); break; } default: case WL_VERBOSE: Com_Printf ( S_COLOR_GREEN"INFO: %s", text ); break; } }
/* ======================================================================================================================================= SV_CreateBaseline Entity baselines are used to compress non-delta messages to the clients -- only the fields that differ from the baseline will be transmitted. ======================================================================================================================================= */ static void SV_CreateBaseline(void) { sharedEntity_t *svent; int entnum; for (entnum = 1; entnum < sv.num_entities; entnum++) { svent = SV_GentityNum(entnum); if (!svent->r.linked) { continue; } svent->s.number = entnum; // take current state as baseline sv.svEntities[entnum].baseline = svent->s; } }
/* ================ SV_CreateBaseline Entity baselines are used to compress non-delta messages to the clients -- only the fields that differ from the baseline will be transmitted ================ */ static void SV_CreateBaseline( void ) { sharedEntity_t *svent; int entnum; DA_Init( &sv.svEntitiesBaseline, MAX_GENTITIES, sv.gameEntityStateSize, qfalse ); for ( entnum = 1; entnum < sv.num_entities ; entnum++ ) { svent = SV_GentityNum(entnum); if (!svent->r.linked) { continue; } svent->s.number = entnum; // // take current state as baseline // DA_SetElement( &sv.svEntitiesBaseline, entnum, SV_GameEntityStateNum(entnum) ); } }
/* ================ SV_CreateBaseline Entity baselines are used to compress non-delta messages to the clients -- only the fields that differ from the baseline will be transmitted ================ */ static void SV_CreateBaseline( void ) { edict_s* svent; int entnum; // dont create baselines for players for ( entnum = MAX_CLIENTS; entnum < sv.num_entities ; entnum++ ) { svent = SV_GentityNum( entnum ); // skip if entity is inactive if ( svent->s == 0 ) { continue; } // take current state as baseline sv.svEntities[entnum].baseline = *svent->s; } }
/* ================ SV_CreateBaseline Entity baselines are used to compress non-delta messages to the clients -- only the fields that differ from the baseline will be transmitted ================ */ void SV_CreateBaseline( void ) { gentity_t *svent; int entnum; for ( entnum = 0; entnum < ge->num_entities ; entnum++ ) { svent = SV_GentityNum(entnum); if (!svent->inuse) { continue; } if (!svent->linked) { continue; } svent->s.number = entnum; // // take current state as baseline // sv.svEntities[entnum].baseline = svent->s; } }
/* ================== SV_ClientEnterWorld ================== */ void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd ) { int clientNum; sharedEntity_t *ent; Log::Debug( "Going from CS_PRIMED to CS_ACTIVE for %s", client->name ); client->state = clientState_t::CS_ACTIVE; // set up the entity for the client clientNum = client - svs.clients; ent = SV_GentityNum( clientNum ); ent->s.number = clientNum; client->gentity = ent; client->deltaMessage = -1; client->nextSnapshotTime = svs.time; // generate a snapshot immediately client->lastUsercmd = *cmd; // call the game begin function gvm.GameClientBegin( client - svs.clients ); }
//--------------------------------------------------------------------------- // CROFFSystem::ClearLerp // Helper function to clear a given entities lerp fields // // INPUTS: // The ID of the entity to clear // // RETURN: // success or failure of the operation //--------------------------------------------------------------------------- qboolean CROFFSystem::ClearLerp( SROFFEntity *roff_ent ) { sharedEntity_t *ent; trajectory_t *originTrajectory, *angleTrajectory; vec_t *origin, *angle; if (roff_ent->mIsClient) { #ifndef DEDICATED vec3_t originTemp, angleTemp; originTrajectory = (trajectory_t *)VM_Call( cgvm, CG_GET_ORIGIN_TRAJECTORY, roff_ent->mEntID ); angleTrajectory = (trajectory_t *)VM_Call( cgvm, CG_GET_ANGLE_TRAJECTORY, roff_ent->mEntID ); VM_Call( cgvm, CG_GET_ORIGIN, roff_ent->mEntID, originTemp ); origin = originTemp; VM_Call( cgvm, CG_GET_ANGLES, roff_ent->mEntID, angleTemp ); angle = angleTemp; #endif } else { // Find the entity to apply the roff to ent = SV_GentityNum( roff_ent->mEntID ); if ( ent == 0 ) { // bad stuff return qfalse; } originTrajectory = &ent->s.pos; angleTrajectory = &ent->s.apos; origin = ent->r.currentOrigin; angle = ent->r.currentAngles; } SetLerp( originTrajectory, TR_STATIONARY, origin, NULL, svs.time, ROFF_SAMPLE_RATE ); SetLerp( angleTrajectory, TR_STATIONARY, angle, NULL, svs.time, ROFF_SAMPLE_RATE ); return qtrue; }
//--------------------------------------------------------------------------- // CROFFSystem::ClearLerp // Helper function to clear a given entities lerp fields // // INPUTS: // The ID of the entity to clear // // RETURN: // success or failure of the operation //--------------------------------------------------------------------------- qboolean CROFFSystem::ClearLerp( SROFFEntity *roff_ent ) { sharedEntity_t *ent; trajectory_t *originTrajectory = NULL, *angleTrajectory = NULL; vec_t *origin = NULL, *angle = NULL; if (roff_ent->mIsClient) { #ifndef DEDICATED vec3_t originTemp, angleTemp; originTrajectory = CGVM_GetOriginTrajectory( roff_ent->mEntID ); angleTrajectory = CGVM_GetAngleTrajectory( roff_ent->mEntID ); CGVM_GetOrigin( roff_ent->mEntID, originTemp ); origin = originTemp; CGVM_GetAngles( roff_ent->mEntID, angleTemp ); angle = angleTemp; #endif } else { // Find the entity to apply the roff to ent = SV_GentityNum( roff_ent->mEntID ); if ( ent == 0 ) { // bad stuff return qfalse; } originTrajectory = &ent->s.pos; angleTrajectory = &ent->s.apos; origin = ent->r.currentOrigin; angle = ent->r.currentAngles; } SetLerp( originTrajectory, TR_STATIONARY, origin, NULL, svs.time, ROFF_SAMPLE_RATE ); SetLerp( angleTrajectory, TR_STATIONARY, angle, NULL, svs.time, ROFF_SAMPLE_RATE ); return qtrue; }
/* ================== SV_BotAllocateClient ================== */ int SV_BotAllocateClient() { int i; for (i = std::max(1, sv_privateClients->integer); i < sv_maxclients->integer; i++) { if (svs.clients[i].state == CS_FREE) { break; } } if (i >= sv_maxclients->integer) { return -1; } client_t* cl = svs.clients + i; cl->gentity = SV_GentityNum(i); cl->gentity->s.number = i; cl->state = CS_ACTIVE; cl->lastPacketTime = svs.time; cl->netchan.remoteAddress.type = NA_BOT; cl->rate = 16384; return i; }
/* ================== SV_ClientEnterWorld ================== */ void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd, SavedGameJustLoaded_e eSavedGameJustLoaded ) { int clientNum; gentity_t *ent; Com_DPrintf ("SV_ClientEnterWorld() from %s\n", client->name); client->state = CS_ACTIVE; // set up the entity for the client clientNum = client - svs.clients; ent = SV_GentityNum( clientNum ); ent->s.number = clientNum; client->gentity = ent; // normally I check 'qbFromSavedGame' to avoid overwriting loaded client data, but this stuff I want // to be reset so that client packet delta-ing bgins afresh, rather than based on your previous frame // (which didn't in fact happen now if we've just loaded from a saved game...) // client->deltaMessage = -1; client->cmdNum = 0; // call the game begin function ge->ClientBegin( client - svs.clients, cmd, eSavedGameJustLoaded ); }
/* * SV_BotAllocateClient */ int SV_BotAllocateClient(void) { int i; Client *cl; /* find a client slot */ for(i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++) if(cl->state == CS_FREE) break; if(i == sv_maxclients->integer) return -1; cl->gentity = SV_GentityNum(i); cl->gentity->s.number = i; cl->state = CS_ACTIVE; cl->lastPacketTime = svs.time; cl->netchan.remoteAddress.type = NA_BOT; cl->rate = 16384; return i; }
/* * SV_ClipToEntity * */ void SV_ClipToEntity(Trace *trace, const Vec3 start, const Vec3 mins, const Vec3 maxs, const Vec3 end, int entityNum, int contentmask, int capsule) { Sharedent *touch; Cliphandle clipHandle; float *origin, *angles; touch = SV_GentityNum(entityNum); Q_Memset(trace, 0, sizeof(Trace)); /* if it doesn't have any brushes of a type we * are looking for, ignore it */ if(!(contentmask & touch->r.contents)){ trace->fraction = 1.0; return; } /* might intersect, so do an exact clip */ clipHandle = SV_ClipHandleForEntity (touch); origin = touch->r.currentOrigin; angles = touch->r.currentAngles; if(!touch->r.bmodel) angles = vec3_origin; /* boxes don't rotate */ CM_TransformedBoxTrace (trace, (float*)start, (float*)end, (float*)mins, (float*)maxs, clipHandle, contentmask, origin, angles, capsule); if(trace->fraction < 1) trace->entityNum = touch->s.number; }
/* * SV_PointContents */ int SV_PointContents(const Vec3 p, int passEntityNum) { int touch[MAX_GENTITIES]; Sharedent *hit; int i, num; int contents, c2; Cliphandle clipHandle; float *angles; /* get base contents from world */ contents = CM_PointContents(p, 0); /* or in contents from all the other entities */ num = SV_AreaEntities(p, p, touch, MAX_GENTITIES); for(i=0; i<num; i++){ if(touch[i] == passEntityNum) continue; hit = SV_GentityNum(touch[i]); /* might intersect, so do an exact clip */ clipHandle = SV_ClipHandleForEntity(hit); angles = hit->r.currentAngles; if(!hit->r.bmodel) angles = vec3_origin; /* boxes don't rotate */ c2 = CM_TransformedPointContents (p, clipHandle, hit->r.currentOrigin, angles); contents |= c2; } return contents; }
/* ================== SV_ClientEnterWorld ================== */ void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd ) { int clientNum; sharedEntity_t *ent; Com_DPrintf( "Going from CS_PRIMED to CS_ACTIVE for %s\n", client->name ); client->state = CS_ACTIVE; // resend all configstrings using the cs commands since these are // no longer sent when the client is CS_PRIMED SV_UpdateConfigstrings( client ); // set up the entity for the client clientNum = client - svs.clients; ent = SV_GentityNum( clientNum ); ent->s.number = clientNum; client->gentity = ent; client->deltaMessage = -1; client->nextSnapshotTime = svs.time; // generate a snapshot immediately client->lastUsercmd = *cmd; // call the game begin function VM_Call( gvm, GAME_CLIENT_BEGIN, client - svs.clients ); }
/* ================== SV_DirectConnect A "connect" OOB command has been received ================== */ void SV_DirectConnect( netadr_t from ) { char userinfo[MAX_INFO_STRING]; int i; client_t *cl, *newcl; MAC_STATIC client_t temp; gentity_t *ent; int clientNum; int version; int qport; int challenge; char *denied; Com_DPrintf ("SVC_DirectConnect ()\n"); Q_strncpyz( userinfo, Cmd_Argv(1), sizeof(userinfo) ); version = atoi( Info_ValueForKey( userinfo, "protocol" ) ); if ( version != PROTOCOL_VERSION ) { NET_OutOfBandPrint( NS_SERVER, from, "print\nServer uses protocol version %i.\n", PROTOCOL_VERSION ); Com_DPrintf (" rejected connect from version %i\n", version); return; } qport = atoi( Info_ValueForKey( userinfo, "qport" ) ); challenge = atoi( Info_ValueForKey( userinfo, "challenge" ) ); // see if the challenge is valid (local clients don't need to challenge) if ( !NET_IsLocalAddress (from) ) { NET_OutOfBandPrint( NS_SERVER, from, "print\nNo challenge for address.\n" ); return; } else { // force the "ip" info key to "localhost" Info_SetValueForKey( userinfo, "ip", "localhost" ); } newcl = &temp; memset (newcl, 0, sizeof(client_t)); // if there is already a slot for this ip, reuse it for (i=0,cl=svs.clients ; i < 1 ; i++,cl++) { if ( cl->state == CS_FREE ) { continue; } if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress ) && ( cl->netchan.qport == qport || from.port == cl->netchan.remoteAddress.port ) ) { if (( sv.time - cl->lastConnectTime) < (sv_reconnectlimit->integer * 1000)) { Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (from)); return; } Com_Printf ("%s:reconnect\n", NET_AdrToString (from)); newcl = cl; goto gotnewcl; } } newcl = NULL; for ( i = 0; i < 1 ; i++ ) { cl = &svs.clients[i]; if (cl->state == CS_FREE) { newcl = cl; break; } } if ( !newcl ) { NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is full.\n" ); Com_DPrintf ("Rejected a connection.\n"); return; } gotnewcl: // build a new connection // accept the new client // this is the only place a client_t is ever initialized *newcl = temp; clientNum = newcl - svs.clients; ent = SV_GentityNum( clientNum ); newcl->gentity = ent; // save the address Netchan_Setup (NS_SERVER, &newcl->netchan , from, qport); // save the userinfo Q_strncpyz( newcl->userinfo, userinfo, sizeof(newcl->userinfo) ); // get the game a chance to reject this connection or modify the userinfo denied = ge->ClientConnect( clientNum, qtrue, eSavedGameJustLoaded ); // firstTime = qtrue if ( denied ) { NET_OutOfBandPrint( NS_SERVER, from, "print\n%s\n", denied ); Com_DPrintf ("Game rejected a connection: %s.\n", denied); return; } SV_UserinfoChanged( newcl ); // send the connect packet to the client NET_OutOfBandPrint( NS_SERVER, from, "connectResponse" ); newcl->state = CS_CONNECTED; newcl->nextSnapshotTime = sv.time; newcl->lastPacketTime = sv.time; newcl->lastConnectTime = sv.time; // when we receive the first packet from the client, we will // notice that it is from a different serverid and that the // gamestate message was not just sent, forcing a retransmit newcl->gamestateMessageNum = -1; }