mirror of
https://github.com/Facepunch/Facepunch.Steamworks.git
synced 2024-12-25 06:05:46 +03:00
Flatter, safer, but more resource intensive server query
This commit is contained in:
parent
f84c84e950
commit
99e1740961
@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace Facepunch.Steamworks.Test
|
||||
{
|
||||
public partial class Client
|
||||
{
|
||||
[TestMethod]
|
||||
public void UpdateStats()
|
||||
{
|
||||
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
|
||||
{
|
||||
client.Stats.UpdateStats();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void UpdateSUpdateGlobalStatstats()
|
||||
{
|
||||
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
|
||||
{
|
||||
client.Stats.UpdateGlobalStats( 1 );
|
||||
client.Stats.UpdateGlobalStats( 3 );
|
||||
client.Stats.UpdateGlobalStats( 7 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -111,26 +111,7 @@ public void GetVoice()
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetServers()
|
||||
{
|
||||
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
|
||||
{
|
||||
var query = client.ServerList.Test();
|
||||
|
||||
for ( int i = 0; i < 100 ; i++ )
|
||||
{
|
||||
client.Update();
|
||||
System.Threading.Thread.Sleep( 5 );
|
||||
|
||||
if ( query.Finished )
|
||||
break;
|
||||
}
|
||||
|
||||
Console.WriteLine( "Responded: " + query.Responded.Count.ToString() );
|
||||
Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() );
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void InventoryDefinitions()
|
||||
|
@ -87,7 +87,7 @@
|
||||
</Choose>
|
||||
<ItemGroup>
|
||||
<Compile Include="Client.cs" />
|
||||
<Compile Include="Client.Networking.cs" />
|
||||
<Compile Include="Networking.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -97,7 +97,8 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Client.Stats.cs" />
|
||||
<Compile Include="Serverlist.cs" />
|
||||
<Compile Include="Stats.cs" />
|
||||
</ItemGroup>
|
||||
<Choose>
|
||||
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
|
||||
|
@ -5,7 +5,10 @@
|
||||
|
||||
namespace Facepunch.Steamworks.Test
|
||||
{
|
||||
public partial class Client
|
||||
[TestClass]
|
||||
[DeploymentItem( "FacepunchSteamworksApi.dll" )]
|
||||
[DeploymentItem( "steam_appid.txt" )]
|
||||
public partial class Networking
|
||||
{
|
||||
[TestMethod]
|
||||
public void PeerToPeerSend()
|
104
Facepunch.Steamworks.Test/Serverlist.cs
Normal file
104
Facepunch.Steamworks.Test/Serverlist.cs
Normal file
@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace Facepunch.Steamworks.Test
|
||||
{
|
||||
[TestClass]
|
||||
[DeploymentItem( "FacepunchSteamworksApi.dll" )]
|
||||
[DeploymentItem( "steam_appid.txt" )]
|
||||
public partial class ServerList
|
||||
{
|
||||
[TestMethod]
|
||||
public void InternetList()
|
||||
{
|
||||
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
|
||||
{
|
||||
var query = client.ServerList.Test();
|
||||
|
||||
for ( int i = 0; i < 100; i++ )
|
||||
{
|
||||
client.Update();
|
||||
System.Threading.Thread.Sleep( 10 );
|
||||
|
||||
if ( query.Finished )
|
||||
break;
|
||||
}
|
||||
|
||||
Console.WriteLine( "Responded: " + query.Responded.Count.ToString() );
|
||||
Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() );
|
||||
|
||||
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 >();
|
||||
|
||||
for ( int i = 0; i < 10; i++ )
|
||||
queries.Add( client.ServerList.Test() );
|
||||
|
||||
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 HistoryList()
|
||||
{
|
||||
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
|
||||
{
|
||||
var query = client.ServerList.History( new Dictionary<string, string>() );
|
||||
|
||||
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() );
|
||||
|
||||
query.Dispose();
|
||||
|
||||
for ( int i = 0; i < 100; i++ )
|
||||
{
|
||||
client.Update();
|
||||
System.Threading.Thread.Sleep( 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
73
Facepunch.Steamworks.Test/Stats.cs
Normal file
73
Facepunch.Steamworks.Test/Stats.cs
Normal file
@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace Facepunch.Steamworks.Test
|
||||
{
|
||||
[TestClass]
|
||||
[DeploymentItem( "FacepunchSteamworksApi.dll" )]
|
||||
[DeploymentItem( "steam_appid.txt" )]
|
||||
public class Stats
|
||||
{
|
||||
[TestMethod]
|
||||
public void UpdateStats()
|
||||
{
|
||||
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
|
||||
{
|
||||
client.Stats.UpdateStats();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void UpdateSUpdateGlobalStatstats()
|
||||
{
|
||||
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
|
||||
{
|
||||
client.Stats.UpdateGlobalStats( 1 );
|
||||
client.Stats.UpdateGlobalStats( 3 );
|
||||
client.Stats.UpdateGlobalStats( 7 );
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetClientFloat()
|
||||
{
|
||||
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
|
||||
{
|
||||
var v = client.Stats.GetFloat( "deaths" );
|
||||
Console.WriteLine( v );
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetClientInt()
|
||||
{
|
||||
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
|
||||
{
|
||||
var v = client.Stats.GetInt( "deaths" );
|
||||
Console.WriteLine( v );
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetGlobalFloat()
|
||||
{
|
||||
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
|
||||
{
|
||||
var v = client.Stats.GetGlobalFloat( "deaths" );
|
||||
Console.WriteLine( v );
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetGlobalInt()
|
||||
{
|
||||
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
|
||||
{
|
||||
var v = client.Stats.GetGlobalInt( "deaths" );
|
||||
Console.WriteLine( v );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -14,9 +14,6 @@ public class Request : IDisposable
|
||||
internal Client client;
|
||||
internal IntPtr Id;
|
||||
|
||||
private IntPtr m_pVTable;
|
||||
private GCHandle m_pGCHandle;
|
||||
|
||||
public struct Server
|
||||
{
|
||||
public string Name { get; set; }
|
||||
@ -56,8 +53,6 @@ public string ConnectionAddress
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal static Server FromSteam( gameserveritem_t item )
|
||||
{
|
||||
return new Server()
|
||||
@ -100,21 +95,11 @@ internal static Server FromSteam( gameserveritem_t item )
|
||||
/// </summary>
|
||||
public bool Finished = false;
|
||||
|
||||
internal Request()
|
||||
internal Request( Client c )
|
||||
{
|
||||
//
|
||||
// Create a fake vtable for Steam to respond to
|
||||
//
|
||||
var vt = new VTable()
|
||||
{
|
||||
responded = OnServerResponded,
|
||||
nonresponsive = NonResponsive,
|
||||
complete = Complete
|
||||
};
|
||||
client = c;
|
||||
|
||||
m_pVTable = Marshal.AllocHGlobal( Marshal.SizeOf( typeof( VTable ) ) );
|
||||
Marshal.StructureToPtr( vt, m_pVTable, false );
|
||||
m_pGCHandle = GCHandle.Alloc( m_pVTable, GCHandleType.Pinned );
|
||||
client.OnUpdate += Update;
|
||||
}
|
||||
|
||||
~Request()
|
||||
@ -122,88 +107,98 @@ internal Request()
|
||||
Dispose();
|
||||
}
|
||||
|
||||
int lastCount = 0;
|
||||
|
||||
internal List<int> watchlist = new List<int>();
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if ( Id == IntPtr.Zero )
|
||||
return;
|
||||
|
||||
//
|
||||
// Add any servers we're not watching to our watch list
|
||||
//
|
||||
var count = client.native.servers.GetServerCount( Id );
|
||||
if ( count != lastCount )
|
||||
{
|
||||
for ( int i = lastCount; i < count; i++ )
|
||||
{
|
||||
watchlist.Add( i );
|
||||
}
|
||||
|
||||
lastCount = count;
|
||||
}
|
||||
|
||||
//
|
||||
// Remove any servers that respond successfully
|
||||
//
|
||||
watchlist.RemoveAll( x =>
|
||||
{
|
||||
var info = client.native.servers.GetServerDetails( Id, x );
|
||||
if ( info.m_bHadSuccessfulResponse )
|
||||
{
|
||||
OnServer( info );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} );
|
||||
|
||||
//
|
||||
// If we've finished refreshing
|
||||
//
|
||||
if ( client.native.servers.IsRefreshing( Id ) == false )
|
||||
{
|
||||
//
|
||||
// Put any other servers on the 'no response' list
|
||||
//
|
||||
watchlist.RemoveAll( x =>
|
||||
{
|
||||
var info = client.native.servers.GetServerDetails( Id, x );
|
||||
OnServer( info );
|
||||
return true;
|
||||
} );
|
||||
|
||||
Finished = true;
|
||||
client.OnUpdate -= Update;
|
||||
client.native.servers.CancelQuery( Id );
|
||||
Id = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnServer( gameserveritem_t info )
|
||||
{
|
||||
if ( info.m_bHadSuccessfulResponse )
|
||||
{
|
||||
Responded.Add( Server.FromSteam( info ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
Unresponsive.Add( Server.FromSteam( info ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposing will end the query
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
client.OnUpdate -= Update;
|
||||
|
||||
//
|
||||
// Cancel the query if it's still running
|
||||
//
|
||||
if ( !Finished && Id != IntPtr.Zero )
|
||||
if ( Id != IntPtr.Zero )
|
||||
{
|
||||
if ( client.Valid )
|
||||
client.native.servers.CancelQuery( Id );
|
||||
|
||||
Id = IntPtr.Zero;
|
||||
}
|
||||
|
||||
//
|
||||
// Release the pinned GC resources
|
||||
//
|
||||
if ( m_pVTable != IntPtr.Zero )
|
||||
{
|
||||
Marshal.FreeHGlobal( m_pVTable );
|
||||
m_pVTable = IntPtr.Zero;
|
||||
}
|
||||
|
||||
if ( m_pGCHandle.IsAllocated )
|
||||
{
|
||||
m_pGCHandle.Free();
|
||||
}
|
||||
}
|
||||
|
||||
private void Complete( IntPtr thisptr, IntPtr RequestId, int response )
|
||||
{
|
||||
if ( RequestId != Id )
|
||||
throw new Exception( "Request ID is invalid!" );
|
||||
|
||||
Finished = true;
|
||||
Id = IntPtr.Zero;
|
||||
}
|
||||
|
||||
private void NonResponsive( IntPtr thisptr, IntPtr RequestId, int iServer )
|
||||
{
|
||||
if ( RequestId != Id )
|
||||
throw new Exception( "Request ID is invalid!" );
|
||||
|
||||
var info = client.native.servers.GetServerDetails( Id, iServer );
|
||||
Unresponsive.Add( Server.FromSteam( info ) );
|
||||
}
|
||||
|
||||
private void OnServerResponded( IntPtr thisptr, IntPtr RequestId, int iServer )
|
||||
{
|
||||
if ( RequestId != Id )
|
||||
throw new Exception( "Request ID is invalid!" );
|
||||
|
||||
var info = client.native.servers.GetServerDetails( Id, iServer );
|
||||
Responded.Add( Server.FromSteam( info ) );
|
||||
|
||||
System.Diagnostics.Debug.WriteLine( info.m_szServerName );
|
||||
}
|
||||
|
||||
internal IntPtr GetVTablePointer()
|
||||
{
|
||||
return m_pGCHandle.AddrOfPinnedObject();
|
||||
}
|
||||
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
internal class VTable
|
||||
{
|
||||
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
|
||||
internal delegate void InternalServerResponded( IntPtr thisptr, IntPtr hRequest, int iServer );
|
||||
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
|
||||
internal delegate void InternalServerFailedToRespond( IntPtr thisptr, IntPtr hRequest, int iServer );
|
||||
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
|
||||
internal delegate void InternalRefreshComplete( IntPtr thisptr, IntPtr hRequest, int response );
|
||||
|
||||
[NonSerialized, MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
internal InternalServerResponded responded;
|
||||
[NonSerialized, MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
internal InternalServerFailedToRespond nonresponsive;
|
||||
[NonSerialized, MarshalAs(UnmanagedType.FunctionPtr)]
|
||||
internal InternalRefreshComplete complete;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,25 +48,41 @@ public unsafe Request Test()
|
||||
//fixed ( void* a = array )
|
||||
{
|
||||
|
||||
var request = new Request()
|
||||
{
|
||||
client = client
|
||||
};
|
||||
var request = new Request( client );
|
||||
|
||||
request.Id = client.native.servers.RequestInternetServerList( client.AppId, new IntPtr[] { }, request.GetVTablePointer() );
|
||||
request.Id = client.native.servers.RequestInternetServerList( client.AppId, new IntPtr[] { }, IntPtr.Zero );
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
||||
class ResponseClass : ISteamMatchmakingServerListResponse
|
||||
{
|
||||
internal override IntPtr GetIntPtr()
|
||||
{
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
internal override void RefreshComplete( uint hRequest, uint response )
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal override void ServerFailedToRespond( uint hRequest, int iServer )
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal override void ServerResponded( uint hRequest, int iServer )
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe Request History( Dictionary< string, string > filter )
|
||||
{
|
||||
var request = new Request()
|
||||
{
|
||||
client = client
|
||||
};
|
||||
|
||||
request.Id = client.native.servers.RequestHistoryServerList( client.AppId, new IntPtr[] { }, request.GetVTablePointer() );
|
||||
var request = new Request( client );
|
||||
request.Id = client.native.servers.RequestHistoryServerList( client.AppId, new IntPtr[] { }, IntPtr.Zero );
|
||||
|
||||
return request;
|
||||
}
|
||||
|
@ -157,15 +157,23 @@ private void InternalOnWarning( int nSeverity, System.Text.StringBuilder text )
|
||||
}
|
||||
}
|
||||
|
||||
internal event Action OnUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// Should be called at least once every frame
|
||||
/// </summary>
|
||||
public void Update()
|
||||
{
|
||||
if ( native == null )
|
||||
return;
|
||||
|
||||
Valve.Steamworks.SteamAPI.RunCallbacks();
|
||||
Voice.Update();
|
||||
Inventory.Update();
|
||||
Networking.Update();
|
||||
|
||||
if ( OnUpdate != null )
|
||||
OnUpdate();
|
||||
}
|
||||
|
||||
public bool Valid
|
||||
|
@ -44,22 +44,30 @@ public void UpdateGlobalStats( int days = 1 )
|
||||
|
||||
public int GetInt( string name )
|
||||
{
|
||||
return 0;
|
||||
int data = 0;
|
||||
client.native.userstats.GetStat( name, ref data );
|
||||
return data;
|
||||
}
|
||||
|
||||
public int GetGlobalInt( string name )
|
||||
public long GetGlobalInt( string name )
|
||||
{
|
||||
return 0;
|
||||
long data = 0;
|
||||
client.native.userstats.GetGlobalStat( name, ref data );
|
||||
return data;
|
||||
}
|
||||
|
||||
public int GetFloat( string name )
|
||||
public float GetFloat( string name )
|
||||
{
|
||||
return 0;
|
||||
float data = 0;
|
||||
client.native.userstats.GetStat0( name, ref data );
|
||||
return data;
|
||||
}
|
||||
|
||||
public int GetGlobalFloat( string name )
|
||||
public double GetGlobalFloat( string name )
|
||||
{
|
||||
return 0;
|
||||
double data = 0;
|
||||
client.native.userstats.GetGlobalStat0( name, ref data );
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user