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 Windstrides Cinematic Female Hair v1.0.5
BepInEx/plugins/CinematicFemaleHair/CinematicFemaleHair.dll
Decompiled a week agousing System; 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 BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using MagicaCloth2; using Newtonsoft.Json; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Windstride")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("A custom ponytail hairstyle for Valheim with native hair physics.")] [assembly: AssemblyFileVersion("1.0.5.0")] [assembly: AssemblyInformationalVersion("1.0.5")] [assembly: AssemblyProduct("Windstride's Cinematic Female Hair")] [assembly: AssemblyTitle("CinematicFemaleHair")] [assembly: AssemblyVersion("1.0.5.0")] namespace CinematicFemaleHair; public sealed class HairSimulation : MonoBehaviour { public void Configure(VisEquipment equipment) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Expected O, but got Unknown //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Expected O, but got Unknown //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Expected O, but got Unknown //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_030d: Expected O, but got Unknown //IL_034f: Unknown result type (might be due to invalid IL or missing references) //IL_0359: Expected O, but got Unknown //IL_03b3: Unknown result type (might be due to invalid IL or missing references) //IL_03bd: Expected O, but got Unknown //IL_03c4: Unknown result type (might be due to invalid IL or missing references) List<ColliderComponent> list = new List<ColliderComponent>(); if (equipment.m_clothColliders != null) { list.AddRange(equipment.m_clothColliders.Where((ColliderComponent c) => Object.op_Implicit((Object)(object)c))); } HairCollider[] colliders = Plugin.Asset.Colliders; foreach (HairCollider hairCollider in colliders) { GameObject val = new GameObject("CH_Collision_" + hairCollider.Name); val.transform.SetParent(((Component)this).transform, false); val.transform.localPosition = new Vector3(hairCollider.Center[0], hairCollider.Center[1], hairCollider.Center[2]); MagicaCapsuleCollider val2 = val.AddComponent<MagicaCapsuleCollider>(); val2.direction = (Direction)1; val2.alignedOnCenter = true; val2.SetSize(hairCollider.Radius, hairCollider.Radius, hairCollider.Height); list.Add((ColliderComponent)(object)val2); } Player component = ((Component)equipment).GetComponent<Player>(); int completed = 0; int expected = Plugin.Asset.Parts.Count((HairPart p) => p.Simulated && Plugin.PhysicsEnabled.Value); HairPart[] parts = Plugin.Asset.Parts; foreach (HairPart part in parts) { MeshRenderer component2 = ((Component)((Component)this).transform.Find(part.Name)).GetComponent<MeshRenderer>(); if (!part.Simulated || !Plugin.PhysicsEnabled.Value) { continue; } GameObject val3 = new GameObject(part.Name + "_Cloth"); val3.transform.SetParent(((Component)this).transform, false); MagicaCloth val4 = val3.AddComponent<MagicaCloth>(); ClothSerializeData serializeData = val4.SerializeData; serializeData.Import(Plugin.Donor.SerializeData, false); serializeData.clothType = (ClothType)0; serializeData.sourceRenderers.Clear(); serializeData.sourceRenderers.Add((Renderer)(object)component2); serializeData.paintMode = (PaintMode)0; serializeData.paintMaps.Clear(); VertexAttribute[] item = part.Attributes.Select((int a) => (a != 0) ? VertexAttribute.Move : VertexAttribute.Fixed).ToArray(); ClothSerializeData2 serializeData2 = val4.GetSerializeData2(); serializeData2.vertexAttributeList.Clear(); serializeData2.vertexAttributeList.Add(item); serializeData.reductionSetting.simpleDistance = 0f; serializeData.reductionSetting.shapeDistance = 0f; serializeData.radius = new CurveSerializeData(0.0035f); serializeData.damping = new CurveSerializeData(0.14f); serializeData.angleRestorationConstraint.useAngleRestoration = true; serializeData.angleRestorationConstraint.stiffness = new CurveSerializeData(1f, MakeCurve(part, (float s) => Mathf.Lerp(0.38f, 0.045f, s))); serializeData.angleLimitConstraint.useAngleLimit = true; serializeData.angleLimitConstraint.limitAngle = new CurveSerializeData(1f, MakeCurve(part, (float s) => Mathf.Lerp(2f, 48f, s))); serializeData.motionConstraint.useMaxDistance = true; serializeData.motionConstraint.maxDistance = new CurveSerializeData(part.Length * 0.55f * Plugin.MotionScale.Value, MakeCurve(part, (float s) => s)); serializeData.colliderCollisionConstraint.mode = (Mode)1; serializeData.colliderCollisionConstraint.colliderList = list; val4.Initialize(); val4.DisableAutoBuild(); if (Object.op_Implicit((Object)(object)component)) { val3.AddComponent<PlayerClothWindShelter>().SetPlayer(component); } val4.OnBuildComplete = (Action<MagicaCloth, bool>)Delegate.Combine(val4.OnBuildComplete, (Action<MagicaCloth, bool>)delegate(MagicaCloth val5, bool success) { //IL_0006: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) ResultCode result = val5.Process.Result; if (!success && ((ResultCode)(ref result)).IsError()) { Plugin.Error("Hair physics build failed for " + part.Name + ": " + ((object)((ResultCode)(ref result)).Result/*cast due to .constrained prefix*/).ToString() + " " + ((ResultCode)(ref result)).GetResultInformation()); } if (success) { int num2 = completed + 1; completed = num2; if (num2 == expected) { Plugin.LogInfo("Hair physics ready: " + completed + " regions."); } } }); if (!val4.BuildAndRun()) { throw new InvalidOperationException("Build did not start: " + part.Name); } } Plugin.Debug("Attached Windstride's Cinematic Female Hair."); } private static AnimationCurve MakeCurve(HairPart part, Func<float, float> convert) { //IL_002b: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown Keyframe[] array = (Keyframe[])(object)new Keyframe[part.FlexCurve.Length]; for (int i = 0; i < array.Length; i++) { array[i] = new Keyframe((float)i / (float)(array.Length - 1), convert(part.FlexCurve[i])); } return new AnimationCurve(array); } } [BepInPlugin("brunoluccas.valheim.cinematichair", "Windstride's Cinematic Female Hair", "1.0.5")] [BepInDependency("com.jotunn.jotunn", "2.30.1")] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { [HarmonyPatch(typeof(VisEquipment), "SetHairEquipped")] private static class AttachPhysics { private static void Postfix(VisEquipment __instance, int __0, bool __result, GameObject ___m_hairItemInstance) { if (!__result || __0 != StringExtensionMethods.GetStableHashCode("HairCinematicPonytail") || !Object.op_Implicit((Object)(object)___m_hairItemInstance) || Object.op_Implicit((Object)(object)___m_hairItemInstance.GetComponent<HairSimulation>())) { return; } try { ___m_hairItemInstance.AddComponent<HairSimulation>().Configure(__instance); } catch (Exception ex) { ((BaseUnityPlugin)Instance).Logger.LogError((object)("Custom hair simulation failed: " + ex)); } } } public const string Guid = "brunoluccas.valheim.cinematichair"; public const string HairName = "HairCinematicPonytail"; internal static Plugin Instance; internal static HairAsset Asset; internal static MagicaCloth Donor; internal static ConfigEntry<bool> PhysicsEnabled; internal static ConfigEntry<float> MotionScale; internal static string ModDirectory; private Harmony harmony; private bool registered; private void Awake() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown Instance = this; if ((int)SystemInfo.graphicsDeviceType == 4) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Windstride's Cinematic Female Hair is a client visual mod; skipping the dedicated server."); return; } ModDirectory = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); PhysicsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Simulation", "Enabled", true, "Use the game's MagicaCloth hair simulation."); MotionScale = ((BaseUnityPlugin)this).Config.Bind<float>("Simulation", "MotionScale", 1f, new ConfigDescription("Overall motion multiplier; 1 follows the authored reference.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f), Array.Empty<object>())); Asset = JsonConvert.DeserializeObject<HairAsset>(File.ReadAllText(Path.Combine(ModDirectory, "assets", "Hair_Mesh.json"))); if (Asset == null || Asset.Parts == null || Asset.Parts.Length != 8) { throw new InvalidDataException("Hair_Mesh.json is missing or invalid."); } PrefabManager.OnVanillaPrefabsAvailable += Register; harmony = new Harmony("brunoluccas.valheim.cinematichair"); harmony.PatchAll(typeof(Plugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Windstride's Cinematic Female Hair ready."); } private void Register() { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Expected O, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Expected O, but got Unknown //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Expected O, but got Unknown if (registered) { return; } try { GameObject prefab = PrefabManager.Instance.GetPrefab("Hair2"); if (!Object.op_Implicit((Object)(object)prefab)) { throw new InvalidOperationException("Native Hair2 is not loaded."); } Donor = prefab.GetComponentInChildren<MagicaCloth>(true); if (!Object.op_Implicit((Object)(object)Donor)) { throw new InvalidOperationException("Native MeshCloth donor missing."); } Material val = new Material((from r in prefab.GetComponentsInChildren<Renderer>(true) select r.sharedMaterial).First((Material m) => Object.op_Implicit((Object)(object)m) && m.HasProperty("_SkinBumpMap"))) { name = "CinematicFemaleHair_PlayerHair" }; val.SetTexture("_MainTex", (Texture)(object)LoadTexture("Hair_Color.png", linear: false)); val.SetTexture("_SkinBumpMap", (Texture)(object)LoadPackedNormal()); CustomItem val2 = new CustomItem("HairCinematicPonytail", "Hair2"); GameObject itemPrefab = val2.ItemPrefab; if (!Object.op_Implicit((Object)(object)itemPrefab)) { throw new InvalidOperationException("Could not clone customization item."); } Transform val3 = itemPrefab.transform.Find("attach"); if (Object.op_Implicit((Object)(object)val3)) { Object.DestroyImmediate((Object)(object)((Component)val3).gameObject); } GameObject val4 = new GameObject("attach"); val4.transform.SetParent(itemPrefab.transform, false); HairPart[] parts = Asset.Parts; foreach (HairPart hairPart in parts) { GameObject val5 = new GameObject(hairPart.Name); val5.transform.SetParent(val4.transform, false); val5.AddComponent<MeshFilter>().sharedMesh = CreateMesh(hairPart); MeshRenderer obj = val5.AddComponent<MeshRenderer>(); ((Renderer)obj).sharedMaterial = val; ((Renderer)obj).shadowCastingMode = (ShadowCastingMode)1; ((Renderer)obj).receiveShadows = true; } SharedData shared = val2.ItemDrop.m_itemData.m_shared; shared.m_name = "$hair_cinematic_ponytail"; shared.m_description = "$hair_cinematic_ponytail_description"; shared.m_toolTier = 0; shared.m_helmetHairSettings = new List<HelmetHairSettings>(); CustomLocalization val6 = new CustomLocalization(((BaseUnityPlugin)this).Info.Metadata); string text = "English"; val6.AddTranslation(ref text, new Dictionary<string, string> { { "hair_cinematic_ponytail", "Half up Ponytail" }, { "hair_cinematic_ponytail_description", "Swept hair with loose strands and a short ponytail." } }); LocalizationManager.Instance.AddLocalization(val6); if (!ItemManager.Instance.AddItem(val2)) { throw new InvalidOperationException("Jotunn rejected the hairstyle."); } registered = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Registered Windstride's Cinematic Female Hair."); PrefabManager.OnVanillaPrefabsAvailable -= Register; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Hair registration failed: " + ex)); } } private static Mesh CreateMesh(HairPart part) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) Mesh val = new Mesh { name = part.Name }; val.vertices = Vectors(part.Vertices); val.normals = Vectors(part.Normals); Vector2[] array = (Vector2[])(object)new Vector2[part.Uv.Length / 2]; for (int i = 0; i < array.Length; i++) { array[i] = new Vector2(part.Uv[i * 2], part.Uv[i * 2 + 1]); } val.uv = array; val.triangles = part.Triangles; val.RecalculateTangents(); val.RecalculateBounds(); return val; } private static Vector3[] Vectors(float[] values) { //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) Vector3[] array = (Vector3[])(object)new Vector3[values.Length / 3]; for (int i = 0; i < array.Length; i++) { array[i] = new Vector3(values[i * 3], values[i * 3 + 1], values[i * 3 + 2]); } return array; } private static Texture2D LoadTexture(string filename, bool linear) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear) { name = filename, wrapMode = (TextureWrapMode)0, filterMode = (FilterMode)0, anisoLevel = 1 }; if (!ImageConversion.LoadImage(val, File.ReadAllBytes(Path.Combine(ModDirectory, "assets", filename)), false)) { throw new InvalidDataException(filename); } if (((Texture)val).width != ((Texture)val).height || (((Texture)val).width != 64 && ((Texture)val).width != 128)) { throw new InvalidDataException(filename + " must be 64x64 or 128x128."); } val.Apply(true, false); return val; } private static Texture2D LoadPackedNormal() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) Texture2D val = LoadTexture("Hair_Normal.png", linear: true); Color32[] pixels = val.GetPixels32(); for (int i = 0; i < pixels.Length; i++) { pixels[i] = new Color32(byte.MaxValue, pixels[i].g, pixels[i].b, pixels[i].r); } val.SetPixels32(pixels); val.Apply(true, false); ((Object)val).name = "CinematicHair_Normal_AG"; return val; } internal static void Debug(string message) { ((BaseUnityPlugin)Instance).Logger.LogDebug((object)message); } internal static void LogInfo(string message) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)message); } internal static void Error(string message) { ((BaseUnityPlugin)Instance).Logger.LogError((object)message); } private void OnDestroy() { PrefabManager.OnVanillaPrefabsAvailable -= Register; Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } } [Serializable] public sealed class HairAsset { public string Name; public HairPart[] Parts; public HairCollider[] Colliders; } [Serializable] public sealed class HairPart { public string Name; public float[] Vertices; public float[] Normals; public float[] Uv; public float[] FlexCurve; public int[] Triangles; public int[] Attributes; public float Length; public bool Simulated; } [Serializable] public sealed class HairCollider { public string Name; public float[] Center; public float Radius; public float Height; }