using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using DM;
using HarmonyLib;
using Landfall.TABS;
using Landfall.TABS.Workshop;
using LevelCreator;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
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 FactionUnitSort;
internal enum ContentKind
{
Units,
Factions,
Battles,
Campaigns,
Maps
}
internal static class ContentSort
{
private static readonly Dictionary<Type, MethodInfo> WriteTimeCache = new Dictionary<Type, MethodInfo>();
private static readonly Dictionary<Type, PropertyInfo> FilePathCache = new Dictionary<Type, PropertyInfo>();
private static readonly Dictionary<Type, MethodInfo> CostCache = new Dictionary<Type, MethodInfo>();
internal static IEnumerable<T> Apply<T>(IEnumerable<T> source, ContentKind kind) where T : class
{
if (source == null)
{
return null;
}
Plugin.ContentSortMode value = Plugin.ConfigFor(kind).Value;
if (value == Plugin.ContentSortMode.Default)
{
return source;
}
List<T> list = source.ToList();
if (list.Count < 2)
{
return list;
}
switch (value)
{
case Plugin.ContentSortMode.TimeNewest:
list = list.OrderByDescending((T item) => TimeOf(item)).ThenBy(NameOf).ToList();
break;
case Plugin.ContentSortMode.TimeOldest:
list = list.OrderBy((T item) => TimeOf(item)).ThenBy(NameOf).ToList();
break;
case Plugin.ContentSortMode.CostHigh:
list = list.OrderByDescending((T item) => CostOf(item)).ThenBy(NameOf).ToList();
break;
case Plugin.ContentSortMode.CostLow:
list = list.OrderBy((T item) => CostOf(item)).ThenBy(NameOf).ToList();
break;
}
Plugin.LogInfo("[ContentSort] " + kind.ToString() + ": " + value.ToString() + ", sorted " + list.Count + " item(s)");
return list;
}
internal static DateTime TimeOf(object item)
{
if (item == null)
{
return DateTime.MinValue;
}
Type type = item.GetType();
if (!WriteTimeCache.TryGetValue(type, out var value))
{
value = type.GetMethod("GetWriteTime", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);
WriteTimeCache[type] = value;
}
if (value != null && value.ReturnType == typeof(DateTime))
{
try
{
return (DateTime)value.Invoke(item, null);
}
catch
{
}
}
if (!FilePathCache.TryGetValue(type, out var value2))
{
value2 = type.GetProperty("FilePath", BindingFlags.Instance | BindingFlags.Public);
FilePathCache[type] = value2;
}
if (value2 != null)
{
try
{
string text = value2.GetValue(item, null) as string;
if (!string.IsNullOrEmpty(text) && File.Exists(text))
{
return File.GetLastWriteTimeUtc(text);
}
}
catch
{
}
}
return DateTime.MinValue;
}
internal static string NameOf(object item)
{
if (item == null)
{
return string.Empty;
}
try
{
object obj = Member(item, "Entity");
if (obj != null)
{
object obj2 = Member(obj, "Name");
if (obj2 is string)
{
return (string)obj2;
}
}
object obj3 = Member(item, "Name");
if (obj3 is string)
{
return (string)obj3;
}
}
catch
{
}
return string.Empty;
}
internal static uint CostOf(object item)
{
if (item == null)
{
return 0u;
}
UnitBlueprint val = (UnitBlueprint)((item is UnitBlueprint) ? item : null);
if ((Object)(object)val != (Object)null)
{
try
{
return val.GetUnitCost(true);
}
catch
{
return 0u;
}
}
Faction val2 = (Faction)((item is Faction) ? item : null);
if ((Object)(object)val2 != (Object)null)
{
uint num = 0u;
try
{
UnitBlueprint[] units = val2.Units;
if (units != null)
{
for (int i = 0; i < units.Length; i++)
{
if ((Object)(object)units[i] != (Object)null)
{
num += CostOf(units[i]);
}
}
}
}
catch
{
}
return num;
}
Type type = item.GetType();
if (!CostCache.TryGetValue(type, out var value))
{
MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public);
for (int j = 0; j < methods.Length; j++)
{
if (!(methods[j].Name != "GetUnitCost") && methods[j].GetParameters().Length <= 1)
{
value = methods[j];
break;
}
}
CostCache[type] = value;
}
if (value != null)
{
try
{
object[] parameters = ((value.GetParameters().Length == 0) ? null : new object[1] { true });
object obj3 = value.Invoke(item, parameters);
if (obj3 != null)
{
return Convert.ToUInt32(obj3);
}
}
catch
{
}
}
try
{
if (Member(item, "Units") is Array array)
{
uint num2 = 0u;
for (int k = 0; k < array.Length; k++)
{
num2 += CostOf(array.GetValue(k));
}
return num2;
}
}
catch
{
}
return 0u;
}
private static object Member(object target, string name)
{
if (target == null)
{
return null;
}
Type type = target.GetType();
PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public);
if (property != null)
{
return property.GetValue(target, null);
}
FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public);
if (!(field != null))
{
return null;
}
return field.GetValue(target);
}
}
[HarmonyPatch(typeof(ContentDatabase), "GetUserUnitBlueprintsByNamePartAndType")]
internal static class UnitListSortPatch
{
[HarmonyPostfix]
internal static void Postfix(ref IEnumerable<UnitBlueprint> __result)
{
if (!Plugin.CfgEnabled.Value)
{
return;
}
try
{
__result = ContentSort.Apply(__result, ContentKind.Units);
}
catch (Exception ex)
{
Plugin.LogWarn("[ContentSort] units: " + ex.Message);
}
}
}
[HarmonyPatch(typeof(ContentDatabase), "GetUserFactionsByNamePartAndType")]
internal static class FactionListSortPatch
{
[HarmonyPostfix]
internal static void Postfix(ref IEnumerable<Faction> __result)
{
if (!Plugin.CfgEnabled.Value)
{
return;
}
try
{
__result = ContentSort.Apply(__result, ContentKind.Factions);
}
catch (Exception ex)
{
Plugin.LogWarn("[ContentSort] factions: " + ex.Message);
}
}
}
[HarmonyPatch(typeof(ContentDatabase), "GetUserCampaignLevelsByFilter")]
internal static class BattleListSortPatch
{
[HarmonyPostfix]
internal static void Postfix(ref IEnumerable<TABSCampaignLevelAsset> __result)
{
if (!Plugin.CfgEnabled.Value)
{
return;
}
try
{
__result = ContentSort.Apply(__result, ContentKind.Battles);
}
catch (Exception ex)
{
Plugin.LogWarn("[ContentSort] battles: " + ex.Message);
}
}
}
[HarmonyPatch(typeof(ContentDatabase), "GetUserCampaignsByFilter")]
internal static class CampaignListSortPatch
{
[HarmonyPostfix]
internal static void Postfix(ref IEnumerable<TABSCampaignAsset> __result)
{
if (!Plugin.CfgEnabled.Value)
{
return;
}
try
{
__result = ContentSort.Apply(__result, ContentKind.Campaigns);
}
catch (Exception ex)
{
Plugin.LogWarn("[ContentSort] campaigns: " + ex.Message);
}
}
}
[HarmonyPatch(typeof(ContentDatabase), "GetUserMapsByFilter")]
internal static class MapListSortPatch
{
[HarmonyPostfix]
internal static void Postfix(ref IEnumerable<CustomMap> __result)
{
if (!Plugin.CfgEnabled.Value)
{
return;
}
try
{
__result = ContentSort.Apply(__result, ContentKind.Maps);
}
catch (Exception ex)
{
Plugin.LogWarn("[ContentSort] maps: " + ex.Message);
}
}
}
internal class FactionUnitEditor : MonoBehaviour
{
private const string ButtonName = "FactionUnitSortCostButton";
private FactionCreatorManager _manager;
private GameObject _button;
private float _nextScan;
private bool _warnedNoSource;
private bool _warnedNoManager;
private Image _swatch;
private static string ButtonLabel => Plugin.CfgSortLabel.Value;
private void Update()
{
if (!Plugin.CfgEnabled.Value || !Plugin.CfgSortButton.Value || Time.unscaledTime < _nextScan)
{
return;
}
_nextScan = Time.unscaledTime + 0.5f;
try
{
Scan();
}
catch (Exception ex)
{
Plugin.LogWarn("[FactionSort] " + ex.Message);
}
}
private void Scan()
{
if (!FactionUnits.Available)
{
if (!_warnedNoManager)
{
_warnedNoManager = true;
Plugin.LogWarn("[FactionSort] the faction editor's unit list could not be reflected - sorting and dragging are disabled");
}
return;
}
if ((Object)(object)_manager == (Object)null)
{
_manager = Object.FindObjectOfType<FactionCreatorManager>();
}
if ((Object)(object)_manager == (Object)null)
{
return;
}
bool flag;
try
{
flag = _manager.isOpen;
}
catch
{
flag = false;
}
if ((Object)(object)_button != (Object)null && (!flag || !_button.activeInHierarchy))
{
Object.Destroy((Object)(object)_button);
_button = null;
}
if (flag)
{
if ((Object)(object)_button == (Object)null)
{
CreateButton();
return;
}
SetLabel(_button, ButtonLabel);
UpdateSwatch();
}
}
private static void MatchSize(RectTransform target, RectTransform source)
{
//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_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)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//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)
//IL_0055: 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_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: 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)
try
{
Rect rect = source.rect;
Vector2 size = ((Rect)(ref rect)).size;
if (!(size.x < 1f) && !(size.y < 1f))
{
Transform parent = ((Transform)target).parent;
RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
Vector2 val2;
if (!((Object)(object)val != (Object)null))
{
val2 = Vector2.zero;
}
else
{
rect = val.rect;
val2 = ((Rect)(ref rect)).size;
}
Vector2 val3 = val2;
Vector2 sizeDelta = size;
if (target.anchorMax.x - target.anchorMin.x > 0.001f)
{
sizeDelta.x = size.x - val3.x;
}
if (target.anchorMax.y - target.anchorMin.y > 0.001f)
{
sizeDelta.y = size.y - val3.y;
}
target.sizeDelta = sizeDelta;
}
}
catch
{
}
}
private static bool ExceedsScreen(RectTransform rect)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
try
{
Vector3[] array = (Vector3[])(object)new Vector3[4];
rect.GetWorldCorners(array);
Canvas componentInParent = ((Component)rect).GetComponentInParent<Canvas>();
Camera val = (((Object)(object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0) ? componentInParent.worldCamera : null);
float num = float.MinValue;
for (int i = 0; i < array.Length; i++)
{
num = Mathf.Max(num, RectTransformUtility.WorldToScreenPoint(val, array[i]).x);
}
return num > (float)Screen.width - 4f;
}
catch
{
return false;
}
}
private static Image FindSwatch(GameObject button, RectTransform rect)
{
//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_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)button == (Object)null || (Object)(object)rect == (Object)null)
{
return null;
}
Image result = null;
float num = float.MaxValue;
Image[] componentsInChildren = button.GetComponentsInChildren<Image>(true);
foreach (Image val in componentsInChildren)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
Transform transform = ((Component)val).transform;
RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
if ((Object)(object)val2 == (Object)null)
{
continue;
}
Rect rect2 = val2.rect;
float num2 = Mathf.Max(((Rect)(ref rect2)).width, ((Rect)(ref rect2)).height);
Rect rect3 = rect.rect;
float width = ((Rect)(ref rect3)).width;
rect3 = rect.rect;
float num3 = Mathf.Max(width, ((Rect)(ref rect3)).height);
if (!(num2 <= 1f) && !(num2 > num3 * 0.45f))
{
float num4 = ((Rect)(ref rect2)).width * ((Rect)(ref rect2)).height;
if (num4 < num)
{
num = num4;
result = val;
}
}
}
return result;
}
private void UpdateSwatch()
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_swatch == (Object)null || (Object)(object)_manager == (Object)null)
{
return;
}
try
{
((Graphic)_swatch).color = _manager.GetFactionColor();
}
catch
{
}
}
private void CreateButton()
{
//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
//IL_01e7: Expected O, but got Unknown
//IL_00bb: 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_00d3: 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_00eb: 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)
//IL_0138: Unknown result type (might be due to invalid IL or missing references)
//IL_0150: 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)
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_016c: Unknown result type (might be due to invalid IL or missing references)
//IL_0171: Unknown result type (might be due to invalid IL or missing references)
//IL_0185: Unknown result type (might be due to invalid IL or missing references)
//IL_018b: Unknown result type (might be due to invalid IL or missing references)
//IL_0190: Unknown result type (might be due to invalid IL or missing references)
//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
Button val = FindSourceButton();
if ((Object)(object)val == (Object)null)
{
if (!_warnedNoSource)
{
_warnedNoSource = true;
Plugin.LogWarn("[FactionSort] no game button to clone was found - the COST button is skipped");
}
return;
}
_button = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)val).transform.parent);
((Object)_button).name = "FactionUnitSortCostButton";
_button.SetActive(true);
try
{
_button.transform.SetSiblingIndex(((Component)val).transform.GetSiblingIndex() + 1);
}
catch
{
}
Transform transform = ((Component)val).transform;
RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
Transform transform2 = _button.transform;
RectTransform val3 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null);
if ((Object)(object)val2 != (Object)null && (Object)(object)val3 != (Object)null)
{
val3.anchorMin = val2.anchorMin;
val3.anchorMax = val2.anchorMax;
val3.pivot = val2.pivot;
val3.sizeDelta = val2.sizeDelta;
((Transform)val3).localScale = ((Transform)val2).localScale;
MatchSize(val3, val2);
if (!((Object)(object)((Component)val).transform.parent != (Object)null) || !((Object)(object)((Component)((Component)val).transform.parent).GetComponent<LayoutGroup>() != (Object)null))
{
Rect rect = val2.rect;
float num = Mathf.Max(8f, ((Rect)(ref rect)).width * 0.06f);
Vector2 anchoredPosition = val2.anchoredPosition;
rect = val2.rect;
val3.anchoredPosition = anchoredPosition + new Vector2(((Rect)(ref rect)).width + num, 0f);
if (ExceedsScreen(val3))
{
Vector2 anchoredPosition2 = val2.anchoredPosition;
rect = val2.rect;
val3.anchoredPosition = anchoredPosition2 - new Vector2(((Rect)(ref rect)).width + num, 0f);
}
}
}
Button component = _button.GetComponent<Button>();
if ((Object)(object)component != (Object)null)
{
((UnityEventBase)component.onClick).RemoveAllListeners();
((UnityEvent)component.onClick).AddListener(new UnityAction(OnSortClicked));
}
_swatch = FindSwatch(_button, val3);
SetLabel(_button, ButtonLabel);
UpdateSwatch();
Plugin.LogInfo("[FactionSort] added the COST button (cloned from '" + Path(((Component)val).transform) + "')");
}
private void OnSortClicked()
{
if (!((Object)(object)_manager == (Object)null))
{
int num = ((FactionUnits.List(_manager) != null) ? FactionUnits.List(_manager).Count : 0);
bool flag = FactionUnits.SortByCost(_manager, Plugin.CfgSortDescending.Value);
Plugin.LogInfo("[FactionSort] sorted " + num + " unit(s) by cost (" + (Plugin.CfgSortDescending.Value ? "expensive first" : "cheapest first") + ")" + (flag ? string.Empty : " - the order was already correct"));
}
}
private Button FindSourceButton()
{
//IL_0122: Unknown result type (might be due to invalid IL or missing references)
//IL_0127: Unknown result type (might be due to invalid IL or missing references)
//IL_0139: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
Button[] componentsInChildren = ((Component)((Component)_manager).transform.root).GetComponentsInChildren<Button>(true);
Button val = null;
Button val2 = null;
Button val3 = null;
foreach (Button val4 in componentsInChildren)
{
if (!((Object)(object)val4 == (Object)null) && !(((Object)((Component)val4).gameObject).name == "FactionUnitSortCostButton"))
{
if ((Object)(object)val == (Object)null && CallsColorPage(val4))
{
val = val4;
}
string text = ((Object)((Component)val4).gameObject).name.ToLowerInvariant();
if ((Object)(object)val2 == (Object)null && text.Contains("color"))
{
val2 = val4;
}
if ((Object)(object)val3 == (Object)null && LabelContains(val4, "color"))
{
val3 = val4;
}
}
}
Button val5 = val ?? val2 ?? val3;
if ((Object)(object)val5 != (Object)null)
{
return val5;
}
foreach (Button val6 in componentsInChildren)
{
if ((Object)(object)val6 == (Object)null || ((Object)((Component)val6).gameObject).name == "FactionUnitSortCostButton")
{
continue;
}
Transform transform = ((Component)val6).transform;
RectTransform val7 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
if ((Object)(object)val7 == (Object)null)
{
continue;
}
Rect rect = val7.rect;
if (!(((Rect)(ref rect)).height < 20f))
{
rect = val7.rect;
if (!(((Rect)(ref rect)).height > 90f) && (!((Object)(object)((Transform)val7).parent != (Object)null) || !((Object)(object)((Component)((Transform)val7).parent).GetComponent<LayoutGroup>() != (Object)null)) && (Object)(object)LabelOf(val6) != (Object)null)
{
return val6;
}
}
}
return null;
}
private bool CallsColorPage(Button button)
{
try
{
int persistentEventCount = ((UnityEventBase)button.onClick).GetPersistentEventCount();
for (int i = 0; i < persistentEventCount; i++)
{
string persistentMethodName = ((UnityEventBase)button.onClick).GetPersistentMethodName(i);
if (persistentMethodName != null && persistentMethodName.ToLowerInvariant().Contains("color"))
{
return true;
}
}
}
catch
{
}
return false;
}
private bool LabelContains(Button button, string text)
{
Component val = LabelOf(button);
if ((Object)(object)val == (Object)null)
{
return false;
}
return LabelText(val)?.ToLowerInvariant().Contains(text) ?? false;
}
private static Component LabelOf(Button button)
{
if ((Object)(object)button == (Object)null)
{
return null;
}
Component[] componentsInChildren = ((Component)button).GetComponentsInChildren<Component>(true);
foreach (Component val in componentsInChildren)
{
if (!((Object)(object)val == (Object)null) && (((object)val).GetType().Name == "TextMeshProUGUI" || ((object)val).GetType().Name == "Text"))
{
return val;
}
}
return null;
}
private static string LabelText(Component label)
{
if ((Object)(object)label == (Object)null)
{
return null;
}
try
{
PropertyInfo property = ((object)label).GetType().GetProperty("text");
return (property != null) ? (property.GetValue(label, null) as string) : null;
}
catch
{
return null;
}
}
private static void SetLabel(GameObject target, string text)
{
if ((Object)(object)target == (Object)null)
{
return;
}
Component[] componentsInChildren = target.GetComponentsInChildren<Component>(true);
foreach (Component val in componentsInChildren)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
string name = ((object)val).GetType().Name;
if (name != "TextMeshProUGUI" && name != "Text")
{
continue;
}
try
{
PropertyInfo property = ((object)val).GetType().GetProperty("text");
if (!(property == null) && property.CanWrite && property.GetValue(val, null) as string != text)
{
property.SetValue(val, text, null);
}
}
catch
{
}
}
}
private static string Path(Transform t)
{
if ((Object)(object)t == (Object)null)
{
return "<null>";
}
string text = ((Object)t).name;
Transform parent = t.parent;
int num = 0;
while ((Object)(object)parent != (Object)null && num++ < 6)
{
text = ((Object)parent).name + "/" + text;
parent = parent.parent;
}
return text;
}
}
internal static class FactionUnits
{
private static readonly FieldInfo AddedUnitsField;
private static readonly FieldInfo UnitField;
private static readonly FieldInfo ButtonField;
internal static bool Available
{
get
{
if (AddedUnitsField != null && UnitField != null)
{
return ButtonField != null;
}
return false;
}
}
static FactionUnits()
{
AddedUnitsField = AccessTools.Field(typeof(FactionCreatorManager), "addedUnits");
try
{
if (!(AddedUnitsField == null))
{
Type fieldType = AddedUnitsField.FieldType;
if (fieldType.IsGenericType)
{
Type obj = fieldType.GetGenericArguments()[0];
UnitField = obj.GetField("unit", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
ButtonField = obj.GetField("spawnedButton", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
}
}
catch (Exception ex)
{
Plugin.LogWarn("[FactionSort] could not reflect the unit list: " + ex.Message);
}
}
internal static IList List(FactionCreatorManager manager)
{
if ((Object)(object)manager == (Object)null || AddedUnitsField == null)
{
return null;
}
try
{
return AddedUnitsField.GetValue(manager) as IList;
}
catch
{
return null;
}
}
internal static UnitBlueprint UnitOf(object wrapper)
{
if (wrapper == null || UnitField == null)
{
return null;
}
try
{
object? value = UnitField.GetValue(wrapper);
return (UnitBlueprint)((value is UnitBlueprint) ? value : null);
}
catch
{
return null;
}
}
internal static UnitButtonBase ButtonOf(object wrapper)
{
if (wrapper == null || ButtonField == null)
{
return null;
}
try
{
object? value = ButtonField.GetValue(wrapper);
return (UnitButtonBase)((value is UnitButtonBase) ? value : null);
}
catch
{
return null;
}
}
internal static int IndexOfUnit(FactionCreatorManager manager, UnitBlueprint unit)
{
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
IList list = List(manager);
if (list == null || (Object)(object)unit == (Object)null || unit.Entity == null)
{
return -1;
}
for (int i = 0; i < list.Count; i++)
{
UnitBlueprint val = UnitOf(list[i]);
if (!((Object)(object)val == (Object)null) && val.Entity != null && val.Entity.GUID == unit.Entity.GUID)
{
return i;
}
}
return -1;
}
internal static int IndexAtScreenPoint(FactionCreatorManager manager, Vector2 screenPoint, Camera camera)
{
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: 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_0062: Unknown result type (might be due to invalid IL or missing references)
IList list = List(manager);
if (list == null)
{
return -1;
}
int result = -1;
float num = float.MaxValue;
for (int i = 0; i < list.Count; i++)
{
UnitButtonBase val = ButtonOf(list[i]);
if ((Object)(object)val == (Object)null)
{
continue;
}
Transform transform = ((Component)val).transform;
RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
if (!((Object)(object)val2 == (Object)null))
{
if (RectTransformUtility.RectangleContainsScreenPoint(val2, screenPoint, camera))
{
return i;
}
float num2 = Vector2.Distance(RectTransformUtility.WorldToScreenPoint(camera, ((Transform)val2).position), screenPoint);
if (num2 < num)
{
num = num2;
result = i;
}
}
}
return result;
}
internal static bool Move(FactionCreatorManager manager, int from, int to)
{
IList list = List(manager);
if (list == null)
{
return false;
}
if (from < 0 || from >= list.Count)
{
return false;
}
to = Mathf.Clamp(to, 0, list.Count - 1);
if (from == to)
{
return false;
}
object value = list[from];
list.RemoveAt(from);
list.Insert(to, value);
SyncSiblings(list);
return true;
}
internal static bool SortByCost(FactionCreatorManager manager, bool descending)
{
IList list = List(manager);
if (list == null || list.Count < 2)
{
return false;
}
List<object> list2 = new List<object>();
for (int i = 0; i < list.Count; i++)
{
list2.Add(list[i]);
}
List<object> list3 = (descending ? list2.OrderByDescending((object w) => Cost(UnitOf(w))) : list2.OrderBy((object w) => Cost(UnitOf(w)))).ToList();
bool result = false;
for (int num = 0; num < list3.Count; num++)
{
if (list3[num] != list[num])
{
result = true;
break;
}
}
for (int num2 = 0; num2 < list3.Count; num2++)
{
list[num2] = list3[num2];
}
SyncSiblings(list);
return result;
}
internal static uint Cost(UnitBlueprint unit)
{
if ((Object)(object)unit == (Object)null)
{
return 0u;
}
try
{
return unit.GetUnitCost(true);
}
catch
{
return 0u;
}
}
internal static void SyncSiblings(IList list)
{
if (list == null || list.Count == 0)
{
return;
}
List<Transform> list2 = new List<Transform>();
for (int i = 0; i < list.Count; i++)
{
UnitButtonBase val = ButtonOf(list[i]);
if ((Object)(object)val != (Object)null)
{
list2.Add(((Component)val).transform);
}
}
if (list2.Count == 0)
{
return;
}
Transform parent = list2[0].parent;
if ((Object)(object)parent == (Object)null)
{
return;
}
for (int j = 1; j < list2.Count; j++)
{
if ((Object)(object)list2[j].parent != (Object)(object)parent)
{
return;
}
}
List<int> list3 = new List<int>();
for (int k = 0; k < list2.Count; k++)
{
list3.Add(list2[k].GetSiblingIndex());
}
list3.Sort();
for (int l = 0; l < list2.Count; l++)
{
if (list2[l].GetSiblingIndex() != list3[l])
{
list2[l].SetSiblingIndex(list3[l]);
}
}
}
internal static void AttachDragToNewest(FactionCreatorManager manager)
{
if ((Object)(object)manager == (Object)null || (Object)(object)manager.FactionListParent == (Object)null)
{
return;
}
Transform factionListParent = manager.FactionListParent;
for (int num = factionListParent.childCount - 1; num >= 0; num--)
{
Transform child = factionListParent.GetChild(num);
if (!((Object)(object)child == (Object)null) && !((Object)(object)((Component)child).GetComponent<UnitButtonBase>() == (Object)null))
{
if (!((Object)(object)((Component)child).GetComponent<UnitDragReorder>() != (Object)null))
{
((Component)child).gameObject.AddComponent<UnitDragReorder>().Init(manager);
}
break;
}
}
}
internal static int AttachDragToAll(FactionCreatorManager manager)
{
if ((Object)(object)manager == (Object)null || (Object)(object)manager.FactionListParent == (Object)null)
{
return 0;
}
int num = 0;
Transform factionListParent = manager.FactionListParent;
for (int i = 0; i < factionListParent.childCount; i++)
{
Transform child = factionListParent.GetChild(i);
if (!((Object)(object)child == (Object)null) && !((Object)(object)((Component)child).GetComponent<UnitButtonBase>() == (Object)null) && !((Object)(object)((Component)child).GetComponent<UnitDragReorder>() != (Object)null))
{
((Component)child).gameObject.AddComponent<UnitDragReorder>().Init(manager);
num++;
}
}
return num;
}
}
[HarmonyPatch(typeof(FactionCreatorManager), "OnClickUnit")]
internal static class UnitAddedPatch
{
[HarmonyPostfix]
internal static void Postfix(FactionCreatorManager __instance)
{
if (!Plugin.CfgEnabled.Value || !Plugin.CfgDragReorder.Value)
{
return;
}
try
{
FactionUnits.AttachDragToNewest(__instance);
}
catch (Exception ex)
{
Plugin.LogWarn("[FactionSort] could not attach the drag handler: " + ex.Message);
}
}
}
[HarmonyPatch(typeof(FactionCreatorManager), "LoadFaction")]
internal static class FactionLoadedPatch
{
[HarmonyPostfix]
internal static void Postfix(FactionCreatorManager __instance)
{
if (!Plugin.CfgEnabled.Value || !Plugin.CfgDragReorder.Value)
{
return;
}
try
{
int num = FactionUnits.AttachDragToAll(__instance);
if (num > 0)
{
Plugin.LogInfo("[FactionSort] " + num + " unit(s) can be dragged");
}
}
catch (Exception ex)
{
Plugin.LogWarn("[FactionSort] could not attach the drag handlers: " + ex.Message);
}
}
}
[HarmonyPatch(typeof(UnitButtonBase), "OnPointerClick")]
internal static class ClickSuppressPatch
{
[HarmonyPrefix]
internal static bool Prefix()
{
return !UnitDragReorder.SuppressClick;
}
}
[HarmonyPatch(typeof(UnitButtonBase), "OnSubmit")]
internal static class SubmitSuppressPatch
{
[HarmonyPrefix]
internal static bool Prefix()
{
return !UnitDragReorder.SuppressClick;
}
}
[BepInPlugin("saucein.tabs.factionunitsort", "Faction Unit Sort", "1.2.0")]
[BepInProcess("TotallyAccurateBattleSimulator.exe")]
public class Plugin : BaseUnityPlugin
{
public enum ContentSortMode
{
Default,
TimeNewest,
TimeOldest,
CostHigh,
CostLow
}
public const string PluginGuid = "saucein.tabs.factionunitsort";
public const string PluginName = "Faction Unit Sort";
public const string PluginVersion = "1.2.0";
internal static ManualLogSource Log;
internal static ConfigEntry<bool> CfgEnabled;
internal static ConfigEntry<bool> CfgDragReorder;
internal static ConfigEntry<bool> CfgSortButton;
internal static ConfigEntry<bool> CfgSortDescending;
internal static ConfigEntry<string> CfgSortLabel;
internal static ConfigEntry<ContentSortMode> CfgSortUnits;
internal static ConfigEntry<ContentSortMode> CfgSortFactions;
internal static ConfigEntry<ContentSortMode> CfgSortBattles;
internal static ConfigEntry<ContentSortMode> CfgSortCampaigns;
internal static ConfigEntry<ContentSortMode> CfgSortMaps;
internal static ConfigEntry<bool> CfgVerbose;
private void Awake()
{
//IL_0174: Unknown result type (might be due to invalid IL or missing references)
//IL_017a: Expected O, but got Unknown
//IL_023f: Unknown result type (might be due to invalid IL or missing references)
//IL_0244: Unknown result type (might be due to invalid IL or missing references)
//IL_024a: Expected O, but got Unknown
//IL_024a: Unknown result type (might be due to invalid IL or missing references)
Log = ((BaseUnityPlugin)this).Logger;
CfgEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Turn the plugin's editor additions on or off.");
CfgDragReorder = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DragToReorder", true, "Drag a unit in the faction row to move it to any position, instead of only ever appending to the right end.");
CfgSortButton = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SortButton", true, "Add a COST button (cloned from the game's colour button) that sorts the faction's units by their cost.");
CfgSortDescending = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SortDescending", false, "Sort direction for the COST button. false = cheapest first, true = most expensive first.");
CfgSortLabel = ((BaseUnityPlugin)this).Config.Bind<string>("General", "SortButtonLabel", "COST", "Text shown on the added sort button. Matches the game's own short button labels (COLOR, ICON, ...), so 'COST' or e.g. a Chinese label both work.");
CfgSortUnits = ((BaseUnityPlugin)this).Config.Bind<ContentSortMode>("Sorting", "SortUnits", ContentSortMode.Default, "Order of your own units (UNITS page). Written by the dropdown next to the search box.");
CfgSortFactions = ((BaseUnityPlugin)this).Config.Bind<ContentSortMode>("Sorting", "SortFactions", ContentSortMode.Default, "Order of your own factions (FACTION page). Time comes from the faction file, cost is the sum of the faction's units.");
CfgSortBattles = ((BaseUnityPlugin)this).Config.Bind<ContentSortMode>("Sorting", "SortBattles", ContentSortMode.Default, "Order of your own battles (BATTLE page), by file time.");
CfgSortCampaigns = ((BaseUnityPlugin)this).Config.Bind<ContentSortMode>("Sorting", "SortCampaigns", ContentSortMode.Default, "Order of your own campaigns (CAMPAIGN page), by file time.");
CfgSortMaps = ((BaseUnityPlugin)this).Config.Bind<ContentSortMode>("Sorting", "SortMaps", ContentSortMode.Default, "Order of your own maps (MAP page), by file time.");
CfgVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "VerboseLogging", true, "Log details (useful when reporting a problem).");
Harmony val = new Harmony("saucein.tabs.factionunitsort");
try
{
val.PatchAll(typeof(UnitAddedPatch));
val.PatchAll(typeof(FactionLoadedPatch));
val.PatchAll(typeof(ClickSuppressPatch));
val.PatchAll(typeof(SubmitSuppressPatch));
val.PatchAll(typeof(UnitListSortPatch));
val.PatchAll(typeof(FactionListSortPatch));
val.PatchAll(typeof(BattleListSortPatch));
val.PatchAll(typeof(CampaignListSortPatch));
val.PatchAll(typeof(MapListSortPatch));
LogInfo("Harmony patches applied (faction editor + five custom content sorters).");
}
catch (Exception ex)
{
Log.LogError((object)("Could not apply the Harmony patches: " + ex));
}
GameObject val2 = new GameObject("FactionUnitSort");
Object.DontDestroyOnLoad((Object)val2);
val2.AddComponent<FactionUnitEditor>();
val2.AddComponent<UnitSortDropdown>();
LogInfo("Faction Unit Sort 1.2.0 loaded.");
}
internal static ConfigEntry<ContentSortMode> ConfigFor(ContentKind kind)
{
return (ConfigEntry<ContentSortMode>)(kind switch
{
ContentKind.Factions => CfgSortFactions,
ContentKind.Battles => CfgSortBattles,
ContentKind.Campaigns => CfgSortCampaigns,
ContentKind.Maps => CfgSortMaps,
_ => CfgSortUnits,
});
}
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 class UnitDragReorder : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler, IEndDragHandler
{
private FactionCreatorManager _manager;
private bool _dragging;
private Vector3 _originalScale = Vector3.one;
internal static float LastDragTime = -100f;
private readonly Dictionary<Graphic, bool> _raycasts = new Dictionary<Graphic, bool>();
internal static bool SuppressClick => Time.unscaledTime - LastDragTime < 0.3f;
internal void Init(FactionCreatorManager manager)
{
_manager = manager;
}
private void Awake()
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
_originalScale = ((Component)this).transform.localScale;
}
public void OnBeginDrag(PointerEventData eventData)
{
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
if (Plugin.CfgEnabled.Value && Plugin.CfgDragReorder.Value && !((Object)(object)_manager == (Object)null))
{
_dragging = true;
LastDragTime = Time.unscaledTime;
((Component)this).transform.localScale = _originalScale * 1.15f;
SetRaycasts(enabled: false);
}
}
public void OnDrag(PointerEventData eventData)
{
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
if (!_dragging || (Object)(object)_manager == (Object)null)
{
return;
}
int num = FactionUnits.IndexOfUnit(_manager, GetUnit());
if (num >= 0)
{
int num2 = FactionUnits.IndexAtScreenPoint(_manager, eventData.position, eventData.pressEventCamera);
if (num2 >= 0 && num2 != num && FactionUnits.Move(_manager, num, num2))
{
LastDragTime = Time.unscaledTime;
Plugin.LogInfo("[FactionSort] moved unit from position " + num + " to " + num2);
}
}
}
public void OnEndDrag(PointerEventData eventData)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
_dragging = false;
((Component)this).transform.localScale = _originalScale;
LastDragTime = Time.unscaledTime;
SetRaycasts(enabled: true);
}
private void OnDisable()
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
if (_dragging)
{
_dragging = false;
((Component)this).transform.localScale = _originalScale;
SetRaycasts(enabled: true);
}
}
private void SetRaycasts(bool enabled)
{
try
{
Graphic[] componentsInChildren = ((Component)this).GetComponentsInChildren<Graphic>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
if ((Object)(object)componentsInChildren[i] == (Object)null)
{
continue;
}
if (enabled)
{
if (_raycasts.TryGetValue(componentsInChildren[i], out var value))
{
componentsInChildren[i].raycastTarget = value;
}
}
else
{
_raycasts[componentsInChildren[i]] = componentsInChildren[i].raycastTarget;
componentsInChildren[i].raycastTarget = false;
}
}
}
catch (Exception ex)
{
Plugin.LogWarn("[FactionSort] could not toggle the button raycasts: " + ex.Message);
}
}
private UnitBlueprint GetUnit()
{
UnitButtonBase component = ((Component)this).GetComponent<UnitButtonBase>();
if (!((Object)(object)component != (Object)null))
{
return null;
}
return component.GetUnit();
}
}
internal class UnitSortDropdown : MonoBehaviour
{
private const float RowHeight = 30f;
private const float Width = 210f;
private CustomContentGridBrowser _browser;
private RectTransform _anchor;
private ContentKind _kind;
private GameObject _blocker;
private bool _open;
private bool _logged;
private float _nextScan;
private GUIStyle _style;
private Texture2D _white;
private float _styleHeight = -1f;
private Rect _buttonRect;
private readonly List<Rect> _itemRects = new List<Rect>();
private static Font _font;
private static bool _fontTried;
private static readonly Plugin.ContentSortMode[] FullModes = new Plugin.ContentSortMode[5]
{
Plugin.ContentSortMode.Default,
Plugin.ContentSortMode.TimeNewest,
Plugin.ContentSortMode.TimeOldest,
Plugin.ContentSortMode.CostHigh,
Plugin.ContentSortMode.CostLow
};
private static readonly Plugin.ContentSortMode[] TimeModes = new Plugin.ContentSortMode[3]
{
Plugin.ContentSortMode.Default,
Plugin.ContentSortMode.TimeNewest,
Plugin.ContentSortMode.TimeOldest
};
private static float _languageChecked = -100f;
private static string _languageReason;
private static bool Chinese => ChineseReason() != null;
private static string ButtonWord
{
get
{
if (!Chinese)
{
return "Sort";
}
return "排序";
}
}
private static Color Background => new Color(0f, 0f, 0f, 1f);
private static Color Hover => new Color(0.16f, 0.16f, 0.16f, 1f);
private static Color Selected => new Color(0.32f, 0.32f, 0.32f, 1f);
private void Update()
{
if (!Plugin.CfgEnabled.Value || Time.unscaledTime < _nextScan)
{
return;
}
_nextScan = Time.unscaledTime + 0.5f;
try
{
Scan();
}
catch (Exception ex)
{
Plugin.LogWarn("[ContentSort] " + ex.Message);
Hide();
}
}
private void Scan()
{
CustomContentGridBrowser bestBrowser = null;
TMP_InputField bestField = null;
string text = "page state";
try
{
CustomContetnManager val = Object.FindObjectOfType<CustomContetnManager>();
object obj = (((Object)(object)val != (Object)null) ? Member(val, "currentPage") : null);
GameObject val2 = (GameObject)((obj != null) ? /*isinst with value type is only supported in some contexts*/: null);
if ((Object)(object)val2 != (Object)null)
{
bestBrowser = val2.GetComponentInChildren<CustomContentGridBrowser>(true);
if ((Object)(object)bestBrowser != (Object)null)
{
bestField = FieldOf(bestBrowser);
}
}
}
catch (Exception ex)
{
Plugin.LogWarn("[ContentSort] could not read the current page: " + ex.Message);
}
if ((Object)(object)bestBrowser == (Object)null || (Object)(object)bestField == (Object)null)
{
text = "visibility";
bestBrowser = null;
bestField = null;
PickByVisibility(ref bestBrowser, ref bestField);
}
_browser = bestBrowser;
_anchor = (RectTransform)(((Object)(object)bestField != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
_kind = KindOf(bestBrowser);
if ((Object)(object)_anchor == (Object)null)
{
Hide();
_logged = false;
}
else if (!_logged)
{
_logged = true;
string text2 = ChineseReason();
Plugin.LogInfo("[ContentSort] dropdown on the " + _kind.ToString() + " page via " + text + " (" + PathOf((Transform)(object)_anchor) + "), labels: " + ((text2 != null) ? ("Chinese (" + text2 + ")") : "English"));
}
}
private void PickByVisibility(ref CustomContentGridBrowser bestBrowser, ref TMP_InputField bestField)
{
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
float num = -1f;
StringBuilder stringBuilder = new StringBuilder();
CustomContentGridBrowser[] array = Resources.FindObjectsOfTypeAll<CustomContentGridBrowser>();
foreach (CustomContentGridBrowser val in array)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
Scene scene = ((Component)val).gameObject.scene;
if (!((Scene)(ref scene)).IsValid())
{
continue;
}
TMP_InputField val2 = FieldOf(val);
if (!((Object)(object)val2 == (Object)null) && IsVisible((RectTransform)/*isinst with value type is only supported in some contexts*/, out var area))
{
int num2 = VisibleEntries(val);
float num3 = area * (1f + (float)Mathf.Min(num2, 60) * 0.05f);
stringBuilder.Append(' ').Append(KindOf(val)).Append('(')
.Append(Mathf.RoundToInt(area))
.Append("px/")
.Append(num2)
.Append(')');
if (!(num3 <= num))
{
num = num3;
bestBrowser = val;
bestField = val2;
}
}
}
if (stringBuilder.Length > 0)
{
Plugin.LogInfo("[ContentSort] page candidates:" + stringBuilder);
}
}
private static object Member(object target, string name)
{
if (target == null)
{
return null;
}
try
{
Type type = target.GetType();
FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field != null)
{
return field.GetValue(target);
}
PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
return (property != null) ? property.GetValue(target, null) : null;
}
catch
{
return null;
}
}
private static string PathOf(Transform t)
{
if ((Object)(object)t == (Object)null)
{
return "<null>";
}
string text = ((Object)t).name;
Transform parent = t.parent;
int num = 0;
while ((Object)(object)parent != (Object)null && num++ < 5)
{
text = ((Object)parent).name + "/" + text;
parent = parent.parent;
}
return text;
}
private static int VisibleEntries(CustomContentGridBrowser browser)
{
try
{
GridLayoutGroup currentLayoutGroup = browser.CurrentLayoutGroup;
if ((Object)(object)currentLayoutGroup == (Object)null)
{
return 0;
}
int num = 0;
Transform transform = ((Component)currentLayoutGroup).transform;
for (int i = 0; i < transform.childCount; i++)
{
Transform child = transform.GetChild(i);
if ((Object)(object)child != (Object)null && ((Component)child).gameObject.activeInHierarchy)
{
num++;
}
}
return num;
}
catch
{
return 0;
}
}
private void Hide()
{
_open = false;
if ((Object)(object)_blocker != (Object)null)
{
_blocker.SetActive(false);
}
}
private static TMP_InputField FieldOf(object browser)
{
try
{
Type type = browser.GetType();
FieldInfo field = type.GetField("filterInputField", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field != null)
{
object? value = field.GetValue(browser);
return (TMP_InputField)((value is TMP_InputField) ? value : null);
}
PropertyInfo property = type.GetProperty("filterInputField", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
return (TMP_InputField)((property != null) ? /*isinst with value type is only supported in some contexts*/: null);
}
catch
{
return null;
}
}
private static ContentKind KindOf(object browser)
{
if (browser == null)
{
return ContentKind.Units;
}
string name = browser.GetType().Name;
if (name.IndexOf("Unit", StringComparison.Ordinal) >= 0)
{
return ContentKind.Units;
}
if (name.IndexOf("Faction", StringComparison.Ordinal) >= 0)
{
return ContentKind.Factions;
}
if (name.IndexOf("Battle", StringComparison.Ordinal) >= 0)
{
return ContentKind.Battles;
}
if (name.IndexOf("Campaign", StringComparison.Ordinal) >= 0)
{
return ContentKind.Campaigns;
}
if (name.IndexOf("Level", StringComparison.Ordinal) >= 0)
{
return ContentKind.Maps;
}
if (name.IndexOf("Map", StringComparison.Ordinal) >= 0)
{
return ContentKind.Maps;
}
return ContentKind.Units;
}
private static Plugin.ContentSortMode[] ModesFor(ContentKind kind)
{
if (kind != ContentKind.Units && kind != ContentKind.Factions)
{
return TimeModes;
}
return FullModes;
}
private static string LabelFor(Plugin.ContentSortMode mode)
{
bool chinese = Chinese;
switch (mode)
{
case Plugin.ContentSortMode.TimeNewest:
if (!chinese)
{
return "Newest first";
}
return "时间:新 → 旧";
case Plugin.ContentSortMode.TimeOldest:
if (!chinese)
{
return "Oldest first";
}
return "时间:旧 → 新";
case Plugin.ContentSortMode.CostHigh:
if (!chinese)
{
return "Cost: high to low";
}
return "价格:高 → 低";
case Plugin.ContentSortMode.CostLow:
if (!chinese)
{
return "Cost: low to high";
}
return "价格:低 → 高";
default:
if (!chinese)
{
return "Default order";
}
return "默认顺序";
}
}
private static string ShortFor(Plugin.ContentSortMode mode)
{
bool chinese = Chinese;
switch (mode)
{
case Plugin.ContentSortMode.TimeNewest:
if (!chinese)
{
return "Newest";
}
return "时间 ↓";
case Plugin.ContentSortMode.TimeOldest:
if (!chinese)
{
return "Oldest";
}
return "时间 ↑";
case Plugin.ContentSortMode.CostHigh:
if (!chinese)
{
return "Cost high";
}
return "价格 ↓";
case Plugin.ContentSortMode.CostLow:
if (!chinese)
{
return "Cost low";
}
return "价格 ↑";
default:
if (!chinese)
{
return "Default";
}
return "默认";
}
}
private static string ChineseReason()
{
if (Time.unscaledTime - _languageChecked < 2f)
{
return _languageReason;
}
_languageChecked = Time.unscaledTime;
_languageReason = DetectChineseReason();
return _languageReason;
}
private static string DetectChineseReason()
{
try
{
string text = Localizer.ActiveCultureInfo?.Name;
if (!string.IsNullOrEmpty(text) && text.StartsWith("zh", StringComparison.OrdinalIgnoreCase))
{
return "game language";
}
}
catch
{
}
try
{
FieldInfo fieldInfo = AccessTools.Field(typeof(Localizer), "m_locale");
object obj2 = ((fieldInfo != null) ? fieldInfo.GetValue(null) : null);
if (obj2 != null && obj2.ToString().IndexOf("CH", StringComparison.OrdinalIgnoreCase) >= 0)
{
return "game language";
}
}
catch
{
}
try
{
Dictionary<string, PluginInfo> pluginInfos = Chainloader.PluginInfos;
if (pluginInfos != null)
{
foreach (KeyValuePair<string, PluginInfo> item in pluginInfos)
{
if (LooksChinese(item.Key))
{
return "translation mod";
}
PluginInfo value = item.Value;
if (value != null && value.Metadata != null && LooksChinese(value.Metadata.Name))
{
return "translation mod";
}
}
}
}
catch
{
}
try
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
for (int i = 0; i < assemblies.Length; i++)
{
if (LooksChinese(assemblies[i].GetName().Name))
{
return "translation mod";
}
Type[] types;
try
{
types = assemblies[i].GetTypes();
}
catch
{
continue;
}
for (int j = 0; j < types.Length; j++)
{
string fullName = types[j].FullName;
if (fullName != null && (fullName.IndexOf("AllInOnePatch", StringComparison.OrdinalIgnoreCase) >= 0 || fullName.IndexOf("CN_AllInOne", StringComparison.OrdinalIgnoreCase) >= 0))
{
return "translation mod";
}
}
}
}
catch
{
}
return null;
}
private static bool LooksChinese(string value)
{
if (string.IsNullOrEmpty(value))
{
return false;
}
string text = value.ToLowerInvariant();
if (text.Contains("chinese") || text.Contains("allinone") || text.Contains("cn_all"))
{
return true;
}
if (text.Contains("汉化") || text.Contains("中文"))
{
return true;
}
if (text.Contains("translation"))
{
return text.Contains("cn");
}
return false;
}
private void OnGUI()
{
//IL_0060: 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_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_0176: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_0185: Unknown result type (might be due to invalid IL or missing references)
//IL_017e: Unknown result type (might be due to invalid IL or missing references)
//IL_0191: 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_0129: Unknown result type (might be due to invalid IL or missing references)
//IL_012d: Unknown result type (might be due to invalid IL or missing references)
//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
//IL_01f1: 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_01f9: Unknown result type (might be due to invalid IL or missing references)
//IL_0205: Unknown result type (might be due to invalid IL or missing references)
//IL_0232: Unknown result type (might be due to invalid IL or missing references)
//IL_0237: Unknown result type (might be due to invalid IL or missing references)
//IL_0247: Unknown result type (might be due to invalid IL or missing references)
//IL_0211: Unknown result type (might be due to invalid IL or missing references)
//IL_0216: Unknown result type (might be due to invalid IL or missing references)
//IL_021a: Unknown result type (might be due to invalid IL or missing references)
//IL_0222: Unknown result type (might be due to invalid IL or missing references)
//IL_0227: Unknown result type (might be due to invalid IL or missing references)
if (!Plugin.CfgEnabled.Value || (Object)(object)_anchor == (Object)null)
{
return;
}
try
{
Plugin.ContentSortMode[] array = ModesFor(_kind);
Plugin.ContentSortMode contentSortMode = Plugin.ConfigFor(_kind).Value;
if (Array.IndexOf(array, contentSortMode) < 0)
{
contentSortMode = array[0];
}
EnsureResources();
GUI.depth = -10000;
ComputeRects(array.Length);
Vector2 val = GuiMouse();
bool flag = ((Rect)(ref _buttonRect)).Contains(val);
bool flag2 = false;
Rect val2;
if (_open)
{
for (int i = 0; i < _itemRects.Count; i++)
{
val2 = _itemRects[i];
if (((Rect)(ref val2)).Contains(val))
{
flag2 = true;
break;
}
}
}
UpdateBlocker(flag || flag2 || _open);
Event current = Event.current;
if (current != null && (int)current.type == 0 && current.button == 0)
{
if (flag)
{
_open = !_open;
current.Use();
}
else if (_open)
{
bool flag3 = false;
for (int j = 0; j < _itemRects.Count && j < array.Length; j++)
{
val2 = _itemRects[j];
if (((Rect)(ref val2)).Contains(val))
{
Choose(array[j]);
flag3 = true;
break;
}
}
if (flag3)
{
current.Use();
}
else
{
_open = false;
}
}
}
DrawPill(_buttonRect, flag ? Hover : Background);
DrawLabel(_buttonRect, ButtonWord + ": " + ShortFor(contentSortMode) + (_open ? " ^" : " v"));
if (!_open)
{
return;
}
for (int k = 0; k < _itemRects.Count && k < array.Length; k++)
{
bool num = array[k] == contentSortMode;
val2 = _itemRects[k];
Color color = (((Rect)(ref val2)).Contains(val) ? Hover : Background);
if (num)
{
val2 = _itemRects[k];
if (!((Rect)(ref val2)).Contains(val))
{
color = Selected;
}
}
DrawPill(_itemRects[k], color);
DrawLabel(_itemRects[k], LabelFor(array[k]));
}
}
catch (Exception ex)
{
Plugin.LogWarn("[ContentSort] dropdown draw failed: " + ex.Message);
}
}
private void Choose(Plugin.ContentSortMode mode)
{
_open = false;
try
{
Plugin.ConfigFor(_kind).Value = mode;
Plugin.LogInfo("[ContentSort] " + _kind.ToString() + " order set to " + mode);
if ((Object)(object)_browser != (Object)null)
{
_browser.Refresh();
}
}
catch (Exception ex)
{
Plugin.LogWarn("[ContentSort] could not refresh the browser: " + ex.Message);
}
}
private void ComputeRects(int count)
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_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_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: 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_0097: 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_00eb: Unknown result type (might be due to invalid IL or missing references)
//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_0121: 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_015f: Unknown result type (might be due to invalid IL or missing references)
Vector3[] array = (Vector3[])(object)new Vector3[4];
_anchor.GetWorldCorners(array);
Canvas componentInParent = ((Component)_anchor).GetComponentInParent<Canvas>();
Camera obj = (((Object)(object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0) ? componentInParent.worldCamera : null);
Vector2 val = RectTransformUtility.WorldToScreenPoint(obj, array[0]);
Vector2 val2 = RectTransformUtility.WorldToScreenPoint(obj, array[2]);
float num = Mathf.Abs(val2.x - val.x);
Rect rect = _anchor.rect;
float num2;
if (!(((Rect)(ref rect)).width > 1f))
{
num2 = 1f;
}
else
{
rect = _anchor.rect;
num2 = num / ((Rect)(ref rect)).width;
}
float num3 = num2;
if (num3 <= 0.01f)
{
num3 = 1f;
}
float num4 = Mathf.Clamp(30f * num3, 20f, 44f);
float num5 = Mathf.Clamp(210f * num3, 140f, 320f);
float num6 = Mathf.Min(val.x, val2.x);
float num7 = (float)Screen.height - Mathf.Min(val.y, val2.y) + 6f;
_buttonRect = new Rect(num6, num7, num5, num4);
_itemRects.Clear();
for (int i = 0; i < count; i++)
{
_itemRects.Add(new Rect(num6, ((Rect)(ref _buttonRect)).yMax + (float)i * (num4 + 2f), num5, num4));
}
}
private void UpdateBlocker(bool active)
{
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Expected O, but got Unknown
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_blocker == (Object)null)
{
Canvas val = (((Object)(object)_anchor != (Object)null) ? ((Component)_anchor).GetComponentInParent<Canvas>() : null);
if ((Object)(object)val == (Object)null)
{
return;
}
_blocker = new GameObject("ContentSortClickBlocker", new Type[2]
{
typeof(RectTransform),
typeof(Image)
});
_blocker.transform.SetParent(((Component)val).transform, false);
Transform transform = _blocker.transform;
Transform obj = ((transform is RectTransform) ? transform : null);
((RectTransform)obj).anchorMin = Vector2.zero;
((RectTransform)obj).anchorMax = Vector2.one;
((RectTransform)obj).pivot = new Vector2(0.5f, 0.5f);
((RectTransform)obj).offsetMin = Vector2.zero;
((RectTransform)obj).offsetMax = Vector2.zero;
Image component = _blocker.GetComponent<Image>();
((Graphic)component).color = new Color(0f, 0f, 0f, 0f);
((Graphic)component).raycastTarget = true;
_blocker.SetActive(false);
}
if (_blocker.activeSelf == active)
{
return;
}
_blocker.SetActive(active);
if (active)
{
try
{
_blocker.transform.SetAsLastSibling();
}
catch
{
}
}
}
private void DrawPill(Rect rect, Color color)
{
//IL_001d: 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)
float num = Mathf.Clamp(((Rect)(ref rect)).height * 0.28f, 3f, 12f);
GUI.DrawTexture(rect, (Texture)(object)_white, (ScaleMode)0, true, 0f, color, 0f, num);
}
private void DrawLabel(Rect rect, string text)
{
//IL_001f: 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_006d: 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)
_style.normal.textColor = new Color(0f, 0f, 0f, 0.35f);
GUI.Label(new Rect(((Rect)(ref rect)).x + 1f, ((Rect)(ref rect)).y + 1f, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height), text, _style);
_style.normal.textColor = Color.white;
GUI.Label(rect, text, _style);
}
private void EnsureResources()
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Expected O, but got Unknown
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Expected O, but got Unknown
//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)
if ((Object)(object)_white == (Object)null)
{
_white = new Texture2D(4, 4, (TextureFormat)4, false);
Color[] array = (Color[])(object)new Color[16];
for (int i = 0; i < array.Length; i++)
{
array[i] = Color.white;
}
_white.SetPixels(array);
_white.Apply();
((Object)_white).hideFlags = (HideFlags)61;
}
if (_style == null)
{
_style = new GUIStyle(GUI.skin.label);
_style.alignment = (TextAnchor)4;
_style.richText = false;
_style.clipping = (TextClipping)1;
Font font = GetFont();
if ((Object)(object)font != (Object)null)
{
_style.font = font;
}
}
if (!Mathf.Approximately(_styleHeight, ((Rect)(ref _buttonRect)).height))
{
_styleHeight = ((Rect)(ref _buttonRect)).height;
_style.fontSize = Mathf.RoundToInt(Mathf.Clamp(((Rect)(ref _buttonRect)).height * 0.55f, 11f, 20f));
}
}
private static Font GetFont()
{
if (_fontTried)
{
return _font;
}
_fontTried = true;
try
{
_font = Font.CreateDynamicFontFromOSFont(new string[5] { "Microsoft YaHei UI", "Microsoft YaHei", "SimHei", "Segoe UI", "Arial" }, 16);
}
catch
{
_font = null;
}
return _font;
}
private static Vector2 GuiMouse()
{
//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_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
Vector2 val = Vector2.op_Implicit(Input.mousePosition);
return new Vector2(val.x, (float)Screen.height - val.y);
}
private static bool IsVisible(RectTransform rect, out float area)
{
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: 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_00b9: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
//IL_00f5: 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_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_012d: Unknown result type (might be due to invalid IL or missing references)
//IL_0134: Unknown result type (might be due to invalid IL or missing references)
area = 0f;
if ((Object)(object)rect == (Object)null || !((Component)rect).gameObject.activeInHierarchy)
{
return false;
}
Transform val = (Transform)(object)rect;
int num = 0;
while ((Object)(object)val != (Object)null && num++ < 10)
{
Canvas component = ((Component)val).GetComponent<Canvas>();
if ((Object)(object)component != (Object)null && !((Behaviour)component).enabled)
{
return false;
}
CanvasGroup component2 = ((Component)val).GetComponent<CanvasGroup>();
if ((Object)(object)component2 != (Object)null && component2.alpha <= 0.01f)
{
return false;
}
val = val.parent;
}
Vector3[] array = (Vector3[])(object)new Vector3[4];
rect.GetWorldCorners(array);
Canvas componentInParent = ((Component)rect).GetComponentInParent<Canvas>();
Camera obj = (((Object)(object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0) ? componentInParent.worldCamera : null);
Vector2 val2 = RectTransformUtility.WorldToScreenPoint(obj, array[0]);
Vector2 val3 = RectTransformUtility.WorldToScreenPoint(obj, array[2]);
float num2 = Mathf.Max(0f, Mathf.Min(val2.x, val3.x));
float num3 = Mathf.Min((float)Screen.width, Mathf.Max(val2.x, val3.x));
float num4 = Mathf.Max(0f, Mathf.Min(val2.y, val3.y));
float num5 = Mathf.Min((float)Screen.height, Mathf.Max(val2.y, val3.y));
if (num3 - num2 < 30f || num5 - num4 < 8f)
{
return false;
}
area = (num3 - num2) * (num5 - num4);
return true;
}
}