Decompiled source of balrond character customization v0.1.7

plugins/BalrondCharacterCustomization.dll

Decompiled 2 weeks 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.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using JetBrains.Annotations;
using LitJson2;
using Microsoft.CodeAnalysis;
using ServerSync;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
public static class BalrondHashCompat
{
	private static readonly MethodInfo _getStableHashCodeStringBool;

	private static readonly MethodInfo _getStableHashCodeString;

	private static readonly bool _initialized;

	static BalrondHashCompat()
	{
		try
		{
			Type typeFromHandle = typeof(StringExtensionMethods);
			_getStableHashCodeStringBool = typeFromHandle.GetMethod("GetStableHashCode", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
			{
				typeof(string),
				typeof(bool)
			}, null);
			_getStableHashCodeString = typeFromHandle.GetMethod("GetStableHashCode", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(string) }, null);
			_initialized = true;
		}
		catch
		{
			_initialized = false;
		}
	}

	public static int StableHash(string value)
	{
		if (value == null)
		{
			return 0;
		}
		try
		{
			if (_getStableHashCodeStringBool != null)
			{
				return (int)_getStableHashCodeStringBool.Invoke(null, new object[2] { value, false });
			}
			if (_getStableHashCodeString != null)
			{
				return (int)_getStableHashCodeString.Invoke(null, new object[1] { value });
			}
		}
		catch
		{
		}
		return FallbackStableHash(value);
	}

	private static int FallbackStableHash(string value)
	{
		int num = 5381;
		int num2 = num;
		for (int i = 0; i < value.Length; i += 2)
		{
			num = ((num << 5) + num) ^ value[i];
			if (i == value.Length - 1)
			{
				break;
			}
			num2 = ((num2 << 5) + num2) ^ value[i + 1];
		}
		return num + num2 * 1566083941;
	}
}
namespace BalPlayerColorsrondVnV
{
	[Serializable]
	public class MappedEffectList
	{
		public List<EffectInfo> pieceEffect;

		public List<EffectInfo> destroyedEffects;

		public List<EffectInfo> hitEffects;

		public List<EffectInfo> switchEffect;

		public List<EffectInfo> blockEffect;

		public List<EffectInfo> equipEffect;

		public List<EffectInfo> hitEffect;

		public List<EffectInfo> hitTerrainEffect;

		public List<EffectInfo> holdStartEffect;

		public List<EffectInfo> startEffect;

		public List<EffectInfo> trailStartEffect;

		public List<EffectInfo> triggerEffect;

		public List<EffectInfo> unequipEffect;

		public EffectList createEffectListFromInfo(List<EffectInfo> list)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			EffectList val = new EffectList();
			List<EffectData> list2 = new List<EffectData>();
			val.m_effectPrefabs = list2.ToArray();
			return val;
		}

		private EffectData createEffectData(EffectInfo info)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			EffectData val = new EffectData();
			val.m_inheritParentRotation = info.inheritRotation;
			val.m_multiplyParentVisualScale = info.multiplyScale;
			val.m_childTransform = info.childName;
			val.m_inheritParentScale = info.inheritScale;
			val.m_variant = info.variant;
			val.m_scale = info.scale;
			val.m_attach = info.attach;
			val.m_follow = info.follow;
			val.m_prefab = ZNetScene.instance.m_prefabs.Find((GameObject x) => ((Object)x).name == info.name);
			return val;
		}
	}
	[Serializable]
	public struct EffectInfo
	{
		public string name;

		public bool enabled;

		public int variant;

		public bool attach;

		public bool follow;

		public bool inheritRotation;

		public bool inheritScale;

		public bool multiplyScale;

		public bool radnomRotation;

		public bool scale;

		public string childName;

		public EffectInfo(string name, bool enabled = true, int variant = -1, bool attach = false, bool follow = false, bool inheritRotation = false, bool inheritScale = false, bool multiplyScale = false, bool radnomRotation = false, bool scale = false, string childName = null)
		{
			this.name = name;
			this.enabled = enabled;
			this.variant = variant;
			this.attach = attach;
			this.follow = follow;
			this.inheritRotation = inheritRotation;
			this.inheritScale = inheritScale;
			this.multiplyScale = multiplyScale;
			this.radnomRotation = radnomRotation;
			this.scale = scale;
			this.childName = childName;
		}
	}
}
namespace PlayerColors
{
	public class BalrondPlayerCustomization : MonoBehaviour
	{
		private static readonly int SkinColorId = Shader.PropertyToID("_SkinColor");

		private static readonly int ColorId = Shader.PropertyToID("_Color");

		private ZNetView netView;

		private Player _player;

		private VisEquipment _visEquipment;

		private SkinnedMeshRenderer _meshRenderer;

		private Transform _visual;

		private Transform _skeletonRoot;

		private readonly Dictionary<string, Transform> _liveBones = new Dictionary<string, Transform>(StringComparer.Ordinal);

		private readonly Dictionary<string, Vector3> _humanBoneScales = new Dictionary<string, Vector3>(StringComparer.Ordinal);

		private readonly Dictionary<RaceExtraSlot, GameObject> _raceExtraInstances = new Dictionary<RaceExtraSlot, GameObject>();

		private readonly List<Renderer> _skinTintedExtraRenderers = new List<Renderer>();

		private readonly MaterialPropertyBlock _skinBlock = new MaterialPropertyBlock();

		private Mesh[] _humanModelMeshes;

		private Material[] _humanModelMaterials;

		private Vector3 _humanVisualScale = Vector3.one;

		private int _lastModelIndex = -1;

		private float _nextNetworkRefresh;

		private Vector3 _lastExtraSkinColor = new Vector3(float.NaN, float.NaN, float.NaN);

		private float _nextScaleGuardLogTime;

		private const float BoneScaleEpsilon = 0.0001f;

		public Color eyeColor;

		public Vector3 eyeColorVector;

		public float height;

		public string raceId = "Human";

		public GameObject eyesObject;

		public GameObject _eyesInstanced;

		public int eyesItemHash;

		public bool isFemale = false;

		private void Start()
		{
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			netView = ((Component)this).GetComponent<ZNetView>();
			_player = ((Component)this).GetComponent<Player>();
			_visEquipment = ((Component)this).GetComponent<VisEquipment>();
			if (!((Object)(object)_player == (Object)null) && !((Object)(object)_visEquipment == (Object)null))
			{
				_meshRenderer = _visEquipment.m_bodyModel;
				_visual = ((Component)_player).transform.Find("Visual");
				if ((Object)(object)_visual == (Object)null)
				{
					_visual = ((Component)_player).transform;
				}
				CaptureHumanBaseline();
				EnsureEyes();
				eyeColorVector = GetFromPlayerCustomData();
				eyeColor = new Color(eyeColorVector.x, eyeColorVector.y, eyeColorVector.z, 1f);
				height = GetHeightFromPlayerCustomData();
				raceId = GetRaceFromPlayerData();
				if (Launch.CustomRacesEnabled && (Object)(object)netView != (Object)null && netView.IsOwner())
				{
					SaveRaceToPlayerData();
				}
				ApplyRaceVisuals(rebuildExtras: true);
				SetEyeColorInternal(eyeColor, save: false);
				ApplyHeight(height);
				RefreshEyesBinding();
				RefreshRaceExtraSkinColor(force: true);
			}
		}

		private void Update()
		{
			if (!((Object)(object)_player == (Object)null) && !((Object)(object)_visEquipment == (Object)null) && !(Time.time < _nextNetworkRefresh))
			{
				_nextNetworkRefresh = Time.time + 0.5f;
				string raceFromPlayerData = GetRaceFromPlayerData();
				int playerModel = _player.GetPlayerModel();
				if (!string.Equals(raceFromPlayerData, raceId, StringComparison.OrdinalIgnoreCase))
				{
					raceId = RaceManager.NormalizeRaceId(raceFromPlayerData);
					ApplyRaceVisuals(rebuildExtras: true);
				}
				else if (playerModel != _lastModelIndex)
				{
					ApplyRaceVisuals(rebuildExtras: true);
				}
				RefreshRaceExtraSkinColor(force: false);
			}
		}

		private void LateUpdate()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			if (!Launch.CustomRacesEnabled || (Object)(object)_player == (Object)null || (Object)(object)_visEquipment == (Object)null || _liveBones.Count == 0 || !RaceManager.TryGetRace(raceId, out var race) || race == null)
			{
				return;
			}
			int num = 0;
			string text = null;
			Vector3 val = Vector3.one;
			Vector3 val2 = Vector3.one;
			foreach (KeyValuePair<string, Vector3> boneScale in race.BoneScales)
			{
				if (_liveBones.TryGetValue(boneScale.Key, out var value) && !((Object)(object)value == (Object)null) && (!_humanBoneScales.TryGetValue(boneScale.Key, out var value2) || !ApproximatelyScale(boneScale.Value, value2)) && !ApproximatelyScale(value.localScale, boneScale.Value))
				{
					if (text == null)
					{
						text = boneScale.Key;
						val = value.localScale;
						val2 = boneScale.Value;
					}
					value.localScale = boneScale.Value;
					num++;
				}
			}
			if (num > 0 && Time.unscaledTime >= _nextScaleGuardLogTime)
			{
				_nextScaleGuardLogTime = Time.unscaledTime + 5f;
				Debug.LogWarning((object)(string.Format("{0}: Animator changed {1} race bone scale(s) for '{2}'. ", "BalrondCharacterCustomization", num, raceId) + $"Reapplied them in LateUpdate. First='{text}', actual={val}, expected={val2}."));
			}
		}

		private static bool ApproximatelyScale(Vector3 a, Vector3 b)
		{
			//IL_0001: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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)
			return Mathf.Abs(a.x - b.x) <= 0.0001f && Mathf.Abs(a.y - b.y) <= 0.0001f && Mathf.Abs(a.z - b.z) <= 0.0001f;
		}

		private void OnDestroy()
		{
			ClearRaceExtras();
		}

		public void SetEyeColor(Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			SetEyeColorInternal(color, save: true);
		}

		private void SetEyeColorInternal(Color color, bool save)
		{
			//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_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			eyeColor = color;
			eyeColorVector = Utils.ColorToVec3(color);
			if (save)
			{
				SaveToCustomData();
			}
			ApplyColorToInstancedEyes(color);
		}

		public void SetHeight(float value)
		{
			height = value;
			SaveHeightToCustomData();
			ApplyHeight(value);
		}

		public void SetRace(string id)
		{
			SetRace(id, save: true);
		}

		public void SetRace(string id, bool save)
		{
			string b = (Launch.CustomRacesEnabled ? RaceManager.NormalizeRaceId(id) : "Human");
			bool flag = !string.Equals(raceId, b, StringComparison.OrdinalIgnoreCase);
			raceId = b;
			if (save)
			{
				SaveRaceToPlayerData();
			}
			if (flag || save)
			{
				ApplyRaceVisuals(rebuildExtras: true);
			}
		}

