Decompiled source of SearchThing v0.5.0
Mods/SearchThing.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text.Json; using System.Text.RegularExpressions; using System.Threading; using BoneLib; using FuzzySharp; using FuzzySharp.Edits; using FuzzySharp.Extensions; using FuzzySharp.Extractor; using FuzzySharp.PreProcess; using FuzzySharp.SimilarityRatio; using FuzzySharp.SimilarityRatio.Scorer; using FuzzySharp.SimilarityRatio.Scorer.Composite; using FuzzySharp.SimilarityRatio.Scorer.Generic; using FuzzySharp.SimilarityRatio.Scorer.StrategySensitive; using FuzzySharp.SimilarityRatio.Scorer.StrategySensitive.Generic; using FuzzySharp.SimilarityRatio.Strategy; using FuzzySharp.SimilarityRatio.Strategy.Generic; using FuzzySharp.Utils; using HarmonyLib; using Il2CppCysharp.Threading.Tasks; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSLZ.Bonelab; using Il2CppSLZ.Marrow; using Il2CppSLZ.Marrow.SceneStreaming; using Il2CppSLZ.Marrow.Warehouse; using Il2CppSLZ.UI; using Il2CppTMPro; using LabFusion.Data; using LabFusion.Marrow.Serialization; using LabFusion.Network; using LabFusion.Player; using LabFusion.Scene; using LabFusion.Utilities; using MelonLoader; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using SearchThing; using SearchThing.Extensions; using SearchThing.Extensions.Components; using SearchThing.Extensions.Pages; using SearchThing.Extensions.Panel; using SearchThing.Extensions.Panel.Abstract; using SearchThing.Extensions.Panel.Data; using SearchThing.Extensions.Panel.Filter; using SearchThing.Extensions.Panel.History; using SearchThing.Extensions.Sort; using SearchThing.Fusion; using SearchThing.History; using SearchThing.Keyboard; using SearchThing.Patches; using SearchThing.Patches.Compatibility; using SearchThing.Presets; using SearchThing.Presets.Data; using SearchThing.Search; using SearchThing.Util; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Mod), "SearchThing", "0.5.0", "Mash", null)] [assembly: MelonGame("Stress Level Zero", "BONELAB")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] [assembly: AssemblyCompany("SearchThing")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SearchThing")] [assembly: AssemblyTitle("SearchThing")] [assembly: AssemblyVersion("1.0.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace SearchThing { public class Mod : MelonMod { public static bool IsFusionLoaded; public override void OnInitializeMelon() { IsFusionLoaded = MelonBase.FindMelon("LabFusion", "Lakatrazz") != null; Hooking.OnWarehouseReady += OnWarehouseReady; } private static void HookFusion() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown FusionNetworkSpawnPatch.TryInitialize(); MultiplayerHooking.OnTargetLevelLoaded += new UpdateEvent(SpawnGunPatches.ClearSelectedCrate); } private static void OnWarehouseReady() { SearchManager.InitializeSearchThread(); PresetManager.LoadPresets(); if (IsFusionLoaded) { HookFusion(); } } public override void OnDeinitializeMelon() { SearchManager.ShutdownSearchThread(); } } public static class SpawnablesPanelManager { private static SpawnablePanelExtension? _extension; public static void Load(SpawnablesPanelView panelView) { if (_extension != null && _extension.Is(panelView)) { if (_extension.IsSearchActive()) { _extension.RequestRefresh(); } } else { _extension = new SpawnablePanelExtension(panelView); } } public static void OnTabSelected(SpawnablesPanelView panelView, int index) { if (_extension != null && _extension.Is(panelView)) { if (index == 5) { _extension.Show(); } else { _extension.Hide(); } } } public static SpawnablePanelExtension? Get() { return _extension; } public static bool TryGet(SpawnablesPanelView instance, [MaybeNullWhen(false)] out SpawnablePanelExtension extension) { if (_extension != null && _extension.Is(instance)) { extension = _extension; return true; } extension = null; return false; } } } namespace SearchThing.Util { public class BodylogAccessor { private static PullCordDevice? _cordDevice; private static RigManager GetFusionRig() { return RigData.Refs.RigManager; } private static RigManager GetRig() { if (Mod.IsFusionLoaded) { return GetFusionRig(); } return Player.RigManager; } public static PullCordDevice? GetCordDevice() { if ((Object)(object)_cordDevice != (Object)null) { return _cordDevice; } RigManager rig = GetRig(); if ((Object)(object)rig == (Object)null) { return null; } _cordDevice = (from item in (IEnumerable<SlotContainer>)rig.inventory.specialItems select ((Component)item).transform into transform where transform.childCount > 0 select ((Component)transform.GetChild(0)).GetComponent<PullCordDevice>()).FirstOrDefault((Func<PullCordDevice, bool>)((PullCordDevice item) => (Object)(object)item != (Object)null)); return _cordDevice; } } public static class CrateIconProvider { private static readonly Sprite AvatarIcon = ImageHelper.LoadEmbeddedSprite("SearchThing.resources.AvatarIcon.png"); private static readonly Sprite CrateIcon = ImageHelper.LoadEmbeddedSprite("SearchThing.resources.CrateIcon.png"); private static readonly Sprite LevelIcon = ImageHelper.LoadEmbeddedSprite("SearchThing.resources.LevelIcon.png"); private static readonly Sprite GunIcon = ImageHelper.LoadEmbeddedSprite("SearchThing.resources.GunIcon.png"); private static readonly Sprite MeleeIcon = ImageHelper.LoadEmbeddedSprite("SearchThing.resources.MeleeIcon.png"); private static readonly Sprite ThrowableIcon = ImageHelper.LoadEmbeddedSprite("SearchThing.resources.ThrowableIcon.png"); private static readonly Sprite VehicleIcon = ImageHelper.LoadEmbeddedSprite("SearchThing.resources.VehicleIcon.png"); private static Sprite GetAvatarIcon() { return AvatarIcon; } private static Sprite GetPropIcon(ISearchableCrate searchableCrate) { return (Sprite)(searchableCrate.CrateSubType switch { CrateSubType.Gun => GunIcon, CrateSubType.Melee => MeleeIcon, CrateSubType.Throwable => ThrowableIcon, CrateSubType.Vehicle => VehicleIcon, _ => CrateIcon, }); } private static Sprite GetLevelIcon() { return LevelIcon; } public static Sprite GetIcon(ISearchableCrate searchableCrate) { return (Sprite)(searchableCrate.CrateType switch { CrateType.Avatar => GetAvatarIcon(), CrateType.Prop => GetPropIcon(searchableCrate), CrateType.Level => GetLevelIcon(), _ => CrateIcon, }); } } public static class ImageHelper { public static Texture2D LoadEmbeddedImage(string resourceName) { //IL_0047: 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_0053: 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_0067: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown using Stream stream = typeof(ImageHelper).Assembly.GetManifestResourceStream(resourceName); if (stream == null) { throw new Exception("Resource not found: " + resourceName); } byte[] array = new byte[stream.Length]; stream.Read(array, 0, array.Length); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false) { name = resourceName, hideFlags = (HideFlags)32 }; if (!ImageConversion.LoadImage(val, Il2CppStructArray<byte>.op_Implicit(array))) { throw new Exception("Failed to load image from resource: " + resourceName); } val.Apply(); return val; } public static Sprite LoadEmbeddedSprite(string resourceName) { //IL_0020: 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_002f: Unknown result type (might be due to invalid IL or missing references) Texture2D val = LoadEmbeddedImage(resourceName); Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), Vector2.one * 0.5f); ((Object)obj).hideFlags = (HideFlags)32; return obj; } } public static class SearchHelper { public static int GetSalt(this string str) { return str.Aggregate(23, (int current, char c) => current * 31 + c); } public static bool IsCrate<T>(this Crate crate) where T : Crate { return (Object)(object)((Il2CppObjectBase)crate).TryCast<T>() != (Object)null; } public static CrateType GetCrateType(this Crate crate) { if (crate.IsCrate<AvatarCrate>()) { return CrateType.Avatar; } if (crate.IsCrate<LevelCrate>()) { return CrateType.Level; } return CrateType.Prop; } private static List<string> GetTags(this Crate crate) { return (from tag in (IEnumerable<string>)crate._tags._items where !string.IsNullOrEmpty(tag) select tag.ToLower()).ToList(); } private static List<string> GetMetaDataList(this Crate crate) { List<string> tags = crate.GetTags(); if (!string.IsNullOrEmpty(((Scannable)crate).Title)) { tags.AddRange(from p in ((Scannable)crate).Title.ToLower().Split(" ") select p.Trim()); } return tags; } private static CrateSubType GetPropSubType(this Crate crate) { List<string> metaDataList = crate.GetMetaDataList(); if (metaDataList.Contains("gun")) { return CrateSubType.Gun; } if (metaDataList.Contains("grenade")) { return CrateSubType.Throwable; } if (metaDataList.Contains("melee")) { return CrateSubType.Melee; } if (metaDataList.Contains("vehicle")) { return CrateSubType.Vehicle; } return CrateSubType.None; } public static CrateSubType GetCrateSubType(this Crate crate, CrateType crateType) { if (crateType == CrateType.Prop) { return crate.GetPropSubType(); } return CrateSubType.None; } public static bool TryGetCrate(this ISearchableCrate crate, [MaybeNullWhen(false)] out Crate outCrate) { return AssetWarehouse.Instance.TryGetCrate(crate.Barcode, ref outCrate); } } public struct SearchTag { public string Original { get; } public string Preprocessed { get; } public SearchTag(string original) { Original = original; Preprocessed = Preprocess(original); } public int PartialRatio(string other) { return Fuzz.PartialRatio(Preprocessed, other, PreprocessMode.None); } public bool Contains(string preprocessedQuery) { return Preprocessed.Contains(preprocessedQuery); } public static string Preprocess(string value) { return StringHelper.RemoveUnityRichText(StringHelper.RemoveNonAlphanumeric(value.ToLowerInvariant())).Replace(" ", "").Trim(); } } public static class StringHelper { private static readonly Regex UnityRichTextRegex = new Regex("</?[a-zA-Z]*=[^>]*>|</?[a-zA-Z]+>", RegexOptions.Compiled); private static readonly Regex NonAlphanumericRegex = new Regex("[^ a-zA-Z0-9]", RegexOptions.Compiled); public static string RemoveUnityRichText(string input) { return UnityRichTextRegex.Replace(input, string.Empty); } public static string RemoveNonAlphanumeric(string input) { return NonAlphanumericRegex.Replace(input, string.Empty); } } public static class ThreadUtils { public static void RunOnMainThread(this Action action) { MelonCoroutines.Start(InvokeOnMainThread(action)); } public static void RunOnMainThread<T>(this Action<T> action, T arg) { Action<T> action2 = action; T arg2 = arg; MelonCoroutines.Start(InvokeOnMainThread(delegate { action2(arg2); })); } private static IEnumerator InvokeOnMainThread(Action action) { yield return null; action(); } } } namespace SearchThing.Search { public enum CrateType { Prop, Avatar, Level, Invalid } public enum CrateSubType { None, Gun, Melee, Throwable, Vehicle, Large, Medium, Small } public static class GlobalCrateManager { private static readonly SearchableCrateLookup SearchableCrateCrates = new SearchableCrateLookup(); public static ISearchableCrateList<ISearchableCrate> GetCrates() { return SearchableCrateCrates; } public static void AddPallet(Pallet pallet) { SearchableCrateCrates.AddCrates(from c in (IEnumerable<Crate>)pallet._crates._items where (Object)(object)c != (Object)null select c into crate select new SearchableCrate(crate)); } public static ISearchableCrate? GetCrate(Barcode barcode) { return SearchableCrateCrates.GetCrateByBarcode(barcode._id); } } public interface ISearchableCrate { SearchTag Name { get; } SearchTag PalletName { get; } SearchTag Author { get; } SearchTag[] Tags { get; } string Description { get; } bool Redacted { get; } CrateType CrateType { get; } CrateSubType CrateSubType { get; } int Salt { get; } int Score { get; } DateTime DateAdded { get; } Barcode Barcode { get; } } public interface ISearchOrder { int Order(ISearchableCrate searchableCrate); } public class SearchableCrate : ISearchableCrate, IEquatable<SearchableCrate> { public SearchTag Name { get; } public SearchTag PalletName { get; } public SearchTag Author { get; } public SearchTag[] Tags { get; } public string Description { get; } public bool Redacted { get; } public int Salt { get; } public CrateType CrateType { get; } public CrateSubType CrateSubType { get; } public virtual int Score => 0; public DateTime DateAdded { get; } public Barcode Barcode { get; } public SearchableCrate(Crate spawnableCrate) { if ((Object)(object)spawnableCrate == (Object)null) { throw new ArgumentNullException("spawnableCrate"); } Name = new SearchTag(((Object)spawnableCrate).name); Description = ((Scannable)spawnableCrate)._description; PalletName = new SearchTag(((Object)spawnableCrate._pallet).name); Author = new SearchTag(spawnableCrate._pallet._author); Tags = ((IEnumerable<string>)spawnableCrate._tags.ToArray()).Select((string t) => new SearchTag(t)).ToArray(); Redacted = ((Scannable)spawnableCrate)._redacted; Salt = ((Object)spawnableCrate).name.GetSalt(); PalletManifest val = default(PalletManifest); if (!spawnableCrate._pallet.IsInMarrowGame() && AssetWarehouse.Instance.TryGetPalletManifest(((Scannable)spawnableCrate._pallet)._barcode, ref val)) { DateAdded = (long.TryParse(val.UpdatedDate, out var result) ? DateTime.UnixEpoch.AddMilliseconds(result) : DateTime.MinValue); } else { DateAdded = DateTime.MinValue; } CrateType = spawnableCrate.GetCrateType(); CrateSubType = spawnableCrate.GetCrateSubType(CrateType); Barcode = ((Scannable)spawnableCrate).Barcode; } public SearchableCrate(Barcode barcode) { Crate spawnableCrate = default(Crate); if (!AssetWarehouse.Instance.TryGetCrate(barcode, ref spawnableCrate)) { throw new ArgumentException($"Crate with barcode {barcode} not found in warehouse", "barcode"); } this..ctor(spawnableCrate); } public bool Equals(SearchableCrate? other) { if (other == null) { return false; } if (this == other) { return true; } return Barcode._id.Equals(other.Barcode._id); } public override bool Equals(object? obj) { if (obj == null) { return false; } if (this == obj) { return true; } if (obj.GetType() != GetType()) { return false; } return Equals((SearchableCrate)obj); } public override int GetHashCode() { return Barcode._id.GetHashCode(); } } public interface ISearchableCrateList<out TCrate> where TCrate : class, ISearchableCrate { IEnumerable<TCrate> GetCrates(); } public class SearchableCrateList<TCrate> : ISearchableCrateList<TCrate> where TCrate : class, ISearchableCrate { private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); private readonly List<TCrate> _crates = new List<TCrate>(); public void AddCrate(TCrate crate) { _lock.EnterWriteLock(); try { _crates.Add(crate); } finally { _lock.ExitWriteLock(); } } public void AddCrates(IEnumerable<TCrate> crates) { _lock.EnterWriteLock(); try { _crates.AddRange(crates); } finally { _lock.ExitWriteLock(); } } public IEnumerable<TCrate> GetCrates() { _lock.EnterReadLock(); try { return _crates.ToArray(); } finally { _lock.ExitReadLock(); } } } public record SearchableCrateListWrapper<TCrate>(IEnumerable<TCrate> Crates) : ISearchableCrateList<TCrate> where TCrate : class, ISearchableCrate { public IEnumerable<TCrate> GetCrates() { return Crates; } } public static class SearchableCrateListWrapperHelper { public static ISearchableCrateList<TCrate> ToSearchable<TCrate>(this IEnumerable<TCrate> crates) where TCrate : class, ISearchableCrate { return new SearchableCrateListWrapper<TCrate>(crates); } } public class SearchableCrateLookup : ISearchableCrateList<ISearchableCrate> { private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); private readonly Dictionary<string, ISearchableCrate> _lookup = new Dictionary<string, ISearchableCrate>(); private readonly List<ISearchableCrate> _crates = new List<ISearchableCrate>(); public void AddCrate(ISearchableCrate crate) { _lock.EnterWriteLock(); try { _lookup[crate.Barcode._id] = crate; _crates.Add(crate); } finally { _lock.ExitWriteLock(); } } public void AddCrates(IEnumerable<ISearchableCrate> crates) { _lock.EnterWriteLock(); try { foreach (ISearchableCrate crate in crates) { _lookup[crate.Barcode._id] = crate; _crates.Add(crate); } } finally { _lock.ExitWriteLock(); } } public ISearchableCrate? GetCrateByBarcode(string barcode) { _lock.EnterReadLock(); try { return _lookup.GetValueOrDefault(barcode); } finally { _lock.ExitReadLock(); } } public IEnumerable<ISearchableCrate> GetCrates() { _lock.EnterReadLock(); try { return _crates.ToArray(); } finally { _lock.ExitReadLock(); } } } public record ScoredCrate(ISearchableCrate Crate, int Score) : ISearchableCrate { public SearchTag Name => Crate.Name; public SearchTag PalletName => Crate.PalletName; public SearchTag Author => Crate.Author; public SearchTag[] Tags => Crate.Tags; public string Description => Crate.Description; public bool Redacted => Crate.Redacted; public CrateType CrateType => Crate.CrateType; public CrateSubType CrateSubType => Crate.CrateSubType; public int Salt => Crate.Salt; public Barcode Barcode => Crate.Barcode; public DateTime DateAdded => Crate.DateAdded; public static ScoredCrate ScoreCrate(ISearchableCrate crate, string preprocessedQuery) { return new ScoredCrate(crate, SearchManager.ScoreCrate(preprocessedQuery, crate)); } } internal interface ISearchTask { string Query { get; } ISearchableCrateList<ISearchableCrate> PureSourceList { get; } Func<ISearchableCrate, bool> Filter { get; } ISearchOrder SearchOrder { get; } CancellationToken CancellationToken { get; } void RunAndStore(IEnumerable<ISearchableCrate> results); } public record SearchTask<TCrate>(string Query, ISearchableCrateList<TCrate> SourceList, Func<ISearchableCrate, bool> Filter, ISearchOrder SearchOrder, Action<SearchResults<TCrate>> OnComplete, CancellationToken CancellationToken) : ISearchTask where TCrate : class, ISearchableCrate { public ISearchableCrateList<ISearchableCrate> PureSourceList => SourceList; public void RunAndStore(IEnumerable<ISearchableCrate> results) { List<TCrate> entries = results.OfType<TCrate>().ToList(); SearchResults<TCrate> searchResults = new SearchResults<TCrate>(entries); ThreadUtils.RunOnMainThread(delegate { OnComplete(searchResults); }); } } public static class SearchManager { private const int RequiredMatchRate = 75; private static readonly object SearchLock = new object(); private static CancellationTokenSource? _lastSearchCts = new CancellationTokenSource(); private static Thread? _searchThread; private static readonly BlockingCollection<ISearchTask> SearchQueue = new BlockingCollection<ISearchTask>(); private static readonly CancellationTokenSource SearchThreadCts = new CancellationTokenSource(); public static void InitializeSearchThread() { _searchThread = new Thread(SearchThreadWorker) { IsBackground = true, Name = "SearchWorker" }; _searchThread.Start(); } public static void ShutdownSearchThread() { SearchThreadCts.Cancel(); SearchQueue.CompleteAdding(); _searchThread?.Join(TimeSpan.FromMilliseconds(500.0)); } private static void SearchThreadWorker() { try { foreach (ISearchTask item in SearchQueue.GetConsumingEnumerable(SearchThreadCts.Token)) { ExecuteSearch(item); } } catch (OperationCanceledException) { } } private static void ExecuteSearch(ISearchTask task) { IEnumerable<ISearchableCrate> crates = task.PureSourceList.GetCrates(); try { if (string.IsNullOrWhiteSpace(task.Query) || !AssetWarehouse.ready) { OrderedParallelQuery<ISearchableCrate> results = crates.AsParallel().WithDegreeOfParallelism(Math.Max(1, Environment.ProcessorCount / 2)).WithCancellation(task.CancellationToken) .Where(task.Filter) .OrderByDescending(task.SearchOrder.Order) .ThenByDescending((ISearchableCrate c) => c.Salt); task.RunAndStore(results); return; } string preprocessedQuery = SearchTag.Preprocess(task.Query); ParallelQuery<ISearchableCrate> results2 = from c in (from crate in crates.AsParallel().WithDegreeOfParallelism(Math.Max(1, Environment.ProcessorCount / 2)).WithCancellation(task.CancellationToken) .Where(task.Filter) select new ScoredCrate(crate, ScoreCrate(preprocessedQuery, crate)) into c where c.Score >= 75 select c).OrderByDescending(task.SearchOrder.Order).ThenByDescending((ScoredCrate c) => c.Crate.Salt) select c.Crate; task.RunAndStore(results2); } catch (OperationCanceledException) { } catch (Exception ex2) { MelonLogger.Error("Search failed: {0}", ex2); } } public static void SearchAsync<TCrate>(string query, ISearchableCrateList<TCrate> crateList, Func<ISearchableCrate, bool> filter, ISearchOrder searchOrder, Action<SearchResults<TCrate>> onComplete) where TCrate : class, ISearchableCrate { lock (SearchLock) { _lastSearchCts?.Cancel(); _lastSearchCts?.Dispose(); _lastSearchCts = new CancellationTokenSource(); } SearchTask<TCrate> item = new SearchTask<TCrate>(query, crateList, filter, searchOrder, onComplete, _lastSearchCts.Token); SearchQueue.Add(item); } public static int ScoreCrate(string preprocessedQuery, ISearchableCrate crate) { string preprocessedQuery2 = preprocessedQuery; int num = crate.Name.PartialRatio(preprocessedQuery2); int num2 = crate.PalletName.PartialRatio(preprocessedQuery2); int num3 = crate.Author.PartialRatio(preprocessedQuery2); int num4 = (crate.Tags.Any((SearchTag t) => t.PartialRatio(preprocessedQuery2) > 80) ? 90 : 0); return new int[4] { num, num2, num3, num4 }.Max(); } } public class SearchResults<TCrate> where TCrate : class, ISearchableCrate { public static SearchResults<ISearchableCrate> Empty { get; } = new SearchResults<ISearchableCrate>(new List<ISearchableCrate>()); private IReadOnlyList<TCrate> Entries { get; } public SearchResults(List<TCrate> entries) { Entries = entries; } private IEnumerable<TCrate> GetPageIterator(int start, int end) { for (int i = start; i < end; i++) { yield return Entries[i]; } } public IEnumerable<TCrate> GetPage(int page, int pageSize) { int num = page * pageSize; int end = Math.Min(num + pageSize, Entries.Count); if (num >= Entries.Count) { return Array.Empty<TCrate>(); } return GetPageIterator(num, end); } public TCrate? GetEntryAt(int index) { if (index < 0 || index >= Entries.Count) { return null; } return Entries[index]; } public TCrate? GetEntryAt(int page, int pageSize, int index) { int index2 = page * pageSize + index; return GetEntryAt(index2); } public int GetPageCount(int pageSize) { return (Entries.Count + pageSize - 1) / pageSize; } } } namespace SearchThing.Presets { public class Preset : BasicSearchPanel<ISearchableCrate> { private const string DefaultTag = "EMPTY"; private static readonly Sprite PresetRemoveIcon = ImageHelper.LoadEmbeddedSprite("SearchThing.resources.RemoveIcon.png"); private static readonly Sprite EditIcon = ImageHelper.LoadEmbeddedSprite("SearchThing.resources.EditIcon.png"); private string _tag = "EMPTY"; public override string Tag { get { if (!IsInitialized) { if (!PresetManager.IsAssignmentMode) { return "Empty Preset"; } return "Add Presset"; } return _tag; } } public override bool TagEditable => true; public bool IsInitialized { get; private set; } public override bool ResearchOnPageChange => true; public HashSet<ISearchableCrate> AssignedCrates { get; } = new HashSet<ISearchableCrate>(); public override bool HasPanelFunction => true; public override Sprite PanelFunctionIcon => EditIcon; public override bool HasItemFunction => true; public override Sprite ItemFunctionIcon => PresetRemoveIcon; public Preset() { IsInitialized = false; } public Preset(string tag) { _tag = tag; IsInitialized = true; } public override Color? GetItemFunctionHighlight(SpawnablePanelExtension extension, ISearchableCrate? crate) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return Color.red; } public override void OnItemFunction(SpawnablePanelExtension extension, ISearchableCrate crate) { PresetManager.IsAssignmentMode = false; RemoveCrate(crate); extension.RequestRefresh(); } public override Color? GetPanelFunctionHighlight(SpawnablePanelExtension extension) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return extension.IsEditing ? Color.green : Color.white; } public override void OnPanelFunction(SpawnablePanelExtension extension) { extension.SetIsEditing(!extension.IsEditing); extension.RenderFavoriteButton(); } public override Color? IsForceHighlighted(SpawnablePanelExtension extension, ISearchableCrate? selectedCrate) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (extension.IsPanelSelected(this)) { return Color.white; } if (!IsInitialized || selectedCrate == null || !AssignedCrates.Contains(selectedCrate)) { return null; } return Color.yellow; } private bool IsTagValid(string tag) { return !string.IsNullOrEmpty(tag); } public override void OnTagEdited(SpawnablePanelExtension extension, string newTag) { if (IsTagValid(newTag)) { _tag = newTag; IsInitialized = true; } } public override bool OnSelected(SpawnablePanelExtension extension) { if (!PresetManager.IsAssignmentMode) { return true; } bool flag = extension.IsPanelSelected(this); if (!IsInitialized) { _tag = $"Preset {Random.Shared.Next(1000, 9999)}"; IsInitialized = true; } ISearchableCrate selectedSpawnable = extension.GetSelectedSpawnable(); if (selectedSpawnable == null) { return false; } if (!AssignedCrates.Add(selectedSpawnable)) { AssignedCrates.Remove(selectedSpawnable); } PresetManager.IsAssignmentMode = false; if (flag) { extension.RequestRefresh(); } else { extension.RenderTags(); extension.RenderFavoriteButton(); } return false; } public void RemoveCrate(ISearchableCrate crate) { AssignedCrates.Remove(crate); } protected override void Search(string query, ISearchOrder order, Action<SearchResults<ISearchableCrate>> callback) { SearchManager.SearchAsync(query, AssignedCrates.ToSearchable(), (ISearchableCrate _) => true, order, callback); } public PresetData ToData() { return new PresetData { Name = _tag, Barcodes = AssignedCrates.Select((ISearchableCrate b) => b.Barcode._id).ToList() }; } public void FromData(PresetData data) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown _tag = data.Name; IsInitialized = _tag != "EMPTY"; if (!IsInitialized) { return; } AssignedCrates.Clear(); foreach (string barcode in data.Barcodes) { AssignedCrates.Add(new SearchableCrate(new Barcode(barcode))); } } } public static class PresetManager { private static readonly string FilePath; private const int MaxPresets = 6; private static bool _assignmentMode; private static readonly List<PresetPage> PresetPages; public static bool IsAssignmentMode { get { return _assignmentMode; } set { if (!value) { SavePresets(); } _assignmentMode = value; } } static PresetManager() { FilePath = MelonEnvironment.UserDataDirectory + "/SearchThingPresets.json"; PresetPages = new List<PresetPage>(); for (int i = 0; i < 6; i++) { PresetPages.Add(new PresetPage()); } } public static IReadOnlyList<ISearchPage> GetPages() { return PresetPages; } public static void LoadPresets() { if (!File.Exists(FilePath)) { return; } try { List<PresetPageData> list = JsonSerializer.Deserialize<List<PresetPageData>>(File.ReadAllText(FilePath)); if (list == null) { return; } for (int i = 0; i < list.Count; i++) { PresetPageData data = list[i]; if (i < PresetPages.Count) { PresetPages[i].FromData(data); continue; } break; } } catch (Exception ex) { MelonLogger.Error("Failed to load presets from file!", ex); } } public static void SavePresets() { try { string contents = JsonSerializer.Serialize(PresetPages.Select((PresetPage p) => p.ToData()).ToList(), new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(FilePath, contents); } catch (Exception ex) { MelonLogger.Error("Failed to save presets to file!", ex); } } } public class PresetPage : ISearchPage { public const int MaxPresets = 6; private readonly List<Preset> _presets = new List<Preset>(); public bool IsVisible => true; public IReadOnlyList<ISearchPanel> Panels => _presets; public PresetPage() { for (int i = 0; i < 6; i++) { _presets.Add(new Preset()); } } public PresetPageData ToData() { return new PresetPageData { Presets = _presets.Select((Preset p) => p.ToData()).ToList() }; } public void FromData(PresetPageData data) { for (int i = 0; i < 6; i++) { _presets[i].FromData(data.Presets[i]); } } } } namespace SearchThing.Presets.Data { public class PresetData { public string Name { get; set; } = "New Preset"; public List<string> Barcodes { get; set; } = new List<string>(); } public class PresetPageData { public List<PresetData> Presets { get; set; } = new List<PresetData>(); } } namespace SearchThing.Patches { [HarmonyPatch(typeof(AssetWarehouse))] public static class AssetWarehousePatches { [HarmonyPatch("AddPallet")] [HarmonyPostfix] public static void AddPallet_Postfix(Pallet pallet) { GlobalCrateManager.AddPallet(pallet); } } [HarmonyPatch(typeof(PopUpMenuView))] public static class PopupMenuViewPatches { [HarmonyPatch("Activate")] [HarmonyPrefix] public static void Activate_Prefix(PopUpMenuView __instance) { if (!((Object)(object)__instance == (Object)null)) { __instance.AddSpawnMenu(); } } [HarmonyPatch("RemoveSpawnMenu")] [HarmonyPrefix] public static bool RemoveSpawnMenu_Prefix(PopUpMenuView __instance) { return false; } } [HarmonyPatch(typeof(RigManager))] public static class RigManagerPatches { private static bool CheckIfLocalRig(RigManager rigManager) { return FusionPlayer.IsLocalPlayer(rigManager); } [HarmonyPatch("SwapAvatarCrate")] [HarmonyPostfix] public static void SwapAvatarCrate_Prefix(RigManager __instance, Barcode barcode) { Crate crate = default(Crate); if (!((Object)(object)__instance == (Object)null) && (!Mod.IsFusionLoaded || CheckIfLocalRig(__instance)) && AssetWarehouse.ready && AssetWarehouse.Instance.TryGetCrate(barcode, ref crate)) { HistoryManager.AddEntry(crate); } } } [HarmonyPatch(typeof(SpawnGun))] public class SpawnGunPatches { private static SpawnableCrate? _selectedCrate; private static SpawnGun? HeldSpawnGun { get; set; } public static void SelectCrate(SpawnableCrate crate) { _selectedCrate = crate; if ((Object)(object)HeldSpawnGun != (Object)null) { HeldSpawnGun.OnSpawnableSelected(_selectedCrate); } } public static void ClearSelectedCrate() { _selectedCrate = null; } private static bool IsHeldByLocalPlayer(SpawnGun spawnGun) { if (!NetworkSceneManager.IsLevelNetworked) { return true; } InteractableHost host = ((Gun)spawnGun).host; if ((Object)(object)host == (Object)null) { return false; } Hand hand = host.GetHand(0); RigManager val = ((hand != null) ? hand.manager : null); if ((Object)(object)val != (Object)null) { return FusionPlayer.IsLocalPlayer(val); } return false; } [HarmonyPatch("OnTriggerGripAttached")] [HarmonyPostfix] public static void OnTriggerGripAttached_Prefix(SpawnGun __instance, Hand hand) { if (!((Object)(object)__instance == (Object)null) && (!Mod.IsFusionLoaded || IsHeldByLocalPlayer(__instance))) { HeldSpawnGun = __instance; if ((Object)(object)_selectedCrate != (Object)null) { __instance.OnSpawnableSelected(_selectedCrate); } } } [HarmonyPatch("OnTriggerGripDetached")] [HarmonyPostfix] public static void OnTriggerGripDetached_Prefix(SpawnGun __instance, Hand hand) { if (!((Object)(object)__instance == (Object)null) && (!Mod.IsFusionLoaded || IsHeldByLocalPlayer(__instance))) { HeldSpawnGun = null; } } [HarmonyPatch("OnFire")] [HarmonyPrefix] [HarmonyPriority(800)] public static void OnFire_Prefix(SpawnGun __instance) { if (!((Object)(object)__instance == (Object)null) && (!Mod.IsFusionLoaded || IsHeldByLocalPlayer(__instance))) { SpawnableCrate selectedCrate = __instance._selectedCrate; if (!((Object)(object)selectedCrate == (Object)null)) { HistoryManager.AddEntry((Crate)(object)selectedCrate); } } } [HarmonyPatch("OnSpawnableSelected")] [HarmonyPrefix] public static bool OnSpawnableSelected_Prefix(SpawnGun __instance, SpawnableCrate crate) { if ((Object)(object)__instance == (Object)null) { return true; } if (Mod.IsFusionLoaded && !IsHeldByLocalPlayer(__instance)) { return true; } _selectedCrate = crate; if ((Object)(object)((Il2CppObjectBase)crate).TryCast<AvatarCrate>() == (Object)null) { return true; } return false; } } [HarmonyPatch(typeof(SpawnablesPanelView))] public static class ToolUiPatches { private static SpawnGun? _DummySpawnGun; private static SpawnGun GetDummySpawnGun() { //IL_0018: 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) if ((Object)(object)_DummySpawnGun != (Object)null) { return _DummySpawnGun; } GameObject val = new GameObject("DummySpawnGun"); val.SetActive(false); _DummySpawnGun = val.AddComponent<SpawnGun>(); return _DummySpawnGun; } [HarmonyPatch("Activate")] [HarmonyPrefix] public static void SpawnablesPanelView_Activate_Prefix(SpawnablesPanelView __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.spawnGun != (Object)null)) { __instance.spawnGun = GetDummySpawnGun(); __instance._spawnGun_k__BackingField = GetDummySpawnGun(); } } [HarmonyPatch("Activate")] [HarmonyPostfix] public static void SpawnablesPanelView_Activate_Postfix(SpawnablesPanelView __instance) { if (!((Object)(object)__instance == (Object)null)) { SpawnablesPanelManager.Load(__instance); } } [HarmonyPatch("SelectTab")] [HarmonyPostfix] public static void SpawnablesPanelView_SelectTab_Postfix(SpawnablesPanelView __instance, int idx) { if (!((Object)(object)__instance == (Object)null)) { SpawnablesPanelManager.OnTabSelected(__instance, idx); } } [HarmonyPatch("NextPage")] [HarmonyPrefix] public static bool NextPage_Prefix(SpawnablesPanelView __instance) { if ((Object)(object)__instance == (Object)null) { return true; } if (!SpawnablesPanelManager.TryGet(__instance, out SpawnablePanelExtension extension)) { return true; } if (!extension.IsSearchActive()) { return true; } extension.ChangePanelPage(1); return false; } [HarmonyPatch("PrevPage")] [HarmonyPrefix] public static bool PrevPage_Prefix(SpawnablesPanelView __instance) { if ((Object)(object)__instance == (Object)null) { return true; } if (!SpawnablesPanelManager.TryGet(__instance, out SpawnablePanelExtension extension)) { return true; } if (!extension.IsSearchActive()) { return true; } extension.ChangePanelPage(-1); return false; } [HarmonyPatch("SelectItem")] [HarmonyPrefix] public static bool SelectItem_Prefix(SpawnablesPanelView __instance, int idx) { if ((Object)(object)__instance == (Object)null) { return true; } if (!SpawnablesPanelManager.TryGet(__instance, out SpawnablePanelExtension extension)) { return true; } if (!extension.IsSearchActive()) { return true; } extension.OnSelectItem(idx); return false; } [HarmonyPatch("SelectCategory")] [HarmonyPrefix] public static bool SelectCategory_Prefix(SpawnablesPanelView __instance, int idx) { if ((Object)(object)__instance == (Object)null) { return true; } if (!SpawnablesPanelManager.TryGet(__instance, out SpawnablePanelExtension extension)) { return true; } if (!extension.IsSearchActive()) { return true; } extension.SelectCategory(idx); return false; } [HarmonyPatch("NextTagPage")] [HarmonyPrefix] private static bool NextTagPage_Prefix(SpawnablesPanelView __instance) { if ((Object)(object)__instance == (Object)null) { return true; } if (!SpawnablesPanelManager.TryGet(__instance, out SpawnablePanelExtension extension)) { return true; } if (!extension.IsSearchActive()) { return true; } extension.ChangeTagPage(1); return false; } [HarmonyPatch("PrevTagPage")] [HarmonyPrefix] private static bool PrevTagPage_Prefix(SpawnablesPanelView __instance) { if ((Object)(object)__instance == (Object)null) { return true; } if (!SpawnablesPanelManager.TryGet(__instance, out SpawnablePanelExtension extension)) { return true; } if (!extension.IsSearchActive()) { return true; } extension.ChangeTagPage(-1); return false; } [HarmonyPatch("SwapSortButton")] [HarmonyPrefix] public static bool SwapSortButton_Prefix(SpawnablesPanelView __instance) { if ((Object)(object)__instance == (Object)null) { return true; } if (!SpawnablesPanelManager.TryGet(__instance, out SpawnablePanelExtension extension)) { return true; } if (!extension.IsSearchActive()) { return true; } extension.SwapSortButton(); return false; } [HarmonyPatch("FavoriteItem")] [HarmonyPrefix] public static bool FavoriteItem_Prefix(SpawnablesPanelView __instance) { if ((Object)(object)__instance == (Object)null) { return true; } if (!SpawnablesPanelManager.TryGet(__instance, out SpawnablePanelExtension extension)) { return true; } if (!extension.IsSearchActive()) { return true; } extension.OnFavoriteButton(); return false; } [HarmonyPatch("SelectItem")] [HarmonyPostfix] public static void SelectItem_Postfix(SpawnablesPanelView __instance, int idx) { if (!((Object)(object)__instance == (Object)null) && SpawnablesPanelManager.TryGet(__instance, out SpawnablePanelExtension extension) && extension.IsSearchActive()) { extension.RenderFavoriteButton(); } } [HarmonyPatch("SelectItem")] [HarmonyPrefix] public static void ToggleFavorite_Prefix(SpawnablesPanelView __instance, int idx) { if (!((Object)(object)__instance == (Object)null) && SpawnablesPanelManager.TryGet(__instance, out SpawnablePanelExtension extension) && extension.IsSearchActive()) { extension.RenderFavoriteButton(); } } } } namespace SearchThing.Patches.Compatibility { public static class FusionNetworkSpawnPatch { private static class FusionIntegrationPatches { [HarmonyPostfix] public static void RegisterSpawnHistory(ReceivedMessage received) { if (NetworkInfo.HasServer) { SerializedSpawnData val = ((ReceivedMessage)(ref received)).ReadData<SerializedSpawnData>(); if (val != null) { FusionSpawnHistory.AddEntry(val.Barcode, ((ReceivedMessage)(ref received)).Sender); } } } } private static void TryPatch() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown try { Harmony val = new Harmony("com.mash.searchthing.fusionspawnhistoryintegration"); MethodInfo method = typeof(SpawnRequestMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.NonPublic); if (method == null) { MelonLogger.Warning("MIDT integration: Could not find OnSpawnDelegateFusion method"); return; } MethodInfo method2 = typeof(FusionIntegrationPatches).GetMethod("RegisterSpawnHistory"); if (val.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null) != null) { MelonLogger.Msg("Fusion integration: Successfully applied RegisterSpawnHistory patch"); } else { MelonLogger.Warning("Fusion integration: Failed to apply patch, harmony.Patch returned null"); } } catch (Exception value) { MelonLogger.Error($"Failed to patch MIDT integration: {value}"); } } public static void TryInitialize() { if (Mod.IsFusionLoaded) { TryPatch(); } } } } namespace SearchThing.Keyboard { public class Keyboard { private static readonly Vector2 KeySize = new Vector2(80f, 80f); private static readonly Vector2 KeySpacing = new Vector2(10f, 10f); private const int KeyboardLayer = 5; private static readonly string[] KeyRows = new string[4] { "1234567890", "QWERTYUIOP", "ASDFGHJKL", "ZXCVBNM" }; private readonly GameObject _parent; private GameObject? _keyboardRoot; private string _text = ""; private readonly TMP_FontAsset _font; private readonly Sprite _bg; private readonly Sprite _outlineBg; public event Action<string>? OnTextChanged; public Keyboard(GameObject parent, ButtonReferenceHolder resources) { _parent = parent; _font = ((TMP_Text)resources.tmp).font; _bg = resources.background.sprite; _outlineBg = resources.highlight.sprite; Create(); } public void SetText(string text, bool triggerEvent = true) { _text = text; if (triggerEvent) { OnInternalTextChanged(_text); } } private void Create() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) _keyboardRoot = new GameObject("Keyboard"); _keyboardRoot.transform.SetParent(_parent.transform, false); _keyboardRoot.transform.localPosition = new Vector3(-85f, -450f, 0f); _keyboardRoot.transform.localRotation = Quaternion.Euler(0f, 0f, 0f); _keyboardRoot.layer = 5; _keyboardRoot.AddComponent<CanvasRenderer>(); ((Graphic)_keyboardRoot.AddComponent<Image>()).color = Color.clear; RectTransform component = _keyboardRoot.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0f, 0f); component.anchorMax = new Vector2(1f, 1f); component.pivot = new Vector2(0.5f, 0.5f); component.offsetMin = new Vector2(10f, 10f); component.offsetMax = new Vector2(-10f, -10f); CreateKeys(); } private void CreateKey(string text, Vector2 position, Vector2 size, Action action, Vector2? margin = null) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011f: 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_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0193: 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_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: 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_0234: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_keyboardRoot == (Object)null) { throw new InvalidOperationException("Keyboard root is not initialized."); } GameObject val = new GameObject("Key_" + text); val.transform.SetParent(_keyboardRoot.transform, false); RectTransform val2 = val.AddComponent<RectTransform>(); val.AddComponent<CanvasRenderer>(); GameObject val3 = new GameObject("bg"); val3.transform.SetParent(val.transform, false); val3.AddComponent<RectTransform>().sizeDelta = size; Image val4 = val3.AddComponent<Image>(); val4.sprite = _bg; val4.type = (Type)1; GameObject val5 = new GameObject("image_backline"); val5.transform.SetParent(val.transform, false); val5.AddComponent<RectTransform>().sizeDelta = size; Image obj = val5.AddComponent<Image>(); obj.sprite = _outlineBg; obj.type = (Type)1; ((Graphic)obj).raycastTarget = false; obj.fillCenter = false; GameObject val6 = new GameObject("Collider"); val6.transform.SetParent(val.transform, false); BoxCollider obj2 = val6.AddComponent<BoxCollider>(); Vector2 val7 = size + margin.GetValueOrDefault(); obj2.size = new Vector3(val7.x, val7.y, 1f); ((Collider)obj2).isTrigger = true; Button obj3 = val.AddComponent<Button>(); ((UnityEvent)obj3.onClick).AddListener(UnityAction.op_Implicit(action)); ((Selectable)obj3).transition = (Transition)1; ((Selectable)obj3).targetGraphic = (Graphic)(object)val4; ColorBlock colors = ((Selectable)obj3).colors; ((ColorBlock)(ref colors)).normalColor = new Color(0f, 0f, 0f, 0.6118f); ((ColorBlock)(ref colors)).highlightedColor = new Color(0.6038f, 0.6038f, 0.6038f, 0.209f); ((ColorBlock)(ref colors)).pressedColor = new Color(0.7176f, 0.7176f, 0.7176f, 1f); ((ColorBlock)(ref colors)).selectedColor = ((ColorBlock)(ref colors)).normalColor; ((Selectable)obj3).colors = colors; val.AddComponent<ButtonHoverClick>(); GameObject val8 = new GameObject("Text"); val8.transform.SetParent(val.transform, false); TextMeshProUGUI obj4 = val8.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj4).text = text; ((TMP_Text)obj4).font = _font; ((TMP_Text)obj4).fontSize = 40f; ((Graphic)obj4).color = Color.white; ((TMP_Text)obj4).alignment = (TextAlignmentOptions)514; RectTransform component = val8.GetComponent<RectTransform>(); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; component.offsetMin = Vector2.zero; component.offsetMax = Vector2.zero; val2.sizeDelta = size; val2.anchoredPosition = position; val.layer = 5; val6.layer = 5; } private void CreateKeys() { //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_keyboardRoot == (Object)null) { return; } float num = 0f; string[] keyRows = KeyRows; Vector2 position = default(Vector2); foreach (string text in keyRows) { float num2 = (0f - ((float)text.Length * KeySize.x + (float)(text.Length - 1) * KeySpacing.x)) / 2f; for (int j = 0; j < text.Length; j++) { char keyChar = text[j]; ((Vector2)(ref position))..ctor(num2 + (float)j * (KeySize.x + KeySpacing.x) + KeySize.x / 2f, num); CreateKey(keyChar.ToString(), position, KeySize, delegate { OnKeyPress(keyChar); }, KeySpacing / 2f); } num -= KeySize.y + KeySpacing.y; } CreateKey("Backspace", new Vector2(-280f, num), new Vector2(240f, 80f), OnBackspace); CreateKey("Space", new Vector2(0f, num), new Vector2(249f, 80f), OnSpace); CreateKey("Clear", new Vector2(280f, num), new Vector2(240f, 80f), delegate { SetText(""); }); } private void OnInternalTextChanged(string text) { this.OnTextChanged?.Invoke(text); } private void OnKeyPress(char key) { _text += key; OnInternalTextChanged(_text); } private void OnBackspace() { if (_text.Length > 0) { string text = _text; _text = text.Substring(0, text.Length - 1); OnInternalTextChanged(_text); } } private void OnSpace() { _text += " "; OnInternalTextChanged(_text); } public void Show() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_keyboardRoot == (Object)null)) { _keyboardRoot.SetActive(true); _keyboardRoot.transform.SetAsLastSibling(); _keyboardRoot.transform.localPosition = new Vector3(-85f, -450f, 0f); } } public void Hide() { if (!((Object)(object)_keyboardRoot == (Object)null)) { _keyboardRoot.SetActive(false); } } } } namespace SearchThing.History { public interface IHistorySearchableCrate : ISearchableCrate { new DateTime DateAdded { get; set; } } public class BoundCrateList<TCrate> : ISearchableCrateList<TCrate> where TCrate : class, IHistorySearchableCrate { private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); private readonly Dictionary<string, TCrate> _crates = new Dictionary<string, TCrate>(); private readonly LinkedList<string> _accessOrder = new LinkedList<string>(); private readonly Dictionary<string, LinkedListNode<string>> _nodes = new Dictionary<string, LinkedListNode<string>>(); private const int MaxEntries = 100; public void AddCrate(TCrate crate) { _lock.EnterWriteLock(); try { string id = crate.Barcode._id; if (_crates.TryGetValue(id, out var value)) { value.DateAdded = DateTime.UtcNow; _accessOrder.Remove(_nodes[id]); _nodes[id] = _accessOrder.AddLast(id); return; } crate.DateAdded = DateTime.UtcNow; _crates[id] = crate; _nodes[id] = _accessOrder.AddLast(id); if (_crates.Count > 100) { RemoveOldest(); } } finally { _lock.ExitWriteLock(); } } private void RemoveOldest() { if (_accessOrder.First != null) { string value = _accessOrder.First.Value; _accessOrder.RemoveFirst(); _nodes.Remove(value); _crates.Remove(value); } } public IEnumerable<TCrate> GetCrates() { _lock.EnterReadLock(); try { return _crates.Values.ToArray(); } finally { _lock.ExitReadLock(); } } } public class HistoryCrateEntry : IHistorySearchableCrate, ISearchableCrate { public ISearchableCrate Crate { get; } public DateTime DateAdded { get; set; } public SearchTag Name => Crate.Name; public SearchTag PalletName => Crate.PalletName; public SearchTag Author => Crate.Author; public SearchTag[] Tags => Crate.Tags; public string Description => Crate.Description; public bool Redacted => Crate.Redacted; public CrateType CrateType => Crate.CrateType; public CrateSubType CrateSubType => Crate.CrateSubType; public int Salt => Crate.Salt; public int Score => 0; public Barcode Barcode => Crate.Barcode; public HistoryCrateEntry(ISearchableCrate crate, DateTime dateAdded) { Crate = crate; DateAdded = dateAdded; } } public static class HistoryManager { private static readonly BoundCrateList<HistoryCrateEntry> BoundEntries = new BoundCrateList<HistoryCrateEntry>(); public static void AddEntry(Crate crate) { BoundEntries.AddCrate(new HistoryCrateEntry(new SearchableCrate(crate), DateTime.Now)); } public static void SearchAsync(string query, ISearchOrder order, Func<ISearchableCrate, bool> filter, Action<SearchResults<HistoryCrateEntry>> callback) { SearchManager.SearchAsync(query, BoundEntries, filter, order, callback); } } } namespace SearchThing.Fusion { public static class FusionBlacklistHelper { private static List<string>? GetBlacklist() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) Traverse val = new Traverse(typeof(ModBlacklist)).Field("_blacklistedModIds"); if (val.FieldExists()) { return val.GetValue<List<string>>(); } MelonLogger.Error("Failed to get blacklist: _blacklistedModIds field not found"); return new List<string>(); } private static void SaveBlacklist(List<string> blacklist) { using StreamWriter streamWriter = File.CreateText(PersistentData.GetPath("mod_blacklist.txt")); streamWriter.WriteLine("# This file is for preventing the use of specific mods while in a server."); streamWriter.WriteLine("# To blacklist a mod, add a mod identifier on its own line."); streamWriter.WriteLine("# A mod identifier can either be its mod.io number ID, mod.io URL ID, or AssetWarehouse barcode."); streamWriter.WriteLine("# When the identifier is a number ID or URL ID, it will block the mod from being downloaded."); streamWriter.WriteLine("# On the other hand, if the identifier is a AssetWarehouse barcode, it will prevent the mod from being used."); streamWriter.WriteLine("# For server hosts, blacklisting a barcode prevents all clients from using that mod."); streamWriter.WriteLine("#"); streamWriter.WriteLine("# Examples"); streamWriter.WriteLine("# -------------------------------------"); streamWriter.WriteLine("# Number ID"); streamWriter.WriteLine("# 4057308"); streamWriter.WriteLine("#"); streamWriter.WriteLine("# URL ID"); streamWriter.WriteLine("# test-chambers"); streamWriter.WriteLine("#"); streamWriter.WriteLine("# Barcode"); streamWriter.WriteLine("# SLZ.TestChambers.Level.TestChamber02"); streamWriter.WriteLine("# SLZ.TestChambers.Level.TestChamber07"); streamWriter.WriteLine("# -------------------------------------"); foreach (string item in blacklist) { streamWriter.WriteLine(item); } } public static void ToggleBlacklist(string barcode) { List<string> blacklist = GetBlacklist(); if (blacklist == null) { MelonLogger.Error("Cannot toggle blacklist: failed to retrieve blacklist"); return; } if (blacklist.Contains(barcode)) { blacklist.Remove(barcode); } else { blacklist.Add(barcode); } SaveBlacklist(blacklist); } public static bool IsBlacklisted(string barcodeID) { return ModBlacklist.IsBlacklisted(barcodeID); } } public class FusionBlocklistPage : BasicSearchPanel<ISearchableCrate> { private static readonly Sprite BlockIcon = ImageHelper.LoadEmbeddedSprite("SearchThing.resources.BlockIcon.png"); public override string Tag => "Fusion Blocklist"; public override bool CanAssign => false; public override Sprite ItemFunctionIcon => BlockIcon; public override bool HasItemFunction => true; public override ISelectableSearchOrder[] SupportedOrders { get; } = new ISelectableSearchOrder[5] { new IsBlockedFilter(), new DateNewAddedSearchOrder(), new DateOldAddedSearchOrder(), new ScoreSearchOrder(), new AlphabeticalSearchOrder() }; public override Color? GetItemFunctionHighlight(SpawnablePanelExtension extension, ISearchableCrate? crate) { //IL_0015: 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) return (crate != null && FusionBlacklistHelper.IsBlacklisted(crate.Barcode._id)) ? Color.red : Color.green; } public override void OnItemFunction(SpawnablePanelExtension extension, ISearchableCrate crate) { FusionBlacklistHelper.ToggleBlacklist(crate.Barcode._id); MakeDirty(); extension.RequestRefresh(); } protected override void Search(string query, ISearchOrder order, Action<SearchResults<ISearchableCrate>> callback) { SearchManager.SearchAsync(query, GlobalCrateManager.GetCrates(), (ISearchableCrate c) => c.CrateType == CrateType.Prop, order, callback); } } public class FusionPage : ISearchPage { public bool IsVisible => Mod.IsFusionLoaded; public IReadOnlyList<ISearchPanel> Panels { get; } = new ISearchPanel[2] { new FusionBlocklistPage(), new FusionSpawnHistoryPage() }; } public record FusionSpawnHistoryEntry(Barcode Barcode, PlayerID? SpawnerId) : IHistorySearchableCrate, ISearchableCrate { public ISearchableCrate? Crate { get; } = GlobalCrateManager.GetCrate(Barcode); public SearchTag Name => Crate?.Name ?? UnknownCrateTag; public SearchTag PalletName => Crate?.PalletName ?? UnknownCrateTag; public SearchTag Author => Crate?.Author ?? UnknownCrateTag; public SearchTag[] Tags => Crate?.Tags ?? Array.Empty<SearchTag>(); public string Description => Crate?.Description ?? "No description available."; public bool Redacted => Crate?.Redacted ?? false; public CrateType CrateType => Crate?.CrateType ?? CrateType.Invalid; public CrateSubType CrateSubType => Crate?.CrateSubType ?? CrateSubType.None; public int Salt => Crate?.Salt ?? 0; public int Score => Crate?.Score ?? 0; public DateTime DateAdded { get; set; } private static readonly SearchTag UnknownCrateTag = new SearchTag("Unknown Crate"); [CompilerGenerated] protected FusionSpawnHistoryEntry(FusionSpawnHistoryEntry original) { Barcode = original.Barcode; SpawnerId = original.SpawnerId; Crate = original.Crate; DateAdded = original.DateAdded; } } public static class FusionSpawnHistory { private static readonly BoundCrateList<FusionSpawnHistoryEntry> BoundEntries = new BoundCrateList<FusionSpawnHistoryEntry>(); public static void AddEntry(string barcode, byte? smallPlayerId) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown PlayerID spawnerId = (smallPlayerId.HasValue ? PlayerIDManager.GetPlayerID(smallPlayerId.Value) : null); Barcode barcode2 = new Barcode(barcode); BoundEntries.AddCrate(new FusionSpawnHistoryEntry(barcode2, spawnerId)); } public static void SearchAsync(string query, ISearchOrder order, Func<ISearchableCrate, bool> filter, Action<SearchResults<FusionSpawnHistoryEntry>> callback) { SearchManager.SearchAsync(query, BoundEntries, filter, order, callback); } } public class FusionSpawnHistoryPage : BasicSearchPanel<FusionSpawnHistoryEntry> { private static readonly Sprite BlockIcon = ImageHelper.LoadEmbeddedSprite("SearchThing.resources.BlockIcon.png"); public override string Tag => "Fusion Spawn History"; public override bool IsVisible => NetworkInfo.HasServer; public override bool CanAssign => false; public override bool ResearchOnPageChange => true; public override Sprite ItemFunctionIcon => BlockIcon; public override bool HasItemFunction => true; public override ISelectableSearchOrder[] SupportedOrders { get; } = new ISelectableSearchOrder[5] { new DateNewAddedSearchOrder(), new DateOldAddedSearchOrder(), new ScoreSearchOrder(), new AlphabeticalSearchOrder(), new RandomSearchOrder() }; public override Color? GetItemFunctionHighlight(SpawnablePanelExtension extension, ISearchableCrate? crate) { //IL_0015: 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) return (crate != null && FusionBlacklistHelper.IsBlacklisted(crate.Barcode._id)) ? Color.red : Color.green; } public override void OnItemFunction(SpawnablePanelExtension extension, ISearchableCrate crate) { FusionBlacklistHelper.ToggleBlacklist(crate.Barcode._id); extension.RequestRefresh(); } public override ItemRenderData GetRenderDataForCrate(FusionSpawnHistoryEntry crate) { PlayerID? spawnerId = crate.SpawnerId; string input = default(string); string text = ((spawnerId != null && spawnerId.IsValid && MetadataHelper.TryGetDisplayName(crate.SpawnerId, ref input)) ? StringHelper.RemoveUnityRichText(input) : "Unknown"); return new ItemRenderData { Name = crate.Name.Original + " (" + text + ")", Description = crate.Description, Author = crate.Author.Original, PalletName = crate.PalletName.Original, Tags = crate.Tags.Select((SearchTag t) => t.Original).ToArray(), Icon = CrateIconProvider.GetIcon(crate) }; } protected override void Search(string query, ISearchOrder order, Action<SearchResults<FusionSpawnHistoryEntry>> callback) { FusionSpawnHistory.SearchAsync(query, order, (ISearchableCrate c) => c.CrateType == CrateType.Prop, callback); } } public class IsBlockedFilter : ISelectableSearchOrder, ISearchOrder { public string Name => "Blocked First"; public int Order(ISearchableCrate searchableCrate) { if (FusionBlacklistHelper.IsBlacklisted(searchableCrate.Barcode._id)) { return 10000 + searchableCrate.Score; } return searchableCrate.Score; } } } namespace SearchThing.Extensions { public class SpawnablePageProvider { private readonly ISearchPage[] _basePages = new ISearchPage[2] { new BasicSearchPage(new PropTagSearchPanel(), new AvatarTagSearchPanel(), new PropHistorySearchPanel(), new AvatarHistorySearchPanel(), new LevelTagSearchPanel()), new FusionPage() }; public int PageCount => GetAllPages().Count((ISearchPage c) => c.IsVisible); public IEnumerable<ISearchPage> GetAllPages() { return _basePages.Concat(PresetManager.GetPages()); } public ISearchPage[] GetVisiblePages() { return (from p in GetAllPages() where p.IsVisible select p).ToArray(); } public ISearchPage GetBasePage() { return _basePages[0]; } public ISearchPage GetPage(int index) { ISearchPage[] visiblePages = GetVisiblePages(); int num = Math.Clamp(index, 0, visiblePages.Length - 1); return visiblePages[num]; } } public class SpawnablePanelExtension { public const int SearchTabIndex = 5; private const string SourceTabButtonPath = "group_tabs/grid_tabs/button_tab_05"; private const string SearchTabName = "button_tab_search"; private string _searchQuery = ""; private readonly SpawnablesPanelView _panelView; private readonly SearchThing.Keyboard.Keyboard _keyboard; private readonly List<ItemButton> _itemButtons = new List<ItemButton>(); private GameObject _itemPageNextButton; private GameObject _itemPagePreviousButton; private readonly List<TagButton> _tagButtons = new List<TagButton>(); private GameObject _tagPageNextButton; private GameObject _tagPagePreviousButton; private static readonly Sprite TabIcon = ImageHelper.LoadEmbeddedSprite("SearchThing.resources.SearchIcon.png"); private SpawnInfoFocus _currentFocus = SpawnInfoFocus.SelectedItem; private string _editValue = ""; private Image _fadedButtonImage; private Image _favoriteButtonImage; private Sprite _originalFavoriteSprite; private Color _originalFavoriteColor = Color.white; private TextMeshPro _sortButtonText; private GameObject _sortButtonObject; private int _renderedTagPageIndex; private int _selectedItemIndex; private int _selectedTagIndex; private int _selectedPageIndex; private readonly SpawnablePageProvider _pages = new SpawnablePageProvider(); public bool IsEditing { get; private set; } private void AddTab() { Transform val = ((Component)_panelView).transform.Find("group_tabs/grid_tabs/button_tab_05"); if ((Object)(object)val == (Object)null) { MelonLogger.Error("Failed to find source button at path: group_tabs/grid_tabs/button_tab_05"); } else { if ((Object)(object)((Component)val).transform.FindChild("button_tab_search") != (Object)null) { return; } GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, val.parent); ((Object)val2).name = "button_tab_search"; Button component = val2.GetComponent<Button>(); ButtonReferenceHolder component2 = val2.GetComponent<ButtonReferenceHolder>(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null) { MelonLogger.Error("Failed to find Button component in search button."); return; } ((UnityEventBase)component.onClick).RemoveAllListeners(); ((UnityEvent)component.onClick).AddListener(UnityAction.op_Implicit((Action)OnSearchTabClicked)); Transform obj = val2.transform.FindChild("image_icon"); Image val3 = ((obj != null) ? ((Component)obj).GetComponent<Image>() : null); if ((Object)(object)val3 != (Object)null) { val3.sprite = TabIcon; } List<ButtonReferenceHolder> list = ((IEnumerable<ButtonReferenceHolder>)_panelView.tabButtons).ToList(); list.Add(component2); _panelView.tabButtons = new Il2CppReferenceArray<ButtonReferenceHolder>(list.ToArray()); Transform obj2 = val2.transform.Find("text_spawnable_val"); TextMeshPro val4 = ((obj2 != null) ? ((Component)obj2).GetComponent<TextMeshPro>() : null); if ((Object)(object)val4 != (Object)null) { ((TMP_Text)val4).text = "Search"; } else { MelonLogger.Error("Failed to find text component in search button."); } } } private void OnSearchTabClicked() { _panelView.SelectTab(5); } private void FetchSortButton() { _sortButtonText = ((Component)((Component)_panelView).transform.Find("group_treePath/text_treePath")).GetComponent<TextMeshPro>(); ((TMP_Text)_sortButtonText).alignment = (TextAlignmentOptions)513; _sortButtonObject = ((Component)((Component)_panelView).transform.Find("group_treePath/button_SwapSort")).gameObject; } private void FetchFavoriteButton() { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) Transform val = ((Component)_panelView).transform.Find("group_selectedInfo/button_Favorite"); if ((Object)(object)val == (Object)null) { MelonLogger.Error("Failed to find favorite button."); return; } ButtonReferenceHolder component = ((Component)val).GetComponent<ButtonReferenceHolder>(); _fadedButtonImage = component.highlight; _favoriteButtonImage = component.special; if ((Object)(object)_favoriteButtonImage == (Object)null || (Object)(object)_fadedButtonImage == (Object)null) { MelonLogger.Error("Failed to find Image component in favorite button."); return; } _originalFavoriteSprite = _favoriteButtonImage.sprite; _originalFavoriteColor = ((Graphic)_favoriteButtonImage).color; } private void FetchTagButtons() { foreach (ButtonReferenceHolder item in (Il2CppArrayBase<ButtonReferenceHolder>)(object)_panelView.treeButtons) { if (!((Object)(object)item == (Object)null)) { _tagButtons.Add(new TagButton(item)); } } _tagPageNextButton = ((Component)_panelView.treeScrollDownButton).gameObject; _tagPagePreviousButton = ((Component)_panelView.treeScrollUpButton).gameObject; } private void FetchItemButtons() { foreach (ButtonReferenceHolder item in (Il2CppArrayBase<ButtonReferenceHolder>)(object)_panelView.itemButtons) { if (!((Object)(object)item == (Object)null)) { _itemButtons.Add(new ItemButton(item)); } } _itemPageNextButton = ((Component)_panelView.itemScrollDownButton).gameObject; _itemPagePreviousButton = ((Component)_panelView.itemScrollUpButton).gameObject; } public SpawnablePanelExtension(SpawnablesPanelView panelView) { //IL_0034: 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) _panelView = panelView; AddTab(); FetchSortButton(); FetchFavoriteButton(); FetchItemButtons(); FetchTagButtons(); ButtonReferenceHolder component = ((Component)((Component)_panelView).transform.Find("group_spawnSelect/section_SpawnablesList/grid_buttons/button_item_01")).GetComponent<ButtonReferenceHolder>(); _keyboard = new SearchThing.Keyboard.Keyboard(((Component)_panelView).gameObject, component); _keyboard.OnTextChanged += OnSearchQueryChanged; _keyboard.Hide(); RequestRefresh(); } public bool IsPanelSelected(ISearchPanel page) { return GetSelectedPanel().Id == page.Id; } private ISearchPage GetRenderPage() { int renderedTagPageIndex = _renderedTagPageIndex; if (renderedTagPageIndex < 0 || renderedTagPageIndex >= _pages.PageCount) { return _pages.GetBasePage(); } return _pages.GetPage(renderedTagPageIndex); } private ISearchPanel? GetRenderPanel(int idx) { ISearchPage renderPage = GetRenderPage(); if (idx < 0 || idx >= renderPage.Panels.Count) { return null; } return renderPage.Panels[idx]; } private ISearchPage GetSelectedPage() { int selectedPageIndex = _selectedPageIndex; if (selectedPageIndex < 0 || selectedPageIndex >= _pages.PageCount) { return _pages.GetBasePage(); } return _pages.GetPage(selectedPageIndex); } private ISearchPanel GetSelectedPanel(int idx = -1) { ISearchPage selectedPage = GetSelectedPage(); int selectedTagIndex = _selectedTagIndex; if (selectedTagIndex < 0 || selectedTagIndex >= selectedPage.Panels.Count) { return selectedPage.Panels[0]; } return selectedPage.Panels[(idx >= 0) ? idx : selectedTagIndex]; } private void OnSearchQueryChanged(string query) { if (IsEditing) { _editValue = query; RenderTags(); RenderFocus(); } else { _searchQuery = query; RequestRefresh(); } } public void SetIsEditing(bool isEditing) { if (isEditing == IsEditing) { return; } IsEditing = isEditing; ISearchPanel selectedPanel = GetSelectedPanel(); if (!selectedPanel.TagEditable) { IsEditing = false; return; } if (IsEditing) { PresetManager.IsAssignmentMode = false; _editValue = selectedPanel.Tag; _keyboard.SetText(_editValue, triggerEvent: false); } else { _keyboard.SetText(_searchQuery, triggerEvent: false); selectedPanel.OnTagEdited(this, _editValue); RenderTags(); } RequestRefresh(); } public void RequestRefresh() { ISearchPanel selectedPanel = GetSelectedPanel(); selectedPanel.Query = _searchQuery; selectedPanel.RequestSearch(this); } public ISearchableCrate? GetSelectedSpawnable() { ISearchPanel selectedPanel = GetSelectedPanel(); int selectedItemIndex = _selectedItemIndex; if (selectedItemIndex < 0 || selectedItemIndex >= 12) { return null; } return selectedPanel.GetCrateAt(_selectedItemIndex); } public void RenderTags() { ISearchableCrate selectedSpawnable = GetSelectedSpawnable(); for (int i = 0; i < _tagButtons.Count; i++) { TagButton tagButton = _tagButtons[i]; ISearchPanel renderPanel = GetRenderPanel(i); if (renderPanel == null || !renderPanel.IsVisible) { tagButton.Hide(); continue; } bool flag = i == _selectedTagIndex && _selectedPageIndex == _renderedTagPageIndex; string tag = ((IsEditing && _currentFocus == SpawnInfoFocus.SelectedPage && flag) ? _editValue : renderPanel.Tag); Color? color = renderPanel.IsForceHighlighted(this, selectedSpawnable); tagButton.SetTag(tag, flag || color.HasValue, color); } int pageCount = _pages.PageCount; ((TMP_Text)_panelView.treePageText).text = $"{_renderedTagPageIndex + 1}/{pageCount}"; _tagPageNextButton.SetActive(_renderedTagPageIndex < pageCount - 1); _tagPagePreviousButton.SetActive(_renderedTagPageIndex > 0); } public void RenderSpecialButtons(ISearchPanel? selectedPanel = null) { if (selectedPanel == null) { selectedPanel = GetSelectedPanel(); } if (selectedPanel.SupportedOrders.Length > 1) { _sortButtonObject.SetActive(true); ((Component)_sortButtonText).gameObject.SetActive(true); ISelectableSearchOrder selectableSearchOrder = selectedPanel.SupportedOrders[selectedPanel.SelectedOrderIndex]; ((TMP_Text)_sortButtonText).text = selectableSearchOrder.Name; ((TMP_Text)_sortButtonText).alignment = (TextAlignmentOptions)513; } else { _sortButtonObject.SetActive(false); ((Component)_sortButtonText).gameObject.SetActive(false); } RenderFavoriteButton(); } public (Sprite?, Color?) GetFavoriteSprite() { ISearchPanel selectedPanel = GetSelectedPanel(); if (_currentFocus == SpawnInfoFocus.SelectedItem && selectedPanel.HasItemFunction) { ISearchableCrate selectedSpawnable = GetSelectedSpawnable(); Color? itemFunctionHighlight = selectedPanel.GetItemFunctionHighlight(this, selectedSpawnable); return (selectedPanel.ItemFunctionIcon ?? _originalFavoriteSprite, itemFunctionHighlight); } if (selectedPanel.HasPanelFunction) { Color? panelFunctionHighlight = selectedPanel.GetPanelFunctionHighlight(this); return (selectedPanel.PanelFunctionIcon ?? _originalFavoriteSprite, panelFunctionHighlight); } return (null, null); } public void RenderFavoriteButton() { //IL_00eb: Unknown result type (might be due to invalid IL or missing references) bool flag = (Object)(object)_panelView.selectedObject != (Object)null && _panelView.favoriteCrates.ContainsKey(((Scannable)_panelView.selectedObject)._barcode._id); if (!IsSearchActive()) { ((Behaviour)_fadedButtonImage).enabled = !flag; ((Behaviour)_favoriteButtonImage).enabled = flag; _favoriteButtonImage.sprite = _originalFavoriteSprite; _fadedButtonImage.sprite = _originalFavoriteSprite; return; } (Sprite?, Color?) favoriteSprite = GetFavoriteSprite(); Sprite item = favoriteSprite.Item1; bool flag2 = (Object)(object)item != (Object)null; Color? item2 = favoriteSprite.Item2; bool hasValue = item2.HasValue; ((Behaviour)_fadedButtonImage).enabled = !hasValue && flag2; ((Behaviour)_favoriteButtonImage).enabled = hasValue && flag2; _fadedButtonImage.sprite = item; _favoriteButtonImage.sprite = item; if (hasValue) { ((Graphic)_favoriteButtonImage).color = item2.Value; } } public void RenderFocus() { if (_currentFocus == SpawnInfoFocus.SelectedItem) { ISearchableCrate selectedSpawnable = GetSelectedSpawnable(); if (selectedSpawnable == null) { ((TMP_Text)_panelView.selectedTitle).text = ""; ((TMP_Text)_panelView.selectedDescription).text = ""; ((TMP_Text)_panelView.selectedAuthor).text = ""; ((TMP_Text)_panelView.selectedPallet).text = ""; ((TMP_Text)_panelView.selectedTags).text = ""; } else { ((TMP_Text)_panelView.selectedTitle).text = selectedSpawnable.Name.Original; ((TMP_Text)_panelView.selectedDescription).text = selectedSpawnable.Description; ((TMP_Text)_panelView.selectedPallet).text = selectedSpawnable.PalletName.Original; ((TMP_Text)_panelView.selectedAuthor).text = selectedSpawnable.Author.Original ?? ""; ((TMP_Text)_panelView.selectedTags).text = string.Join(", ", selectedSpawnable.Tags.Select((SearchTag t) => t.Original)); } } else { ISearchPanel selectedPanel = GetSelectedPanel(); ((TMP_Text)_panelView.selectedTitle).text = (IsEditing ? _editValue : selectedPanel.Tag); ((TMP_Text)_panelView.selectedDescription).text = "N/A"; ((TMP_Text)_panelView.selectedAuthor).text = "N/A"; ((TMP_Text)_panelView.selectedPallet).text = "N/A"; ((TMP_Text)_panelView.selectedTags).text = "N/A"; } RenderFavoriteButton(); } public void RenderItemButtons() { ISearchPanel selectedPanel = GetSelectedPanel(); IReadOnlyList<ItemRenderData> page = selectedPanel.GetPage(selectedPanel.Page); if (_selectedItemIndex >= page.Count) { _selectedItemIndex = page.Count - 1; RenderFocus(); } for (int i = 0; i < _itemButtons.Count; i++) { ItemButton itemButton = _itemButtons[i]; if (i < page.Count) { ItemRenderData crate = page[i]; itemButton.SetCrate(crate, _selectedItemIndex == i); } else { itemButton.Hide(); } } int pageCount = selectedPanel.PageCount; _panelView._numberOfPages = pageCount; ((TMP_Text)_panelView.labelText).text = _searchQuery; ((TMP_Text)_panelView.itemPageText).text = $"{selectedPanel.Page + 1}/{pageCount}"; _itemPageNextButton.SetActive(selectedPanel.Page < selectedPanel.PageCount - 1); _itemPagePreviousButton.SetActive(selectedPanel.Page > 0); } public void RenderAll() { if (IsSearchActive()) { RenderTags(); RenderItemButtons(); RenderFocus(); RenderSpecialButtons(); } } public void ChangePanelPage(int offset) { GetSelectedPanel().ChangePage(this, offset); } private void AssignSpawnableCrate(SpawnableCrate spawnableCrate) { SpawnGunPatches.SelectCrate(spawnableCrate); } private void AssignAvatarCrate(Scannable avatarCrate) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) AvatarCrateReference val = new AvatarCrateReference(avatarCrate._barcode); PullCordDevice cordDevice = BodylogAccessor.GetCordDevice(); if ((Object)(object)cordDevice != (Object)null) { UniTaskVoid val2 = cordDevice.SwapAvatar(val); ((UniTaskVoid)(ref val2)).Forget(); } } private void LoadLevelCrate(Scannable levelCrate) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown UniTaskExtensions.Forget(SceneStreamer.LoadAsync(new LevelCrateReference(levelCrate._barcode), (LevelCrateReference)null)); } private void AssignCrate() { ISearchableCrate selectedSpawnable = GetSelectedSpawnable(); if (selectedSpawnable == null || !selectedSpawnable.TryGetCrate(out Crate outCrate)) { return; } AvatarCrate val = ((Il2CppObjectBase)outCrate).TryCast<AvatarCrate>(); if ((Object)(object)val != (Object)null) { AssignAvatarCrate((Scannable)(object)val); return; } SpawnableCrate val2 = ((Il2CppObjectBase)outCrate).TryCast<SpawnableCrate>(); if ((Object)(object)val2 != (Object)null) { AssignSpawnableCrate(val2); } LevelCrate val3 = ((Il2CppObjectBase)outCrate).TryCast<LevelCrate>(); if ((Object)(object)val3 != (Object)null) { LoadLevelCrate((Scannable)(object)val3); } } public void OnSelectItem(int idx) { _currentFocus = SpawnInfoFocus.SelectedItem; _selectedItemIndex = idx; SetIsEditing(isEditing: false); RenderItemButtons(); RenderTags(); RenderFocus(); if (GetSelectedPanel().CanAssign) { AssignCrate(); } } public void SelectCategory(int idx) { ISearchPanel? renderPanel = GetRenderPanel(idx); if (renderPanel != null && renderPanel.OnSelected(this)) { _currentFocus = SpawnInfoFocus.SelectedPage; SetIsEditing(isEditing: false); _selectedPageIndex = _renderedTagPageIndex; _selectedTagIndex = idx; _searchQuery = ""; _keyboard.SetText(_searchQuery, triggerEvent: false); RequestRefresh(); } } public void ChangeTagPage(int offset) { int num = _renderedTagPageIndex + offset; if (num >= 0 && num < _pages.PageCount) { _renderedTagPageIndex = num; RenderTags(); } } public void SwapSortButton() { ISearchPanel selectedPanel = GetSelectedPanel(); selectedPanel.SelectedOrderIndex = (selectedPanel.SelectedOrderIndex + 1) % selectedPanel.SupportedOrders.Length; RequestRefresh(); } public void OnFavoriteButton() { ISearchPanel selectedPanel = GetSelectedPanel(); if (_currentFocus == SpawnInfoFocus.SelectedItem) { if (selectedPanel.HasItemFunction) { ISearchableCrate selectedSpawnable = GetSelectedSpawnable(); if (selectedSpawnable != null) { selectedPanel.OnItemFunction(this, selectedSpawnable); } } } else if (selectedPanel.HasPanelFunction) { selectedPanel.OnPanelFunction(this); } } public void Show() { ShowKeyboard(); RenderTags(); RenderSpecialButtons(); RequestRefresh(); } public void Hide() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) CloseKeyboard(); _fadedButtonImage.sprite = _originalFavoriteSprite; _favoriteButtonImage.sprite = _originalFavoriteSprite; ((Graphic)_favoriteButtonImage).color = _originalFavoriteColor; foreach (ItemButton itemButton in _itemButtons) { itemButton.Reset(); } foreach (TagButton tagButton in _tagButtons) { tagButton.Reset(); } } public void ShowKeyboard() { _keyboard.Show(); } public void CloseKeyboard() { _keyboard.Hide(); } public bool IsSearchActive() { return _panelView._selectedTabIndex == 5; } public bool Is(SpawnablesPanelView panelView) { if ((Object)(object)_panelView == (Object)null || (Object)(object)panelView == (Object)null) { return false; } if ((Object)(object)((Component)_panelView).gameObject == (Object)null) { return false; } return ((Object)((Component)_panelView).gameObject).GetInstanceID() == ((Object)((Component)panelView).gameObject).GetInstanceID(); } } public enum SpawnInfoFocus { SelectedPage, SelectedItem } } namespace SearchThing.Extensions.Sort { public class AlphabeticalSearchOrder : ISelectableSearchOrder, ISearchOrder { public string Name => "ABC"; public int Order(ISearchableCrate searchableCrate) { return -string.Compare(searchableCrate.Name.Original, string.Empty, StringComparison.Ordinal); } } public class DateNewAddedSearchOrder : ISelectableSearchOrder, ISearchOrder { public string Name => "DateNew"; public int Order(ISearchableCrate searchableCrate) { return (int)(searchableCrate.DateAdded.Ticks >> 32); } } public class DateOldAddedSearchOrder : ISelectableSearchOrder, ISearchOrder { public string Name => "DateOld"; public int Order(ISearchableCrate searchableCrate) { return -(int)(searchableCrate.DateAdded.Ticks >> 32); } } public interface ISelectableSearchOrder : ISearchOrder { string Name { get; } } public class RandomSearchOrder : ISelectableSearchOrder, ISearchOrder { public string Name => "Random"; public int Order(ISearchableCrate searchableCrate) { return Random.Shared.Next(); } } public class ScoreSearchOrder : ISelectableSearchOrder, ISearchOrder { public string Name => "Relevance"; public int Order(ISearchableCrate searchableCrate) { return searchableCrate.Score; } } } namespace SearchThing.Extensions.Panel { public interface ISearchPanel { const int PanelSize = 12; Guid Id { get; } string Tag { get; } bool IsVisible { get; } bool CanAssign { get; } bool TagEditable { get; } string Query { get; set; } int SelectedOrderIndex { get; set; } ISelectableSearchOrder[] SupportedOrders { get; } int Page { get; set; } int PageCount { get; } bool HasPanelFunction { get; } Sprite? PanelFunctionIcon { get; } bool HasItemFunction { get; } Sprite? ItemFunctionIcon { get; } Color? GetPanelFunctionHighlight(SpawnablePanelExtension extension); Color? GetItemFunctionHighlight(SpawnablePanelExtension extension, ISearchableCrate? crate); void OnPanelFunction(SpawnablePanelExtension extension); void OnItemFunction(SpawnablePanelExtension extension, ISearchableCrate crate); void OnTagEdited(SpawnablePanelExtension extension, string newTag); Color? IsForceHighlighted(SpawnablePanelExtension extension, ISearchableCrate? selectedCrate); void RequestSearch(SpawnablePanelExtension extension); void ChangePage(SpawnablePanelExtension extension, int offset); bool OnSelected(SpawnablePanelExtension extension); ISearchableCrate? GetCrateAt(int index); IReadOnlyList<ItemRenderData> GetPage(int page); } } namespace SearchThing.Extensions.Panel.History { public class AvatarHistorySearchPanel : HistorySearchPanel { public override string Tag => "Avatar History"; protected override bool Filter(ISearchableCrate entry) { return entry.CrateType == CrateType.Avatar; } } public abstract class HistorySearchPanel : BasicSearchPanel<HistoryCrateEntry> { public override bool ResearchOnPageChange => true; public abstract override string Tag { get; } public override ISelectableSearchOrder[] SupportedOrders { get; } = new ISelectableSearchOrder[5] { new DateNewAddedSearchOrder(), new DateOldAddedSearchOrder(), new ScoreSearchOrder(), new AlphabeticalSearchOrder(), new RandomSearchOrder() }; protected abstract bool Filter(ISearchableCrate entry); protected override void Search(string query, ISearchOrder searchOrder, Action<SearchResults<HistoryCrateEntry>> callback) { HistoryManager.SearchAsync(query, searchOrder, Filter, callback); } } public class PropHistorySearchPanel : HistorySearchPanel { public override string Tag => "Prop History"; protected override bool Filter(ISearchableCrate entry) { return entry.CrateType == CrateType.Prop; } } } namespace SearchThing.Extensions.Panel.Filter { public class AvatarTagSearchPanel : FilterSearchSearchPanel { public override string Tag => "Avatar"; protected override bool Filter(ISearchableCrate searchableCrate) { if (searchableCrate != null && searchableCrate.CrateType == CrateType.Avatar) { return !searchableCrate.Redacted; } return false; } } public abstract class FilterSearchSearchPanel : BasicSearchPanel<ISearchableCrate> { private static readonly Sprite PresetAddIcon = ImageHelper.LoadEmbeddedSprite("SearchThing.resources.AddIcon.png"); public abstract override string Tag { get; } public override bool HasItemFunction => true; public override Sprite ItemFunctionIcon => PresetAddIcon; protected abstract bool Filter(ISearchableCrate searchableCrate); public override Color? GetItemFunctionHighlight(SpawnablePanelExtension extension, ISearchableCrate? crate) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) if (!PresetManager.IsAssignmentMode) { return null; } return Color.green; } public override void OnItemFunction(SpawnablePanelExtension extension, ISearchableCrate crate) { PresetManager.IsAssignmentMode = !PresetManager.IsAssignmentMode; extension.RenderAll(); } protected override void Search(string query, ISearchOrder order, Action<SearchResults<ISearchableCrate>> callback) { SearchManager.SearchAsync(query, GlobalCrateManager.GetCrates(), Filter, order, callback); } } public class LevelTagSearchPanel : FilterSearchSearchPanel { public override string Tag => "Levels"; protected override bool Filter(ISearchableCrate searchableCrate) { if (searchableCrate != null && searchableCrate.CrateType == CrateType.Level) { return !searchableCrate.Redacted; } return false; } } public class PropTagSearchPanel : FilterSearchSearchPanel { public override string Tag => "Props"; protected override bool Filter(ISearchableCrate searchableCrate) { if (searchableCrate != null && searchableCrate.CrateType == CrateType.Prop) { return !searchableCrate.Redacted; } return false; } } public class RedactedSearchPanel : FilterSearchSearchPanel { public override string Tag => "Redacted"; protected override bool Filter(ISearchableCrate searchableCrate) { return searchableCrate?.Redacted ?? false; } } } namespace SearchThing.Extensions.Panel.Data { public class ItemRenderData { public string Name { get; set; } public string Author { get; set; } public string Description { get; set; } public string PalletName { get; set; } public Sprite? Icon { get; set; } public string[] Tags { get; set; } } } namespace SearchThing.Extensions.Panel.Abstract { public abstract class BasicSearchPanel<TCrate> : ISearchPanel where TCrate : class, ISearchableCrate { private bool _isDirty = true; private SearchResults<TCrate>? _results; private string _query = ""; private int _selectedOrderIndex; public virtual bool ResearchOnPageChange => false; public abstract string Tag { get; } public virtual bool IsVisible => true; public virtual bool CanAssign => true; public virtual bool TagEditable => false; public Guid Id { get; } = Guid.NewGuid(); public string Query { get { return _query; } set { if (!(value == _query)) { _isDirty = true; _query = value; } } } public int SelectedOrderIndex { get { return _selectedOrderIndex; } set { if (value != _selectedOrderIndex && value >= 0 && value < SupportedOrders.Length) { _isDirty = true; _selectedOrderIndex = value; } } } public virtual ISelectableSearchOrder[] SupportedOrders { get; } = new ISelectableSearchOrder[5] { new ScoreSearchOrder(), new AlphabeticalSearchOrder(), new DateNewAddedSearchOrder(), new DateOldAddedSearchOrder(), new RandomSearchOrder() }; public int Page { get; set; } public int PageCount { get; private set; } = 1; public virtual bool HasPanelFunction => false; public virtual Sprite? PanelFunctionIcon => null; public virtual bool HasItemFunction => false; public virtual Sprite? ItemFunctionIcon => null; protected abstract void Search(string query, ISearchOrder order, Action<SearchResults<TCrate>> callback); public void RequestSearch(SpawnablePanelExtension extension) { SpawnablePanelExtension extension2 = extension; if (!ResearchOnPageChange && !_isDirty) { extension2.RenderAll(); return; } _isDirty = false; ISelectableSearchOrder order = SupportedOrders[SelectedOrderIndex]; Search(_query, order, delegate(SearchResults<TCrate> results) { _results = results; Page = 0; PageCount = results.GetPageCount(12); extension2.RenderAll(); }); } public void ChangePage(SpawnablePanelExtension extension, int offset) { int num = Page + offset; if (num >= 0 && num < PageCount) { Page = num; extension.RenderAll(); } } public void MakeDirty() { _isDirty = true; } public virtual Color? GetPanelFunctionHighlight(SpawnablePanelExtension extension) { return null; } public virtual Color? GetItemFunctionHighlight(SpawnablePanelExtension extension, ISearchableCrate? crate) { return null; } public virtual void OnPanelFunction(SpawnablePanelExtension extension) { } public virtual void OnItemFunction(SpawnablePanelExtension extension, ISearchableCrate crate) { } public virtual void OnTagEdited(SpawnablePanelExtension extension, string newTag) { } public virtual Color? IsForceHighlighted(SpawnablePanelExtension extension, ISearchableCrate? selectedCrate) { return null; } public virtual bool OnSelected(SpawnablePanelExtension extension) { return true; } public virtual ItemRenderData GetRenderDataForCrate(TCrate crate) { return new ItemRenderData { Name = crate.Name.Original, PalletName = crate.PalletName.Original, Author = crate.Author.Original, Tags = crate.Tags.Select((SearchTag t) => t.Original).ToArray(), Description = crate.Description, Icon = CrateIconProvider.GetIcon(crate) }; } public ISearchableCrate? GetCrateAt(int index) { SearchResults<TCrate>? results = _results; return (results != null) ? results.GetEntryAt(Page, 12, index) : null; } public IReadOnlyList<ItemRenderData> GetPage(int page) { if (_results == null) { return Array.Empty<ItemRenderData>(); } return _results.GetPage(page, 12).Select(GetRenderDataForCrate).ToList(); } } } namespace SearchThing.Extensions.Pages { public class BasicSearchPage : ISearchPage { private readonly Func<bool> _isVisibleFunc = () => true; public bool IsVisible => _isVisibleFunc(); public IReadOnlyList<ISearchPanel> Panels { get; } public BasicSearchPage(Func<bool> isVisibleFunc, params ISearchPanel[] panels) { _isVisibleFunc = isVisibleFunc; Panels = panels; } public BasicSearchPage(params ISearchPanel[] panels) { Panels = panels; } } public interface ISearchPage { bool IsVisible { get; } IReadOnlyList<ISearchPanel> Panels { get; } } } namespace SearchThing.Extensions.Components { public class ItemButton { private static Sprite? _defaultIcon; private static Color? _defaultIconColor; private static Color? _defaultHighlightColor; private GameObject _button; private TextMeshPro _text; private Image _highlight; private Image _icon; public ItemButton(ButtonReferenceHolder button) { //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) //IL_0056: 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_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) //IL_0046: 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_0074: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_defaultIcon == (Object)null) { _defaultIcon = button.special.sprite; } Color valueOrDefault = _defaultIconColor.GetValueOrDefault(); if (!_defaultIconColor.HasValue) { valueOrDefault = ((Graphic)button.special).color; _defaultIconColor = valueOrDefault; } valueOrDefault = _defaultHighlightColor.GetValueOrDefault(); if (!_defaultHighlightColor.HasValue) { valueOrDefault = ((Graphic)button.highlight).color; _defaultHighlightColor = valueOrDefault; } _button = ((Component)button).gameObject; _text = button.tmp; _highlight = button.highlight; _icon = button.special; } public void SetCrate(ItemRenderData crate, bool isSelected = false) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) _button.SetActive(true); ((TMP_Text)_text).text = crate.Name; ((Behaviour)_icon).enabled = (Object)(o