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 ShaderHelperForMac v4.0.1
plugins/ShaderHelperForMac.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Logging; using HarmonyLib; using ShaderHelper.Apply; using ShaderHelper.Decide; using ShaderHelper.Diagnostics; using ShaderHelper.Facts; using ShaderHelper.Patches; using ShaderHelper.Scan; using Unity.Collections; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ShaderHelperForMac")] [assembly: AssemblyProduct("ShaderHelperForMac")] [assembly: AssemblyFileVersion("4.0.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("4.0.1.0")] namespace ShaderHelper { [BepInPlugin("aaa.drummercraig.shaderhelperformac", "ShaderHelperForMac", "4.0.1")] public sealed class ShaderHelperPlugin : BaseUnityPlugin { public const string PluginGuid = "aaa.drummercraig.shaderhelperformac"; public const string PluginName = "ShaderHelperForMac"; public const string PluginVersion = "4.0.1"; internal static ManualLogSource Log; internal static ShaderHelperPlugin Instance; private Harmony _harmony; private void Awake() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; VanillaBaseline.Load(Log); _harmony = new Harmony("aaa.drummercraig.shaderhelperformac"); ResilientPatcher.ApplyAll(_harmony, typeof(ShaderHelperPlugin).Assembly, Log); } private void Update() { try { HitchWatchdog.Tick(); } catch (Exception) { } } } } namespace ShaderHelper.Scan { internal sealed class CatchUp { private const int ExampleCap = 6; private readonly Dictionary<int, bool> _pink = new Dictionary<int, bool>(); private readonly List<string> _examples = new List<string>(); internal int Count { get; private set; } internal void Note(Material m) { if ((Object)(object)m == (Object)null) { return; } try { if (Coverage.Seen(((Object)m).GetInstanceID())) { return; } Shader shader = m.shader; if ((Object)(object)shader == (Object)null) { return; } int instanceID = ((Object)shader).GetInstanceID(); if (!_pink.TryGetValue(instanceID, out var value)) { value = (_pink[instanceID] = IsPinkModInstance(shader, instanceID)); } if (value) { Count++; if (_examples.Count < 6) { _examples.Add($"'{((Object)m).name}' on '{Names.Shader(((Object)shader).name)}'#{instanceID}"); } } } catch (Exception) { } } private static bool IsPinkModInstance(Shader sh, int sid) { string name = ((Object)sh).name; if (string.IsNullOrEmpty(name) || string.Equals(name, "Hidden/InternalErrorShader", StringComparison.Ordinal)) { return false; } if (VanillaShaders.IsHarvested(sid) || ValheimPrefabShaders.IsProven(sid)) { return false; } if (Targets.TryGet(Names.Shader(name), out var target) && target.InstanceId == sid) { return false; } return ShaderStructure.IsPlaceholder(sh); } internal string Summary(int scanned, double ms, int frames, bool queued) { return $"[Eval] catch-up check: {scanned} loaded material(s); {Count} unseen by the pass on a placeholder-shaped mod instance" + ((_examples.Count > 0) ? (" (" + string.Join(" ", _examples) + ((Count > _examples.Count) ? $" +{Count - _examples.Count} more" : "") + ")") : "") + $"; {ms:F1} ms over {frames} frame(s); " + (queued ? "one catch-up pass queued." : ((Count > 0) ? "no catch-up (a pass is already queued, or the world closed)." : "no catch-up needed.")); } } internal static class Coverage { private const int TopNames = 10; private const int ExamplesPerGroup = 6; private static readonly HashSet<int> _seen = new HashSet<int>(); private static readonly Dictionary<int, Verdict> _verdicts = new Dictionary<int, Verdict>(); private static bool _passed; internal static void BeginPass() { _seen.Clear(); _verdicts.Clear(); _passed = true; } internal static void NoteSeen(int materialId) { _seen.Add(materialId); } internal static bool Seen(int materialId) { return _seen.Contains(materialId); } internal static void NoteDecided(int materialId, Verdict v) { _verdicts[materialId] = v; } internal static void AtWorldClose() { try { Count(); } finally { _seen.Clear(); _verdicts.Clear(); _passed = false; } } private static void Count() { if (!_passed) { ShaderHelperPlugin.Log.LogInfo((object)"[Coverage] world closed before any world-load pass; nothing to compare."); return; } long timestamp = Stopwatch.GetTimestamp(); Material[] array; try { array = Resources.FindObjectsOfTypeAll<Material>(); } catch (Exception ex) { ShaderHelperPlugin.Log.LogWarning((object)("[Coverage] material scan FAILED (" + ex.GetType().Name + "); no coverage count.")); return; } int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal); Material[] array2 = array; foreach (Material val in array2) { if ((Object)(object)val == (Object)null || _seen.Contains(((Object)val).GetInstanceID())) { continue; } num++; try { if (VanillaBaseline.IsVanillaMaterial(Names.MaterialBase(((Object)val).name ?? "", out var _))) { num2++; continue; } Shader shader = val.shader; string text = (((Object)(object)shader != (Object)null) ? ((Object)shader).name : null); if (string.IsNullOrEmpty(text)) { num5++; continue; } string text2 = Names.Shader(text); if (Targets.TryGet(text2, out var target) && target.InstanceId == ((Object)shader).GetInstanceID()) { num3++; continue; } num4++; dictionary.TryGetValue(text2, out var value); dictionary[text2] = value + 1; } catch (Exception) { num5++; } } long ticks = Stopwatch.GetTimestamp() - timestamp; WorkMeter.Add(ticks); IEnumerable<string> values = from kv in dictionary.OrderByDescending((KeyValuePair<string, int> kv) => kv.Value).ThenBy<KeyValuePair<string, int>, string>((KeyValuePair<string, int> kv) => kv.Key, StringComparer.Ordinal).Take(10) select $"'{kv.Key}' x{kv.Value}"; ShaderHelperPlugin.Log.LogInfo((object)($"[Coverage] world close: {array.Length} loaded material(s), {num} not seen by the world-load pass " + $"(lower bound: teardown may have destroyed some): {num2} cache-named, {num3} non-cache (mod, or engine/UI) on a Valheim target " + string.Format("instance, {0} non-cache NOT on one, {1} unreadable{2}; ", num4, num5, Evaluator.IsRunning ? "; the pass was still running" : "") + $"{WorkMeter.Ms(ticks):F1} ms." + ((dictionary.Count > 0) ? (" Not on one, by bound shader: " + string.Join("; ", values)) : ""))); Placeholders(array); } private static void Placeholders(Material[] all) { if (!ShaderStructure.PlaceholderKnown) { ShaderHelperPlugin.Log.LogInfo((object)"[Coverage] placeholder-shaped now: not measured (the placeholder shape was not read this session)."); return; } long timestamp = Stopwatch.GetTimestamp(); Dictionary<int, bool> dictionary = new Dictionary<int, bool>(); Dictionary<string, (int, List<string>, HashSet<string>)> dictionary2 = new Dictionary<string, (int, List<string>, HashSet<string>)>(StringComparer.Ordinal); int num = 0; int num2 = 0; foreach (Material val in all) { if ((Object)(object)val == (Object)null) { continue; } try { Shader shader = val.shader; if ((Object)(object)shader == (Object)null) { continue; } string name = ((Object)shader).name; if (string.IsNullOrEmpty(name) || string.Equals(name, "Hidden/InternalErrorShader", StringComparison.Ordinal)) { continue; } int instanceID = ((Object)shader).GetInstanceID(); if (!dictionary.TryGetValue(instanceID, out var value)) { value = (dictionary[instanceID] = ShaderStructure.IsPlaceholder(shader)); } if (value) { num++; string key = Status(((Object)val).GetInstanceID()) + ": '" + Names.Shader(name) + "'"; if (!dictionary2.TryGetValue(key, out var value2)) { value2 = (0, new List<string>(), new HashSet<string>(StringComparer.Ordinal)); } string text = ((Object)val).name ?? ""; if (value2.Item2.Count < 6 && value2.Item3.Add(text)) { value2.Item2.Add($"'{text}'#{instanceID}"); } dictionary2[key] = (value2.Item1 + 1, value2.Item2, value2.Item3); } } catch (Exception) { num2++; } } long ticks = Stopwatch.GetTimestamp() - timestamp; WorkMeter.Add(ticks); List<KeyValuePair<string, (int, List<string>, HashSet<string>)>> list = dictionary2.OrderByDescending<KeyValuePair<string, (int, List<string>, HashSet<string>)>, int>((KeyValuePair<string, (int Count, List<string> Names, HashSet<string> Seen)> kv) => kv.Value.Count).ThenBy<KeyValuePair<string, (int, List<string>, HashSet<string>)>, string>((KeyValuePair<string, (int Count, List<string> Names, HashSet<string> Seen)> kv) => kv.Key, StringComparer.Ordinal).ToList(); ShaderHelperPlugin.Log.LogInfo((object)($"[Coverage] placeholder-shaped now: {num} loaded material(s) bound to a shader shaped like the error " + $"shader (most likely pink), {num2} unreadable, by status (world-load verdict, decided before any write) and bound shader: " + ((list.Count == 0) ? "none" : string.Join("; ", list.Select<KeyValuePair<string, (int, List<string>, HashSet<string>)>, string>((KeyValuePair<string, (int Count, List<string> Names, HashSet<string> Seen)> kv) => $"{kv.Key} x{kv.Value.Count}"))) + string.Format("{0}; {1:F1} ms.", Evaluator.IsRunning ? "; the pass was still running" : "", WorkMeter.Ms(ticks)))); foreach (KeyValuePair<string, (int, List<string>, HashSet<string>)> item in list) { int num3 = item.Value.Item1 - item.Value.Item2.Count; ShaderHelperPlugin.Log.LogInfo((object)("[Coverage] " + item.Key + ": " + string.Join(" ", item.Value.Item2) + ((num3 > 0) ? $" +{num3} more" : ""))); } } private static string Status(int id) { if (_verdicts.TryGetValue(id, out var value)) { if (!Verdicts.WouldWrite(value)) { return value.ToString(); } return string.Format("{0}{1}", value, ShaderWriter.WasWritten(id) ? "+written" : "+notWritten"); } if (!_seen.Contains(id)) { return "unseen"; } return "seen-undecided"; } } internal static class Evaluator { private static bool _running; private static bool _again; private static string _againLabel; private const string CatchUpLabel = "catch-up"; internal static bool IsRunning => _running; internal static void RequestPass(string label) { if (_running) { _again = true; _againLabel = label; } else if (!((Object)(object)ShaderHelperPlugin.Instance == (Object)null)) { ((MonoBehaviour)ShaderHelperPlugin.Instance).StartCoroutine(Pass(label)); } } private static IEnumerator Pass(string label) { _running = true; try { yield return null; if (!VanillaBaseline.Loaded) { ShaderHelperPlugin.Log.LogError((object)"[Eval] baseline not loaded; nothing is decided."); yield break; } Slicer s = new Slicer(); s.Resume(); Targets.Build(); PropertyMatch.BeginPass(); ShaderWriter.BeginPass(); EquipmentMaterials.BeginSeed(); ArmorMaterials.Begin(); ValheimPrefabShaders.Begin(); foreach (GameObject go in Copy(((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.m_items : null)) { if (s.Due(1)) { s.Pause(); yield return null; s.Resume(); } EquipmentMaterials.SeedFrom(go); ArmorMaterials.AddFrom(go); ValheimPrefabShaders.AddFrom(go); } if ((Object)(object)ObjectDB.instance == (Object)null) { ShaderHelperPlugin.Log.LogWarning((object)"[Equip] ObjectDB not available at world load; the equipment seed is empty this pass."); } EquipmentMaterials.EndSeed(); PieceMaterials.Begin(); foreach (GameObject go in Copy(((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.m_prefabs : null)) { if (s.Due(1)) { s.Pause(); yield return null; s.Resume(); } PieceMaterials.AddFrom(go); ValheimPrefabShaders.AddFrom(go); } Targets.AddPrefabProven(); RendererKinds.Begin(); Renderer[] array = FindAll<Renderer>(); foreach (Renderer r in array) { if (s.Due()) { s.Pause(); yield return null; s.Resume(); } RendererKinds.Record(r); } CameraMaterials.Walk(); Material[] materials = FindAll<Material>(); List<MaterialRow> rows = new List<MaterialRow>(materials.Length); Report report = new Report(); Coverage.BeginPass(); CopySource.BeginPass(); Material[] array2 = materials; foreach (Material m in array2) { if (s.Due()) { s.Pause(); yield return null; s.Resume(); } if ((Object)(object)m == (Object)null) { report.CountGone(); continue; } Coverage.NoteSeen(((Object)m).GetInstanceID()); if (MaterialRows.TryBuild(m, report, out var row)) { rows.Add(row); MaterialRows.CaptureAuthored(in row); } } List<(MaterialRow Row, Decision D)> candidates = new List<(MaterialRow, Decision)>(); foreach (MaterialRow item2 in rows) { MaterialRow row2 = item2; if (s.Due()) { s.Pause(); yield return null; s.Resume(); } if ((Object)(object)row2.Mat == (Object)null || (Object)(object)row2.Bound == (Object)null) { report.CountGone(); continue; } Decision item = MaterialRows.Record(report, in row2); Coverage.NoteDecided(row2.Id, item.Verdict); if (ShaderWriter.InScope(item.Verdict)) { candidates.Add((row2, item)); } } rows.Clear(); foreach (var item3 in candidates) { (MaterialRow Row, Decision D) c = item3; if (s.Due()) { s.Pause(); yield return null; s.Resume(); } if (MaterialRows.Write(in c.Row, c.D) && s.Due(1)) { s.Pause(); yield return null; s.Resume(); } } candidates.Clear(); s.Pause(); long timestamp = Stopwatch.GetTimestamp(); MaterialRows.Emit(report, label, materials.Length, s); WorkMeter.Add(Stopwatch.GetTimestamp() - timestamp); if (string.Equals(label, "catch-up", StringComparison.Ordinal)) { yield break; } Slicer c2 = new Slicer(); c2.Resume(); array2 = FindAll<Material>(); CatchUp check = new CatchUp(); Material[] array3 = array2; foreach (Material m in array3) { if (c2.Due()) { c2.Pause(); yield return null; c2.Resume(); if ((Object)(object)ZNetScene.instance == (Object)null) { break; } } check.Note(m); } c2.Pause(); bool flag = check.Count > 0 && !_again && (Object)(object)ZNetScene.instance != (Object)null; ShaderHelperPlugin.Log.LogInfo((object)check.Summary(array2.Length, c2.WorkMs, c2.Frames, flag)); if (flag) { RequestPass("catch-up"); } } finally { _running = false; ValheimMaterials.End(); if (_again) { _again = false; RequestPass(_againLabel); } } } private static List<GameObject> Copy(List<GameObject> src) { if (src == null) { return new List<GameObject>(); } return new List<GameObject>(src); } private static T[] FindAll<T>() where T : Object { try { return Resources.FindObjectsOfTypeAll<T>(); } catch (Exception ex) { ShaderHelperPlugin.Log.LogWarning((object)("[Eval] scan of " + typeof(T).Name + " FAILED (" + ex.GetType().Name + "); that fact is empty this pass.")); return Array.Empty<T>(); } } } internal static class MaterialRows { internal static bool TryBuild(Material m, Report report, out MaterialRow row) { row = default(MaterialRow); try { string name = ((Object)m).name ?? ""; bool copy; string baseName = Names.MaterialBase(name, out copy); Shader shader = m.shader; string text = (((Object)(object)shader != (Object)null) ? ((Object)shader).name : null); if (string.IsNullOrEmpty(text)) { report.CountUnreadable(); return false; } if (string.Equals(text, "Hidden/InternalErrorShader", StringComparison.Ordinal)) { report.CountErrorShader(); return false; } row = new MaterialRow(m, ((Object)m).GetInstanceID(), name, baseName, copy, shader, Names.Shader(text), Names.IsMock(text)); return true; } catch (Exception) { report.CountUnreadable(); return false; } } internal static void CaptureAuthored(in MaterialRow row) { if (!VanillaBaseline.IsVanillaMaterial(row.Base)) { AuthoredShader.Capture(row.Id, row.Base, row.Copy, row.BoundName, ((Object)row.Bound).GetInstanceID()); } if (VanillaBaseline.IsVanillaMaterial(row.Base)) { return; } try { if (row.Copy) { CopySource.NoteCopy(row.Mat, row.Id, row.Base, row.Bound); } else { CopySource.NoteOriginal(row.Mat, row.Base, row.Bound); } } catch (Exception) { } } internal static Decision DecideSafely(in MaterialRow row) { try { return Decider.Decide(in row); } catch (Exception ex) { ShaderHelperPlugin.Log.LogDebug((object)("[Eval] decide threw for '" + row.Name + "': " + ex.GetType().Name + ": " + ex.Message)); return new Decision(Verdict.Unreadable, null, row.BoundName, default(Target)); } } internal static Decision Record(Report report, in MaterialRow row) { Decision decision = DecideSafely(in row); try { report.Record(in row, decision); } catch (Exception ex) { ShaderHelperPlugin.Log.LogDebug((object)("[Eval] record threw for '" + row.Name + "': " + ex.GetType().Name + ": " + ex.Message)); } if (row.Copy && !VanillaBaseline.IsVanillaMaterial(row.Base)) { try { CopySource.Judge(row.Id, row.Base, decision.Verdict.ToString()); } catch (Exception) { } } return decision; } internal static bool Write(in MaterialRow row, Decision d) { try { return ShaderWriter.Consider(in row, d) == WriteOutcome.Written; } catch (Exception ex) { ShaderHelperPlugin.Log.LogDebug((object)("[Apply] consider threw for '" + row.Name + "': " + ex.GetType().Name + ": " + ex.Message)); return false; } } internal static void Emit(Report report, string label, int loaded, Slicer s) { try { report.Emit(label, loaded, s); } catch (Exception arg) { ShaderHelperPlugin.Log.LogError((object)$"[Eval] report failed: {arg}"); } } } internal sealed class Slicer { internal const double FrameBudgetMs = 1.0; internal const int CheapItems = 64; private readonly long _budget = (long)(1.0 * (double)Stopwatch.Frequency / 1000.0); private long _start; private long _work; private int _n; internal int Frames { get; private set; } internal double WorkMs => WorkMeter.Ms(_work); internal void Resume() { _start = Stopwatch.GetTimestamp(); _n = 0; Frames++; } internal bool Due(int every = 64) { if (++_n < every) { return false; } _n = 0; return Stopwatch.GetTimestamp() - _start >= _budget; } internal void Pause() { long num = Stopwatch.GetTimestamp() - _start; _work += num; WorkMeter.Add(num); } } } namespace ShaderHelper.Patches { internal static class JotunnOverlayPatches { private const string ManagerType = "Jotunn.Managers.MinimapManager"; private static bool _armed; private static bool _hooked; private static bool _disabled; private static bool _deferPass; private static FieldInfo _composeField; private static int _decidedId; private static bool _decidedBroken; private static bool _loggedTakeover; private static bool _ensureTried; internal static void Arm() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown if (_armed) { return; } _armed = true; try { Type type = FindManager(); if (type == null) { ShaderHelperPlugin.Log.LogDebug((object)"[Overlay] Jotunn not loaded: map-overlay compose left alone."); return; } MethodInfo methodInfo = AccessTools.Method(type, "SetupOverlays", (Type[])null, (Type[])null); if (methodInfo == null) { ShaderHelperPlugin.Log.LogWarning((object)"[Overlay] Jotunn has no MinimapManager.SetupOverlays: overlays stay as Jotunn draws them."); return; } new Harmony("aaa.drummercraig.shaderhelperformac").Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(JotunnOverlayPatches), "AfterSetupOverlays", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ShaderHelperPlugin.Log.LogDebug((object)"[Overlay] armed on Jotunn's SetupOverlays."); object obj = AccessTools.Field(type, "_instance")?.GetValue(null); if (obj != null && AccessTools.Field(type, "Overlays")?.GetValue(obj) is ICollection { Count: >0 }) { AfterSetupOverlays(obj); } } catch (Exception ex) { ShaderHelperPlugin.Log.LogWarning((object)("[Overlay] arming failed (Jotunn unaffected): " + ex.GetType().Name + ": " + ex.Message)); } } private static Type FindManager() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (string.Equals(assembly.GetName().Name, "Jotunn", StringComparison.Ordinal)) { return assembly.GetType("Jotunn.Managers.MinimapManager", throwOnError: false); } } return null; } private static void AfterSetupOverlays(object __instance) { //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Expected O, but got Unknown //IL_015f: Expected O, but got Unknown //IL_015f: Expected O, but got Unknown //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Expected O, but got Unknown if (_hooked || _disabled || __instance == null) { return; } try { Type type = __instance.GetType(); MethodInfo methodInfo = AccessTools.Method(type, "DrawLayer", new Type[4] { typeof(Texture2D), typeof(Texture2D), typeof(Material), typeof(RenderTextureFormat) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(type, "DrawOverlay", (Type[])null, (Type[])null); MethodInfo methodInfo3 = ((methodInfo2 != null) ? AccessTools.EnumeratorMoveNext((MethodBase)methodInfo2) : null); _composeField = AccessTools.Field(type, "ComposeOverlayMaterial"); if (methodInfo == null || methodInfo3 == null || _composeField == null) { _disabled = true; ShaderHelperPlugin.Log.LogWarning((object)($"[Overlay] Jotunn's compose hooks not found (DrawLayer={methodInfo != null} DrawOverlay.MoveNext={methodInfo3 != null} " + $"ComposeOverlayMaterial={_composeField != null}): overlays stay as Jotunn draws them.")); return; } Harmony val = new Harmony("aaa.drummercraig.shaderhelperformac"); Type typeFromHandle = typeof(JotunnOverlayPatches); val.Patch((MethodBase)methodInfo3, new HarmonyMethod(AccessTools.Method(typeFromHandle, "RedrawStart", (Type[])null, (Type[])null)), new HarmonyMethod(AccessTools.Method(typeFromHandle, "RedrawEnd", (Type[])null, (Type[])null)), (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeFromHandle, "RedrawFinally", (Type[])null, (Type[])null)), (HarmonyMethod)null); val.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeFromHandle, "BeforeDrawLayer", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _hooked = true; ShaderHelperPlugin.Log.LogInfo((object)"[Overlay] Jotunn map overlays: compose hooks installed (each takes over only while the compose shader reads placeholder-shaped)."); } catch (Exception ex) { _disabled = true; ShaderHelperPlugin.Log.LogWarning((object)("[Overlay] hook install failed; Jotunn's own path stands: " + ex.GetType().Name + ": " + ex.Message)); } } private static void RedrawStart() { if (!_disabled) { _deferPass = false; _ensureTried = false; OverlayCompose.BeginPass(); } } private static void RedrawEnd() { if (_disabled) { OverlayCompose.Abort(); return; } try { string text = OverlayCompose.Flush(); if (text != null) { ShaderHelperPlugin.Log.LogDebug((object)("[Overlay] redraw: " + text + ".")); } } catch (Exception ex) { Disable("upload", ex); } } private static void RedrawFinally() { OverlayCompose.Abort(); } private static bool BeforeDrawLayer(object __instance, Texture2D __0, Texture2D __1, Material __2) { if (_disabled || _deferPass) { return true; } try { if ((Object)(object)__0 == (Object)null || (Object)(object)__1 == (Object)null || (Object)(object)__2 == (Object)null) { return true; } object? value = _composeField.GetValue(__instance); if (__2 != ((value is Material) ? value : null)) { return true; } if (!Broken(__2)) { return true; } if (!OverlayCompose.PassActive) { Disable("redraw brackets not firing", null); return true; } string text = OverlayCompose.Blend(__0, __1); if (text == null) { if (!_loggedTakeover) { _loggedTakeover = true; ShaderHelperPlugin.Log.LogInfo((object)("[Overlay] compose shader '" + ((Object)__2.shader).name + "' is pink: overlays composited on the CPU.")); } return false; } if (!OverlayCompose.Dirty) { _deferPass = true; ShaderHelperPlugin.Log.LogWarning((object)("[Overlay] " + text + ": this redraw is left to Jotunn.")); return true; } ShaderHelperPlugin.Log.LogWarning((object)("[Overlay] " + text + ": this overlay is skipped (the redraw is already partly composited).")); return false; } catch (Exception ex) { Disable("compose", ex); return true; } } private static bool Broken(Material mat) { int instanceID = ((Object)mat).GetInstanceID(); if (instanceID == _decidedId && instanceID != 0) { return _decidedBroken; } if (!ShaderStructure.PlaceholderKnown && !_ensureTried) { _ensureTried = true; ShaderStructure.EnsurePlaceholder(); } if (!ShaderStructure.PlaceholderKnown) { return false; } _decidedId = instanceID; _decidedBroken = ShaderStructure.IsPlaceholder(mat.shader); ShaderHelperPlugin.Log.LogInfo((object)(string.Format("[Overlay] compose material #{0} on '{1}': ", instanceID, ((Object)(object)mat.shader != (Object)null) ? ((Object)mat.shader).name : "?") + (_decidedBroken ? "placeholder-shaped, CPU compose takes over." : "not placeholder-shaped, Jotunn's own path."))); return _decidedBroken; } private static void Disable(string where, Exception ex) { _disabled = true; OverlayCompose.Abort(); ShaderHelperPlugin.Log.LogError((object)("[Overlay] " + where + " failed; CPU compose off for this session, Jotunn's own path resumes" + ((ex != null) ? (": " + ex.GetType().Name + ": " + ex.Message) : "."))); } } internal static class ResilientPatcher { internal static void ApplyAll(Harmony harmony, Assembly assembly, ManualLogSource log) { if (harmony == null || assembly == null) { return; } int num = 0; int num2 = 0; List<string> list = null; Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(assembly); foreach (Type type in typesFromAssembly) { try { List<MethodInfo> list2 = harmony.CreateClassProcessor(type).Patch(); if (list2 != null && list2.Count > 0) { num++; if (log != null) { log.LogDebug((object)$"[ShaderHelper] patched {type.Name} ({list2.Count} method(s))."); } } } catch (Exception ex) { num2++; (list ?? (list = new List<string>())).Add(type.Name); if (log != null) { log.LogWarning((object)("[ShaderHelper] SKIP patch class " + type.Name + ": " + ex.Message)); } } } if (num2 == 0) { if (log != null) { log.LogInfo((object)$"[ShaderHelper] patches: {num} applied, 0 skipped."); } } else if (log != null) { log.LogWarning((object)(string.Format("[ShaderHelper] patches: {0} applied, {1} skipped ({2}). ", num, num2, string.Join(", ", list)) + "A skipped patch usually means a Valheim update changed a hooked method; that feature is disabled but the mod is still running.")); } } } [HarmonyPatch(typeof(VisEquipment), "AttachItem", new Type[] { typeof(int), typeof(int), typeof(Transform), typeof(bool), typeof(bool), typeof(int) })] internal static class PatchVisEquipmentAttachItem { private static readonly List<GameObject> _one = new List<GameObject>(1); private static void Postfix(int __0, GameObject __result) { try { if (!((Object)(object)__result == (Object)null)) { _one.Clear(); _one.Add(__result); EquipmentMaterials.RecordEquip(_one, __0, "AttachItem"); } } catch (Exception ex) { ShaderHelperPlugin.Log.LogDebug((object)("[Equip] AttachItem postfix: " + ex.GetType().Name + ": " + ex.Message)); } finally { _one.Clear(); } } } [HarmonyPatch(typeof(VisEquipment), "AttachArmor", new Type[] { typeof(int), typeof(int), typeof(int) })] internal static class PatchVisEquipmentAttachArmor { private static void Postfix(int __0, List<GameObject> __result) { try { if (__result != null && __result.Count > 0) { EquipmentMaterials.RecordEquip(__result, __0, "AttachArmor"); } } catch (Exception ex) { ShaderHelperPlugin.Log.LogDebug((object)("[Equip] AttachArmor postfix: " + ex.GetType().Name + ": " + ex.Message)); } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class PatchZNetSceneAwake { private static void Postfix() { try { if (!VanillaBaseline.Loaded) { ShaderHelperPlugin.Log.LogError((object)"[Eval] baseline not loaded; nothing is decided."); return; } if (!Evaluator.IsRunning) { EquipmentMaterials.BeginSeed(); } VanillaShaders.Harvest("world load"); JotunnOverlayPatches.Arm(); Evaluator.RequestPass("world load"); } catch (Exception arg) { ShaderHelperPlugin.Log.LogError((object)$"[Eval] world-load hook failed (Valheim unaffected): {arg}"); } } } [HarmonyPatch(typeof(ZNetScene), "OnDestroy")] internal static class PatchZNetSceneOnDestroy { private static void Prefix() { try { Coverage.AtWorldClose(); } catch (Exception ex) { ShaderHelperPlugin.Log.LogDebug((object)("[Coverage] failed (Valheim unaffected): " + ex.GetType().Name + ": " + ex.Message)); } } private static void Postfix() { try { ShaderHelperPlugin.Log.LogInfo((object)$"[Eval] world closed. {EquipmentMaterials.Summary()}; total plugin work {WorkMeter.TotalMs:F0} ms."); } catch (Exception) { } } } } namespace ShaderHelper.Facts { internal static class ArmorMaterials { private static readonly HashSet<int> _ids = new HashSet<int>(); private static readonly HashSet<string> _names = new HashSet<string>(StringComparer.Ordinal); internal static int Count => _ids.Count; internal static void Begin() { _ids.Clear(); _names.Clear(); } internal static void AddFrom(GameObject prefab) { try { ItemDrop val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ItemDrop>() : null); Material val2 = ((!((Object)(object)val != (Object)null)) ? null : val.m_itemData?.m_shared?.m_armorMaterial); if (!((Object)(object)val2 == (Object)null)) { _ids.Add(((Object)val2).GetInstanceID()); _names.Add(Names.MaterialBase(((Object)val2).name, out var _)); } } catch (Exception ex) { ShaderHelperPlugin.Log.LogDebug((object)("[Equip] armour material skipped a prefab: " + ex.GetType().Name)); } } internal static bool Contains(int id, string baseName, bool copy) { if (!_ids.Contains(id)) { if (copy) { return _names.Contains(baseName); } return false; } return true; } } internal enum AuthoredStatus { Unknown, Known, AmbiguousName } internal static class AuthoredShader { private readonly struct Entry { internal readonly string MaterialName; internal readonly string Shader; internal Entry(string materialName, string shader) { MaterialName = materialName; Shader = shader; } } private static readonly Dictionary<int, Entry> _byId = new Dictionary<int, Entry>(); private static readonly Dictionary<string, string> _byName = new Dictionary<string, string>(StringComparer.Ordinal); private static readonly HashSet<string> _ambiguousNames = new HashSet<string>(StringComparer.Ordinal); private static readonly Dictionary<string, Dictionary<int, string>> _assignedByName = new Dictionary<string, Dictionary<int, string>>(StringComparer.Ordinal); private static readonly Dictionary<int, Entry> _copyById = new Dictionary<int, Entry>(); internal static int AmbiguousNameCount => _ambiguousNames.Count; internal static bool IsAssigned(string baseName, int shaderId) { if (baseName != null && _assignedByName.TryGetValue(baseName, out var value)) { return value.ContainsKey(shaderId); } return false; } internal static bool TryGetAssigned(string baseName, int shaderId, out string authored) { authored = null; if (baseName != null && _assignedByName.TryGetValue(baseName, out var value)) { return value.TryGetValue(shaderId, out authored); } return false; } internal static void NoteAssigned(string baseName, int shaderId, string authored) { if (baseName != null && !string.IsNullOrEmpty(authored)) { if (!_assignedByName.TryGetValue(baseName, out var value)) { value = (_assignedByName[baseName] = new Dictionary<int, string>()); } if (!value.ContainsKey(shaderId)) { value[shaderId] = authored; } } } internal static void Capture(int id, string baseName, bool copy, string boundName, int boundShaderId) { if (string.IsNullOrEmpty(boundName)) { return; } Dictionary<int, Entry> dictionary = (copy ? _copyById : _byId); if (baseName != null && _assignedByName.TryGetValue(baseName, out var value) && value.TryGetValue(boundShaderId, out var value2)) { if (!dictionary.ContainsKey(id)) { dictionary[id] = new Entry(baseName, value2); } return; } if (copy) { CaptureCopy(id, baseName, boundName); return; } if (!_byId.ContainsKey(id)) { _byId[id] = new Entry(baseName, boundName); } if (!_byName.TryGetValue(baseName, out var value3)) { _byName[baseName] = boundName; } else if (!string.Equals(value3, boundName, StringComparison.OrdinalIgnoreCase)) { _ambiguousNames.Add(baseName); } } private static void CaptureCopy(int id, string baseName, string boundName) { if (baseName != null && !_copyById.ContainsKey(id)) { _copyById[id] = new Entry(baseName, boundName); } } internal static AuthoredStatus Get(int id, string baseName, bool copy, out string authored) { authored = null; if (!copy) { if (!_byId.TryGetValue(id, out var value) || !string.Equals(value.MaterialName, baseName, StringComparison.Ordinal)) { return AuthoredStatus.Unknown; } authored = value.Shader; return AuthoredStatus.Known; } if (_ambiguousNames.Contains(baseName)) { return AuthoredStatus.AmbiguousName; } if (_byName.TryGetValue(baseName, out authored) && !CopySource.OwnTexture(id, baseName)) { return AuthoredStatus.Known; } authored = null; if (!_copyById.TryGetValue(id, out var value2) || !string.Equals(value2.MaterialName, baseName, StringComparison.Ordinal)) { return AuthoredStatus.Unknown; } authored = value2.Shader; return AuthoredStatus.Known; } internal static bool ResolvesByName(string baseName, out string authored) { authored = null; if (baseName != null && !_ambiguousNames.Contains(baseName)) { return _byName.TryGetValue(baseName, out authored); } return false; } internal static bool TryGetCopyFirstSight(int id, string baseName, out string shader) { shader = null; if (!_copyById.TryGetValue(id, out var value) || !string.Equals(value.MaterialName, baseName, StringComparison.Ordinal)) { return false; } shader = value.Shader; return true; } internal static int ReadBoundId(Material m) { try { return ((Object)(object)m != (Object)null && (Object)(object)m.shader != (Object)null) ? ((Object)m.shader).GetInstanceID() : 0; } catch (Exception) { return 0; } } internal static string ReadBound(Material m) { if ((Object)(object)m == (Object)null) { return null; } Shader shader; try { shader = m.shader; } catch (Exception) { return null; } if ((Object)(object)shader == (Object)null) { return null; } string name; try { name = ((Object)shader).name; } catch (Exception) { return null; } if (string.IsNullOrEmpty(name) || string.Equals(name, "Hidden/InternalErrorShader", StringComparison.Ordinal)) { return null; } return Names.Shader(name); } } internal static class CameraMaterials { private const int LineCap = 24; private static readonly Dictionary<Type, FieldInfo[]> _fieldsByType = new Dictionary<Type, FieldInfo[]>(); private static readonly Dictionary<Type, bool> _blitsByType = new Dictionary<Type, bool>(); private static readonly HashSet<int> _ids = new HashSet<int>(); private static readonly HashSet<int> _blitIds = new HashSet<int>(); private static readonly List<Component> _comps = new List<Component>(); private static int _cameras; private static int _components; private static int _lines; private static int _errorShader; internal static bool Contains(int materialId) { return _ids.Contains(materialId); } internal static bool IsBlit(int materialId) { return _blitIds.Contains(materialId); } internal static void Walk() { _ids.Clear(); _blitIds.Clear(); _cameras = (_components = (_lines = (_errorShader = 0))); try { Camera[] allCameras = Camera.allCameras; foreach (Camera val in allCameras) { if ((Object)(object)val == (Object)null) { continue; } _cameras++; try { string name = ((Object)val).name; ((Component)val).GetComponents<Component>(_comps); foreach (Component comp in _comps) { if (!((Object)(object)comp == (Object)null) && !(comp is Renderer)) { _components++; try { ReadComponent(name, comp); } catch (Exception ex) { ShaderHelperPlugin.Log.LogDebug((object)("[Eval] camera walk skipped one component: " + ex.GetType().Name)); } } } } catch (Exception ex2) { ShaderHelperPlugin.Log.LogDebug((object)("[Eval] camera walk skipped one camera: " + ex2.GetType().Name)); } finally { _comps.Clear(); } } ShaderHelperPlugin.Log.LogInfo((object)($"[Eval] camera-held: {_cameras} camera(s), {_components} component(s), {_ids.Count} material(s) " + $"({Math.Max(0, _ids.Count - _lines)} not listed, {_errorShader} on the error shader skipped). {PassThroughLine()}")); } catch (Exception ex3) { ShaderHelperPlugin.Log.LogWarning((object)("[Eval] camera walk FAILED (" + ex3.GetType().Name + "); no camera-held facts this pass.")); } } private static void ReadComponent(string camName, Component c) { FieldInfo[] array = FieldsOf(((object)c).GetType()); if (array.Length == 0) { return; } Behaviour val = (Behaviour)(object)((c is Behaviour) ? c : null); bool enabled = val == null || val.enabled; FieldInfo[] array2 = array; foreach (FieldInfo fieldInfo in array2) { object value; try { value = fieldInfo.GetValue(c); } catch (Exception) { continue; } Material val2 = (Material)((value is Material) ? value : null); if (val2 != null) { Note(camName, c, enabled, fieldInfo.Name, val2); } else if (value is Material[] array3) { for (int j = 0; j < array3.Length; j++) { Note(camName, c, enabled, $"{fieldInfo.Name}[{j}]", array3[j]); } } } } private static void Note(string camName, Component c, bool enabled, string field, Material m) { if ((Object)(object)m == (Object)null) { return; } Shader shader = m.shader; string text = (((Object)(object)shader != (Object)null) ? ((Object)shader).name : null); if (string.Equals(text, "Hidden/InternalErrorShader", StringComparison.Ordinal)) { _errorShader++; return; } bool flag = Blits(((object)c).GetType()); if (flag) { _blitIds.Add(((Object)m).GetInstanceID()); } if (_ids.Add(((Object)m).GetInstanceID()) && _lines < 24) { _lines++; bool copy; string canonicalName = Names.MaterialBase(((Object)m).name ?? "", out copy); string item = Names.Shader(text ?? ""); int num = (((Object)(object)shader != (Object)null) ? ((Object)shader).GetInstanceID() : 0); bool b = (Object)(object)shader != (Object)null && (VanillaShaders.IsHarvested(num) || ValheimPrefabShaders.IsProven(num)); ShaderHelperPlugin.Log.LogInfo((object)($"[Eval] camera-held: camera='{camName}' component='{((object)c).GetType().Name}' enabled={enabled} blits={YesNo(flag)} field='{field}' " + $"mat='{((Object)m).name}'#{((Object)m).GetInstanceID()} kind={RendererKinds.Get(((Object)m).GetInstanceID())} shader='{text}'#{num} " + "placeholder=" + YesNo(ShaderStructure.IsPlaceholder(shader)) + " cacheMaterial=" + YesNo(VanillaBaseline.IsVanillaMaterial(canonicalName)) + " shippedShader=" + YesNo(VanillaBaseline.ShaderNames.Contains(item) || VanillaBaseline.ShippedShaderNames.Contains(item)) + " " + $"builtin={YesNo(UnityBuiltIns.ShaderNames.Contains(item))} valheimInstance={YesNo(b)} queue={m.renderQueue}")); } } private static string PassThroughLine() { Shader val; try { val = Shader.Find("Hidden/BlitCopy"); } catch (Exception ex) { return "pass-through 'Hidden/BlitCopy': Find threw " + ex.GetType().Name; } if ((Object)(object)val == (Object)null) { return "pass-through 'Hidden/BlitCopy': NOT found"; } ShaderShape shaderShape = ShaderStructure.Read(val); return string.Format("pass-through '{0}': found #{1} {2} readable={3} ", "Hidden/BlitCopy", ((Object)val).GetInstanceID(), shaderShape, YesNo(ShaderStructure.IsReadable(shaderShape))) + "placeholder=" + YesNo(ShaderStructure.IsPlaceholder(val)) + " placeholderKnown=" + YesNo(ShaderStructure.PlaceholderKnown); } private static FieldInfo[] FieldsOf(Type type) { if (_fieldsByType.TryGetValue(type, out var value)) { return value; } List<FieldInfo> list = new List<FieldInfo>(); try { Type type2 = type; while (type2 != null && type2 != typeof(MonoBehaviour) && type2 != typeof(Behaviour) && type2 != typeof(Component)) { FieldInfo[] fields = type2.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { try { if (fieldInfo.FieldType == typeof(Material) || fieldInfo.FieldType == typeof(Material[])) { list.Add(fieldInfo); } } catch (Exception) { } } type2 = type2.BaseType; } } catch (Exception) { list.Clear(); } FieldInfo[] array = list.ToArray(); _fieldsByType[type] = array; return array; } private static bool Blits(Type type) { if (_blitsByType.TryGetValue(type, out var value)) { return value; } bool flag = false; try { Type type2 = type; while (!flag && type2 != null && type2 != typeof(MonoBehaviour) && type2 != typeof(Behaviour) && type2 != typeof(Component)) { MethodInfo[] methods = type2.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < methods.Length; i++) { if (methods[i].Name == "OnRenderImage") { flag = true; break; } } if (flag) { break; } FieldInfo[] fields = type2.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { try { if (fieldInfo.FieldType == typeof(CommandBuffer)) { flag = true; break; } } catch (Exception) { } } type2 = type2.BaseType; } } catch (Exception) { flag = false; } _blitsByType[type] = flag; return flag; } private static string YesNo(bool b) { if (!b) { return "no"; } return "yes"; } } internal static class CopySource { private readonly struct Seen { internal readonly string Base; internal readonly string Slot; internal readonly string Name; internal readonly int Width; internal readonly int Height; internal Seen(string baseName, string slot, string name, int w, int h) { Base = baseName; Slot = slot; Name = name; Width = w; Height = h; } public override string ToString() { if (Name != null) { return $"{Slot} '{Name}' {Width}x{Height}"; } return Slot + " none"; } } private const int ExampleCap = 40; private static readonly Dictionary<string, Seen> _originals = new Dictionary<string, Seen>(StringComparer.Ordinal); private static readonly Dictionary<int, Seen> _copies = new Dictionary<int, Seen>(); private static readonly Dictionary<string, int> _examples = new Dictionary<string, int>(StringComparer.Ordinal); private static int _byName; private static int _same; private static int _bothEmpty; private static int _sizeOnly; private static int _own; private static int _notComparable; private static int _overflow; internal static IEnumerable<string> Examples => from kv in _examples.OrderByDescending((KeyValuePair<string, int> kv) => kv.Value).ThenBy<KeyValuePair<string, int>, string>((KeyValuePair<string, int> kv) => kv.Key, StringComparer.Ordinal) select $"x{kv.Value} {kv.Key}"; internal static void BeginPass() { _examples.Clear(); _byName = (_same = (_bothEmpty = (_sizeOnly = (_own = (_notComparable = (_overflow = 0)))))); } internal static void NoteOriginal(Material m, string baseName, Shader bound) { if (!((Object)(object)m == (Object)null) && !((Object)(object)bound == (Object)null) && !string.IsNullOrEmpty(baseName) && !_originals.ContainsKey(baseName) && !AuthoredShader.IsAssigned(baseName, ((Object)bound).GetInstanceID()) && TryRead(m, baseName, bound, out var seen)) { _originals[baseName] = seen; } } internal static void NoteCopy(Material m, int id, string baseName, Shader bound) { if (!((Object)(object)m == (Object)null) && !((Object)(object)bound == (Object)null) && !string.IsNullOrEmpty(baseName) && !_copies.ContainsKey(id) && !AuthoredShader.IsAssigned(baseName, ((Object)bound).GetInstanceID()) && TryRead(m, baseName, bound, out var seen)) { _copies[id] = seen; } } internal static bool OwnTexture(int id, string baseName) { if (Compare(id, baseName, out var original, out var copy) && original.Name != null && copy.Name != null) { return !string.Equals(original.Name, copy.Name, StringComparison.Ordinal); } return false; } internal static void Judge(int id, string baseName, string verdict) { if (!AuthoredShader.ResolvesByName(baseName, out var authored)) { return; } _byName++; if (!Compare(id, baseName, out var original, out var copy)) { _notComparable++; return; } if (original.Name == null && copy.Name == null) { _bothEmpty++; return; } if (original.Name == null || copy.Name == null) { _notComparable++; return; } if (string.Equals(original.Name, copy.Name, StringComparison.Ordinal)) { if (original.Width == copy.Width && original.Height == copy.Height) { _same++; } else { _sizeOnly++; } return; } _own++; AuthoredShader.TryGetCopyFirstSight(id, baseName, out var shader); string key = $"'{baseName}' copy {copy} vs source {original}: own first sight '{shader}' (name gives '{authored}') -> {verdict}"; if (_examples.TryGetValue(key, out var value)) { _examples[key] = value + 1; } else if (_examples.Count < 40) { _examples[key] = 1; } else { _overflow++; } } internal static string Summary() { return $"copy source by texture: {_byName} cop(ies) of a captured original's name; same texture {_same}, size only {_sizeOnly}, " + $"both empty {_bothEmpty}, not comparable {_notComparable}; texture name differs {_own} (decided from their own first sight); " + $"{_examples.Count} distinct case(s) listed" + ((_overflow > 0) ? $", {_overflow} cop(ies) in cases past the first {40}." : "."); } private static bool Compare(int id, string baseName, out Seen original, out Seen copy) { original = default(Seen); copy = default(Seen); if (baseName != null && _originals.TryGetValue(baseName, out original) && _copies.TryGetValue(id, out copy) && string.Equals(copy.Base, baseName, StringComparison.Ordinal)) { return string.Equals(original.Slot, copy.Slot, StringComparison.Ordinal); } return false; } private static bool TryRead(Material m, string baseName, Shader bound, out Seen seen) { seen = default(Seen); try { string text = MainSlot(bound); if (text == null) { return false; } Texture texture = m.GetTexture(text); if ((Object)(object)texture == (Object)null) { seen = new Seen(baseName, text, null, 0, 0); return true; } string text2 = ((Object)texture).name; if (string.IsNullOrEmpty(text2)) { return false; } if (text2.StartsWith("JVLmock_", StringComparison.Ordinal)) { text2 = text2.Substring(8); } seen = new Seen(baseName, text, text2, texture.width, texture.height); return true; } catch (Exception) { return false; } } private static string MainSlot(Shader sh) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 if (sh.FindPropertyIndex("_MainTex") >= 0) { return "_MainTex"; } int propertyCount = sh.GetPropertyCount(); for (int i = 0; i < propertyCount; i++) { if ((int)sh.GetPropertyType(i) == 4) { return sh.GetPropertyName(i); } } return null; } } internal static class EquipmentMaterials { private const int LinesPerMinute = 20; private const int NamesPerLine = 8; private static readonly MaterialSet _seeded = new MaterialSet(); private static readonly MaterialSet _attached = new MaterialSet(); private static readonly Dictionary<ItemType, int> _seedPrefabsByType = new Dictionary<ItemType, int>(); private static readonly List<Material> _seen = new List<Material>(); private static readonly HashSet<int> _seenIds = new HashSet<int>(); private static readonly HashSet<int> _hookOnlyIds = new HashSet<int>(); private static int _seedPrefabs; private static int _hookItem; private static int _hookArmor; private static int _hookSkipped; private static int _linesInWindow; private static float _windowStart; internal static bool SeedDone { get; private set; } internal static bool Contains(int id, string baseName, bool copy) { if (!_seeded.Contains(id, baseName, copy)) { return _attached.Contains(id, baseName, copy); } return true; } internal static void BeginSeed() { _seeded.Clear(); _seedPrefabsByType.Clear(); _seedPrefabs = 0; SeedDone = false; } internal static void SeedFrom(GameObject prefab) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) try { if (EquipmentTypes.TryGetType(prefab, out var type) && EquipmentTypes.IsEquipment(type)) { _seeded.AddFrom(prefab); _seedPrefabs++; _seedPrefabsByType.TryGetValue(type, out var value); _seedPrefabsByType[type] = value + 1; } } catch (Exception ex) { ShaderHelperPlugin.Log.LogDebug((object)("[Equip] seed skipped a prefab: " + ex.GetType().Name + ": " + ex.Message)); } } internal static void EndSeed() { SeedDone = true; } internal static void RecordEquip(IReadOnlyList<GameObject> instances, int itemHash, string via) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) long timestamp = Stopwatch.GetTimestamp(); try { GameObject val = null; try { val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(itemHash) : null); } catch (Exception) { } if (!EquipmentTypes.TryGetType(val, out var type) || !EquipmentTypes.IsEquipment(type)) { _hookSkipped++; return; } if (via == "AttachArmor") { _hookArmor++; } else { _hookItem++; } _seen.Clear(); foreach (GameObject instance in instances) { try { if ((Object)(object)instance != (Object)null) { _attached.AddFrom(instance, _seen); RendererKinds.RecordUnder(instance); } } catch (Exception ex2) { ShaderHelperPlugin.Log.LogDebug((object)("[Equip] " + via + " skipped an instance: " + ex2.GetType().Name + ": " + ex2.Message)); } } Distinct(_seen); foreach (Material item in _seen) { string text = AuthoredShader.ReadBound(item); bool copy; string text2 = Names.MaterialBase(((Object)item).name, out copy); if (text != null && !VanillaBaseline.IsVanillaMaterial(text2)) { AuthoredShader.Capture(((Object)item).GetInstanceID(), text2, copy, text, AuthoredShader.ReadBoundId(item)); } } int num = 0; foreach (Material item2 in _seen) { bool copy2; string baseName = Names.MaterialBase(((Object)item2).name, out copy2); if (!_seeded.Contains(((Object)item2).GetInstanceID(), baseName, copy2)) { num++; if (SeedDone) { _hookOnlyIds.Add(((Object)item2).GetInstanceID()); } } } LogEquip(via, ((Object)val).name, type, num); } finally { _seen.Clear(); WorkMeter.Add(Stopwatch.GetTimestamp() - timestamp); } } private static void Distinct(List<Material> list) { _seenIds.Clear(); list.RemoveAll((Material m) => (Object)(object)m == (Object)null || !_seenIds.Add(((Object)m).GetInstanceID())); _seenIds.Clear(); } private static void LogEquip(string via, string item, ItemType type, int notSeeded) { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup - _windowStart > 60f) { _windowStart = realtimeSinceStartup; _linesInWindow = 0; } if (_linesInWindow++ >= 20) { return; } List<string> list = new List<string>(_seen.Count); foreach (Material item2 in _seen) { list.Add(Names.MaterialBase(((Object)item2).name, out var _)); } ManualLogSource log = ShaderHelperPlugin.Log; log.LogInfo((object)($"[Equip] {via} '{item}' ({type}): {_seen.Count} material(s), " + (SeedDone ? (notSeeded + " not in the world-load seed") : "seed not built yet") + "; " + MaterialLine.PrefabCheck(item, list))); int num = 0; foreach (Material item3 in _seen) { if (num >= 8) { log.LogInfo((object)$"[Equip] ... {_seen.Count - num} more"); break; } string text; try { text = MaterialLine.Describe(item3); } catch (Exception ex) { text = "'" + ((Object)item3).name + "' not describable: " + ex.GetType().Name; } if (text != null) { num++; log.LogInfo((object)("[Equip] " + text)); } } } internal static string Summary() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder($"equipment: seed {_seedPrefabs} prefab(s) -> {_seeded.Count} material(s) ["); bool flag = true; foreach (KeyValuePair<ItemType, int> item in _seedPrefabsByType) { stringBuilder.Append(flag ? "" : " ").Append(item.Key).Append('=') .Append(item.Value); flag = false; } stringBuilder.Append($"]; equip hooks (calls): AttachItem={_hookItem} AttachArmor={_hookArmor} non-equipment skipped={_hookSkipped}, " + $"{_attached.Count} distinct material(s) recorded, {_hookOnlyIds.Count} distinct not in the seed"); return stringBuilder.ToString(); } } internal static class EquipmentTypes { internal static bool IsEquipment(ItemType t) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected I4, but got Unknown switch (t - 3) { case 0: case 1: case 2: case 3: case 4: case 8: case 9: case 11: case 12: case 14: case 15: case 16: case 19: case 21: return true; default: return false; } } internal static bool TryGetType(GameObject prefab, out ItemType type) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected I4, but got Unknown type = (ItemType)0; if ((Object)(object)prefab == (Object)null) { return false; } try { ItemDrop component = prefab.GetComponent<ItemDrop>(); SharedData val = ((!((Object)(object)component != (Object)null)) ? null : component.m_itemData?.m_shared); if (val == null) { return false; } type = (ItemType)(int)val.m_itemType; return true; } catch (Exception) { return false; } } } internal sealed class MaterialSet { private static readonly List<Renderer> _renderers = new List<Renderer>(); private static readonly List<Material> _materials = new List<Material>(); private readonly HashSet<int> _ids = new HashSet<int>(); private readonly HashSet<string> _names = new HashSet<string>(StringComparer.Ordinal); internal int Count => _ids.Count; internal int AddFrom(GameObject root, List<Material> seen = null) { if ((Object)(object)root == (Object)null) { return 0; } int num = 0; _renderers.Clear(); root.GetComponentsInChildren<Renderer>(true, _renderers); foreach (Renderer renderer in _renderers) { if ((Object)(object)renderer == (Object)null) { continue; } _materials.Clear(); renderer.GetSharedMaterials(_materials); foreach (Material material in _materials) { if (!((Object)(object)material == (Object)null)) { if (_ids.Add(((Object)material).GetInstanceID())) { num++; } _names.Add(Names.MaterialBase(((Object)material).name, out var _)); seen?.Add(material); } } } _renderers.Clear(); _materials.Clear(); return num; } internal bool Contains(int id, string baseName, bool copy) { if (!_ids.Contains(id)) { if (copy) { return _names.Contains(baseName); } return false; } return true; } internal void Clear() { _ids.Clear(); _names.Clear(); } } internal static class Names { private const string InstanceSuffix = " (Instance)"; private const string CloneSuffix = "(Clone)"; private const string JotunnMockPrefix = "JVLmock_"; internal static string MaterialBase(string name, out bool copy) { copy = false; if (string.IsNullOrEmpty(name)) { return name ?? ""; } string text = name; while (true) { if (text.EndsWith(" (Instance)", StringComparison.Ordinal)) { text = text.Substring(0, text.Length - " (Instance)".Length); } else { if (!text.EndsWith("(Clone)", StringComparison.Ordinal)) { break; } text = text.Substring(0, text.Length - "(Clone)".Length).TrimEnd(Array.Empty<char>()); } copy = true; } return text; } internal static string Shader(string name) { if (string.IsNullOrEmpty(name)) { return name; } if (!name.StartsWith("JVLmock_", StringComparison.Ordinal)) { return name; } return name.Substring("JVLmock_".Length); } internal static bool IsMock(string shaderName) { return shaderName?.StartsWith("JVLmock_", StringComparison.Ordinal) ?? false; } } internal static class PassThroughTarget { private static Target _target; private static int _loaded; internal static bool TryGet(out Target target) { target = _target; return (Object)(object)target.Shader != (Object)null; } internal static void Clear() { _target = default(Target); } internal static void Resolve(int loaded) { _target = default(Target); _loaded = loaded; Shader val; try { val = Shader.Find("Hidden/BlitCopy"); } catch (Exception) { val = null; } if (!((Object)(object)val == (Object)null) && ShaderStructure.PlaceholderKnown) { ShaderShape shaderShape = ShaderStructure.Read(val); if (ShaderStructure.IsReadable(shaderShape) && !ShaderStructure.Equal(shaderShape, ShaderStructure.Placeholder)) { _target = new Target(val, ((Object)val).GetInstanceID(), TargetTier.Engine, 1); } } } internal static string Summary() { object arg; if (!((Object)(object)_target.Shader != (Object)null)) { arg = "none"; } else { int instanceId = _target.InstanceId; arg = "#" + instanceId; } return $"passThrough={arg} (loaded x{_loaded})"; } } internal static class PieceMaterials { private static readonly MaterialSet _set = new MaterialSet(); private static int _prefabs; internal static bool Contains(int id, string baseName, bool copy) { return _set.Contains(id, baseName, copy); } internal static void Begin() { _set.Clear(); _prefabs = 0; } internal static void AddFrom(GameObject prefab) { try { if (!((Object)(object)prefab == (Object)null) && !((Object)(object)prefab.GetComponent<Piece>() == (Object)null)) { _set.AddFrom(prefab); _prefabs++; } } catch (Exception ex) { ShaderHelperPlugin.Log.LogDebug((object)("[Pieces] skipped a prefab: " + ex.GetType().Name + ": " + ex.Message)); } } internal static string Summary() { return $"pieces: {_prefabs} prefab(s) -> {_set.Count} material(s)"; } } internal static class PropertyMatch { private static readonly HashSet<string> _neverReturned = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Custom/Creature", "Custom/Piece" }; private static readonly string[] _neverPrefixes = new string[5] { "Hidden/", "UI/", "GUI/", "TextMeshPro/", "Skybox/" }; private const int MinProperties = 2; private static readonly Dictionary<string, List<string>> _valheimBySignature = new Dictionary<string, List<string>>(StringComparer.Ordinal); private static readonly Dictionary<int, string> _signatureById = new Dictionary<int, string>(); private static bool _built; internal static void BeginPass() { _valheimBySignature.Clear(); _signatureById.Clear(); _built = false; } internal static string Find(Shader bound, string boundName) { if ((Object)(object)bound == (Object)null) { return null; } if (!_built) { Build(); } string text = Signature(bound); if (text == null || !_valheimBySignature.TryGetValue(text, out var value)) { return null; } string text2 = ((value.Count == 1) ? value[0] : TieBreak(value, boundName)); if (text2 != null && !_neverReturned.Contains(text2)) { return text2; } return null; } private static string TieBreak(List<string> names, string boundName) { string text = Normal(boundName); if (text.Length == 0) { return null; } string result = null; string result2 = null; int num = 0; int num2 = 0; int num3 = 0; foreach (string name in names) { string text2 = Normal(name); if (text2.Length == 0) { continue; } if (text2 == text) { result = name; num++; } else if (text.Contains(text2)) { if (text2.Length > num2) { num2 = text2.Length; result2 = name; num3 = 1; } else if (text2.Length == num2) { num3++; } } } switch (num) { case 1: return result; case 0: if (num3 == 1) { return result2; } break; } return null; } private static string Normal(string s) { if (string.IsNullOrEmpty(s)) { return ""; } StringBuilder stringBuilder = new StringBuilder(s.Length); foreach (char c in s) { if (char.IsLetterOrDigit(c)) { stringBuilder.Append(char.ToLowerInvariant(c)); } } return stringBuilder.ToString(); } private static void Build() { _built = true; foreach (string name in VanillaBaseline.ShaderNames) { if (IsNeverCandidate(name) || !Targets.TryGet(name, out var target) || (Object)(object)target.Shader == (Object)null) { continue; } string text = Signature(target.Shader); if (text != null) { if (!_valheimBySignature.TryGetValue(text, out var value)) { value = (_valheimBySignature[text] = new List<string>(1)); } if (!value.Exists((string n) => string.Equals(n, name, StringComparison.OrdinalIgnoreCase))) { value.Add(name); } } } foreach (List<string> value2 in _valheimBySignature.Values) { value2.Sort(StringComparer.Ordinal); } } private static bool IsNeverCandidate(string name) { string[] neverPrefixes = _neverPrefixes; foreach (string value in neverPrefixes) { if (name.StartsWith(value, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private static string Signature(Shader sh) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected I4, but got Unknown int instanceID = ((Object)sh).GetInstanceID(); if (_signatureById.TryGetValue(instanceID, out var value)) { return value; } string text = null; try { int propertyCount = sh.GetPropertyCount(); if (propertyCount >= 2) { string[] array = new string[propertyCount]; for (int i = 0; i < propertyCount; i++) { array[i] = sh.GetPropertyName(i) + ":" + (int)sh.GetPropertyType(i); } Array.Sort(array, (IComparer<string>?)StringComparer.Ordinal); StringBuilder stringBuilder = new StringBuilder(); string[] array2 = array; foreach (string value2 in array2) { stringBuilder.Append(value2).Append(';'); } text = stringBuilder.ToString(); } } catch (Exception) { text = null; } _signatureById[instanceID] = text; return text; } } [Flags] internal enum RendererKind { None = 0, Mesh = 1, Particle = 2, Other = 4 } internal static class RendererKinds { private static readonly Dictionary<int, RendererKind> _byId = new Dictionary<int, RendererKind>(); private static readonly List<Material> _buf = new List<Material>(); private static readonly List<Renderer> _renderersBuf = new List<Renderer>(); private static int _renderers; internal static void RecordUnder(GameObject root) { if ((Object)(object)root == (Object)null) { return; } _renderersBuf.Clear(); try { root.GetComponentsInChildren<Renderer>(true, _renderersBuf); foreach (Renderer item in _renderersBuf) { Record(item); } } catch (Exception) { } finally { _renderersBuf.Clear(); } } internal static void Begin() { _byId.Clear(); _renderers = 0; } internal static void Record(Renderer r) { try { if ((Object)(object)r == (Object)null) { return; } RendererKind rendererKind = KindOf(r); _renderers++; _buf.Clear(); r.GetSharedMaterials(_buf); foreach (Material item in _buf) { if (!((Object)(object)item == (Object)null)) { int instanceID = ((Object)item).GetInstanceID(); _byId.TryGetValue(instanceID, out var value); _byId[instanceID] = value | rendererKind; } } } catch (Exception) { } finally { _buf.Clear(); } } internal static RendererKind Get(int id) { if (!_byId.TryGetValue(id, out var value)) { return RendererKind.None; } return value; } private static RendererKind KindOf(Renderer r) { if (r is MeshRenderer || r is SkinnedMeshRenderer) { return RendererKind.Mesh; } if (r is ParticleSystemRenderer || r is TrailRenderer || r is LineRenderer) { return RendererKind.Particle; } return RendererKind.Other; } internal static string Summary() { return $"renderers: {_renderers} -> {_byId.Count} material(s) classified"; } } internal readonly struct ShaderShape { internal readonly int Subshaders; internal readonly int ActivePasses; internal readonly int[] PassesPerSubshader; internal ShaderShape(int subshaders, int activePasses, int[] passesPerSubshader) { Subshaders = subshaders; ActivePasses = activePasses; PassesPerSubshader = passesPerSubshader ?? Array.Empty<int>(); } public override string ToString() { return string.Format("sub={0} passes={1} [{2}]", Subshaders, ActivePasses, string.Join(",", PassesPerSubshader)); } } internal static class ShaderStructure { private const int MaxEnsureScans = 3; private static int _ensureScans; internal static ShaderShape Placeholder { get; private set; } internal static bool PlaceholderKnown { get; private set; } internal static void SetPlaceholder(ShaderShape shape, bool known) { Placeholder = shape; PlaceholderKnown = known && IsReadable(shape); } internal static ShaderShape Read(Shader sh) { int num; try { num = sh.subshaderCount; } catch (Exception) { num = -1; } int activePasses; try { activePasses = sh.passCount; } catch (Exception) { activePasses = -1; } if (num <= 0) { return new ShaderShape(num, activePasses, Array.Empty<int>()); } int[] array = new int[num]; for (int i = 0; i < num; i++) { try { array[i] = sh.GetPassCountInSubshader(i); } catch (Exception) { array[i] = -1; } } return new ShaderShape(num, activePasses, array); } internal static bool IsReadable(ShaderShape s) { if (s.Subshaders < 0 || s.ActivePasses < 0) { return false; } int[] passesPerSubshader = s.PassesPerSubshader; for (int i = 0; i < passesPerSubshader.Length; i++) { if (passesPerSubshader[i] < 0) { return false; } } return true; } internal static bool Equal(ShaderShape a, ShaderShape b) { if (a.Subshaders < 0 || b.Subshaders < 0 || a.ActivePasses < 0 || b.ActivePasses < 0) { return false; } if (a.Subshaders != b.Subshaders || a.ActivePasses != b.ActivePasses) { return false; } if (a.PassesPerSubshader.Length != b.PassesPerSubshader.Length) { return false; } for (int i = 0; i < a.PassesPerSubshader.Length; i++) { int num = a.PassesPerSubshader[i]; int num2 = b.PassesPerSubshader[i]; if (num < 0 || num2 < 0 || num != num2) { return false; } } return true; } internal static bool IsPlaceholder(Shader sh) { if ((Object)(object)sh != (Object)null && PlaceholderKnown) { return Equal(Read(sh), Placeholder); } return false; } internal static void EnsurePlaceholder() { if (PlaceholderKnown || _ensureScans >= 3) { return; } _ensureScans++; try { Shader[] array = Resources.FindObjectsOfTypeAll<Shader>(); foreach (Shader val in array) { if (!((Object)(object)val == (Object)null) && string.Equals(((Object)val).name, "Hidden/InternalErrorShader", StringComparison.Ordinal)) { SetPlaceholder(Read(val), known: true); break; } } } catch (Exception) { } } } internal sealed class ShippedRow { internal string Shader { get; private set; } internal string Source { get; private set; } internal int Queue { get; private set; } internal string[] Keywords { get; private set; } internal Dictionary<string, float> Blend { get; private set; } internal string SourceBundle { get; private set; } internal static ShippedRow Parse(string[] cols) { if (cols.Length < 6 || cols[1].Length == 0 || cols[2].Length == 0) { return null; } if (!int.TryParse(cols[3], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return null; } string[] array = ((cols[4] == "-") ? Array.Empty<string>() : cols[4].Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries)); Array.Sort(array, (IComparer<string>?)StringComparer.Ordinal); Dictionary<string, float> dictionary = new Dictionary<string, float>(StringComparer.Ordinal); if (cols[5] != "-") { string[] array2 = cols[5].Split(new char[1] { ';' }); foreach (string text in array2) { int num = text.IndexOf('='); if (num <= 0) { return null; } if (!float.TryParse(text.Substring(num + 1), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { return null; } dictionary[text.Substring(0, num)] = result2; } } string sourceBundle = (cols[2].StartsWith("bundle:", StringComparison.Ordinal) ? cols[2].Substring(7) : null); return new ShippedRow { Shader = cols[1], Source = cols[2], SourceBundle = sourceBundle, Queue = result, Keywords = array, Blend = dictionary }; } } internal enum TargetTier { None, Bundle, Engine, Structural, Source, Prefab } internal readonly struct Target { internal readonly Shader Shader; internal readonly int InstanceId; internal readonly TargetTier Tier; internal readonly int RivalCount; internal Target(Shader shader, int instanceId, TargetTier tier, int rivalCount) { Shader = shader; InstanceId = instanceId; Tier = tier; RivalCount = rivalCount; } } internal static class Targets { private const int NameCap = 24; private static readonly Dictionary<string, Target> _byName = new Dictionary<string, Target>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, HashSet<int>> _loadedIds = new Dictionary<string, HashSet<int>>(StringComparer.OrdinalIgnoreCase); private static readonly int[] _tierCounts = new int[4]; private static readonly List<string> _refused = new List<string>(); private static readonly Dictionary<string, List<Shader>> _unresolved = new Dictionary<string, List<Shader>>(StringComparer.OrdinalIgnoreCase); private static int _prefabTier; private static int _bundleRefused; private static int _noVanillaAuthor; private static int _ambiguous; private static int _noneUsable; private static int _unreadable; private static long _buildTicks; internal static bool TryGetForSource(string name, string sourceBundle, out Target target) { target = default(Target); if (string.IsNullOrEmpty(name)) { return false; } if (sourceBundle != null && _loadedIds.TryGetValue(name, out var value)) { Shader val = VanillaShaders.GetFrom(sourceBundle, name); if ((Object)(object)val != (Object)null && value.Contains(((Object)val).GetInstanceID())) { target = new Target(val, ((Object)val).GetInstanceID(), TargetTier.Source, value.Count); return true; } } return TryGet(name, out target); } internal static bool TryGet(string name, out Target target) { target = default(Target); if (!string.IsNullOrEmpty(name)) { return _byName.TryGetValue(name, out target); } return false; } internal static void Build() { long timestamp = Stopwatch.GetTimestamp(); ResetCounts(); Dictionary<string, List<Shader>> dictionary = LoadedByName(); _loadedIds.Clear(); if (dictionary == null) { return; } foreach (KeyValuePair<string, List<Shader>> item in dictionary) { HashSet<int> hashSet = new HashSet<int>(); foreach (Shader item2 in item.Value) { if ((Object)(object)item2 != (Object)null) { hashSet.Add(((Object)item2).GetInstanceID()); } } _loadedIds[item.Key] = hashSet; } ReadPlaceholder(dictionary); PassThroughTarget.Resolve(dictionary.TryGetValue("Hidden/BlitCopy", out var value) ? value.Count : 0); foreach (string shaderName in VanillaBaseline.ShaderNames) { dictionary.TryGetValue(shaderName, out var value2); if (value2 != null && value2.Count != 0) { TargetTier tier = TargetTier.None; Shader val = TryBundle(shaderName, value2, ref tier) ?? TryEngine(shaderName, value2, ref tier) ?? TryStructural(shaderName, value2, ref tier); if ((Object)(object)val == (Object)null) { _unresolved[shaderName] = value2; continue; } _byName[shaderName] = new Target(val, ((Object)val).GetInstanceID(), tier, value2.Count); _tierCounts[(int)tier]++; } } _buildTicks = Stopwatch.GetTimestamp() - timestamp; } internal static void AddPrefabProven() { try { if (!ShaderStructure.PlaceholderKnown) { return; } foreach (KeyValuePair<string, List<Shader>> item in _unresolved) { if (!ValheimPrefabShaders.TryGetSole(item.Key, out var instanceId)) { continue; } foreach (Shader item2 in item.Value) { if (!((Object)(object)item2 == (Object)null) && ((Object)item2).GetInstanceID() == instanceId) { ShaderShape shaderShape = ShaderStructure.Read(item2); if (ShaderStructure.IsReadable(shaderShape) && !ShaderStructure.Equal(shaderShape, ShaderStructure.Placeholder)) { _byName[item.Key] = new Target(item2, instanceId, TargetTier.Prefab, item.Value.Count); _prefabTier++; } break; } } } } catch (Exception ex) { ShaderHelperPlugin.Log.LogDebug((object)("[Targets] prefab tier skipped: " + ex.GetType().Name + ": " + ex.Message)); } finally { _unresolved.Clear(); } } internal static string Summary() { return $"targets={_byName.Count} (bundle={_tierCounts[1]} engine={_tierCounts[2]} structural={_tierCounts[3]} prefab={_prefabTier}); " + PassThroughTarget.Summary() + "; " + $"refused: bundleNotLoaded={_bundleRefused} noVanillaAuthor={_noVanillaAuthor} ambiguous={_ambiguous} " + string.Format("noneUsable={0} unreadable={1}; placeholder={2}; ", _noneUsable, _unreadable, ShaderStructure.PlaceholderKnown ? ShaderStructure.Placeholder.ToString() : "UNREAD") + $"{WorkMeter.Ms(_buildTicks):F1} ms" + ((_refused.Count > 0) ? ("; refused names: " + string.Join(", ", _refused)) : ""); } private static Shader TryBundle(string name, List<Shader> rivals, ref TargetTier tier) { Shader val = VanillaShaders.Get(name); if ((Object)(object)val == (Object)null) { return null; } if (Contains(rivals, val)) { tier = TargetTier.Bundle; return val; } _bundleRefused++; Note(name + "(bundleNotLoaded)"); return null; } private static Shader TryEngine(string name, List<Shader> rivals, ref TargetTier tier) { if (!UnityBuiltIns.ShaderNames.Contains(name)) { return null; } Shader val; try { val = Shader.Find(name); } catch (Exception) { val = null; } if ((Object)(object)val == (Object)null || !Contains(rivals, val)) { return null; } tier = TargetTier.Engine; return val; } private static Shader TryStructural(string name, List<Shader> rivals, ref TargetTier tier) { if (!ShaderStructure.PlaceholderKnown) { return null; } if (!VanillaBaseline.AuthoredShaderNames.Contains(name)) { _noVanillaAuthor++; Note(name + "(noVanillaAuthor)"); return null; } Shader val = null; int num = 0; foreach (Shader rival in rivals) { ShaderShape shaderShape = ShaderStructure.Read(rival); if (!ShaderStructure.IsReadable(shaderShape)) { _unreadable++; Note(name + "(unreadableRival)"); return null; } if (!ShaderStructure.Equal(shaderShape, ShaderStructure.Placeholder)) { num++; if ((Object)(object)val == (Object)null) { val = rival; } } } switch (num) { case 1: tier = TargetTier.Structural; return val; case 0: _noneUsable++; break; default: _ambiguous++; break; } Note(name + "(" + ((num == 0) ? "noneUsable" : (num + "usable")) + ")"); return null; } private static Dictionary<string, List<Shader>> LoadedByName() { Shader[] array; try { array = Resources.FindObjectsOfTypeAll<Shader>(); } catch (Exception ex) { ShaderHelperPlugin.Log.LogWarning((object)("[Targets] shader scan FAILED (" + ex.GetType().Name + "); no targets this pass (read failure, not a measurement).")); return null; } Dictionary<string, List<Shader>> dictionary = new Dictionary<string, List<Shader>>(StringComparer.OrdinalIgnoreCase); Shader[] array2 = array; foreach (Shader val in array2) { if ((Object)(object)val == (Object)null) { continue; } string name; try { name = ((Object)val).name; } catch (Exception) { continue; } if (!string.IsNullOrEmpty(name)) { if (!dictionary.TryGetValue(name, out var value)) { value = (dictionary[name] = new List<Shader>()); } if (!Contains(value, val)) { value.Add(val); } } } return dictionary; } private static void ReadPlaceholder(Dictionary<string, List<Shader>> byName) { if (byName.TryGetValue("Hidden/InternalErrorShader", out var value) && value.Count > 0) { ShaderStructure.SetPlaceholder(ShaderStructure.Read(value[0]), known: true); if (ShaderStructure.PlaceholderKnown) { return; } } ShaderStructure.SetPlaceholder(default(ShaderShape), known: false); ShaderHelperPlugin.Log.LogWarning((object)"[Targets] 'Hidden/InternalErrorShader' not loaded or not fully readable; structural tier disabled this pass."); } private static bool Contains(List<Shader> list, Shader sh) { int instanceID = ((Object)sh).GetInstanceID(); foreach (Shader item in list) { if ((Object)(object)item != (Object)null && ((Object)item).GetInstanceID() == instanceID) { return true; } } return false; } private static void Note(string s) { if (_refused.Count < 24) { _refused.Add(s); } } private static void ResetCounts() { _byName.Clear(); _refused.Clear(); _unresolved.Clear(); PassThroughTarget.Clear(); Array.Clear(_tierCounts, 0, _tierCounts.Length); _bundleRefused = (_noVanillaAuthor = (_ambiguous = (_noneUsable = (_unreadable = (_prefabTier = 0))))); } } internal static class UnityBuiltIns { internal const string ErrorShaderName = "Hidden/InternalErrorShader"; internal const string PassThroughShaderName = "Hidden/BlitCopy"; internal static readonly HashSet<string> ShaderNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Standard", "Standard (Specular setup)", "Standard (Roughness setup)", "Sprites/Default", "Sprites/Mask", "UI/Default", "UI/DefaultFont", "UI/Unlit/Text", "UI/Unlit/Transparent", "Unlit/Color", "Unlit/Texture", "Unlit/Transparent", "Unlit/Transparent Cutout", "Diffuse", "Mobile/Diffuse", "Transparent/Diffuse", "VertexLit", "Mobile/VertexLit", "Legacy Shaders/Particles/Alpha Blended", "Legacy Shaders/Particles/Additive", "Legacy Shaders/Particles/Additive (Soft)", "Legacy Shaders/Particles/Multiply", "Legacy Shaders/Particles/VertexLit Blended", "Particles/Standard Unlit", "Particles/Standard Surface", "TextMeshPro/Distance Field", "TextMeshPro/Distance Field (Surface)", "TextMeshPro/Distance Field Overlay", "TextMeshPro/Distance Field SSD", "TextMeshPro/Mobile/Distance Field", "TextMeshPro/Mobile/Distance Field - Masking", "TextMeshPro/Mobile/Distance Field Overlay", "TextMeshPro/Bitmap", "TextMeshPro/Mobile/Bitmap", "TextMeshPro/Sprite", "GUI/Text Shader" }; internal static readonly HashSet<string> DefaultMaterialNames = new HashSet<string>(StringComparer.Ordinal) { "Default-Line", "Default-Material", "Default-Particle", "Default-ParticleSystem", "Sprites-Default", "Font Material" }; } internal static class ValheimMaterials { private static readonly Dictionary<string, Material> _byName = new Dictionary<string, Material>(StringComparer.Ordinal); internal static int Count => _byName.Count; internal static void Begin() { _byName.Clear(); } internal static void End() { _byName.Clear(); } internal static void Add(string baseName, Material m) { if (!((Object)(object)m == (Object)null) && !string.IsNullOrEmpty(baseName)) { if (!_byName.TryGetValue(baseName, out var value)) { _byName[baseName] = m; } else if ((Object)(object)value != (Object)null && ((Object)value).GetInstanceID() != ((Object)m).GetInstanceID()) { _byName[baseName] = null; } } } internal static bool TryGet(string baseName, out Material m) { m = null; if (!string.IsNullOrEmpty(baseName) && _byName.TryGetValue(baseName, out m) && (Object)(object)m != (Object)null) { return (Object)(object)m.shader != (Object)null; } return false; } } internal static class ValheimPrefabShaders { private static readonly List<Renderer> _renderers = new List<Renderer>(); private static readonly List<Material> _materials = new List<Material>(); private static readonly HashSet<string> _listed = new HashSet<string>(StringComparer.Ordinal); private static readonly Dictionary<string, Dictionary<int, HashSet<string>>> _byName = new Dictionary<string, Dictionary<int, HashSet<string>>>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet<int> _ids = new HashSet<int>(); private static readonly Dictionary<int, (string Name, int Id)?> _judged = new Dictionary<int, (string, int)?>(); private static readonly HashSet<int> _valheimMaterialIds = new HashSet<int>(); private static readonly HashSet<string> _offPairNames = new HashSet<string>(StringComparer.Ordinal); private static int _prefabs; private static int _accepted; private static bool _faulted; private static long _ticks; private const int MinRoots = 2; internal static void Begin() { _byName.Clear(); _ids.Clear(); _judged.Clear(); _valheimMaterialIds.Clear(); _offPairNames.Clear(); _prefabs = (_accepted = 0); _faulted = false; _ticks = 0L; ValheimMaterials.Begin(); } internal static void AddFrom(GameObject prefab) { long timestamp = Stopwatch.GetTimestamp(); try { if ((Object)(object)prefab == (Object)null || !VanillaPrefabs.TryGet(((Object)prefab).name, out var prefabs)) { return; } _listed.Clear(); foreach (VanillaPrefab item2 in prefabs) { foreach (var material in item2.Materials) { string item = material.Material; if (VanillaBaseline.IsVanillaMaterial(item)) { _listed.Add(item); } } } if (_listed.Count == 0) { return; } _prefabs++; _renderers.Clear(); prefab.GetComponentsInChildren<Renderer>(true, _renderers); foreach (Renderer renderer in _renderers) { if ((Object)(object)renderer == (Object)null) { continue; } _materials.Clear(); renderer.GetSharedMaterials(_materials); foreach (Material material2 in _materials) { Note(material2, ((Object)prefab).name); } } } catch (Exception ex) { _faulted = true; ShaderHelperPlugin.Log.LogDebug((object)("[Targets] prefab proof skipped a prefab: " + ex.GetType().Name + ": " + ex.Message)); } finally { _renderers.Clear(); _materials.Clear(); _ticks += Stopwatch.GetTimestamp() - timestamp; } } private static void Note(Material m, string root) { if ((Object)(object)m == (Object)null) { return; } bool copy; string text = Names.MaterialBase(((Object)m).name, out copy); if (copy || !_listed.Contains(text)) { return; } int instanceID = ((Object)m).GetInstanceID(); _valheimMaterialIds.Add(instanceID); if (!_judged.TryGetValue(instanceID, out (string, int)? value)) { value = (_judged[instanceID] = Judge(m, text)); } if (!value.HasValue) { string text2 = Names.Shader(((Object)(object)m.shader != (Object)null) ? ((Object)m.shader).name : ""); bool num; if (!VanillaBaseline.TryGetPair(text, out var shader)) { if (!VanillaBaseline.IsAmbiguous(text)) { return; } num = !VanillaBaseline.TryGetRowsOn(text, text2, out var _); } else { num = !string.Equals(text2, shader, StringComparison.OrdinalIgnoreCase); } if (num) { _offPairNames.Add(text); } } else { var (key, key2) = value.Value; if (!_byName.TryGetValue(key, out var value2)) { value2 = (_byName[key] = new Dictionary<int, HashSet<string>>()); } if (!value2.TryGetValue(key2, out var value3)) { value3 = (value2[key2] = new HashSet<string>(StringComparer.Ordinal)); } value3.Add(root); } } private static (string Name, int Id)? Judge(Material m, string baseName) { Shader shader = m.shader; string text = (((Object)(object)shader != (Object)null) ? ((Object)shader).name : null); if (string.IsNullOrEmpty(text) || string.Equals(text, "Hidden/InternalErrorShader", StringComparison.Ordinal)) { return null; } string text2 = Names.Shader(text); bool num; if (!VanillaBaseline.TryGetPair(baseName, out var shader2)) { if (!VanillaBaseline.IsAmbiguous(baseName)) { goto IL_006c; } num = VanillaBaseline.TryGetRowsOn(baseName, text2, out var _); } else { num = string.Equals(text2, shader2, StringComparison.OrdinalIgnoreCase); } if (num) { int instanceID = ((Object)shader).GetInstanceID(); if (ShaderWriter.WasWritten(((Object)m).GetInstanceID())) { return null; } _ids.Add(instanceID); _accepted++; ValheimMaterials.Add(baseName, m); return (text2, instanceID); } goto IL_006c; IL_006c: return null; } internal static bool IsProven(int shaderId) { return _ids.Contains(shaderId); } internal static bool IsValheimMaterial(int materialId, string baseName, bool copy) { if (!_valheimMaterialIds.Contains(materialId)) { if (copy) { return _offPairNames.Contains(baseName); } return false; } return true; } internal static bool ProvesTarget(string shaderName, int targetId) { if (TryGetSole(shaderName, out var instanceId)) { return instanceId == targetId; } return false; } internal static bool TryGetSole(string shaderName, out int instanceId) { instanceId = 0; if (_faulted || string.IsNullOrEmpty(shaderName) || !_byName.TryGetValue(shaderName, out var value) || value.Count != 1) { return false; } foreach (KeyValuePair<int, HashSet<string>> item in value) { if (item.Value.Count < 2) { return false; } instanceId = item.Key; } return true; } internal static string Summary() { List<string> list = new List<string>(); foreach (KeyValuePair<string, Dictionary<int, HashSet<string>>> item in _byName) { if (item.Value.Count < 2) { continue; } List<string> list2 = new List<string>(); foreach (KeyValuePair<int, HashSet<string>> item2 in item.Value) { list2.Add($"#{item2.Key}x{item2.Value.Count}"); } list.Add("'" + item.Key + "' " + string.Join("/", list2)); } return $"prefab proof: {_prefabs} Valheim prefab(s) -> {_accepted} material(s) on {_byName.Count} shader name(s); " + string.Format("{0} name(s) on 2+ instances (refused){1}; ", list.Count, _faulted ? "; a prefab walk FAULTED: no target proven this pass" : "") + $"{WorkMeter.Ms(_ticks):F1} ms" + ((list.Count > 0) ? (": " + string.Join("; ", list)) : ""); } } internal static class VanillaBaseline { private const string ResourceName = "ShaderHelper.vanilla_baseline.cache"; private const string Magic = "# shaderhelper-vanilla-baseline"; private const int SchemaVersion = 6; internal static readonly HashSet<string> BundleNames = new HashSet<string>(StringComparer.Ordinal); internal static readonly HashSet<string> ShaderNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static readonly HashSet<string> ShippedShaderNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static readonly HashSet<string> AuthoredShaderNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet<string> _materialNames = new HashSet<string>(StringComparer.Ordinal); private static readonly Dictionary<string, List<ShippedRow>> _rows = new Dictionary<string, List<ShippedRow>>(StringComparer.Ordinal); private static readonly HashSet<string> _ambiguous = new HashSet<string>(StringComparer.Ordinal); internal static bool Loaded { get; private set; } internal static string ValheimVersion { get; private set; } = ""; internal static bool IsVanillaMaterial(string canonicalName) { if (!string.IsNullOrEmpty(canonicalName)) { if (!_materialNames.Contains(canonicalName)) { return _rows.ContainsKey(canonicalName); } return true; } return false; } internal static bool TryGetPair(string canonicalName, out string shader) { shader = null; if (string.IsNullOrEmpty(canonicalName) || _ambiguous.Contains(canonicalName) || !_rows.TryGetValue(canonicalName, out var value)) { return false; } shader = value[0].Shader; return true; } internal static bool TryGetRows(string canonicalName, out List<ShippedRow> rows) { rows = null; if (!string.IsNullOrEmpty(canonicalName)) { return _rows.TryGetValue(canonicalName, out rows); } return false; } internal static bool IsAmbiguous(string canonicalName) { if (!string.IsNullOrEmpty(canonicalName)) { return _ambiguous.Contains(canonicalName); } return false; } internal static bool TryGetRowsOn(string canonicalName, string shader, out List<ShippedRow> rows) { rows = null; if (string.IsNullOrEmpty(shader) || !TryGetRows(canonicalName, out var rows2)) { return false; } foreach (ShippedRow item in rows2) { if (string.Equals(item.Shader, shader, StringComparison.OrdinalIgnoreCase)) { (rows ?? (rows = new List<ShippedRow>(1))).Add(item); } } return rows != null; } internal static void Load(ManualLogSource log) { Clear(); long timestamp = Stopwatch.GetTimestamp(); try { using Stream stream = typeof(VanillaBaseline).Assembly.GetManifestResourceStream("ShaderHelper.vanilla_baseline.cache"); if (stream == null) { log.LogError((object)"[Baseline] embedded resource 'ShaderHelper.vanilla_baseline.cache' missing; NOTHING will be decided."); return; } using StreamReader r = new StreamReader(stream); Parse(r, log, timestamp); } catch (Exception ex) { Clear(); log.LogError((object)("[Baseline] read failed (" + ex.GetType().Name + ": " + ex.Message + "); NOTHING will be decided.")); } } private static void Parse(StreamReader r, ManualLogSource log, long t0) { string text = r.ReadLine(); if (text == null || !text.StartsWith("# shaderhelper-vanilla-baseline", StringComparison.Ordinal)) { log.LogError((object)"[Baseline] bad header."); return; } if (HeaderField(text, "schema=") != 6.ToString()) { log.LogError((object)$"[Baseline] schema mismatch (want {6}): '{text}'."); return; } ValheimVersion = HeaderField(text, "valheim-version="); if (ValheimVersion.Length == 0) { log.LogError((object)("[Baseline] header has no valheim-version: '" + text + "'.")); return; } int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; string text2 = ""; string text3; while ((text3 = r.ReadLine()) != null) { if (text3.Length > 0 && text3[text3.Length - 1] == '\r') { text3 = text3.Substring(0, text3.Length - 1); } if (text3.Length == 0 || text3[0] == '#') { continue; } if (text3[0] == '[' && text3[text3.Length - 1] == ']') { text2 = text3.Substring(1, text3.Length - 2); continue; } switch (text2) { case "bundles": BundleNames.Add(text3); break; case "mats": _materialNames.Add(text3); break; case "shaders": ShaderNames.Add(text3); break; case "matshaders": if (AddRow(text3.Split(new char[1] { '\t' }))) { num3++; } else { num++; } break; case "shadersrc": num4++; AddShipped(text3); break; case "prefabs": if (!VanillaPrefabs.Add(text3.Split(new char[1] { '\t' }))) { num2++; } break; } } foreach (KeyValuePair<string, List<ShippedRow>> row in _rows) { if (!_ambiguous.Contains(row.Key) && !UnityBuiltIns.DefaultMaterialNames.Contains(row.Key)) { AuthoredShaderNames.Add(row.Value[0].Shader); } } Loaded = BundleNames.Count > 0 && ShaderNames.Count > 0 && _rows.Count > 0; double num5 = (double)(Stopwatch.GetTimestamp() - t0) * 1000.0 / (double)Stopwatch.Frequency; log.LogInfo((object)($"[Baseline] schema {6}, valheim-version={ValheimVersion}: {BundleNames.Count} bundles, {_materialNames.Count} materials, " + $"{ShaderNames.Count} shaders, {num3} shipped rows over {_rows.Count - _ambiguous.Count} usable names ({_ambiguous.Count} ambiguous refused, " + $"{num} malformed; exact-case names), {num4} shader sources, {VanillaPrefabs.Count} prefabs ({num2} malformed); parsed in {num5:F0} ms.")); } private static bool AddRow(string[] cols) { ShippedRow shippedRow = ShippedRow.Parse(cols); if (shippedRow == null || cols[0].Length == 0) { return false; } if (!_rows.TryGetValue(cols[0], out var value)) { value = (_rows[cols[0]] = new List<ShippedRow>(1)); } else if (!string.Equals(value[0].Shader, shippedRow.Shader, StringComparison.OrdinalIgnoreCase)) { _ambiguous.Add(cols[0]); } value.Add(shippedRow); return true; } private static void AddShipped(string line) { int num = line.IndexOf('\t'); string text = ((num < 0) ? line : line.Substring(0, num)); if (text.Length > 0) { ShippedShaderNames.Add(text); } } private static string HeaderField(string header, string key) { int num = header.IndexOf(key, StringComparison.Ordinal); if (num < 0) { return ""; } int num2 = num + key.Length; int num3 = header.IndexOf(' ', num2); return header.Substring(num2, ((num3 < 0) ? header.Length : num3) - num2).Trim(); } private static void Clear() { BundleNames.Clear(); ShaderNames.Clear(); ShippedShaderNames.Clear(); AuthoredShaderNames.Clear(); _materialNames.Clear(); _rows.Clear(); _ambiguous.Clear(); VanillaPrefabs.Clear(); Loaded = false; ValheimVer