online fix

This commit is contained in:
2025-10-27 14:09:52 +01:00
parent 8ea4b173a3
commit 9ded503704
6 changed files with 181 additions and 40 deletions

View File

@@ -22,9 +22,6 @@ namespace MegaKoop.Game.Enemy
public class SteamEnemyController : MonoBehaviour public class SteamEnemyController : MonoBehaviour
{ {
private static readonly List<Health> SharedHealthBuffer = new(32); private static readonly List<Health> SharedHealthBuffer = new(32);
private static int nextEnemyNetworkId = StartingEnemyNetworkId;
private const int StartingEnemyNetworkId = 10000;
[Header("Movement")] [Header("Movement")]
[SerializeField] private float moveSpeed = 3.5f; [SerializeField] private float moveSpeed = 3.5f;
@@ -118,7 +115,7 @@ namespace MegaKoop.Game.Enemy
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void ResetNetworkIdCounter() private static void ResetNetworkIdCounter()
{ {
nextEnemyNetworkId = StartingEnemyNetworkId; NetworkIdAllocator.Reset();
} }
private void EnsureIdentity() private void EnsureIdentity()
@@ -143,7 +140,8 @@ namespace MegaKoop.Game.Enemy
return; return;
} }
identity.SetNetworkId(nextEnemyNetworkId++); int allocatedId = NetworkIdAllocator.AllocateEnemyId();
identity.SetNetworkId(allocatedId);
} }
private void OnEnable() private void OnEnable()

View File

@@ -256,7 +256,7 @@ namespace MegaKoop.Game.Networking
{ {
// Ensure network identity is deterministic across clients. // Ensure network identity is deterministic across clients.
var identity = clone.GetComponent<NetworkIdentity>() ?? clone.AddComponent<NetworkIdentity>(); var identity = clone.GetComponent<NetworkIdentity>() ?? clone.AddComponent<NetworkIdentity>();
identity.SetNetworkId(index + 1); identity.SetNetworkId(NetworkIdAllocator.PlayerIdStart + index);
var bridge = clone.GetComponent<SteamCharacterNetworkBridge>() ?? clone.AddComponent<SteamCharacterNetworkBridge>(); var bridge = clone.GetComponent<SteamCharacterNetworkBridge>() ?? clone.AddComponent<SteamCharacterNetworkBridge>();
bridge.AssignOwner(ParseSteamId(info.SteamId), info.IsLocal); bridge.AssignOwner(ParseSteamId(info.SteamId), info.IsLocal);

View File

@@ -0,0 +1,65 @@
using UnityEngine;
namespace MegaKoop.Game.Networking
{
internal static class NetworkIdAllocator
{
public const int PlayerIdStart = 1;
public const int EnemyIdStart = 10000;
private const int EnemyIdRange = 10000;
private static int nextEnemyId = EnemyIdStart;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void ResetOnLoad()
{
Reset();
}
public static void Reset()
{
nextEnemyId = EnemyIdStart;
}
public static int AllocateEnemyId()
{
if (nextEnemyId < EnemyIdStart)
{
nextEnemyId = EnemyIdStart;
}
const int maxAttempts = EnemyIdRange;
int attempts = 0;
while ((NetworkIdRegistry.IsIdRegistered(nextEnemyId) || NetworkIdRegistry.IsIdReserved(nextEnemyId)) && attempts < maxAttempts)
{
AdvanceEnemyCursor();
attempts++;
}
int allocated = nextEnemyId;
AdvanceEnemyCursor();
return allocated;
}
public static bool IsPlayerId(int id) => id >= PlayerIdStart && id < EnemyIdStart;
public static bool IsEnemyId(int id) => id >= EnemyIdStart;
public static void SyncEnemyCursor(int id)
{
if (id >= EnemyIdStart && id >= nextEnemyId)
{
nextEnemyId = id + 1;
}
}
private static void AdvanceEnemyCursor()
{
nextEnemyId++;
if (nextEnemyId >= EnemyIdStart + EnemyIdRange)
{
nextEnemyId = EnemyIdStart;
}
}
}
}

View File

@@ -242,6 +242,7 @@ namespace MegaKoop.Game.Networking
instance.registry.Clear(); instance.registry.Clear();
instance.steamIdToNetworkId.Clear(); instance.steamIdToNetworkId.Clear();
instance.reservedIds.Clear(); instance.reservedIds.Clear();
NetworkIdAllocator.Reset();
Debug.Log($"[NetworkIdRegistry] Registry cleared. Removed {registryCount} identities, {mappingCount} Steam ID mappings, and {reservedCount} reserved IDs."); Debug.Log($"[NetworkIdRegistry] Registry cleared. Removed {registryCount} identities, {mappingCount} Steam ID mappings, and {reservedCount} reserved IDs.");
} }

