GameServer baseline

This commit is contained in:
Garry Newman 2019-04-15 20:54:50 +01:00
parent 90d9ae8c4c
commit 3255135df1
28 changed files with 1039 additions and 536 deletions

View File

@ -196,7 +196,7 @@ namespace Facepunch.Steamworks.Test
Assert.IsNotNull( client.Inventory.SerializedItems );
Assert.IsTrue( client.Inventory.SerializedItems.Length > 4 );
/*
using ( var server = new Facepunch.Steamworks.Server( 252490, new ServerInit( "rust", "Rust" ) ) )
{
server.LogOnAnonymous();
@ -223,6 +223,7 @@ namespace Facepunch.Steamworks.Test
Console.WriteLine( "Item: {0} ({1})", item.Id, item.DefinitionId );
}
}
*/
}
}

View File

@ -1,6 +1,6 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
/*
namespace Facepunch.Steamworks.Test
{
[DeploymentItem( "steam_api64.dll" )]
@ -148,3 +148,4 @@ namespace Facepunch.Steamworks.Test
}
}
}
*/

View File

@ -2,7 +2,7 @@
using System.Text;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
/*
namespace Facepunch.Steamworks.Test
{
public partial class Server
@ -40,3 +40,4 @@ namespace Facepunch.Steamworks.Test
}
}
*/

View File

@ -30,12 +30,6 @@
<Compile Remove="*AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Compile Update="Server.cs">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Compile>
</ItemGroup>
<ItemGroup>
<None Update="steam_api64.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>

View File

