Basic object sync

This commit is contained in:
2025-02-27 21:16:52 +02:00
parent 43f6710697
commit ee1b827c91
14 changed files with 499 additions and 153 deletions

View File

@@ -35,6 +35,7 @@ namespace BoneSync
transport = new SteamTransport();
SceneSync.Initialize();
NetworkMessage.RegisterPacketTypes();
}
public static void PatchAll()
@@ -62,21 +63,12 @@ namespace BoneSync
{
transport.Tick();
PlayerRig.Tick();
//PlayerRig.Tick();
if (Input.GetKeyDown(KeyCode.P))
{
MelonLogger.Msg("P key pressed");
PlayerRig playerRig = PlayerRig.InstantiatePlayerRigPrefab();
if (playerRig == null)
{
MelonLogger.Error("Failed to instantiate player rig prefab");
return;
}
else
{
MelonLogger.Msg("Player rig instantiated");
}
//PlayerRig playerRig = PlayerRig.InstantiatePlayerRigPrefab();
}
if (Input.GetKeyDown(KeyCode.I))
{

View File

@@ -36,6 +36,10 @@ namespace BoneSync.Networking
}
public byte[] ReadBytes(int count)
{
if (Data.Count < count)
{
throw new Exception("Not enough data to read, expected " + count + " but only have " + Data.Count);
}
byte[] value = Data.GetRange(0, count).ToArray();
Data.RemoveRange(0, count);
return value;

View File

@@ -12,6 +12,8 @@ namespace BoneSync.Networking.LobbyManager
public abstract ulong GetLobbyId();
public abstract ulong GetHostId();
public abstract ulong GetLocalId();
public bool IsHost => GetLocalId() == GetHostId();
public abstract bool IsConnected();
public abstract void CreateLobby();
public abstract void JoinLobby(ulong lobbyId);

View File

@@ -42,8 +42,22 @@ namespace BoneSync.Networking.LobbyManager
UpdateLobbyData();
};
MelonLogger.Msg("SteamLobbyManager initialized");
}
SteamFriends.OnGameLobbyJoinRequested += (Lobby lobby, SteamId friend) =>
{
MelonLogger.Msg("Joining lobby " + lobby.Id);
JoinLobby(lobby.Id.Value);
};
SteamFriends.OnGameRichPresenceJoinRequested += (Friend friend, string connectString) =>
{
MelonLogger.Msg("Joining lobby " + connectString);
ulong lobbyId = ulong.Parse(connectString.Split(':')[1]);
JoinLobby(lobbyId);
};
SteamNetworkingUtils.InitRelayNetworkAccess();
}
private Lobby _lobbyInstance;
public Friend[] LobbyMembers
@@ -57,6 +71,11 @@ namespace BoneSync.Networking.LobbyManager
private set;
}
public override bool IsConnected()
{
return _lobbyInstance.Id.IsValid;
}
public override ulong[] GetPeers() => steamIds.Select(x => x.Value).ToArray();
public override ulong GetLocalId() => SteamClient.SteamId.Value;
public override ulong GetHostId() => _lobbyInstance.Owner.Id.Value;
@@ -88,6 +107,7 @@ namespace BoneSync.Networking.LobbyManager
public override void CreateLobby()
{
LeaveLobby();
MelonLogger.Msg("Trying to create lobby");
_ = SteamMatchmaking.CreateLobbyAsync(16);
@@ -95,13 +115,16 @@ namespace BoneSync.Networking.LobbyManager
public override void JoinLobby(ulong lobbyId)
{
LeaveLobby();
MelonLogger.Msg("Trying to join lobby " + lobbyId);
_ = SteamMatchmaking.JoinLobbyAsync(lobbyId);
}
public override void LeaveLobby()
{
if (!IsConnected()) return;
_lobbyInstance.Leave();
_lobbyInstance = new Lobby();
BoneSync.transport.CleanUp();
}

View File

@@ -1,4 +1,5 @@
using System;
using BoneSync.Sync;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -15,9 +16,11 @@ namespace BoneSync.Networking.Messages
}
public struct ObjectSyncMessageData
{
public ulong objectId;
public ushort objectId;
public ObjectSyncTransform[] objectSyncTransforms;
}
[PacketType(PacketType.ObjectSync), PacketReliability(PacketReliability.UnreliableNoDelay)]
internal class ObjectSyncMessage : NetworkMessage
{
private ObjectSyncMessageData _objectSyncMessageData = new ObjectSyncMessageData();
@@ -26,7 +29,7 @@ namespace BoneSync.Networking.Messages
public ObjectSyncMessage(ObjectSyncMessageData objectSyncMessageData)
{
_objectSyncMessageData = objectSyncMessageData;
byteEncoder.WriteUlong(_objectSyncMessageData.objectId);
byteEncoder.WriteUShort(_objectSyncMessageData.objectId);
byte length = (byte)_objectSyncMessageData.objectSyncTransforms.Length;
byteEncoder.WriteByte(length);
for (int i = 0; i < length; i++)
@@ -39,7 +42,7 @@ namespace BoneSync.Networking.Messages
public ObjectSyncMessage(Packet packet)
{
byteEncoder.WriteBytes(packet.Data);
_objectSyncMessageData.objectId = byteEncoder.ReadUlong();
_objectSyncMessageData.objectId = byteEncoder.ReadUShort();
byte length = byteEncoder.ReadByte();
_objectSyncMessageData.objectSyncTransforms = new ObjectSyncTransform[length];
for (int i = 0; i < length; i++)
@@ -49,11 +52,9 @@ namespace BoneSync.Networking.Messages
}
}
public override void Execute()
{
throw new NotImplementedException();
ObjectSync.OnObjectSyncMessage(this);
}
}
}

