UBrowser
Class UBrowserServerPing

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

class UBrowserServerPing
extends IpDrv.UdpLink

//============================================================================= // UBrowserServerPing: Query an Unreal server for its details //=============================================================================
Variables
 string AdminEmailText
 string AdminNameText
 int AttemptNumber
 string BalanceTeamsText
 int BindAttempts
 int BindRetryTime
 string BotSkillText
 string ChangeLevelsText
 string DedicatedText
 string FalseString
 string FragLimitText
 string FriendlyFireText
 string GameModeText
 string GameTypeText
 string GameVersionText
 string GoalTeamScoreText
 float LastDelta
 int MaxBindAttempts
 string MaxTeamsText
 string MinNetVersionText
 string MinPlayersText
 string MultiplayerBotsText
 string MutatorsText
 string NonDedicatedText
 int PingAttempts
 int PingTimeout
 string PlayersBalanceTeamsText
 string PlayersText
 name QueryState
 float RequestSentTime
 UBrowserServerList Server
 string ServerAddressText
 IpAddr ServerIPAddr
 string ServerModeText
 string TimeLimitText
 string TournamentText
 string TrueString
 string WorldLogText
 string WorldLogWorkingFalse
 string WorldLogWorkingText
 string WorldLogWorkingTrue
 bool bInitial
 bool bJustThisServer
 bool bNoSort
 bool bUseMapName

States
Resolving, GetInfo, GetStatus, BindFailed, Binding

Function Summary
 void AddRule(string Rule, string Value)
 bool GetNextValue(string In, out string, out string)
 string LocalizeBoolValue(string Value)
 string LocalizeSkin(string SkinName)
 string LocalizeTeam(string TeamNum)
 string ParseReply(string Text, string Key)
 void Resolved(IpAddr Addr)
 void StartQuery(name S, int InPingAttempts)
 void ValidateServer()


State Resolving Function Summary


State GetInfo Function Summary


State GetStatus Function Summary


State BindFailed Function Summary


State Binding Function Summary



Source Code