@ -9,6 +9,10 @@ namespace Steamworks.Internal
{
public class ISteamApps : BaseSteamInterface
{
public ISteamApps( bool server = false ) : base( server )
{
}
public override string InterfaceName => "STEAMAPPS_INTERFACE_VERSION008";
public override void InitInternals()

View File

@ -9,6 +9,10 @@ namespace Steamworks.Internal
{
public class ISteamFriends : BaseSteamInterface
{
public ISteamFriends( bool server = false ) : base( server )
{
}
public override string InterfaceName => "SteamFriends017";
public override void InitInternals()

View File

@ -0,0 +1,563 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using SteamNative;
namespace Steamworks.Internal
{
public class ISteamGameServer : BaseSteamInterface
{
public ISteamGameServer( bool server = false ) : base( server )
{
}
public override string InterfaceName => "SteamGameServer012";
public override void InitInternals()
{
InitGameServerDelegatePointer = Marshal.GetDelegateForFunctionPointer<InitGameServerDelegate>( Marshal.ReadIntPtr( VTable, 0) );
SetProductDelegatePointer = Marshal.GetDelegateForFunctionPointer<SetProductDelegate>( Marshal.ReadIntPtr( VTable, 8) );
SetGameDescriptionDelegatePointer = Marshal.GetDelegateForFunctionPointer<SetGameDescriptionDelegate>( Marshal.ReadIntPtr( VTable, 16) );
SetModDirDelegatePointer = Marshal.GetDelegateForFunctionPointer<SetModDirDelegate>( Marshal.ReadIntPtr( VTable, 24) );
SetDedicatedServerDelegatePointer = Marshal.GetDelegateForFunctionPointer<SetDedicatedServerDelegate>( Marshal.ReadIntPtr( VTable, 32) );
LogOnDelegatePointer = Marshal.GetDelegateForFunctionPointer<LogOnDelegate>( Marshal.ReadIntPtr( VTable, 40) );
LogOnAnonymousDelegatePointer = Marshal.GetDelegateForFunctionPointer<LogOnAnonymousDelegate>( Marshal.ReadIntPtr( VTable, 48) );
LogOffDelegatePointer = Marshal.GetDelegateForFunctionPointer<LogOffDelegate>( Marshal.ReadIntPtr( VTable, 56) );
BLoggedOnDelegatePointer = Marshal.GetDelegateForFunctionPointer<BLoggedOnDelegate>( Marshal.ReadIntPtr( VTable, 64) );
BSecureDelegatePointer = Marshal.GetDelegateForFunctionPointer<BSecureDelegate>( Marshal.ReadIntPtr( VTable, 72) );
GetSteamIDDelegatePointer = Marshal.GetDelegateForFunctionPointer<GetSteamIDDelegate>( Marshal.ReadIntPtr( VTable, 80) );
WasRestartRequestedDelegatePointer = Marshal.GetDelegateForFunctionPointer<WasRestartRequestedDelegate>( Marshal.ReadIntPtr( VTable, 88) );
SetMaxPlayerCountDelegatePointer = Marshal.GetDelegateForFunctionPointer<SetMaxPlayerCountDelegate>( Marshal.ReadIntPtr( VTable, 96) );
SetBotPlayerCountDelegatePointer = Marshal.GetDelegateForFunctionPointer<SetBotPlayerCountDelegate>( Marshal.ReadIntPtr( VTable, 104) );
SetServerNameDelegatePointer = Marshal.GetDelegateForFunctionPointer<SetServerNameDelegate>( Marshal.ReadIntPtr( VTable, 112) );
SetMapNameDelegatePointer = Marshal.GetDelegateForFunctionPointer<SetMapNameDelegate>( Marshal.ReadIntPtr( VTable, 120) );
SetPasswordProtectedDelegatePointer = Marshal.GetDelegateForFunctionPointer<SetPasswordProtectedDelegate>( Marshal.ReadIntPtr( VTable, 128) );
SetSpectatorPortDelegatePointer = Marshal.GetDelegateForFunctionPointer<SetSpectatorPortDelegate>( Marshal.ReadIntPtr( VTable, 136) );
SetSpectatorServerNameDelegatePointer = Marshal.GetDelegateForFunctionPointer<SetSpectatorServerNameDelegate>( Marshal.ReadIntPtr( VTable, 144) );
ClearAllKeyValuesDelegatePointer = Marshal.GetDelegateForFunctionPointer<ClearAllKeyValuesDelegate>( Marshal.ReadIntPtr( VTable, 152) );
SetKeyValueDelegatePointer = Marshal.GetDelegateForFunctionPointer<SetKeyValueDelegate>( Marshal.ReadIntPtr( VTable, 160) );
SetGameTagsDelegatePointer = Marshal.GetDelegateForFunctionPointer<SetGameTagsDelegate>( Marshal.ReadIntPtr( VTable, 168) );
SetGameDataDelegatePointer = Marshal.GetDelegateForFunctionPointer<SetGameDataDelegate>( Marshal.ReadIntPtr( VTable, 176) );
SetRegionDelegatePointer = Marshal.GetDelegateForFunctionPointer<SetRegionDelegate>( Marshal.ReadIntPtr( VTable, 184) );
SendUserConnectAndAuthenticateDelegatePointer = Marshal.GetDelegateForFunctionPointer<SendUserConnectAndAuthenticateDelegate>( Marshal.ReadIntPtr( VTable, 192) );
CreateUnauthenticatedUserConnectionDelegatePointer = Marshal.GetDelegateForFunctionPointer<CreateUnauthenticatedUserConnectionDelegate>( Marshal.ReadIntPtr( VTable, 200) );
SendUserDisconnectDelegatePointer = Marshal.GetDelegateForFunctionPointer<SendUserDisconnectDelegate>( Marshal.ReadIntPtr( VTable, 208) );
BUpdateUserDataDelegatePointer = Marshal.GetDelegateForFunctionPointer<BUpdateUserDataDelegate>( Marshal.ReadIntPtr( VTable, 216) );
GetAuthSessionTicketDelegatePointer = Marshal.GetDelegateForFunctionPointer<GetAuthSessionTicketDelegate>( Marshal.ReadIntPtr( VTable, 224) );
BeginAuthSessionDelegatePointer = Marshal.GetDelegateForFunctionPointer<BeginAuthSessionDelegate>( Marshal.ReadIntPtr( VTable, 232) );
EndAuthSessionDelegatePointer = Marshal.GetDelegateForFunctionPointer<EndAuthSessionDelegate>( Marshal.ReadIntPtr( VTable, 240) );
CancelAuthTicketDelegatePointer = Marshal.GetDelegateForFunctionPointer<CancelAuthTicketDelegate>( Marshal.ReadIntPtr( VTable, 248) );
UserHasLicenseForAppDelegatePointer = Marshal.GetDelegateForFunctionPointer<UserHasLicenseForAppDelegate>( Marshal.ReadIntPtr( VTable, 256) );
RequestUserGroupStatusDelegatePointer = Marshal.GetDelegateForFunctionPointer<RequestUserGroupStatusDelegate>( Marshal.ReadIntPtr( VTable, 264) );
GetGameplayStatsDelegatePointer = Marshal.GetDelegateForFunctionPointer<GetGameplayStatsDelegate>( Marshal.ReadIntPtr( VTable, 272) );
GetServerReputationDelegatePointer = Marshal.GetDelegateForFunctionPointer<GetServerReputationDelegate>( Marshal.ReadIntPtr( VTable, 280) );
GetPublicIPDelegatePointer = Marshal.GetDelegateForFunctionPointer<GetPublicIPDelegate>( Marshal.ReadIntPtr( VTable, 288) );
HandleIncomingPacketDelegatePointer = Marshal.GetDelegateForFunctionPointer<HandleIncomingPacketDelegate>( Marshal.ReadIntPtr( VTable, 296) );
GetNextOutgoingPacketDelegatePointer = Marshal.GetDelegateForFunctionPointer<GetNextOutgoingPacketDelegate>( Marshal.ReadIntPtr( VTable, 304) );
EnableHeartbeatsDelegatePointer = Marshal.GetDelegateForFunctionPointer<EnableHeartbeatsDelegate>( Marshal.ReadIntPtr( VTable, 312) );
SetHeartbeatIntervalDelegatePointer = Marshal.GetDelegateForFunctionPointer<SetHeartbeatIntervalDelegate>( Marshal.ReadIntPtr( VTable, 320) );
ForceHeartbeatDelegatePointer = Marshal.GetDelegateForFunctionPointer<ForceHeartbeatDelegate>( Marshal.ReadIntPtr( VTable, 328) );
AssociateWithClanDelegatePointer = Marshal.GetDelegateForFunctionPointer<AssociateWithClanDelegate>( Marshal.ReadIntPtr( VTable, 336) );
ComputeNewPlayerCompatibilityDelegatePointer = Marshal.GetDelegateForFunctionPointer<ComputeNewPlayerCompatibilityDelegate>( Marshal.ReadIntPtr( VTable, 344) );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
[return: MarshalAs( UnmanagedType.I1 )]
public delegate bool InitGameServerDelegate( IntPtr self, uint unIP, ushort usGamePort, ushort usQueryPort, uint unFlags, AppId_t nGameAppId, string pchVersionString );
private InitGameServerDelegate InitGameServerDelegatePointer;
#endregion
public bool InitGameServer( uint unIP, ushort usGamePort, ushort usQueryPort, uint unFlags, AppId_t nGameAppId, string pchVersionString )
{
return InitGameServerDelegatePointer( Self, unIP, usGamePort, usQueryPort, unFlags, nGameAppId, pchVersionString );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void SetProductDelegate( IntPtr self, string pszProduct );
private SetProductDelegate SetProductDelegatePointer;
#endregion
public void SetProduct( string pszProduct )
{
SetProductDelegatePointer( Self, pszProduct );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void SetGameDescriptionDelegate( IntPtr self, string pszGameDescription );
private SetGameDescriptionDelegate SetGameDescriptionDelegatePointer;
#endregion
public void SetGameDescription( string pszGameDescription )
{
SetGameDescriptionDelegatePointer( Self, pszGameDescription );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void SetModDirDelegate( IntPtr self, string pszModDir );
private SetModDirDelegate SetModDirDelegatePointer;
#endregion
public void SetModDir( string pszModDir )
{
SetModDirDelegatePointer( Self, pszModDir );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void SetDedicatedServerDelegate( IntPtr self, [MarshalAs( UnmanagedType.U1 )] bool bDedicated );
private SetDedicatedServerDelegate SetDedicatedServerDelegatePointer;
#endregion
public void SetDedicatedServer( [MarshalAs( UnmanagedType.U1 )] bool bDedicated )
{
SetDedicatedServerDelegatePointer( Self, bDedicated );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void LogOnDelegate( IntPtr self, string pszToken );
private LogOnDelegate LogOnDelegatePointer;
#endregion
public void LogOn( string pszToken )
{
LogOnDelegatePointer( Self, pszToken );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void LogOnAnonymousDelegate( IntPtr self );
private LogOnAnonymousDelegate LogOnAnonymousDelegatePointer;
#endregion
public void LogOnAnonymous()
{
LogOnAnonymousDelegatePointer( Self );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void LogOffDelegate( IntPtr self );
private LogOffDelegate LogOffDelegatePointer;
#endregion
public void LogOff()
{
LogOffDelegatePointer( Self );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
[return: MarshalAs( UnmanagedType.I1 )]
public delegate bool BLoggedOnDelegate( IntPtr self );
private BLoggedOnDelegate BLoggedOnDelegatePointer;
#endregion
public bool BLoggedOn()
{
return BLoggedOnDelegatePointer( Self );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
[return: MarshalAs( UnmanagedType.I1 )]
public delegate bool BSecureDelegate( IntPtr self );
private BSecureDelegate BSecureDelegatePointer;
#endregion
public bool BSecure()
{
return BSecureDelegatePointer( Self );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void GetSteamIDDelegate( IntPtr self, ref CSteamID retVal );
private GetSteamIDDelegate GetSteamIDDelegatePointer;
#endregion
public CSteamID GetSteamID()
{
var retVal = default( CSteamID );
GetSteamIDDelegatePointer( Self, ref retVal );
return retVal;
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
[return: MarshalAs( UnmanagedType.I1 )]
public delegate bool WasRestartRequestedDelegate( IntPtr self );
private WasRestartRequestedDelegate WasRestartRequestedDelegatePointer;
#endregion
public bool WasRestartRequested()
{
return WasRestartRequestedDelegatePointer( Self );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void SetMaxPlayerCountDelegate( IntPtr self, int cPlayersMax );
private SetMaxPlayerCountDelegate SetMaxPlayerCountDelegatePointer;
#endregion
public void SetMaxPlayerCount( int cPlayersMax )
{
SetMaxPlayerCountDelegatePointer( Self, cPlayersMax );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void SetBotPlayerCountDelegate( IntPtr self, int cBotplayers );
private SetBotPlayerCountDelegate SetBotPlayerCountDelegatePointer;
#endregion
public void SetBotPlayerCount( int cBotplayers )
{
SetBotPlayerCountDelegatePointer( Self, cBotplayers );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void SetServerNameDelegate( IntPtr self, string pszServerName );
private SetServerNameDelegate SetServerNameDelegatePointer;
#endregion
public void SetServerName( string pszServerName )
{
SetServerNameDelegatePointer( Self, pszServerName );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void SetMapNameDelegate( IntPtr self, string pszMapName );
private SetMapNameDelegate SetMapNameDelegatePointer;
#endregion
public void SetMapName( string pszMapName )
{
SetMapNameDelegatePointer( Self, pszMapName );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void SetPasswordProtectedDelegate( IntPtr self, [MarshalAs( UnmanagedType.U1 )] bool bPasswordProtected );
private SetPasswordProtectedDelegate SetPasswordProtectedDelegatePointer;
#endregion
public void SetPasswordProtected( [MarshalAs( UnmanagedType.U1 )] bool bPasswordProtected )
{
SetPasswordProtectedDelegatePointer( Self, bPasswordProtected );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void SetSpectatorPortDelegate( IntPtr self, ushort unSpectatorPort );
private SetSpectatorPortDelegate SetSpectatorPortDelegatePointer;
#endregion
public void SetSpectatorPort( ushort unSpectatorPort )
{
SetSpectatorPortDelegatePointer( Self, unSpectatorPort );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void SetSpectatorServerNameDelegate( IntPtr self, string pszSpectatorServerName );
private SetSpectatorServerNameDelegate SetSpectatorServerNameDelegatePointer;
#endregion
public void SetSpectatorServerName( string pszSpectatorServerName )
{
SetSpectatorServerNameDelegatePointer( Self, pszSpectatorServerName );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void ClearAllKeyValuesDelegate( IntPtr self );
private ClearAllKeyValuesDelegate ClearAllKeyValuesDelegatePointer;
#endregion
public void ClearAllKeyValues()
{
ClearAllKeyValuesDelegatePointer( Self );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void SetKeyValueDelegate( IntPtr self, string pKey, string pValue );
private SetKeyValueDelegate SetKeyValueDelegatePointer;
#endregion
public void SetKeyValue( string pKey, string pValue )
{
SetKeyValueDelegatePointer( Self, pKey, pValue );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void SetGameTagsDelegate( IntPtr self, string pchGameTags );
private SetGameTagsDelegate SetGameTagsDelegatePointer;
#endregion
public void SetGameTags( string pchGameTags )
{
SetGameTagsDelegatePointer( Self, pchGameTags );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void SetGameDataDelegate( IntPtr self, string pchGameData );
private SetGameDataDelegate SetGameDataDelegatePointer;
#endregion
public void SetGameData( string pchGameData )
{
SetGameDataDelegatePointer( Self, pchGameData );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void SetRegionDelegate( IntPtr self, string pszRegion );
private SetRegionDelegate SetRegionDelegatePointer;
#endregion
public void SetRegion( string pszRegion )
{
SetRegionDelegatePointer( Self, pszRegion );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
[return: MarshalAs( UnmanagedType.I1 )]
public delegate bool SendUserConnectAndAuthenticateDelegate( IntPtr self, uint unIPClient, IntPtr pvAuthBlob, uint cubAuthBlobSize, ref CSteamID pSteamIDUser );
private SendUserConnectAndAuthenticateDelegate SendUserConnectAndAuthenticateDelegatePointer;
#endregion
public bool SendUserConnectAndAuthenticate( uint unIPClient, IntPtr pvAuthBlob, uint cubAuthBlobSize, ref CSteamID pSteamIDUser )
{
return SendUserConnectAndAuthenticateDelegatePointer( Self, unIPClient, pvAuthBlob, cubAuthBlobSize, ref pSteamIDUser );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void CreateUnauthenticatedUserConnectionDelegate( IntPtr self, ref CSteamID retVal );
private CreateUnauthenticatedUserConnectionDelegate CreateUnauthenticatedUserConnectionDelegatePointer;
#endregion
public CSteamID CreateUnauthenticatedUserConnection()
{
var retVal = default( CSteamID );
CreateUnauthenticatedUserConnectionDelegatePointer( Self, ref retVal );
return retVal;
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void SendUserDisconnectDelegate( IntPtr self, CSteamID steamIDUser );
private SendUserDisconnectDelegate SendUserDisconnectDelegatePointer;
#endregion
public void SendUserDisconnect( CSteamID steamIDUser )
{
SendUserDisconnectDelegatePointer( Self, steamIDUser );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
[return: MarshalAs( UnmanagedType.I1 )]
public delegate bool BUpdateUserDataDelegate( IntPtr self, CSteamID steamIDUser, string pchPlayerName, uint uScore );
private BUpdateUserDataDelegate BUpdateUserDataDelegatePointer;
#endregion
public bool BUpdateUserData( CSteamID steamIDUser, string pchPlayerName, uint uScore )
{
return BUpdateUserDataDelegatePointer( Self, steamIDUser, pchPlayerName, uScore );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate HAuthTicket GetAuthSessionTicketDelegate( IntPtr self, IntPtr pTicket, int cbMaxTicket, ref uint pcbTicket );
private GetAuthSessionTicketDelegate GetAuthSessionTicketDelegatePointer;
#endregion
public HAuthTicket GetAuthSessionTicket( IntPtr pTicket, int cbMaxTicket, ref uint pcbTicket )
{
return GetAuthSessionTicketDelegatePointer( Self, pTicket, cbMaxTicket, ref pcbTicket );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate BeginAuthSessionResult BeginAuthSessionDelegate( IntPtr self, IntPtr pAuthTicket, int cbAuthTicket, CSteamID steamID );
private BeginAuthSessionDelegate BeginAuthSessionDelegatePointer;
#endregion
public BeginAuthSessionResult BeginAuthSession( IntPtr pAuthTicket, int cbAuthTicket, CSteamID steamID )
{
return BeginAuthSessionDelegatePointer( Self, pAuthTicket, cbAuthTicket, steamID );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void EndAuthSessionDelegate( IntPtr self, CSteamID steamID );
private EndAuthSessionDelegate EndAuthSessionDelegatePointer;
#endregion
public void EndAuthSession( CSteamID steamID )
{
EndAuthSessionDelegatePointer( Self, steamID );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void CancelAuthTicketDelegate( IntPtr self, HAuthTicket hAuthTicket );
private CancelAuthTicketDelegate CancelAuthTicketDelegatePointer;
#endregion
public void CancelAuthTicket( HAuthTicket hAuthTicket )
{
CancelAuthTicketDelegatePointer( Self, hAuthTicket );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate UserHasLicenseForAppResult UserHasLicenseForAppDelegate( IntPtr self, CSteamID steamID, AppId_t appID );
private UserHasLicenseForAppDelegate UserHasLicenseForAppDelegatePointer;
#endregion
public UserHasLicenseForAppResult UserHasLicenseForApp( CSteamID steamID, AppId_t appID )
{
return UserHasLicenseForAppDelegatePointer( Self, steamID, appID );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
[return: MarshalAs( UnmanagedType.I1 )]
public delegate bool RequestUserGroupStatusDelegate( IntPtr self, CSteamID steamIDUser, CSteamID steamIDGroup );
private RequestUserGroupStatusDelegate RequestUserGroupStatusDelegatePointer;
#endregion
public bool RequestUserGroupStatus( CSteamID steamIDUser, CSteamID steamIDGroup )
{
return RequestUserGroupStatusDelegatePointer( Self, steamIDUser, steamIDGroup );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void GetGameplayStatsDelegate( IntPtr self );
private GetGameplayStatsDelegate GetGameplayStatsDelegatePointer;
#endregion
public void GetGameplayStats()
{
GetGameplayStatsDelegatePointer( Self );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate SteamAPICall_t GetServerReputationDelegate( IntPtr self );
private GetServerReputationDelegate GetServerReputationDelegatePointer;
#endregion
public async Task<GSReputation_t?> GetServerReputation()
{
return await (new Result<GSReputation_t>( GetServerReputationDelegatePointer( Self ) )).GetResult();
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate uint GetPublicIPDelegate( IntPtr self );
private GetPublicIPDelegate GetPublicIPDelegatePointer;
#endregion
public uint GetPublicIP()
{
return GetPublicIPDelegatePointer( Self );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
[return: MarshalAs( UnmanagedType.I1 )]
public delegate bool HandleIncomingPacketDelegate( IntPtr self, IntPtr pData, int cbData, uint srcIP, ushort srcPort );
private HandleIncomingPacketDelegate HandleIncomingPacketDelegatePointer;
#endregion
public bool HandleIncomingPacket( IntPtr pData, int cbData, uint srcIP, ushort srcPort )
{
return HandleIncomingPacketDelegatePointer( Self, pData, cbData, srcIP, srcPort );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate int GetNextOutgoingPacketDelegate( IntPtr self, IntPtr pOut, int cbMaxOut, ref uint pNetAdr, ref ushort pPort );
private GetNextOutgoingPacketDelegate GetNextOutgoingPacketDelegatePointer;
#endregion
public int GetNextOutgoingPacket( IntPtr pOut, int cbMaxOut, ref uint pNetAdr, ref ushort pPort )
{
return GetNextOutgoingPacketDelegatePointer( Self, pOut, cbMaxOut, ref pNetAdr, ref pPort );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void EnableHeartbeatsDelegate( IntPtr self, [MarshalAs( UnmanagedType.U1 )] bool bActive );
private EnableHeartbeatsDelegate EnableHeartbeatsDelegatePointer;
#endregion
public void EnableHeartbeats( [MarshalAs( UnmanagedType.U1 )] bool bActive )
{
EnableHeartbeatsDelegatePointer( Self, bActive );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void SetHeartbeatIntervalDelegate( IntPtr self, int iHeartbeatInterval );
private SetHeartbeatIntervalDelegate SetHeartbeatIntervalDelegatePointer;
#endregion
public void SetHeartbeatInterval( int iHeartbeatInterval )
{
SetHeartbeatIntervalDelegatePointer( Self, iHeartbeatInterval );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void ForceHeartbeatDelegate( IntPtr self );
private ForceHeartbeatDelegate ForceHeartbeatDelegatePointer;
#endregion
public void ForceHeartbeat()
{
ForceHeartbeatDelegatePointer( Self );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate SteamAPICall_t AssociateWithClanDelegate( IntPtr self, CSteamID steamIDClan );
private AssociateWithClanDelegate AssociateWithClanDelegatePointer;
#endregion
public async Task<AssociateWithClanResult_t?> AssociateWithClan( CSteamID steamIDClan )
{
return await (new Result<AssociateWithClanResult_t>( AssociateWithClanDelegatePointer( Self, steamIDClan ) )).GetResult();
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate SteamAPICall_t ComputeNewPlayerCompatibilityDelegate( IntPtr self, CSteamID steamIDNewPlayer );
private ComputeNewPlayerCompatibilityDelegate ComputeNewPlayerCompatibilityDelegatePointer;
#endregion
public async Task<ComputeNewPlayerCompatibilityResult_t?> ComputeNewPlayerCompatibility( CSteamID steamIDNewPlayer )
{
return await (new Result<ComputeNewPlayerCompatibilityResult_t>( ComputeNewPlayerCompatibilityDelegatePointer( Self, steamIDNewPlayer ) )).GetResult();
}
}
}

View File

@ -9,6 +9,10 @@ namespace Steamworks.Internal
{
public class ISteamMatchmakingServers : BaseSteamInterface
{
public ISteamMatchmakingServers( bool server = false ) : base( server )
{
}
public override string InterfaceName => "SteamMatchMakingServers002";
public override void InitInternals()

View File

@ -9,6 +9,10 @@ namespace Steamworks.Internal
{
public class ISteamMusic : BaseSteamInterface
{
public ISteamMusic( bool server = false ) : base( server )
{
}
public override string InterfaceName => "STEAMMUSIC_INTERFACE_VERSION001";
public override void InitInternals()

View File

@ -9,6 +9,10 @@ namespace Steamworks.Internal
{
public class ISteamParentalSettings : BaseSteamInterface
{
public ISteamParentalSettings( bool server = false ) : base( server )
{
}
public override string InterfaceName => "STEAMPARENTALSETTINGS_INTERFACE_VERSION001";
public override void InitInternals()

View File

@ -9,6 +9,10 @@ namespace Steamworks.Internal
{
public class ISteamUser : BaseSteamInterface
{
public ISteamUser( bool server = false ) : base( server )
{
}
public override string InterfaceName => "SteamUser020";
public override void InitInternals()

View File

@ -9,6 +9,10 @@ namespace Steamworks.Internal
{
public class ISteamUtils : BaseSteamInterface
{
public ISteamUtils( bool server = false ) : base( server )
{
}
public override string InterfaceName => "SteamUtils009";
public override void InitInternals()

View File

@ -9,6 +9,10 @@ namespace Steamworks.Internal
{
public class ISteamVideo : BaseSteamInterface
{
public ISteamVideo( bool server = false ) : base( server )
{
}
public override string InterfaceName => "STEAMVIDEO_INTERFACE_V002";
public override void InitInternals()

View File

@ -13,6 +13,9 @@ public static class SteamApi
[DllImport( "Steam_api64", EntryPoint = "SteamAPI_GetHSteamUser", CallingConvention = CallingConvention.Cdecl )]
public static extern int GetHSteamUser();
[DllImport( "Steam_api64", EntryPoint = "SteamGameServer_GetHSteamUser", CallingConvention = CallingConvention.Cdecl )]
public static extern int SteamGameServer_GetHSteamUser();
[DllImport( "Steam_api64", EntryPoint = "SteamAPI_RunCallbacks", CallingConvention = CallingConvention.Cdecl )]
public static extern int RunCallbacks();

View File

@ -8,4 +8,8 @@ public static class SteamInternal
{
[DllImport( "Steam_api64", EntryPoint = "SteamInternal_FindOrCreateUserInterface", CallingConvention = CallingConvention.Cdecl )]
public static extern IntPtr FindOrCreateUserInterface( int hSteamUser, [MarshalAs( UnmanagedType.LPStr )] string pszVersion );
[DllImport( "Steam_api64", EntryPoint = "SteamInternal_FindOrCreateGameServerInterface", CallingConvention = CallingConvention.Cdecl )]
public static extern IntPtr FindOrCreateGameServerInterface( int hSteamUser, [MarshalAs( UnmanagedType.LPStr )] string pszVersion );
}

View File

@ -31,9 +31,6 @@ namespace Facepunch.Steamworks.Interop
internal bool InitClient( BaseSteamworks steamworks )
{
if ( Steamworks.Server.Instance != null )
throw new System.Exception("Steam client should be initialized before steam server - or there's big trouble.");
isServer = false;
api = new SteamNative.SteamApi();

View File

@ -0,0 +1,334 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Facepunch.Steamworks;
using SteamNative;
namespace Steamworks
{
/// <summary>
/// Provides the core of the Steam Game Servers API
/// </summary>
public static partial class GameServer
{
static Internal.ISteamGameServer _internal;
internal static Internal.ISteamGameServer Internal
{
get
{
if ( _internal == null )
_internal = new Internal.ISteamGameServer( true );
return _internal;
}
}
internal static void InstallEvents()
{
new Event<ValidateAuthTicketResponse_t>( x => OnValidateAuthTicketResponse?.Invoke( x.SteamID, x.OwnerSteamID, x.AuthSessionResponse ), true );
}
/// <summary>
/// User has been authed or rejected
/// </summary>
public static event Action<CSteamID, CSteamID, AuthSessionResponse> OnValidateAuthTicketResponse;
public static bool Init( AppId appid, ServerInit init )
{
uint ipaddress = 0; // Any Port
if ( init.SteamPort == 0 )
init = init.WithRandomSteamPort();
if ( init.IpAddress != null )
ipaddress = Utility.IpToInt32( init.IpAddress );
//
// Get other interfaces
//
if ( !Internal.InitGameServer( ipaddress, init.GamePort, init.QueryPort, (uint)( init.Secure ? 3 : 2 ), appid.Value, init.VersionString ) )
{
return false;
}
//
// Initial settings
//
Internal.EnableHeartbeats( true );
MaxPlayers = 32;
BotCount = 0;
Product = $"{appid.Value}";
ModDir = init.ModDir;
GameDescription = init.GameDescription;
Passworded = false;
DedicatedServer = true;
InstallEvents();
return true;
}
/// <summary>
/// Sets whether this should be marked as a dedicated server.
/// If not, it is assumed to be a listen server.
/// </summary>
public static bool DedicatedServer
{
get => _dedicatedServer;
set { if ( _dedicatedServer == value ) return; Internal.SetDedicatedServer( value ); _dedicatedServer = value; }
}
private static bool _dedicatedServer;
/// <summary>
/// Gets or sets the current MaxPlayers.
/// This doesn't enforce any kind of limit, it just updates the master server.
/// </summary>
public static int MaxPlayers
{
get => _maxplayers;
set { if ( _maxplayers == value ) return; Internal.SetMaxPlayerCount( value ); _maxplayers = value; }
}
private static int _maxplayers = 0;
/// <summary>
/// Gets or sets the current BotCount.
/// This doesn't enforce any kind of limit, it just updates the master server.
/// </summary>
public static int BotCount
{
get => _botcount;
set { if ( _botcount == value ) return; Internal.SetBotPlayerCount( value ); _botcount = value; }
}
private static int _botcount = 0;
/// <summary>
/// Gets or sets the current Map Name.
/// </summary>
public static string MapName
{
get => _mapname;
set { if ( _mapname == value ) return; Internal.SetMapName( value ); _mapname = value; }
}
private static string _mapname;
/// <summary>
/// Gets or sets the current ModDir
/// </summary>
public static string ModDir
{
get => _modDir;
internal set { if ( _modDir == value ) return; Internal.SetModDir( value ); _modDir = value; }
}
private static string _modDir = "";
/// <summary>
/// Gets the current product
/// </summary>
public static string Product
{
get => _product;
internal set { if ( _product == value ) return; Internal.SetProduct( value ); _product = value; }
}
private static string _product = "";
/// <summary>
/// Gets or sets the current Product
/// </summary>
public static string GameDescription
{
get => _gameDescription;
internal set { if ( _gameDescription == value ) return; Internal.SetGameDescription( value ); _gameDescription = value; }
}
private static string _gameDescription = "";
/// <summary>
/// Gets or sets the current ServerName
/// </summary>
public static string ServerName
{
get => _serverName;
set { if ( _serverName == value ) return; Internal.SetServerName( value ); _serverName = value; }
}
private static string _serverName = "";
/// <summary>
/// Set whether the server should report itself as passworded
/// </summary>
public static bool Passworded
{
get => _passworded;
set { if ( _passworded == value ) return; Internal.SetPasswordProtected( value ); _passworded = value; }
}
private static bool _passworded;
/// <summary>
/// Gets or sets the current GameTags. This is a comma seperated list of tags for this server.
/// When querying the server list you can filter by these tags.
/// </summary>
public static string GameTags
{
get => _gametags;
set { if ( _gametags == value ) return; Internal.SetGameTags( value ); _gametags = value; }
}
private static string _gametags = "";
/// <summary>
/// Log onto Steam anonymously.
/// </summary>
public static void LogOnAnonymous()
{
Internal.LogOnAnonymous();
ForceHeartbeat();
}
/// <summary>
/// Returns true if the server is connected and registered with the Steam master server
/// You should have called LogOnAnonymous etc on startup.
/// </summary>
public static bool LoggedOn => Internal.BLoggedOn();
/// <summary>
/// To the best of its ability this tries to get the server's
/// current public ip address. Be aware that this is likely to return
/// null for the first few seconds after initialization.
/// </summary>
public static System.Net.IPAddress PublicIp
{
get
{
var ip = Internal.GetPublicIP();
if ( ip == 0 ) return null;
return Utility.Int32ToIp( ip );
}
}
/// <summary>
/// Enable or disable heartbeats, which are sent regularly to the master server.
/// Enabled by default.
/// </summary>
public static bool AutomaticHeartbeats
{
set { Internal.EnableHeartbeats( value ); }
}
/// <summary>
/// Set heartbeat interval, if automatic heartbeats are enabled.
/// You can leave this at the default.
/// </summary>
public static int AutomaticHeartbeatRate
{
set { Internal.SetHeartbeatInterval( value ); }
}
/// <summary>
/// Force send a heartbeat to the master server instead of waiting
/// for the next automatic update (if you've left them enabled)
/// </summary>
public static void ForceHeartbeat()
{
Internal.ForceHeartbeat();
}
/// <summary>
/// Update this connected player's information. You should really call this
/// any time a player's name or score changes. This keeps the information shown
/// to server queries up to date.
/// </summary>
public static void UpdatePlayer( ulong steamid, string name, int score )
{
Internal.BUpdateUserData( steamid, name, (uint)score );
}
static Dictionary<string, string> KeyValue = new Dictionary<string, string>();
/// <summary>
/// Sets a Key Value. These can be anything you like, and are accessible
/// when querying servers from the server list.
///
/// Information describing gamemodes are common here.
/// </summary>
public static void SetKey( string Key, string Value )
{
if ( KeyValue.ContainsKey( Key ) )
{
if ( KeyValue[Key] == Value )
return;
KeyValue[Key] = Value;
}
else
{
KeyValue.Add( Key, Value );
}
Internal.SetKeyValue( Key, Value );
}
/// <summary>
/// Start authorizing a ticket. This user isn't authorized yet. Wait for a call to OnAuthChange.
/// </summary>
public static unsafe bool BeginAuthSession( byte[] data, ulong steamid )
{
fixed ( byte* p = data )
{
var result = Internal.BeginAuthSession( (IntPtr)p, data.Length, steamid );
if ( result == SteamNative.BeginAuthSessionResult.OK )
return true;
return false;
}
}
/// <summary>
/// Forget this guy. They're no longer in the game.
/// </summary>
public static void EndSession( ulong steamid )
{
Internal.EndAuthSession( steamid );
}
/// <summary>
/// If true, Steam wants to send a packet. You should respond by sending
/// this packet in an unconnected way to the returned Address and Port.
/// </summary>
/// <param name="packet">Packet to send. The Data passed is pooled - so use it immediately.</param>
/// <returns>True if we want to send a packet</returns>
public static unsafe bool GetOutgoingPacket( out OutgoingPacket packet )
{
var buffer = Helpers.TakeBuffer( 1024 * 32 );
packet = new OutgoingPacket();
fixed ( byte* ptr = buffer )
{
uint addr = 0;
ushort port = 0;
var size = Internal.GetNextOutgoingPacket( (IntPtr)ptr, buffer.Length, ref addr, ref port );
if ( size == 0 )
return false;
packet.Size = size;
packet.Data = buffer;
packet.Address = addr;
packet.Port = port;
return true;
}
}
/// <summary>
/// We have received a server query on our game port. Pass it to Steam to handle.
/// </summary>
public static unsafe void HandleIncomingPacket( byte[] data, int size, uint address, ushort port )
{
fixed ( byte* ptr = data )
{
Internal.HandleIncomingPacket( (IntPtr)ptr, size, address, port );
}
}
}
}

View File

@ -0,0 +1,30 @@
namespace Steamworks
{
/// <summary>
/// A server query packet.
/// </summary>
public struct OutgoingPacket
{
/// <summary>
/// Target IP address
/// </summary>
public uint Address { get; internal set; }
/// <summary>
/// Target port
/// </summary>
public ushort Port { get; internal set; }
/// <summary>
/// This data is pooled. Make a copy if you don't use it immediately.
/// This buffer is also quite large - so pay attention to Size.
/// </summary>
public byte[] Data { get; internal set; }
/// <summary>
/// Size of the data
/// </summary>
public int Size { get; internal set; }
}
}

View File

@ -5,48 +5,56 @@ using System.Net;
using System.Runtime.InteropServices;
using System.Text;
namespace Facepunch.Steamworks
namespace Steamworks
{
/// <summary>
/// Used to set up the server.
/// The variables in here are all required to be set, and can't be changed once the server is created.
/// </summary>
public class ServerInit
public struct ServerInit
{
public IPAddress IpAddress;
public ushort SteamPort;
public ushort GamePort = 27015;
public ushort QueryPort = 27016;
public bool Secure = true;
public ushort GamePort;
public ushort QueryPort;
public bool Secure;
/// <summary>
/// The version string is usually in the form x.x.x.x, and is used by the master server to detect when the server is out of date.
/// If you go into the dedicated server tab on steamworks you'll be able to server the latest version. If this version number is
/// less than that latest version then your server won't show.
/// </summary>
public string VersionString = "2.0.0.0";
public string VersionString;
/// <summary>
/// This should be the same directory game where gets installed into. Just the folder name, not the whole path. I.e. "Rust", "Garrysmod".
/// </summary>
public string ModDir = "unset";
/// <summary>
/// This should be the same directory game where gets installed into. Just the folder name, not the whole path. I.e. "Rust", "Garrysmod".
/// </summary>
public string ModDir;
/// <summary>
/// The game description. Setting this to the full name of your game is recommended.
/// </summary>
public string GameDescription = "unset";
public string GameDescription;
public ServerInit( string modDir, string gameDesc )
{
ModDir = modDir;
GameDescription = gameDesc;
}
GamePort = 27015;
QueryPort = 27016;
Secure = true;
VersionString = "1.0.0.0";
ModDir = "unset";
GameDescription = "unset";
IpAddress = null;
SteamPort = 0;
}
/// <summary>
/// Set the Steam quert port
/// </summary>
public ServerInit RandomSteamPort()
public ServerInit WithRandomSteamPort()
{
SteamPort = (ushort)new Random().Next( 10000, 60000 );
return this;
@ -59,7 +67,7 @@ namespace Facepunch.Steamworks
///
/// More info about this here: https://partner.steamgames.com/doc/api/ISteamGameServer#HandleIncomingPacket
/// </summary>
public ServerInit QueryShareGamePort()
public ServerInit WithQueryShareGamePort()
{
QueryPort = 0xFFFF;
return this;

View File

@ -1,338 +0,0 @@
using System;
using System.Collections.Generic;
namespace Facepunch.Steamworks
{
/// <summary>
/// Initialize this class for Game Servers.
///
/// Game servers offer a limited amount of Steam functionality - and don't require the Steam client.
/// </summary>
public partial class Server : BaseSteamworks
{
/// <summary>
/// A singleton accessor to get the current client instance.
/// </summary>
public static Server Instance { get; private set; }
internal override bool IsGameServer { get { return true; } }
public ServerQuery Query { get; internal set; }
public ServerStats Stats { get; internal set; }
public ServerAuth Auth { get; internal set; }
/// <summary>
/// Initialize a Steam Server instance
/// </summary>
public Server( uint appId, ServerInit init) : base( appId )
{
if ( Instance != null )
{
throw new System.Exception( "Only one Facepunch.Steamworks.Server can exist - dispose the old one before trying to create a new one." );
}
Instance = this;
native = new Interop.NativeInterface();
uint ipaddress = 0; // Any Port
if ( init.SteamPort == 0 ) init.RandomSteamPort();
if ( init.IpAddress != null ) ipaddress = Utility.IpToInt32( init.IpAddress );
//
// Get other interfaces
//
if ( !native.InitServer( this, ipaddress, init.SteamPort, init.GamePort, init.QueryPort, init.Secure ? 3 : 2, init.VersionString ) )
{
native.Dispose();
native = null;
Instance = null;
return;
}
//
// Register Callbacks
//
SteamNative.Callbacks.RegisterCallbacks( this );
//
// Setup interfaces that client and server both have
//
SetupCommonInterfaces();
//
// Initial settings
//
native.gameServer.EnableHeartbeats( true );
MaxPlayers = 32;
BotCount = 0;
Product = $"{AppId}";
ModDir = init.ModDir;
GameDescription = init.GameDescription;
Passworded = false;
DedicatedServer = true;
//
// Child classes
//
Query = new ServerQuery( this );
Stats = new ServerStats( this );
Auth = new ServerAuth( this );
//
// Run update, first call does some initialization
//
Update();
}
~Server()
{
Dispose();
}
/// <summary>
/// Should be called at least once every frame
/// </summary>
public override void Update()
{
if ( !IsValid )
return;
native.api.SteamGameServer_RunCallbacks();
base.Update();
}
/// <summary>
/// Sets whether this should be marked as a dedicated server.
/// If not, it is assumed to be a listen server.
/// </summary>
public bool DedicatedServer
{
get { return _dedicatedServer; }
set { if ( _dedicatedServer == value ) return; native.gameServer.SetDedicatedServer( value ); _dedicatedServer = value; }
}
private bool _dedicatedServer;
/// <summary>
/// Gets or sets the current MaxPlayers.
/// This doesn't enforce any kind of limit, it just updates the master server.
/// </summary>
public int MaxPlayers
{
get { return _maxplayers; }
set { if ( _maxplayers == value ) return; native.gameServer.SetMaxPlayerCount( value ); _maxplayers = value; }
}
private int _maxplayers = 0;
/// <summary>
/// Gets or sets the current BotCount.
/// This doesn't enforce any kind of limit, it just updates the master server.
/// </summary>
public int BotCount
{
get { return _botcount; }
set { if ( _botcount == value ) return; native.gameServer.SetBotPlayerCount( value ); _botcount = value; }
}
private int _botcount = 0;
/// <summary>
/// Gets or sets the current Map Name.
/// </summary>
public string MapName
{
get { return _mapname; }
set { if ( _mapname == value ) return; native.gameServer.SetMapName( value ); _mapname = value; }
}
private string _mapname;
/// <summary>
/// Gets or sets the current ModDir
/// </summary>
public string ModDir
{
get { return _modDir; }
internal set { if ( _modDir == value ) return; native.gameServer.SetModDir( value ); _modDir = value; }
}
private string _modDir = "";
/// <summary>
/// Gets the current product
/// </summary>
public string Product
{
get { return _product; }
internal set { if ( _product == value ) return; native.gameServer.SetProduct( value ); _product = value; }
}
private string _product = "";
/// <summary>
/// Gets or sets the current Product
/// </summary>
public string GameDescription
{
get { return _gameDescription; }
internal set { if ( _gameDescription == value ) return; native.gameServer.SetGameDescription( value ); _gameDescription = value; }
}
private string _gameDescription = "";
/// <summary>
/// Gets or sets the current ServerName
/// </summary>
public string ServerName
{
get { return _serverName; }
set { if ( _serverName == value ) return; native.gameServer.SetServerName( value ); _serverName = value; }
}
private string _serverName = "";
/// <summary>
/// Set whether the server should report itself as passworded
/// </summary>
public bool Passworded
{
get { return _passworded; }
set { if ( _passworded == value ) return; native.gameServer.SetPasswordProtected( value ); _passworded = value; }
}
private bool _passworded;
/// <summary>
/// Gets or sets the current GameTags. This is a comma seperated list of tags for this server.
/// When querying the server list you can filter by these tags.
/// </summary>
public string GameTags
{
get { return _gametags; }
set { if ( _gametags == value ) return; native.gameServer.SetGameTags( value ); _gametags = value; }
}
private string _gametags = "";
/// <summary>
/// Log onto Steam anonymously.
/// </summary>
public void LogOnAnonymous()
{
native.gameServer.LogOnAnonymous();
ForceHeartbeat();
}
/// <summary>
/// Returns true if the server is connected and registered with the Steam master server
/// You should have called LogOnAnonymous etc on startup.
/// </summary>
public bool LoggedOn => native.gameServer.BLoggedOn();
Dictionary<string, string> KeyValue = new Dictionary<string, string>();
/// <summary>
/// Sets a Key Value. These can be anything you like, and are accessible
/// when querying servers from the server list.
///
/// Information describing gamemodes are common here.
/// </summary>
public void SetKey( string Key, string Value )
{
if ( KeyValue.ContainsKey( Key ) )
{
if ( KeyValue[Key] == Value )
return;
KeyValue[Key] = Value;
}
else
{
KeyValue.Add( Key, Value );
}
native.gameServer.SetKeyValue( Key, Value );
}
/// <summary>
/// Update this connected player's information. You should really call this
/// any time a player's name or score changes. This keeps the information shown
/// to server queries up to date.
/// </summary>
public void UpdatePlayer( ulong steamid, string name, int score )
{
native.gameServer.BUpdateUserData( steamid, name, (uint) score );
}
/// <summary>
/// Shutdown interface, disconnect from Steam
/// </summary>
public override void Dispose()
{
if ( disposed ) return;
if ( Query != null )
{
Query = null;
}
if ( Stats != null )
{
Stats = null;
}
if ( Auth != null )
{
Auth = null;
}
if ( Instance == this )
{
Instance = null;
}
base.Dispose();
}
/// <summary>
/// To the best of its ability this tries to get the server's
/// current public ip address. Be aware that this is likely to return
/// null for the first few seconds after initialization.
/// </summary>
public System.Net.IPAddress PublicIp
{
get
{
var ip = native.gameServer.GetPublicIP();
if ( ip == 0 ) return null;
return Utility.Int32ToIp( ip );
}
}
/// <summary>
/// Enable or disable heartbeats, which are sent regularly to the master server.
/// Enabled by default.
/// </summary>
public bool AutomaticHeartbeats
{
set { native.gameServer.EnableHeartbeats( value ); }
}
/// <summary>
/// Set heartbeat interval, if automatic heartbeats are enabled.
/// You can leave this at the default.
/// </summary>
public int AutomaticHeartbeatRate
{
set { native.gameServer.SetHeartbeatInterval( value ); }
}
/// <summary>
/// Force send a heartbeat to the master server instead of waiting
/// for the next automatic update (if you've left them enabled)
/// </summary>
public void ForceHeartbeat()
{
native.gameServer.ForceHeartbeat();
}
}
}

View File

@ -1,73 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Facepunch.Steamworks
{
public class ServerAuth
{
internal Server server;
/// <summary>
/// Steamid, Ownerid, Status
/// </summary>
public Action<ulong, ulong, Status> OnAuthChange;
/// <summary>
/// Steam authetication statuses
/// </summary>
public enum Status : int
{
OK = 0,
UserNotConnectedToSteam = 1,
NoLicenseOrExpired = 2,
VACBanned = 3,
LoggedInElseWhere = 4,
VACCheckTimedOut = 5,
AuthTicketCanceled = 6,
AuthTicketInvalidAlreadyUsed = 7,
AuthTicketInvalid = 8,
PublisherIssuedBan = 9,
}
internal ServerAuth( Server s )
{
server = s;
server.RegisterCallback<SteamNative.ValidateAuthTicketResponse_t>( OnAuthTicketValidate );
}
void OnAuthTicketValidate( SteamNative.ValidateAuthTicketResponse_t data )
{
if ( OnAuthChange != null )
OnAuthChange( data.SteamID, data.OwnerSteamID, (Status) data.AuthSessionResponse );
}
/// <summary>
/// Start authorizing a ticket. This user isn't authorized yet. Wait for a call to OnAuthChange.
/// </summary>
public unsafe bool StartSession( byte[] data, ulong steamid )
{
fixed ( byte* p = data )
{
var result = server.native.gameServer.BeginAuthSession( (IntPtr)p, data.Length, steamid );
if ( result == SteamNative.BeginAuthSessionResult.OK )
return true;
return false;
}
}
/// <summary>
/// Forget this guy. They're no longer in the game.
/// </summary>
public void EndSession( ulong steamid )
{
server.native.gameServer.EndAuthSession( steamid );
}
}
}

View File

@ -1,88 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace Facepunch.Steamworks
{
/// <summary>
/// If you're manually processing the server queries, you should use this class.
/// </summary>
public class ServerQuery
{
internal Server server;
internal static byte[] buffer = new byte[64*1024];
internal ServerQuery( Server s )
{
server = s;
}
/// <summary>
/// A server query packet.
/// </summary>
public struct Packet
{
/// <summary>
/// Target IP address
/// </summary>
public uint Address { get; internal set; }
/// <summary>
/// Target port
/// </summary>
public ushort Port { get; internal set; }
/// <summary>
/// This data is pooled. Make a copy if you don't use it immediately.
/// This buffer is also quite large - so pay attention to Size.
/// </summary>
public byte[] Data { get; internal set; }
/// <summary>
/// Size of the data
/// </summary>
public int Size { get; internal set; }
}
/// <summary>
/// If true, Steam wants to send a packet. You should respond by sending
/// this packet in an unconnected way to the returned Address and Port.
/// </summary>
/// <param name="packet">Packet to send. The Data passed is pooled - so use it immediately.</param>
/// <returns>True if we want to send a packet</returns>
public unsafe bool GetOutgoingPacket( out Packet packet )
{
packet = new Packet();
fixed ( byte* ptr = buffer )
{
uint addr = 0;
ushort port = 0;
var size = server.native.gameServer.GetNextOutgoingPacket( (IntPtr)ptr, buffer.Length, out addr, out port );
if ( size == 0 )
return false;
packet.Size = size;
packet.Data = buffer;
packet.Address = addr;
packet.Port = port;
return true;
}
}
/// <summary>
/// We have received a server query on our game port. Pass it to Steam to handle.
/// </summary>
public unsafe void Handle( byte[] data, int size, uint address, ushort port )
{
fixed ( byte* ptr = data )
{
server.native.gameServer.HandleIncomingPacket( (IntPtr)ptr, size, address, port );
}
}
}
}

View File

@ -4,6 +4,7 @@ using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
#if false
namespace Facepunch.Steamworks
{
/// <summary>
@ -144,3 +145,4 @@ namespace Facepunch.Steamworks
}
}
}
#endif

View File

@ -326,9 +326,6 @@ namespace SteamNative
if ( Facepunch.Steamworks.Client.Instance != null )
Facepunch.Steamworks.Client.Instance.OnCallback<T>( value );
if ( Facepunch.Steamworks.Server.Instance != null )
Facepunch.Steamworks.Server.Instance.OnCallback<T>( value );
}
}

View File

@ -16,14 +16,25 @@ namespace Steamworks.Internal
public virtual string InterfaceName => null;
public BaseSteamInterface()
public BaseSteamInterface( bool server = false )
{
if ( Steamworks.Steam.HUser == 0 )
var hUser = server ? SteamApi.SteamGameServer_GetHSteamUser() : SteamApi.GetHSteamUser();
if ( hUser == 0 )
throw new System.Exception( "Steamworks is uninitialized" );
Self = SteamInternal.FindOrCreateUserInterface( Steamworks.Steam.HUser, InterfaceName );
if ( server )
{
Self = SteamInternal.FindOrCreateUserInterface( hUser, InterfaceName );
}
else
{
Self = SteamInternal.FindOrCreateUserInterface( hUser, InterfaceName );
}
if ( Self == IntPtr.Zero )
throw new System.Exception( $"Couldn't find interface {InterfaceName}" );
throw new System.Exception( $"Couldn't find interface {InterfaceName} (server:{server})" );
VTable = Marshal.ReadIntPtr( Self, 0 );
if ( Self == IntPtr.Zero )

View File

@ -27,6 +27,12 @@ namespace Generator
{
StartBlock( $"public class {clss.Name} : BaseSteamInterface" );
{
StartBlock( $"public {clss.Name}( bool server = false ) : base( server )" );
{
}
EndBlock();
WriteLine();
WriteLine( $"public override string InterfaceName => \"{clss.InterfaceString}\";" );
WriteLine();

View File

@ -100,6 +100,7 @@ namespace Generator
GenerateVTableClass( "ISteamUser", $"{folder}../Generated/Interfaces/ISteamUser.cs" );
GenerateVTableClass( "ISteamMatchmakingServers", $"{folder}../Generated/Interfaces/ISteamMatchmakingServers.cs" );
GenerateVTableClass( "ISteamFriends", $"{folder}../Generated/Interfaces/ISteamFriends.cs" );
GenerateVTableClass( "ISteamGameServer", $"{folder}../Generated/Interfaces/ISteamGameServer.cs" );
}
}

View File

@ -40,7 +40,7 @@ internal class BaseType
return new BaseType { NativeType = type, VarName = varname };
}
public virtual string AsArgument() => IsVector? $"[In,Out] {Ref}{TypeName.Trim( '*', ' ' )}[] {VarName}" : $"{Ref}{TypeName.Trim( '*', ' ' )} {VarName}";
public virtual string AsArgument() => IsVector ? $"[In,Out] {Ref}{TypeName.Trim( '*', ' ' )}[] {VarName}" : $"{Ref}{TypeName.Trim( '*', ' ' )} {VarName}";
public virtual string AsCallArgument() => $"{Ref}{VarName}";
public virtual string Return( string varname ) => $"return {varname};";
@ -49,9 +49,26 @@ internal class BaseType
public virtual string ReturnType => TypeName;
public virtual string Ref => !IsVector && NativeType.EndsWith( "*" ) || NativeType.EndsWith( "**" ) ? "ref " : "";
public virtual bool IsVector => (NativeType.EndsWith( "*" ) && (VarName.StartsWith( "pvec" ) || VarName.StartsWith( "pub" ) || VarName.StartsWith( "pOut" )))
|| NativeType.EndsWith( "**" )
|| VarName == "psteamIDClans";
public virtual bool IsVector
{
get
{
if ( VarName == "pOut" ) return false;
if ( VarName == "psteamIDClans" ) return true;
if ( NativeType.EndsWith( "**" ) ) return true;
if ( NativeType.EndsWith( "*" ) )
{
if ( VarName.StartsWith( "pvec" ) ) return true;
if ( VarName.StartsWith( "pub" ) ) return true;
if ( VarName.StartsWith( "pOut" ) ) return true;
}
return false;
}
}
public virtual bool IsVoid => false;
public virtual bool IsReturnedWeird => false;