Ownership transfer and shit, and some pool stuff

This commit is contained in:
Aaro Varis
2025-03-01 23:05:46 +02:00
parent 061e7e6d8d
commit 76062e026e
17 changed files with 311 additions and 102 deletions

View File

@@ -86,6 +86,7 @@
<ItemGroup> <ItemGroup>
<Compile Include="Networking\Messages\ObjectDamageMessage.cs" /> <Compile Include="Networking\Messages\ObjectDamageMessage.cs" />
<Compile Include="Networking\Messages\ObjectSyncMessage.cs" /> <Compile Include="Networking\Messages\ObjectSyncMessage.cs" />
<Compile Include="Networking\Messages\OnwershipTransferMessage.cs" />
<Compile Include="Networking\Messages\RegisterSyncableMessage.cs" /> <Compile Include="Networking\Messages\RegisterSyncableMessage.cs" />
<Compile Include="Patching\CallPatchedMethod.cs" /> <Compile Include="Patching\CallPatchedMethod.cs" />
<Compile Include="Patching\InteractableHostPatches.cs" /> <Compile Include="Patching\InteractableHostPatches.cs" />

View File

@@ -124,7 +124,7 @@ namespace BoneSync.Networking
return Encoding.UTF8.GetString(ReadBytes(length)); return Encoding.UTF8.GetString(ReadBytes(length));
} }
public void WriteUlong(ulong value) public void WriteULong(ulong value)
{ {
WriteBytes(BitConverter.GetBytes(value)); WriteBytes(BitConverter.GetBytes(value));
} }

View File

@@ -39,6 +39,7 @@ namespace BoneSync.Networking.LobbyManager
SteamMatchmaking.OnLobbyMemberJoined += (Lobby lobby, Friend friend) => SteamMatchmaking.OnLobbyMemberJoined += (Lobby lobby, Friend friend) =>
{ {
MelonLogger.Msg("Member joined " + friend.Id); MelonLogger.Msg("Member joined " + friend.Id);
SteamFriends.SetPlayedWith(friend.Id);
UpdateLobbyData(); UpdateLobbyData();
}; };
MelonLogger.Msg("SteamLobbyManager initialized"); MelonLogger.Msg("SteamLobbyManager initialized");
@@ -55,8 +56,6 @@ namespace BoneSync.Networking.LobbyManager
ulong lobbyId = ulong.Parse(connectString.Split(':')[1]); ulong lobbyId = ulong.Parse(connectString.Split(':')[1]);
JoinLobby(lobbyId); JoinLobby(lobbyId);
}; };
SteamNetworkingUtils.InitRelayNetworkAccess();
} }
private Lobby _lobbyInstance; private Lobby _lobbyInstance;

View File

