network stuff

This commit is contained in:
Aaro Varis
2025-03-02 11:45:15 +02:00
parent 055ee44da5
commit fc744fd1ab
12 changed files with 162 additions and 19 deletions

View File

@@ -85,11 +85,13 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Networking\Messages\DiscardSyncableMessage.cs" /> <Compile Include="Networking\Messages\DiscardSyncableMessage.cs" />
<Compile Include="Networking\Messages\ObjectAttributeMessage.cs" />
<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\OwnershipTransferMessage.cs" /> <Compile Include="Networking\Messages\OwnershipTransferMessage.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\GripPatches.cs" />
<Compile Include="Patching\InteractableHostPatches.cs" /> <Compile Include="Patching\InteractableHostPatches.cs" />
<Compile Include="Patching\ObjectHealthPatches.cs" /> <Compile Include="Patching\ObjectHealthPatches.cs" />
<Compile Include="Sync\Components\SyncableBase.cs" /> <Compile Include="Sync\Components\SyncableBase.cs" />

View File

@@ -8,6 +8,40 @@ using System.Threading.Tasks;
namespace BoneSync.Networking namespace BoneSync.Networking
{ {
public static class BitPacking
{
public static byte[] PackBits(bool[] bits)
{
int byteCount = bits.Length / 8;
if (bits.Length % 8 != 0)
{
byteCount++;
}
byte[] bytes = new byte[byteCount];
for (int i = 0; i < bits.Length; i++)
{
int byteIndex = i / 8;
int bitIndex = i % 8;
if (bits[i])
{
bytes[byteIndex] |= (byte)(1 << bitIndex);
}
}
return bytes;
}
public static bool[] UnpackBits(byte[] bytes, int bitCount)
{
bool[] bits = new bool[bitCount];
for (int i = 0; i < bitCount; i++)
{
int byteIndex = i / 8;
int bitIndex = i % 8;
bits[i] = (bytes[byteIndex] & (1 << bitIndex)) != 0;
}
return bits;
}
}
internal class ByteEncoder internal class ByteEncoder
{ {
public List<byte> Data; public List<byte> Data;
@@ -203,5 +237,19 @@ namespace BoneSync.Networking
} }
return matrix; return matrix;
} }
public void WriteBoolArray(bool[] array)
{
byte[] bytes = BitPacking.PackBits(array);
WriteByte((byte)bytes.Length);
WriteBytes(bytes);
}
public bool[] ReadBoolArray()
{
byte length = ReadByte();
byte[] bytes = ReadBytes(length);
return BitPacking.UnpackBits(bytes, length);
}
} }
} }

View File

