Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ShadowPersonMaterialFix v1.1.0
ShadowPersonMaterialFix/ShadowPersonMaterialFix.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using ShadowPersonFix.Patches; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("nezuma")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0+6cd044a0222d0f42c1644522c7ed0d07b0228ddd")] [assembly: AssemblyProduct("ShadowPersonMaterialFix")] [assembly: AssemblyTitle("ShadowPersonMaterialFix")] [assembly: AssemblyVersion("1.1.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ShadowPersonFix { internal static class PluginConstants { public const string Guid = "ru.nezuma.valheim.shadowpersonfix"; public const string Name = "ShadowPerson Material Fix"; public const string Version = "1.0.0"; } internal static class PluginState { public static Shader Shader { get; set; } } internal sealed class ShaderFinder { private const int RequiredPropertyCount = 5; private static readonly string[] CandidateNames = new string[8] { "Custom/Creature", "Custom/Player", "Custom/Character", "Custom/Lit", "Custom/Prop", "Custom/StaticRock", "Custom/Vegetation", "Custom/Standard" }; private static readonly string[] TrackedProperties = new string[7] { "_SkinBumpMap", "_ChestTex", "_ChestBumpMap", "_LegsTex", "_LegsBumpMap", "_ChestMetal", "_LegsMetal" }; private readonly ManualLogSource _log; private bool _warningLogged; public ShaderFinder(ManualLogSource log) { _log = log; } public Shader Find() { return FindByName() ?? FindByScan(); } private Shader FindByName() { string[] candidateNames = CandidateNames; foreach (string text in candidateNames) { try { Shader val = Shader.Find(text); if ((Object)(object)val != (Object)null && HasEnoughProperties(val)) { _log.LogInfo((object)("Найден хороший шейдер через Shader.Find: '" + ((Object)val).name + "'")); return val; } } catch { } } return null; } private Shader FindByScan() { Shader val = null; int num = 0; try { Shader[] array = Resources.FindObjectsOfTypeAll<Shader>(); foreach (Shader val2 in array) { if (!((Object)(object)val2 == (Object)null)) { int num2 = CountTrackedProperties(val2); if (num2 >= 5 && num2 > num) { num = num2; val = val2; } } } } catch (Exception ex) { _log.LogError((object)("Ошибка поиска шейдеров: " + ex.Message)); } if ((Object)(object)val != (Object)null) { _log.LogInfo((object)$"Найден хороший шейдер сканированием: '{((Object)val).name}' с {num}/7 свойствами"); } else if (!_warningLogged) { _warningLogged = true; _log.LogWarning((object)"Не найден подходящий шейдер. Продолжаю искать..."); } return val; } private static bool HasEnoughProperties(Shader shader) { return CountTrackedProperties(shader) >= 5; } private static int CountTrackedProperties(Shader shader) { int num = 0; try { string[] trackedProperties = TrackedProperties; foreach (string name in trackedProperties) { if (HasProperty(shader, name)) { num++; } } } catch { } return num; } private static bool HasProperty(Shader shader, string name) { try { int propertyCount = shader.GetPropertyCount(); for (int i = 0; i < propertyCount; i++) { if (shader.GetPropertyName(i) == name) { return true; } } } catch { } return false; } } [BepInPlugin("ru.nezuma.valheim.shadowpersonfix", "ShadowPerson Material Fix", "1.0.0")] public sealed class ShadowPersonFixPlugin : BaseUnityPlugin { private ShadowPersonMaterialUpdater _materialUpdater; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ShaderFinder finder = new ShaderFinder(Log); _materialUpdater = new ShadowPersonMaterialUpdater(Log, finder); Harmony val = new Harmony("ru.nezuma.valheim.shadowpersonfix"); val.PatchAll(typeof(RendererMaterialPatch).Assembly); Log.LogInfo((object)"ShadowPerson Material Fix v1.0.0 загружен. Шейдер будет найден при первом обращении."); } private void Update() { _materialUpdater.Tick(); } } internal sealed class ShadowPersonMaterialUpdater { private const float SearchInterval = 5f; private const string TargetPrefix = "ShadowPerson"; private readonly ManualLogSource _log; private readonly ShaderFinder _finder; private readonly List<Material> _fixedMaterials = new List<Material>(); private float _lastSearchTime; public ShadowPersonMaterialUpdater(ManualLogSource log, ShaderFinder finder) { _log = log; _finder = finder; } public void Tick() { if ((Object)(object)PluginState.Shader == (Object)null) { if (Time.time - _lastSearchTime < 5f) { return; } _lastSearchTime = Time.time; PluginState.Shader = _finder.Find(); if ((Object)(object)PluginState.Shader == (Object)null) { return; } } UpdateAllMaterials(); } private void UpdateAllMaterials() { Material[] array; try { array = Resources.FindObjectsOfTypeAll<Material>(); } catch { return; } Material[] array2 = array; foreach (Material material in array2) { TryReplaceShader(material); } } private void TryReplaceShader(Material material) { if (!ShouldProcess(material)) { return; } Shader shader = PluginState.Shader; if ((Object)(object)shader == (Object)null || (Object)(object)material.shader == (Object)(object)shader) { return; } try { Shader shader2 = material.shader; material.shader = shader; _fixedMaterials.Add(material); _log.LogInfo((object)("Подменил шейдер у '" + ((Object)material).name + "': '" + ((shader2 != null) ? ((Object)shader2).name : null) + "' → '" + ((Object)shader).name + "'")); } catch { } } private bool ShouldProcess(Material material) { if ((Object)(object)material == (Object)null) { return false; } if (string.IsNullOrEmpty(((Object)material).name)) { return false; } if (_fixedMaterials.Contains(material)) { return false; } return ((Object)material).name.IndexOf("ShadowPerson", StringComparison.OrdinalIgnoreCase) >= 0; } } } namespace ShadowPersonFix.Patches { [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class RendererMaterialPatch { [HarmonyPrefix] private static void Prefix(Renderer __instance) { try { Material sharedMaterial = __instance.sharedMaterial; if ((Object)(object)sharedMaterial == (Object)null) { return; } string name = ((Object)sharedMaterial).name; if (string.IsNullOrEmpty(name) || name.IndexOf("ShadowPerson", StringComparison.OrdinalIgnoreCase) < 0) { return; } Shader shader = PluginState.Shader; if (!((Object)(object)shader != (Object)null) || !((Object)(object)sharedMaterial.shader != (Object)(object)shader)) { return; } try { sharedMaterial.shader = shader; } catch { } } catch { } } } [HarmonyPatch] internal static class VisEquipmentPatch { private static readonly string[] TargetMethodNames = new string[3] { "UpdateBaseModel", "SetChestEquipped", "SetLegEquipped" }; [HarmonyTargetMethods] public static IEnumerable<MethodBase> TargetMethods() { Type type = AccessTools.TypeByName("VisEquipment"); if (type == null) { yield break; } string[] targetMethodNames = TargetMethodNames; foreach (string name in targetMethodNames) { MethodInfo method = AccessTools.Method(type, name, (Type[])null, (Type[])null); if (method != null) { yield return method; } } } [HarmonyTranspiler] public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { return TextureSetRewriter.Rewrite(instructions); } } internal static class TextureSetRewriter { private static readonly HashSet<int> GuardedPropertyIds = new HashSet<int> { Shader.PropertyToID("_SkinBumpMap"), Shader.PropertyToID("_ChestTex"), Shader.PropertyToID("_ChestBumpMap"), Shader.PropertyToID("_LegsTex"), Shader.PropertyToID("_LegsBumpMap"), Shader.PropertyToID("_ChestMetal"), Shader.PropertyToID("_LegsMetal") }; private static readonly MethodInfo SafeByInt = AccessTools.Method(typeof(TextureSetRewriter), "SafeSetTexture", new Type[3] { typeof(Material), typeof(int), typeof(Texture) }, (Type[])null); private static readonly MethodInfo SafeByString = AccessTools.Method(typeof(TextureSetRewriter), "SafeSetTexture", new Type[3] { typeof(Material), typeof(string), typeof(Texture) }, (Type[])null); public static IEnumerable<CodeInstruction> Rewrite(IEnumerable<CodeInstruction> instructions) { foreach (CodeInstruction instruction in instructions) { yield return TryRewrite(instruction) ?? instruction; } } private static CodeInstruction TryRewrite(CodeInstruction instruction) { //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Expected O, but got Unknown //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Expected O, but got Unknown if (instruction.opcode != OpCodes.Callvirt && instruction.opcode != OpCodes.Call) { return null; } if (!(instruction.operand is MethodInfo methodInfo)) { return null; } if (methodInfo.Name != "SetTexture") { return null; } if (methodInfo.DeclaringType?.FullName != "UnityEngine.Material") { return null; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length != 2) { return null; } if (parameters[0].ParameterType == typeof(int) && SafeByInt != null) { return new CodeInstruction(OpCodes.Call, (object)SafeByInt); } if (parameters[0].ParameterType == typeof(string) && SafeByString != null) { return new CodeInstruction(OpCodes.Call, (object)SafeByString); } return null; } public static void SafeSetTexture(Material material, int propertyId, Texture texture) { if ((Object)(object)material == (Object)null || IsGuarded(material, propertyId)) { return; } try { material.SetTexture(propertyId, texture); } catch { } } public static void SafeSetTexture(Material material, string propertyName, Texture texture) { if ((Object)(object)material == (Object)null || string.IsNullOrEmpty(propertyName) || IsShadowPerson(propertyName)) { return; } try { material.SetTexture(propertyName, texture); } catch { } } private static bool IsGuarded(Material material, int propertyId) { return GuardedPropertyIds.Contains(propertyId) && IsShadowPerson(material); } private static bool IsShadowPerson(Material material) { return IsShadowPerson((material != null) ? ((Object)material).name : null); } private static bool IsShadowPerson(string name) { return !string.IsNullOrEmpty(name) && name.IndexOf("ShadowPerson", StringComparison.OrdinalIgnoreCase) >= 0; } } }