more sync stuff

This commit is contained in:
Aaro Varis
2025-03-02 17:35:20 +02:00
parent fc744fd1ab
commit 7f266321db
12 changed files with 184 additions and 41 deletions

View File

@@ -7,6 +7,7 @@ using UnityEngine;
using BoneSync.Player; using BoneSync.Player;
using BoneSync.Sync; using BoneSync.Sync;
using Facepunch.Steamworks; using Facepunch.Steamworks;
using System.Reflection.Emit;
namespace BoneSync namespace BoneSync
{ {
@@ -52,6 +53,7 @@ namespace BoneSync
public override void OnSceneWasInitialized(int buildIndex, string sceneName) public override void OnSceneWasInitialized(int buildIndex, string sceneName)
{ {
//MelonLogger.Msg("OnLevelWasInitialized: " + sceneName); //MelonLogger.Msg("OnLevelWasInitialized: " + sceneName);
SceneSync.OnSceneInit(buildIndex);
} }
public override void OnSceneWasUnloaded(int buildIndex, string sceneName) public override void OnSceneWasUnloaded(int buildIndex, string sceneName)
@@ -76,11 +78,6 @@ namespace BoneSync
} }
} }
public override void OnLevelWasInitialized(int level)
{
SceneSync.OnSceneInit(level);
}
public override void BONEWORKS_OnLoadingScreen() public override void BONEWORKS_OnLoadingScreen()
{ {
base.BONEWORKS_OnLoadingScreen(); base.BONEWORKS_OnLoadingScreen();

View File

@@ -5,12 +5,14 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using BoneSync.Sync; using BoneSync.Sync;
using BoneSync.Sync.Components; using BoneSync.Sync.Components;
using MelonLoader;
namespace BoneSync.Networking.Messages namespace BoneSync.Networking.Messages
{ {
public struct DiscardSyncableMessageData public struct DiscardSyncableMessageData
{ {
public ushort syncId; public ushort syncId;
public bool despawn;
} }
[PacketType(PacketType.DiscardSyncable), PacketReliability(PacketReliability.ReliableFast)] [PacketType(PacketType.DiscardSyncable), PacketReliability(PacketReliability.ReliableFast)]
internal class DiscardSyncableMessage : NetworkMessage internal class DiscardSyncableMessage : NetworkMessage
@@ -21,20 +23,26 @@ namespace BoneSync.Networking.Messages
{ {
_data = discardSyncableMessageData; _data = discardSyncableMessageData;
byteEncoder.WriteUShort(_data.syncId); byteEncoder.WriteUShort(_data.syncId);
byteEncoder.WriteBool(_data.despawn);
} }
public DiscardSyncableMessage(Packet packet) public DiscardSyncableMessage(Packet packet)
{ {
byteEncoder.WriteBytes(packet.Data); byteEncoder.WriteBytes(packet.Data);
_data.syncId = byteEncoder.ReadUShort(); _data.syncId = byteEncoder.ReadUShort();
_data.despawn = byteEncoder.ReadBool();
} }
public override void Execute() public override void Execute()
{ {
Syncable syncable = ObjectSyncCache.GetSyncable(_data.syncId); Syncable syncable = ObjectSyncCache.GetSyncable(_data.syncId);
if (syncable != null) if (syncable != null)
{ {
syncable.DiscardSyncable(true); syncable.DiscardSyncable(true, _data.despawn);
} else
{
MelonLogger.Warning(senderId + " tried to discard a syncable that doesn't exist (syncId: " + _data.syncId + ")");
} }
} }

View File

@@ -16,6 +16,8 @@ namespace BoneSync.Networking.Messages
public bool[] _attributes; public bool[] _attributes;
public ObjectMagazineData? magazineData; public ObjectMagazineData? magazineData;
} }
[PacketType(PacketType.ObjectAttribute), PacketReliability(PacketReliability.ReliableFast)]
internal class ObjectAttributeMessage : NetworkMessage internal class ObjectAttributeMessage : NetworkMessage
{ {
private ObjectAttributeMessageData _data; private ObjectAttributeMessageData _data;
@@ -26,8 +28,8 @@ namespace BoneSync.Networking.Messages
_data = objectAttributeMessageData; _data = objectAttributeMessageData;
byteEncoder.WriteUShort(_data.syncId); byteEncoder.WriteUShort(_data.syncId);
attributes.Add(_data.magazineData != null); attributes.Add(_data.magazineData.HasValue);
if (_data.magazineData != null) if (_data.magazineData.HasValue)
{ {
byteEncoder.WriteByte(_data.magazineData.Value.ammoCount); byteEncoder.WriteByte(_data.magazineData.Value.ammoCount);
} }

View File

@@ -16,5 +16,6 @@ namespace BoneSync.Networking
ObjectEvent = 5, ObjectEvent = 5,
ObjectOwnership = 6, ObjectOwnership = 6,
DiscardSyncable = 7, DiscardSyncable = 7,
ObjectAttribute = 8,
} }
} }

