online fix
This commit is contained in:
355
Game/Scripts/Networking/SteamEnemySpawnerNetworkBridge.cs
Normal file
355
Game/Scripts/Networking/SteamEnemySpawnerNetworkBridge.cs
Normal file
@@ -0,0 +1,355 @@
|
||||
using System.Collections.Generic;
|
||||
using Game.Scripts.Runtime.Data;
|
||||
using Game.Scripts.Runtime.Game;
|
||||
using Game.Scripts.Runtime.Pooling;
|
||||
using Game.Scripts.Runtime.Spawning;
|
||||
using Steamworks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MegaKoop.Game.Networking
|
||||
{
|
||||
[DefaultExecutionOrder(-120)]
|
||||
[DisallowMultipleComponent]
|
||||
public class SteamEnemySpawnerNetworkBridge : MonoBehaviour
|
||||
{
|
||||
[Header("References")]
|
||||
[SerializeField] private EnemySpawner spawner;
|
||||
[SerializeField] private GameController gameController;
|
||||
[SerializeField] private ObjectPooler pooler;
|
||||
[SerializeField] private List<EnemyDefinition> additionalDefinitions = new();
|
||||
|
||||
[Header("Behaviour")]
|
||||
[SerializeField] private bool autoFindReferences = true;
|
||||
|
||||
private SteamCoopNetworkManager networkManager;
|
||||
private bool handlersRegistered;
|
||||
private bool spawnerSubscribed;
|
||||
private bool poolerSubscribed;
|
||||
private bool cachedAuthority;
|
||||
private bool hasPendingRemoteSpawn;
|
||||
private EnemySpawnMessage pendingRemoteSpawn;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (autoFindReferences)
|
||||
{
|
||||
spawner ??= GetComponent<EnemySpawner>();
|
||||
gameController ??= GetComponent<GameController>();
|
||||
pooler ??= spawner != null ? spawner.Pool : ObjectPooler.SharedInstance;
|
||||
}
|
||||
|
||||
cachedAuthority = DetermineAuthority();
|
||||
ApplyAuthorityOverride(cachedAuthority);
|
||||
RegisterDefinitionsFromSpawner();
|
||||
RegisterAdditionalDefinitions();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
RefreshNetworkManager();
|
||||
RegisterHandlers();
|
||||
SubscribeEvents();
|
||||
cachedAuthority = DetermineAuthority();
|
||||
ApplyAuthorityOverride(cachedAuthority);
|
||||
RegisterDefinitionsFromSpawner();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
UnsubscribeEvents();
|
||||
UnregisterHandlers();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
RefreshNetworkManager();
|
||||
|
||||
bool authority = DetermineAuthority();
|
||||
if (authority != cachedAuthority)
|
||||
{
|
||||
cachedAuthority = authority;
|
||||
ApplyAuthorityOverride(authority);
|
||||
}
|
||||
|
||||
if (!handlersRegistered)
|
||||
{
|
||||
RegisterHandlers();
|
||||
}
|
||||
}
|
||||
|
||||
private void SubscribeEvents()
|
||||
{
|
||||
if (spawner != null && !spawnerSubscribed)
|
||||
{
|
||||
spawner.OnEnemySpawned += HandleEnemySpawned;
|
||||
spawnerSubscribed = true;
|
||||
}
|
||||
|
||||
if (pooler != null && !poolerSubscribed)
|
||||
{
|
||||
pooler.InstanceDespawned += HandleInstanceDespawned;
|
||||
poolerSubscribed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UnsubscribeEvents()
|
||||
{
|
||||
if (spawner != null && spawnerSubscribed)
|
||||
{
|
||||
spawner.OnEnemySpawned -= HandleEnemySpawned;
|
||||
spawnerSubscribed = false;
|
||||
}
|
||||
|
||||
if (pooler != null && poolerSubscribed)
|
||||
{
|
||||
pooler.InstanceDespawned -= HandleInstanceDespawned;
|
||||
poolerSubscribed = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterHandlers()
|
||||
{
|
||||
if (handlersRegistered)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshNetworkManager();
|
||||
if (networkManager == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
networkManager.RegisterHandler(NetworkMessageType.EnemySpawn, HandleEnemySpawnMessage);
|
||||
networkManager.RegisterHandler(NetworkMessageType.EnemyDespawn, HandleEnemyDespawnMessage);
|
||||
handlersRegistered = true;
|
||||
}
|
||||
|
||||
private void UnregisterHandlers()
|
||||
{
|
||||
if (!handlersRegistered || networkManager == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
networkManager.UnregisterHandler(NetworkMessageType.EnemySpawn, HandleEnemySpawnMessage);
|
||||
networkManager.UnregisterHandler(NetworkMessageType.EnemyDespawn, HandleEnemyDespawnMessage);
|
||||
handlersRegistered = false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
spawner?.SetAuthorityOverride(authority);
|
||||
}
|
||||
|
||||
private void RegisterDefinitionsFromSpawner()
|
||||
{
|
||||
if (spawner == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var table = spawner.ActiveTable;
|
||||
if (table?.Entries == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var entry in table.Entries)
|
||||
{
|
||||
if (entry?.Def == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
EnemyDefinitionRegistry.Register(entry.Def);
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterAdditionalDefinitions()
|
||||
{
|
||||
if (additionalDefinitions == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var definition in additionalDefinitions)
|
||||
{
|
||||
EnemyDefinitionRegistry.Register(definition);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleEnemySpawned(GameObject instance, EnemyDefinition definition)
|
||||
{
|
||||
if (definition != null)
|
||||
{
|
||||
EnemyDefinitionRegistry.Register(definition);
|
||||
}
|
||||
|
||||
if (!DetermineAuthority() || networkManager == null)
|
||||
{
|
||||
if (hasPendingRemoteSpawn)
|
||||
{
|
||||
ApplyPendingRemoteSpawn(instance, definition);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (instance == null || definition == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string definitionId = EnemyDefinitionRegistry.ResolveId(definition);
|
||||
var identity = instance.GetComponent<NetworkIdentity>();
|
||||
int networkId = identity != null ? identity.NetworkId : 0;
|
||||
Vector3 spawnRootPosition = instance.transform.position - definition.PrefabPivotOffset;
|
||||
Quaternion rotation = instance.transform.rotation;
|
||||
bool isBoss = definition.IsBoss;
|
||||
int waveIndex = spawner != null ? spawner.CurrentWaveIndex : -1;
|
||||
float timestamp = gameController != null ? gameController.Elapsed : Time.time;
|
||||
|
||||
var message = new EnemySpawnMessage(definitionId, spawnRootPosition, rotation, networkId, isBoss, waveIndex, timestamp);
|
||||
byte[] payload = EnemySpawnMessage.Serialize(message);
|
||||
networkManager.SendToAll(NetworkMessageType.EnemySpawn, payload, EP2PSend.k_EP2PSendReliable);
|
||||
}
|
||||
|
||||
private void HandleInstanceDespawned(GameObject instance, EnemyDefinition definition)
|
||||
{
|
||||
if (!DetermineAuthority() || networkManager == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (instance == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var identity = instance.GetComponent<NetworkIdentity>();
|
||||
if (identity == null || identity.NetworkId == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var message = new EnemyDespawnMessage(identity.NetworkId);
|
||||
byte[] payload = EnemyDespawnMessage.Serialize(message);
|
||||
SteamCharacterStateCache.RemoveState(identity.NetworkId);
|
||||
networkManager.SendToAll(NetworkMessageType.EnemyDespawn, payload, EP2PSend.k_EP2PSendReliable);
|
||||
}
|
||||
|
||||
private void HandleEnemySpawnMessage(NetworkMessage message)
|
||||
{
|
||||
if (DetermineAuthority())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pendingRemoteSpawn = EnemySpawnMessage.Deserialize(message.Payload);
|
||||
hasPendingRemoteSpawn = true;
|
||||
|
||||
if (!EnemyDefinitionRegistry.TryGet(pendingRemoteSpawn.DefinitionId, out var definition))
|
||||
{
|
||||
Debug.LogWarning($"[SteamEnemySpawnerNetworkBridge] Missing EnemyDefinition for id '{pendingRemoteSpawn.DefinitionId}'.");
|
||||
hasPendingRemoteSpawn = false;
|
||||
return;
|
||||
}
|
||||
|
||||
bool success = spawner != null && spawner.TrySpawn(definition, pendingRemoteSpawn.Position);
|
||||
if (success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject instance = pooler != null
|
||||
? pooler.Spawn(definition, pendingRemoteSpawn.Position, pendingRemoteSpawn.Rotation)
|
||||
: null;
|
||||
|
||||
if (instance == null)
|
||||
{
|
||||
Debug.LogWarning($"[SteamEnemySpawnerNetworkBridge] Fallback spawn failed for '{pendingRemoteSpawn.DefinitionId}'.");
|
||||
hasPendingRemoteSpawn = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyPendingRemoteSpawn(instance, definition);
|
||||
}
|
||||
|
||||
private void HandleEnemyDespawnMessage(NetworkMessage message)
|
||||
{
|
||||
if (DetermineAuthority())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnemyDespawnMessage despawnMessage = EnemyDespawnMessage.Deserialize(message.Payload);
|
||||
if (despawnMessage.NetworkId == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NetworkIdentity.TryGet(despawnMessage.NetworkId, out var identity) || identity == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SteamCharacterStateCache.RemoveState(identity.NetworkId);
|
||||
|
||||
var pooled = identity.GetComponent<PooledInstance>();
|
||||
if (pooled != null)
|
||||
{
|
||||
pooled.ReturnToPool();
|
||||
}
|
||||
else
|
||||
{
|
||||
identity.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyPendingRemoteSpawn(GameObject instance, EnemyDefinition definition)
|
||||
{
|
||||
if (!hasPendingRemoteSpawn || instance == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
hasPendingRemoteSpawn = false;
|
||||
instance.transform.rotation = pendingRemoteSpawn.Rotation;
|
||||
if (definition != null)
|
||||
{
|
||||
EnemyDefinitionRegistry.Register(definition);
|
||||
}
|
||||
|
||||
var identity = instance.GetComponent<NetworkIdentity>();
|
||||
if (identity != null && pendingRemoteSpawn.NetworkId != 0 && identity.NetworkId != pendingRemoteSpawn.NetworkId)
|
||||
{
|
||||
identity.SetNetworkId(pendingRemoteSpawn.NetworkId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user