using System; using System.Collections.Generic; using Steamworks; using UnityEngine; namespace MegaKoop.Game.Networking { /// /// High level orchestrator for Steam lobby + P2P messaging. Keeps track of handlers per message type. /// [DisallowMultipleComponent] public class SteamCoopNetworkManager : MonoBehaviour { public static SteamCoopNetworkManager Instance { get; private set; } [SerializeField] private SteamLobbyManager lobbyManager; [SerializeField] private SteamP2PTransport p2pTransport; private readonly Dictionary> handlers = new(); private bool isHost; private bool isConnected; public bool IsHost => isHost; public bool IsConnected => isConnected; public CSteamID ActiveLobby => lobbyManager != null ? lobbyManager.GetActiveLobby() : CSteamID.Nil; private void Awake() { if (Instance != null) { Destroy(gameObject); return; } Instance = this; DontDestroyOnLoad(gameObject); if (lobbyManager == null) { lobbyManager = GetComponentInChildren(); } if (p2pTransport == null) { p2pTransport = GetComponentInChildren(); } if (lobbyManager != null) { lobbyManager.LobbyCreated += HandleLobbyCreated; lobbyManager.LobbyJoined += HandleLobbyJoined; lobbyManager.LobbyMemberJoined += HandleLobbyMemberJoined; lobbyManager.LobbyMemberLeft += HandleLobbyMemberLeft; } if (p2pTransport != null) { p2pTransport.MessageReceived += DispatchMessage; } } private void OnDestroy() { if (Instance == this) { Instance = null; } if (lobbyManager != null) { lobbyManager.LobbyCreated -= HandleLobbyCreated; lobbyManager.LobbyJoined -= HandleLobbyJoined; lobbyManager.LobbyMemberJoined -= HandleLobbyMemberJoined; lobbyManager.LobbyMemberLeft -= HandleLobbyMemberLeft; } if (p2pTransport != null) { p2pTransport.MessageReceived -= DispatchMessage; } } public void RegisterHandler(NetworkMessageType type, Action handler) { if (handlers.TryGetValue(type, out Action existing)) { existing += handler; handlers[type] = existing; } else { handlers[type] = handler; } } public void UnregisterHandler(NetworkMessageType type, Action handler) { if (!handlers.TryGetValue(type, out Action existing)) { return; } existing -= handler; if (existing == null) { handlers.Remove(type); } else { handlers[type] = existing; } } public void SendToAll(NetworkMessageType type, byte[] payload, EP2PSend sendType = EP2PSend.k_EP2PSendReliable) { p2pTransport?.Broadcast(type, payload, sendType); } public void SendToPlayer(CSteamID target, NetworkMessageType type, byte[] payload, EP2PSend sendType = EP2PSend.k_EP2PSendReliable) { p2pTransport?.Send(target, type, payload, sendType); } public void SynchronizeWithLobby(MegaKoop.Steam.SteamLobbyService steamService) { if (steamService == null) { return; } isConnected = steamService.IsInLobby; isHost = steamService.IsHost; #if STEAMWORKSNET if (p2pTransport != null) { if (steamService.IsInLobby) { CSteamID lobbyId = steamService.LobbyId; if (lobbyId != CSteamID.Nil) { p2pTransport.SetActiveLobby(lobbyId); } else if (ulong.TryParse(steamService.LobbyIdString, out ulong lobbyValue) && lobbyValue != 0) { p2pTransport.SetActiveLobby(new CSteamID(lobbyValue)); } } else { p2pTransport.SetActiveLobby(CSteamID.Nil); } } #endif } private void DispatchMessage(NetworkMessage message) { if (handlers.TryGetValue(message.Type, out Action handler)) { handler?.Invoke(message); } } private void HandleLobbyCreated(CSteamID lobbyId) { isHost = true; isConnected = true; p2pTransport?.SetActiveLobby(lobbyId); } private void HandleLobbyJoined(CSteamID lobbyId) { isConnected = true; p2pTransport?.SetActiveLobby(lobbyId); string ownerId = SteamMatchmaking.GetLobbyData(lobbyId, "owner"); if (!string.IsNullOrEmpty(ownerId) && ulong.TryParse(ownerId, out ulong ownerSteamId)) { isHost = ownerSteamId == SteamUser.GetSteamID().m_SteamID; } else { isHost = SteamMatchmaking.GetLobbyOwner(lobbyId) == SteamUser.GetSteamID(); } } private void HandleLobbyMemberJoined(CSteamID member) { Debug.Log("[SteamCoopNetworkManager] Member joined: " + member); } private void HandleLobbyMemberLeft(CSteamID member) { Debug.Log("[SteamCoopNetworkManager] Member left: " + member); } } }