online fix
This commit is contained in:
365
Game/Scripts/Networking/SteamGameControllerNetworkBridge.cs
Normal file
365
Game/Scripts/Networking/SteamGameControllerNetworkBridge.cs
Normal file
@@ -0,0 +1,365 @@
|
||||
using Game.Scripts.Runtime.Data;
|
||||
using Game.Scripts.Runtime.Game;
|
||||
using Game.Scripts.Runtime.Spawning;
|
||||
using Steamworks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MegaKoop.Game.Networking
|
||||
{
|
||||
[DefaultExecutionOrder(-140)]
|
||||
[DisallowMultipleComponent]
|
||||
public class SteamGameControllerNetworkBridge : MonoBehaviour
|
||||
{
|
||||
[Header("References")]
|
||||
[SerializeField] private GameController gameController;
|
||||
[SerializeField] private EnemySpawner enemySpawner;
|
||||
|
||||
[Header("Heartbeat")]
|
||||
[SerializeField, Min(0.1f)] private float heartbeatInterval = 0.5f;
|
||||
|
||||
private SteamCoopNetworkManager networkManager;
|
||||
private bool handlersRegistered;
|
||||
private bool controllerSubscribed;
|
||||
private bool cachedAuthority;
|
||||
private float heartbeatTimer;
|
||||
private int lastWaveBroadcast = -1;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
gameController ??= GetComponent<GameController>();
|
||||
enemySpawner ??= GetComponent<EnemySpawner>();
|
||||
|
||||
cachedAuthority = DetermineAuthority();
|
||||
ApplyAuthorityOverride(cachedAuthority);
|
||||
RegisterBossDefinitions();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
RefreshNetworkManager();
|
||||
RegisterHandlers();
|
||||
SubscribeControllerEvents();
|
||||
|
||||
cachedAuthority = DetermineAuthority();
|
||||
ApplyAuthorityOverride(cachedAuthority);
|
||||
heartbeatTimer = heartbeatInterval;
|
||||
RegisterBossDefinitions();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
UnsubscribeControllerEvents();
|
||||
UnregisterHandlers();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
RefreshNetworkManager();
|
||||
|
||||
bool authority = DetermineAuthority();
|
||||
if (authority != cachedAuthority)
|
||||
{
|
||||
cachedAuthority = authority;
|
||||
ApplyAuthorityOverride(authority);
|
||||
}
|
||||
|
||||
if (authority)
|
||||
{
|
||||
RunHeartbeat(Time.deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
private void RunHeartbeat(float deltaTime)
|
||||
{
|
||||
heartbeatTimer -= deltaTime;
|
||||
if (heartbeatTimer > 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
heartbeatTimer = Mathf.Max(0.1f, heartbeatInterval);
|
||||
SendState(GameStateEvent.Heartbeat, lastWaveBroadcast);
|
||||
}
|
||||
|
||||
private void SubscribeControllerEvents()
|
||||
{
|
||||
if (gameController == null || controllerSubscribed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gameController.OnGameStarted += HandleGameStarted;
|
||||
gameController.OnGamePaused += HandleGamePaused;
|
||||
gameController.OnGameResumed += HandleGameResumed;
|
||||
gameController.OnGameStopped += HandleGameStopped;
|
||||
gameController.OnWaveStarted += HandleWaveStarted;
|
||||
gameController.OnBossSpawned += HandleBossSpawned;
|
||||
controllerSubscribed = true;
|
||||
}
|
||||
|
||||
private void UnsubscribeControllerEvents()
|
||||
{
|
||||
if (gameController == null || !controllerSubscribed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gameController.OnGameStarted -= HandleGameStarted;
|
||||
gameController.OnGamePaused -= HandleGamePaused;
|
||||
gameController.OnGameResumed -= HandleGameResumed;
|
||||
gameController.OnGameStopped -= HandleGameStopped;
|
||||
gameController.OnWaveStarted -= HandleWaveStarted;
|
||||
gameController.OnBossSpawned -= HandleBossSpawned;
|
||||
controllerSubscribed = false;
|
||||
}
|
||||
|
||||
private void HandleGameStarted()
|
||||
{
|
||||
if (!DetermineAuthority())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SendState(GameStateEvent.Started, -1);
|
||||
lastWaveBroadcast = gameController != null ? gameController.CurrentWaveIndex : -1;
|
||||
}
|
||||
|
||||
private void HandleGamePaused()
|
||||
{
|
||||
if (!DetermineAuthority())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SendState(GameStateEvent.Paused, gameController != null ? gameController.CurrentWaveIndex : -1);
|
||||
}
|
||||
|
||||
private void HandleGameResumed()
|
||||
{
|
||||
if (!DetermineAuthority())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SendState(GameStateEvent.Resumed, gameController != null ? gameController.CurrentWaveIndex : -1);
|
||||
}
|
||||
|
||||
private void HandleGameStopped()
|
||||
{
|
||||
if (!DetermineAuthority())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SendState(GameStateEvent.Stopped, gameController != null ? gameController.CurrentWaveIndex : -1);
|
||||
lastWaveBroadcast = -1;
|
||||
}
|
||||
|
||||
private void HandleWaveStarted(int waveIndex)
|
||||
{
|
||||
if (!DetermineAuthority())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int previousWave = lastWaveBroadcast >= 0 ? lastWaveBroadcast : waveIndex - 1;
|
||||
lastWaveBroadcast = waveIndex;
|
||||
SendState(GameStateEvent.WaveAdvanced, previousWave);
|
||||
}
|
||||
|
||||
private void HandleBossSpawned(EnemyDefinition boss, int count)
|
||||
{
|
||||
if (!DetermineAuthority())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnemyDefinitionRegistry.Register(boss);
|
||||
string definitionId = EnemyDefinitionRegistry.ResolveId(boss);
|
||||
SendState(GameStateEvent.BossSpawned, lastWaveBroadcast, definitionId, count);
|
||||
}
|
||||
|
||||
private void SendState(GameStateEvent evt, int previousWave, string definitionId = "", int count = 0)
|
||||
{
|
||||
if (networkManager == null || gameController == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float elapsed = gameController.Elapsed;
|
||||
int currentWave = gameController.CurrentWaveIndex;
|
||||
bool isPaused = gameController.IsPaused;
|
||||
bool isRunning = gameController.IsGameActive;
|
||||
|
||||
var message = new GameStateMessage(evt, elapsed, currentWave, previousWave, isPaused, isRunning, definitionId, count);
|
||||
byte[] payload = GameStateMessage.Serialize(message);
|
||||
var sendType = evt == GameStateEvent.Heartbeat ? EP2PSend.k_EP2PSendUnreliableNoDelay : EP2PSend.k_EP2PSendReliable;
|
||||
networkManager.SendToAll(NetworkMessageType.GameState, payload, sendType);
|
||||
}
|
||||
|
||||
private void RegisterHandlers()
|
||||
{
|
||||
if (handlersRegistered)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshNetworkManager();
|
||||
if (networkManager == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
networkManager.RegisterHandler(NetworkMessageType.GameState, HandleGameStateMessage);
|
||||
handlersRegistered = true;
|
||||
}
|
||||
|
||||
private void UnregisterHandlers()
|
||||
{
|
||||
if (!handlersRegistered || networkManager == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
networkManager.UnregisterHandler(NetworkMessageType.GameState, HandleGameStateMessage);
|
||||
handlersRegistered = false;
|
||||
}
|
||||
|
||||
private void HandleGameStateMessage(NetworkMessage message)
|
||||
{
|
||||
if (DetermineAuthority())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameStateMessage state = GameStateMessage.Deserialize(message.Payload);
|
||||
ApplyRemoteState(state);
|
||||
}
|
||||
|
||||
private void ApplyRemoteState(GameStateMessage state)
|
||||
{
|
||||
if (gameController == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (state.Event)
|
||||
{
|
||||
case GameStateEvent.Started:
|
||||
if (!gameController.IsGameActive)
|
||||
{
|
||||
gameController.StartGame();
|
||||
}
|
||||
|
||||
gameController.SetElapsedFromRemote(state.Elapsed);
|
||||
gameController.SetRunningFlagsFromRemote(state.IsRunning, state.IsPaused);
|
||||
gameController.ApplyRemoteWaveStarted(state.CurrentWave);
|
||||
lastWaveBroadcast = state.CurrentWave;
|
||||
break;
|
||||
|
||||
case GameStateEvent.Paused:
|
||||
if (!gameController.IsPaused && gameController.IsGameActive)
|
||||
{
|
||||
gameController.PauseGame();
|
||||
}
|
||||
|
||||
gameController.SetElapsedFromRemote(state.Elapsed);
|
||||
gameController.SetRunningFlagsFromRemote(state.IsRunning, state.IsPaused);
|
||||
break;
|
||||
|
||||
case GameStateEvent.Resumed:
|
||||
if (gameController.IsPaused)
|
||||
{
|
||||
gameController.ResumeGame();
|
||||
}
|
||||
|
||||
gameController.SetElapsedFromRemote(state.Elapsed);
|
||||
gameController.SetRunningFlagsFromRemote(state.IsRunning, state.IsPaused);
|
||||
break;
|
||||
|
||||
case GameStateEvent.Stopped:
|
||||
if (gameController.IsGameActive)
|
||||
{
|
||||
gameController.StopGame();
|
||||
}
|
||||
|
||||
lastWaveBroadcast = -1;
|
||||
gameController.SetElapsedFromRemote(state.Elapsed);
|
||||
gameController.SetRunningFlagsFromRemote(state.IsRunning, state.IsPaused);
|
||||
break;
|
||||
|
||||
case GameStateEvent.WaveAdvanced:
|
||||
gameController.SetElapsedFromRemote(state.Elapsed);
|
||||
gameController.ApplyRemoteWaveAdvance(state.PreviousWave, state.CurrentWave);
|
||||
lastWaveBroadcast = state.CurrentWave;
|
||||
break;
|
||||
|
||||
case GameStateEvent.BossSpawned:
|
||||
gameController.SetElapsedFromRemote(state.Elapsed);
|
||||
if (EnemyDefinitionRegistry.TryGet(state.DefinitionId, out var bossDefinition))
|
||||
{
|
||||
gameController.ApplyRemoteBossSpawned(bossDefinition, state.Count);
|
||||
}
|
||||
break;
|
||||
|
||||
case GameStateEvent.Heartbeat:
|
||||
gameController.SetElapsedFromRemote(state.Elapsed);
|
||||
gameController.SetRunningFlagsFromRemote(state.IsRunning, state.IsPaused);
|
||||
if (state.CurrentWave >= 0 && state.CurrentWave != gameController.CurrentWaveIndex)
|
||||
{
|
||||
gameController.ApplyRemoteWaveAdvance(gameController.CurrentWaveIndex, state.CurrentWave);
|
||||
lastWaveBroadcast = state.CurrentWave;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshNetworkManager()
|
||||
{
|
||||
if (networkManager == null)
|
||||
{
|
||||
networkManager = SteamCoopNetworkManager.Instance;
|
||||
}
|
||||
}
|
||||
|
||||
private bool DetermineAuthority()
|
||||
{
|
||||
RefreshNetworkManager();
|
||||
if (networkManager == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!networkManager.IsConnected)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return networkManager.IsHost;
|
||||
}
|
||||
|
||||
private void ApplyAuthorityOverride(bool authority)
|
||||
{
|
||||
gameController?.SetAuthorityOverride(authority);
|
||||
enemySpawner?.SetAuthorityOverride(authority);
|
||||
}
|
||||
|
||||
private void RegisterBossDefinitions()
|
||||
{
|
||||
if (gameController?.BossSchedule?.Events == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var bossEvent in gameController.BossSchedule.Events)
|
||||
{
|
||||
if (bossEvent?.Boss == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
EnemyDefinitionRegistry.Register(bossEvent.Boss);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user