home *** CD-ROM | disk | FTP | other *** search
/ Game Level Design / GLDesign.bin / Software / UnrealEngine2Runtime / UE2Runtime-22262001_Demo.exe / IpDrv / Classes / UdpGamespyQuery.uc < prev    next >
Text File  |  2003-10-22  |  13KB  |  470 lines

  1. //=============================================================================
  2. // UdpGameSpyQuery
  3. //
  4. // Version: 1.5
  5. //
  6. // This query server is compliant with the GameSpy Uplink Specification.
  7. // The specification is available at http://www.gamespy.com/developer
  8. // and might be of use to progammers who are writing or maintaining
  9. // their own stat gathering/game querying software.
  10. //
  11. // Note: Currently, SendText returns false if successful.
  12. //
  13. // Full documentation on this class is available at http://unreal.epicgames.com/
  14. //
  15. //=============================================================================
  16. class UdpGameSpyQuery extends UdpLink config;
  17.  
  18. // Game Server Config.
  19. var() name                    QueryName;            // Name to set this object's Tag to.
  20. var int                        CurrentQueryNum;    // Query ID Number.
  21. //crt
  22. var string ReplyData;
  23.  
  24. var globalconfig int        MinNetVer;
  25.  
  26. //!! Hack to prevent port swapping
  27. var globalconfig int        OldQueryPortNumber;
  28. var globalconfig bool        bRestartServerOnPortSwap;
  29.  
  30.  
  31.  
  32. // Initialize.
  33. function PreBeginPlay()
  34. {
  35.     local int boundport;
  36.  
  37.     // Set the Tag
  38.     Tag = QueryName;
  39.  
  40.     // Bind the listen socket
  41.     boundport = BindPort(Level.Game.GetServerPort()+10, true);
  42.     if( boundport == 0 )
  43.     {
  44.         Log("UdpServerQuery: Port failed to bind.");
  45.         return;
  46.     }
  47.     Log("UdpServerQuery(crt): Port "$boundport$" successfully bound.");
  48.  
  49.     if( bRestartServerOnPortSwap )
  50.     {
  51.         if( OldQueryPortNumber != 0 )
  52.             assert( OldQueryPortNumber == boundport );
  53.         OldQueryPortNumber = boundport;
  54.         SaveConfig();
  55.     }
  56. }
  57.  
  58. function PostBeginPlay()
  59. {
  60.     local UdpBeacon    Beacon;
  61.  
  62.     foreach AllActors(class'UdpBeacon', Beacon)
  63.     {
  64.         Beacon.UdpServerQueryPort = Port;
  65.     }
  66.     Super.PostBeginPlay();
  67. }
  68.  
  69. // Received a query request.
  70. event ReceivedText( IpAddr Addr, string Text )
  71. {
  72.     local string Query;
  73.     local bool QueryRemaining;
  74.     local int  QueryNum, PacketNum;
  75.  
  76.     // Assign this packet a unique value from 1 to 100
  77.     CurrentQueryNum++;
  78.     if (CurrentQueryNum > 100)
  79.         CurrentQueryNum = 1;
  80.     QueryNum = CurrentQueryNum;
  81.  
  82.     Query = Text;
  83.     if (Query == "")        // If the string is empty, don't parse it
  84.         QueryRemaining = false;
  85.     else
  86.         QueryRemaining = true;
  87.     //crt
  88.     PacketNum =  0;
  89.     ReplyData = "";
  90.     while (QueryRemaining) {
  91.         Query = ParseQuery(Addr, Query, QueryNum, PacketNum);
  92.         if (Query == "")
  93.             QueryRemaining = false;
  94.         else
  95.             QueryRemaining = true;
  96.     }
  97. }
  98.  
  99. function bool ParseNextQuery( string Query, out string QueryType, out string QueryValue, out string QueryRest, out int bFinalPacket )
  100. {
  101.     local string TempQuery;
  102.     local int ClosingSlash;
  103.  
  104.     if (Query == "")
  105.         return false;
  106.  
  107.     // Query should be:
  108.     //   \[type]\<value>
  109.     if (Left(Query, 1) == "\\")
  110.     {
  111.         // Check to see if closed.
  112.         ClosingSlash = InStr(Right(Query, Len(Query)-1), "\\");
  113.         if (ClosingSlash == 0)
  114.             return false;
  115.  
  116.         TempQuery = Query;
  117.  
  118.         // Query looks like:
  119.         //  \[type]\
  120.         QueryType = Right(Query, Len(Query)-1);
  121.         QueryType = Left(QueryType, ClosingSlash);
  122.  
  123.         QueryRest = Right(Query, Len(Query) - (Len(QueryType) + 2));
  124.  
  125.         if ((QueryRest == "") || (Len(QueryRest) == 1))
  126.         {
  127.             bFinalPacket = 1;
  128.             return true;
  129.         } else if (Left(QueryRest, 1) == "\\")
  130.             return true;    // \type\\
  131.  
  132.         // Query looks like:
  133.         //  \type\value
  134.         ClosingSlash = InStr(QueryRest, "\\");
  135.         if (ClosingSlash >= 0)
  136.             QueryValue = Left(QueryRest, ClosingSlash);
  137.         else
  138.             QueryValue = QueryRest;
  139.  
  140.         QueryRest = Right(Query, Len(Query) - (Len(QueryType) + Len(QueryValue) + 3));
  141.         if (QueryRest == "")
  142.         {
  143.             bFinalPacket = 1;
  144.             return true;
  145.         } else
  146.             return true;
  147.     } else {
  148.         return false;
  149.     }
  150. }
  151.  
  152. function string ParseQuery( IpAddr Addr, coerce string Query, int QueryNum, out int PacketNum )
  153. {
  154.     local string QueryType, QueryValue, QueryRest, ValidationString;
  155.     local bool Result;
  156.     local int bFinalPacket;
  157.     
  158.     bFinalPacket = 0;
  159.     Result = ParseNextQuery(Query, QueryType, QueryValue, QueryRest, bFinalPacket);
  160.     if( !Result )
  161.         return "";
  162.  
  163.     //Log("Got  Query: "  $ QueryNum $ "." $ PacketNum $ ":" $ QueryType);
  164.  
  165.     if( QueryType=="basic" )
  166.     {
  167.         Result = SendQueryPacket(Addr, GetBasic(), QueryNum, PacketNum, bFinalPacket);
  168.     }
  169.     else if( QueryType=="info" )
  170.     {
  171.         Result = SendQueryPacket(Addr, GetInfo(), QueryNum, PacketNum, bFinalPacket);
  172.     }
  173.     else if( QueryType=="rules" )
  174.     {
  175.         Result = SendQueryPacket(Addr, GetRules(), QueryNum, PacketNum, bFinalPacket);
  176.     }
  177.     else if( QueryType=="players" )
  178.     {
  179.         if( Level.Game.NumPlayers > 0 )
  180.             Result = SendPlayers(Addr, QueryNum, PacketNum, bFinalPacket);
  181.         else
  182.             Result = SendQueryPacket(Addr, "", QueryNum, PacketNum, bFinalPacket);
  183.     }
  184.     else if( QueryType=="status" )
  185.     {
  186.         Result = SendQueryPacket(Addr, GetBasic(), QueryNum, PacketNum, 0);
  187.         Result = SendQueryPacket(Addr, GetInfo(), QueryNum, PacketNum, 0);
  188.         if( Level.Game.NumPlayers == 0 )
  189.         {
  190.             Result = SendQueryPacket(Addr, GetRules(), QueryNum, PacketNum, bFinalPacket);
  191.         }
  192.         else
  193.         {
  194.             Result = SendQueryPacket(Addr, GetRules(), QueryNum, PacketNum, 0);
  195.             Result = SendPlayers(Addr, QueryNum, PacketNum, bFinalPacket);
  196.         }
  197.     }
  198.     else if( QueryType=="echo" )
  199.     {
  200.         // Respond to an echo with the same string
  201.         //!! disabled due to security problem - the remote ip/port could be spoofed to cause an echo loop!
  202.         Result = SendQueryPacket(Addr, "\\ignoring\\"$QueryValue, QueryNum, PacketNum, bFinalPacket);
  203.     }
  204.     else if( QueryType=="secure" )
  205.     {
  206.         ValidationString = "\\validate\\"$GameSpyValidate(QueryValue);
  207.         Result = SendQueryPacket(Addr, ValidationString, QueryNum, PacketNum, bFinalPacket);
  208.     }
  209.     else if( QueryType=="level_property" )
  210.     {
  211.         Result = SendQueryPacket(Addr, GetLevelProperty(QueryValue), QueryNum, PacketNum, bFinalPacket);
  212.     }
  213.     else if( QueryType=="game_property" )
  214.     {
  215.             Result = SendQueryPacket(Addr, GetGameProperty(QueryValue), QueryNum, PacketNum, bFinalPacket);
  216.     }
  217.     else if( QueryType=="player_property" )
  218.     {
  219.         Result = SendQueryPacket(Addr, GetPlayerProperty(QueryValue), QueryNum, PacketNum, bFinalPacket);
  220.     }
  221.     return QueryRest;
  222. }
  223.  
  224. function bool SendAPacket(IpAddr Addr, int QueryNum, out int PacketNum, int bFinalPacket)
  225. {
  226.     local bool Result;
  227.  
  228.     ReplyData = ReplyData$"\\queryid\\"$QueryNum$"."$++PacketNum;
  229.     if (bFinalPacket == 1) {
  230.         ReplyData = ReplyData $ "\\final\\";
  231.     }
  232.     Result = SendText(Addr, ReplyData);
  233.     ReplyData = "";
  234.     
  235.     return Result;
  236.  
  237. }
  238.  
  239. // SendQueryPacket is a wrapper for SendText that allows for packet numbering.
  240. function bool SendQueryPacket(IpAddr Addr, coerce string SendString, int QueryNum, out int PacketNum, int bFinalPacket)
  241. {
  242.     local bool Result;
  243.     
  244.     //Log("Send Query: "  $ QueryNum $ "." $ PacketNum $ ":" $ bFinalPacket);
  245.     result = true;
  246.     if (len(ReplyData) + len(SendString) > 1000)
  247.         result = SendAPacket(Addr, QueryNum, PacketNum, 0);
  248.     
  249.     ReplyData = ReplyData $ SendString;
  250.     
  251.     if (bFinalPacket == 1)
  252.         result = SendAPacket(Addr, QueryNum, PacketNum, bFinalPacket);
  253.         
  254.     return Result;
  255. }
  256.  
  257. // Return a string of basic information.
  258. function string GetBasic() {
  259.     local string ResultSet;
  260.  
  261.     // The name of this game.
  262.     ResultSet = "\\gamename\\"$GameSpyGameName();
  263.  
  264.     // The version of this game.
  265.     ResultSet = ResultSet$"\\gamever\\"$Level.EngineVersion;
  266.  
  267.     // The most recent network compatible version.
  268.     if( MinNetVer >= Int(Level.MinNetVersion) && 
  269.         MinNetVer <= Int(Level.EngineVersion) )
  270.         ResultSet = ResultSet$"\\minnetver\\"$string(MinNetVer);
  271.     else
  272.         ResultSet = ResultSet$"\\minnetver\\"$Level.MinNetVersion;
  273.  
  274.     // The regional location of this game.
  275.     ResultSet = ResultSet$"\\location\\"$class'UdpGamespyUplink'.default.ServerRegion;
  276.     
  277.     return ResultSet;
  278. }
  279.  
  280. // Return a string of important system information.
  281. function string GetInfo() {
  282.     local string ResultSet;
  283.     local string ServerName;
  284.     
  285.     ServerName = Level.Game.GameReplicationInfo.ServerName;
  286.     ReplaceText(ServerName,"\\","");    // strip \'s
  287.  
  288.     // The server name, i.e.: Bob's Server
  289.     ResultSet = "\\hostname\\"$ServerName;
  290.  
  291.     // The short server name
  292.     //ResultSet = ResultSet$"\\shortname\\"$Level.Game.GameReplicationInfo.ShortName;
  293.  
  294.     // The server port.
  295.     ResultSet = ResultSet$"\\hostport\\"$Level.Game.GetServerPort();
  296.  
  297.     // (optional) The server IP
  298.     // if (ServerIP != "")
  299.     //    ResultSet = ResultSet$"\\hostip\\"$ServerIP;
  300.  
  301.     // The map/level title
  302.     ResultSet = ResultSet$"\\maptitle\\"$Level.Title;
  303.     
  304.     // Map name
  305.     ResultSet = ResultSet$"\\mapname\\"$Left(string(Level), InStr(string(Level), "."));
  306.  
  307.     // The mod or game type
  308.     ResultSet = ResultSet$"\\gametype\\"$GetItemName(string(Level.Game.Class));
  309.  
  310.     // The number of players
  311.     ResultSet = ResultSet$"\\numplayers\\"$Level.Game.GetNumPlayers();
  312.  
  313.     // The maximum number of players
  314.     ResultSet = ResultSet$"\\maxplayers\\"$Level.Game.MaxPlayers;
  315.  
  316.     // The game mode: openplaying
  317.     ResultSet = ResultSet$"\\gamemode\\openplaying";
  318.  
  319.     // The version of this game.
  320.     ResultSet = ResultSet$"\\gamever\\"$Level.EngineVersion;
  321.  
  322.     // The most recent network compatible version.
  323.     if( MinNetVer >= Int(Level.MinNetVersion) && 
  324.         MinNetVer <= Int(Level.EngineVersion) )
  325.         ResultSet = ResultSet$"\\minnetver\\"$string(MinNetVer);
  326.     else
  327.         ResultSet = ResultSet$"\\minnetver\\"$Level.MinNetVersion;
  328.  
  329.     //ResultSet = ResultSet$Level.Game.GetInfo();
  330.  
  331.     return ResultSet;
  332. }
  333.  
  334. // Return a string of miscellaneous information.
  335. // Game specific information, user defined data, custom parameters for the command line.
  336. function string GetRules()
  337. {
  338.     local string ResultSet;
  339.  
  340.     //ResultSet = Level.Game.GetRules();
  341.  
  342.     // Admin's Name
  343.     if( Level.Game.GameReplicationInfo.AdminName != "" )
  344.         ResultSet = ResultSet$"\\AdminName\\"$Level.Game.GameReplicationInfo.AdminName;
  345.     
  346.     // Admin's Email
  347.     if( Level.Game.GameReplicationInfo.AdminEmail != "" )
  348.         ResultSet = ResultSet$"\\AdminEMail\\"$Level.Game.GameReplicationInfo.AdminEmail;
  349.  
  350.     // Whether the server is password protected.
  351.     if( Level.Game.AccessControl != None && Level.Game.AccessControl.RequiresPassword() )
  352.         ResultSet = ResultSet$"\\password\\1";
  353.     else
  354.         ResultSet = ResultSet$"\\password\\0";
  355.  
  356.     return ResultSet;
  357. }
  358.  
  359. // Return a string of information on a player.
  360. function string GetPlayer( PlayerController P, int PlayerNum )
  361. {
  362.     local string ResultSet;
  363.     local string PlayerName;
  364.     
  365.     PlayerName = P.PlayerReplicationInfo.PlayerName;
  366.  
  367.     // Name
  368.     ReplaceText(PlayerName,"\\","");    // strip \'s
  369.     ResultSet = "\\player_"$PlayerNum$"\\"$PlayerName;
  370.  
  371.     // Frags
  372.     ResultSet = ResultSet$"\\frags_"$PlayerNum$"\\"$int(P.PlayerReplicationInfo.Score);
  373.  
  374.     // Ping
  375.     ResultSet = ResultSet$"\\ping_"$PlayerNum$"\\"$P.ConsoleCommand("GETPING");
  376.  
  377.     // Team
  378.     if(P.PlayerReplicationInfo.Team != None)
  379.         ResultSet = ResultSet$"\\team_"$PlayerNum$"\\"$P.PlayerReplicationInfo.Team.TeamIndex;
  380.     else
  381.         ResultSet = ResultSet$"\\team_"$PlayerNum$"\\0";
  382.  
  383.     return ResultSet;
  384. }
  385.  
  386. // Send data for each player
  387. function bool SendPlayers(IpAddr Addr, int QueryNum, out int PacketNum, int bFinalPacket)
  388. {
  389.     local Controller C;
  390.     local int i;
  391.     local bool Result, SendResult;
  392.     
  393.     Result = false;
  394.  
  395.     C = Level.ControllerList;
  396.     while( i < Level.Game.NumPlayers )
  397.     {
  398.         if (C == None)
  399.         {
  400.             if(bFinalPacket==1)
  401.                 SendResult = SendAPacket(Addr,QueryNum,PacketNum,bFinalPacket);
  402.             Result = SendResult || Result;
  403.             break;
  404.         }
  405.         else if (C.IsA('PlayerController') && C.PlayerReplicationInfo != None && !C.PlayerReplicationInfo.bOnlySpectator)
  406.         {
  407.             if( i==Level.Game.NumPlayers-1 && bFinalPacket==1)
  408.                 SendResult = SendQueryPacket(Addr, GetPlayer(PlayerController(C), i), QueryNum, PacketNum, 1);
  409.             else
  410.                 SendResult = SendQueryPacket(Addr, GetPlayer(PlayerController(C), i), QueryNum, PacketNum, 0);
  411.             Result = SendResult || Result;
  412.             i++;
  413.         }
  414.         C = C.NextController;
  415.     }
  416.  
  417.     return Result;
  418. }
  419.  
  420. // Get an arbitrary property from the level object.
  421. function string GetLevelProperty( string Prop )
  422. {
  423.     local string ResultSet;
  424.     
  425.     ResultSet = "\\"$Prop$"\\"$Level.GetPropertyText(Prop);
  426.     
  427.     return ResultSet;
  428. }
  429.  
  430. // Get an arbitrary property from the game object.
  431. function string GetGameProperty( string Prop )
  432. {
  433.     local string ResultSet;
  434.  
  435.     ResultSet = "\\"$Prop$"\\"$Level.Game.GetPropertyText(Prop);
  436.     
  437.     return ResultSet;
  438. }
  439.  
  440. // Get an arbitrary property from the players.
  441. function string GetPlayerProperty( string Prop )
  442. {
  443.     local string ResultSet;
  444.     local int i;
  445.     local Controller C;
  446.  
  447.     foreach AllActors(class'Controller', C)
  448.     {
  449.         if( C.PlayerReplicationInfo!=None && !C.PlayerReplicationInfo.bBot )
  450.         {
  451.             i++;
  452.             ResultSet = ResultSet$
  453.                 "\\"$
  454.                 Prop$
  455.                 "_"$
  456.                 i$
  457.                 "\\"$
  458.                 C.GetPropertyText(Prop);
  459.         }
  460.     }
  461.     
  462.     
  463.     return ResultSet;
  464. }
  465.  
  466. defaultproperties
  467. {
  468.      QueryName=MasterUplink
  469.      RemoteRole=ROLE_None
  470. }