IpServer
Class UdpServerQuery

source: e:\games\UnrealTournament\IpServer\Classes\UdpServerQuery.uc
Core.Object
   |
   +--Engine.Actor
      |
      +--Engine.Info
         |
         +--Engine.InternetInfo
            |
            +--IpDrv.InternetLink
               |
               +--IpDrv.UdpLink
                  |
                  +--IpServer.UdpServerQuery
Direct Known Subclasses:None

class UdpServerQuery
extends IpDrv.UdpLink

//============================================================================= // UdpServerQuery // // Version: 1.5 // // This query server is compliant with the GameSpy Uplink Specification. // The specification is available at http://www.gamespy.com/developer // and might be of use to progammers who are writing or maintaining // their own stat gathering/game querying software. // // Note: Currently, SendText returns false if successful. // // Full documentation on this class is available at http://unreal.epicgames.com/ // //=============================================================================
Variables
 int CurrentQueryNum
           Query ID Number.
 string GameName
           Query ID Number.
 int MinNetVer
           Query ID Number.
 int OldQueryPortNumber
           Query ID Number.
 name QueryName
           Name to set this object's Tag to.
 string ReplyData
           Query ID Number.
 bool bRestartServerOnPortSwap
           Query ID Number.


Function Summary
 string GetBasic()
     
// Return a string of basic information.
 string GetGameProperty(string Prop)
     
// Get an arbitrary property from the game object.
 string GetInfo()
     
// Return a string of important system information.
 string GetLevelProperty(string Prop)
     
// Get an arbitrary property from the level object.
 string GetPlayer(PlayerPawn P, int PlayerNum)
     
// Return a string of information on a player.
 string GetPlayerProperty(string Prop)
     
// Get an arbitrary property from the players.
 string GetRules()
     
// Return a string of miscellaneous information.
// Game specific information, user defined data, custom parameters for the command line.
 bool ParseNextQuery(string Query, out string, out string, out string, out int)
 string ParseQuery(IpAddr Addr, string Query, int QueryNum, out int)
 void PostBeginPlay()
 void PreBeginPlay()
     
// Initialize.
 bool SendAPacket(IpAddr Addr, int QueryNum, out int, int bFinalPacket)
 bool SendPlayers(IpAddr Addr, int QueryNum, out int, int bFinalPacket)
     
// Send data for each player
 bool SendQueryPacket(IpAddr Addr, string SendString, int QueryNum, out int, int bFinalPacket)
     
// SendQueryPacket is a wrapper for SendText that allows for packet numbering.



Source Code


