using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using HarmonyLib; using SideLoader; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] namespace RunicArsenal; [BepInPlugin("com.merofos.outward.runicarsenal", "Runic Arsenal", "0.1.17")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class RunicArsenalPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(Equipment), "OnUnequip")] private static class EquipmentOnUnequipPatch { private static void Postfix(Equipment __instance, Character _char) { HideRunicChakramVisualsAfterUnequip(__instance, _char); } } [HarmonyPatch(typeof(Character), "LeftHandChanged")] private static class CharacterLeftHandChangedPatch { private static void Postfix(Character __instance) { try { Equipment val = (((Object)(object)__instance == (Object)null) ? null : __instance.LeftHandEquipment); if (!((Object)(object)val != (Object)null) || ((Item)val).ItemID != -2525260) { HideRunicChakramVisualSlot(__instance); } } catch { } } } private sealed class RunicWeaponDefinition { private readonly string[] _visualNameFragments; public int ItemId { get; private set; } public int BaseItemId { get; private set; } public string DisplayName { get; private set; } public string InternalName { get; private set; } public string IconRelativePath { get; private set; } public string IconId { get; private set; } public bool HasCustomIcon { get { if (!string.IsNullOrEmpty(IconRelativePath)) { return !string.IsNullOrEmpty(IconId); } return false; } } public RunicWeaponDefinition(int itemId, int baseItemId, string displayName, string internalName, string iconRelativePath, string iconId, string[] visualNameFragments) { ItemId = itemId; BaseItemId = baseItemId; DisplayName = displayName; InternalName = internalName; IconRelativePath = iconRelativePath; IconId = iconId; _visualNameFragments = visualNameFragments; } public bool MatchesVisualName(string lowerInvariantName) { for (int i = 0; i < _visualNameFragments.Length; i++) { if (lowerInvariantName.Contains(_visualNameFragments[i])) { return true; } } return false; } } private const string PluginGuid = "com.merofos.outward.runicarsenal"; private const string SideLoaderGuid = "com.sinai.SideLoader"; private const string PluginName = "Runic Arsenal"; private const string PluginVersion = "0.1.17"; private const int VanillaRunicBladeItemId = 2000100; private const int RunicChakramItemId = -2525260; private const string CapturedRunicBladeMaterialName = "mat_itm_crystalBladeRunicBladeLight"; private const string CapturedRunicBladeMainTextureName = "tex_fx_PerlinNoiseGray"; private const string CapturedRunicBladeWaveTextureName = "tex_env_waterWave_n"; private static readonly RunicWeaponDefinition[] RunicWeapons = new RunicWeaponDefinition[8] { new RunicWeaponDefinition(-2525200, 2010060, "Runic Axe", "RunicAxe", "SideLoader/Items/-2525200-Runic_Axe/runic_axe_item_icon.png", "MEROFOS_RunicAxeIcon", new string[7] { "2010060", "marbleaxe", "marble axe", "runicaxe", "runic axe", "-2525200", "2525200" }), new RunicWeaponDefinition(-2525210, 2110020, "Runic Greataxe", "RunicGreataxe", "SideLoader/Items/-2525210-Runic_Greataxe/runic_greataxe_item_icon.png", "MEROFOS_RunicGreataxeIcon", new string[7] { "2110020", "marblegreataxe", "marble greataxe", "runicgreataxe", "runic greataxe", "-2525210", "2525210" }), new RunicWeaponDefinition(-2525220, 2020040, "Runic Morningstar", "RunicMorningstar", "SideLoader/Items/-2525220-Runic_Morningstar/runic_morningstar_item_icon.png", "MEROFOS_RunicMorningstarIcon", new string[7] { "2020040", "marblemorningstar", "marble morningstar", "runicmorningstar", "runic morningstar", "-2525220", "2525220" }), new RunicWeaponDefinition(-2525230, 2120030, "Runic Greathammer", "RunicGreathammer", "SideLoader/Items/-2525230-Runic_Greathammer/runic_greathammer_item_icon.png", "MEROFOS_RunicGreathammerIcon", new string[7] { "2120030", "marblegreathammer", "marble greathammer", "runicgreathammer", "runic greathammer", "-2525230", "2525230" }), new RunicWeaponDefinition(-2525240, 2140030, "Runic Halberd", "RunicHalberd", "SideLoader/Items/-2525240-Runic_Halberd/runic_halberd_item_icon.png", "MEROFOS_RunicHalberdIcon", new string[7] { "2140030", "marblehalberd", "marble halberd", "runichalberd", "runic halberd", "-2525240", "2525240" }), new RunicWeaponDefinition(-2525250, 2130050, "Runic Spear", "RunicSpear", "SideLoader/Items/-2525250-Runic_Spear/runic_spear_item_icon.png", "MEROFOS_RunicSpearIcon", new string[7] { "2130050", "marblespear", "marble spear", "runicspear", "runic spear", "-2525250", "2525250" }), new RunicWeaponDefinition(-2525260, 5110030, "Runic Chakram", "RunicChakram", "SideLoader/Items/-2525260-Runic_Chakram/runic_chakram_item_icon.png", "MEROFOS_RunicChakramIcon", new string[6] { "5110030", "chakram", "runicchakram", "runic chakram", "-2525260", "2525260" }), new RunicWeaponDefinition(-2525270, 2160210, "Runic Knuckles", "RunicKnuckles", "SideLoader/Items/-2525270-Runic_Knuckles/runic_knuckles_item_icon.png", "MEROFOS_RunicKnucklesIcon", new string[7] { "2160210", "smokeknuckles", "smoke knuckles", "runicknuckles", "runic knuckles", "-2525270", "2525270" }) }; private static readonly HashSet s_missingTextureWarnings = new HashSet(); private static readonly float[] VisualRetryDelays = new float[8] { 0f, 0.1f, 0.25f, 0.5f, 1f, 2f, 4f, 8f }; private static readonly FieldInfo ItemIconField = typeof(Item).GetField("m_itemIcon", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo ItemIconPathField = typeof(Item).GetField("m_itemIconPath", BindingFlags.Instance | BindingFlags.NonPublic); private static Texture s_capturedMainTexture; private static Texture s_capturedWaveTexture; private readonly Dictionary _definitionsByItemId = new Dictionary(); private readonly Dictionary _materialCache = new Dictionary(); private readonly Dictionary _iconCache = new Dictionary(); private readonly Dictionary _knownRunicItems = new Dictionary(); private readonly HashSet _pendingVisualRetries = new HashSet(); private readonly HashSet _loggedIconFailures = new HashSet(); private Material _runicBladeSourceMaterial; private int _runicMaterialGeneration; private bool _capturedTexturesReady; private bool _loggedNoRenderer; private bool _loggedPrefabMaterialFailure; private static string PluginDirectory { get { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (!string.IsNullOrEmpty(directoryName)) { return directoryName; } return "."; } } private void Awake() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) new Harmony("com.merofos.outward.runicarsenal").PatchAll(typeof(RunicArsenalPlugin).Assembly); for (int i = 0; i < RunicWeapons.Length; i++) { RunicWeaponDefinition runicWeaponDefinition = RunicWeapons[i]; _definitionsByItemId[runicWeaponDefinition.ItemId] = runicWeaponDefinition; SL_Item.AddOnInstanceStartListener(runicWeaponDefinition.ItemId, (Action)OnRunicWeaponInstanceStart); } SL.OnPacksLoaded += OnSideLoaderPacksLoaded; TryRefreshCapturedTextureState(); TryRefreshRunicBladeSourceMaterial(allowLoadedMaterialSearch: false); Debug.Log((object)"[Runic Arsenal] Loaded."); } private void OnRunicWeaponInstanceStart(Item item) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown if (TryGetDefinition(item, out var definition)) { ApplyRunicWeaponIcon(item, definition); _knownRunicItems[((Object)item).GetInstanceID()] = item; item.OnProcessVisual -= new ProcessVisual(OnRunicWeaponProcessVisual); item.OnProcessVisual += new ProcessVisual(OnRunicWeaponProcessVisual); QueueRunicVisualApply(item); } } private void OnSideLoaderPacksLoaded() { for (int i = 0; i < RunicWeapons.Length; i++) { ApplyRunicWeaponIconToPrefab(RunicWeapons[i]); } ((MonoBehaviour)this).StartCoroutine(PreloadRunicBladeMaterialWhenReady()); } private void OnRunicWeaponProcessVisual(Item item) { QueueRunicVisualApply(item); } private void QueueRunicVisualApply(Item item) { if (TryGetDefinition(item, out var definition)) { TryRefreshCapturedTextureState(); TryRefreshRunicBladeSourceMaterial(allowLoadedMaterialSearch: true); ApplyRunicVisual(item, definition, logMissingRenderer: false); int instanceID = ((Object)item).GetInstanceID(); if (_pendingVisualRetries.Add(instanceID)) { ((MonoBehaviour)this).StartCoroutine(ApplyRunicVisualWhenReady(item, definition, instanceID)); } } } private IEnumerator ApplyRunicVisualWhenReady(Item item, RunicWeaponDefinition definition, int instanceId) { bool applied = false; for (int i = 0; i < VisualRetryDelays.Length; i++) { float num = VisualRetryDelays[i]; if (num > 0f) { yield return (object)new WaitForSecondsRealtime(num); } else { yield return null; } if ((Object)(object)item == (Object)null) { break; } TryRefreshCapturedTextureState(); TryRefreshRunicBladeSourceMaterial(allowLoadedMaterialSearch: true); applied |= ApplyRunicVisual(item, definition, logMissingRenderer: false); } if (!applied && (Object)(object)item != (Object)null) { ApplyRunicVisual(item, definition, logMissingRenderer: true); } _pendingVisualRetries.Remove(instanceId); } private bool ApplyRunicVisual(Item item, RunicWeaponDefinition definition, bool logMissingRenderer) { if ((Object)(object)item == (Object)null || item.ItemID != definition.ItemId) { return false; } if (ApplyToKnownVisualRoots(item, definition)) { return true; } if (logMissingRenderer && !_loggedNoRenderer) { _loggedNoRenderer = true; Debug.LogWarning((object)"[Runic Arsenal] Could not find a safe runic weapon renderer to recolor."); } return false; } private void TryRefreshRunicBladeSourceMaterial(bool allowLoadedMaterialSearch) { if (!((Object)(object)_runicBladeSourceMaterial != (Object)null)) { Material val = LoadCapturedRunicBladeMaterial(); if ((Object)(object)val == (Object)null) { val = FindRunicBladePrefabMaterial(); } if ((Object)(object)val == (Object)null && allowLoadedMaterialSearch) { val = FindLoadedCapturedRunicBladeMaterial(); } if (!((Object)(object)val == (Object)null)) { _runicBladeSourceMaterial = val; _runicMaterialGeneration++; _materialCache.Clear(); Debug.Log((object)("[Runic Arsenal] Captured Runic Blade material '" + ((Object)val).name + "' with shader '" + ((Object)val.shader).name + "'.")); DumpRunicBladeMaterial(val); RefreshKnownRunicItems(); } } } private IEnumerator PreloadRunicBladeMaterialWhenReady() { float[] delays = new float[5] { 0f, 0.25f, 1f, 2f, 4f }; for (int i = 0; i < delays.Length; i++) { if (delays[i] > 0f) { yield return (object)new WaitForSecondsRealtime(delays[i]); } else { yield return null; } TryRefreshRunicBladeSourceMaterial(allowLoadedMaterialSearch: true); if ((Object)(object)_runicBladeSourceMaterial != (Object)null) { break; } } } private void RefreshKnownRunicItems() { List list = new List(); foreach (KeyValuePair knownRunicItem in _knownRunicItems) { Item value = knownRunicItem.Value; if ((Object)(object)value == (Object)null) { list.Add(knownRunicItem.Key); } else { QueueRunicVisualApply(value); } } for (int i = 0; i < list.Count; i++) { _knownRunicItems.Remove(list[i]); } } private void TryRefreshCapturedTextureState() { bool flag = CapturedRunicBladeTexturesReady(); if (flag != _capturedTexturesReady) { _capturedTexturesReady = flag; if (flag) { _runicMaterialGeneration++; _materialCache.Clear(); Debug.Log((object)"[Runic Arsenal] Captured Runic Blade fallback textures are ready."); } } } private bool TryGetDefinition(Item item, out RunicWeaponDefinition definition) { if ((Object)(object)item == (Object)null) { definition = null; return false; } return _definitionsByItemId.TryGetValue(item.ItemID, out definition); } private void ApplyRunicWeaponIconToPrefab(RunicWeaponDefinition definition) { if (!definition.HasCustomIcon) { return; } try { if (ResourcesPrefabManager.Instance != null) { Item itemPrefab = ResourcesPrefabManager.Instance.GetItemPrefab(definition.ItemId); ApplyRunicWeaponIcon(itemPrefab, definition); } } catch (Exception ex) { LogIconFailure(definition, "Could not apply custom icon to prefab: " + ex.Message); } } private void ApplyRunicWeaponIcon(Item item, RunicWeaponDefinition definition) { if (!definition.HasCustomIcon || (Object)(object)item == (Object)null || item.ItemID != definition.ItemId) { return; } Sprite runicWeaponIcon = GetRunicWeaponIcon(definition); if ((Object)(object)runicWeaponIcon == (Object)null) { return; } try { if (ItemIconField != null) { ItemIconField.SetValue(item, runicWeaponIcon); } if (ItemIconPathField != null) { ItemIconPathField.SetValue(item, definition.IconId); } else { item.ItemIconPath = definition.IconId; } } catch (Exception ex) { LogIconFailure(definition, "Could not apply custom icon: " + ex.Message); } } private Sprite GetRunicWeaponIcon(RunicWeaponDefinition definition) { if (!definition.HasCustomIcon) { return null; } if (_iconCache.TryGetValue(definition.IconId, out var value)) { return value; } string text = Path.Combine(PluginDirectory, definition.IconRelativePath.Replace('/', Path.DirectorySeparatorChar)); if (!File.Exists(text)) { return null; } try { Texture2D val = CustomTextures.LoadTexture(text, false, false); if ((Object)(object)val == (Object)null) { LogIconFailure(definition, "Could not load custom icon from " + text); return null; } ((Object)val).name = definition.IconId; Sprite val2 = CustomTextures.CreateSprite(val, (SpriteBorderTypes)1); ((Object)val2).name = definition.IconId; _iconCache[definition.IconId] = val2; return val2; } catch (Exception ex) { LogIconFailure(definition, "Could not create custom icon: " + ex.Message); return null; } } private void LogIconFailure(RunicWeaponDefinition definition, string message) { string item = (definition.HasCustomIcon ? definition.IconId : definition.InternalName); if (_loggedIconFailures.Add(item)) { Debug.LogWarning((object)("[Runic Arsenal] " + definition.DisplayName + ": " + message)); } } private bool ApplyToKnownVisualRoots(Item item, RunicWeaponDefinition definition) { HashSet visitedRoots = new HashSet(); bool flag = false; bool flag2 = SafeIsInWorld(item); bool flag3 = SafeIsEquipped(item); if (!flag2 && !flag3) { HideKnownItemVisuals(item); return false; } ItemVisual val = SafeGetCurrentVisual(item); if ((Object)(object)val != (Object)null) { flag |= ApplyToVisualRoot(((Component)val).gameObject, definition, visitedRoots); } ItemVisual val2 = SafeGetLoadedVisual(item); if ((Object)(object)val2 != (Object)null) { flag |= ApplyToVisualRoot(((Component)val2).gameObject, definition, visitedRoots); } if (flag2 || flag3) { flag |= ApplyToVisualRoot(((Component)item).gameObject, definition, visitedRoots); } return flag; } private bool ApplyToVisualRoot(GameObject root, RunicWeaponDefinition definition, HashSet visitedRoots) { if ((Object)(object)root == (Object)null) { return false; } int instanceID = ((Object)root).GetInstanceID(); if (!visitedRoots.Add(instanceID)) { return false; } if (definition.ItemId != -2525260) { SetRootRenderersVisible(root, visible: true); } Renderer[] componentsInChildren = root.GetComponentsInChildren(true); return ApplyToRenderers(componentsInChildren, definition, requireVisualName: true); } private static ItemVisual SafeGetCurrentVisual(Item item) { try { return item.CurrentVisual; } catch { return null; } } private static ItemVisual SafeGetLoadedVisual(Item item) { try { return item.LoadedVisual; } catch { return null; } } private static bool SafeIsInWorld(Item item) { try { return (Object)(object)item != (Object)null && item.IsInWorld; } catch { return false; } } private static bool SafeIsEquipped(Item item) { try { return (Object)(object)item != (Object)null && item.IsEquipped; } catch { return false; } } private static void HideKnownItemVisuals(Item item) { ItemVisual val = SafeGetCurrentVisual(item); if ((Object)(object)val != (Object)null) { SafeHideVisual(val); } ItemVisual val2 = SafeGetLoadedVisual(item); if ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)val) { SafeHideVisual(val2); } if ((Object)(object)item != (Object)null) { SetRootRenderersVisible(((Component)item).gameObject, visible: false); } } private static void SafeHideVisual(ItemVisual visual) { try { visual.Hide(); } catch { } } private static void SetRootRenderersVisible(GameObject root, bool visible) { if ((Object)(object)root == (Object)null) { return; } try { Renderer[] componentsInChildren = root.GetComponentsInChildren(true); if (componentsInChildren == null) { return; } foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !(val is TrailRenderer) && !(val is LineRenderer) && !(val is ParticleSystemRenderer)) { val.enabled = visible; } } } catch { } } private static void HideRunicChakramVisualsAfterUnequip(Equipment equipment, Character character) { if (!((Object)(object)equipment == (Object)null) && ((Item)equipment).ItemID == -2525260) { HideKnownItemVisuals((Item)(object)equipment); HideRunicChakramVisualSlot(character); } } private static void HideRunicChakramVisualSlot(Character character) { Transform val = SafeGetEquipmentVisualSlot(character, (EquipmentSlotIDs)6); if (!((Object)(object)val == (Object)null)) { HideRunicChakramRenderers(val); } } private static Transform SafeGetEquipmentVisualSlot(Character character, EquipmentSlotIDs slotId) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)character == (Object)null || (Object)(object)character.Inventory == (Object)null) { return null; } return character.Inventory.GetEquipmentVisualSlotTransform(slotId); } catch { return null; } } private static void HideRunicChakramRenderers(Transform root) { if ((Object)(object)root == (Object)null) { return; } try { Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); if (componentsInChildren == null) { return; } foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !(val is TrailRenderer) && !(val is LineRenderer) && !(val is ParticleSystemRenderer) && IsRunicChakramRenderer(val)) { val.enabled = false; } } } catch { } } private static bool IsRunicChakramRenderer(Renderer renderer) { if ((Object)(object)renderer == (Object)null) { return false; } if (HasRunicChakramVisualName(((Component)renderer).transform)) { return true; } Material[] sharedMaterials = renderer.sharedMaterials; if (sharedMaterials == null) { return false; } foreach (Material val in sharedMaterials) { if ((((Object)(object)val == (Object)null) ? string.Empty : ((Object)val).name).StartsWith("MEROFOS_RunicArsenal_", StringComparison.Ordinal)) { return true; } } return false; } private static bool HasRunicChakramVisualName(Transform transform) { Transform val = transform; while ((Object)(object)val != (Object)null) { string text = ((((Object)val).name == null) ? string.Empty : ((Object)val).name.ToLowerInvariant()); if (text.Contains("chakram") || text.Contains("-2525260") || text.Contains("2525260")) { return true; } val = val.parent; } return false; } private bool ApplyToRenderers(Renderer[] renderers, RunicWeaponDefinition definition, bool requireVisualName) { bool result = false; foreach (Renderer val in renderers) { if (!ShouldPatchRenderer(val, definition, requireVisualName)) { continue; } Material[] sharedMaterials = val.sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { continue; } Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; bool flag = false; for (int j = 0; j < sharedMaterials.Length; j++) { Material val2 = sharedMaterials[j]; if ((Object)(object)val2 == (Object)null || ShouldSkipMaterial(val2)) { array[j] = val2; continue; } if (IsRunicArsenalMaterial(val2) && !ShouldRefreshRunicMaterial(val2)) { array[j] = val2; continue; } array[j] = GetRunicMaterial(val2, definition); flag = true; } if (flag) { val.sharedMaterials = array; result = true; } } return result; } private Material GetRunicMaterial(Material original, RunicWeaponDefinition definition) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown string text = ((Object)original).name ?? string.Empty; string key = definition.ItemId + ":" + ((Object)original).GetInstanceID(); if (_materialCache.TryGetValue(key, out var value) && (Object)(object)value != (Object)null) { return value; } Material val = new Material(original); ((Object)val).name = "MEROFOS_RunicArsenal_" + definition.InternalName + "_" + text; Material runicBladeSourceMaterial = GetRunicBladeSourceMaterial(); if ((Object)(object)runicBladeSourceMaterial != (Object)null) { val = new Material(runicBladeSourceMaterial); ((Object)val).name = "MEROFOS_RunicArsenal_Exact_" + ((Object)runicBladeSourceMaterial).name; } else { ApplyCapturedRunicBladeMaterial(val); } _materialCache[key] = val; return val; } private bool ShouldRefreshRunicMaterial(Material material) { string text = ((Object)material).name ?? string.Empty; if ((Object)(object)_runicBladeSourceMaterial != (Object)null && !text.StartsWith("MEROFOS_RunicArsenal_Exact_", StringComparison.Ordinal)) { return true; } if (CapturedRunicBladeTexturesReady() && text.StartsWith("MEROFOS_RunicArsenal_Captured_", StringComparison.Ordinal)) { if (HasTexture(material, "_MainTex") && HasTexture(material, "_NormalMap")) { return !HasTexture(material, "_DistortMap"); } return true; } return false; } private Material GetRunicBladeSourceMaterial() { if ((Object)(object)_runicBladeSourceMaterial != (Object)null) { return _runicBladeSourceMaterial; } TryRefreshRunicBladeSourceMaterial(allowLoadedMaterialSearch: true); return _runicBladeSourceMaterial; } private static void ApplyRunicShader(Material material) { Shader val = Shader.Find("Custom/Distort/DistortTextureSpec"); if ((Object)(object)val != (Object)null) { material.shader = val; } } private static Material LoadCapturedRunicBladeMaterial() { string[] array = new string[5] { "mat_itm_crystalBladeRunicBladeLight", "Materials/mat_itm_crystalBladeRunicBladeLight", "_Materials/mat_itm_crystalBladeRunicBladeLight", "Items/mat_itm_crystalBladeRunicBladeLight", "Weapons/mat_itm_crystalBladeRunicBladeLight" }; for (int i = 0; i < array.Length; i++) { Material val = Resources.Load(array[i]); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static Material FindLoadedCapturedRunicBladeMaterial() { Material[] array = Resources.FindObjectsOfTypeAll(); foreach (Material val in array) { if (!((Object)(object)val == (Object)null) && ((Object)val).name != null && !((Object)val).name.StartsWith("MEROFOS_RunicArsenal_", StringComparison.Ordinal)) { string name = ((Object)val).name; if (string.Equals(name, "mat_itm_crystalBladeRunicBladeLight", StringComparison.Ordinal) || name.StartsWith("mat_itm_crystalBladeRunicBladeLight ", StringComparison.Ordinal) || name.StartsWith("mat_itm_crystalBladeRunicBladeLight(", StringComparison.Ordinal)) { return val; } } } return null; } private Material FindRunicBladePrefabMaterial() { try { if (ResourcesPrefabManager.Instance == null) { return null; } return FindMaterialOnItem(ResourcesPrefabManager.Instance.GetItemPrefab(2000100)); } catch (Exception ex) { if (!_loggedPrefabMaterialFailure) { _loggedPrefabMaterialFailure = true; Debug.LogWarning((object)("[Runic Arsenal] Could not inspect vanilla Runic Blade prefab material: " + ex.Message)); } } return null; } private static Material FindMaterialOnItem(Item item) { if ((Object)(object)item == (Object)null) { return null; } Material val = FindMaterialInRenderers(((Component)item).GetComponentsInChildren(true)); if ((Object)(object)val != (Object)null) { return val; } ItemVisual val2 = SafeGetCurrentVisual(item); if ((Object)(object)val2 != (Object)null) { val = FindMaterialInRenderers(((Component)val2).GetComponentsInChildren(true)); if ((Object)(object)val != (Object)null) { return val; } } ItemVisual val3 = SafeGetLoadedVisual(item); if ((Object)(object)val3 != (Object)null) { val = FindMaterialInRenderers(((Component)val3).GetComponentsInChildren(true)); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static Material FindMaterialInRenderers(Renderer[] renderers) { if (renderers == null) { return null; } foreach (Renderer val in renderers) { if ((Object)(object)val == (Object)null || val is TrailRenderer || val is LineRenderer || val is ParticleSystemRenderer) { continue; } Material[] sharedMaterials = val.sharedMaterials; if (sharedMaterials == null) { continue; } foreach (Material val2 in sharedMaterials) { if ((Object)(object)val2 != (Object)null && IsCapturedRunicBladeMaterialName(((Object)val2).name)) { return val2; } } } return null; } private static bool IsCapturedRunicBladeMaterialName(string materialName) { if (string.IsNullOrEmpty(materialName)) { return false; } if (materialName.StartsWith("MEROFOS_RunicArsenal_", StringComparison.Ordinal)) { return false; } if (!string.Equals(materialName, "mat_itm_crystalBladeRunicBladeLight", StringComparison.Ordinal) && !materialName.StartsWith("mat_itm_crystalBladeRunicBladeLight ", StringComparison.Ordinal) && !materialName.StartsWith("mat_itm_crystalBladeRunicBladeLight(", StringComparison.Ordinal) && !materialName.StartsWith("MEROFOS_PermanentRunicBlades_Exact_mat_itm_crystalBladeRunicBladeLight", StringComparison.Ordinal)) { return materialName.StartsWith("MEROFOS_RunicDagger_Exact_mat_itm_crystalBladeRunicBladeLight", StringComparison.Ordinal); } return true; } private static void ApplyCapturedRunicBladeMaterial(Material material) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) ((Object)material).name = "MEROFOS_RunicArsenal_Captured_mat_itm_crystalBladeRunicBladeLight"; material.renderQueue = 2000; ApplyRunicShader(material); SetTexture(material, "_MainTex", GetCapturedMainTexture()); SetTexture(material, "_NormalMap", GetCapturedWaveTexture()); SetTexture(material, "_DistortMap", GetCapturedWaveTexture()); SetColor(material, "_Color", new Color(14.55578f, 6.948529f, 15f, 1f)); SetColor(material, "_SpecColor", new Color(0.3455882f, 0.3455882f, 0.3455882f, 0.759f)); SetFloat(material, "_NormalStrength", 1f); SetFloat(material, "_Speed", 1f); SetFloat(material, "_Scale", 2f); SetFloat(material, "_MaskPow", 0f); material.shaderKeywords = new string[2] { "_ALPHATEST_ON", "_NORMALMAP" }; material.EnableKeyword("_ALPHATEST_ON"); material.EnableKeyword("_NORMALMAP"); } private static void DumpRunicBladeMaterial(Material material) { try { string text = Path.Combine(Paths.ConfigPath, "MEROFOS.RunicArsenal.RunicBladeMaterialDump.txt"); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Runic Arsenal - captured Runic Blade material"); stringBuilder.AppendLine("Generated: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); stringBuilder.AppendLine("Material: " + SafeName((Object)(object)material)); stringBuilder.AppendLine("Shader: " + (((Object)(object)material.shader == (Object)null) ? "" : SafeName((Object)(object)material.shader))); stringBuilder.AppendLine("RenderQueue: " + material.renderQueue); stringBuilder.AppendLine("Keywords: " + string.Join(", ", material.shaderKeywords ?? new string[0])); stringBuilder.AppendLine(); stringBuilder.AppendLine("[Textures]"); AppendTexture(stringBuilder, material, "_MainTex"); AppendTexture(stringBuilder, material, "_BumpMap"); AppendTexture(stringBuilder, material, "_NormalMap"); AppendTexture(stringBuilder, material, "_DistortMap"); AppendTexture(stringBuilder, material, "_EmissionMap"); stringBuilder.AppendLine(); stringBuilder.AppendLine("[Colors]"); AppendColor(stringBuilder, material, "_Color"); AppendColor(stringBuilder, material, "_SpecColor"); AppendColor(stringBuilder, material, "_EmissionColor"); AppendColor(stringBuilder, material, "_TintColor"); stringBuilder.AppendLine(); stringBuilder.AppendLine("[Floats]"); AppendFloat(stringBuilder, material, "_NormalStrength"); AppendFloat(stringBuilder, material, "_Speed"); AppendFloat(stringBuilder, material, "_Scale"); AppendFloat(stringBuilder, material, "_MaskPow"); AppendFloat(stringBuilder, material, "_EmissionIntensity"); AppendFloat(stringBuilder, material, "_EmissionPower"); AppendFloat(stringBuilder, material, "_Glow"); AppendFloat(stringBuilder, material, "_GlowIntensity"); AppendFloat(stringBuilder, material, "_Intensity"); AppendFloat(stringBuilder, material, "_Glossiness"); AppendFloat(stringBuilder, material, "_Metallic"); File.WriteAllText(text, stringBuilder.ToString()); Debug.Log((object)("[Runic Arsenal] Wrote Runic Blade material dump to " + text)); } catch (Exception ex) { Debug.LogWarning((object)("[Runic Arsenal] Could not write Runic Blade material dump: " + ex.Message)); } } private static void AppendTexture(StringBuilder builder, Material material, string propertyName) { if (!material.HasProperty(propertyName)) { builder.AppendLine(propertyName + " = "); return; } Texture texture = material.GetTexture(propertyName); builder.AppendLine(propertyName + " = " + (((Object)(object)texture == (Object)null) ? "" : SafeName((Object)(object)texture))); } private static void AppendColor(StringBuilder builder, Material material, string propertyName) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (!material.HasProperty(propertyName)) { builder.AppendLine(propertyName + " = "); return; } Color color = material.GetColor(propertyName); builder.AppendLine(propertyName + " = " + color.r + ", " + color.g + ", " + color.b + ", " + color.a); } private static void AppendFloat(StringBuilder builder, Material material, string propertyName) { if (!material.HasProperty(propertyName)) { builder.AppendLine(propertyName + " = "); } else { builder.AppendLine(propertyName + " = " + material.GetFloat(propertyName)); } } private static string SafeName(Object obj) { if (!(obj == (Object)null)) { return obj.name; } return ""; } private static bool CapturedRunicBladeTexturesReady() { if ((Object)(object)GetCapturedMainTexture() != (Object)null) { return (Object)(object)GetCapturedWaveTexture() != (Object)null; } return false; } private static Texture GetCapturedMainTexture() { if ((Object)(object)s_capturedMainTexture == (Object)null) { s_capturedMainTexture = FindTexture("tex_fx_PerlinNoiseGray"); } return s_capturedMainTexture; } private static Texture GetCapturedWaveTexture() { if ((Object)(object)s_capturedWaveTexture == (Object)null) { s_capturedWaveTexture = FindTexture("tex_env_waterWave_n"); } return s_capturedWaveTexture; } private static Texture FindTexture(string textureName) { string[] array = new string[6] { textureName, "Textures/" + textureName, "_Textures/" + textureName, "FX/" + textureName, "VFX/" + textureName, "Environment/" + textureName }; for (int i = 0; i < array.Length; i++) { Texture val = Resources.Load(array[i]); if ((Object)(object)val != (Object)null) { return val; } } Texture[] array2 = Resources.FindObjectsOfTypeAll(); foreach (Texture val2 in array2) { if ((Object)(object)val2 != (Object)null && string.Equals(((Object)val2).name, textureName, StringComparison.Ordinal)) { return val2; } } if (!s_missingTextureWarnings.Contains(textureName)) { s_missingTextureWarnings.Add(textureName); Debug.LogWarning((object)("[Runic Arsenal] Could not find texture '" + textureName + "' for captured Runic Blade material.")); } return null; } private static void SetColor(Material material, string propertyName, Color value) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (material.HasProperty(propertyName)) { material.SetColor(propertyName, value); } } private static void SetFloat(Material material, string propertyName, float value) { if (material.HasProperty(propertyName)) { material.SetFloat(propertyName, value); } } private static void SetTexture(Material material, string propertyName, Texture texture) { if ((Object)(object)texture != (Object)null && material.HasProperty(propertyName)) { material.SetTexture(propertyName, texture); } } private static bool HasTexture(Material material, string propertyName) { if (material.HasProperty(propertyName)) { return (Object)(object)material.GetTexture(propertyName) != (Object)null; } return false; } private static bool IsRunicArsenalMaterial(Material material) { if ((Object)(object)material != (Object)null && ((Object)material).name != null) { return ((Object)material).name.StartsWith("MEROFOS_RunicArsenal_", StringComparison.Ordinal); } return false; } private static bool ShouldPatchRenderer(Renderer renderer, RunicWeaponDefinition definition, bool requireVisualName) { if ((Object)(object)renderer == (Object)null || renderer is TrailRenderer || renderer is LineRenderer || renderer is ParticleSystemRenderer) { return false; } if (requireVisualName && !HasRunicWeaponVisualName(((Component)renderer).transform, definition)) { return false; } string text = ((((Object)renderer).name == null) ? string.Empty : ((Object)renderer).name.ToLowerInvariant()); if (!text.Contains("highlight") && !text.Contains("trail") && !text.Contains("linecast") && !text.Contains("gateframe") && !text.Contains("hair") && !text.Contains("head")) { return !text.Contains("face"); } return false; } private static bool ShouldSkipMaterial(Material material) { string text = ((((Object)material).name == null) ? string.Empty : ((Object)material).name.ToLowerInvariant()); if (!text.Contains("hair") && !text.Contains("skin") && !text.Contains("head") && !text.Contains("face") && !text.Contains("beard")) { return text.StartsWith("mat_cha_", StringComparison.Ordinal); } return true; } private static bool HasRunicWeaponVisualName(Transform transform, RunicWeaponDefinition definition) { Transform val = transform; while ((Object)(object)val != (Object)null) { string lowerInvariantName = ((((Object)val).name == null) ? string.Empty : ((Object)val).name.ToLowerInvariant()); if (definition.MatchesVisualName(lowerInvariantName)) { return true; } val = val.parent; } return false; } }