View File

@@ -7,18 +7,30 @@ using System.Threading.Tasks;
namespace BoneSync.Networking.Messages
{
public enum RegisterSyncType
{
RegisterFromPath = 0,
RegisterAndSpawn = 1,
}
public struct RegisterSyncableInfo
{
public string transformPath;
public ushort id;
public ulong ownerId;
public RegisterSyncType type;
}
[PacketType(PacketType.RegisterSyncable)]
internal class RegisterSyncableMessage : NetworkMessage
{
private RegisterSyncableInfo _info;
public RegisterSyncableInfo info => _info;
public RegisterSyncableMessage(RegisterSyncableInfo info)
{
_info = info;
byteEncoder.WriteByte((byte)_info.type);
byteEncoder.WriteString(_info.transformPath);
byteEncoder.WriteUlong(_info.ownerId);
byteEncoder.WriteUShort(_info.id);
}
@@ -26,13 +38,15 @@ namespace BoneSync.Networking.Messages
public RegisterSyncableMessage(Packet packet)
{
byteEncoder.WriteBytes(packet.Data);
_info.type = (RegisterSyncType)byteEncoder.ReadByte();
_info.transformPath = byteEncoder.ReadString();
_info.ownerId = byteEncoder.ReadUlong();
_info.id = byteEncoder.ReadUShort();
}
public override void Execute()
{
ObjectSync.OnRegisterSyncMessage(this);
}
}
}

View File

