Join and leave improvements

This commit is contained in:
2025-10-12 14:36:59 +02:00
parent ba150ac5d3
commit e1abeeb547
3 changed files with 347 additions and 2 deletions

View File

@@ -18,15 +18,18 @@ namespace MegaKoop.Game.Networking
public class LobbyGameSceneCoordinator : MonoBehaviour
{
private static LobbyGameSceneCoordinator Instance;
public static LobbyGameSceneCoordinator Current => Instance;
[SerializeField] private string characterSceneName = "CharacterScene";
[SerializeField] private float spawnRadius = 3f;
[SerializeField] private float minimumSpawnSpacing = 2.5f;
private readonly List<LobbyPlayerInfo> pendingPlayers = new();
private readonly Dictionary<ulong, GameObject> spawnedPlayerObjects = new();
private string localSteamId = string.Empty;
private bool loadPending;
private bool hasSpawned;
private SteamCoopNetworkManager coopNetworkManager;
private void Awake()
{
@@ -40,11 +43,13 @@ namespace MegaKoop.Game.Networking
Instance = this;
DontDestroyOnLoad(gameObject);
SceneManager.sceneLoaded += HandleSceneLoaded;
EnsureNetworkSubscription();
}
private void OnDestroy()
{
SceneManager.sceneLoaded -= HandleSceneLoaded;
UnsubscribeFromNetwork();
}
/// <summary>
@@ -113,6 +118,14 @@ namespace MegaKoop.Game.Networking
pendingPlayers.Sort((a, b) => string.CompareOrdinal(a.SteamId ?? string.Empty, b.SteamId ?? string.Empty));
}
private void LateUpdate()
{
if (coopNetworkManager == null)
{
EnsureNetworkSubscription();
}
}
private void HandleSceneLoaded(Scene scene, LoadSceneMode mode)
{
if (!string.Equals(scene.name, characterSceneName, StringComparison.OrdinalIgnoreCase))
@@ -125,6 +138,7 @@ namespace MegaKoop.Game.Networking
return;
}
EnsureNetworkSubscription();
loadPending = false;
hasSpawned = false;
SpawnPlayersInScene(scene);
@@ -137,6 +151,7 @@ namespace MegaKoop.Game.Networking
return;
}
EnsureNetworkSubscription();
var template = FindWizardTemplate(scene);
if (template == null)
{
@@ -148,6 +163,7 @@ namespace MegaKoop.Game.Networking
// Proactively remove any previously spawned character clones (e.g., from a duplicate coordinator)
DespawnExistingClones(scene, template);
spawnedPlayerObjects.Clear();
Vector3 basePosition = template.transform.position;
Quaternion baseRotation = template.transform.rotation;
@@ -168,6 +184,17 @@ namespace MegaKoop.Game.Networking
ConfigureCloneForPlayer(clone, info, i);
ulong ownerSteamId = ParseSteamId(info.SteamId);
if (ownerSteamId == 0UL && info.IsLocal)
{
ownerSteamId = ParseSteamId(localSteamId);
}
if (ownerSteamId != 0UL)
{
spawnedPlayerObjects[ownerSteamId] = clone;
}
clone.SetActive(true);
}
}
@@ -359,5 +386,106 @@ namespace MegaKoop.Game.Networking
public string DisplayName;
public bool IsLocal;
}
private void EnsureNetworkSubscription()
{
var manager = SteamCoopNetworkManager.Instance;
if (manager == null || manager == coopNetworkManager)
{
return;
}
UnsubscribeFromNetwork();
coopNetworkManager = manager;
coopNetworkManager.HostClosed += HandleHostClosed;
coopNetworkManager.PlayerDisconnected += HandlePlayerDisconnected;
}
private void UnsubscribeFromNetwork()
{
if (coopNetworkManager == null)
{
return;
}
coopNetworkManager.HostClosed -= HandleHostClosed;
coopNetworkManager.PlayerDisconnected -= HandlePlayerDisconnected;
coopNetworkManager = null;
}
private void HandleHostClosed()
{
Debug.Log("[LobbyGameSceneCoordinator] Host closed session; despawning all players.");
RemoveAllSpawnedPlayers();
}
private void HandlePlayerDisconnected(ulong steamId)
{
RemoveSpawnedPlayer(steamId);
}
private void RemoveAllSpawnedPlayers()
{
if (spawnedPlayerObjects.Count == 0)
{
return;
}
foreach (var avatar in spawnedPlayerObjects.Values)
{
if (avatar != null)
{
Destroy(avatar);
}
}
spawnedPlayerObjects.Clear();
hasSpawned = false;
}
private void RemoveSpawnedPlayer(ulong steamId)
{
if (steamId == 0)
{
return;
}
if (spawnedPlayerObjects.TryGetValue(steamId, out GameObject avatar))
{
if (avatar != null)
{
Destroy(avatar);
}
spawnedPlayerObjects.Remove(steamId);
Debug.Log($"[LobbyGameSceneCoordinator] Removed avatar for {steamId}.");
return;
}
ulong? keyToRemove = null;
foreach (var kvp in spawnedPlayerObjects)
{
var target = kvp.Value;
if (target == null)
{
keyToRemove = kvp.Key;
continue;
}
var bridge = target.GetComponent<SteamCharacterNetworkBridge>();
if (bridge != null && bridge.OwnerSteamId == steamId)
{
Destroy(target);
keyToRemove = kvp.Key;
break;
}
}
if (keyToRemove.HasValue)
{
spawnedPlayerObjects.Remove(keyToRemove.Value);
Debug.Log($"[LobbyGameSceneCoordinator] Removed avatar for {steamId} (fallback search).");
}
}
}
}