Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of BodyBlend v0.4.1
BodyBlend.dll
Decompiled 4 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using BodyBlend.Utils; using On.RoR2; using RiskOfOptions; using RiskOfOptions.OptionConfigs; using RiskOfOptions.Options; using RoR2; using RoR2.ContentManagement; using SuspiciousTentacle; using UnityEngine; using UnityEngine.Events; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("BodyBlend")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+a2f2e4adafeea51cd50c164ff512798676ab722c")] [assembly: AssemblyProduct("BodyBlend")] [assembly: AssemblyTitle("BodyBlend")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace BodyBlend { [DisallowMultipleComponent] public class BodyBlendController : MonoBehaviour { private BodyBlendUtils.DictionaryList<string, BodyBlendControl> bodyBlendControls = new BodyBlendUtils.DictionaryList<string, BodyBlendControl>(); private string SkinDefKey = ""; public void Awake() { } public void LateUpdate() { foreach (KeyValuePair<string, List<BodyBlendControl>> bodyBlendControl in bodyBlendControls) { float maxBlend = FetchMaxBlendConfig(bodyBlendControl.Key); float minBlend = FetchMinBlendConfig(bodyBlendControl.Key); foreach (BodyBlendControl item in bodyBlendControl.Value) { item.SetMinBlend(minBlend); item.SetMaxBlend(maxBlend); item.Update(Time.deltaTime); } } } private float FetchMinBlendConfig(string name) { float? num = BodyBlendOptions.MinBlendConfigs.GetValue(SkinDefKey)?.GetValue(name)?.Value; if (!num.HasValue) { return 0f; } return num.Value / 100f; } private float FetchMaxBlendConfig(string name) { float? num = BodyBlendOptions.MaxBlendConfigs.GetValue(SkinDefKey)?.GetValue(name)?.Value; if (!num.HasValue) { return 1f; } return num.Value / 100f; } public void SetBlendTargetWeight(string name, float value, string source = "Default", bool setInstant = false) { if (!HasBlendControl(name)) { return; } foreach (BodyBlendControl item in bodyBlendControls[name]) { item.SetTargetWeight(value, source); if (setInstant) { item.Update(0f, forceNoLerp: true); } } } public void SetBlendTargetWeightPercent(string name, float value, string source = "Default", bool setInstant = false) { if (!HasBlendControl(name)) { return; } foreach (BodyBlendControl item in bodyBlendControls[name]) { item.SetTargetWeightPercent(value, source); if (setInstant) { item.Update(0f, forceNoLerp: true); } } } public void RemoveBlendTargetWeight(string name, string source = "Default") { if (!HasBlendControl(name)) { return; } foreach (BodyBlendControl item in bodyBlendControls[name]) { item.RemoveTargetWeight(source); } } public bool HasBlendControl(string name) { return bodyBlendControls.ContainsKey(name); } internal void AddBlendControl(string name, BodyBlendControl control) { if (!bodyBlendControls.ContainsKey(name)) { bodyBlendControls[name] = new List<BodyBlendControl>(); } bodyBlendControls[name].Add(control); } internal void RemoveBlendControl(string name) { bodyBlendControls.Remove(name); } internal void SetSkinDefKey(string key) { SkinDefKey = key; } } internal class BodyBlendControl { public Dictionary<int, AnimationCurve> blendShapeControls = new Dictionary<int, AnimationCurve>(); public List<DynamicBoneControl> boneControls = new List<DynamicBoneControl>(); private SkinnedMeshRenderer targetRenderer; private float minBlend = 0f; private float maxBlend = 1f; private float elapsedTime = 0f; private float currentWeight = 0f; private Dictionary<string, float> targetWeights = new Dictionary<string, float> { { "Default", 0f } }; private Dictionary<string, float> targetWeightPercents = new Dictionary<string, float> { { "Default", 0f } }; public BodyBlendControl(SkinnedMeshRenderer targetRenderer = null) { this.targetRenderer = targetRenderer; } public void SetTargetRenderer(SkinnedMeshRenderer renderer) { targetRenderer = renderer; } public void AddDynBoneControl(List<DynamicBone> bones, AnimationCurve inertCurve = null, AnimationCurve elasticityCurve = null, AnimationCurve stiffnessCurve = null, AnimationCurve dampingCurve = null, DynBoneControlMode mode = DynBoneControlMode.FULL_CONTROL) { DynamicBoneControl dynamicBoneControl = new DynamicBoneControl(); dynamicBoneControl.SetBoneControls(bones, inertCurve, elasticityCurve, stiffnessCurve, dampingCurve, mode); boneControls.Add(dynamicBoneControl); } public void SetTargetWeight(float weight, string source) { targetWeights[source] = weight; } public void SetTargetWeightPercent(float weight, string source) { targetWeightPercents[source] = weight; } public void RemoveTargetWeight(string source) { targetWeights.Remove(source); } public void SetMaxBlend(float value) { maxBlend = value; } public void SetMinBlend(float value) { minBlend = value; } public void Update(float t, bool forceNoLerp = false) { elapsedTime += t; bool flag = forceNoLerp; if (BodyBlendOptions.BoneUpdateInterval.Value <= 0f) { flag = true; } else if (elapsedTime >= BodyBlendOptions.BoneUpdateInterval.Value) { elapsedTime -= BodyBlendOptions.BoneUpdateInterval.Value; elapsedTime = Mathf.Min(elapsedTime, BodyBlendOptions.BoneUpdateInterval.Value); flag = true; } if (BodyBlendOptions.UseLerp.Value && !forceNoLerp) { currentWeight = Mathf.Lerp(currentWeight, GetTargetWeight(), t * BodyBlendOptions.LerpSpeed.Value); } else { currentWeight = GetTargetWeight(); } float num = Mathf.Lerp(minBlend, maxBlend, currentWeight); if (flag && boneControls != null) { foreach (DynamicBoneControl boneControl in boneControls) { boneControl.UpdateBoneValues(num); } } if ((Object)(object)targetRenderer == (Object)null) { return; } foreach (KeyValuePair<int, AnimationCurve> blendShapeControl in blendShapeControls) { float num2 = blendShapeControl.Value.Evaluate(num); if (targetRenderer.sharedMesh.blendShapeCount > blendShapeControl.Key) { targetRenderer.SetBlendShapeWeight(blendShapeControl.Key, num2 * 100f); } } } private float GetTargetWeight() { float num = targetWeights.Values.Sum(); num = Mathf.Clamp01(num); float num2 = targetWeightPercents.Values.Max(); return Mathf.Lerp(num, 1f, num2); } } [Serializable] public class BBJsonConfig { public string skinName; public string skinDefName; public string skinDefToken; [NonSerialized] public string filePath; public List<BBJsonPartControl> parts; } [Serializable] public class BBJsonPartControl { public string name; public List<BBJsonCtrlTemplate> controls; } [Serializable] public class BBJsonCtrlTemplate { public int targetRendererIndex = -1; public List<BBShapeControl> blendControls; public List<BBBoneControl> boneControls; } [Serializable] public class BBBoneControl { public List<string> boneNames = new List<string>(); public List<BBAnimKey> inertCurve; public List<BBAnimKey> elasticityCurve; public List<BBAnimKey> stiffnessCurve; public List<BBAnimKey> dampingCurve; public string controlMode = "FULL_CONTROL"; } [Serializable] public class BBShapeControl { public int blendIdx = -1; public List<BBAnimKey> keyframes; } [Serializable] public class BBAnimKey { public List<float> val; } internal static class BBJsonExtensions { private static Dictionary<string, DynBoneControlMode> DynBoneDict = new Dictionary<string, DynBoneControlMode> { { "ZERO_TO_BASE", DynBoneControlMode.ZERO_TO_BASE }, { "BASE_TO_ONE", DynBoneControlMode.BASE_TO_ONE }, { "FULL_CONTROL", DynBoneControlMode.FULL_CONTROL } }; public static BodyBlendUtils.DictionaryList<string, BodyBlendUtils.BlendControlTemplate> ToTemplates(this BBJsonConfig self) { BodyBlendUtils.DictionaryList<string, BodyBlendUtils.BlendControlTemplate> dictionaryList = new BodyBlendUtils.DictionaryList<string, BodyBlendUtils.BlendControlTemplate>(); foreach (BBJsonPartControl part in self.parts) { List<BodyBlendUtils.BlendControlTemplate> list = new List<BodyBlendUtils.BlendControlTemplate>(); foreach (BBJsonCtrlTemplate control in part.controls) { BodyBlendUtils.BlendControlTemplate blendControlTemplate = new BodyBlendUtils.BlendControlTemplate(); blendControlTemplate.targetRendererIndex = control.targetRendererIndex; blendControlTemplate.blendShapeControls = control.blendControls.ToAnimDict(); blendControlTemplate.boneControls = (from bone in control.boneControls select bone.ToTemplate() into bone where bone != null select bone).ToList(); list.Add(blendControlTemplate); } dictionaryList.Add(part.name, list); } return dictionaryList; } private static Dictionary<int, AnimationCurve> ToAnimDict(this List<BBShapeControl> self) { if (self == null || self.Count() < 1) { return null; } Dictionary<int, AnimationCurve> dictionary = new Dictionary<int, AnimationCurve>(); foreach (BBShapeControl item in self) { dictionary.Add(item.blendIdx, item.keyframes.ToAnimationCurve()); } return dictionary; } private static BodyBlendUtils.BoneControlTemplate ToTemplate(this BBBoneControl self) { if (self == null) { return null; } BodyBlendUtils.BoneControlTemplate boneControlTemplate = new BodyBlendUtils.BoneControlTemplate(); boneControlTemplate.associatedDynBoneNames = self.boneNames; boneControlTemplate.dynBoneInertCurve = self.inertCurve.ToAnimationCurve(); boneControlTemplate.dynBoneElasticityCurve = self.elasticityCurve.ToAnimationCurve(); boneControlTemplate.dynBoneStiffnessCurve = self.stiffnessCurve.ToAnimationCurve(); boneControlTemplate.dynBoneDampingCurve = self.dampingCurve.ToAnimationCurve(); if (DynBoneDict.ContainsKey(self.controlMode)) { boneControlTemplate.dynBoneControlMode = DynBoneDict[self.controlMode]; } return boneControlTemplate; } private static AnimationCurve ToAnimationCurve(this List<BBAnimKey> self) { if (self == null || self.Count < 2) { return null; } Keyframe[] keyframes = self.Where((BBAnimKey elem) => elem.val.Count == 2 || elem.val.Count == 4 || elem.val.Count == 6).Select((Func<BBAnimKey, Keyframe>)delegate(BBAnimKey elem) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) List<float> val = elem.val; if (val.Count == 2) { return new Keyframe(val[0], val[1]); } return (val.Count == 4) ? new Keyframe(val[0], val[1], val[2], val[3]) : new Keyframe(val[0], val[1], val[2], val[3], val[4], val[5]); }).ToArray(); return BodyBlendUtils.MakeAnimationCurve(keyframes); } } internal static class BodyBlendOptions { internal static ConfigEntry<bool> UseLerp; internal static ConfigEntry<float> LerpSpeed; internal static ConfigEntry<float> BoneUpdateInterval; internal static BodyBlendUtils.NestedDictionary<string, string, ConfigEntry<float>> MinBlendConfigs = new BodyBlendUtils.NestedDictionary<string, string, ConfigEntry<float>>(); internal static BodyBlendUtils.NestedDictionary<string, string, ConfigEntry<float>> MaxBlendConfigs = new BodyBlendUtils.NestedDictionary<string, string, ConfigEntry<float>>(); internal static List<string> SusTentacleParts = new List<string>(); internal static bool CheckUseLerp() { return !UseLerp.Value; } internal static void InitializeOptions(ConfigFile config) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Expected O, but got Unknown //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Expected O, but got Unknown //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Expected O, but got Unknown //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Expected O, but got Unknown //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Expected O, but got Unknown UseLerp = config.Bind<bool>("BodyBlend", "Use Lerp", true, "Enable smooth transition. If disabled, the model instantly changes to match the target size."); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(UseLerp, new CheckBoxConfig())); LerpSpeed = config.Bind<float>("BodyBlend", "Lerp Speed", 2f, "If lerp is enabled, this controls how fast the model changes to match the target size.\nDefault: 2.0"); ConfigEntry<float> lerpSpeed = LerpSpeed; StepSliderConfig val = new StepSliderConfig(); ((SliderConfig)val).min = 0.1f; ((SliderConfig)val).max = 10f; val.increment = 0.1f; ((BaseOptionConfig)val).checkIfDisabled = new IsDisabledDelegate(CheckUseLerp); ModSettingsManager.AddOption((BaseOption)new StepSliderOption(lerpSpeed, val)); BoneUpdateInterval = config.Bind<float>("BodyBlend", "Bone Update Interval", 0.15f, "Intervals between each update to dynamic bone.\nDefault: 0.15"); ModSettingsManager.AddOption((BaseOption)new StepSliderOption(BoneUpdateInterval, new StepSliderConfig { min = 0.01f, max = 1f, increment = 0.01f })); ModSettingsManager.AddOption((BaseOption)new GenericButtonOption("", "BodyBlend", "Click to reload all BodyBlend configuration files in the /plugins folder.\nCheck the console log to see if files have been reloaded.\nAny adjustment will only apply after entering a new stage.\nIf you have added a new part in the config file, you'll need to restart the game for BodyBlend to work properly.", "Reload Config Files", new UnityAction(BodyBlendPlugin.ReloadJson))); foreach (KeyValuePair<string, BodyBlendUtils.DictionaryList<string, BodyBlendUtils.BlendControlTemplate>> registeredSkinBlendControl in BodyBlendUtils.RegisteredSkinBlendControls) { string key = registeredSkinBlendControl.Key; string skinName = BodyBlendUtils.GetSkinName(key); Dictionary<string, ConfigEntry<float>> dictionary = new Dictionary<string, ConfigEntry<float>>(); Dictionary<string, ConfigEntry<float>> dictionary2 = new Dictionary<string, ConfigEntry<float>>(); foreach (KeyValuePair<string, List<BodyBlendUtils.BlendControlTemplate>> item in registeredSkinBlendControl.Value) { string key2 = item.Key; ConfigEntry<float> val2 = config.Bind<float>(skinName, "Min " + key2 + " Size", 0f, "Minimum size for the part \"" + key2 + "\".\nBodyBlend will interpolate the size from the minimum value to the maximum value."); ModSettingsManager.AddOption((BaseOption)new SliderOption(val2, new SliderConfig { min = 0f, max = 100f })); dictionary.Add(key2, val2); ConfigEntry<float> val3 = config.Bind<float>(skinName, "Max " + key2 + " Size", 100f, "Maximum size for the part \"" + key2 + "\".\nBodyBlend will interpolate the size from the minimum value to the maximum value."); ModSettingsManager.AddOption((BaseOption)new SliderOption(val3, new SliderConfig { min = 0f, max = 100f })); dictionary2.Add(key2, val3); } MinBlendConfigs.Add(key, dictionary); MaxBlendConfigs.Add(key, dictionary2); } } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("com.Maiesen.BodyBlend", "BodyBlend", "0.4.1")] public sealed class BodyBlendPlugin : BaseUnityPlugin { public const string MODNAME = "BodyBlend"; public const string AUTHOR = "Maiesen"; public const string GUID = "com.Maiesen.BodyBlend"; public const string VERSION = "0.4.1"; private const BindingFlags AllFlags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private static Dictionary<string, BBJsonConfig> FoundJson = new Dictionary<string, BBJsonConfig>(); public static event Action AfterBodyBlendLoaded; private void Awake() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown Log.Init(((BaseUnityPlugin)this).Logger); ModelSkinController.ApplySkinAsync += new hook_ApplySkinAsync(ModelSkinController_ApplySkinAsync); if (SuspiciousTentacleCompatibility.enabled) { SuspiciousTentacleCompatibility.HookGrowthProgress(); } } private void Start() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); using (MemoryStream memoryStream = new MemoryStream()) { Assembly.GetExecutingAssembly().GetManifestResourceStream("BodyBlend.icon.png").CopyTo(memoryStream); ImageConversion.LoadImage(val, memoryStream.ToArray()); } Sprite modIcon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).height, (float)((Texture)val).width), new Vector2(0.5f, 0.5f), 100f); ModSettingsManager.SetModIcon(modIcon); RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(OnLoad)); SearchConfigJson(); } private void OnLoad() { SkinDef[] allSkinDefs = SkinCatalog.allSkinDefs; foreach (SkinDef skinDef in allSkinDefs) { LoadBodyBlendJson(skinDef); } BodyBlendOptions.InitializeOptions(((BaseUnityPlugin)this).Config); BodyBlendPlugin.AfterBodyBlendLoaded?.Invoke(); if (SuspiciousTentacleCompatibility.enabled) { SuspiciousTentacleCompatibility.SetupCompatibility(); } } public static void ReloadJson() { Log.Info("Reloading config files."); SearchConfigJson(); BodyBlendUtils.ClearRegister(); SkinDef[] allSkinDefs = SkinCatalog.allSkinDefs; foreach (SkinDef skinDef in allSkinDefs) { LoadBodyBlendJson(skinDef, overwrite: true); } } public static List<string> GetBodyBlendParts() { return BodyBlendUtils.PartsList.ToList(); } private IEnumerator ModelSkinController_ApplySkinAsync(orig_ApplySkinAsync orig, ModelSkinController self, int skinIndex, AsyncReferenceHandleUnloadType unloadType) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) IEnumerator result = orig.Invoke(self, skinIndex, unloadType); Action<int> setup = null; self.onSkinApplied += (setup = delegate(int index) { SetUpBodyBlend(self.skins[index], ((Component)self).gameObject); self.onSkinApplied -= setup; }); return result; } public static void SetUpBodyBlend(SkinDef skinDef, GameObject model) { if (!(skinDef.nameToken == "") || !(((Object)skinDef).name == "")) { BodyBlendController component = model.GetComponent<BodyBlendController>(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } if (BodyBlendUtils.FindRegisteredSkinControl(skinDef) != null) { BodyBlendController controller = model.AddComponent<BodyBlendController>(); controller.ApplyFromRegisteredBlendControls(model, skinDef); } } } private static void LoadBodyBlendJson(SkinDef skinDef, bool overwrite = false) { if (BodyBlendUtils.FindRegisteredSkinControl(skinDef) != null && !overwrite) { return; } string text = BodyBlendUtils.FindSkinDefKey(FoundJson, skinDef); if (text == null) { return; } Log.Info("Loading " + ((Object)skinDef).name + "|" + skinDef.nameToken + " BodyBlend config from json."); BBJsonConfig bBJsonConfig = FoundJson[text]; if (overwrite) { string filePath = bBJsonConfig.filePath; BBJsonConfig bBJsonConfig2 = LoadJson(filePath); if (bBJsonConfig2 == null) { Log.Warning("Fail to reload BodyBlend config."); } FoundJson[text] = bBJsonConfig2; bBJsonConfig = bBJsonConfig2; } if (bBJsonConfig != null) { BodyBlendUtils.RegisterFromJson(bBJsonConfig, skinDef); } } private static void SearchConfigJson() { FoundJson.Clear(); string bepInExAssemblyDirectory = Paths.BepInExAssemblyDirectory; string fullPath = Path.GetFullPath(Path.Combine(bepInExAssemblyDirectory, "..\\plugins\\")); string[] files = Directory.GetFiles(fullPath, "*.json", SearchOption.AllDirectories); string[] array = files; foreach (string path in array) { if (!File.Exists(path) || Path.GetFileName(path) == "manifest.json") { continue; } BBJsonConfig bBJsonConfig = LoadJson(path); if (bBJsonConfig != null) { string text = BodyBlendUtils.MakeSkinDefKey(bBJsonConfig.skinDefName, bBJsonConfig.skinDefToken); if (text == null) { text = (bBJsonConfig.skinDefToken = Path.GetFileName(path).Replace(".json", "")); } FoundJson[text] = bBJsonConfig; } } } private static BBJsonConfig LoadJson(string path) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown TextAsset val = new TextAsset(File.ReadAllText(path)); BBJsonConfig bBJsonConfig = JsonUtility.FromJson<BBJsonConfig>(val.text); if (bBJsonConfig != null) { bBJsonConfig.filePath = path; } return bBJsonConfig; } } public enum DynBoneControlMode { ZERO_TO_BASE, FULL_CONTROL, BASE_TO_ONE } internal class DynamicBoneControl { private struct DynBoneValue { public float m_Damping; public float m_Elasticity; public float m_Stiffness; public float m_Inert; public DynBoneValue(float d, float e, float s, float i) { m_Damping = d; m_Elasticity = e; m_Stiffness = s; m_Inert = i; } } private List<DynBoneValue> defaultBones = null; private List<DynamicBone> dynamicBones = null; private AnimationCurve inertCurve = null; private AnimationCurve elasticityCurve = null; private AnimationCurve stiffnessCurve = null; private AnimationCurve dampingCurve = null; private DynBoneControlMode dynBoneControlMode = DynBoneControlMode.FULL_CONTROL; internal void SetBoneControls(List<DynamicBone> bones, AnimationCurve inertCurve = null, AnimationCurve elasticityCurve = null, AnimationCurve stiffnessCurve = null, AnimationCurve dampingCurve = null, DynBoneControlMode dynBoneControlMode = DynBoneControlMode.FULL_CONTROL) { if (bones != null && bones.Count > 0) { dynamicBones = bones; this.inertCurve = inertCurve; this.elasticityCurve = elasticityCurve; this.stiffnessCurve = stiffnessCurve; this.dampingCurve = dampingCurve; this.dynBoneControlMode = dynBoneControlMode; SaveDynBoneValues(dynamicBones); } } internal void UpdateBoneValues(float currentWeight) { if (dynamicBones != null) { for (int i = 0; i < dynamicBones.Count; i++) { dynamicBones[i].m_Inert = GetDynBoneValue(inertCurve, defaultBones[i].m_Inert, currentWeight); dynamicBones[i].m_Elasticity = GetDynBoneValue(elasticityCurve, defaultBones[i].m_Elasticity, currentWeight); dynamicBones[i].m_Stiffness = GetDynBoneValue(stiffnessCurve, defaultBones[i].m_Stiffness, currentWeight); dynamicBones[i].m_Damping = GetDynBoneValue(dampingCurve, defaultBones[i].m_Damping, currentWeight); UpdateDynBoneParameters(dynamicBones[i]); } } } private float GetDynBoneValue(AnimationCurve curve, float defaultValue, float currentWeight) { if (curve == null) { return defaultValue; } float num = Mathf.Clamp01(curve.Evaluate(currentWeight)); return dynBoneControlMode switch { DynBoneControlMode.BASE_TO_ONE => Mathf.Lerp(defaultValue, 1f, num), DynBoneControlMode.ZERO_TO_BASE => Mathf.Lerp(0f, defaultValue, num), DynBoneControlMode.FULL_CONTROL => num, _ => defaultValue, }; } private static void UpdateDynBoneParameters(DynamicBone bone) { List<Particle> particles = bone.m_Particles; for (int i = 0; i < particles.Count; i++) { Particle val = particles[i]; val.m_Damping = bone.m_Damping; val.m_Elasticity = bone.m_Elasticity; val.m_Stiffness = bone.m_Stiffness; val.m_Inert = bone.m_Inert; val.m_Radius = bone.m_Radius; float boneTotalLength = bone.m_BoneTotalLength; if (boneTotalLength > 0f) { float num = val.m_BoneLength / boneTotalLength; if (bone.m_DampingDistrib != null && bone.m_DampingDistrib.keys.Length != 0) { val.m_Damping *= bone.m_DampingDistrib.Evaluate(num); } if (bone.m_ElasticityDistrib != null && bone.m_ElasticityDistrib.keys.Length != 0) { val.m_Elasticity *= bone.m_ElasticityDistrib.Evaluate(num); } if (bone.m_StiffnessDistrib != null && bone.m_StiffnessDistrib.keys.Length != 0) { val.m_Stiffness *= bone.m_StiffnessDistrib.Evaluate(num); } if (bone.m_InertDistrib != null && bone.m_InertDistrib.keys.Length != 0) { val.m_Inert *= bone.m_InertDistrib.Evaluate(num); } if (bone.m_RadiusDistrib != null && bone.m_RadiusDistrib.keys.Length != 0) { val.m_Radius *= bone.m_RadiusDistrib.Evaluate(num); } } val.m_Damping = Mathf.Clamp01(val.m_Damping); val.m_Elasticity = Mathf.Clamp01(val.m_Elasticity); val.m_Stiffness = Mathf.Clamp01(val.m_Stiffness); val.m_Inert = Mathf.Clamp01(val.m_Inert); val.m_Radius = Mathf.Max(val.m_Radius, 0f); } } private void SaveDynBoneValues(List<DynamicBone> dynamicBones) { if (defaultBones == null) { defaultBones = new List<DynBoneValue>(); } foreach (DynamicBone dynamicBone in dynamicBones) { defaultBones.Add(new DynBoneValue(dynamicBone.m_Damping, dynamicBone.m_Elasticity, dynamicBone.m_Stiffness, dynamicBone.m_Inert)); } } } internal static class Log { private static ManualLogSource _logSource; internal static void Init(ManualLogSource logSource) { _logSource = logSource; } internal static void Debug(object data) { _logSource.LogDebug(data); } internal static void Error(object data) { _logSource.LogError(data); } internal static void Fatal(object data) { _logSource.LogFatal(data); } internal static void Info(object data) { _logSource.LogInfo(data); } internal static void Message(object data) { _logSource.LogMessage(data); } internal static void Warning(object data) { _logSource.LogWarning(data); } } internal class SuspiciousTentacleCompatibility { private static bool? _enabled; private static BaseUnityPlugin SuspiciousTentaclePlugin; private static ConfigEntry<bool> EnableSusTentacleCompat; private static Dictionary<string, float> DefaultPartInfluences = new Dictionary<string, float> { { "Belly", 25f } }; protected static Dictionary<string, ConfigEntry<float>> PartInfluences = new Dictionary<string, ConfigEntry<float>>(); public static bool enabled { get { if (!_enabled.HasValue) { _enabled = Chainloader.PluginInfos.ContainsKey("com.RuneFoxMods.SuspiciousTentacle"); } return _enabled.Value; } } private static void FindPluginInstance() { foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos) { BepInPlugin metadata = pluginInfo.Value.Metadata; if (metadata.GUID.Equals("com.RuneFoxMods.SuspiciousTentacle")) { SuspiciousTentaclePlugin = pluginInfo.Value.Instance; break; } } } public static ICollection<string> GetParts() { return PartInfluences.Keys; } public static float GetInfluence(string part) { return PartInfluences[part].Value / 100f; } public static void SetupCompatibility() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown FindPluginInstance(); ConfigFile config = SuspiciousTentaclePlugin.Config; EnableSusTentacleCompat = config.Bind<bool>("BodyBlend", "Enable Compatibility", true, "Enable compatibility with BodyBlend."); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(EnableSusTentacleCompat, new CheckBoxConfig()), "com.RuneFoxMods.SuspiciousTentacle", "SuspiciousTentacle"); foreach (KeyValuePair<string, float> defaultPartInfluence in DefaultPartInfluences) { CreatePartConfig(config, defaultPartInfluence.Key, defaultPartInfluence.Value); } foreach (string bodyBlendPart in BodyBlendPlugin.GetBodyBlendParts()) { if (!PartInfluences.ContainsKey(bodyBlendPart)) { CreatePartConfig(config, bodyBlendPart, 0f); } } } private static void CreatePartConfig(ConfigFile config, string part, float defaultInfluence) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown ConfigEntry<float> val = config.Bind<float>("BodyBlend", part + " Influence", defaultInfluence, "Determine how much \"" + part + "\" will get influenced by Suspicious Tentacle per egg.\n" + $"Default: {defaultInfluence:0}"); SliderConfig val2 = new SliderConfig(); val2.min = 0f; val2.max = 100f; ((BaseOptionConfig)val2).checkIfDisabled = new IsDisabledDelegate(GetSusTentacleBodyBlendDisable); ModSettingsManager.AddOption((BaseOption)new SliderOption(val, val2), "com.RuneFoxMods.SuspiciousTentacle", "SuspiciousTentacle"); PartInfluences[part] = val; } public static void HookGrowthProgress() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown CharacterBody.Update += new hook_Update(UpdateBodyBlend); CharacterBody.OnBuffFinalStackLost += new hook_OnBuffFinalStackLost(ClearBodyBlend); } private static float GetBuffDuration(CharacterBody body, BuffIndex buffIndex) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) List<TimedBuff> timedBuffs = body.timedBuffs; if (timedBuffs == null) { return 0f; } if (timedBuffs.Count > 0) { return timedBuffs.Max((TimedBuff p) => (p.buffIndex == buffIndex) ? p.timer : 0f); } return 0f; } protected static void UpdateBodyBlend(orig_Update orig, CharacterBody body) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) orig.Invoke(body); if (!EnableSusTentacleCompat.Value) { return; } BuffIndex buffIndex = ((SuspiciousTentacle)SuspiciousTentaclePlugin).EggGrowthDebuff.buffIndex; if (!body.HasBuff(buffIndex)) { return; } float num = 0f; if (SuspiciousTentacle.EggGrowthTime.Value > 0f) { num = 1f - GetBuffDuration(body, buffIndex) / SuspiciousTentacle.EggGrowthTime.Value; } float num2 = body.inventory.GetItemCount(SuspiciousTentacle.SusTentacleItemDef); if (num2 < 1f) { num2 = 1f; } BodyBlendController component = ((Component)body.modelLocator.modelTransform).gameObject.GetComponent<BodyBlendController>(); if (!Object.op_Implicit((Object)(object)component)) { return; } foreach (string key in PartInfluences.Keys) { float influence = GetInfluence(key); if (influence > 0.0001f) { component.SetBlendTargetWeight(key, num * influence * num2, "SuspiciousTentacle"); } else { component.RemoveBlendTargetWeight(key, "SuspiciousTentacle"); } } } protected static void ClearBodyBlend(orig_OnBuffFinalStackLost orig, CharacterBody body, BuffDef buffDef) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) orig.Invoke(body, buffDef); if (!EnableSusTentacleCompat.Value) { return; } BodyBlendController component = ((Component)body.modelLocator.modelTransform).gameObject.GetComponent<BodyBlendController>(); if (!Object.op_Implicit((Object)(object)component) || !((Object)(object)buffDef == (Object)(object)((SuspiciousTentacle)SuspiciousTentaclePlugin).EggGrowthDebuff)) { return; } foreach (string key in PartInfluences.Keys) { component.RemoveBlendTargetWeight(key, "SuspiciousTentacle"); } } private static bool GetSusTentacleBodyBlendDisable() { return !EnableSusTentacleCompat.Value; } } } namespace BodyBlend.Utils { public static class BodyBlendUtils { public class DictionaryList<K1, V> : Dictionary<K1, List<V>> { } public class NestedDictionaryList<K1, K2, V> : Dictionary<K1, DictionaryList<K2, V>> { } public class NestedDictionary<K1, K2, V> : Dictionary<K1, Dictionary<K2, V>> { } public class BlendControlTemplate { public int targetRendererIndex = -1; public string targetRendererName = null; public Dictionary<int, AnimationCurve> blendShapeControls = new Dictionary<int, AnimationCurve>(); public List<BoneControlTemplate> boneControls = new List<BoneControlTemplate>(); } public class BoneControlTemplate { public List<string> associatedDynBoneNames = new List<string>(); public AnimationCurve dynBoneInertCurve = null; public AnimationCurve dynBoneElasticityCurve = null; public AnimationCurve dynBoneStiffnessCurve = null; public AnimationCurve dynBoneDampingCurve = null; public DynBoneControlMode dynBoneControlMode = DynBoneControlMode.FULL_CONTROL; } public static NestedDictionaryList<string, string, BlendControlTemplate> RegisteredSkinBlendControls = new NestedDictionaryList<string, string, BlendControlTemplate>(); internal static HashSet<string> PartsList = new HashSet<string>(); private static Dictionary<string, string> SkinNameMapping = new Dictionary<string, string>(); public static void ClearRegister() { RegisteredSkinBlendControls.Clear(); PartsList.Clear(); } public static string MakeSkinDefKey(BBJsonConfig config) { return MakeSkinDefKey(config.skinDefName, config.skinDefToken); } public static string MakeSkinDefKey(string skinDefName = null, string skinDefToken = null) { List<string> list = new List<string>(); if (!string.IsNullOrEmpty(skinDefName)) { list.Add(skinDefName); } if (!string.IsNullOrEmpty(skinDefToken)) { list.Add(skinDefToken); } if (list.Count == 0) { return null; } return string.Join("|", list); } public static string FindSkinDefKey<T>(Dictionary<string, T> dict, SkinDef skinDef) { return FindSkinDefKey(dict, ((Object)skinDef).name, skinDef.nameToken); } public static string FindSkinDefKey<T>(Dictionary<string, T> dict, string skinDefName = null, string skinDefToken = null) { if (skinDefName != null && dict.ContainsKey(skinDefName)) { return skinDefName; } if (skinDefToken != null && dict.ContainsKey(skinDefToken)) { return skinDefToken; } if (dict.ContainsKey(skinDefName + "|" + skinDefToken)) { return skinDefName + "|" + skinDefToken; } return null; } public static string GetSkinName(string skinDefKey) { return SkinNameMapping[skinDefKey]; } public static void RegisterFromJson(BBJsonConfig jsonConfig, SkinDef skinDef) { string text = MakeSkinDefKey(jsonConfig); if (text == null) { return; } if (string.IsNullOrEmpty(jsonConfig.skinName)) { SkinNameMapping[text] = ((Object)skinDef).name; } else { SkinNameMapping[text] = jsonConfig.skinName; } DictionaryList<string, BlendControlTemplate> dictionaryList = jsonConfig.ToTemplates(); foreach (KeyValuePair<string, List<BlendControlTemplate>> item in dictionaryList) { RegisterSkinBlendControl(text, item.Key, item.Value); } } public static void RegisterSkinBlendControl(string skinDefKey, string blendName, List<BlendControlTemplate> templates) { if (!RegisteredSkinBlendControls.ContainsKey(skinDefKey)) { RegisteredSkinBlendControls[skinDefKey] = new DictionaryList<string, BlendControlTemplate>(); } if (!RegisteredSkinBlendControls[skinDefKey].ContainsKey(blendName)) { RegisteredSkinBlendControls[skinDefKey][blendName] = new List<BlendControlTemplate>(); } RegisteredSkinBlendControls[skinDefKey][blendName] = templates; PartsList.Add(blendName); } public static void RegisterSkinBlendControl(string skinDefKey, string blendName, BlendControlTemplate template) { RegisterSkinBlendControl(skinDefKey, blendName, new List<BlendControlTemplate> { template }); } public static TV GetValue<TK, TV>(this IDictionary<TK, TV> dict, TK key, TV defaultValue = default(TV)) { TV value; return dict.TryGetValue(key, out value) ? value : defaultValue; } internal static void ApplyFromRegisteredBlendControls(this BodyBlendController controller, GameObject modelObject, SkinDef skinDef) { if (!Object.op_Implicit((Object)(object)controller)) { return; } CharacterModel component = modelObject.GetComponent<CharacterModel>(); if (!Object.op_Implicit((Object)(object)component)) { return; } string text = FindSkinDefKey(RegisteredSkinBlendControls, skinDef); if (text == null || !RegisteredSkinBlendControls.ContainsKey(text)) { return; } controller.SetSkinDefKey(text); foreach (KeyValuePair<string, List<BlendControlTemplate>> item in RegisteredSkinBlendControls[text]) { controller.ApplyFromTemplates(component, item.Key, item.Value); } } private static void ApplyFromTemplates(this BodyBlendController controller, CharacterModel charModel, string blendName, List<BlendControlTemplate> templates) { foreach (BlendControlTemplate template in templates) { if (template == null || template.targetRendererIndex < 0) { break; } SkinnedMeshRenderer renderer = GetRenderer(charModel, template.targetRendererIndex); if (!Object.op_Implicit((Object)(object)renderer)) { continue; } BodyBlendControl bodyBlendControl = new BodyBlendControl(renderer); bodyBlendControl.blendShapeControls = template.blendShapeControls; if (template.boneControls != null && template.boneControls.Count > 0) { foreach (BoneControlTemplate boneControl in template.boneControls) { List<DynamicBone> bones = FindDynamicBones(charModel, boneControl.associatedDynBoneNames); bodyBlendControl.AddDynBoneControl(bones, boneControl.dynBoneInertCurve, boneControl.dynBoneElasticityCurve, boneControl.dynBoneStiffnessCurve, boneControl.dynBoneDampingCurve, boneControl.dynBoneControlMode); } } controller.AddBlendControl(blendName, bodyBlendControl); } } public static string FindRegisteredSkinControl(SkinDef skinDef) { return FindSkinDefKey(RegisteredSkinBlendControls, skinDef); } public static List<DynamicBone> FindDynamicBones(CharacterModel charModel, params string[] names) { List<DynamicBone> list = new List<DynamicBone>(); foreach (string boneName in names) { DynamicBone val = FindDynamicBone(charModel, boneName); if (Object.op_Implicit((Object)(object)val)) { list.Add(val); } } return list; } public static List<DynamicBone> FindDynamicBones(CharacterModel charModel, List<string> names) { List<DynamicBone> list = new List<DynamicBone>(); foreach (string name in names) { DynamicBone val = FindDynamicBone(charModel, name); if (Object.op_Implicit((Object)(object)val)) { list.Add(val); } } return list; } public static DynamicBone FindDynamicBone(CharacterModel charModel, string boneName) { Transform? obj = ((IEnumerable<Transform>)((Component)charModel).gameObject.GetComponentsInChildren<Transform>()).FirstOrDefault((Func<Transform, bool>)((Transform c) => ((Object)((Component)c).gameObject).name == boneName)); GameObject val = ((obj != null) ? ((Component)obj).gameObject : null); if (Object.op_Implicit((Object)(object)val)) { return val.GetComponent<DynamicBone>(); } return null; } public static SkinnedMeshRenderer GetRenderer(CharacterModel charModel, int index) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown if (index < charModel.baseRendererInfos.Length) { return (SkinnedMeshRenderer)charModel.baseRendererInfos[index].renderer; } return null; } public static AnimationCurve MakeAnimationCurve(params Keyframe[] keyframes) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return new AnimationCurve(keyframes) { postWrapMode = (WrapMode)8, preWrapMode = (WrapMode)8 }; } } }