@@ -21,6 +21,16 @@ namespace BoneSync.Networking
public PacketType packetType { get; }
}
public class PacketReliabilityAttribute : Attribute
{
public PacketReliabilityAttribute(PacketReliability reliability)
{
this.reliability = reliability;
}
public PacketReliability reliability { get; }
}
public abstract class NetworkMessage
{
public ulong senderId
@@ -33,6 +43,7 @@ namespace BoneSync.Networking
internal static Dictionary<PacketType, Type> PacketTypeMap = new Dictionary<PacketType, Type>();
internal PacketType _packetType;
internal PacketReliability? _reliability;
internal ByteEncoder byteEncoder = new ByteEncoder();
public byte[] GetBytes() => byteEncoder.ToArray();
@@ -53,6 +64,20 @@ namespace BoneSync.Networking
return _packetType;
}
public PacketReliability GetPacketReliability()
{
if (_reliability.HasValue) return _reliability.Value;
PacketReliabilityAttribute reliabilityAttribute = GetType().GetCustomAttribute<PacketReliabilityAttribute>();
if (reliabilityAttribute == null)
{
_reliability = PacketReliability.Reliable;
return PacketReliability.Reliable;
}
_reliability = reliabilityAttribute.reliability;
return _reliability.Value;
}
public static void RegisterPacketTypes()
{
if (PacketTypesRegistered)
@@ -73,6 +98,7 @@ namespace BoneSync.Networking
}
public static NetworkMessage ParsePacket(Packet packet)
{
MelonLogger.Msg("Received packet of type " + packet.Info.packetType + " from " + packet.Info.senderId + " Length: " + packet.Data.Length);
// find a class that can parse this packet using Reflection
// and return it
if (!PacketTypeMap.ContainsKey(packet.Info.packetType))
@@ -92,7 +118,7 @@ namespace BoneSync.Networking
public Packet GetPacket(int id, ulong senderId, ulong receiverId)
{
PacketInfo packetInfo = new PacketInfo(id, senderId, receiverId, GetPacketType());
PacketInfo packetInfo = new PacketInfo(id, senderId, receiverId, GetPacketType(), GetPacketReliability());
Packet packet = new Packet(packetInfo, GetBytes());
return packet;
}
@@ -102,6 +128,11 @@ namespace BoneSync.Networking
}
public void Send(ulong receiverId)
{
if (BoneSync.lobby.IsConnected() == false)
{
MelonLogger.Warning("Cannot send packet, not connected to lobby");
return;
}
int PacketId = Packet.GenerateId();
ulong senderId = BoneSync.lobby.GetLocalId();
Packet packet = GetPacket(PacketId, senderId, receiverId);

View File

@@ -1,4 +1,5 @@
using BoneSync.Networking.Messages;
using Facepunch.Steamworks;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -9,19 +10,34 @@ using Xunit;
namespace BoneSync.Networking
{
public enum PacketReliability
{
Unreliable = 0,
UnreliableNoDelay = 1,
Reliable = 2,
ReliableWithBuffering = 3,
}
public struct PacketInfo
{
public int id;
public ulong senderId;
public ulong receiverId;
public PacketType packetType;
public PacketReliability reliability;
public PacketInfo(int id, ulong senderId, ulong receiverId, PacketType packetType)
public PacketInfo(
int id,
ulong senderId,
ulong receiverId,
PacketType packetType,
PacketReliability reliability = PacketReliability.Reliable
)
{
this.id = id;
this.senderId = senderId;
this.receiverId = receiverId;
this.packetType = packetType;
this.reliability = reliability;
}
}
public class Packet
@@ -46,19 +62,21 @@ namespace BoneSync.Networking
ByteEncoder byteEncoder = new ByteEncoder();
byteEncoder.WriteBytes(bytes);
int packetType = byteEncoder.ReadInt();
byte packetType = byteEncoder.ReadByte();
byte reliability = byteEncoder.ReadByte();
int id = byteEncoder.ReadInt();
ulong senderId = byteEncoder.ReadUlong();
ulong receiverId = byteEncoder.ReadUlong();
PacketInfo packetInfo = new PacketInfo(id, senderId, receiverId, (PacketType)packetType);
PacketInfo packetInfo = new PacketInfo(id, senderId, receiverId, (PacketType)packetType, (PacketReliability)reliability);
return new Packet(packetInfo, byteEncoder.ToArray());
}
public byte[] ToBytes()
{
ByteEncoder byteEncoder = new ByteEncoder();
byteEncoder.WriteInt((int)_packetInfo.packetType);
byteEncoder.WriteByte((byte)_packetInfo.packetType);
byteEncoder.WriteByte((byte)_packetInfo.reliability);
byteEncoder.WriteInt(_packetInfo.id);
byteEncoder.WriteUlong(_packetInfo.senderId);
byteEncoder.WriteUlong(_packetInfo.receiverId);

View File

@@ -11,5 +11,7 @@ namespace BoneSync.Networking
Unknown = 0,
LobbyInfo = 1,
PlayerSync = 2,
RegisterSyncable = 3,
ObjectSync = 4,
}
}

View File