		public void RefreshRacePolicy()
		{
			string raceFromPlayerData = GetRaceFromPlayerData();
			string b = (Launch.CustomRacesEnabled ? RaceManager.NormalizeRaceId(raceFromPlayerData) : "Human");
			bool flag = !string.Equals(raceId, b, StringComparison.OrdinalIgnoreCase);
			raceId = b;
			if ((Object)(object)_player != (Object)null && (Object)(object)_visEquipment != (Object)null && (flag || !Launch.CustomRacesEnabled))
			{
				ApplyRaceVisuals(rebuildExtras: true);
			}
		}

		public string GetRaceFromPlayerCustomData(Player player = null)
		{
			Player val = (((Object)(object)player != (Object)null) ? player : _player);
			if ((Object)(object)val == (Object)null || val.m_customData == null)
			{
				return "Human";
			}
			string value;
			return val.m_customData.TryGetValue("BalrondRace", out value) ? RaceManager.NormalizeRaceId(value) : "Human";
		}

		public void SaveRaceToPlayerData()
		{
			if (!Launch.CustomRacesEnabled)
			{
				return;
			}
			if ((Object)(object)_player != (Object)null && _player.m_customData != null)
			{
				_player.m_customData["BalrondRace"] = raceId;
			}
			if ((Object)(object)netView != (Object)null && netView.IsOwner())
			{
				ZDO zDO = netView.GetZDO();
				if (zDO != null)
				{
					zDO.Set(RaceManager.RaceZdoKey, raceId);
				}
			}
		}

		public void SaveHeightToCustomData()
		{
			if (!((Object)(object)_player == (Object)null) && _player.m_customData != null)
			{
				_player.m_customData["BalrondHeight"] = height.ToString(CultureInfo.InvariantCulture);
			}
		}

		public void SaveToCustomData()
		{
			if (!((Object)(object)_player == (Object)null) && _player.m_customData != null)
			{
				_player.m_customData["BalrondEyesX"] = eyeColorVector.x.ToString(CultureInfo.InvariantCulture);
				_player.m_customData["BalrondEyesY"] = eyeColorVector.y.ToString(CultureInfo.InvariantCulture);
				_player.m_customData["BalrondEyesZ"] = eyeColorVector.z.ToString(CultureInfo.InvariantCulture);
			}
		}

		public float GetHeightFromPlayerCustomData(Player player = null)
		{
			Player val = (((Object)(object)player != (Object)null) ? player : _player);
			if ((Object)(object)val == (Object)null || val.m_customData == null)
			{
				return 0f;
			}
			if (!val.m_customData.TryGetValue("BalrondHeight", out var value))
			{
				return 0f;
			}
			return ParseFloat(value, 0f);
		}

