using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using Steamworks.Data; namespace Steamworks { /// /// Methods for clients to access matchmaking services, favorites, and to operate on game lobbies /// public class SteamMatchmaking : SteamClientClass { internal static ISteamMatchmaking? Internal => Interface as ISteamMatchmaking; internal override bool InitializeInterface( bool server ) { SetInterface( server, new ISteamMatchmaking( server ) ); if ( Interface is null || Interface.Self == IntPtr.Zero ) return false; InstallEvents(); return true; } /// /// Maximum number of characters a lobby metadata key can be /// internal static int MaxLobbyKeyLength => 255; internal static void InstallEvents() { Dispatch.Install( x => OnLobbyInvite?.Invoke( new Friend( x.SteamIDUser ), new Lobby( x.SteamIDLobby ) ) ); Dispatch.Install( x => OnLobbyEntered?.Invoke( new Lobby( x.SteamIDLobby ) ) ); Dispatch.Install( x => OnLobbyCreated?.Invoke( x.Result, new Lobby( x.SteamIDLobby ) ) ); Dispatch.Install( x => OnLobbyGameCreated?.Invoke( new Lobby( x.SteamIDLobby ), x.IP, x.Port, x.SteamIDGameServer ) ); Dispatch.Install( x => { if ( x.Success == 0 ) return; if ( x.SteamIDLobby == x.SteamIDMember ) OnLobbyDataChanged?.Invoke( new Lobby( x.SteamIDLobby ) ); else OnLobbyMemberDataChanged?.Invoke( new Lobby( x.SteamIDLobby ), new Friend( x.SteamIDMember ) ); } ); Dispatch.Install( x => { if ( (x.GfChatMemberStateChange & (int)ChatMemberStateChange.Entered) != 0 ) OnLobbyMemberJoined?.Invoke( new Lobby( x.SteamIDLobby ), new Friend( x.SteamIDUserChanged ) ); if ( (x.GfChatMemberStateChange & (int)ChatMemberStateChange.Left) != 0 ) OnLobbyMemberLeave?.Invoke( new Lobby( x.SteamIDLobby ), new Friend( x.SteamIDUserChanged ) ); if ( (x.GfChatMemberStateChange & (int)ChatMemberStateChange.Disconnected) != 0 ) OnLobbyMemberDisconnected?.Invoke( new Lobby( x.SteamIDLobby ), new Friend( x.SteamIDUserChanged ) ); if ( (x.GfChatMemberStateChange & (int)ChatMemberStateChange.Kicked) != 0 ) OnLobbyMemberKicked?.Invoke( new Lobby( x.SteamIDLobby ), new Friend( x.SteamIDUserChanged ), new Friend( x.SteamIDMakingChange ) ); if ( (x.GfChatMemberStateChange & (int)ChatMemberStateChange.Banned) != 0 ) OnLobbyMemberBanned?.Invoke( new Lobby( x.SteamIDLobby ), new Friend( x.SteamIDUserChanged ), new Friend( x.SteamIDMakingChange ) ); } ); Dispatch.Install( OnLobbyChatMessageRecievedAPI ); } static private unsafe void OnLobbyChatMessageRecievedAPI( LobbyChatMsg_t callback ) { if (Internal is null) { return; } SteamId steamid = default; ChatEntryType chatEntryType = default; using var buffer = Helpers.TakeMemory(); var readData = Internal.GetLobbyChatEntry( callback.SteamIDLobby, (int)callback.ChatID, ref steamid, buffer, Helpers.MemoryBufferSize, ref chatEntryType ); if ( readData > 0 ) { OnChatMessage?.Invoke( new Lobby( callback.SteamIDLobby ), new Friend( steamid ), Helpers.MemoryToString( buffer ) ); } } public static void ResetActions() { OnLobbyInvite = null; OnLobbyEntered = null; OnLobbyCreated = null; OnLobbyGameCreated = null; OnLobbyDataChanged = null; OnLobbyMemberDataChanged = null; OnLobbyMemberJoined = null; OnLobbyMemberLeave = null; OnLobbyMemberDisconnected = null; OnLobbyMemberKicked = null; OnLobbyMemberBanned = null; OnChatMessage = null; } /// /// Invoked when the current user is invited to a lobby. /// public static event Action? OnLobbyInvite; /// /// Invoked when the current user joins a lobby. /// public static event Action? OnLobbyEntered; /// /// Invoked when the current user creates a lobby. /// public static event Action? OnLobbyCreated; /// /// Invoked when a game server has been associated with a lobby. /// public static event Action? OnLobbyGameCreated; /// /// Invoked when a lobby's metadata is modified. /// public static event Action? OnLobbyDataChanged; /// /// Invoked when a member in a lobby's metadata is modified. /// public static event Action? OnLobbyMemberDataChanged; /// /// Invoked when a member joins a lobby. /// public static event Action? OnLobbyMemberJoined; /// /// Invoked when a lobby member leaves the lobby. /// public static event Action? OnLobbyMemberLeave; /// /// Invoked when a lobby member leaves the lobby. /// public static event Action? OnLobbyMemberDisconnected; /// /// Invoked when a lobby member is kicked from a lobby. The 3rd param is the user that kicked them. /// public static event Action? OnLobbyMemberKicked; /// /// Invoked when a lobby member is kicked from a lobby. The 3rd param is the user that kicked them. /// public static event Action? OnLobbyMemberBanned; /// /// Invoked when a chat message is received from a member of the lobby. /// public static event Action? OnChatMessage; public static LobbyQuery CreateLobbyQuery() { return new LobbyQuery(); } /// /// Creates a new invisible lobby. Call to take it online. /// public static async Task CreateLobbyAsync( int maxMembers = 100 ) { if (Internal is null) { return null; } var lobby = await Internal.CreateLobby( LobbyType.Invisible, maxMembers ); if ( !lobby.HasValue ) { return null; } return new Lobby { Id = lobby.Value.SteamIDLobby, Result = lobby.Value.Result }; } /// /// Attempts to directly join the specified lobby. /// public static async Task JoinLobbyAsync( SteamId lobbyId ) { if (Internal is null) { return null; } var lobby = await Internal.JoinLobby( lobbyId ); if ( !lobby.HasValue ) return null; return new Lobby { Id = lobby.Value.SteamIDLobby }; } /// /// Get a list of servers that are on the current user's favorites list. /// public static IEnumerable GetFavoriteServers() { if (Internal is null) { yield break; } var count = Internal.GetFavoriteGameCount(); for( int i=0; i /// Get a list of servers that the current user has added to their history. /// public static IEnumerable GetHistoryServers() { if (Internal is null) { yield break; } var count = Internal.GetFavoriteGameCount(); for ( int i = 0; i < count; i++ ) { uint timeplayed = 0; uint flags = 0; ushort qport = 0; ushort cport = 0; uint ip = 0; AppId appid = default; if ( Internal.GetFavoriteGame( i, ref appid, ref ip, ref cport, ref qport, ref flags, ref timeplayed ) ) { if ( (flags & ServerInfo.k_unFavoriteFlagHistory) == 0 ) continue; yield return new ServerInfo( ip, cport, qport, timeplayed ); } } } } }