using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using GameNetcodeStuff;
using HarmonyLib;
using InteractiveTerminalAPI.UI;
using InteractiveTerminalAPI.UI.Application;
using InteractiveTerminalAPI.UI.Cursor;
using InteractiveTerminalAPI.UI.Screen;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("MergeScrap")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.2.0")]
[assembly: AssemblyInformationalVersion("1.1.2+61b99a9c7132bbcc8f0f00a03be764f6596b6ccd")]
[assembly: AssemblyProduct("MergeScrap")]
[assembly: AssemblyTitle("MergeScrap")]
[assembly: AssemblyVersion("1.1.2.0")]
[module: RefSafetyRules(11)]
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;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace MergeScrap
{
internal static class TokMerge
{
internal static bool LooksMerge(string[] parts)
{
int num = parts.Length;
int result;
while (num > 0 && int.TryParse(parts[num - 1], out result))
{
num--;
}
switch (num)
{
case 1:
{
bool result2;
switch (parts[0])
{
case "merge":
case "merge-scrap":
case "scrap-merge":
result2 = true;
break;
default:
result2 = false;
break;
}
return result2;
}
case 2:
return parts[0] == "merge" && parts[1] == "scrap";
default:
return false;
}
}
}
internal static class DoneGroups
{
private static readonly HashSet<string> completed = new HashSet<string>(StringComparer.Ordinal);
internal static void Wipe()
{
completed.Clear();
}
internal static void MarkGroupMerged(string groupKey)
{
if (!string.IsNullOrEmpty(groupKey))
{
completed.Add(groupKey);
}
}
internal static bool IsGroupMerged(string groupKey)
{
if (string.IsNullOrEmpty(groupKey))
{
return false;
}
return completed.Contains(groupKey);
}
}
internal static class EnterOnce
{
private static int lastMergeConfirmFrame = -1;
internal static bool AlreadyHandledThisFrame()
{
return Time.frameCount == lastMergeConfirmFrame;
}
internal static void MarkHandledThisFrame()
{
lastMergeConfirmFrame = Time.frameCount;
}
}
internal static class EnterOk
{
internal static bool WantsConfirm(object terminal)
{
if (TerminalReflection.GetTextAdded(terminal) <= 0)
{
return true;
}
if (MergeMenu.UserHasNavigatedSinceOpen)
{
if (!TerminalReflection.TryGetInputChunk(terminal, out string chunk))
{
return true;
}
string text = NormCmd.Strip(chunk).Trim();
if (TokMerge.LooksMerge(text.Split(Array.Empty<char>(), StringSplitOptions.RemoveEmptyEntries)))
{
return true;
}
if (text.Length == 0)
{
return true;
}
return false;
}
if (!TerminalReflection.TryGetInputChunk(terminal, out string chunk2))
{
return false;
}
TokMerge.LooksMerge(NormCmd.Strip(chunk2).Trim().Split(Array.Empty<char>(), StringSplitOptions.RemoveEmptyEntries));
return false;
}
}
internal static class ShutHudChat
{
private static bool snap;
private static float savedTargetAlpha;
private static float savedCgAlpha;
private static bool savedBlocksRaycasts;
private static bool savedInteractable;
internal static void GoDark()
{
HUDManager instance = HUDManager.Instance;
if ((Object)(object)instance == (Object)null)
{
return;
}
if ((Object)(object)instance.Chat?.canvasGroup != (Object)null)
{
if (!snap)
{
savedTargetAlpha = instance.Chat.targetAlpha;
savedCgAlpha = instance.Chat.canvasGroup.alpha;
savedBlocksRaycasts = instance.Chat.canvasGroup.blocksRaycasts;
savedInteractable = instance.Chat.canvasGroup.interactable;
snap = true;
}
if (instance.Chat.fadeCoroutine != null)
{
((MonoBehaviour)instance).StopCoroutine(instance.Chat.fadeCoroutine);
instance.Chat.fadeCoroutine = null;
}
instance.Chat.targetAlpha = 0f;
instance.Chat.canvasGroup.alpha = 0f;
instance.Chat.canvasGroup.blocksRaycasts = false;
instance.Chat.canvasGroup.interactable = false;
}
if (!((Object)(object)instance.chatTextField == (Object)null))
{
((Selectable)instance.chatTextField).interactable = false;
instance.chatTextField.readOnly = true;
instance.chatTextField.text = string.Empty;
instance.chatTextField.DeactivateInputField(false);
if ((Object)(object)instance.chatText != (Object)null)
{
((Behaviour)instance.chatText).enabled = false;
}
if ((Object)(object)instance.typingIndicator != (Object)null)
{
((Behaviour)instance.typingIndicator).enabled = false;
}
if ((Object)(object)GameNetworkManager.Instance?.localPlayerController != (Object)null)
{
GameNetworkManager.Instance.localPlayerController.isTypingChat = false;
}
}
}
internal static void UnDim()
{
HUDManager instance = HUDManager.Instance;
if ((Object)(object)instance?.Chat?.canvasGroup != (Object)null && snap)
{
instance.Chat.targetAlpha = savedTargetAlpha;
instance.Chat.canvasGroup.alpha = savedCgAlpha;
instance.Chat.canvasGroup.blocksRaycasts = savedBlocksRaycasts;
instance.Chat.canvasGroup.interactable = savedInteractable;
}
snap = false;
if (!((Object)(object)instance?.chatTextField == (Object)null))
{
instance.chatTextField.readOnly = false;
((Selectable)instance.chatTextField).interactable = true;
if ((Object)(object)instance.chatText != (Object)null)
{
((Behaviour)instance.chatText).enabled = true;
}
}
}
}
internal static class LateChatNuke
{
internal static void Tick()
{
if (!MergeMenu.IsActive || MergeMenu.BoundTerminal == null)
{
return;
}
HUDManager instance = HUDManager.Instance;
if ((Object)(object)instance == (Object)null)
{
return;
}
if ((Object)(object)instance.Chat?.canvasGroup != (Object)null)
{
instance.Chat.targetAlpha = 0f;
instance.Chat.canvasGroup.alpha = 0f;
instance.Chat.canvasGroup.blocksRaycasts = false;
instance.Chat.canvasGroup.interactable = false;
}
if ((Object)(object)instance.chatText != (Object)null)
{
((Behaviour)instance.chatText).enabled = false;
}
if ((Object)(object)instance.typingIndicator != (Object)null)
{
((Behaviour)instance.typingIndicator).enabled = false;
}
if ((Object)(object)GameNetworkManager.Instance?.localPlayerController != (Object)null)
{
GameNetworkManager.Instance.localPlayerController.isTypingChat = false;
}
TMP_InputField chatTextField = instance.chatTextField;
if ((Object)(object)chatTextField == (Object)null)
{
return;
}
if (chatTextField.text.Length > 0)
{
chatTextField.text = string.Empty;
chatTextField.stringPosition = 0;
}
EventSystem current = EventSystem.current;
if ((Object)(object)current == (Object)null)
{
return;
}
GameObject currentSelectedGameObject = current.currentSelectedGameObject;
Transform transform = ((Component)chatTextField).transform;
if ((Object)(object)currentSelectedGameObject != (Object)null && ((Object)(object)currentSelectedGameObject.transform == (Object)(object)transform || currentSelectedGameObject.transform.IsChildOf(transform)))
{
chatTextField.DeactivateInputField(false);
current.SetSelectedGameObject((GameObject)null);
if (MergeMenu.BoundTerminal != null)
{
TerminalReflection.LockTermField(MergeMenu.BoundTerminal, on: true);
}
}
}
}
internal static class MergeMenu
{
private static TerminalNode? pendingNode;
private static object? pendingTerm;
private static List<ScrapPile>? rows;
internal static bool IsActive { get; private set; }
internal static object? BoundTerminal { get; private set; }
internal static int SelectedIndex { get; private set; }
internal static bool OpenedViaItapi { get; private set; }
internal static bool UserHasNavigatedSinceOpen { get; private set; }
internal static List<ScrapPile>? GetRowsSnapshot()
{
return rows;
}
internal static void Open(object term, List<ScrapPile> rowList)
{
Arm(term, rowList, itapi: false);
}
internal static void OpenForItapi(object term, List<ScrapPile> rowList)
{
Arm(term, rowList, itapi: true);
}
private static void Arm(object term, List<ScrapPile> rowList, bool itapi)
{
SelectedIndex = 0;
UserHasNavigatedSinceOpen = false;
if (rowList == null || rowList.Count == 0)
{
IsActive = false;
BoundTerminal = null;
rows = null;
OpenedViaItapi = false;
return;
}
OpenedViaItapi = itapi;
BoundTerminal = term;
rows = rowList;
IsActive = true;
if (!itapi)
{
RefreshDisplay(term);
TerminalReflection.LockTermField(term, on: true);
}
ShutHudChat.GoDark();
}
internal static void SetSelectedIndex(int i)
{
if (rows != null && rows.Count > 0)
{
SelectedIndex = Mathf.Clamp(i, 0, rows.Count - 1);
}
}
internal static void SetPendingFinalNodeAfterItapi(object term, TerminalNode node)
{
pendingTerm = term;
pendingNode = node;
}
internal static void ApplyPendingNodeAfterItapiDestroyed()
{
if (pendingTerm != null && (Object)(object)pendingNode != (Object)null)
{
TerminalReflection.LoadNewNode(pendingTerm, pendingNode);
}
pendingTerm = null;
pendingNode = null;
}
internal static void Close()
{
if (IsActive || BoundTerminal != null || OpenedViaItapi)
{
ShutHudChat.UnDim();
if (BoundTerminal != null)
{
TerminalReflection.LockTermField(BoundTerminal, on: false);
}
IsActive = false;
BoundTerminal = null;
rows = null;
SelectedIndex = 0;
UserHasNavigatedSinceOpen = false;
OpenedViaItapi = false;
}
}
private static List<ScrapPile> RebuildFiltered()
{
List<ScrapPile> list = GrabPiles.ListForMenu();
List<ScrapPile> list2 = new List<ScrapPile>();
for (int i = 0; i < list.Count; i++)
{
ScrapPile scrapPile = list[i];
if (!DoneGroups.IsGroupMerged(scrapPile.GroupKey))
{
list2.Add(scrapPile);
}
}
return list2;
}
internal static void RefreshDisplay(object term)
{
if (IsActive && term == BoundTerminal && rows != null)
{
TerminalReflection.SetScreenBody(term, "\n\n\n" + GrabPiles.FormatMenu(rows, SelectedIndex));
}
}
internal static bool TryConfirmSelection(out TerminalNode node)
{
node = null;
if (!IsActive || BoundTerminal == null || rows == null || rows.Count == 0)
{
return false;
}
SelectedIndex = Mathf.Clamp(SelectedIndex, 0, rows.Count - 1);
ScrapPile scrapPile = rows[SelectedIndex];
string displayName = scrapPile.DisplayName;
int totalValue = scrapPile.TotalValue;
if (!SquashGroup.TryMergeRow(scrapPile, out string error, out int destroyed))
{
rows = RebuildFiltered();
SelectedIndex = Mathf.Clamp(SelectedIndex, 0, Mathf.Max(0, rows.Count - 1));
node = ScreenNode.Make(error + "\n\n" + GrabPiles.FormatMenu(rows, SelectedIndex));
return true;
}
DoneGroups.MarkGroupMerged(scrapPile.GroupKey);
Plugin.PlayMergeSound();
rows = RebuildFiltered();
SelectedIndex = Mathf.Clamp(SelectedIndex, 0, Mathf.Max(0, rows.Count - 1));
string text = displayName + " merged " + destroyed + " stack $" + totalValue + " item in ship middle\n\n";
if (rows.Count == 0)
{
Close();
node = ScreenNode.Make(text + "nothing left\n\n");
return true;
}
UserHasNavigatedSinceOpen = true;
node = ScreenNode.Make(text + GrabPiles.FormatMenu(rows, SelectedIndex));
return true;
}
internal static void MoveSelection(int delta, object term)
{
if (rows != null && rows.Count != 0)
{
int count = rows.Count;
SelectedIndex = ((Mathf.Clamp(SelectedIndex, 0, count - 1) + delta) % count + count) % count;
UserHasNavigatedSinceOpen = true;
RefreshDisplay(term);
}
}
}
internal enum PileSpot
{
Ship,
Vehicle,
Facility
}
internal sealed class ScrapPile
{
public string GroupKey { get; set; } = "";
public string DisplayName { get; set; } = "";
public List<GrabbableObject> PhysicalItems { get; } = new List<GrabbableObject>();
public int InventoryCount { get; set; }
public int InventoryValueSum { get; set; }
public int PhysicalCount => PhysicalItems.Count;
public int TotalPieces => PhysicalCount + InventoryCount;
public int PhysicalValueSum
{
get
{
int num = 0;
for (int i = 0; i < PhysicalItems.Count; i++)
{
GrabbableObject val = PhysicalItems[i];
if ((Object)(object)val != (Object)null)
{
num += val.scrapValue;
}
}
return num;
}
}
public int TotalValue => PhysicalValueSum + InventoryValueSum;
public int CountAt(PileSpot place)
{
int num = 0;
for (int i = 0; i < PhysicalItems.Count; i++)
{
GrabbableObject val = PhysicalItems[i];
if ((Object)(object)val != (Object)null && GrabPiles.PlaceOf(val) == place)
{
num++;
}
}
return num;
}
public string FormatLocationCounts()
{
List<string> list = new List<string>();
int num = CountAt(PileSpot.Ship);
int num2 = CountAt(PileSpot.Facility);
int num3 = CountAt(PileSpot.Vehicle);
if (num > 0)
{
list.Add($"Ship:{num}");
}
if (num2 > 0)
{
list.Add($"Floor:{num2}");
}
if (num3 > 0)
{
list.Add($"Cruiser:{num3}");
}
if (InventoryCount > 0)
{
list.Add($"Inv:{InventoryCount}");
}
if (list.Count <= 0)
{
return "";
}
return " [" + string.Join(" ", list) + "]";
}
}
internal static class GrabPiles
{
internal static string PrefabKeyOf(GrabbableObject g)
{
return ((Object)g).name.Replace("(Clone)", "", StringComparison.Ordinal);
}
internal static PileSpot PlaceOf(GrabbableObject g)
{
StartOfRound instance = StartOfRound.Instance;
object obj;
if (instance == null)
{
obj = null;
}
else
{
VehicleController attachedVehicle = instance.attachedVehicle;
obj = ((attachedVehicle != null) ? ((Component)attachedVehicle).transform : null);
}
Transform val = (Transform)obj;
if ((Object)(object)val != (Object)null)
{
Transform val2 = ((Component)g).transform;
while ((Object)(object)val2 != (Object)null)
{
if ((Object)(object)val2 == (Object)(object)val)
{
return PileSpot.Vehicle;
}
val2 = val2.parent;
}
}
if (!g.isInShipRoom)
{
return PileSpot.Facility;
}
return PileSpot.Ship;
}
internal static List<GrabbableObject> CollectPhysicalScrap()
{
List<GrabbableObject> list = new List<GrabbableObject>();
GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>(true);
foreach (GrabbableObject val in array)
{
if ((Object)(object)val == (Object)null || (Object)(object)val.itemProperties == (Object)null || !val.itemProperties.isScrap || val.isHeld)
{
continue;
}
if (!val.grabbable)
{
ConfigEntry<bool> skipGrabbableCheck = Plugin.SkipGrabbableCheck;
if (skipGrabbableCheck == null || !skipGrabbableCheck.Value)
{
continue;
}
}
list.Add(val);
}
return list;
}
internal static List<ScrapPile> BuildRows()
{
Dictionary<string, ScrapPile> dictionary = new Dictionary<string, ScrapPile>(StringComparer.Ordinal);
foreach (GrabbableObject item in CollectPhysicalScrap())
{
string text = PrefabKeyOf(item);
if (!string.IsNullOrEmpty(text))
{
if (!dictionary.TryGetValue(text, out var value))
{
ScrapPile obj = new ScrapPile
{
GroupKey = text,
DisplayName = (item.itemProperties?.itemName ?? text)
};
value = obj;
dictionary[text] = obj;
}
value.PhysicalItems.Add(item);
}
}
foreach (var (text2, displayName, num) in ShipInventoryMerge.EnumerateInventoryScrapRows())
{
if (!string.IsNullOrEmpty(text2))
{
if (!dictionary.TryGetValue(text2, out var value2))
{
ScrapPile obj2 = new ScrapPile
{
GroupKey = text2,
DisplayName = displayName
};
value2 = obj2;
dictionary[text2] = obj2;
}
value2.InventoryCount++;
value2.InventoryValueSum += num;
}
}
List<ScrapPile> list = new List<ScrapPile>(dictionary.Values);
list.Sort(ComparePilesForDisplay);
return list;
}
private static int ComparePilesForDisplay(ScrapPile a, ScrapPile b)
{
int num = b.TotalPieces.CompareTo(a.TotalPieces);
if (num == 0)
{
return b.TotalValue.CompareTo(a.TotalValue);
}
return num;
}
internal static List<ScrapPile> ListForMenu()
{
List<ScrapPile> list = BuildRows();
List<ScrapPile> list2 = new List<ScrapPile>();
for (int i = 0; i < list.Count; i++)
{
if (list[i].TotalPieces >= 2)
{
list2.Add(list[i]);
}
}
return list2;
}
internal static string FormatMenu(IReadOnlyList<ScrapPile> rows, int sel = -1)
{
if (rows.Count == 0)
{
return "empty\n\n";
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("arrows, enter");
stringBuilder.AppendLine();
for (int i = 0; i < rows.Count; i++)
{
ScrapPile scrapPile = rows[i];
stringBuilder.AppendLine(string.Format("{0}{1}. {2} ×{3} → ${4}{5}", (sel == i) ? "* " : " ", i + 1, scrapPile.DisplayName, scrapPile.TotalPieces, scrapPile.TotalValue, scrapPile.FormatLocationCounts()));
}
return stringBuilder.ToString();
}
}
internal static class SquashGroup
{
private const BindingFlags PublicInstance = BindingFlags.Instance | BindingFlags.Public;
private const float ShipJitter = 0.15f;
private static int GrabbableLocationSortRank(GrabbableObject g)
{
return GrabPiles.PlaceOf(g) switch
{
PileSpot.Ship => 2,
PileSpot.Facility => 1,
_ => 0,
};
}
internal static bool TryMergeRow(ScrapPile row, out string error, out int destroyed)
{
error = "";
destroyed = 0;
PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
if ((Object)(object)val == (Object)null)
{
error = "no player";
return false;
}
if (!((NetworkBehaviour)val).IsHost)
{
error = "host only";
return false;
}
List<GrabbableObject> list = new List<GrabbableObject>();
for (int i = 0; i < row.PhysicalItems.Count; i++)
{
GrabbableObject val2 = row.PhysicalItems[i];
if ((Object)(object)val2 != (Object)null && !val2.isHeld)
{
list.Add(val2);
}
}
List<object> list2 = ShipInventoryMerge.CollectInventoryEntriesMatchingGroup(row.GroupKey);
if (list.Count + list2.Count < 2)
{
error = "need 2+";
return false;
}
int num = ShipInventoryMerge.SumInventoryScrapValues(list2);
object obj = ((list2.Count > 0) ? list2[0] : null);
List<GrabbableObject> list3;
if (list.Count >= 2)
{
list3 = new List<GrabbableObject>(list);
list3.Sort(delegate(GrabbableObject a, GrabbableObject b)
{
int value = GrabbableLocationSortRank(a);
int num4 = GrabbableLocationSortRank(b).CompareTo(value);
return (num4 == 0) ? a.scrapValue.CompareTo(b.scrapValue) : num4;
});
}
else
{
list3 = list;
}
GrabbableObject val3 = ((list3.Count > 0) ? list3[0] : null);
int num2 = 0;
for (int j = 0; j < list3.Count; j++)
{
num2 += list3[j].scrapValue;
}
int num3 = (((Object)(object)val3 != (Object)null && list3.Count >= 2) ? (num2 + num) : ((!((Object)(object)val3 != (Object)null)) ? num : (val3.scrapValue + num)));
if (list2.Count > 0 && !ShipInventoryMerge.TryRemoveInventoryEntries(list2, out error))
{
return false;
}
destroyed = list.Count + list2.Count - 1;
if ((Object)(object)val3 != (Object)null)
{
for (int k = 1; k < list3.Count; k++)
{
Object.Destroy((Object)(object)((Component)list3[k]).gameObject);
}
val3.SetScrapValue(num3);
MergeScrapValueSync.HostBroadcastMergedScrap(val3, num3);
PlaceAtShipCenter(val3);
return true;
}
if (obj == null || !TrySpawnMergedFromInv(obj, num3, out error))
{
if (list2.Count > 0)
{
ShipInventoryMerge.TryAddInventoryEntries(list2, out string _, verifyCount: false);
}
return false;
}
return true;
}
private static void PlaceAtShipCenter(GrabbableObject g)
{
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: 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_0132: Unknown result type (might be due to invalid IL or missing references)
//IL_0137: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: Unknown result type (might be due to invalid IL or missing references)
//IL_0144: Unknown result type (might be due to invalid IL or missing references)
//IL_0149: Unknown result type (might be due to invalid IL or missing references)
//IL_0155: Unknown result type (might be due to invalid IL or missing references)
//IL_0161: Unknown result type (might be due to invalid IL or missing references)
//IL_0166: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
StartOfRound instance = StartOfRound.Instance;
if (!((Object)(object)instance == (Object)null))
{
GameObject obj = GameObject.Find("/Environment/HangarShip");
Transform val = ((obj != null) ? obj.transform : null) ?? instance.elevatorTransform;
Transform[] insideShipPositions = instance.insideShipPositions;
Vector3 val2 = ((insideShipPositions != null && insideShipPositions.Length > 10 && (Object)(object)insideShipPositions[10] != (Object)null) ? (insideShipPositions[10].position + new Vector3(0f, 0f, 1.5f)) : (((Object)(object)instance.elevatorTransform != (Object)null) ? instance.elevatorTransform.position : ((Component)g).transform.position));
val2.x += Random.Range(-0.15f, 0.15f);
val2.z += Random.Range(-0.15f, 0.15f);
g.parentObject = null;
((Component)g).transform.SetParent(val, true);
((Component)g).transform.position = val2;
g.isInShipRoom = (g.isInElevator = true);
g.EnablePhysics(true);
g.EnableItemMeshes(true);
g.fallTime = 0f;
g.hasHitGround = true;
g.floorYRot = -1;
((Component)g).transform.rotation = Quaternion.Euler(g.itemProperties.restingRotation);
g.targetFloorPosition = val.InverseTransformPoint(val2);
((Component)g).transform.localPosition = g.targetFloorPosition;
g.startFallingPosition = g.targetFloorPosition;
}
}
private static object? GetPropertyOrField(Type declaringType, object instance, string memberName)
{
PropertyInfo property = declaringType.GetProperty(memberName, BindingFlags.Instance | BindingFlags.Public);
if (property != null)
{
return property.GetValue(instance);
}
return declaringType.GetField(memberName, BindingFlags.Instance | BindingFlags.Public)?.GetValue(instance);
}
private static bool TrySpawnMergedFromInv(object data, int scrap, out string err)
{
err = "";
if (!ShipInventoryMerge.EnsureItemDataApiReady())
{
err = "no ShipInv API";
return false;
}
object obj = ShipInventoryMerge.ResolveGameItemFromItemDataBoxed(data);
if (obj == null)
{
err = "bad inv row";
return false;
}
Type type = obj.GetType();
object? propertyOrField = GetPropertyOrField(type, obj, "spawnPrefab");
GameObject val = (GameObject)((propertyOrField is GameObject) ? propertyOrField : null);
if (val == null)
{
err = "no prefab";
return false;
}
Type type2 = data.GetType();
object propertyOrField2 = GetPropertyOrField(type, obj, "saveItemVariable");
bool flag = default(bool);
int num;
if (propertyOrField2 is bool)
{
flag = (bool)propertyOrField2;
num = 1;
}
else
{
num = 0;
}
bool flag2 = (byte)((uint)num & (flag ? 1u : 0u)) != 0;
propertyOrField2 = GetPropertyOrField(type2, data, "PERSISTED_THROUGH_ROUNDS");
bool flag3 = default(bool);
int num2;
if (propertyOrField2 is bool)
{
flag3 = (bool)propertyOrField2;
num2 = 1;
}
else
{
num2 = 0;
}
bool scrapPersistedThroughRounds = (byte)((uint)num2 & (flag3 ? 1u : 0u)) != 0;
int num4 = ((GetPropertyOrField(type2, data, "SAVE_DATA") is int num3) ? num3 : 0);
GameObject val2 = Object.Instantiate<GameObject>(val);
NetworkObject componentInChildren = default(NetworkObject);
if (!val2.TryGetComponent<NetworkObject>(ref componentInChildren))
{
componentInChildren = val2.GetComponentInChildren<NetworkObject>(true);
}
GrabbableObject componentInChildren2 = default(GrabbableObject);
if (!val2.TryGetComponent<GrabbableObject>(ref componentInChildren2))
{
componentInChildren2 = val2.GetComponentInChildren<GrabbableObject>(true);
}
if ((Object)(object)componentInChildren == (Object)null || (Object)(object)componentInChildren2 == (Object)null)
{
Object.Destroy((Object)(object)val2);
err = "spawn busted";
return false;
}
try
{
componentInChildren.Spawn(true);
}
catch (Exception ex)
{
Object.Destroy((Object)(object)val2);
err = ex.InnerException?.Message ?? ex.Message;
return false;
}
componentInChildren2.scrapPersistedThroughRounds = scrapPersistedThroughRounds;
if (flag2)
{
componentInChildren2.LoadItemSaveData(num4);
}
componentInChildren2.SetScrapValue(scrap);
MergeScrapValueSync.HostBroadcastMergedScrapNextFrame(componentInChildren2, scrap);
PlaceAtShipCenter(componentInChildren2);
return true;
}
}
[HarmonyPatch(typeof(GameNetworkManager), "Start")]
internal static class MergeHooks_NetworkInit
{
private static void Postfix()
{
MergeScrapValueSync.EnsureRegistered();
}
}
[HarmonyPatch(typeof(StartOfRound), "Start")]
internal static class MergeHooks_StartOfRoundStart
{
private static void Postfix()
{
MergeScrapValueSync.EnsureRegistered();
}
}
[HarmonyPatch]
internal static class MergeHooks_NetworkManagerShutdownNoArgs
{
private static MethodBase? TargetMethod()
{
return AccessTools.Method(typeof(NetworkManager), "Shutdown", Type.EmptyTypes, (Type[])null);
}
private static bool Prepare()
{
return TargetMethod() != null;
}
private static void Prefix(NetworkManager __instance)
{
MergeScrapValueSync.Teardown(__instance);
}
}
[HarmonyPatch]
internal static class MergeHooks_NetworkManagerShutdownBool
{
private static MethodBase? TargetMethod()
{
return AccessTools.Method(typeof(NetworkManager), "Shutdown", new Type[1] { typeof(bool) }, (Type[])null);
}
private static bool Prepare()
{
return TargetMethod() != null;
}
private static void Prefix(NetworkManager __instance)
{
MergeScrapValueSync.Teardown(__instance);
}
}
[HarmonyPatch]
internal static class MergeHooks_TerminalParse
{
private static readonly Lazy<MethodInfo> Target = new Lazy<MethodInfo>(() => AccessTools.Method(TerminalType.Value, "ParsePlayerSentence", (Type[])null, (Type[])null) ?? throw new InvalidOperationException("no ParsePlayerSentence"));
private static MethodBase TargetMethod()
{
return Target.Value;
}
[HarmonyPriority(800)]
private static bool Prefix(object __instance, ref TerminalNode __result)
{
if (!TerminalReflection.TryGetInputChunk(__instance, out string chunk))
{
return true;
}
chunk = NormCmd.Strip(chunk);
string[] array = chunk.Split(Array.Empty<char>(), StringSplitOptions.RemoveEmptyEntries);
if (MergeMenu.IsActive && array.Length != 0 && !TokMerge.LooksMerge(array))
{
MergeMenu.Close();
}
if (!TokMerge.LooksMerge(array))
{
return true;
}
DoneGroups.Wipe();
List<ScrapPile> list = GrabPiles.ListForMenu();
bool flag = InteractiveTerminalManager.ContainsApplication(TerminalReflection.GetRawInputSuffixForItapi(__instance).Trim());
if (list.Count == 0)
{
__result = ScreenNode.Make("\n\n\n" + GrabPiles.FormatMenu(list));
return false;
}
if (flag)
{
MergeMenu.OpenForItapi(__instance, list);
return true;
}
MergeMenu.Open(__instance, list);
string text = GrabPiles.FormatMenu(list, MergeMenu.IsActive ? MergeMenu.SelectedIndex : (-1));
__result = ScreenNode.Make("\n\n\n" + text);
return false;
}
}
[HarmonyPatch]
internal static class MergeHooks_TerminalSubmit
{
private static MethodBase TargetMethod()
{
return AccessTools.Method(TerminalType.Value, "OnSubmit", (Type[])null, (Type[])null) ?? throw new InvalidOperationException("no OnSubmit");
}
[HarmonyPriority(800)]
private static bool Prefix(object __instance)
{
if (!TerminalReflection.GetTerminalInUse(__instance))
{
return true;
}
if (!MergeMenu.IsActive || MergeMenu.BoundTerminal != __instance)
{
return true;
}
if (MergeMenu.OpenedViaItapi)
{
return true;
}
if (!EnterOk.WantsConfirm(__instance))
{
return true;
}
if (EnterOnce.AlreadyHandledThisFrame())
{
return false;
}
if (!MergeMenu.TryConfirmSelection(out TerminalNode node) || (Object)(object)node == (Object)null)
{
return true;
}
TerminalReflection.LoadNewNode(__instance, node);
EnterOnce.MarkHandledThisFrame();
if (!MergeMenu.IsActive)
{
TerminalReflection.ActivateInput(__instance);
}
return false;
}
}
[HarmonyPatch]
internal static class MergeHooks_TerminalQuit
{
private static MethodBase TargetMethod()
{
return AccessTools.Method(TerminalType.Value, "QuitTerminal", (Type[])null, (Type[])null) ?? throw new InvalidOperationException("no QuitTerminal");
}
private static void Postfix()
{
MergeMenu.Close();
}
}
[HarmonyPatch]
internal static class MergeHooks_AfterLoadNode
{
private static MethodBase TargetMethod()
{
return AccessTools.Method(TerminalType.Value, "LoadNewNode", (Type[])null, (Type[])null) ?? throw new InvalidOperationException("no LoadNewNode");
}
private static void Postfix(object __instance)
{
if (MergeMenu.IsActive && MergeMenu.BoundTerminal != null && MergeMenu.BoundTerminal == __instance && !MergeMenu.OpenedViaItapi)
{
if ((Object)(object)GameNetworkManager.Instance?.localPlayerController != (Object)null)
{
GameNetworkManager.Instance.localPlayerController.isTypingChat = false;
}
ShutHudChat.GoDark();
MergeMenu.RefreshDisplay(__instance);
TerminalReflection.LockTermField(__instance, on: true);
}
}
}
[HarmonyPatch(typeof(TerminalApplication), "UpdateText")]
internal static class MergeHooks_ItapiUpdateText
{
private static readonly FieldInfo? CurrentScreenField = AccessTools.Field(typeof(TerminalApplication), "currentScreen");
private static bool Prefix(TerminalApplication __instance)
{
if (CurrentScreenField == null)
{
return true;
}
return CurrentScreenField.GetValue(__instance) != null;
}
}
[HarmonyPatch(typeof(InteractiveTerminalManager), "OnDestroy")]
internal static class MergeHooks_ItapiDestroy
{
private static void Postfix()
{
MergeMenu.ApplyPendingNodeAfterItapiDestroyed();
MergeMenu.Close();
}
}
[HarmonyPatch]
internal static class MergeHooks_TerminalUpdate
{
private static MethodBase TargetMethod()
{
return AccessTools.Method(TerminalType.Value, "Update", (Type[])null, (Type[])null) ?? throw new InvalidOperationException("no Terminal.Update");
}
[HarmonyPostfix]
[HarmonyPriority(int.MaxValue)]
private static void Postfix(object __instance)
{
if (!MergeMenu.IsActive || MergeMenu.BoundTerminal == null || MergeMenu.BoundTerminal != __instance || MergeMenu.OpenedViaItapi)
{
return;
}
Keyboard current = Keyboard.current;
bool num = ((current != null) ? ((ButtonControl)current.upArrowKey).wasPressedThisFrame : Input.GetKeyDown((KeyCode)273));
bool flag = ((current != null) ? ((ButtonControl)current.downArrowKey).wasPressedThisFrame : Input.GetKeyDown((KeyCode)274));
if (num)
{
MergeMenu.MoveSelection(-1, __instance);
}
else if (flag)
{
MergeMenu.MoveSelection(1, __instance);
}
bool num2;
if (current == null)
{
if (!Input.GetKeyDown((KeyCode)13))
{
num2 = Input.GetKeyDown((KeyCode)271);
goto IL_00a6;
}
}
else if (!((ButtonControl)current.enterKey).wasPressedThisFrame)
{
num2 = ((ButtonControl)current.numpadEnterKey).wasPressedThisFrame;
goto IL_00a6;
}
goto IL_00a8;
IL_00a6:
if (!num2)
{
return;
}
goto IL_00a8;
IL_00a8:
Terminal val = (Terminal)((__instance is Terminal) ? __instance : null);
if (val == null || EnterOnce.AlreadyHandledThisFrame())
{
return;
}
TerminalNode node;
if (!EnterOk.WantsConfirm(__instance))
{
val.OnSubmit();
}
else if (MergeMenu.TryConfirmSelection(out node) && (Object)(object)node != (Object)null)
{
TerminalReflection.LoadNewNode(__instance, node);
EnterOnce.MarkHandledThisFrame();
if (!MergeMenu.IsActive)
{
TerminalReflection.ActivateInput(__instance);
}
}
else
{
val.OnSubmit();
}
}
}
[HarmonyPatch(typeof(TMP_InputField), "ProcessEvent")]
[HarmonyPriority(800)]
internal static class MergeHooks_ChatField
{
private static bool Prefix(TMP_InputField __instance, Event e)
{
if (!MergeMenu.IsActive)
{
return true;
}
TMP_InputField val = HUDManager.Instance?.chatTextField;
if (val == null || __instance != val)
{
return true;
}
e.Use();
return false;
}
}
[HarmonyPatch(typeof(TMP_InputField), "ProcessEvent")]
[HarmonyPriority(800)]
internal static class MergeHooks_TerminalArrows
{
private static bool Prefix(TMP_InputField __instance, Event e)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Invalid comparison between Unknown and I4
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Invalid comparison between Unknown and I4
if (!MergeMenu.IsActive || MergeMenu.BoundTerminal == null)
{
return true;
}
if (TerminalReflection.GetScreenTextObject(MergeMenu.BoundTerminal) != __instance)
{
return true;
}
if ((int)e.type != 4)
{
return true;
}
KeyCode keyCode = e.keyCode;
if (keyCode - 273 > 1)
{
return true;
}
e.Use();
return false;
}
}
[HarmonyPatch]
internal static class MergeHooks_HudEnableChat
{
private static MethodBase TargetMethod()
{
return AccessTools.DeclaredMethod(typeof(HUDManager), "EnableChat_performed", new Type[1] { typeof(CallbackContext) }, (Type[])null) ?? throw new InvalidOperationException("no EnableChat_performed");
}
private static bool Prefix()
{
return !MergeMenu.IsActive;
}
}
[HarmonyPatch]
internal static class MergeHooks_HudSubmitChat
{
private static MethodBase TargetMethod()
{
return AccessTools.DeclaredMethod(typeof(HUDManager), "SubmitChat_performed", new Type[1] { typeof(CallbackContext) }, (Type[])null) ?? throw new InvalidOperationException("no SubmitChat_performed");
}
private static bool Prefix()
{
return !MergeMenu.IsActive;
}
}
[HarmonyPatch(typeof(HUDManager), "PingHUDElement")]
internal static class MergeHooks_HudPing
{
private static bool Prefix(HUDElement element)
{
if (MergeMenu.IsActive && !((Object)(object)HUDManager.Instance == (Object)null))
{
return HUDManager.Instance.Chat != element;
}
return true;
}
}
[HarmonyPatch]
internal static class MergeHooks_ChuteRpc
{
private static bool Prepare()
{
return (object)TargetMethod() != null;
}
private static MethodBase? TargetMethod()
{
Type type = AccessTools.TypeByName("ShipInventoryUpdated.Scripts.ChuteRetrieve");
if ((object)type == null)
{
return null;
}
MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (MethodInfo methodInfo in methods)
{
if (!(methodInfo.Name != "RetrieveItemsServerRpc"))
{
ParameterInfo[] parameters = methodInfo.GetParameters();
if (parameters.Length == 1 && parameters[0].ParameterType.IsArray)
{
return methodInfo;
}
}
}
return null;
}
[HarmonyPrefix]
private static bool Prefix()
{
return !ShipInventoryMergeSuppression.IsSuppressed;
}
}
internal static class MergeScrapValueSync
{
[CompilerGenerated]
private static class <>O
{
public static HandleNamedMessageDelegate <0>__OnMessageReceived;
}
[CompilerGenerated]
private sealed class <DelayedBroadcastWithRetry>d__7 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public GrabbableObject grab;
public int scrapValue;
private int <i>5__2;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <DelayedBroadcastWithRetry>d__7(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<i>5__2 = 0;
break;
case 1:
<>1__state = -1;
<i>5__2++;
break;
}
if (<i>5__2 < 8)
{
if ((Object)(object)grab == (Object)null)
{
return false;
}
NetworkObject val = default(NetworkObject);
if (((Component)grab).TryGetComponent<NetworkObject>(ref val))
{
NetworkManager singleton = NetworkManager.Singleton;
if (singleton != null && (singleton.SpawnManager?.SpawnedObjects.ContainsKey(val.NetworkObjectId)).GetValueOrDefault())
{
HostBroadcastMergedScrap(grab, scrapValue);
return false;
}
}
<>2__current = null;
<>1__state = 1;
return true;
}
if ((Object)(object)grab != (Object)null)
{
HostBroadcastMergedScrap(grab, scrapValue);
}
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
internal const string MessageName = "mine9289.MergeScrap.ScrapVal";
private static bool _handlerRegistered;
internal static void Teardown(NetworkManager? nm)
{
if (!_handlerRegistered)
{
return;
}
try
{
NetworkManager? obj = nm ?? NetworkManager.Singleton;
if (obj != null)
{
CustomMessagingManager customMessagingManager = obj.CustomMessagingManager;
if (customMessagingManager != null)
{
customMessagingManager.UnregisterNamedMessageHandler("mine9289.MergeScrap.ScrapVal");
}
}
}
catch
{
}
_handlerRegistered = false;
}
internal static bool EnsureRegistered()
{
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Expected O, but got Unknown
if (_handlerRegistered)
{
return true;
}
NetworkManager singleton = NetworkManager.Singleton;
if ((Object)(object)singleton == (Object)null || !singleton.IsListening || singleton.CustomMessagingManager == null)
{
return false;
}
CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager;
object obj = <>O.<0>__OnMessageReceived;
if (obj == null)
{
HandleNamedMessageDelegate val = OnMessageReceived;
<>O.<0>__OnMessageReceived = val;
obj = (object)val;
}
customMessagingManager.RegisterNamedMessageHandler("mine9289.MergeScrap.ScrapVal", (HandleNamedMessageDelegate)obj);
_handlerRegistered = true;
return true;
}
private static void OnMessageReceived(ulong senderClientId, FastBufferReader reader)
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: 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_002b: Unknown result type (might be due to invalid IL or missing references)
if (!_handlerRegistered || senderClientId != 0L)
{
return;
}
try
{
ulong num = default(ulong);
((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num, default(ForPrimitives));
int scrapValue = default(int);
((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref scrapValue, default(ForPrimitives));
if (num == 0L)
{
return;
}
NetworkManager singleton = NetworkManager.Singleton;
if (((singleton != null) ? singleton.SpawnManager : null) != null && singleton.SpawnManager.SpawnedObjects.TryGetValue(num, out var value) && !((Object)(object)value == (Object)null))
{
GrabbableObject component = ((Component)value).GetComponent<GrabbableObject>();
if (component != null)
{
component.SetScrapValue(scrapValue);
}
}
}
catch (Exception ex)
{
Plugin.LogModWarning("[MergeScrap sync] " + ex.Message);
}
}
internal static void HostBroadcastMergedScrap(GrabbableObject grab, int scrapValue)
{
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
if (!EnsureRegistered())
{
return;
}
NetworkManager singleton = NetworkManager.Singleton;
if ((Object)(object)singleton == (Object)null || !singleton.IsServer)
{
return;
}
NetworkObject val = default(NetworkObject);
if (!((Component)grab).TryGetComponent<NetworkObject>(ref val))
{
Plugin.LogModWarning("[MergeScrap sync] merged item has no NetworkObject");
return;
}
ulong networkObjectId = val.NetworkObjectId;
if (networkObjectId == 0L)
{
return;
}
FastBufferWriter val2 = default(FastBufferWriter);
foreach (ulong connectedClientsId in singleton.ConnectedClientsIds)
{
if (connectedClientsId != singleton.LocalClientId)
{
((FastBufferWriter)(ref val2))..ctor(12, (Allocator)2, -1);
try
{
((FastBufferWriter)(ref val2)).WriteValueSafe<ulong>(ref networkObjectId, default(ForPrimitives));
((FastBufferWriter)(ref val2)).WriteValueSafe<int>(ref scrapValue, default(ForPrimitives));
singleton.CustomMessagingManager.SendNamedMessage("mine9289.MergeScrap.ScrapVal", connectedClientsId, val2, (NetworkDelivery)2);
}
finally
{
((FastBufferWriter)(ref val2)).Dispose();
}
}
}
}
internal static void HostBroadcastMergedScrapNextFrame(GrabbableObject grab, int scrapValue)
{
if ((Object)(object)Plugin.Instance != (Object)null)
{
((MonoBehaviour)Plugin.Instance).StartCoroutine(DelayedBroadcastWithRetry(grab, scrapValue));
}
else
{
HostBroadcastMergedScrap(grab, scrapValue);
}
}
[IteratorStateMachine(typeof(<DelayedBroadcastWithRetry>d__7))]
private static IEnumerator DelayedBroadcastWithRetry(GrabbableObject grab, int scrapValue)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <DelayedBroadcastWithRetry>d__7(0)
{
grab = grab,
scrapValue = scrapValue
};
}
}
[BepInPlugin("mine.MergeScrap", "MergeScrap", "1.1.2")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
public const string PluginGuid = "mine.MergeScrap";
public const string PluginName = "MergeScrap";
public const string PluginVersion = "1.1.2";
public const int MergeSoundClipIndex = 0;
private Harmony harmony;
public static Plugin Instance { get; private set; }
public static ConfigEntry<bool> SoundOnMerge { get; private set; }
public static ConfigEntry<bool> SkipGrabbableCheck { get; private set; }
private void Awake()
{
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Expected O, but got Unknown
Instance = this;
SoundOnMerge = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SoundOnMerge", true, "merge sound");
SkipGrabbableCheck = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SkipGrabbableCheck", true, "Skip grabbable==false filter when listing scrap (needed for some v81 items)");
InteractiveTerminalManager.RegisterApplication<ItapiPicker>(new string[4] { "merge", "merge scrap", "merge-scrap", "scrap-merge" }, false);
harmony = new Harmony("mine9289.mergescrap");
harmony.PatchAll(typeof(Plugin).Assembly);
((BaseUnityPlugin)this).Logger.LogInfo((object)"mine9289 / MergeScrap 1.1.2");
}
private void LateUpdate()
{
LateChatNuke.Tick();
}
private void OnDestroy()
{
MergeMenu.Close();
}
internal static void LogModWarning(string msg)
{
if ((Object)(object)Instance != (Object)null)
{
((BaseUnityPlugin)Instance).Logger.LogWarning((object)msg);
}
}
internal static void PlayMergeSound()
{
if (!SoundOnMerge.Value)
{
return;
}
Terminal val = Object.FindObjectOfType<Terminal>();
if ((Object)(object)val == (Object)null)
{
return;
}
try
{
val.PlayTerminalAudioServerRpc(0);
}
catch
{
}
}
public static bool ScrapListable(GrabbableObject g)
{
if ((Object)(object)g == (Object)null)
{
return false;
}
if ((Object)(object)g.itemProperties == (Object)null)
{
return false;
}
if (!g.itemProperties.isScrap)
{
return false;
}
if (g.isHeld)
{
return false;
}
if (!g.grabbable)
{
ConfigEntry<bool> skipGrabbableCheck = SkipGrabbableCheck;
if (skipGrabbableCheck == null || !skipGrabbableCheck.Value)
{
return false;
}
}
return true;
}
}
public sealed class ItapiPicker : InteractiveTerminalApplication<CursorElement>
{
private string banner = "Pick an item";
public override void Initialization()
{
Rebuild(MergeMenu.GetRowsSnapshot() ?? new List<ScrapPile>());
}
protected override Action PreviousScreen()
{
return delegate
{
PopItapi();
};
}
private static void PopItapi()
{
InteractiveTerminalManager instance = InteractiveTerminalManager.Instance;
if ((Object)(object)instance != (Object)null)
{
Object.Destroy((Object)(object)((Component)instance).gameObject);
}
}
private void Rebuild(List<ScrapPile> rows)
{
if (rows.Count == 0)
{
CursorElement val = CursorElement.Create("close", "", (Action)delegate
{
PopItapi();
}, (Func<CursorElement, bool>)null, true);
CursorMenu<CursorElement> val2 = (CursorMenu<CursorElement>)(object)(((BaseInteractiveApplication<CursorElement>)(object)this).currentCursorMenu = (BaseCursorMenu<CursorElement>)(object)CursorMenu<CursorElement>.Create(0, '>', (CursorElement[])(object)new CursorElement[1] { val }, (Func<CursorElement, CursorElement, int>[])null));
((TerminalApplication)this).currentScreen = (IScreen)(object)BoxedScreen.Create("merge", (ITextElement[])(object)new ITextElement[3]
{
(ITextElement)TextElement.Create("empty"),
(ITextElement)TextElement.Create(" "),
(ITextElement)val2
});
return;
}
CursorElement[] array = (CursorElement[])(object)new CursorElement[rows.Count];
for (int i = 0; i < rows.Count; i++)
{
ScrapPile scrapPile = rows[i];
string gk = scrapPile.GroupKey;
array[i] = CursorElement.Create($"{scrapPile.DisplayName}{scrapPile.FormatLocationCounts()} ×{scrapPile.TotalPieces} → ${scrapPile.TotalValue}", "", (Action)delegate
{
OnPick(gk);
}, (Func<CursorElement, bool>)null, true);
}
CursorMenu<CursorElement> val3 = (CursorMenu<CursorElement>)(object)(((BaseInteractiveApplication<CursorElement>)(object)this).currentCursorMenu = (BaseCursorMenu<CursorElement>)(object)CursorMenu<CursorElement>.Create(0, '>', array, (Func<CursorElement, CursorElement, int>[])null));
((TerminalApplication)this).currentScreen = (IScreen)(object)BoxedScreen.Create("merge", (ITextElement[])(object)new ITextElement[5]
{
(ITextElement)TextElement.Create(banner),
(ITextElement)TextElement.Create(" "),
(ITextElement)TextElement.Create("enter = merge / esc = cancel"),
(ITextElement)TextElement.Create(" "),
(ITextElement)val3
});
}
private static string Truncate(string? t)
{
if (string.IsNullOrEmpty(t))
{
return "—";
}
string[] array = t.Split(new char[2] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
string text = ((array.Length != 0) ? array[0] : t);
if (text.Length <= 220)
{
return text;
}
return text.Substring(0, 217) + "...";
}
private void OnPick(string groupKey)
{
string groupKey2 = groupKey;
object boundTerminal = MergeMenu.BoundTerminal;
int num = MergeMenu.GetRowsSnapshot()?.FindIndex((ScrapPile r) => r.GroupKey == groupKey2) ?? (-1);
if (num < 0)
{
return;
}
MergeMenu.SetSelectedIndex(num);
if (!MergeMenu.TryConfirmSelection(out TerminalNode node) || (Object)(object)node == (Object)null)
{
return;
}
if (!MergeMenu.IsActive)
{
if (boundTerminal != null)
{
MergeMenu.SetPendingFinalNodeAfterItapi(boundTerminal, node);
}
PopItapi();
}
else
{
banner = Truncate(node.displayText);
Rebuild(MergeMenu.GetRowsSnapshot() ?? new List<ScrapPile>());
}
}
}
internal static class ShipInventoryMergeSuppression
{
private static int depth;
internal static bool IsSuppressed => depth > 0;
internal static void Enter()
{
depth++;
}
internal static void Exit()
{
if (depth > 0)
{
depth--;
}
}
}
internal static class ShipInventoryMerge
{
[CompilerGenerated]
private sealed class <EnumerateInventoryScrapRows>d__23 : IEnumerable<(string groupKey, string displayName, int scrapValue)>, IEnumerable, IEnumerator<(string groupKey, string displayName, int scrapValue)>, IEnumerator, IDisposable
{
private int <>1__state;
private (string groupKey, string displayName, int scrapValue) <>2__current;
private int <>l__initialThreadId;
private IEnumerator <>7__wrap1;
(string, string, int) IEnumerator<(string, string, int)>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <EnumerateInventoryScrapRows>d__23(int <>1__state)
{
this.<>1__state = <>1__state;
<>l__initialThreadId = Environment.CurrentManagedThreadId;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
int num = <>1__state;
if (num == -3 || num == 1)
{
try
{
}
finally
{
<>m__Finally1();
}
}
<>7__wrap1 = null;
<>1__state = -2;
}
private bool MoveNext()
{
try
{
switch (<>1__state)
{
default:
return false;
case 0:
{
<>1__state = -1;
if (!EnsureLoaded())
{
return false;
}
IEnumerable enumerable = InvItems();
if (enumerable == null)
{
return false;
}
<>7__wrap1 = enumerable.GetEnumerator();
<>1__state = -3;
break;
}
case 1:
<>1__state = -3;
break;
}
while (<>7__wrap1.MoveNext())
{
object current = <>7__wrap1.Current;
if (current != null && TryInspect(current, out string groupKey, out string displayName, out int scrapValue))
{
<>2__current = (groupKey, displayName, scrapValue);
<>1__state = 1;
return true;
}
}
<>m__Finally1();
<>7__wrap1 = null;
return false;
}
catch
{
//try-fault
((IDisposable)this).Dispose();
throw;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
private void <>m__Finally1()
{
<>1__state = -1;
if (<>7__wrap1 is IDisposable disposable)
{
disposable.Dispose();
}
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
[DebuggerHidden]
IEnumerator<(string groupKey, string displayName, int scrapValue)> IEnumerable<(string, string, int)>.GetEnumerator()
{
if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
{
<>1__state = 0;
return this;
}
return new <EnumerateInventoryScrapRows>d__23(0);
}
[DebuggerHidden]
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<(string, string, int)>)this).GetEnumerator();
}
}
private const BindingFlags PublicInstance = BindingFlags.Instance | BindingFlags.Public;
private const BindingFlags PublicStatic = BindingFlags.Static | BindingFlags.Public;
private static bool ok;
private static Assembly? asm;
private static Type? itemDataType;
private static Type? inventoryType;
private static MethodInfo? getItem;
private static MethodInfo? remove;
private static MethodInfo? add;
private static MethodInfo? addRpc;
private static FieldInfo? invInstanceField;
private static Func<object, int>? scrap;
internal static bool EnsureItemDataApiReady()
{
return EnsureLoaded();
}
internal static object? ResolveGameItemFromItemDataBoxed(object boxed)
{
if (!EnsureLoaded() || getItem == null)
{
return null;
}
try
{
return getItem.Invoke(boxed, null);
}
catch
{
return null;
}
}
private static object? GetPropertyOrField(Type declaringType, object instance, string memberName)
{
PropertyInfo property = declaringType.GetProperty(memberName, BindingFlags.Instance | BindingFlags.Public);
if (property != null)
{
return property.GetValue(instance);
}
return declaringType.GetField(memberName, BindingFlags.Instance | BindingFlags.Public)?.GetValue(instance);
}
private static bool IsScrap(Type declaringType, object instance)
{
object propertyOrField = GetPropertyOrField(declaringType, instance, "isScrap");
bool flag = default(bool);
int num;
if (propertyOrField is bool)
{
flag = (bool)propertyOrField;
num = 1;
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
private static IEnumerable? InvItems()
{
if (inventoryType?.GetProperty("Items", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) is IEnumerable result)
{
return result;
}
return null;
}
internal static int GetInventoryItemCount()
{
if (!EnsureLoaded() || inventoryType == null)
{
return -1;
}
object obj = inventoryType.GetProperty("Count", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
if (obj is int)
{
return (int)obj;
}
return -1;
}
private static object? InvBehaviour()
{
if (inventoryType == null)
{
return null;
}
if ((object)invInstanceField == null)
{
invInstanceField = inventoryType.GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic);
}
object obj = invInstanceField?.GetValue(null);
if (obj == null)
{
Object[] array = Object.FindObjectsByType(inventoryType, (FindObjectsSortMode)0);
if (array == null || array.Length <= 0)
{
return null;
}
obj = array[0];
}
return obj;
}
internal static List<object> CollectInventoryEntriesMatchingGroup(string key)
{
List<object> list = new List<object>();
if (string.IsNullOrEmpty(key) || !EnsureLoaded())
{
return list;
}
IEnumerable enumerable = InvItems();
if (enumerable == null)
{
return list;
}
foreach (object item in enumerable)
{
if (item != null && TryInspect(item, out string groupKey, out string _, out int _) && string.Equals(groupKey, key, StringComparison.Ordinal))
{
list.Add(item);
}
}
return list;
}
internal static int SumInventoryScrapValues(IReadOnlyList<object> list)
{
if (scrap == null || list.Count == 0)
{
return 0;
}
int num = 0;
for (int i = 0; i < list.Count; i++)
{
if (list[i] != null)
{
num += scrap(list[i]);
}
}
return num;
}
internal static bool TryRemoveInventoryEntries(IReadOnlyList<object> entries, out string error)
{
error = "";
if (entries == null || entries.Count == 0)
{
return true;
}
if (!EnsureLoaded() || itemDataType == null || remove == null)
{
error = "no ShipInv Remove";
return false;
}
ShipInventoryMergeSuppression.Enter();
try
{
Array array = Array.CreateInstance(itemDataType, entries.Count);
for (int i = 0; i < entries.Count; i++)
{
array.SetValue(entries[i], i);
}
remove.Invoke(null, new object[1] { array });
return true;
}
catch (Exception ex)
{
error = ex.InnerException?.Message ?? ex.Message;
return false;
}
finally
{
ShipInventoryMergeSuppression.Exit();
}
}
internal static bool TryAddInventoryEntries(IReadOnlyList<object> entries, out string error, bool verifyCount = true)
{
error = "";
if (entries == null || entries.Count == 0)
{
return true;
}
if (!EnsureLoaded() || itemDataType == null || add == null)
{
error = "no ShipInv Add";
return false;
}
int num = (verifyCount ? GetInventoryItemCount() : (-1));
try
{
Array array = Array.CreateInstance(itemDataType, entries.Count);
for (int i = 0; i < entries.Count; i++)
{
array.SetValue(entries[i], i);
}
add.Invoke(null, new object[1] { array });
if (verifyCount && num >= 0)
{
int num2 = num + entries.Count;
int inventoryItemCount = GetInventoryItemCount();
if (inventoryItemCount != num2)
{
object obj = InvBehaviour();
if (obj != null && addRpc != null)
{
RpcDefaults(addRpc, obj, array);
inventoryItemCount = GetInventoryItemCount();
}
}
if (inventoryItemCount != num2)
{
error = $"inv count {num}->{inventoryItemCount}";
return false;
}
}
return true;
}
catch (Exception ex)
{
error = ex.InnerException?.Message ?? ex.Message;
return false;
}
}
[IteratorStateMachine(typeof(<EnumerateInventoryScrapRows>d__23))]
internal static IEnumerable<(string groupKey, string displayName, int scrapValue)> EnumerateInventoryScrapRows()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <EnumerateInventoryScrapRows>d__23(-2);
}
private static bool TryInspect(object boxed, out string groupKey, out string displayName, out int scrapValue)
{
groupKey = (displayName = "");
scrapValue = 0;
if (!EnsureLoaded() || itemDataType == null || scrap == null || getItem == null)
{
return false;
}
if (!itemDataType.IsInstanceOfType(boxed))
{
return false;
}
object obj;
try
{
obj = getItem.Invoke(boxed, null);
}
catch
{
return false;
}
if (obj == null)
{
return false;
}
Type type = obj.GetType();
if (!IsScrap(type, obj))
{
return false;
}
int num = scrap(boxed);
displayName = (GetPropertyOrField(type, obj, "itemName") as string) ?? "?";
object? propertyOrField = GetPropertyOrField(type, obj, "spawnPrefab");
GameObject val = (GameObject)((propertyOrField is GameObject) ? propertyOrField : null);
groupKey = ((val != null) ? ((Object)val).name.Replace("(Clone)", "", StringComparison.Ordinal) : displayName);
if (string.IsNullOrEmpty(groupKey))
{
groupKey = displayName;
}
scrapValue = num;
return true;
}
private static bool EnsureLoaded()
{
if (ok)
{
return true;
}
try
{
if (asm == null)
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
if (assembly.GetName().Name == "ShipInventoryUpdated")
{
asm = assembly;
break;
}
}
}
if (asm == null)
{
return false;
}
if ((object)itemDataType == null)
{
itemDataType = asm.GetType("ShipInventoryUpdated.Objects.ItemData");
}
if ((object)inventoryType == null)
{
inventoryType = asm.GetType("ShipInventoryUpdated.Scripts.Inventory");
}
if (itemDataType == null || (getItem = itemDataType.GetMethod("GetItem", Type.EmptyTypes)) == null)
{
return false;
}
if (inventoryType != null)
{
Type type = itemDataType.MakeArrayType();
if ((object)remove == null)
{
remove = inventoryType.GetMethod("Remove", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { type }, null);
}
if ((object)add == null)
{
add = inventoryType.GetMethod("Add", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { type }, null);
}
if ((object)addRpc == null)
{
addRpc = FindRpc(inventoryType, "AddServerRpc", type);
}
}
if (scrap == null)
{
Type type2 = itemDataType;
PropertyInfo prop = type2.GetProperty("SCRAP_VALUE", BindingFlags.Instance | BindingFlags.Public);
FieldInfo fld = ((prop == null) ? type2.GetField("SCRAP_VALUE", BindingFlags.Instance | BindingFlags.Public) : null);
if (prop != null)
{
scrap = (object b) => Convert.ToInt32(prop.GetValue(b) ?? ((object)0));
}
else
{
if (!(fld != null))
{
return false;
}
scrap = (object b) => Convert.ToInt32(fld.GetValue(b) ?? ((object)0));
}
}
ok = true;
return true;
}
catch
{
return false;
}
}
private static MethodInfo? FindRpc(Type t, string name, Type arg0)
{
MethodInfo[] methods = t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (MethodInfo methodInfo in methods)
{
if (!(methodInfo.Name != name))
{
ParameterInfo[] parameters = methodInfo.GetParameters();
if (parameters.Length != 0 && parameters[0].ParameterType == arg0)
{
return methodInfo;
}
}
}
return null;
}
private static void RpcDefaults(MethodInfo m, object target, object first)
{
ParameterInfo[] parameters = m.GetParameters();
object[] array = new object[parameters.Length];
array[0] = first;
for (int i = 1; i < parameters.Length; i++)
{
array[i] = (parameters[i].HasDefaultValue ? parameters[i].DefaultValue : Activator.CreateInstance(parameters[i].ParameterType));
}
m.Invoke(target, array);
}
}
internal static class TerminalType
{
private static readonly Lazy<Type> Lazy = new Lazy<Type>(delegate
{
Type? type = typeof(StartOfRound).Assembly.GetType("Terminal");
if (type == null)
{
throw new InvalidOperationException("no Terminal type");
}
return type;
});
internal static Type Value => Lazy.Value;
}
internal static class NormCmd
{
internal static string Strip(string s)
{
StringBuilder stringBuilder = new StringBuilder();
foreach (char c in s)
{
if (!char.IsPunctuation(c))
{
stringBuilder.Append(c);
}
}
return stringBuilder.ToString().ToLowerInvariant();
}
}
internal static class ScreenNode
{
internal static TerminalNode Make(string text, int maxChars = 80)
{
TerminalNode obj = ScriptableObject.CreateInstance<TerminalNode>();
obj.displayText = text;
obj.clearPreviousText = true;
obj.maxCharactersToType = maxChars;
return obj;
}
}
internal static class TerminalReflection
{
private static readonly FieldInfo? ScreenTextField;
private static readonly PropertyInfo? ScreenTextTextProperty;
private static readonly FieldInfo? TextAddedField;
private static readonly FieldInfo? CurrentTextField;
private static readonly FieldInfo? ModifyingTextField;
private static int inputLockDepth;
private static bool lockCaretSaved;
private static Color lockCaret;
private static Type? terminalNodeType;
private static Type TerminalNodeType
{
get
{
object obj = terminalNodeType;
if (obj == null)
{
obj = typeof(StartOfRound).Assembly.GetType("TerminalNode") ?? throw new InvalidOperationException("no TerminalNode");
terminalNodeType = (Type?)obj;
}
return (Type)obj;
}
}
static TerminalReflection()
{
Type value = TerminalType.Value;
ScreenTextField = value.GetField("screenText", BindingFlags.Instance | BindingFlags.Public);
TextAddedField = value.GetField("textAdded", BindingFlags.Instance | BindingFlags.Public);
CurrentTextField = value.GetField("currentText", BindingFlags.Instance | BindingFlags.Public);
ModifyingTextField = value.GetField("modifyingText", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
Type type = ScreenTextField?.FieldType;
if (type != null)
{
ScreenTextTextProperty = type.GetProperty("text", BindingFlags.Instance | BindingFlags.Public);
}
}
private static object? ScreenOf(object term)
{
return ScreenTextField?.GetValue(term);
}
internal static object? GetScreenTextObject(object term)
{
return ScreenTextField?.GetValue(term);
}
internal static void SetScreenBody(object term, string body)
{
ModifyingTextField?.SetValue(term, true);
object obj = ScreenOf(term);
if (obj != null && !(ScreenTextTextProperty == null))
{
ScreenTextTextProperty.SetValue(obj, body);
CurrentTextField?.SetValue(term, body);
TextAddedField?.SetValue(term, 0);
}
}
internal static void LockTermField(object term, bool on)
{
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: 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)
object obj = ScreenOf(term);
if (obj == null)
{
return;
}
Type type = obj.GetType();
PropertyInfo property = type.GetProperty("readOnly", BindingFlags.Instance | BindingFlags.Public);
PropertyInfo property2 = type.GetProperty("interactable", BindingFlags.Instance | BindingFlags.Public);
PropertyInfo property3 = type.GetProperty("caretColor", BindingFlags.Instance | BindingFlags.Public);
if (on)
{
if (inputLockDepth == 0)
{
if (property3?.GetValue(obj) is Color val)
{
lockCaret = val;
lockCaretSaved = true;
}
else
{
lockCaretSaved = false;
}
}
inputLockDepth++;
type.GetMethod("ReleaseSelection", BindingFlags.Instance | BindingFlags.Public)?.Invoke(obj, null);
type.GetMethod("DeactivateInputField", BindingFlags.Instance | BindingFlags.Public)?.Invoke(obj, null);
property?.SetValue(obj, true);
property2?.SetValue(obj, false);
property3?.SetValue(obj, (object)new Color(0f, 0f, 0f, 0f));
return;
}
if (inputLockDepth > 0)
{
inputLockDepth--;
}
if (inputLockDepth == 0)
{
if (lockCaretSaved)
{
property3?.SetValue(obj, lockCaret);
}
lockCaretSaved = false;
property?.SetValue(obj, false);
property2?.SetValue(obj, true);
}
}
internal static void LoadNewNode(object term, object node)
{
MethodInfo methodInfo = null;
MethodInfo[] methods = TerminalType.Value.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (MethodInfo methodInfo2 in methods)
{
if (!(methodInfo2.Name != "LoadNewNode") && methodInfo2.GetParameters().Length == 1 && methodInfo2.GetParameters()[0].ParameterType.IsAssignableFrom(TerminalNodeType))
{
methodInfo = methodInfo2;
break;
}
}
methodInfo?.Invoke(term, new object[1] { node });
}
internal static bool GetTerminalInUse(object term)
{
Type value = TerminalType.Value;
object obj = value.GetField("terminalInUse", BindingFlags.Instance | BindingFlags.Public)?.GetValue(term);
if (obj is bool)
{
return (bool)obj;
}
obj = value.GetProperty("terminalInUse", BindingFlags.Instance | BindingFlags.Public)?.GetValue(term);
bool flag = default(bool);
int num;
if (obj is bool)
{
flag = (bool)obj;
num = 1;
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
internal static void ActivateInput(object term)
{
object obj = ScreenOf(term);
if (obj != null)
{
Type type = obj.GetType();
type.GetMethod("ActivateInputField", BindingFlags.Instance | BindingFlags.Public)?.Invoke(obj, null);
type.GetMethod("Select", BindingFlags.Instance | BindingFlags.Public)?.Invoke(obj, null);
}
}
internal static int GetTextAdded(object term)
{
object obj = TextAddedField?.GetValue(term);
if (obj is int)
{
return (int)obj;
}
obj = TerminalType.Value.GetProperty("textAdded", BindingFlags.Instance | BindingFlags.Public)?.GetValue(term);
if (obj is int)
{
return (int)obj;
}
return 0;
}
internal static string GetRawInputSuffixForItapi(object term)
{
object obj = ScreenOf(term);
if (obj == null || !(ScreenTextTextProperty?.GetValue(obj) is string text))
{
return "";
}
int textAdded = GetTextAdded(term);
if (textAdded > 0 && textAdded <= text.Length)
{
return text.Substring(text.Length - textAdded);
}
return "";
}
internal static bool TryGetInputChunk(object term, out string chunk)
{
chunk = "";
object obj = ScreenOf(term);
if (obj == null || !(ScreenTextTextProperty?.GetValue(obj) is string text))
{
return false;
}
int textAdded = GetTextAdded(term);
if (textAdded <= 0 || textAdded > text.Length)
{
return false;
}
chunk = text.Substring(text.Length - textAdded);
return true;
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "MergeScrap";
public const string PLUGIN_NAME = "MergeScrap";
public const string PLUGIN_VERSION = "1.1.2";
}
}