Decompiled source of CraftableRunicBlades v0.1.6

plugins/CraftableRunicBlades.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using SideLoader;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace CraftableRunicBlades;

[BepInPlugin("com.merofos.outward.craftablerunicblades", "Craftable Runic Blades", "0.1.4")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class CraftableRunicBladesPlugin : BaseUnityPlugin
{
	private sealed class RunicWeaponDefinition
	{
		public readonly int ItemId;

		public readonly string Marker;

		public readonly string DisplayName;

		public readonly string IconRelativePath;

		public readonly string IconId;

		public readonly string[] VisualNameTokens;

		public RunicWeaponDefinition(int itemId, string marker, string displayName, string iconRelativePath, string iconId, params string[] visualNameTokens)
		{
			ItemId = itemId;
			Marker = marker;
			DisplayName = displayName;
			IconRelativePath = iconRelativePath;
			IconId = iconId;
			VisualNameTokens = visualNameTokens;
		}
	}

	private const string PluginGuid = "com.merofos.outward.craftablerunicblades";

	private const string SideLoaderGuid = "com.sinai.SideLoader";

	private const string PluginName = "Craftable Runic Blades";

	private const string PluginVersion = "0.1.4";

	private const int VanillaRunicBladeItemId = 2000100;

	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 float[] VisualRetryDelays = new float[8] { 0f, 0.1f, 0.25f, 0.5f, 1f, 2f, 4f, 8f };

	private static readonly HashSet<string> s_missingTextureWarnings = new HashSet<string>();

	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 static readonly RunicWeaponDefinition[] WeaponDefinitions = new RunicWeaponDefinition[2]
	{
		new RunicWeaponDefinition(-2525300, "RunicBlade", "Runic Blade", "SideLoader/Items/-2525300-Runic_Blade/runic_blade_item_icon.png", "MEROFOS_CraftableRunicBladeIcon", "2000090", "oldlegiongladius", "old legion gladius", "runicblade", "runic blade", "-2525300", "2525300"),
		new RunicWeaponDefinition(-2525310, "GreatRunicBlade", "Great Runic Blade", "SideLoader/Items/-2525310-Great_Runic_Blade/great_runic_blade_item_icon.png", "MEROFOS_CraftableGreatRunicBladeIcon", "2100130", "pathfinderclaymore", "pathfinder claymore", "greatrunicblade", "great runic blade", "-2525310", "2525310")
	};

	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<string> _loggedIconFailures = new HashSet<string>();

	private readonly HashSet<int> _pendingVisualRetries = new HashSet<int>();

	private Material _runicBladeSourceMaterial;

	private bool _capturedTexturesReady;

	private bool _loggedNoRenderer;

	private int _runicMaterialGeneration;

	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()
	{
		SL.OnPacksLoaded += OnSideLoaderPacksLoaded;
		for (int i = 0; i < WeaponDefinitions.Length; i++)
		{
			SL_Item.AddOnInstanceStartListener(WeaponDefinitions[i].ItemId, (Action<Item>)OnRunicWeaponInstanceStart);
		}
		TryRefreshCapturedTextureState();
		TryRefreshRunicBladeSourceMaterial(allowLoadedMaterialSearch: false);
		Debug.Log((object)"[Craftable Runic Blades] Loaded.");
	}

	private void OnSideLoaderPacksLoaded()
	{
		for (int i = 0; i < WeaponDefinitions.Length; i++)
		{
			ApplyRunicWeaponIconToPrefab(WeaponDefinitions[i]);
		}
		((MonoBehaviour)this).StartCoroutine(PreloadRunicBladeMaterialWhenReady());
	}

	private void OnRunicWeaponInstanceStart(Item item)
	{
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Expected O, but got Unknown
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Expected O, but got Unknown
		RunicWeaponDefinition runicWeaponDefinition = FindDefinition(item);
		if (runicWeaponDefinition != null)
		{
			ApplyRunicWeaponIcon(item, runicWeaponDefinition);
			_knownRunicItems[((Object)item).GetInstanceID()] = item;
			item.OnProcessVisual -= new ProcessVisual(OnRunicWeaponProcessVisual);
			item.OnProcessVisual += new ProcessVisual(OnRunicWeaponProcessVisual);
			QueueRunicVisualApply(item);
		}
	}

	private void OnRunicWeaponProcessVisual(Item item)
	{
		QueueRunicVisualApply(item);
	}

	private void QueueRunicVisualApply(Item item)
	{
		RunicWeaponDefinition runicWeaponDefinition = FindDefinition(item);
		if (runicWeaponDefinition != null)
		{
			TryRefreshCapturedTextureState();
			TryRefreshRunicBladeSourceMaterial(allowLoadedMaterialSearch: true);
			ApplyRunicVisual(item, runicWeaponDefinition, logMissingRenderer: false);
			int instanceID = ((Object)item).GetInstanceID();
			if (_pendingVisualRetries.Add(instanceID))
			{
				((MonoBehaviour)this).StartCoroutine(ApplyRunicVisualWhenReady(item, runicWeaponDefinition.ItemId, instanceID));
			}
		}
	}

	private IEnumerator ApplyRunicVisualWhenReady(Item item, int itemId, int instanceId)
	{
		bool applied = false;
		RunicWeaponDefinition definition = FindDefinition(itemId);
		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 || definition == null)
			{
				break;
			}
			TryRefreshCapturedTextureState();
			TryRefreshRunicBladeSourceMaterial(allowLoadedMaterialSearch: true);
			applied |= ApplyRunicVisual(item, definition, logMissingRenderer: false);
		}
		if (!applied && (Object)(object)item != (Object)null && definition != null)
		{
			ApplyRunicVisual(item, definition, logMissingRenderer: true);
		}
		_pendingVisualRetries.Remove(instanceId);
	}

	private bool ApplyRunicVisual(Item item, RunicWeaponDefinition definition, bool logMissingRenderer)
	{
		if ((Object)(object)item == (Object)null || definition == null || item.ItemID != definition.ItemId)
		{
			return false;
		}
		if (ApplyToKnownVisualRoots(item, definition))
		{
			return true;
		}
		if (logMissingRenderer && !_loggedNoRenderer)
		{
			_loggedNoRenderer = true;
			Debug.LogWarning((object)"[Craftable Runic Blades] Could not find a safe 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)("[Craftable Runic Blades] Captured Runic Blade material '" + ((Object)val).name + "' with shader '" + ((Object)val.shader).name + "'."));
				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 ApplyRunicWeaponIconToPrefab(RunicWeaponDefinition definition)
	{
		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 ((Object)(object)item == (Object)null || definition == 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 (_iconCache.TryGetValue(definition.IconId, out var value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		string text = Path.Combine(PluginDirectory, definition.IconRelativePath.Replace('/', Path.DirectorySeparatorChar));
		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 == null) ? "unknown" : definition.IconId);
		if (_loggedIconFailures.Add(item))
		{
			Debug.LogWarning((object)("[Craftable Runic Blades] " + message));
		}
	}

	private void TryRefreshCapturedTextureState()
	{
		bool flag = CapturedRunicBladeTexturesReady();
		if (flag != _capturedTexturesReady)
		{
			_capturedTexturesReady = flag;
			if (flag)
			{
				_runicMaterialGeneration++;
				_materialCache.Clear();
				Debug.Log((object)"[Craftable Runic Blades] Captured Runic Blade fallback textures are ready.");
			}
		}
	}

	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, visitedRoots, definition);
		}
		ItemVisual val2 = SafeGetLoadedVisual(item);
		if ((Object)(object)val2 != (Object)null)
		{
			flag |= ApplyToVisualRoot(((Component)val2).gameObject, visitedRoots, definition);
		}
		if (flag2)
		{
			flag |= ApplyToVisualRoot(((Component)item).gameObject, visitedRoots, definition);
		}
		return flag;
	}

	private bool ApplyToVisualRoot(GameObject root, HashSet<int> visitedRoots, RunicWeaponDefinition definition)
	{
		if ((Object)(object)root == (Object)null)
		{
			return false;
		}
		int instanceID = ((Object)root).GetInstanceID();
		if (!visitedRoots.Add(instanceID))
		{
			return false;
		}
		Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
		if (!ApplyToRenderers(componentsInChildren, definition, requireVisualName: true))
		{
			return ApplyToRenderers(componentsInChildren, definition, requireVisualName: false);
		}
		return true;
	}

	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;
				}
				else if (IsPermanentRunicBladeMaterial(val2) && !ShouldRefreshRunicMaterial(val2))
				{
					result = true;
					array[j] = val2;
				}
				else
				{
					array[j] = GetRunicMaterial(val2, definition);
					flag = true;
					result = true;
				}
			}
			if (flag)
			{
				val.sharedMaterials = array;
			}
		}
		return result;
	}

	private Material GetRunicMaterial(Material original, RunicWeaponDefinition definition)
	{
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Expected O, but got Unknown
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Expected O, but got Unknown
		string text = ((Object)original).name ?? string.Empty;
		int itemId = definition.ItemId;
		string key = itemId + "|" + ((Object)original).GetInstanceID();
		if (_materialCache.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		Material runicBladeSourceMaterial = GetRunicBladeSourceMaterial();
		Material val;
		if ((Object)(object)runicBladeSourceMaterial != (Object)null)
		{
			val = new Material(runicBladeSourceMaterial);
			((Object)val).name = "MEROFOS_PermanentRunicBlades_Exact_" + definition.Marker + "_" + ((Object)runicBladeSourceMaterial).name;
		}
		else
		{
			val = new Material(original);
			ApplyCapturedRunicBladeMaterial(val, definition.Marker);
			Material obj = val;
			((Object)obj).name = ((Object)obj).name + "_" + text;
		}
		_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_PermanentRunicBlades_Captured_", StringComparison.Ordinal))
		{
			return true;
		}
		if (CapturedRunicBladeTexturesReady() && text.StartsWith("MEROFOS_PermanentRunicBlades_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_PermanentRunicBlades_", 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;
			}
			Material val = FindMaterialOnItem(ResourcesPrefabManager.Instance.GetItemPrefab(2000100));
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
		}
		catch (Exception ex)
		{
			if (!_loggedPrefabMaterialFailure)
			{
				_loggedPrefabMaterialFailure = true;
				Debug.LogWarning((object)("[Craftable Runic Blades] 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_PermanentRunicBlades_", 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_RunicDagger_Exact_mat_itm_crystalBladeRunicBladeLight", StringComparison.Ordinal))
		{
			return materialName.StartsWith("MEROFOS_RunicArsenal_Exact_mat_itm_crystalBladeRunicBladeLight", StringComparison.Ordinal);
		}
		return true;
	}

	private static void ApplyCapturedRunicBladeMaterial(Material material, string marker)
	{
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		((Object)material).name = "MEROFOS_PermanentRunicBlades_Captured_" + marker + "_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 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)("[Craftable Runic Blades] 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 IsPermanentRunicBladeMaterial(Material material)
	{
		if ((Object)(object)material != (Object)null && ((Object)material).name != null)
		{
			return ((Object)material).name.StartsWith("MEROFOS_PermanentRunicBlades_", 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 text = ((((Object)val).name == null) ? string.Empty : ((Object)val).name.ToLowerInvariant());
			for (int i = 0; i < definition.VisualNameTokens.Length; i++)
			{
				if (text.Contains(definition.VisualNameTokens[i]))
				{
					return true;
				}
			}
			val = val.parent;
		}
		return false;
	}

	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);
		}
	}

	private static void SafeHideVisual(ItemVisual visual)
	{
		try
		{
			visual.Hide();
		}
		catch
		{
		}
	}

	private static RunicWeaponDefinition FindDefinition(Item item)
	{
		if ((Object)(object)item == (Object)null)
		{
			return null;
		}
		return FindDefinition(item.ItemID);
	}

	private static RunicWeaponDefinition FindDefinition(int itemId)
	{
		for (int i = 0; i < WeaponDefinitions.Length; i++)
		{
			if (WeaponDefinitions[i].ItemId == itemId)
			{
				return WeaponDefinitions[i];
			}
		}
		return null;
	}
}