mirror of
https://github.com/Facepunch/Facepunch.Steamworks.git
synced 2025-02-04 17:50:43 +03:00
LobbyQuery, Lobby Joining, Lobby Creating
This commit is contained in:
parent
5a68e15676
commit
e3840a9a3a
@ -38,6 +38,7 @@
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@ -62,7 +63,7 @@
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
@ -71,7 +72,7 @@
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
@ -90,6 +91,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="FriendsTest.cs" />
|
||||
<Compile Include="SteamMatchmakingTest.cs" />
|
||||
<Compile Include="RemoteStorageTest.cs" />
|
||||
<Compile Include="InventoryTest.cs" />
|
||||
<Compile Include="SteamNetworkingTest.cs" />
|
||||
|
73
Facepunch.Steamworks.Test/SteamMatchmakingTest.cs
Normal file
73
Facepunch.Steamworks.Test/SteamMatchmakingTest.cs
Normal file
@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Steamworks.Data;
|
||||
|
||||
namespace Steamworks
|
||||
{
|
||||
[TestClass]
|
||||
[DeploymentItem( "steam_api64.dll" )]
|
||||
public class SteamMatchmakingTest
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task LobbyList()
|
||||
{
|
||||
await CreateLobby();
|
||||
|
||||
var list = await SteamMatchmaking.LobbyList
|
||||
.RequestAsync();
|
||||
|
||||
if ( list == null )
|
||||
{
|
||||
Console.WriteLine( "No Lobbies Found!" );
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( var lobby in list )
|
||||
{
|
||||
Console.WriteLine( $"[{lobby.Id}] owned by {lobby.Owner} ({lobby.MemberCount}/{lobby.MaxMembers})" );
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task LobbyListWithAtLeastOne()
|
||||
{
|
||||
await CreateLobby();
|
||||
await LobbyList();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task CreateLobby()
|
||||
{
|
||||
var lobbyr = await SteamMatchmaking.CreateLobbyAsync( 32 );
|
||||
if ( !lobbyr.HasValue )
|
||||
{
|
||||
Console.WriteLine( "No lobby created!" );
|
||||
return;
|
||||
}
|
||||
|
||||
var lobby = lobbyr.Value;
|
||||
lobby.SetPublic();
|
||||
lobby.SetData( "gametype", "sausage" );
|
||||
lobby.SetData( "dicks", "unlicked" );
|
||||
|
||||
Console.WriteLine( $"lobby: {lobby.Id}" );
|
||||
|
||||
foreach ( var entry in lobby.Data )
|
||||
{
|
||||
Console.WriteLine( $" - {entry.Key} {entry.Value}" );
|
||||
}
|
||||
|
||||
Console.WriteLine( $"members: {lobby.MemberCount}/{lobby.MaxMembers}" );
|
||||
|
||||
Console.WriteLine( $"Owner: {lobby.Owner}" );
|
||||
Console.WriteLine( $"Owner Is Local Player: {lobby.Owner.IsMe}" );
|
||||
|
||||
lobby.SendChatString( "Hello I Love Lobbies" );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -338,7 +338,7 @@ namespace Steamworks
|
||||
//
|
||||
// EChatRoomEnterResponse
|
||||
//
|
||||
internal enum ChatRoomEnterResponse : int
|
||||
public enum RoomEnter : int
|
||||
{
|
||||
Success = 1,
|
||||
DoesntExist = 2,
|
||||
|
@ -1429,7 +1429,7 @@ namespace Steamworks.Data
|
||||
internal struct JoinClanChatRoomCompletionResult_t
|
||||
{
|
||||
internal ulong SteamIDClanChat; // m_steamIDClanChat class CSteamID
|
||||
internal ChatRoomEnterResponse ChatRoomEnterResponse; // m_eChatRoomEnterResponse enum EChatRoomEnterResponse
|
||||
internal RoomEnter ChatRoomEnterResponse; // m_eChatRoomEnterResponse enum EChatRoomEnterResponse
|
||||
|
||||
#region SteamCallback
|
||||
internal static readonly int StructSize = System.Runtime.InteropServices.Marshal.SizeOf( typeof(JoinClanChatRoomCompletionResult_t) );
|
||||
|
@ -35,5 +35,18 @@ namespace Steamworks
|
||||
//VolumeHasChanged_t.Install( x => OnVolumeChanged?.Invoke( x.NewVolume ) );
|
||||
}
|
||||
|
||||
public static LobbyQuery LobbyList => new LobbyQuery();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new invisible lobby. Call lobby.SetPublic to take it online.
|
||||
/// </summary>
|
||||
public static async Task<Lobby?> CreateLobbyAsync( int maxMembers = 100 )
|
||||
{
|
||||
var lobby = await Internal.CreateLobby( LobbyType.Invisible, maxMembers );
|
||||
if ( !lobby.HasValue || lobby.Value.Result != Result.OK ) return null;
|
||||
|
||||
return new Lobby { Id = lobby.Value.SteamIDLobby };
|
||||
}
|
||||
|
||||
}
|
||||
}
|
206
Facepunch.Steamworks/Structs/Lobby.cs
Normal file
206
Facepunch.Steamworks/Structs/Lobby.cs
Normal file
@ -0,0 +1,206 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Steamworks.Data
|
||||
{
|
||||
public struct Lobby
|
||||
{
|
||||
public SteamId Id { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Try to join this room. Will return RoomEnter.Success on success,
|
||||
/// and anything else is a failure
|
||||
/// </summary>
|
||||
public async Task<RoomEnter> Join()
|
||||
{
|
||||
var result = await SteamMatchmaking.Internal.JoinLobby( Id );
|
||||
if ( !result.HasValue ) return RoomEnter.Error;
|
||||
|
||||
return (RoomEnter) result.Value.EChatRoomEnterResponse;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Leave a lobby; this will take effect immediately on the client side
|
||||
/// other users in the lobby will be notified by a LobbyChatUpdate_t callback
|
||||
/// </summary>
|
||||
public void Leave()
|
||||
{
|
||||
SteamMatchmaking.Internal.LeaveLobby( Id );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invite another user to the lobby
|
||||
/// will return true if the invite is successfully sent, whether or not the target responds
|
||||
/// returns false if the local user is not connected to the Steam servers
|
||||
/// </summary>
|
||||
public bool InviteFriend( SteamId steamid )
|
||||
{
|
||||
return SteamMatchmaking.Internal.InviteUserToLobby( Id, steamid );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// returns the number of users in the specified lobby
|
||||
/// </summary>
|
||||
public int MemberCount => SteamMatchmaking.Internal.GetNumLobbyMembers( Id );
|
||||
|
||||
/// <summary>
|
||||
/// Returns current members. Need to be in the lobby to see the users.
|
||||
/// </summary>
|
||||
public IEnumerable<Friend> Members
|
||||
{
|
||||
get
|
||||
{
|
||||
for( int i = 0; i < MemberCount; i++ )
|
||||
{
|
||||
yield return new Friend( SteamMatchmaking.Internal.GetLobbyMemberByIndex( Id, i ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get data associated with this lobby
|
||||
/// </summary>
|
||||
public string GetData( string key )
|
||||
{
|
||||
return SteamMatchmaking.Internal.GetLobbyData( Id, key );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get data associated with this lobby
|
||||
/// </summary>
|
||||
public bool SetData( string key, string value )
|
||||
{
|
||||
if ( key.Length > 255 ) throw new System.ArgumentException( "Key should be < 255 chars", nameof( key ) );
|
||||
if ( value.Length > 8192 ) throw new System.ArgumentException( "Value should be < 8192 chars", nameof( key ) );
|
||||
|
||||
return SteamMatchmaking.Internal.SetLobbyData( Id, key, value );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a metadata key from the lobby
|
||||
/// </summary>
|
||||
public bool DeleteData( string key )
|
||||
{
|
||||
return SteamMatchmaking.Internal.DeleteLobbyData( Id, key );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all data for this lobby
|
||||
/// </summary>
|
||||
public IEnumerable<KeyValuePair<string, string>> Data
|
||||
{
|
||||
get
|
||||
{
|
||||
var cnt = SteamMatchmaking.Internal.GetLobbyDataCount( Id );
|
||||
|
||||
var a = Helpers.TakeStringBuilder();
|
||||
var b = Helpers.TakeStringBuilder();
|
||||
|
||||
for ( int i =0; i<cnt; i++)
|
||||
{
|
||||
if ( SteamMatchmaking.Internal.GetLobbyDataByIndex( Id, i, a, a.Capacity, b, b.Capacity ) )
|
||||
{
|
||||
yield return new KeyValuePair<string, string>( a.ToString(), b.ToString() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets per-user metadata for someone in this lobby
|
||||
/// </summary>
|
||||
public string GetMemberData( Friend member, string key )
|
||||
{
|
||||
return SteamMatchmaking.Internal.GetLobbyMemberData( Id, member.Id, key );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets per-user metadata (for the local user implicitly)
|
||||
/// </summary>
|
||||
public void SetMemberData( Friend member, string key, string value )
|
||||
{
|
||||
SteamMatchmaking.Internal.SetLobbyMemberData( Id, key, value );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a string to the chat room
|
||||
/// </summary>
|
||||
public bool SendChatString( string message )
|
||||
{
|
||||
var data = System.Text.Encoding.UTF8.GetBytes( message );
|
||||
return SendChatBytes( data );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends bytes the the chat room
|
||||
/// </summary>
|
||||
public unsafe bool SendChatBytes( byte[] data )
|
||||
{
|
||||
fixed ( byte* ptr = data )
|
||||
{
|
||||
return SteamMatchmaking.Internal.SendLobbyChatMsg( Id, (IntPtr)ptr, data.Length );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes metadata for a lobby you're not necessarily in right now
|
||||
/// you never do this for lobbies you're a member of, only if your
|
||||
/// this will send down all the metadata associated with a lobby
|
||||
/// this is an asynchronous call
|
||||
/// returns false if the local user is not connected to the Steam servers
|
||||
/// results will be returned by a LobbyDataUpdate_t callback
|
||||
/// if the specified lobby doesn't exist, LobbyDataUpdate_t::m_bSuccess will be set to false
|
||||
/// </summary>
|
||||
public bool Refresh()
|
||||
{
|
||||
return SteamMatchmaking.Internal.RequestLobbyData( Id );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Max members able to join this lobby. Cannot be over 250.
|
||||
/// Can only be set by the owner
|
||||
/// </summary>
|
||||
public int MaxMembers
|
||||
{
|
||||
get => SteamMatchmaking.Internal.GetLobbyMemberLimit( Id );
|
||||
set => SteamMatchmaking.Internal.SetLobbyMemberLimit( Id, value );
|
||||
}
|
||||
|
||||
public bool SetPublic()
|
||||
{
|
||||
return SteamMatchmaking.Internal.SetLobbyType( Id, LobbyType.Public );
|
||||
}
|
||||
|
||||
public bool SetPrivate()
|
||||
{
|
||||
return SteamMatchmaking.Internal.SetLobbyType( Id, LobbyType.Private );
|
||||
}
|
||||
|
||||
public bool SetInvisible()
|
||||
{
|
||||
return SteamMatchmaking.Internal.SetLobbyType( Id, LobbyType.Invisible );
|
||||
}
|
||||
|
||||
public bool SetFriendsOnly()
|
||||
{
|
||||
return SteamMatchmaking.Internal.SetLobbyType( Id, LobbyType.FriendsOnly );
|
||||
}
|
||||
|
||||
public bool SetJoinable( bool b )
|
||||
{
|
||||
return SteamMatchmaking.Internal.SetLobbyJoinable( Id, b );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// You must be the lobby owner to set the owner
|
||||
/// </summary>
|
||||
public Friend Owner
|
||||
{
|
||||
get => new Friend( SteamMatchmaking.Internal.GetLobbyOwner( Id ) );
|
||||
set => SteamMatchmaking.Internal.SetLobbyOwner( Id, value.Id );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
116
Facepunch.Steamworks/Structs/LobbyQuery.cs
Normal file
116
Facepunch.Steamworks/Structs/LobbyQuery.cs
Normal file
@ -0,0 +1,116 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Steamworks.Data
|
||||
{
|
||||
public struct LobbyQuery
|
||||
{
|
||||
// TODO FILTERS
|
||||
// AddRequestLobbyListStringFilter
|
||||
// - WithKeyValue, WithoutKeyValue
|
||||
// AddRequestLobbyListNumericalFilter
|
||||
// - WithLower, WithHigher, WithEqual, WithNotEqual
|
||||
// AddRequestLobbyListNearValueFilter
|
||||
// - OrderByNear
|
||||
|
||||
#region Distance Filter
|
||||
internal LobbyDistanceFilter? distance;
|
||||
|
||||
/// <summary>
|
||||
/// only lobbies in the same immediate region will be returned
|
||||
/// </summary>
|
||||
public LobbyQuery FilterDistanceClose()
|
||||
{
|
||||
distance = LobbyDistanceFilter.Close;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// only lobbies in the same immediate region will be returned
|
||||
/// </summary>
|
||||
public LobbyQuery FilterDistanceFar()
|
||||
{
|
||||
distance = LobbyDistanceFilter.Far;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// only lobbies in the same immediate region will be returned
|
||||
/// </summary>
|
||||
public LobbyQuery FilterDistanceWorldwide()
|
||||
{
|
||||
distance = LobbyDistanceFilter.Worldwide;
|
||||
return this;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Slots Filter
|
||||
internal int? slotsAvailable;
|
||||
|
||||
/// <summary>
|
||||
/// returns only lobbies with the specified number of slots available
|
||||
/// </summary>
|
||||
public LobbyQuery WithSlotsAvailable( int minSlots )
|
||||
{
|
||||
slotsAvailable = minSlots;
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Max results filter
|
||||
internal int? maxResults;
|
||||
|
||||
/// <summary>
|
||||
/// sets how many results to return, the lower the count the faster it is to download the lobby results
|
||||
/// </summary>
|
||||
public LobbyQuery WithMaxResults( int max )
|
||||
{
|
||||
maxResults = max;
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
void ApplyFilters()
|
||||
{
|
||||
if ( distance.HasValue )
|
||||
{
|
||||
SteamMatchmaking.Internal.AddRequestLobbyListDistanceFilter( distance.Value );
|
||||
}
|
||||
|
||||
if ( slotsAvailable.HasValue )
|
||||
{
|
||||
SteamMatchmaking.Internal.AddRequestLobbyListFilterSlotsAvailable( slotsAvailable.Value );
|
||||
}
|
||||
|
||||
if ( maxResults.HasValue )
|
||||
{
|
||||
SteamMatchmaking.Internal.AddRequestLobbyListResultCountFilter( maxResults.Value );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the query, get the matching lobbies
|
||||
/// </summary>
|
||||
public async Task<Lobby[]> RequestAsync()
|
||||
{
|
||||
ApplyFilters();
|
||||
|
||||
LobbyMatchList_t? list = await SteamMatchmaking.Internal.RequestLobbyList();
|
||||
if ( !list.HasValue || list.Value.LobbiesMatching == 0 )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Lobby[] lobbies = new Lobby[list.Value.LobbiesMatching];
|
||||
|
||||
for ( int i = 0; i < list.Value.LobbiesMatching; i++ )
|
||||
{
|
||||
lobbies[i] = new Lobby { Id = SteamMatchmaking.Internal.GetLobbyByIndex( i ) };
|
||||
}
|
||||
|
||||
return lobbies;
|
||||
}
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ public static class Cleanup
|
||||
type = type.Replace( "UGCMatchingUGCType", "UgcType" );
|
||||
type = type.Replace( "SteamItemInstanceID_t", "InventoryItemId" );
|
||||
type = type.Replace( "SteamItemDef_t", "InventoryDefId" );
|
||||
type = type.Replace( "ChatRoomEnterResponse", "RoomEnter" );
|
||||
|
||||
return type;
|
||||
}
|
||||
@ -59,6 +60,7 @@ public static class Cleanup
|
||||
if ( name == "InventoryItemId" ) return "public";
|
||||
if ( name == "InventoryDefId" ) return "public";
|
||||
if ( name == "P2PSend" ) return "public";
|
||||
if ( name == "RoomEnter" ) return "public";
|
||||
|
||||
return "internal";
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user