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 RavenwoodUnderground v1.0.2
plugins/RavenwoodUnderground/RavenwoodUnderground.dll
Decompiled 2 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.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using ServerSync; using TMPro; using UnityEngine; using UnityEngine.Audio; using UnityEngine.Rendering; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("BalrondJamesDungeonPack")] [assembly: AssemblyDescription("Balrond James Dungeon Pack - refactored Valheim build-piece pack with synchronized recipe configuration.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BalrondJamesDungeonPack")] [assembly: AssemblyCopyright("Copyright © Balrond")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("cde312a0-cf19-4264-8616-e1c74774beed")] [assembly: AssemblyFileVersion("1.1.9.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.9.0")] [module: UnverifiableCode] namespace RavenwoodUnderground { internal sealed class BuildPieceDefinition { internal string PrefabName { get; private set; } internal string DefaultRecipe { get; private set; } internal BuildPieceDefinition(string prefabName, string defaultRecipe) { PrefabName = prefabName; DefaultRecipe = defaultRecipe; } } internal static class BuildPieceList { internal static readonly BuildPieceDefinition[] Definitions = new BuildPieceDefinition[95] { new BuildPieceDefinition("piece_trollcaveroom1", "Stone:100,RWc_Bear:40"), new BuildPieceDefinition("piece_trollcaveroom2", "Stone:100,RWc_Wolf:8"), new BuildPieceDefinition("piece_ashlandsCaveCastle", "Stone:100,RWc_Lion:4"), new BuildPieceDefinition("piece_morgenHole1", "Stone:100,RWc_Lion:5"), new BuildPieceDefinition("piece_forestcrypt_Bend1", "Stone:75,RWc_Deer:5,RWc_Bear:4"), new BuildPieceDefinition("piece_forestcrypt_Bend2", "Stone:75,RWc_Deer:5,RWc_Bear:4"), new BuildPieceDefinition("piece_forestcrypt_chamber_hildir", "Stone:175,RWc_Bear:40"), new BuildPieceDefinition("piece_forestcrypt_Chasm01", "Stone:175,RWc_Deer:15,RWc_Bear:20"), new BuildPieceDefinition("piece_forestcrypt_Corridor1", "Stone:100,RWc_Bear:20"), new BuildPieceDefinition("piece_forestcrypt_Corridor2", "Stone:100,RWc_Bear:20"), new BuildPieceDefinition("piece_forestcrypt_Corridor3", "Stone:100,RWc_Bear:20"), new BuildPieceDefinition("piece_forestcrypt_EndCap", "Stone:10,RWc_Bear:1"), new BuildPieceDefinition("piece_forestcrypt_EndCap2", "Stone:10,RWc_Bear:1"), new BuildPieceDefinition("piece_forestcrypt_EndCap3", "Stone:10,RWc_Bear:1"), new BuildPieceDefinition("piece_forestcrypt_entrance_large", "Stone:125,RWc_Deer:25,RWc_Bear:20"), new BuildPieceDefinition("piece_forestcrypt_new_BurialChamber01", "Stone:150,RWc_Bear:20"), new BuildPieceDefinition("piece_forestcrypt_new_BurialChamber02", "Stone:150,RWc_Bear:20"), new BuildPieceDefinition("piece_forestcrypt_new_Burialchamber03", "Stone:150,RWc_Bear:20"), new BuildPieceDefinition("piece_forestcrypt_new_Burialchamber04", "Stone:150,RWc_Bear:20"), new BuildPieceDefinition("piece_forestcrypt_new_Burialchamber05", "Stone:150,RWc_Bear:30"), new BuildPieceDefinition("piece_forestcrypt_room1", "Stone:100,RWc_Bear:12"), new BuildPieceDefinition("piece_forestcrypt_room_16", "Stone:150,RWc_Bear:30"), new BuildPieceDefinition("piece_forestcrypt_Stairs1", "Stone:100,RWc_Bear:5"), new BuildPieceDefinition("piece_sunkencrypt_new_Corridor1", "Stone:150,RWc_Bear:10,RWc_Snake:10"), new BuildPieceDefinition("piece_sunkencrypt_new_Corridor2", "Stone:150,RWc_Bear:10,RWc_Snake:10"), new BuildPieceDefinition("piece_sunkencrypt_new_Corridor3", "Stone:150,RWc_Bear:10,RWc_Snake:10"), new BuildPieceDefinition("piece_sunkencrypt_new_Corridor4", "Stone:150,RWc_Bear:10,RWc_Snake:10"), new BuildPieceDefinition("piece_sunkencrypt_new_Corridor5", "Stone:150,RWc_Bear:10,RWc_Snake:10"), new BuildPieceDefinition("piece_sunkencrypt_new_Endcap1", "Stone:25,RWc_Snake:1"), new BuildPieceDefinition("piece_sunkencrypt_new_Endcap2", "Stone:25,RWc_Snake:1"), new BuildPieceDefinition("piece_sunkencrypt_new_Endcap3", "Stone:10,RWc_Snake:1"), new BuildPieceDefinition("piece_sunkencrypt_new_EndcapWater1", "Stone:10,RWc_Snake:1"), new BuildPieceDefinition("piece_sunkencrypt_new_EndcapWater2", "Stone:10,RWc_Snake:1"), new BuildPieceDefinition("piece_sunkencrypt_new_Room1", "Stone:175,RWc_Deer:30,RWc_Bear:10,RWc_Snake:10"), new BuildPieceDefinition("piece_sunkencrypt_new_Room2", "Stone:175,RWc_Deer:30,RWc_Bear:10,RWc_Snake:10"), new BuildPieceDefinition("piece_sunkencrypt_new_Room3", "Stone:175,RWc_Deer:30,RWc_Bear:10,RWc_Snake:10"), new BuildPieceDefinition("piece_sunkencrypt_new_Room4", "Stone:175,RWc_Deer:30,RWc_Bear:10,RWc_Snake:10"), new BuildPieceDefinition("piece_sunkencrypt_new_Stair1", "Stone:125,RWc_Deer:20,RWc_Snake:10"), new BuildPieceDefinition("piece_sunkencrypt_new_Start1", "Stone:100,RWc_Snake:15"), new BuildPieceDefinition("piece_cave_new_corridor01", "Stone:75,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_corridor03", "Stone:75,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_corridor05", "Stone:75,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_corridor06", "Stone:75,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_corridor07", "Stone:75,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_corridor08", "Stone:75,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_corridor09", "Stone:75,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_crossroads01", "Stone:150,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_crossroads02", "Stone:150,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_crossroads03", "Stone:150,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_crossroads01_hole", "Stone:175,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_slope_endcap01", "Stone:50,RWc_Wolf:1"), new BuildPieceDefinition("piece_cave_new_deeproom_bottom", "Stone:200,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_deeproom_bottom_lake", "Stone:200,RWc_Wolf:2"), new BuildPieceDefinition("piece_cave_new_deeproom_bottom_shrine", "Stone:200,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_deeproom_endcap", "Stone:50,RWc_Wolf:1"), new BuildPieceDefinition("piece_cave_new_deeproom_middle", "Stone:200,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_deeproom_roof", "Stone:200,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_deeproom_top", "Stone:200,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_endcap02", "Stone:45,RWc_Wolf:1"), new BuildPieceDefinition("piece_cave_new_entrance02", "Stone:125,RWc_Wolf:7"), new BuildPieceDefinition("piece_cave_new_icecorridor01", "Stone:125,RWc_Wolf:7"), new BuildPieceDefinition("piece_cave_new_icecorridor02", "Stone:125,RWc_Wolf:7"), new BuildPieceDefinition("piece_cave_new_icecorridor03", "Stone:125,RWc_Wolf:7"), new BuildPieceDefinition("piece_cave_divider", "Stone:50,RWc_Wolf:2"), new BuildPieceDefinition("piece_cave_divider02", "Stone:50,RWc_Wolf:2"), new BuildPieceDefinition("piece_cave_new_crossroads01_hole_long", "Stone:200,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_crossroads01_hole_shrine", "Stone:200,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_crossroads01_hole_to_deeproom", "Stone:200,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_new_sloperoom01", "Stone:300,RWc_Wolf:15"), new BuildPieceDefinition("piece_cave_new_sloperoom02", "Stone:300,RWc_Wolf:15"), new BuildPieceDefinition("piece_cave_new_sloperoom03", "Stone:300,RWc_Wolf:15"), new BuildPieceDefinition("piece_cave_new_sloperoom04", "Stone:300,RWc_Wolf:15"), new BuildPieceDefinition("piece_cave_new_sloperoom05", "Stone:300,RWc_Wolf:15"), new BuildPieceDefinition("piece_cave_new_sloperoom_w_hole", "Stone:300,RWc_Wolf:15"), new BuildPieceDefinition("piece_cave_shrine_corridor01", "Stone:75,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_shrine_corridor02", "Stone:75,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_shrine_corridor03", "Stone:75,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_shrine_corridor04", "Stone:75,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_shrine_corridor05", "Stone:75,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_shrine_corridor06", "Stone:75,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_shrine_corridor07", "Stone:75,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_shrine_endcap04", "Stone:25,RWc_Wolf:1"), new BuildPieceDefinition("piece_cave_shrine_endcap_noshrine02", "Stone:40,RWc_Wolf:1"), new BuildPieceDefinition("piece_cave_shrine_hole01", "Stone:175,RWc_Wolf:12"), new BuildPieceDefinition("piece_cave_shrine_lootencap02", "Stone:10,RWc_Wolf:1"), new BuildPieceDefinition("piece_cave_shrine_room01", "Stone:125,RWc_Wolf:10"), new BuildPieceDefinition("piece_cave_shrine_room02", "Stone:125,RWc_Wolf:10"), new BuildPieceDefinition("piece_cave_shrine_shrine01", "Stone:150,RWc_Wolf:10"), new BuildPieceDefinition("piece_cave_shrine_shrine02", "Stone:150,RWc_Wolf:10"), new BuildPieceDefinition("piece_cave_shrine_shrine03", "Stone:150,RWc_Wolf:10"), new BuildPieceDefinition("piece_cave_shrine_shrine03_HILDIR", "Stone:150,RWc_Wolf:10"), new BuildPieceDefinition("piece_cave_shrine_start02", "Stone:150,RWc_Wolf:10"), new BuildPieceDefinition("piece_cave_shrine_start02_corridor", "Stone:75,RWc_Wolf:8"), new BuildPieceDefinition("piece_cave_shrine_start02_ice", "Stone:150,RWc_Wolf:10"), new BuildPieceDefinition("piece_cave_shrine_start02_ice_corridor", "Stone:125,RWc_Wolf:8") }; internal static readonly string[] buildPieces = CreatePrefabNameArray(); private static string[] CreatePrefabNameArray() { string[] array = new string[Definitions.Length]; for (int i = 0; i < Definitions.Length; i++) { array[i] = Definitions[i].PrefabName; } return array; } internal static BuildPieceDefinition Find(string prefabName) { if (string.IsNullOrEmpty(prefabName)) { return null; } for (int i = 0; i < Definitions.Length; i++) { BuildPieceDefinition buildPieceDefinition = Definitions[i]; if (string.Equals(buildPieceDefinition.PrefabName, prefabName, StringComparison.Ordinal)) { return buildPieceDefinition; } } return null; } } internal static class BuildPieceRecipeConfig { private const string GeneralSection = "1 - General"; private const string RecipeSection = "2 - Build Piece Recipes"; private static readonly Dictionary<string, ConfigEntry<string>> RecipeEntries = new Dictionary<string, ConfigEntry<string>>(StringComparer.Ordinal); internal static ConfigEntry<bool> LockConfiguration { get; private set; } internal static event Action<string> RecipeChanged; internal static void Initialize(Launch plugin) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown if ((Object)(object)plugin == (Object)null) { throw new ArgumentNullException("plugin"); } ResetEntries(); LockConfiguration = ((BaseUnityPlugin)plugin).Config.Bind<bool>("1 - General", "Lock Configuration", true, new ConfigDescription("When enabled, build-piece recipe settings are controlled by the server/host for connected clients.", (AcceptableValueBase)null, Array.Empty<object>())); ServerSyncBridge.AddLockingConfigEntry(LockConfiguration); BuildPieceDefinition[] definitions = BuildPieceList.Definitions; foreach (BuildPieceDefinition buildPieceDefinition in definitions) { string prefabName = buildPieceDefinition.PrefabName; ConfigEntry<string> val = ((BaseUnityPlugin)plugin).Config.Bind<string>("2 - Build Piece Recipes", prefabName, buildPieceDefinition.DefaultRecipe, new ConfigDescription("Recipe for '" + prefabName + "'. Format: ItemPrefab:Amount,ItemPrefab:Amount. Example: Stone:100 or Stone:80,Iron:10. Use NONE for a zero-cost piece.", (AcceptableValueBase)null, Array.Empty<object>())); val.SettingChanged += OnRecipeSettingChanged; RecipeEntries[prefabName] = val; ServerSyncBridge.AddConfigEntry<string>(val); } } internal static string GetRecipe(BuildPieceDefinition definition) { if (definition == null) { return null; } if (RecipeEntries.TryGetValue(definition.PrefabName, out var value) && value != null) { return value.Value; } return definition.DefaultRecipe; } internal static void Reset() { ResetEntries(); LockConfiguration = null; BuildPieceRecipeConfig.RecipeChanged = null; } private static void ResetEntries() { foreach (KeyValuePair<string, ConfigEntry<string>> recipeEntry in RecipeEntries) { if (recipeEntry.Value != null) { recipeEntry.Value.SettingChanged -= OnRecipeSettingChanged; } } RecipeEntries.Clear(); } private static void OnRecipeSettingChanged(object sender, EventArgs eventArgs) { ConfigEntryBase val = (ConfigEntryBase)((sender is ConfigEntryBase) ? sender : null); if (val != null) { BuildPieceRecipeConfig.RecipeChanged?.Invoke(val.Definition.Key); } } } internal static class ServerSyncBridge { private static object _syncObject; internal static void Initialize(string pluginGuid, string displayName, string version) { ConfigSync syncObject = new ConfigSync(pluginGuid) { DisplayName = displayName, CurrentVersion = version, MinimumRequiredVersion = version }; _syncObject = syncObject; } internal static void AddLockingConfigEntry(ConfigEntry<bool> entry) { GetSync().AddLockingConfigEntry<bool>(entry); } internal static void AddConfigEntry<T>(ConfigEntry<T> entry) { SyncedConfigEntry<T> syncedConfigEntry = GetSync().AddConfigEntry<T>(entry); syncedConfigEntry.SynchronizedConfig = true; } internal static void Reset() { _syncObject = null; } private static ConfigSync GetSync() { if (!(_syncObject is ConfigSync result)) { throw new InvalidOperationException("ServerSyncBridge was used before successful initialization."); } return result; } } internal static class BalrondHashCompat { public static int StableHash(string value) { if (value == null) { return 0; } return StringExtensionMethods.GetStableHashCode(value); } } internal sealed class EffectReferenceMapper { private readonly PrefabLookupCache _prefabCache = new PrefabLookupCache(); private List<GameObject> _scenePrefabs; internal void Rebuild(List<GameObject> scenePrefabs) { _scenePrefabs = scenePrefabs; _prefabCache.Rebuild(scenePrefabs); } internal void RepairBuildPiece(GameObject prefab) { if (!((Object)(object)prefab == (Object)null) && _scenePrefabs != null) { Piece component = prefab.GetComponent<Piece>(); if ((Object)(object)component != (Object)null) { RepairEffectList(component.m_placeEffect); } WearNTear component2 = prefab.GetComponent<WearNTear>(); if ((Object)(object)component2 != (Object)null) { RepairEffectList(component2.m_hitEffect); RepairEffectList(component2.m_destroyedEffect); } } } private void RepairEffectList(EffectList effectList) { if (effectList == null) { return; } EffectData[] effectPrefabs = effectList.m_effectPrefabs; if (effectPrefabs == null || effectPrefabs.Length == 0) { return; } foreach (EffectData val in effectPrefabs) { if ((Object)(object)val.m_prefab == (Object)null) { continue; } string name = ((Object)val.m_prefab).name; if (!string.IsNullOrEmpty(name)) { GameObject val2 = _prefabCache.Find(name, _scenePrefabs); if ((Object)(object)val2 != (Object)null) { val.m_prefab = val2; } } } } } public class ModResourceLoader { private const string BundleResourceName = "jamesdungeon"; private const string BaseAssetPath = "Assets/Custom/Comission/JamseDUngeon/"; private static readonly FieldInfo ObjectDbBuildPiecesField = typeof(ObjectDB).GetField("m_buildPieces", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static bool _loggedMissingObjectDbBuildPiecesField; private static readonly string[] HammerNames = new string[4] { "Hammer", "HammerIron", "HammerDverger", "HammerBlackmetal" }; private static readonly string[] OtherPrefabNames = new string[0]; private readonly PrefabLookupCache _scenePrefabCache = new PrefabLookupCache(); private readonly Dictionary<int, string> _sceneHashNames = new Dictionary<int, string>(); private readonly EffectReferenceMapper _effectReferenceMapper = new EffectReferenceMapper(); private bool _sceneRegistrationCompleted; public AssetBundle assetBundle; public readonly List<GameObject> buildPrefabs = new List<GameObject>(); public readonly List<GameObject> vfxPrefabs = new List<GameObject>(); public readonly List<GameObject> registeredBuildPrefabs = new List<GameObject>(); public void loadAssets() { buildPrefabs.Clear(); vfxPrefabs.Clear(); registeredBuildPrefabs.Clear(); _sceneRegistrationCompleted = false; assetBundle = GetAssetBundleFromResources("jamesdungeon"); if (!((Object)(object)assetBundle == (Object)null)) { LoadPieces("Assets/Custom/Comission/JamseDUngeon/Pieces/"); LoadOther("Assets/Custom/Comission/JamseDUngeon/Other/"); } } public void AddPrefabsToZnetScene(ZNetScene zNetScene) { if (!((Object)(object)zNetScene == (Object)null) && zNetScene.m_prefabs != null) { registeredBuildPrefabs.Clear(); _scenePrefabCache.Rebuild(zNetScene.m_prefabs); RebuildSceneHashCache(zNetScene.m_prefabs); RegisterPrefabCollection(vfxPrefabs, zNetScene, null); RegisterPrefabCollection(buildPrefabs, zNetScene, registeredBuildPrefabs); _effectReferenceMapper.Rebuild(zNetScene.m_prefabs); for (int i = 0; i < registeredBuildPrefabs.Count; i++) { _effectReferenceMapper.RepairBuildPiece(registeredBuildPrefabs[i]); } _sceneRegistrationCompleted = true; } } public void FinalizeZNetSceneSetup(ZNetScene zNetScene) { if (!((Object)(object)zNetScene == (Object)null) && zNetScene.m_prefabs != null) { _scenePrefabCache.Rebuild(zNetScene.m_prefabs); RefreshRegisteredBuildPrefabs(zNetScene.m_prefabs); SetupBuildPiecesList(zNetScene); setupBuildPiecesListDB(); } } public void setupBuildPiecesListDB() { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null || instance.m_items == null || !_sceneRegistrationCompleted) { return; } GameObject val = instance.GetItemPrefab("Hammer"); if ((Object)(object)val == (Object)null) { val = instance.m_items.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == "Hammer"); } if (TryGetPieceTable(val, out var pieceTable)) { AddBuildPrefabsToPieceTable(pieceTable, registeredBuildPrefabs); RavenwoodBuildMenuCompat.EnsureCategoryOnPieceTable(pieceTable, (PieceCategory)0); InvalidateObjectDbBuildPieceCache(instance); } } public bool IsHammerPieceTable(PieceTable pieceTable) { if ((Object)(object)pieceTable == (Object)null) { return false; } ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null || instance.m_items == null) { return false; } GameObject val = instance.GetItemPrefab("Hammer"); if ((Object)(object)val == (Object)null) { val = instance.m_items.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == "Hammer"); } if (!TryGetPieceTable(val, out var pieceTable2)) { return false; } return pieceTable == pieceTable2 || (!string.IsNullOrEmpty(((Object)pieceTable).name) && string.Equals(((Object)pieceTable).name, ((Object)pieceTable2).name, StringComparison.Ordinal)); } public int EnsureRuntimeHammerPieces(PieceTable pieceTable) { if (!IsHammerPieceTable(pieceTable) || pieceTable.m_pieces == null) { return 0; } int count = pieceTable.m_pieces.Count; AddBuildPrefabsToPieceTable(pieceTable, registeredBuildPrefabs); RavenwoodBuildMenuCompat.EnsureCategoryOnPieceTable(pieceTable, (PieceCategory)0); if ((Object)(object)ObjectDB.instance != (Object)null) { InvalidateObjectDbBuildPieceCache(ObjectDB.instance); } return pieceTable.m_pieces.Count - count; } public IEnumerable<GameObject> EnumerateAudioPrefabs() { for (int i = 0; i < buildPrefabs.Count; i++) { if ((Object)(object)buildPrefabs[i] != (Object)null) { yield return buildPrefabs[i]; } } for (int j = 0; j < vfxPrefabs.Count; j++) { if ((Object)(object)vfxPrefabs[j] != (Object)null) { yield return vfxPrefabs[j]; } } } private void LoadPieces(string path) { LoadPrefabCollection(BuildPieceList.buildPieces, path, buildPrefabs, "piece"); } private void LoadOther(string path) { LoadPrefabCollection(OtherPrefabNames, path, vfxPrefabs, "object"); } private void LoadPrefabCollection(string[] prefabNames, string path, List<GameObject> destination, string assetKind) { if (prefabNames == null || destination == null || (Object)(object)assetBundle == (Object)null) { return; } HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); List<string> list = new List<string>(); foreach (string text in prefabNames) { if (string.IsNullOrWhiteSpace(text)) { continue; } if (!hashSet.Add(text)) { if (Launch.Log != null) { Launch.Log.LogWarning((object)("Duplicate " + assetKind + " entry ignored while loading: " + text)); } continue; } GameObject val = null; try { val = assetBundle.LoadAsset<GameObject>(path + text + ".prefab"); } catch (Exception ex) { if (Launch.Log != null) { Launch.Log.LogError((object)("Failed to load " + assetKind + " '" + text + "': " + ex)); } continue; } if ((Object)(object)val == (Object)null) { list.Add(text); continue; } ShaderReplacment.Replace(val); destination.Add(val); } if (list.Count > 0 && Launch.Log != null) { int num = Math.Min(list.Count, 24); string text2 = string.Join(", ", list.GetRange(0, num).ToArray()); if (list.Count > num) { text2 += ", ..."; } Launch.Log.LogWarning((object)("AssetBundle is missing " + list.Count + " " + assetKind + " prefab(s): " + text2)); } } private AssetBundle GetAssetBundleFromResources(string filename) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string[] manifestResourceNames = executingAssembly.GetManifestResourceNames(); string text = null; for (int i = 0; i < manifestResourceNames.Length; i++) { if (manifestResourceNames[i].EndsWith(filename, StringComparison.OrdinalIgnoreCase)) { text = manifestResourceNames[i]; break; } } if (string.IsNullOrEmpty(text)) { if (Launch.Log != null) { Launch.Log.LogError((object)("Embedded AssetBundle resource not found: " + filename)); } return null; } using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { if (Launch.Log != null) { Launch.Log.LogError((object)("Could not open embedded AssetBundle resource: " + text)); } return null; } AssetBundle val = AssetBundle.LoadFromStream(stream); if ((Object)(object)val == (Object)null && Launch.Log != null) { Launch.Log.LogError((object)("AssetBundle.LoadFromStream returned null for: " + text)); } return val; } private void RebuildSceneHashCache(List<GameObject> prefabs) { _sceneHashNames.Clear(); if (prefabs == null) { return; } for (int i = 0; i < prefabs.Count; i++) { GameObject val = prefabs[i]; if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(((Object)val).name)) { int key = BalrondHashCompat.StableHash(((Object)val).name); if (!_sceneHashNames.ContainsKey(key)) { _sceneHashNames.Add(key, ((Object)val).name); } } } } private void RegisterPrefabCollection(List<GameObject> prefabs, ZNetScene zNetScene, List<GameObject> registered) { if (prefabs == null) { return; } for (int i = 0; i < prefabs.Count; i++) { GameObject val = prefabs[i]; if (RegisterPrefab(val, zNetScene) && registered != null && (Object)(object)val != (Object)null) { registered.Add(val); } } } private bool RegisterPrefab(GameObject prefab, ZNetScene zNetScene) { if ((Object)(object)prefab == (Object)null || string.IsNullOrEmpty(((Object)prefab).name) || (Object)(object)zNetScene == (Object)null || zNetScene.m_prefabs == null) { return false; } GameObject val = _scenePrefabCache.Find(((Object)prefab).name, zNetScene.m_prefabs); if ((Object)(object)val != (Object)null) { if ((Object)(object)val == (Object)(object)prefab) { return true; } if (Launch.Log != null) { Launch.Log.LogWarning((object)("Prefab name conflict for '" + ((Object)prefab).name + "'. Keeping the prefab already registered by the game or another mod.")); } return false; } int key = BalrondHashCompat.StableHash(((Object)prefab).name); if (_sceneHashNames.TryGetValue(key, out var value)) { if (Launch.Log != null) { Launch.Log.LogError((object)("Cannot register prefab '" + ((Object)prefab).name + "': stable hash is already used by '" + value + "'.")); } return false; } zNetScene.m_prefabs.Add(prefab); _scenePrefabCache.Remember(prefab); _sceneHashNames[key] = ((Object)prefab).name; return true; } private void RefreshRegisteredBuildPrefabs(List<GameObject> scenePrefabs) { registeredBuildPrefabs.Clear(); if (scenePrefabs == null) { return; } for (int i = 0; i < buildPrefabs.Count; i++) { GameObject val = buildPrefabs[i]; if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(((Object)val).name)) { GameObject val2 = _scenePrefabCache.Find(((Object)val).name, scenePrefabs); if ((Object)(object)val2 == (Object)(object)val) { registeredBuildPrefabs.Add(val); } } } } private void SetupBuildPiecesList(ZNetScene zNetScene) { GameObject tool = _scenePrefabCache.Find("Hammer", zNetScene.m_prefabs); if (!TryGetPieceTable(tool, out var pieceTable)) { if (Launch.Log != null) { Launch.Log.LogError((object)"Hammer PieceTable could not be resolved in ZNetScene."); } return; } for (int i = 0; i < HammerNames.Length; i++) { GameObject val = _scenePrefabCache.Find(HammerNames[i], zNetScene.m_prefabs); if ((Object)(object)val == (Object)null) { continue; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null) { if (Launch.Log != null) { Launch.Log.LogWarning((object)("Build tool has invalid ItemDrop data: " + HammerNames[i])); } } else { component.m_itemData.m_shared.m_buildPieces = pieceTable; } } GameObject ravenGuidePrefab = GetRavenGuidePrefab(zNetScene); for (int j = 0; j < registeredBuildPrefabs.Count; j++) { GameObject gameObject = registeredBuildPrefabs[j]; SetupRavenGuide(gameObject, ravenGuidePrefab); } AddBuildPrefabsToPieceTable(pieceTable, registeredBuildPrefabs); RavenwoodBuildMenuCompat.EnsureCategoryOnPieceTable(pieceTable, (PieceCategory)0); } private void AddBuildPrefabsToPieceTable(PieceTable pieceTable, List<GameObject> prefabs) { if ((Object)(object)pieceTable == (Object)null || pieceTable.m_pieces == null || prefabs == null) { return; } List<GameObject> pieces = pieceTable.m_pieces; HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); for (int i = 0; i < pieces.Count; i++) { GameObject val = pieces[i]; if ((Object)(object)val != (Object)null && !string.IsNullOrEmpty(((Object)val).name)) { hashSet.Add(((Object)val).name); } } for (int j = 0; j < prefabs.Count; j++) { GameObject prefab = prefabs[j]; if (!((Object)(object)prefab == (Object)null) && !string.IsNullOrEmpty(((Object)prefab).name) && !hashSet.Contains(((Object)prefab).name)) { GameObject val2 = pieces.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == ((Object)prefab).name); if ((Object)(object)val2 != (Object)null) { hashSet.Add(((Object)prefab).name); continue; } pieces.Add(prefab); hashSet.Add(((Object)prefab).name); } } } private static void InvalidateObjectDbBuildPieceCache(ObjectDB objectDb) { if ((Object)(object)objectDb == (Object)null) { return; } if (ObjectDbBuildPiecesField == null) { if (!_loggedMissingObjectDbBuildPiecesField && Launch.Log != null) { _loggedMissingObjectDbBuildPiecesField = true; Launch.Log.LogWarning((object)"ObjectDB.m_buildPieces was not found. Build-piece cache invalidation was skipped; verify the current Valheim API."); } return; } try { ObjectDbBuildPiecesField.SetValue(objectDb, null); } catch (Exception ex) { if (Launch.Log != null) { Launch.Log.LogWarning((object)("Could not invalidate ObjectDB build-piece cache: " + ex)); } } } private GameObject GetRavenGuidePrefab(ZNetScene zNetScene) { GameObject val = _scenePrefabCache.Find("Ravens", zNetScene.m_prefabs); if ((Object)(object)val != (Object)null) { return val; } GameObject val2 = _scenePrefabCache.Find("piece_workbench", zNetScene.m_prefabs); if ((Object)(object)val2 == (Object)null) { return null; } Transform val3 = val2.transform.Find("GuidePoint"); if ((Object)(object)val3 == (Object)null) { return null; } GuidePoint component = ((Component)val3).GetComponent<GuidePoint>(); return ((Object)(object)component != (Object)null) ? component.m_ravenPrefab : null; } private void SetupRavenGuide(GameObject gameObject, GameObject ravenPrefab) { if ((Object)(object)gameObject == (Object)null || (Object)(object)ravenPrefab == (Object)null) { return; } Transform val = gameObject.transform.Find("GuidePoint"); if (!((Object)(object)val == (Object)null)) { GuidePoint component = ((Component)val).GetComponent<GuidePoint>(); if ((Object)(object)component != (Object)null) { component.m_ravenPrefab = ravenPrefab; } } } private static bool TryGetPieceTable(GameObject tool, out PieceTable pieceTable) { pieceTable = null; if ((Object)(object)tool == (Object)null) { return false; } ItemDrop component = tool.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null) { return false; } pieceTable = component.m_itemData.m_shared.m_buildPieces; return (Object)(object)pieceTable != (Object)null && pieceTable.m_pieces != null; } } internal static class PieceMetadataCompat { private const int MaxAuditNames = 24; public static void Apply(Piece piece, string prefabName) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Invalid comparison between Unknown and I4 //IL_0053: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)piece == (Object)null)) { if (piece.m_resources == null) { piece.m_resources = (Requirement[])(object)new Requirement[0]; } UsageTagFlags val = InferUsageTags(piece, prefabName); piece.m_usage |= val; RavenwoodBuildMenuCompat.ApplyProviderUsageTag(piece); if ((int)piece.m_usage == 0) { piece.m_usage = (UsageTagFlags)1; } } } public static void Audit(IList<GameObject> prefabs) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Invalid comparison between Unknown and I4 //IL_00ca: Unknown result type (might be due to invalid IL or missing references) if (prefabs == null || Launch.Log == null) { return; } int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; List<string> list = new List<string>(); for (int i = 0; i < prefabs.Count; i++) { GameObject val = prefabs[i]; if ((Object)(object)val == (Object)null) { continue; } num++; Piece component = val.GetComponent<Piece>(); if ((Object)(object)component == (Object)null) { num2++; RememberBadName(list, ((Object)val).name + "[no Piece]"); continue; } bool flag = false; if (!component.m_enabled) { num3++; flag = true; } if ((int)component.m_usage == 0) { num4++; flag = true; } if (!IsValidCategory(component.m_category)) { num5++; flag = true; } if ((Object)(object)component.m_icon == (Object)null) { num6++; flag = true; } if (flag) { RememberBadName(list, ((Object)val).name); } } Launch.Log.LogInfo((object)("Build-piece metadata audit: total=" + num + ", noPiece=" + num2 + ", disabled=" + num3 + ", zeroUsage=" + num4 + ", invalidCategory=" + num5 + ", missingIcon=" + num6 + ".")); if (list.Count > 0) { Launch.Log.LogWarning((object)("Build-piece metadata requires attention: " + string.Join(", ", list.ToArray()))); } } private static UsageTagFlags InferUsageTags(Piece piece, string prefabName) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Unknown result type (might be due to invalid IL or missing references) //IL_036f: Unknown result type (might be due to invalid IL or missing references) //IL_03cc: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_0433: Unknown result type (might be due to invalid IL or missing references) //IL_0434: Unknown result type (might be due to invalid IL or missing references) //IL_0458: Unknown result type (might be due to invalid IL or missing references) //IL_045e: Unknown result type (might be due to invalid IL or missing references) //IL_045f: Unknown result type (might be due to invalid IL or missing references) //IL_047a: Unknown result type (might be due to invalid IL or missing references) //IL_0480: Unknown result type (might be due to invalid IL or missing references) //IL_0481: Unknown result type (might be due to invalid IL or missing references) //IL_049c: Unknown result type (might be due to invalid IL or missing references) //IL_04a2: Unknown result type (might be due to invalid IL or missing references) //IL_04a3: Unknown result type (might be due to invalid IL or missing references) //IL_04c6: Unknown result type (might be due to invalid IL or missing references) //IL_04cc: Unknown result type (might be due to invalid IL or missing references) //IL_04cd: Unknown result type (might be due to invalid IL or missing references) //IL_0500: Unknown result type (might be due to invalid IL or missing references) //IL_0501: Unknown result type (might be due to invalid IL or missing references) //IL_04f8: Unknown result type (might be due to invalid IL or missing references) //IL_04fe: Unknown result type (might be due to invalid IL or missing references) //IL_04ff: Unknown result type (might be due to invalid IL or missing references) //IL_0505: Unknown result type (might be due to invalid IL or missing references) UsageTagFlags val = (UsageTagFlags)(UsageFromClassicCategory(piece.m_category) | 4 | 0x40); string value = (prefabName ?? ((Object)piece).name ?? string.Empty).ToLowerInvariant(); if (ContainsAny(value, "floor", "platform", "celling", "ceiling")) { val = (UsageTagFlags)(val | 0xC); } if (ContainsAny(value, "wall", "window")) { val = (UsageTagFlags)(val | 0x14); } if (ContainsAny(value, "roof")) { val = (UsageTagFlags)(val | 0x24); } if (ContainsAny(value, "stair", "ladder", "ramp", "step")) { val = (UsageTagFlags)(val | 0x20004); } if (ContainsAny(value, "door", "gate", "hatch")) { val = (UsageTagFlags)(val | 0x40004); } if (ContainsAny(value, "beam", "pole", "pillar", "column", "arch", "frame", "trim", "railing", "ledge", "counter", "oriel", "slab", "corridor", "room", "chamber", "crypt", "cave", "castle", "entrance", "start", "endcap", "crossroad", "divider", "chasm", "hole", "shrine", "tunnel", "slope")) { val = (UsageTagFlags)(val | 0x44); } if (ContainsAny(value, "bridge")) { val = (UsageTagFlags)(val | 0x844); } if (ContainsAny(value, "stake", "spike", "fence", "palisade", "barricade", "defense", "ballista", "trap")) { val = (UsageTagFlags)(val | 0x8000); } if (ContainsAny(value, "chair", "bench", "table", "bed", "throne", "stool")) { val = (UsageTagFlags)(val | 0x80); } if (ContainsAny(value, "torch", "light", "lantern", "brazier", "candle", "fire")) { val = (UsageTagFlags)(val | 0x100); } if (ContainsAny(value, "chest", "storage", "shelf", "rack")) { val = (UsageTagFlags)(val | 0x400); } if (ContainsAny(value, "deco", "decor", "raven", "dragon", "head_", "head1", "head2", "vigvisir", "rune")) { val = (UsageTagFlags)(val | 0x200); } if (ContainsAny(value, "workbench", "forge", "cauldron", "craft", "smelter", "kiln", "oven", "windmill", "spinning")) { val = (UsageTagFlags)(val | 2); } if (ContainsAny(value, "food", "cheese")) { val = (UsageTagFlags)(val | 0x1000); } if (ContainsAny(value, "mead")) { val = (UsageTagFlags)(val | 0x2000); } if (ContainsAny(value, "feast")) { val = (UsageTagFlags)(val | 0x4000); } if (ContainsAny(value, "stack", "pile")) { val = (UsageTagFlags)(val | 0x10000); } if (ContainsAny(value, "seasonal", "yule", "midsummer")) { val = (UsageTagFlags)(val | 0x80000); } return val; } private static UsageTagFlags UsageFromClassicCategory(PieceCategory category) { //IL_0001: 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_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected I4, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 switch ((int)category) { default: if ((int)category == 100) { } break; case 1: return (UsageTagFlags)2; case 2: case 3: return (UsageTagFlags)4; case 4: return (UsageTagFlags)128; case 6: return (UsageTagFlags)16384; case 7: return (UsageTagFlags)4096; case 8: return (UsageTagFlags)8192; case 0: return (UsageTagFlags)1; case 5: break; } return (UsageTagFlags)0; } private static bool IsValidCategory(PieceCategory category) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return RavenwoodBuildMenuCompat.IsKnownCategory(category); } private static bool ContainsAny(string value, params string[] needles) { if (string.IsNullOrEmpty(value) || needles == null) { return false; } for (int i = 0; i < needles.Length; i++) { if (!string.IsNullOrEmpty(needles[i]) && value.IndexOf(needles[i], StringComparison.Ordinal) >= 0) { return true; } } return false; } private static void RememberBadName(List<string> names, string name) { if (names.Count < 24 && !string.IsNullOrEmpty(name)) { names.Add(name); } } } internal static class RavenwoodBuildMenuCompat { internal const string CategoryName = "Ravenwood"; internal const string CategoryLabelToken = "$jotunn_cat_ravenwood"; internal const string LegacyBuildMenuGuid = "Azumatt.LegacyBuildMenu"; internal const string RavenwoodJapanGuid = "JamesJonesTV.RavenwoodJapan"; internal const string JotunnGuid = "com.jotunn.jotunn"; internal const string MinimumJotunnVersion = "2.30.1"; internal const string HammerTimeGuid = "com.maxsch.valheim.HammerTime"; private static bool _hasCachedCategory; private static PieceCategory _cachedCategory; private static bool _loggedCategory; private static bool _loggedLegacyMirror; private static bool _loggedHudExpansion; internal static PieceCategory GetOrCreateRavenwoodCategory(PieceCategory fallback) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) try { PieceCategory? pieceCategory = PieceManager.Instance.GetPieceCategory("Ravenwood"); PieceCategory val = (pieceCategory.HasValue ? pieceCategory.Value : PieceManager.Instance.AddPieceCategory("Ravenwood")); Cache(val); return val; } catch (Exception ex) { if (Launch.Log != null) { Launch.Log.LogError((object)("Jotunn Ravenwood category registration failed: " + ex)); } return fallback; } } internal static PieceCategory RefreshRavenwoodCategory(PieceCategory fallback) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) _hasCachedCategory = false; return GetOrCreateRavenwoodCategory(fallback); } internal static bool TryGetResolvedCategory(out PieceCategory category) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Expected I4, but got Unknown category = (PieceCategory)(int)GetOrCreateRavenwoodCategory((PieceCategory)0); return _hasCachedCategory; } internal static void AssignCategory(Piece piece, PieceCategory fallback) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)piece == (Object)null)) { PieceCategory orCreateRavenwoodCategory = GetOrCreateRavenwoodCategory(fallback); piece.m_category = (_hasCachedCategory ? orCreateRavenwoodCategory : fallback); } } internal static void ApplyProviderUsageTag(Piece piece) { } internal static void EnsureCategoryOnPieceTable(PieceTable pieceTable, PieceCategory fallback) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Expected I4, but got Unknown if ((Object)(object)pieceTable == (Object)null) { return; } PieceCategory orCreateRavenwoodCategory = GetOrCreateRavenwoodCategory(fallback); if (!_hasCachedCategory || pieceTable.m_categories == null || pieceTable.m_categoryLabels == null) { return; } int num = pieceTable.m_categories.IndexOf(orCreateRavenwoodCategory); if (num < 0) { pieceTable.m_categories.Add(orCreateRavenwoodCategory); pieceTable.m_categoryLabels.Add("$jotunn_cat_ravenwood"); num = pieceTable.m_categories.Count - 1; } else { while (pieceTable.m_categoryLabels.Count <= num) { pieceTable.m_categoryLabels.Add(string.Empty); } string text = pieceTable.m_categoryLabels[num]; if (string.IsNullOrEmpty(text) || string.Equals(text, "Ravenwood", StringComparison.OrdinalIgnoreCase)) { pieceTable.m_categoryLabels[num] = "$jotunn_cat_ravenwood"; } } if (!_loggedLegacyMirror && Launch.Log != null) { _loggedLegacyMirror = true; Launch.Log.LogInfo((object)("Ravenwood mirrored into Hammer PieceTable categories (id=" + (int)orCreateRavenwoodCategory + ", index=" + num + ").")); } } internal static void SyncLegacyHudTabs(PieceTable pieceTable) { if ((Object)(object)pieceTable == (Object)null || (Object)(object)Hud.instance == (Object)null) { return; } EnsureCategoryOnPieceTable(pieceTable, (PieceCategory)0); GameObject[] array = Hud.instance.m_pieceCategoryTabs; if (array == null || array.Length == 0) { return; } int count = pieceTable.m_categories.Count; if (count <= 0) { return; } int num = array.Length; if (num < count) { GameObject val = array[0]; if ((Object)(object)val == (Object)null) { return; } Array.Resize(ref array, count); for (int i = num; i < count; i++) { GameObject val2 = Object.Instantiate<GameObject>(val, val.transform.parent); val2.SetActive(false); UIInputHandler val3 = val2.GetComponent<UIInputHandler>(); if ((Object)(object)val3 == (Object)null) { val3 = val2.AddComponent<UIInputHandler>(); } UIInputHandler obj = val3; obj.m_onLeftDown = (Action<UIInputHandler>)Delegate.Combine(obj.m_onLeftDown, new Action<UIInputHandler>(Hud.instance.OnLeftClickCategory)); array[i] = val2; } Hud.instance.m_pieceCategoryTabs = array; if (!_loggedHudExpansion && Launch.Log != null) { _loggedHudExpansion = true; Launch.Log.LogInfo((object)("Expanded legacy Hud category tabs from " + num + " to " + count + " for Ravenwood.")); } } int num2 = Math.Min(Hud.instance.m_pieceCategoryTabs.Length, Math.Min(pieceTable.m_categories.Count, pieceTable.m_categoryLabels.Count)); for (int j = 0; j < num2; j++) { GameObject val4 = Hud.instance.m_pieceCategoryTabs[j]; if (!((Object)(object)val4 == (Object)null)) { TMP_Text componentInChildren = val4.GetComponentInChildren<TMP_Text>(); if (!((Object)(object)componentInChildren == (Object)null)) { string text = pieceTable.m_categoryLabels[j]; componentInChildren.text = ((Localization.instance != null) ? Localization.instance.Localize(text) : ((text == "$jotunn_cat_ravenwood") ? "Ravenwood" : text)); } } } } internal static void RequestCategoryUiRefresh() { PieceTable val = null; if ((Object)(object)Player.m_localPlayer != (Object)null) { val = Player.m_localPlayer.m_buildPieces; } if ((Object)(object)val == (Object)null && (Object)(object)ObjectDB.instance != (Object)null) { try { val = PieceManager.Instance.GetPieceTable("Hammer"); } catch { } } if ((Object)(object)val != (Object)null) { SyncLegacyHudTabs(val); } } internal unsafe static bool IsKnownCategory(PieceCategory category) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected I4, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) if (_hasCachedCategory && ((object)(*(PieceCategory*)(&category))/*cast due to .constrained prefix*/).Equals((object?)_cachedCategory)) { return true; } try { PieceCategory? pieceCategory = PieceManager.Instance.GetPieceCategory("Ravenwood"); if (pieceCategory.HasValue && ((object)pieceCategory.Value/*cast due to .constrained prefix*/).Equals((object?)category)) { Cache(pieceCategory.Value); return true; } } catch { } int num = (int)category; return num == 100 || (num >= 0 && num < 9); } internal static string GetProviderDescription() { return _hasCachedCategory ? "Jotunn PieceManager + legacy PieceTable mirror" : "Jotunn category unresolved"; } private static void Cache(PieceCategory category) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected I4, but got Unknown int num; if (_hasCachedCategory) { object obj = category; num = ((!((object)Unsafe.As<PieceCategory, PieceCategory>(ref _cachedCategory)/*cast due to .constrained prefix*/).Equals(obj)) ? 1 : 0); } else { num = 1; } bool flag = (byte)num != 0; _cachedCategory = category; _hasCachedCategory = true; if ((flag || !_loggedCategory) && Launch.Log != null) { _loggedCategory = true; Launch.Log.LogInfo((object)("Ravenwood PieceCategory resolved through Jotunn (id=" + (int)category + ").")); } } } internal static class RavenwoodJotunnRegistrar { private static readonly HashSet<string> RegisteredNames = new HashSet<string>(StringComparer.Ordinal); internal static void RegisterPieces(IList<GameObject> prefabs) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Expected I4, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Expected O, but got Unknown if (prefabs == null) { return; } PieceCategory val = PieceManager.Instance.AddPieceCategory("Ravenwood"); int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; for (int i = 0; i < prefabs.Count; i++) { GameObject val2 = prefabs[i]; if ((Object)(object)val2 == (Object)null || string.IsNullOrEmpty(((Object)val2).name)) { num3++; continue; } Piece component = val2.GetComponent<Piece>(); if ((Object)(object)component == (Object)null) { num3++; if (Launch.Log != null) { Launch.Log.LogWarning((object)("Jotunn registration skipped prefab without Piece: " + ((Object)val2).name)); } continue; } component.m_category = val; component.m_enabled = true; PieceMetadataCompat.Apply(component, ((Object)val2).name); if (!RegisteredNames.Add(((Object)val2).name)) { num2++; continue; } CustomPiece piece = PieceManager.Instance.GetPiece(((Object)val2).name); if (piece != null) { if (piece.PiecePrefab == val2) { piece.PieceTable = PieceTables.Hammer; piece.Category = "Ravenwood"; num2++; continue; } num4++; if (Launch.Log != null) { Launch.Log.LogError((object)("Jotunn already owns a different prefab named '" + ((Object)val2).name + "'. Ravenwood piece was not registered.")); } continue; } try { CustomPiece val3 = new CustomPiece(val2, PieceTables.Hammer, false); val3.Category = "Ravenwood"; val3.Usage = null; if (PieceManager.Instance.AddPiece(val3)) { num++; continue; } num4++; RegisteredNames.Remove(((Object)val2).name); if (Launch.Log != null) { Launch.Log.LogError((object)("Jotunn rejected Ravenwood CustomPiece '" + ((Object)val2).name + "'. Check the preceding Jotunn log for prefab/icon validation details.")); } } catch (Exception ex) { num4++; RegisteredNames.Remove(((Object)val2).name); if (Launch.Log != null) { Launch.Log.LogError((object)("Jotunn CustomPiece registration failed for '" + ((Object)val2).name + "': " + ex)); } } } if (Launch.Log != null) { Launch.Log.LogInfo((object)("Direct Jotunn Ravenwood registration: categoryId=" + (int)val + ", loaded=" + prefabs.Count + ", added=" + num + ", already=" + num2 + ", skipped=" + num3 + ", failed=" + num4 + ".")); } } } internal static class RavenwoodCurrencyCompat { internal const string PluginGuid = "RavenwoodCurrency.rwc"; private static readonly Dictionary<string, int> CoinValues = new Dictionary<string, int>(StringComparer.Ordinal) { { "RWc_Deer", 1 }, { "RWc_Bear", 5 }, { "RWc_Snake", 10 }, { "RWc_Wolf", 25 }, { "RWc_Lion", 100 }, { "RWc_Raven", 1000 } }; internal static bool TryConvertToVanillaCoins(string prefabName, int amount, out int coinAmount, out string error) { coinAmount = 0; error = null; if (string.IsNullOrEmpty(prefabName) || !CoinValues.TryGetValue(prefabName, out var value)) { return false; } long num = (long)amount * (long)value; if (num <= 0 || num > int.MaxValue) { error = "fallback value for '" + prefabName + "' exceeds Int32.MaxValue"; return true; } coinAmount = (int)num; return true; } internal static bool IsKnownCurrencyPrefab(string prefabName) { return !string.IsNullOrEmpty(prefabName) && CoinValues.ContainsKey(prefabName); } internal static int GetCoinValue(string prefabName) { int value; return (!string.IsNullOrEmpty(prefabName) && CoinValues.TryGetValue(prefabName, out value)) ? value : 0; } } internal sealed class PrefabLookupCache { private readonly Dictionary<string, GameObject> _byName = new Dictionary<string, GameObject>(StringComparer.Ordinal); private List<GameObject> _source; public void Rebuild(List<GameObject> source) { _source = source; _byName.Clear(); if (source != null) { for (int i = 0; i < source.Count; i++) { Remember(source[i]); } } } public GameObject Find(string name, List<GameObject> source = null) { if (string.IsNullOrWhiteSpace(name)) { return null; } string normalizedName = name.Trim(); List<GameObject> list = source ?? _source; if (source != null && source != _source) { Rebuild(source); list = source; } if (_byName.TryGetValue(normalizedName, out var value)) { if ((Object)(object)value != (Object)null && ((Object)value).name == normalizedName) { return value; } _byName.Remove(normalizedName); } if (list == null) { return null; } GameObject val = list.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == normalizedName); if ((Object)(object)val != (Object)null) { _byName[normalizedName] = val; } return val; } public void Remember(GameObject prefab) { if (!((Object)(object)prefab == (Object)null) && !string.IsNullOrEmpty(((Object)prefab).name) && !_byName.ContainsKey(((Object)prefab).name)) { _byName.Add(((Object)prefab).name, prefab); } } public void Clear() { _source = null; _byName.Clear(); } } public static class ShaderReplacment { private sealed class MaterialRegistration { public string OriginalDummyShaderName; public MaterialSnapshot OriginalSnapshot; } private sealed class MaterialSnapshot { public string MaterialName; public string ShaderName; public int RenderQueue; public bool HadCustomRenderQueue; public MaterialGlobalIlluminationFlags GlobalIlluminationFlags; public bool DoubleSidedGI; public string[] DiagnosticOriginalKeywords; public readonly Dictionary<string, PropertySnapshot> Properties = new Dictionary<string, PropertySnapshot>(StringComparer.Ordinal); } private sealed class PropertySnapshot { public string Name; public ShaderPropertyType Type; public Texture TextureValue; public Vector2 TextureScale; public Vector2 TextureOffset; public float FloatValue; public Color ColorValue; public Vector4 VectorValue; } private sealed class ShaderEvidence { public Shader Shader; public int MaterialReferenceCount; public int LiveRendererReferenceCount; public bool ReturnedByShaderFind; public bool IsSupported; public int PassCount; public int PropertyCount; public bool HasRuntimeEvidence => MaterialReferenceCount > 0 || LiveRendererReferenceCount > 0; public long Score { get { long num = 0L; num += (long)LiveRendererReferenceCount * 1000000000L; num += (long)MaterialReferenceCount * 1000000L; num += (long)PropertyCount * 100L; num += (long)PassCount * 10L; if (ReturnedByShaderFind) { num++; } return num; } } } private sealed class ShaderEvidenceSnapshot { public readonly Dictionary<string, Dictionary<Shader, ShaderEvidence>> ByName = new Dictionary<string, Dictionary<Shader, ShaderEvidence>>(StringComparer.Ordinal); public ShaderEvidence GetOrCreate(string shaderName, Shader shader) { if ((Object)(object)shader == (Object)null || string.IsNullOrEmpty(shaderName)) { return null; } if (!ByName.TryGetValue(shaderName, out var value)) { value = new Dictionary<Shader, ShaderEvidence>(ShaderReferenceComparer.Instance); ByName.Add(shaderName, value); } if (!value.TryGetValue(shader, out var value2)) { value2 = new ShaderEvidence { Shader = shader, IsSupported = SafeGetIsSupported(shader), PassCount = SafeGetPassCount(shader), PropertyCount = SafeGetPropertyCount(shader) }; value.Add(shader, value2); } return value2; } } private sealed class MaterialReferenceComparer : IEqualityComparer<Material> { public static readonly MaterialReferenceComparer Instance = new MaterialReferenceComparer(); public bool Equals(Material x, Material y) { return x == y; } public int GetHashCode(Material obj) { return (!((Object)(object)obj == (Object)null)) ? RuntimeHelpers.GetHashCode(obj) : 0; } } private sealed class ShaderReferenceComparer : IEqualityComparer<Shader> { public static readonly ShaderReferenceComparer Instance = new ShaderReferenceComparer(); public bool Equals(Shader x, Shader y) { return x == y; } public int GetHashCode(Shader obj) { return (!((Object)(object)obj == (Object)null)) ? RuntimeHelpers.GetHashCode(obj) : 0; } } public static readonly List<GameObject> prefabsToReplaceShader = new List<GameObject>(); public static readonly List<Material> materialsInPrefabs = new List<Material>(); public static readonly List<Shader> shaders = new List<Shader>(); public static bool debug = false; public static bool debugShaderDifferences = false; public static bool debugTargetOnlyProperties = false; public static bool debugShaderCollisions = false; public static int maxDifferenceLogsPerShaderPair = 20; public static float fallbackCutoff = 0.5f; private const float MeaningfulFloatEpsilon = 0.0001f; private static readonly Dictionary<string, Shader> ShaderCache = new Dictionary<string, Shader>(StringComparer.Ordinal); private static readonly Dictionary<string, Shader> TrustedShaderOverrides = new Dictionary<string, Shader>(StringComparer.Ordinal); private static readonly Dictionary<string, List<ShaderEvidence>> LastShaderEvidence = new Dictionary<string, List<ShaderEvidence>>(StringComparer.Ordinal); private static readonly HashSet<Material> RegisteredMaterials = new HashSet<Material>(MaterialReferenceComparer.Instance); private static readonly Dictionary<Material, MaterialRegistration> MaterialRegistrations = new Dictionary<Material, MaterialRegistration>(MaterialReferenceComparer.Instance); private static readonly HashSet<Material> SuccessfullyProcessedMaterials = new HashSet<Material>(MaterialReferenceComparer.Instance); private static readonly HashSet<string> AnalysedShaderPairs = new HashSet<string>(StringComparer.Ordinal); private static ShaderEvidenceSnapshot CurrentEvidenceSnapshot; private static readonly HashSet<string> StrictCutoutShaderNames = new HashSet<string>(StringComparer.Ordinal) { "Custom/Grass", "Custom/Vegetation" }; private static readonly HashSet<string> ProtectedCutoutStateProperties = new HashSet<string>(StringComparer.Ordinal) { "_Mode", "_Surface", "_Blend", "_SrcBlend", "_DstBlend", "_ZWrite", "_AlphaClip", "_AlphaClipThreshold" }; public static void Replace(GameObject gameObject) { if (!IsDedicatedServer() && !((Object)(object)gameObject == (Object)null)) { if (!prefabsToReplaceShader.Contains(gameObject)) { prefabsToReplaceShader.Add(gameObject); } CollectMaterialsFromPrefab(gameObject); } } public static void GetMaterialsInPrefab(GameObject gameObject) { CollectMaterialsFromPrefab(gameObject); } public static void ForceEnableGpuInstancing(GameObject gameObject) { CollectMaterialsFromPrefab(gameObject); } public static void LoadShadersFromBundles() { RefreshShaderCache(); } public static void getMeShaders() { LoadShadersFromBundles(); } public static void RefreshShaderCache() { ShaderCache.Clear(); shaders.Clear(); LastShaderEvidence.Clear(); foreach (KeyValuePair<string, Shader> trustedShaderOverride in TrustedShaderOverrides) { if (!((Object)(object)trustedShaderOverride.Value == (Object)null)) { ShaderCache[trustedShaderOverride.Key] = trustedShaderOverride.Value; AddPublicShaderReference(trustedShaderOverride.Value); } } HashSet<string> hashSet = CollectRegisteredTargetShaderNames(); CurrentEvidenceSnapshot = BuildEvidenceSnapshot(hashSet); foreach (string item in hashSet) { if (!TrustedShaderOverrides.ContainsKey(item)) { Shader val = ResolveShaderByEvidence(item, CurrentEvidenceSnapshot, forceDiagnosticLog: false); if (!((Object)(object)val == (Object)null)) { ShaderCache[item] = val; AddPublicShaderReference(val); } } } if (debug) { Debug.Log((object)("[BalrondShaderReplacement] Shader cache rebuilt. targets=" + hashSet.Count + ", resolved=" + ShaderCache.Count + ", trustedOverrides=" + TrustedShaderOverrides.Count)); } } public static void RegisterTrustedShader(Shader shader) { if (!((Object)(object)shader == (Object)null) && !string.IsNullOrWhiteSpace(((Object)shader).name)) { RegisterTrustedShader(((Object)shader).name, shader); } } public static void RegisterTrustedShader(string shaderName, Shader shader) { if (!((Object)(object)shader == (Object)null) && !string.IsNullOrWhiteSpace(shaderName)) { string text = shaderName.Trim(); TrustedShaderOverrides[text] = shader; ShaderCache[text] = shader; AddPublicShaderReference(shader); if (debug) { Debug.Log((object)("[BalrondShaderReplacement] Explicit trusted shader '" + text + "', instanceID=" + SafeGetInstanceId((Object)(object)shader) + ", passes=" + SafeGetPassCount(shader) + ", properties=" + SafeGetPropertyCount(shader))); } } } public static void RemoveTrustedShader(string shaderName) { if (!string.IsNullOrWhiteSpace(shaderName)) { string key = shaderName.Trim(); TrustedShaderOverrides.Remove(key); ShaderCache.Remove(key); } } public static Shader GetShaderByName(string name) { if (string.IsNullOrWhiteSpace(name)) { return null; } string text = name.Trim(); if (TrustedShaderOverrides.TryGetValue(text, out var value) && (Object)(object)value != (Object)null) { return value; } if (ShaderCache.TryGetValue(text, out var value2) && (Object)(object)value2 != (Object)null) { return value2; } HashSet<string> targetNames = new HashSet<string>(StringComparer.Ordinal) { text }; ShaderEvidenceSnapshot snapshot = BuildEvidenceSnapshot(targetNames); Shader val = ResolveShaderByEvidence(text, snapshot, forceDiagnosticLog: false); if ((Object)(object)val != (Object)null) { ShaderCache[text] = val; AddPublicShaderReference(val); } return val; } public static Shader findShader(string name) { return GetShaderByName(name); } public static void RunMaterialFix() { if (IsDedicatedServer()) { return; } RefreshShaderCache(); int count = materialsInPrefabs.Count; int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; for (int i = 0; i < count; i++) { Material val = materialsInPrefabs[i]; if ((Object)(object)val == (Object)null) { num5++; continue; } val.enableInstancing = true; Shader targetShader; string selectedTargetName; bool cutoutRepaired; if (!TryGetOrCreateMaterialRegistration(val, out var registration)) { num4++; } else if (!TryResolveTargetShader(registration.OriginalDummyShaderName, out targetShader, out selectedTargetName)) { SuccessfullyProcessedMaterials.Remove(val); num3++; } else if (val.shader == targetShader) { if (RepairStrictCutoutState(val, registration.OriginalSnapshot, targetShader)) { num6++; } val.enableInstancing = true; SuccessfullyProcessedMaterials.Add(val); num2++; } else if (TryApplyTargetShader(val, registration, targetShader, selectedTargetName, out cutoutRepaired)) { if (cutoutRepaired) { num6++; } SuccessfullyProcessedMaterials.Add(val); num++; } else { SuccessfullyProcessedMaterials.Remove(val); num3++; } } if (debug) { Debug.Log((object)("[BalrondShaderReplacement] Material fix finished. registered=" + count + ", replaced=" + num + ", alreadyExact=" + num2 + ", cutoutRepairs=" + num6 + ", missingShader=" + num3 + ", unmanaged=" + num4 + ", invalid=" + num5)); } } public static void runMaterialFix() { RunMaterialFix(); } public static void ForceRefreshAndRunMaterialFix() { SuccessfullyProcessedMaterials.Clear(); AnalysedShaderPairs.Clear(); ShaderCache.Clear(); CurrentEvidenceSnapshot = null; RunMaterialFix(); } public static void RepairAllRegisteredMaterials() { ForceRefreshAndRunMaterialFix(); } public static void ClearRegisteredMaterials() { prefabsToReplaceShader.Clear(); materialsInPrefabs.Clear(); RegisteredMaterials.Clear(); MaterialRegistrations.Clear(); SuccessfullyProcessedMaterials.Clear(); ShaderCache.Clear(); LastShaderEvidence.Clear(); AnalysedShaderPairs.Clear(); CurrentEvidenceSnapshot = null; } public static void ResetProcessedMaterials() { SuccessfullyProcessedMaterials.Clear(); AnalysedShaderPairs.Clear(); } public static void DiagnoseRegisteredShaderCollisions() { HashSet<string> hashSet = CollectRegisteredTargetShaderNames(); ShaderEvidenceSnapshot snapshot = BuildEvidenceSnapshot(hashSet); foreach (string item in hashSet) { ResolveShaderByEvidence(item, snapshot, forceDiagnosticLog: true); } } private static void CollectMaterialsFromPrefab(GameObject gameObject) { if ((Object)(object)gameObject == (Object)null) { return; } Renderer[] componentsInChildren = gameObject.GetComponentsInChildren<Renderer>(true); if (componentsInChildren != null) { foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } Material[] sharedMaterials = val.sharedMaterials; if (sharedMaterials != null) { for (int j = 0; j < sharedMaterials.Length; j++) { RegisterMaterial(sharedMaterials[j]); } } } } InstanceRenderer[] componentsInChildren2 = gameObject.GetComponentsInChildren<InstanceRenderer>(true); if (componentsInChildren2 == null) { return; } foreach (InstanceRenderer val2 in componentsInChildren2) { if (!((Object)(object)val2 == (Object)null)) { RegisterMaterial(val2.m_material); } } } private static void RegisterMaterial(Material material) { if (!((Object)(object)material == (Object)null)) { material.enableInstancing = true; if (RegisteredMaterials.Add(material)) { materialsInPrefabs.Add(material); } TryGetOrCreateMaterialRegistration(material, out var _); } } private static bool TryGetOrCreateMaterialRegistration(Material material, out MaterialRegistration registration) { registration = null; if ((Object)(object)material == (Object)null) { return false; } if (MaterialRegistrations.TryGetValue(material, out registration) && registration != null && !string.IsNullOrEmpty(registration.OriginalDummyShaderName)) { return true; } Shader shader = material.shader; if ((Object)(object)shader == (Object)null || !IsDummyShader(((Object)shader).name)) { return false; } registration = new MaterialRegistration { OriginalDummyShaderName = ((Object)shader).name, OriginalSnapshot = CaptureMaterial(material) }; MaterialRegistrations[material] = registration; if (debug) { float snapshotFloat = GetSnapshotFloat(registration.OriginalSnapshot, "_Cutoff", float.NaN); Debug.Log((object)("[BalrondShaderReplacement] Registered material '" + ((Object)material).name + "', dummy='" + ((Object)shader).name + "', properties=" + registration.OriginalSnapshot.Properties.Count + ", cutoff=" + (float.IsNaN(snapshotFloat) ? "<missing>" : snapshotFloat.ToString("0.####")) + ", queue=" + registration.OriginalSnapshot.RenderQueue)); } return true; } private static bool IsDummyShader(string shaderName) { return !string.IsNullOrEmpty(shaderName) && shaderName.StartsWith("Balrond/", StringComparison.Ordinal); } private static List<string> GetTargetShaderCandidates(string oldShaderName) { List<string> list = new List<string>(); if (string.IsNullOrEmpty(oldShaderName)) { return list; } string text = oldShaderName; if (text.StartsWith("Balrond/", StringComparison.Ordinal)) { text = text.Substring("Balrond/".Length); } string text2 = RemovePrefix(text, "Particles/"); if (ContainsOrdinalIgnoreCase(text, "Tess Bumped")) { AddCandidate(list, "Lux Lit Particles/ Tess Bumped"); AddCandidate(list, "Lux Lit Particles/Tess Bumped"); AddCandidate(list, "Lux Lit Particles/" + text2); } if (ContainsOrdinalIgnoreCase(text, "Bumped")) { AddCandidate(list, "Lux Lit Particles/ Bumped"); AddCandidate(list, "Lux Lit Particles/Bumped"); AddCandidate(list, "Lux Lit Particles/" + text2); } if (ContainsOrdinalIgnoreCase(text, "Standard Surface")) { AddCandidate(list, "Particles/Standard Surface"); AddCandidate(list, "Particles/Standard Surface2"); string text3 = text2; if (ContainsOrdinalIgnoreCase(text3, "Standard Surface2")) { text3 = ReplaceOrdinalIgnoreCase(text3, "Standard Surface2", "Standard Surface"); } AddCandidate(list, "Particles/" + text3); } if (ContainsOrdinalIgnoreCase(text, "Standard Unlit")) { AddCandidate(list, "Particles/Standard Unlit2"); AddCandidate(list, "Particles/Standard Unlit"); string text4 = text2; if (!ContainsOrdinalIgnoreCase(text4, "Standard Unlit2")) { text4 = ReplaceOrdinalIgnoreCase(text4, "Standard Unlit", "Standard Unlit2"); } AddCandidate(list, "Particles/" + text4); } AddCandidate(list, "Custom/" + text); return list; } private static void AddCandidate(List<string> candidates, string shaderName) { if (!string.IsNullOrWhiteSpace(shaderName)) { string item = shaderName.Trim(); if (!candidates.Contains(item)) { candidates.Add(item); } } } private static bool TryResolveTargetShader(string oldShaderName, out Shader targetShader, out string selectedTargetName) { targetShader = null; selectedTargetName = null; List<string> targetShaderCandidates = GetTargetShaderCandidates(oldShaderName); for (int i = 0; i < targetShaderCandidates.Count; i++) { string text = targetShaderCandidates[i]; Shader shaderByName = GetShaderByName(text); if (IsUsableTargetShader(shaderByName, text)) { targetShader = shaderByName; selectedTargetName = text; return true; } } if (debug) { Debug.LogWarning((object)("[BalrondShaderReplacement] No target shader for dummy '" + oldShaderName + "'. Checked: " + string.Join(", ", targetShaderCandidates))); } return false; } private static bool IsUsableTargetShader(Shader shader, string expectedName) { if ((Object)(object)shader == (Object)null) { return false; } if (!string.Equals(((Object)shader).name, expectedName, StringComparison.Ordinal)) { return false; } if (!SafeGetIsSupported(shader)) { if (debug) { Debug.LogWarning((object)("[BalrondShaderReplacement] Rejected unsupported shader '" + expectedName + "', instanceID=" + SafeGetInstanceId((Object)(object)shader))); } return false; } if (SafeGetPassCount(shader) <= 0) { if (debug) { Debug.LogWarning((object)("[BalrondShaderReplacement] Rejected zero-pass shader '" + expectedName + "', instanceID=" + SafeGetInstanceId((Object)(object)shader))); } return false; } return true; } private static HashSet<string> CollectRegisteredTargetShaderNames() { HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); foreach (KeyValuePair<Material, MaterialRegistration> materialRegistration in MaterialRegistrations) { MaterialRegistration value = materialRegistration.Value; if (value != null && !string.IsNullOrEmpty(value.OriginalDummyShaderName)) { List<string> targetShaderCandidates = GetTargetShaderCandidates(value.OriginalDummyShaderName); for (int i = 0; i < targetShaderCandidates.Count; i++) { hashSet.Add(targetShaderCandidates[i]); } } } return hashSet; } private static ShaderEvidenceSnapshot BuildEvidenceSnapshot(HashSet<string> targetNames) { //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) ShaderEvidenceSnapshot shaderEvidenceSnapshot = new ShaderEvidenceSnapshot(); if (targetNames == null || targetNames.Count == 0) { return shaderEvidenceSnapshot; } Material[] array = Resources.FindObjectsOfTypeAll<Material>(); if (array != null) { foreach (Material val in array) { if ((Object)(object)val == (Object)null || RegisteredMaterials.Contains(val) || (Object)(object)val.shader == (Object)null) { continue; } Shader shader = val.shader; string name = ((Object)shader).name; if (!string.IsNullOrEmpty(name) && targetNames.Contains(name)) { ShaderEvidence orCreate = shaderEvidenceSnapshot.GetOrCreate(name, shader); if (orCreate != null) { orCreate.MaterialReferenceCount++; } } } } Renderer[] array2 = Resources.FindObjectsOfTypeAll<Renderer>(); if (array2 != null) { foreach (Renderer val2 in array2) { if ((Object)(object)val2 == (Object)null || (Object)(object)((Component)val2).gameObject == (Object)null) { continue; } Scene scene = ((Component)val2).gameObject.scene; if (!((Scene)(ref scene)).IsValid()) { continue; } scene = ((Component)val2).gameObject.scene; if (!((Scene)(ref scene)).isLoaded) { continue; } Material[] sharedMaterials = val2.sharedMaterials; if (sharedMaterials == null) { continue; } foreach (Material val3 in sharedMaterials) { if ((Object)(object)val3 == (Object)null || RegisteredMaterials.Contains(val3) || (Object)(object)val3.shader == (Object)null) { continue; } Shader shader2 = val3.shader; string name2 = ((Object)shader2).name; if (!string.IsNullOrEmpty(name2) && targetNames.Contains(name2)) { ShaderEvidence orCreate2 = shaderEvidenceSnapshot.GetOrCreate(name2, shader2); if (orCreate2 != null) { orCreate2.LiveRendererReferenceCount++; } } } } } Shader[] array3 = Resources.FindObjectsOfTypeAll<Shader>(); if (array3 != null) { foreach (Shader val4 in array3) { if (!((Object)(object)val4 == (Object)null) && !string.IsNullOrEmpty(((Object)val4).name) && targetNames.Contains(((Object)val4).name)) { shaderEvidenceSnapshot.GetOrCreate(((Object)val4).name, val4); } } } foreach (string targetName in targetNames) { Shader val5 = null; try { val5 = Shader.Find(targetName); } catch (Exception ex) { if (debug) { Debug.LogWarning((object)("[BalrondShaderReplacement] Shader.Find failed for '" + targetName + "': " + ex.Message)); } } if (!((Object)(object)val5 == (Object)null) && string.Equals(((Object)val5).name, targetName, StringComparison.Ordinal)) { ShaderEvidence orCreate3 = shaderEvidenceSnapshot.GetOrCreate(targetName, val5); if (orCreate3 != null) { orCreate3.ReturnedByShaderFind = true; } } } return shaderEvidenceSnapshot; } private static Shader ResolveShaderByEvidence(string shaderName, ShaderEvidenceSnapshot snapshot, bool forceDiagnosticLog) { if (string.IsNullOrWhiteSpace(shaderName)) { return null; } string text = shaderName.Trim(); if (TrustedShaderOverrides.TryGetValue(text, out var value) && (Object)(object)value != (Object)null) { return value; } if (snapshot == null || !snapshot.ByName.TryGetValue(text, out var value2)) { if (debug) { Debug.LogWarning((object)("[BalrondShaderReplacement] No loaded shader candidates for '" + text + "'.")); } return null; } bool flag = false; foreach (ShaderEvidence value3 in value2.Values) { if (value3 == null || (Object)(object)value3.Shader == (Object)null || !value3.IsSupported || value3.PassCount <= 0 || !value3.HasRuntimeEvidence) { continue; } flag = true; break; } ShaderEvidence shaderEvidence = null; foreach (ShaderEvidence value4 in value2.Values) { if (value4 != null && !((Object)(object)value4.Shader == (Object)null) && value4.IsSupported && value4.PassCount > 0 && (!flag || value4.HasRuntimeEvidence) && (shaderEvidence == null || value4.Score > shaderEvidence.Score)) { shaderEvidence = value4; } } List<ShaderEvidence> list = new List<ShaderEvidence>(value2.Values); list.Sort(delegate(ShaderEvidence left, ShaderEvidence right) { if (left == right) { return 0; } return (left == null) ? 1 : (right?.Score.CompareTo(left.Score) ?? (-1)); }); LastShaderEvidence[text] = list; bool flag2 = list.Count > 1; if (forceDiagnosticLog || (debugShaderCollisions && flag2)) { Debug.LogWarning((object)("[BalrondShaderReplacement] Shader candidates for '" + text + "': count=" + list.Count + ", runtimeEvidenceMode=" + flag + ", selected=" + ((shaderEvidence != null) ? SafeGetInstanceId((Object)(object)shaderEvidence.Shader).ToString() : "<none>"))); for (int num = 0; num < list.Count; num++) { ShaderEvidence shaderEvidence2 = list[num]; if (shaderEvidence2 != null) { bool flag3 = shaderEvidence != null && shaderEvidence2.Shader == shaderEvidence.Shader; Debug.LogWarning((object)("[BalrondShaderReplacement] " + (flag3 ? "[SELECTED] " : string.Empty) + "instanceID=" + SafeGetInstanceId((Object)(object)shaderEvidence2.Shader) + ", supported=" + shaderEvidence2.IsSupported + ", passes=" + shaderEvidence2.PassCount + ", properties=" + shaderEvidence2.PropertyCount + ", externalMaterialRefs=" + shaderEvidence2.MaterialReferenceCount + ", externalLiveRendererRefs=" + shaderEvidence2.LiveRendererReferenceCount + ", Shader.Find=" + shaderEvidence2.ReturnedByShaderFind + ", score=" + shaderEvidence2.Score)); } } } return shaderEvidence?.Shader; } private static bool TryApplyTargetShader(Material material, MaterialRegistration registration, Shader targetShader, string selectedTargetName, out bool cutoutRepaired) { //IL_00ee: Unknown result type (might be due to invalid IL or missing references) cutoutRepaired = false; if ((Object)(object)material == (Object)null || registration == null || (Object)(object)targetShader == (Object)null) { return false; } Shader shader = material.shader; string text = (((Object)(object)shader != (Object)null) ? ((Object)shader).name : "<null>"); MaterialSnapshot materialSnapshot = registration.OriginalSnapshot ?? CaptureMaterial(material); if (debugShaderDifferences) { AnalyseShaderDifferences(material, materialSnapshot, targetShader, registration.OriginalDummyShaderName, selectedTargetName); } string text2 = (debug ? FormatKeywords(material.shaderKeywords) : string.Empty); try { material.shader = targetShader; bool flag = IsStrictCutoutTarget(targetShader); int num = RestoreCompatibleProperties(material, materialSnapshot, flag); if (flag) { material.renderQueue = -1; } else if (materialSnapshot != null && materialSnapshot.HadCustomRenderQueue) { material.renderQueue = materialSnapshot.RenderQueue; } if (materialSnapshot != null) { material.globalIlluminationFlags = materialSnapshot.GlobalIlluminationFlags; material.doubleSidedGI = materialSnapshot.DoubleSidedGI; } material.enableInstancing = true; cutoutRepaired = RepairStrictCutoutState(material, materialSnapshot, targetShader); if (debug) { float f = (material.HasProperty("_Cutoff") ? material.GetFloat("_Cutoff") : float.NaN); string text3 = FormatKeywords(material.shaderKeywords); Debug.Log((object)("[BalrondShaderReplacement] Repaired material '" + ((Object)material).name + "': '" + text + "' [" + SafeGetInstanceId((Object)(object)shader) + "] -> '" + ((Object)targetShader).name + "' [" + SafeGetInstanceId((Object)(object)targetShader) + "], restoredProperties=" + num + ", queue=" + material.renderQueue + ", cutoff=" + (float.IsNaN(f) ? "<none>" : f.ToString("0.####")) + ", cutoffSafety=" + cutoutRepaired + ", keywordsBefore='" + text2 + "', keywordsAfter='" + text3 + "'")); } return true; } catch (Exception ex) { Debug.LogError((object)("[BalrondShaderReplacement] Failed replacing shader on material '" + ((Object)material).name + "'. dummy='" + registration.OriginalDummyShaderName + "', current='" + text + "', target='" + ((Object)targetShader).name + "'. " + ex)); return false; } } private static bool IsStrictCutoutTarget(Shader shader) { return (Object)(object)shader != (Object)null && StrictCutoutShaderNames.Contains(((Object)shader).name); } private static bool RepairStrictCutoutState(Material material, MaterialSnapshot originalSnapshot, Shader targetShader) { if ((Object)(object)material == (Object)null || (Object)(object)targetShader == (Object)null || !IsStrictCutoutTarget(targetShader)) { return false; } bool result = false; if (material.HasProperty("_Cutoff")) { float num = material.GetFloat("_Cutoff"); float snapshotFloat = GetSnapshotFloat(originalSnapshot, "_Cutoff", float.NaN); float num2 = ((float.IsNaN(snapshotFloat) || !(snapshotFloat > 0.0001f)) ? Mathf.Clamp01(fallbackCutoff) : Mathf.Clamp01(snapshotFloat)); if (num2 > 0.0001f && Mathf.Abs(num - num2) > 0.0001f) { material.SetFloat("_Cutoff", num2); result = true; } } if (material.renderQueue != -1) { material.renderQueue = -1; result = true; } return result; } private static MaterialSnapshot CaptureMaterial(Material material) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Expected I4, but got Unknown //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) MaterialSnapshot materialSnapshot = new MaterialSnapshot(); if ((Object)(object)material == (Object)null) { return materialSnapshot; } Shader shader = material.shader; materialSnapshot.MaterialName = ((Object)material).name; materialSnapshot.ShaderName = (((Object)(object)shader != (Object)null) ? ((Object)shader).name : string.Empty); materialSnapshot.RenderQueue = material.renderQueue; materialSnapshot.HadCustomRenderQueue = (Object)(object)shader != (Object)null && material.renderQueue != shader.renderQueue; materialSnapshot.GlobalIlluminationFlags = material.globalIlluminationFlags; materialSnapshot.DoubleSidedGI = material.doubleSidedGI; try { string[] shaderKeywords = material.shaderKeywords; materialSnapshot.DiagnosticOriginalKeywords = ((shaderKeywords != null) ? ((string[])shaderKeywords.Clone()) : new string[0]); } catch { materialSnapshot.DiagnosticOriginalKeywords = new string[0]; } if ((Object)(object)shader == (Object)null) { return materialSnapshot; } int num = SafeGetPropertyCount(shader); for (int i = 0; i < num; i++) { string propertyName; ShaderPropertyType propertyType; try { propertyName = shader.GetPropertyName(i); propertyType = shader.GetPropertyType(i); } catch (Exception ex) { if (debug) { Debug.LogWarning((object)("[BalrondShaderReplacement] Could not read shader property metadata from '" + ((Object)shader).name + "': " + ex.Message)); } continue; } if (string.IsNullOrEmpty(propertyName) || !material.HasProperty(propertyName)) { continue; } PropertySnapshot propertySnapshot = new PropertySnapshot { Name = propertyName, Type = propertyType }; try { ShaderPropertyType val = propertyType; ShaderPropertyType val2 = val; switch ((int)val2) { default: goto end_IL_0179; case 4: propertySnapshot.TextureValue = material.GetTexture(propertyName); propertySnapshot.TextureScale = material.GetTextureScale(propertyName); propertySnapshot.TextureOffset = material.GetTextureOffset(propertyName); break; case 0: propertySnapshot.ColorValue = material.GetColor(propertyName); break; case 1: propertySnapshot.VectorValue = material.GetVector(propertyName); break; case 2: case 3: propertySnapshot.FloatValue = material.GetFloat(propertyName); break; } materialSnapshot.Properties[propertyName] = propertySnapshot; end_IL_0179:; } catch (Exception ex2) { if (debug) { Debug.LogWarning((object)("[BalrondShaderReplacement] Could not capture property '" + propertyName + "' from material '" + ((Object)material).name + "': " + ex2.Message)); } } } return materialSnapshot; } private static int RestoreCompatibleProperties(Material material, MaterialSnapshot snapshot, bool protectCutoutRenderState) { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Expected I4, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material == (Object)null || (Object)(object)material.shader == (Object)null || snapshot == null) { return 0; } Dictionary<string, ShaderPropertyType> shaderPropertyTypes = GetShaderPropertyTypes(material.shader); int num = 0; foreach (KeyValuePair<string, PropertySnapshot> property in snapshot.Properties) { string key = property.Key; PropertySnapshot value = property.Value; if ((protectCutoutRenderState && ProtectedCutoutStateProperties.Contains(key)) || !shaderPropertyTypes.TryGetValue(key, out var value2) || !ArePropertyTypesCompatible(value.Type, value2) || !material.HasProperty(key)) { continue; } try { ShaderPropertyType val = value2; ShaderPropertyType val2 = val; switch ((int)val2) { default: goto end_IL_00ca; case 4: material.SetTexture(key, value.TextureValue); material.SetTextureScale(key, value.TextureScale); material.SetTextureOffset(key, value.TextureOffset); break; case 0: material.SetColor(key, value.ColorValue); break; case 1: material.SetVector(key, value.VectorValue); break; case 2: case 3: material.SetFloat(key, value.FloatValue); break; } num++; end_IL_00ca:; } catch (Exception ex) { if (debug) { Debug.LogWarning((object)("[BalrondShaderReplacement] Could not restore property '" + key + "' on material '" + ((Object)material).name + "': " + ex.Message)); } } } return num; } private static Dictionary<string, ShaderPropertyType> GetShaderPropertyTypes(Shader shader) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, ShaderPropertyType> dictionary = new Dictionary<string, ShaderPropertyType>(StringComparer.Ordinal); if ((Object)(object)shader == (Object)null) { return dictionary; } int num = SafeGetPropertyCount(shader); for (int i = 0; i < num; i++) { try { string propertyName = shader.GetPropertyName(i); ShaderPropertyType propertyType = shader.GetPropertyType(i); if (!string.IsNullOrEmpty(propertyName)) { dictionary[propertyName] = propertyType; } } catch { } } return dictionary; } private static bool ArePropertyTypesCompatible(ShaderPropertyType sourceType, ShaderPropertyType targetType) { //IL_0001: 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_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 if (sourceType == targetType) { return true; } bool flag = (int)sourceType == 2 || (int)sourceType == 3; bool flag2 = (int)targetType == 2 || (int)targetType == 3; return flag && flag2; } private static float GetSnapshotFloat(MaterialSnapshot snapshot, string propertyName, float fallback) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Invalid comparison between Unknown and I4 //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Invalid comparison between Unknown and I4 if (snapshot == null || string.IsNullOrEmpty(propertyName) || !snapshot.Properties.TryGetValue(propertyName, out var value)) { return fallback; } if ((int)value.Type != 2 && (int)value.Type != 3) { return fallback; } return value.FloatValue; } private unsafe static void AnalyseShaderDifferences(Material material, MaterialSnapshot sourceSnapshot, Shader targetShader, string oldShaderName, string targetShaderName) { //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) if (sourceSnapshot == null || (Object)(object)targetShader == (Object)null) { return; } string text = oldShaderName + " -> " + targetShaderName; if (!Analyse