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<string> s_missingTextureWarnings = new HashSet<string>();
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<int, RunicWeaponDefinition> _definitionsByItemId = new Dictionary<int, RunicWeaponDefinition>();
private readonly Dictionary<string, Material> _materialCache = new Dictionary<string, Material>();
private readonly Dictionary<string, Sprite> _iconCache = new Dictionary<string, Sprite>();
private readonly Dictionary<int, Item> _knownRunicItems = new Dictionary<int, Item>();
private readonly HashSet<int> _pendingVisualRetries = new HashSet<int>();
private readonly HashSet<string> _loggedIconFailures = new HashSet<string>();
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<Item>)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<int> list = new List<int>();
foreach (KeyValuePair<int, Item> 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<int> visitedRoots = new HashSet<int>();
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<int> 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<Renderer>(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<Renderer>(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<Renderer>(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<Material>(array[i]);
if ((Object)(object)val != (Object)null)
{
return val;
}
}
return null;
}
private static Material FindLoadedCapturedRunicBladeMaterial()
{
Material[] array = Resources.FindObjectsOfTypeAll<Material>();
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<Renderer>(true));
if ((Object)(object)val != (Object)null)
{
return val;
}
ItemVisual val2 = SafeGetCurrentVisual(item);
if ((Object)(object)val2 != (Object)null)
{
val = FindMaterialInRenderers(((Component)val2).GetComponentsInChildren<Renderer>(true));
if ((Object)(object)val != (Object)null)
{
return val;
}
}
ItemVisual val3 = SafeGetLoadedVisual(item);
if ((Object)(object)val3 != (Object)null)
{
val = FindMaterialInRenderers(((Component)val3).GetComponentsInChildren<Renderer>(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) ? "<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 + " = <missing>");
return;
}
Texture texture = material.GetTexture(propertyName);
builder.AppendLine(propertyName + " = " + (((Object)(object)texture == (Object)null) ? "<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 + " = <missing>");
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 + " = <missing>");
}
else
{
builder.AppendLine(propertyName + " = " + material.GetFloat(propertyName));
}
}
private static string SafeName(Object obj)
{
if (!(obj == (Object)null))
{
return obj.name;
}
return "<null>";
}
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<Texture>(array[i]);
if ((Object)(object)val != (Object)null)
{
return val;
}
}
Texture[] array2 = Resources.FindObjectsOfTypeAll<Texture>();
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;
}
}