View File

@@ -31,6 +31,13 @@ namespace BoneSync.Patching
allowPatchedMethodCall = false; allowPatchedMethodCall = false;
} }
public static void Despawn(Poolee poolee)
{
allowPatchedMethodCall = true;
poolee.Despawn();
allowPatchedMethodCall = false;
}
public static Poolee InstantiatePoolee(Pool pool, Vector3 position, Quaternion rotation, Vector3 scale) public static Poolee InstantiatePoolee(Pool pool, Vector3 position, Quaternion rotation, Vector3 scale)
{ {
allowPatchedMethodCall = true; allowPatchedMethodCall = true;

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using BoneSync.Sync; using BoneSync.Sync;
using BoneSync.Sync.Components;
using HarmonyLib; using HarmonyLib;
using StressLevelZero.Interaction; using StressLevelZero.Interaction;
namespace BoneSync.Patching namespace BoneSync.Patching
@@ -15,7 +16,13 @@ namespace BoneSync.Patching
public static void OnEnablePatch(ForcePullGrip __instance) public static void OnEnablePatch(ForcePullGrip __instance)
{ {
MelonLoader.MelonLogger.Msg("ForcePullGrip.Pull: " + __instance.name); MelonLoader.MelonLogger.Msg("ForcePullGrip.Pull: " + __instance.name);
ObjectSync.MakeOrGetSyncable(__instance.gameObject); InteractableHost interactableHost = __instance.GetComponent<InteractableHost>();
if (interactableHost == null) return;
Syncable syncable = ObjectSync.MakeOrGetSyncable(interactableHost);
if (syncable)
{
syncable.RegisterSyncable();
}
} }
} }

View File

