2024-03-20 15:45:33 +01:00

614 lines
21 KiB
C#

#if hNETCODE
using System.Collections.Generic;
using UnityEngine;
using Unity.Netcode;
using Unity.Netcode.Components;
namespace Passer.Humanoid {
#pragma warning disable 0618
[RequireComponent(typeof(Unity.Netcode.NetworkObject))]
public partial class HumanoidPlayer : NetworkBehaviour, IHumanoidNetworking {
// temporary (?) dummies
public void Send(bool b) { }
public void Send(byte b) { }
public void Send(int x) { }
public void Send(float f) { }
public void Send(Vector3 v) { }
public void Send(Quaternion q) { }
public bool ReceiveBool() {
return false;
}
public byte ReceiveByte() {
return 0;
}
public int ReceiveInt() {
return 0;
}
public float ReceiveFloat() {
return 0;
}
public Vector3 ReceiveVector3() {
return Vector3.zero;
}
public Quaternion ReceiveQuaternion() {
return Quaternion.identity;
}
// end temporary dummies
public ulong nwId {
get { return identity.NetworkObjectId; }
}
[SerializeField]
protected float _sendRate = 25;
public float sendRate {
get { return _sendRate; }
}
public HumanoidNetworking.Smoothing smoothing => HumanoidNetworking.Smoothing.None;
public bool isLocal { get; set; }
public List<HumanoidControl> humanoids { get; set; }
protected Unity.Netcode.NetworkObject identity;
public ulong GetObjectIdentity(GameObject obj) {
Unity.Netcode.NetworkObject identity = obj.GetComponent<Unity.Netcode.NetworkObject>();
if (identity == null)
return 0;
return identity.NetworkObjectId;
}
public GameObject GetGameObject(ulong objIdentity) {
// Generic Objects
Unity.Netcode.NetworkObject nwObject = GetNetworkObject(objIdentity);
if (nwObject == null) {
// Player Objects
nwObject = NetworkManager.Singleton.ConnectedClients[objIdentity].PlayerObject;
if (nwObject != null)
return nwObject.gameObject;
else
return null;
}
GameObject gameObject = nwObject.gameObject;
return gameObject;
}
float lastSend;
[SerializeField]
protected bool _createLocalRemotes = false;
public bool createLocalRemotes {
get { return _createLocalRemotes; }
set { _createLocalRemotes = value; }
}
protected Vector3 _localRemotePosition = new(0, 0, -1);
public Vector3 localRemotePosition { get { return _localRemotePosition; } }
#region Init
public void Awake() {
if (identity == null)
identity = GetComponent<Unity.Netcode.NetworkObject>();
humanoids = HumanoidNetworking.FindLocalHumanoids();
if (debug <= HumanoidNetworking.DebugLevel.Info)
DebugLog("Found " + humanoids.Count + " Humanoids");
for (int i = 0; i < humanoids.Count; i++) {
HumanoidControl humanoid = humanoids[i];
if (humanoid.isRemote || createLocalRemotes == false)
continue;
humanoid.humanoidNetworking = this;
((IHumanoidNetworking)this).InstantiateHumanoid(humanoid);
}
}
public virtual void OnStartClient() {
Debug.Log("starting client");
//name = name + " " + netId;
NetworkManager nwManager = FindObjectOfType<NetworkManager>();
//short msgType = MsgType.Highest + 2;
//nwManager.client.RegisterHandler(msgType, ClientProcessAvatarPose);
//No idea how this works with Netcode
if (IsServer) {
IHumanoidNetworking[] nwHumanoids = FindObjectsOfType<HumanoidPlayer>();
foreach (IHumanoidNetworking nwHumanoid in nwHumanoids) {
foreach (HumanoidControl humanoid in nwHumanoid.humanoids) {
if (humanoid.isRemote)
continue;
DebugLog("Server Instantiate " + humanoid.nwId + " " + humanoid.humanoidId);
((IHumanoidNetworking)this).InstantiateHumanoid(humanoid);
}
}
}
}
public virtual void OnStartServer() {
Debug.Log("starting server");
//short msgType = MsgType.Highest + 1;
//NetworkServer.RegisterHandler(msgType, ForwardAvatarPose);
}
#endregion
#region Start
public virtual void OnStartLocalPlayer() {
isLocal = true;
name = "HumanoidPlayer(Local)";
humanoids = HumanoidNetworking.FindLocalHumanoids();
if (debug <= HumanoidNetworking.DebugLevel.Info)
Debug.Log((int)identity.NetworkObjectId + ": Found " + humanoids.Count + " Humanoids");
for (int i = 0; i < humanoids.Count; i++) {
HumanoidControl humanoid = humanoids[i];
if (humanoid.isRemote)
continue;
humanoid.nwId = identity.NetworkObjectId;
humanoid.humanoidNetworking = this;
if (debug <= HumanoidNetworking.DebugLevel.Info)
Debug.Log(humanoid.nwId + ": Send Start Humanoid " + humanoid.humanoidId);
((IHumanoidNetworking)this).InstantiateHumanoid(humanoid);
}
foreach (HumanoidControl humanoid in humanoids)
DetectNetworkObjects(humanoid);
NetworkingSpawner spawner = FindObjectOfType<NetworkingSpawner>();
if (spawner != null)
spawner.OnNetworkingStarted();
}
#endregion
#region Update
protected virtual void FixedUpdate() {
//if (Time.time > lastSend + 1 / sendRate) {
// foreach (HumanoidControl humanoid in humanoids) {
// if (!humanoid.isRemote) {
// UpdateHumanoidPose(humanoid);
// if (syncTracking)
// SyncTrackingSpace(humanoid);
// }
// }
// lastSend = Time.time;
//}
}
protected virtual void Update() {
if (smoothing == HumanoidNetworking.Smoothing.Interpolation ||
smoothing == HumanoidNetworking.Smoothing.Extrapolation) {
HumanoidNetworking.SmoothUpdate(humanoids);
}
}
public virtual void LateUpdate() {
if (Time.time > lastSend + 1 / sendRate) {
if (humanoids == null)
return;
foreach (HumanoidControl humanoid in humanoids) {
if (!humanoid.isRemote) {
UpdateHumanoidPose(humanoid);
if (syncTracking)
SyncTrackingSpace(humanoid);
}
}
lastSend = Time.time;
}
}
#endregion
#region Stop
override public void OnDestroy() {
if (debug <= HumanoidNetworking.DebugLevel.Info)
Debug.Log((int)identity.NetworkObjectId + ": Destroy Remote Humanoid");
if (humanoids == null)
return;
foreach (HumanoidControl humanoid in humanoids) {
if (humanoid == null)
continue;
if (humanoid.isRemote) {
if (humanoid.gameObject != null)
Destroy(humanoid.gameObject);
}
else
humanoid.nwId = 0;
}
}
#endregion Stop
//protected virtual void SendToServer(NetworkObject identity, HumanoidNetworking.IMessage msg) {
// byte[] data = msg.Serialize();
// short msgType = MsgType.Highest + 1;
// writer = new NetworkWriter();
// writer.StartMessage(msgType);
// writer.WriteBytesAndSize(data, data.Length);
// writer.FinishMessage();
// identity.connectionToServer.SendWriter(writer, Channels.DefaultUnreliable);
//}
//protected virtual void SendToClients(byte[] data) {
// short msgType = MsgType.Highest + 2;
// NetworkWriter sWriter = new NetworkWriter();
// sWriter.StartMessage(msgType);
// sWriter.WriteBytesAndSize(data, data.Length);
// sWriter.FinishMessage();
// NetworkServer.SendWriterToReady(null, sWriter, Channels.DefaultUnreliable);
//}
#region Instantiate Humanoid
void IHumanoidNetworking.InstantiateHumanoid(HumanoidControl humanoid) {
if (debug <= HumanoidNetworking.DebugLevel.Info)
DebugLog("Send Instantiate Humanoid " + humanoid.humanoidId);
HumanoidNetworking.InstantiateHumanoid instantiateHumanoid = new HumanoidNetworking.InstantiateHumanoid(humanoid);
if (createLocalRemotes)
this.Receive(instantiateHumanoid);
byte[] data = instantiateHumanoid.Serialize();
ForwardInstantiateHumanoidRpc(data);
}
protected HumanoidNetworking.InstantiateHumanoid instantiatedHumanoid;
[Rpc(SendTo.Server)] // @ server
protected virtual void ForwardInstantiateHumanoidRpc(byte[] data) {
instantiatedHumanoid = new HumanoidNetworking.InstantiateHumanoid(data);
HumanoidPlayer[] nwHumanoids = UnityEngine.Object.FindObjectsOfType<HumanoidPlayer>();
foreach (HumanoidPlayer nwHumanoid in nwHumanoids)
nwHumanoid.ServerSendInstantiateHumanoid();
}
protected virtual void ServerSendInstantiateHumanoid() {
if (debug <= HumanoidNetworking.DebugLevel.Info) {
DebugLog("Server Send InstantiateHumanoid: " + instantiatedHumanoid.nwId + "/" + instantiatedHumanoid.humanoidId);
}
byte[] data = instantiatedHumanoid.Serialize();
ReceiveInitiateHumanoidRpc(data);
}
[Rpc(SendTo.NotServer)] // @ remote client
protected virtual void ReceiveInitiateHumanoidRpc(byte[] data) {
HumanoidNetworking.InstantiateHumanoid instantiateHumanoid = new HumanoidNetworking.InstantiateHumanoid(data);
if (debug <= HumanoidNetworking.DebugLevel.Info)
DebugLog("Received Instantiate Humanoid " + instantiateHumanoid.nwId + "/" + instantiateHumanoid.humanoidId);
if (instantiateHumanoid.nwId != identity.NetworkObjectId) {
// Get the right HumanoidPlayer for this humanoid
//NetworkInstanceId netId = new NetworkInstanceId((uint)instantiateHumanoid.nwId);
//GameObject gameObject = ClientScene.FindLocalObject(netId);
Unity.Netcode.NetworkObject nwObject = GetNetworkObject(instantiatedHumanoid.nwId);
GameObject gameObject = nwObject.gameObject;
HumanoidPlayer humanoidPlayer = gameObject.GetComponent<HumanoidPlayer>();
if (humanoidPlayer != null)
humanoidPlayer.ReceiveInstantiate(data);
else
DebugError("Could not find HumanoidPlayer with id = " + instantiateHumanoid.nwId);
}
else
this.ReceiveInstantiate(data);
}
#endregion Instantiate Humanoid
#region Destroy Humanoid
void IHumanoidNetworking.DestroyHumanoid(HumanoidControl humanoid) {
if (humanoid == null)
return;
if (debug <= HumanoidNetworking.DebugLevel.Info)
DebugLog("Destroy Humanoid " + humanoid.humanoidId);
HumanoidNetworking.DestroyHumanoid destroyHumanoid = new HumanoidNetworking.DestroyHumanoid(humanoid);
byte[] data = destroyHumanoid.Serialize();
ForwardDestroyHumanoidRpc(data);
}
[Rpc(SendTo.Server)] // @ server
private void ForwardDestroyHumanoidRpc(byte[] data) {
if (debug <= HumanoidNetworking.DebugLevel.Debug)
DebugLog("Forward DestroyHumanoid");
ReceiveDestroyHumanoidRpc(data);
}
[Rpc(SendTo.NotServer)]
private void ReceiveDestroyHumanoidRpc(byte[] data) {
this.ReceiveDestroy(data);
}
#endregion Destroy Humanoid
#region Pose
public HumanoidNetworking.HumanoidPose lastHumanoidPose { get; set; }
public void UpdateHumanoidPose(HumanoidControl humanoid) {
if (debug <= HumanoidNetworking.DebugLevel.Debug)
DebugLog("Send Pose Humanoid " + humanoid.humanoidId + " nwId: " + humanoid.nwId);
HumanoidNetworking.HumanoidPose humanoidPose =
new HumanoidNetworking.HumanoidPose(humanoid, Time.time, syncFingerSwing, syncFace);
if (createLocalRemotes)
this.Receive(humanoidPose);
byte[] data = humanoidPose.Serialize();
ForwardHumanoidPoseRpc(data);
}
[Rpc(SendTo.Server)]
protected virtual void ForwardHumanoidPoseRpc(byte[] data) {
if (debug <= HumanoidNetworking.DebugLevel.Debug) {
HumanoidNetworking.HumanoidPose humanoidPose = new HumanoidNetworking.HumanoidPose(data);
DebugLog("Forward HumanoidPose " + humanoidPose.nwId + "/" + humanoidPose.humanoidId);
}
ReceiveHumanoidPoseRpc(data);
}
[Rpc(SendTo.NotServer)]
protected virtual void ReceiveHumanoidPoseRpc(byte[] data) {
this.ReceiveHumanoidPose(data);
}
#endregion
#region Grab
void IHumanoidNetworking.Grab(HandTarget handTarget, GameObject obj, bool rangeCheck, HandTarget.GrabType grabType) {
if (debug <= HumanoidNetworking.DebugLevel.Info)
Debug.Log(handTarget.humanoid.nwId + ": Grab " + obj);
ulong objIdentity = GetObjectIdentity(obj);
if (objIdentity == 0) {
if (debug <= HumanoidNetworking.DebugLevel.Error)
Debug.LogError("Grabbed object " + obj + " does not have a network identity");
return;
}
HumanoidNetworking.Grab grab = new HumanoidNetworking.Grab(handTarget, objIdentity, rangeCheck, grabType);
byte[] data = grab.Serialize();
ForwardGrabRpc(data);
}
[Rpc(SendTo.Server)]
protected virtual void ForwardGrabRpc(byte[] data) {
ReceiveGrabRpc(data);
}
[Rpc(SendTo.NotServer)]
protected virtual void ReceiveGrabRpc(byte[] data) {
this.ReceiveGrab(data);
}
#endregion
#region Let Go
void IHumanoidNetworking.LetGo(HandTarget handTarget) {
if (debug <= HumanoidNetworking.DebugLevel.Info)
DebugLog("LetGo");
HumanoidNetworking.LetGo letGo = new HumanoidNetworking.LetGo(handTarget);
byte[] data = letGo.Serialize();
ForwardLetGoRpc(data);
}
[Rpc(SendTo.Server)]
protected virtual void ForwardLetGoRpc(byte[] data) {
ReceiveLetGoRpc(data);
}
[Rpc(SendTo.NotServer)]
protected virtual void ReceiveLetGoRpc(byte[] data) {
this.ReceiveLetGo(data);
}
#endregion
#region ChangeAvatar
void IHumanoidNetworking.ChangeAvatar(HumanoidControl humanoid, string avatarPrefabName, string possessionLocation) {
if (debug <= HumanoidNetworking.DebugLevel.Info)
DebugLog("Change Avatar: " + avatarPrefabName);
HumanoidNetworking.ChangeAvatar changeAvatar = new HumanoidNetworking.ChangeAvatar(humanoid, avatarPrefabName, possessionLocation);
byte[] data = changeAvatar.Serialize();
ForwardChangeAvatarRpc(data);
}
[Rpc(SendTo.Server)]
protected virtual void ForwardChangeAvatarRpc(byte[] data) {
ReceiveChangeAvatarRpc(data);
}
[Rpc(SendTo.NotServer)]
protected virtual void ReceiveChangeAvatarRpc(byte[] data) {
this.ReceiveChangeAvatar(data);
}
#endregion
#region Tracking
public void SyncTrackingSpace(HumanoidControl humanoid) {
Transform trackingTransform = HumanoidNetworking.GetTrackingTransform(humanoid);
if (trackingTransform == null)
return;
HumanoidNetworking.SyncTrackingSpace syncTracking = new HumanoidNetworking.SyncTrackingSpace(humanoid, trackingTransform.position, trackingTransform.rotation);
byte[] data = syncTracking.Serialize();
ForwardSyncTrackingRpc(data);
}
[Rpc(SendTo.Server)]
protected virtual void ForwardSyncTrackingRpc(byte[] data) {
ReceiveSyncTrackingRpc(data);
}
[Rpc(SendTo.NotServer)]
protected virtual void ReceiveSyncTrackingRpc(byte[] data) {
this.ReceiveSyncTrackingSpace(data);
}
#endregion
#region Network Sync
void IHumanoidNetworking.ReenableNetworkSync(GameObject obj) {
ReenableNetworkSync(obj);
}
void IHumanoidNetworking.DisableNetworkSync(GameObject obj) {
DisableNetworkSync(obj);
}
public static void ReenableNetworkSync(GameObject obj) {
NetworkTransform networkTransform = obj.GetComponent<NetworkTransform>();
if (networkTransform != null) {
networkTransform.enabled = true;
}
}
public static void DisableNetworkSync(GameObject obj) {
NetworkTransform networkTransform = obj.GetComponent<NetworkTransform>();
if (networkTransform != null) {
networkTransform.enabled = false;
}
}
#endregion Network Sync
#region Network Object
protected NetworkObject[] networkObjects;
protected void DetectNetworkObjects(HumanoidControl humanoid) {
if (networkObjects != null)
Debug.LogError("Network Objects currently support only one humanoid");
networkObjects = humanoid.GetComponentsInChildren<NetworkObject>();
}
public int GetNwObjectId(NetworkObject nwObject) {
for (int i = 0; i < networkObjects.Length; i++) {
if (networkObjects[i] == nwObject)
return i;
}
return -1;
}
#region Void Event
//public void RPC(FunctionCall functionCall) {
// RPCVoidServerRpc(functionCall.targetGameObject, functionCall.methodName);
//}
//[Rpc(SendTo.Server)] // @ server
//public void RPCVoidServerRpc(GameObject target, string methodName) {
// RPCVoidRpc(target, methodName);
//}
//[Rpc(SendTo.NotServer)] // @ remote client
//public void RPCVoidRpc(GameObject targetGameObject, string methodName) {
// Debug.Log("RPC: " + methodName);
// FunctionCall.Execute(targetGameObject, methodName);
//}
#endregion
#region Bool Event
//public void RPC(FunctionCall functionCall, bool value) {
// RPCBoolServerRpc(functionCall.targetGameObject, functionCall.methodName, value);
//}
//[Rpc(SendTo.Server)] // @ server
//public void RPCBoolServerRpc(GameObject target, string methodName, bool value) {
// RPCBoolRpc(target, methodName, value);
//}
//[Rpc(SendTo.NotServer)] // @ remote client
//public void RPCBoolRpc(GameObject target, string methodName, bool value) {
// FunctionCall.Execute(target, methodName, value);
//}
#endregion
#region String Event
//public void RPC(FunctionCall functionCall, string value) {
// Debug.Log("HC RPC functioncall " + value);
// //CmdRPCString(nwObjectId, functionCall.methodName, value);
//}
//[Command] // @ server
//public void CmdRPCString(int nwObjectId, string methodName, string value) {
// Debug.Log("HC Cmd functioncall " + value);
// RpcRPCString(nwObjectId, methodName, value);
//}
//[ClientRpc] // @ remote client
//public void RpcRPCString(int nwObjectId, string methodName, string value) {
// Debug.Log("HC Client RPC functioncall " + value);
// GameObject target = networkObjects[nwObjectId].gameObject;
// FunctionCall.Execute(target, methodName, value);
//}
#endregion
#endregion Network Object
#region Debug
public void DebugLog(string message) {
Debug.Log(identity.NetworkObjectId + ": " + message);
}
public void DebugWarning(string message) {
Debug.LogWarning(identity.NetworkObjectId + ": " + message);
}
public void DebugError(string message) {
Debug.LogError(identity.NetworkObjectId + ": " + message);
}
#endregion
#pragma warning restore 0618
}
#endif
}