@@ -6,6 +6,7 @@ using System.Threading.Tasks;
using BoneSync.Sync;
using BoneSync.Sync.Components;
using HarmonyLib;
using MelonLoader;
using StressLevelZero.Interaction;
using UnityEngine;
@@ -24,8 +25,29 @@ namespace BoneSync.Patching
[HarmonyPatch(nameof(InteractableHost.OnDestroy)), HarmonyPostfix]
public static void OnDestroyPatch(InteractableHost __instance)
{
MelonLoader.MelonLogger.Msg("InteractableHost destroyed: " + __instance.name);
MelonLogger.Msg("InteractableHost destroyed: " + __instance.name);
}
[HarmonyPatch(nameof(InteractableHost.AttachHand)), HarmonyPostfix]
public static void AttachHandPatch(InteractableHost __instance, Hand hand)
{
MelonLogger.Msg("InteractableHost attached to hand: " + __instance.name + " Hand: " + hand.name);
Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance);
if (syncable == null)
{
MelonLogger.Error("Syncable is null for " + __instance.name);
return;
}
syncable.RegisterSyncable();
}
/*[HarmonyPatch(nameof(InteractableHost.AddForcePullGrip)), HarmonyPostfix]
public static void AddForcePullGripPatch(InteractableHost __instance, ForcePullGrip grip)
{
MelonLoader.MelonLogger.Msg("AddForcePullGrip to hand: " + __instance.name + " Hand: " + grip.name);
}*/
}
[HarmonyPatch(typeof(InteractableHostManager))]

View File

