mirror of
https://github.com/id-Software/DOOM-3.git
synced 2026-03-20 08:59:56 +01:00
hello world
This commit is contained in:
2334
neo/framework/async/AsyncClient.cpp
Normal file
2334
neo/framework/async/AsyncClient.cpp
Normal file
File diff suppressed because it is too large
Load Diff
218
neo/framework/async/AsyncClient.h
Normal file
218
neo/framework/async/AsyncClient.h
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __ASYNCCLIENT_H__
|
||||
#define __ASYNCCLIENT_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Network Client for asynchronous networking.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
CS_DISCONNECTED,
|
||||
CS_PURERESTART,
|
||||
CS_CHALLENGING,
|
||||
CS_CONNECTING,
|
||||
CS_CONNECTED,
|
||||
CS_INGAME
|
||||
} clientState_t;
|
||||
|
||||
typedef enum {
|
||||
AUTHKEY_BADKEY,
|
||||
AUTHKEY_GUID
|
||||
} authKeyMsg_t;
|
||||
|
||||
typedef enum {
|
||||
AUTHKEY_BAD_INVALID,
|
||||
AUTHKEY_BAD_BANNED,
|
||||
AUTHKEY_BAD_INUSE,
|
||||
AUTHKEY_BAD_MSG
|
||||
} authBadKeyStatus_t;
|
||||
|
||||
typedef enum {
|
||||
UPDATE_NONE,
|
||||
UPDATE_SENT,
|
||||
UPDATE_READY,
|
||||
UPDATE_DLING,
|
||||
UPDATE_DONE
|
||||
} clientUpdateState_t;
|
||||
|
||||
typedef struct {
|
||||
idStr url;
|
||||
idStr filename;
|
||||
int size;
|
||||
int checksum;
|
||||
} pakDlEntry_t;
|
||||
|
||||
class idAsyncClient {
|
||||
public:
|
||||
idAsyncClient();
|
||||
|
||||
void Shutdown( void );
|
||||
bool InitPort( void );
|
||||
void ClosePort( void );
|
||||
void ConnectToServer( const netadr_t adr );
|
||||
void ConnectToServer( const char *address );
|
||||
void Reconnect( void );
|
||||
void DisconnectFromServer( void );
|
||||
void GetServerInfo( const netadr_t adr );
|
||||
void GetServerInfo( const char *address );
|
||||
void GetLANServers( void );
|
||||
void GetNETServers( void );
|
||||
void ListServers( void );
|
||||
void ClearServers( void );
|
||||
void RemoteConsole( const char *command );
|
||||
bool IsPortInitialized() { return clientPort.GetPort() != 0; }
|
||||
|
||||
bool IsActive( void ) const { return active; }
|
||||
int GetLocalClientNum( void ) const { return clientNum; }
|
||||
int GetPrediction( void ) const;
|
||||
int GetTimeSinceLastPacket( void ) const;
|
||||
int GetOutgoingRate( void ) const;
|
||||
int GetIncomingRate( void ) const;
|
||||
float GetOutgoingCompression( void ) const;
|
||||
float GetIncomingCompression( void ) const;
|
||||
float GetIncomingPacketLoss( void ) const;
|
||||
int GetPredictedFrames( void ) const { return lastFrameDelta; }
|
||||
|
||||
void RunFrame( void );
|
||||
void SendReliableGameMessage( const idBitMsg &msg );
|
||||
|
||||
void SendVersionCheck( bool fromMenu = false );
|
||||
// pass NULL for the keys you don't care to auth for
|
||||
// returns false if internet link doesn't appear to be available
|
||||
bool SendAuthCheck( const char *cdkey, const char *xpkey );
|
||||
|
||||
void PacifierUpdate( void );
|
||||
|
||||
idServerScan serverList;
|
||||
|
||||
private:
|
||||
bool active; // true if client is active
|
||||
int realTime; // absolute time
|
||||
|
||||
int clientTime; // client local time
|
||||
idPort clientPort; // UDP port
|
||||
int clientId; // client identification
|
||||
int clientDataChecksum; // checksum of the data used by the client
|
||||
int clientNum; // client number on server
|
||||
clientState_t clientState; // client state
|
||||
int clientPrediction; // how far the client predicts ahead
|
||||
int clientPredictTime; // prediction time used to send user commands
|
||||
|
||||
netadr_t serverAddress; // IP address of server
|
||||
int serverId; // server identification
|
||||
int serverChallenge; // challenge from server
|
||||
int serverMessageSequence; // sequence number of last server message
|
||||
|
||||
netadr_t lastRconAddress; // last rcon address we emitted to
|
||||
int lastRconTime; // when last rcon emitted
|
||||
|
||||
idMsgChannel channel; // message channel to server
|
||||
int lastConnectTime; // last time a connect message was sent
|
||||
int lastEmptyTime; // last time an empty message was sent
|
||||
int lastPacketTime; // last time a packet was received from the server
|
||||
int lastSnapshotTime; // last time a snapshot was received
|
||||
|
||||
int snapshotSequence; // sequence number of the last received snapshot
|
||||
int snapshotGameFrame; // game frame number of the last received snapshot
|
||||
int snapshotGameTime; // game time of the last received snapshot
|
||||
|
||||
int gameInitId; // game initialization identification
|
||||
int gameFrame; // local game frame
|
||||
int gameTime; // local game time
|
||||
int gameTimeResidual; // left over time from previous frame
|
||||
|
||||
usercmd_t userCmds[MAX_USERCMD_BACKUP][MAX_ASYNC_CLIENTS];
|
||||
|
||||
idUserInterface * guiNetMenu;
|
||||
|
||||
clientUpdateState_t updateState;
|
||||
int updateSentTime;
|
||||
idStr updateMSG;
|
||||
idStr updateURL;
|
||||
bool updateDirectDownload;
|
||||
idStr updateFile;
|
||||
dlMime_t updateMime;
|
||||
idStr updateFallback;
|
||||
bool showUpdateMessage;
|
||||
|
||||
backgroundDownload_t backgroundDownload;
|
||||
int dltotal;
|
||||
int dlnow;
|
||||
|
||||
int lastFrameDelta;
|
||||
|
||||
int dlRequest; // randomized number to keep track of the requests
|
||||
int dlChecksums[ MAX_PURE_PAKS ]; // 0-terminated, first element is the game pak checksum or 0
|
||||
int dlCount; // total number of paks we request download for ( including the game pak )
|
||||
idList<pakDlEntry_t>dlList; // list of paks to download, with url and name
|
||||
int currentDlSize;
|
||||
int totalDlSize; // for partial progress stuff
|
||||
|
||||
void Clear( void );
|
||||
void ClearPendingPackets( void );
|
||||
void DuplicateUsercmds( int frame, int time );
|
||||
void SendUserInfoToServer( void );
|
||||
void SendEmptyToServer( bool force = false, bool mapLoad = false );
|
||||
void SendPingResponseToServer( int time );
|
||||
void SendUsercmdsToServer( void );
|
||||
void InitGame( int serverGameInitId, int serverGameFrame, int serverGameTime, const idDict &serverSI );
|
||||
void ProcessUnreliableServerMessage( const idBitMsg &msg );
|
||||
void ProcessReliableServerMessages( void );
|
||||
void ProcessChallengeResponseMessage( const netadr_t from, const idBitMsg &msg );
|
||||
void ProcessConnectResponseMessage( const netadr_t from, const idBitMsg &msg );
|
||||
void ProcessDisconnectMessage( const netadr_t from, const idBitMsg &msg );
|
||||
void ProcessInfoResponseMessage( const netadr_t from, const idBitMsg &msg );
|
||||
void ProcessPrintMessage( const netadr_t from, const idBitMsg &msg );
|
||||
void ProcessServersListMessage( const netadr_t from, const idBitMsg &msg );
|
||||
void ProcessAuthKeyMessage( const netadr_t from, const idBitMsg &msg );
|
||||
void ProcessVersionMessage( const netadr_t from, const idBitMsg &msg );
|
||||
void ConnectionlessMessage( const netadr_t from, const idBitMsg &msg );
|
||||
void ProcessMessage( const netadr_t from, idBitMsg &msg );
|
||||
void SetupConnection( void );
|
||||
void ProcessPureMessage( const netadr_t from, const idBitMsg &msg );
|
||||
bool ValidatePureServerChecksums( const netadr_t from, const idBitMsg &msg );
|
||||
void ProcessReliableMessagePure( const idBitMsg &msg );
|
||||
static const char* HandleGuiCommand( const char *cmd );
|
||||
const char* HandleGuiCommandInternal( const char *cmd );
|
||||
void SendVersionDLUpdate( int state );
|
||||
void HandleDownloads( void );
|
||||
void Idle( void );
|
||||
int UpdateTime( int clamp );
|
||||
void ReadLocalizedServerString( const idBitMsg &msg, char* out, int maxLen );
|
||||
bool CheckTimeout( void );
|
||||
void ProcessDownloadInfoMessage( const netadr_t from, const idBitMsg &msg );
|
||||
int GetDownloadRequest( const int checksums[ MAX_PURE_PAKS ], int count, int gamePakChecksum );
|
||||
};
|
||||
|
||||
#endif /* !__ASYNCCLIENT_H__ */
|
||||
513
neo/framework/async/AsyncNetwork.cpp
Normal file
513
neo/framework/async/AsyncNetwork.cpp
Normal file
@@ -0,0 +1,513 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "../../idlib/precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "AsyncNetwork.h"
|
||||
|
||||
idAsyncServer idAsyncNetwork::server;
|
||||
idAsyncClient idAsyncNetwork::client;
|
||||
|
||||
idCVar idAsyncNetwork::verbose( "net_verbose", "0", CVAR_SYSTEM | CVAR_INTEGER | CVAR_NOCHEAT, "1 = verbose output, 2 = even more verbose output", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
|
||||
idCVar idAsyncNetwork::allowCheats( "net_allowCheats", "0", CVAR_SYSTEM | CVAR_BOOL | CVAR_NETWORKSYNC, "Allow cheats in network game" );
|
||||
#ifdef ID_DEDICATED
|
||||
// dedicated executable can only have a value of 1 for net_serverDedicated
|
||||
idCVar idAsyncNetwork::serverDedicated( "net_serverDedicated", "1", CVAR_SERVERINFO | CVAR_SYSTEM | CVAR_INTEGER | CVAR_NOCHEAT | CVAR_ROM, "" );
|
||||
#else
|
||||
idCVar idAsyncNetwork::serverDedicated( "net_serverDedicated", "0", CVAR_SERVERINFO | CVAR_SYSTEM | CVAR_INTEGER | CVAR_NOCHEAT, "1 = text console dedicated server, 2 = graphical dedicated server", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
|
||||
#endif
|
||||
idCVar idAsyncNetwork::serverSnapshotDelay( "net_serverSnapshotDelay", "50", CVAR_SYSTEM | CVAR_INTEGER | CVAR_NOCHEAT, "delay between snapshots in milliseconds" );
|
||||
idCVar idAsyncNetwork::serverMaxClientRate( "net_serverMaxClientRate", "16000", CVAR_SYSTEM | CVAR_INTEGER | CVAR_ARCHIVE | CVAR_NOCHEAT, "maximum rate to a client in bytes/sec" );
|
||||
idCVar idAsyncNetwork::clientMaxRate( "net_clientMaxRate", "16000", CVAR_SYSTEM | CVAR_INTEGER | CVAR_ARCHIVE | CVAR_NOCHEAT, "maximum rate requested by client from server in bytes/sec" );
|
||||
idCVar idAsyncNetwork::serverMaxUsercmdRelay( "net_serverMaxUsercmdRelay", "5", CVAR_SYSTEM | CVAR_INTEGER | CVAR_NOCHEAT, "maximum number of usercmds from other clients the server relays to a client", 1, MAX_USERCMD_RELAY, idCmdSystem::ArgCompletion_Integer<1,MAX_USERCMD_RELAY> );
|
||||
idCVar idAsyncNetwork::serverZombieTimeout( "net_serverZombieTimeout", "5", CVAR_SYSTEM | CVAR_INTEGER | CVAR_NOCHEAT, "disconnected client timeout in seconds" );
|
||||
idCVar idAsyncNetwork::serverClientTimeout( "net_serverClientTimeout", "40", CVAR_SYSTEM | CVAR_INTEGER | CVAR_NOCHEAT, "client time out in seconds" );
|
||||
idCVar idAsyncNetwork::clientServerTimeout( "net_clientServerTimeout", "40", CVAR_SYSTEM | CVAR_INTEGER | CVAR_NOCHEAT, "server time out in seconds" );
|
||||
idCVar idAsyncNetwork::serverDrawClient( "net_serverDrawClient", "-1", CVAR_SYSTEM | CVAR_INTEGER, "number of client for which to draw view on server" );
|
||||
idCVar idAsyncNetwork::serverRemoteConsolePassword( "net_serverRemoteConsolePassword", "", CVAR_SYSTEM | CVAR_NOCHEAT, "remote console password" );
|
||||
idCVar idAsyncNetwork::clientPrediction( "net_clientPrediction", "16", CVAR_SYSTEM | CVAR_INTEGER | CVAR_NOCHEAT, "additional client side prediction in milliseconds" );
|
||||
idCVar idAsyncNetwork::clientMaxPrediction( "net_clientMaxPrediction", "1000", CVAR_SYSTEM | CVAR_INTEGER | CVAR_NOCHEAT, "maximum number of milliseconds a client can predict ahead of server." );
|
||||
idCVar idAsyncNetwork::clientUsercmdBackup( "net_clientUsercmdBackup", "5", CVAR_SYSTEM | CVAR_INTEGER | CVAR_NOCHEAT, "number of usercmds to resend" );
|
||||
idCVar idAsyncNetwork::clientRemoteConsoleAddress( "net_clientRemoteConsoleAddress", "localhost", CVAR_SYSTEM | CVAR_NOCHEAT, "remote console address" );
|
||||
idCVar idAsyncNetwork::clientRemoteConsolePassword( "net_clientRemoteConsolePassword", "", CVAR_SYSTEM | CVAR_NOCHEAT, "remote console password" );
|
||||
idCVar idAsyncNetwork::master0( "net_master0", IDNET_HOST ":" IDNET_MASTER_PORT, CVAR_SYSTEM | CVAR_ROM, "idnet master server address" );
|
||||
idCVar idAsyncNetwork::master1( "net_master1", "", CVAR_SYSTEM | CVAR_ARCHIVE, "1st master server address" );
|
||||
idCVar idAsyncNetwork::master2( "net_master2", "", CVAR_SYSTEM | CVAR_ARCHIVE, "2nd master server address" );
|
||||
idCVar idAsyncNetwork::master3( "net_master3", "", CVAR_SYSTEM | CVAR_ARCHIVE, "3rd master server address" );
|
||||
idCVar idAsyncNetwork::master4( "net_master4", "", CVAR_SYSTEM | CVAR_ARCHIVE, "4th master server address" );
|
||||
idCVar idAsyncNetwork::LANServer( "net_LANServer", "0", CVAR_SYSTEM | CVAR_BOOL | CVAR_NOCHEAT, "config LAN games only - affects clients and servers" );
|
||||
idCVar idAsyncNetwork::serverReloadEngine( "net_serverReloadEngine", "0", CVAR_SYSTEM | CVAR_INTEGER | CVAR_NOCHEAT, "perform a full reload on next map restart (including flushing referenced pak files) - decreased if > 0" );
|
||||
idCVar idAsyncNetwork::serverAllowServerMod( "net_serverAllowServerMod", "0", CVAR_SYSTEM | CVAR_BOOL | CVAR_NOCHEAT, "allow server-side mods" );
|
||||
idCVar idAsyncNetwork::idleServer( "si_idleServer", "0", CVAR_SYSTEM | CVAR_BOOL | CVAR_INIT | CVAR_SERVERINFO, "game clients are idle" );
|
||||
idCVar idAsyncNetwork::clientDownload( "net_clientDownload", "1", CVAR_SYSTEM | CVAR_INTEGER | CVAR_ARCHIVE, "client pk4 downloads policy: 0 - never, 1 - ask, 2 - always (will still prompt for binary code)" );
|
||||
|
||||
int idAsyncNetwork::realTime;
|
||||
master_t idAsyncNetwork::masters[ MAX_MASTER_SERVERS ];
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::idAsyncNetwork
|
||||
==================
|
||||
*/
|
||||
idAsyncNetwork::idAsyncNetwork( void ) {
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::Init
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::Init( void ) {
|
||||
|
||||
realTime = 0;
|
||||
|
||||
memset( masters, 0, sizeof( masters ) );
|
||||
masters[0].var = &master0;
|
||||
masters[1].var = &master1;
|
||||
masters[2].var = &master2;
|
||||
masters[3].var = &master3;
|
||||
masters[4].var = &master4;
|
||||
|
||||
#ifndef ID_DEMO_BUILD
|
||||
cmdSystem->AddCommand( "spawnServer", SpawnServer_f, CMD_FL_SYSTEM, "spawns a server", idCmdSystem::ArgCompletion_MapName );
|
||||
cmdSystem->AddCommand( "nextMap", NextMap_f, CMD_FL_SYSTEM, "loads the next map on the server" );
|
||||
cmdSystem->AddCommand( "connect", Connect_f, CMD_FL_SYSTEM, "connects to a server" );
|
||||
cmdSystem->AddCommand( "reconnect", Reconnect_f, CMD_FL_SYSTEM, "reconnect to the last server we tried to connect to" );
|
||||
cmdSystem->AddCommand( "serverInfo", GetServerInfo_f, CMD_FL_SYSTEM, "shows server info" );
|
||||
cmdSystem->AddCommand( "LANScan", GetLANServers_f, CMD_FL_SYSTEM, "scans LAN for servers" );
|
||||
cmdSystem->AddCommand( "listServers", ListServers_f, CMD_FL_SYSTEM, "lists scanned servers" );
|
||||
cmdSystem->AddCommand( "rcon", RemoteConsole_f, CMD_FL_SYSTEM, "sends remote console command to server" );
|
||||
cmdSystem->AddCommand( "heartbeat", Heartbeat_f, CMD_FL_SYSTEM, "send a heartbeat to the the master servers" );
|
||||
cmdSystem->AddCommand( "kick", Kick_f, CMD_FL_SYSTEM, "kick a client by connection number" );
|
||||
cmdSystem->AddCommand( "checkNewVersion", CheckNewVersion_f, CMD_FL_SYSTEM, "check if a new version of the game is available" );
|
||||
cmdSystem->AddCommand( "updateUI", UpdateUI_f, CMD_FL_SYSTEM, "internal - cause a sync down of game-modified userinfo" );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::GetMasterAddress
|
||||
==================
|
||||
*/
|
||||
netadr_t idAsyncNetwork::GetMasterAddress( void ) {
|
||||
netadr_t ret;
|
||||
GetMasterAddress( 0, ret );
|
||||
return masters[ 0 ].address;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::GetMasterAddress
|
||||
==================
|
||||
*/
|
||||
bool idAsyncNetwork::GetMasterAddress( int index, netadr_t &adr ) {
|
||||
if ( !masters[ index ].var ) {
|
||||
return false;
|
||||
}
|
||||
if ( masters[ index ].var->GetString()[0] == '\0' ) {
|
||||
return false;
|
||||
}
|
||||
if ( !masters[ index ].resolved || masters[ index ].var->IsModified() ) {
|
||||
masters[ index ].var->ClearModified();
|
||||
if ( !Sys_StringToNetAdr( masters[ index ].var->GetString(), &masters[ index ].address, true ) ) {
|
||||
common->Printf( "Failed to resolve master%d: %s\n", index, masters[ index ].var->GetString() );
|
||||
memset( &masters[ index ].address, 0, sizeof( netadr_t ) );
|
||||
masters[ index ].resolved = true;
|
||||
return false;
|
||||
}
|
||||
if ( masters[ index ].address.port == 0 ) {
|
||||
masters[ index ].address.port = atoi( IDNET_MASTER_PORT );
|
||||
}
|
||||
masters[ index ].resolved = true;
|
||||
}
|
||||
adr = masters[ index ].address;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::Shutdown
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::Shutdown( void ) {
|
||||
client.serverList.Shutdown();
|
||||
client.DisconnectFromServer();
|
||||
client.ClearServers();
|
||||
client.ClosePort();
|
||||
server.Kill();
|
||||
server.ClosePort();
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::RunFrame
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::RunFrame( void ) {
|
||||
if ( console->Active() ) {
|
||||
Sys_GrabMouseCursor( false );
|
||||
usercmdGen->InhibitUsercmd( INHIBIT_ASYNC, true );
|
||||
} else {
|
||||
Sys_GrabMouseCursor( true );
|
||||
usercmdGen->InhibitUsercmd( INHIBIT_ASYNC, false );
|
||||
}
|
||||
client.RunFrame();
|
||||
server.RunFrame();
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::WriteUserCmdDelta
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::WriteUserCmdDelta( idBitMsg &msg, const usercmd_t &cmd, const usercmd_t *base ) {
|
||||
if ( base ) {
|
||||
msg.WriteDeltaLongCounter( base->gameTime, cmd.gameTime );
|
||||
msg.WriteDeltaByte( base->buttons, cmd.buttons );
|
||||
msg.WriteDeltaShort( base->mx, cmd.mx );
|
||||
msg.WriteDeltaShort( base->my, cmd.my );
|
||||
msg.WriteDeltaChar( base->forwardmove, cmd.forwardmove );
|
||||
msg.WriteDeltaChar( base->rightmove, cmd.rightmove );
|
||||
msg.WriteDeltaChar( base->upmove, cmd.upmove );
|
||||
msg.WriteDeltaShort( base->angles[0], cmd.angles[0] );
|
||||
msg.WriteDeltaShort( base->angles[1], cmd.angles[1] );
|
||||
msg.WriteDeltaShort( base->angles[2], cmd.angles[2] );
|
||||
return;
|
||||
}
|
||||
|
||||
msg.WriteLong( cmd.gameTime );
|
||||
msg.WriteByte( cmd.buttons );
|
||||
msg.WriteShort( cmd.mx );
|
||||
msg.WriteShort( cmd.my );
|
||||
msg.WriteChar( cmd.forwardmove );
|
||||
msg.WriteChar( cmd.rightmove );
|
||||
msg.WriteChar( cmd.upmove );
|
||||
msg.WriteShort( cmd.angles[0] );
|
||||
msg.WriteShort( cmd.angles[1] );
|
||||
msg.WriteShort( cmd.angles[2] );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::ReadUserCmdDelta
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::ReadUserCmdDelta( const idBitMsg &msg, usercmd_t &cmd, const usercmd_t *base ) {
|
||||
memset( &cmd, 0, sizeof( cmd ) );
|
||||
|
||||
if ( base ) {
|
||||
cmd.gameTime = msg.ReadDeltaLongCounter( base->gameTime );
|
||||
cmd.buttons = msg.ReadDeltaByte( base->buttons );
|
||||
cmd.mx = msg.ReadDeltaShort( base->mx );
|
||||
cmd.my = msg.ReadDeltaShort( base->my );
|
||||
cmd.forwardmove = msg.ReadDeltaChar( base->forwardmove );
|
||||
cmd.rightmove = msg.ReadDeltaChar( base->rightmove );
|
||||
cmd.upmove = msg.ReadDeltaChar( base->upmove );
|
||||
cmd.angles[0] = msg.ReadDeltaShort( base->angles[0] );
|
||||
cmd.angles[1] = msg.ReadDeltaShort( base->angles[1] );
|
||||
cmd.angles[2] = msg.ReadDeltaShort( base->angles[2] );
|
||||
return;
|
||||
}
|
||||
|
||||
cmd.gameTime = msg.ReadLong();
|
||||
cmd.buttons = msg.ReadByte();
|
||||
cmd.mx = msg.ReadShort();
|
||||
cmd.my = msg.ReadShort();
|
||||
cmd.forwardmove = msg.ReadChar();
|
||||
cmd.rightmove = msg.ReadChar();
|
||||
cmd.upmove = msg.ReadChar();
|
||||
cmd.angles[0] = msg.ReadShort();
|
||||
cmd.angles[1] = msg.ReadShort();
|
||||
cmd.angles[2] = msg.ReadShort();
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::DuplicateUsercmd
|
||||
==================
|
||||
*/
|
||||
bool idAsyncNetwork::DuplicateUsercmd( const usercmd_t &previousUserCmd, usercmd_t ¤tUserCmd, int frame, int time ) {
|
||||
|
||||
if ( currentUserCmd.gameTime <= previousUserCmd.gameTime ) {
|
||||
|
||||
currentUserCmd = previousUserCmd;
|
||||
currentUserCmd.gameFrame = frame;
|
||||
currentUserCmd.gameTime = time;
|
||||
currentUserCmd.duplicateCount++;
|
||||
|
||||
if ( currentUserCmd.duplicateCount > MAX_USERCMD_DUPLICATION ) {
|
||||
currentUserCmd.buttons &= ~BUTTON_ATTACK;
|
||||
if ( abs( currentUserCmd.forwardmove ) > 2 ) currentUserCmd.forwardmove >>= 1;
|
||||
if ( abs( currentUserCmd.rightmove ) > 2 ) currentUserCmd.rightmove >>= 1;
|
||||
if ( abs( currentUserCmd.upmove ) > 2 ) currentUserCmd.upmove >>= 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::UsercmdInputChanged
|
||||
==================
|
||||
*/
|
||||
bool idAsyncNetwork::UsercmdInputChanged( const usercmd_t &previousUserCmd, const usercmd_t ¤tUserCmd ) {
|
||||
return previousUserCmd.buttons != currentUserCmd.buttons ||
|
||||
previousUserCmd.forwardmove != currentUserCmd.forwardmove ||
|
||||
previousUserCmd.rightmove != currentUserCmd.rightmove ||
|
||||
previousUserCmd.upmove != currentUserCmd.upmove ||
|
||||
previousUserCmd.angles[0] != currentUserCmd.angles[0] ||
|
||||
previousUserCmd.angles[1] != currentUserCmd.angles[1] ||
|
||||
previousUserCmd.angles[2] != currentUserCmd.angles[2];
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::SpawnServer_f
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::SpawnServer_f( const idCmdArgs &args ) {
|
||||
|
||||
if(args.Argc() > 1) {
|
||||
cvarSystem->SetCVarString("si_map", args.Argv(1));
|
||||
}
|
||||
|
||||
// don't let a server spawn with singleplayer game type - it will crash
|
||||
if ( idStr::Icmp( cvarSystem->GetCVarString( "si_gameType" ), "singleplayer" ) == 0 ) {
|
||||
cvarSystem->SetCVarString( "si_gameType", "deathmatch" );
|
||||
}
|
||||
com_asyncInput.SetBool( false );
|
||||
// make sure the current system state is compatible with net_serverDedicated
|
||||
switch ( cvarSystem->GetCVarInteger( "net_serverDedicated" ) ) {
|
||||
case 0:
|
||||
case 2:
|
||||
if ( !renderSystem->IsOpenGLRunning() ) {
|
||||
common->Warning( "OpenGL is not running, net_serverDedicated == %d", cvarSystem->GetCVarInteger( "net_serverDedicated" ) );
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if ( renderSystem->IsOpenGLRunning() ) {
|
||||
Sys_ShowConsole( 1, false );
|
||||
renderSystem->ShutdownOpenGL();
|
||||
}
|
||||
soundSystem->SetMute( true );
|
||||
soundSystem->ShutdownHW();
|
||||
break;
|
||||
}
|
||||
// use serverMapRestart if we already have a running server
|
||||
if ( server.IsActive() ) {
|
||||
cmdSystem->BufferCommandText( CMD_EXEC_NOW, "serverMapRestart" );
|
||||
} else {
|
||||
server.Spawn();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::NextMap_f
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::NextMap_f( const idCmdArgs &args ) {
|
||||
server.ExecuteMapChange();
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::Connect_f
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::Connect_f( const idCmdArgs &args ) {
|
||||
if ( server.IsActive() ) {
|
||||
common->Printf( "already running a server\n" );
|
||||
return;
|
||||
}
|
||||
if ( args.Argc() != 2 ) {
|
||||
common->Printf( "USAGE: connect <serverName>\n" );
|
||||
return;
|
||||
}
|
||||
com_asyncInput.SetBool( false );
|
||||
client.ConnectToServer( args.Argv( 1 ) );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::Reconnect_f
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::Reconnect_f( const idCmdArgs &args ) {
|
||||
client.Reconnect();
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::GetServerInfo_f
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::GetServerInfo_f( const idCmdArgs &args ) {
|
||||
client.GetServerInfo( args.Argv( 1 ) );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::GetLANServers_f
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::GetLANServers_f( const idCmdArgs &args ) {
|
||||
client.GetLANServers();
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::ListServers_f
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::ListServers_f( const idCmdArgs &args ) {
|
||||
client.ListServers();
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::RemoteConsole_f
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::RemoteConsole_f( const idCmdArgs &args ) {
|
||||
client.RemoteConsole( args.Args() );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::Heartbeat_f
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::Heartbeat_f( const idCmdArgs &args ) {
|
||||
if ( !server.IsActive() ) {
|
||||
common->Printf( "server is not running\n" );
|
||||
return;
|
||||
}
|
||||
server.MasterHeartbeat( true );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::Kick_f
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::Kick_f( const idCmdArgs &args ) {
|
||||
idStr clientId;
|
||||
int iclient;
|
||||
|
||||
if ( !server.IsActive() ) {
|
||||
common->Printf( "server is not running\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
clientId = args.Argv( 1 );
|
||||
if ( !clientId.IsNumeric() ) {
|
||||
common->Printf( "usage: kick <client number>\n" );
|
||||
return;
|
||||
}
|
||||
iclient = atoi( clientId );
|
||||
|
||||
if ( server.GetLocalClientNum() == iclient ) {
|
||||
common->Printf( "can't kick the host\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
server.DropClient( iclient, "#str_07134" );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::GetNETServers
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::GetNETServers( ) {
|
||||
client.GetNETServers();
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::CheckNewVersion_f
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::CheckNewVersion_f( const idCmdArgs &args ) {
|
||||
client.SendVersionCheck();
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idAsyncNetwork::ExecuteSessionCommand
|
||||
==================
|
||||
*/
|
||||
void idAsyncNetwork::ExecuteSessionCommand( const char *sessCmd ) {
|
||||
if ( sessCmd[ 0 ] ) {
|
||||
if ( !idStr::Icmp( sessCmd, "game_startmenu" ) ) {
|
||||
session->SetGUI( game->StartMenu(), NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idAsyncNetwork::UpdateUI_f
|
||||
=================
|
||||
*/
|
||||
void idAsyncNetwork::UpdateUI_f( const idCmdArgs &args ) {
|
||||
if ( args.Argc() != 2 ) {
|
||||
common->Warning( "idAsyncNetwork::UpdateUI_f: wrong arguments\n" );
|
||||
return;
|
||||
}
|
||||
if ( !server.IsActive() ) {
|
||||
common->Warning( "idAsyncNetwork::UpdateUI_f: server is not active\n" );
|
||||
return;
|
||||
}
|
||||
int clientNum = atoi( args.Args( 1 ) );
|
||||
server.UpdateUI( clientNum );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idAsyncNetwork::BuildInvalidKeyMsg
|
||||
===============
|
||||
*/
|
||||
void idAsyncNetwork::BuildInvalidKeyMsg( idStr &msg, bool valid[ 2 ] ) {
|
||||
if ( !valid[ 0 ] ) {
|
||||
msg += common->GetLanguageDict()->GetString( "#str_07194" );
|
||||
}
|
||||
if ( fileSystem->HasD3XP() && !valid[ 1 ] ) {
|
||||
if ( msg.Length() ) {
|
||||
msg += "\n";
|
||||
}
|
||||
msg += common->GetLanguageDict()->GetString( "#str_07195" );
|
||||
}
|
||||
msg += "\n";
|
||||
msg += common->GetLanguageDict()->GetString( "#str_04304" );
|
||||
}
|
||||
|
||||
219
neo/framework/async/AsyncNetwork.h
Normal file
219
neo/framework/async/AsyncNetwork.h
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __ASYNCNETWORK_H__
|
||||
#define __ASYNCNETWORK_H__
|
||||
|
||||
/*
|
||||
DOOM III gold: 33
|
||||
1.1 beta patch: 34
|
||||
1.1 patch: 35
|
||||
1.2 XP: 36-39
|
||||
1.3 patch: 40
|
||||
1.3.1: 41
|
||||
*/
|
||||
const int ASYNC_PROTOCOL_MINOR = 41;
|
||||
const int ASYNC_PROTOCOL_VERSION = ( ASYNC_PROTOCOL_MAJOR << 16 ) + ASYNC_PROTOCOL_MINOR;
|
||||
#define MAJOR_VERSION(v) ( v >> 16 )
|
||||
|
||||
const int MAX_ASYNC_CLIENTS = 32;
|
||||
|
||||
const int MAX_USERCMD_BACKUP = 256;
|
||||
const int MAX_USERCMD_DUPLICATION = 25;
|
||||
const int MAX_USERCMD_RELAY = 10;
|
||||
|
||||
// index 0 is hardcoded to be the idnet master
|
||||
// which leaves 4 to user customization
|
||||
const int MAX_MASTER_SERVERS = 5;
|
||||
|
||||
const int MAX_NICKLEN = 32;
|
||||
|
||||
// max number of servers that will be scanned for at a single IP address
|
||||
const int MAX_SERVER_PORTS = 8;
|
||||
|
||||
// special game init ids
|
||||
const int GAME_INIT_ID_INVALID = -1;
|
||||
const int GAME_INIT_ID_MAP_LOAD = -2;
|
||||
|
||||
|
||||
#include "MsgChannel.h"
|
||||
#include "AsyncServer.h"
|
||||
#include "ServerScan.h"
|
||||
#include "AsyncClient.h"
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Asynchronous Networking.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
|
||||
// unreliable server -> client messages
|
||||
enum {
|
||||
SERVER_UNRELIABLE_MESSAGE_EMPTY = 0,
|
||||
SERVER_UNRELIABLE_MESSAGE_PING,
|
||||
SERVER_UNRELIABLE_MESSAGE_GAMEINIT,
|
||||
SERVER_UNRELIABLE_MESSAGE_SNAPSHOT
|
||||
};
|
||||
|
||||
// reliable server -> client messages
|
||||
enum {
|
||||
SERVER_RELIABLE_MESSAGE_PURE = 0,
|
||||
SERVER_RELIABLE_MESSAGE_RELOAD,
|
||||
SERVER_RELIABLE_MESSAGE_CLIENTINFO,
|
||||
SERVER_RELIABLE_MESSAGE_SYNCEDCVARS,
|
||||
SERVER_RELIABLE_MESSAGE_PRINT,
|
||||
SERVER_RELIABLE_MESSAGE_DISCONNECT,
|
||||
SERVER_RELIABLE_MESSAGE_APPLYSNAPSHOT,
|
||||
SERVER_RELIABLE_MESSAGE_GAME,
|
||||
SERVER_RELIABLE_MESSAGE_ENTERGAME
|
||||
};
|
||||
|
||||
// unreliable client -> server messages
|
||||
enum {
|
||||
CLIENT_UNRELIABLE_MESSAGE_EMPTY = 0,
|
||||
CLIENT_UNRELIABLE_MESSAGE_PINGRESPONSE,
|
||||
CLIENT_UNRELIABLE_MESSAGE_USERCMD
|
||||
};
|
||||
|
||||
// reliable client -> server messages
|
||||
enum {
|
||||
CLIENT_RELIABLE_MESSAGE_PURE = 0,
|
||||
CLIENT_RELIABLE_MESSAGE_CLIENTINFO,
|
||||
CLIENT_RELIABLE_MESSAGE_PRINT,
|
||||
CLIENT_RELIABLE_MESSAGE_DISCONNECT,
|
||||
CLIENT_RELIABLE_MESSAGE_GAME
|
||||
};
|
||||
|
||||
// server print messages
|
||||
enum {
|
||||
SERVER_PRINT_MISC = 0,
|
||||
SERVER_PRINT_BADPROTOCOL,
|
||||
SERVER_PRINT_RCON,
|
||||
SERVER_PRINT_GAMEDENY,
|
||||
SERVER_PRINT_BADCHALLENGE
|
||||
};
|
||||
|
||||
enum {
|
||||
SERVER_DL_REDIRECT = 1,
|
||||
SERVER_DL_LIST,
|
||||
SERVER_DL_NONE
|
||||
};
|
||||
|
||||
enum {
|
||||
SERVER_PAK_NO = 0,
|
||||
SERVER_PAK_YES,
|
||||
SERVER_PAK_END
|
||||
};
|
||||
|
||||
typedef struct master_s {
|
||||
idCVar * var;
|
||||
netadr_t address;
|
||||
bool resolved;
|
||||
} master_t;
|
||||
|
||||
|
||||
class idAsyncNetwork {
|
||||
public:
|
||||
idAsyncNetwork();
|
||||
|
||||
static void Init( void );
|
||||
static void Shutdown( void );
|
||||
static bool IsActive( void ) { return ( server.IsActive() || client.IsActive() ); }
|
||||
static void RunFrame( void );
|
||||
|
||||
static void WriteUserCmdDelta( idBitMsg &msg, const usercmd_t &cmd, const usercmd_t *base );
|
||||
static void ReadUserCmdDelta( const idBitMsg &msg, usercmd_t &cmd, const usercmd_t *base );
|
||||
|
||||
static bool DuplicateUsercmd( const usercmd_t &previousUserCmd, usercmd_t ¤tUserCmd, int frame, int time );
|
||||
static bool UsercmdInputChanged( const usercmd_t &previousUserCmd, const usercmd_t ¤tUserCmd );
|
||||
|
||||
// returns true if the corresponding master is set to something (and could be resolved)
|
||||
static bool GetMasterAddress( int index, netadr_t &adr );
|
||||
// get the hardcoded idnet master, equivalent to GetMasterAddress( 0, .. )
|
||||
static netadr_t GetMasterAddress( void );
|
||||
|
||||
static void GetNETServers( );
|
||||
|
||||
static void ExecuteSessionCommand( const char *sessCmd );
|
||||
|
||||
static idAsyncServer server;
|
||||
static idAsyncClient client;
|
||||
|
||||
static idCVar verbose; // verbose output
|
||||
static idCVar allowCheats; // allow cheats
|
||||
static idCVar serverDedicated; // if set run a dedicated server
|
||||
static idCVar serverSnapshotDelay; // number of milliseconds between snapshots
|
||||
static idCVar serverMaxClientRate; // maximum outgoing rate to clients
|
||||
static idCVar clientMaxRate; // maximum rate from server requested by client
|
||||
static idCVar serverMaxUsercmdRelay; // maximum number of usercmds relayed to other clients
|
||||
static idCVar serverZombieTimeout; // time out in seconds for zombie clients
|
||||
static idCVar serverClientTimeout; // time out in seconds for connected clients
|
||||
static idCVar clientServerTimeout; // time out in seconds for server
|
||||
static idCVar serverDrawClient; // the server draws the view of this client
|
||||
static idCVar serverRemoteConsolePassword; // remote console password
|
||||
static idCVar clientPrediction; // how many additional milliseconds the clients runs ahead
|
||||
static idCVar clientMaxPrediction; // max milliseconds into the future a client can run prediction
|
||||
static idCVar clientUsercmdBackup; // how many usercmds the client sends from previous frames
|
||||
static idCVar clientRemoteConsoleAddress; // remote console address
|
||||
static idCVar clientRemoteConsolePassword; // remote console password
|
||||
static idCVar master0; // idnet master server
|
||||
static idCVar master1; // 1st master server
|
||||
static idCVar master2; // 2nd master server
|
||||
static idCVar master3; // 3rd master server
|
||||
static idCVar master4; // 4th master server
|
||||
static idCVar LANServer; // LAN mode
|
||||
static idCVar serverReloadEngine; // reload engine on map change instead of growing the referenced paks
|
||||
static idCVar serverAllowServerMod; // let a pure server start with a different game code than what is referenced in game code
|
||||
static idCVar idleServer; // serverinfo reply, indicates all clients are idle
|
||||
static idCVar clientDownload; // preferred download policy
|
||||
|
||||
// same message used for offline check and network reply
|
||||
static void BuildInvalidKeyMsg( idStr &msg, bool valid[ 2 ] );
|
||||
|
||||
private:
|
||||
static int realTime;
|
||||
static master_t masters[ MAX_MASTER_SERVERS]; // master1 etc.
|
||||
|
||||
static void SpawnServer_f( const idCmdArgs &args );
|
||||
static void NextMap_f( const idCmdArgs &args );
|
||||
static void Connect_f( const idCmdArgs &args );
|
||||
static void Reconnect_f( const idCmdArgs &args );
|
||||
static void GetServerInfo_f( const idCmdArgs &args );
|
||||
static void GetLANServers_f( const idCmdArgs &args );
|
||||
static void ListServers_f( const idCmdArgs &args );
|
||||
static void RemoteConsole_f( const idCmdArgs &args );
|
||||
static void Heartbeat_f( const idCmdArgs &args );
|
||||
static void Kick_f( const idCmdArgs &args );
|
||||
static void CheckNewVersion_f( const idCmdArgs &args );
|
||||
static void UpdateUI_f( const idCmdArgs &args );
|
||||
};
|
||||
|
||||
#endif /* !__ASYNCNETWORK_H__ */
|
||||
2825
neo/framework/async/AsyncServer.cpp
Normal file
2825
neo/framework/async/AsyncServer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
259
neo/framework/async/AsyncServer.h
Normal file
259
neo/framework/async/AsyncServer.h
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __ASYNCSERVER_H__
|
||||
#define __ASYNCSERVER_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Network Server for asynchronous networking.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
// MAX_CHALLENGES is made large to prevent a denial of service attack that could cycle
|
||||
// all of them out before legitimate users connected
|
||||
const int MAX_CHALLENGES = 1024;
|
||||
|
||||
// if we don't hear from authorize server, assume it is down
|
||||
const int AUTHORIZE_TIMEOUT = 5000;
|
||||
|
||||
// states for the server's authorization process
|
||||
typedef enum {
|
||||
CDK_WAIT = 0, // we are waiting for a confirm/deny from auth
|
||||
// this is subject to timeout if we don't hear from auth
|
||||
// or a permanent wait if auth said so
|
||||
CDK_OK,
|
||||
CDK_ONLYLAN,
|
||||
CDK_PUREWAIT,
|
||||
CDK_PUREOK,
|
||||
CDK_MAXSTATES
|
||||
} authState_t;
|
||||
|
||||
// states from the auth server, while the client is in CDK_WAIT
|
||||
typedef enum {
|
||||
AUTH_NONE = 0, // no reply yet
|
||||
AUTH_OK, // this client is good
|
||||
AUTH_WAIT, // wait - keep sending me srvAuth though
|
||||
AUTH_DENY, // denied - don't send me anything about this client anymore
|
||||
AUTH_MAXSTATES
|
||||
} authReply_t;
|
||||
|
||||
// message from auth to be forwarded back to the client
|
||||
// some are locally hardcoded to save space, auth has the possibility to send a custom reply
|
||||
typedef enum {
|
||||
AUTH_REPLY_WAITING = 0, // waiting on an initial reply from auth
|
||||
AUTH_REPLY_UNKNOWN, // client unknown to auth
|
||||
AUTH_REPLY_DENIED, // access denied
|
||||
AUTH_REPLY_PRINT, // custom message
|
||||
AUTH_REPLY_SRVWAIT, // auth server replied and tells us he's working on it
|
||||
AUTH_REPLY_MAXSTATES
|
||||
} authReplyMsg_t;
|
||||
|
||||
typedef struct challenge_s {
|
||||
netadr_t address; // client address
|
||||
int clientId; // client identification
|
||||
int challenge; // challenge code
|
||||
int time; // time the challenge was created
|
||||
int pingTime; // time the challenge response was sent to client
|
||||
bool connected; // true if the client is connected
|
||||
authState_t authState; // local state regarding the client
|
||||
authReply_t authReply; // cd key check replies
|
||||
authReplyMsg_t authReplyMsg; // default auth messages
|
||||
idStr authReplyPrint; // custom msg
|
||||
char guid[12]; // guid
|
||||
int OS;
|
||||
} challenge_t;
|
||||
|
||||
typedef enum {
|
||||
SCS_FREE, // can be reused for a new connection
|
||||
SCS_ZOMBIE, // client has been disconnected, but don't reuse connection for a couple seconds
|
||||
SCS_PUREWAIT, // client needs to update it's pure checksums before we can go further
|
||||
SCS_CONNECTED, // client is connected
|
||||
SCS_INGAME // client is in the game
|
||||
} serverClientState_t;
|
||||
|
||||
typedef struct serverClient_s {
|
||||
int OS;
|
||||
int clientId;
|
||||
serverClientState_t clientState;
|
||||
int clientPrediction;
|
||||
int clientAheadTime;
|
||||
int clientRate;
|
||||
int clientPing;
|
||||
|
||||
int gameInitSequence;
|
||||
int gameFrame;
|
||||
int gameTime;
|
||||
|
||||
idMsgChannel channel;
|
||||
int lastConnectTime;
|
||||
int lastEmptyTime;
|
||||
int lastPingTime;
|
||||
int lastSnapshotTime;
|
||||
int lastPacketTime;
|
||||
int lastInputTime;
|
||||
int snapshotSequence;
|
||||
int acknowledgeSnapshotSequence;
|
||||
int numDuplicatedUsercmds;
|
||||
|
||||
char guid[12]; // Even Balance - M. Quinn
|
||||
|
||||
} serverClient_t;
|
||||
|
||||
|
||||
class idAsyncServer {
|
||||
public:
|
||||
idAsyncServer();
|
||||
|
||||
bool InitPort( void );
|
||||
void ClosePort( void );
|
||||
void Spawn( void );
|
||||
void Kill( void );
|
||||
void ExecuteMapChange( void );
|
||||
|
||||
int GetPort( void ) const;
|
||||
netadr_t GetBoundAdr( void ) const;
|
||||
bool IsActive( void ) const { return active; }
|
||||
int GetDelay( void ) const { return gameTimeResidual; }
|
||||
int GetOutgoingRate( void ) const;
|
||||
int GetIncomingRate( void ) const;
|
||||
bool IsClientInGame( int clientNum ) const;
|
||||
int GetClientPing( int clientNum ) const;
|
||||
int GetClientPrediction( int clientNum ) const;
|
||||
int GetClientTimeSinceLastPacket( int clientNum ) const;
|
||||
int GetClientTimeSinceLastInput( int clientNum ) const;
|
||||
int GetClientOutgoingRate( int clientNum ) const;
|
||||
int GetClientIncomingRate( int clientNum ) const;
|
||||
float GetClientOutgoingCompression( int clientNum ) const;
|
||||
float GetClientIncomingCompression( int clientNum ) const;
|
||||
float GetClientIncomingPacketLoss( int clientNum ) const;
|
||||
int GetNumClients( void ) const;
|
||||
int GetNumIdleClients( void ) const;
|
||||
int GetLocalClientNum( void ) const { return localClientNum; }
|
||||
|
||||
void RunFrame( void );
|
||||
void ProcessConnectionLessMessages( void );
|
||||
void RemoteConsoleOutput( const char *string );
|
||||
void SendReliableGameMessage( int clientNum, const idBitMsg &msg );
|
||||
void SendReliableGameMessageExcluding( int clientNum, const idBitMsg &msg );
|
||||
void LocalClientSendReliableMessage( const idBitMsg &msg );
|
||||
|
||||
void MasterHeartbeat( bool force = false );
|
||||
void DropClient( int clientNum, const char *reason );
|
||||
|
||||
void PacifierUpdate( void );
|
||||
|
||||
void UpdateUI( int clientNum );
|
||||
|
||||
void UpdateAsyncStatsAvg( void );
|
||||
void GetAsyncStatsAvgMsg( idStr &msg );
|
||||
|
||||
void PrintLocalServerInfo( void );
|
||||
|
||||
private:
|
||||
bool active; // true if server is active
|
||||
int realTime; // absolute time
|
||||
|
||||
int serverTime; // local server time
|
||||
idPort serverPort; // UDP port
|
||||
int serverId; // server identification
|
||||
int serverDataChecksum; // checksum of the data used by the server
|
||||
int localClientNum; // local client on listen server
|
||||
|
||||
challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting
|
||||
serverClient_t clients[MAX_ASYNC_CLIENTS]; // clients
|
||||
usercmd_t userCmds[MAX_USERCMD_BACKUP][MAX_ASYNC_CLIENTS];
|
||||
|
||||
int gameInitId; // game initialization identification
|
||||
int gameFrame; // local game frame
|
||||
int gameTime; // local game time
|
||||
int gameTimeResidual; // left over time from previous frame
|
||||
|
||||
netadr_t rconAddress;
|
||||
|
||||
int nextHeartbeatTime;
|
||||
int nextAsyncStatsTime;
|
||||
|
||||
bool serverReloadingEngine; // flip-flop to not loop over when net_serverReloadEngine is on
|
||||
|
||||
bool noRconOutput; // for default rcon response when command is silent
|
||||
|
||||
int lastAuthTime; // global for auth server timeout
|
||||
|
||||
// track the max outgoing rate over the last few secs to watch for spikes
|
||||
// dependent on net_serverSnapshotDelay. 50ms, for a 3 seconds backlog -> 60 samples
|
||||
static const int stats_numsamples = 60;
|
||||
int stats_outrate[ stats_numsamples ];
|
||||
int stats_current;
|
||||
int stats_average_sum;
|
||||
int stats_max;
|
||||
int stats_max_index;
|
||||
|
||||
void PrintOOB( const netadr_t to, int opcode, const char *string );
|
||||
void DuplicateUsercmds( int frame, int time );
|
||||
void ClearClient( int clientNum );
|
||||
void InitClient( int clientNum, int clientId, int clientRate );
|
||||
void InitLocalClient( int clientNum );
|
||||
void BeginLocalClient( void );
|
||||
void LocalClientInput( void );
|
||||
void CheckClientTimeouts( void );
|
||||
void SendPrintBroadcast( const char *string );
|
||||
void SendPrintToClient( int clientNum, const char *string );
|
||||
void SendUserInfoBroadcast( int userInfoNum, const idDict &info, bool sendToAll = false );
|
||||
void SendUserInfoToClient( int clientNum, int userInfoNum, const idDict &info );
|
||||
void SendSyncedCvarsBroadcast( const idDict &cvars );
|
||||
void SendSyncedCvarsToClient( int clientNum, const idDict &cvars );
|
||||
void SendApplySnapshotToClient( int clientNum, int sequence );
|
||||
bool SendEmptyToClient( int clientNum, bool force = false );
|
||||
bool SendPingToClient( int clientNum );
|
||||
void SendGameInitToClient( int clientNum );
|
||||
bool SendSnapshotToClient( int clientNum );
|
||||
void ProcessUnreliableClientMessage( int clientNum, const idBitMsg &msg );
|
||||
void ProcessReliableClientMessages( int clientNum );
|
||||
void ProcessChallengeMessage( const netadr_t from, const idBitMsg &msg );
|
||||
void ProcessConnectMessage( const netadr_t from, const idBitMsg &msg );
|
||||
void ProcessRemoteConsoleMessage( const netadr_t from, const idBitMsg &msg );
|
||||
void ProcessGetInfoMessage( const netadr_t from, const idBitMsg &msg );
|
||||
bool ConnectionlessMessage( const netadr_t from, const idBitMsg &msg );
|
||||
bool ProcessMessage( const netadr_t from, idBitMsg &msg );
|
||||
void ProcessAuthMessage( const idBitMsg &msg );
|
||||
bool SendPureServerMessage( const netadr_t to, int OS ); // returns false if no pure paks on the list
|
||||
void ProcessPureMessage( const netadr_t from, const idBitMsg &msg );
|
||||
int ValidateChallenge( const netadr_t from, int challenge, int clientId ); // returns -1 if validate failed
|
||||
bool SendReliablePureToClient( int clientNum );
|
||||
void ProcessReliablePure( int clientNum, const idBitMsg &msg );
|
||||
bool VerifyChecksumMessage( int clientNum, const netadr_t *from, const idBitMsg &msg, idStr &reply, int OS ); // if from is NULL, clientNum is used for error messages
|
||||
void SendReliableMessage( int clientNum, const idBitMsg &msg ); // checks for overflow and disconnects the faulty client
|
||||
int UpdateTime( int clamp );
|
||||
void SendEnterGameToClient( int clientNum );
|
||||
void ProcessDownloadRequestMessage( const netadr_t from, const idBitMsg &msg );
|
||||
};
|
||||
|
||||
#endif /* !__ASYNCSERVER_H__ */
|
||||
790
neo/framework/async/MsgChannel.cpp
Normal file
790
neo/framework/async/MsgChannel.cpp
Normal file
@@ -0,0 +1,790 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "../../idlib/precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "MsgChannel.h"
|
||||
|
||||
/*
|
||||
|
||||
packet header
|
||||
-------------
|
||||
2 bytes id
|
||||
4 bytes outgoing sequence. high bit will be set if this is a fragmented message.
|
||||
2 bytes optional fragment start byte if fragment bit is set.
|
||||
2 bytes optional fragment length if fragment bit is set. if < FRAGMENT_SIZE, this is the last fragment.
|
||||
|
||||
If the id is -1, the packet should be handled as an out-of-band
|
||||
message instead of as part of the message channel.
|
||||
|
||||
All fragments will have the same sequence numbers.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#define MAX_PACKETLEN 1400 // max size of a network packet
|
||||
#define FRAGMENT_SIZE (MAX_PACKETLEN - 100)
|
||||
#define FRAGMENT_BIT (1<<31)
|
||||
|
||||
idCVar net_channelShowPackets( "net_channelShowPackets", "0", CVAR_SYSTEM | CVAR_BOOL, "show all packets" );
|
||||
idCVar net_channelShowDrop( "net_channelShowDrop", "0", CVAR_SYSTEM | CVAR_BOOL, "show dropped packets" );
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgQueue::idMsgQueue
|
||||
===============
|
||||
*/
|
||||
idMsgQueue::idMsgQueue( void ) {
|
||||
Init( 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgQueue::Init
|
||||
===============
|
||||
*/
|
||||
void idMsgQueue::Init( int sequence ) {
|
||||
first = last = sequence;
|
||||
startIndex = endIndex = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgQueue::Add
|
||||
===============
|
||||
*/
|
||||
bool idMsgQueue::Add( const byte *data, const int size ) {
|
||||
if ( GetSpaceLeft() < size + 8 ) {
|
||||
return false;
|
||||
}
|
||||
int sequence = last;
|
||||
WriteShort( size );
|
||||
WriteLong( sequence );
|
||||
WriteData( data, size );
|
||||
last++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgQueue::Get
|
||||
===============
|
||||
*/
|
||||
bool idMsgQueue::Get( byte *data, int &size ) {
|
||||
if ( first == last ) {
|
||||
size = 0;
|
||||
return false;
|
||||
}
|
||||
int sequence;
|
||||
size = ReadShort();
|
||||
sequence = ReadLong();
|
||||
ReadData( data, size );
|
||||
assert( sequence == first );
|
||||
first++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgQueue::GetTotalSize
|
||||
===============
|
||||
*/
|
||||
int idMsgQueue::GetTotalSize( void ) const {
|
||||
if ( startIndex <= endIndex ) {
|
||||
return ( endIndex - startIndex );
|
||||
} else {
|
||||
return ( sizeof( buffer ) - startIndex + endIndex );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgQueue::GetSpaceLeft
|
||||
===============
|
||||
*/
|
||||
int idMsgQueue::GetSpaceLeft( void ) const {
|
||||
if ( startIndex <= endIndex ) {
|
||||
return sizeof( buffer ) - ( endIndex - startIndex ) - 1;
|
||||
} else {
|
||||
return ( startIndex - endIndex ) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgQueue::CopyToBuffer
|
||||
===============
|
||||
*/
|
||||
void idMsgQueue::CopyToBuffer( byte *buf ) const {
|
||||
if ( startIndex <= endIndex ) {
|
||||
memcpy( buf, buffer + startIndex, endIndex - startIndex );
|
||||
} else {
|
||||
memcpy( buf, buffer + startIndex, sizeof( buffer ) - startIndex );
|
||||
memcpy( buf + sizeof( buffer ) - startIndex, buffer, endIndex );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgQueue::WriteByte
|
||||
===============
|
||||
*/
|
||||
void idMsgQueue::WriteByte( byte b ) {
|
||||
buffer[endIndex] = b;
|
||||
endIndex = ( endIndex + 1 ) & ( MAX_MSG_QUEUE_SIZE - 1 );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgQueue::ReadByte
|
||||
===============
|
||||
*/
|
||||
byte idMsgQueue::ReadByte( void ) {
|
||||
byte b = buffer[startIndex];
|
||||
startIndex = ( startIndex + 1 ) & ( MAX_MSG_QUEUE_SIZE - 1 );
|
||||
return b;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgQueue::WriteShort
|
||||
===============
|
||||
*/
|
||||
void idMsgQueue::WriteShort( int s ) {
|
||||
WriteByte( ( s >> 0 ) & 255 );
|
||||
WriteByte( ( s >> 8 ) & 255 );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgQueue::ReadShort
|
||||
===============
|
||||
*/
|
||||
int idMsgQueue::ReadShort( void ) {
|
||||
return ReadByte() | ( ReadByte() << 8 );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgQueue::WriteLong
|
||||
===============
|
||||
*/
|
||||
void idMsgQueue::WriteLong( int l ) {
|
||||
WriteByte( ( l >> 0 ) & 255 );
|
||||
WriteByte( ( l >> 8 ) & 255 );
|
||||
WriteByte( ( l >> 16 ) & 255 );
|
||||
WriteByte( ( l >> 24 ) & 255 );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgQueue::ReadLong
|
||||
===============
|
||||
*/
|
||||
int idMsgQueue::ReadLong( void ) {
|
||||
return ReadByte() | ( ReadByte() << 8 ) | ( ReadByte() << 16 ) | ( ReadByte() << 24 );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgQueue::WriteData
|
||||
===============
|
||||
*/
|
||||
void idMsgQueue::WriteData( const byte *data, const int size ) {
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
WriteByte( data[i] );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgQueue::ReadData
|
||||
===============
|
||||
*/
|
||||
void idMsgQueue::ReadData( byte *data, const int size ) {
|
||||
if ( data ) {
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
data[i] = ReadByte();
|
||||
}
|
||||
} else {
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgChannel::idMsgChannel
|
||||
===============
|
||||
*/
|
||||
idMsgChannel::idMsgChannel() {
|
||||
id = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
idMsgChannel::Init
|
||||
|
||||
Opens a channel to a remote system.
|
||||
==============
|
||||
*/
|
||||
void idMsgChannel::Init( const netadr_t adr, const int id ) {
|
||||
this->remoteAddress = adr;
|
||||
this->id = id;
|
||||
this->maxRate = 50000;
|
||||
this->compressor = idCompressor::AllocRunLength_ZeroBased();
|
||||
|
||||
lastSendTime = 0;
|
||||
lastDataBytes = 0;
|
||||
outgoingRateTime = 0;
|
||||
outgoingRateBytes = 0;
|
||||
incomingRateTime = 0;
|
||||
incomingRateBytes = 0;
|
||||
incomingReceivedPackets = 0.0f;
|
||||
incomingDroppedPackets = 0.0f;
|
||||
incomingPacketLossTime = 0;
|
||||
outgoingCompression = 0.0f;
|
||||
incomingCompression = 0.0f;
|
||||
outgoingSequence = 1;
|
||||
incomingSequence = 0;
|
||||
unsentFragments = false;
|
||||
unsentFragmentStart = 0;
|
||||
fragmentSequence = 0;
|
||||
fragmentLength = 0;
|
||||
reliableSend.Init( 1 );
|
||||
reliableReceive.Init( 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgChannel::Shutdown
|
||||
================
|
||||
*/
|
||||
void idMsgChannel::Shutdown( void ) {
|
||||
delete compressor;
|
||||
compressor = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idMsgChannel::ResetRate
|
||||
=================
|
||||
*/
|
||||
void idMsgChannel::ResetRate( void ) {
|
||||
lastSendTime = 0;
|
||||
lastDataBytes = 0;
|
||||
outgoingRateTime = 0;
|
||||
outgoingRateBytes = 0;
|
||||
incomingRateTime = 0;
|
||||
incomingRateBytes = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idMsgChannel::ReadyToSend
|
||||
=================
|
||||
*/
|
||||
bool idMsgChannel::ReadyToSend( const int time ) const {
|
||||
int deltaTime;
|
||||
|
||||
if ( !maxRate ) {
|
||||
return true;
|
||||
}
|
||||
deltaTime = time - lastSendTime;
|
||||
if ( deltaTime > 1000 ) {
|
||||
return true;
|
||||
}
|
||||
return ( ( lastDataBytes - ( deltaTime * maxRate ) / 1000 ) <= 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgChannel::WriteMessageData
|
||||
================
|
||||
*/
|
||||
void idMsgChannel::WriteMessageData( idBitMsg &out, const idBitMsg &msg ) {
|
||||
idBitMsg tmp;
|
||||
byte tmpBuf[MAX_MESSAGE_SIZE];
|
||||
|
||||
tmp.Init( tmpBuf, sizeof( tmpBuf ) );
|
||||
|
||||
// write acknowledgement of last received reliable message
|
||||
tmp.WriteLong( reliableReceive.GetLast() );
|
||||
|
||||
// write reliable messages
|
||||
reliableSend.CopyToBuffer( tmp.GetData() + tmp.GetSize() );
|
||||
tmp.SetSize( tmp.GetSize() + reliableSend.GetTotalSize() );
|
||||
tmp.WriteShort( 0 );
|
||||
|
||||
// write data
|
||||
tmp.WriteData( msg.GetData(), msg.GetSize() );
|
||||
|
||||
// write message size
|
||||
out.WriteShort( tmp.GetSize() );
|
||||
|
||||
// compress message
|
||||
idFile_BitMsg file( out );
|
||||
compressor->Init( &file, true, 3 );
|
||||
compressor->Write( tmp.GetData(), tmp.GetSize() );
|
||||
compressor->FinishCompress();
|
||||
outgoingCompression = compressor->GetCompressionRatio();
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgChannel::ReadMessageData
|
||||
================
|
||||
*/
|
||||
bool idMsgChannel::ReadMessageData( idBitMsg &out, const idBitMsg &msg ) {
|
||||
int reliableAcknowledge, reliableMessageSize, reliableSequence;
|
||||
|
||||
// read message size
|
||||
out.SetSize( msg.ReadShort() );
|
||||
|
||||
// decompress message
|
||||
idFile_BitMsg file( msg );
|
||||
compressor->Init( &file, false, 3 );
|
||||
compressor->Read( out.GetData(), out.GetSize() );
|
||||
incomingCompression = compressor->GetCompressionRatio();
|
||||
out.BeginReading();
|
||||
|
||||
// read acknowledgement of sent reliable messages
|
||||
reliableAcknowledge = out.ReadLong();
|
||||
|
||||
// remove acknowledged reliable messages
|
||||
while( reliableSend.GetFirst() <= reliableAcknowledge ) {
|
||||
if ( !reliableSend.Get( NULL, reliableMessageSize ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// read reliable messages
|
||||
reliableMessageSize = out.ReadShort();
|
||||
while( reliableMessageSize != 0 ) {
|
||||
if ( reliableMessageSize <= 0 || reliableMessageSize > out.GetSize() - out.GetReadCount() ) {
|
||||
common->Printf( "%s: bad reliable message\n", Sys_NetAdrToString( remoteAddress ) );
|
||||
return false;
|
||||
}
|
||||
reliableSequence = out.ReadLong();
|
||||
if ( reliableSequence == reliableReceive.GetLast() + 1 ) {
|
||||
reliableReceive.Add( out.GetData() + out.GetReadCount(), reliableMessageSize );
|
||||
}
|
||||
out.ReadData( NULL, reliableMessageSize );
|
||||
reliableMessageSize = out.ReadShort();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idMsgChannel::SendNextFragment
|
||||
|
||||
Sends one fragment of the current message.
|
||||
=================
|
||||
*/
|
||||
void idMsgChannel::SendNextFragment( idPort &port, const int time ) {
|
||||
idBitMsg msg;
|
||||
byte msgBuf[MAX_PACKETLEN];
|
||||
int fragLength;
|
||||
|
||||
if ( remoteAddress.type == NA_BAD ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !unsentFragments ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// write the packet
|
||||
msg.Init( msgBuf, sizeof( msgBuf ) );
|
||||
msg.WriteShort( id );
|
||||
msg.WriteLong( outgoingSequence | FRAGMENT_BIT );
|
||||
|
||||
fragLength = FRAGMENT_SIZE;
|
||||
if ( unsentFragmentStart + fragLength > unsentMsg.GetSize() ) {
|
||||
fragLength = unsentMsg.GetSize() - unsentFragmentStart;
|
||||
}
|
||||
|
||||
msg.WriteShort( unsentFragmentStart );
|
||||
msg.WriteShort( fragLength );
|
||||
msg.WriteData( unsentMsg.GetData() + unsentFragmentStart, fragLength );
|
||||
|
||||
// send the packet
|
||||
port.SendPacket( remoteAddress, msg.GetData(), msg.GetSize() );
|
||||
|
||||
// update rate control variables
|
||||
UpdateOutgoingRate( time, msg.GetSize() );
|
||||
|
||||
if ( net_channelShowPackets.GetBool() ) {
|
||||
common->Printf( "%d send %4i : s = %i fragment = %i,%i\n", id, msg.GetSize(), outgoingSequence - 1, unsentFragmentStart, fragLength );
|
||||
}
|
||||
|
||||
unsentFragmentStart += fragLength;
|
||||
|
||||
// this exit condition is a little tricky, because a packet
|
||||
// that is exactly the fragment length still needs to send
|
||||
// a second packet of zero length so that the other side
|
||||
// can tell there aren't more to follow
|
||||
if ( unsentFragmentStart == unsentMsg.GetSize() && fragLength != FRAGMENT_SIZE ) {
|
||||
outgoingSequence++;
|
||||
unsentFragments = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgChannel::SendMessage
|
||||
|
||||
Sends a message to a connection, fragmenting if necessary
|
||||
A 0 length will still generate a packet.
|
||||
================
|
||||
*/
|
||||
int idMsgChannel::SendMessage( idPort &port, const int time, const idBitMsg &msg ) {
|
||||
int totalLength;
|
||||
|
||||
if ( remoteAddress.type == NA_BAD ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( unsentFragments ) {
|
||||
common->Error( "idMsgChannel::SendMessage: called with unsent fragments left" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
totalLength = 4 + reliableSend.GetTotalSize() + 4 + msg.GetSize();
|
||||
|
||||
if ( totalLength > MAX_MESSAGE_SIZE ) {
|
||||
common->Printf( "idMsgChannel::SendMessage: message too large, length = %i\n", totalLength );
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsentMsg.Init( unsentBuffer, sizeof( unsentBuffer ) );
|
||||
unsentMsg.BeginWriting();
|
||||
|
||||
// fragment large messages
|
||||
if ( totalLength >= FRAGMENT_SIZE ) {
|
||||
unsentFragments = true;
|
||||
unsentFragmentStart = 0;
|
||||
|
||||
// write out the message data
|
||||
WriteMessageData( unsentMsg, msg );
|
||||
|
||||
// send the first fragment now
|
||||
SendNextFragment( port, time );
|
||||
|
||||
return outgoingSequence;
|
||||
}
|
||||
|
||||
// write the header
|
||||
unsentMsg.WriteShort( id );
|
||||
unsentMsg.WriteLong( outgoingSequence );
|
||||
|
||||
// write out the message data
|
||||
WriteMessageData( unsentMsg, msg );
|
||||
|
||||
// send the packet
|
||||
port.SendPacket( remoteAddress, unsentMsg.GetData(), unsentMsg.GetSize() );
|
||||
|
||||
// update rate control variables
|
||||
UpdateOutgoingRate( time, unsentMsg.GetSize() );
|
||||
|
||||
if ( net_channelShowPackets.GetBool() ) {
|
||||
common->Printf( "%d send %4i : s = %i ack = %i\n", id, unsentMsg.GetSize(), outgoingSequence - 1, incomingSequence );
|
||||
}
|
||||
|
||||
outgoingSequence++;
|
||||
|
||||
return ( outgoingSequence - 1 );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idMsgChannel::Process
|
||||
|
||||
Returns false if the message should not be processed due to being out of order or a fragment.
|
||||
|
||||
msg must be large enough to hold MAX_MESSAGE_SIZE, because if this is the final
|
||||
fragment of a multi-part message, the entire thing will be copied out.
|
||||
=================
|
||||
*/
|
||||
bool idMsgChannel::Process( const netadr_t from, int time, idBitMsg &msg, int &sequence ) {
|
||||
int fragStart, fragLength, dropped;
|
||||
bool fragmented;
|
||||
idBitMsg fragMsg;
|
||||
|
||||
// the IP port can't be used to differentiate them, because
|
||||
// some address translating routers periodically change UDP
|
||||
// port assignments
|
||||
if ( remoteAddress.port != from.port ) {
|
||||
common->Printf( "idMsgChannel::Process: fixing up a translated port\n" );
|
||||
remoteAddress.port = from.port;
|
||||
}
|
||||
|
||||
// update incoming rate
|
||||
UpdateIncomingRate( time, msg.GetSize() );
|
||||
|
||||
// get sequence numbers
|
||||
sequence = msg.ReadLong();
|
||||
|
||||
// check for fragment information
|
||||
if ( sequence & FRAGMENT_BIT ) {
|
||||
sequence &= ~FRAGMENT_BIT;
|
||||
fragmented = true;
|
||||
} else {
|
||||
fragmented = false;
|
||||
}
|
||||
|
||||
// read the fragment information
|
||||
if ( fragmented ) {
|
||||
fragStart = msg.ReadShort();
|
||||
fragLength = msg.ReadShort();
|
||||
} else {
|
||||
fragStart = 0; // stop warning message
|
||||
fragLength = 0;
|
||||
}
|
||||
|
||||
if ( net_channelShowPackets.GetBool() ) {
|
||||
if ( fragmented ) {
|
||||
common->Printf( "%d recv %4i : s = %i fragment = %i,%i\n", id, msg.GetSize(), sequence, fragStart, fragLength );
|
||||
} else {
|
||||
common->Printf( "%d recv %4i : s = %i\n", id, msg.GetSize(), sequence );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// discard out of order or duplicated packets
|
||||
//
|
||||
if ( sequence <= incomingSequence ) {
|
||||
if ( net_channelShowDrop.GetBool() || net_channelShowPackets.GetBool() ) {
|
||||
common->Printf( "%s: out of order packet %i at %i\n", Sys_NetAdrToString( remoteAddress ), sequence, incomingSequence );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// dropped packets don't keep this message from being used
|
||||
//
|
||||
dropped = sequence - (incomingSequence+1);
|
||||
if ( dropped > 0 ) {
|
||||
if ( net_channelShowDrop.GetBool() || net_channelShowPackets.GetBool() ) {
|
||||
common->Printf( "%s: dropped %i packets at %i\n", Sys_NetAdrToString( remoteAddress ), dropped, sequence );
|
||||
}
|
||||
UpdatePacketLoss( time, 0, dropped );
|
||||
}
|
||||
|
||||
//
|
||||
// if the message is fragmented
|
||||
//
|
||||
if ( fragmented ) {
|
||||
// make sure we have the correct sequence number
|
||||
if ( sequence != fragmentSequence ) {
|
||||
fragmentSequence = sequence;
|
||||
fragmentLength = 0;
|
||||
}
|
||||
|
||||
// if we missed a fragment, dump the message
|
||||
if ( fragStart != fragmentLength ) {
|
||||
if ( net_channelShowDrop.GetBool() || net_channelShowPackets.GetBool() ) {
|
||||
common->Printf( "%s: dropped a message fragment at seq %d\n", Sys_NetAdrToString( remoteAddress ), sequence );
|
||||
}
|
||||
// we can still keep the part that we have so far,
|
||||
// so we don't need to clear fragmentLength
|
||||
UpdatePacketLoss( time, 0, 1 );
|
||||
return false;
|
||||
}
|
||||
|
||||
// copy the fragment to the fragment buffer
|
||||
if ( fragLength < 0 || fragLength > msg.GetRemaingData() || fragmentLength + fragLength > sizeof( fragmentBuffer ) ) {
|
||||
if ( net_channelShowDrop.GetBool() || net_channelShowPackets.GetBool() ) {
|
||||
common->Printf( "%s: illegal fragment length\n", Sys_NetAdrToString( remoteAddress ) );
|
||||
}
|
||||
UpdatePacketLoss( time, 0, 1 );
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy( fragmentBuffer + fragmentLength, msg.GetData() + msg.GetReadCount(), fragLength );
|
||||
|
||||
fragmentLength += fragLength;
|
||||
|
||||
UpdatePacketLoss( time, 1, 0 );
|
||||
|
||||
// if this wasn't the last fragment, don't process anything
|
||||
if ( fragLength == FRAGMENT_SIZE ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
memcpy( fragmentBuffer, msg.GetData() + msg.GetReadCount(), msg.GetRemaingData() );
|
||||
fragmentLength = msg.GetRemaingData();
|
||||
UpdatePacketLoss( time, 1, 0 );
|
||||
}
|
||||
|
||||
fragMsg.Init( fragmentBuffer, fragmentLength );
|
||||
fragMsg.SetSize( fragmentLength );
|
||||
fragMsg.BeginReading();
|
||||
|
||||
incomingSequence = sequence;
|
||||
|
||||
// read the message data
|
||||
if ( !ReadMessageData( msg, fragMsg ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idMsgChannel::SendReliableMessage
|
||||
=================
|
||||
*/
|
||||
bool idMsgChannel::SendReliableMessage( const idBitMsg &msg ) {
|
||||
bool result;
|
||||
|
||||
assert( remoteAddress.type != NA_BAD );
|
||||
if ( remoteAddress.type == NA_BAD ) {
|
||||
return false;
|
||||
}
|
||||
result = reliableSend.Add( msg.GetData(), msg.GetSize() );
|
||||
if ( !result ) {
|
||||
common->Warning( "idMsgChannel::SendReliableMessage: overflowed" );
|
||||
return false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idMsgChannel::GetReliableMessage
|
||||
=================
|
||||
*/
|
||||
bool idMsgChannel::GetReliableMessage( idBitMsg &msg ) {
|
||||
int size;
|
||||
bool result;
|
||||
|
||||
result = reliableReceive.Get( msg.GetData(), size );
|
||||
msg.SetSize( size );
|
||||
msg.BeginReading();
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idMsgChannel::ClearReliableMessages
|
||||
================
|
||||
*/
|
||||
void idMsgChannel::ClearReliableMessages( void ) {
|
||||
reliableSend.Init( 1 );
|
||||
reliableReceive.Init( 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idMsgChannel::UpdateOutgoingRate
|
||||
=================
|
||||
*/
|
||||
void idMsgChannel::UpdateOutgoingRate( const int time, const int size ) {
|
||||
// update the outgoing rate control variables
|
||||
int deltaTime = time - lastSendTime;
|
||||
if ( deltaTime > 1000 ) {
|
||||
lastDataBytes = 0;
|
||||
} else {
|
||||
lastDataBytes -= ( deltaTime * maxRate ) / 1000;
|
||||
if ( lastDataBytes < 0 ) {
|
||||
lastDataBytes = 0;
|
||||
}
|
||||
}
|
||||
lastDataBytes += size;
|
||||
lastSendTime = time;
|
||||
|
||||
// update outgoing rate variables
|
||||
if ( time - outgoingRateTime > 1000 ) {
|
||||
outgoingRateBytes -= outgoingRateBytes * ( time - outgoingRateTime - 1000 ) / 1000;
|
||||
if ( outgoingRateBytes < 0 ) {
|
||||
outgoingRateBytes = 0;
|
||||
}
|
||||
}
|
||||
outgoingRateTime = time - 1000;
|
||||
outgoingRateBytes += size;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idMsgChannel::UpdateIncomingRate
|
||||
=================
|
||||
*/
|
||||
void idMsgChannel::UpdateIncomingRate( const int time, const int size ) {
|
||||
// update incoming rate variables
|
||||
if ( time - incomingRateTime > 1000 ) {
|
||||
incomingRateBytes -= incomingRateBytes * ( time - incomingRateTime - 1000 ) / 1000;
|
||||
if ( incomingRateBytes < 0 ) {
|
||||
incomingRateBytes = 0;
|
||||
}
|
||||
}
|
||||
incomingRateTime = time - 1000;
|
||||
incomingRateBytes += size;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idMsgChannel::UpdatePacketLoss
|
||||
=================
|
||||
*/
|
||||
void idMsgChannel::UpdatePacketLoss( const int time, const int numReceived, const int numDropped ) {
|
||||
// update incoming packet loss variables
|
||||
if ( time - incomingPacketLossTime > 5000 ) {
|
||||
float scale = ( time - incomingPacketLossTime - 5000 ) * ( 1.0f / 5000.0f );
|
||||
incomingReceivedPackets -= incomingReceivedPackets * scale;
|
||||
if ( incomingReceivedPackets < 0.0f ) {
|
||||
incomingReceivedPackets = 0.0f;
|
||||
}
|
||||
incomingDroppedPackets -= incomingDroppedPackets * scale;
|
||||
if ( incomingDroppedPackets < 0.0f ) {
|
||||
incomingDroppedPackets = 0.0f;
|
||||
}
|
||||
}
|
||||
incomingPacketLossTime = time - 5000;
|
||||
incomingReceivedPackets += numReceived;
|
||||
incomingDroppedPackets += numDropped;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idMsgChannel::GetIncomingPacketLoss
|
||||
=================
|
||||
*/
|
||||
float idMsgChannel::GetIncomingPacketLoss( void ) const {
|
||||
if ( incomingReceivedPackets == 0.0f && incomingDroppedPackets == 0.0f ) {
|
||||
return 0.0f;
|
||||
}
|
||||
return incomingDroppedPackets * 100.0f / ( incomingReceivedPackets + incomingDroppedPackets );
|
||||
}
|
||||
201
neo/framework/async/MsgChannel.h
Normal file
201
neo/framework/async/MsgChannel.h
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __MSGCHANNEL_H__
|
||||
#define __MSGCHANNEL_H__
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Network channel.
|
||||
|
||||
Handles message fragmentation and out of order / duplicate suppression.
|
||||
Unreliable messages are not garrenteed to arrive but when they do, they
|
||||
arrive in order and without duplicates. Reliable messages always arrive,
|
||||
and they also arrive in order without duplicates. Reliable messages piggy
|
||||
back on unreliable messages. As such an unreliable message stream is
|
||||
required for the reliable messages to be delivered.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#define MAX_MESSAGE_SIZE 16384 // max length of a message, which may
|
||||
// be fragmented into multiple packets
|
||||
#define CONNECTIONLESS_MESSAGE_ID -1 // id for connectionless messages
|
||||
#define CONNECTIONLESS_MESSAGE_ID_MASK 0x7FFF // value to mask away connectionless message id
|
||||
|
||||
#define MAX_MSG_QUEUE_SIZE 16384 // must be a power of 2
|
||||
|
||||
|
||||
class idMsgQueue {
|
||||
public:
|
||||
idMsgQueue();
|
||||
|
||||
void Init( int sequence );
|
||||
|
||||
bool Add( const byte *data, const int size );
|
||||
bool Get( byte *data, int &size );
|
||||
int GetTotalSize( void ) const;
|
||||
int GetSpaceLeft( void ) const;
|
||||
int GetFirst( void ) const { return first; }
|
||||
int GetLast( void ) const { return last; }
|
||||
void CopyToBuffer( byte *buf ) const;
|
||||
|
||||
private:
|
||||
byte buffer[MAX_MSG_QUEUE_SIZE];
|
||||
int first; // sequence number of first message in queue
|
||||
int last; // sequence number of last message in queue
|
||||
int startIndex; // index pointing to the first byte of the first message
|
||||
int endIndex; // index pointing to the first byte after the last message
|
||||
|
||||
void WriteByte( byte b );
|
||||
byte ReadByte( void );
|
||||
void WriteShort( int s );
|
||||
int ReadShort( void );
|
||||
void WriteLong( int l );
|
||||
int ReadLong( void );
|
||||
void WriteData( const byte *data, const int size );
|
||||
void ReadData( byte *data, const int size );
|
||||
};
|
||||
|
||||
|
||||
class idMsgChannel {
|
||||
public:
|
||||
idMsgChannel();
|
||||
|
||||
void Init( const netadr_t adr, const int id );
|
||||
void Shutdown( void );
|
||||
void ResetRate( void );
|
||||
|
||||
// Sets the maximum outgoing rate.
|
||||
void SetMaxOutgoingRate( int rate ) { maxRate = rate; }
|
||||
|
||||
// Gets the maximum outgoing rate.
|
||||
int GetMaxOutgoingRate( void ) { return maxRate; }
|
||||
|
||||
// Returns the address of the entity at the other side of the channel.
|
||||
netadr_t GetRemoteAddress( void ) const { return remoteAddress; }
|
||||
|
||||
// Returns the average outgoing rate over the last second.
|
||||
int GetOutgoingRate( void ) const { return outgoingRateBytes; }
|
||||
|
||||
// Returns the average incoming rate over the last second.
|
||||
int GetIncomingRate( void ) const { return incomingRateBytes; }
|
||||
|
||||
// Returns the average outgoing compression ratio over the last second.
|
||||
float GetOutgoingCompression( void ) const { return outgoingCompression; }
|
||||
|
||||
// Returns the average incoming compression ratio over the last second.
|
||||
float GetIncomingCompression( void ) const { return incomingCompression; }
|
||||
|
||||
// Returns the average incoming packet loss over the last 5 seconds.
|
||||
float GetIncomingPacketLoss( void ) const;
|
||||
|
||||
// Returns true if the channel is ready to send new data based on the maximum rate.
|
||||
bool ReadyToSend( const int time ) const;
|
||||
|
||||
// Sends an unreliable message, in order and without duplicates.
|
||||
int SendMessage( idPort &port, const int time, const idBitMsg &msg );
|
||||
|
||||
// Sends the next fragment if the last message was too large to send at once.
|
||||
void SendNextFragment( idPort &port, const int time );
|
||||
|
||||
// Returns true if there are unsent fragments left.
|
||||
bool UnsentFragmentsLeft( void ) const { return unsentFragments; }
|
||||
|
||||
// Processes the incoming message. Returns true when a complete message
|
||||
// is ready for further processing. In that case the read pointer of msg
|
||||
// points to the first byte ready for reading, and sequence is set to
|
||||
// the sequence number of the message.
|
||||
bool Process( const netadr_t from, int time, idBitMsg &msg, int &sequence );
|
||||
|
||||
// Sends a reliable message, in order and without duplicates.
|
||||
bool SendReliableMessage( const idBitMsg &msg );
|
||||
|
||||
// Returns true if a new reliable message is available and stores the message.
|
||||
bool GetReliableMessage( idBitMsg &msg );
|
||||
|
||||
// Removes any pending outgoing or incoming reliable messages.
|
||||
void ClearReliableMessages( void );
|
||||
|
||||
private:
|
||||
netadr_t remoteAddress; // address of remote host
|
||||
int id; // our identification used instead of port number
|
||||
int maxRate; // maximum number of bytes that may go out per second
|
||||
idCompressor * compressor; // compressor used for data compression
|
||||
|
||||
// variables to control the outgoing rate
|
||||
int lastSendTime; // last time data was sent out
|
||||
int lastDataBytes; // bytes left to send at last send time
|
||||
|
||||
// variables to keep track of the rate
|
||||
int outgoingRateTime;
|
||||
int outgoingRateBytes;
|
||||
int incomingRateTime;
|
||||
int incomingRateBytes;
|
||||
|
||||
// variables to keep track of the compression ratio
|
||||
float outgoingCompression;
|
||||
float incomingCompression;
|
||||
|
||||
// variables to keep track of the incoming packet loss
|
||||
float incomingReceivedPackets;
|
||||
float incomingDroppedPackets;
|
||||
int incomingPacketLossTime;
|
||||
|
||||
// sequencing variables
|
||||
int outgoingSequence;
|
||||
int incomingSequence;
|
||||
|
||||
// outgoing fragment buffer
|
||||
bool unsentFragments;
|
||||
int unsentFragmentStart;
|
||||
byte unsentBuffer[MAX_MESSAGE_SIZE];
|
||||
idBitMsg unsentMsg;
|
||||
|
||||
// incoming fragment assembly buffer
|
||||
int fragmentSequence;
|
||||
int fragmentLength;
|
||||
byte fragmentBuffer[MAX_MESSAGE_SIZE];
|
||||
|
||||
// reliable messages
|
||||
idMsgQueue reliableSend;
|
||||
idMsgQueue reliableReceive;
|
||||
|
||||
private:
|
||||
void WriteMessageData( idBitMsg &out, const idBitMsg &msg );
|
||||
bool ReadMessageData( idBitMsg &out, const idBitMsg &msg );
|
||||
|
||||
void UpdateOutgoingRate( const int time, const int size );
|
||||
void UpdateIncomingRate( const int time, const int size );
|
||||
|
||||
void UpdatePacketLoss( const int time, const int numReceived, const int numDropped );
|
||||
};
|
||||
|
||||
#endif /* !__MSGCHANNEL_H__ */
|
||||
215
neo/framework/async/NetworkSystem.cpp
Normal file
215
neo/framework/async/NetworkSystem.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "../../idlib/precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "NetworkSystem.h"
|
||||
|
||||
idNetworkSystem networkSystemLocal;
|
||||
idNetworkSystem * networkSystem = &networkSystemLocal;
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
idNetworkSystem::ServerSendReliableMessage
|
||||
==================
|
||||
*/
|
||||
void idNetworkSystem::ServerSendReliableMessage( int clientNum, const idBitMsg &msg ) {
|
||||
if ( idAsyncNetwork::server.IsActive() ) {
|
||||
idAsyncNetwork::server.SendReliableGameMessage( clientNum, msg );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idNetworkSystem::ServerSendReliableMessageExcluding
|
||||
==================
|
||||
*/
|
||||
void idNetworkSystem::ServerSendReliableMessageExcluding( int clientNum, const idBitMsg &msg ) {
|
||||
if ( idAsyncNetwork::server.IsActive() ) {
|
||||
idAsyncNetwork::server.SendReliableGameMessageExcluding( clientNum, msg );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idNetworkSystem::ServerGetClientPing
|
||||
==================
|
||||
*/
|
||||
int idNetworkSystem::ServerGetClientPing( int clientNum ) {
|
||||
if ( idAsyncNetwork::server.IsActive() ) {
|
||||
return idAsyncNetwork::server.GetClientPing( clientNum );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idNetworkSystem::ServerGetClientPrediction
|
||||
==================
|
||||
*/
|
||||
int idNetworkSystem::ServerGetClientPrediction( int clientNum ) {
|
||||
if ( idAsyncNetwork::server.IsActive() ) {
|
||||
return idAsyncNetwork::server.GetClientPrediction( clientNum );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idNetworkSystem::ServerGetClientTimeSinceLastPacket
|
||||
==================
|
||||
*/
|
||||
int idNetworkSystem::ServerGetClientTimeSinceLastPacket( int clientNum ) {
|
||||
if ( idAsyncNetwork::server.IsActive() ) {
|
||||
return idAsyncNetwork::server.GetClientTimeSinceLastPacket( clientNum );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idNetworkSystem::ServerGetClientTimeSinceLastInput
|
||||
==================
|
||||
*/
|
||||
int idNetworkSystem::ServerGetClientTimeSinceLastInput( int clientNum ) {
|
||||
if ( idAsyncNetwork::server.IsActive() ) {
|
||||
return idAsyncNetwork::server.GetClientTimeSinceLastInput( clientNum );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idNetworkSystem::ServerGetClientOutgoingRate
|
||||
==================
|
||||
*/
|
||||
int idNetworkSystem::ServerGetClientOutgoingRate( int clientNum ) {
|
||||
if ( idAsyncNetwork::server.IsActive() ) {
|
||||
return idAsyncNetwork::server.GetClientOutgoingRate( clientNum );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idNetworkSystem::ServerGetClientIncomingRate
|
||||
==================
|
||||
*/
|
||||
int idNetworkSystem::ServerGetClientIncomingRate( int clientNum ) {
|
||||
if ( idAsyncNetwork::server.IsActive() ) {
|
||||
return idAsyncNetwork::server.GetClientIncomingRate( clientNum );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idNetworkSystem::ServerGetClientIncomingPacketLoss
|
||||
==================
|
||||
*/
|
||||
float idNetworkSystem::ServerGetClientIncomingPacketLoss( int clientNum ) {
|
||||
if ( idAsyncNetwork::server.IsActive() ) {
|
||||
return idAsyncNetwork::server.GetClientIncomingPacketLoss( clientNum );
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idNetworkSystem::ClientSendReliableMessage
|
||||
==================
|
||||
*/
|
||||
void idNetworkSystem::ClientSendReliableMessage( const idBitMsg &msg ) {
|
||||
if ( idAsyncNetwork::client.IsActive() ) {
|
||||
idAsyncNetwork::client.SendReliableGameMessage( msg );
|
||||
} else if ( idAsyncNetwork::server.IsActive() ) {
|
||||
idAsyncNetwork::server.LocalClientSendReliableMessage( msg );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idNetworkSystem::ClientGetPrediction
|
||||
==================
|
||||
*/
|
||||
int idNetworkSystem::ClientGetPrediction( void ) {
|
||||
if ( idAsyncNetwork::client.IsActive() ) {
|
||||
return idAsyncNetwork::client.GetPrediction();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idNetworkSystem::ClientGetTimeSinceLastPacket
|
||||
==================
|
||||
*/
|
||||
int idNetworkSystem::ClientGetTimeSinceLastPacket( void ) {
|
||||
if ( idAsyncNetwork::client.IsActive() ) {
|
||||
return idAsyncNetwork::client.GetTimeSinceLastPacket();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idNetworkSystem::ClientGetOutgoingRate
|
||||
==================
|
||||
*/
|
||||
int idNetworkSystem::ClientGetOutgoingRate( void ) {
|
||||
if ( idAsyncNetwork::client.IsActive() ) {
|
||||
return idAsyncNetwork::client.GetOutgoingRate();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idNetworkSystem::ClientGetIncomingRate
|
||||
==================
|
||||
*/
|
||||
int idNetworkSystem::ClientGetIncomingRate( void ) {
|
||||
if ( idAsyncNetwork::client.IsActive() ) {
|
||||
return idAsyncNetwork::client.GetIncomingRate();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
idNetworkSystem::ClientGetIncomingPacketLoss
|
||||
==================
|
||||
*/
|
||||
float idNetworkSystem::ClientGetIncomingPacketLoss( void ) {
|
||||
if ( idAsyncNetwork::client.IsActive() ) {
|
||||
return idAsyncNetwork::client.GetIncomingPacketLoss();
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
65
neo/framework/async/NetworkSystem.h
Normal file
65
neo/framework/async/NetworkSystem.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __NETWORKSYSTEM_H__
|
||||
#define __NETWORKSYSTEM_H__
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Network System.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idNetworkSystem {
|
||||
public:
|
||||
virtual ~idNetworkSystem( void ) {}
|
||||
|
||||
virtual void ServerSendReliableMessage( int clientNum, const idBitMsg &msg );
|
||||
virtual void ServerSendReliableMessageExcluding( int clientNum, const idBitMsg &msg );
|
||||
virtual int ServerGetClientPing( int clientNum );
|
||||
virtual int ServerGetClientPrediction( int clientNum );
|
||||
virtual int ServerGetClientTimeSinceLastPacket( int clientNum );
|
||||
virtual int ServerGetClientTimeSinceLastInput( int clientNum );
|
||||
virtual int ServerGetClientOutgoingRate( int clientNum );
|
||||
virtual int ServerGetClientIncomingRate( int clientNum );
|
||||
virtual float ServerGetClientIncomingPacketLoss( int clientNum );
|
||||
|
||||
virtual void ClientSendReliableMessage( const idBitMsg &msg );
|
||||
virtual int ClientGetPrediction( void );
|
||||
virtual int ClientGetTimeSinceLastPacket( void );
|
||||
virtual int ClientGetOutgoingRate( void );
|
||||
virtual int ClientGetIncomingRate( void );
|
||||
virtual float ClientGetIncomingPacketLoss( void );
|
||||
};
|
||||
|
||||
extern idNetworkSystem * networkSystem;
|
||||
|
||||
#endif /* !__NETWORKSYSTEM_H__ */
|
||||
639
neo/framework/async/ServerScan.cpp
Normal file
639
neo/framework/async/ServerScan.cpp
Normal file
@@ -0,0 +1,639 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "../../idlib/precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
idCVar gui_filter_password( "gui_filter_password", "0", CVAR_GUI | CVAR_INTEGER | CVAR_ARCHIVE, "Password filter" );
|
||||
idCVar gui_filter_players( "gui_filter_players", "0", CVAR_GUI | CVAR_INTEGER | CVAR_ARCHIVE, "Players filter" );
|
||||
idCVar gui_filter_gameType( "gui_filter_gameType", "0", CVAR_GUI | CVAR_INTEGER | CVAR_ARCHIVE, "Gametype filter" );
|
||||
idCVar gui_filter_idle( "gui_filter_idle", "0", CVAR_GUI | CVAR_INTEGER | CVAR_ARCHIVE, "Idle servers filter" );
|
||||
idCVar gui_filter_game( "gui_filter_game", "0", CVAR_GUI | CVAR_INTEGER | CVAR_ARCHIVE, "Game filter" );
|
||||
|
||||
const char* l_gameTypes[] = {
|
||||
"Deathmatch",
|
||||
"Tourney",
|
||||
"Team DM",
|
||||
"Last Man",
|
||||
"CTF",
|
||||
NULL
|
||||
};
|
||||
|
||||
static idServerScan *l_serverScan = NULL;
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::idServerScan
|
||||
================
|
||||
*/
|
||||
idServerScan::idServerScan( ) {
|
||||
m_pGUI = NULL;
|
||||
m_sort = SORT_PING;
|
||||
m_sortAscending = true;
|
||||
challenge = 0;
|
||||
LocalClear();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::LocalClear
|
||||
================
|
||||
*/
|
||||
void idServerScan::LocalClear( ) {
|
||||
scan_state = IDLE;
|
||||
incoming_net = false;
|
||||
lan_pingtime = -1;
|
||||
net_info.Clear();
|
||||
net_servers.Clear();
|
||||
cur_info = 0;
|
||||
if ( listGUI ) {
|
||||
listGUI->Clear();
|
||||
}
|
||||
incoming_useTimeout = false;
|
||||
m_sortedServers.Clear();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::Clear
|
||||
================
|
||||
*/
|
||||
void idServerScan::Clear( ) {
|
||||
LocalClear();
|
||||
idList<networkServer_t>::Clear();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::Shutdown
|
||||
================
|
||||
*/
|
||||
void idServerScan::Shutdown( ) {
|
||||
m_pGUI = NULL;
|
||||
if ( listGUI ) {
|
||||
listGUI->Config( NULL, NULL );
|
||||
uiManager->FreeListGUI( listGUI );
|
||||
listGUI = NULL;
|
||||
}
|
||||
screenshot.Clear();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::SetupLANScan
|
||||
================
|
||||
*/
|
||||
void idServerScan::SetupLANScan( ) {
|
||||
Clear();
|
||||
GUIUpdateSelected();
|
||||
scan_state = LAN_SCAN;
|
||||
challenge++;
|
||||
lan_pingtime = Sys_Milliseconds();
|
||||
common->DPrintf( "SetupLANScan with challenge %d\n", challenge );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::InfoResponse
|
||||
================
|
||||
*/
|
||||
int idServerScan::InfoResponse( networkServer_t &server ) {
|
||||
if ( scan_state == IDLE ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
idStr serv = Sys_NetAdrToString( server.adr );
|
||||
|
||||
if ( server.challenge != challenge ) {
|
||||
common->DPrintf( "idServerScan::InfoResponse - ignoring response from %s, wrong challenge %d.", serv.c_str(), server.challenge );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( scan_state == NET_SCAN ) {
|
||||
const idKeyValue *info = net_info.FindKey( serv.c_str() );
|
||||
if ( !info ) {
|
||||
common->DPrintf( "idServerScan::InfoResponse NET_SCAN: reply from unknown %s\n", serv.c_str() );
|
||||
return false;
|
||||
}
|
||||
int id = atoi( info->GetValue() );
|
||||
net_info.Delete( serv.c_str() );
|
||||
inServer_t iserv = net_servers[ id ];
|
||||
server.ping = Sys_Milliseconds() - iserv.time;
|
||||
server.id = iserv.id;
|
||||
} else {
|
||||
server.ping = Sys_Milliseconds() - lan_pingtime;
|
||||
server.id = 0;
|
||||
|
||||
// check for duplicate servers
|
||||
for ( int i = 0; i < Num() ; i++ ) {
|
||||
if ( memcmp( &(*this)[ i ].adr, &server.adr, sizeof(netadr_t) ) == 0 ) {
|
||||
common->DPrintf( "idServerScan::InfoResponse LAN_SCAN: duplicate server %s\n", serv.c_str() );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *si_map = server.serverInfo.GetString( "si_map" );
|
||||
const idDecl *mapDecl = declManager->FindType( DECL_MAPDEF, si_map, false );
|
||||
const idDeclEntityDef *mapDef = static_cast< const idDeclEntityDef * >( mapDecl );
|
||||
if ( mapDef ) {
|
||||
const char *mapName = common->GetLanguageDict()->GetString( mapDef->dict.GetString( "name", si_map ) );
|
||||
server.serverInfo.Set( "si_mapName", mapName );
|
||||
} else {
|
||||
server.serverInfo.Set( "si_mapName", si_map );
|
||||
}
|
||||
|
||||
int index = Append( server );
|
||||
// for now, don't maintain sorting when adding new info response servers
|
||||
m_sortedServers.Append( Num()-1 );
|
||||
if ( listGUI->IsConfigured( ) && !IsFiltered( server ) ) {
|
||||
GUIAdd( Num()-1, server );
|
||||
}
|
||||
if ( listGUI->GetSelection( NULL, 0 ) == ( Num()-1 ) ) {
|
||||
GUIUpdateSelected();
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::AddServer
|
||||
================
|
||||
*/
|
||||
void idServerScan::AddServer( int id, const char *srv ) {
|
||||
inServer_t s;
|
||||
|
||||
incoming_net = true;
|
||||
incoming_lastTime = Sys_Milliseconds() + INCOMING_TIMEOUT;
|
||||
s.id = id;
|
||||
|
||||
// using IPs, not hosts
|
||||
if ( !Sys_StringToNetAdr( srv, &s.adr, false ) ) {
|
||||
common->DPrintf( "idServerScan::AddServer: failed to parse server %s\n", srv );
|
||||
return;
|
||||
}
|
||||
if ( !s.adr.port ) {
|
||||
s.adr.port = PORT_SERVER;
|
||||
}
|
||||
|
||||
net_servers.Append( s );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::EndServers
|
||||
================
|
||||
*/
|
||||
void idServerScan::EndServers( ) {
|
||||
incoming_net = false;
|
||||
l_serverScan = this;
|
||||
m_sortedServers.Sort( idServerScan::Cmp );
|
||||
ApplyFilter();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::StartServers
|
||||
================
|
||||
*/
|
||||
void idServerScan::StartServers( bool timeout ) {
|
||||
incoming_net = true;
|
||||
incoming_useTimeout = timeout;
|
||||
incoming_lastTime = Sys_Milliseconds() + REFRESH_START;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::EmitGetInfo
|
||||
================
|
||||
*/
|
||||
void idServerScan::EmitGetInfo( netadr_t &serv ) {
|
||||
idAsyncNetwork::client.GetServerInfo( serv );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idServerScan::GetChallenge
|
||||
===============
|
||||
*/
|
||||
int idServerScan::GetChallenge( ) {
|
||||
return challenge;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::NetScan
|
||||
================
|
||||
*/
|
||||
void idServerScan::NetScan( ) {
|
||||
if ( !idAsyncNetwork::client.IsPortInitialized() ) {
|
||||
// if the port isn't open, initialize it, but wait for a short
|
||||
// time to let the OS do whatever magic things it needs to do...
|
||||
idAsyncNetwork::client.InitPort();
|
||||
// start the scan one second from now...
|
||||
scan_state = WAIT_ON_INIT;
|
||||
endWaitTime = Sys_Milliseconds() + 1000;
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure the client port is open
|
||||
idAsyncNetwork::client.InitPort();
|
||||
|
||||
scan_state = NET_SCAN;
|
||||
challenge++;
|
||||
|
||||
idList<networkServer_t>::Clear();
|
||||
m_sortedServers.Clear();
|
||||
cur_info = 0;
|
||||
net_info.Clear();
|
||||
listGUI->Clear();
|
||||
GUIUpdateSelected();
|
||||
common->DPrintf( "NetScan with challenge %d\n", challenge );
|
||||
|
||||
while ( cur_info < Min( net_servers.Num(), MAX_PINGREQUESTS ) ) {
|
||||
netadr_t serv = net_servers[ cur_info ].adr;
|
||||
EmitGetInfo( serv );
|
||||
net_servers[ cur_info ].time = Sys_Milliseconds();
|
||||
net_info.SetInt( Sys_NetAdrToString( serv ), cur_info );
|
||||
cur_info++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idServerScan::ServerScanFrame
|
||||
===============
|
||||
*/
|
||||
void idServerScan::RunFrame( ) {
|
||||
if ( scan_state == IDLE ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( scan_state == WAIT_ON_INIT ) {
|
||||
if ( Sys_Milliseconds() >= endWaitTime ) {
|
||||
scan_state = IDLE;
|
||||
NetScan();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int timeout_limit = Sys_Milliseconds() - REPLY_TIMEOUT;
|
||||
|
||||
if ( scan_state == LAN_SCAN ) {
|
||||
if ( timeout_limit > lan_pingtime ) {
|
||||
common->Printf( "Scanned for servers on the LAN\n" );
|
||||
scan_state = IDLE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// if scan_state == NET_SCAN
|
||||
|
||||
// check for timeouts
|
||||
int i = 0;
|
||||
while ( i < net_info.GetNumKeyVals() ) {
|
||||
if ( timeout_limit > net_servers[ atoi( net_info.GetKeyVal( i )->GetValue().c_str() ) ].time ) {
|
||||
common->DPrintf( "timeout %s\n", net_info.GetKeyVal( i )->GetKey().c_str() );
|
||||
net_info.Delete( net_info.GetKeyVal( i )->GetKey().c_str() );
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// possibly send more queries
|
||||
while ( cur_info < net_servers.Num() && net_info.GetNumKeyVals() < MAX_PINGREQUESTS ) {
|
||||
netadr_t serv = net_servers[ cur_info ].adr;
|
||||
EmitGetInfo( serv );
|
||||
net_servers[ cur_info ].time = Sys_Milliseconds();
|
||||
net_info.SetInt( Sys_NetAdrToString( serv ), cur_info );
|
||||
cur_info++;
|
||||
}
|
||||
|
||||
// update state
|
||||
if ( ( !incoming_net || ( incoming_useTimeout && Sys_Milliseconds() > incoming_lastTime ) ) && net_info.GetNumKeyVals() == 0 ) {
|
||||
EndServers();
|
||||
// the list is complete, we are no longer waiting for any getInfo replies
|
||||
common->Printf( "Scanned %d servers.\n", cur_info );
|
||||
scan_state = IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idServerScan::GetBestPing
|
||||
===============
|
||||
*/
|
||||
bool idServerScan::GetBestPing( networkServer_t &serv ) {
|
||||
int i, ic;
|
||||
ic = Num();
|
||||
if ( !ic ) {
|
||||
return false;
|
||||
}
|
||||
serv = (*this)[ 0 ];
|
||||
for ( i = 0 ; i < ic ; i++ ) {
|
||||
if ( (*this)[ i ].ping < serv.ping ) {
|
||||
serv = (*this)[ i ];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::GUIConfig
|
||||
================
|
||||
*/
|
||||
void idServerScan::GUIConfig( idUserInterface *pGUI, const char *name ) {
|
||||
m_pGUI = pGUI;
|
||||
if ( listGUI == NULL ) {
|
||||
listGUI = uiManager->AllocListGUI();
|
||||
}
|
||||
listGUI->Config( pGUI, name );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::GUIUpdateSelected
|
||||
================
|
||||
*/
|
||||
void idServerScan::GUIUpdateSelected( void ) {
|
||||
char screenshot[ MAX_STRING_CHARS ];
|
||||
|
||||
if ( !m_pGUI ) {
|
||||
return;
|
||||
}
|
||||
int i = listGUI->GetSelection( NULL, 0 );
|
||||
if ( i == -1 || i >= Num() ) {
|
||||
m_pGUI->SetStateString( "server_name", "" );
|
||||
m_pGUI->SetStateString( "player1", "" );
|
||||
m_pGUI->SetStateString( "player2", "" );
|
||||
m_pGUI->SetStateString( "player3", "" );
|
||||
m_pGUI->SetStateString( "player4", "" );
|
||||
m_pGUI->SetStateString( "player5", "" );
|
||||
m_pGUI->SetStateString( "player6", "" );
|
||||
m_pGUI->SetStateString( "player7", "" );
|
||||
m_pGUI->SetStateString( "player8", "" );
|
||||
m_pGUI->SetStateString( "server_map", "" );
|
||||
m_pGUI->SetStateString( "browser_levelshot", "" );
|
||||
m_pGUI->SetStateString( "server_gameType", "" );
|
||||
m_pGUI->SetStateString( "server_IP", "" );
|
||||
m_pGUI->SetStateString( "server_passworded", "" );
|
||||
} else {
|
||||
m_pGUI->SetStateString( "server_name", (*this)[ i ].serverInfo.GetString( "si_name" ) );
|
||||
for ( int j = 0; j < 8; j++ ) {
|
||||
if ( (*this)[i].clients > j ) {
|
||||
m_pGUI->SetStateString( va( "player%i", j + 1 ) , (*this)[ i ].nickname[ j ] );
|
||||
} else {
|
||||
m_pGUI->SetStateString( va( "player%i", j + 1 ) , "" );
|
||||
}
|
||||
}
|
||||
m_pGUI->SetStateString( "server_map", (*this)[ i ].serverInfo.GetString( "si_mapName" ) );
|
||||
fileSystem->FindMapScreenshot( (*this)[ i ].serverInfo.GetString( "si_map" ), screenshot, MAX_STRING_CHARS );
|
||||
m_pGUI->SetStateString( "browser_levelshot", screenshot );
|
||||
m_pGUI->SetStateString( "server_gameType", (*this)[ i ].serverInfo.GetString( "si_gameType" ) );
|
||||
m_pGUI->SetStateString( "server_IP", Sys_NetAdrToString( (*this)[ i ].adr ) );
|
||||
if ( (*this)[ i ].serverInfo.GetBool( "si_usePass" ) ) {
|
||||
m_pGUI->SetStateString( "server_passworded", "PASSWORD REQUIRED" );
|
||||
} else {
|
||||
m_pGUI->SetStateString( "server_passworded", "" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::GUIAdd
|
||||
================
|
||||
*/
|
||||
void idServerScan::GUIAdd( int id, const networkServer_t server ) {
|
||||
idStr name = server.serverInfo.GetString( "si_name", GAME_NAME " Server" );
|
||||
bool d3xp = false;
|
||||
bool mod = false;
|
||||
|
||||
if ( !idStr::Icmp( server.serverInfo.GetString( "fs_game" ), "d3xp" ) ||
|
||||
!idStr::Icmp( server.serverInfo.GetString( "fs_game_base" ), "d3xp" ) ) {
|
||||
d3xp = true;
|
||||
}
|
||||
if ( server.serverInfo.GetString( "fs_game" )[ 0 ] != '\0' ) {
|
||||
mod = true;
|
||||
}
|
||||
|
||||
name += "\t";
|
||||
if ( server.serverInfo.GetString( "sv_punkbuster" )[ 0 ] == '1' ) {
|
||||
name += "mtr_PB";
|
||||
}
|
||||
|
||||
name += "\t";
|
||||
if ( d3xp ) {
|
||||
// FIXME: even for a 'D3XP mod'
|
||||
// could have a specific icon for this case
|
||||
name += "mtr_doom3XPIcon";
|
||||
} else if ( mod ) {
|
||||
name += "mtr_doom3Mod";
|
||||
} else {
|
||||
name += "mtr_doom3Icon";
|
||||
}
|
||||
name += "\t";
|
||||
name += va( "%i/%i\t", server.clients, server.serverInfo.GetInt( "si_maxPlayers" ) );
|
||||
name += ( server.ping > -1 ) ? va( "%i\t", server.ping ) : "na\t";
|
||||
name += server.serverInfo.GetString( "si_gametype" );
|
||||
name += "\t";
|
||||
name += server.serverInfo.GetString( "si_mapName" );
|
||||
name += "\t";
|
||||
listGUI->Add( id, name );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::ApplyFilter
|
||||
================
|
||||
*/
|
||||
void idServerScan::ApplyFilter( ) {
|
||||
int i;
|
||||
networkServer_t serv;
|
||||
idStr s;
|
||||
|
||||
listGUI->SetStateChanges( false );
|
||||
listGUI->Clear();
|
||||
for ( i = m_sortAscending ? 0 : m_sortedServers.Num() - 1;
|
||||
m_sortAscending ? i < m_sortedServers.Num() : i >= 0;
|
||||
m_sortAscending ? i++ : i-- ) {
|
||||
serv = (*this)[ m_sortedServers[ i ] ];
|
||||
if ( !IsFiltered( serv ) ) {
|
||||
GUIAdd( m_sortedServers[ i ], serv );
|
||||
}
|
||||
}
|
||||
GUIUpdateSelected();
|
||||
listGUI->SetStateChanges( true );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::IsFiltered
|
||||
================
|
||||
*/
|
||||
bool idServerScan::IsFiltered( const networkServer_t server ) {
|
||||
int i;
|
||||
const idKeyValue *keyval;
|
||||
|
||||
// OS support filter
|
||||
#if 0
|
||||
// filter out pure servers that won't provide checksumed game code for client OS
|
||||
keyval = server.serverInfo.FindKey( "si_pure" );
|
||||
if ( keyval && !idStr::Cmp( keyval->GetValue(), "1" ) ) {
|
||||
if ( ( server.OSMask & ( 1 << BUILD_OS_ID ) ) == 0 ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if ( ( server.OSMask & ( 1 << BUILD_OS_ID ) ) == 0 ) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
// password filter
|
||||
keyval = server.serverInfo.FindKey( "si_usePass" );
|
||||
if ( keyval && gui_filter_password.GetInteger() == 1 ) {
|
||||
// show passworded only
|
||||
if ( keyval->GetValue()[ 0 ] == '0' ) {
|
||||
return true;
|
||||
}
|
||||
} else if ( keyval && gui_filter_password.GetInteger() == 2 ) {
|
||||
// show no password only
|
||||
if ( keyval->GetValue()[ 0 ] != '0' ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// players filter
|
||||
keyval = server.serverInfo.FindKey( "si_maxPlayers" );
|
||||
if ( keyval ) {
|
||||
if ( gui_filter_players.GetInteger() == 1 && server.clients == atoi( keyval->GetValue() ) ) {
|
||||
return true;
|
||||
} else if ( gui_filter_players.GetInteger() == 2 && ( !server.clients || server.clients == atoi( keyval->GetValue() ) ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// gametype filter
|
||||
keyval = server.serverInfo.FindKey( "si_gameType" );
|
||||
if ( keyval && gui_filter_gameType.GetInteger() ) {
|
||||
i = 0;
|
||||
while ( l_gameTypes[ i ] ) {
|
||||
if ( !keyval->GetValue().Icmp( l_gameTypes[ i ] ) ) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if ( l_gameTypes[ i ] && i != gui_filter_gameType.GetInteger() -1 ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// idle server filter
|
||||
keyval = server.serverInfo.FindKey( "si_idleServer" );
|
||||
if ( keyval && !gui_filter_idle.GetInteger() ) {
|
||||
if ( !keyval->GetValue().Icmp( "1" ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// autofilter D3XP games if the user does not has the XP installed
|
||||
if(!fileSystem->HasD3XP() && !idStr::Icmp(server.serverInfo.GetString( "fs_game" ), "d3xp")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// filter based on the game doom or XP
|
||||
if(gui_filter_game.GetInteger() == 1) { //Only Doom
|
||||
if(idStr::Icmp(server.serverInfo.GetString("fs_game"), "")) {
|
||||
return true;
|
||||
}
|
||||
} else if(gui_filter_game.GetInteger() == 2) { //Only D3XP
|
||||
if(idStr::Icmp(server.serverInfo.GetString("fs_game"), "d3xp")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::Cmp
|
||||
================
|
||||
*/
|
||||
|
||||
int idServerScan::Cmp( const int *a, const int *b ) {
|
||||
networkServer_t serv1, serv2;
|
||||
idStr s1, s2;
|
||||
int ret;
|
||||
|
||||
serv1 = (*l_serverScan)[ *a ];
|
||||
serv2 = (*l_serverScan)[ *b ];
|
||||
switch ( l_serverScan->m_sort ) {
|
||||
case SORT_PING:
|
||||
ret = serv1.ping < serv2.ping ? -1 : ( serv1.ping > serv2.ping ? 1 : 0 );
|
||||
return ret;
|
||||
case SORT_SERVERNAME:
|
||||
serv1.serverInfo.GetString( "si_name", "", s1 );
|
||||
serv2.serverInfo.GetString( "si_name", "", s2 );
|
||||
return s1.IcmpNoColor( s2 );
|
||||
case SORT_PLAYERS:
|
||||
ret = serv1.clients < serv2.clients ? -1 : ( serv1.clients > serv2.clients ? 1 : 0 );
|
||||
return ret;
|
||||
case SORT_GAMETYPE:
|
||||
serv1.serverInfo.GetString( "si_gameType", "", s1 );
|
||||
serv2.serverInfo.GetString( "si_gameType", "", s2 );
|
||||
return s1.Icmp( s2 );
|
||||
case SORT_MAP:
|
||||
serv1.serverInfo.GetString( "si_mapName", "", s1 );
|
||||
serv2.serverInfo.GetString( "si_mapName", "", s2 );
|
||||
return s1.Icmp( s2 );
|
||||
case SORT_GAME:
|
||||
serv1.serverInfo.GetString( "fs_game", "", s1 );
|
||||
serv2.serverInfo.GetString( "fs_game", "", s2 );
|
||||
return s1.Icmp( s2 );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idServerScan::SetSorting
|
||||
================
|
||||
*/
|
||||
void idServerScan::SetSorting( serverSort_t sort ) {
|
||||
l_serverScan = this;
|
||||
if ( sort == m_sort ) {
|
||||
m_sortAscending = !m_sortAscending;
|
||||
} else {
|
||||
m_sort = sort;
|
||||
m_sortAscending = true; // is the default for any new sort
|
||||
m_sortedServers.Sort( idServerScan::Cmp );
|
||||
}
|
||||
// trigger a redraw
|
||||
ApplyFilter();
|
||||
}
|
||||
|
||||
170
neo/framework/async/ServerScan.h
Normal file
170
neo/framework/async/ServerScan.h
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
||||
|
||||
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 Source Code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __SERVERSCAN_H__
|
||||
#define __SERVERSCAN_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Scan for servers, on the LAN or from a list
|
||||
Update a listDef GUI through usage of idListGUI class
|
||||
When updating large lists of servers, sends out getInfo in small batches to avoid congestion
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
// storage for incoming servers / server scan
|
||||
typedef struct {
|
||||
netadr_t adr;
|
||||
int id;
|
||||
int time;
|
||||
} inServer_t;
|
||||
|
||||
// the menu gui uses a hard-coded control type to display a list of network games
|
||||
typedef struct {
|
||||
netadr_t adr;
|
||||
idDict serverInfo;
|
||||
int ping;
|
||||
int id; // idnet mode sends an id for each server in list
|
||||
int clients;
|
||||
char nickname[ MAX_NICKLEN ][ MAX_ASYNC_CLIENTS ];
|
||||
short pings[ MAX_ASYNC_CLIENTS ];
|
||||
int rate[ MAX_ASYNC_CLIENTS ];
|
||||
int OSMask;
|
||||
int challenge;
|
||||
} networkServer_t;
|
||||
|
||||
typedef enum {
|
||||
SORT_PING,
|
||||
SORT_SERVERNAME,
|
||||
SORT_PLAYERS,
|
||||
SORT_GAMETYPE,
|
||||
SORT_MAP,
|
||||
SORT_GAME
|
||||
} serverSort_t;
|
||||
|
||||
class idServerScan : public idList<networkServer_t> {
|
||||
public:
|
||||
idServerScan( );
|
||||
|
||||
int InfoResponse( networkServer_t &server );
|
||||
|
||||
// add an internet server - ( store a numeric id along with it )
|
||||
void AddServer( int id, const char *srv );
|
||||
|
||||
// we are going to feed server entries to be pinged
|
||||
// if timeout is true, use a timeout once we start AddServer to trigger EndServers and decide the scan is done
|
||||
void StartServers( bool timeout );
|
||||
// we are done filling up the list of server entries
|
||||
void EndServers( );
|
||||
|
||||
// scan the current list of servers - used for refreshes and while receiving a fresh list
|
||||
void NetScan( );
|
||||
|
||||
// clear
|
||||
void Clear( );
|
||||
|
||||
// called each game frame. Updates the scanner state, takes care of ongoing scans
|
||||
void RunFrame( );
|
||||
|
||||
typedef enum {
|
||||
IDLE = 0,
|
||||
WAIT_ON_INIT,
|
||||
LAN_SCAN,
|
||||
NET_SCAN
|
||||
} scan_state_t;
|
||||
|
||||
scan_state_t GetState() { return scan_state; }
|
||||
void SetState( scan_state_t );
|
||||
|
||||
bool GetBestPing( networkServer_t &serv );
|
||||
|
||||
// prepare for a LAN scan. idAsyncClient does the network job (UDP broadcast), we do the storage
|
||||
void SetupLANScan( );
|
||||
|
||||
void GUIConfig( idUserInterface *pGUI, const char *name );
|
||||
// update the GUI fields with information about the currently selected server
|
||||
void GUIUpdateSelected( void );
|
||||
|
||||
void Shutdown( );
|
||||
|
||||
void ApplyFilter( );
|
||||
|
||||
// there is an internal toggle, call twice with same sort to switch
|
||||
void SetSorting( serverSort_t sort );
|
||||
|
||||
int GetChallenge( );
|
||||
|
||||
private:
|
||||
static const int MAX_PINGREQUESTS = 32; // how many servers to query at once
|
||||
static const int REPLY_TIMEOUT = 999; // how long should we wait for a reply from a game server
|
||||
static const int INCOMING_TIMEOUT = 1500; // when we got an incoming server list, how long till we decide the list is done
|
||||
static const int REFRESH_START = 10000; // how long to wait when sending the initial refresh request
|
||||
|
||||
scan_state_t scan_state;
|
||||
|
||||
bool incoming_net; // set to true while new servers are fed through AddServer
|
||||
bool incoming_useTimeout;
|
||||
int incoming_lastTime;
|
||||
|
||||
int lan_pingtime; // holds the time of LAN scan
|
||||
|
||||
// servers we're waiting for a reply from
|
||||
// won't exceed MAX_PINGREQUESTS elements
|
||||
// holds index of net_servers elements, indexed by 'from' string
|
||||
idDict net_info;
|
||||
|
||||
idList<inServer_t> net_servers;
|
||||
// where we are in net_servers list for getInfo emissions ( NET_SCAN only )
|
||||
// we may either be waiting on MAX_PINGREQUESTS, or for net_servers to grow some more ( through AddServer )
|
||||
int cur_info;
|
||||
|
||||
idUserInterface *m_pGUI;
|
||||
idListGUI * listGUI;
|
||||
|
||||
serverSort_t m_sort;
|
||||
bool m_sortAscending;
|
||||
idList<int> m_sortedServers; // use ascending for the walking order
|
||||
|
||||
idStr screenshot;
|
||||
int challenge; // challenge for current scan
|
||||
|
||||
int endWaitTime; // when to stop waiting on a port init
|
||||
|
||||
private:
|
||||
void LocalClear( ); // we need to clear some internal data as well
|
||||
|
||||
void EmitGetInfo( netadr_t &serv );
|
||||
void GUIAdd( int id, const networkServer_t server );
|
||||
bool IsFiltered( const networkServer_t server );
|
||||
|
||||
static int Cmp( const int *a, const int *b );
|
||||
};
|
||||
|
||||
#endif /* !__SERVERSCAN_H__ */
|
||||
Reference in New Issue
Block a user