AI Sync initial changes

This commit is contained in:
Aaro Varis
2025-03-09 21:42:39 +02:00
parent adbd7f4704
commit 20a624fb0f
19 changed files with 311 additions and 73 deletions

View File

@@ -93,8 +93,10 @@
<Compile Include="Data\PlayerScripts.cs" /> <Compile Include="Data\PlayerScripts.cs" />
<Compile Include="Data\SpawnableManager.cs" /> <Compile Include="Data\SpawnableManager.cs" />
<Compile Include="Data\Structs.cs" /> <Compile Include="Data\Structs.cs" />
<Compile Include="Networking\Messages\AISyncMessage.cs" />
<Compile Include="Networking\Messages\DiscardSyncableMessage.cs" /> <Compile Include="Networking\Messages\DiscardSyncableMessage.cs" />
<Compile Include="Networking\Messages\GunSyncMessage.cs" /> <Compile Include="Networking\Messages\GunSyncMessage.cs" />
<Compile Include="Patching\AIHealthPatches.cs" />
<Compile Include="Patching\HolsterSlotPatches.cs" /> <Compile Include="Patching\HolsterSlotPatches.cs" />
<Compile Include="Networking\Messages\MagazineSyncMessage.cs" /> <Compile Include="Networking\Messages\MagazineSyncMessage.cs" />
<Compile Include="Networking\Messages\ObjectDamageMessage.cs" /> <Compile Include="Networking\Messages\ObjectDamageMessage.cs" />

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.Data namespace BoneSync.Data
{ {
@@ -45,6 +46,7 @@ namespace BoneSync.Data
} }
internal class ByteEncoder internal class ByteEncoder
{ {
public List<byte> Data; public List<byte> Data;
public ByteEncoder() public ByteEncoder()
{ {
@@ -61,6 +63,11 @@ namespace BoneSync.Data
return Data.ToArray(); return Data.ToArray();
} }
public void SetBytes(byte[] data)
{
Data = data.ToList();
}
public void WriteByte(byte value) public void WriteByte(byte value)
{ {
Data.Add(value); Data.Add(value);
@@ -169,30 +176,30 @@ namespace BoneSync.Data
return BitConverter.ToUInt64(ReadBytes(sizeof(ulong)), 0); return BitConverter.ToUInt64(ReadBytes(sizeof(ulong)), 0);
} }
public void WriteVector3(UnityEngine.Vector3 value) public void WriteVector3(Vector3 value)
{ {
WriteFloat(value.x); WriteFloat(value.x);
WriteFloat(value.y); WriteFloat(value.y);
WriteFloat(value.z); WriteFloat(value.z);
} }
public UnityEngine.Vector3 ReadVector3() public Vector3 ReadVector3()
{ {
float x = ReadFloat(); float x = ReadFloat();
float y = ReadFloat(); float y = ReadFloat();
float z = ReadFloat(); float z = ReadFloat();
return new UnityEngine.Vector3(x, y, z); return new Vector3(x, y, z);
} }
public void WriteQuaternion(UnityEngine.Quaternion value) public void WriteQuaternion(Quaternion value)
{ {
WriteVector3(value.eulerAngles); WriteVector3(value.eulerAngles);
} }
public UnityEngine.Quaternion ReadQuaternion() public Quaternion ReadQuaternion()
{ {
UnityEngine.Vector3 eulerAngles = ReadVector3(); Vector3 eulerAngles = ReadVector3();
return UnityEngine.Quaternion.Euler(eulerAngles); return Quaternion.Euler(eulerAngles);
} }
public void WriteSimpleTransform(SimpleSyncTransform value) public void WriteSimpleTransform(SimpleSyncTransform value)
@@ -204,9 +211,9 @@ namespace BoneSync.Data
public SimpleSyncTransform ReadSimpleTransform() public SimpleSyncTransform ReadSimpleTransform()
{ {
UnityEngine.Vector3 position = ReadVector3(); Vector3 position = ReadVector3();
UnityEngine.Quaternion rotation = ReadQuaternion(); Quaternion rotation = ReadQuaternion();
UnityEngine.Vector3 scale = ReadVector3(); Vector3 scale = ReadVector3();
return new SimpleSyncTransform() return new SimpleSyncTransform()
{ {
position = position, position = position,
@@ -215,7 +222,7 @@ namespace BoneSync.Data
}; };
} }
public void WriteMatrix4x4(UnityEngine.Matrix4x4 matrix) public void WriteMatrix4x4(Matrix4x4 matrix)
{ {
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
{ {
@@ -223,9 +230,9 @@ namespace BoneSync.Data
} }
} }
public UnityEngine.Matrix4x4 ReadMatrix4x4() public Matrix4x4 ReadMatrix4x4()
{ {
UnityEngine.Matrix4x4 matrix = new UnityEngine.Matrix4x4(); Matrix4x4 matrix = new Matrix4x4();
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
{ {
matrix[i] = ReadFloat(); matrix[i] = ReadFloat();
@@ -307,12 +314,14 @@ namespace BoneSync.Data
public void WriteCompressedFloat(float value) public void WriteCompressedFloat(float value)
{ {
// write a float in the range of 0-1 with 2 decimal places // write a float in the range of 0-1 with 2 decimal places
WriteByte((byte)(value * 100)); value = Mathf.Clamp01(value);
int rounded = Mathf.FloorToInt(value * 255f);
WriteByte((byte)rounded);
} }
public float ReadCompressedFloat() public float ReadCompressedFloat()
{ {
return ReadByte() / 100f; return ReadByte() / 255f;
} }
public void WriteFingerCurl(SimpleFingerCurl fingerCurl) public void WriteFingerCurl(SimpleFingerCurl fingerCurl)

View File

@@ -10,12 +10,14 @@ using StressLevelZero.Rig;
using StressLevelZero.VRMK; using StressLevelZero.VRMK;
using UnhollowerBaseLib; using UnhollowerBaseLib;
using UnityEngine; using UnityEngine;
using StressLevelZero.Player;
namespace BoneSync.Data namespace BoneSync.Data
{ {
// copied from Entanglement mod // copied from Entanglement mod
public static class PlayerScripts public static class PlayerScripts
{ {
public static GameObject localPlayerGameObject;
public static RigManager playerRig; public static RigManager playerRig;
public static PhysBody playerPhysBody; public static PhysBody playerPhysBody;
public static Player_Health playerHealth; public static Player_Health playerHealth;
@@ -28,13 +30,15 @@ namespace BoneSync.Data
public static void GetPlayerScripts() public static void GetPlayerScripts()
{ {
GameObject localPlayerRig = GameObject.Find("[RigManager (Default Brett)]/[SkeletonRig (GameWorld Brett)]"); if (playerRig != null)
playerRig = localPlayerRig.GetComponentInChildren<RigManager>(); return;
localPlayerGameObject = GameObject.Find("[RigManager (Default Brett)]");
playerRig = localPlayerGameObject.GetComponentInChildren<RigManager>();
playerHealth = playerRig.playerHealth; playerHealth = playerRig.playerHealth;
reloadLevelOnDeath = playerHealth.reloadLevelOnDeath; reloadLevelOnDeath = playerHealth.reloadLevelOnDeath;
playerHealth.reloadLevelOnDeath = !BoneSync.lobby.IsConnected(); playerHealth.reloadLevelOnDeath = !BoneSync.IsConnected;
try try
{ {
@@ -54,6 +58,7 @@ namespace BoneSync.Data
public static void GetHandPoses() public static void GetHandPoses()
{ {
GetPlayerScripts();
// Checks if we already got the hand poses to prevent crashes // Checks if we already got the hand poses to prevent crashes
if (playerHandPoses == null) if (playerHandPoses == null)
CharacterAnimationManager.FetchHandPoseList(out playerHandPoses); // Lets hope this is constant! CharacterAnimationManager.FetchHandPoseList(out playerHandPoses); // Lets hope this is constant!

View File

@@ -24,6 +24,12 @@ namespace BoneSync
public class BoneSync : MelonMod public class BoneSync : MelonMod
{ {
public static bool IsConnected
{
get; private set;
}
public static LobbyManager lobby; public static LobbyManager lobby;
public static TransportBase transport; public static TransportBase transport;
public override void OnApplicationStart() public override void OnApplicationStart()
@@ -70,8 +76,8 @@ namespace BoneSync
public override void OnUpdate() public override void OnUpdate()
{ {
PlayerRig.LocalSyncTick();
bool processPackets = transport.Tick(); transport.Tick();
//PlayerRig.Tick(); //PlayerRig.Tick();
@@ -85,12 +91,6 @@ namespace BoneSync
lobby.CreateLobby(); lobby.CreateLobby();
} }
if (Input.GetKeyDown(KeyCode.L))
{
MelonLogger.Msg("Reloading bundle");
PlayerRig.LoadBundle();
}
if (Input.GetKeyDown(KeyCode.N)) if (Input.GetKeyDown(KeyCode.N))
{ {
MelonLogger.Msg("Creating debug player rig"); MelonLogger.Msg("Creating debug player rig");
@@ -111,6 +111,8 @@ namespace BoneSync
public override void OnFixedUpdate() public override void OnFixedUpdate()
{ {
IsConnected = lobby.IsConnected();
transport.Tick();
PlayerRig.Tick(); PlayerRig.Tick();
} }

View File

@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BoneSync.Sync;
using BoneSync.Sync.Components;
using PuppetMasta;
using StressLevelZero.AI;
namespace BoneSync.Networking.Messages
{
public struct AIBehaviourHealth
{
public float cur_hp;
public float cur_arm_lf;
public float cur_arm_rt;
public float cur_leg_lf;
public float cur_leg_rt;
public AIBehaviourHealth(SubBehaviourHealth behaviourHealth)
{
cur_hp = behaviourHealth.cur_hp;
cur_arm_lf = behaviourHealth.cur_arm_lf;
cur_arm_rt = behaviourHealth.cur_arm_rt;
cur_leg_lf = behaviourHealth.cur_leg_lf;
cur_leg_rt = behaviourHealth.cur_leg_rt;
}
}
public struct AISyncInfo
{
public ushort syncId;
public AIBehaviourHealth health;
public PuppetMaster.State puppetState;
public PuppetMaster.Mode puppetMode;
public BehaviourBaseNav.MentalState mentalState;
public AISyncInfo(ushort syncid, AIBrain aiBrain)
{
this.syncId = syncid;
this.health = new AIBehaviourHealth(aiBrain.behaviour.health);
this.puppetState = aiBrain.puppetMaster.activeState;
this.puppetMode = aiBrain.puppetMaster.activeMode;
this.mentalState = aiBrain.behaviour.mentalState;
}
}
[PacketType(PacketType.AISync), PacketReliability(PacketReliability.Unreliable)]
public class AISyncMessage : NetworkMessage
{
private AISyncInfo _aiSyncInfo;
public AISyncInfo aiSyncInfo => _aiSyncInfo;
public AISyncMessage(AISyncInfo aiSyncInfo)
{
_aiSyncInfo = aiSyncInfo;
byteEncoder.WriteUShort(_aiSyncInfo.syncId);
byteEncoder.WriteCompressedFloat(_aiSyncInfo.health.cur_hp);
byteEncoder.WriteCompressedFloat(_aiSyncInfo.health.cur_arm_lf);
byteEncoder.WriteCompressedFloat(_aiSyncInfo.health.cur_arm_rt);
byteEncoder.WriteCompressedFloat(_aiSyncInfo.health.cur_leg_lf);
byteEncoder.WriteCompressedFloat(_aiSyncInfo.health.cur_leg_rt);
byteEncoder.WriteByte((byte)_aiSyncInfo.puppetState);
byteEncoder.WriteByte((byte)_aiSyncInfo.puppetMode);
byteEncoder.WriteByte((byte)_aiSyncInfo.mentalState);
}
public AISyncMessage(Packet packet)
{
byteEncoder.WriteBytes(packet.Data);
_aiSyncInfo = new AISyncInfo();
_aiSyncInfo.syncId = byteEncoder.ReadUShort();
_aiSyncInfo.health.cur_hp = byteEncoder.ReadCompressedFloat();
_aiSyncInfo.health.cur_arm_lf = byteEncoder.ReadCompressedFloat();
_aiSyncInfo.health.cur_arm_rt = byteEncoder.ReadCompressedFloat();
_aiSyncInfo.health.cur_leg_lf = byteEncoder.ReadCompressedFloat();
_aiSyncInfo.health.cur_leg_rt = byteEncoder.ReadCompressedFloat();
_aiSyncInfo.puppetState = (PuppetMaster.State)byteEncoder.ReadByte();
_aiSyncInfo.puppetMode = (PuppetMaster.Mode)byteEncoder.ReadByte();
_aiSyncInfo.mentalState = (BehaviourBaseNav.MentalState)byteEncoder.ReadByte();
}
public override void Execute()
{
Syncable syncable = ObjectSyncCache.GetSyncable(_aiSyncInfo.syncId);
if (syncable == null) return;
syncable.OnAISyncData(_aiSyncInfo);
}
}
}

View File

@@ -56,12 +56,12 @@ namespace BoneSync.Networking.Messages
byteEncoder.WriteSimpleTransform(_playerSyncInfo.headPos); byteEncoder.WriteSimpleTransform(_playerSyncInfo.headPos);
byteEncoder.WriteSimpleTransform(_playerSyncInfo.leftHandPos); byteEncoder.WriteSimpleTransform(_playerSyncInfo.leftHandPos);
byteEncoder.WriteSimpleTransform(_playerSyncInfo.rightHandPos); byteEncoder.WriteSimpleTransform(_playerSyncInfo.rightHandPos);
byteEncoder.WriteFingerCurl(_playerSyncInfo.leftHandFingerCurl);
byteEncoder.WriteFingerCurl(_playerSyncInfo.rightHandFingerCurl);
byteEncoder.WriteByte(_playerSyncInfo.poseIndexRight); byteEncoder.WriteByte(_playerSyncInfo.poseIndexRight);
byteEncoder.WriteByte(_playerSyncInfo.poseIndexLeft); byteEncoder.WriteByte(_playerSyncInfo.poseIndexLeft);
byteEncoder.WriteFloat(_playerSyncInfo.poseRadiusRight); byteEncoder.WriteCompressedFloat(_playerSyncInfo.poseRadiusRight);
byteEncoder.WriteFloat(_playerSyncInfo.poseRadiusLeft); byteEncoder.WriteCompressedFloat(_playerSyncInfo.poseRadiusLeft);
byteEncoder.WriteFingerCurl(_playerSyncInfo.leftHandFingerCurl);
byteEncoder.WriteFingerCurl(_playerSyncInfo.rightHandFingerCurl);
} }
public PlayerSyncMessage(Packet packet) public PlayerSyncMessage(Packet packet)
@@ -71,12 +71,12 @@ namespace BoneSync.Networking.Messages
_playerSyncInfo.headPos = byteEncoder.ReadSimpleTransform(); _playerSyncInfo.headPos = byteEncoder.ReadSimpleTransform();
_playerSyncInfo.leftHandPos = byteEncoder.ReadSimpleTransform(); _playerSyncInfo.leftHandPos = byteEncoder.ReadSimpleTransform();
_playerSyncInfo.rightHandPos = byteEncoder.ReadSimpleTransform(); _playerSyncInfo.rightHandPos = byteEncoder.ReadSimpleTransform();
_playerSyncInfo.leftHandFingerCurl = byteEncoder.ReadFingerCurl();
_playerSyncInfo.rightHandFingerCurl = byteEncoder.ReadFingerCurl();
_playerSyncInfo.poseIndexRight = byteEncoder.ReadByte(); _playerSyncInfo.poseIndexRight = byteEncoder.ReadByte();
_playerSyncInfo.poseIndexLeft = byteEncoder.ReadByte(); _playerSyncInfo.poseIndexLeft = byteEncoder.ReadByte();
_playerSyncInfo.poseRadiusRight = byteEncoder.ReadFloat(); _playerSyncInfo.poseRadiusRight = byteEncoder.ReadCompressedFloat();
_playerSyncInfo.poseRadiusLeft = byteEncoder.ReadFloat(); _playerSyncInfo.poseRadiusLeft = byteEncoder.ReadCompressedFloat();
_playerSyncInfo.leftHandFingerCurl = byteEncoder.ReadFingerCurl();
_playerSyncInfo.rightHandFingerCurl = byteEncoder.ReadFingerCurl();
} }
public override void Execute() public override void Execute()

View File

@@ -145,7 +145,7 @@ namespace BoneSync.Networking
} }
public void Send(ulong receiverId) public void Send(ulong receiverId)
{ {
if (BoneSync.lobby.IsConnected() == false) if (BoneSync.IsConnected == false)
{ {
MelonLogger.Warning("Cannot send packet, not connected to lobby"); MelonLogger.Warning("Cannot send packet, not connected to lobby");
return; return;

View File

@@ -20,5 +20,6 @@ namespace BoneSync.Networking
GunSync = 9, GunSync = 9,
SimpleObjectEventSync = 10, SimpleObjectEventSync = 10,
PlugSync = 11, PlugSync = 11,
AISync = 12,
} }
} }

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HarmonyLib;
using PuppetMasta;
namespace BoneSync.Patching
{
/*
[HarmonyPatch(typeof(SubBehaviourHealth))]
internal class AIHealthPatches
{
[HarmonyPatch(nameof(SubBehaviourHealth.TakeDamage)), HarmonyPostfix]
private static void DamagePrefix(SubBehaviourHealth __instance)
{
}
}*/
}

View File

@@ -27,7 +27,7 @@ namespace BoneSync.Patching
public static void OnFirePatch(Gun __instance) public static void OnFirePatch(Gun __instance)
{ {
MelonLoader.MelonLogger.Msg("Gun.OnFire: " + __instance.name); MelonLoader.MelonLogger.Msg("Gun.OnFire: " + __instance.name);
if (!BoneSync.lobby.IsConnected()) return; if (!BoneSync.IsConnected) return;
Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance.gameObject); Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance.gameObject);
if (syncable == null) return; if (syncable == null) return;

View File

@@ -24,6 +24,7 @@ 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 (!BoneSync.IsConnected) return true;
if (damage < 0.05f) return true; // ignore small damage (e.g. a little bit of fall damage) 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);
@@ -46,7 +47,7 @@ namespace BoneSync.Patching
[HarmonyPrefix] [HarmonyPrefix]
private static bool LootTablePatch(ObjectDestructable __instance, ref LootTableData __result) private static bool LootTablePatch(ObjectDestructable __instance, ref LootTableData __result)
{ {
if (!BoneSync.lobby.IsConnected()) return true; if (!BoneSync.IsConnected) return true;
Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance.gameObject); Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance.gameObject);
if (syncable != null && !BoneSync.lobby.IsHost) if (syncable != null && !BoneSync.lobby.IsHost)
{ {
@@ -65,6 +66,7 @@ namespace BoneSync.Patching
private static bool TakeDamagePatch(Prop_Health __instance, ref float damage, ref bool crit, ref AttackType attackType) private static bool TakeDamagePatch(Prop_Health __instance, ref float damage, ref bool crit, ref AttackType attackType)
{ {
if (CallPatchedMethods.allowPatchedMethodCall) return true; if (CallPatchedMethods.allowPatchedMethodCall) return true;
if (!BoneSync.IsConnected) return true;
MelonLoader.MelonLogger.Msg("Prop_Health.TAKEDAMAGE: " + damage); MelonLoader.MelonLogger.Msg("Prop_Health.TAKEDAMAGE: " + damage);
Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance.gameObject); Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance.gameObject);
if (syncable != null) if (syncable != null)

View File

@@ -92,7 +92,7 @@ namespace BoneSync.Patching
if (__instance.Prefab == null) return; if (__instance.Prefab == null) return;
if (CallPatchedMethods.allowPatchedMethodCall) return; if (CallPatchedMethods.allowPatchedMethodCall) return;
if (PoolBlacklist.isBlacklistedPool(__instance)) return; if (PoolBlacklist.isBlacklistedPool(__instance)) return;
if (BoneSync.lobby.IsConnected()) if (BoneSync.IsConnected)
{ {
MelonLogger.Msg("Patched Spawning object in pool: " + __instance.name); MelonLogger.Msg("Patched Spawning object in pool: " + __instance.name);
bool isHost = BoneSync.lobby.IsHost; bool isHost = BoneSync.lobby.IsHost;
@@ -108,7 +108,7 @@ namespace BoneSync.Patching
if (__instance.Prefab == null) return true; if (__instance.Prefab == null) return true;
if (CallPatchedMethods.allowPatchedMethodCall) return true; if (CallPatchedMethods.allowPatchedMethodCall) return true;
if (PoolBlacklist.isBlacklistedPool(__instance)) return true; if (PoolBlacklist.isBlacklistedPool(__instance)) return true;
if (BoneSync.lobby.IsConnected()) if (BoneSync.IsConnected)
{ {
MelonLogger.Msg("Patched Spawning object in pool: " + __instance.name); MelonLogger.Msg("Patched Spawning object in pool: " + __instance.name);
return BoneSync.lobby.IsHost; // only allow host to spawn objects naturally return BoneSync.lobby.IsHost; // only allow host to spawn objects naturally
@@ -126,7 +126,7 @@ namespace BoneSync.Patching
public static void OnSpawnPatchPost(Poolee __instance) public static void OnSpawnPatchPost(Poolee __instance)
{ {
if (CallPatchedMethods.allowPatchedMethodCall) return; if (CallPatchedMethods.allowPatchedMethodCall) return;
if (!BoneSync.lobby.IsConnected()) return; if (!BoneSync.IsConnected) return;
MelonLogger.Msg("Poolee.OnSpawn: " + __instance.gameObject.transform.GetPath()); MelonLogger.Msg("Poolee.OnSpawn: " + __instance.gameObject.transform.GetPath());
@@ -149,7 +149,7 @@ namespace BoneSync.Patching
public static void OnDespawnPatchPost(Poolee __instance) public static void OnDespawnPatchPost(Poolee __instance)
{ {
if (CallPatchedMethods.allowPatchedMethodCall) return; if (CallPatchedMethods.allowPatchedMethodCall) return;
if (!BoneSync.lobby.IsConnected()) return; if (!BoneSync.IsConnected) return;
MelonLogger.Msg("Poolee.OnDespawn: " + __instance.gameObject.transform.GetPath()); MelonLogger.Msg("Poolee.OnDespawn: " + __instance.gameObject.transform.GetPath());

View File

@@ -21,13 +21,43 @@ namespace BoneSync.Patching
public static byte poseIndexLeft = 0; public static byte poseIndexLeft = 0;
public static float radiusLeft = 0.0f; public static float radiusLeft = 0.0f;
[HarmonyPatch(nameof(SkeletonHand.SetHandPose)), HarmonyPostfix] private static Dictionary<string, byte> handPoses = new Dictionary<string, byte>();
private static byte GetHandPoseIndex(string handPoseName)
{
if (handPoses.ContainsKey(handPoseName))
return handPoses[handPoseName];
if (PlayerScripts.playerHandPoses == null)
{
MelonLogger.Error("PlayerScripts.playerHandPoses is null!");
return 0;
}
if (PlayerScripts.playerHandPoses.Count == 0)
{
MelonLogger.Msg("PlayerScripts.playerHandPoses is empty, getting hand poses...");
PlayerScripts.GetHandPoses();
}
bool found = PlayerScripts.playerHandPoses.Contains(handPoseName);
if (!found)
{
//MelonLogger.Error($"Hand pose {handPoseName} not found in playerHandPoses!");
return 0;
}
byte index = (byte)PlayerScripts.playerHandPoses.IndexOf(handPoseName);
handPoses.Add(handPoseName, index);
return index;
}
[HarmonyPatch(nameof(SkeletonHand.SetHandPose)), HarmonyPrefix]
private static void SetHandPosePostfix(SkeletonHand __instance, string handPoseName) private static void SetHandPosePostfix(SkeletonHand __instance, string handPoseName)
{ {
if (!__instance.GetCharacterAnimationManager()) return; if (!__instance.GetCharacterAnimationManager()) return;
MelonLogger.Msg($"SetHandPosePostfix: {handPoseName}"); MelonLogger.Msg($"SetHandPosePostfix: {handPoseName}");
int poseIndex = PlayerScripts.playerHandPoses.IndexOf(handPoseName); int poseIndex = GetHandPoseIndex(handPoseName);
switch (__instance.handedness) switch (__instance.handedness)
{ {
case Handedness.LEFT: case Handedness.LEFT:
@@ -40,18 +70,23 @@ namespace BoneSync.Patching
} }
[HarmonyPatch(nameof(SkeletonHand.SetCylinderRadius)), HarmonyPostfix] [HarmonyPatch(nameof(SkeletonHand.SetCylinderRadius)), HarmonyPrefix]
private static void SetCylinderRadiusPrefix(SkeletonHand __instance, float radius) private static void SetCylinderRadiusPrefix(SkeletonHand __instance, float radius)
{ {
if (!__instance.GetCharacterAnimationManager()) return; if (!__instance.GetCharacterAnimationManager()) return;
MelonLogger.Msg($"SetCylinderRadiusPrefix: {radius}");
//MelonLogger.Msg($"SetCylinderRadiusPrefix: {radius}");
switch (__instance.handedness) switch (__instance.handedness)
{ {
case Handedness.LEFT: case Handedness.LEFT:
if (radiusLeft == radius) return;
MelonLogger.Msg($"SetCylinderRadiusPrefixLeft: {radius}");
radiusLeft = radius; radiusLeft = radius;
break; break;
case Handedness.RIGHT: case Handedness.RIGHT:
if (radiusRight == radius) return;
MelonLogger.Msg($"SetCylinderRadiusPrefixRight: {radius}");
radiusRight = radius; radiusRight = radius;
break; break;
} }

View File

@@ -18,7 +18,7 @@ namespace BoneSync.Patching
[HarmonyPatch(nameof(ZoneSpawner.Spawn)), HarmonyPrefix] [HarmonyPatch(nameof(ZoneSpawner.Spawn)), HarmonyPrefix]
public static bool ZoneSpawnPrefix(ZoneSpawner __instance) public static bool ZoneSpawnPrefix(ZoneSpawner __instance)
{ {
if (!BoneSync.lobby.IsConnected()) return true; // do not block if not connected if (!BoneSync.IsConnected) return true; // do not block if not connected
MelonLogger.Msg("ZoneSpawner.Spawn: " + __instance.transform.GetPath()); MelonLogger.Msg("ZoneSpawner.Spawn: " + __instance.transform.GetPath());
@@ -38,7 +38,7 @@ namespace BoneSync.Patching
[HarmonyPatch(nameof(ZoneEncounter.StartEncounter)), HarmonyPrefix] [HarmonyPatch(nameof(ZoneEncounter.StartEncounter)), HarmonyPrefix]
public static bool ZoneEncounterSpawnPrefix(ZoneEncounter __instance) public static bool ZoneEncounterSpawnPrefix(ZoneEncounter __instance)
{ {
if (!BoneSync.lobby.IsConnected()) return true; if (!BoneSync.IsConnected) return true;
MelonLogger.Msg("ZoneEncounter.StartEncounter: " + __instance.transform.GetPath()); MelonLogger.Msg("ZoneEncounter.StartEncounter: " + __instance.transform.GetPath());

View File

@@ -17,13 +17,15 @@ using BoneSync.Data;
using StressLevelZero.Interaction; using StressLevelZero.Interaction;
using UnhollowerBaseLib; using UnhollowerBaseLib;
using BoneSync.Patching; using BoneSync.Patching;
using BoneSync.Sync.Components;
using Oculus.Platform.Models;
namespace BoneSync.Player namespace BoneSync.Player
{ {
internal class PlayerRig internal class PlayerRig
{ {
private const float RIG_SYNC_FPS = 30; private const float RIG_SYNC_FPS = Syncable.SYNC_FPS;
public static AssetBundle rigBundle; public static AssetBundle rigBundle;
private static float _lastLocalSyncTime = 0; private static float _lastLocalSyncTime = 0;
@@ -57,15 +59,18 @@ namespace BoneSync.Player
{ {
playerRig.UpdateIK(); playerRig.UpdateIK();
} }
if (Time.time - _lastLocalSyncTime > 1 / RIG_SYNC_FPS)
{
SendLocalPlayerSync();
_lastLocalSyncTime = Time.time;
}
} }
public static void LocalSyncTick()
{
if (Time.realtimeSinceStartup - _lastLocalSyncTime > 1 / RIG_SYNC_FPS)
{
SendLocalPlayerSync();
_lastLocalSyncTime = Time.realtimeSinceStartup;
}
}
private void SetFingerCurl(Handedness handedness, SimpleFingerCurl fingerCurl) private void SetFingerCurl(Handedness handedness, SimpleFingerCurl fingerCurl)
{ {
characterAnimationManager.ApplyFingerCurl(handedness, 1f - fingerCurl.thumb, 1f - fingerCurl.index, 1f - fingerCurl.middle, 1f - fingerCurl.ring, 1f - fingerCurl.pinky); characterAnimationManager.ApplyFingerCurl(handedness, 1f - fingerCurl.thumb, 1f - fingerCurl.index, 1f - fingerCurl.middle, 1f - fingerCurl.ring, 1f - fingerCurl.pinky);
@@ -82,6 +87,12 @@ namespace BoneSync.Player
SetFingerCurl(Handedness.LEFT, playerSyncInfo.leftHandFingerCurl); SetFingerCurl(Handedness.LEFT, playerSyncInfo.leftHandFingerCurl);
SetFingerCurl(Handedness.RIGHT, playerSyncInfo.rightHandFingerCurl); SetFingerCurl(Handedness.RIGHT, playerSyncInfo.rightHandFingerCurl);
UpdatePose(Handedness.LEFT, playerSyncInfo.poseIndexLeft);
UpdatePose(Handedness.RIGHT, playerSyncInfo.poseIndexRight);
UpdatePoseRadius(Handedness.LEFT, playerSyncInfo.poseRadiusLeft);
UpdatePoseRadius(Handedness.RIGHT, playerSyncInfo.poseRadiusRight);
} }
public void UpdatePose(Handedness hand, int index) public void UpdatePose(Handedness hand, int index)
@@ -97,21 +108,34 @@ namespace BoneSync.Player
public void UpdatePoseRadius(Handedness hand, float radius) => characterAnimationManager?.SetCylinderRadius(hand, radius); public void UpdatePoseRadius(Handedness hand, float radius) => characterAnimationManager?.SetCylinderRadius(hand, radius);
private static GameObject localPlayerRig;
private static Transform localRigRoot;
private static Transform localRigHeadTransform;
private static Transform localRigLeftHandTransform;
private static Transform localRigRightHandTransform;
public static void SetLocalRigReferences()
{
if (localPlayerRig != null) return;
localPlayerRig = GameObject.Find("[RigManager (Default Brett)]/[SkeletonRig (GameWorld Brett)]");
localRigRoot = localPlayerRig.transform;
localRigHeadTransform = localRigRoot.Find("Head");
localRigLeftHandTransform = localRigRoot.Find("Hand (left)");
localRigRightHandTransform = localRigRoot.Find("Hand (right)");
}
public static PlayerSyncInfo? GetLocalSyncInfo() public static PlayerSyncInfo? GetLocalSyncInfo()
{ {
GameObject localPlayerRig = GameObject.Find("[RigManager (Default Brett)]/[SkeletonRig (GameWorld Brett)]"); SetLocalRigReferences();
if (localPlayerRig == null) if (localPlayerRig == null)
{ {
MelonLogger.Msg("Local player rig not found"); MelonLogger.Msg("Local player rig not found");
return null; return null;
} }
Transform root = localPlayerRig.transform;
Transform localHeadTransform = root.Find("Head"); if (localRigHeadTransform == null || localRigLeftHandTransform == null || localRigRightHandTransform == null)
Transform localLeftHandTransform = root.Find("Hand (left)");
Transform localRightHandTransform = root.Find("Hand (right)");
if (localHeadTransform == null || localLeftHandTransform == null || localRightHandTransform == null)
{ {
MelonLogger.Msg("Local player rig components not found"); MelonLogger.Msg("Local player rig components not found");
return null; return null;
@@ -119,10 +143,10 @@ namespace BoneSync.Player
PlayerSyncInfo playerSyncInfo = new PlayerSyncInfo() PlayerSyncInfo playerSyncInfo = new PlayerSyncInfo()
{ {
rootPos = root.position, rootPos = localRigRoot.position,
headPos = new SimpleSyncTransform(localHeadTransform), headPos = new SimpleSyncTransform(localRigHeadTransform),
leftHandPos = new SimpleSyncTransform(localLeftHandTransform), leftHandPos = new SimpleSyncTransform(localRigLeftHandTransform),
rightHandPos = new SimpleSyncTransform(localRightHandTransform), rightHandPos = new SimpleSyncTransform(localRigRightHandTransform),
//leftHandFingerCurl = new SimpleFingerCurl(PlayerScripts.playerLeftHand.fingerCurl), //leftHandFingerCurl = new SimpleFingerCurl(PlayerScripts.playerLeftHand.fingerCurl),
//rightHandFingerCurl = new SimpleFingerCurl(PlayerScripts.playerRightHand.fingerCurl) //rightHandFingerCurl = new SimpleFingerCurl(PlayerScripts.playerRightHand.fingerCurl)
poseIndexLeft = SkeletonHandPatches.poseIndexLeft, poseIndexLeft = SkeletonHandPatches.poseIndexLeft,
@@ -142,7 +166,7 @@ namespace BoneSync.Player
private static void SendLocalPlayerSync() private static void SendLocalPlayerSync()
{ {
if (!BoneSync.lobby.IsConnected()) return; if (!BoneSync.IsConnected) return;
//MelonLogger.Msg("Sending local player sync"); //MelonLogger.Msg("Sending local player sync");
PlayerSyncInfo? playerSyncInfo = GetLocalSyncInfo(); PlayerSyncInfo? playerSyncInfo = GetLocalSyncInfo();
if (!playerSyncInfo.HasValue) return; if (!playerSyncInfo.HasValue) return;

View File

@@ -3,13 +3,62 @@ 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 BoneSync.Networking.Messages;
using UnityEngine; using UnityEngine;
namespace BoneSync.Sync.Components namespace BoneSync.Sync.Components
{ {
public partial class Syncable : MonoBehaviour public partial class Syncable : MonoBehaviour
{ {
private AISyncInfo _aiSyncInfo;
private float _lastAISyncTime;
private const float AI_SYNC_FPS = 5f;
private void TrySendAISync()
{
if (!isOwner) return;
if (!aiBrain) return;
if (Time.realtimeSinceStartup - _lastAISyncTime > 1 / AI_SYNC_FPS)
{
_SendAIStateSync();
}
}
private void _SendAIStateSync()
{
if (!aiBrain) return;
_lastAISyncTime = Time.realtimeSinceStartup;
AISyncInfo aiSyncInfo = new AISyncInfo(_syncId, aiBrain);
AISyncMessage message = new AISyncMessage(aiSyncInfo);
message.Broadcast();
}
private void _ApplyAISyncInfo(AISyncInfo aiSyncInfo)
{
if (!aiBrain) return;
aiBrain.behaviour.health.cur_hp = aiSyncInfo.health.cur_hp;
aiBrain.behaviour.health.cur_arm_lf = aiSyncInfo.health.cur_arm_lf;
aiBrain.behaviour.health.cur_arm_rt = aiSyncInfo.health.cur_arm_rt;
aiBrain.behaviour.health.cur_leg_lf = aiSyncInfo.health.cur_leg_lf;
aiBrain.behaviour.health.cur_leg_rt = aiSyncInfo.health.cur_leg_rt;
if (aiSyncInfo.health.cur_hp <= 0 && !aiBrain.puppetMaster.isDead)
{
aiBrain.puppetMaster.Kill();
}
else if (aiSyncInfo.health.cur_hp > 0 && aiBrain.puppetMaster.isDead)
{
aiBrain.puppetMaster.Resurrect();
}
aiBrain.puppetMaster.activeState = aiSyncInfo.puppetState;
aiBrain.puppetMaster.activeMode = aiSyncInfo.puppetMode;
aiBrain.behaviour.mentalState = aiSyncInfo.mentalState;
}
public void OnAISyncData(AISyncInfo aiSyncInfo)
{
_aiSyncInfo = aiSyncInfo;
_ApplyAISyncInfo(_aiSyncInfo);
}
} }
} }

View File

@@ -79,7 +79,7 @@ namespace BoneSync.Sync.Components
private bool _attemptedRegister; private bool _attemptedRegister;
public bool Registered => _syncId != 0; public bool Registered => _syncId != 0;
public bool isStale => Time.time - _lastSyncTime > 5f; public bool isStale => Time.realtimeSinceStartup - _lastSyncTime > 5f;
public bool isOwner => _ownerId == BoneSync.lobby.GetLocalId(); public bool isOwner => _ownerId == BoneSync.lobby.GetLocalId();
public void SetInHolster(bool val) public void SetInHolster(bool val)
@@ -119,7 +119,6 @@ namespace BoneSync.Sync.Components
private Socket[] sockets; private Socket[] sockets;
private AIBrain aiBrain; private AIBrain aiBrain;
private PuppetMaster puppetMaster;
private PullDevice pullDevice; private PullDevice pullDevice;
private ButtonToggle[] buttonToggles; private ButtonToggle[] buttonToggles;
@@ -167,6 +166,7 @@ namespace BoneSync.Sync.Components
public string GetSyncableWorldPath() public string GetSyncableWorldPath()
{ {
if (transform == null) return "";
if (poolee && poolee.pool) if (poolee && poolee.pool)
{ {
return ""; return "";
@@ -195,7 +195,6 @@ namespace BoneSync.Sync.Components
sockets = GetComponentsInChildren<Socket>(); sockets = GetComponentsInChildren<Socket>();
aiBrain = GetComponent<AIBrain>(); aiBrain = GetComponent<AIBrain>();
buttonToggles = GetComponentsInChildren<ButtonToggle>(); buttonToggles = GetComponentsInChildren<ButtonToggle>();
puppetMaster = aiBrain?.puppetMaster;
if (sockets.Length == 0) if (sockets.Length == 0)
{ {
plugs = GetComponentsInChildren<AlignPlug>(); plugs = GetComponentsInChildren<AlignPlug>();
@@ -342,7 +341,7 @@ namespace BoneSync.Sync.Components
public void RegisterSyncable() public void RegisterSyncable()
{ {
if (!BoneSync.lobby.IsConnected()) return; if (!BoneSync.IsConnected) return;
FindAndUpdateComponents(); FindAndUpdateComponents();
if (Registered) if (Registered)
{ {

View File

@@ -23,7 +23,7 @@ namespace BoneSync.Sync.Components
originalLootTableData = objectDestructable.lootTable; originalLootTableData = objectDestructable.lootTable;
} }
if (!BoneSync.lobby.IsConnected() || BoneSync.lobby.IsHost) if (!BoneSync.IsConnected || BoneSync.lobby.IsHost)
{ {
objectDestructable.lootTable = originalLootTableData; objectDestructable.lootTable = originalLootTableData;
} }

View File

@@ -16,7 +16,7 @@ namespace BoneSync.Sync.Components
{ {
private void SendObjectSync() private void SendObjectSync()
{ {
_lastSyncTime = Time.time; _lastSyncTime = Time.realtimeSinceStartup;
ObjectSync.SendObjectSyncMessage(this); ObjectSync.SendObjectSyncMessage(this);
} }
public IEnumerator SyncCoroutineAsync() public IEnumerator SyncCoroutineAsync()