00001	//=============================================================================
00002	// UBrowserServerPing: Query an Unreal server for its details
00003	//=============================================================================
00004	class UBrowserServerPing extends UdpLink;
00005	
00006	var UBrowserServerList	Server;
00007	
00008	var IpAddr				ServerIPAddr;
00009	var float				RequestSentTime;
00010	var float				LastDelta;
00011	var name				QueryState;
00012	var bool				bInitial;
00013	var bool				bJustThisServer;
00014	var bool				bNoSort;
00015	var int					PingAttempts;
00016	var int					AttemptNumber;
00017	var int					BindAttempts;
00018	
00019	var localized string	AdminEmailText;
00020	var localized string	AdminNameText;
00021	var localized string	ChangeLevelsText;
00022	var localized string	MultiplayerBotsText;
00023	var localized string	FragLimitText;
00024	var localized string	TimeLimitText;
00025	var localized string	GameModeText;
00026	var localized string	GameTypeText;
00027	var localized string	GameVersionText;
00028	var localized string	WorldLogText;
00029	var localized string	MutatorsText;
00030	var localized string	TrueString;
00031	var localized string	FalseString;
00032	var localized string	ServerAddressText;
00033	var localized string	GoalTeamScoreText;
00034	var localized string	MinPlayersText;
00035	var localized string	PlayersText;
00036	var localized string	MaxTeamsText;
00037	var localized string	BalanceTeamsText;
00038	var localized string	PlayersBalanceTeamsText;
00039	var localized string	FriendlyFireText;
00040	var localized string	MinNetVersionText;
00041	var localized string	BotSkillText;
00042	var localized string	TournamentText;
00043	var localized string	ServerModeText;
00044	var localized string	DedicatedText;
00045	var localized string	NonDedicatedText;
00046	var localized string	WorldLogWorkingText;
00047	var localized string	WorldLogWorkingTrue;
00048	var localized string	WorldLogWorkingFalse;
00049	
00050	// config
00051	var config int			MaxBindAttempts;
00052	var config int			BindRetryTime;
00053	var config int			PingTimeout;
00054	var config bool			bUseMapName;
00055	
00056	function ValidateServer()
00057	{
00058		if(Server.ServerPing != Self)
00059		{
00060			Log("ORPHANED: "$Self);
00061			Destroy();
00062		}
00063	}
00064	
00065	function StartQuery(name S, int InPingAttempts)
00066	{
00067		QueryState = S;
00068		ValidateServer();
00069		ServerIPAddr.Port = Server.QueryPort;
00070		GotoState('Resolving');
00071		PingAttempts=InPingAttempts;
00072		AttemptNumber=1;
00073	}
00074	
00075	function Resolved( IpAddr Addr )
00076	{
00077		ServerIPAddr.Addr = Addr.Addr;
00078	
00079		GotoState('Binding');
00080	}
00081	
00082	function bool GetNextValue(string In, out string Out, out string Result)
00083	{
00084		local int i;
00085		local bool bFoundStart;
00086	
00087		Result = "";
00088		bFoundStart = False;
00089	
00090		for(i=0;i<Len(In);i++) 
00091		{
00092			if(bFoundStart)
00093			{
00094				if(Mid(In, i, 1) == "\\")
00095				{
00096					Out = Right(In, Len(In) - i);
00097					return True;
00098				}
00099				else
00100				{
00101					Result = Result $ Mid(In, i, 1);
00102				}
00103			}
00104			else
00105			{
00106				if(Mid(In, i, 1) == "\\")
00107				{
00108					bFoundStart = True;
00109				}
00110			}
00111		}
00112	
00113		return False;
00114	}
00115	
00116	function string LocalizeBoolValue(string Value)
00117	{
00118		if(Value ~= "True")
00119			return TrueString;
00120		
00121		if(Value ~= "False")
00122			return FalseString;
00123	
00124		return Value;
00125	}
00126	
00127	function string LocalizeSkin(string SkinName)
00128	{
00129		local string MeshName, Junk, SkinDesc;
00130	
00131		MeshName = Left(SkinName, InStr(SkinName, "."));
00132	
00133		GetNextSkin(MeshName, SkinName$"1", 0, Junk, SkinDesc);
00134		if(Junk == "")
00135			GetNextSkin(MeshName, SkinName, 0, Junk, SkinDesc);
00136		if(Junk == "")
00137			return GetItemName(SkinName);
00138		
00139		return SkinDesc;
00140	}
00141	
00142	function string LocalizeTeam(string TeamNum)
00143	{
00144		if(TeamNum == "255")
00145			return "";
00146	
00147		return TeamNum;
00148	}
00149	
00150	function AddRule(string Rule, string Value)
00151	{
00152		local UBrowserRulesList  RulesList;
00153	
00154		ValidateServer();
00155	
00156		for(RulesList = UBrowserRulesList(Server.RulesList.Next); RulesList != None; RulesList = UBrowserRulesList(RulesList.Next))
00157			if(RulesList.Rule == Rule)
00158				return; // Rule already exists
00159	
00160		// Add the rule
00161		RulesList = UBrowserRulesList(Server.RulesList.Append(class'UBrowserRulesList'));
00162		RulesList.Rule = Rule;
00163		RulesList.Value = Value;
00164	}
00165	
00166	state Binding
00167	{
00168	Begin:
00169		if( BindPort(2000, true) == 0 )
00170		{
00171			Log("UBrowserServerPing: Port failed to bind.  Attempt "$BindAttempts);
00172			BindAttempts++;
00173	
00174			ValidateServer();
00175			if(BindAttempts == MaxBindAttempts)
00176				Server.PingDone(bInitial, bJustThisServer, False, bNoSort);
00177			else
00178				GotoState('BindFailed');
00179		}
00180		else
00181		{
00182			GotoState(QueryState);
00183		}
00184	}
00185	
00186	state BindFailed
00187	{
00188		event Timer()
00189		{
00190			GotoState('Binding');
00191		}
00192	
00193	Begin:
00194		SetTimer(BindRetryTime, False);
00195	}
00196	
00197	state GetStatus 
00198	{
00199		event ReceivedText( IpAddr Addr, string Text )
00200		{
00201			local string Value;
00202			local string In;
00203			local string Out;
00204			local byte ID;
00205			local bool bOK;
00206			local UBrowserPlayerList PlayerEntry;
00207	
00208			ValidateServer();
00209	
00210			In = Text;
00211			do 
00212			{
00213				bOK = GetNextValue(In, Out, Value);
00214				In = Out;
00215				if(Left(Value, 7) == "player_")
00216				{
00217					ID = Int(Right(Value, Len(Value) - 7));
00218	
00219					PlayerEntry = Server.PlayerList.FindID(ID);
00220					if(PlayerEntry == None) 
00221						PlayerEntry = UBrowserPlayerList(Server.PlayerList.Append(class'UBrowserPlayerList'));
00222					PlayerEntry.PlayerID = ID;
00223	
00224					bOK = GetNextValue(In, Out, Value);
00225					In = Out;
00226					PlayerEntry.PlayerName = Value;
00227				} 
00228				else if(Left(Value, 6) == "frags_") 
00229				{
00230					ID = Int(Right(Value, Len(Value) - 6));
00231	
00232					bOK = GetNextValue(In, Out, Value);
00233					In = Out;
00234					PlayerEntry = Server.PlayerList.FindID(ID);
00235					PlayerEntry.PlayerFrags = Int(Value);
00236				}
00237				else if(Left(Value, 5) == "ping_")
00238				{
00239					ID = Int(Right(Value, Len(Value) - 5));
00240	
00241					bOK = GetNextValue(In, Out, Value);
00242					In = Out;
00243					PlayerEntry = Server.PlayerList.FindID(ID);
00244					PlayerEntry.PlayerPing = Int(Right(Value, len(Value) - 1));  // leading space
00245				}
00246				else if(Left(Value, 5) == "team_")
00247				{
00248					ID = Int(Right(Value, Len(Value) - 5));
00249	
00250					bOK = GetNextValue(In, Out, Value);
00251					In = Out;
00252					PlayerEntry = Server.PlayerList.FindID(ID);
00253					PlayerEntry.PlayerTeam = LocalizeTeam(Value);
00254				}
00255				else if(Left(Value, 5) == "skin_")
00256				{
00257					ID = Int(Right(Value, Len(Value) - 5));
00258	
00259					bOK = GetNextValue(In, Out, Value);
00260					In = Out;
00261					PlayerEntry = Server.PlayerList.FindID(ID);
00262					PlayerEntry.PlayerSkin = LocalizeSkin(Value);
00263				}
00264				else if(Left(Value, 5) == "face_")
00265				{
00266					ID = Int(Right(Value, Len(Value) - 5));
00267	
00268					bOK = GetNextValue(In, Out, Value);
00269					In = Out;
00270					PlayerEntry = Server.PlayerList.FindID(ID);
00271					PlayerEntry.PlayerFace = GetItemName(Value);
00272				}
00273				else if(Left(Value, 5) == "mesh_")
00274				{
00275					ID = Int(Right(Value, Len(Value) - 5));
00276	
00277					bOK = GetNextValue(In, Out, Value);
00278					In = Out;
00279					PlayerEntry = Server.PlayerList.FindID(ID);
00280					PlayerEntry.PlayerMesh = Value;
00281				}
00282				else if(Left(Value, 9) == "ngsecret_")
00283				{
00284					ID = Int(Right(Value, Len(Value) - 9));
00285	
00286					bOK = GetNextValue(In, Out, Value);
00287					In = Out;
00288					PlayerEntry = Server.PlayerList.FindID(ID);
00289					PlayerEntry.PlayerStats = Value;
00290				}
00291				else if(Value == "final")
00292				{
00293					Server.StatusDone(True);
00294					return;
00295				}
00296				else if(Value ~= "gamever")
00297				{
00298					bOK = GetNextValue(In, Out, Value);
00299					AddRule(GameVersionText, Value);
00300				}
00301				else if(Value ~= "minnetver")
00302				{
00303					bOK = GetNextValue(In, Out, Value);
00304					AddRule(MinNetVersionText, Value);
00305				}
00306				else if(Value ~= "gametype")
00307				{
00308					bOK = GetNextValue(In, Out, Value);
00309					AddRule(GameTypeText, Value);
00310				}
00311	/*			else if(Value ~= "gamemode") // "openplaying"
00312				{
00313					bOK = GetNextValue(In, Out, Value);
00314					AddRule(GameModeText, Value);
00315				}*/
00316				else if(Value ~= "timelimit") 
00317				{
00318					bOK = GetNextValue(In, Out, Value);
00319					AddRule(TimeLimitText, Value);
00320				}
00321				else if(Value ~= "fraglimit") 
00322				{
00323					bOK = GetNextValue(In, Out, Value);
00324					AddRule(FragLimitText, Value);
00325				}
00326				else if(Value ~= "MultiplayerBots") 
00327				{
00328					bOK = GetNextValue(In, Out, Value);
00329					AddRule(MultiplayerBotsText, LocalizeBoolValue(Value));
00330				}
00331				else if(Value ~= "AdminName") 
00332				{
00333					bOK = GetNextValue(In, Out, Value);
00334					AddRule(AdminNameText, Value);
00335				}
00336				else if(Value ~= "AdminEMail")
00337				{
00338					bOK = GetNextValue(In, Out, Value);
00339					AddRule(AdminEmailText, Value);
00340				}
00341				else if(Value ~= "WantWorldLog")
00342				{
00343					bOK = GetNextValue(In, Out, Value);
00344					AddRule(WorldLogText, LocalizeBoolValue(Value));
00345				}
00346				else if(Value ~= "WorldLog")
00347				{
00348					bOK = GetNextValue(In, Out, Value);
00349					if( Server.GameVer >= 406 )
00350					{
00351						if( Value ~= "True" )
00352							AddRule(WorldLogWorkingText, WorldLogWorkingTrue);
00353						else
00354							AddRule(WorldLogWorkingText, WorldLogWorkingFalse);
00355					}
00356					else
00357						AddRule(WorldLogText, LocalizeBoolValue(Value));
00358				}
00359				else if(Value ~= "mutators")
00360				{
00361					bOK = GetNextValue(In, Out, Value);
00362					AddRule(MutatorsText, Value);
00363				}
00364				else if(Value ~= "goalteamscore")
00365				{
00366					bOK = GetNextValue(In, Out, Value);
00367					AddRule(GoalTeamScoreText, Value);		
00368				}
00369				else if(Value ~= "minplayers")
00370				{
00371					bOK = GetNextValue(In, Out, Value);
00372					if(Value == "0")
00373						AddRule(MultiplayerBotsText, FalseString);
00374					else
00375						AddRule(MinPlayersText, Value@PlayersText);		
00376				}
00377				else if(Value ~= "changelevels")
00378				{
00379					bOK = GetNextValue(In, Out, Value);
00380					AddRule(ChangeLevelsText, LocalizeBoolValue(Value));		
00381				}
00382				else if(Value ~= "botskill")
00383				{
00384					bOK = GetNextValue(In, Out, Value);
00385					AddRule(BotSkillText, Value);		
00386				}
00387				else if(Value ~= "maxteams")
00388				{
00389					bOK = GetNextValue(In, Out, Value);
00390					AddRule(MaxTeamsText, Value);
00391				}
00392				else if(Value ~= "balanceteams")
00393				{
00394					bOK = GetNextValue(In, Out, Value);
00395					AddRule(BalanceTeamsText, LocalizeBoolValue(Value));
00396				}
00397				else if(Value ~= "playersbalanceteams")
00398				{
00399					bOK = GetNextValue(In, Out, Value);
00400					AddRule(PlayersBalanceTeamsText, LocalizeBoolValue(Value));
00401				}
00402				else if(Value ~= "friendlyfire")
00403				{
00404					bOK = GetNextValue(In, Out, Value);
00405					AddRule(FriendlyFireText, Value);
00406				}
00407				else if(Value ~= "gamestyle")
00408				{
00409					bOK = GetNextValue(In, Out, Value);
00410					AddRule(GameModeText, Value);
00411				}
00412				else if(Value ~= "tournament")
00413				{
00414					bOK = GetNextValue(In, Out, Value);
00415					AddRule(TournamentText, LocalizeBoolValue(Value));
00416				}
00417				else if(Value ~= "listenserver")
00418				{
00419					bOK = GetNextValue(In, Out, Value);
00420					if(bool(Value))
00421						AddRule(ServerModeText, NonDedicatedText);
00422					else
00423						AddRule(ServerModeText, DedicatedText);
00424				}
00425			} until(!bOK);
00426		}	
00427	
00428		event Timer()
00429		{
00430			if(AttemptNumber < PingAttempts)
00431			{
00432				Log("Timed out getting player replies.  Attempt "$AttemptNumber);
00433				AttemptNumber++;
00434				GotoState(QueryState);
00435			}
00436			else
00437			{
00438				Server.StatusDone(False);
00439				Log("Timed out getting player replies.  Giving Up");
00440			}
00441		}
00442	Begin:
00443		// Player info
00444	
00445		ValidateServer();
00446		if(Server.PlayerList != None)
00447		{
00448			Server.PlayerList.DestroyList();
00449		}
00450		Server.PlayerList = New(None) class'UBrowserPlayerList';
00451		Server.PlayerList.SetupSentinel();	
00452	
00453		if(Server.RulesList != None)
00454		{
00455			Server.RulesList.DestroyList();
00456		}
00457		Server.RulesList = New(None) class'UBrowserRulesList';
00458		Server.RulesList.SetupSentinel();
00459		AddRule(ServerAddressText, "unreal://"$Server.IP$":"$string(Server.GamePort));
00460	
00461		SendText( ServerIPAddr, "\\status\\" );
00462		SetTimer(PingTimeout + FRand(), False);
00463	}
00464	
00465	function string ParseReply(string Text, string Key)
00466	{
00467		local int i;
00468		local string Temp;
00469	
00470		i=InStr(Text, "\\"$Key$"\\");
00471		Temp = Mid(Text, i + Len(Key) + 2);
00472		return Left(Temp, InStr(Temp, "\\"));
00473	}
00474	
00475	state GetInfo
00476	{
00477		event ReceivedText(IpAddr Addr, string Text)
00478		{
00479			local string Temp;
00480			local float ElapsedTime;
00481	
00482			// Make sure this packet really is for us.
00483			Temp = IpAddrToString(Addr);
00484			if(Server.IP != Left(Temp, InStr(Temp, ":")))
00485				return;
00486	
00487			ValidateServer();
00488			ElapsedTime = (Level.TimeSeconds - RequestSentTime) * Level.TimeDilation;
00489			Server.Ping = Max(1000*ElapsedTime - (0.5*LastDelta) - 10, 4); // subtract avg client and server frametime from ping.
00490			if(!Server.bKeepDescription)
00491				Server.HostName = Server.IP;
00492			Server.GamePort = 0;
00493			Server.MapName = "";
00494			Server.MapTitle = "";
00495			Server.MapDisplayName = "";
00496			Server.GameType = "";
00497			Server.GameMode = "";
00498			Server.NumPlayers = 0;
00499			Server.MaxPlayers = 0;
00500			Server.GameVer = 0;
00501			Server.MinNetVer = 0;
00502	
00503			Temp = ParseReply(Text, "hostname");
00504			if(Temp != "" && !Server.bKeepDescription)
00505				Server.HostName = Temp;
00506	
00507			Temp = ParseReply(Text, "hostport");
00508			if(Temp != "")
00509				Server.GamePort = Int(Temp);
00510	
00511			Temp = ParseReply(Text, "mapname");
00512			if(Temp != "")
00513				Server.MapName = Temp;
00514	
00515			Temp = ParseReply(Text, "maptitle");
00516			if(Temp != "")
00517			{
00518				Server.MapTitle = Temp;
00519				Server.MapDisplayName = Server.MapTitle;
00520				if(Server.MapTitle == "" || Server.MapTitle ~= "Untitled" || bUseMapName)
00521					Server.MapDisplayName = Server.MapName;
00522			}
00523			
00524			Temp = ParseReply(Text, "gametype");
00525			if(Temp != "")
00526				Server.GameType = Temp;
00527		
00528			Temp = ParseReply(Text, "numplayers");
00529			if(Temp != "")
00530				Server.NumPlayers = Int(Temp);
00531	
00532			Temp = ParseReply(Text, "maxplayers");
00533			if(Temp != "")
00534				Server.MaxPlayers = Int(Temp);
00535		
00536			Temp = ParseReply(Text, "gamemode");
00537			if(Temp != "")
00538				Server.GameMode = Temp;
00539	
00540			Temp = ParseReply(Text, "gamever");
00541			if(Temp != "")
00542				Server.GameVer = Int(Temp);
00543	
00544			Temp = ParseReply(Text, "minnetver");
00545			if(Temp != "")
00546				Server.MinNetVer = Int(Temp);
00547	
00548			if( Server.DecodeServerProperties(Text) )
00549			{
00550				Server.PingDone(bInitial, bJustThisServer, True, bNoSort);
00551				Disable('Tick');
00552			}
00553		}
00554	
00555		event Tick(Float DeltaTime)
00556		{
00557			LastDelta = DeltaTime;
00558		}
00559	
00560		event Timer()
00561		{
00562			ValidateServer();
00563			if(AttemptNumber < PingAttempts)
00564			{
00565				Log("Ping Timeout from "$Server.IP$".  Attempt "$AttemptNumber);
00566				AttemptNumber++;
00567				GotoState(QueryState);
00568			}
00569			else
00570			{
00571				Log("Ping Timeout from "$Server.IP$" Giving Up");
00572	
00573				Server.Ping = 9999;
00574				Server.GamePort = 0;
00575				Server.MapName = "";
00576				Server.MapDisplayName = "";
00577				Server.MapTitle = "";
00578				Server.GameType = "";
00579				Server.GameMode = "";
00580				Server.NumPlayers = 0;
00581				Server.MaxPlayers = 0;
00582	
00583				Disable('Tick');
00584	
00585				Server.PingDone(bInitial, bJustThisServer, False, bNoSort);
00586			}
00587		}
00588	
00589	Begin:
00590		Enable('Tick');
00591		SendText( ServerIPAddr, "\\info\\" );
00592		RequestSentTime = Level.TimeSeconds;
00593		SetTimer(PingTimeout + FRand(), False);
00594	}
00595	
00596	state Resolving
00597	{
00598	Begin:
00599		Resolve( Server.IP );
00600	}
00601	
00602	defaultproperties
00603	{
00604	     AdminEmailText="Admin Email"
00605	     AdminNameText="Admin Name"
00606	     ChangeLevelsText="Change Levels"
00607	     MultiplayerBotsText="Bots in Multiplayer"
00608	     FragLimitText="Frag Limit"
00609	     TimeLimitText="Time Limit"
00610	     GameModeText="Game Mode"
00611	     GameTypeText="Game Type"
00612	     GameVersionText="Game Version"
00613	     WorldLogText="ngWorldStats"
00614	     MutatorsText="Mutators"
00615	     TrueString="Enabled"
00616	     FalseString="Disabled"
00617	     ServerAddressText="Server Address"
00618	     GoalTeamScoreText="Required Team Score"
00619	     MinPlayersText="Bots Enter Game for Min. of"
00620	     PlayersText="Players"
00621	     MaxTeamsText="Max Teams"
00622	     BalanceTeamsText="Bots Balance Teams"
00623	     PlayersBalanceTeamsText="Force Team Balance"
00624	     FriendlyFireText="Friendly Fire Damage"
00625	     MinNetVersionText="Min. Compatible Version"
00626	     BotSkillText="Bot Skill"
00627	     TournamentText="Tournament Mode"
00628	     ServerModeText="Server Mode"
00629	     DedicatedText="Dedicated"
00630	     NonDedicatedText="Non-Dedicated"
00631	     WorldLogWorkingText="ngWorldStats Status"
00632	     WorldLogWorkingTrue="Processing Stats Correctly"
00633	     WorldLogWorkingFalse="Not Processing Stats Correctly"
00634	     MaxBindAttempts=5
00635	     BindRetryTime=10
00636	     PingTimeout=1
00637	}

End Source Code