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 balrond constructions v1.4.5
plugins/BalrondConstructions.dll
Decompiled 5 days 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.Collections.Specialized; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using Balrond.Shared; using BepInEx; using BepInEx.Logging; using HarmonyLib; using LitJson2; 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("BalrondConstructions")] [assembly: AssemblyDescription("Balrond construction pieces for Valheim")] [assembly: AssemblyCompany("Balrond")] [assembly: AssemblyProduct("BalrondConstructions")] [assembly: ComVisible(false)] [assembly: AssemblyFileVersion("1.5.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.5.1.0")] [module: UnverifiableCode] public class BalrondDrawBridge : MonoBehaviour, Hoverable, Interactable { public enum DrawBridgeMode { Single, Double } public enum DrawBridgeState { Closed, Opening, Open, Closing } private const string RpcToggle = "RPC_BalrondDrawBridge_Toggle"; private const string ZdoState = "balrond_drawbridge_state"; private const string ZdoAnimStartTime = "balrond_drawbridge_anim_start_time"; private ZNetView _nview; [Header("Mode")] public DrawBridgeMode m_mode = DrawBridgeMode.Double; [Header("Interaction")] public string m_name = "Drawbridge"; public float m_hoverOffset = 0f; public bool m_requireWardAccess = true; public bool m_blockInteractionWhileMoving = true; [Header("Animation")] public float m_animationSeconds = 3f; public float m_openAngle = 70f; [Header("Bridge Leaves")] public Transform m_leftPivot; public Transform m_rightPivot; [Header("Leaf Rotation Axis")] public Vector3 m_leftLeafAxis = Vector3.right; public Vector3 m_rightLeafAxis = Vector3.right; [Header("Gears")] public Transform m_leftStaticGear; public Transform m_leftBridgeGear; public Transform m_rightStaticGear; public Transform m_rightBridgeGear; public Vector3 m_gearAxis = Vector3.forward; public float m_gearDegreesPerBridgeDegree = 4f; [Header("Animation Audio Object")] public GameObject m_animationActiveObject; [Header("Effects")] public EffectList m_openStartEffects = new EffectList(); public EffectList m_closeStartEffects = new EffectList(); [Header("Debug")] public bool m_debugLogs = false; private void Awake() { _nview = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)_nview != (Object)null) { _nview.Register("RPC_BalrondDrawBridge_Toggle", (Action<long>)RPC_Toggle); } UpdateAnimationAndState(); } private void Update() { UpdateAnimationAndState(); } public string GetHoverText() { if (!IsValid()) { return string.Empty; } DrawBridgeState state = GetState(); string text = (IsOpenOrOpening(state) ? "Close" : "Open"); string name = m_name; name = name + "\n[<color=yellow><b>$KEY_Use</b></color>] " + text; if (IsAnimating(state)) { name += "\n<color=orange>Moving</color>"; } return (Localization.instance != null) ? Localization.instance.Localize(name) : name; } public string GetHoverName() { return m_name; } public float GetHoverOffset() { return m_hoverOffset; } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (hold) { return false; } if (!IsValid()) { return false; } if (m_requireWardAccess && !PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return true; } DrawBridgeState state = GetState(); if (m_blockInteractionWhileMoving && IsAnimating(state)) { Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val != (Object)null) { ((Character)val).Message((MessageType)2, "Bridge is moving", 0, (Sprite)null, false); } return true; } _nview.InvokeRPC("RPC_BalrondDrawBridge_Toggle", Array.Empty<object>()); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } private void RPC_Toggle(long sender) { if (!IsValid()) { return; } DrawBridgeState state = GetState(); if (m_blockInteractionWhileMoving && IsAnimating(state)) { Log("Toggle rejected: bridge is moving"); return; } ClaimOwnershipIfNeeded(); if (state == DrawBridgeState.Closed || state == DrawBridgeState.Closing) { SetStateOwned(DrawBridgeState.Opening); CreateEffects(m_openStartEffects); Log("Opening"); } else if (state == DrawBridgeState.Open || state == DrawBridgeState.Opening) { SetStateOwned(DrawBridgeState.Closing); CreateEffects(m_closeStartEffects); Log("Closing"); } } private void UpdateAnimationAndState() { if (!IsValid()) { UpdateAnimationActiveObject(active: false); return; } DrawBridgeState state = GetState(); float num = Mathf.Max(0.01f, SanitizeFloat(m_animationSeconds, 3f)); float animStartTime = GetAnimStartTime(); float networkTimeSecondsFloat = GetNetworkTimeSecondsFloat(); float num2 = Mathf.Clamp01((networkTimeSecondsFloat - animStartTime) / num); float progress = 0f; switch (state) { case DrawBridgeState.Closed: progress = 0f; break; case DrawBridgeState.Open: progress = 1f; break; case DrawBridgeState.Opening: progress = num2; if (num2 >= 1f && IsOwner()) { SetStateNoRestartOwned(DrawBridgeState.Open); } break; case DrawBridgeState.Closing: progress = 1f - num2; if (num2 >= 1f && IsOwner()) { SetStateNoRestartOwned(DrawBridgeState.Closed); } break; } UpdateAnimationActiveObject(IsAnimating(state)); ApplyVisual(progress); } private void ApplyVisual(float progress) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp01(progress); float num2 = num * SanitizeFloat(m_openAngle, 70f); if ((Object)(object)m_leftPivot != (Object)null) { Vector3 safeAxis = GetSafeAxis(m_leftLeafAxis, Vector3.right); m_leftPivot.localRotation = Quaternion.AngleAxis(0f - num2, safeAxis); } if (m_mode == DrawBridgeMode.Double && (Object)(object)m_rightPivot != (Object)null) { Vector3 safeAxis2 = GetSafeAxis(m_rightLeafAxis, Vector3.right); m_rightPivot.localRotation = Quaternion.AngleAxis(num2, safeAxis2); } float num3 = num2 * SanitizeFloat(m_gearDegreesPerBridgeDegree, 4f); ApplyGear(m_leftStaticGear, num3); ApplyGear(m_leftBridgeGear, 0f - num3); if (m_mode == DrawBridgeMode.Double) { ApplyGear(m_rightStaticGear, 0f - num3); ApplyGear(m_rightBridgeGear, num3); } } private void ApplyGear(Transform gear, float angle) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)gear == (Object)null)) { Vector3 safeAxis = GetSafeAxis(m_gearAxis, Vector3.forward); gear.localRotation = Quaternion.AngleAxis(angle, safeAxis); } } private void UpdateAnimationActiveObject(bool active) { if (!((Object)(object)m_animationActiveObject == (Object)null) && m_animationActiveObject.activeSelf != active) { m_animationActiveObject.SetActive(active); } } private void CreateEffects(EffectList effects) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (effects != null && effects.m_effectPrefabs != null && effects.m_effectPrefabs.Length != 0) { effects.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1, default(ZDOID)); } } private void SetStateOwned(DrawBridgeState state) { ZDO zdo = GetZdo(); if (zdo != null) { ClaimOwnershipIfNeeded(); zdo.Set("balrond_drawbridge_state", (int)state); zdo.Set("balrond_drawbridge_anim_start_time", GetNetworkTimeSecondsFloat()); } } private void SetStateNoRestartOwned(DrawBridgeState state) { ZDO zdo = GetZdo(); if (zdo != null) { ClaimOwnershipIfNeeded(); zdo.Set("balrond_drawbridge_state", (int)state); } } public DrawBridgeState GetState() { ZDO zdo = GetZdo(); if (zdo == null) { return DrawBridgeState.Closed; } return zdo.GetInt("balrond_drawbridge_state", 0) switch { 1 => DrawBridgeState.Opening, 2 => DrawBridgeState.Open, 3 => DrawBridgeState.Closing, _ => DrawBridgeState.Closed, }; } private float GetAnimStartTime() { ZDO zdo = GetZdo(); if (zdo == null) { return GetNetworkTimeSecondsFloat(); } return zdo.GetFloat("balrond_drawbridge_anim_start_time", GetNetworkTimeSecondsFloat()); } private bool IsOpenOrOpening(DrawBridgeState state) { return state == DrawBridgeState.Open || state == DrawBridgeState.Opening; } private bool IsAnimating(DrawBridgeState state) { return state == DrawBridgeState.Opening || state == DrawBridgeState.Closing; } private bool IsValid() { return (Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.GetZDO() != null; } private ZDO GetZdo() { if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { return null; } return _nview.GetZDO(); } private bool IsOwner() { return (Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.IsOwner(); } private void ClaimOwnershipIfNeeded() { if ((Object)(object)_nview != (Object)null && _nview.IsValid() && !_nview.IsOwner()) { _nview.ClaimOwnership(); } } private static Vector3 GetSafeAxis(Vector3 axis, Vector3 fallback) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (((Vector3)(ref axis)).sqrMagnitude <= 0.0001f) { return ((Vector3)(ref fallback)).normalized; } return ((Vector3)(ref axis)).normalized; } private static float SanitizeFloat(float value, float fallback) { if (float.IsNaN(value) || float.IsInfinity(value)) { return fallback; } return value; } private static float GetNetworkTimeSecondsFloat() { if ((Object)(object)ZNet.instance != (Object)null) { return (float)ZNet.instance.GetTimeSeconds(); } return Time.time; } private void Log(string msg) { if (m_debugLogs) { Debug.Log((object)("[BalrondDrawBridge][" + ((Object)((Component)this).gameObject).name + "] " + msg)); } } } namespace BalrondConstructions { public class BalrondTranslator { public static Dictionary<string, Dictionary<string, string>> translations = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); public static Dictionary<string, string> getLanguage(string language) { if (string.IsNullOrWhiteSpace(language)) { return null; } Dictionary<string, string> value; return translations.TryGetValue(language, out value) ? value : null; } } internal class BuildPieceList { public static string[] buildPieces = new string[345] { "ashwood_decowall_divider_bal", "ashwood_roof26_bal", "ashwood_roof45_bal", "ashwood_roof_icorner_45_bal", "ashwood_roof_icorner_left45_bal", "ashwood_roof_icorner_right45_bal", "ashwood_roof_ocorner_45_bal", "ashwood_roof_top45_bal", "ashwood_wall_beam_64_bal", "bg_stake_wall_bal", "bigstonepillar4m_bal", "bigstonepillar4m_reverse_bal", "blackmarble_1x1_enforced_bal", "blackmarble_2x2x1_bal", "blackmarble_2x2_enforced_bal", "blackmarble_beam_bal", "blackmarble_columnbase_bal", "blackmarble_columntop_bal", "blackmarble_creep_slope_inverted_2x2x1_bal", "blackmarble_floor4m_bal", "blackmarble_gate_bal", "blackmarble_head_big01_bal", "blackmarble_head_big02_bal", "blackmarble_long_stair_bal", "blackmarble_pole_bal", "blackmarble_roof27_bal", "blackmarble_slope1x2_bal", "blackmarble_slope1x2_inverted_bal", "blackmarble_stair_corner_bal", "blackmarble_stair_corner_left_bal", "blackmarble_stair_inner_bal", "blackmarble_stair_outer_bal", "blackmarble_stone_ladder_bal", "blackmarble_Wall_Window_2x2_bal", "BoneFragmentsFloorl1_bal", "BoneFragmentsFloorl2_bal", "bone_fence_bal", "bridge_end_bal", "bridge_floor_bal", "bronze_gate_left_bal", "bush_roof_bal", "bush_roof_icorner_bal", "bush_roof_ocorner_bal", "bush_roof_top_bal", "CheeseBlock_bal", "chitin_wall_spikes_bal", "ClayBeam_bal", "ClayCube_bal", "ClayPole_bal", "clayr_arch_bal", "ClayWall_bal", "ClayWall_half_bal", "ClayWall_quarter_bal", "Clay_arch45_bal", "clay_celling_bal", "clay_floor_2x2_bal", "clay_slab_wall4x4_bal", "clay_stair_bal", "coppermarble_1x1_enforced_bal", "coppermarble_head1_bal", "coppermarble_head2_bal", "copper_dropgate_large_bal", "Copper_Wall_Spikes_bal", "corewood_gate_large_bal", "core_wood_roof26_bal", "core_wood_stair_bal", "core_wood_wall_2_bal", "core_wood_wall_4_bal", "core_wood_wall_corner_bal", "core_wood_wall_deco2_bal", "core_wood_wall_deco4_bal", "wood_wall_log1m_bal", "wood_log_64_bal", "wood_pole_log1m_bal", "crystal_tile_floor_2x2_bal", "crystal_wall_2x2_bal", "darkwoodwall1m_bal", "darkwoodwall_bal", "darkwood_beam_26_deco_bal", "darkwood_beam_45_deco_bal", "darkwood_beam_64_bal", "darkwood_beam_deco_bal", "darkwood_gate_large_bal", "darkwood_pole_deco_bal", "darkwood_roof64_bal", "darkwood_roof_quarter_26_bal", "darkwood_roof_quarter_45_bal", "darkwood_roof_top_cap2_bal", "darkwood_roof_top_cap_bal", "darkwood_roof_top_center_bal", "darkwood_roof_top_half_45_bal", "darkwood_roof_top_half_bal", "decowall_bal", "decr_wall_half_bal", "dverger_gate_bal", "dvergr_secretdoor_bal", "emberwood_pillar2_bal", "emberwood_pillar4_bal", "fineood_wall_roof_26_bal", "finewood_arch_bottom_bal", "finewood_arch_top_bal", "finewood_beam2_bal", "finewood_beam4_bal", "finewood_beam_26_bal", "finewood_beam_45_bal", "finewood_beam_64_bal", "finewood_beam_bal", "finewood_floor1x1_bal", "finewood_floor2x2_bal", "finewood_frame_bal", "finewood_pole2_bal", "finewood_pole4_bal", "finewood_pole_bal", "finewood_stair_bal", "finewood_wall_1x1_bal", "finewood_wall_1x2_bal", "finewood_wall_2x1_bal", "finewood_wall_2x2_bal", "finewood_wall_arch_bal", "finewood_wall_cross_26_bal", "finewood_wall_cross_45_bal", "finewood_wall_cross_64_bal", "finewood_wall_roof_26_upsidedown_bal", "finewood_wall_roof_45_bal", "finewood_wall_roof_45_upsidedown_bal", "finewood_wall_roof_64_bal", "finewood_wall_roof_64_upsidedown_bal", "flametalchain_beam2_26_bal", "flametalchain_beam2_45_bal", "flametalchain_beam2_bal", "flametalchain_pole2_bal", "flametalchain_hook_bal", "flametalchain_hook_top_bal", "flametalchain_hook_wall_bal", "gabro_arch4m_bal", "gabro_barkwood_beam2_bal", "gabro_barkwood_beam_bal", "gabro_barkwood_pole2_bal", "gabro_barkwood_pole_26_bal", "gabro_barkwood_pole_45_bal", "gabro_barkwood_pole_bal", "gabro_bark_pillar_empty2m_bal", "gabro_bark_pillar_empty2m_reverse_bal", "gabro_bark_pillar_empty2m_side_bal", "gabro_beam4_bal", "gabro_clolumnbase_bal", "gabro_columntop_bal", "gabro_column_bal", "gabro_counter1x1_bal", "gabro_counter_corner_bal", "gabro_floor1x1_bal", "gabro_floor2x2_bal", "gabro_floor4x4_bal", "gabro_floor_slope26_bal", "gabro_floor_slope45_bal", "gabro_oriel4m_bal", "gabro_pass_1x3_bal", "gabro_pole4_bal", "gabro_stair_bal", "gabro_wall2x1_bal", "gabro_wall2x2_bal", "gabro_wall2x4_bal", "gabro_wall4x4_bal", "gabro_wall_1x1_thin_bal", "gabro_window1m_bal", "gabro_window2m_bal", "gabro_window_deco2m_bal", "gabro_window_glass_3m_bal", "gabro_window_large2m_bal", "gabro_window_round2m_bal", "gabro_window_triangle2m_bal", "giant_metal_gate_bal", "grausten_round_column_bal", "grausten_stair_corner_bal", "grausten_stair_corner_left_bal", "grausten_stair_inner_bal", "grausten_stair_outer_bal", "hardwood_door_bal", "hexwood_floor_4m_bal", "hexwood_floor_half_4m_bal", "iron_beam1_bal", "iron_beam_26_bal", "iron_beam_45_bal", "iron_beam_64_bal", "iron_beam_bal", "iron_pole1_bal", "iron_pole_bal", "iron_trim1_bal", "iron_trim_1_90_bal", "iron_trim_26_bal", "iron_trim_45_bal", "iron_trim_90_bal", "iron_trim_bal", "leather_roof_bal", "metalbar_1x2_bal", "obsidian_tile_floor_2x2_bal", "obsidian_wall_2x2_bal", "piece_grausten_pillar4_tip2_bal", "piece_grausten_pillar4_tip3_bal", "piece_grausten_pillar4_tip_bal", "piece_grausten_pillarbase_twisted_bal", "piece_grausten_pillarbase_twisted_reversed_bal", "piece_grausten_reinforced_wall_4x6_bal", "piece_grausten_roof_45_top_bal", "piece_grausten_twisted_pillarbase_bal", "piece_grausten_twisted_pillarbase_small_bal", "piece_grausten_twisted_pillartop_small_bal", "piece_grausten_twisted_pillar_small_bal", "piece_grausten_twist_arch_bal", "piece_hardwoodwall2m_bal", "piece_hardwood_floor2x2_bal", "Piece_hardwood_pillarbase_medium_bal", "Piece_hardwood_pillarbase_small_bal", "Piece_hardwood_pillarbase_tapered_bal", "Piece_hardwood_pillarbase_tapered_inverted_bal", "Piece_hardwood_pillarbeam_medium_bal", "Piece_hardwood_pillarbeam_small_bal", "Piece_hardwood_pillar_arch_bal", "Piece_hardwood_pillar_arch_small_bal", "piece_hardwood_roof_45_arch_bal", "piece_hardwood_roof_45_arch_corner2_bal", "piece_hardwood_roof_45_arch_corner_bal", "piece_hardwood_roof_45_bal", "piece_hardwood_roof_45_corner2_bal", "piece_hardwood_roof_45_corner_bal", "piece_hardwood_roof_45_top_bal", "piece_iron_fence_bal", "piece_iron_fence_small_bal", "piece_sharpstakes_big_bal", "plate_gate_bal", "rune_floor_bal", "spiked_copper_gate_left_bal", "spiked_copper_gate_right_bal", "stonemoss_tile_floor_2x2_bal", "stone_1x1_enforced_bal", "stone_arch4m_bal", "stone_beam2_bal", "stone_beam_bal", "stone_celling_bal", "stone_circle_arch_bal", "stone_floor4m_bal", "stone_floor_slope45_bal", "stone_floor_slope_bal", "stone_floor_triangle_bal", "stone_floor_trianlge_1x2m_bal", "stone_floor_trianlge_1x2m_reverse_bal", "stone_frame_bal", "stone_long_stair_bal", "stone_pillar6m1_bal", "stone_pillar6m3_bal", "stone_platform_bal", "stone_pole2_bal", "stone_pole_bal", "stone_railing_bal", "stone_roof27_bal", "stone_secretdoor_bal", "stone_slab_wall4x4_bal", "stone_stair_corner_bal", "stone_stair_corner_left_bal", "stone_stair_inner_bal", "stone_stair_outer_bal", "stone_stair_railing_bal", "stone_stair_railing_left_bal", "stone_stair_railing_right_bal", "stone_stepladder_bal", "stone_trim1_90_bal", "stone_trim1_bal", "stone_trim_26_bal", "stone_trim_45_bal", "stone_trim_90_bal", "stone_trim_bal", "stone_Wall_2x2_bal", "stone_window_bal", "tiledwood_floor_2x2_bal", "vigvisir_floor_bal", "woodiron_beam_64_bal", "wood_floor2x2_curved_bal", "woodwall4m_bal", "woodwall_1m_bal", "woodwall_deco_bal", "wood_arch_bal", "wood_beam4_bal", "wood_beam_64_bal", "wood_double_wall_roof_26_bal", "wood_dragon_dark_bal", "wood_fence_bal", "wood_floor4x4_bal", "wood_frame_decorative_bal", "wood_frame_window_bal", "wood_frame_window_half_bal", "wood_gate_cage_bal", "wood_gate_large_bal", "wood_hidden_gate_bal", "wood_iron_gate_large_bal", "wood_iron_log_beam4_bal", "wood_iron_log_pole4_bal", "wood_ledge_bal", "wood_long_stair_bal", "wood_pillar4_bal", "wood_plot_1m_bal", "wood_plot_3m_bal", "wood_plot_gate_bal", "wood_pole4_bal", "wood_railing_bal", "wood_ramp_bal", "woodwall_curved_bal", "wood_raven_bal", "wood_roof64_bal", "wood_roof64_corner_bottom_bal", "wood_roof64_corner_top_bal", "wood_roof64_icorner_bottom_bal", "wood_roof_flat_quarter_bal", "wood_roof_quad_top64_bal", "wood_roof_top_64_bal", "wood_roof_top_cap2_45_bal", "wood_roof_top_cap2_bal", "wood_roof_45_lukarna_bal", "wood_roof_top_cap_45_bal", "wood_roof_top_cap_bal", "wood_roof_top_center_45_bal", "wood_roof_top_center_bal", "wood_roof_top_half_45_bal", "wood_roof_top_half_bal", "wood_roof_top_quarter_45_bal", "wood_roof_top_quarter_bal", "wood_spiralstair_bal", "wood_spiralstair_right_bal", "wood_trim1_90_bal", "wood_trim1_bal", "wood_trim_26_bal", "wood_trim_45_bal", "wood_trim_64_bal", "wood_trim_90_bal", "wood_trim_bal", "wood_wall_cross_64_bal", "wood_wall_roof_26to45gap2_bal", "wood_wall_roof_26to45gap3_bal", "wood_wall_roof_26to45_bal", "wood_wall_roof_64_bal", "wood_wall_roof_upsidedown_64_bal", "wood_window2m_bal", "wood_windowiron_bal", "woven_fence_bal", "Yggdrasil_wood_block_bal", "Yggdrasil_wood_pillar_bal" }; } internal static class BalrondHashCompat { public static int StableHash(string value) { if (value == null) { return 0; } return StringExtensionMethods.GetStableHashCode(value); } } public class ModResourceLoader { private const string BundleResourceName = "balrondconstructions"; private const string BaseAssetPath = "Assets/Custom/BalrondConstructions/"; 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[1] { "sfx_queendoor_open1" }; private readonly PrefabLookupCache _scenePrefabCache = new PrefabLookupCache(); private readonly Dictionary<int, string> _sceneHashNames = new Dictionary<int, string>(); 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("balrondconstructions"); if (!((Object)(object)assetBundle == (Object)null)) { LoadPieces("Assets/Custom/BalrondConstructions/Pieces/"); LoadOther("Assets/Custom/BalrondConstructions/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); _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); InvalidateObjectDbBuildPieceCache(instance); } } 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); } 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 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(); } } internal static class PieceMetadataCompat { private const int MaxAuditNames = 24; public static void Apply(Piece piece, string prefabName) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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_0027: Invalid comparison between Unknown and I4 //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)piece == (Object)null) && (int)piece.m_usage <= 0) { UsageTagFlags val = InferUsageTags(piece, prefabName); if ((int)val > 0) { piece.m_usage = val; } } } 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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_007c: 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_0080: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_033e: Unknown result type (might be due to invalid IL or missing references) //IL_039c: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Unknown result type (might be due to invalid IL or missing references) //IL_03c9: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Unknown result type (might be due to invalid IL or missing references) //IL_03eb: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_0407: Unknown result type (might be due to invalid IL or missing references) //IL_040d: Unknown result type (might be due to invalid IL or missing references) //IL_040e: 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_0437: Unknown result type (might be due to invalid IL or missing references) //IL_0438: Unknown result type (might be due to invalid IL or missing references) //IL_046b: Unknown result type (might be due to invalid IL or missing references) //IL_046c: Unknown result type (might be due to invalid IL or missing references) //IL_0463: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Unknown result type (might be due to invalid IL or missing references) //IL_046a: Unknown result type (might be due to invalid IL or missing references) //IL_0470: Unknown result type (might be due to invalid IL or missing references) UsageTagFlags val = UsageFromClassicCategory(piece.m_category); 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")) { 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) //IL_0003: Expected I4, but got Unknown int num = (int)category; return num == 100 || (num >= 0 && num < 9); } 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); } } } 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 (!AnalysedShaderPairs.Add(text)) { return; } Dictionary<string, ShaderPropertyType> shaderPropertyTypes = GetShaderPropertyTypes(targetShader); int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int currentCount = 0; foreach (KeyValuePair<string, PropertySnapshot> property in sourceSnapshot.Properties) { string key = property.Key; PropertySnapshot value = property.Value; if (!shaderPropertyTypes.TryGetValue(key, out var value2)) { if (IsMeaningfulValue(value)) { num2++; if (CanLogAnotherDifference(ref currentCount)) { Debug.LogWarning((object)("[BalrondShaderReplacement] Target '" + targetShaderName + "' is missing source property '" + key + "' (" + ((object)Unsafe.As<ShaderPropertyType, ShaderPropertyType>(ref value.Type)/*cast due to .constrained prefix*/).ToString() + ") from material '" + ((Object)material).name + "', value=" + FormatPropertyValue(value))); } } } else if (!ArePropertyTypesCompatible(value.Type, value2)) { num3++; if (CanLogAnotherDifference(ref currentCount)) { Debug.LogWarning((object)("[BalrondShaderReplacement] Property type mismatch for '" + text + "', property='" + key + "', dummy=" + ((object)Unsafe.As<ShaderPropertyType, ShaderPropertyType>(ref value.Type)/*cast due to .constrained prefix*/).ToString() + ", target=" + ((object)(*(ShaderPropertyType*)(&value2))/*cast due to .constrained prefix*/).ToString())); } } else { num++; } } foreach (string key2 in shaderPropertyTypes.Keys) { if (!sourceSnapshot.Properties.ContainsKey(key2)) { num4++; if (debugTargetOnlyProperties && CanLogAnotherDifference(ref currentCount)) { Debug.Log((object)("[BalrondShaderReplacement] Target-only property for '" + text + "': '" + key2 + "'.")); } } } Debug.Log((object)("[BalrondShaderReplacement] Shader analysis '" + text + "': dummyProperties=" + sourceSnapshot.Properties.Count + ", targetProperties=" + shaderPropertyTypes.Count + ", compatible=" + num + ", meaningfulMissing=" + num2 + ", typeMismatch=" + num3 + ", targetOnly=" + num4)); } private static bool IsMeaningfulValue(PropertySnapshot property) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected I4, but got Unknown if (property == null) { return false; } ShaderPropertyType type = property.Type; ShaderPropertyType val = type; switch ((int)val) { case 4: return (Object)(object)property.TextureValue != (Object)null; case 2: case 3: return Mathf.Abs(property.FloatValue) > 0.0001f; case 0: return Mathf.Abs(property.ColorValue.r) > 0.0001f || Mathf.Abs(property.ColorValue.g) > 0.0001f || Mathf.Abs(property.ColorValue.b) > 0.0001f || Mathf.Abs(property.ColorValue.a) > 0.0001f; case 1: return ((Vector4)(ref property.VectorValue)).sqrMagnitude > 9.999999E-09f; default: return false; } } private static string FormatPropertyValue(PropertySnapshot property) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_0037: Expected I4, but got Unknown if (property == null) { return "null"; } ShaderPropertyType type = property.Type; ShaderPropertyType val = type; switch ((int)val) { case 4: return ((Object)(object)property.TextureValue != (Object)null) ? ((Object)property.TextureValue).name : "null"; case 2: case 3: return property.FloatValue.ToString("0.####"); case 0: return ((object)Unsafe.As<Color, Color>(ref property.ColorValue)/*cast due to .constrained prefix*/).ToString(); case 1: return ((object)Unsafe.As<Vector4, Vector4>(ref property.VectorValue)/*cast due to .constrained prefix*/).ToString(); default: return "unsupported"; } } private static bool CanLogAnotherDifference(ref int currentCount) { if (maxDifferenceLogsPerShaderPair <= 0 || currentCount >= maxDifferenceLogsPerShaderPair) { return false; } currentCount++; return true; } private static void AddPublicShaderReference(Shader shader) { if ((Object)(object)shader == (Object)null) { return; } for (int i = 0; i < shaders.Count; i++) { if (shaders[i] == shader) { return; } } shaders.Add(shader); } private static string FormatKeywords(string[] keywords) { if (keywords == null || keywords.Length == 0) { return string.Empty; } return string.Join(",", keywords); } private static int SafeGetPropertyCount(Shader shader) { if ((Object)(object)shader == (Object)null) { return 0; } try { return shader.GetPropertyCount(); } catch (Exception ex) { if (debug) { Debug.LogWarning((object)("[BalrondShaderReplacement] GetPropertyCount failed for '" + ((Object)shader).name + "': " + ex.Message)); } return 0; } } private static int SafeGetPassCount(Shader shader) { if ((Object)(object)shader == (Object)null) { return 0; } try { return shader.passCount; } catch (Exception ex) { if (debug) { Debug.LogWarning((object)("[BalrondShaderReplacement] passCount failed for '" + ((Object)shader).name + "': " + ex.Message)); } return 0; } } private static bool SafeGetIsSupported(Shader shader) { if ((Object)(object)shader == (Object)null) { return false; } try { return shader.isSupported; } catch (Exception ex) { if (debug) { Debug.LogWarning((object)("[BalrondShaderReplacement] isSupported failed for '" + ((Object)shader).name + "': " + ex.Message)); } return false; } } private static int SafeGetInstanceId(Object unityObject) { if (unityObject == (Object)null) { return 0; } try { return unityObject.GetInstanceID(); } catch { return 0; } } private static bool IsDedicatedServer() { try { return (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated(); } catch { return false; } } private static string RemovePrefix(string value, string prefix) { if (string.IsNullOrEmpty(value) || string.IsNullOrEmpty(prefix)) { return value; } return value.StartsWith(prefix, StringComparison.Ordinal) ? value.Substring(prefix.Length) : value; } private static bool ContainsOrdinalIgnoreCase(string value, string fragment) { return !string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(fragment) && value.IndexOf(fragment, StringComparison.OrdinalIgnoreCase) >= 0; } private static string ReplaceOrdinalIgnoreCase(string source, string oldValue, string newValue) { if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(oldValue)) { return source; } int num = source.IndexOf(oldValue, StringComparison.OrdinalIgnoreCase); if (num < 0) { return source; } return source.Substring(0, num) + newValue + source.Substring(num + oldValue.Length); } } public class TableMapper { public static CraftingStation cauldron; public static CraftingStation workbench; public static CraftingStation heavyWorkbench; public static CraftingStation forge; public static CraftingStation blackforge; public static CraftingStation stoneCutter; private static readonly PrefabLookupCache PrefabCache = new PrefabLookupCache(); private static List<GameObject> _prefabs; public static void setupTables(List<GameObject> prefabs) { _prefabs = prefabs; PrefabCache.Rebuild(prefabs); PrepareTables(); } private static CraftingStation FindStation(string name, CraftingStation fallback = null) { GameObject val = PrefabCache.Find(name, _prefabs); if ((Object)(object)val != (Object)null) { CraftingStation component = val.GetComponent<CraftingStation>(); if ((Object)(object)component != (Object)null) { return component; } if (Launch.Log != null) { Launch.Log.LogWarning((object)("Crafting-station prefab '" + name + "' has no CraftingStation component.")); } } if ((Object)(object)fallback != (Object)null) { return fallback; } if (Launch.Log != null) { Launch.Log.LogWarning((object)("Required crafting station not found: " + name)); } return null; } private static void PrepareTables() { cauldron = FindStation("piece_cauldron"); workbench = FindStation("piece_workbench"); heavyWorkbench = FindStation("piece_heavy_workbench_bal", workbench); forge = FindStation("forge"); blackforge = FindStation("blackforge"); stoneCutter = FindStation("piece_stonecutter"); } } public class JsonLoader { public string defaultPath = string.Empty; public void loadJson() { string translationPath = GetTranslationPath(); EnsureDirectory(translationPath); defaultPath = translationPath; LoadTranslations(translationPath); } public void justDefaultPath() { defaultPath = GetTranslationPath(); } public void createDefaultPath() { string translationPath = GetTranslationPath(); EnsureDirectory(translationPath); defaultPath = translationPath; } private static string GetTranslationPath() { return Path.Combine(Paths.ConfigPath, "BalrondConstructions-translation"); } private static void EnsureDirectory(string path) { if (Directory.Exists(path)) { return; } try { Directory.CreateDirectory(path); } catch (Exception ex) { if (Launch.Log != null) { Launch.Log.LogError((object)("Failed to create translation directory '" + path + "': " + ex)); } } } private static void LoadTranslations(string path) { if (!Directory.Exists(path)) { return; } string[] files; try { files = Directory.GetFiles(path, "*.json"); } catch (Exception ex) { if (Launch.Log != null) { Launch.Log.LogError((object)("Failed to enumerate translation files: " + ex)); } return; } foreach (string text in files) { try { string json = File.ReadAllText(text); JsonData jsonData = JsonMapper.ToObject(json); if (jsonData == null) { throw new InvalidDataException("JSON root is null."); } Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal); foreach (string key in jsonData.Keys) { if (!string.IsNullOrEmpty(key)) { JsonData jsonData2 = jsonData[key]; dictionary[key] = ((jsonData2 != null) ? jsonData2.ToString() : string.Empty); } } string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text); if (!string.IsNullOrWhiteSpace(fileNameWithoutExtension)) { BalrondTranslator.translations[fileNameWithoutExtension] = dictionary; } } catch (Exception e