diff --git a/Facepunch.Steamworks.Test/Client/ServerlistTest.cs b/Facepunch.Steamworks.Test/Client/ServerlistTest.cs index 3e03e6d..1de984e 100644 --- a/Facepunch.Steamworks.Test/Client/ServerlistTest.cs +++ b/Facepunch.Steamworks.Test/Client/ServerlistTest.cs @@ -4,13 +4,14 @@ using System.Linq; using System.Net; using System.Text; using System.Threading; +using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Facepunch.Steamworks.Test +namespace Steamworks { [TestClass] [DeploymentItem( "steam_api64.dll" )] - public partial class ServerList + public partial class ServerListTest { [TestMethod] public void IpAddressConversions() @@ -30,440 +31,115 @@ namespace Facepunch.Steamworks.Test [TestMethod] - public void InternetList() + public async Task ServerListInternetInterupted() { - using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) - { - var filter = new Facepunch.Steamworks.ServerList.Filter(); - filter.Add( "appid", client.AppId.ToString() ); - filter.Add( "gamedir", "rust" ); - filter.Add( "secure", "1" ); - - var query = client.ServerList.Internet( filter ); - - for ( int i = 0; i < 1000; i++ ) - { - client.Update(); - System.Threading.Thread.Sleep( 100 ); - - foreach ( var s in query.Responded ) - { - Assert.AreEqual( s.AppId, client.AppId ); - Assert.AreEqual( s.GameDir, "rust" ); - } - - if ( query.Finished ) - break; - } - - Assert.IsTrue( query.Responded.Count > 0 ); - - Console.WriteLine( "Responded: " + query.Responded.Count.ToString() ); - Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() ); - - foreach ( var server in query.Responded.Take( 20 ) ) - { - Console.WriteLine( "{0} {1}", server.Address, server.Name ); - } - - query.Dispose(); - - for ( int i = 0; i < 100; i++ ) - { - client.Update(); - System.Threading.Thread.Sleep( 1 ); - } - } - } - - [TestMethod] - public void MultipleInternetList() - { - using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) - { - var queries = new List(); - - var filter = new Facepunch.Steamworks.ServerList.Filter(); - filter.Add( "map", "barren" ); - - for ( int i = 0; i < 10; i++ ) - queries.Add( client.ServerList.Internet( filter ) ); - - for ( int i = 0; i < 100; i++ ) - { - client.Update(); - System.Threading.Thread.Sleep( 5 ); - - if ( queries.Any( x => x.Finished ) ) - break; - } - - foreach ( var query in queries ) - { - Console.WriteLine( "Responded: " + query.Responded.Count.ToString() ); - Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() ); - - client.Update(); - query.Dispose(); - client.Update(); - } - } - } - - [TestMethod] - public void Filters() - { - using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) - { - var filter = new Facepunch.Steamworks.ServerList.Filter(); - filter.Add( "map", "barren" ); - - - var query = client.ServerList.Internet( filter ); - - while ( true ) - { - client.Update(); - System.Threading.Thread.Sleep( 2 ); - - if ( query.Finished ) - break; - } - - foreach ( var x in query.Responded ) - { - Assert.AreEqual( x.Map.ToLower(), "barren" ); - } - - query.Dispose(); - - for ( int i = 0; i < 100; i++ ) - { - client.Update(); - System.Threading.Thread.Sleep( 1 ); - } - } - } - - [TestMethod] - public void HistoryList() - { - using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) - { - var filter = new Facepunch.Steamworks.ServerList.Filter(); - filter.Add( "appid", client.AppId.ToString() ); - filter.Add( "gamedir", "rust" ); - filter.Add( "secure", "1" ); - - var query = client.ServerList.History( filter ); - - while ( true ) - { - client.Update(); - System.Threading.Thread.Sleep( 2 ); - - if ( query.Finished ) - break; - } - - Console.WriteLine( "Responded: " + query.Responded.Count.ToString() ); - Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() ); - - foreach ( var x in query.Responded ) - { - Console.WriteLine( x.Map ); - } - - query.Dispose(); - - for ( int i = 0; i < 100; i++ ) - { - client.Update(); - System.Threading.Thread.Sleep( 1 ); - } - } - } - - [TestMethod] - public void FavouriteList() - { - using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) - { - var filter = new Facepunch.Steamworks.ServerList.Filter(); - filter.Add( "appid", client.AppId.ToString() ); - filter.Add( "gamedir", "rust" ); - filter.Add( "secure", "1" ); - - var query = client.ServerList.Favourites( filter ); - - while ( true ) - { - client.Update(); - System.Threading.Thread.Sleep( 2 ); - - if ( query.Finished ) - break; - } - - Console.WriteLine( "Responded: " + query.Responded.Count.ToString() ); - Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() ); - - foreach ( var x in query.Responded ) - { - Console.WriteLine( x.Map ); - } - - query.Dispose(); - - for ( int i = 0; i < 100; i++ ) - { - client.Update(); - System.Threading.Thread.Sleep( 1 ); - } - } - } - - [TestMethod] - public void LocalList() - { - using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) - { - var filter = new Facepunch.Steamworks.ServerList.Filter(); - filter.Add( "appid", client.AppId.ToString() ); - filter.Add( "gamedir", "rust" ); - filter.Add( "secure", "1" ); - - var query = client.ServerList.Local( filter ); - - while ( true ) - { - client.Update(); - System.Threading.Thread.Sleep( 2 ); - - if ( query.Finished ) - break; - } - - Console.WriteLine( "Responded: " + query.Responded.Count.ToString() ); - Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() ); - - foreach ( var x in query.Responded ) - { - Console.WriteLine( x.Map ); - } - - query.Dispose(); - - for ( int i = 0; i < 100; i++ ) - { - client.Update(); - System.Threading.Thread.Sleep( 1 ); - } - } - } - - [TestMethod] - public void CustomList() - { - using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) - { - var servers = new List(); - - servers.Add( "158.85.101.20:28015" ); - servers.Add( "158.85.101.20:28022" ); - servers.Add( "173.192.176.171:28615" ); - servers.Add( "109.95.212.35:28215" ); - servers.Add( "109.95.212.35:28115" ); - servers.Add( "27.50.72.176:28015" ); - servers.Add( "109.95.212.40:28015" ); - servers.Add( "212.38.168.149:28215" ); - servers.Add( "27.50.72.167:28215" ); - servers.Add( "85.236.105.7:28215" ); - servers.Add( "107.182.233.216:28215" ); - servers.Add( "85.236.105.11:28215" ); - servers.Add( "109.95.211.198:28215" ); - servers.Add( "8.26.94.190:28015" ); - servers.Add( "221.121.151.37:28215" ); - servers.Add( "161.202.144.216:28215" ); - servers.Add( "107.182.230.181:28215" ); - servers.Add( "107.182.231.134:27101" ); - servers.Add( "107.182.233.181:27101" ); - servers.Add( "78.129.153.47:27101" ); - servers.Add( "109.95.211.206:27101" ); - servers.Add( "169.57.142.73:27101" ); - servers.Add( "221.121.154.147:27101" ); - servers.Add( "31.216.52.44:30015" ); - servers.Add( "109.169.94.17:28215" ); - servers.Add( "109.169.94.17:28315" ); - servers.Add( "109.169.94.17:28015" ); - servers.Add( "41.0.11.167:27141" ); - servers.Add( "78.129.153.47:27131" ); - servers.Add( "109.95.211.206:27111" ); - servers.Add( "107.182.231.134:27111" ); - servers.Add( "198.27.70.162:28015" ); - servers.Add( "198.27.70.162:28215" ); - servers.Add( "198.27.70.162:28115" ); - servers.Add( "169.57.142.73:27111" ); - servers.Add( "221.121.154.147:27111" ); - servers.Add( "107.182.233.181:27111" ); - servers.Add( "78.129.153.47:27111" ); - servers.Add( "109.95.211.215:28015" ); - servers.Add( "50.23.131.208:28015" ); - servers.Add( "50.23.131.208:28115" ); - servers.Add( "50.23.131.208:28215" ); - servers.Add( "63.251.114.37:28215" ); - servers.Add( "63.251.114.37:28115" ); - servers.Add( "63.251.114.37:28015" ); - servers.Add( "149.202.89.85:27101" ); - servers.Add( "149.202.89.85:27111" ); - servers.Add( "149.202.89.85:27131" ); - servers.Add( "8.26.94.147:27101" ); - servers.Add( "8.26.94.147:27111" ); - servers.Add( "8.26.94.147:27121" ); - servers.Add( "159.8.147.197:28025" ); - servers.Add( "162.248.88.203:27038" ); - servers.Add( "162.248.88.203:28091" ); - servers.Add( "74.91.119.142:28069" ); - servers.Add( "162.248.88.203:25063" ); - servers.Add( "64.251.7.189:28115" ); - servers.Add( "64.251.7.189:28015" ); - servers.Add( "216.52.0.170:28215" ); - servers.Add( "217.147.91.80:28215" ); - servers.Add( "63.251.112.121:28215" ); - servers.Add( "162.248.88.203:28074" ); - servers.Add( "74.91.119.142:27095" ); - servers.Add( "95.172.92.176:28065" ); - servers.Add( "192.223.26.55:26032" ); - servers.Add( "40.114.199.6:28085" ); - servers.Add( "95.172.92.176:27095" ); - servers.Add( "216.52.0.172:28015" ); - servers.Add( "216.52.0.171:28115" ); - servers.Add( "27.50.72.179:28015" ); - servers.Add( "27.50.72.180:28115" ); - servers.Add( "221.121.158.203:28015" ); - servers.Add( "63.251.242.246:28015" ); - servers.Add( "85.236.105.51:28015" ); - servers.Add( "85.236.105.47:28015" ); - servers.Add( "209.95.60.216:28015" ); - servers.Add( "212.38.168.14:28015" ); - servers.Add( "217.147.91.138:28015" ); - servers.Add( "31.216.52.42:28015" ); - servers.Add( "107.182.226.225:28015" ); - servers.Add( "109.95.211.69:28015" ); - servers.Add( "209.95.56.13:28015" ); - servers.Add( "173.244.192.101:28015" ); - servers.Add( "221.121.158.201:28115" ); - servers.Add( "63.251.242.245:28115" ); - servers.Add( "85.236.105.50:28115" ); - servers.Add( "85.236.105.46:28115" ); - servers.Add( "209.95.60.217:28115" ); - servers.Add( "212.38.168.13:28115" ); - servers.Add( "217.147.91.139:28115" ); - servers.Add( "107.182.226.224:28115" ); - servers.Add( "109.95.211.14:28115" ); - servers.Add( "109.95.211.16:28115" ); - servers.Add( "109.95.211.17:28115" ); - servers.Add( "209.95.56.14:28115" ); - servers.Add( "173.244.192.100:28115" ); - servers.Add( "209.95.60.218:28215" ); - servers.Add( "109.95.211.13:28215" ); - servers.Add( "109.95.211.15:28215" ); - servers.Add( "31.216.52.41:29015" ); - - var query = client.ServerList.Custom( servers ); - - for ( int i = 0; i < 1000; i++ ) - { - client.Update(); - System.Threading.Thread.Sleep( 20 ); - - if ( query.Finished ) - break; - } - - Console.WriteLine( "Responded: " + query.Responded.Count.ToString() ); - Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() ); - - foreach ( var s in query.Responded ) - { - Console.WriteLine( "{0} - {1}", s.Address, s.Name ); - - Assert.IsTrue( servers.Contains( $"{s.Address}:{s.QueryPort}" ) ); - } - - query.Dispose(); - } - } - - [TestMethod] - public void Rules() - { - using ( var client = new Facepunch.Steamworks.Client( 252490 ) ) - { - var filter = new Facepunch.Steamworks.ServerList.Filter(); - filter.Add( "appid", client.AppId.ToString() ); - filter.Add( "gamedir", "rust" ); - filter.Add( "secure", "1" ); - - filter.Add( "addr", "185.97.254.146" ); - - using ( var query = client.ServerList.Internet( filter ) ) - { - for ( int i = 0; i < 1000; i++ ) - { - GC.Collect(); - client.Update(); - GC.Collect(); - System.Threading.Thread.Sleep( 10 ); - - // if ( query.Responded.Count > 20 ) - // break; - - if ( query.Finished ) - break; - } - - query.Dispose(); - - var servers = query.Responded.Take( 100 ); - - foreach ( var server in servers ) - { - server.FetchRules(); - - int i = 0; - while ( !server.HasRules ) - { - i++; - client.Update(); - System.Threading.Thread.Sleep( 10 ); - - if ( i > 100 ) - break; - } - - if ( server.HasRules ) - { - Console.WriteLine( "" ); - Console.WriteLine( "" ); - Console.WriteLine( server.Address ); - Console.WriteLine( "" ); - - foreach ( var rule in server.Rules ) - { - Console.WriteLine( rule.Key + " = " + rule.Value ); - } - } - else - { - Console.WriteLine( "SERVER HAS NO RULES :(" ); - } - } - - - - } - } - } + using ( var list = new ServerListInternet() ) + { + var task = list.RunQueryAsync(); + + await Task.Delay( 1000 ); + + Console.WriteLine( $"Querying.." ); + + list.Cancel(); + + foreach ( var s in list.Responsive ) + { + Console.WriteLine( $"{s.Address} {s.Name}" ); + } + + Console.WriteLine( $"Found {list.Responsive.Count} Responsive Servers" ); + Console.WriteLine( $"Found {list.Unresponsive.Count} Unresponsive Servers" ); + Console.WriteLine( $"task.IsCompleted {task.IsCompleted}" ); + + } + } + + [TestMethod] + public async Task ServerListInternet() + { + using ( var list = new ServerListInternet() ) + { + var success = await list.RunQueryAsync(); + + Console.WriteLine( $"success {success}" ); + Console.WriteLine( $"Found {list.Responsive.Count} Responsive Servers" ); + Console.WriteLine( $"Found {list.Unresponsive.Count} Unresponsive Servers" ); + } + } + + [TestMethod] + public async Task ServerListLan() + { + using ( var list = new ServerListLan() ) + { + var success = await list.RunQueryAsync(); + + Console.WriteLine( $"success {success}" ); + Console.WriteLine( $"Found {list.Responsive.Count} Responsive Servers" ); + Console.WriteLine( $"Found {list.Unresponsive.Count} Unresponsive Servers" ); + } + } + + [TestMethod] + public async Task ServerListFavourites() + { + using ( var list = new ServerListFavourites() ) + { + var success = await list.RunQueryAsync(); + + Console.WriteLine( $"success {success}" ); + Console.WriteLine( $"Found {list.Responsive.Count} Responsive Servers" ); + Console.WriteLine( $"Found {list.Unresponsive.Count} Unresponsive Servers" ); + } + } + + [TestMethod] + public async Task ServerListFriends() + { + using ( var list = new ServerListFriends() ) + { + var success = await list.RunQueryAsync(); + + Console.WriteLine( $"success {success}" ); + Console.WriteLine( $"Found {list.Responsive.Count} Responsive Servers" ); + Console.WriteLine( $"Found {list.Unresponsive.Count} Unresponsive Servers" ); + } + } + + [TestMethod] + public async Task ServerListHistory() + { + using ( var list = new ServerListHistory() ) + { + var success = await list.RunQueryAsync(); + + Console.WriteLine( $"success {success}" ); + Console.WriteLine( $"Found {list.Responsive.Count} Responsive Servers" ); + Console.WriteLine( $"Found {list.Unresponsive.Count} Unresponsive Servers" ); + } + } + + [TestMethod] + public async Task FilterByMap() + { + using ( var list = new ServerListInternet() ) + { + list.AddFilter( "map", "de_dust" ); + + var success = await list.RunQueryAsync(); + + Console.WriteLine( $"success {success}" ); + Console.WriteLine( $"Found {list.Responsive.Count} Responsive Servers" ); + Console.WriteLine( $"Found {list.Unresponsive.Count} Unresponsive Servers" ); + + foreach ( var server in list.Responsive ) + { + Assert.AreEqual( server.Map.ToLower(), "de_dust" ); + + Console.WriteLine( $"[{server.Map}] - {server.Name}" ); + } + } + } } } diff --git a/Facepunch.Steamworks/BaseSteamworks.cs b/Facepunch.Steamworks/BaseSteamworks.cs index caae58a..6c6e719 100644 --- a/Facepunch.Steamworks/BaseSteamworks.cs +++ b/Facepunch.Steamworks/BaseSteamworks.cs @@ -148,13 +148,6 @@ namespace Facepunch.Steamworks { CallResults[i].Try(); } - - // - // The SourceServerQuery's happen in another thread, so we - // query them to see if they're finished, and if so post a callback - // in our main thread. This will all suck less once we have async. - // - Facepunch.Steamworks.SourceServerQuery.Cycle(); } /// diff --git a/Facepunch.Steamworks/Client/ServerList.Request.cs b/Facepunch.Steamworks/Client/ServerList.Request.cs deleted file mode 100644 index f3da876..0000000 --- a/Facepunch.Steamworks/Client/ServerList.Request.cs +++ /dev/null @@ -1,232 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; - -namespace Facepunch.Steamworks -{ - public partial class ServerList - { - public class Request : IDisposable - { - internal Client client; - - internal List Requests = new List(); - - internal class SubRequest - { - internal IntPtr Request; - internal int Pointer = 0; - internal List WatchList = new List(); - internal System.Diagnostics.Stopwatch Timer = System.Diagnostics.Stopwatch.StartNew(); - - internal bool Update( SteamNative.SteamMatchmakingServers servers, Action OnServer, Action OnUpdate ) - { - if ( Request == IntPtr.Zero ) - return true; - - if ( Timer.Elapsed.TotalSeconds < 0.5f ) - return false; - - Timer.Reset(); - Timer.Start(); - - bool changes = false; - - // - // Add any servers we're not watching to our watch list - // - var count = servers.GetServerCount( Request ); - if ( count != Pointer ) - { - for ( int i = Pointer; i < count; i++ ) - { - WatchList.Add( i ); - } - } - Pointer = count; - - // - // Remove any servers that respond successfully - // - WatchList.RemoveAll( x => - { - var info = servers.GetServerDetails( Request, x ); - if ( info.HadSuccessfulResponse ) - { - OnServer( info ); - changes = true; - return true; - } - - return false; - } ); - - // - // If we've finished refreshing - // - if ( servers.IsRefreshing( Request ) == false ) - { - // - // Put any other servers on the 'no response' list - // - WatchList.RemoveAll( x => - { - var info = servers.GetServerDetails( Request, x ); - OnServer( info ); - return true; - } ); - - servers.CancelQuery( Request ); - Request = IntPtr.Zero; - changes = true; - } - - if ( changes && OnUpdate != null ) - OnUpdate(); - - return Request == IntPtr.Zero; - } - } - - public Action OnUpdate; - public Action OnServerResponded; - public Action OnFinished; - - /// - /// A list of servers that responded. If you're only interested in servers that responded since you - /// last updated, then simply clear this list. - /// - public List Responded = new List(); - - /// - /// A list of servers that were in the master list but didn't respond. - /// - public List Unresponsive = new List(); - - /// - /// True when we have finished - /// - public bool Finished = false; - - internal Request( Client c ) - { - client = c; - - client.OnUpdate += Update; - } - - ~Request() - { - Dispose(); - } - - internal IEnumerable ServerList { get; set; } - internal Filter Filter { get; set; } - - internal void StartCustomQuery() - { - if ( ServerList == null ) - return; - - int blockSize = 16; - int Pointer = 0; - - while ( true ) - { - var sublist = ServerList.Skip( Pointer ).Take( blockSize ); - - if ( sublist.Count() == 0 ) - break; - - Pointer += sublist.Count(); - - var filter = new Filter(); - filter.Add( "or", sublist.Count().ToString() ); - - foreach ( var server in sublist ) - { - filter.Add( "gameaddr", server ); - } - - filter.Start(); - var id = client.native.servers.RequestInternetServerList( client.AppId, filter.NativeArray, (uint)filter.Count, IntPtr.Zero ); - filter.Free(); - - AddRequest( id ); - } - - ServerList = null; - } - - internal void AddRequest( IntPtr id ) - { - Requests.Add( new SubRequest() { Request = id } ); - } - - private void Update() - { - if ( Requests.Count == 0 ) - return; - - for( int i=0; i< Requests.Count(); i++ ) - { - if ( Requests[i].Update( client.native.servers, OnServer, OnUpdate ) ) - { - Requests.RemoveAt( i ); - i--; - } - } - - if ( Requests.Count == 0 ) - { - Finished = true; - client.OnUpdate -= Update; - - OnFinished?.Invoke(); - } - } - - private void OnServer( SteamNative.gameserveritem_t info ) - { - if ( info.HadSuccessfulResponse ) - { - if ( Filter != null && !Filter.Test( info ) ) - return; - - var s = Server.FromSteam( client, info ); - Responded.Add( s ); - - OnServerResponded?.Invoke( s ); - } - else - { - Unresponsive.Add( Server.FromSteam( client, info ) ); - } - - } - - /// - /// Disposing will end the query - /// - public void Dispose() - { - if ( client.IsValid ) - client.OnUpdate -= Update; - - // - // Cancel the query if it's still running - // - foreach( var subRequest in Requests ) - { - if ( client.IsValid ) - client.native.servers.CancelQuery( subRequest.Request ); - } - Requests.Clear(); - - } - - } - } -} diff --git a/Facepunch.Steamworks/Client/ServerList.Server.cs b/Facepunch.Steamworks/Client/ServerList.Server.cs deleted file mode 100644 index fbe10b8..0000000 --- a/Facepunch.Steamworks/Client/ServerList.Server.cs +++ /dev/null @@ -1,160 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Runtime.InteropServices; -using System.Text; - -namespace Facepunch.Steamworks -{ - public partial class ServerList - { - public class Server - { - public string Name { get; set; } - public int Ping { get; set; } - public string GameDir { get; set; } - public string Map { get; set; } - public string Description { get; set; } - public uint AppId { get; set; } - public int Players { get; set; } - public int MaxPlayers { get; set; } - public int BotPlayers { get; set; } - public bool Passworded { get; set; } - public bool Secure { get; set; } - public uint LastTimePlayed { get; set; } - public int Version { get; set; } - public string[] Tags { get; set; } - public ulong SteamId { get; set; } - public IPAddress Address { get; set; } - public int ConnectionPort { get; set; } - public int QueryPort { get; set; } - - /// - /// Returns true if this server is in the favourites list - /// - public bool Favourite - { - get - { - return Client.ServerList.IsFavourite( this ); - } - } - - internal Client Client; - - - internal static Server FromSteam( Client client, SteamNative.gameserveritem_t item ) - { - return new Server() - { - Client = client, - Address = Utility.Int32ToIp( item.NetAdr.IP ), - ConnectionPort = item.NetAdr.ConnectionPort, - QueryPort = item.NetAdr.QueryPort, - Name = item.ServerName, - Ping = item.Ping, - GameDir = item.GameDir, - Map = item.Map, - Description = item.GameDescription, - AppId = item.AppID, - Players = item.Players, - MaxPlayers = item.MaxPlayers, - BotPlayers = item.BotPlayers, - Passworded = item.Password, - Secure = item.Secure, - LastTimePlayed = item.TimeLastPlayed, - Version = item.ServerVersion, - Tags = item.GameTags == null ? null : item.GameTags.Split( ',' ), - SteamId = item.SteamID - }; - } - - /// - /// Callback when rules are receieved. - /// The bool is true if server responded properly. - /// - public Action OnReceivedRules; - - /// - /// List of server rules. Use HasRules to see if this is safe to access. - /// - public Dictionary Rules; - - /// - /// Returns true if this server has rules - /// - public bool HasRules { get { return Rules != null && Rules.Count > 0; } } - - internal SourceServerQuery RulesRequest; - - /// - /// Populates Rules for this server - /// - public void FetchRules() - { - if ( RulesRequest != null ) - return; - - Rules = null; - RulesRequest = new SourceServerQuery( this, Address, QueryPort ); - } - - internal void OnServerRulesReceiveFinished( Dictionary rules, bool Success ) - { - RulesRequest = null; - - if ( Success ) - { - Rules = rules; - } - - if ( OnReceivedRules != null ) - { - OnReceivedRules( Success ); - } - } - - internal const uint k_unFavoriteFlagNone = 0x00; - internal const uint k_unFavoriteFlagFavorite = 0x01; // this game favorite entry is for the favorites list - internal const uint k_unFavoriteFlagHistory = 0x02; // this game favorite entry is for the history list - - /// - /// Add this server to our history list - /// If we're already in the history list, weill set the last played time to now - /// - public void AddToHistory() - { - Client.native.matchmaking.AddFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagHistory, (uint)Utility.Epoch.Current ); - Client.ServerList.UpdateFavouriteList(); - } - - /// - /// Remove this server from our history list - /// - public void RemoveFromHistory() - { - Client.native.matchmaking.RemoveFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagHistory ); - Client.ServerList.UpdateFavouriteList(); - } - - /// - /// Add this server to our favourite list - /// - public void AddToFavourites() - { - Client.native.matchmaking.AddFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagFavorite, (uint)Utility.Epoch.Current ); - Client.ServerList.UpdateFavouriteList(); - } - - /// - /// Remove this server from our favourite list - /// - public void RemoveFromFavourites() - { - Client.native.matchmaking.RemoveFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagFavorite ); - Client.ServerList.UpdateFavouriteList(); - } - } - } -} diff --git a/Facepunch.Steamworks/Client/ServerList.cs b/Facepunch.Steamworks/Client/ServerList.cs index 407d98f..b9e118d 100644 --- a/Facepunch.Steamworks/Client/ServerList.cs +++ b/Facepunch.Steamworks/Client/ServerList.cs @@ -41,11 +41,11 @@ namespace Facepunch.Steamworks encoded = encoded << 32; encoded = encoded | (uint)conPort; - if ( ( flags & Server.k_unFavoriteFlagFavorite ) == Server.k_unFavoriteFlagFavorite ) - FavouriteHash.Add( encoded ); + // if ( ( flags & Server.k_unFavoriteFlagFavorite ) == Server.k_unFavoriteFlagFavorite ) + // FavouriteHash.Add( encoded ); - if ( ( flags & Server.k_unFavoriteFlagFavorite ) == Server.k_unFavoriteFlagFavorite ) - HistoryHash.Add( encoded ); + // if ( ( flags & Server.k_unFavoriteFlagFavorite ) == Server.k_unFavoriteFlagFavorite ) + // HistoryHash.Add( encoded ); } } @@ -113,8 +113,6 @@ namespace Facepunch.Steamworks } } - - [StructLayout( LayoutKind.Sequential )] private struct MatchPair { @@ -123,145 +121,5 @@ namespace Facepunch.Steamworks [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string value; } - - - - public Request Internet( Filter filter = null ) - { - if ( filter == null ) - { - filter = new Filter(); - filter.Add( "appid", client.AppId.ToString() ); - } - - filter.Start(); - - var request = new Request( client ); - request.Filter = filter; - request.AddRequest( client.native.servers.RequestInternetServerList( client.AppId, filter.NativeArray, (uint) filter.Count, IntPtr.Zero ) ); - - filter.Free(); - - return request; - } - - /// - /// Query a list of addresses. No filters applied. - /// - public Request Custom( IEnumerable serverList ) - { - var request = new Request( client ); - request.ServerList = serverList; - request.StartCustomQuery(); - return request; - } - - /// - /// Request a list of servers we've been on. History isn't applied automatically - /// You need to call server.AddtoHistoryList() when you join a server etc. - /// - public Request History( Filter filter = null ) - { - if ( filter == null ) - { - filter = new Filter(); - filter.Add( "appid", client.AppId.ToString() ); - } - - filter.Start(); - - var request = new Request( client ); - request.Filter = filter; - request.AddRequest( client.native.servers.RequestHistoryServerList( client.AppId, filter.NativeArray, (uint)filter.Count, IntPtr.Zero ) ); - - filter.Free(); - - return request; - } - - /// - /// Request a list of servers we've favourited - /// - public Request Favourites( Filter filter = null ) - { - if ( filter == null ) - { - filter = new Filter(); - filter.Add( "appid", client.AppId.ToString() ); - } - - filter.Start(); - - var request = new Request( client ); - request.Filter = filter; - request.AddRequest( client.native.servers.RequestFavoritesServerList( client.AppId, filter.NativeArray, (uint)filter.Count, IntPtr.Zero ) ); - - filter.Free(); - - return request; - } - - /// - /// Request a list of servers that our friends are on - /// - public Request Friends( Filter filter = null ) - { - if ( filter == null ) - { - filter = new Filter(); - filter.Add( "appid", client.AppId.ToString() ); - } - - filter.Start(); - - var request = new Request( client ); - request.Filter = filter; - request.AddRequest( client.native.servers.RequestFriendsServerList( client.AppId, filter.NativeArray, (uint)filter.Count, IntPtr.Zero ) ); - - filter.Free(); - - return request; - } - - /// - /// Request a list of servers that are running on our LAN - /// - public Request Local( Filter filter = null ) - { - if ( filter == null ) - { - filter = new Filter(); - filter.Add( "appid", client.AppId.ToString() ); - } - - filter.Start(); - - var request = new Request( client ); - request.Filter = filter; - request.AddRequest( client.native.servers.RequestLANServerList( client.AppId, IntPtr.Zero ) ); - - filter.Free(); - - return request; - } - - - internal bool IsFavourite( Server server ) - { - ulong encoded = Utility.IpToInt32( server.Address ); - encoded = encoded << 32; - encoded = encoded | (uint)server.ConnectionPort; - - return FavouriteHash.Contains( encoded ); - } - - internal bool IsHistory( Server server ) - { - ulong encoded = Utility.IpToInt32( server.Address ); - encoded = encoded << 32; - encoded = encoded | (uint)server.ConnectionPort; - - return HistoryHash.Contains( encoded ); - } } } diff --git a/Facepunch.Steamworks/Generated/Interfaces/ISteamMatchmakingServers.cs b/Facepunch.Steamworks/Generated/Interfaces/ISteamMatchmakingServers.cs index 3f89385..912e9ef 100644 --- a/Facepunch.Steamworks/Generated/Interfaces/ISteamMatchmakingServers.cs +++ b/Facepunch.Steamworks/Generated/Interfaces/ISteamMatchmakingServers.cs @@ -111,13 +111,13 @@ namespace Steamworks.Internal #region FunctionMeta [UnmanagedFunctionPointer( CallingConvention.ThisCall )] - public delegate gameserveritem_t GetServerDetailsDelegate( IntPtr self, HServerListRequest hRequest, int iServer ); + public delegate IntPtr GetServerDetailsDelegate( IntPtr self, HServerListRequest hRequest, int iServer ); private GetServerDetailsDelegate GetServerDetailsDelegatePointer; #endregion public gameserveritem_t GetServerDetails( HServerListRequest hRequest, int iServer ) { - return GetServerDetailsDelegatePointer( Self, hRequest, iServer ); + return new gameserveritem_t().Fill( GetServerDetailsDelegatePointer( Self, hRequest, iServer ) ); } #region FunctionMeta diff --git a/Facepunch.Steamworks/Generated/SteamApi.cs b/Facepunch.Steamworks/Generated/SteamApi.cs index a0206ec..444d9f0 100644 --- a/Facepunch.Steamworks/Generated/SteamApi.cs +++ b/Facepunch.Steamworks/Generated/SteamApi.cs @@ -22,4 +22,6 @@ public static class SteamApi [DllImport( "Steam_api64", EntryPoint = "SteamAPI_UnregisterCallback", CallingConvention = CallingConvention.Cdecl )] public static extern int UnregisterCallback( IntPtr pCallback ); + + } diff --git a/Facepunch.Steamworks/Redux/ServerList/BaseServerList.cs b/Facepunch.Steamworks/Redux/ServerList/BaseServerList.cs new file mode 100644 index 0000000..d564d7a --- /dev/null +++ b/Facepunch.Steamworks/Redux/ServerList/BaseServerList.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using SteamNative; + +namespace Steamworks +{ + /// + /// Not for reuse by newbs + /// + public abstract class BaseServerList : IDisposable + { + + #region ISteamMatchmakingServers + + static Internal.ISteamMatchmakingServers _internal; + internal static Internal.ISteamMatchmakingServers Internal + { + get + { + if ( _internal == null ) + _internal = new Internal.ISteamMatchmakingServers(); + + return _internal; + } + } + + #endregion + + + /// + /// Which app we're querying. Defaults to the current app. + /// + public AppId AppId { get; set; } + + /// + /// When a new server is added, this function will get called + /// + public event Action OnChanges; + + /// + /// Called for every responsive server + /// + public event Action OnResponsiveServer; + + /// + /// A list of servers that responded. If you're only interested in servers that responded since you + /// last updated, then simply clear this list. + /// + public List Responsive = new List(); + + /// + /// A list of servers that were in the master list but didn't respond. + /// + public List Unresponsive = new List(); + + + public BaseServerList() + { + AppId = Utils.AppId; // Default AppId is this + } + + /// + /// Query the server list. Task result will be true when finished + /// + /// + public async Task RunQueryAsync() + { + Reset(); + LaunchQuery(); + + var thisRequest = request; + + while ( IsRefreshing ) + { + await Task.Delay( 33 ); + + // + // The request has been cancelled or changed in some way + // + if ( request == IntPtr.Zero || thisRequest.Value != request.Value ) + return false; + + var r = Responsive.Count; + + UpdatePending(); + UpdateResponsive(); + + if ( r != Responsive.Count ) + { + OnChanges?.Invoke(); + } + } + + MovePendingToUnresponsive(); + OnChanges?.Invoke(); + + return true; + } + + public void Cancel() => Internal.CancelQuery( request ); + + // Overrides + internal abstract void LaunchQuery(); + + protected HServerListRequest request; + + #region Filters + + internal List filters = new List(); + internal MatchMakingKeyValuePair_t[] GetFilters() => filters.ToArray(); + + public void AddFilter( string key, string value ) + { + filters.Add( new MatchMakingKeyValuePair_t { Key = key, Value = value } ); + } + + #endregion + + internal int Count => Internal.GetServerCount( request ); + internal bool IsRefreshing => request != IntPtr.Zero && Internal.IsRefreshing( request ); + internal List watchList = new List(); + internal int LastCount = 0; + + void Reset() + { + ReleaseQuery(); + LastCount = 0; + watchList.Clear(); + } + + void ReleaseQuery() + { + if ( request.Value != IntPtr.Zero ) + { + Cancel(); + Internal.ReleaseRequest( request ); + request = IntPtr.Zero; + } + } + + public void Dispose() + { + ReleaseQuery(); + } + + void UpdatePending() + { + var count = Count; + if ( count == LastCount ) return; + + for ( int i = LastCount; i < count; i++ ) + { + watchList.Add( i ); + } + + LastCount = count; + } + + public void UpdateResponsive() + { + watchList.RemoveAll( x => + { + var info = Internal.GetServerDetails( request, x ); + if ( info.HadSuccessfulResponse ) + { + OnServer( ServerInfo.From( info ), info.HadSuccessfulResponse ); + return true; + } + + return false; + } ); + } + + void MovePendingToUnresponsive() + { + watchList.RemoveAll( x => + { + var info = Internal.GetServerDetails( request, x ); + OnServer( ServerInfo.From( info ), info.HadSuccessfulResponse ); + return true; + } ); + } + + private void OnServer( ServerInfo serverInfo, bool responded ) + { + if ( responded ) + { + Responsive.Add( serverInfo ); + OnResponsiveServer?.Invoke( serverInfo ); + return; + } + + Unresponsive.Add( serverInfo ); + } + } +} \ No newline at end of file diff --git a/Facepunch.Steamworks/Redux/ServerList/ServerListFavourites.cs b/Facepunch.Steamworks/Redux/ServerList/ServerListFavourites.cs new file mode 100644 index 0000000..c6a435f --- /dev/null +++ b/Facepunch.Steamworks/Redux/ServerList/ServerListFavourites.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using SteamNative; + +namespace Steamworks +{ + /// + /// Not for reuse by newbs + /// + public class ServerListFavourites : BaseServerList + { + internal override void LaunchQuery() + { + var filters = GetFilters(); + request = Internal.RequestFavoritesServerList( AppId.Value, filters, (uint)filters.Length, IntPtr.Zero ); + } + } +} \ No newline at end of file diff --git a/Facepunch.Steamworks/Redux/ServerList/ServerListFriends.cs b/Facepunch.Steamworks/Redux/ServerList/ServerListFriends.cs new file mode 100644 index 0000000..2b675e9 --- /dev/null +++ b/Facepunch.Steamworks/Redux/ServerList/ServerListFriends.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using SteamNative; + +namespace Steamworks +{ + /// + /// Not for reuse by newbs + /// + public class ServerListFriends : BaseServerList + { + internal override void LaunchQuery() + { + var filters = GetFilters(); + request = Internal.RequestFriendsServerList( AppId.Value, filters, (uint)filters.Length, IntPtr.Zero ); + } + } +} \ No newline at end of file diff --git a/Facepunch.Steamworks/Redux/ServerList/ServerListHistory.cs b/Facepunch.Steamworks/Redux/ServerList/ServerListHistory.cs new file mode 100644 index 0000000..00441bb --- /dev/null +++ b/Facepunch.Steamworks/Redux/ServerList/ServerListHistory.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using SteamNative; + +namespace Steamworks +{ + /// + /// Not for reuse by newbs + /// + public class ServerListHistory : BaseServerList + { + internal override void LaunchQuery() + { + var filters = GetFilters(); + request = Internal.RequestHistoryServerList( AppId.Value, filters, (uint)filters.Length, IntPtr.Zero ); + } + } +} \ No newline at end of file diff --git a/Facepunch.Steamworks/Redux/ServerList/ServerListInternet.cs b/Facepunch.Steamworks/Redux/ServerList/ServerListInternet.cs new file mode 100644 index 0000000..4f3ef64 --- /dev/null +++ b/Facepunch.Steamworks/Redux/ServerList/ServerListInternet.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using SteamNative; + +namespace Steamworks +{ + /// + /// Not for reuse by newbs + /// + public class ServerListInternet : BaseServerList + { + internal override void LaunchQuery() + { + var filters = GetFilters(); + + request = Internal.RequestInternetServerList( AppId.Value, filters, (uint)filters.Length, IntPtr.Zero ); + } + } +} \ No newline at end of file diff --git a/Facepunch.Steamworks/Redux/ServerList/ServerListLan.cs b/Facepunch.Steamworks/Redux/ServerList/ServerListLan.cs new file mode 100644 index 0000000..09810fd --- /dev/null +++ b/Facepunch.Steamworks/Redux/ServerList/ServerListLan.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using SteamNative; + +namespace Steamworks +{ + /// + /// Not for reuse by newbs + /// + public class ServerListLan : BaseServerList + { + internal override void LaunchQuery() + { + request = Internal.RequestLANServerList( AppId.Value, IntPtr.Zero ); + } + } +} \ No newline at end of file diff --git a/Facepunch.Steamworks/Redux/ServerList/ServerListSpectator.cs b/Facepunch.Steamworks/Redux/ServerList/ServerListSpectator.cs new file mode 100644 index 0000000..56a314e --- /dev/null +++ b/Facepunch.Steamworks/Redux/ServerList/ServerListSpectator.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using SteamNative; + +namespace Steamworks +{ + /* + public class ServerListSpectator : BaseServerList + { + internal override void LaunchQuery() + { + var filters = GetFilters(); + request = Internal.RequestSpectatorServerList( AppId.Value, filters, (uint)filters.Length, IntPtr.Zero ); + } + } + */ +} \ No newline at end of file diff --git a/Facepunch.Steamworks/Redux/Steam.cs b/Facepunch.Steamworks/Redux/Steam.cs index a16e1c5..accc51e 100644 --- a/Facepunch.Steamworks/Redux/Steam.cs +++ b/Facepunch.Steamworks/Redux/Steam.cs @@ -37,6 +37,24 @@ namespace Steamworks Music.InstallEvents(); Video.InstallEvents(); User.InstallEvents(); + + RunCallbacks(); + } + + internal static async void RunCallbacks() + { + while ( true ) + { + await Task.Delay( 16 ); + try + { + SteamApi.RunCallbacks(); + } + catch ( System.Exception ) + { + // TODO - error outputs + } + } } internal static void RegisterCallback( IntPtr intPtr, int callbackId ) @@ -44,6 +62,11 @@ namespace Steamworks SteamApi.RegisterCallback( intPtr, callbackId ); } + public static void Update() + { + SteamApi.RunCallbacks(); + } + internal static void UnregisterCallback( IntPtr intPtr ) { SteamApi.UnregisterCallback( intPtr ); diff --git a/Facepunch.Steamworks/Redux/Structs/Server.cs b/Facepunch.Steamworks/Redux/Structs/Server.cs new file mode 100644 index 0000000..0e8d4c5 --- /dev/null +++ b/Facepunch.Steamworks/Redux/Structs/Server.cs @@ -0,0 +1,94 @@ +using Facepunch.Steamworks; +using System; +using System.Collections.Generic; +using System.Net; +using System.Runtime.InteropServices; +using System.Text; + + +namespace Steamworks +{ + public struct ServerInfo + { + public string Name { get; set; } + public int Ping { get; set; } + public string GameDir { get; set; } + public string Map { get; set; } + public string Description { get; set; } + public uint AppId { get; set; } + public int Players { get; set; } + public int MaxPlayers { get; set; } + public int BotPlayers { get; set; } + public bool Passworded { get; set; } + public bool Secure { get; set; } + public uint LastTimePlayed { get; set; } + public int Version { get; set; } + public string Tags { get; set; } + public ulong SteamId { get; set; } + public IPAddress Address { get; set; } + public int ConnectionPort { get; set; } + public int QueryPort { get; set; } + + internal static ServerInfo From( SteamNative.gameserveritem_t item ) + { + return new ServerInfo() + { + Address = Utility.Int32ToIp( item.NetAdr.IP ), + ConnectionPort = item.NetAdr.ConnectionPort, + QueryPort = item.NetAdr.QueryPort, + Name = item.ServerName, + Ping = item.Ping, + GameDir = item.GameDir, + Map = item.Map, + Description = item.GameDescription, + AppId = item.AppID, + Players = item.Players, + MaxPlayers = item.MaxPlayers, + BotPlayers = item.BotPlayers, + Passworded = item.Password, + Secure = item.Secure, + LastTimePlayed = item.TimeLastPlayed, + Version = item.ServerVersion, + Tags = item.GameTags, + SteamId = item.SteamID + }; + } + + internal const uint k_unFavoriteFlagNone = 0x00; + internal const uint k_unFavoriteFlagFavorite = 0x01; // this game favorite entry is for the favorites list + internal const uint k_unFavoriteFlagHistory = 0x02; // this game favorite entry is for the history list + + /// + /// Add this server to our history list + /// If we're already in the history list, weill set the last played time to now + /// + public void AddToHistory() + { + //Client.native.matchmaking.AddFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagHistory, (uint)Utility.Epoch.Current ); + } + + /// + /// Remove this server from our history list + /// + public void RemoveFromHistory() + { + //Client.native.matchmaking.RemoveFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagHistory ); + } + + /// + /// Add this server to our favourite list + /// + public void AddToFavourites() + { + //Client.native.matchmaking.AddFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagFavorite, (uint)Utility.Epoch.Current ); + } + + /// + /// Remove this server from our favourite list + /// + public void RemoveFromFavourites() + { + //Client.native.matchmaking.RemoveFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagFavorite ); + } + } +} \ No newline at end of file diff --git a/Facepunch.Steamworks/Utility/SourceServerQuery.cs b/Facepunch.Steamworks/Utility/SourceServerQuery.cs deleted file mode 100644 index 43847d8..0000000 --- a/Facepunch.Steamworks/Utility/SourceServerQuery.cs +++ /dev/null @@ -1,206 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Sockets; - -namespace Facepunch.Steamworks -{ - - internal class SourceServerQuery : IDisposable - { - public static List Current = new List(); - - public static void Cycle() - { - if ( Current.Count == 0 ) - return; - - for( int i = Current.Count; i>0; i-- ) - { - Current[i-1].Update(); - } - } - - private static readonly byte[] A2S_SERVERQUERY_GETCHALLENGE = { 0x55, 0xFF, 0xFF, 0xFF, 0xFF }; - // private static readonly byte A2S_PLAYER = 0x55; - private static readonly byte A2S_RULES = 0x56; - - public volatile bool IsRunning; - public volatile bool IsSuccessful; - - private ServerList.Server Server; - private UdpClient udpClient; - private IPEndPoint endPoint; - private System.Threading.Thread thread; - private byte[] _challengeBytes; - - private Dictionary rules = new Dictionary(); - - public SourceServerQuery( ServerList.Server server, IPAddress address, int queryPort ) - { - Server = server; - endPoint = new IPEndPoint( address, queryPort ); - - Current.Add( this ); - - IsRunning = true; - IsSuccessful = false; - thread = new System.Threading.Thread( ThreadedStart ); - thread.Start(); - } - - void Update() - { - if ( !IsRunning ) - { - Current.Remove( this ); - Server.OnServerRulesReceiveFinished( rules, IsSuccessful ); - } - } - - private void ThreadedStart( object obj ) - { - try - { - using ( udpClient = new UdpClient() ) - { - udpClient.Client.SendTimeout = 3000; - udpClient.Client.ReceiveTimeout = 3000; - udpClient.Connect( endPoint ); - - GetRules(); - - IsSuccessful = true; - } - } - catch ( System.Exception ) - { - IsSuccessful = false; - } - - udpClient = null; - IsRunning = false; - } - - void GetRules() - { - GetChallengeData(); - - _challengeBytes[0] = A2S_RULES; - Send( _challengeBytes ); - var ruleData = Receive(); - - using ( var br = new BinaryReader( new MemoryStream( ruleData ) ) ) - { - if ( br.ReadByte() != 0x45 ) - throw new Exception( "Invalid data received in response to A2S_RULES request" ); - - var numRules = br.ReadUInt16(); - for ( int index = 0; index < numRules; index++ ) - { - rules.Add( br.ReadNullTerminatedUTF8String( readBuffer ), br.ReadNullTerminatedUTF8String( readBuffer ) ); - } - } - - } - - byte[] readBuffer = new byte[1024 * 4]; - - private byte[] Receive() - { - byte[][] packets = null; - byte packetNumber = 0, packetCount = 1; - - do - { - var result = udpClient.Receive( ref endPoint ); - - using ( var br = new BinaryReader( new MemoryStream( result ) ) ) - { - var header = br.ReadInt32(); - - if ( header == -1 ) - { - var unsplitdata = new byte[result.Length - br.BaseStream.Position]; - Buffer.BlockCopy( result, (int)br.BaseStream.Position, unsplitdata, 0, unsplitdata.Length ); - return unsplitdata; - } - else if ( header == -2 ) - { - int requestId = br.ReadInt32(); - packetNumber = br.ReadByte(); - packetCount = br.ReadByte(); - int splitSize = br.ReadInt32(); - } - else - { - throw new System.Exception( "Invalid Header" ); - } - - if ( packets == null ) packets = new byte[packetCount][]; - - var data = new byte[result.Length - br.BaseStream.Position]; - Buffer.BlockCopy( result, (int)br.BaseStream.Position, data, 0, data.Length ); - packets[packetNumber] = data; - } - } - while ( packets.Any( p => p == null ) ); - - var combinedData = Combine( packets ); - return combinedData; - } - - private void GetChallengeData() - { - if ( _challengeBytes != null ) return; - - Send( A2S_SERVERQUERY_GETCHALLENGE ); - - var challengeData = Receive(); - - if ( challengeData[0] != 0x41 ) - throw new Exception( "Invalid Challenge" ); - - _challengeBytes = challengeData; - } - - byte[] sendBuffer = new byte[1024]; - - private void Send( byte[] message ) - { - sendBuffer[0] = 0xFF; - sendBuffer[1] = 0xFF; - sendBuffer[2] = 0xFF; - sendBuffer[3] = 0xFF; - - Buffer.BlockCopy( message, 0, sendBuffer, 4, message.Length ); - - udpClient.Send( sendBuffer, message.Length + 4 ); - } - - private byte[] Combine( byte[][] arrays ) - { - var rv = new byte[arrays.Sum( a => a.Length )]; - int offset = 0; - foreach ( byte[] array in arrays ) - { - Buffer.BlockCopy( array, 0, rv, offset, array.Length ); - offset += array.Length; - } - return rv; - } - - public void Dispose() - { - if ( thread != null && thread.IsAlive ) - { - thread.Abort(); - } - - thread = null; - } - }; - -} diff --git a/Generator/CodeWriter/Types/BaseType.cs b/Generator/CodeWriter/Types/BaseType.cs index b0f29e2..bc98307 100644 --- a/Generator/CodeWriter/Types/BaseType.cs +++ b/Generator/CodeWriter/Types/BaseType.cs @@ -69,6 +69,18 @@ internal class StructType : BaseType public string StructName; public override string TypeName => StructName; + + public override string TypeNameFrom => NativeType.EndsWith( "*" ) ? "IntPtr" : base.ReturnType; + + public override string Return( string varname ) + { + if ( NativeType.EndsWith( "*" ) ) + { + return $"return new {TypeName}().Fill( {varname} );"; + } + + return base.Return( varname ); + } } internal class SteamApiCallType : BaseType