IpServer
Class UdpServerQuery

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

End Source Code