Decompiled source of Skin Search v1.0.0

SkinSearch.dll

Decompiled 6 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using CrewBoom;
using CrewBoom.Data;
using CrewBoomMono;
using Reptile;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("SkinSearch")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SkinSearch")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("18b1ae4b-dea5-497b-b560-b7750c5c9075")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace SkinSearch;

[BepInPlugin("chimp.brc.skinsearch", "Skin Search", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class SkinSearchPlugin : BaseUnityPlugin
{
	private enum SortMode
	{
		Name,
		Recent
	}

	public const string PluginGuid = "chimp.brc.skinsearch";

	public const string PluginName = "Skin Search";

	public const string PluginVersion = "1.0.0";

	internal static ManualLogSource Log;

	private ConfigEntry<KeyCode> _toggleKey;

	private ConfigEntry<string> _favoritesConfig;

	private ConfigEntry<string> _recentConfig;

	private ConfigEntry<SortMode> _sortConfig;

	private ConfigEntry<bool> _showThumbnails;

	private ConfigEntry<int> _pageSize;

	private readonly List<SkinEntry> _allSkins = new List<SkinEntry>();

	private List<SkinEntry> _results = new List<SkinEntry>();

	private readonly HashSet<Guid> _favorites = new HashSet<Guid>();

	private readonly List<Guid> _recent = new List<Guid>();

	private bool _listBuilt;

	private bool _open;

	private string _query = "";

	private string _lastQuery = null;

	private bool _resultsDirty = true;

	private int _selected;

	private int _page;

	private Vector2 _scroll;

	private bool _focusSearchField;

	private bool _prevCursorVisible;

	private CursorLockMode _prevCursorLock;

	private const int MaxRecent = 20;

	private const int MaxVanillaSlot = 26;

	private const float RowHeight = 44f;

	private Rect _windowRect = new Rect(40f, 40f, 520f, 560f);

	private GUIStyle _rowStyle;

	private GUIStyle _rowStyleSelected;

	private GUIStyle _starStyle;

	private ConfigFile _crewBoomConfig;

	private int PageCount => Math.Max(1, (_results.Count + _pageSize.Value - 1) / _pageSize.Value);

	private void Awake()
	{
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		_toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "ToggleKey", (KeyCode)288, "Opens/closes the skin search window.");
		_showThumbnails = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowThumbnails", true, "Show each skin's graffiti as a thumbnail.");
		_sortConfig = ((BaseUnityPlugin)this).Config.Bind<SortMode>("General", "SortMode", SortMode.Name, "How the list is sorted (favorites always stay on top).");
		_pageSize = ((BaseUnityPlugin)this).Config.Bind<int>("General", "SkinsPerPage", 25, new ConfigDescription("How many skins are shown per page.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 200), Array.Empty<object>()));
		_favoritesConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Data", "Favorites", "", "Favorite skin GUIDs, comma-separated. Managed in-game.");
		_recentConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Data", "Recent", "", "Recently used skin GUIDs, newest first. Managed in-game.");
		foreach (Guid item in ParseGuids(_favoritesConfig.Value))
		{
			_favorites.Add(item);
		}
		_recent.AddRange(ParseGuids(_recentConfig.Value));
	}

	private void RefreshSkinList()
	{
		//IL_010f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//IL_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_011b: Invalid comparison between Unknown and I4
		_allSkins.Clear();
		if (!(typeof(CharacterDatabase).GetField("_characterBundlePaths", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) is Dictionary<Guid, string> dictionary))
		{
			Log.LogWarning((object)"CrewBoom database isn't initialized yet - try again once you're in a stage.");
			return;
		}
		Characters val = default(Characters);
		CustomCharacter val2 = default(CustomCharacter);
		foreach (KeyValuePair<Guid, string> item in dictionary)
		{
			Guid key = item.Key;
			string value = item.Value;
			if (CharacterDatabase.GetCharacterValueFromGuid(key, ref val))
			{
				string displayName = Path.GetFileNameWithoutExtension(value);
				if (CharacterDatabase.GetCharacter(key, ref val2) && ((val2 != null) ? val2.StreamData : null) != null && !string.IsNullOrEmpty(val2.StreamData.Name))
				{
					displayName = val2.StreamData.Name;
				}
				_allSkins.Add(new SkinEntry
				{
					Guid = key,
					FileName = Path.GetFileNameWithoutExtension(value),
					DisplayName = displayName,
					Slot = val,
					IsReplacement = ((int)val <= 26),
					HiddenFromCypher = value.Replace('\\', '/').Contains("/no_cypher/")
				});
			}
		}
		_resultsDirty = true;
		_listBuilt = true;
		Log.LogInfo((object)$"Loaded {_allSkins.Count} CrewBoom skins.");
	}

	private void UpdateResults()
	{
		if (!_resultsDirty && _query == _lastQuery)
		{
			return;
		}
		if (_query != _lastQuery)
		{
			_page = 0;
		}
		_resultsDirty = false;
		_lastQuery = _query;
		string q = _query.Trim();
		string[] words = q.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
		var source = from s in _allSkins
			select new
			{
				Skin = s,
				Score = ((q.Length == 0) ? 1 : MatchScore(s, q, words))
			} into x
			where x.Score > 0
			select x;
		var source2 = source.OrderByDescending(x => _favorites.Contains(x.Skin.Guid));
		if (_sortConfig.Value == SortMode.Recent)
		{
			source2 = source2.ThenBy(x => RecentRank(x.Skin.Guid));
		}
		if (q.Length > 0)
		{
			source2 = source2.ThenByDescending(x => x.Score);
		}
		_results = (from x in source2.ThenBy(x => x.Skin.DisplayName, StringComparer.OrdinalIgnoreCase)
			select x.Skin).ToList();
		_selected = Mathf.Clamp(_selected, 0, Math.Max(0, _results.Count - 1));
		_page = Mathf.Clamp(_page, 0, PageCount - 1);
	}

	private void SetPage(int page)
	{
		//IL_0028: 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)
		int num = Mathf.Clamp(page, 0, PageCount - 1);
		if (num != _page)
		{
			_page = num;
			_scroll = Vector2.zero;
		}
	}

	private int RecentRank(Guid guid)
	{
		int num = _recent.IndexOf(guid);
		return (num < 0) ? int.MaxValue : num;
	}

	private static int MatchScore(SkinEntry s, string q, string[] words)
	{
		return Math.Max(Score(s.DisplayName, q, words), Math.Max(Score(s.FileName, q, words) - 5, s.IsReplacement ? (Score(s.SlotName, q, words) - 20) : 0));
	}

	private static int Score(string name, string query, string[] words)
	{
		if (string.IsNullOrEmpty(name))
		{
			return 0;
		}
		StringComparison cmp = StringComparison.OrdinalIgnoreCase;
		if (name.Equals(query, cmp))
		{
			return 100;
		}
		if (name.StartsWith(query, cmp))
		{
			return 75;
		}
		int num = name.IndexOf(query, cmp);
		if (num >= 0)
		{
			return 50 - Math.Min(num, 40);
		}
		if (words.All((string w) => name.IndexOf(w, cmp) >= 0))
		{
			return 25;
		}
		return 0;
	}

	private void ToggleFavorite(SkinEntry skin)
	{
		if (!_favorites.Remove(skin.Guid))
		{
			_favorites.Add(skin.Guid);
		}
		_favoritesConfig.Value = string.Join(",", _favorites.Select((Guid g) => g.ToString()));
		_resultsDirty = true;
	}

	private void AddRecent(Guid guid)
	{
		_recent.Remove(guid);
		_recent.Insert(0, guid);
		if (_recent.Count > 20)
		{
			_recent.RemoveRange(20, _recent.Count - 20);
		}
		_recentConfig.Value = string.Join(",", _recent.Select((Guid g) => g.ToString()));
		_resultsDirty = true;
	}

	private static IEnumerable<Guid> ParseGuids(string raw)
	{
		if (string.IsNullOrEmpty(raw))
		{
			yield break;
		}
		string[] array = raw.Split(new char[1] { ',' });
		foreach (string part in array)
		{
			if (Guid.TryParse(part.Trim(), out var g))
			{
				yield return g;
			}
		}
	}

	private Texture GetThumbnail(SkinEntry skin)
	{
		if ((Object)(object)skin.Thumbnail != (Object)null || skin.ThumbnailTried)
		{
			return skin.Thumbnail;
		}
		skin.ThumbnailTried = true;
		try
		{
			CustomCharacter val = default(CustomCharacter);
			if (!CharacterDatabase.GetCharacter(skin.Guid, ref val) || val == null)
			{
				return null;
			}
			object member = GetMember(val, "Graffiti");
			if (member == null)
			{
				return null;
			}
			object member2 = GetMember(member, "graffitiMaterial");
			Material val2 = (Material)((member2 is Material) ? member2 : null);
			if (val2 != null && (Object)(object)val2.mainTexture != (Object)null)
			{
				return skin.Thumbnail = val2.mainTexture;
			}
			FieldInfo[] fields = member.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				object value = fieldInfo.GetValue(member);
				Texture val3 = (Texture)((value is Texture) ? value : null);
				if (val3 != null)
				{
					return skin.Thumbnail = val3;
				}
				Material val4 = (Material)((value is Material) ? value : null);
				if (val4 != null && (Object)(object)val4.mainTexture != (Object)null)
				{
					return skin.Thumbnail = val4.mainTexture;
				}
			}
		}
		catch (Exception ex)
		{
			Log.LogDebug((object)("No thumbnail for " + skin.DisplayName + ": " + ex.Message));
		}
		return null;
	}

	private static object GetMember(object obj, string name)
	{
		Type type = obj.GetType();
		PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (property != null)
		{
			return property.GetValue(obj);
		}
		return type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj);
	}

	private void Update()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		if (Input.GetKeyDown(_toggleKey.Value))
		{
			if (_open)
			{
				Close();
			}
			else
			{
				Open();
			}
		}
	}

	private void Open()
	{
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		if (!_listBuilt)
		{
			RefreshSkinList();
		}
		foreach (SkinEntry allSkin in _allSkins)
		{
			if ((Object)(object)allSkin.Thumbnail == (Object)null)
			{
				allSkin.ThumbnailTried = false;
			}
		}
		_open = true;
		_focusSearchField = true;
		_resultsDirty = true;
		_prevCursorVisible = Cursor.visible;
		_prevCursorLock = Cursor.lockState;
		Cursor.visible = true;
		Cursor.lockState = (CursorLockMode)0;
	}

	private void Close()
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		GUI.FocusControl((string)null);
		_open = false;
		Cursor.visible = _prevCursorVisible;
		Cursor.lockState = _prevCursorLock;
	}

	private void OnGUI()
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Expected O, but got Unknown
		//IL_004c: 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)
		if (_open)
		{
			InitStyles();
			HandleKeyboard(Event.current);
			UpdateResults();
			_windowRect = GUILayout.Window(23578, _windowRect, new WindowFunction(DrawWindow), "Skin Search", Array.Empty<GUILayoutOption>());
			ClampWindowToScreen();
		}
	}

	private void ClampWindowToScreen()
	{
		((Rect)(ref _windowRect)).width = Mathf.Min(((Rect)(ref _windowRect)).width, (float)Screen.width);
		((Rect)(ref _windowRect)).height = Mathf.Min(((Rect)(ref _windowRect)).height, (float)Screen.height);
		((Rect)(ref _windowRect)).x = Mathf.Clamp(((Rect)(ref _windowRect)).x, 0f, (float)Screen.width - ((Rect)(ref _windowRect)).width);
		((Rect)(ref _windowRect)).y = Mathf.Clamp(((Rect)(ref _windowRect)).y, 0f, (float)Screen.height - ((Rect)(ref _windowRect)).height);
	}

	private void InitStyles()
	{
		//IL_001e: 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_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Expected O, but got Unknown
		//IL_0058: 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_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: 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_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Expected O, but got Unknown
		if (_rowStyle == null)
		{
			_rowStyle = new GUIStyle(GUI.skin.button)
			{
				alignment = (TextAnchor)3,
				fixedHeight = 44f
			};
			_rowStyleSelected = new GUIStyle(_rowStyle);
			_rowStyleSelected.normal.textColor = Color.yellow;
			_rowStyleSelected.hover.textColor = Color.yellow;
			_starStyle = new GUIStyle(GUI.skin.button)
			{
				fontSize = 18,
				fixedHeight = 44f,
				fixedWidth = 32f
			};
		}
	}

	private void HandleKeyboard(Event e)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Invalid comparison between Unknown and I4
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Invalid comparison between Unknown and I4
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Invalid comparison between Unknown and I4
		//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)
		//IL_004f: Expected I4, but got Unknown
		if ((int)e.type != 4)
		{
			return;
		}
		KeyCode keyCode = e.keyCode;
		KeyCode val = keyCode;
		if ((int)val != 13)
		{
			if ((int)val == 27)
			{
				Close();
				e.Use();
				return;
			}
			switch (val - 271)
			{
			default:
				return;
			case 3:
				_selected = Math.Min(_selected + 1, _results.Count - 1);
				SetPage(_selected / _pageSize.Value);
				e.Use();
				return;
			case 2:
				_selected = Math.Max(_selected - 1, 0);
				SetPage(_selected / _pageSize.Value);
				e.Use();
				return;
			case 0:
				break;
			case 1:
				return;
			}
		}
		if (_selected >= 0 && _selected < _results.Count)
		{
			ApplySkin(_results[_selected]);
		}
		e.Use();
	}

	private void DrawWindow(int id)
	{
		//IL_01db: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_029b: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUI.SetNextControlName("SkinSearchField");
		_query = GUILayout.TextField(_query, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		if (GUILayout.Button("Refresh", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }))
		{
			RefreshSkinList();
		}
		if (GUILayout.Button("X", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(28f) }))
		{
			Close();
		}
		GUILayout.EndHorizontal();
		if (_focusSearchField)
		{
			GUI.FocusControl("SkinSearchField");
			_focusSearchField = false;
		}
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		string text = ((_sortConfig.Value == SortMode.Recent) ? "Sort: Recent" : "Sort: A-Z");
		if (GUILayout.Button(text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) }))
		{
			_sortConfig.Value = ((_sortConfig.Value != SortMode.Recent) ? SortMode.Recent : SortMode.Name);
			_resultsDirty = true;
			SetPage(0);
		}
		_showThumbnails.Value = GUILayout.Toggle(_showThumbnails.Value, " Thumbnails", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) });
		GUILayout.FlexibleSpace();
		GUILayout.Label($"{_results.Count} / {_allSkins.Count}   ★ {_favorites.Count}", Array.Empty<GUILayoutOption>());
		GUILayout.EndHorizontal();
		int num = _page * _pageSize.Value;
		int num2 = Math.Min(num + _pageSize.Value, _results.Count);
		_scroll = GUILayout.BeginScrollView(_scroll, Array.Empty<GUILayoutOption>());
		for (int i = num; i < num2; i++)
		{
			SkinEntry skinEntry = _results[i];
			bool flag = _favorites.Contains(skinEntry.Guid);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button(flag ? "★" : "☆", _starStyle, Array.Empty<GUILayoutOption>()))
			{
				ToggleFavorite(skinEntry);
			}
			if (_showThumbnails.Value)
			{
				Texture thumbnail = GetThumbnail(skinEntry);
				Rect rect = GUILayoutUtility.GetRect(44f, 44f, (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(44f),
					GUILayout.Height(44f)
				});
				if ((Object)(object)thumbnail != (Object)null)
				{
					GUI.DrawTexture(rect, thumbnail, (ScaleMode)2);
				}
				else
				{
					GUI.Box(rect, "?");
				}
			}
			string text2 = (skinEntry.IsReplacement ? ("   [replaces " + skinEntry.SlotName + "]") : "");
			string text3 = ((_recent.Count > 0 && _recent[0] == skinEntry.Guid) ? "  • current" : "");
			if (GUILayout.Button(skinEntry.DisplayName + text2 + text3, (i == _selected) ? _rowStyleSelected : _rowStyle, Array.Empty<GUILayoutOption>()))
			{
				_selected = i;
				ApplySkin(skinEntry);
			}
			GUILayout.EndHorizontal();
		}
		GUILayout.EndScrollView();
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUI.enabled = _page > 0;
		if (GUILayout.Button("<<", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) }))
		{
			SetPage(0);
		}
		if (GUILayout.Button("<", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) }))
		{
			SetPage(_page - 1);
		}
		GUI.enabled = true;
		GUILayout.FlexibleSpace();
		GUILayout.Label($"Page {_page + 1} / {PageCount}", Array.Empty<GUILayoutOption>());
		GUILayout.FlexibleSpace();
		GUI.enabled = _page < PageCount - 1;
		if (GUILayout.Button(">", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) }))
		{
			SetPage(_page + 1);
		}
		if (GUILayout.Button(">>", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) }))
		{
			SetPage(PageCount - 1);
		}
		GUI.enabled = true;
		GUILayout.EndHorizontal();
		GUI.DragWindow();
	}

	private void ApplySkin(SkinEntry skin)
	{
		try
		{
			ApplySkinInternal(skin);
		}
		catch (Exception arg)
		{
			Log.LogError((object)$"Failed to apply {skin.DisplayName} ({skin.Guid}): {arg}");
		}
	}

	private void ApplySkinInternal(SkinEntry skin)
	{
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: 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)
		WorldHandler instance = WorldHandler.instance;
		Player val = ((instance != null) ? instance.GetCurrentPlayer() : null);
		if ((Object)(object)val == (Object)null)
		{
			Log.LogWarning((object)"No player found - are you in a stage?");
		}
		else if (!skin.IsReplacement || SetReplacementOverride(skin.Slot, skin.Guid))
		{
			int savedOutfit = GetSavedOutfit(skin);
			val.SetCharacter(skin.Slot, savedOutfit);
			AddRecent(skin.Guid);
			if ((Object)(object)skin.Thumbnail == (Object)null)
			{
				skin.ThumbnailTried = false;
			}
			Log.LogInfo((object)$"Applied {skin.DisplayName} ({skin.Guid}) to slot {skin.Slot}, outfit {savedOutfit}");
		}
	}

	private static int GetSavedOutfit(SkinEntry skin)
	{
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		int num = 0;
		try
		{
			if (!skin.IsReplacement)
			{
				CharacterProgress val = default(CharacterProgress);
				if (CharacterSaveSlots.GetCharacterData(skin.Guid, ref val) && val != null)
				{
					num = val.outfit;
				}
			}
			else
			{
				Core instance = Core.Instance;
				object obj;
				if (instance == null)
				{
					obj = null;
				}
				else
				{
					SaveManager saveManager = instance.SaveManager;
					if (saveManager == null)
					{
						obj = null;
					}
					else
					{
						SaveSlotData currentSaveSlot = saveManager.CurrentSaveSlot;
						obj = ((currentSaveSlot != null) ? currentSaveSlot.GetCharacterProgress(skin.Slot) : null);
					}
				}
				CharacterProgress val2 = (CharacterProgress)obj;
				if (val2 != null)
				{
					num = val2.outfit;
				}
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Couldn't read saved outfit for " + skin.DisplayName + ": " + ex.Message));
		}
		return Mathf.Clamp(num, 0, 3);
	}

	private unsafe bool SetReplacementOverride(Characters slot, Guid guid)
	{
		//IL_008d: 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)
		if (_crewBoomConfig == null)
		{
			Assembly crewBoomAsm = typeof(CharacterDatabase).Assembly;
			PluginInfo val = ((IEnumerable<PluginInfo>)Chainloader.PluginInfos.Values).FirstOrDefault((Func<PluginInfo, bool>)((PluginInfo p) => (Object)(object)p.Instance != (Object)null && ((object)p.Instance).GetType().Assembly == crewBoomAsm));
			object crewBoomConfig;
			if (val == null)
			{
				crewBoomConfig = null;
			}
			else
			{
				BaseUnityPlugin instance = val.Instance;
				crewBoomConfig = ((instance != null) ? instance.Config : null);
			}
			_crewBoomConfig = (ConfigFile)crewBoomConfig;
		}
		if (_crewBoomConfig == null)
		{
			Log.LogWarning((object)"Couldn't find CrewBoom's config.");
			return false;
		}
		BrcCharacter val2 = (BrcCharacter)slot;
		string text = ((object)(*(BrcCharacter*)(&val2))/*cast due to .constrained prefix*/).ToString();
		ConfigEntry<string> val3 = default(ConfigEntry<string>);
		if (!_crewBoomConfig.TryGetEntry<string>("Replacement IDs", text, ref val3))
		{
			Log.LogWarning((object)("No CrewBoom 'Replacement IDs' entry for " + text + "."));
			return false;
		}
		val3.Value = guid.ToString();
		return true;
	}
}
public class SkinEntry
{
	public Guid Guid;

	public string FileName;

	public string DisplayName;

	public Characters Slot;

	public bool IsReplacement;

	public bool HiddenFromCypher;

	public Texture Thumbnail;

	public bool ThumbnailTried;

	public unsafe string SlotName
	{
		get
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			object result;
			if (!IsReplacement)
			{
				result = "";
			}
			else
			{
				BrcCharacter slot = (BrcCharacter)Slot;
				result = ((object)(*(BrcCharacter*)(&slot))/*cast due to .constrained prefix*/).ToString();
			}
			return (string)result;
		}
	}
}