View File

@@ -30,12 +30,14 @@ namespace MegaKoop.Game.Networking
private Vector3 remoteTargetVelocity; private Vector3 remoteTargetVelocity;
private bool haveRemoteState; private bool haveRemoteState;
private bool localOverrideSet; private bool localOverrideSet;
private int expectedNetworkId;
public void AssignOwner(ulong steamId, bool localPlayer) public void AssignOwner(ulong steamId, bool localPlayer)
{ {
ownerSteamId = steamId; ownerSteamId = steamId;
isLocalPlayer = localPlayer; isLocalPlayer = localPlayer;
localOverrideSet = true; localOverrideSet = true;
CaptureExpectedNetworkId();
UpdateAuthority(); UpdateAuthority();
ConfigureController(); ConfigureController();
} }
@@ -87,6 +89,7 @@ namespace MegaKoop.Game.Networking
private void Start() private void Start()
{ {
networkManager = SteamCoopNetworkManager.Instance; networkManager = SteamCoopNetworkManager.Instance;
CaptureExpectedNetworkId();
UpdateAuthority(); UpdateAuthority();
ConfigureController(); ConfigureController();
} }
@@ -94,6 +97,7 @@ namespace MegaKoop.Game.Networking
private void OnEnable() private void OnEnable()
{ {
networkManager = SteamCoopNetworkManager.Instance; networkManager = SteamCoopNetworkManager.Instance;
CaptureExpectedNetworkId();
RegisterHandlers(); RegisterHandlers();
} }
@@ -221,6 +225,11 @@ namespace MegaKoop.Game.Networking
return; return;
} }
if (identity.NetworkId == 0)
{
return;
}
var unityController = GetComponent<CharacterController>(); var unityController = GetComponent<CharacterController>();
Vector3 velocity = unityController != null ? unityController.velocity : Vector3.zero; Vector3 velocity = unityController != null ? unityController.velocity : Vector3.zero;
SteamCharacterStateCache.ReportLocalState(identity.NetworkId, rootTransform.position, rootTransform.rotation, velocity); SteamCharacterStateCache.ReportLocalState(identity.NetworkId, rootTransform.position, rootTransform.rotation, velocity);
@@ -238,6 +247,11 @@ namespace MegaKoop.Game.Networking
return; return;
} }
if (identity.NetworkId == 0)
{
return;
}
float moveX = animator.GetFloat("MoveX"); float moveX = animator.GetFloat("MoveX");
float moveZ = animator.GetFloat("MoveZ"); float moveZ = animator.GetFloat("MoveZ");
float speed = animator.GetFloat("Speed"); float speed = animator.GetFloat("Speed");
@@ -285,24 +299,9 @@ namespace MegaKoop.Game.Networking
} }
CharacterTransformMessage transformMessage = CharacterTransformMessage.Deserialize(message.Payload); CharacterTransformMessage transformMessage = CharacterTransformMessage.Deserialize(message.Payload);
if (identity != null && transformMessage.NetworkId != identity.NetworkId) if (!EnsureMatchingNetworkId(transformMessage.NetworkId, message.Sender))
{ {
if (ownerSteamId != 0 && message.Sender != ownerSteamId) return;
{
return;
}
var existing = NetworkIdRegistry.GetById(transformMessage.NetworkId);
if (existing != null && existing != identity)
{
return;
}
identity.SetNetworkId(transformMessage.NetworkId);
if (identity.NetworkId != transformMessage.NetworkId)
{
return;
}
} }
remoteTargetPosition = transformMessage.Position; remoteTargetPosition = transformMessage.Position;
@@ -319,24 +318,9 @@ namespace MegaKoop.Game.Networking
} }
CharacterAnimMessage anim = CharacterAnimMessage.Deserialize(message.Payload); CharacterAnimMessage anim = CharacterAnimMessage.Deserialize(message.Payload);
if (identity != null && anim.NetworkId != identity.NetworkId) if (!EnsureMatchingNetworkId(anim.NetworkId, message.Sender))
{ {
if (ownerSteamId != 0 && message.Sender != ownerSteamId) return;
{
return;
}
var existing = NetworkIdRegistry.GetById(anim.NetworkId);
if (existing != null && existing != identity)
{
return;
}
identity.SetNetworkId(anim.NetworkId);
if (identity.NetworkId != anim.NetworkId)
{
return;
}
} }
if (animator == null) if (animator == null)
@@ -358,6 +342,93 @@ namespace MegaKoop.Game.Networking
animator.SetBool("IsJumping", anim.IsJumping); animator.SetBool("IsJumping", anim.IsJumping);
} }
private void CaptureExpectedNetworkId()
{
if (identity == null)
{
identity = GetComponent<NetworkIdentity>();
}
if (identity == null)
{
return;
}
if (identity.NetworkId != 0)
{
expectedNetworkId = identity.NetworkId;
if (ownerSteamId != 0)
{
var mapped = NetworkIdRegistry.GetNetworkIdForSteamId(ownerSteamId);
if (mapped != expectedNetworkId)
{
NetworkIdRegistry.MapSteamIdToNetworkId(ownerSteamId, expectedNetworkId);
}
}
}
}
private bool EnsureMatchingNetworkId(int incomingId, ulong sender)
{
if (identity == null)
{
return false;
}
if (incomingId == 0)
{
return false;
}
int currentId = identity.NetworkId;
if (currentId == incomingId)
{
return true;
}
if (currentId != 0)
{
return false;
}
if (ownerSteamId != 0 && sender != ownerSteamId)
{
return false;
}
int mappedId = ownerSteamId != 0 ? NetworkIdRegistry.GetNetworkIdForSteamId(ownerSteamId) : expectedNetworkId;
if (mappedId != 0)
{
identity.SetNetworkId(mappedId);
if (identity.NetworkId == mappedId)
{
expectedNetworkId = mappedId;
return mappedId == incomingId;
}
return false;
}
if (!NetworkIdAllocator.IsPlayerId(incomingId))
{
return false;
}
identity.SetNetworkId(incomingId);
if (identity.NetworkId != incomingId)
{
return false;
}
expectedNetworkId = incomingId;
if (ownerSteamId != 0)
{
NetworkIdRegistry.MapSteamIdToNetworkId(ownerSteamId, incomingId);
}
return true;
}
public void SendLocalInput(Vector2 moveInput, bool jump) public void SendLocalInput(Vector2 moveInput, bool jump)
{ {
if (networkManager == null || identity == null || !isAuthority) if (networkManager == null || identity == null || !isAuthority)
@@ -370,6 +441,11 @@ namespace MegaKoop.Game.Networking
return; return;
} }
if (identity.NetworkId == 0)
{
return;
}
networkManager.SendToAll(NetworkMessageType.PlayerInput, PlayerInputMessage.Serialize(new PlayerInputMessage(identity.NetworkId, moveInput, jump)), EP2PSend.k_EP2PSendUnreliableNoDelay); networkManager.SendToAll(NetworkMessageType.PlayerInput, PlayerInputMessage.Serialize(new PlayerInputMessage(identity.NetworkId, moveInput, jump)), EP2PSend.k_EP2PSendUnreliableNoDelay);
} }
} }

View File

@@ -348,6 +348,7 @@ namespace MegaKoop.Game.Networking
var identity = instance.GetComponent<NetworkIdentity>(); var identity = instance.GetComponent<NetworkIdentity>();
if (identity != null && pendingRemoteSpawn.NetworkId != 0 && identity.NetworkId != pendingRemoteSpawn.NetworkId) if (identity != null && pendingRemoteSpawn.NetworkId != 0 && identity.NetworkId != pendingRemoteSpawn.NetworkId)
{ {
NetworkIdAllocator.SyncEnemyCursor(pendingRemoteSpawn.NetworkId);
identity.SetNetworkId(pendingRemoteSpawn.NetworkId); identity.SetNetworkId(pendingRemoteSpawn.NetworkId);
} }
} }