online fix
This commit is contained in:
@@ -19,7 +19,10 @@ namespace Game.Scripts.Runtime.Game
|
||||
|
||||
public float Elapsed => _elapsed;
|
||||
public bool IsRunning => _isRunning && !_isPaused;
|
||||
public bool IsGameActive => _isRunning;
|
||||
public bool IsPaused => _isPaused;
|
||||
public int CurrentWaveIndex => _currentWaveIndex;
|
||||
public BossSchedule BossSchedule => bossSchedule;
|
||||
|
||||
public event Action OnGameStarted;
|
||||
public event Action OnGamePaused;
|
||||
@@ -35,6 +38,8 @@ namespace Game.Scripts.Runtime.Game
|
||||
private bool _isPaused;
|
||||
private int _currentWaveIndex = -1;
|
||||
private int _bossCursor;
|
||||
private bool _hasAuthorityOverride;
|
||||
private bool _authorityOverride;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
@@ -66,9 +71,16 @@ namespace Game.Scripts.Runtime.Game
|
||||
spawner?.SetClock(this);
|
||||
spawner?.Begin();
|
||||
|
||||
UpdateWaveState();
|
||||
if (HasAuthority())
|
||||
{
|
||||
UpdateWaveState();
|
||||
_loop = StartCoroutine(GameLoop());
|
||||
}
|
||||
else
|
||||
{
|
||||
_loop = null;
|
||||
}
|
||||
|
||||
_loop = StartCoroutine(GameLoop());
|
||||
OnGameStarted?.Invoke();
|
||||
Log($"Game started – waveDuration={waveDurationSeconds}s");
|
||||
}
|
||||
@@ -268,5 +280,84 @@ namespace Game.Scripts.Runtime.Game
|
||||
Debug.Log($"[{name}] {message}", this);
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetAuthorityOverride(bool hasAuthority)
|
||||
{
|
||||
_hasAuthorityOverride = true;
|
||||
if (_authorityOverride == hasAuthority)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_authorityOverride = hasAuthority;
|
||||
|
||||
if (!HasAuthority() && _loop != null)
|
||||
{
|
||||
StopCoroutine(_loop);
|
||||
_loop = null;
|
||||
}
|
||||
else if (HasAuthority() && _isRunning && _loop == null)
|
||||
{
|
||||
_loop = StartCoroutine(GameLoop());
|
||||
}
|
||||
}
|
||||
|
||||
internal bool HasAuthority() => !_hasAuthorityOverride || _authorityOverride;
|
||||
|
||||
internal void SetElapsedFromRemote(float elapsed)
|
||||
{
|
||||
_elapsed = Mathf.Max(0f, elapsed);
|
||||
}
|
||||
|
||||
internal void SetRunningFlagsFromRemote(bool isRunning, bool isPaused)
|
||||
{
|
||||
_isRunning = isRunning;
|
||||
_isPaused = isPaused;
|
||||
}
|
||||
|
||||
internal void ApplyRemoteWaveAdvance(int previousWave, int newWave)
|
||||
{
|
||||
int oldWave = _currentWaveIndex;
|
||||
|
||||
if (previousWave >= 0 && oldWave == previousWave)
|
||||
{
|
||||
OnWaveCompleted?.Invoke(previousWave);
|
||||
}
|
||||
else if (oldWave >= 0 && oldWave != newWave)
|
||||
{
|
||||
OnWaveCompleted?.Invoke(oldWave);
|
||||
}
|
||||
|
||||
_currentWaveIndex = newWave;
|
||||
if (_currentWaveIndex >= 0)
|
||||
{
|
||||
spawner?.SetWaveIndex(_currentWaveIndex);
|
||||
OnWaveStarted?.Invoke(_currentWaveIndex);
|
||||
}
|
||||
}
|
||||
|
||||
internal void ApplyRemoteWaveStarted(int waveIndex)
|
||||
{
|
||||
if (_currentWaveIndex != waveIndex)
|
||||
{
|
||||
_currentWaveIndex = waveIndex;
|
||||
}
|
||||
|
||||
if (_currentWaveIndex >= 0)
|
||||
{
|
||||
spawner?.SetWaveIndex(_currentWaveIndex);
|
||||
OnWaveStarted?.Invoke(_currentWaveIndex);
|
||||
}
|
||||
}
|
||||
|
||||
internal void ApplyRemoteWaveCompleted(int waveIndex)
|
||||
{
|
||||
OnWaveCompleted?.Invoke(waveIndex);
|
||||
}
|
||||
|
||||
internal void ApplyRemoteBossSpawned(EnemyDefinition boss, int count)
|
||||
{
|
||||
OnBossSpawned?.Invoke(boss, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using Game.Scripts.Runtime.Abstractions;
|
||||
using Game.Scripts.Runtime.Data;
|
||||
using UnityEngine;
|
||||
using Unity.Netcode;
|
||||
|
||||
namespace Game.Scripts.Runtime.Pooling
|
||||
{
|
||||
@@ -112,7 +113,7 @@ namespace Game.Scripts.Runtime.Pooling
|
||||
}
|
||||
|
||||
bucket.Active.Add(go);
|
||||
go.transform.SetParent(null, true);
|
||||
SetParentSafely(go, null, true);
|
||||
go.transform.SetPositionAndRotation(position + definition.PrefabPivotOffset, rotation);
|
||||
go.SetActive(true);
|
||||
|
||||
@@ -137,7 +138,12 @@ namespace Game.Scripts.Runtime.Pooling
|
||||
bucket.Active.Remove(instance);
|
||||
|
||||
instance.SetActive(false);
|
||||
instance.transform.SetParent(poolRoot, false);
|
||||
var netObj = instance.GetComponent<NetworkObject>();
|
||||
SetParentSafely(instance, poolRoot, false, netObj, false);
|
||||
if (netObj != null)
|
||||
{
|
||||
Destroy(netObj);
|
||||
}
|
||||
bucket.Available.Enqueue(instance);
|
||||
item.Handle?.NotifyDespawned();
|
||||
InstanceDespawned?.Invoke(instance, item.Definition);
|
||||
@@ -172,7 +178,8 @@ namespace Game.Scripts.Runtime.Pooling
|
||||
}
|
||||
|
||||
EnsureRoot();
|
||||
var go = Instantiate(definition.Prefab, poolRoot);
|
||||
var go = Instantiate(definition.Prefab);
|
||||
SetParentSafely(go, poolRoot, false);
|
||||
go.name = $"{definition.Prefab.name}_Pooled";
|
||||
go.SetActive(false);
|
||||
|
||||
@@ -230,6 +237,38 @@ namespace Game.Scripts.Runtime.Pooling
|
||||
root.transform.SetParent(transform, false);
|
||||
poolRoot = root.transform;
|
||||
}
|
||||
|
||||
private void SetParentSafely(GameObject instance, Transform parent, bool worldPositionStays, NetworkObject cachedNetworkObject = null, bool restoreAutoSync = true)
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var netObj = cachedNetworkObject != null ? cachedNetworkObject : instance.GetComponent<NetworkObject>();
|
||||
var shouldRestore = false;
|
||||
var previousAutoSync = false;
|
||||
|
||||
if (netObj != null && !HasListeningNetworkManager(netObj))
|
||||
{
|
||||
previousAutoSync = netObj.AutoObjectParentSync;
|
||||
netObj.AutoObjectParentSync = false;
|
||||
shouldRestore = restoreAutoSync;
|
||||
}
|
||||
|
||||
instance.transform.SetParent(parent, worldPositionStays);
|
||||
|
||||
if (shouldRestore && netObj != null)
|
||||
{
|
||||
netObj.AutoObjectParentSync = previousAutoSync;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool HasListeningNetworkManager(NetworkObject netObj)
|
||||
{
|
||||
var manager = netObj != null ? (netObj.NetworkManager != null ? netObj.NetworkManager : NetworkManager.Singleton) : NetworkManager.Singleton;
|
||||
return manager != null && manager.IsListening;
|
||||
}
|
||||
}
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
|
||||
@@ -6,6 +6,7 @@ using Game.Scripts.Runtime.Data;
|
||||
using Game.Scripts.Runtime.Pooling;
|
||||
using Game.Scripts.Runtime.Navigation;
|
||||
using MegaKoop.Game;
|
||||
using MegaKoop.Game.Networking;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
|
||||
@@ -68,6 +69,8 @@ namespace Game.Scripts.Runtime.Spawning
|
||||
private IEnemyFactory _factory;
|
||||
private bool _warnedMissingPlayer;
|
||||
private bool _warnedMissingNavMesh;
|
||||
private bool _authorityOverrideSet;
|
||||
private bool _authorityOverrideValue = true;
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
@@ -170,8 +173,16 @@ namespace Game.Scripts.Runtime.Spawning
|
||||
_spawnedThisWave.Clear();
|
||||
_localElapsed = 0f;
|
||||
_nextSpawnTimestamp = 0f;
|
||||
_spawnLoop = StartCoroutine(SpawnLoop());
|
||||
LogLifecycle($"Begin – wave {CurrentWaveIndex}, pool prewarm complete, maxConcurrent={_runtimeConfig.MaxConcurrent}");
|
||||
if (HasAuthority())
|
||||
{
|
||||
_spawnLoop = StartCoroutine(SpawnLoop());
|
||||
LogLifecycle($"Begin – wave {CurrentWaveIndex}, pool prewarm complete, maxConcurrent={_runtimeConfig.MaxConcurrent}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_spawnLoop = null;
|
||||
LogLifecycle($"Begin – follower mode (no spawn loop), wave {CurrentWaveIndex}, maxConcurrent={_runtimeConfig?.MaxConcurrent}");
|
||||
}
|
||||
}
|
||||
|
||||
public void End()
|
||||
@@ -226,6 +237,12 @@ namespace Game.Scripts.Runtime.Spawning
|
||||
_localElapsed = _clock.Elapsed;
|
||||
}
|
||||
|
||||
if (!HasAuthority())
|
||||
{
|
||||
yield return null;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_localElapsed >= _nextSpawnTimestamp)
|
||||
{
|
||||
ExecuteSpawnTick();
|
||||
@@ -640,6 +657,22 @@ namespace Game.Scripts.Runtime.Spawning
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetAuthorityOverride(bool hasAuthority)
|
||||
{
|
||||
_authorityOverrideSet = true;
|
||||
_authorityOverrideValue = hasAuthority;
|
||||
|
||||
if (!HasAuthority() && _spawnLoop != null)
|
||||
{
|
||||
StopCoroutine(_spawnLoop);
|
||||
_spawnLoop = null;
|
||||
}
|
||||
else if (HasAuthority() && _spawnLoop == null && _runtimeConfig != null && _runtimeTable != null)
|
||||
{
|
||||
_spawnLoop = StartCoroutine(SpawnLoop());
|
||||
}
|
||||
}
|
||||
|
||||
private bool RequirePlayerReference()
|
||||
{
|
||||
if (EnsurePlayerReference())
|
||||
@@ -706,5 +739,26 @@ namespace Game.Scripts.Runtime.Spawning
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasAuthority()
|
||||
{
|
||||
if (_authorityOverrideSet)
|
||||
{
|
||||
return _authorityOverrideValue;
|
||||
}
|
||||
|
||||
var manager = SteamCoopNetworkManager.Instance;
|
||||
if (manager == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!manager.IsConnected)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return manager.IsHost;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user