@@ -41,7 +41,7 @@ namespace BoneSync.Networking.Messages
public ObjectHealthInfo objectHealthInfo; public ObjectHealthInfo objectHealthInfo;
} }
[PacketType(PacketType.ObjectEvent), PacketReliability(PacketReliability.UnreliableNoDelay)] [PacketType(PacketType.ObjectEvent), PacketReliability(PacketReliability.Unreliable)]
public class ObjectDamageMessage : NetworkMessage public class ObjectDamageMessage : NetworkMessage
{ {
public ObjectDamageInfo objectEventInfo => _objectEventInfo; public ObjectDamageInfo objectEventInfo => _objectEventInfo;

View File

@@ -21,7 +21,7 @@ namespace BoneSync.Networking.Messages
public ObjectSyncTransform[] objectSyncTransforms; public ObjectSyncTransform[] objectSyncTransforms;
} }
[PacketType(PacketType.ObjectSync), PacketReliability(PacketReliability.UnreliableNoDelay)] [PacketType(PacketType.ObjectSync), PacketReliability(PacketReliability.Unreliable)]
internal class ObjectSyncMessage : NetworkMessage internal class ObjectSyncMessage : NetworkMessage
{ {
private ObjectSyncMessageData _objectSyncMessageData = new ObjectSyncMessageData(); private ObjectSyncMessageData _objectSyncMessageData = new ObjectSyncMessageData();

View File

@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BoneSync.Sync;
namespace BoneSync.Networking.Messages
{
public struct OnwershipTransferMessageData
{
public ushort SyncId;
public bool force;
public ulong NewOwnerId;
}
[PacketType(PacketType.ObjectOwnership)]
internal class OnwershipTransferMessage : NetworkMessage
{
private OnwershipTransferMessageData Data;
public OnwershipTransferMessage(OnwershipTransferMessageData data)
{
Data = data;
byteEncoder.WriteUShort(Data.SyncId);
byteEncoder.WriteULong(Data.NewOwnerId);
byteEncoder.WriteBool(Data.force);
}
public OnwershipTransferMessage(Packet packet)
{
byteEncoder.WriteBytes(packet.Data);
Data.SyncId = byteEncoder.ReadUShort();
Data.NewOwnerId = byteEncoder.ReadUlong();
Data.force = byteEncoder.ReadBool();
}
override public void Execute()
{
ObjectSync.OnOwnershipChangeMessage(Data.SyncId, Data.NewOwnerId, Data.force);
}
}
}

View File

@@ -23,12 +23,13 @@ namespace BoneSync.Networking.Messages
{ {
public string transformPath; public string transformPath;
public ushort id; public ushort id;
public ushort callbackId;
public ulong ownerId; public ulong ownerId;
public RegisterSyncType type; public RegisterSyncType type;
public SpawnPoolableInfo? spawnInfo; public SpawnPoolableInfo? spawnInfo;
} }
[PacketType(PacketType.RegisterSyncable)] [PacketType(PacketType.RegisterSyncable), PacketReliability(PacketReliability.ReliableFast)]
internal class RegisterSyncableMessage : NetworkMessage internal class RegisterSyncableMessage : NetworkMessage
{ {
private RegisterSyncableInfo _info; private RegisterSyncableInfo _info;
@@ -37,8 +38,9 @@ namespace BoneSync.Networking.Messages
{ {
_info = info; _info = info;
byteEncoder.WriteByte((byte)_info.type); byteEncoder.WriteByte((byte)_info.type);
byteEncoder.WriteUlong(_info.ownerId); byteEncoder.WriteULong(_info.ownerId);
byteEncoder.WriteUShort(_info.id); byteEncoder.WriteUShort(_info.id);
byteEncoder.WriteUShort(_info.callbackId);
switch (_info.type) switch (_info.type)
{ {
case RegisterSyncType.RegisterAndSpawn: case RegisterSyncType.RegisterAndSpawn:
@@ -58,6 +60,7 @@ namespace BoneSync.Networking.Messages
_info.type = (RegisterSyncType)byteEncoder.ReadByte(); _info.type = (RegisterSyncType)byteEncoder.ReadByte();
_info.ownerId = byteEncoder.ReadUlong(); _info.ownerId = byteEncoder.ReadUlong();
_info.id = byteEncoder.ReadUShort(); _info.id = byteEncoder.ReadUShort();
_info.callbackId = byteEncoder.ReadUShort();
switch (_info.type) switch (_info.type)
{ {
case RegisterSyncType.RegisterAndSpawn: case RegisterSyncType.RegisterAndSpawn:

View File

@@ -118,9 +118,9 @@ namespace BoneSync.Networking
public Packet GetPacket(int id, ulong senderId, ulong receiverId) public Packet GetPacket(ulong senderId, ulong receiverId)
{ {
PacketInfo packetInfo = new PacketInfo(id, senderId, receiverId, GetPacketType(), GetPacketReliability()); PacketInfo packetInfo = new PacketInfo(senderId, receiverId, GetPacketType(), GetPacketReliability());
Packet packet = new Packet(packetInfo, GetBytes()); Packet packet = new Packet(packetInfo, GetBytes());
return packet; return packet;
} }
@@ -140,9 +140,8 @@ namespace BoneSync.Networking
MelonLogger.Warning("Cannot send packet, not connected to lobby"); MelonLogger.Warning("Cannot send packet, not connected to lobby");
return; return;
} }
int PacketId = Packet.GenerateId();
ulong senderId = BoneSync.lobby.GetLocalId(); ulong senderId = BoneSync.lobby.GetLocalId();
Packet packet = GetPacket(PacketId, senderId, receiverId); Packet packet = GetPacket(senderId, receiverId);
BoneSync.transport.Send(packet); BoneSync.transport.Send(packet);
} }

View File

@@ -15,35 +15,61 @@ namespace BoneSync.Networking
public enum PacketReliability public enum PacketReliability
{ {
Unreliable = 0, Unreliable = 0,
UnreliableNoDelay = 1, Reliable = 1,
Reliable = 2, ReliableFast = 2,
ReliableWithBuffering = 3,
} }
public struct PacketInfo public struct PacketInfo
{ {
public int id; public ulong id;
public ulong senderId; public ulong senderId;
public ulong receiverId; public ulong receiverId;
public PacketType packetType; public PacketType packetType;
public PacketReliability reliability; public PacketReliability reliability;
public PacketInfo( public PacketInfo(
int id,
ulong senderId, ulong senderId,
ulong receiverId, ulong receiverId,
PacketType packetType, PacketType packetType,
PacketReliability reliability = PacketReliability.Reliable PacketReliability reliability = PacketReliability.Reliable,
ulong id = 0
) )
{ {
this.id = id;
this.senderId = senderId; this.senderId = senderId;
this.receiverId = receiverId; this.receiverId = receiverId;
this.packetType = packetType; this.packetType = packetType;
this.reliability = reliability; this.reliability = reliability;
this.id = id == 0 ? Packet.GenerateId() : id;
} }
} }
public class Packet public class Packet
{ {
private static ulong _packetId = 1;
private static Dictionary<ulong, Dictionary<PacketType, ulong>> _latestPacketIds = new Dictionary<ulong, Dictionary<PacketType, ulong>>();
private static void SetLatestPacketId(ulong id, PacketType packetType, ulong value)
{
if (!_latestPacketIds.ContainsKey(id))
{
_latestPacketIds.Add(id, new Dictionary<PacketType, ulong>());
}
_latestPacketIds[id][packetType] = value;
}
private static ulong GetLatestPacketId(ulong id, PacketType packetType)
{
if (!_latestPacketIds.ContainsKey(id))
{
return 0;
}
if (!_latestPacketIds[id].ContainsKey(packetType))
{
return 0;
}
return _latestPacketIds[id][packetType];
}
public PacketInfo Info public PacketInfo Info
{ {
get => _packetInfo; get => _packetInfo;
@@ -66,11 +92,11 @@ namespace BoneSync.Networking
byte packetType = byteEncoder.ReadByte(); byte packetType = byteEncoder.ReadByte();
byte reliability = byteEncoder.ReadByte(); byte reliability = byteEncoder.ReadByte();
int id = byteEncoder.ReadInt(); ulong id = byteEncoder.ReadUlong();
ulong senderId = byteEncoder.ReadUlong(); ulong senderId = byteEncoder.ReadUlong();
ulong receiverId = byteEncoder.ReadUlong(); ulong receiverId = byteEncoder.ReadUlong();
PacketInfo packetInfo = new PacketInfo(id, senderId, receiverId, (PacketType)packetType, (PacketReliability)reliability); PacketInfo packetInfo = new PacketInfo(senderId, receiverId, (PacketType)packetType, (PacketReliability)reliability, id);
return new Packet(packetInfo, byteEncoder.ToArray()); return new Packet(packetInfo, byteEncoder.ToArray());
} }
@@ -79,15 +105,24 @@ namespace BoneSync.Networking
ByteEncoder byteEncoder = new ByteEncoder(); ByteEncoder byteEncoder = new ByteEncoder();
byteEncoder.WriteByte((byte)_packetInfo.packetType); byteEncoder.WriteByte((byte)_packetInfo.packetType);
byteEncoder.WriteByte((byte)_packetInfo.reliability); byteEncoder.WriteByte((byte)_packetInfo.reliability);
byteEncoder.WriteInt(_packetInfo.id); byteEncoder.WriteULong(_packetInfo.id);
byteEncoder.WriteUlong(_packetInfo.senderId); byteEncoder.WriteULong(_packetInfo.senderId);
byteEncoder.WriteUlong(_packetInfo.receiverId); byteEncoder.WriteULong(_packetInfo.receiverId);
byteEncoder.WriteBytes(_dataBytes); byteEncoder.WriteBytes(_dataBytes);
return byteEncoder.ToArray(); return byteEncoder.ToArray();
} }
public static bool OnPacketReceived(Packet packet) public static bool OnPacketReceived(Packet packet)
{ {
if (packet._packetInfo.reliability == PacketReliability.ReliableFast)
{
if (packet.Info.id <= GetLatestPacketId(packet.Info.senderId, packet.Info.packetType))
{
return false;
}
SetLatestPacketId(packet.Info.senderId, packet.Info.packetType, packet.Info.id);
}
NetworkMessage networkMessage = NetworkMessage.ParsePacket(packet); NetworkMessage networkMessage = NetworkMessage.ParsePacket(packet);
networkMessage.Execute(); networkMessage.Execute();
return true; return true;
@@ -95,9 +130,9 @@ namespace BoneSync.Networking
public byte[] Data => _dataBytes; public byte[] Data => _dataBytes;
public static int GenerateId() public static ulong GenerateId()
{ {
return new Random().Next(); return _packetId++;
} }
} }
#if TEST #if TEST

View File

@@ -14,5 +14,6 @@ namespace BoneSync.Networking
RegisterSyncable = 3, RegisterSyncable = 3,
ObjectSync = 4, ObjectSync = 4,
ObjectEvent = 5, ObjectEvent = 5,
ObjectOwnership = 6,
} }
} }

View File

@@ -8,6 +8,7 @@ using BoneSync.Networking.LobbyManager;
using Facepunch.Steamworks; using Facepunch.Steamworks;
using Facepunch.Steamworks.Data; using Facepunch.Steamworks.Data;
using MelonLoader; using MelonLoader;
using Oculus.Platform;
namespace BoneSync.Networking.Transport namespace BoneSync.Networking.Transport
{ {
@@ -17,6 +18,7 @@ namespace BoneSync.Networking.Transport
public SteamTransport() public SteamTransport()
{ {
SteamNetworking.OnP2PSessionRequest += OnP2PSessionRequest; SteamNetworking.OnP2PSessionRequest += OnP2PSessionRequest;
SteamNetworkingUtils.InitRelayNetworkAccess();
} }
private List<SteamId> OpenP2PConnections = new List<SteamId>(); private List<SteamId> OpenP2PConnections = new List<SteamId>();
private void OnP2PSessionRequest(SteamId steamId) private void OnP2PSessionRequest(SteamId steamId)
@@ -72,18 +74,44 @@ namespace BoneSync.Networking.Transport
return processed > 0; return processed > 0;
} }
public void SendP2P(SteamId peer, byte[] data, P2PSend sendType) public P2PSend GetSteamSendType(PacketReliability packetReliability)
{ {
switch (packetReliability)
{
case PacketReliability.Unreliable:
return P2PSend.UnreliableNoDelay;
case PacketReliability.Reliable:
return P2PSend.Reliable;
default:
return P2PSend.Reliable;
}
}
public void SendP2P(SteamId peer, byte[] data, PacketReliability sendType)
{
if (peer == BoneSync.lobby.GetLocalId()) if (peer == BoneSync.lobby.GetLocalId())
{ {
//MelonLogger.Msg("Trying to send packet to self"); //MelonLogger.Msg("Trying to send packet to self");
return; return;
} }
SteamNetworking.SendP2PPacket(peer, data, data.Length, 0, sendType);
if (sendType == PacketReliability.ReliableFast)
{
SteamNetworking.SendP2PPacket(peer, data, data.Length, 0, P2PSend.UnreliableNoDelay);
SteamNetworking.SendP2PPacket(peer, data, data.Length, 0, P2PSend.Reliable);
return;
}
P2PSend steamSendType = GetSteamSendType(sendType);
SteamNetworking.SendP2PPacket(peer, data, data.Length, 0, steamSendType);
} }
public override void Send(Packet packet) public override void Send(Packet packet)
{ {
P2PSend sendType = (P2PSend)packet.Info.reliability;
LobbyManager.LobbyManager _instance = BoneSync.lobby; LobbyManager.LobbyManager _instance = BoneSync.lobby;
if (_instance == null) if (_instance == null)
{ {
@@ -94,14 +122,14 @@ namespace BoneSync.Networking.Transport
{ {
foreach (SteamId peer in _instance.GetPeers()) foreach (SteamId peer in _instance.GetPeers())
{ {
SendP2P(peer, packet.ToBytes(), sendType); SendP2P(peer, packet.ToBytes(), packet.Info.reliability);
} }
return; return;
} }
else else
{ {
SendP2P(packet.Info.receiverId, packet.ToBytes(), sendType); SendP2P(packet.Info.receiverId, packet.ToBytes(), packet.Info.reliability);
} }
} }

View File

@@ -19,7 +19,8 @@ namespace BoneSync.Patching
{ {
public static class PoolBlacklist public static class PoolBlacklist
{ {
private static Dictionary<Pool, Boolean> _blacklistedCache = new Dictionary<Pool, bool>(); private static Dictionary<Pool, bool> _blacklistedCache = new Dictionary<Pool, bool>();
private static Dictionary<Pool, bool> _clientSpawnCache = new Dictionary<Pool, bool>();
private static bool _isBlacklistedPool(Pool pool) private static bool _isBlacklistedPool(Pool pool)
{ {
@@ -31,10 +32,15 @@ namespace BoneSync.Patching
if (pool.Prefab.GetComponent<SpawnFragment>() != null) return true; if (pool.Prefab.GetComponent<SpawnFragment>() != null) return true;
if (pool.Prefab.GetComponent<SpawnFragmentArray>() != null) return true; if (pool.Prefab.GetComponent<SpawnFragmentArray>() != null) return true;
if (pool.Prefab.GetComponent<Magazine>() != null) return true;
return false; return false;
} }
private static bool _isClientSpawnPool(Pool pool)
{
if (pool.Prefab.GetComponent<Magazine>() != null) return true;
return false;
}
public static bool isBlacklistedPool(Pool pool) public static bool isBlacklistedPool(Pool pool)
{ {
if (_blacklistedCache.ContainsKey(pool)) if (_blacklistedCache.ContainsKey(pool))
@@ -42,6 +48,14 @@ namespace BoneSync.Patching
_blacklistedCache[pool] = _isBlacklistedPool(pool); _blacklistedCache[pool] = _isBlacklistedPool(pool);
return _blacklistedCache[pool]; return _blacklistedCache[pool];
} }
public static bool IsClientSpawnPool(Pool pool)
{
if (_clientSpawnCache.ContainsKey(pool))
return _clientSpawnCache[pool];
_clientSpawnCache[pool] = _isClientSpawnPool(pool);
return _clientSpawnCache[pool];
}
} }
[HarmonyPatch(typeof(Pool))] [HarmonyPatch(typeof(Pool))]
@@ -110,19 +124,19 @@ namespace BoneSync.Patching
public static void OnSpawnPatchPost(Poolee __instance) public static void OnSpawnPatchPost(Poolee __instance)
{ {
if (CallPatchedMethods.allowPatchedMethodCall) return; if (CallPatchedMethods.allowPatchedMethodCall) return;
if (__instance.pool == null) return;
if (PoolBlacklist.isBlacklistedPool(__instance.pool)) return;
MelonLogger.Msg("Poolee.OnSpawn: " + __instance.gameObject.transform.GetPath());
if (!BoneSync.lobby.IsConnected()) return; if (!BoneSync.lobby.IsConnected()) return;
Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance);
if (BoneSync.lobby.IsHost) MelonLogger.Msg("Poolee.OnSpawn: " + __instance.gameObject.transform.GetPath());
{
//syncable.RegisterSyncable(); ObjectSync.MakeOrGetSyncable(__instance);
} else
{ bool spawnNormally = BoneSync.lobby.IsHost || PoolBlacklist.IsClientSpawnPool(__instance.pool);
MelonCoroutines.Start(OnSpawnClient(__instance));
} if (spawnNormally) return;
MelonCoroutines.Start(OnSpawnClient(__instance)); // block object from spawning
} }
public static IEnumerator OnSpawnClient(Poolee poolee) public static IEnumerator OnSpawnClient(Poolee poolee)
@@ -135,8 +149,6 @@ namespace BoneSync.Patching
go.SetActive(false); go.SetActive(false);
yield return null; yield return null;
} }
} }
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)