@@ -10,7 +10,7 @@ namespace BoneSync.Networking.Messages
{ {
public struct DiscardSyncableMessageData public struct DiscardSyncableMessageData
{ {
public ushort syncableId; public ushort syncId;
} }
[PacketType(PacketType.DiscardSyncable), PacketReliability(PacketReliability.ReliableFast)] [PacketType(PacketType.DiscardSyncable), PacketReliability(PacketReliability.ReliableFast)]
internal class DiscardSyncableMessage : NetworkMessage internal class DiscardSyncableMessage : NetworkMessage
@@ -20,18 +20,18 @@ namespace BoneSync.Networking.Messages
public DiscardSyncableMessage(DiscardSyncableMessageData discardSyncableMessageData) public DiscardSyncableMessage(DiscardSyncableMessageData discardSyncableMessageData)
{ {
_data = discardSyncableMessageData; _data = discardSyncableMessageData;
byteEncoder.WriteUShort(_data.syncableId); byteEncoder.WriteUShort(_data.syncId);
} }
public DiscardSyncableMessage(Packet packet) public DiscardSyncableMessage(Packet packet)
{ {
byteEncoder.WriteBytes(packet.Data); byteEncoder.WriteBytes(packet.Data);
_data.syncableId = byteEncoder.ReadUShort(); _data.syncId = byteEncoder.ReadUShort();
} }
public override void Execute() public override void Execute()
{ {
Syncable syncable = ObjectSyncCache.GetSyncable(_data.syncableId); Syncable syncable = ObjectSyncCache.GetSyncable(_data.syncId);
if (syncable != null) if (syncable != null)
{ {
syncable.DiscardSyncable(true); syncable.DiscardSyncable(true);

View File

@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BoneSync.Networking.Messages
{
public struct ObjectMagazineData
{
public byte ammoCount;
}
public struct ObjectAttributeMessageData
{
public ushort syncId;
public bool[] _attributes;
public ObjectMagazineData? magazineData;
}
internal class ObjectAttributeMessage : NetworkMessage
{
private ObjectAttributeMessageData _data;
public ObjectAttributeMessage(ObjectAttributeMessageData objectAttributeMessageData)
{
List<bool> attributes = new List<bool>();
_data = objectAttributeMessageData;
byteEncoder.WriteUShort(_data.syncId);
attributes.Add(_data.magazineData != null);
if (_data.magazineData != null)
{
byteEncoder.WriteByte(_data.magazineData.Value.ammoCount);
}
_data._attributes = attributes.ToArray();
}
public ObjectAttributeMessage(Packet packet)
{
byteEncoder.WriteBytes(packet.Data);
_data.syncId = byteEncoder.ReadUShort();
_data._attributes = byteEncoder.ReadBoolArray();
if (_data._attributes[0])
{
_data.magazineData = new ObjectMagazineData()
{
ammoCount = byteEncoder.ReadByte(),
};
}
}
}
}

View File

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

View File

@@ -9,19 +9,19 @@ namespace BoneSync.Networking.Messages
{ {
public struct OwnershipTransferMessageData public struct OwnershipTransferMessageData
{ {
public ushort SyncId; public ushort syncId;
public bool force; public bool force;
public ulong NewOwnerId; public ulong NewOwnerId;
} }
[PacketType(PacketType.ObjectOwnership), PacketReliability(PacketReliability.ReliableFast)] [PacketType(PacketType.ObjectOwnership), PacketReliability(PacketReliability.ReliableFast), PacketCatchup(2)]
internal class OwnershipTransferMessage : NetworkMessage internal class OwnershipTransferMessage : NetworkMessage
{ {
private OwnershipTransferMessageData Data; private OwnershipTransferMessageData Data;
public OwnershipTransferMessage(OwnershipTransferMessageData data) public OwnershipTransferMessage(OwnershipTransferMessageData data)
{ {
Data = data; Data = data;
byteEncoder.WriteUShort(Data.SyncId); byteEncoder.WriteUShort(Data.syncId);
byteEncoder.WriteULong(Data.NewOwnerId); byteEncoder.WriteULong(Data.NewOwnerId);
byteEncoder.WriteBool(Data.force); byteEncoder.WriteBool(Data.force);
} }
@@ -29,14 +29,14 @@ namespace BoneSync.Networking.Messages
public OwnershipTransferMessage(Packet packet) public OwnershipTransferMessage(Packet packet)
{ {
byteEncoder.WriteBytes(packet.Data); byteEncoder.WriteBytes(packet.Data);
Data.SyncId = byteEncoder.ReadUShort(); Data.syncId = byteEncoder.ReadUShort();
Data.NewOwnerId = byteEncoder.ReadULong(); Data.NewOwnerId = byteEncoder.ReadULong();
Data.force = byteEncoder.ReadBool(); Data.force = byteEncoder.ReadBool();
} }
override public void Execute() override public void Execute()
{ {
ObjectSync.OnOwnershipChangeMessage(Data.SyncId, Data.NewOwnerId, Data.force); ObjectSync.OnOwnershipChangeMessage(Data.syncId, Data.NewOwnerId, Data.force);
} }
} }

View File

@@ -29,7 +29,7 @@ namespace BoneSync.Networking.Messages
public SpawnPoolableInfo? spawnInfo; public SpawnPoolableInfo? spawnInfo;
} }
[PacketType(PacketType.RegisterSyncable), PacketReliability(PacketReliability.ReliableFast)] [PacketType(PacketType.RegisterSyncable), PacketReliability(PacketReliability.ReliableFast), PacketCatchup(0)]
internal class RegisterSyncableMessage : NetworkMessage internal class RegisterSyncableMessage : NetworkMessage
{ {
private RegisterSyncableInfo _info; private RegisterSyncableInfo _info;

View File

@@ -33,6 +33,15 @@ namespace BoneSync.Networking
public PacketReliability reliability { get; } public PacketReliability reliability { get; }
} }
public class PacketCatchupAttribute : Attribute
{
public int order { get; }
public PacketCatchupAttribute(int order = 1)
{
this.order = order;
}
}
public abstract class NetworkMessage public abstract class NetworkMessage
{ {
public ulong senderId public ulong senderId

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BoneSync.Sync;
using HarmonyLib;
using StressLevelZero.Interaction;
namespace BoneSync.Patching
{
[HarmonyPatch(typeof(ForcePullGrip))]
internal class ForcePullGripPatches
{
[HarmonyPatch(nameof(ForcePullGrip.Pull)), HarmonyPostfix]
public static void OnEnablePatch(ForcePullGrip __instance)
{
MelonLoader.MelonLogger.Msg("ForcePullGrip.Pull: " + __instance.name);
ObjectSync.MakeOrGetSyncable(__instance.gameObject);
}
}
}

View File

@@ -23,12 +23,13 @@ namespace BoneSync.Patching
private static bool TakeDamagePatch(ObjectDestructable __instance, ref Vector3 normal, ref float damage, ref bool crit, ref AttackType attackType) private static bool TakeDamagePatch(ObjectDestructable __instance, ref Vector3 normal, ref float damage, ref bool crit, ref AttackType attackType)
{ {
if (CallPatchedMethods.allowPatchedMethodCall) return true; if (CallPatchedMethods.allowPatchedMethodCall) return true;
if (damage < 0.05f) return true; // ignore small damage (e.g. a little bit of fall damage)
MelonLoader.MelonLogger.Msg("ObjectDestructable.TakeDamage: " + damage); MelonLoader.MelonLogger.Msg("ObjectDestructable.TakeDamage: " + damage);
Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance.gameObject); Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance.gameObject);
if (syncable != null) if (syncable != null)
{ {
if (damage > 0.5f) syncable.RegisterSyncable(); if (damage > 0.5f) syncable.RegisterSyncable(); // register syncable if damage is very significant, e.g. a bullet hit
if (!syncable.isOwner) return true; if (!syncable.isOwner) return false;
MelonLoader.MelonLogger.Msg("Patch: ObjectDestructable.TakeDamage: " + damage + " " + syncable.gameObject.name); MelonLoader.MelonLogger.Msg("Patch: ObjectDestructable.TakeDamage: " + damage + " " + syncable.gameObject.name);
ObjectHealthInfo objectHealthInfo = new ObjectHealthInfo(__instance._health, __instance._hits, normal, damage, crit, attackType); ObjectHealthInfo objectHealthInfo = new ObjectHealthInfo(__instance._health, __instance._hits, normal, damage, crit, attackType);

View File

@@ -60,7 +60,7 @@ namespace BoneSync.Sync.Components
{ {
DiscardSyncableMessageData discardSyncableMessageData = new DiscardSyncableMessageData() DiscardSyncableMessageData discardSyncableMessageData = new DiscardSyncableMessageData()
{ {
syncableId = _syncId syncId = _syncId
}; };
DiscardSyncableMessage discardSyncableMessage = new DiscardSyncableMessage(discardSyncableMessageData); DiscardSyncableMessage discardSyncableMessage = new DiscardSyncableMessage(discardSyncableMessageData);
discardSyncableMessage.Broadcast(); discardSyncableMessage.Broadcast();
@@ -73,7 +73,7 @@ namespace BoneSync.Sync.Components
MelonLogger.Msg("Sending ownership transfer for " + _syncId + " to " + newOwnerId); MelonLogger.Msg("Sending ownership transfer for " + _syncId + " to " + newOwnerId);
OwnershipTransferMessageData data = new OwnershipTransferMessageData() OwnershipTransferMessageData data = new OwnershipTransferMessageData()
{ {
SyncId = _syncId, syncId = _syncId,
NewOwnerId = newOwnerId, NewOwnerId = newOwnerId,
force = true force = true
}; };
@@ -90,7 +90,7 @@ namespace BoneSync.Sync.Components
MelonLogger.Msg("Attempting to become owner of " + _syncId); MelonLogger.Msg("Attempting to become owner of " + _syncId);
OwnershipTransferMessageData data = new OwnershipTransferMessageData() OwnershipTransferMessageData data = new OwnershipTransferMessageData()
{ {
SyncId = _syncId, syncId = _syncId,
NewOwnerId = BoneSync.lobby.GetLocalId(), NewOwnerId = BoneSync.lobby.GetLocalId(),
force = false force = false
}; };

View File

@@ -105,7 +105,12 @@ 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
@@ -128,7 +133,7 @@ namespace BoneSync.Sync
return syncable; return syncable;
} }
public static Syncable GetSyncableFromCache(GameObject gameObject) private static Syncable _GetSyncableFromCache(GameObject gameObject)
{ {
bool success = Syncable.syncablesCache.TryGetValue(gameObject, out Syncable syncable); bool success = Syncable.syncablesCache.TryGetValue(gameObject, out Syncable syncable);
if (!success) if (!success)
@@ -140,7 +145,7 @@ namespace BoneSync.Sync
public static Syncable MakeOrGetSyncable(GameObject gameObject) public static Syncable MakeOrGetSyncable(GameObject gameObject)
{ {
Syncable syncable = GetSyncableFromCache(gameObject); Syncable syncable = _GetSyncableFromCache(gameObject);
if (syncable == null) if (syncable == null)
{ {
syncable = _MakeOrGetSyncable(gameObject); syncable = _MakeOrGetSyncable(gameObject);