00001	//=============================================================================
00002	// UdpServerQuery
00003	//
00004	// Version: 1.5
00005	//
00006	// This query server is compliant with the GameSpy Uplink Specification.
00007	// The specification is available at http://www.gamespy.com/developer
00008	// and might be of use to progammers who are writing or maintaining
00009	// their own stat gathering/game querying software.
00010	//
00011	// Note: Currently, SendText returns false if successful.
00012	//
00013	// Full documentation on this class is available at http://unreal.epicgames.com/
00014	//
00015	//=============================================================================
00016	class UdpServerQuery extends UdpLink config;
00017	
00018	// Game Server Config.
00019	var() name					QueryName;			// Name to set this object's Tag to.
00020	var int					    CurrentQueryNum;	// Query ID Number.
00021	var globalconfig string		GameName;
00022	//crt
00023	var string ReplyData;
00024	
00025	var globalconfig int		MinNetVer;
00026	
00027	//!! Hack to prevent port swapping
00028	var globalconfig int		OldQueryPortNumber;
00029	var globalconfig bool		bRestartServerOnPortSwap;
00030	
00031	
00032	
00033	// Initialize.
00034	function PreBeginPlay()
00035	{
00036		local int boundport;
00037	
00038		// Set the Tag
00039		Tag = QueryName;
00040	
00041		// Bind the listen socket
00042		boundport = BindPort(Level.Game.GetServerPort(), true);
00043		if( boundport == 0 )
00044		{
00045			Log("UdpServerQuery: Port failed to bind.");
00046			return;
00047		}
00048		Log("UdpServerQuery(crt): Port "$boundport$" successfully bound.");
00049	
00050		if( bRestartServerOnPortSwap )
00051		{
00052			if( OldQueryPortNumber != 0 )
00053				assert( OldQueryPortNumber == boundport );
00054			OldQueryPortNumber = boundport;
00055			SaveConfig();
00056		}
00057	}
00058	
00059	function PostBeginPlay()
00060	{
00061		local UdpBeacon	Beacon;
00062	
00063		foreach AllActors(class'UdpBeacon', Beacon)
00064		{
00065			Beacon.UdpServerQueryPort = Port;
00066		}
00067		Super.PostBeginPlay();
00068	}
00069	
00070	// Received a query request.
00071	event ReceivedText( IpAddr Addr, string Text )
00072	{
00073		local string Query;
00074		local bool QueryRemaining;
00075		local int  QueryNum, PacketNum;
00076	
00077		// Assign this packet a unique value from 1 to 100
00078		CurrentQueryNum++;
00079		if (CurrentQueryNum > 100)
00080			CurrentQueryNum = 1;
00081		QueryNum = CurrentQueryNum;
00082	
00083		Query = Text;
00084		if (Query == "")		// If the string is empty, don't parse it
00085			QueryRemaining = false;
00086		else
00087			QueryRemaining = true;
00088		//crt
00089		PacketNum =  0;
00090		ReplyData = "";
00091		while (QueryRemaining) {
00092			Query = ParseQuery(Addr, Query, QueryNum, PacketNum);
00093			if (Query == "")
00094				QueryRemaining = false;
00095			else
00096				QueryRemaining = true;
00097		}
00098	}
00099	
00100	function bool ParseNextQuery( string Query, out string QueryType, out string QueryValue, out string QueryRest, out int bFinalPacket )
00101	{
00102		local string TempQuery;
00103		local int ClosingSlash;
00104	
00105		if (Query == "")
00106			return false;
00107	
00108		// Query should be:
00109		//   \[type]\<value>
00110		if (Left(Query, 1) == "\\")
00111		{
00112			// Check to see if closed.
00113			ClosingSlash = InStr(Right(Query, Len(Query)-1), "\\");
00114			if (ClosingSlash == 0)
00115				return false;
00116	
00117			TempQuery = Query;
00118	
00119			// Query looks like:
00120			//  \[type]\
00121			QueryType = Right(Query, Len(Query)-1);
00122			QueryType = Left(QueryType, ClosingSlash);
00123	
00124			QueryRest = Right(Query, Len(Query) - (Len(QueryType) + 2));
00125	
00126			if ((QueryRest == "") || (Len(QueryRest) == 1))
00127			{
00128				bFinalPacket = 1;
00129				return true;
00130			} else if (Left(QueryRest, 1) == "\\")
00131				return true;	// \type\\
00132	
00133			// Query looks like:
00134			//  \type\value
00135			ClosingSlash = InStr(QueryRest, "\\");
00136			if (ClosingSlash >= 0)
00137				QueryValue = Left(QueryRest, ClosingSlash);
00138			else
00139				QueryValue = QueryRest;
00140	
00141			QueryRest = Right(Query, Len(Query) - (Len(QueryType) + Len(QueryValue) + 3));
00142			if (QueryRest == "")
00143			{
00144				bFinalPacket = 1;
00145				return true;
00146			} else
00147				return true;
00148		} else {
00149			return false;
00150		}
00151	}
00152	
00153	function string ParseQuery( IpAddr Addr, coerce string Query, int QueryNum, out int PacketNum )
00154	{
00155		local string QueryType, QueryValue, QueryRest, ValidationString;
00156		local bool Result;
00157		local int bFinalPacket;
00158		
00159		bFinalPacket = 0;
00160		Result = ParseNextQuery(Query, QueryType, QueryValue, QueryRest, bFinalPacket);
00161		if( !Result )
00162			return "";
00163	
00164		//Log("Got  Query: "  $ QueryNum $ "." $ PacketNum $ ":" $ QueryType);
00165	
00166		if( QueryType=="basic" )
00167		{
00168			Result = SendQueryPacket(Addr, GetBasic(), QueryNum, PacketNum, bFinalPacket);
00169		}
00170		else if( QueryType=="info" )
00171		{
00172			Result = SendQueryPacket(Addr, GetInfo(), QueryNum, PacketNum, bFinalPacket);
00173		}
00174		else if( QueryType=="rules" )
00175		{
00176			Result = SendQueryPacket(Addr, GetRules(), QueryNum, PacketNum, bFinalPacket);
00177		}
00178		else if( QueryType=="players" )
00179		{
00180			if( Level.Game.NumPlayers > 0 )
00181				Result = SendPlayers(Addr, QueryNum, PacketNum, bFinalPacket);
00182			else
00183				Result = SendQueryPacket(Addr, "", QueryNum, PacketNum, bFinalPacket);
00184		}
00185		else if( QueryType=="status" )
00186		{
00187			Result = SendQueryPacket(Addr, GetBasic(), QueryNum, PacketNum, 0);
00188			Result = SendQueryPacket(Addr, GetInfo(), QueryNum, PacketNum, 0);
00189			if( Level.Game.NumPlayers == 0 )
00190			{
00191				Result = SendQueryPacket(Addr, GetRules(), QueryNum, PacketNum, bFinalPacket);
00192			}
00193			else
00194			{
00195				Result = SendQueryPacket(Addr, GetRules(), QueryNum, PacketNum, 0);
00196				Result = SendPlayers(Addr, QueryNum, PacketNum, bFinalPacket);
00197			}
00198		}
00199		else if( QueryType=="echo" )
00200		{
00201			// Respond to an echo with the same string
00202			Result = SendQueryPacket(Addr, "\\echo\\"$QueryValue, QueryNum, PacketNum, bFinalPacket);
00203		}
00204		else if( QueryType=="secure" )
00205		{
00206			ValidationString = "\\validate\\"$Validate(QueryValue, GameName);
00207			Result = SendQueryPacket(Addr, ValidationString, QueryNum, PacketNum, bFinalPacket);
00208		}
00209		else if( QueryType=="level_property" )
00210		{
00211			Result = SendQueryPacket(Addr, GetLevelProperty(QueryValue), QueryNum, PacketNum, bFinalPacket);
00212		}
00213		else if( QueryType=="game_property" )
00214		{
00215				Result = SendQueryPacket(Addr, GetGameProperty(QueryValue), QueryNum, PacketNum, bFinalPacket);
00216		}
00217		else if( QueryType=="player_property" )
00218		{
00219			Result = SendQueryPacket(Addr, GetPlayerProperty(QueryValue), QueryNum, PacketNum, bFinalPacket);
00220		}
00221		return QueryRest;
00222	}
00223	
00224	function bool SendAPacket(IpAddr Addr, int QueryNum, out int PacketNum, int bFinalPacket)
00225	{
00226		local bool Result;
00227	
00228		ReplyData = ReplyData$"\\queryid\\"$QueryNum$"."$++PacketNum;
00229		if (bFinalPacket == 1) {
00230			ReplyData = ReplyData $ "\\final\\";
00231		}
00232		Result = SendText(Addr, ReplyData);
00233		ReplyData = "";
00234		
00235		return Result;
00236	
00237	}
00238	
00239	// SendQueryPacket is a wrapper for SendText that allows for packet numbering.
00240	function bool SendQueryPacket(IpAddr Addr, coerce string SendString, int QueryNum, out int PacketNum, int bFinalPacket)
00241	{
00242		local bool Result;
00243		
00244		//Log("Send Query: "  $ QueryNum $ "." $ PacketNum $ ":" $ bFinalPacket);
00245		result = true;
00246		if (len(ReplyData) + len(SendString) > 1000)
00247			result = SendAPacket(Addr, QueryNum, PacketNum, 0);
00248		
00249		ReplyData = ReplyData $ SendString;
00250		
00251		if (bFinalPacket == 1)
00252			result = SendAPacket(Addr, QueryNum, PacketNum, bFinalPacket);
00253			
00254		return Result;
00255	}
00256	
00257	// Return a string of basic information.
00258	function string GetBasic() {
00259		local string ResultSet;
00260	
00261		// The name of this game.
00262		ResultSet = "\\gamename\\"$GameName;
00263	
00264		// The version of this game.
00265		ResultSet = ResultSet$"\\gamever\\"$Level.EngineVersion;
00266	
00267		// The most recent network compatible version.
00268		if( MinNetVer >= Int(Level.MinNetVersion) && 
00269			MinNetVer <= Int(Level.EngineVersion) )
00270			ResultSet = ResultSet$"\\minnetver\\"$string(MinNetVer);
00271		else
00272			ResultSet = ResultSet$"\\minnetver\\"$Level.MinNetVersion;
00273	
00274		// The regional location of this game.
00275		ResultSet = ResultSet$"\\location\\"$Level.Game.GameReplicationInfo.Region;
00276		
00277		return ResultSet;
00278	}
00279	
00280	// Return a string of important system information.
00281	function string GetInfo() {
00282		local string ResultSet;
00283	
00284		// The server name, i.e.: Bob's Server
00285		ResultSet = "\\hostname\\"$Level.Game.GameReplicationInfo.ServerName;
00286	
00287		// The short server name
00288		//ResultSet = ResultSet$"\\shortname\\"$Level.Game.GameReplicationInfo.ShortName;
00289	
00290		// The server port.
00291		ResultSet = ResultSet$"\\hostport\\"$Level.Game.GetServerPort();
00292	
00293		// (optional) The server IP
00294		// if (ServerIP != "")
00295		//	ResultSet = ResultSet$"\\hostip\\"$ServerIP;
00296	
00297		// The map/level title
00298		ResultSet = ResultSet$"\\maptitle\\"$Level.Title;
00299		
00300		// Map name
00301		ResultSet = ResultSet$"\\mapname\\"$Left(string(Level), InStr(string(Level), "."));
00302	
00303		// The mod or game type
00304		ResultSet = ResultSet$"\\gametype\\"$GetItemName(string(Level.Game.Class));
00305	
00306		// The number of players
00307		ResultSet = ResultSet$"\\numplayers\\"$Level.Game.NumPlayers;
00308	
00309		// The maximum number of players
00310		ResultSet = ResultSet$"\\maxplayers\\"$Level.Game.MaxPlayers;
00311	
00312		// The game mode: openplaying
00313		ResultSet = ResultSet$"\\gamemode\\openplaying";
00314	
00315		// The version of this game.
00316		ResultSet = ResultSet$"\\gamever\\"$Level.EngineVersion;
00317	
00318		// The most recent network compatible version.
00319		if( MinNetVer >= Int(Level.MinNetVersion) && 
00320			MinNetVer <= Int(Level.EngineVersion) )
00321			ResultSet = ResultSet$"\\minnetver\\"$string(MinNetVer);
00322		else
00323			ResultSet = ResultSet$"\\minnetver\\"$Level.MinNetVersion;
00324	
00325		ResultSet = ResultSet$Level.Game.GetInfo();
00326	
00327		return ResultSet;
00328	}
00329	
00330	// Return a string of miscellaneous information.
00331	// Game specific information, user defined data, custom parameters for the command line.
00332	function string GetRules()
00333	{
00334		local string ResultSet;
00335	
00336		ResultSet = Level.Game.GetRules();
00337	
00338		// Admin's Name
00339		if( Level.Game.GameReplicationInfo.AdminName != "" )
00340			ResultSet = ResultSet$"\\AdminName\\"$Level.Game.GameReplicationInfo.AdminName;
00341		
00342		// Admin's Email
00343		if( Level.Game.GameReplicationInfo.AdminEmail != "" )
00344			ResultSet = ResultSet$"\\AdminEMail\\"$Level.Game.GameReplicationInfo.AdminEmail;
00345	
00346		return ResultSet;
00347	}
00348	
00349	// Return a string of information on a player.
00350	function string GetPlayer( PlayerPawn P, int PlayerNum )
00351	{
00352		local string ResultSet;
00353		local string SkinName, FaceName;
00354	
00355		// Name
00356		ResultSet = "\\player_"$PlayerNum$"\\"$P.PlayerReplicationInfo.PlayerName;
00357	
00358		// Frags
00359		ResultSet = ResultSet$"\\frags_"$PlayerNum$"\\"$int(P.PlayerReplicationInfo.Score);
00360	
00361		// Ping
00362		ResultSet = ResultSet$"\\ping_"$PlayerNum$"\\"$P.ConsoleCommand("GETPING");
00363	
00364		// Team
00365		ResultSet = ResultSet$"\\team_"$PlayerNum$"\\"$P.PlayerReplicationInfo.Team;
00366	
00367		// Class
00368		ResultSet = ResultSet$"\\mesh_"$PlayerNum$"\\"$P.Menuname;
00369	
00370		// Skin
00371		if(P.Skin == None)
00372		{
00373			P.static.GetMultiSkin(P, SkinName, FaceName);
00374			ResultSet = ResultSet$"\\skin_"$PlayerNum$"\\"$SkinName;
00375			ResultSet = ResultSet$"\\face_"$PlayerNum$"\\"$FaceName;
00376		}
00377		else
00378		{
00379			ResultSet = ResultSet$"\\skin_"$PlayerNum$"\\"$string(P.Skin);
00380			ResultSet = ResultSet$"\\face_"$PlayerNum$"\\None";
00381		}
00382		if( P.PlayerReplicationInfo.bIsABot )
00383			ResultSet = ResultSet$"\\ngsecret_"$PlayerNum$"\\bot";
00384		else
00385		if( P.ReceivedSecretChecksum )
00386			ResultSet = ResultSet$"\\ngsecret_"$PlayerNum$"\\true";
00387		else
00388			ResultSet = ResultSet$"\\ngsecret_"$PlayerNum$"\\false";
00389		return ResultSet;
00390	}
00391	
00392	// Send data for each player
00393	function bool SendPlayers(IpAddr Addr, int QueryNum, out int PacketNum, int bFinalPacket)
00394	{
00395		local Pawn P;
00396		local int i;
00397		local bool Result, SendResult;
00398		
00399		Result = false;
00400	
00401		P = Level.PawnList;
00402		while( i < Level.Game.NumPlayers )
00403		{
00404			if (P.IsA('PlayerPawn'))
00405			{
00406				if( i==Level.Game.NumPlayers-1 && bFinalPacket==1)
00407					SendResult = SendQueryPacket(Addr, GetPlayer(PlayerPawn(P), i), QueryNum, PacketNum, 1);
00408				else
00409					SendResult = SendQueryPacket(Addr, GetPlayer(PlayerPawn(P), i), QueryNum, PacketNum, 0);
00410				Result = SendResult || Result;
00411				i++;
00412			}
00413			P = P.nextPawn;
00414		}
00415	
00416		return Result;
00417	}
00418	
00419	// Get an arbitrary property from the level object.
00420	function string GetLevelProperty( string Prop )
00421	{
00422		local string ResultSet;
00423		
00424		ResultSet = "\\"$Prop$"\\"$Level.GetPropertyText(Prop);
00425		
00426		return ResultSet;
00427	}
00428	
00429	// Get an arbitrary property from the game object.
00430	function string GetGameProperty( string Prop )
00431	{
00432		local string ResultSet;
00433	
00434		ResultSet = "\\"$Prop$"\\"$Level.Game.GetPropertyText(Prop);
00435		
00436		return ResultSet;
00437	}
00438	
00439	// Get an arbitrary property from the players.
00440	function string GetPlayerProperty( string Prop )
00441	{
00442		local string ResultSet;
00443		local int i;
00444		local PlayerPawn P;
00445	
00446		foreach AllActors(class'PlayerPawn', P) {
00447			i++;
00448			ResultSet = ResultSet$"\\"$Prop$"_"$i$"\\"$P.GetPropertyText(Prop);
00449		}
00450		
00451		return ResultSet;
00452	}
00453	
00454	defaultproperties
00455	{
00456	     QueryName=MasterUplink
00457	     GameName="ut"
00458	     RemoteRole=ROLE_None
00459	}

End Source Code