This commit is contained in:
2025-10-24 19:56:38 +02:00
parent 33d34c251b
commit b13d748ec4
7 changed files with 815 additions and 71 deletions

View File

@@ -0,0 +1,216 @@
using Steamworks;
using UnityEngine;
namespace MegaKoop.Game.Networking
{
/// <summary>
/// Host-authoritative transform replication that mirrors state to all peers via Steam P2P messages.
/// </summary>
[DisallowMultipleComponent]
public class SteamNetworkTransform : MonoBehaviour
{
[Header("References")]
[SerializeField] private Transform targetTransform;
[SerializeField] private NetworkIdentity identity;
[SerializeField] private Rigidbody trackedRigidbody;
[SerializeField] private UnityEngine.AI.NavMeshAgent trackedNavMeshAgent;
[Header("Authority")]
[SerializeField] private bool authorityIsHost = true;
[SerializeField] private bool simulateWhenDisconnected = true;
[Header("Synchronization")]
[SerializeField] private float broadcastInterval = 0.05f;
[SerializeField] private float remoteLerpSpeed = 12f;
[SerializeField] private float teleportThreshold = 4f;
private SteamCoopNetworkManager networkManager;
private float broadcastTimer;
private bool isRegistered;
private Vector3 remoteTargetPosition;
private Quaternion remoteTargetRotation;
private Vector3 remoteTargetVelocity;
private bool haveRemoteState;
private void Awake()
{
if (targetTransform == null)
{
targetTransform = transform;
}
if (identity == null)
{
identity = GetComponent<NetworkIdentity>();
}
if (trackedRigidbody == null)
{
trackedRigidbody = GetComponent<Rigidbody>();
}
if (trackedNavMeshAgent == null)
{
trackedNavMeshAgent = GetComponent<UnityEngine.AI.NavMeshAgent>();
}
remoteTargetPosition = targetTransform.position;
remoteTargetRotation = targetTransform.rotation;
remoteTargetVelocity = Vector3.zero;
broadcastTimer = Random.Range(0f, Mathf.Max(0.01f, broadcastInterval));
}
private void OnEnable()
{
EnsureNetworkManager();
RegisterHandlers();
}
private void OnDisable()
{
UnregisterHandlers();
}
private void Update()
{
RefreshNetworkManager();
if (HasAuthority())
{
broadcastTimer -= Time.deltaTime;
if (broadcastTimer <= 0f)
{
BroadcastState();
broadcastTimer = Mathf.Max(0.01f, broadcastInterval);
}
}
else if (haveRemoteState)
{
float lerpFactor = Mathf.Clamp01(remoteLerpSpeed * Time.deltaTime);
Vector3 currentPosition = targetTransform.position;
float sqrDistance = (remoteTargetPosition - currentPosition).sqrMagnitude;
if (sqrDistance >= teleportThreshold * teleportThreshold)
{
targetTransform.SetPositionAndRotation(remoteTargetPosition, remoteTargetRotation);
}
else
{
targetTransform.position = Vector3.Lerp(currentPosition, remoteTargetPosition, lerpFactor);
targetTransform.rotation = Quaternion.Slerp(targetTransform.rotation, remoteTargetRotation, lerpFactor);
}
}
}
private void RefreshNetworkManager()
{
if (networkManager == null)
{
networkManager = SteamCoopNetworkManager.Instance;
if (networkManager != null && isActiveAndEnabled)
{
RegisterHandlers();
}
}
}
private void EnsureNetworkManager()
{
RefreshNetworkManager();
}
private bool HasAuthority()
{
if (!authorityIsHost)
{
return true;
}
if (networkManager == null)
{
return simulateWhenDisconnected;
}
if (!networkManager.IsConnected)
{
return simulateWhenDisconnected;
}
return networkManager.IsHost;
}
private void BroadcastState()
{
if (identity == null || targetTransform == null || networkManager == null)
{
return;
}
Vector3 velocity = Vector3.zero;
if (trackedNavMeshAgent != null && trackedNavMeshAgent.enabled)
{
velocity = trackedNavMeshAgent.velocity;
}
else if (trackedRigidbody != null)
{
velocity = trackedRigidbody.linearVelocity;
}
var message = new CharacterTransformMessage(identity.NetworkId, targetTransform.position, targetTransform.rotation, velocity);
byte[] payload = CharacterTransformMessage.Serialize(message);
networkManager.SendToAll(NetworkMessageType.CharacterTransform, payload, EP2PSend.k_EP2PSendUnreliableNoDelay);
}
private void RegisterHandlers()
{
if (isRegistered || networkManager == null)
{
return;
}
networkManager.RegisterHandler(NetworkMessageType.CharacterTransform, HandleTransformMessage);
isRegistered = true;
}
private void UnregisterHandlers()
{
if (!isRegistered || networkManager == null)
{
return;
}
networkManager.UnregisterHandler(NetworkMessageType.CharacterTransform, HandleTransformMessage);
isRegistered = false;
}
private void HandleTransformMessage(NetworkMessage message)
{
if (identity == null || targetTransform == null)
{
return;
}
if (HasAuthority())
{
return;
}
CharacterTransformMessage transformMessage = CharacterTransformMessage.Deserialize(message.Payload);
if (transformMessage.NetworkId != identity.NetworkId)
{
return;
}
remoteTargetPosition = transformMessage.Position;
remoteTargetRotation = transformMessage.Rotation;
remoteTargetVelocity = transformMessage.Velocity;
haveRemoteState = true;
}
private void OnValidate()
{
broadcastInterval = Mathf.Max(0.01f, broadcastInterval);
remoteLerpSpeed = Mathf.Max(0f, remoteLerpSpeed);
teleportThreshold = Mathf.Max(0.01f, teleportThreshold);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 88efaaed4187a0ee8ad63b619f65e970