Join and leave improvements
This commit is contained in:
@@ -17,13 +17,20 @@ namespace MegaKoop.Game.Networking
|
||||
[SerializeField] private SteamP2PTransport p2pTransport;
|
||||
|
||||
private readonly Dictionary<NetworkMessageType, Action<NetworkMessage>> handlers = new();
|
||||
private readonly HashSet<ulong> lobbyMembers = new();
|
||||
private readonly Dictionary<ulong, string> memberNames = new();
|
||||
private readonly List<OnScreenMessage> onScreenMessages = new();
|
||||
private bool isHost;
|
||||
private bool isConnected;
|
||||
private ulong lobbyOwnerSteamId;
|
||||
|
||||
public bool IsHost => isHost;
|
||||
public bool IsConnected => isConnected;
|
||||
public CSteamID ActiveLobby => lobbyManager != null ? lobbyManager.GetActiveLobby() : CSteamID.Nil;
|
||||
|
||||
public event Action HostClosed;
|
||||
public event Action<ulong> PlayerDisconnected;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null)
|
||||
@@ -131,6 +138,44 @@ namespace MegaKoop.Game.Networking
|
||||
isConnected = steamService.IsInLobby;
|
||||
isHost = steamService.IsHost;
|
||||
|
||||
if (steamService.IsInLobby)
|
||||
{
|
||||
lobbyMembers.Clear();
|
||||
memberNames.Clear();
|
||||
lobbyOwnerSteamId = 0;
|
||||
|
||||
var members = steamService.GetMembers();
|
||||
if (members != null)
|
||||
{
|
||||
foreach (var member in members)
|
||||
{
|
||||
if (!ulong.TryParse(member.steamId, out ulong steamId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
lobbyMembers.Add(steamId);
|
||||
memberNames[steamId] = string.IsNullOrWhiteSpace(member.name) ? steamId.ToString() : member.name;
|
||||
|
||||
if (member.isHost)
|
||||
{
|
||||
lobbyOwnerSteamId = steamId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lobbyOwnerSteamId == 0 && steamService.IsHost && SteamBootstrap.IsInitialized)
|
||||
{
|
||||
lobbyOwnerSteamId = SteamUser.GetSteamID().m_SteamID;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lobbyMembers.Clear();
|
||||
memberNames.Clear();
|
||||
lobbyOwnerSteamId = 0;
|
||||
}
|
||||
|
||||
#if STEAMWORKSNET
|
||||
if (p2pTransport != null)
|
||||
{
|
||||
@@ -167,6 +212,10 @@ namespace MegaKoop.Game.Networking
|
||||
isHost = true;
|
||||
isConnected = true;
|
||||
p2pTransport?.SetActiveLobby(lobbyId);
|
||||
lobbyOwnerSteamId = SteamUser.GetSteamID().m_SteamID;
|
||||
lobbyMembers.Clear();
|
||||
memberNames.Clear();
|
||||
RegisterMember(lobbyOwnerSteamId);
|
||||
}
|
||||
|
||||
private void HandleLobbyJoined(CSteamID lobbyId)
|
||||
@@ -177,22 +226,189 @@ namespace MegaKoop.Game.Networking
|
||||
string ownerId = SteamMatchmaking.GetLobbyData(lobbyId, "owner");
|
||||
if (!string.IsNullOrEmpty(ownerId) && ulong.TryParse(ownerId, out ulong ownerSteamId))
|
||||
{
|
||||
lobbyOwnerSteamId = ownerSteamId;
|
||||
isHost = ownerSteamId == SteamUser.GetSteamID().m_SteamID;
|
||||
}
|
||||
else
|
||||
{
|
||||
isHost = SteamMatchmaking.GetLobbyOwner(lobbyId) == SteamUser.GetSteamID();
|
||||
CSteamID owner = SteamMatchmaking.GetLobbyOwner(lobbyId);
|
||||
lobbyOwnerSteamId = owner.m_SteamID;
|
||||
isHost = owner == SteamUser.GetSteamID();
|
||||
}
|
||||
|
||||
RegisterExistingMembers(lobbyId);
|
||||
}
|
||||
|
||||
private void HandleLobbyMemberJoined(CSteamID member)
|
||||
{
|
||||
RegisterMember(member.m_SteamID);
|
||||
|
||||
if (ActiveLobby != CSteamID.Nil)
|
||||
{
|
||||
CSteamID owner = SteamMatchmaking.GetLobbyOwner(ActiveLobby);
|
||||
if (owner != CSteamID.Nil)
|
||||
{
|
||||
lobbyOwnerSteamId = owner.m_SteamID;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log("[SteamCoopNetworkManager] Member joined: " + member);
|
||||
}
|
||||
|
||||
private void HandleLobbyMemberLeft(CSteamID member)
|
||||
{
|
||||
Debug.Log("[SteamCoopNetworkManager] Member left: " + member);
|
||||
ulong steamId = member.m_SteamID;
|
||||
string displayName = ResolveMemberName(steamId);
|
||||
|
||||
bool hostLeft = lobbyOwnerSteamId != 0 && steamId == lobbyOwnerSteamId;
|
||||
lobbyMembers.Remove(steamId);
|
||||
memberNames.Remove(steamId);
|
||||
|
||||
if (hostLeft)
|
||||
{
|
||||
Debug.Log("[SteamCoopNetworkManager] Host left lobby: " + member);
|
||||
ShowOnScreenMessage("Host closed the game.", 6f);
|
||||
HostClosed?.Invoke();
|
||||
|
||||
if (!isHost)
|
||||
{
|
||||
ForceDisconnectFromLobby();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("[SteamCoopNetworkManager] Member left: " + member);
|
||||
string message = string.IsNullOrEmpty(displayName) ? "A player disconnected." : $"{displayName} disconnected.";
|
||||
ShowOnScreenMessage(message, 4f);
|
||||
PlayerDisconnected?.Invoke(steamId);
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (onScreenMessages.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float now = Time.unscaledTime;
|
||||
for (int i = onScreenMessages.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (onScreenMessages[i].ExpiresAt <= now)
|
||||
{
|
||||
onScreenMessages.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (onScreenMessages.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float y = 20f;
|
||||
foreach (var entry in onScreenMessages)
|
||||
{
|
||||
if (entry.ExpiresAt <= Time.unscaledTime)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GUIContent content = new(entry.Text);
|
||||
Vector2 size = GUI.skin.box.CalcSize(content);
|
||||
Rect rect = new(20f, y, Mathf.Max(220f, size.x + 20f), size.y + 10f);
|
||||
GUI.Box(rect, content);
|
||||
y += rect.height + 6f;
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterExistingMembers(CSteamID lobbyId)
|
||||
{
|
||||
lobbyMembers.Clear();
|
||||
memberNames.Clear();
|
||||
|
||||
int count = SteamMatchmaking.GetNumLobbyMembers(lobbyId);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
CSteamID member = SteamMatchmaking.GetLobbyMemberByIndex(lobbyId, i);
|
||||
RegisterMember(member.m_SteamID);
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterMember(ulong steamId)
|
||||
{
|
||||
if (steamId == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lobbyMembers.Add(steamId);
|
||||
memberNames[steamId] = ResolveMemberNameInternal(steamId);
|
||||
}
|
||||
|
||||
private string ResolveMemberName(ulong steamId)
|
||||
{
|
||||
if (memberNames.TryGetValue(steamId, out string cached) && !string.IsNullOrEmpty(cached))
|
||||
{
|
||||
return cached;
|
||||
}
|
||||
|
||||
return ResolveMemberNameInternal(steamId);
|
||||
}
|
||||
|
||||
private string ResolveMemberNameInternal(ulong steamId)
|
||||
{
|
||||
#if STEAMWORKSNET
|
||||
if (steamId != 0 && SteamBootstrap.IsInitialized)
|
||||
{
|
||||
try
|
||||
{
|
||||
return SteamFriends.GetFriendPersonaName(new CSteamID(steamId));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore Steam API hiccups and fall back to id string.
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return steamId != 0 ? steamId.ToString() : string.Empty;
|
||||
}
|
||||
|
||||
private void ShowOnScreenMessage(string message, float lifetimeSeconds)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float expiry = Time.unscaledTime + Mathf.Max(0.5f, lifetimeSeconds);
|
||||
onScreenMessages.Add(new OnScreenMessage
|
||||
{
|
||||
Text = message,
|
||||
ExpiresAt = expiry
|
||||
});
|
||||
}
|
||||
|
||||
private void ForceDisconnectFromLobby()
|
||||
{
|
||||
if (ActiveLobby != CSteamID.Nil && SteamBootstrap.IsInitialized)
|
||||
{
|
||||
SteamMatchmaking.LeaveLobby(ActiveLobby);
|
||||
}
|
||||
|
||||
lobbyMembers.Clear();
|
||||
memberNames.Clear();
|
||||
lobbyOwnerSteamId = 0;
|
||||
isConnected = false;
|
||||
p2pTransport?.SetActiveLobby(CSteamID.Nil);
|
||||
}
|
||||
|
||||
private struct OnScreenMessage
|
||||
{
|
||||
public string Text;
|
||||
public float ExpiresAt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user