View File

@@ -72,23 +72,6 @@ namespace BoneSync.Sync.Components
return false; return false;
} }
public bool ShouldSendSync()
{
if (!Registered) return false;
if (!isOwner) return false;
if (isStale) return true;
if (AllRigidbodiesSleeping()) return false;
return true;
}
public ushort GetSyncId() => _syncId;
public void SetSyncId(ushort id)
{
_syncId = id;
ObjectSyncCache.UpdateSyncId(this);
}
public InteractableHost interactableHost { private set; get; } public InteractableHost interactableHost { private set; get; }
public InteractableHostManager interactableManager { private set; get; } public InteractableHostManager interactableManager { private set; get; }
public Poolee poolee { private set; get; } public Poolee poolee { private set; get; }
@@ -117,7 +100,7 @@ namespace BoneSync.Sync.Components
FindComponents(); FindComponents();
bool shouldAutoSync = CheckIfShouldAutoSync(); bool shouldAutoSync = CheckIfShouldAutoSync();
if (shouldAutoSync && BoneSync.lobby.IsHost) if (shouldAutoSync && (BoneSync.lobby.IsHost || ClientSpawningAllowed()))
{ {
MelonLogger.Msg("AutoSyncing: " + transform.GetPath()); MelonLogger.Msg("AutoSyncing: " + transform.GetPath());
RegisterSyncable(); RegisterSyncable();
@@ -181,6 +164,10 @@ namespace BoneSync.Sync.Components
public void DiscardSyncable() public void DiscardSyncable()
{ {
if (Registered)
{
MelonLogger.Warning("Discarding registered syncable: " + transform.GetPath());
}
syncablesCache.Remove(gameObject); syncablesCache.Remove(gameObject);
ObjectSyncCache.RemoveSyncable(this); ObjectSyncCache.RemoveSyncable(this);
Destroy(this); Destroy(this);
@@ -188,20 +175,18 @@ namespace BoneSync.Sync.Components
public void OnDisable() public void OnDisable()
{ {
if (!Registered) DiscardSyncable();
{
DiscardSyncable();
return;
}
MelonLogger.Warning("Registered Syncable disabled: " + transform.GetPath());
} }
public void RegisterSyncable() public void RegisterSyncable()
{ {
if (!BoneSync.lobby.IsConnected()) return; if (!BoneSync.lobby.IsConnected()) return;
if (Registered)
{
TryBecomeOwner();
return;
}
if (_attemptedRegister) return; if (_attemptedRegister) return;
if (Registered) return;
if (!CanBeSynced()) return; if (!CanBeSynced()) return;
_attemptedRegister = true; _attemptedRegister = true;
_SendRegisterSync(); _SendRegisterSync();

View File

@@ -1,4 +1,6 @@
using MelonLoader; using BoneSync.Networking.Messages;
using BoneSync.Patching;
using MelonLoader;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
@@ -37,6 +39,16 @@ namespace BoneSync.Sync.Components
MelonCoroutines.Start(SyncCoroutineAsync()); MelonCoroutines.Start(SyncCoroutineAsync());
UpdateKinematic(); UpdateKinematic();
} }
public bool ClientSpawningAllowed()
{
if (poolee && poolee.pool)
{
return PoolBlacklist.IsClientSpawnPool(poolee.pool);
}
return false;
}
private void _SendRegisterSync() private void _SendRegisterSync()
{ {
MelonLogger.Msg("Registering syncable object: " + gameObject.name); MelonLogger.Msg("Registering syncable object: " + gameObject.name);
@@ -46,12 +58,53 @@ namespace BoneSync.Sync.Components
public void OnOwnershipTransferRequest(ulong newOwnerId) public void OnOwnershipTransferRequest(ulong newOwnerId)
{ {
MelonLogger.Msg("Ownership transfer request for " + _syncId + " to " + newOwnerId); //MelonLogger.Msg("Ownership transfer request for " + _syncId + " to " + newOwnerId);
if (isOwner) if (isOwner && !IsHolding())
{ {
MelonLogger.Msg("Sending ownership transfer for " + _syncId + " to " + newOwnerId); MelonLogger.Msg("Sending ownership transfer for " + _syncId + " to " + newOwnerId);
//BoneSync.lobby.SendOwnershipTransferMessage(_syncId, newOwnerId); OnwershipTransferMessageData data = new OnwershipTransferMessageData()
{
SyncId = _syncId,
NewOwnerId = newOwnerId,
force = true
};
OnwershipTransferMessage message = new OnwershipTransferMessage(data);
message.Broadcast();
SetOwner(newOwnerId);
} }
} }
public void TryBecomeOwner()
{
if (!isOwner)
{
MelonLogger.Msg("Attempting to become owner of " + _syncId);
OnwershipTransferMessageData data = new OnwershipTransferMessageData()
{
SyncId = _syncId,
NewOwnerId = BoneSync.lobby.GetLocalId(),
force = false
};
OnwershipTransferMessage message = new OnwershipTransferMessage(data);
message.Broadcast();
}
}
public bool ShouldSendSync()
{
if (!Registered) return false;
if (!isOwner) return false;
if (isStale) return true;
if (AllRigidbodiesSleeping()) return false;
return true;
}
public ushort GetSyncId() => _syncId;
public void SetSyncId(ushort id)
{
_syncId = id;
ObjectSyncCache.UpdateSyncId(this);
}
} }
} }

View File

@@ -17,15 +17,25 @@ namespace BoneSync.Sync.Components
{ {
foreach (Rigidbody rb in rigidbodies) foreach (Rigidbody rb in rigidbodies)
{ {
if (!rb.IsSleeping()) return false; try
{
if (!rb.IsSleeping()) return false;
}
catch { } // ignore null rigidbodies
} }
return true; return true;
} }
private void SetKinematic(bool kinematic) private void SetKinematic(bool kinematic)
{ {
foreach (Rigidbody rb in rigidbodies) foreach (Rigidbody rb in rigidbodies)
{ {
rb.isKinematic = kinematic; try
{
rb.isKinematic = kinematic;
}
catch { } // ignore null rigidbodies
} }
} }

View File

@@ -12,6 +12,7 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
using Random = UnityEngine.Random;
namespace BoneSync.Sync namespace BoneSync.Sync
{ {
@@ -23,8 +24,10 @@ namespace BoneSync.Sync
return _nextSyncableId++; return _nextSyncableId++;
} }
public static RegisterSyncableInfo? GetRegisterInfo(Syncable syncable)
public static RegisterSyncableInfo? GetRegisterInfo(Syncable syncable, bool allowClientRegister)
{ {
ulong ownerId = BoneSync.lobby.GetLocalId();
RegisterSyncableInfo? info = null; RegisterSyncableInfo? info = null;
string path = syncable.GetSyncableWorldPath(); string path = syncable.GetSyncableWorldPath();
if (path.Length > 0) if (path.Length > 0)
@@ -33,13 +36,14 @@ namespace BoneSync.Sync
{ {
type = RegisterSyncType.RegisterFromPath, type = RegisterSyncType.RegisterFromPath,
transformPath = path, transformPath = path,
ownerId = syncable._ownerId, ownerId = ownerId,
}; };
} }
else if (syncable.poolee && syncable.poolee.pool && BoneSync.lobby.IsHost) else if (syncable.poolee && syncable.poolee.pool && (BoneSync.lobby.IsHost || allowClientRegister))
{ {
info = new RegisterSyncableInfo() info = new RegisterSyncableInfo()
{ {
ownerId = ownerId,
type = RegisterSyncType.RegisterAndSpawn, type = RegisterSyncType.RegisterAndSpawn,
spawnInfo = new SpawnPoolableInfo() spawnInfo = new SpawnPoolableInfo()
{ {
@@ -53,7 +57,7 @@ namespace BoneSync.Sync
public static ushort SendRegisterSyncableMessage(Syncable syncable) public static ushort SendRegisterSyncableMessage(Syncable syncable)
{ {
RegisterSyncableInfo? infoNullable = GetRegisterInfo(syncable); RegisterSyncableInfo? infoNullable = GetRegisterInfo(syncable, syncable.ClientSpawningAllowed());
if (infoNullable == null) if (infoNullable == null)
{ {
@@ -71,7 +75,8 @@ namespace BoneSync.Sync
new RegisterSyncableMessage(info).Broadcast(); new RegisterSyncableMessage(info).Broadcast();
} else } else
{ {
info.id = 0; info.callbackId = (ushort)Random.Range(1, ushort.MaxValue);
ObjectSyncCache._callbackIdToSyncable[info.callbackId] = syncable;
new RegisterSyncableMessage(info).SendToHost(); new RegisterSyncableMessage(info).SendToHost();
} }
@@ -100,15 +105,19 @@ 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[] subSyncables = gameObject.GetComponentsInChildren<Syncable>();
Syncable syncable = gameObject.GetComponent<Syncable>(); Syncable syncable = gameObject.GetComponent<Syncable>();
// delete all sub syncables // delete all sub syncables
for (int i = 0; i < subSyncables.Length; i++) if (deleteSubSyncabled)
{ {
if (subSyncables[i] != syncable) Syncable[] subSyncables = gameObject.GetComponentsInChildren<Syncable>(true);
for (int i = 0; i < subSyncables.Length; i++)
{ {
subSyncables[i].DiscardSyncable(); if (subSyncables[i] != syncable)
{
subSyncables[i].DiscardSyncable();
}
} }
} }
@@ -116,10 +125,6 @@ namespace BoneSync.Sync
{ {
syncable = gameObject.AddComponent<Syncable>(); syncable = gameObject.AddComponent<Syncable>();
} }
else
{
syncable.FindComponents();
}
return syncable; return syncable;
} }
@@ -158,10 +163,9 @@ namespace BoneSync.Sync
return _MakeOrGetSyncable(interactableHostManager.gameObject); return _MakeOrGetSyncable(interactableHostManager.gameObject);
} }
public static Syncable SpawnPooleeAndMakeSyncable(RegisterSyncableInfo info) public static Syncable SpawnPooleeAndMakeSyncable(SpawnPoolableInfo spawnInfo)
{ {
SpawnPoolableInfo spawnInfo = info.spawnInfo.Value;
SimpleTransform spawnLocation = spawnInfo.spawnLocation; SimpleTransform spawnLocation = spawnInfo.spawnLocation;
// !! This is a bit of a hack, but it works for now // !! This is a bit of a hack, but it works for now
@@ -180,6 +184,7 @@ namespace BoneSync.Sync
Poolee poolee = CallPatchedMethods.InstantiatePoolee(pool, spawnLocation.position, spawnLocation.rotation, pool.Prefab.transform.localScale); Poolee poolee = CallPatchedMethods.InstantiatePoolee(pool, spawnLocation.position, spawnLocation.rotation, pool.Prefab.transform.localScale);
Syncable syncable = MakeOrGetSyncable(poolee); Syncable syncable = MakeOrGetSyncable(poolee);
MelonLogger.Msg("Spawned poolee with syncable: " + poolee.transform.GetPath());
return syncable; return syncable;
} }
public static void OnRegisterSyncMessage(RegisterSyncableMessage registerSyncableMessage) public static void OnRegisterSyncMessage(RegisterSyncableMessage registerSyncableMessage)
@@ -192,6 +197,7 @@ namespace BoneSync.Sync
new RegisterSyncableMessage(info).Broadcast(); new RegisterSyncableMessage(info).Broadcast();
} else } else
{ {
// only host can register syncables, all spawn requests should be sent to host
if (registerSyncableMessage.senderId != BoneSync.lobby.GetHostId()) if (registerSyncableMessage.senderId != BoneSync.lobby.GetHostId())
{ {
MelonLogger.Warning("Received register sync message from non-host: " + registerSyncableMessage.senderId); MelonLogger.Warning("Received register sync message from non-host: " + registerSyncableMessage.senderId);
@@ -199,16 +205,30 @@ namespace BoneSync.Sync
} }
} }
switch (info.type) bool hasCallback = info.callbackId != 0;
if (hasCallback)
{ {
case RegisterSyncType.RegisterFromPath: MelonLogger.Msg("Received register sync message with callback id: " + info.callbackId);
MelonLogger.Msg("Registering syncable from path: " + info.transformPath + " with id: " + info.id); }
syncable = ObjectSyncCache.GetSyncable(info.transformPath);
break; if (hasCallback && ObjectSyncCache._callbackIdToSyncable.ContainsKey(info.callbackId))
case RegisterSyncType.RegisterAndSpawn: {
MelonLogger.Msg("Registering and spawning syncable from pool: " + info.spawnInfo.Value.poolName + " with id: " + info.id); MelonLogger.Msg("Found syncable for callback id: " + info.callbackId);
syncable = SpawnPooleeAndMakeSyncable(info); syncable = ObjectSyncCache._callbackIdToSyncable[info.callbackId];
break; ObjectSyncCache._callbackIdToSyncable.Remove(info.callbackId);
} else
{
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:
MelonLogger.Msg("Registering and spawning syncable from pool: " + info.spawnInfo.Value.poolName + " with id: " + info.id);
syncable = SpawnPooleeAndMakeSyncable(info.spawnInfo.Value);
break;
}
} }
if (!syncable) if (!syncable)
@@ -241,7 +261,7 @@ namespace BoneSync.Sync
Syncable syncable = ObjectSyncCache.GetSyncable(damageInfo.objectId); Syncable syncable = ObjectSyncCache.GetSyncable(damageInfo.objectId);
if (syncable == null) if (syncable == null)
{ {
MelonLogger.Msg("DamageEvent: Syncable not found for id: " + damageInfo.objectId); //MelonLogger.Msg("DamageEvent: Syncable not found for id: " + damageInfo.objectId);
return; return;
} }
syncable.Damage(damageInfo); syncable.Damage(damageInfo);
@@ -259,5 +279,23 @@ namespace BoneSync.Sync
message.Broadcast(); message.Broadcast();
message.Execute(); message.Execute();
} }
internal static void OnOwnershipChangeMessage(ushort syncId, ulong newOwnerId, bool force)
{
Syncable syncable = ObjectSyncCache.GetSyncable(syncId);
if (syncable == null)
{
MelonLogger.Warning("Ownership transfer request for non-existant syncable: " + syncId);
return;
}
if (force)
{
syncable.SetOwner(newOwnerId);
}
else
{
syncable.OnOwnershipTransferRequest(newOwnerId);
}
}
} }
} }

View File

@@ -17,6 +17,8 @@ namespace BoneSync.Sync
private static Dictionary<InteractableHost, Syncable> _interactableHostToSyncable = new Dictionary<InteractableHost, Syncable>(); private static Dictionary<InteractableHost, Syncable> _interactableHostToSyncable = new Dictionary<InteractableHost, Syncable>();
private static Dictionary<InteractableHostManager, Syncable> _interactableHostManagerToSyncable = new Dictionary<InteractableHostManager, Syncable>(); private static Dictionary<InteractableHostManager, Syncable> _interactableHostManagerToSyncable = new Dictionary<InteractableHostManager, Syncable>();
public static Dictionary<ushort, Syncable> _callbackIdToSyncable = new Dictionary<ushort, Syncable>();
public static void AddSyncable(Syncable syncable) public static void AddSyncable(Syncable syncable)
{ {
string path = syncable.GetSyncableWorldPath(); string path = syncable.GetSyncableWorldPath();