UBrowser
Class UBrowserServerPing

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

End Source Code