diff --git a/BoneSync/BoneSync.csproj b/BoneSync/BoneSync.csproj
index da32c39..671feac 100644
--- a/BoneSync/BoneSync.csproj
+++ b/BoneSync/BoneSync.csproj
@@ -75,6 +75,10 @@
False
..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\Managed\UnityEngine.AnimationModule.dll
+
+ False
+ A:\SteamLibrary\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\Managed\UnityEngine.AssetBundleModule.dll
+
..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\BONEWORKS\BONEWORKS\MelonLoader\Managed\UnityEngine.CoreModule.dll
@@ -105,6 +109,7 @@
+
@@ -280,7 +285,7 @@
-
+
diff --git a/BoneSync/Data/ByteEncoder.cs b/BoneSync/Data/ByteEncoder.cs
index 49a6874..e23f804 100644
--- a/BoneSync/Data/ByteEncoder.cs
+++ b/BoneSync/Data/ByteEncoder.cs
@@ -1,4 +1,5 @@
-using StressLevelZero;
+using BoneSync.Networking.Messages;
+using StressLevelZero;
using StressLevelZero.Combat;
using System;
using System.Collections.Generic;
@@ -302,5 +303,27 @@ namespace BoneSync.Data
return mag;
}
+
+ public void WriteFingerCurl(SimpleFingerCurl fingerCurl)
+ {
+ WriteFloat(fingerCurl.thumb);
+ WriteFloat(fingerCurl.index);
+ WriteFloat(fingerCurl.middle);
+ WriteFloat(fingerCurl.ring);
+ WriteFloat(fingerCurl.pinky);
+ }
+
+ public SimpleFingerCurl ReadFingerCurl()
+ {
+ SimpleFingerCurl fingerCurl = new SimpleFingerCurl()
+ {
+ thumb = ReadFloat(),
+ index = ReadFloat(),
+ middle = ReadFloat(),
+ ring = ReadFloat(),
+ pinky = ReadFloat()
+ };
+ return fingerCurl;
+ }
}
}
diff --git a/BoneSync/MelonLoaderMod.cs b/BoneSync/MelonLoaderMod.cs
index be252c0..27b088b 100644
--- a/BoneSync/MelonLoaderMod.cs
+++ b/BoneSync/MelonLoaderMod.cs
@@ -9,6 +9,7 @@ using BoneSync.Sync;
using Facepunch.Steamworks;
using System.Reflection.Emit;
using BoneSync.Data;
+using BoneSync.Networking.Messages;
namespace BoneSync
{
@@ -39,6 +40,8 @@ namespace BoneSync
SpawnableManager.Initialize();
+ PlayerRig.LoadBundle();
+
PatchAll();
}
@@ -57,6 +60,7 @@ namespace BoneSync
{
//MelonLogger.Msg("OnLevelWasInitialized: " + sceneName);
SceneSync.OnSceneInit(buildIndex);
+ PlayerScripts.GetPlayerScripts();
}
public override void OnSceneWasUnloaded(int buildIndex, string sceneName)
@@ -79,6 +83,24 @@ namespace BoneSync
{
lobby.CreateLobby();
}
+
+ if (Input.GetKeyDown(KeyCode.L))
+ {
+ MelonLogger.Msg("Reloading bundle");
+ PlayerRig.LoadBundle();
+ }
+
+ if (Input.GetKeyDown(KeyCode.N))
+ {
+ MelonLogger.Msg("Creting debug player rig");
+ PlayerRig debugRig = PlayerRig.GetPlayerRig(0);
+ PlayerSyncInfo? playerSyncInfo = PlayerRig.GetLocalSyncInfo();
+ if (!playerSyncInfo.HasValue)
+ {
+ MelonLogger.Msg("PlayerSyncInfo is null");
+ }
+ debugRig.UpdatePlayerSync(playerSyncInfo.Value);
+ }
}
public override void BONEWORKS_OnLoadingScreen()
@@ -88,7 +110,7 @@ namespace BoneSync
public override void OnFixedUpdate()
{
- //MelonLogger.Msg("OnFixedUpdate");
+ PlayerRig.Tick();
}
public override void OnLateUpdate()
diff --git a/BoneSync/Networking/LobbyManager/SteamLobbyManager.cs b/BoneSync/Networking/LobbyManager/SteamLobbyManager.cs
index afd656c..0bfeb12 100644
--- a/BoneSync/Networking/LobbyManager/SteamLobbyManager.cs
+++ b/BoneSync/Networking/LobbyManager/SteamLobbyManager.cs
@@ -1,4 +1,5 @@
-using BoneSync.Sync;
+using BoneSync.Player;
+using BoneSync.Sync;
using Facepunch.Steamworks;
using Facepunch.Steamworks.Data;
using MelonLoader;
diff --git a/BoneSync/Networking/Messages/GunSyncMessage.cs b/BoneSync/Networking/Messages/GunSyncMessage.cs
index 877873f..08989c1 100644
--- a/BoneSync/Networking/Messages/GunSyncMessage.cs
+++ b/BoneSync/Networking/Messages/GunSyncMessage.cs
@@ -38,6 +38,7 @@ namespace BoneSync.Networking.Messages
byteEncoder.WriteByte((byte)gunSyncInfo.messageType);
byteEncoder.WriteByte((byte)gunSyncInfo.hammerState);
byteEncoder.WriteByte((byte)gunSyncInfo.cartridgeState);
+
byteEncoder.WriteBool(gunSyncInfo.bulletObject != null);
byteEncoder.WriteAmmoVariables(gunSyncInfo.bulletObject.ammoVariables);
@@ -49,11 +50,9 @@ namespace BoneSync.Networking.Messages
gunSyncInfo.messageType = (GunSyncMessageType)byteEncoder.ReadByte();
gunSyncInfo.hammerState = (Gun.HammerStates)byteEncoder.ReadByte();
gunSyncInfo.cartridgeState = (Gun.CartridgeStates)byteEncoder.ReadByte();
+
if (byteEncoder.ReadBool()) { // If bulletObject is not null
- gunSyncInfo.bulletObject = new BulletObject()
- {
- ammoVariables = byteEncoder.ReadAmmoVariables()
- };
+ gunSyncInfo.bulletObject = new BulletObject() { ammoVariables = byteEncoder.ReadAmmoVariables() };
}
}
diff --git a/BoneSync/Networking/Messages/PlayerSyncMessage.cs b/BoneSync/Networking/Messages/PlayerSyncMessage.cs
index 975d484..c3a03b4 100644
--- a/BoneSync/Networking/Messages/PlayerSyncMessage.cs
+++ b/BoneSync/Networking/Messages/PlayerSyncMessage.cs
@@ -2,23 +2,43 @@
using BoneSync.Data;
using BoneSync.Sync;
+using StressLevelZero.Player;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using UnityEngine;
namespace BoneSync.Networking.Messages
{
-
+ public struct SimpleFingerCurl
+ {
+ public float thumb;
+ public float index;
+ public float middle;
+ public float ring;
+ public float pinky;
+ public SimpleFingerCurl(FingerCurl fingerCurl)
+ {
+ thumb = fingerCurl.thumb;
+ index = fingerCurl.index;
+ middle = fingerCurl.middle;
+ ring = fingerCurl.ring;
+ pinky = fingerCurl.pinky;
+ }
+ }
public struct PlayerSyncInfo
{
+ public Vector3 rootPos;
public SimpleSyncTransform headPos;
public SimpleSyncTransform leftHandPos;
public SimpleSyncTransform rightHandPos;
+ public SimpleFingerCurl leftHandFingerCurl;
+ public SimpleFingerCurl rightHandFingerCurl;
}
- [PacketType(PacketType.PlayerSync)]
+ [PacketType(PacketType.PlayerSync), PacketReliability(PacketReliability.Unreliable)]
internal class PlayerSyncMessage : NetworkMessage
{
private PlayerSyncInfo _playerSyncInfo;
@@ -27,17 +47,23 @@ namespace BoneSync.Networking.Messages
public PlayerSyncMessage(PlayerSyncInfo playerSyncInfo)
{
_playerSyncInfo = playerSyncInfo;
+ byteEncoder.WriteVector3(_playerSyncInfo.rootPos);
byteEncoder.WriteSimpleTransform(_playerSyncInfo.headPos);
byteEncoder.WriteSimpleTransform(_playerSyncInfo.leftHandPos);
byteEncoder.WriteSimpleTransform(_playerSyncInfo.rightHandPos);
+ byteEncoder.WriteFingerCurl(_playerSyncInfo.leftHandFingerCurl);
+ byteEncoder.WriteFingerCurl(_playerSyncInfo.rightHandFingerCurl);
}
public PlayerSyncMessage(Packet packet)
{
byteEncoder.WriteBytes(packet.Data);
+ _playerSyncInfo.rootPos = byteEncoder.ReadVector3();
_playerSyncInfo.headPos = byteEncoder.ReadSimpleTransform();
_playerSyncInfo.leftHandPos = byteEncoder.ReadSimpleTransform();
_playerSyncInfo.rightHandPos = byteEncoder.ReadSimpleTransform();
+ _playerSyncInfo.leftHandFingerCurl = byteEncoder.ReadFingerCurl();
+ _playerSyncInfo.rightHandFingerCurl = byteEncoder.ReadFingerCurl();
}
public override void Execute()
diff --git a/BoneSync/Networking/Messages/SimpleSyncableEventMessage.cs b/BoneSync/Networking/Messages/SimpleSyncableEventMessage.cs
index 93f6fbb..e199533 100644
--- a/BoneSync/Networking/Messages/SimpleSyncableEventMessage.cs
+++ b/BoneSync/Networking/Messages/SimpleSyncableEventMessage.cs
@@ -12,7 +12,9 @@ namespace BoneSync.Networking.Messages
{
None = 0,
OnDevicePull = 1,
- OnDeviceRelease = 2
+ OnDeviceRelease = 2,
+ OnButtonPress = 3,
+ OnButtonRelease = 4,
}
public struct SimpleSyncableEvent
{
diff --git a/BoneSync/Player/PlayerRig.cs b/BoneSync/Player/PlayerRig.cs
index fc430ab..51fc782 100644
--- a/BoneSync/Player/PlayerRig.cs
+++ b/BoneSync/Player/PlayerRig.cs
@@ -11,39 +11,269 @@ using StressLevelZero.Player;
using StressLevelZero.VRMK;
using BoneSync.Networking;
using BoneSync.Networking.Messages;
+using System.Reflection;
+using System.IO;
+using BoneSync.Data;
+using StressLevelZero.Interaction;
+using UnhollowerBaseLib;
namespace BoneSync.Player
{
+ public static class EmebeddedAssetBundle
+ {
+ // Credit to the "Entanglement" mod. The playerrep asset bundle is also by them.
+ public static AssetBundle LoadFromAssembly(string name)
+ {
+ Assembly assembly = Assembly.GetExecutingAssembly();
+ string[] manifestResources = assembly.GetManifestResourceNames();
+
+ if (manifestResources.Contains(name))
+ {
+ MelonLogger.Msg($"Loading embedded bundle data {name}...");
+
+ byte[] bytes;
+ using (Stream str = assembly.GetManifestResourceStream(name))
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ str.CopyTo(memoryStream);
+ bytes = memoryStream.ToArray();
+ }
+
+ MelonLogger.Msg($"Loading bundle from data {name}, please be patient...");
+ AssetBundle temp = AssetBundle.LoadFromMemory(bytes);
+ MelonLogger.Msg($"Done!");
+ return temp;
+ }
+
+ return null;
+ }
+ }
+
internal class PlayerRig
{
- //public const string RIGMANAGER_SCENE_NAME = "[RigManager (Default Brett)]";
+ private const float RIG_SYNC_FPS = 30;
- private static List _playerRigs = new List();
+ public static AssetBundle rigBundle;
+ private static float _lastLocalSyncTime = 0;
+ private static Dictionary _playerRigs = new Dictionary();
+
+ private ulong _ownerId;
private GameObject playerRig;
- private RigManager rigManager;
private SLZ_Body body;
private CharacterAnimationManager characterAnimationManager;
- private Animator repAnimator;
+ private Animator animator;
+ private Transform headTransform;
+ private Transform leftHandTransform;
+ private Transform rightHandTransform;
+
+ public static void LoadBundle()
+ {
+ rigBundle = EmebeddedAssetBundle.LoadFromAssembly("BoneSync.playerrep.eres");
+
+ if (rigBundle == null)
+ throw new NullReferenceException("playerRepBundle is null! Did you forget to compile the player bundle into the dll?");
+
+
+ MelonLogger.Msg("Loaded playerRepBundle success");
+ }
+
+ public static void Tick()
+ {
+ foreach (PlayerRig playerRig in _playerRigs.Values)
+ {
+ playerRig.UpdateIK();
+ }
+
+ if (Time.time - _lastLocalSyncTime > 1 / RIG_SYNC_FPS)
+ {
+ SendLocalPlayerSync();
+ _lastLocalSyncTime = Time.time;
+ }
+ }
+
+
+ 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);
+ }
public void UpdatePlayerSync(PlayerSyncInfo playerSyncInfo)
{
- //playerRig.transform.ApplySimpleTransform(playerSyncInfo.headPos);
+ playerRig.transform.position = playerSyncInfo.rootPos;
+
+ headTransform.ApplySimpleTransform(playerSyncInfo.headPos);
+ leftHandTransform.ApplySimpleTransform(playerSyncInfo.leftHandPos);
+ rightHandTransform.ApplySimpleTransform(playerSyncInfo.rightHandPos);
+
+ SetFingerCurl(Handedness.LEFT, playerSyncInfo.leftHandFingerCurl);
+ SetFingerCurl(Handedness.RIGHT, playerSyncInfo.rightHandFingerCurl);
}
- public PlayerRig()
+ public static PlayerSyncInfo? GetLocalSyncInfo()
{
+ GameObject localPlayerRig = GameObject.Find("[RigManager (Default Brett)]/[SkeletonRig (GameWorld Brett)]");
+ if (localPlayerRig == null)
+ {
+ MelonLogger.Msg("Local player rig not found");
+ return null;
+ }
+ Transform root = localPlayerRig.transform;
- _playerRigs.Add(this);
+ Transform localHeadTransform = root.Find("Head");
+ 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");
+ return null;
+ }
+
+ PlayerSyncInfo playerSyncInfo = new PlayerSyncInfo()
+ {
+ rootPos = root.position,
+ headPos = new SimpleSyncTransform(localHeadTransform),
+ leftHandPos = new SimpleSyncTransform(localLeftHandTransform),
+ rightHandPos = new SimpleSyncTransform(localRightHandTransform),
+ //leftHandFingerCurl = new SimpleFingerCurl(PlayerScripts.playerLeftHand.fingerCurl),
+ //rightHandFingerCurl = new SimpleFingerCurl(PlayerScripts.playerRightHand.fingerCurl)
+
+ };
+
+ return playerSyncInfo;
+ }
+
+ private static void SendLocalPlayerSync()
+ {
+ if (!BoneSync.lobby.IsConnected()) return;
+ PlayerSyncInfo? playerSyncInfo = GetLocalSyncInfo();
+ if (!playerSyncInfo.HasValue) return;
+ PlayerSyncMessage playerSyncMessage = new PlayerSyncMessage(playerSyncInfo.Value);
+ playerSyncMessage.Broadcast();
+ }
+
+ public static PlayerRig GetPlayerRig(ulong ownerId)
+ {
+ if (_playerRigs.ContainsKey(ownerId))
+ {
+ MelonLogger.Msg("PlayerRig already exists for " + ownerId);
+ return _playerRigs[ownerId];
+ }
+
+ if (rigBundle == null)
+ {
+ MelonLogger.Msg("playerRepBundle is null! Did you forget to load the bundle?");
+ return null;
+ }
+ PlayerRig rig = new PlayerRig(ownerId);
+ rig.EnsurePlayerRig();
+ return rig;
+ }
+
+ public static void DestroyRig(ulong ownerId)
+ {
+ if (_playerRigs.ContainsKey(ownerId))
+ {
+ _playerRigs[ownerId].Destroy();
+ }
+ }
+
+ private void EnsurePlayerRig() {
+ if (playerRig != null) return;
+
+ playerRig = GameObject.Instantiate(rigBundle.LoadAsset("PlayerRep"));
+ playerRig.name = "PlayerRep";
+
+ body = playerRig.GetComponentInChildren();
+ characterAnimationManager = playerRig.GetComponentInChildren();
+ animator = playerRig.GetComponentInChildren();
+
+ headTransform = playerRig.transform.Find("Head");
+ leftHandTransform = playerRig.transform.Find("Hand (left)");
+ rightHandTransform = playerRig.transform.Find("Hand (right)");
+
+ body.OnStart();
+
+ }
+
+ public void UpdateIK()
+ {
+ // Catch errors so other players arent broken
+ try
+ {
+ EnsurePlayerRig();
+ //Re-Apply playermodel if unloaded
+ //if ((!currentSkinBundle || !currentSkinObject) && isCustomSkinned)
+ // PlayerSkinLoader.ApplyPlayermodel(this, currentSkinPath);
+ // Prevent exceptions if we are in the middle of deleting a playermodel
+ if (!animator)
+ return;
+
+ animator.Update(Time.fixedDeltaTime);
+ characterAnimationManager.OnLateUpdate();
+ Vector3 repInputVel = Vector3.zero;
+
+ body.FullBodyUpdate(repInputVel, Vector3.zero);
+ body.ArtToBlender.UpdateBlender();
+ }
+ catch { }
+ }
+
+
+ private PlayerRig(ulong id)
+ {
+ _playerRigs.Add(id, this);
+ _ownerId = id;
}
public void Destroy()
{
- _playerRigs.Remove(this);
+ _playerRigs.Remove(_ownerId);
GameObject.Destroy(playerRig);
}
}
+
+ // copied from Entanglement mod
+ public static class PlayerScripts
+ {
+ public static RigManager playerRig;
+ public static PhysBody playerPhysBody;
+ public static Player_Health playerHealth;
+ public static PhysGrounder playerGrounder;
+ public static Hand playerLeftHand;
+ public static Hand playerRightHand;
+ public static bool reloadLevelOnDeath;
+ public static RuntimeAnimatorController playerAnimatorController;
+ public static Il2CppStringArray playerHandPoses = null;
+
+ public static void GetPlayerScripts()
+ {
+ GameObject localPlayerRig = GameObject.Find("[RigManager (Default Brett)]/[SkeletonRig (GameWorld Brett)]");
+ playerRig = localPlayerRig.GetComponentInChildren();
+ playerHealth = playerRig.playerHealth;
+
+ reloadLevelOnDeath = playerHealth.reloadLevelOnDeath;
+
+ playerHealth.reloadLevelOnDeath = !BoneSync.lobby.IsConnected();
+
+ PhysicsRig physicsRig = playerRig.physicsRig;
+ playerPhysBody = physicsRig.physBody;
+ playerGrounder = playerPhysBody.physG;
+ playerLeftHand = physicsRig.leftHand;
+ playerRightHand = physicsRig.rightHand;
+ playerAnimatorController = playerRig.gameWorldSkeletonRig.characterAnimationManager.animator.runtimeAnimatorController;
+ GetHandPoses();
+ }
+
+ public static void GetHandPoses()
+ {
+ // Checks if we already got the hand poses to prevent crashes
+ if (playerHandPoses == null)
+ CharacterAnimationManager.FetchHandPoseList(out playerHandPoses); // Lets hope this is constant!
+ }
+ }
}
diff --git a/BoneSync/Sync/Components/SyncableAI.cs b/BoneSync/Sync/Components/SyncableAI.cs
new file mode 100644
index 0000000..67692a9
--- /dev/null
+++ b/BoneSync/Sync/Components/SyncableAI.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+
+namespace BoneSync.Sync.Components
+{
+ public partial class Syncable : MonoBehaviour
+ {
+
+
+ }
+}
diff --git a/BoneSync/Sync/Components/SyncableBase.cs b/BoneSync/Sync/Components/SyncableBase.cs
index e6dface..a6e4fee 100644
--- a/BoneSync/Sync/Components/SyncableBase.cs
+++ b/BoneSync/Sync/Components/SyncableBase.cs
@@ -122,6 +122,7 @@ namespace BoneSync.Sync.Components
private PuppetMaster puppetMaster;
private PullDevice pullDevice;
+ private ButtonToggle[] buttonToggles;
private SpawnFragment spawnFragment;
@@ -192,6 +193,9 @@ namespace BoneSync.Sync.Components
gun = GetComponent();
magazine = GetComponent();
sockets = GetComponentsInChildren();
+ aiBrain = GetComponent();
+ buttonToggles = GetComponentsInChildren();
+ puppetMaster = aiBrain.puppetMaster;
if (sockets.Length == 0)
{
plugs = GetComponentsInChildren();
@@ -202,7 +206,7 @@ namespace BoneSync.Sync.Components
spawnFragment = GetComponent();
UpdateTransformList();
- _TryPatchPullDevice();
+ TryPatchUnityEvents();
ObjectSyncCache.AddSyncable(this);
}
diff --git a/BoneSync/Sync/Components/SyncableNetworking.cs b/BoneSync/Sync/Components/SyncableNetworking.cs
index 82d982a..45b1c40 100644
--- a/BoneSync/Sync/Components/SyncableNetworking.cs
+++ b/BoneSync/Sync/Components/SyncableNetworking.cs
@@ -124,12 +124,14 @@ namespace BoneSync.Sync.Components
return true;
}
- private void _SendSimpleEvent(SimpleEventType eType)
+ private void _SendSimpleEvent(SimpleEventType eType, byte index = 0)
{
+ MelonLogger.Msg("Sending simple event: " + eType);
SimpleSyncableEvent data = new SimpleSyncableEvent()
{
syncId = _syncId,
- eventType = eType
+ eventType = eType,
+ index = index
};
SimpleSyncableEventMessage simpleSyncEvent = new SimpleSyncableEventMessage(data);
diff --git a/BoneSync/Sync/Components/SyncablePhysics.cs b/BoneSync/Sync/Components/SyncablePhysics.cs
index d8651bd..ce94609 100644
--- a/BoneSync/Sync/Components/SyncablePhysics.cs
+++ b/BoneSync/Sync/Components/SyncablePhysics.cs
@@ -4,6 +4,7 @@ using BoneSync.Networking.Messages;
using BoneSync.Patching;
using Facepunch.Steamworks;
using MelonLoader;
+using StressLevelZero.Interaction;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -13,22 +14,65 @@ using UnityEngine;
using UnityEngine.Events;
namespace BoneSync.Sync.Components
{
+ public static class UnityEventExtentions
+ {
+ public static void AddListenerWithArgsRaw(this UnityEvent unityEvent, Action