// Consolidated decompiled source — Wubarrk-Wings_of_the_Valkyrie v1.1.2 // Generated by Hexium's decompiled-source browser. Best-effort concatenation of every type in this // version's manifest — decompiler output isn't guaranteed to compile as-is. using System; using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis; using HarmonyLib; using Jotunn; using UnityEngine; using WingsoftheValkyrie.VFX; using BepInEx.Configuration; using System.Collections.Generic; using System.Linq; using System.Reflection; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using BepInEx; using Jotunn.Utils; // ---- WingsoftheValkyrie/plugins/WingsoftheValkyrie.dll :: Microsoft.CodeAnalysis.EmbeddedAttribute ---- namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } // ---- WingsoftheValkyrie/plugins/WingsoftheValkyrie.dll :: System.Runtime.CompilerServices.RefSafetyRulesAttribute ---- namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } // ---- WingsoftheValkyrie/plugins/WingsoftheValkyrie.dll :: WingsoftheValkyrie.FlightController ---- namespace WingsoftheValkyrie { [HarmonyPatch(typeof(Player))] public static class FlightController { [HarmonyPatch("Update")] [HarmonyPostfix] public static void UpdatePostfix(Player __instance) { if (!ModConfig.EnableMod.Value) { return; } try { RuneWingVFX runeWingVFX = __instance.GetComponent(); if (runeWingVFX == null) { runeWingVFX = __instance.gameObject.AddComponent(); } string equippedWingsName = WingsItem.GetEquippedWingsName(__instance); if (equippedWingsName != null) { switch (equippedWingsName) { case "WingsOf_Crude": runeWingVFX.SetTierColor(Color.green); break; case "WingsOf_Troll": runeWingVFX.SetTierColor(Color.cyan); break; case "WingsOf_Lox": runeWingVFX.SetTierColor(new Color(0.8f, 0.8f, 1f)); break; case "WingsOf_Dragon": runeWingVFX.SetTierColor(new Color(0.8f, 0.1f, 1f)); break; } if (__instance == Player.m_localPlayer) { if (!__instance.IsOnGround() && !__instance.IsSwimming() && !__instance.InWater()) { if (ZInput.GetButtonDown("Jump")) { float num = 10f; switch (equippedWingsName) { case "WingsOf_Crude": num = ModConfig.CrudeFlapStaminaCost.Value; break; case "WingsOf_Troll": num = ModConfig.TrollFlapStaminaCost.Value; break; case "WingsOf_Lox": num = ModConfig.LoxFlapStaminaCost.Value; break; case "WingsOf_Dragon": num = ModConfig.DragonFlapStaminaCost.Value; break; } if (__instance.HaveStamina(num)) { __instance.UseStamina(num); runeWingVFX.TriggerFlap(); runeWingVFX.WantsToFlap = true; } else { __instance.Message(MessageHud.MessageType.Center, "Not enough stamina to flap!"); } } if (!runeWingVFX.IsGlidingLocal && (runeWingVFX.WantsToFlap || __instance.GetVelocity().y < -5f)) { runeWingVFX.IsGlidingLocal = true; } if (runeWingVFX.IsGlidingLocal) { Traverse.Create(__instance).Field("m_maxAirAltitude").SetValue(__instance.transform.position.y); } } else { runeWingVFX.IsGlidingLocal = false; } } else if (!__instance.IsOnGround() && !__instance.IsSwimming() && !__instance.InWater()) { if (__instance.GetVelocity().y < -2f || __instance.GetVelocity().y > 2f) { runeWingVFX.IsGlidingLocal = true; } } else { runeWingVFX.IsGlidingLocal = false; } } else { runeWingVFX.IsGlidingLocal = false; } runeWingVFX.SetGlidingState(runeWingVFX.IsGlidingLocal); } catch (Exception ex) { Logger.LogWarning((object)("[Wings of the Valkyrie] Error in UpdatePostfix for " + __instance?.GetPlayerName() + ": " + ex.Message)); } } [HarmonyPatch("FixedUpdate")] [HarmonyPostfix] public static void FixedUpdatePostfix(Player __instance) { if (__instance != Player.m_localPlayer || !ModConfig.EnableMod.Value) { return; } try { RuneWingVFX component = __instance.GetComponent(); if (component == null || !component.IsGlidingLocal || __instance.IsOnGround() || __instance.IsSwimming() || __instance.InWater()) { return; } Rigidbody component2 = __instance.GetComponent(); if (!(component2 != null)) { return; } float num = 15f; float num2 = 50f; float y = 12f; string equippedWingsName = WingsItem.GetEquippedWingsName(__instance); switch (equippedWingsName) { case "WingsOf_Crude": num = ModConfig.CrudeGlideSpeed.Value; num2 = ModConfig.CrudeFlightCeiling.Value; y = ModConfig.CrudeFlapForce.Value; break; case "WingsOf_Troll": num = ModConfig.TrollGlideSpeed.Value; num2 = ModConfig.TrollFlightCeiling.Value; y = ModConfig.TrollFlapForce.Value; break; case "WingsOf_Lox": num = ModConfig.LoxGlideSpeed.Value; num2 = ModConfig.LoxFlightCeiling.Value; y = ModConfig.LoxFlapForce.Value; break; case "WingsOf_Dragon": num = ModConfig.DragonGlideSpeed.Value; num2 = ModConfig.DragonFlightCeiling.Value; y = ModConfig.DragonFlapForce.Value; break; } if (component.WantsToFlap) { component2.velocity = new Vector3(component2.velocity.x, y, component2.velocity.z); component.WantsToFlap = false; } else { Vector3 lookDir = __instance.GetLookDir(); float num3 = -2f; if (lookDir.y < 0f) { num3 = Mathf.Lerp(-2f, -20f, 0f - lookDir.y); } if (component2.velocity.y < num3) { component2.velocity = new Vector3(component2.velocity.x, num3, component2.velocity.z); } } Vector3 value = Traverse.Create(__instance).Field("m_moveDir").GetValue(); if (value.magnitude > 0.1f) { Vector3 b = value * num; b.y = component2.velocity.y; component2.velocity = Vector3.Lerp(component2.velocity, b, 3f * Time.fixedDeltaTime); } if (ZoneSystem.instance != null) { float groundHeight = ZoneSystem.instance.GetGroundHeight(__instance.transform.position); float num4 = 50f; switch (equippedWingsName) { case "WingsOf_Crude": num4 = ModConfig.CrudeFlightCeiling.Value; break; case "WingsOf_Troll": num4 = ModConfig.TrollFlightCeiling.Value; break; case "WingsOf_Lox": num4 = ModConfig.LoxFlightCeiling.Value; break; case "WingsOf_Dragon": num4 = ModConfig.DragonFlightCeiling.Value; break; } if (__instance.transform.position.y - groundHeight > num4 && component2.velocity.y > 0f) { component2.velocity = new Vector3(component2.velocity.x, 0f, component2.velocity.z); } } } catch (Exception ex) { Logger.LogWarning((object)("[Wings of the Valkyrie] Error in FixedUpdatePostfix for " + __instance?.GetPlayerName() + ": " + ex.Message)); } } } } // ---- WingsoftheValkyrie/plugins/WingsoftheValkyrie.dll :: WingsoftheValkyrie.ModConfig ---- namespace WingsoftheValkyrie { public static class ModConfig { public static ConfigEntry EnableMod { get; private set; } public static ConfigEntry GlobalWingSpan { get; private set; } public static ConfigEntry CrudeFlightCeiling { get; private set; } public static ConfigEntry CrudeGlideSpeed { get; private set; } public static ConfigEntry CrudeFlapForce { get; private set; } public static ConfigEntry CrudeFlapStaminaCost { get; private set; } public static ConfigEntry CrudeCraftingStation { get; private set; } public static ConfigEntry CrudeMinStationLevel { get; private set; } public static ConfigEntry CrudeCraftingRequirements { get; private set; } public static ConfigEntry TrollFlightCeiling { get; private set; } public static ConfigEntry TrollGlideSpeed { get; private set; } public static ConfigEntry TrollFlapForce { get; private set; } public static ConfigEntry TrollFlapStaminaCost { get; private set; } public static ConfigEntry TrollCraftingStation { get; private set; } public static ConfigEntry TrollMinStationLevel { get; private set; } public static ConfigEntry TrollCraftingRequirements { get; private set; } public static ConfigEntry LoxFlightCeiling { get; private set; } public static ConfigEntry LoxGlideSpeed { get; private set; } public static ConfigEntry LoxFlapForce { get; private set; } public static ConfigEntry LoxFlapStaminaCost { get; private set; } public static ConfigEntry LoxCraftingStation { get; private set; } public static ConfigEntry LoxMinStationLevel { get; private set; } public static ConfigEntry LoxCraftingRequirements { get; private set; } public static ConfigEntry DragonFlightCeiling { get; private set; } public static ConfigEntry DragonGlideSpeed { get; private set; } public static ConfigEntry DragonFlapForce { get; private set; } public static ConfigEntry DragonFlapStaminaCost { get; private set; } public static ConfigEntry DragonCraftingStation { get; private set; } public static ConfigEntry DragonMinStationLevel { get; private set; } public static ConfigEntry DragonCraftingRequirements { get; private set; } public static void Init(ConfigFile config) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown ConfigurationManagerAttributes val = new ConfigurationManagerAttributes { IsAdminOnly = true }; AcceptableValueRange acceptableValues = new AcceptableValueRange(10f, 5000f); AcceptableValueRange acceptableValues2 = new AcceptableValueRange(1f, 100f); AcceptableValueRange acceptableValues3 = new AcceptableValueRange(1f, 100f); AcceptableValueRange acceptableValues4 = new AcceptableValueRange(0f, 100f); AcceptableValueRange acceptableValues5 = new AcceptableValueRange(1, 10); EnableMod = config.Bind("1. General", "EnableMod", defaultValue: true, new ConfigDescription("Enable or disable the Valkyrie Wings mod.", null, val)); GlobalWingSpan = config.Bind("1. General", "GlobalWingSpan", 1f, new ConfigDescription("Multiplier for the overall size of the wings.", new AcceptableValueRange(0.1f, 5f), val)); CrudeFlightCeiling = config.Bind("2. Crude Wings", "FlightCeiling", 120f, new ConfigDescription("Flight ceiling limit above ground.", acceptableValues, val)); CrudeGlideSpeed = config.Bind("2. Crude Wings", "GlideSpeed", 10f, new ConfigDescription("Horizontal glide speed.", acceptableValues2, val)); CrudeFlapForce = config.Bind("2. Crude Wings", "FlapForce", 15f, new ConfigDescription("Upward lift force when flapping.", acceptableValues3, val)); CrudeFlapStaminaCost = config.Bind("2. Crude Wings", "FlapStaminaCost", 10f, new ConfigDescription("Stamina consumed per flap.", acceptableValues4, val)); CrudeCraftingStation = config.Bind("2. Crude Wings", "CraftingStation", "piece_workbench", new ConfigDescription("Prefab name of the crafting station.", null, val)); CrudeMinStationLevel = config.Bind("2. Crude Wings", "MinStationLevel", 1, new ConfigDescription("Minimum station level required.", acceptableValues5, val)); CrudeCraftingRequirements = config.Bind("2. Crude Wings", "CraftingRequirements", "Feathers:10,LeatherScraps:10", new ConfigDescription("Required items. Format: ItemName:Amount,ItemName:Amount", null, val)); TrollFlightCeiling = config.Bind("3. Troll Wings", "FlightCeiling", 135f, new ConfigDescription("Flight ceiling limit above ground.", acceptableValues, val)); TrollGlideSpeed = config.Bind("3. Troll Wings", "GlideSpeed", 15f, new ConfigDescription("Horizontal glide speed.", acceptableValues2, val)); TrollFlapForce = config.Bind("3. Troll Wings", "FlapForce", 18f, new ConfigDescription("Upward lift force when flapping.", acceptableValues3, val)); TrollFlapStaminaCost = config.Bind("3. Troll Wings", "FlapStaminaCost", 8f, new ConfigDescription("Stamina consumed per flap.", acceptableValues4, val)); TrollCraftingStation = config.Bind("3. Troll Wings", "CraftingStation", "piece_workbench", new ConfigDescription("Prefab name of the crafting station.", null, val)); TrollMinStationLevel = config.Bind("3. Troll Wings", "MinStationLevel", 2, new ConfigDescription("Minimum station level required.", acceptableValues5, val)); TrollCraftingRequirements = config.Bind("3. Troll Wings", "CraftingRequirements", "TrollHide:5,Feathers:15", new ConfigDescription("Required items.", null, val)); LoxFlightCeiling = config.Bind("4. Lox Wings", "FlightCeiling", 160f, new ConfigDescription("Flight ceiling limit above ground.", acceptableValues, val)); LoxGlideSpeed = config.Bind("4. Lox Wings", "GlideSpeed", 20f, new ConfigDescription("Horizontal glide speed.", acceptableValues2, val)); LoxFlapForce = config.Bind("4. Lox Wings", "FlapForce", 22f, new ConfigDescription("Upward lift force when flapping.", acceptableValues3, val)); LoxFlapStaminaCost = config.Bind("4. Lox Wings", "FlapStaminaCost", 6f, new ConfigDescription("Stamina consumed per flap.", acceptableValues4, val)); LoxCraftingStation = config.Bind("4. Lox Wings", "CraftingStation", "forge", new ConfigDescription("Prefab name of the crafting station.", null, val)); LoxMinStationLevel = config.Bind("4. Lox Wings", "MinStationLevel", 1, new ConfigDescription("Minimum station level required.", acceptableValues5, val)); LoxCraftingRequirements = config.Bind("4. Lox Wings", "CraftingRequirements", "LoxPelt:5,Silver:5", new ConfigDescription("Required items.", null, val)); DragonFlightCeiling = config.Bind("5. Dragon Wings", "FlightCeiling", 1100f, new ConfigDescription("Flight ceiling limit above ground.", acceptableValues, val)); DragonGlideSpeed = config.Bind("5. Dragon Wings", "GlideSpeed", 30f, new ConfigDescription("Horizontal glide speed.", acceptableValues2, val)); DragonFlapForce = config.Bind("5. Dragon Wings", "FlapForce", 28f, new ConfigDescription("Upward lift force when flapping.", acceptableValues3, val)); DragonFlapStaminaCost = config.Bind("5. Dragon Wings", "FlapStaminaCost", 4f, new ConfigDescription("Stamina consumed per flap.", acceptableValues4, val)); DragonCraftingStation = config.Bind("5. Dragon Wings", "CraftingStation", "piece_magetable", new ConfigDescription("Prefab name of the crafting station.", null, val)); DragonMinStationLevel = config.Bind("5. Dragon Wings", "MinStationLevel", 1, new ConfigDescription("Minimum station level required.", acceptableValues5, val)); DragonCraftingRequirements = config.Bind("5. Dragon Wings", "CraftingRequirements", "Feathers:20,Eitr:5", new ConfigDescription("Required items.", null, val)); } } } // ---- WingsoftheValkyrie/plugins/WingsoftheValkyrie.dll :: WingsoftheValkyrie.WingsItem ---- namespace WingsoftheValkyrie { public static class WingsItem { public static void Init() { PrefabManager.OnVanillaPrefabsAvailable += CreateCustomWings; } private static void CreateCustomWings() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Expected O, but got Unknown //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Expected O, but got Unknown //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Expected O, but got Unknown //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Expected O, but got Unknown CustomItem val = new CustomItem("WingsOf_Crude", "CapeDeerHide", new ItemConfig { Name = "Wings of the Valkyrie (Crude)", Description = "Basic crafted wings. Low flight ceiling.", CraftingStation = ModConfig.CrudeCraftingStation.Value, MinStationLevel = ModConfig.CrudeMinStationLevel.Value, Requirements = ParseRequirements(ModConfig.CrudeCraftingRequirements.Value) }); StripCapeVisuals(val.ItemPrefab); ItemManager.Instance.AddItem(val); CustomItem val2 = new CustomItem("WingsOf_Troll", "CapeTrollHide", new ItemConfig { Name = "Wings of the Valkyrie (Troll)", Description = "Improved glide and lift.", CraftingStation = ModConfig.TrollCraftingStation.Value, MinStationLevel = ModConfig.TrollMinStationLevel.Value, Requirements = ParseRequirements(ModConfig.TrollCraftingRequirements.Value) }); StripCapeVisuals(val2.ItemPrefab); ItemManager.Instance.AddItem(val2); CustomItem val3 = new CustomItem("WingsOf_Lox", "CapeLox", new ItemConfig { Name = "Wings of the Valkyrie (Lox)", Description = "High glide speed, strong lift.", CraftingStation = ModConfig.LoxCraftingStation.Value, MinStationLevel = ModConfig.LoxMinStationLevel.Value, Requirements = ParseRequirements(ModConfig.LoxCraftingRequirements.Value) }); StripCapeVisuals(val3.ItemPrefab); ItemManager.Instance.AddItem(val3); CustomItem val4 = new CustomItem("WingsOf_Dragon", "CapeFeather", new ItemConfig { Name = "Wings of the Valkyrie (Dragon)", Description = "Unlimited sky ceiling and excellent speed.", CraftingStation = ModConfig.DragonCraftingStation.Value, MinStationLevel = ModConfig.DragonMinStationLevel.Value, Requirements = ParseRequirements(ModConfig.DragonCraftingRequirements.Value) }); StripCapeVisuals(val4.ItemPrefab); ItemManager.Instance.AddItem(val4); PrefabManager.OnVanillaPrefabsAvailable -= CreateCustomWings; } private static void StripCapeVisuals(GameObject prefab) { if (prefab == null) { return; } ItemDrop component = prefab.GetComponent(); if (component != null && component.m_itemData != null && component.m_itemData.m_shared != null) { component.m_itemData.m_shared.m_armorMaterial = null; component.m_itemData.m_shared.m_equipStatusEffect = null; } Component[] componentsInChildren = prefab.GetComponentsInChildren(includeInactive: true); Component[] array = componentsInChildren; foreach (Component component2 in array) { if (component2 != null && component2.GetType().Name == "Cloth") { PropertyInfo property = component2.GetType().GetProperty("enabled"); if (property != null) { property.SetValue(component2, false, null); } } } SkinnedMeshRenderer[] componentsInChildren2 = prefab.GetComponentsInChildren(includeInactive: true); SkinnedMeshRenderer[] array2 = componentsInChildren2; foreach (SkinnedMeshRenderer skinnedMeshRenderer in array2) { skinnedMeshRenderer.forceRenderingOff = true; } MeshRenderer[] componentsInChildren3 = prefab.GetComponentsInChildren(includeInactive: true); MeshRenderer[] array3 = componentsInChildren3; foreach (MeshRenderer meshRenderer in array3) { meshRenderer.forceRenderingOff = true; } } private static RequirementConfig[] ParseRequirements(string requirementsString) { if (string.IsNullOrWhiteSpace(requirementsString)) { return (RequirementConfig[])(object)new RequirementConfig[0]; } return (from r in ((IEnumerable)requirementsString.Split(new char[1] { ',' })).Select((Func)delegate(string req) { //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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown string[] array = req.Split(new char[1] { ':' }); int result; return (array.Length == 2 && int.TryParse(array[1], out result)) ? new RequirementConfig { Item = array[0].Trim(), Amount = result } : ((RequirementConfig)null); }) where r != null select r).ToArray(); } public static string GetEquippedWingsName(Player player) { if (player == null) { return null; } ItemDrop.ItemData value = Traverse.Create(player).Field("m_shoulderItem").GetValue(); if (value != null && value.m_dropPrefab != null) { string name = value.m_dropPrefab.name; switch (name) { default: if (!(name == "WingsOf_Dragon")) { break; } goto case "WingsOf_Crude"; case "WingsOf_Crude": case "WingsOf_Troll": case "WingsOf_Lox": return name; } } VisEquipment component = player.GetComponent(); if (component != null) { string value2 = Traverse.Create(component).Field("m_shoulderItem").GetValue(); if (!string.IsNullOrEmpty(value2)) { switch (value2) { case "WingsOf_Crude": return "WingsOf_Crude"; case "WingsOf_Troll": return "WingsOf_Troll"; case "WingsOf_Lox": return "WingsOf_Lox"; case "WingsOf_Dragon": return "WingsOf_Dragon"; } } } return null; } public static bool IsWingsEquipped(Player player) { return GetEquippedWingsName(player) != null; } } } // ---- WingsoftheValkyrie/plugins/WingsoftheValkyrie.dll :: WingsoftheValkyrie.WingsoftheValkyriePlugin ---- namespace WingsoftheValkyrie { [BepInPlugin("wubarrk.wingsofthevalkyrie", "Wings of the Valkyrie", "1.1.2")] [BepInDependency("com.jotunn.jotunn", BepInDependency.DependencyFlags.HardDependency)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class WingsoftheValkyriePlugin : BaseUnityPlugin { public const string PluginGUID = "wubarrk.wingsofthevalkyrie"; public const string PluginName = "Wings of the Valkyrie"; public const string PluginVersion = "1.1.2"; private readonly Harmony harmony = new Harmony("wubarrk.wingsofthevalkyrie"); private void Awake() { Logger.LogInfo((object)"Wings of the Valkyrie initializing..."); ModConfig.Init(base.Config); WingsItem.Init(); harmony.PatchAll(); Logger.LogInfo((object)"Wings of the Valkyrie has loaded!"); } } } // ---- WingsoftheValkyrie/plugins/WingsoftheValkyrie.dll :: WingsoftheValkyrie.VFX.RuneWingVFX ---- namespace WingsoftheValkyrie.VFX { public class RuneWingVFX : MonoBehaviour { private Player _player; private ParticleSystem _leftWing; private ParticleSystem _rightWing; private Transform _leftRoot; private Transform _rightRoot; private LineRenderer[] _leftLines = new LineRenderer[7]; private LineRenderer[] _rightLines = new LineRenderer[7]; private MeshFilter _leftMeshFilter; private MeshFilter _rightMeshFilter; private Mesh _leftMesh; private Mesh _rightMesh; private bool _isGliding = false; private float _flapTimer = 0f; private Color _currentTierColor = Color.clear; private Vector3 _lastEmitPosL; private Vector3 _lastEmitPosR; public bool IsGlidingLocal = false; public bool WantsToFlap = false; private Color[] _whiteColors; private void Awake() { _player = GetComponent(); } public void EnsureEmitters() { if (!(_leftWing != null) || !(_rightWing != null)) { Transform parent = _player.transform; Texture2D runeTex = ValkyrieRuneTextureGenerator.GenerateSoftTrail(Color.white); Material orCreateRuneMaterial = ValkyrieRuneVFX_Helper.GetOrCreateRuneMaterial(runeTex, Color.white); Texture2D runeTex2 = ValkyrieRuneTextureGenerator.GenerateRuneAtlas(Color.white); Material orCreateRuneMaterial2 = ValkyrieRuneVFX_Helper.GetOrCreateRuneMaterial(runeTex2, Color.white); _leftRoot = new GameObject("RuneWing_Left").transform; _leftRoot.gameObject.layer = _player.gameObject.layer; _leftRoot.SetParent(parent, worldPositionStays: false); _leftRoot.localPosition = new Vector3(-0.3f, 1.2f, -0.3f); _rightRoot = new GameObject("RuneWing_Right").transform; _rightRoot.gameObject.layer = _player.gameObject.layer; _rightRoot.SetParent(parent, worldPositionStays: false); _rightRoot.localPosition = new Vector3(0.3f, 1.2f, -0.3f); InitWingObjects(_leftRoot.gameObject, orCreateRuneMaterial, orCreateRuneMaterial2, isRight: false, ref _leftLines, out _leftMeshFilter, out _leftMesh); InitWingObjects(_rightRoot.gameObject, orCreateRuneMaterial, orCreateRuneMaterial2, isRight: true, ref _rightLines, out _rightMeshFilter, out _rightMesh); _leftWing = CreateParticleSystem(_leftRoot.gameObject, orCreateRuneMaterial2); _rightWing = CreateParticleSystem(_rightRoot.gameObject, orCreateRuneMaterial2); UpdateWingMeshes(0f, 0f); } } private void InitWingObjects(GameObject root, Material lineMat, Material atlasMat, bool isRight, ref LineRenderer[] lines, out MeshFilter meshFilter, out Mesh mesh) { for (int i = 0; i < 7; i++) { GameObject gameObject = new GameObject("BoneLine_" + i); gameObject.layer = root.layer; gameObject.transform.SetParent(root.transform, worldPositionStays: false); LineRenderer lineRenderer = gameObject.AddComponent(); lineRenderer.useWorldSpace = false; lineRenderer.material = lineMat; lineRenderer.enabled = false; lines[i] = lineRenderer; } mesh = new Mesh(); mesh.MarkDynamic(); mesh.vertices = new Vector3[23]; if (_whiteColors == null) { _whiteColors = new Color[23]; for (int j = 0; j < 23; j++) { _whiteColors[j] = Color.white; } } mesh.colors = _whiteColors; Vector2[] uv = new Vector2[23] { new Vector2(0f, 1f) * 3f, new Vector2(0.2f, 0.8f) * 3f, new Vector2(0.3f, 1f) * 3f, new Vector2(0.5f, 0.9f) * 3f, new Vector2(0.7f, 0.8f) * 3f, new Vector2(1f, 0.8f) * 3f, new Vector2(0.5f, 0.6f) * 3f, new Vector2(0.7f, 0.5f) * 3f, new Vector2(1f, 0.5f) * 3f, new Vector2(0.4f, 0.4f) * 3f, new Vector2(0.6f, 0.3f) * 3f, new Vector2(0.9f, 0.2f) * 3f, new Vector2(0.3f, 0.2f) * 3f, new Vector2(0.4f, 0.1f) * 3f, new Vector2(0.6f, 0f) * 3f, new Vector2(0f, 0f) * 3f, default(Vector2), default(Vector2), default(Vector2), default(Vector2), default(Vector2), default(Vector2), default(Vector2) }; mesh.uv = uv; int[] array = new int[63] { 0, 1, 2, 2, 6, 3, 3, 6, 7, 3, 7, 4, 4, 7, 8, 4, 8, 5, 2, 9, 6, 6, 9, 10, 6, 10, 7, 7, 10, 11, 7, 11, 8, 2, 12, 9, 9, 12, 13, 9, 13, 10, 10, 13, 14, 10, 14, 11, 2, 1, 12, 1, 0, 12, 0, 15, 12, 15, 13, 12, 15, 14, 13 }; int[] array2 = new int[array.Length * 2]; for (int k = 0; k < array.Length; k += 3) { array2[k] = array[k]; array2[k + 1] = array[k + 1]; array2[k + 2] = array[k + 2]; array2[array.Length + k] = array[k]; array2[array.Length + k + 1] = array[k + 2]; array2[array.Length + k + 2] = array[k + 1]; } mesh.triangles = array2; GameObject gameObject2 = new GameObject("Membrane"); gameObject2.layer = root.layer; gameObject2.transform.SetParent(root.transform, worldPositionStays: false); meshFilter = gameObject2.AddComponent(); meshFilter.mesh = mesh; MeshRenderer meshRenderer = gameObject2.AddComponent(); meshRenderer.material = atlasMat; meshRenderer.enabled = false; } private Vector3[] GetBezierCurve(Vector3 p0, Vector3 p1, Vector3 p2, int segments) { Vector3[] array = new Vector3[segments + 1]; for (int i = 0; i <= segments; i++) { float num = (float)i / (float)segments; float num2 = 1f - num; array[i] = num2 * num2 * p0 + 2f * num2 * num * p1 + num * num * p2; } return array; } private void SetupBoneLine(LineRenderer lr, Vector3[] points, float startWidth, float endWidth) { lr.positionCount = points.Length; lr.SetPositions(points); lr.startWidth = startWidth; lr.endWidth = endWidth; if (_currentTierColor != Color.clear) { lr.startColor = _currentTierColor; lr.endColor = new Color(_currentTierColor.r, _currentTierColor.g, _currentTierColor.b, 0.2f); } } private ParticleSystem CreateParticleSystem(GameObject go, Material mat) { ParticleSystem particleSystem = go.AddComponent(); ParticleSystem.MainModule main = particleSystem.main; main.loop = true; main.playOnAwake = true; main.startSpeed = 0f; main.startLifetime = new ParticleSystem.MinMaxCurve(0.5f, 1.2f); main.startSize = new ParticleSystem.MinMaxCurve(0.1f, 0.2f); main.simulationSpace = ParticleSystemSimulationSpace.World; main.scalingMode = ParticleSystemScalingMode.Local; ParticleSystem.EmissionModule emission = particleSystem.emission; emission.enabled = false; ParticleSystem.ShapeModule shape = particleSystem.shape; shape.enabled = true; shape.shapeType = ParticleSystemShapeType.SingleSidedEdge; shape.radius = 3f; ParticleSystem.TextureSheetAnimationModule textureSheetAnimation = particleSystem.textureSheetAnimation; textureSheetAnimation.enabled = true; textureSheetAnimation.numTilesX = 4; textureSheetAnimation.numTilesY = 4; textureSheetAnimation.animation = ParticleSystemAnimationType.WholeSheet; textureSheetAnimation.startFrame = new ParticleSystem.MinMaxCurve(0f, 15f); textureSheetAnimation.timeMode = ParticleSystemAnimationTimeMode.Lifetime; ParticleSystemRenderer component = go.GetComponent(); component.renderMode = ParticleSystemRenderMode.Billboard; if (mat != null) { component.material = mat; } particleSystem.Stop(withChildren: true, ParticleSystemStopBehavior.StopEmittingAndClear); return particleSystem; } public void SetTierColor(Color c) { if (_currentTierColor == c) { return; } _currentTierColor = c; if (_leftWing == null || _rightWing == null) { EnsureEmitters(); } ParticleSystem.MainModule main = _leftWing.main; main.startColor = c; ParticleSystem.MainModule main2 = _rightWing.main; main2.startColor = c; ParticleSystemRenderer component = _leftWing.GetComponent(); if (component != null && component.material != null) { if (component.material.HasProperty("_Color")) { component.material.SetColor("_Color", c); } if (component.material.HasProperty("_TintColor")) { component.material.SetColor("_TintColor", c); } if (component.material.HasProperty("_EmissionColor")) { component.material.SetColor("_EmissionColor", c); } } ParticleSystemRenderer component2 = _rightWing.GetComponent(); if (component2 != null && component2.material != null) { if (component2.material.HasProperty("_Color")) { component2.material.SetColor("_Color", c); } if (component2.material.HasProperty("_TintColor")) { component2.material.SetColor("_TintColor", c); } if (component2.material.HasProperty("_EmissionColor")) { component2.material.SetColor("_EmissionColor", c); } } LineRenderer[] leftLines = _leftLines; foreach (LineRenderer lineRenderer in leftLines) { lineRenderer.startColor = c; lineRenderer.endColor = new Color(c.r, c.g, c.b, 0.2f); if (lineRenderer != null && lineRenderer.material != null) { if (lineRenderer.material.HasProperty("_Color")) { lineRenderer.material.SetColor("_Color", c); } if (lineRenderer.material.HasProperty("_TintColor")) { lineRenderer.material.SetColor("_TintColor", c); } if (lineRenderer.material.HasProperty("_EmissionColor")) { lineRenderer.material.SetColor("_EmissionColor", c); } } } LineRenderer[] rightLines = _rightLines; foreach (LineRenderer lineRenderer2 in rightLines) { lineRenderer2.startColor = c; lineRenderer2.endColor = new Color(c.r, c.g, c.b, 0.2f); if (lineRenderer2 != null && lineRenderer2.material != null) { if (lineRenderer2.material.HasProperty("_Color")) { lineRenderer2.material.SetColor("_Color", c); } if (lineRenderer2.material.HasProperty("_TintColor")) { lineRenderer2.material.SetColor("_TintColor", c); } if (lineRenderer2.material.HasProperty("_EmissionColor")) { lineRenderer2.material.SetColor("_EmissionColor", c); } } } MeshRenderer component3 = _leftMeshFilter.GetComponent(); if (component3.material.HasProperty("_Color")) { component3.material.SetColor("_Color", new Color(c.r, c.g, c.b, 0.15f)); } if (component3.material.HasProperty("_TintColor")) { component3.material.SetColor("_TintColor", new Color(c.r, c.g, c.b, 0.15f)); } if (component3.material.HasProperty("_EmissionColor")) { component3.material.SetColor("_EmissionColor", new Color(c.r, c.g, c.b, 0.05f)); } MeshRenderer component4 = _rightMeshFilter.GetComponent(); if (component4.material.HasProperty("_Color")) { component4.material.SetColor("_Color", new Color(c.r, c.g, c.b, 0.15f)); } if (component4.material.HasProperty("_TintColor")) { component4.material.SetColor("_TintColor", new Color(c.r, c.g, c.b, 0.15f)); } if (component4.material.HasProperty("_EmissionColor")) { component4.material.SetColor("_EmissionColor", new Color(c.r, c.g, c.b, 0.05f)); } } public void SetGlidingState(bool gliding) { if (_isGliding == gliding) { return; } _isGliding = gliding; if (_leftWing == null || _rightWing == null) { EnsureEmitters(); } if (_isGliding) { if (!_leftWing.isPlaying) { _leftWing.Play(); } if (!_rightWing.isPlaying) { _rightWing.Play(); } LineRenderer[] leftLines = _leftLines; foreach (LineRenderer lineRenderer in leftLines) { lineRenderer.enabled = true; } LineRenderer[] rightLines = _rightLines; foreach (LineRenderer lineRenderer2 in rightLines) { lineRenderer2.enabled = true; } _leftMeshFilter.GetComponent().enabled = true; _rightMeshFilter.GetComponent().enabled = true; } else { _leftWing.Stop(withChildren: true, ParticleSystemStopBehavior.StopEmitting); _rightWing.Stop(withChildren: true, ParticleSystemStopBehavior.StopEmitting); LineRenderer[] leftLines2 = _leftLines; foreach (LineRenderer lineRenderer3 in leftLines2) { lineRenderer3.enabled = false; } LineRenderer[] rightLines2 = _rightLines; foreach (LineRenderer lineRenderer4 in rightLines2) { lineRenderer4.enabled = false; } _leftMeshFilter.GetComponent().enabled = false; _rightMeshFilter.GetComponent().enabled = false; } } public void TriggerFlap() { if (_leftWing == null || _rightWing == null) { EnsureEmitters(); } _flapTimer = 0.4f; if (!_isGliding) { _leftWing.Emit(15); _rightWing.Emit(15); } } private void Update() { if (_leftRoot == null || _rightRoot == null) { return; } float num = ModConfig.GlobalWingSpan?.Value ?? 1f; _leftRoot.localScale = new Vector3(num, num, num); _rightRoot.localScale = new Vector3(num, num, num); float num2 = 0f; if (_flapTimer > 0f) { _flapTimer -= Time.deltaTime; num2 = 1f - Mathf.Clamp01(_flapTimer / 0.4f); } if (_isGliding && _leftWing != null && _rightWing != null) { if (Vector3.Distance(_leftRoot.position, _lastEmitPosL) > 0.1f) { _leftWing.Emit(1); _lastEmitPosL = _leftRoot.position; } if (Vector3.Distance(_rightRoot.position, _lastEmitPosR) > 0.1f) { _rightWing.Emit(1); _lastEmitPosR = _rightRoot.position; } } float num3 = ((_isGliding && _flapTimer <= 0f) ? Time.time : 0f); UpdateWingMeshes(num2, num3); float num4 = 0f; if (num2 > 0f) { num4 = ((num2 < 0.2f) ? Mathf.Lerp(0f, 20f, num2 / 0.2f) : ((!(num2 < 0.5f)) ? Mathf.Lerp(-50f, 0f, (num2 - 0.5f) / 0.5f) : Mathf.Lerp(20f, -50f, (num2 - 0.2f) / 0.3f))); } else if (num3 > 0f) { num4 = Mathf.Sin(num3 * 4f) * 5f; } float num5 = ((num3 > 0f) ? (Mathf.Cos(num3 * 2f) * 2f) : 0f); _leftRoot.localRotation = Quaternion.Lerp(_leftRoot.localRotation, Quaternion.Euler(num5, -20f + num5, num4), Time.deltaTime * 15f); _rightRoot.localRotation = Quaternion.Lerp(_rightRoot.localRotation, Quaternion.Euler(0f - num5, 20f - num5, 0f - num4), Time.deltaTime * 15f); } private void UpdateWingMeshes(float flapProgress, float idleTime) { UpdateSingleWing(isRight: false, _leftLines, _leftMesh, flapProgress, idleTime); UpdateSingleWing(isRight: true, _rightLines, _rightMesh, flapProgress, idleTime); } private void UpdateSingleWing(bool isRight, LineRenderer[] lines, Mesh mesh, float flapProgress, float idleTime) { float num = (isRight ? 1f : (-1f)); float num2 = 0f; float num3 = 0f; if (flapProgress > 0f) { if (flapProgress < 0.2f) { float t = flapProgress / 0.2f; num2 = Mathf.Lerp(0f, -0.8f, t); num3 = Mathf.Lerp(0f, -0.5f, t); } else if (flapProgress < 0.5f) { float t2 = (flapProgress - 0.2f) / 0.3f; num2 = Mathf.Lerp(-0.8f, 0.2f, t2); num3 = Mathf.Lerp(-0.5f, 0.3f, t2); } else { float t3 = (flapProgress - 0.5f) / 0.5f; num2 = Mathf.Lerp(0.2f, 0f, t3); num3 = Mathf.Lerp(0.3f, 0f, t3); } } else if (idleTime > 0f) { num2 = Mathf.Sin(idleTime * 2f) * 0.1f; num3 = Mathf.Cos(idleTime * 4f) * 0.1f; } Vector3 vector = new Vector3(0f, 0f, 0f); Vector3 p = new Vector3(0.8f * num, 0.2f, 0.4f); Vector3 vector2 = new Vector3((2.2f + num2 * 0.5f) * num, 0.5f + num3 * 0.5f, 0.2f + num2); Vector3 vector3 = vector2 + new Vector3(0.2f * num, 0.2f, 0.1f); Vector3 vector4 = vector2 + new Vector3(0.3f * num, 0.4f, 0.2f); Vector3 p2 = vector2 + new Vector3(1.6f * num, -0.1f + num3, -0.4f + num2); Vector3 vector5 = vector2 + new Vector3((2.8f + num2) * num, -0.3f + num3 * 2f, -1.2f + num2 * 2f); Vector3 p3 = vector2 + new Vector3(1.3f * num, -0.4f + num3, -0.8f + num2); Vector3 vector6 = vector2 + new Vector3((2.4f + num2) * num, -0.7f + num3 * 2f, -1.8f + num2 * 2f); Vector3 p4 = vector2 + new Vector3(0.8f * num, -0.7f + num3, -1.2f + num2); Vector3 vector7 = vector2 + new Vector3((1.6f + num2) * num, -1f + num3 * 2f, -2.4f + num2 * 2f); Vector3 p5 = vector2 + new Vector3(0.1f * num, -0.9f + num3, -1.4f + num2); Vector3 vector8 = vector2 + new Vector3((0.4f + num2) * num, -1.2f + num3 * 2f, -2.8f + num2 * 2f); Vector3 vector9 = new Vector3(0.2f * num, -0.5f, -0.5f); Vector3[] bezierCurve = GetBezierCurve(vector, p, vector2, 10); Vector3[] bezierCurve2 = GetBezierCurve(vector2, p2, vector5, 10); Vector3[] bezierCurve3 = GetBezierCurve(vector2, p3, vector6, 10); Vector3[] bezierCurve4 = GetBezierCurve(vector2, p4, vector7, 10); Vector3[] bezierCurve5 = GetBezierCurve(vector2, p5, vector8, 10); SetupBoneLine(lines[0], bezierCurve, 0.25f, 0.15f); SetupBoneLine(lines[1], new Vector3[3] { vector2, vector3, vector4 }, 0.08f, 0.01f); SetupBoneLine(lines[2], bezierCurve2, 0.12f, 0.01f); SetupBoneLine(lines[3], bezierCurve3, 0.12f, 0.01f); SetupBoneLine(lines[4], bezierCurve4, 0.12f, 0.01f); SetupBoneLine(lines[5], bezierCurve5, 0.12f, 0.01f); SetupBoneLine(lines[6], new Vector3[2] { vector, vector9 }, 0.1f, 0.05f); mesh.vertices = new Vector3[23] { vector, bezierCurve[5], vector2, bezierCurve2[2], bezierCurve2[6], vector5, bezierCurve3[2], bezierCurve3[6], vector6, bezierCurve4[2], bezierCurve4[6], vector7, bezierCurve5[2], bezierCurve5[6], vector8, vector9, default(Vector3), default(Vector3), default(Vector3), default(Vector3), default(Vector3), default(Vector3), default(Vector3) }; if (_whiteColors != null) { mesh.colors = _whiteColors; } mesh.RecalculateNormals(); mesh.RecalculateBounds(); } } } // ---- WingsoftheValkyrie/plugins/WingsoftheValkyrie.dll :: WingsoftheValkyrie.VFX.ValkyrieRuneTextureGenerator ---- namespace WingsoftheValkyrie.VFX { public static class ValkyrieRuneTextureGenerator { private const int Size = 128; public static Texture2D GenerateRune(Color color) { int num = Mathf.Abs(color.GetHashCode()); int runeIndex = num % 16; return GenerateRune(color, runeIndex); } public static Texture2D GenerateRuneAtlas(Color color) { int num = 512; int num2 = 128; Texture2D texture2D = new Texture2D(num, num, TextureFormat.RGBA32, mipChain: true); texture2D.filterMode = FilterMode.Bilinear; texture2D.wrapMode = TextureWrapMode.Clamp; Color color2 = new Color(0f, 0f, 0f, 0f); Color[] array = new Color[num * num]; for (int i = 0; i < array.Length; i++) { array[i] = color2; } texture2D.SetPixels(array); for (int j = 0; j < 16; j++) { int num3 = j % 4; int num4 = 3 - j / 4; DrawRuneOntoAtlas(texture2D, color, j, num3 * num2, num4 * num2, num2); } texture2D.Apply(updateMipmaps: true); return texture2D; } public static Texture2D GenerateSoftTrail(Color color) { Texture2D texture2D = new Texture2D(128, 128, TextureFormat.RGBA32, mipChain: false); texture2D.filterMode = FilterMode.Bilinear; Vector2 b = new Vector2(64f, 64f); float num = 64f; for (int i = 0; i < 128; i++) { for (int j = 0; j < 128; j++) { Vector2 a = new Vector2((float)j + 0.5f, (float)i + 0.5f); float num2 = Vector2.Distance(a, b) / num; float t = Mathf.Clamp01(1f - num2); t = Mathf.SmoothStep(0f, 1f, t); t = Mathf.Pow(t, 1.6f); Color color2 = new Color(color.r, color.g, color.b, color.a * t); texture2D.SetPixel(j, i, color2); } } texture2D.Apply(updateMipmaps: true); return texture2D; } public static Texture2D GenerateStreak(Color color) { Texture2D texture2D = new Texture2D(128, 128, TextureFormat.RGBA32, mipChain: false); texture2D.filterMode = FilterMode.Bilinear; Vector2 vector = new Vector2(64f, 64f); float num = 64f; for (int i = 0; i < 128; i++) { for (int j = 0; j < 128; j++) { float t = Mathf.Abs((float)i + 0.5f - vector.y) / num; float num2 = Mathf.Abs((float)j + 0.5f - vector.x) / (num * 0.6f); float num3 = Mathf.Clamp01(1f - num2); float f = Mathf.SmoothStep(1f, 0f, t); num3 *= Mathf.Pow(f, 0.9f); Color color2 = new Color(color.r, color.g, color.b, color.a * num3); texture2D.SetPixel(j, i, color2); } } texture2D.Apply(updateMipmaps: true); return texture2D; } public static Texture2D GenerateBlend(Color color) { Texture2D texture2D = GenerateSoftTrail(color); Texture2D texture2D2 = GenerateRune(color); Texture2D texture2D3 = new Texture2D(128, 128, TextureFormat.RGBA32, mipChain: false); texture2D3.filterMode = FilterMode.Bilinear; for (int i = 0; i < 128; i++) { for (int j = 0; j < 128; j++) { Color pixel = texture2D.GetPixel(j, i); Color pixel2 = texture2D2.GetPixel(j, i); float num = Mathf.Clamp01(pixel.a + pixel2.a * 0.65f); Color color2 = new Color(color.r, color.g, color.b, color.a * num); texture2D3.SetPixel(j, i, color2); } } texture2D3.Apply(updateMipmaps: true); return texture2D3; } private static void DrawRuneOntoAtlas(Texture2D tex, Color color, int runeIndex, int offsetX, int offsetY, int size) { Color c = new Color(color.r * 0.6f, color.g * 0.6f, color.b * 0.6f, 0.6f); Color c2 = new Color(color.r, color.g, color.b, 1f); float scale = (float)size / 128f; switch (runeIndex) { case 0: DrawLineLocal(20, 20, 108, 108, c, 6); DrawLineLocal(108, 20, 20, 108, c, 6); DrawLineLocal(20, 20, 108, 108, c2, 3); DrawLineLocal(108, 20, 20, 108, c2, 3); break; case 1: DrawLineLocal(64, 16, 64, 112, c, 6); DrawLineLocal(64, 64, 32, 96, c, 5); DrawLineLocal(64, 64, 96, 96, c, 5); DrawLineLocal(64, 16, 64, 112, c2, 3); DrawLineLocal(64, 64, 32, 96, c2, 2); DrawLineLocal(64, 64, 96, 96, c2, 2); break; case 2: DrawLineLocal(40, 20, 40, 108, c, 6); DrawLineLocal(40, 96, 96, 112, c, 5); DrawLineLocal(40, 72, 96, 88, c, 5); DrawLineLocal(40, 20, 40, 108, c2, 3); DrawLineLocal(40, 96, 96, 112, c2, 2); DrawLineLocal(40, 72, 96, 88, c2, 2); break; case 3: DrawLineLocal(40, 20, 40, 112, c, 6); DrawLineLocal(40, 96, 88, 112, c, 5); DrawLineLocal(88, 112, 88, 80, c, 5); DrawLineLocal(88, 80, 40, 96, c, 5); DrawLineLocal(40, 20, 40, 112, c2, 3); DrawLineLocal(40, 96, 88, 112, c2, 2); DrawLineLocal(88, 112, 88, 80, c2, 2); DrawLineLocal(88, 80, 40, 96, c2, 2); break; case 4: DrawLineLocal(64, 16, 64, 112, c, 8); DrawLineLocal(64, 16, 64, 112, c2, 4); break; case 5: DrawLineLocal(64, 16, 64, 112, c, 6); DrawLineLocal(64, 40, 32, 72, c, 5); DrawLineLocal(64, 40, 96, 72, c, 5); DrawLineLocal(64, 16, 64, 112, c2, 3); DrawLineLocal(64, 40, 32, 72, c2, 2); DrawLineLocal(64, 40, 96, 72, c2, 2); break; case 6: DrawLineLocal(36, 16, 36, 112, c, 6); DrawLineLocal(92, 16, 92, 112, c, 6); DrawLineLocal(36, 36, 92, 92, c, 5); DrawLineLocal(36, 16, 36, 112, c2, 3); DrawLineLocal(92, 16, 92, 112, c2, 3); DrawLineLocal(36, 36, 92, 92, c2, 2); break; case 7: DrawLineLocal(80, 20, 40, 20, c, 5); DrawLineLocal(80, 20, 40, 64, c, 5); DrawLineLocal(40, 64, 80, 108, c, 5); DrawLineLocal(80, 108, 40, 108, c, 5); DrawLineLocal(80, 20, 40, 20, c2, 2); DrawLineLocal(80, 20, 40, 64, c2, 2); DrawLineLocal(40, 64, 80, 108, c2, 2); DrawLineLocal(80, 108, 40, 108, c2, 2); break; case 8: DrawLineLocal(64, 16, 64, 112, c, 6); DrawLineLocal(96, 96, 32, 32, c, 5); DrawLineLocal(64, 16, 64, 112, c2, 3); DrawLineLocal(96, 96, 32, 32, c2, 2); break; case 9: DrawLineLocal(32, 48, 32, 112, c, 6); DrawLineLocal(96, 48, 96, 112, c, 6); DrawLineLocal(32, 48, 64, 16, c, 5); DrawLineLocal(64, 16, 96, 48, c, 5); DrawLineLocal(32, 48, 32, 112, c2, 3); DrawLineLocal(96, 48, 96, 112, c2, 3); DrawLineLocal(32, 48, 64, 16, c2, 2); DrawLineLocal(64, 16, 96, 48, c2, 2); break; case 10: DrawLineLocal(48, 16, 48, 112, c, 6); DrawLineLocal(48, 80, 96, 48, c, 5); DrawLineLocal(48, 16, 48, 112, c2, 3); DrawLineLocal(48, 80, 96, 48, c2, 2); break; case 11: DrawLineLocal(64, 112, 96, 72, c, 5); DrawLineLocal(96, 72, 64, 32, c, 5); DrawLineLocal(64, 32, 32, 72, c, 5); DrawLineLocal(32, 72, 64, 112, c, 5); DrawLineLocal(32, 72, 16, 16, c, 5); DrawLineLocal(96, 72, 112, 16, c, 5); DrawLineLocal(64, 112, 96, 72, c2, 2); DrawLineLocal(96, 72, 64, 32, c2, 2); DrawLineLocal(64, 32, 32, 72, c2, 2); DrawLineLocal(32, 72, 64, 112, c2, 2); DrawLineLocal(32, 72, 16, 16, c2, 2); DrawLineLocal(96, 72, 112, 16, c2, 2); break; case 12: DrawLineLocal(20, 20, 64, 64, c, 5); DrawLineLocal(20, 108, 64, 64, c, 5); DrawLineLocal(108, 20, 64, 64, c, 5); DrawLineLocal(108, 108, 64, 64, c, 5); DrawLineLocal(20, 20, 64, 64, c2, 2); DrawLineLocal(20, 108, 64, 64, c2, 2); DrawLineLocal(108, 20, 64, 64, c2, 2); DrawLineLocal(108, 108, 64, 64, c2, 2); break; case 13: DrawLineLocal(36, 16, 36, 112, c, 6); DrawLineLocal(36, 96, 80, 80, c, 5); DrawLineLocal(80, 80, 36, 64, c, 5); DrawLineLocal(36, 64, 80, 48, c, 5); DrawLineLocal(80, 48, 36, 32, c, 5); DrawLineLocal(36, 16, 36, 112, c2, 3); DrawLineLocal(36, 96, 80, 80, c2, 2); DrawLineLocal(80, 80, 36, 64, c2, 2); DrawLineLocal(36, 64, 80, 48, c2, 2); DrawLineLocal(80, 48, 36, 32, c2, 2); break; case 14: DrawLineLocal(32, 16, 32, 112, c, 6); DrawLineLocal(96, 16, 96, 112, c, 6); DrawLineLocal(32, 112, 96, 64, c, 5); DrawLineLocal(96, 112, 32, 64, c, 5); DrawLineLocal(32, 16, 32, 112, c2, 3); DrawLineLocal(96, 16, 96, 112, c2, 3); DrawLineLocal(32, 112, 96, 64, c2, 2); DrawLineLocal(96, 112, 32, 64, c2, 2); break; case 15: DrawLineLocal(64, 16, 108, 64, c, 6); DrawLineLocal(108, 64, 64, 112, c, 6); DrawLineLocal(64, 112, 20, 64, c, 6); DrawLineLocal(20, 64, 64, 16, c, 6); DrawLineLocal(64, 16, 108, 64, c2, 3); DrawLineLocal(108, 64, 64, 112, c2, 3); DrawLineLocal(64, 112, 20, 64, c2, 3); DrawLineLocal(20, 64, 64, 16, c2, 3); break; } void DrawLineLocal(int x0, int y0, int x1, int y1, Color c3, int thickness) { DrawLineAtlas(tex, offsetX + (int)((float)x0 * scale), offsetY + (int)((float)y0 * scale), offsetX + (int)((float)x1 * scale), offsetY + (int)((float)y1 * scale), c3, thickness, 512); } } public static Texture2D GenerateRune(Color color, int runeIndex) { Texture2D texture2D = new Texture2D(128, 128, TextureFormat.RGBA32, mipChain: true); texture2D.filterMode = FilterMode.Bilinear; texture2D.wrapMode = TextureWrapMode.Clamp; Color color2 = new Color(0f, 0f, 0f, 0f); Color c = new Color(color.r * 0.6f, color.g * 0.6f, color.b * 0.6f, 0.6f); Color c2 = new Color(color.r, color.g, color.b, 1f); Color[] array = new Color[16384]; for (int i = 0; i < array.Length; i++) { array[i] = color2; } texture2D.SetPixels(array); switch (runeIndex) { case 0: DrawLine(texture2D, 20, 20, 108, 108, c, 6); DrawLine(texture2D, 108, 20, 20, 108, c, 6); DrawLine(texture2D, 20, 20, 108, 108, c2, 3); DrawLine(texture2D, 108, 20, 20, 108, c2, 3); break; case 1: DrawLine(texture2D, 64, 16, 64, 112, c, 6); DrawLine(texture2D, 64, 64, 32, 96, c, 5); DrawLine(texture2D, 64, 64, 96, 96, c, 5); DrawLine(texture2D, 64, 16, 64, 112, c2, 3); DrawLine(texture2D, 64, 64, 32, 96, c2, 2); DrawLine(texture2D, 64, 64, 96, 96, c2, 2); break; case 2: DrawLine(texture2D, 40, 20, 40, 108, c, 6); DrawLine(texture2D, 40, 96, 96, 112, c, 5); DrawLine(texture2D, 40, 72, 96, 88, c, 5); DrawLine(texture2D, 40, 20, 40, 108, c2, 3); DrawLine(texture2D, 40, 96, 96, 112, c2, 2); DrawLine(texture2D, 40, 72, 96, 88, c2, 2); break; case 3: DrawLine(texture2D, 40, 20, 40, 112, c, 6); DrawLine(texture2D, 40, 96, 88, 112, c, 5); DrawLine(texture2D, 88, 112, 88, 80, c, 5); DrawLine(texture2D, 88, 80, 40, 96, c, 5); DrawLine(texture2D, 40, 20, 40, 112, c2, 3); DrawLine(texture2D, 40, 96, 88, 112, c2, 2); DrawLine(texture2D, 88, 112, 88, 80, c2, 2); DrawLine(texture2D, 88, 80, 40, 96, c2, 2); break; case 4: DrawLine(texture2D, 64, 16, 64, 112, c, 8); DrawLine(texture2D, 64, 16, 64, 112, c2, 4); break; case 5: DrawLine(texture2D, 64, 16, 64, 112, c, 6); DrawLine(texture2D, 64, 40, 32, 72, c, 5); DrawLine(texture2D, 64, 40, 96, 72, c, 5); DrawLine(texture2D, 64, 16, 64, 112, c2, 3); DrawLine(texture2D, 64, 40, 32, 72, c2, 2); DrawLine(texture2D, 64, 40, 96, 72, c2, 2); break; case 6: DrawLine(texture2D, 36, 16, 36, 112, c, 6); DrawLine(texture2D, 92, 16, 92, 112, c, 6); DrawLine(texture2D, 36, 36, 92, 92, c, 5); DrawLine(texture2D, 36, 16, 36, 112, c2, 3); DrawLine(texture2D, 92, 16, 92, 112, c2, 3); DrawLine(texture2D, 36, 36, 92, 92, c2, 2); break; default: DrawLine(texture2D, 80, 20, 40, 20, c, 5); DrawLine(texture2D, 80, 20, 40, 64, c, 5); DrawLine(texture2D, 40, 64, 80, 108, c, 5); DrawLine(texture2D, 80, 108, 40, 108, c, 5); DrawLine(texture2D, 80, 20, 40, 20, c2, 2); DrawLine(texture2D, 80, 20, 40, 64, c2, 2); DrawLine(texture2D, 40, 64, 80, 108, c2, 2); DrawLine(texture2D, 80, 108, 40, 108, c2, 2); break; case 8: DrawLine(texture2D, 64, 16, 64, 112, c, 6); DrawLine(texture2D, 96, 96, 32, 32, c, 5); DrawLine(texture2D, 64, 16, 64, 112, c2, 3); DrawLine(texture2D, 96, 96, 32, 32, c2, 2); break; case 9: DrawLine(texture2D, 32, 48, 32, 112, c, 6); DrawLine(texture2D, 96, 48, 96, 112, c, 6); DrawLine(texture2D, 32, 48, 64, 16, c, 5); DrawLine(texture2D, 64, 16, 96, 48, c, 5); DrawLine(texture2D, 32, 48, 32, 112, c2, 3); DrawLine(texture2D, 96, 48, 96, 112, c2, 3); DrawLine(texture2D, 32, 48, 64, 16, c2, 2); DrawLine(texture2D, 64, 16, 96, 48, c2, 2); break; case 10: DrawLine(texture2D, 48, 16, 48, 112, c, 6); DrawLine(texture2D, 48, 80, 96, 48, c, 5); DrawLine(texture2D, 48, 16, 48, 112, c2, 3); DrawLine(texture2D, 48, 80, 96, 48, c2, 2); break; case 11: DrawLine(texture2D, 64, 112, 96, 72, c, 5); DrawLine(texture2D, 96, 72, 64, 32, c, 5); DrawLine(texture2D, 64, 32, 32, 72, c, 5); DrawLine(texture2D, 32, 72, 64, 112, c, 5); DrawLine(texture2D, 32, 72, 16, 16, c, 5); DrawLine(texture2D, 96, 72, 112, 16, c, 5); DrawLine(texture2D, 64, 112, 96, 72, c2, 2); DrawLine(texture2D, 96, 72, 64, 32, c2, 2); DrawLine(texture2D, 64, 32, 32, 72, c2, 2); DrawLine(texture2D, 32, 72, 64, 112, c2, 2); DrawLine(texture2D, 32, 72, 16, 16, c2, 2); DrawLine(texture2D, 96, 72, 112, 16, c2, 2); break; case 12: DrawLine(texture2D, 20, 20, 64, 64, c, 5); DrawLine(texture2D, 20, 108, 64, 64, c, 5); DrawLine(texture2D, 108, 20, 64, 64, c, 5); DrawLine(texture2D, 108, 108, 64, 64, c, 5); DrawLine(texture2D, 20, 20, 64, 64, c2, 2); DrawLine(texture2D, 20, 108, 64, 64, c2, 2); DrawLine(texture2D, 108, 20, 64, 64, c2, 2); DrawLine(texture2D, 108, 108, 64, 64, c2, 2); break; case 13: DrawLine(texture2D, 36, 16, 36, 112, c, 6); DrawLine(texture2D, 36, 96, 80, 80, c, 5); DrawLine(texture2D, 80, 80, 36, 64, c, 5); DrawLine(texture2D, 36, 64, 80, 48, c, 5); DrawLine(texture2D, 80, 48, 36, 32, c, 5); DrawLine(texture2D, 36, 16, 36, 112, c2, 3); DrawLine(texture2D, 36, 96, 80, 80, c2, 2); DrawLine(texture2D, 80, 80, 36, 64, c2, 2); DrawLine(texture2D, 36, 64, 80, 48, c2, 2); DrawLine(texture2D, 80, 48, 36, 32, c2, 2); break; case 14: DrawLine(texture2D, 32, 16, 32, 112, c, 6); DrawLine(texture2D, 96, 16, 96, 112, c, 6); DrawLine(texture2D, 32, 112, 96, 64, c, 5); DrawLine(texture2D, 96, 112, 32, 64, c, 5); DrawLine(texture2D, 32, 16, 32, 112, c2, 3); DrawLine(texture2D, 96, 16, 96, 112, c2, 3); DrawLine(texture2D, 32, 112, 96, 64, c2, 2); DrawLine(texture2D, 96, 112, 32, 64, c2, 2); break; case 15: DrawLine(texture2D, 64, 16, 108, 64, c, 6); DrawLine(texture2D, 108, 64, 64, 112, c, 6); DrawLine(texture2D, 64, 112, 20, 64, c, 6); DrawLine(texture2D, 20, 64, 64, 16, c, 6); DrawLine(texture2D, 64, 16, 108, 64, c2, 3); DrawLine(texture2D, 108, 64, 64, 112, c2, 3); DrawLine(texture2D, 64, 112, 20, 64, c2, 3); DrawLine(texture2D, 20, 64, 64, 16, c2, 3); break; } texture2D.Apply(updateMipmaps: true); return texture2D; } private static void DrawLineAtlas(Texture2D tex, int x0, int y0, int x1, int y1, Color c, int thickness, int atlasSize) { int num = Mathf.Abs(x1 - x0); int num2 = Mathf.Abs(y1 - y0); int num3 = ((x0 < x1) ? 1 : (-1)); int num4 = ((y0 < y1) ? 1 : (-1)); int num5 = num - num2; while (true) { DrawCircleAtlas(tex, x0, y0, thickness, c, atlasSize); if (x0 == x1 && y0 == y1) { break; } int num6 = 2 * num5; if (num6 > -num2) { num5 -= num2; x0 += num3; } if (num6 < num) { num5 += num; y0 += num4; } } } private static void DrawCircleAtlas(Texture2D tex, int cx, int cy, int r, Color c, int atlasSize) { for (int i = -r; i <= r; i++) { for (int j = -r; j <= r; j++) { if (j * j + i * i <= r * r) { int num = cx + j; int num2 = cy + i; if (num >= 0 && num < atlasSize && num2 >= 0 && num2 < atlasSize) { tex.SetPixel(num, num2, c); } } } } } private static void DrawLine(Texture2D tex, int x0, int y0, int x1, int y1, Color c, int thickness) { int num = Mathf.Abs(x1 - x0); int num2 = Mathf.Abs(y1 - y0); int num3 = ((x0 < x1) ? 1 : (-1)); int num4 = ((y0 < y1) ? 1 : (-1)); int num5 = num - num2; while (true) { DrawCircle(tex, x0, y0, thickness, c); if (x0 == x1 && y0 == y1) { break; } int num6 = 2 * num5; if (num6 > -num2) { num5 -= num2; x0 += num3; } if (num6 < num) { num5 += num; y0 += num4; } } } private static void DrawCircle(Texture2D tex, int cx, int cy, int r, Color c) { for (int i = -r; i <= r; i++) { for (int j = -r; j <= r; j++) { if (j * j + i * i <= r * r) { int num = cx + j; int num2 = cy + i; if (num >= 0 && num < 128 && num2 >= 0 && num2 < 128) { tex.SetPixel(num, num2, c); } } } } } } } // ---- WingsoftheValkyrie/plugins/WingsoftheValkyrie.dll :: WingsoftheValkyrie.VFX.ValkyrieRuneVFX_Helper ---- namespace WingsoftheValkyrie.VFX { public static class ValkyrieRuneVFX_Helper { private static readonly Dictionary _materialCache = new Dictionary(); private static bool _initialized = false; private static void Init() { if (!_initialized) { _initialized = true; Logger.LogInfo((object)"\ud83d\udf01 VFX‑Forge: Seeking glowing, additive, unlit shaders worthy of Njord."); } } private static long MakeCacheKey(Shader shader, Texture2D tex, Color color) { int num = ((shader != null) ? shader.GetInstanceID() : 0); int num2 = ((tex != null) ? tex.GetInstanceID() : 0); int hashCode = color.GetHashCode(); return (long)((ulong)((long)num << 32) ^ ((ulong)(uint)num2 << 16) ^ (uint)hashCode); } public static Material GetOrCreateRuneMaterial(Texture2D runeTex, Color color) { Init(); Shader shader = Shader.Find("Particles/Standard Unlit") ?? Shader.Find("Legacy Shaders/Particles/Alpha Blended") ?? Shader.Find("Particles/Alpha Blended") ?? Shader.Find("Particles/Additive"); if (shader == null) { float num = float.MinValue; Material[] array = Resources.FindObjectsOfTypeAll(); foreach (Material material in array) { if (!(material == null) && !(material.shader == null)) { Shader shader2 = material.shader; string text = shader2.name.ToLower(); float num2 = 0f; if (text.Contains("particle")) { num2 += 3f; } if (text.Contains("add")) { num2 += 3f; } if (text.Contains("unlit")) { num2 += 2f; } if (text.Contains("transparent")) { num2 += 1.5f; } if ((material.HasProperty("_Color") || material.HasProperty("_TintColor")) && num2 > num) { num = num2; shader = shader2; } } } } if (shader == null) { Logger.LogError((object)"\ud83d\udf01 VFX‑Forge: No glowing shader found. The runes refuse to shine."); return null; } long key = MakeCacheKey(shader, runeTex, color); if (_materialCache.TryGetValue(key, out var value) && value != null) { return value; } Material material2 = new Material(shader); if (runeTex != null) { if (material2.HasProperty("_MainTex")) { material2.SetTexture("_MainTex", runeTex); } if (material2.HasProperty("_BaseMap")) { material2.SetTexture("_BaseMap", runeTex); } try { material2.mainTexture = runeTex; } catch { } } if (material2.HasProperty("_Color")) { material2.SetColor("_Color", color); } if (material2.HasProperty("_TintColor")) { material2.SetColor("_TintColor", color); } if (material2.HasProperty("_EmissionColor")) { material2.SetColor("_EmissionColor", color * 3f); } material2.SetInt("_SrcBlend", 1); material2.SetInt("_DstBlend", 1); material2.SetInt("_ZWrite", 0); material2.DisableKeyword("_ALPHATEST_ON"); material2.EnableKeyword("_ALPHABLEND_ON"); material2.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material2.renderQueue = 3000; _materialCache[key] = material2; Logger.LogInfo((object)("\ud83d\udf01 VFX‑Forge: Forged glowing additive rune material from '" + shader.name + "'.")); return material2; } public static void ClearCache() { _materialCache.Clear(); _initialized = false; } } }