mirror of
https://github.com/Facepunch/Facepunch.Steamworks.git
synced 2024-12-25 06:05:46 +03:00
ServerList
This commit is contained in:
parent
1f0e34cf40
commit
41dfaeb2f7
@ -4,13 +4,14 @@
|
||||
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 @@ public void IpAddressConversions()
|
||||
|
||||
|
||||
[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<Facepunch.Steamworks.ServerList.Request>();
|
||||
|
||||
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<string>();
|
||||
|
||||
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}" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -148,13 +148,6 @@ public void RunUpdateCallbacks()
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -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<SubRequest> Requests = new List<SubRequest>();
|
||||
|
||||
internal class SubRequest
|
||||
{
|
||||
internal IntPtr Request;
|
||||
internal int Pointer = 0;
|
||||
internal List<int> WatchList = new List<int>();
|
||||
internal System.Diagnostics.Stopwatch Timer = System.Diagnostics.Stopwatch.StartNew();
|
||||
|
||||
internal bool Update( SteamNative.SteamMatchmakingServers servers, Action<SteamNative.gameserveritem_t> 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<Server> OnServerResponded;
|
||||
public Action OnFinished;
|
||||
|
||||
/// <summary>
|
||||
/// A list of servers that responded. If you're only interested in servers that responded since you
|
||||
/// last updated, then simply clear this list.
|
||||
/// </summary>
|
||||
public List<Server> Responded = new List<Server>();
|
||||
|
||||
/// <summary>
|
||||
/// A list of servers that were in the master list but didn't respond.
|
||||
/// </summary>
|
||||
public List<Server> Unresponsive = new List<Server>();
|
||||
|
||||
/// <summary>
|
||||
/// True when we have finished
|
||||
/// </summary>
|
||||
public bool Finished = false;
|
||||
|
||||
internal Request( Client c )
|
||||
{
|
||||
client = c;
|
||||
|
||||
client.OnUpdate += Update;
|
||||
}
|
||||
|
||||
~Request()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
internal IEnumerable<string> 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 ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposing will end the query
|
||||
/// </summary>
|
||||
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();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this server is in the favourites list
|
||||
/// </summary>
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback when rules are receieved.
|
||||
/// The bool is true if server responded properly.
|
||||
/// </summary>
|
||||
public Action<bool> OnReceivedRules;
|
||||
|
||||
/// <summary>
|
||||
/// List of server rules. Use HasRules to see if this is safe to access.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Rules;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this server has rules
|
||||
/// </summary>
|
||||
public bool HasRules { get { return Rules != null && Rules.Count > 0; } }
|
||||
|
||||
internal SourceServerQuery RulesRequest;
|
||||
|
||||
/// <summary>
|
||||
/// Populates Rules for this server
|
||||
/// </summary>
|
||||
public void FetchRules()
|
||||
{
|
||||
if ( RulesRequest != null )
|
||||
return;
|
||||
|
||||
Rules = null;
|
||||
RulesRequest = new SourceServerQuery( this, Address, QueryPort );
|
||||
}
|
||||
|
||||
internal void OnServerRulesReceiveFinished( Dictionary<string, string> 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
|
||||
|
||||
/// <summary>
|
||||
/// Add this server to our history list
|
||||
/// If we're already in the history list, weill set the last played time to now
|
||||
/// </summary>
|
||||
public void AddToHistory()
|
||||
{
|
||||
Client.native.matchmaking.AddFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagHistory, (uint)Utility.Epoch.Current );
|
||||
Client.ServerList.UpdateFavouriteList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove this server from our history list
|
||||
/// </summary>
|
||||
public void RemoveFromHistory()
|
||||
{
|
||||
Client.native.matchmaking.RemoveFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagHistory );
|
||||
Client.ServerList.UpdateFavouriteList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add this server to our favourite list
|
||||
/// </summary>
|
||||
public void AddToFavourites()
|
||||
{
|
||||
Client.native.matchmaking.AddFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagFavorite, (uint)Utility.Epoch.Current );
|
||||
Client.ServerList.UpdateFavouriteList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove this server from our favourite list
|
||||
/// </summary>
|
||||
public void RemoveFromFavourites()
|
||||
{
|
||||
Client.native.matchmaking.RemoveFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagFavorite );
|
||||
Client.ServerList.UpdateFavouriteList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -41,11 +41,11 @@ internal void UpdateFavouriteList()
|
||||
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 @@ internal bool Test( gameserveritem_t info )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
private struct MatchPair
|
||||
{
|
||||
@ -123,145 +121,5 @@ private struct MatchPair
|
||||
[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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query a list of addresses. No filters applied.
|
||||
/// </summary>
|
||||
public Request Custom( IEnumerable<string> serverList )
|
||||
{
|
||||
var request = new Request( client );
|
||||
request.ServerList = serverList;
|
||||
request.StartCustomQuery();
|
||||
return request;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request a list of servers we've favourited
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request a list of servers that our friends are on
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request a list of servers that are running on our LAN
|
||||
/// </summary>
|
||||
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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,13 +111,13 @@ public void ReleaseRequest( HServerListRequest hServerListRequest )
|
||||
|
||||
#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
|
||||
|
@ -22,4 +22,6 @@ public static class SteamApi
|
||||
[DllImport( "Steam_api64", EntryPoint = "SteamAPI_UnregisterCallback", CallingConvention = CallingConvention.Cdecl )]
|
||||
public static extern int UnregisterCallback( IntPtr pCallback );
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
199
Facepunch.Steamworks/Redux/ServerList/BaseServerList.cs
Normal file
199
Facepunch.Steamworks/Redux/ServerList/BaseServerList.cs
Normal file
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Not for reuse by newbs
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Which app we're querying. Defaults to the current app.
|
||||
/// </summary>
|
||||
public AppId AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When a new server is added, this function will get called
|
||||
/// </summary>
|
||||
public event Action OnChanges;
|
||||
|
||||
/// <summary>
|
||||
/// Called for every responsive server
|
||||
/// </summary>
|
||||
public event Action<ServerInfo> OnResponsiveServer;
|
||||
|
||||
/// <summary>
|
||||
/// A list of servers that responded. If you're only interested in servers that responded since you
|
||||
/// last updated, then simply clear this list.
|
||||
/// </summary>
|
||||
public List<ServerInfo> Responsive = new List<ServerInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// A list of servers that were in the master list but didn't respond.
|
||||
/// </summary>
|
||||
public List<ServerInfo> Unresponsive = new List<ServerInfo>();
|
||||
|
||||
|
||||
public BaseServerList()
|
||||
{
|
||||
AppId = Utils.AppId; // Default AppId is this
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query the server list. Task result will be true when finished
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> 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<MatchMakingKeyValuePair_t> filters = new List<MatchMakingKeyValuePair_t>();
|
||||
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<int> watchList = new List<int>();
|
||||
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 );
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Not for reuse by newbs
|
||||
/// </summary>
|
||||
public class ServerListFavourites : BaseServerList
|
||||
{
|
||||
internal override void LaunchQuery()
|
||||
{
|
||||
var filters = GetFilters();
|
||||
request = Internal.RequestFavoritesServerList( AppId.Value, filters, (uint)filters.Length, IntPtr.Zero );
|
||||
}
|
||||
}
|
||||
}
|
21
Facepunch.Steamworks/Redux/ServerList/ServerListFriends.cs
Normal file
21
Facepunch.Steamworks/Redux/ServerList/ServerListFriends.cs
Normal file
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Not for reuse by newbs
|
||||
/// </summary>
|
||||
public class ServerListFriends : BaseServerList
|
||||
{
|
||||
internal override void LaunchQuery()
|
||||
{
|
||||
var filters = GetFilters();
|
||||
request = Internal.RequestFriendsServerList( AppId.Value, filters, (uint)filters.Length, IntPtr.Zero );
|
||||
}
|
||||
}
|
||||
}
|
21
Facepunch.Steamworks/Redux/ServerList/ServerListHistory.cs
Normal file
21
Facepunch.Steamworks/Redux/ServerList/ServerListHistory.cs
Normal file
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Not for reuse by newbs
|
||||
/// </summary>
|
||||
public class ServerListHistory : BaseServerList
|
||||
{
|
||||
internal override void LaunchQuery()
|
||||
{
|
||||
var filters = GetFilters();
|
||||
request = Internal.RequestHistoryServerList( AppId.Value, filters, (uint)filters.Length, IntPtr.Zero );
|
||||
}
|
||||
}
|
||||
}
|
22
Facepunch.Steamworks/Redux/ServerList/ServerListInternet.cs
Normal file
22
Facepunch.Steamworks/Redux/ServerList/ServerListInternet.cs
Normal file
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Not for reuse by newbs
|
||||
/// </summary>
|
||||
public class ServerListInternet : BaseServerList
|
||||
{
|
||||
internal override void LaunchQuery()
|
||||
{
|
||||
var filters = GetFilters();
|
||||
|
||||
request = Internal.RequestInternetServerList( AppId.Value, filters, (uint)filters.Length, IntPtr.Zero );
|
||||
}
|
||||
}
|
||||
}
|
20
Facepunch.Steamworks/Redux/ServerList/ServerListLan.cs
Normal file
20
Facepunch.Steamworks/Redux/ServerList/ServerListLan.cs
Normal file
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Not for reuse by newbs
|
||||
/// </summary>
|
||||
public class ServerListLan : BaseServerList
|
||||
{
|
||||
internal override void LaunchQuery()
|
||||
{
|
||||
request = Internal.RequestLANServerList( AppId.Value, IntPtr.Zero );
|
||||
}
|
||||
}
|
||||
}
|
20
Facepunch.Steamworks/Redux/ServerList/ServerListSpectator.cs
Normal file
20
Facepunch.Steamworks/Redux/ServerList/ServerListSpectator.cs
Normal file
@ -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 );
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
@ -37,6 +37,24 @@ public static void Init( uint appid )
|
||||
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 @@ internal static void RegisterCallback( IntPtr intPtr, int callbackId )
|
||||
SteamApi.RegisterCallback( intPtr, callbackId );
|
||||
}
|
||||
|
||||
public static void Update()
|
||||
{
|
||||
SteamApi.RunCallbacks();
|
||||
}
|
||||
|
||||
internal static void UnregisterCallback( IntPtr intPtr )
|
||||
{
|
||||
SteamApi.UnregisterCallback( intPtr );
|
||||
|
94
Facepunch.Steamworks/Redux/Structs/Server.cs
Normal file
94
Facepunch.Steamworks/Redux/Structs/Server.cs
Normal file
@ -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
|
||||
|
||||
/// <summary>
|
||||
/// Add this server to our history list
|
||||
/// If we're already in the history list, weill set the last played time to now
|
||||
/// </summary>
|
||||
public void AddToHistory()
|
||||
{
|
||||
//Client.native.matchmaking.AddFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagHistory, (uint)Utility.Epoch.Current );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove this server from our history list
|
||||
/// </summary>
|
||||
public void RemoveFromHistory()
|
||||
{
|
||||
//Client.native.matchmaking.RemoveFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagHistory );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add this server to our favourite list
|
||||
/// </summary>
|
||||
public void AddToFavourites()
|
||||
{
|
||||
//Client.native.matchmaking.AddFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagFavorite, (uint)Utility.Epoch.Current );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove this server from our favourite list
|
||||
/// </summary>
|
||||
public void RemoveFromFavourites()
|
||||
{
|
||||
//Client.native.matchmaking.RemoveFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagFavorite );
|
||||
}
|
||||
}
|
||||
}
|
@ -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<SourceServerQuery> Current = new List<SourceServerQuery>();
|
||||
|
||||
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<string, string> rules = new Dictionary<string, string>();
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user