@@ -79,6 +79,7 @@ namespace BoneSync.Patching
if (PoolBlacklist.isBlacklistedPool(__instance)) return; if (PoolBlacklist.isBlacklistedPool(__instance)) return;
MelonLogger.Msg("Patched Instantiating object in pool: " + __instance.name); MelonLogger.Msg("Patched Instantiating object in pool: " + __instance.name);
__result.onSpawnDelegate = Il2CppSystem.Delegate.Combine(__result.onSpawnDelegate, (Il2CppSystem.Action<GameObject>)((g) => { PooleePatches.OnSpawnPatchPost(__result); })).Cast<Il2CppSystem.Action<GameObject>>(); __result.onSpawnDelegate = Il2CppSystem.Delegate.Combine(__result.onSpawnDelegate, (Il2CppSystem.Action<GameObject>)((g) => { PooleePatches.OnSpawnPatchPost(__result); })).Cast<Il2CppSystem.Action<GameObject>>();
__result.onDespawnDelegate = Il2CppSystem.Delegate.Combine(__result.onDespawnDelegate, (Il2CppSystem.Action<GameObject>)((g) => { PooleePatches.OnDespawnPatchPost(__result); })).Cast<Il2CppSystem.Action<GameObject>>();
} }
@@ -140,6 +141,22 @@ namespace BoneSync.Patching
} }
public static void OnDespawnPatchPost(Poolee __instance)
{
if (CallPatchedMethods.allowPatchedMethodCall) return;
if (!BoneSync.lobby.IsConnected()) return;
MelonLogger.Msg("Poolee.OnDespawn: " + __instance.gameObject.transform.GetPath());
//Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance);
//if (syncable == null) return;
//if (syncable.isOwner) return;
//syncable.DiscardSyncable(true);
}
public static IEnumerator OnSpawnClient(Poolee poolee) public static IEnumerator OnSpawnClient(Poolee poolee)
{ {
GameObject go = poolee.gameObject; GameObject go = poolee.gameObject;

View File

@@ -31,6 +31,28 @@ namespace BoneSync.Sync.Components
return "/" + current.name; return "/" + current.name;
return current.parent.GetPath() + "/" + current.name; return current.parent.GetPath() + "/" + current.name;
} }
public static Transform TransformFromPath(string path)
{
if (path.StartsWith("/"))
{
path = path.Substring(1);
}
string[] pathParts = path.Split('/');
Transform current = null;
foreach (string part in pathParts)
{
if (current == null)
{
current = GameObject.Find(part).transform;
}
else
{
current = current.Find(part);
}
}
return current;
}
} }
[RegisterTypeInIl2Cpp] [RegisterTypeInIl2Cpp]
@@ -92,15 +114,20 @@ namespace BoneSync.Sync.Components
private SpawnFragment spawnFragment; private SpawnFragment spawnFragment;
private IEnumerator _CheckAutoSyncCo() private void CheckAutoSync()
{ {
yield return null;
bool shouldAutoSync = CheckIfShouldAutoSync(); bool shouldAutoSync = CheckIfShouldAutoSync();
if (shouldAutoSync && (BoneSync.lobby.IsHost || ClientSpawningAllowed())) if (shouldAutoSync && (BoneSync.lobby.IsHost || ClientSpawningAllowed()))
{ {
MelonLogger.Msg("AutoSyncing: " + transform.GetPath()); MelonLogger.Msg("AutoSyncing: " + transform.GetPath());
RegisterSyncable(); RegisterSyncable();
} }
}
private IEnumerator _OnEnableCo()
{
yield return null; // wait a frame to make sure all components are initialized, I hate this but it works
FindComponents();
CheckAutoSync();
yield break; yield break;
} }
@@ -110,11 +137,15 @@ namespace BoneSync.Sync.Components
FindComponents(); FindComponents();
MelonCoroutines.Start(_CheckAutoSyncCo()); MelonCoroutines.Start(_OnEnableCo());
} }
public bool CheckIfShouldAutoSync() public bool CheckIfShouldAutoSync()
{ {
if (transform.GetPath().StartsWith("/Pool Manager/"))
{
return false;
}
if (poolee && poolee.pool) { if (poolee && poolee.pool) {
return true; return true;
} }
@@ -129,7 +160,7 @@ namespace BoneSync.Sync.Components
} }
if (interactableHost || interactableManager) if (interactableHost || interactableManager)
{ {
return transform.GetPath().Replace(" ", "[]"); return transform.GetPath();
} }
return ""; return "";
} }
@@ -153,6 +184,13 @@ namespace BoneSync.Sync.Components
ObjectSyncCache.AddSyncable(this); ObjectSyncCache.AddSyncable(this);
} }
private void ResetSyncStatus()
{
_ownerId = 0;
_syncId = 0;
_attemptedRegister = false;
SetKinematic(false);
}
public bool CanBeSynced() public bool CanBeSynced()
{ {
if (spawnFragment) return false; // if has spawn fragment, don't sync if (spawnFragment) return false; // if has spawn fragment, don't sync
@@ -162,24 +200,38 @@ namespace BoneSync.Sync.Components
return false; return false;
} }
private void _DiscardSyncable(bool force) private void _DiscardSyncable(bool force, bool despawn)
{ {
if (Registered) bool isRegistered = Registered;
MelonLogger.Msg("Discarding syncable: " + transform.GetPath() + " force: " + force + " isRegistered: " + isRegistered + " despawn: " + despawn);
if (isRegistered)
{ {
MelonLogger.Warning("Discarding registered syncable: " + transform.GetPath() + " force: " + force); //MelonLogger.Warning("Discarding registered syncable: " + transform.GetPath() + " force: " + force);
bool isowner = isOwner; bool isowner = isOwner;
if (isowner) if (isowner)
{ {
_SendDiscard(); // owner sends discard message _SendDiscard(true); // owner sends discard message
} }
if (!isowner && !force) return; // only owner can discard if (!isowner && !force) return; // only owner can discard
} }
syncablesCache.Remove(gameObject);
if (gameObject) syncablesCache.Remove(gameObject);
ObjectSyncCache.RemoveSyncable(this); ObjectSyncCache.RemoveSyncable(this);
Destroy(this); // delete the component
ResetSyncStatus();
DestroyImmediate(this); // delete the component
if (despawn)
{
gameObject?.SetActive(false);
}
} }
public void OnDestroy() public void OnDestroy()
@@ -188,19 +240,25 @@ namespace BoneSync.Sync.Components
{ {
MelonLogger.Warning("Destroying registered syncable: " + transform.GetPath()); MelonLogger.Warning("Destroying registered syncable: " + transform.GetPath());
} }
_DiscardSyncable(true); DiscardSyncableImmediate(true, Registered);
//MelonLogger.Msg("Syncable destroyed: " + transform.GetPath()); //MelonLogger.Msg("Syncable destroyed: " + transform.GetPath());
} }
private IEnumerator _FlagForDiscardCo(bool force) private IEnumerator _FlagForDiscardCo(bool force, bool despawn) { yield return null; _DiscardSyncable(force, despawn); } // delay discard to prevent silly behavior
public void DiscardSyncable(bool force = false, bool despawn = false)
{ {
yield return null; if (Registered && isOwner)
_DiscardSyncable(force); {
DiscardSyncableImmediate(force, despawn);
return;
}
MelonCoroutines.Start(_FlagForDiscardCo(force, despawn));
} }
public void DiscardSyncable(bool force = false) public void DiscardSyncableImmediate(bool force = false, bool despawn = false)
{ {
MelonCoroutines.Start(_FlagForDiscardCo(force)); _DiscardSyncable(true, despawn);
} }
public void OnDisable() public void OnDisable()
@@ -209,10 +267,9 @@ namespace BoneSync.Sync.Components
{ {
MelonLogger.Warning("tried to disable non-owner syncable: " + transform.GetPath()); MelonLogger.Warning("tried to disable non-owner syncable: " + transform.GetPath());
gameObject.SetActive(true); gameObject.SetActive(true);
} else return;
{
DiscardSyncable();
} }
DiscardSyncable();
} }
public void RegisterSyncable() public void RegisterSyncable()

