using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: AssemblyTitle("BoneMod")] [assembly: AssemblyDescription("Valheim BoneMod")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("an0nymooose")] [assembly: AssemblyProduct("BoneMod")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("8f2e2083-d7bc-4426-802f-6cc9402029fc")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace BoneMod; public class Body { public Vector3 jaw { get; set; } = new Vector3(1f, 1f, 1f); public Vector3 head { get; set; } = new Vector3(1f, 1f, 1f); public Vector3 chest { get; set; } = new Vector3(1f, 1f, 1f); public Vector3 neck { get; set; } = new Vector3(1f, 1f, 1f); public Vector3 spine { get; set; } = new Vector3(1f, 1f, 1f); public Vector3 hips { get; set; } = new Vector3(1f, 1f, 1f); public Vector3 lefthand { get; set; } = new Vector3(1f, 1f, 1f); public Vector3 righthand { get; set; } = new Vector3(1f, 1f, 1f); public Vector3 leftfoot { get; set; } = new Vector3(1f, 1f, 1f); public Vector3 rightfoot { get; set; } = new Vector3(1f, 1f, 1f); public Vector3 leftleg { get; set; } = new Vector3(1f, 1f, 1f); public Vector3 rightleg { get; set; } = new Vector3(1f, 1f, 1f); public Vector3 leftarm { get; set; } = new Vector3(1f, 1f, 1f); public Vector3 rightarm { get; set; } = new Vector3(1f, 1f, 1f); } public class BodyManager { public static bool bodygroupUpdate(Player p, Vector3 Bodydata, string user, string group) { //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) string[] array = new string[2] { "", "" }; HumanBodyBones[] array2; switch (group) { case "feet": array[0] = "leftfoot"; array[1] = "rightfoot"; array2 = (HumanBodyBones[])(object)new HumanBodyBones[2] { (HumanBodyBones)5, (HumanBodyBones)6 }; break; case "hands": array[0] = "lefthand"; array[1] = "righthand"; array2 = (HumanBodyBones[])(object)new HumanBodyBones[2] { (HumanBodyBones)17, (HumanBodyBones)18 }; break; case "legs": array[0] = "leftleg"; array[1] = "rightleg"; array2 = (HumanBodyBones[])(object)new HumanBodyBones[2] { (HumanBodyBones)2, (HumanBodyBones)1 }; break; case "arms": array[0] = "leftarm"; array[1] = "rightarm"; array2 = (HumanBodyBones[])(object)new HumanBodyBones[2] { (HumanBodyBones)13, (HumanBodyBones)14 }; break; default: return false; } ((Component)((Component)((Component)p).GetComponent()).GetComponentInChildren().GetBoneTransform(array2[0])).transform.localScale = Bodydata; ((Component)((Component)((Component)p).GetComponent()).GetComponentInChildren().GetBoneTransform(array2[1])).transform.localScale = Bodydata; updateBody(array[0], Bodydata, user); updateBody(array[1], Bodydata, user); return true; } public static HumanBodyBones nameToBodyPart(string name) { //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) return (HumanBodyBones)(name.ToLower() switch { "head" => 10, "chest" => 8, "neck" => 9, "spine" => 7, "hips" => 0, "lefthand" => 17, "righthand" => 18, "rightfoot" => 6, "leftfoot" => 5, "jaw" => 23, "leftleg" => 1, "rightleg" => 2, "leftarm" => 13, "rightarm" => 14, _ => 55, }); } public static void updateBody(string part, Vector3 data, string user) { //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) Main.allplayers.TryGetValue(user, out var value); switch (part) { case "head": value.head = data; break; case "chest": value.chest = data; break; case "neck": value.neck = data; break; case "spine": value.spine = data; break; case "hips": value.hips = data; break; case "lefthand": value.lefthand = data; break; case "righthand": value.righthand = data; break; case "rightfoot": value.rightfoot = data; break; case "leftfoot": value.leftfoot = data; break; case "jaw": value.jaw = data; break; case "leftleg": value.leftleg = data; break; case "rightleg": value.rightleg = data; break; case "leftarm": value.leftarm = data; break; case "rightarm": value.rightarm = data; break; } Main.allplayers[user] = value; } public static string vecStr(Vector3 str) { return str.x + " " + str.y + " " + str.z + " "; } public static string serializeBody(string user) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) Main.allplayers.TryGetValue(user, out var value); return vecStr(value.jaw) + vecStr(value.head) + vecStr(value.chest) + vecStr(value.neck) + vecStr(value.spine) + vecStr(value.hips) + vecStr(value.lefthand) + vecStr(value.righthand) + vecStr(value.leftfoot) + vecStr(value.rightfoot) + vecStr(value.leftleg) + vecStr(value.rightleg) + vecStr(value.leftarm) + vecStr(value.rightarm); } public static Player getPlayerObj(string name) { foreach (Player allPlayer in Player.GetAllPlayers()) { if (allPlayer.GetPlayerName().ToLower().Equals(name.ToLower())) { return allPlayer; } } return null; } public static void setBoneDataCmd(float[] scaleData, Player exePlayer, string user, string textBodyPart, HumanBodyBones part) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(scaleData[1], scaleData[2], scaleData[3]); if (!bodygroupUpdate(exePlayer, val, user, textBodyPart)) { ((Component)((Component)((Component)exePlayer).GetComponent()).GetComponentInChildren().GetBoneTransform(part)).transform.localScale = val; updateBody(textBodyPart, val, user); } exePlayer.SetPrivateFieldValue(2, Main.properCase(textBodyPart) + " scale applied!", 0, null); } public static void resetPlayer(Player exePlayer, string playerName, string msg) { ZNetView component = ((Component)((Component)Player.m_localPlayer).GetComponent()).GetComponent(); Main.allplayers.Remove(playerName); Main.allplayers.Add(playerName, new Body()); Main.RPC_applyScaleVectorsToPlayer(component, playerName, serializeBody(playerName)); exePlayer.SetPrivateFieldValue(2, msg, 5, null); } } [BepInPlugin("an0nymooose_BoneMod", "BoneMod", "1.0.0.0")] public class Main : BaseUnityPlugin { [HarmonyPatch(typeof(FejdStartup), "OnCharacterStart")] private class ResetBodyOnLog { private static bool Prefix() { updateSelfBones = true; return true; } } [HarmonyPatch(typeof(Game), "Logout")] private class SaveOnLogout { private static bool Prefix() { BoneSaveManager.saveData(); return true; } } [HarmonyPatch(typeof(Game), "OnApplicationQuit")] private class SaveOnExit { private static bool Prefix() { try { BoneSaveManager.saveData(); } catch { } return true; } } [HarmonyPatch(typeof(Player), "Awake")] public class registerApplyVectors { public static void Postfix(Player __instance) { Debug.Log((object)"[BoneMod] Registering new player object."); ((Component)((Component)__instance).GetComponent()).GetComponent().Register("applyScaleVectorsToPlayer", (Action)applyScaleVectorsToPlayer); } public static void applyScaleVectorsToPlayer(long sender, string name, string vectors) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) Player playerObj = BodyManager.getPlayerObj(name); if (!Object.op_Implicit((Object)(object)playerObj)) { return; } try { string[] array = vectors.Split(new char[1] { ' ' }); string[] array2 = "jaw head chest neck spine hips lefthand righthand leftfoot rightfoot leftleg rightleg leftarm rightarm".Split(new char[1] { ' ' }); int num = 0; Animator componentInChildren = ((Component)((Component)playerObj).GetComponent()).GetComponentInChildren(); Vector3 val2 = default(Vector3); for (int i = 0; i < array2.Length; i++) { HumanBodyBones val = BodyManager.nameToBodyPart(array2[i]); ((Vector3)(ref val2))..ctor(float.Parse(array[num]), float.Parse(array[num + 1]), float.Parse(array[num + 2])); ((Component)componentInChildren.GetBoneTransform(val)).transform.localScale = val2; if (updateSelfBones && Player.m_localPlayer.GetPlayerName().ToLower() == name) { BodyManager.updateBody(array2[i], val2, name); } num += 3; } } catch { Debug.Log((object)"[BoneMod] Failed to apply scaling to dead/loading player. It's normal, Continuing.."); } } } [HarmonyPatch(typeof(Chat), "OnNewChatMessage")] public class BoneMessageSystem : MonoBehaviour { private static bool Prefix(ref Type type, UserInfo sender, string text) { //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Invalid comparison between Unknown and I4 //IL_030e: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { string text2 = text.ToLower(); string name = sender.Name; name = name.ToLower(); if (!allplayers.ContainsKey(name)) { allplayers.Add(name, new Body()); } if (text2.StartsWith("!bm")) { string playerName = Player.m_localPlayer.GetPlayerName(); Player playerObj = BodyManager.getPlayerObj(name.ToLower()); string[] array = text2.Split(new char[1] { ' ' }); string text3 = array[0]; if (text.StartsWith("\nBoneMod by an0nymooose") && name != playerName.ToLower()) { return false; } if (text3 == "!bmhelp" && name == playerName.ToLower()) { BoneSaveManager.saveData(); Chat.instance.SendText((Type)1, "\nBoneMod by an0nymooose\nCommands:\n1) !bm bodypart x y z (Ex: !bm head 2 1 2)\nTo equally scale, just provide X (!bm head 2)\n2) !bmreset Resets the player's bones.\nBones: jaw head chest neck spine hips lefthand righthand leftfoot rightfoot leftleg rightleg leftarm rightarm\n(Group parts \"arms, legs, hands, feet\" also valid)\n3) !bmstop/!bmstart controls your bone syncing between players\n4) !bmclearsave clears all saved local characters bones and resets your bones."); return false; } if (text3 == "!bmreset") { BodyManager.resetPlayer(playerObj, name, "Bones reset!"); return false; } if (text3 == "!bmclearsave" && name == playerName.ToLower()) { BoneSaveManager.clearSaveData(); BodyManager.resetPlayer(playerObj, name, "Bone save file cleared and bones reset!"); return false; } if (text3 == "!bmstop" && name == playerName.ToLower()) { playerObj.SetPrivateFieldValue(2, "Bone syncing stopped!", 5, null); broadcast = false; return false; } if (text3 == "!bmstart" && name == playerName.ToLower()) { playerObj.SetPrivateFieldValue(2, "Bone syncing started!", 5, null); broadcast = true; return false; } if (text3 == "!bm" && array.Length > 2) { array = text2.Trim().Split(new char[1] { ' ' }); string text4 = array[1]; float[] array2 = numCheck(array); if (array2[0] == 0f) { playerObj.SetPrivateFieldValue(2, "Invalid scale numbers / malformed command", 10, null); return false; } if (array2[0] == 2f) { array2[2] = array2[1]; array2[3] = array2[1]; } bool flag = true; type = (Type)2; HumanBodyBones val = BodyManager.nameToBodyPart(text4); if ((int)val == 55 && !"arms legs feet hands".Contains(text4)) { flag = false; } if (text3 == "!bm" && Math.Abs(array2[1]) <= (float)SIZE_LIMIT && Math.Abs(array2[2]) <= (float)SIZE_LIMIT && Math.Abs(array2[3]) <= (float)SIZE_LIMIT && flag) { BodyManager.setBoneDataCmd(array2, playerObj, name, text4, val); return false; } playerObj.SetPrivateFieldValue(2, "Invalid body part / size above " + SIZE_LIMIT, 5, null); return false; } } return true; } return false; } } public const string MODNAME = "BoneMod"; public const string AUTHOR = "an0nymooose"; public const string GUID = "an0nymooose_BoneMod"; public const string VERSION = "1.0.0.0"; internal readonly ManualLogSource log; internal readonly Harmony harmony; internal readonly Assembly assembly; private ConfigEntry configAutoStartBroadcast; private ConfigEntry configAlwaysLoadSavedBones; private ConfigEntry configMAX_SIZE; public static Dictionary allplayers = new Dictionary(); public static bool updateSelfBones = false; public static bool CamUpdate = false; private static bool broadcast = true; private static int SIZE_LIMIT = 10; public const string bodylist = "jaw head chest neck spine hips lefthand righthand leftfoot rightfoot leftleg rightleg leftarm rightarm"; public const string bodygrouplist = "arms legs feet hands"; public const string HELP_TEXT = "\nBoneMod by an0nymooose\nCommands:\n1) !bm bodypart x y z (Ex: !bm head 2 1 2)\nTo equally scale, just provide X (!bm head 2)\n2) !bmreset Resets the player's bones.\nBones: jaw head chest neck spine hips lefthand righthand leftfoot rightfoot leftleg rightleg leftarm rightarm\n(Group parts \"arms, legs, hands, feet\" also valid)\n3) !bmstop/!bmstart controls your bone syncing between players\n4) !bmclearsave clears all saved local characters bones and resets your bones."; public Main() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown log = ((BaseUnityPlugin)this).Logger; harmony = new Harmony("an0nymooose_BoneMod"); assembly = Assembly.GetExecutingAssembly(); } public void Start() { harmony.PatchAll(assembly); Debug.Log((object)"BoneMod Loaded!"); configAutoStartBroadcast = ((BaseUnityPlugin)this).Config.Bind("General.Toggles", "AutoStartBroadcast", true, "Whether or not to automatically start broadcasting your vectors in chat. Turn off if you are playing with others who do not have this mod."); configMAX_SIZE = ((BaseUnityPlugin)this).Config.Bind("General", "Max Size", 10, "The maximum transform size, 10 seems to be a good value without going crazy."); configAlwaysLoadSavedBones = ((BaseUnityPlugin)this).Config.Bind("General.Toggles", "Always load saved bones.", true, "Automatically load and apply saved bone profiles (bonemod.txt)."); SIZE_LIMIT = configMAX_SIZE.Value; if (!configAutoStartBroadcast.Value) { broadcast = false; } ((MonoBehaviour)this).InvokeRepeating("broadcastVectors", 2f, 10f); } private void broadcastVectors() { if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return; } string text = Player.m_localPlayer.GetPlayerName().ToLower(); if (Object.op_Implicit((Object)(object)Chat.instance) && broadcast) { if (updateSelfBones && configAlwaysLoadSavedBones.Value) { BoneSaveManager.loadSaveData(); updateSelfBones = false; } ZNetView component = ((Component)((Component)Player.m_localPlayer).GetComponent()).GetComponent(); RPC_applyScaleVectorsToPlayer(component, text, BodyManager.serializeBody(text)); } } public static void RPC_applyScaleVectorsToPlayer(ZNetView bone_netview, string name, string vectors) { bone_netview.InvokeRPC(ZNetView.Everybody, "applyScaleVectorsToPlayer", new object[2] { name, vectors }); } private static float[] numCheck(string[] command) { float result4; if (command.Length == 5) { if (float.TryParse(command[2], out var result) && float.TryParse(command[3], out var result2) && float.TryParse(command[4], out var result3)) { return new float[4] { 1f, result, result2, result3 }; } } else if (command.Length == 3 && float.TryParse(command[2], out result4)) { return new float[4] { 2f, result4, 0f, 0f }; } return new float[4]; } public static string properCase(string x) { return (x.Length > 0) ? (x[0].ToString().ToUpper() + x.Substring(1, x.Length - 1)) : ""; } } public class BoneSaveManager { public static List readSaveData() { try { Debug.Log((object)"READING BONEMOD.TXT"); using StreamReader streamReader = new StreamReader(Paths.ConfigPath + "\\boneData.txt"); List list = new List(); string text = ""; while ((text = streamReader.ReadLine()) != null) { list.Add(text); } streamReader.Close(); return list; } catch (IOException) { return null; } } public static void saveData() { Debug.Log((object)"WRITING BONEMOD.TXT"); string text = Player.m_localPlayer.GetPlayerName().ToLower(); List list = readSaveData(); bool flag = false; StreamWriter streamWriter = new StreamWriter(Paths.ConfigPath + "\\boneData.txt", append: false); if (list != null) { string[] array = list.ToArray(); for (int i = 0; i < array.Length; i++) { if (array[i].StartsWith("[" + text + "]")) { flag = true; array[i] = "[" + text + "] " + BodyManager.serializeBody(text); streamWriter.WriteLine(array[i]); } else { streamWriter.WriteLine(array[i]); } } if (!flag) { streamWriter.WriteLine("[" + text + "] " + BodyManager.serializeBody(text)); } } else { streamWriter.WriteLine("[" + text + "] " + BodyManager.serializeBody(text)); } streamWriter.Flush(); streamWriter.Close(); } public static void clearSaveData() { Debug.Log((object)"CLEARING BONEMOD.TXT"); StreamWriter streamWriter = new StreamWriter(Paths.ConfigPath + "\\boneData.txt", append: false); streamWriter.Write(""); streamWriter.Flush(); streamWriter.Close(); Utility.GetUniqueFilesInDirectories((IEnumerable)new List { Paths.PluginPath }, "*"); } public static void loadSaveData() { string text = Player.m_localPlayer.GetPlayerName().ToLower(); List list = readSaveData(); if (list == null) { return; } string[] array = list.ToArray(); for (int i = 0; i < array.Length; i++) { if (array[i].StartsWith("[" + text + "]")) { ZNetView component = ((Component)((Component)Player.m_localPlayer).GetComponent()).GetComponent(); string text2 = "[" + text + "]"; string vectors = array[i].Substring(array[i].IndexOf(text2) + text2.Length).Trim(); Main.RPC_applyScaleVectorsToPlayer(component, text, vectors); } } } } public static class PrivateAccessor { public static void SetPrivateFieldValue(this object obj, int propName, string val, int P_3, object P_4) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown ((Character)obj).Message((MessageType)propName, val, P_3, (Sprite)P_4, false); } public static T GetPrivateFieldValue(this object P_0, string P_1) { if (P_0 == null) { throw new ArgumentNullException("obj"); } Type type = P_0.GetType(); FieldInfo fieldInfo = null; while (fieldInfo == null && type != null) { fieldInfo = type.GetField(P_1, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); type = type.BaseType; } if (fieldInfo == null) { throw new ArgumentOutOfRangeException("propName", $"Field {P_1} was not found in Type {P_0.GetType().FullName}"); } return (T)fieldInfo.GetValue(P_0); } }