Decompiled source of balrond constructions v1.4.5

plugins/BalrondConstructions.dll

Decompiled 5 days ago
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