		public Vector3 GetFromPlayerCustomData(Player player = null)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: 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)
			//IL_0034: 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)
			Player val = (((Object)(object)player != (Object)null) ? player : _player);
			if ((Object)(object)val == (Object)null || val.m_customData == null)
			{
				return Vector3.one;
			}
			val.m_customData.TryGetValue("BalrondEyesX", out var value);
			val.m_customData.TryGetValue("BalrondEyesY", out var value2);
			val.m_customData.TryGetValue("BalrondEyesZ", out var value3);
			return new Vector3(ParseFloat(value, 1f), ParseFloat(value2, 1f), ParseFloat(value3, 1f));
		}

		public void OnPlayerModelChanged()
		{
			ApplyRaceVisuals(rebuildExtras: true);
		}

		public void RefreshEyesBinding()
		{
			if ((Object)(object)_eyesInstanced == (Object)null || (Object)(object)_visEquipment == (Object)null || (Object)(object)_visEquipment.m_bodyModel == (Object)null)
			{
				return;
			}
			Transform val = _eyesInstanced.transform.Find("body");
			if ((Object)(object)val == (Object)null)
			{
				SkinnedMeshRenderer componentInChildren = _eyesInstanced.GetComponentInChildren<SkinnedMeshRenderer>(true);
				if (!((Object)(object)componentInChildren == (Object)null))
				{
					BindEyesRenderer(componentInChildren);
				}
			}
			else
			{
				SkinnedMeshRenderer component = ((Component)val).GetComponent<SkinnedMeshRenderer>();
				if ((Object)(object)component != (Object)null)
				{
					BindEyesRenderer(component);
				}
			}
		}

		public void RefreshRaceExtraSkinColor(bool force)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_visEquipment == (Object)null || _skinTintedExtraRenderers.Count == 0)
			{
				return;
			}
			Vector3 skinColor = _visEquipment.m_skinColor;
			if (!force && Approximately(skinColor, _lastExtraSkinColor))
			{
				return;
			}
			_lastExtraSkinColor = skinColor;
			Color val = default(Color);
			((Color)(ref val))..ctor(skinColor.x, skinColor.y, skinColor.z, 1f);
			for (int i = 0; i < _skinTintedExtraRenderers.Count; i++)
			{
				Renderer val2 = _skinTintedExtraRenderers[i];
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				val2.GetPropertyBlock(_skinBlock);
				Material[] sharedMaterials = val2.sharedMaterials;
				bool flag = false;
				bool flag2 = false;
				foreach (Material val3 in sharedMaterials)
				{
					if (!((Object)(object)val3 == (Object)null))
					{
						flag |= val3.HasProperty(SkinColorId);
						flag2 |= val3.HasProperty(ColorId);
					}
				}
				if (flag)
				{
					_skinBlock.SetColor(SkinColorId, val);
				}
				if (flag2)
				{
					_skinBlock.SetColor(ColorId, val);
				}
				val2.SetPropertyBlock(_skinBlock);
			}
		}

		private void CaptureHumanBaseline()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			_humanVisualScale = (((Object)(object)_visual != (Object)null) ? _visual.localScale : Vector3.one);
			_skeletonRoot = RaceManager.FindSkeletonRoot(_visual);
			_liveBones.Clear();
			_humanBoneScales.Clear();
			Dictionary<string, Transform> dictionary = RaceManager.BuildTransformMap(_skeletonRoot);
			foreach (KeyValuePair<string, Transform> item in dictionary)
			{
				_liveBones[item.Key] = item.Value;
				_humanBoneScales[item.Key] = item.Value.localScale;
			}
			if (_visEquipment.m_models != null)
			{
				_humanModelMeshes = (Mesh[])(object)new Mesh[_visEquipment.m_models.Length];
				_humanModelMaterials = (Material[])(object)new Material[_visEquipment.m_models.Length];
				for (int i = 0; i < _visEquipment.m_models.Length; i++)
				{
					_humanModelMeshes[i] = _visEquipment.m_models[i].m_mesh;
					_humanModelMaterials[i] = _visEquipment.m_models[i].m_baseMaterial;
				}
			}
		}

		private void ApplyRaceVisuals(bool rebuildExtras)
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_player == (Object)null || (Object)(object)_visEquipment == (Object)null)
			{
				return;
			}
			RaceDefinition race = null;
			bool flag = Launch.CustomRacesEnabled && RaceManager.TryGetRace(raceId, out race);
			RestoreHumanBoneScales();
			RestoreHumanModels();
			if (flag)
			{
				ApplyRaceBoneScales(race);
				ApplyRaceModels(race);
			}
			ApplyHeight(height);
			RefreshBaseModel();
			if (rebuildExtras)
			{
				ClearRaceExtras();
				if (flag)
				{
					CreateRaceExtras(race);
				}
			}
			_lastModelIndex = _player.GetPlayerModel();
			RefreshEyesBinding();
			ApplyColorToInstancedEyes(eyeColor);
			RefreshRaceExtraSkinColor(force: true);
		}

		private void RestoreHumanBoneScales()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<string, Vector3> humanBoneScale in _humanBoneScales)
			{
				if (_liveBones.TryGetValue(humanBoneScale.Key, out var value) && (Object)(object)value != (Object)null)
				{
					value.localScale = humanBoneScale.Value;
				}
			}
		}

		private void ApplyRaceBoneScales(RaceDefinition race)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<string, Vector3> boneScale in race.BoneScales)
			{
				if (_liveBones.TryGetValue(boneScale.Key, out var value) && (Object)(object)value != (Object)null)
				{
					value.localScale = boneScale.Value;
				}
			}
		}

		private void RestoreHumanModels()
		{
			if (_visEquipment.m_models == null)
			{
				return;
			}
			int num = ((_humanModelMeshes != null) ? Math.Min(_humanModelMeshes.Length, _visEquipment.m_models.Length) : 0);
			int num2 = ((_humanModelMaterials != null) ? Math.Min(_humanModelMaterials.Length, _visEquipment.m_models.Length) : 0);
			for (int i = 0; i < _visEquipment.m_models.Length; i++)
			{
				if (i < num && (Object)(object)_humanModelMeshes[i] != (Object)null)
				{
					_visEquipment.m_models[i].m_mesh = _humanModelMeshes[i];
				}
				if (i < num2 && (Object)(object)_humanModelMaterials[i] != (Object)null)
				{
					_visEquipment.m_models[i].m_baseMaterial = _humanModelMaterials[i];
				}
			}
		}

		private void ApplyRaceModels(RaceDefinition race)
		{
			if (_visEquipment.m_models == null || race == null)
			{
				return;
			}
			int num = Math.Min(2, _visEquipment.m_models.Length);
			for (int i = 0; i < num; i++)
			{
				Mesh mesh = race.GetMesh(i);
				Material material = race.GetMaterial(i);
				if ((Object)(object)mesh != (Object)null)
				{
					_visEquipment.m_models[i].m_mesh = mesh;
				}
				if ((Object)(object)material != (Object)null)
				{
					_visEquipment.m_models[i].m_baseMaterial = material;
				}
			}
		}

		private void ApplyHeight(float value)
		{
			//IL_002b: 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)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_visual == (Object)null))
			{
				RaceDefinition race;
				Vector3 val = (RaceManager.TryGetRace(raceId, out race) ? race.VisualBaseScale : _humanVisualScale);
				float num = Mathf.Max(0.01f, 1f + value);
				_visual.localScale = new Vector3(val.x, val.y * num, val.z);
			}
		}

		private void RefreshBaseModel()
		{
			if (!((Object)(object)_visEquipment == (Object)null))
			{
				try
				{
					Traverse val = Traverse.Create((object)_visEquipment);
					val.Field("m_currentModelIndex").SetValue((object)(-1));
					val.Method("UpdateBaseModel", Array.Empty<object>()).GetValue();
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)("BalrondCharacterCustomization: Could not invalidate/refresh VisEquipment base model: " + ex.Message));
				}
				_meshRenderer = _visEquipment.m_bodyModel;
			}
		}

		private void CreateRaceExtras(RaceDefinition race)
		{
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<RaceExtraSlot, RaceExtraDefinition> extra in race.Extras)
			{
				RaceExtraDefinition value = extra.Value;
				if (value == null || (Object)(object)value.Source == (Object)null)
				{
					continue;
				}
				if (!_liveBones.TryGetValue(value.ParentBonePath ?? string.Empty, out var value2) || (Object)(object)value2 == (Object)null)
				{
					Debug.LogWarning((object)string.Format("{0}: Race '{1}' extra {2} could not find live parent bone '{3}'.", "BalrondCharacterCustomization", race.Id, value.Slot, value.ParentBonePath));
					continue;
				}
				GameObject val = Object.Instantiate<GameObject>(value.Source);
				((Object)val).name = $"BRC_{race.Id}_{value.Slot}";
				val.transform.SetParent(value2, false);
				val.transform.localPosition = value.LocalPosition;
				val.transform.localRotation = value.LocalRotation;
				val.transform.localScale = value.LocalScale;
				val.SetActive(true);
				_raceExtraInstances[value.Slot] = val;
				if (value.SyncSkinColor)
				{
					Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>(true);
					for (int i = 0; i < componentsInChildren.Length; i++)
					{
						_skinTintedExtraRenderers.Add(componentsInChildren[i]);
					}
				}
			}
		}

		private void ClearRaceExtras()
		{
			//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)
			foreach (KeyValuePair<RaceExtraSlot, GameObject> raceExtraInstance in _raceExtraInstances)
			{
				if ((Object)(object)raceExtraInstance.Value != (Object)null)
				{
					Object.Destroy((Object)(object)raceExtraInstance.Value);
				}
			}
			_raceExtraInstances.Clear();
			_skinTintedExtraRenderers.Clear();
			_lastExtraSkinColor = new Vector3(float.NaN, float.NaN, float.NaN);
		}

		private void EnsureEyes()
		{
			if (eyesItemHash == 0 && (Object)(object)ObjectDB.instance != (Object)null)
			{
				eyesObject = ObjectDB.instance.GetItemPrefab("eyes_bal");
				eyesItemHash = (((Object)(object)eyesObject != (Object)null) ? ((object)eyesObject).GetHashCode() : 0);
			}
			if ((Object)(object)Launch.eyesObject != (Object)null)
			{
				eyesObject = Launch.eyesObject;
			}
			if ((Object)(object)_eyesInstanced == (Object)null && (Object)(object)eyesObject != (Object)null)
			{
				_eyesInstanced = Launch.AttachItem(eyesObject, -1, _visEquipment.m_helmet, _visEquipment);
			}
		}

		private void BindEyesRenderer(SkinnedMeshRenderer eyesRenderer)
		{
			SkinnedMeshRenderer bodyModel = _visEquipment.m_bodyModel;
			if (!((Object)(object)bodyModel == (Object)null) && !((Object)(object)eyesRenderer == (Object)null))
			{
				eyesRenderer.sharedMesh = bodyModel.sharedMesh;
				eyesRenderer.rootBone = bodyModel.rootBone;
				eyesRenderer.bones = bodyModel.bones;
			}
		}

		private void ApplyColorToInstancedEyes(Color color)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_eyesInstanced == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren = _eyesInstanced.GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Material material = componentsInChildren[i].material;
				if (material.HasProperty("_Color"))
				{
					material.SetColor("_Color", color);
				}
				if (material.HasProperty("_EmissionColor"))
				{
					material.SetColor("_EmissionColor", color);
				}
			}
		}

		private string GetRaceFromPlayerData()
		{
			if (!Launch.CustomRacesEnabled || (Object)(object)_player == (Object)null)
			{
				return "Human";
			}
			if ((Object)(object)netView == (Object)null || netView.IsOwner() || (Object)(object)_player == (Object)(object)Player.m_localPlayer)
			{
				string raceFromPlayerCustomData = GetRaceFromPlayerCustomData(_player);
				if (!string.Equals(raceFromPlayerCustomData, "Human", StringComparison.OrdinalIgnoreCase) || (_player.m_customData != null && _player.m_customData.ContainsKey("BalrondRace")))
				{
					return raceFromPlayerCustomData;
				}
			}
			if ((Object)(object)netView != (Object)null)
			{
				ZDO zDO = netView.GetZDO();
				if (zDO != null)
				{
					string text = zDO.GetString(RaceManager.RaceZdoKey, string.Empty);
					if (!string.IsNullOrEmpty(text))
					{
						return RaceManager.NormalizeRaceId(text);
					}
				}
			}
			return GetRaceFromPlayerCustomData(_player);
		}

		private static float ParseFloat(string value, float fallback)
		{
			if (string.IsNullOrEmpty(value))
			{
				return fallback;
			}
			if (float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return result;
			}
			if (float.TryParse(value, out result))
			{
				return result;
			}
			return fallback;
		}

		private static bool Approximately(Vector3 a, Vector3 b)
		{
			//IL_0001: 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_0014: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			return Mathf.Approximately(a.x, b.x) && Mathf.Approximately(a.y, b.y) && Mathf.Approximately(a.z, b.z);
		}
	}
	public class BalrondTranslator
	{
		public static Dictionary<string, Dictionary<string, string>> translations = new Dictionary<string, Dictionary<string, string>>();

		public static Dictionary<string, string> getLanguage(string language)
		{
			if (string.IsNullOrEmpty(language))
			{
				return null;
			}
			if (translations.TryGetValue(language, out var value))
			{
				return value;
			}
			return null;
		}
	}
	[BepInPlugin("balrond.astafaraios.BalrondCharacterCustomization", "BalrondCharacterCustomization", "1.0.0")]
	public class Launch : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		public static class Object_CopyOtherDB_Path
		{
			public static void Postfix()
			{
				if (!IsObjectDBValid())
				{
					return;
				}
				databaseAddMethods.AddItems(modResourceLoader.itemPrefabs);
				ShaderReplacment.runMaterialFix();
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Hair3");
				if (!((Object)(object)itemPrefab != (Object)null))
				{
					return;
				}
				Material val = null;
				Renderer[] componentsInChildren = itemPrefab.GetComponentsInChildren<Renderer>();
				foreach (Renderer val2 in componentsInChildren)
				{
					val = val2.material;
				}
				foreach (GameObject itemPrefab2 in modResourceLoader.itemPrefabs)
				{
					if (((Object)itemPrefab2).name.Contains("Hair") && (Object)(object)val != (Object)null)
					{
						Renderer[] componentsInChildren2 = itemPrefab.GetComponentsInChildren<Renderer>();
						foreach (Renderer val3 in componentsInChildren2)
						{
							val3.material = val;
						}
					}
				}
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		public static class ObjectDB_Awake_Path
		{
			public static void Postfix()
			{
				if (IsObjectDBValid())
				{
					databaseAddMethods.AddItems(modResourceLoader.itemPrefabs);
					databaseAddMethods.AddStatuseffects(modResourceLoader.statusEffects);
					databaseAddMethods.AddRecipes(modResourceLoader.recipes);
				}
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		public static class ZNetScene_Awake_Path
		{
			public static bool hasSpawned;

			public static void Prefix(ZNetScene __instance)
			{
				//IL_0086: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance == (Object)null)
				{
					Debug.LogWarning((object)(projectName + ": No ZnetScene found"));
					return;
				}
				modResourceLoader.AddPrefabsToZnetScene(__instance);
				GameObject val = __instance.m_prefabs.Find((GameObject x) => ((Object)x).name == "Player");
				BalrondPlayerCustomization component = val.GetComponent<BalrondPlayerCustomization>();
				if ((Object)(object)component == (Object)null)
				{
					val.AddComponent<BalrondPlayerCustomization>();
				}
				if (!Launch.hasSpawned)
				{
					if (new ZNet().IsDedicated())
					{
						Launch.hasSpawned = true;
						return;
					}
					ShaderReplacment.runMaterialFix();
					Launch.hasSpawned = true;
				}
			}
		}

		[HarmonyPatch(typeof(FejdStartup), "SetupGui")]
		private class FejdStartup_SetupGUI
		{
			private static void Postfix()
			{
				string selectedLanguage = Localization.instance.GetSelectedLanguage();
				Dictionary<string, string> translations = GetTranslations(selectedLanguage);
				AddTranslations(translations);
				RefreshLabels();
			}
		}

		[HarmonyPriority(800)]
		[HarmonyPatch(typeof(Localization), "SetupLanguage")]
		private class Translation_SetupLanguage
		{
			private static void Prefix(Localization __instance, string language)
			{
				Dictionary<string, string> translations = GetTranslations(language);
				AddTranslations(translations, __instance);
				RefreshLabels();
			}
		}

		[HarmonyPriority(800)]
		[HarmonyPatch(typeof(Localization), "LoadCSV")]
		private class Translation_LoadCSV
		{
			private static void Prefix(Localization __instance, string language)
			{
				Dictionary<string, string> translations = GetTranslations(language);
				AddTranslations(translations, __instance);
				RefreshLabels();
			}
		}

		[HarmonyPatch(typeof(PlayerCustomizaton), "OnBeardLeft")]
		public static class PlayerCustomizatonOnBeardLeft
		{
			public static void Prefix(PlayerCustomizaton __instance)
			{
				if (__instance.GetPlayer().GetPlayerModel() == 0)
				{
					return;
				}
				int num = __instance.GetBeardIndex();
				for (int num2 = num - 1; num2 >= 0; num2--)
				{
					if (__instance.m_beards[num2].m_itemData.m_shared.m_toolTier <= __instance.m_hairToolTier)
					{
						num = num2;
						break;
					}
				}
				__instance.SetBeard(num);
			}
		}

		[HarmonyPatch(typeof(PlayerCustomizaton), "OnBeardRight")]
		public static class PlayerCustomizatonOnBeardRight
		{
			public static void Prefix(PlayerCustomizaton __instance)
			{
				if (__instance.GetPlayer().GetPlayerModel() == 0)
				{
					return;
				}
				int num = __instance.GetBeardIndex();
				for (int i = num + 1; i < __instance.m_beards.Count; i++)
				{
					if (__instance.m_beards[i].m_itemData.m_shared.m_toolTier <= __instance.m_hairToolTier)
					{
						num = i;
						break;
					}
				}
				__instance.SetBeard(num);
			}
		}

		[HarmonyPatch(typeof(PlayerCustomizaton), "SetPlayerModel")]
		public static class PlayerCustomizaton_SetPlayerModel_Patch
		{
			public static void Postfix(PlayerCustomizaton __instance, int index)
			{
				Player player = __instance.GetPlayer();
				if (Object.op_Implicit((Object)(object)player))
				{
					BalrondPlayerCustomization component = ((Component)player).GetComponent<BalrondPlayerCustomization>();
					if (!((Object)(object)component == (Object)null))
					{
						((MonoBehaviour)player).StartCoroutine(ApplyRaceAndEyesNextFrame(player, component));
					}
				}
			}

			private static IEnumerator ApplyRaceAndEyesNextFrame(Player player, BalrondPlayerCustomization balrond)
			{
				yield return null;
				if (!((Object)(object)player == (Object)null) && !((Object)(object)balrond == (Object)null))
				{
					balrond.OnPlayerModelChanged();
					balrond.RefreshEyesBinding();
				}
			}
		}

		[HarmonyPatch(typeof(FejdStartup), "Awake")]
		public static class FejdStartup_Awake_Patch
		{
			public static void Postfix(FejdStartup __instance)
			{
				//IL_005a: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bf: Expected O, but got Unknown
				//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dc: Expected O, but got Unknown
				//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
				Transform val = FejdStartup.instance.m_selectCharacterPanel.transform.Find("BottomWindow");
				Transform val2 = Object.Instantiate<Transform>(val.Find("New"));
				((Object)val2).name = "Edit";
				((Component)val2).transform.SetParent(val);
				((Component)val2).GetComponent<RectTransform>().anchoredPosition = Vector2.op_Implicit(new Vector3(-100f, 50f, 0f));
				editButton = ((Component)((Component)val2).transform.Find("Text")).GetComponent<TMP_Text>();
				editButton.text = Localization.instance.Localize("$tag_edit_character_button");
				((UnityEventBase)((Component)val2).GetComponent<Button>().onClick).RemoveAllListeners();
				((Component)val2).GetComponent<Button>().onClick = new ButtonClickedEvent();
				((UnityEvent)((Component)val2).GetComponent<Button>().onClick).AddListener(new UnityAction(StartCharacterEdit));
				((Component)val2).GetComponent<UIGamePad>().m_zinputKey = "JoyLTrigger";
				((TMP_Text)((Component)((Component)val2).transform.Find("gamepad_hint").Find("Text")).GetComponent<TextMeshProUGUI>()).text = "LT";
				title = Object.Instantiate<Transform>(FejdStartup.instance.m_newCharacterPanel.transform.Find("Topic"));
				editTitle = ((Component)title).GetComponent<TMP_Text>();
				((Object)title).name = "EditTitle";
				title.SetParent(FejdStartup.instance.m_newCharacterPanel.transform);
				editTitle.text = Localization.instance.Localize("$tag_edit_character_panel");
				((Component)title).GetComponent<RectTransform>().anchoredPosition = ((Component)FejdStartup.instance.m_newCharacterPanel.transform.Find("Topic")).GetComponent<RectTransform>().anchoredPosition;
				((Component)title).gameObject.SetActive(false);
				EnsureEyesPrefab();
				BalrondPlayerCustomization component = FejdStartup.instance.m_playerPrefab.GetComponent<BalrondPlayerCustomization>();
				if ((Object)(object)component == (Object)null)
				{
					component = FejdStartup.instance.m_playerPrefab.AddComponent<BalrondPlayerCustomization>();
				}
			}
		}

		[HarmonyPatch(typeof(PlayerCustomizaton), "Update")]
		public static class PlayerCustomizatonUpdatePatch
		{
			public static void Postfix(PlayerCustomizaton __instance)
			{
				//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
				//IL_010e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0114: Unknown result type (might be due to invalid IL or missing references)
				//IL_0123: Unknown result type (might be due to invalid IL or missing references)
				//IL_0128: Unknown result type (might be due to invalid IL or missing references)
				//IL_012a: Unknown result type (might be due to invalid IL or missing references)
				//IL_012c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0131: Unknown result type (might be due to invalid IL or missing references)
				//IL_015e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0163: Unknown result type (might be due to invalid IL or missing references)
				//IL_0165: Unknown result type (might be due to invalid IL or missing references)
				//IL_0167: 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_021c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0220: Unknown result type (might be due to invalid IL or missing references)
				//IL_027b: Unknown result type (might be due to invalid IL or missing references)
				CacheCustomizationPanel(__instance);
				if ((Object)(object)CustomizationPanel == (Object)null)
				{
					return;
				}
				CachePanelsAndSliders();
				if ((Object)(object)sliderR == (Object)null || (Object)(object)sliderG == (Object)null || (Object)(object)sliderB == (Object)null)
				{
					return;
				}
				float value = sliderR.value;
				float value2 = sliderG.value;
				float value3 = sliderB.value;
				myR = value;
				myG = value2;
				myB = value3;
				if (myR == 99f || myG == 99f || myB == 99f)
				{
					return;
				}
				Player customizationPlayer = GetCustomizationPlayer(__instance);
				if ((Object)(object)customizationPlayer == (Object)null)
				{
					return;
				}
				Vector3 val = default(Vector3);
				((Vector3)(ref val))..ctor(value, value2, value3);
				if (customizationPlayer.GetHairColor() != val)
				{
					customizationPlayer.SetHairColor(val);
				}
				if ((Object)(object)sliderS != (Object)null)
				{
					Color val2 = Color.Lerp(__instance.m_skinColor0, __instance.m_skinColor1, sliderS.value);
					Vector3 val3 = Utils.ColorToVec3(val2);
					VisEquipment visEquipment = ((Humanoid)customizationPlayer).m_visEquipment;
					bool flag = true;
					if ((Object)(object)visEquipment != (Object)null)
					{
						Vector3 value4 = Traverse.Create((object)visEquipment).Field("m_skinColor").GetValue<Vector3>();
						flag = value4 != val3;
					}
					if (flag)
					{
						customizationPlayer.SetSkinColor(val3);
					}
				}
				EnsureEyesPrefab();
				BalrondPlayerCustomization component = ((Component)customizationPlayer).GetComponent<BalrondPlayerCustomization>();
				if ((Object)(object)component != (Object)null)
				{
					component.RefreshRaceExtraSkinColor(force: false);
				}
				if (!((Object)(object)component == (Object)null) && !((Object)(object)sliderER == (Object)null) && !((Object)(object)sliderEG == (Object)null) && !((Object)(object)sliderEB == (Object)null) && !((Object)(object)sliderH == (Object)null))
				{
					Color val4 = default(Color);
					((Color)(ref val4))..ctor(sliderER.value, sliderEG.value, sliderEB.value, 1f);
					if (val4 != component.eyeColor)
					{
						SetCustomData(customizationPlayer, "BalrondEyesX", val4.r.ToString());
						SetCustomData(customizationPlayer, "BalrondEyesY", val4.g.ToString());
						SetCustomData(customizationPlayer, "BalrondEyesZ", val4.b.ToString());
						component.SetEyeColor(val4);
					}
					float value5 = sliderH.value;
					if (!Mathf.Approximately(value5, component.height))
					{
						SetCustomData(customizationPlayer, "BalrondHeight", value5.ToString());
						component.SetHeight(value5);
					}
				}
			}
		}

		[HarmonyPatch(typeof(FejdStartup), "SetupCharacterPreview")]
		public static class FejdStartup_SetupCharacterPreview_Patch
		{
			public static void Postfix(FejdStartup __instance)
			{
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0086: 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_0092: Unknown result type (might be due to invalid IL or missing references)
				//IL_009d: Unknown result type (might be due to invalid IL or missing references)
				EnsureEyesPrefab();
				BalrondPlayerCustomization component = __instance.m_playerInstance.GetComponent<BalrondPlayerCustomization>();
				if ((Object)(object)component != (Object)null)
				{
					Player previewPlayer = __instance.GetPreviewPlayer();
					Vector3 fromPlayerCustomData = component.GetFromPlayerCustomData(previewPlayer);
					float heightFromPlayerCustomData = component.GetHeightFromPlayerCustomData(previewPlayer);
					string raceFromPlayerCustomData = component.GetRaceFromPlayerCustomData(previewPlayer);
					component.SetRace(raceFromPlayerCustomData, save: false);
					if ((Object)(object)component._eyesInstanced == (Object)null)
					{
						component._eyesInstanced = AttachItem(eyesObject, -1, ((Humanoid)previewPlayer).m_visEquipment.m_helmet, ((Humanoid)previewPlayer).m_visEquipment);
					}
					component.SetEyeColor(new Color(fromPlayerCustomData.x, fromPlayerCustomData.y, fromPlayerCustomData.z, 1f));
					component.SetHeight(heightFromPlayerCustomData);
					component.RefreshEyesBinding();
					component.RefreshRaceExtraSkinColor(force: true);
				}
			}
		}

		[HarmonyPatch(typeof(FejdStartup), "OnNewCharacterDone")]
		public static class FejdStartup_OnNewCharacterDone_Patch
		{
			public static bool Prefix(FejdStartup __instance, ref List<PlayerProfile> ___m_profiles)
			{
				if (!editingCharacter)
				{
					return true;
				}
				((Component)title).gameObject.SetActive(false);
				((Component)FejdStartup.instance.m_newCharacterPanel.transform.Find("Topic")).gameObject.SetActive(true);
				editingCharacter = false;
				string text = ((TMP_InputField)__instance.m_csNewCharacterName).text;
				string text2 = text.ToLower();
				Traverse val = Traverse.Create((object)FejdStartup.instance);
				int value = val.Field("m_profileIndex").GetValue<int>();
				List<PlayerProfile> value2 = val.Field("m_profiles").GetValue<List<PlayerProfile>>();
				PlayerProfile val2 = value2[value];
				GameObject value3 = val.Field("m_playerInstance").GetValue<GameObject>();
				Player component = value3.GetComponent<Player>();
				EnsureEyesPrefab();
				BalrondPlayerCustomization component2 = value3.GetComponent<BalrondPlayerCustomization>();
				if ((Object)(object)component2 != (Object)null)
				{
					SetCustomData(component, "BalrondEyesX", sliderER.value.ToString());
					SetCustomData(component, "BalrondEyesY", sliderEG.value.ToString());
					SetCustomData(component, "BalrondEyesZ", sliderEB.value.ToString());
					SetCustomData(component, "BalrondHeight", sliderH.value.ToString());
					if (CustomRacesEnabled)
					{
						SetCustomData(component, "BalrondRace", component2.raceId);
						component2.SaveRaceToPlayerData();
					}
				}
				else
				{
					Debug.LogWarning((object)"Couldnt save character custom information");
				}
				val2.SavePlayerData(component);
				val2.SetName(text);
				val2.Save();
				__instance.m_selectCharacterPanel.SetActive(true);
				__instance.m_newCharacterPanel.SetActive(false);
				___m_profiles = null;
				Traverse.Create((object)__instance).Method("SetSelectedProfile", new object[1] { text2 }).GetValue();
				return false;
			}
		}

		[HarmonyPatch(typeof(FejdStartup), "OnNewCharacterCancel")]
		public static class FejdStartup_OnNewCharacterCancel_Patch
		{
			public static void Postfix(FejdStartup __instance)
			{
				((Component)title).gameObject.SetActive(false);
				((Component)FejdStartup.instance.m_newCharacterPanel.transform.Find("Topic")).gameObject.SetActive(true);
				editingCharacter = false;
				EnsureEyesPrefab();
			}
		}

		[HarmonyPatch(typeof(PlayerCustomizaton), "OnEnable")]
		public static class PlayerCustomizaton_OnEnable_Patch
		{
			public static void Postfix(PlayerCustomizaton __instance)
			{
				//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c9: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
				//IL_00eb: 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_013e: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c6: 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_020c: Unknown result type (might be due to invalid IL or missing references)
				if (!editingCharacter)
				{
					return;
				}
				FejdStartup componentInParent = ((Component)__instance).GetComponentInParent<FejdStartup>();
				if ((Object)(object)componentInParent == (Object)null)
				{
					return;
				}
				Player previewPlayer = componentInParent.GetPreviewPlayer();
				if ((Object)(object)previewPlayer == (Object)null)
				{
					return;
				}
				if (previewPlayer.GetPlayerModel() == 1)
				{
					__instance.m_maleToggle.isOn = false;
					__instance.m_femaleToggle.isOn = true;
				}
				VisEquipment value = Traverse.Create((object)previewPlayer).Field("m_visEquipment").GetValue<VisEquipment>();
				if ((Object)(object)value == (Object)null)
				{
					return;
				}
				Vector3 value2 = Traverse.Create((object)value).Field("m_skinColor").GetValue<Vector3>();
				Vector3 val = Utils.ColorToVec3(__instance.m_skinColor0);
				Vector3 val2 = Utils.ColorToVec3(__instance.m_skinColor1);
				float num = Vector3.Distance(val2, val);
				float value3 = ((num > 0f) ? (Vector3.Distance(value2, val) / num * (__instance.m_skinHue.maxValue - __instance.m_skinHue.minValue) + __instance.m_skinHue.minValue) : __instance.m_skinHue.minValue);
				__instance.m_skinHue.value = value3;
				Vector3 value4 = Traverse.Create((object)value).Field("m_hairColor").GetValue<Vector3>();
				BalrondPlayerCustomization component = ((Component)previewPlayer).GetComponent<BalrondPlayerCustomization>();
				if ((Object)(object)uiPanel == (Object)null)
				{
					EditExistingPanel();
					CreateHairPanel();
				}
				if ((Object)(object)component != (Object)null)
				{
					component.SetRace(component.GetRaceFromPlayerCustomData(previewPlayer), save: false);
				}
				RaceUI.EnsureCharacterPanel(__instance);
				Slider[] componentsInChildren = uiPanel.GetComponentsInChildren<Slider>();
				foreach (Slider val3 in componentsInChildren)
				{
					string name = ((Object)val3).name;
					switch (name)
					{
					case "Red_Slider":
						val3.value = value4.x;
						break;
					case "Green_Slider":
						val3.value = value4.y;
						break;
					case "Blue_Slider":
						val3.value = value4.z;
						break;
					}
					if ((Object)(object)component != (Object)null)
					{
						switch (name)
						{
						case "RedEye_Slider":
							val3.value = component.eyeColorVector.x;
							break;
						case "GreenEye_Slider":
							val3.value = component.eyeColorVector.y;
							break;
						case "BlueEye_Slider":
							val3.value = component.eyeColorVector.z;
							break;
						case "Height_Slider":
							val3.value = component.height;
							break;
						}
					}
				}
			}
		}

		[HarmonyPatch(typeof(FejdStartup), "OnCharacterNew")]
		public static class OnCharacterNewPatch
		{
			public static void Postfix(FejdStartup __instance)
			{
				string selectedLanguage = Localization.instance.GetSelectedLanguage();
				Dictionary<string, string> translations = GetTranslations(selectedLanguage);
				AddTranslations(translations);
				if ((Object)(object)uiPanel == (Object)null)
				{
					EditExistingPanel();
					CreateHairPanel();
				}
				EnsureEyesPrefab();
				PlayerCustomizaton component = __instance.m_newCharacterPanel.GetComponent<PlayerCustomizaton>();
				if ((Object)(object)component != (Object)null)
				{
					RaceUI.EnsureCharacterPanel(component);
				}
				RefreshLabels();
			}
		}

		[HarmonyPatch(typeof(PlayerCustomizaton), "ShowBarberGui")]
		public static class PlayerCustomizaton_ShowBarberGui_Patch
		{
			public static Vector3 playerHairColor = Vector3.zero;

			public static void Prefix(PlayerCustomizaton __instance)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				playerHairColor = Player.m_localPlayer.GetHairColor();
			}

			public static void Postfix(PlayerCustomizaton __instance)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: 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_0108: Unknown result type (might be due to invalid IL or missing references)
				//IL_012f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0156: Unknown result type (might be due to invalid IL or missing references)
				PlayerCustomizaton.m_lastHairColor = playerHairColor;
				Vector3 eyeColorVector = ((Component)Player.m_localPlayer).GetComponent<BalrondPlayerCustomization>().eyeColorVector;
				float height = ((Component)Player.m_localPlayer).GetComponent<BalrondPlayerCustomization>().height;
				if ((Object)(object)uiHairPanel == (Object)null)
				{
					EditBarberGuiLayout();
					CreateHairColorBarberGui();
				}
				EnsureEyesPrefab();
				RaceUI.EnsureBarberPanel(__instance);
				Slider[] componentsInChildren = uiHairPanel.GetComponentsInChildren<Slider>();
				foreach (Slider val in componentsInChildren)
				{
					if (((Object)val).name == "Red_Slider")
					{
						val.value = playerHairColor.x;
					}
					else if (((Object)val).name == "Green_Slider")
					{
						val.value = playerHairColor.y;
					}
					else if (((Object)val).name == "Blue_Slider")
					{
						val.value = playerHairColor.z;
					}
					if (((Object)val).name == "RedEye_Slider")
					{
						val.value = eyeColorVector.x;
					}
					else if (((Object)val).name == "GreenEye_Slider")
					{
						val.value = eyeColorVector.y;
					}
					else if (((Object)val).name == "BlueEye_Slider")
					{
						val.value = eyeColorVector.z;
					}
					if (((Object)val).name == "Height_Slider")
					{
						val.value = height;
					}
				}
				RefreshLabels();
			}
		}

		private readonly Harmony _harmony = new Harmony("balrond.astafaraios.BalrondCharacterCustomization");

		public static JsonLoader jsonLoader = new JsonLoader();

		public static GameObject RootObject;

		public static GameObject PrefabContainer;

		public static ModResourceLoader modResourceLoader = new ModResourceLoader();

		public static DatabaseAddMethods databaseAddMethods = new DatabaseAddMethods();

		public static string projectName = "BalrondCharacterCustomization";

		public static bool hasSpawned = false;

		public const string PluginGuid = "balrond.astafaraios.BalrondCharacterCustomization";

		public const string PluginName = "BalrondCharacterCustomization";

		public const string PluginVersion = "1.0.0";

		internal static RaceCustomizationConfig Settings;

		public static bool disableTutorials;

		public static bool newHardcorePlayer;

		public static bool skipIntro;

		public static bool editedBarber = false;

		public static GameObject uiPanel;

		public static GameObject uiHairPanel;

		public static Slider sliderR;

		public static Slider sliderG;

		public static Slider sliderB;

		public static Slider sliderS;

		public static Slider sliderER;

		public static Slider sliderEG;

		public static Slider sliderEB;

		public static Slider sliderH;

		public static float myR = 99f;

		public static float myG = 99f;

		public static float myB = 99f;

		public static Transform CustomizationPanel;

		public static Transform BarberCustomizationPanel;

		public static Transform hairPanel;

		public static Transform barberhairPanel;

		public static bool tryToFind = true;

		public static readonly bool isDebug = true;

		public static bool editingCharacter = false;

		public static Transform title;

		public static int eyesItemHash = 0;

		public static GameObject eyesObject;

		public static Dictionary<string, Vector3> eyeColors = new Dictionary<string, Vector3>();

		public static Dictionary<string, TextMeshProUGUI> textMeshProUGUIs = new Dictionary<string, TextMeshProUGUI>();

		public static TMP_Text editButton;

		public static TMP_Text editTitle;

		private const string EyesPrefabName = "eyes_bal";

		public static bool CustomRacesEnabled => Settings == null || Settings.EnableCustomRaces.Value;

		private static void EnsureEyesPrefab()
		{
			if (!((Object)(object)eyesObject != (Object)null) && !((Object)(object)ObjectDB.instance == (Object)null))
			{
				eyesObject = ObjectDB.instance.GetItemPrefab("eyes_bal");
				if ((Object)(object)eyesObject != (Object)null)
				{
					eyesItemHash = ((object)eyesObject).GetHashCode();
				}
			}
		}

		private static void SetCustomData(Player player, string key, string value)
		{
			if (!((Object)(object)player == (Object)null) && player.m_customData != null)
			{
				player.m_customData[key] = value;
			}
		}

		private static Player GetCustomizationPlayer(PlayerCustomizaton customization)
		{
			if ((Object)(object)customization == (Object)null)
			{
				return null;
			}
			FejdStartup componentInParent = ((Component)customization).GetComponentInParent<FejdStartup>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				return componentInParent.GetPreviewPlayer();
			}
			return ((Object)(object)PlayerCustomizaton.m_barberInstance != (Object)null) ? PlayerCustomizaton.m_barberInstance.GetPlayer() : null;
		}

		private static void CacheCustomizationPanel(PlayerCustomizaton customization)
		{
			if (!((Object)(object)CustomizationPanel != (Object)null) && !((Object)(object)customization == (Object)null) && !((Object)(object)customization.m_hairTone == (Object)null))
			{
				Transform transform = ((Component)customization.m_hairTone).transform;
				if ((Object)(object)transform.parent != (Object)null && (Object)(object)transform.parent.parent != (Object)null && (Object)(object)transform.parent.parent.parent != (Object)null)
				{
					CustomizationPanel = transform.parent.parent.parent;
				}
			}
		}

		private static void CachePanelsAndSliders()
		{
			if ((Object)(object)CustomizationPanel == (Object)null)
			{
				return;
			}
			bool flag = (Object)(object)hairPanel == (Object)null || (Object)(object)barberhairPanel == (Object)null;
			bool flag2 = (Object)(object)sliderR == (Object)null || (Object)(object)sliderG == (Object)null || (Object)(object)sliderB == (Object)null || (Object)(object)sliderS == (Object)null || (Object)(object)sliderER == (Object)null || (Object)(object)sliderEG == (Object)null || (Object)(object)sliderEB == (Object)null || (Object)(object)sliderH == (Object)null;
			if (!flag && !flag2)
			{
				return;
			}
			Transform[] componentsInChildren = ((Component)CustomizationPanel).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				string name = ((Object)val).name;
				if (flag)
				{
					if ((Object)(object)hairPanel == (Object)null && name == "BalrondCustomizationPanel")
					{
						hairPanel = val;
					}
					else if ((Object)(object)barberhairPanel == (Object)null && name == "BarberHairPanel")
					{
						barberhairPanel = val;
					}
				}
				if (!flag2)
				{
					continue;
				}
				Slider component = ((Component)val).GetComponent<Slider>();
				if (!((Object)(object)component == (Object)null))
				{
					switch (name)
					{
					case "Red_Slider":
						sliderR = component;
						break;
					case "Green_Slider":
						sliderG = component;
						break;
					case "Blue_Slider":
						sliderB = component;
						break;
					case "Skin slider":
						sliderS = component;
						break;
					case "RedEye_Slider":
						sliderER = component;
						break;
					case "GreenEye_Slider":
						sliderEG = component;
						break;
					case "BlueEye_Slider":
						sliderEB = component;
						break;
					case "Height_Slider":
						sliderH = component;
						break;
					}
				}
			}
		}

		private void Awake()
		{
			ServerSyncBridge.Initialize("balrond.astafaraios.BalrondCharacterCustomization", "BalrondCharacterCustomization", "1.0.0");
			Settings = new RaceCustomizationConfig(this);
			Settings.EnableCustomRaces.SettingChanged += OnCustomRacesSettingChanged;
			jsonLoader.loadJson();
			createPrefabContainer();
			modResourceLoader.loadAssets();
			_harmony.PatchAll();
		}

		private void OnCustomRacesSettingChanged(object sender, EventArgs e)
		{
			RaceUI.SetCustomRacesEnabled(CustomRacesEnabled);
			BalrondPlayerCustomization[] array = Resources.FindObjectsOfTypeAll<BalrondPlayerCustomization>();
			for (int i = 0; i < array.Length; i++)
			{
				if ((Object)(object)array[i] != (Object)null)
				{
					array[i].RefreshRacePolicy();
				}
			}
		}

		internal ConfigEntry<bool> LockingConfig(string section, string key, bool defaultValue, ConfigDescription description)
		{
			ConfigEntry<bool> val = ((BaseUnityPlugin)this).Config.Bind<bool>(section, key, defaultValue, description);
			ServerSyncBridge.AddLockingConfigEntry(val);
			return val;
		}

		internal ConfigEntry<T> SyncedConfig<T>(string section, string key, T defaultValue, ConfigDescription description)
		{
			ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, description);
			ServerSyncBridge.AddConfigEntry<T>(val);
			return val;
		}

		public void createPrefabContainer()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			RootObject = new GameObject("_BalrondRaceCustomizationRoot");
			Object.DontDestroyOnLoad((Object)(object)RootObject);
			PrefabContainer = new GameObject("Prefabs");
			PrefabContainer.transform.parent = RootObject.transform;
			PrefabContainer.SetActive(false);
		}

		public static GameObject cloneMe(GameObject source, string name)
		{
			GameObject val = Object.Instantiate<GameObject>(source, PrefabContainer.transform);
			((Object)val).name = name;
			fixMaterials(val, source);
			val.SetActive(true);
			return val;
		}

		public static GameObject fixMaterials(GameObject clone, GameObject source)
		{
			MeshRenderer[] componentsInChildren = source.GetComponentsInChildren<MeshRenderer>();
			foreach (MeshRenderer val in componentsInChildren)
			{
				MeshRenderer[] componentsInChildren2 = clone.GetComponentsInChildren<MeshRenderer>();
				foreach (MeshRenderer val2 in componentsInChildren2)
				{
					if (((Object)val).name == ((Object)val2).name)
					{
						((Renderer)val2).materials = ((Renderer)val).sharedMaterials;
						((Renderer)val2).sharedMaterials = ((Renderer)val).sharedMaterials;
						break;
					}
				}
			}
			return clone;
		}

		private void OnDestroy()
		{
			if (Settings != null)
			{
				Settings.EnableCustomRaces.SettingChanged -= OnCustomRacesSettingChanged;
			}
			_harmony.UnpatchSelf();
			if ((Object)(object)uiPanel != (Object)null)
			{
				Object.Destroy((Object)(object)uiPanel);
			}
			if ((Object)(object)uiHairPanel != (Object)null)
			{
				Object.Destroy((Object)(object)uiHairPanel);
			}
			RaceUI.DestroyPanels();
			Settings = null;
			ServerSyncBridge.Reset();
		}

		private static bool IsObjectDBValid()
		{
			return (Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_items.Count != 0 && ObjectDB.instance.m_recipes.Count != 0 && (Object)(object)ObjectDB.instance.GetItemPrefab("Amber") != (Object)null;
		}

		public static GameObject FindPrefabInZnet(string name, ZNetScene zNetScene)
		{
			GameObject value = null;
			zNetScene.m_namedPrefabs.TryGetValue(BalrondHashCompat.StableHash(name), out value);
			if ((Object)(object)value == (Object)null)
			{
				value = zNetScene.m_prefabs.Find((GameObject x) => ((Object)x).name == name);
			}
			return value;
		}

		private static Dictionary<string, string> GetTranslations(string language)
		{
			Dictionary<string, string> result = BalrondTranslator.getLanguage("English");
			if (!string.Equals(language, "English", StringComparison.OrdinalIgnoreCase))
			{
				Dictionary<string, string> language2 = BalrondTranslator.getLanguage(language);
				if (language2 != null)
				{
					result = language2;
				}
				else
				{
					Debug.Log((object)("BalrondCharacterCustomization: Did not find translation file for '" + language + "', loading English"));
				}
			}
			return result;
		}

		private static void AddTranslations(Dictionary<string, string> translations, Localization localizationInstance = null)
		{
			RaceUI.AddDefaultLocalization(localizationInstance);
			if (translations == null)
			{
				Debug.LogWarning((object)"BalrondCharacterCustomization: No translation file found!");
				return;
			}
			if (localizationInstance != null)
			{
				foreach (KeyValuePair<string, string> translation in translations)
				{
					localizationInstance.AddWord(translation.Key, translation.Value);
				}
				return;
			}
			foreach (KeyValuePair<string, string> translation2 in translations)
			{
				Localization.instance.AddWord(translation2.Key, translation2.Value);
			}
		}

		public static string ColorToString(Color color)
		{
			//IL_000d: 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_0029: 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)
			return $"{color.r} {color.g} {color.b} {color.a}";
		}

		public static GameObject AttachItem(GameObject itemPrefab, int variant, Transform joint, VisEquipment visEquipment, bool enableEquipEffects = true, bool backAttach = false)
		{
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: 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_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)itemPrefab == (Object)null)
			{
				Debug.LogWarning((object)"attach item not found(probably the Eyes object)");
				return null;
			}
			GameObject val = null;
			Transform val2 = itemPrefab.transform.Find("equipoffset");
			int childCount = itemPrefab.transform.childCount;
			for (int i = 0; i < childCount; i++)
			{
				Transform child = itemPrefab.transform.GetChild(i);
				if (backAttach && ((Object)((Component)child).gameObject).name == "attach_back")
				{
					val = ((Component)child).gameObject;
					break;
				}
				if (((Object)((Component)child).gameObject).name == "attach" || (!backAttach && ((Object)((Component)child).gameObject).name == "attach_skin"))
				{
					val = ((Component)child).gameObject;
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject val3 = Object.Instantiate<GameObject>(val);
			val3.SetActive(true);
			CleanupInstance(val3);
			if (((Object)val).name == "attach_skin")
			{
				val3.transform.SetParent(((Component)visEquipment.m_bodyModel).transform.parent);
				val3.transform.localPosition = Vector3.zero;
				val3.transform.localRotation = Quaternion.identity;
				SkinnedMeshRenderer[] componentsInChildren = val3.GetComponentsInChildren<SkinnedMeshRenderer>();
				SkinnedMeshRenderer[] array = componentsInChildren;
				foreach (SkinnedMeshRenderer val4 in array)
				{
					val4.rootBone = visEquipment.m_bodyModel.rootBone;
					val4.bones = visEquipment.m_bodyModel.bones;
				}
			}
			else
			{
				val3.transform.SetParent(joint);
				val3.transform.localPosition = Vector3.zero;
				val3.transform.localRotation = Quaternion.identity;
			}
			if ((Object)(object)val2 != (Object)null)
			{
				Transform transform = val3.transform;
				transform.localPosition += val2.position;
				Transform transform2 = val3.transform;
				transform2.localRotation *= val2.rotation;
			}
			IEquipmentVisual componentInChildren = val3.GetComponentInChildren<IEquipmentVisual>();
			if (componentInChildren != null)
			{
				componentInChildren.Setup(variant);
			}
			return val3;
		}

		private static void CleanupInstance(GameObject instance)
		{
			Collider[] componentsInChildren = instance.GetComponentsInChildren<Collider>();
			foreach (Collider val in componentsInChildren)
			{
				val.enabled = false;
			}
		}

		public static void StartCharacterEdit()
		{
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: 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_013c: Unknown result type (might be due to invalid IL or missing references)
			string selectedLanguage = Localization.instance.GetSelectedLanguage();
			Dictionary<string, string> translations = GetTranslations(selectedLanguage);
			AddTranslations(translations);
			editingCharacter = true;
			((Component)title).gameObject.SetActive(true);
			((Component)FejdStartup.instance.m_newCharacterPanel.transform.Find("Topic")).gameObject.SetActive(false);
			PlayerProfile val = Traverse.Create((object)FejdStartup.instance).Field("m_profiles").GetValue<List<PlayerProfile>>()[Traverse.Create((object)FejdStartup.instance).Field("m_profileIndex").GetValue<int>()];
			FejdStartup.instance.m_newCharacterPanel.SetActive(true);
			FejdStartup.instance.m_selectCharacterPanel.SetActive(false);
			((TMP_InputField)FejdStartup.instance.m_csNewCharacterName).text = val.GetName();
			FejdStartup.instance.m_newCharacterError.SetActive(false);
			Player previewPlayer = FejdStartup.instance.GetPreviewPlayer();
			BalrondPlayerCustomization balrondPlayerCustomization = ((previewPlayer != null) ? ((Component)previewPlayer).GetComponent<BalrondPlayerCustomization>() : null);
			if ((Object)(object)balrondPlayerCustomization != (Object)null)
			{
				Vector3 fromPlayerCustomData = balrondPlayerCustomization.GetFromPlayerCustomData(FejdStartup.instance.GetPreviewPlayer());
				float heightFromPlayerCustomData = balrondPlayerCustomization.GetHeightFromPlayerCustomData(FejdStartup.instance.GetPreviewPlayer());
				balrondPlayerCustomization.SetEyeColor(new Color(fromPlayerCustomData.x, fromPlayerCustomData.y, fromPlayerCustomData.z, 1f));
				balrondPlayerCustomization.SetHeight(heightFromPlayerCustomData);
			}
			Traverse.Create((object)FejdStartup.instance).Method("SetupCharacterPreview", new object[1] { val }).GetValue();
			Gogan.LogEvent("Screen", "Enter", "CreateCharacter", 0L);
		}

		public static GameObject CreateObjectFrom(GameObject source, Transform parent, string name)
		{
			GameObject val = Object.Instantiate<GameObject>(source, parent);
			((Object)val).name = name;
			return val;
		}

		public static void AddLabel(ref TextMeshProUGUI text, string label)
		{
			textMeshProUGUIs.Remove(label);
			textMeshProUGUIs.Add(label, text);
		}

		public static void RefreshLabels()
		{
			foreach (KeyValuePair<string, TextMeshProUGUI> textMeshProUGUI in textMeshProUGUIs)
			{
				((TMP_Text)textMeshProUGUI.Value).text = Localization.instance.Localize(textMeshProUGUI.Key);
			}
			if ((Object)(object)editButton != (Object)null)
			{
				editButton.text = Localization.instance.Localize("$tag_edit_character_button");
			}
			if ((Object)(object)editTitle != (Object)null)
			{
				editTitle.text = Localization.instance.Localize("$tag_edit_character_panel");
			}
		}

		public static void CreateLabel(GameObject parent, GameObject source, string name, float height, string translation = "", float offset = 0f)
		{
			//IL_008d: 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)
			GameObject val = CreateObjectFrom(source, parent.transform, name + "_Label");
			RectTransform component = val.GetComponent<RectTransform>();
			TextMeshProUGUI text = val.GetComponent<TextMeshProUGUI>();
			if (translation == "")
			{
				AddLabel(ref text, name);
				((TMP_Text)text).SetText(name);
			}
			else
			{
				AddLabel(ref text, translation);
				((TMP_Text)text).SetText(Localization.instance.Localize(translation));
			}
			TextMeshProUGUI obj = text;
			((TMP_Text)obj).fontSize = ((TMP_Text)obj).fontSize * 0.25f;
			val.SetActive(true);
			component.anchoredPosition = new Vector2(source.GetComponent<RectTransform>().anchoredPosition.x + offset, height);
		}

		public static GameObject CreateSlider(GameObject parent, GameObject source, string name, float height)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = CreateObjectFrom(source, parent.transform, name + "_Slider");
			RectTransform component = val.GetComponent<RectTransform>();
			val.SetActive(true);
			component.anchoredPosition = new Vector2(0f, height);
			return val;
		}

		public static void EditExistingPanel()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: 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_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			GameObject newCharacterPanel = FejdStartup.instance.m_newCharacterPanel;
			RectTransform component = ((Component)newCharacterPanel.transform.Find("CusomizationPanel")).GetComponent<RectTransform>();
			component.anchoredPosition += new Vector2(0f, 110f);
			RectTransform component2 = ((Component)((Transform)component).Find("bkg")).GetComponent<RectTransform>();
			component2.anchoredPosition += new Vector2(0f, -190f);
			((Transform)component2).localScale = new Vector3(((Transform)component2).localScale.x, ((Transform)component2).localScale.y * 1.701f, ((Transform)component2).localScale.z);
			component2.sizeDelta += new Vector2(0f, 32f);
			component2.anchoredPosition += new Vector2(0f, -16f);
			RectTransform component3 = ((Component)((Transform)component).Find("HairPanel")).GetComponent<RectTransform>();
			RectTransform component4 = ((Component)((Transform)component).Find("BeardPanel")).GetComponent<RectTransform>();
			component3.anchoredPosition += new Vector2(0f, 50f);
			component4.anchoredPosition += new Vector2(0f, 50f);
			RectTransform component5 = newCharacterPanel.GetComponent<RectTransform>();
			component5.anchoredPosition += new Vector2(0f, 80f);
			string[] array = new string[4] { "Hair tone", "tone", "level", "Hair level" };
			for (int i = 0; i < array.Length; i++)
			{
				Transform val = ((Transform)component).Find("SkinPanel").Find(array[i]);
				if ((Object)(object)val != (Object)null)
				{
					((Component)val).gameObject.SetActive(false);
				}
			}
			string[] array2 = new string[4] { "SexPanel", "HairPanel", "BeardPanel", "SkinPanel" };
			for (int j = 0; j < array2.Length; j++)
			{
				Transform val2 = ((Transform)component).Find("SkinPanel").Find(array2[j]);
				if ((Object)(object)val2 != (Object)null)
				{
					RectTransform component6 = ((Component)val2).GetComponent<RectTransform>();
					component6.anchoredPosition += new Vector2(0f, 50f);
				}
			}
		}

		public static GameObject CreateMainBalrondPanel()
		{
			GameObject newCharacterPanel = FejdStartup.instance.m_newCharacterPanel;
			RectTransform component = ((Component)newCharacterPanel.transform.Find("CusomizationPanel")).GetComponent<RectTransform>();
			GameObject gameObject = ((Component)newCharacterPanel.transform.Find("CusomizationPanel")).gameObject;
			RectTransform component2 = gameObject.GetComponent<RectTransform>();
			return gameObject;
		}

		public static void CreateHairPanel()
		{
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			GameObject newCharacterPanel = FejdStartup.instance.m_newCharacterPanel;
			GameObject gameObject = ((Component)newCharacterPanel.transform.Find("CusomizationPanel")).gameObject;
			PlayerCustomizaton component = newCharacterPanel.GetComponent<PlayerCustomizaton>();
			Transform val = gameObject.transform.Find("SexPanel");
			Transform val2 = gameObject.transform.Find("SkinPanel/tone");
			GameObject source = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null);
			GameObject val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).gameObject : null);
			GameObject val4 = CreateObjectFrom(((Component)component.m_hairTone).gameObject, gameObject.transform, "slider");
			GameObject val5 = CreateObjectFrom(source, gameObject.transform, "HairColorPanel");
			val5.GetComponent<RectTransform>().anchoredPosition = new Vector2(0f, -350f);
			float startHeight = 245f;
			startHeight = CreateColorSection(val5, val3, "Hair Color", new string[3] { "Red", "Green", "Blue" }, val4, startHeight, new string[3] { "$tag_red_slider", "$tag_green_slider", "$tag_blue_slider" }, "$tag_haircolor");
			startHeight = CreateColorSection(val5, val3, "Eye Color", new string[3] { "RedEye", "GreenEye", "BlueEye" }, val4, startHeight - 40f, new string[3] { "$tag_redeye_slider", "$tag_greeneye_slider", "$tag_blueeye_slider" }, "$tag_eyecolor");
			startHeight -= 10f;
			CreateLabel(val5, val3, "Height", startHeight, "$tag_heightslider");
			startHeight -= 30f;
			GameObject val6 = CreateSlider(val5, val4, "Height", startHeight);
			Slider component2 = val6.GetComponent<Slider>();
			component2.minValue = -0.05f;
			component2.maxValue = 0.05f;
			startHeight -= 25f;
			string[] array = new string[3] { "Sex", "MaleToggle", "FemaleToggle" };
			for (int i = 0; i < array.Length; i++)
			{
				DestroyIfFound(val5.transform, array[i]);
			}
			uiPanel = gameObject;
		}

		public static void AdjustVisibilityAndOffset(Transform parent, string name, Vector2 offset, bool assignSlider = false)
		{
			//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)
			Transform val = parent.Find(name);
			if (!((Object)(object)val == (Object)null))
			{
				RectTransform component = ((Component)val).GetComponent<RectTransform>();
				component.anchoredPosition += offset;
				((Component)val).gameObject.SetActive(true);
				if (assignSlider && name == "Skin slider")
				{
					sliderS = PlayerCustomizaton.m_barberInstance.m_skinHue;
				}
			}
		}

		private static void DestroyIfFound(Transform parent, string name)
		{
			Transform val = parent.Find(name);
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
		}

		public static void EditBarberGuiLayout()
		{
			//IL_0015: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: 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_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			GameObject rootPanel = PlayerCustomizaton.m_barberInstance.m_rootPanel;
			RectTransform component = rootPanel.GetComponent<RectTransform>();
			component.anchoredPosition += new Vector2(0f, 130f);
			AdjustRectTransformWithScale(rootPanel.transform, "bkg", new Vector3(1f, 1.74825f, 1f));
			AdjustRectTransformWithMove(rootPanel.transform, "bkg", new Vector2(0f, -140f));
			AdjustRectTransformWithMove(rootPanel.transform, "title", new Vector2(0f, 125f));
			AdjustRectTransform(((Component)PlayerCustomizaton.m_barberInstance.m_apply).transform, new Vector2(0f, -340f));
			AdjustRectTransform(((Component)PlayerCustomizaton.m_barberInstance.m_cancel).transform, new Vector2(0f, -340f));
			string[] array = new string[4] { "Topic", "Left", "Right", "Selected" };
			RectTransform[] componentsInChildren = rootPanel.GetComponentsInChildren<RectTransform>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				for (int j = 0; j < array.Length; j++)
				{
					if (((Object)componentsInChildren[i]).name == array[j])
					{
						RectTransform obj = componentsInChildren[i];
						obj.anchoredPosition += new Vector2(0f, 70f);
						break;
					}
				}
			}
			AdjustVisibilityAndOffset(rootPanel.transform, "SkinTone", new Vector2(0f, 10f));
			AdjustVisibilityAndOffsetAndAssignSlider(rootPanel.transform, "Skin slider", new Vector2(0f, 10f));
			SetActiveIfFound(rootPanel.transform, "level", state: false);
			SetActiveIfFound(rootPanel.transform, "tone", state: false);
			((Component)PlayerCustomizaton.m_barberInstance.m_hairTone).gameObject.SetActive(false);
			((Component)PlayerCustomizaton.m_barberInstance.m_hairLevel).gameObject.SetActive(false);
		}

		private static void AdjustRectTransformWithMove(Transform parent, string childName, Vector2 move)
		{
			//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)
			Transform val = parent.Find(childName);
			if (!((Object)(object)val == (Object)null))
			{
				RectTransform component = ((Component)val).GetComponent<RectTransform>();
				component.anchoredPosition += move;
			}
		}

		private static void AdjustRectTransformWithScale(Transform parent, string childName, Vector3 scale)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			Transform val = parent.Find(childName);
			if (!((Object)(object)val == (Object)null))
			{
				RectTransform component = ((Component)val).GetComponent<RectTransform>();
				((Transform)component).localScale = scale;
			}
		}

		private static void AdjustRectTransformWithMoveAndScale(Transform parent, string childName, Vector2 move, Vector3 scale)
		{
			//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_0031: Unknown result type (might be due to invalid IL or missing references)
			Transform val = parent.Find(childName);
			if (!((Object)(object)val == (Object)null))
			{
				RectTransform component = ((Component)val).GetComponent<RectTransform>();
				component.anchoredPosition += move;
				((Transform)component).localScale = scale;
			}
		}

		private static void AdjustRectTransform(Transform t, Vector2 move)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = ((Component)t).GetComponent<RectTransform>();
			component.anchoredPosition += move;
		}

		private static void AdjustVisibilityAndOffset(Transform parent, string name, Vector2 offset)
		{
			//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)
			Transform val = parent.Find(name);
			if (!((Object)(object)val == (Object)null))
			{
				RectTransform component = ((Component)val).GetComponent<RectTransform>();
				component.anchoredPosition += offset;
				((Component)val).gameObject.SetActive(true);
			}
		}

		private static void AdjustVisibilityAndOffsetAndAssignSlider(Transform parent, string name, Vector2 offset)
		{
			//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)
			Transform val = parent.Find(name);
			if (!((Object)(object)val == (Object)null))
			{
				RectTransform component = ((Component)val).GetComponent<RectTransform>();
				component.anchoredPosition += offset;
				((Component)val).gameObject.SetActive(true);
				if (name == "Skin slider")
				{
					sliderS = PlayerCustomizaton.m_barberInstance.m_skinHue;
				}
			}
		}

		private static void SetActiveIfFound(Transform parent, string name, bool state)
		{
			Transform val = parent.Find(name);
			if ((Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.SetActive(state);
			}
		}

		public static void CreateHairColorBarberGui()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			GameObject rootPanel = PlayerCustomizaton.m_barberInstance.m_rootPanel;
			barberhairPanel = (Transform)(object)((Component)rootPanel.transform.Find("HairPanel")).GetComponent<RectTransform>();
			GameObject val = CreateObjectFrom(((Component)barberhairPanel).gameObject, rootPanel.transform, "BarberHairPanel");
			val.GetComponent<RectTransform>().anchoredPosition = new Vector2(0f, -30f);
			val.SetActive(true);
			GameObject val2 = CreateObjectFrom(((Component)PlayerCustomizaton.m_barberInstance.m_hairTone).gameObject, rootPanel.transform, "slider");
			GameObject gameObject = ((Component)rootPanel.transform.Find("tone")).gameObject;
			float startHeight = 85f;
			startHeight = CreateColorSection(val, gameObject, "Hair Color", new string[3] { "Red", "Green", "Blue" }, val2, startHeight, new string[3] { "$tag_red_slider", "$tag_green_slider", "$tag_blue_slider" }, "$tag_haircolor");
			startHeight = CreateColorSection(val, gameObject, "Eye Color", new string[3] { "RedEye", "GreenEye", "BlueEye" }, val2, startHeight - 55f, new string[3] { "$tag_redeye_slider", "$tag_greeneye_slider", "$tag_blueeye_slider" }, "$tag_eyecolor");
			startHeight -= 10f;
			CreateLabel(val, gameObject, "Height", startHeight, "$tag_heightslider");
			startHeight -= 30f;
			GameObject val3 = CreateSlider(val, val2, "Height", startHeight);
			Slider component = val3.GetComponent<Slider>();
			component.minValue = -0.05f;
			component.maxValue = 0.05f;
			startHeight -= 25f;
			uiHairPanel = val;
		}

		private static float CreateColorSection(GameObject parent, GameObject toneRef, string sectionTitle, string[] colorNames, GameObject sliderTemplate, float startHeight, string[] translationNames, string panelLabel)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = CreateObjectFrom(toneRef, parent.transform, sectionTitle + "_Title");
			RectTransform component = val.GetComponent<RectTransform>();
			TextMeshProUGUI text = val.GetComponent<TextMeshProUGUI>();
			AddLabel(ref text, panelLabel);
			((TMP_Text)text).SetText(Localization.instance.Localize(panelLabel));
			TextMeshProUGUI obj = text;
			((TMP_Text)obj).fontSize = ((TMP_Text)obj).fontSize * 1.8f;
			component.anchoredPosition = new Vector2(0f, startHeight + 35f);
			val.SetActive(true);
			float num = startHeight;
			for (int i = 0; i < colorNames.Length; i++)
			{
				CreateLabel(parent, toneRef, colorNames[i], num, translationNames[i]);
				num -= 30f;
				CreateSlider(parent, sliderTemplate, colorNames[i], num);
				num -= 25f;
			}
			toneRef.SetActive(false);
			return num;
		}
	}
	public enum RaceExtraSlot
	{
		Ears,
		Tusks,
		Horns
	}
	public sealed class RaceExtraDefinition
	{
		public RaceExtraSlot Slot;

		public GameObject Source;

		public string ParentBonePath;

		public Vector3 LocalPosition;

		public Quaternion LocalRotation;

		public Vector3 LocalScale;

		public bool SyncSkinColor;
	}
	public sealed class RaceDefinition
	{
		public string Id;

		public string DisplayName;

		public GameObject SourcePrefab;

		public Vector3 VisualBaseScale = Vector3.one;

		public readonly Dictionary<string, Vector3> BoneScales = new Dictionary<string, Vector3>(StringComparer.Ordinal);

		public readonly Dictionary<RaceExtraSlot, RaceExtraDefinition> Extras = new Dictionary<RaceExtraSlot, RaceExtraDefinition>();

		public Mesh MaleMesh;

		public Mesh FemaleMesh;

		public Material MaleMaterial;

		public Material FemaleMaterial;

		public Mesh GetMesh(int modelIndex)
		{
			return (modelIndex == 1) ? FemaleMesh : MaleMesh;
		}

		public Material GetMaterial(int modelIndex)
		{
			return (modelIndex == 1) ? FemaleMaterial : MaleMaterial;
		}
	}
	public static class RaceManager
	{
		public const string HumanRaceId = "Human";

		public const string RaceCustomDataKey = "BalrondRace";

		public static readonly int RaceZdoKey = BalrondHashCompat.StableHash("BalrondRace");

		private static readonly Dictionary<string, RaceDefinition> RacesInternal = new Dictionary<string, RaceDefinition>(StringComparer.OrdinalIgnoreCase);

		public static IReadOnlyDictionary<string, RaceDefinition> Races => RacesInternal;

		public static bool Initialized { get; private set; }

		public static void Initialize(AssetBundle bundle)
		{
			RacesInternal.Clear();
			Initialized = false;
			if ((Object)(object)bundle == (Object)null)
			{
				Debug.LogError((object)"BalrondCharacterCustomization: RaceManager cannot initialize: AssetBundle is null.");
				return;
			}
			string[] allAssetNames = bundle.GetAllAssetNames();
			string raceFolder = "assets/custom/balrondcharacteredit/race/";
			string[] array = (from path in allAssetNames
				where path.StartsWith(raceFolder, StringComparison.OrdinalIgnoreCase)
				where path.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase)
				select path).ToArray();
			string[] array2 = array;
			foreach (string text in array2)
			{
				GameObject val = bundle.LoadAsset<GameObject>(text);
				if ((Object)(object)val == (Object)null)
				{
					Debug.LogWarning((object)("BalrondCharacterCustomization: Could not load race donor '" + text + "'."));
					continue;
				}
				string text2 = GetRaceIdFromName(((Object)val).name);
				if (string.IsNullOrWhiteSpace(text2))
				{
					text2 = GetRaceIdFromAssetPath(text);
				}
				if (!string.IsNullOrWhiteSpace(text2) && !string.Equals(text2, "Human", StringComparison.OrdinalIgnoreCase))
				{
					RaceDefinition raceDefinition = BuildDefinition(bundle, val, text2);
					if (raceDefinition != null)
					{
						RacesInternal[text2] = raceDefinition;
						Debug.Log((object)("BalrondCharacterCustomization: Registered race '" + text2 + "' from '" + text + "' " + $"({raceDefinition.BoneScales.Count} source transforms, {raceDefinition.Extras.Count} extras)."));
					}
				}
			}
			Initialized = true;
			if (!RacesInternal.ContainsKey("Alfir"))
			{
				Debug.LogWarning((object)"BalrondCharacterCustomization: RaceAlfir_bal was not discovered in the race folder.");
			}
			if (!RacesInternal.ContainsKey("Dverger"))
			{
				Debug.LogWarning((object)"BalrondCharacterCustomization: RaceDverger_bal was not discovered in the race folder.");
			}
		}

		public static bool TryGetRace(string id, out RaceDefinition race)
		{
			race = null;
			if (string.IsNullOrWhiteSpace(id) || string.Equals(id, "Human", StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			return RacesInternal.TryGetValue(id, out race);
		}

		public static string NormalizeRaceId(string id)
		{
			if (string.IsNullOrWhiteSpace(id) || string.Equals(id, "Human", StringComparison.OrdinalIgnoreCase))
			{
				return "Human";
			}
			RaceDefinition value;
			return RacesInternal.TryGetValue(id, out value) ? value.Id : "Human";
		}

		public static Transform FindVisualRoot(GameObject root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return null;
			}
			Transform val = FindDescendantByName(root.transform, "Visual");
			return ((Object)(object)val != (Object)null) ? val : root.transform;
		}

		public static Transform FindSkeletonRoot(Transform visualRoot)
		{
			if ((Object)(object)visualRoot == (Object)null)
			{
				return null;
			}
			Transform val = FindDescendantByName(visualRoot, "Armature");
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			Transform val2 = FindDescendantByName(visualRoot, "Hips");
			if ((Object)(object)val2 != (Object)null && (Object)(object)val2.parent != (Object)null)
			{
				return val2.parent;
			}
			return visualRoot;
		}

		public static Dictionary<string, Transform> BuildTransformMap(Transform root)
		{
			Dictionary<string, Transform> dictionary = new Dictionary<string, Transform>(StringComparer.Ordinal);
			if ((Object)(object)root == (Object)null)
			{
				return dictionary;
			}
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				string relativePath = GetRelativePath(root, val);
				if (!dictionary.ContainsKey(relativePath))
				{
					dictionary.Add(relativePath, val);
				}
			}
			return dictionary;
		}

		public static string GetRelativePath(Transform root, Transform target)
		{
			if ((Object)(object)root == (Object)null || (Object)(object)target == (Object)null)
			{
				return string.Empty;
			}
			if ((Object)(object)target == (Object)(object)root)
			{
				return string.Empty;
			}
			Stack<string> stack = new Stack<string>();
			Transform val = target;
			while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
			{
				stack.Push(((Object)val).name);
				val = val.parent;
			}
			if ((Object)(object)val != (Object)(object)root)
			{
				return string.Empty;
			}
			return string.Join("/", stack.ToArray());
		}

		private static RaceDefinition BuildDefinition(AssetBundle bundle, GameObject source, string id)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			ShaderReplacment.Replace(source);
			Transform val = FindVisualRoot(source);
			Transform val2 = FindSkeletonRoot(val);
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				Debug.LogError((object)("BalrondCharacterCustomization: Race '" + id + "' has no usable visual/skeleton root."));
				return null;
			}
			RaceDefinition raceDefinition = new RaceDefinition
			{
				Id = id,
				DisplayName = id,
				SourcePrefab = source,
				VisualBaseScale = val.localScale
			};
			Dictionary<string, Transform> dictionary = BuildTransformMap(val2);
			foreach (KeyValuePair<string, Transform> item in dictionary)
			{
				raceDefinition.BoneScales[item.Key] = item.Value.localScale;
			}
			FindRaceModels(bundle, source, id, out raceDefinition.MaleMesh, out raceDefinition.MaleMaterial, out raceDefinition.FemaleMesh, out raceDefinition.FemaleMaterial);
			AddExtraIfPresent(raceDefinition, val2, source.transform, RaceExtraSlot.Ears, true, "ears_bal", "ears");
			AddExtraIfPresent(raceDefinition, val2, source.transform, RaceExtraSlot.Tusks, false, "tusks_bal", "tusk_bal", "fangs_bal", "fang_bal", "tusks", "fangs");
			AddExtraIfPresent(raceDefinition, val2, source.transform, RaceExtraSlot.Horns, false, "horns_bal", "horn_bal", "horns", "horn");
			if ((Object)(object)raceDefinition.MaleMaterial == (Object)null)
			{
				Debug.LogWarning((object)("BalrondCharacterCustomization: Race '" + id + "' male body material was not resolved. Vanilla material will be retained."));
			}
			if ((Object)(object)raceDefinition.FemaleMaterial == (Object)null)
			{
				Debug.LogWarning((object)("BalrondCharacterCustomization: Race '" + id + "' female body material was not resolved. Vanilla material will be retained."));
			}
			return raceDefinition;
		}

		private static void AddExtraIfPresent(RaceDefinition race, Transform skeletonRoot, Transform sourceRoot, RaceExtraSlot slot, bool syncSkinColor, params string[] aliases)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unkno