using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace UCMSearch;
internal static class CnAliases
{
private const string PluginTypeName = "CN_AllInOne.AllInOnePatchPlugin";
private const string DataTypeName = "CN_AllInOne.TranslationData";
private const string FieldName = "Translations";
private const string MethodName = "GetTranslations";
private static bool _resolved;
private static bool _warned;
private static DateTime _nextAttempt = DateTime.MinValue;
private static Dictionary<string, string> _exact;
private static Dictionary<string, string> _normalized;
internal static int Count
{
get
{
if (_normalized != null)
{
return _normalized.Count;
}
return 0;
}
}
internal static void EnsureLoaded()
{
if (_resolved || DateTime.UtcNow < _nextAttempt)
{
return;
}
_nextAttempt = DateTime.UtcNow.AddSeconds(3.0);
try
{
IDictionary dictionary = ReadTable();
if (dictionary == null || dictionary.Count == 0)
{
if (!_warned)
{
_warned = true;
Plugin.LogInfo("[CN] no Chinese translation table yet - search stays English only for now");
}
return;
}
_exact = new Dictionary<string, string>(StringComparer.Ordinal);
_normalized = new Dictionary<string, string>(StringComparer.Ordinal);
foreach (DictionaryEntry item in dictionary)
{
string text = item.Key as string;
string value = item.Value as string;
if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(value))
{
if (!_exact.ContainsKey(text))
{
_exact[text] = value;
}
string text2 = Normalize(text);
if (text2.Length > 0 && !_normalized.ContainsKey(text2))
{
_normalized[text2] = value;
}
}
}
_resolved = true;
Plugin.LogInfo("[CN] Chinese aliases loaded: " + _normalized.Count + " keys (" + dictionary.Count + " raw entries)");
}
catch (Exception ex)
{
Plugin.LogWarn("[CN] could not read the Chinese translation table: " + ex.Message);
}
}
private static IDictionary ReadTable()
{
Type type = AccessTools.TypeByName("CN_AllInOne.AllInOnePatchPlugin");
if (type != null)
{
FieldInfo fieldInfo = AccessTools.Field(type, "Translations");
if (fieldInfo != null && fieldInfo.GetValue(null) is IDictionary { Count: >0 } dictionary)
{
return dictionary;
}
}
Type type2 = AccessTools.TypeByName("CN_AllInOne.TranslationData");
if (type2 != null)
{
MethodInfo methodInfo = AccessTools.Method(type2, "GetTranslations", (Type[])null, (Type[])null);
if (methodInfo != null)
{
return methodInfo.Invoke(null, null) as IDictionary;
}
}
return null;
}
private static string Normalize(string s)
{
if (string.IsNullOrEmpty(s))
{
return string.Empty;
}
StringBuilder stringBuilder = new StringBuilder(s.Length);
foreach (char c in s)
{
if (char.IsLetterOrDigit(c))
{
stringBuilder.Append(char.ToUpperInvariant(c));
}
}
return stringBuilder.ToString();
}
internal static string ChineseFor(string english)
{
EnsureLoaded();
if (string.IsNullOrEmpty(english))
{
return null;
}
if (_exact != null && _exact.TryGetValue(english, out var value))
{
return value;
}
if (_normalized != null && _normalized.TryGetValue(Normalize(english), out var value2))
{
return value2;
}
return null;
}
internal static string WithAliases(string haystack, params string[] candidates)
{
if (candidates == null || candidates.Length == 0)
{
return haystack;
}
EnsureLoaded();
if (_normalized == null && _exact == null)
{
return haystack;
}
for (int i = 0; i < candidates.Length; i++)
{
string text = ChineseFor(candidates[i]);
if (!string.IsNullOrEmpty(text))
{
haystack = haystack + " " + text.ToLowerInvariant();
}
}
return haystack;
}
}
[BepInPlugin("saucein.ucm.modelsearch", "UCM Model Search", "1.2.1")]
[BepInProcess("TotallyAccurateBattleSimulator.exe")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
public const string PluginGuid = "saucein.ucm.modelsearch";
public const string PluginName = "UCM Model Search";
public const string PluginVersion = "1.2.1";
internal static ManualLogSource Log;
internal static ConfigEntry<bool> CfgUcmDropdown;
internal static ConfigEntry<bool> CfgAutoApply;
internal static ConfigEntry<bool> CfgBilingual;
internal static ConfigEntry<float> CfgUcmBoxWidth;
internal static ConfigEntry<float> CfgUcmBoxHeight;
internal static ConfigEntry<float> CfgUcmBoxGap;
internal static ConfigEntry<bool> CfgVerbose;
private void Awake()
{
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0101: Unknown result type (might be due to invalid IL or missing references)
//IL_0107: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
CfgUcmDropdown = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SearchInUcmDropdown", true, "Add a search box above UCM's 'uc tools' window that filters the 'LOAD THE UC!' dropdown.");
CfgAutoApply = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoApplyWhenPicked", false, "When picking a model from the filtered UCM dropdown, immediately run UCM's 'update custom base' instead of waiting for you to click the toggle.");
CfgBilingual = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "BilingualSearch", true, "Also match models by their Chinese names taken from the CN_AllInOne Chinese localization patch (CN_All.dll). English names keep working either way; with the patch missing this option does nothing.");
CfgUcmBoxWidth = ((BaseUnityPlugin)this).Config.Bind<float>("General", "UcmSearchBoxWidth", 320f, "Width (in UI units) of the search box that sits above UCM's 'uc tools' window.");
CfgUcmBoxHeight = ((BaseUnityPlugin)this).Config.Bind<float>("General", "UcmSearchBoxHeight", 30f, "Height (in UI units) of that search box.");
CfgUcmBoxGap = ((BaseUnityPlugin)this).Config.Bind<float>("General", "UcmSearchBoxGap", 6f, "Gap (in UI units) between the search box and the top of UCM's 'uc tools' window.");
CfgVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "VerboseLogging", true, "Log extra information to the BepInEx console/log file (useful when reporting a problem).");
GameObject val = new GameObject("UCMSearch");
Object.DontDestroyOnLoad((Object)val);
val.AddComponent<UcmDropdownSearch>();
if (CfgBilingual.Value)
{
CnAliases.EnsureLoaded();
}
LogInfo("UCM Model Search 1.2.1 loaded. Waiting for the game UI.");
}
internal static void LogInfo(string message)
{
if (Log != null)
{
if (CfgVerbose != null && !CfgVerbose.Value)
{
Log.LogDebug((object)message);
}
else
{
Log.LogInfo((object)message);
}
}
}
internal static void LogWarn(string message)
{
if (Log != null)
{
Log.LogWarning((object)message);
}
}
}
internal abstract class SearchOverlay : MonoBehaviour
{
protected Rect BoxRect;
protected bool BoxValid;
protected bool Focused;
protected string Query = string.Empty;
private GUIStyle _style;
private GUIStyle _rightStyle;
private Texture2D _white;
private float _styleHeight = -1f;
private static readonly Color BoxColor = new Color(0.129f, 0.145f, 0.2f, 0.96f);
private static readonly Color BorderColor = new Color(0.239f, 0.263f, 0.333f, 1f);
private static readonly Color TextColor = new Color(0.98f, 0.98f, 0.98f, 1f);
private static readonly Color HintColor = new Color(0.72f, 0.74f, 0.8f, 1f);
private static readonly Color CaretColor = new Color(1f, 1f, 1f, 0.9f);
private static Font _guiFont;
private static bool _guiFontTried;
protected abstract string Hint { get; }
protected virtual string Status => string.Empty;
protected abstract bool ComputeBox(out Rect rect);
protected abstract void ApplyQuery(string query);
protected virtual void Commit()
{
}
protected void TickOverlay()
{
//IL_001f: 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)
BoxValid = ComputeBox(out var rect);
if (!BoxValid)
{
SetFocus(focused: false);
return;
}
BoxRect = rect;
HandleInput();
}
protected void DrawOverlay()
{
//IL_003c: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
//IL_0187: Unknown result type (might be due to invalid IL or missing references)
//IL_0191: 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_02a5: Unknown result type (might be due to invalid IL or missing references)
//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
//IL_0201: Expected O, but got Unknown
//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0259: Unknown result type (might be due to invalid IL or missing references)
//IL_026b: Unknown result type (might be due to invalid IL or missing references)
if (!BoxValid)
{
return;
}
try
{
EnsureResources();
GUI.depth = -10000;
float num = Mathf.Clamp(((Rect)(ref BoxRect)).height * 0.3f, 4f, 12f);
GUI.DrawTexture(BoxRect, (Texture)(object)_white, (ScaleMode)0, true, 0f, BorderColor, 0f, num);
GUI.DrawTexture(new Rect(((Rect)(ref BoxRect)).x + 1f, ((Rect)(ref BoxRect)).y + 1f, ((Rect)(ref BoxRect)).width - 2f, ((Rect)(ref BoxRect)).height - 2f), (Texture)(object)_white, (ScaleMode)0, true, 0f, BoxColor, 0f, Mathf.Max(2f, num - 1f));
float num2 = Mathf.Clamp(((Rect)(ref BoxRect)).height * 0.3f, 5f, 18f);
Rect val = default(Rect);
((Rect)(ref val))..ctor(((Rect)(ref BoxRect)).x + num2, ((Rect)(ref BoxRect)).y + 2f, ((Rect)(ref BoxRect)).width - num2 * 2f, ((Rect)(ref BoxRect)).height - 4f);
string text = string.Empty;
if (Focused)
{
try
{
text = Input.compositionString;
}
catch
{
text = string.Empty;
}
}
string text2 = Query + text;
if (text2.Length == 0 && !Focused)
{
_style.normal.textColor = HintColor;
GUI.Label(val, Hint, _style);
}
else
{
_style.normal.textColor = TextColor;
GUI.Label(val, text2, _style);
if (Focused && Mathf.PingPong(Time.unscaledTime, 1f) < 0.55f)
{
float x = _style.CalcSize(new GUIContent(text2)).x;
float num3 = Mathf.Min(((Rect)(ref val)).x + x + 1f, ((Rect)(ref BoxRect)).xMax - num2 - 2f);
GUI.DrawTexture(new Rect(num3, ((Rect)(ref BoxRect)).y + num2 * 0.5f, 2f, ((Rect)(ref BoxRect)).height - num2), (Texture)(object)_white, (ScaleMode)0, true, 0f, CaretColor, 0f, 1f);
}
}
string status = Status;
if (!string.IsNullOrEmpty(status))
{
_rightStyle.normal.textColor = HintColor;
GUI.Label(val, status, _rightStyle);
}
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("[search] could not draw the search box: " + ex.Message));
BoxValid = false;
}
}
protected string DisplayText()
{
string text = string.Empty;
if (Focused)
{
try
{
text = Input.compositionString;
}
catch
{
text = string.Empty;
}
}
if (Query.Length == 0 && text.Length == 0 && !Focused)
{
return Hint;
}
return Query + text;
}
private void HandleInput()
{
if (Input.GetMouseButtonDown(0))
{
SetFocus(ContainsMouse());
}
if (!Focused)
{
return;
}
bool flag = false;
string inputString = Input.inputString;
if (!string.IsNullOrEmpty(inputString))
{
for (int i = 0; i < inputString.Length; i++)
{
char c = inputString[i];
if (c == '\b' || c == '\u007f')
{
if (Query.Length > 0)
{
Query = Query.Substring(0, Query.Length - 1);
flag = true;
}
continue;
}
if (c == '\n' || c == '\r')
{
Commit();
SetFocus(focused: false);
return;
}
if (c == '\u001b')
{
Query = string.Empty;
SetFocus(focused: false);
ApplyQuery(Query);
return;
}
if (c >= ' ')
{
Query += c;
flag = true;
}
}
}
if (flag)
{
ApplyQuery(Query);
}
if (Input.GetKeyDown((KeyCode)27))
{
Query = string.Empty;
SetFocus(focused: false);
ApplyQuery(Query);
}
}
private bool ContainsMouse()
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: 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)
Vector2 val = Vector2.op_Implicit(Input.mousePosition);
return ((Rect)(ref BoxRect)).Contains(new Vector2(val.x, (float)Screen.height - val.y));
}
protected void SetFocus(bool focused)
{
if (Focused == focused)
{
return;
}
Focused = focused;
try
{
Input.imeCompositionMode = (IMECompositionMode)(focused ? 1 : 0);
}
catch
{
}
}
protected void ClearQuery()
{
Query = string.Empty;
SetFocus(focused: false);
ApplyQuery(Query);
}
private void EnsureResources()
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Expected O, but got Unknown
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Expected O, but got Unknown
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Expected O, but got Unknown
if ((Object)(object)_white == (Object)null)
{
_white = new Texture2D(1, 1);
_white.SetPixel(0, 0, Color.white);
_white.Apply();
((Object)_white).hideFlags = (HideFlags)61;
}
float height = ((Rect)(ref BoxRect)).height;
if (_style == null)
{
_style = new GUIStyle(GUI.skin.label);
_style.alignment = (TextAnchor)3;
_style.fontStyle = (FontStyle)1;
_style.richText = false;
_style.wordWrap = false;
_style.clipping = (TextClipping)1;
_rightStyle = new GUIStyle(_style);
_rightStyle.fontStyle = (FontStyle)1;
_rightStyle.alignment = (TextAnchor)5;
Font guiFont = GetGuiFont();
if ((Object)(object)guiFont != (Object)null)
{
_style.font = guiFont;
_rightStyle.font = guiFont;
}
}
if (!Mathf.Approximately(_styleHeight, height))
{
_styleHeight = height;
int fontSize = Mathf.RoundToInt(Mathf.Clamp(height * 0.45f, 10f, 26f));
_style.fontSize = fontSize;
_rightStyle.fontSize = fontSize;
}
}
private static Font GetGuiFont()
{
if (_guiFontTried)
{
return _guiFont;
}
_guiFontTried = true;
try
{
_guiFont = Font.CreateDynamicFontFromOSFont(new string[7] { "Microsoft YaHei UI", "Microsoft YaHei", "SimHei", "SimSun", "Arial Unicode MS", "Segoe UI", "Arial" }, 16);
Plugin.LogInfo("[search] overlay font: " + (((Object)(object)_guiFont != (Object)null) ? ((Object)_guiFont).name : "<built-in>"));
}
catch (Exception ex)
{
Plugin.LogWarn("[search] could not create an OS font, using the built-in one: " + ex.Message);
_guiFont = null;
}
return _guiFont;
}
protected static bool ScreenRectOf(RectTransform rt, Canvas canvas, out Rect rect, out float scale)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: 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_004e: 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_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: 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)
//IL_0070: 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_0083: 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_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: 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_00c4: 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_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_011b: 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)
rect = default(Rect);
scale = 1f;
if ((Object)(object)rt == (Object)null)
{
return false;
}
Camera val = null;
if ((Object)(object)canvas != (Object)null && (int)canvas.renderMode != 0)
{
val = canvas.worldCamera;
}
Vector3[] array = (Vector3[])(object)new Vector3[4];
rt.GetWorldCorners(array);
Vector2 val2 = RectTransformUtility.WorldToScreenPoint(val, array[0]);
Vector2 val3 = RectTransformUtility.WorldToScreenPoint(val, array[2]);
float num = Mathf.Min(val2.x, val3.x);
float num2 = Mathf.Max(val2.x, val3.x);
float num3 = Mathf.Min(val2.y, val3.y);
float num4 = Mathf.Max(val2.y, val3.y);
if (num2 - num < 2f || num4 - num3 < 2f)
{
return false;
}
Rect rect2 = rt.rect;
float num5;
if (!(((Rect)(ref rect2)).width > 1f))
{
num5 = num2 - num;
}
else
{
rect2 = rt.rect;
num5 = ((Rect)(ref rect2)).width;
}
float num6 = num5;
scale = (num2 - num) / Mathf.Max(1f, num6);
rect = new Rect(num, (float)Screen.height - num4, num2 - num, num4 - num3);
return true;
}
protected static float ScaleOf(RectTransform rt)
{
if (!ScreenRectOf(rt, null, out var _, out var scale))
{
return 1f;
}
return scale;
}
}
internal class UcmDropdownSearch : SearchOverlay
{
private const string NoMatchText = "-- no match --";
private const float ScanInterval = 0.5f;
private Transform _ucmRoot;
private Dropdown _dropdown;
private Canvas _canvas;
private readonly List<string> _master = new List<string>();
private readonly List<string> _lastApplied = new List<string>();
private readonly List<string> _scratch = new List<string>();
private readonly List<string> _filtered = new List<string>();
private string _appliedQuery;
private int _lastSyncedValue = -1;
private float _nextScan;
private Vector2 _lastLoggedSize;
private static Type _mainType;
private static FieldInfo _customBaseField;
private static FieldInfo _instanceField;
private static MethodInfo _buttonsMethod;
private static bool _reflectionResolved;
protected override string Hint => "Search Base";
protected override string Status
{
get
{
int num = 0;
for (int i = 0; i < _filtered.Count; i++)
{
if (_filtered[i] != "-- no match --")
{
num++;
}
}
if (_master.Count <= 0)
{
return string.Empty;
}
return num + "/" + _master.Count;
}
}
private void Update()
{
try
{
if (!Plugin.CfgUcmDropdown.Value)
{
return;
}
if ((Object)(object)_dropdown == (Object)null)
{
if (Time.unscaledTime < _nextScan)
{
return;
}
_nextScan = Time.unscaledTime + 0.5f;
EnsureUi();
if ((Object)(object)_dropdown == (Object)null)
{
return;
}
}
TickOverlay();
if (BoxValid)
{
SyncOptions();
}
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("[UCM search] " + ex));
}
}
private void OnGUI()
{
if (Plugin.CfgUcmDropdown.Value)
{
DrawOverlay();
}
}
private void EnsureUi()
{
if ((Object)(object)_ucmRoot == (Object)null)
{
GameObject val = GameObject.Find("UCMUI(Clone)");
if ((Object)(object)val == (Object)null)
{
return;
}
_ucmRoot = val.transform;
Plugin.LogInfo("[UCM] UCM UI found");
}
if (!((Object)(object)_dropdown == (Object)null))
{
return;
}
Transform val2 = UiFactory.FindDeep(_ucmRoot, "custombasedropdown");
if (!((Object)(object)val2 == (Object)null))
{
_dropdown = ((Component)val2).GetComponent<Dropdown>();
if (!((Object)(object)_dropdown == (Object)null))
{
_canvas = ((Component)_dropdown).GetComponentInParent<Canvas>();
Plugin.LogInfo("[UCM] custom base dropdown located");
}
}
}
protected override bool ComputeBox(out Rect rect)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: 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_011c: 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_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_013d: Unknown result type (might be due to invalid IL or missing references)
rect = default(Rect);
if ((Object)(object)_dropdown == (Object)null)
{
return false;
}
Transform parent = ((Component)_dropdown).transform.parent;
RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy)
{
return false;
}
if (!SearchOverlay.ScreenRectOf(val, _canvas, out var rect2, out var scale))
{
return false;
}
float num = Mathf.Clamp(Plugin.CfgUcmBoxWidth.Value * scale, 160f, Mathf.Max(160f, ((Rect)(ref rect2)).width));
float num2 = Mathf.Max(22f, Plugin.CfgUcmBoxHeight.Value * scale);
float num3 = Mathf.Max(2f, Plugin.CfgUcmBoxGap.Value * scale);
float num4 = Mathf.Clamp(((Rect)(ref rect2)).center.x - num * 0.5f, 0f, Mathf.Max(0f, (float)Screen.width - num));
float num5 = Mathf.Clamp(((Rect)(ref rect2)).y - num3 - num2, 0f, Mathf.Max(0f, (float)Screen.height - num2));
rect = new Rect(num4, num5, num, num2);
Vector2 val2 = default(Vector2);
((Vector2)(ref val2))..ctor(num, num2);
if (val2 != _lastLoggedSize)
{
_lastLoggedSize = val2;
Plugin.LogInfo($"[UCM] search box above the window at ({num4:F0},{num5:F0}) size {num:F0}x{num2:F0} px (scale {scale:F2})");
}
return true;
}
protected override void ApplyQuery(string query)
{
Apply(query);
}
protected override void Commit()
{
string text = null;
for (int i = 0; i < _filtered.Count; i++)
{
if (!(_filtered[i] == "-- no match --"))
{
text = _filtered[i];
break;
}
}
if (text != null)
{
SetCustomBase(text);
if (Plugin.CfgAutoApply.Value)
{
InvokeUpdateCustomBase();
}
}
}
private void SyncOptions()
{
List<string> list = Snapshot(_dropdown, _scratch);
if (!SameList(list, _lastApplied))
{
_master.Clear();
_master.AddRange(list);
_appliedQuery = null;
Plugin.LogInfo("[UCM] custom base dropdown has " + _master.Count + " entries");
}
if (_appliedQuery != Query)
{
Apply(Query);
}
else if (_dropdown.value != _lastSyncedValue)
{
_lastSyncedValue = _dropdown.value;
string text = SelectedText();
if (Plugin.CfgAutoApply.Value && !string.IsNullOrEmpty(text) && text != "-- no match --")
{
SetCustomBase(text);
InvokeUpdateCustomBase();
}
}
}
private void Apply(string query)
{
_appliedQuery = query;
if ((Object)(object)_dropdown == (Object)null || _master.Count == 0)
{
return;
}
List<string> list = UiFactory.SplitQuery(query);
_filtered.Clear();
if (list.Count == 0)
{
_filtered.AddRange(_master);
}
else
{
for (int i = 0; i < _master.Count; i++)
{
if (!(_master[i] == "-- no match --"))
{
string haystack = _master[i].ToLowerInvariant();
if (Plugin.CfgBilingual.Value)
{
haystack = CnAliases.WithAliases(haystack, _master[i]);
}
if (UiFactory.Matches(list, haystack))
{
_filtered.Add(_master[i]);
}
}
}
}
if (_filtered.Count == 0)
{
_filtered.Add("-- no match --");
}
string text = SelectedText();
_dropdown.ClearOptions();
_dropdown.AddOptions(_filtered);
int num = ((text != null) ? _filtered.IndexOf(text) : (-1));
if (num < 0)
{
num = 0;
}
_dropdown.value = num;
_dropdown.RefreshShownValue();
_lastSyncedValue = num;
SetCustomBase(_filtered[num]);
_lastApplied.Clear();
_lastApplied.AddRange(_filtered);
Plugin.LogInfo("[UCM] filter '" + query + "' -> " + ((_filtered.Count != 1 || !(_filtered[0] == "-- no match --")) ? _filtered.Count : 0) + " option(s)");
}
private string SelectedText()
{
if ((Object)(object)_dropdown == (Object)null)
{
return null;
}
List<OptionData> options = _dropdown.options;
int value = _dropdown.value;
if (options == null || value < 0 || value >= options.Count)
{
return null;
}
return options[value].text;
}
private static List<string> Snapshot(Dropdown dropdown, List<string> into)
{
into.Clear();
if ((Object)(object)dropdown == (Object)null || dropdown.options == null)
{
return into;
}
for (int i = 0; i < dropdown.options.Count; i++)
{
into.Add(dropdown.options[i].text);
}
return into;
}
private static bool SameList(List<string> a, List<string> b)
{
if (a.Count != b.Count)
{
return false;
}
for (int i = 0; i < a.Count; i++)
{
if (!string.Equals(a[i], b[i], StringComparison.Ordinal))
{
return false;
}
}
return true;
}
private static void ResolveReflection()
{
if (_reflectionResolved)
{
return;
}
_reflectionResolved = true;
try
{
_mainType = AccessTools.TypeByName("UCU.Main");
if (_mainType == null)
{
Plugin.LogWarn("[UCM] type UCU.Main not found - base sync disabled");
return;
}
_customBaseField = AccessTools.Field(_mainType, "custombase");
_instanceField = AccessTools.Field(_mainType, "instance");
_buttonsMethod = AccessTools.Method(_mainType, "Buttons", new Type[1] { typeof(string) }, (Type[])null);
}
catch (Exception ex)
{
Plugin.LogWarn("[UCM] reflection setup failed: " + ex.Message);
}
}
private static void SetCustomBase(string modelName)
{
ResolveReflection();
if (_customBaseField == null)
{
return;
}
try
{
_customBaseField.SetValue(null, modelName);
}
catch (Exception ex)
{
Plugin.LogWarn("[UCM] could not set custombase: " + ex.Message);
}
}
private static void InvokeUpdateCustomBase()
{
ResolveReflection();
if (_buttonsMethod == null || _instanceField == null)
{
return;
}
try
{
object value = _instanceField.GetValue(null);
if (value != null)
{
_buttonsMethod.Invoke(value, new object[1] { "UpdateCustom" });
Plugin.LogInfo("[UCM] applied the picked model");
}
}
catch (Exception ex)
{
Plugin.LogWarn("[UCM] could not apply the picked model: " + ex.Message);
}
}
}
internal static class UiFactory
{
internal static Transform FindDeep(Transform root, string name)
{
if ((Object)(object)root == (Object)null)
{
return null;
}
if (((Object)root).name == name)
{
return root;
}
for (int i = 0; i < root.childCount; i++)
{
Transform val = FindDeep(root.GetChild(i), name);
if ((Object)(object)val != (Object)null)
{
return val;
}
}
return null;
}
internal static List<Transform> FindAllDeep(Transform root, string name)
{
List<Transform> result = new List<Transform>();
FindAllDeep(root, name, result);
return result;
}
private static void FindAllDeep(Transform root, string name, List<Transform> result)
{
if (!((Object)(object)root == (Object)null))
{
if (((Object)root).name == name)
{
result.Add(root);
}
for (int i = 0; i < root.childCount; i++)
{
FindAllDeep(root.GetChild(i), name, result);
}
}
}
internal static bool IsSceneObject(GameObject go)
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)go == (Object)null)
{
return false;
}
try
{
Scene scene = go.scene;
return ((Scene)(ref scene)).IsValid();
}
catch
{
return false;
}
}
internal static List<string> SplitQuery(string query)
{
List<string> list = new List<string>();
if (string.IsNullOrEmpty(query))
{
return list;
}
string[] array = query.ToLowerInvariant().Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < array.Length; i++)
{
if (array[i].Length > 0)
{
list.Add(array[i]);
}
}
return list;
}
internal static bool Matches(List<string> tokens, string haystack)
{
if (tokens.Count == 0)
{
return true;
}
if (string.IsNullOrEmpty(haystack))
{
return false;
}
for (int i = 0; i < tokens.Count; i++)
{
if (haystack.IndexOf(tokens[i], StringComparison.Ordinal) < 0)
{
return false;
}
}
return true;
}
}