View File

@@ -56,11 +56,13 @@ namespace BoneSync.Sync.Components
SetSyncId(ObjectSync.SendRegisterSyncableMessage(this)); SetSyncId(ObjectSync.SendRegisterSyncableMessage(this));
} }
private void _SendDiscard() private void _SendDiscard(bool despawn = false)
{ {
MelonLogger.Msg("Sending discard for " + _syncId + " despawn: " + despawn);
DiscardSyncableMessageData discardSyncableMessageData = new DiscardSyncableMessageData() DiscardSyncableMessageData discardSyncableMessageData = new DiscardSyncableMessageData()
{ {
syncId = _syncId syncId = _syncId,
despawn = despawn
}; };
DiscardSyncableMessage discardSyncableMessage = new DiscardSyncableMessage(discardSyncableMessageData); DiscardSyncableMessage discardSyncableMessage = new DiscardSyncableMessage(discardSyncableMessageData);
discardSyncableMessage.Broadcast(); discardSyncableMessage.Broadcast();
@@ -85,7 +87,7 @@ namespace BoneSync.Sync.Components
public void TryBecomeOwner() public void TryBecomeOwner()
{ {
if (!isOwner) if (Registered && !isOwner)
{ {
MelonLogger.Msg("Attempting to become owner of " + _syncId); MelonLogger.Msg("Attempting to become owner of " + _syncId);
OwnershipTransferMessageData data = new OwnershipTransferMessageData() OwnershipTransferMessageData data = new OwnershipTransferMessageData()

View File

@@ -105,12 +105,6 @@ namespace BoneSync.Sync
//Scene scene = gameObject.scene; //Scene scene = gameObject.scene;
//MelonLogger.Msg("Making or getting syncable for: " + gameObject.name + " in scene: " + scene.name); //MelonLogger.Msg("Making or getting syncable for: " + gameObject.name + " in scene: " + scene.name);
Syncable parentSyncable = gameObject.transform.parent.GetComponentInParent<Syncable>();
if (parentSyncable != null)
{
return parentSyncable;
}
Syncable syncable = gameObject.GetComponent<Syncable>(); Syncable syncable = gameObject.GetComponent<Syncable>();
// delete all sub syncables // delete all sub syncables
@@ -210,6 +204,12 @@ namespace BoneSync.Sync
} }
} }
if (info.id == 0)
{
MelonLogger.Warning("Received register sync message with id 0");
return;
}
bool hasCallback = info.callbackId != 0; bool hasCallback = info.callbackId != 0;
if (hasCallback) if (hasCallback)
{ {
@@ -250,6 +250,9 @@ namespace BoneSync.Sync
{ {
ObjectSyncMessageData data = objectSyncMessage.objectSyncMessageData; ObjectSyncMessageData data = objectSyncMessage.objectSyncMessageData;
ushort objectId = data.objectId; ushort objectId = data.objectId;
if (objectId == 0) return;
if (objectId >= _nextSyncableId && !BoneSync.lobby.IsHost) if (objectId >= _nextSyncableId && !BoneSync.lobby.IsHost)
{ {
_nextSyncableId = (ushort)(objectId + 1); _nextSyncableId = (ushort)(objectId + 1);
@@ -257,7 +260,7 @@ namespace BoneSync.Sync
Syncable syncable = ObjectSyncCache.GetSyncable(objectId); Syncable syncable = ObjectSyncCache.GetSyncable(objectId);
if (syncable == null) if (syncable == null)
{ {
MelonLogger.Msg("SyncEvent: Syncable not found for id: " + objectId); //MelonLogger.Msg("SyncEvent: Syncable not found for id: " + objectId);
return; return;
} }
syncable.ApplyObjectSyncTransforms(data.objectSyncTransforms); syncable.ApplyObjectSyncTransforms(data.objectSyncTransforms);

View File

@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using UnityEngine;
namespace BoneSync.Sync namespace BoneSync.Sync
{ {
@@ -86,6 +87,11 @@ namespace BoneSync.Sync
{ {
return _pathToSyncable[path]; return _pathToSyncable[path];
} }
Transform transform = TransformExtensions.TransformFromPath(path);
if (transform)
{
return transform.GetComponent<Syncable>();
}
return null; return null;
} }

View File

@@ -1,9 +1,12 @@
using MelonLoader; using BoneSync.Sync.Components;
using MelonLoader;
using StressLevelZero.Interaction;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
namespace BoneSync.Sync namespace BoneSync.Sync
@@ -27,12 +30,45 @@ namespace BoneSync.Sync
return sceneName; return sceneName;
} }
}
public static void RenameDuplicateSceneTransforms(Scene scene)
{
Dictionary<string, ushort> seenTransformNames = new Dictionary<string, ushort>();
uint total = 0;
foreach (GameObject go in scene.GetRootGameObjects())
{
foreach (InteractableHost host in go.GetComponentsInChildren<InteractableHost>(true))
{
Transform t = host.transform;
string path = t.GetPath();
if (seenTransformNames.ContainsKey(path))
{
seenTransformNames[path]++;
t.name = t.name + " (BoneSync." + seenTransformNames[path] + ")";
total++;
//MelonLogger.Msg("Renamed duplicate transform: " + path);
}
else
{
seenTransformNames[path] = 1;
}
}
}
MelonLogger.Msg("Renamed " + total + " duplicate transforms in " + scene.name);
} }
public static void OnSceneInit(int buildIndex) public static void OnSceneInit(int buildIndex)
{ {
string SceneName = SceneManager.GetSceneByBuildIndex(buildIndex).name; Scene scene = SceneManager.GetSceneByBuildIndex(buildIndex);
string SceneName = scene.name;
_currentSceneName = SceneName; _currentSceneName = SceneName;
MelonLogger.Msg("Scene initialized: " + SceneName); MelonLogger.Msg("Scene initialized: " + SceneName);
RenameDuplicateSceneTransforms(scene);
} }
public static void Initialize() public static void Initialize()