@@ -17,9 +17,8 @@ namespace BoneSync.Player
{
internal class PlayerRig
{
public const string RIGMANAGER_SCENE_NAME = "[RigManager (Default Brett)]";
//public const string RIGMANAGER_SCENE_NAME = "[RigManager (Default Brett)]";
private static GameObject _rigPrefabCache = null;
private static List<PlayerRig> _playerRigs = new List<PlayerRig>();
private GameObject playerRig;
@@ -29,100 +28,18 @@ namespace BoneSync.Player
private Animator repAnimator;
public void UpdatePlayerSync(PlayerSyncInfo playerSyncInfo)
{
playerRig.transform.ApplySimpleTransform(playerSyncInfo.headPos);
//playerRig.transform.ApplySimpleTransform(playerSyncInfo.headPos);
}
public static void Tick()
public PlayerRig()
{
TryRegisterRigPrefab();
foreach (PlayerRig playerRig in _playerRigs)
{
try
{
playerRig.UpdateRig();
} catch (Exception e)
{
MelonLogger.Error(e.Message);
//MelonLogger.Error("Failed to update player rig");
}
}
}
public static void TryRegisterRigPrefab()
{
return; // disable this for now
if (_rigPrefabCache) return;
GetPlayerRigPrefab();
}
public static GameObject GetPlayerRigPrefab()
{
if (_rigPrefabCache == null)
{
// find the rig game object in the scene
GameObject playerRig = GameObject.Find(RIGMANAGER_SCENE_NAME);
if (playerRig == null)
{
MelonLogger.Error("Failed to find RigManager scene object");
return null;
}
// create a clone of the rig
GameObject playerRep = GameObject.Instantiate(playerRig);
playerRep.gameObject.SetActive(false);
playerRep.name = "[RigManager (Networked)]";
RigManager repRigManager = playerRep.GetComponent<RigManager>();
repRigManager.oculusControllerRig.gameObject.SetActive(false);
repRigManager.steamControllerRig.gameObject.SetActive(false);
repRigManager.uiRig.gameObject.SetActive(false);
repRigManager.enabled = false;
_rigPrefabCache = playerRep;
MelonLogger.Msg("Player rig prefab created");
}
return _rigPrefabCache;
}
public static PlayerRig InstantiatePlayerRigPrefab()
{
GameObject prefab = GetPlayerRigPrefab();
if (prefab == null)
{
return null;
}
GameObject go = GameObject.Instantiate(prefab);
go.SetActive(true);
PlayerRig playerRig = new PlayerRig(go);
return playerRig;
}
private void UpdateRig()
{
Vector3 velocity = Vector3.zero;
Vector3 acceleration = Vector3.zero;
//SkeletonRig skeletonRig = rigManager.gameWorldSkeletonRig;
//skeletonRig.OnLateUpdate();
rigManager.ControllerRig.gameObject.SetActive(false);
characterAnimationManager.OnLateUpdate();
body.FullBodyUpdate(velocity, acceleration);
body.ArtToBlender.UpdateBlender();
repAnimator.Update(Time.deltaTime);
}
private PlayerRig(GameObject go)
{
playerRig = go;
rigManager = playerRig.GetComponent<RigManager>();
rigManager.enabled = true;
UpdateRig();
_playerRigs.Add(this);
}
public void Destroy()
{
_playerRigs.Remove(this);

View File

@@ -11,6 +11,7 @@ using UnityEngine.Experimental.PlayerLoop;
using BoneSync.Networking.Messages;
using BoneSync.Networking;
using StressLevelZero.Data;
using System.Collections;
namespace BoneSync.Sync.Components
@@ -46,22 +47,95 @@ namespace BoneSync.Sync.Components
[RegisterTypeInIl2Cpp]
public class Syncable : MonoBehaviour
{
public const int SYNC_FPS = 20;
public Syncable(IntPtr intPtr) : base(intPtr) { }
public static List<Syncable> syncablesCache = new List<Syncable>();
public Syncable(IntPtr intPtr) : base(intPtr) {
syncablesCache.Add(this);
}
private bool _syncCoroutineRunning;
public ulong _ownerId
{
private set;
get;
}
private ushort _syncId;
public bool Registered => _syncId != 0;
private ulong _lastSyncTime;
private ulong _ownerId;
private bool _attemptedRegister;
public bool Registered => _syncId != 0;
public bool isStale => Time.time - _lastSyncTime > 5f;
public bool isOwner => _ownerId == BoneSync.lobby.GetLocalId();
public ushort GetSyncId() => _syncId;
public void SetSyncId(ushort id)
{
_syncId = id;
ObjectSyncCache.UpdateSyncId(this);
}
public InteractableHost interactableHost;
public InteractableHostManager interactableManager;
public Poolee poolee;
private Rigidbody[] rigidbodies;
private Transform[] transforms;
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()
{
FindComponents();
@@ -88,22 +162,26 @@ namespace BoneSync.Sync.Components
{
if (poolee && poolee.pool)
{
return null;
return "";
}
if (interactableHost)
if (interactableHost || interactableManager)
{
// get full path from root
return interactableHost.transform.GetPath();
return transform.GetPath();
}
return null;
return "";
}
public void FindComponents()
{
ObjectSyncCache.RemoveSyncable(this);
interactableManager = GetComponent<InteractableHostManager>();
interactableHost = GetComponent<InteractableHost>();
poolee = GetComponent<Poolee>();
rigidbodies = GetComponentsInChildren<Rigidbody>();
UpdateTransformList();
ObjectSyncCache.AddSyncable(this);
}
public bool ShouldSync()
@@ -123,39 +201,48 @@ namespace BoneSync.Sync.Components
public void DiscardSyncable()
{
ObjectSyncCache.RemoveSyncable(this);
Destroy(this);
}
public void OnDisable()
{
if (!Registered)
{
DiscardSyncable();
return;
}
public ObjectSyncMessageData GetObjectSyncData()
{
ObjectSyncMessageData data = new ObjectSyncMessageData()
{
objectId = _syncId,
objectSyncTransforms = new ObjectSyncTransform[transforms.Length],
};
for (int i = 0; i < transforms.Length; i++)
{
data.objectSyncTransforms[i] = new ObjectSyncTransform()
{
transform = new SimpleTransform(transforms[i]),
velocity = Vector3.zero
};
}
return data;
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;
MelonLogger.Msg("Registering syncable object: " + gameObject.name);
ObjectSync.RegisterSyncable(this);
_attemptedRegister = true;
_SendRegisterSync();
}
}

View File

@@ -1,5 +1,8 @@
using BoneSync.Sync.Components;
using BoneSync.Networking.Messages;
using BoneSync.Sync.Components;
using MelonLoader;
using StressLevelZero.Interaction;
using StressLevelZero.Pool;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -9,12 +12,206 @@ using UnityEngine;
namespace BoneSync.Sync
{
public static class ObjectSyncCache
{
private static Dictionary<string, Syncable> _pathToSyncable = new Dictionary<string, Syncable>();
private static Dictionary<ushort, Syncable> _idToSyncable = new Dictionary<ushort, Syncable>();
private static Dictionary<Poolee, Syncable> _pooleeToSyncable = new Dictionary<Poolee, Syncable>();
private static Dictionary<InteractableHost, Syncable> _interactableHostToSyncable = new Dictionary<InteractableHost, Syncable>();
private static Dictionary<InteractableHostManager, Syncable> _interactableHostManagerToSyncable = new Dictionary<InteractableHostManager, Syncable>();
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<ushort, Syncable> 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
{
public static void RegisterSyncable(Syncable syncable)
private static ushort _nextSyncableId = 1;
public static ushort GetNextId()
{
return _nextSyncableId++;
}
public static RegisterSyncableInfo? GetRegisterInfo(Syncable syncable)
{
RegisterSyncableInfo? info = null;
string path = syncable.GetSyncableWorldPath();
if (path.Length > 0)
{
info = new RegisterSyncableInfo()
{
type = RegisterSyncType.RegisterFromPath,
transformPath = path,
ownerId = syncable._ownerId,
};
}
else if (syncable.poolee)
{
info = new RegisterSyncableInfo()
{
type = RegisterSyncType.RegisterAndSpawn,
transformPath = syncable.poolee.transform.GetPath(),
};
}
return info;
}
public static ushort SendRegisterSyncableMessage(Syncable syncable)
{
RegisterSyncableInfo? infoNullable = GetRegisterInfo(syncable);
if (infoNullable == null)
{
MelonLogger.Msg("No valid registeration method for syncable");
return 0;
}
RegisterSyncableInfo info = infoNullable.Value;
RegisterSyncableMessage message = new RegisterSyncableMessage(info);
if (BoneSync.lobby.IsHost)
{
info.id = GetNextId();
message.Broadcast();
}
else
{
info.id = 0;
message.Send(BoneSync.lobby.GetHostId());
}
return info.id;
}
public static void SendObjectSyncMessage(Syncable syncable)
{
MelonLogger.Msg("Sending object sync message for: " + syncable.transform.name);
ObjectSyncTransform[] objectSyncTransforms = syncable.GetObjectSyncTransforms();
ObjectSyncMessageData data = new ObjectSyncMessageData()
{
objectId = syncable.GetSyncId(),
objectSyncTransforms = objectSyncTransforms,
};
ObjectSyncMessage message = new ObjectSyncMessage(data);
message.Broadcast();
}
private static Syncable _MakeOrGetSyncable(GameObject gameObject, bool deleteSubSyncabled = true)
{
@@ -34,6 +231,10 @@ namespace BoneSync.Sync
{
syncable = gameObject.AddComponent<Syncable>();
}
else
{
syncable.FindComponents();
}
return syncable;
}
@@ -47,5 +248,41 @@ namespace BoneSync.Sync
{
return _MakeOrGetSyncable(interactableHostManager.gameObject);
}
public static void OnRegisterSyncMessage(RegisterSyncableMessage registerSyncableMessage)
{
Syncable syncable = null;
RegisterSyncableInfo info = registerSyncableMessage.info;
if (BoneSync.lobby.IsHost)
{
info.id = GetNextId();
new RegisterSyncableMessage(info).Broadcast();
}
switch (info.type)
{
case RegisterSyncType.RegisterFromPath:
MelonLogger.Msg("Registering syncable from path: " + info.transformPath + " with id: " + info.id);
syncable = ObjectSyncCache.GetSyncable(info.transformPath);
break;
case RegisterSyncType.RegisterAndSpawn:
break;
}
syncable.SetSyncId(info.id);
syncable.SetOwner(info.ownerId);
}
public static void OnObjectSyncMessage(ObjectSyncMessage objectSyncMessage)
{
ObjectSyncMessageData data = objectSyncMessage.objectSyncMessageData;
Syncable syncable = ObjectSyncCache.GetSyncable(data.objectId);
if (syncable == null)
{
MelonLogger.Msg("Syncable not found for id: " + data.objectId);
return;
}
syncable.ApplyObjectSyncTransforms(data.objectSyncTransforms);
}
}
}

View File

@@ -20,7 +20,7 @@ namespace BoneSync.Sync
{
if (!_playerRigMap.ContainsKey(playerId))
{
PlayerRig playerRig = PlayerRig.InstantiatePlayerRigPrefab();
PlayerRig playerRig = new PlayerRig();
_playerRigMap.Add(playerId, playerRig);
}
@@ -38,12 +38,8 @@ namespace BoneSync.Sync
public static void SyncPlayer()
{
if (!_localPlayerRig)
{
_localPlayerRig = GameObject.Find(PlayerRig.RIGMANAGER_SCENE_NAME);
}
PlayerSyncInfo playerSyncInfo = new PlayerSyncInfo();
playerSyncInfo.headPos = new SimpleTransform(_localPlayerRig.transform);
playerSyncInfo.headPos = new SimpleTransform();
playerSyncInfo.leftHandPos = new SimpleTransform();
playerSyncInfo.rightHandPos = new SimpleTransform();