From ff70bad234db4221c8954930371e31e32cda425e Mon Sep 17 00:00:00 2001 From: Aaro Varis Date: Fri, 28 Feb 2025 11:13:16 +0200 Subject: [PATCH] Mogus --- BoneSync/BoneSync.csproj | 8 +- BoneSync/Networking/ByteEncoder.cs | 26 +++ .../Messages/ObjectDamageMessage.cs | 80 ++++++++ .../Networking/Messages/ObjectSyncMessage.cs | 1 + .../Messages/RegisterSyncableMessage.cs | 4 +- BoneSync/Networking/PacketTypes.cs | 1 + .../Networking/Transport/SteamTransport.cs | 9 +- BoneSync/Patching/ObjectHealthPatches.cs | 86 +++++++++ .../{Syncable.cs => SyncableBase.cs} | 139 +++++--------- BoneSync/Sync/Components/SyncableDamage.cs | 58 ++++++ .../Sync/Components/SyncableNetworking.cs | 46 +++++ BoneSync/Sync/Components/SyncablePhysics.cs | 86 +++++++++ BoneSync/Sync/ObjectSync.cs | 171 ++++-------------- BoneSync/Sync/ObjectSyncCache.cs | 140 ++++++++++++++ 14 files changed, 622 insertions(+), 233 deletions(-) create mode 100644 BoneSync/Networking/Messages/ObjectDamageMessage.cs create mode 100644 BoneSync/Patching/ObjectHealthPatches.cs rename BoneSync/Sync/Components/{Syncable.cs => SyncableBase.cs} (51%) create mode 100644 BoneSync/Sync/Components/SyncableDamage.cs create mode 100644 BoneSync/Sync/Components/SyncableNetworking.cs create mode 100644 BoneSync/Sync/Components/SyncablePhysics.cs create mode 100644 BoneSync/Sync/ObjectSyncCache.cs diff --git a/BoneSync/BoneSync.csproj b/BoneSync/BoneSync.csproj index 01c145f..71ad709 100644 --- a/BoneSync/BoneSync.csproj +++ b/BoneSync/BoneSync.csproj @@ -113,11 +113,17 @@ + - + + + + + + diff --git a/BoneSync/Networking/ByteEncoder.cs b/BoneSync/Networking/ByteEncoder.cs index 664947c..6d223d8 100644 --- a/BoneSync/Networking/ByteEncoder.cs +++ b/BoneSync/Networking/ByteEncoder.cs @@ -1,4 +1,5 @@ using StressLevelZero; +using StressLevelZero.Combat; using System; using System.Collections.Generic; using System.Linq; @@ -52,6 +53,16 @@ namespace BoneSync.Networking return value; } + public void WriteBool(bool value) + { + WriteByte((byte)(value ? 1 : 0)); + } + + public bool ReadBool() + { + return ReadByte() == 1; + } + public void WriteInt(int value) { WriteBytes(BitConverter.GetBytes(value)); @@ -168,5 +179,20 @@ namespace BoneSync.Networking scale = scale }; } + + public void WriteEnum(T value) where T : Enum + { + WriteByte((byte)(object)value); + } + public T ReadEnum() where T : Enum + { + return (T)(object)ReadByte(); + } + + public void WriteSLZAttack(Attack attack) + { + WriteEnum(attack.attackType); + WriteFloat(attack.damage); + } } } diff --git a/BoneSync/Networking/Messages/ObjectDamageMessage.cs b/BoneSync/Networking/Messages/ObjectDamageMessage.cs new file mode 100644 index 0000000..06a6bdc --- /dev/null +++ b/BoneSync/Networking/Messages/ObjectDamageMessage.cs @@ -0,0 +1,80 @@ +using StressLevelZero.Combat; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace BoneSync.Networking.Messages +{ + public struct ObjectHealthInfo + { + public float _health; + public int _hits; + public Vector3 normal; + public float damage; + public bool crit; + public AttackType attackType; + public ObjectHealthInfo(float health, int hits, Vector3 normal, float damage, bool crit, AttackType attackType) + { + _health = health; + _hits = hits; + this.normal = normal; + this.damage = damage; + this.crit = crit; + this.attackType = attackType; + } + } + public enum ObjectDamageType + { + Unknown = 0, + SyncHealth = 1, + DestructibleTakeDamage = 2, + PropHealthTakeDamage = 3, + } + public struct ObjectDamageInfo + { + public ushort objectId; + public ObjectDamageType eventType; + public ObjectHealthInfo objectHealthInfo; + } + + [PacketType(PacketType.ObjectEvent), PacketReliability(PacketReliability.Reliable)] + public class ObjectDamageMessage : NetworkMessage + { + public ObjectDamageInfo objectEventInfo => _objectEventInfo; + private ObjectDamageInfo _objectEventInfo; + + public ObjectDamageMessage(ObjectDamageInfo objectEventInfo) + { + _objectEventInfo = objectEventInfo; + byteEncoder.WriteUShort(_objectEventInfo.objectId); + byteEncoder.WriteEnum(_objectEventInfo.eventType); + byteEncoder.WriteFloat(_objectEventInfo.objectHealthInfo._health); + byteEncoder.WriteInt(_objectEventInfo.objectHealthInfo._hits); + if (_objectEventInfo.eventType == ObjectDamageType.SyncHealth) return; // No need to write the rest of the data + byteEncoder.WriteVector3(_objectEventInfo.objectHealthInfo.normal); + byteEncoder.WriteFloat(_objectEventInfo.objectHealthInfo.damage); + byteEncoder.WriteBool(_objectEventInfo.objectHealthInfo.crit); + } + + public ObjectDamageMessage(Packet packet) + { + byteEncoder.WriteBytes(packet.Data); + _objectEventInfo.objectId = byteEncoder.ReadUShort(); + _objectEventInfo.eventType = byteEncoder.ReadEnum(); + _objectEventInfo.objectHealthInfo._health = byteEncoder.ReadFloat(); + _objectEventInfo.objectHealthInfo._hits = byteEncoder.ReadInt(); + if (_objectEventInfo.eventType == ObjectDamageType.SyncHealth) return; // No need to read the rest of the data + _objectEventInfo.objectHealthInfo.normal = byteEncoder.ReadVector3(); + _objectEventInfo.objectHealthInfo.damage = byteEncoder.ReadFloat(); + _objectEventInfo.objectHealthInfo.crit = byteEncoder.ReadBool(); + } + + public override void Execute() + { + + } + } +} diff --git a/BoneSync/Networking/Messages/ObjectSyncMessage.cs b/BoneSync/Networking/Messages/ObjectSyncMessage.cs index 66caf86..8bdcc42 100644 --- a/BoneSync/Networking/Messages/ObjectSyncMessage.cs +++ b/BoneSync/Networking/Messages/ObjectSyncMessage.cs @@ -13,6 +13,7 @@ namespace BoneSync.Networking.Messages { public SimpleTransform transform; public Vector3 velocity; + public Vector3 angularVelocity; } public struct ObjectSyncMessageData { diff --git a/BoneSync/Networking/Messages/RegisterSyncableMessage.cs b/BoneSync/Networking/Messages/RegisterSyncableMessage.cs index 8275f30..495bee8 100644 --- a/BoneSync/Networking/Messages/RegisterSyncableMessage.cs +++ b/BoneSync/Networking/Messages/RegisterSyncableMessage.cs @@ -28,7 +28,7 @@ namespace BoneSync.Networking.Messages public RegisterSyncableMessage(RegisterSyncableInfo info) { _info = info; - byteEncoder.WriteByte((byte)_info.type); + byteEncoder.WriteEnum(_info.type); byteEncoder.WriteString(_info.transformPath); byteEncoder.WriteUlong(_info.ownerId); byteEncoder.WriteUShort(_info.id); @@ -38,7 +38,7 @@ namespace BoneSync.Networking.Messages public RegisterSyncableMessage(Packet packet) { byteEncoder.WriteBytes(packet.Data); - _info.type = (RegisterSyncType)byteEncoder.ReadByte(); + _info.type = byteEncoder.ReadEnum(); _info.transformPath = byteEncoder.ReadString(); _info.ownerId = byteEncoder.ReadUlong(); _info.id = byteEncoder.ReadUShort(); diff --git a/BoneSync/Networking/PacketTypes.cs b/BoneSync/Networking/PacketTypes.cs index 8f681f3..3ebf0ae 100644 --- a/BoneSync/Networking/PacketTypes.cs +++ b/BoneSync/Networking/PacketTypes.cs @@ -13,5 +13,6 @@ namespace BoneSync.Networking PlayerSync = 2, RegisterSyncable = 3, ObjectSync = 4, + ObjectEvent = 5, } } diff --git a/BoneSync/Networking/Transport/SteamTransport.cs b/BoneSync/Networking/Transport/SteamTransport.cs index f6edbfe..e1998d5 100644 --- a/BoneSync/Networking/Transport/SteamTransport.cs +++ b/BoneSync/Networking/Transport/SteamTransport.cs @@ -72,17 +72,18 @@ namespace BoneSync.Networking.Transport return processed > 0; } - public void SendP2P(SteamId peer, byte[] data) + public void SendP2P(SteamId peer, byte[] data, P2PSend sendType) { if (peer == BoneSync.lobby.GetLocalId()) { //MelonLogger.Msg("Trying to send packet to self"); return; } - SteamNetworking.SendP2PPacket(peer, data, data.Length, 0, P2PSend.Reliable); + SteamNetworking.SendP2PPacket(peer, data, data.Length, 0, sendType); } public override void Send(Packet packet) { + P2PSend sendType = (P2PSend)packet.Info.reliability; LobbyManager.LobbyManager _instance = BoneSync.lobby; if (_instance == null) { @@ -93,14 +94,14 @@ namespace BoneSync.Networking.Transport { foreach (SteamId peer in _instance.GetPeers()) { - SendP2P(peer, packet.ToBytes()); + SendP2P(peer, packet.ToBytes(), sendType); } return; } else { - SendP2P(packet.Info.receiverId, packet.ToBytes()); + SendP2P(packet.Info.receiverId, packet.ToBytes(), sendType); } } diff --git a/BoneSync/Patching/ObjectHealthPatches.cs b/BoneSync/Patching/ObjectHealthPatches.cs new file mode 100644 index 0000000..79349a9 --- /dev/null +++ b/BoneSync/Patching/ObjectHealthPatches.cs @@ -0,0 +1,86 @@ +using BoneSync.Networking.Messages; +using BoneSync.Sync; +using BoneSync.Sync.Components; +using HarmonyLib; +using StressLevelZero.Combat; +using StressLevelZero.Props; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace BoneSync.Patching +{ + public static class CallPatchedMethods + { + public static bool allowDamageMethodCall + { + private set; + get; + } + public static void TakeDamage(ObjectDestructable __instance, ref Vector3 normal, ref float damage, ref bool crit, ref AttackType attackType) + { + allowDamageMethodCall = true; + __instance.TakeDamage(normal, damage, crit, attackType); + allowDamageMethodCall = false; + } + + public static void TakeDamage(Prop_Health __instance, ref float damage, ref bool crit, ref AttackType attackType) + { + allowDamageMethodCall = true; + __instance.TAKEDAMAGE(damage, crit, attackType); + allowDamageMethodCall = false; + } + } + + [HarmonyPatch(typeof(ObjectDestructable))] + public class ObjectDestructablePatches + { + [HarmonyPatch(nameof(ObjectDestructable.TakeDamage))] + [HarmonyPrefix] + private static bool TakeDamagePatch(ObjectDestructable __instance, ref Vector3 normal, ref float damage, ref bool crit, ref AttackType attackType) + { + if (CallPatchedMethods.allowDamageMethodCall) return true; + MelonLoader.MelonLogger.Msg("ObjectDestructable.TakeDamage: " + damage); + Syncable syncable = ObjectSync.GetSyncableFromCache(__instance.gameObject); + if (syncable != null) + { + if (!syncable.Registered) return true; + MelonLoader.MelonLogger.Msg("Patch: ObjectDestructable.TakeDamage: " + damage + " " + syncable.gameObject.name); + ObjectHealthInfo objectHealthInfo = new ObjectHealthInfo(__instance._health, __instance._hits, normal, damage, crit, attackType); + + ObjectSync.SendObjectDamageMessage(syncable, ObjectDamageType.DestructibleTakeDamage, objectHealthInfo); + + return false; // prevent networked objects from taking damage locally + } + return true; + } + } + + [HarmonyPatch(typeof(Prop_Health))] + public class PropHealthPatches + { + [HarmonyPatch(nameof(Prop_Health.TAKEDAMAGE))] + [HarmonyPrefix] + private static bool TakeDamagePatch(Prop_Health __instance, ref float damage, ref bool crit, ref AttackType attackType) + { + if (CallPatchedMethods.allowDamageMethodCall) return true; + MelonLoader.MelonLogger.Msg("Prop_Health.TAKEDAMAGE: " + damage); + Syncable syncable = ObjectSync.GetSyncableFromCache(__instance.gameObject); + if (syncable != null) + { + if (!syncable.Registered) return true; + MelonLoader.MelonLogger.Msg("Patch: Prop_Health.TAKEDAMAGE: " + damage + " " + syncable.gameObject.name); + ObjectHealthInfo objectHealthInfo = new ObjectHealthInfo(__instance.cur_Health, __instance.hits, Vector3.zero, damage, crit, attackType); + + ObjectSync.SendObjectDamageMessage(syncable, ObjectDamageType.PropHealthTakeDamage, objectHealthInfo); + + return false; // prevent networked objects from taking damage locally + } + return true; + } + } +} diff --git a/BoneSync/Sync/Components/Syncable.cs b/BoneSync/Sync/Components/SyncableBase.cs similarity index 51% rename from BoneSync/Sync/Components/Syncable.cs rename to BoneSync/Sync/Components/SyncableBase.cs index ec728dd..1598fbe 100644 --- a/BoneSync/Sync/Components/Syncable.cs +++ b/BoneSync/Sync/Components/SyncableBase.cs @@ -12,6 +12,9 @@ using BoneSync.Networking.Messages; using BoneSync.Networking; using StressLevelZero.Data; using System.Collections; +using StressLevelZero.Props; +using BoneSync.Patching; +using StressLevelZero.Props.Weapons; namespace BoneSync.Sync.Components @@ -45,13 +48,13 @@ namespace BoneSync.Sync.Components } [RegisterTypeInIl2Cpp] - public class Syncable : MonoBehaviour + public partial class Syncable : MonoBehaviour { public const int SYNC_FPS = 20; - public static List syncablesCache = new List(); - public Syncable(IntPtr intPtr) : base(intPtr) { - syncablesCache.Add(this); + public static Dictionary syncablesCache = new Dictionary(); + public Syncable(IntPtr intPtr) : base(intPtr) { + syncablesCache[gameObject] = this; } private bool _syncCoroutineRunning; @@ -62,7 +65,7 @@ namespace BoneSync.Sync.Components get; } private ushort _syncId; - private ulong _lastSyncTime; + private float _lastSyncTime; private bool _attemptedRegister; @@ -70,6 +73,15 @@ namespace BoneSync.Sync.Components public bool isStale => Time.time - _lastSyncTime > 5f; public bool isOwner => _ownerId == BoneSync.lobby.GetLocalId(); + public bool ShouldSendSync() + { + if (!Registered) return false; + if (!isOwner) return false; + if (isStale) return true; + + return false; + } + public ushort GetSyncId() => _syncId; public void SetSyncId(ushort id) { @@ -78,63 +90,24 @@ namespace BoneSync.Sync.Components ObjectSyncCache.UpdateSyncId(this); } - public InteractableHost interactableHost; - public InteractableHostManager interactableManager; - public Poolee poolee; + public InteractableHost interactableHost { private set; get; } + public InteractableHostManager interactableManager { private set; get; } + public Poolee poolee { private set; get; } + + private Prop_Health propHealth; + private ObjectDestructable objectDestructable; private Rigidbody[] rigidbodies; - private Transform[] transforms; + private Transform[] _transforms; + + private Gun gun; + private Magazine magazine; + + private Plug[] plugs; - private void SetKinematic(bool kinematic) - { - foreach (Rigidbody rb in rigidbodies) - { - rb.isKinematic = kinematic; - } - } - public ObjectSyncTransform[] GetObjectSyncTransforms() - { - ObjectSyncTransform[] objectSyncTransforms = new ObjectSyncTransform[transforms.Length]; - for (int i = 0; i < transforms.Length; i++) - { - objectSyncTransforms[i] = new ObjectSyncTransform() - { - transform = new SimpleTransform(transforms[i]), - velocity = Vector3.zero - }; - } - return objectSyncTransforms; - } - public void ApplyObjectSyncTransforms(ObjectSyncTransform[] objectSyncTransforms) - { - if (objectSyncTransforms.Length != transforms.Length) - { - MelonLogger.Warning("ObjectSyncTransforms length mismatch: " + objectSyncTransforms.Length + " != " + transforms.Length); - return; - } - for (int i = 0; i < objectSyncTransforms.Length; i++) - { - ObjectSyncTransform objectSyncTransform = objectSyncTransforms[i]; - transforms[i].ApplySimpleTransform(objectSyncTransform.transform); - } - } - public async Task SyncCoroutineAsync() - { - MelonLogger.Msg("Running sync coroutine for: " + gameObject.name); - if (_syncCoroutineRunning) return; - _syncCoroutineRunning = true; - while (isOwner) - { - MelonLogger.Msg("Sending object sync message for: " + gameObject.name); - ObjectSync.SendObjectSyncMessage(this); - await Task.Delay( GetSyncId() == 0 ? 1000 : 1000 / SYNC_FPS); - } - _syncCoroutineRunning = false; - return; - } public void OnEnable() { @@ -142,22 +115,6 @@ namespace BoneSync.Sync.Components MelonLogger.Msg("Syncable enabled: " + transform.GetPath()); } - private void UpdateTransformList() - { - if (interactableManager) - { - transforms = interactableManager.hosts.Select(host => host.transform).ToArray(); - } - else if (interactableHost) - { - transforms = new Transform[] { interactableHost.transform }; - } - else if (poolee) - { - transforms = new Transform[] { poolee.transform }; - } - } - public string GetSyncableWorldPath() { if (poolee && poolee.pool) @@ -178,13 +135,18 @@ namespace BoneSync.Sync.Components interactableManager = GetComponent(); interactableHost = GetComponent(); poolee = GetComponent(); - rigidbodies = GetComponentsInChildren(); + propHealth = GetComponent(); + objectDestructable = GetComponent(); + gun = GetComponent(); + magazine = GetComponent(); + plugs = GetComponentsInChildren(); + //rigidbodies = GetComponentsInChildren(); UpdateTransformList(); ObjectSyncCache.AddSyncable(this); } - public bool ShouldSync() + public bool CanBeSynced() { FindComponents(); if (interactableManager && interactableManager.hosts.Count > 0) @@ -199,8 +161,15 @@ namespace BoneSync.Sync.Components return false; } + public void OnDestroy() + { + DiscardSyncable(); + MelonLogger.Msg("Syncable destroyed: " + transform.GetPath()); + } + public void DiscardSyncable() { + syncablesCache.Remove(gameObject); ObjectSyncCache.RemoveSyncable(this); Destroy(this); } @@ -216,34 +185,14 @@ namespace BoneSync.Sync.Components MelonLogger.Warning("Registered Syncable disabled: " + transform.GetPath()); } - public void SetOwner(ulong ownerId) - { - _ownerId = ownerId; - MelonLogger.Msg("Set owner for " + gameObject.name + " to " + ownerId); - _ = SyncCoroutineAsync(); - UpdateKinematic(); - } - - private void UpdateKinematic() - { - SetKinematic(_ownerId != BoneSync.lobby.GetLocalId() && Registered); - } - - private void _SendRegisterSync() - { - MelonLogger.Msg("Registering syncable object: " + gameObject.name); - SetOwner(BoneSync.lobby.GetLocalId()); - SetSyncId(ObjectSync.SendRegisterSyncableMessage(this)); - } public void RegisterSyncable() { if (!BoneSync.lobby.IsConnected()) return; if (_attemptedRegister) return; if (Registered) return; - if (!ShouldSync()) return; + if (!CanBeSynced()) return; _attemptedRegister = true; _SendRegisterSync(); } - } } diff --git a/BoneSync/Sync/Components/SyncableDamage.cs b/BoneSync/Sync/Components/SyncableDamage.cs new file mode 100644 index 0000000..22e6836 --- /dev/null +++ b/BoneSync/Sync/Components/SyncableDamage.cs @@ -0,0 +1,58 @@ +using BoneSync.Networking.Messages; +using BoneSync.Patching; +using MelonLoader; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace BoneSync.Sync.Components +{ + public partial class Syncable : MonoBehaviour + { + private void SetHealth(float health, int hits = 0) + { + if (gameObject.activeSelf == false && health > 0) + { + gameObject.SetActive(true); + } + + if (propHealth) + { + propHealth.cur_Health = health; + propHealth.hits = hits; + } + if (objectDestructable) + { + objectDestructable._health = health; + objectDestructable._hits = hits; + } + } + + public void Damage(ObjectDamageInfo damageInfo) + { + ObjectHealthInfo healthInfo = damageInfo.objectHealthInfo; + SetHealth(healthInfo._health, healthInfo._hits); // always set health first + + ObjectDamageType eventType = damageInfo.eventType; + if (eventType == ObjectDamageType.SyncHealth) return; + + if (eventType == ObjectDamageType.DestructibleTakeDamage && objectDestructable) + { + MelonLogger.Msg("NetworkDestructableTakeDamage: " + healthInfo.damage); + CallPatchedMethods.TakeDamage(objectDestructable, ref healthInfo.normal, ref healthInfo.damage, ref healthInfo.crit, ref healthInfo.attackType); + return; + } + + if (eventType == ObjectDamageType.PropHealthTakeDamage && propHealth) + { + MelonLogger.Msg("NetworkPropHealthTakeDamage: " + healthInfo.damage); + CallPatchedMethods.TakeDamage(propHealth, ref healthInfo.damage, ref healthInfo.crit, ref healthInfo.attackType); + return; + } + + } + } +} diff --git a/BoneSync/Sync/Components/SyncableNetworking.cs b/BoneSync/Sync/Components/SyncableNetworking.cs new file mode 100644 index 0000000..76bbfdd --- /dev/null +++ b/BoneSync/Sync/Components/SyncableNetworking.cs @@ -0,0 +1,46 @@ +using MelonLoader; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace BoneSync.Sync.Components +{ + // SyncableNetworking.cs + public partial class Syncable : MonoBehaviour + { + private void SendObjectSync() + { + _lastSyncTime = Time.time; + ObjectSync.SendObjectSyncMessage(this); + } + public async Task SyncCoroutineAsync() + { + MelonLogger.Msg("Running sync coroutine for: " + transform.GetPath()); + if (_syncCoroutineRunning) return; + _syncCoroutineRunning = true; + while (isOwner) + { + if (ShouldSendSync()) SendObjectSync(); + await Task.Delay(!Registered ? 1000 : 1000 / SYNC_FPS); + } + _syncCoroutineRunning = false; + return; + } + public void SetOwner(ulong ownerId) + { + MelonLogger.Msg("Setting owner for " + _syncId + " to " + ownerId); + _ownerId = ownerId; + _ = SyncCoroutineAsync(); + UpdateKinematic(); + } + private void _SendRegisterSync() + { + MelonLogger.Msg("Registering syncable object: " + gameObject.name); + SetOwner(BoneSync.lobby.GetLocalId()); + SetSyncId(ObjectSync.SendRegisterSyncableMessage(this)); + } + } +} diff --git a/BoneSync/Sync/Components/SyncablePhysics.cs b/BoneSync/Sync/Components/SyncablePhysics.cs new file mode 100644 index 0000000..01d9d19 --- /dev/null +++ b/BoneSync/Sync/Components/SyncablePhysics.cs @@ -0,0 +1,86 @@ +using BoneSync.Networking; +using BoneSync.Networking.Messages; +using BoneSync.Patching; +using MelonLoader; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +namespace BoneSync.Sync.Components +{ + public partial class Syncable : MonoBehaviour + { + private void SetKinematic(bool kinematic) + { + foreach (Rigidbody rb in rigidbodies) + { + rb.isKinematic = kinematic; + } + } + + public ObjectSyncTransform[] GetObjectSyncTransforms() + { + ObjectSyncTransform[] objectSyncTransforms = new ObjectSyncTransform[rigidbodies.Length]; + for (int i = 0; i < _transforms.Length; i++) + { + objectSyncTransforms[i] = new ObjectSyncTransform() + { + transform = new SimpleTransform(_transforms[i]), + velocity = Vector3.zero + }; + } + return objectSyncTransforms; + } + + public void ApplyObjectSyncTransforms(ObjectSyncTransform[] objectSyncTransforms) + { + if (objectSyncTransforms.Length != rigidbodies.Length) + { + MelonLogger.Warning("ObjectSyncTransforms length mismatch: " + objectSyncTransforms.Length + " != " + _transforms.Length); + return; + } + for (int i = 0; i < objectSyncTransforms.Length; i++) + { + ObjectSyncTransform objectSyncTransform = objectSyncTransforms[i]; + rigidbodies[i].angularVelocity = objectSyncTransform.angularVelocity; + rigidbodies[i].velocity = objectSyncTransform.velocity; + rigidbodies[i].position = objectSyncTransform.transform.position; + rigidbodies[i].rotation = objectSyncTransform.transform.rotation; + _transforms[i].localScale = objectSyncTransform.transform.scale; + //_transforms[i].ApplySimpleTransform(objectSyncTransform.transform); + } + } + + private Rigidbody[] UpdateRigidbodyList() + { + if (interactableManager) + { + return interactableManager.hosts.Select(host => host.rb).ToArray(); + } + if (interactableHost) + { + return new Rigidbody[] { interactableHost.rb }; + } + if (poolee) + { + return new Rigidbody[] { poolee.GetComponentInChildren() }; + } + + return new Rigidbody[0]; + } + + private void UpdateTransformList() + { + Rigidbody[] rbs = UpdateRigidbodyList(); + rigidbodies = rbs; + _transforms = rbs.Select(rb => rb.transform).ToArray(); + } + + private void UpdateKinematic() + { + SetKinematic(_ownerId != BoneSync.lobby.GetLocalId() && Registered); + } + } +} diff --git a/BoneSync/Sync/ObjectSync.cs b/BoneSync/Sync/ObjectSync.cs index 0d72c10..87a53d4 100644 --- a/BoneSync/Sync/ObjectSync.cs +++ b/BoneSync/Sync/ObjectSync.cs @@ -12,135 +12,6 @@ using UnityEngine; namespace BoneSync.Sync { - - public static class ObjectSyncCache - { - private static Dictionary _pathToSyncable = new Dictionary(); - private static Dictionary _idToSyncable = new Dictionary(); - private static Dictionary _pooleeToSyncable = new Dictionary(); - private static Dictionary _interactableHostToSyncable = new Dictionary(); - private static Dictionary _interactableHostManagerToSyncable = new Dictionary(); - - - public static void AddSyncable(Syncable syncable) - { - string path = syncable.transform.GetPath(); - if (path != null && path != "") - { - _pathToSyncable[path] = syncable; - } - if (syncable.GetSyncId() != 0) - { - _idToSyncable[syncable.GetSyncId()] = syncable; - } - if (syncable.interactableHost) - { - _interactableHostToSyncable[syncable.interactableHost] = syncable; - } - if (syncable.interactableManager) - { - _interactableHostManagerToSyncable[syncable.interactableManager] = syncable; - } - if (syncable.poolee) - { - _pooleeToSyncable[syncable.poolee] = syncable; - } - } - - public static void RemoveSyncable(Syncable syncable) - { - if (syncable.transform) - { - _pathToSyncable.Remove(syncable.transform.GetPath()); - } - if (syncable.GetSyncId() != 0) - { - _idToSyncable.Remove(syncable.GetSyncId()); - } - if (syncable.interactableHost) - { - _interactableHostToSyncable.Remove(syncable.interactableHost); - } - if (syncable.interactableManager) - { - _interactableHostManagerToSyncable.Remove(syncable.interactableManager); - } - if (syncable.poolee) - { - _pooleeToSyncable.Remove(syncable.poolee); - } - } - - public static void UpdateSyncId(Syncable syncable) - { - // remove other enties where value is the same - foreach (KeyValuePair entry in _idToSyncable) - { - if (entry.Value == syncable) - { - _idToSyncable.Remove(entry.Key); - } - } - ushort id = syncable.GetSyncId(); - if (_idToSyncable.ContainsKey(id)) - { - _idToSyncable.Remove(id); - } - _idToSyncable[id] = syncable; - } - - public static Syncable GetSyncable(string path) - { - if (_pathToSyncable.ContainsKey(path)) - { - return _pathToSyncable[path]; - } - return null; - } - - public static Syncable GetSyncable(ushort id) - { - if (_idToSyncable.ContainsKey(id)) - { - return _idToSyncable[id]; - } - return null; - } - - public static Syncable GetSyncable(Poolee poolee) - { - if (_pooleeToSyncable.ContainsKey(poolee)) - { - return _pooleeToSyncable[poolee]; - } - return null; - } - - public static Syncable GetSyncable(InteractableHost interactableHost) - { - if (_interactableHostToSyncable.ContainsKey(interactableHost)) - { - return _interactableHostToSyncable[interactableHost]; - } - return null; - } - - public static Syncable GetSyncable(InteractableHostManager interactableHostManager) - { - if (_interactableHostManagerToSyncable.ContainsKey(interactableHostManager)) - { - return _interactableHostManagerToSyncable[interactableHostManager]; - } - return null; - } - - public static void DISCARD_ALL_SYNCABLES() { - foreach (Syncable syncable in Syncable.syncablesCache) - { - syncable.DiscardSyncable(); - } - } - } internal class ObjectSync { private static ushort _nextSyncableId = 1; @@ -201,7 +72,8 @@ namespace BoneSync.Sync public static void SendObjectSyncMessage(Syncable syncable) { - MelonLogger.Msg("Sending object sync message for: " + syncable.transform.name); + if (!syncable.Registered) return; + //MelonLogger.Msg("Sending object sync message for: " + syncable.transform.name); ObjectSyncTransform[] objectSyncTransforms = syncable.GetObjectSyncTransforms(); ObjectSyncMessageData data = new ObjectSyncMessageData() @@ -238,6 +110,16 @@ namespace BoneSync.Sync return syncable; } + public static Syncable GetSyncableFromCache(GameObject gameObject) + { + bool success = Syncable.syncablesCache.TryGetValue(gameObject, out Syncable syncable); + if (!success) + { + return null; + } + return syncable; + } + public static Syncable MakeOrGetSyncable(InteractableHost interactableHost) { if (interactableHost.manager) return MakeOrGetSyncable(interactableHost.manager); @@ -279,10 +161,37 @@ namespace BoneSync.Sync Syncable syncable = ObjectSyncCache.GetSyncable(data.objectId); if (syncable == null) { - MelonLogger.Msg("Syncable not found for id: " + data.objectId); + MelonLogger.Msg("SyncEvent: Syncable not found for id: " + data.objectId); return; } syncable.ApplyObjectSyncTransforms(data.objectSyncTransforms); } + + public static void OnObjectDamageMessage(ObjectDamageMessage damageMessge) + { + + ObjectDamageInfo damageInfo = damageMessge.objectEventInfo; + if (damageInfo.objectId == 0) return; + Syncable syncable = ObjectSyncCache.GetSyncable(damageInfo.objectId); + if (syncable == null) + { + MelonLogger.Msg("DamageEvent: Syncable not found for id: " + damageInfo.objectId); + return; + } + syncable.Damage(damageInfo); + } + + public static void SendObjectDamageMessage(Syncable syncable, ObjectDamageType damageType, ObjectHealthInfo healthInfo) + { + ObjectDamageInfo damageInfo = new ObjectDamageInfo() + { + objectId = syncable.GetSyncId(), + objectHealthInfo = healthInfo, + eventType = damageType, + }; + ObjectDamageMessage message = new ObjectDamageMessage(damageInfo); + message.Broadcast(); + message.Execute(); + } } } diff --git a/BoneSync/Sync/ObjectSyncCache.cs b/BoneSync/Sync/ObjectSyncCache.cs new file mode 100644 index 0000000..57e88b0 --- /dev/null +++ b/BoneSync/Sync/ObjectSyncCache.cs @@ -0,0 +1,140 @@ +using BoneSync.Sync.Components; +using StressLevelZero.Interaction; +using StressLevelZero.Pool; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BoneSync.Sync +{ + public static class ObjectSyncCache + { + private static Dictionary _pathToSyncable = new Dictionary(); + private static Dictionary _idToSyncable = new Dictionary(); + private static Dictionary _pooleeToSyncable = new Dictionary(); + private static Dictionary _interactableHostToSyncable = new Dictionary(); + private static Dictionary _interactableHostManagerToSyncable = new Dictionary(); + + public static void AddSyncable(Syncable syncable) + { + string path = syncable.transform.GetPath(); + if (path != null && path != "") + { + _pathToSyncable[path] = syncable; + } + if (syncable.GetSyncId() != 0) + { + _idToSyncable[syncable.GetSyncId()] = syncable; + } + if (syncable.interactableHost) + { + _interactableHostToSyncable[syncable.interactableHost] = syncable; + } + if (syncable.interactableManager) + { + _interactableHostManagerToSyncable[syncable.interactableManager] = syncable; + } + if (syncable.poolee) + { + _pooleeToSyncable[syncable.poolee] = syncable; + } + } + + public static void RemoveSyncable(Syncable syncable) + { + if (syncable.transform) + { + _pathToSyncable.Remove(syncable.transform.GetPath()); + } + if (syncable.GetSyncId() != 0) + { + _idToSyncable.Remove(syncable.GetSyncId()); + } + if (syncable.interactableHost) + { + _interactableHostToSyncable.Remove(syncable.interactableHost); + } + if (syncable.interactableManager) + { + _interactableHostManagerToSyncable.Remove(syncable.interactableManager); + } + if (syncable.poolee) + { + _pooleeToSyncable.Remove(syncable.poolee); + } + } + + public static void UpdateSyncId(Syncable syncable) + { + // remove other enties where value is the same + foreach (KeyValuePair entry in _idToSyncable) + { + if (entry.Value == syncable) + { + _idToSyncable.Remove(entry.Key); + } + } + ushort id = syncable.GetSyncId(); + if (_idToSyncable.ContainsKey(id)) + { + _idToSyncable.Remove(id); + } + _idToSyncable[id] = syncable; + } + + public static Syncable GetSyncable(string path) + { + if (_pathToSyncable.ContainsKey(path)) + { + return _pathToSyncable[path]; + } + return null; + } + + public static Syncable GetSyncable(ushort id) + { + if (_idToSyncable.ContainsKey(id)) + { + return _idToSyncable[id]; + } + return null; + } + + public static Syncable GetSyncable(Poolee poolee) + { + if (_pooleeToSyncable.ContainsKey(poolee)) + { + return _pooleeToSyncable[poolee]; + } + return null; + } + + public static Syncable GetSyncable(InteractableHost interactableHost) + { + if (_interactableHostToSyncable.ContainsKey(interactableHost)) + { + return _interactableHostToSyncable[interactableHost]; + } + return null; + } + + public static Syncable GetSyncable(InteractableHostManager interactableHostManager) + { + if (_interactableHostManagerToSyncable.ContainsKey(interactableHostManager)) + { + return _interactableHostManagerToSyncable[interactableHostManager]; + } + return null; + } + + public static void DISCARD_ALL_SYNCABLES() + { + foreach (Syncable syncable in Syncable.syncablesCache.Values) + { + syncable.DiscardSyncable(); + } + } + } +}