using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Photon.Pun;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Zorro.Core;
using Zorro.Core.Serizalization;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyTitle("Splice Spools")]
[assembly: AssemblyDescription("PEAK BepInEx plugin that splices matching inventory rope spools into one longer spool.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Splice Spools")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("4006febd-7a9f-457c-865d-a3d4e2a97d25")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.0.0")]
[module: UnverifiableCode]
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}
namespace Splice_Spools
{
[BepInPlugin("tony4twentys.Splice_Spools", "Splice_Spools", "1.1.0")]
[BepInProcess("PEAK.exe")]
public class SpliceSpoolsPlugin : BaseUnityPlugin
{
public const string PluginGuid = "tony4twentys.Splice_Spools";
public const string PluginName = "Splice_Spools";
public const string PluginVersion = "1.1.0";
internal static ConfigEntry<KeyCode> SpliceKeyConfig;
internal static ConfigEntry<bool> IncludeBackpackConfig;
internal static ConfigEntry<float> LongPressSecondsConfig;
internal static ConfigEntry<float> RememberedCutMetersConfig;
private Harmony _harmony;
private string _toastText;
private float _toastUntil;
private GUIStyle _toastStyle;
private Coroutine _weightRoutine;
internal static SpliceSpoolsPlugin Instance { get; private set; }
internal static ManualLogSource Log { get; private set; }
private void Awake()
{
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Expected O, but got Unknown
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
Instance = this;
Log = ((BaseUnityPlugin)this).Logger;
SpliceKeyConfig = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Splice", "Splice Key", (KeyCode)99, "Tap to splice matching rope. Tap also opens the cut menu when there is nothing to combine. Hold to open the cut menu.");
IncludeBackpackConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Splice", "Include Backpack", true, "When true, leftover rope in a worn backpack is included when splicing or cutting.");
LongPressSecondsConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Splice", "Long Press Seconds", 0.45f, "Hold the splice key this long to open the cut menu instead of combining.");
RememberedCutMetersConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Cut", "Remembered Cut Meters", 10f, "Last typed cut length for the remembered-amount button.");
_harmony = new Harmony("tony4twentys.Splice_Spools");
_harmony.PatchAll();
CutMenu.EnsureCreated();
((MonoBehaviour)this).StartCoroutine(WatchSpliceKey());
((BaseUnityPlugin)this).Logger.LogInfo((object)($"Splice Spools loaded. Splice key: {SpliceKeyConfig.Value}. " + "Backpack: " + (IncludeBackpackConfig.Value ? "included" : "ignored") + "."));
}
private IEnumerator WatchSpliceKey()
{
while (true)
{
if (CutMenu.IsOpen)
{
yield return (object)new WaitWhile((Func<bool>)(() => CutMenu.IsOpen));
continue;
}
yield return null;
if (CutMenu.IsOpen || IsGameplayInputBlocked())
{
continue;
}
KeyCode key = (KeyCode)((SpliceKeyConfig != null) ? ((int)SpliceKeyConfig.Value) : 0);
if ((int)key == 0 || !Input.GetKeyDown(key))
{
continue;
}
float hold = ((LongPressSecondsConfig != null) ? LongPressSecondsConfig.Value : 0.45f);
if (hold < 0.15f)
{
hold = 0.15f;
}
float started = Time.unscaledTime;
bool openedMenu = false;
while (Input.GetKey(key))
{
if (!openedMenu && Time.unscaledTime - started >= hold)
{
openedMenu = true;
CutMenu.Open();
}
yield return null;
}
if (!openedMenu && !IsGameplayInputBlocked())
{
TryTapSplice();
}
}
}
private void TryTapSplice()
{
Character localCharacter = Character.localCharacter;
if (!((Object)(object)((localCharacter != null) ? localCharacter.player : null) == (Object)null) && localCharacter.IsLocal)
{
if (SpliceExecutor.TrySplice(localCharacter, out var message, out var hadMatchingPair))
{
ShowToast(message);
((BaseUnityPlugin)this).Logger.LogInfo((object)message);
}
else if (hadMatchingPair)
{
ShowToast(message);
((BaseUnityPlugin)this).Logger.LogInfo((object)message);
}
else
{
CutMenu.Open();
}
}
}
private void OnGUI()
{
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: 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_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Expected O, but got Unknown
if (!string.IsNullOrEmpty(_toastText) && !(Time.unscaledTime > _toastUntil))
{
if (_toastStyle == null)
{
_toastStyle = new GUIStyle(GUI.skin.label)
{
alignment = (TextAnchor)4,
fontSize = 16,
fontStyle = (FontStyle)1
};
}
Rect val = default(Rect);
((Rect)(ref val))..ctor(((float)Screen.width - 520f) * 0.5f, 72f, 520f, 36f);
Color color = GUI.color;
GUI.color = new Color(0f, 0f, 0f, 0.55f);
GUI.Box(val, GUIContent.none);
GUI.color = Color.white;
GUI.Label(val, _toastText, _toastStyle);
GUI.color = color;
}
}
private void OnDestroy()
{
CutMenu.DestroyInstance();
if (_harmony != null)
{
_harmony.UnpatchSelf();
}
if ((Object)(object)Instance == (Object)(object)this)
{
Instance = null;
}
Log = null;
}
internal static void RequestWeightRefresh()
{
if (!((Object)(object)Instance == (Object)null) && Instance._weightRoutine == null)
{
Instance._weightRoutine = ((MonoBehaviour)Instance).StartCoroutine(Instance.RefreshWeightNextFrame());
}
}
private IEnumerator RefreshWeightNextFrame()
{
yield return null;
_weightRoutine = null;
Character character = Character.localCharacter;
if ((Object)(object)character?.refs?.items == (Object)null)
{
yield break;
}
try
{
character.refs.items.RefreshAllCharacterCarryWeightRPC();
}
catch (Exception ex)
{
ManualLogSource log = Log;
if (log != null)
{
log.LogWarning((object)("Weight refresh skipped: " + ex.Message));
}
}
}
internal void ShowToast(string text)
{
_toastText = text;
_toastUntil = Time.unscaledTime + 2.5f;
}
private static bool IsGameplayInputBlocked()
{
if (GUIManager.InPauseMenu)
{
return true;
}
GUIManager instance = GUIManager.instance;
return (Object)(object)instance != (Object)null && instance.windowBlockingInput;
}
}
internal static class GameItemIds
{
public const ushort AntiRopeSpoolItemId = 1;
public const ushort RopeSpoolItemId = 65;
}
internal static class RopeSpoolLengthHelper
{
public const float MetersPerSegment = 0.25f;
public const float OutOfRopeSegmentThreshold = 2f;
public const float DefaultSpoolStartFuel = 60f;
public const float SegmentEpsilon = 0.01f;
public static float SegmentsToMeters(float segments)
{
return segments * 0.25f;
}
public static float MetersToSegments(float meters)
{
return meters / 0.25f;
}
public static float GetPlaceableSegments()
{
try
{
int maxSegments = Rope.MaxSegments;
return (maxSegments > 0) ? ((float)maxSegments) : 40f;
}
catch
{
return 40f;
}
}
public static float GetSpoolStartFuel(Item prefab)
{
if ((Object)(object)prefab == (Object)null)
{
return 60f;
}
RopeSpool component = ((Component)prefab).GetComponent<RopeSpool>();
return ((Object)(object)component != (Object)null) ? component.ropeStartFuel : 60f;
}
public static float GetSpoolStartFuel(ItemSlot slot)
{
return GetSpoolStartFuel((slot != null) ? slot.prefab : null);
}
public static float GetRemainingSegments(Item prefab, ItemInstanceData data)
{
float spoolStartFuel = GetSpoolStartFuel(prefab);
if (data == null)
{
return spoolStartFuel;
}
FloatItemData val = default(FloatItemData);
if (data.TryGetDataEntry<FloatItemData>((DataEntryKey)10, ref val))
{
return Mathf.Max(0f, val.Value);
}
FloatItemData val2 = default(FloatItemData);
if (data.TryGetDataEntry<FloatItemData>((DataEntryKey)11, ref val2))
{
return Mathf.Max(0f, val2.Value * spoolStartFuel);
}
return spoolStartFuel;
}
public static float GetRemainingSegments(ItemSlot slot)
{
if (slot == null || slot.IsEmpty())
{
return 0f;
}
return GetRemainingSegments(slot.prefab, slot.data);
}
public static float GetRemainingMeters(Item prefab, ItemInstanceData data)
{
return SegmentsToMeters(GetRemainingSegments(prefab, data));
}
public static int GetScaledCarryWeight(Item prefab, ItemInstanceData data)
{
if ((Object)(object)prefab == (Object)null)
{
return 0;
}
int carryWeight = prefab.CarryWeight;
if (!SpliceInventory.IsRopeSpoolPrefab(prefab))
{
return carryWeight;
}
float spoolStartFuel = GetSpoolStartFuel(prefab);
if (spoolStartFuel <= 0.01f)
{
return carryWeight;
}
float remainingSegments = GetRemainingSegments(prefab, data);
return Mathf.RoundToInt((float)carryWeight * (remainingSegments / spoolStartFuel));
}
public static bool HasSplicableLength(float segments)
{
return segments > 2.01f;
}
}
internal static class ItemDataHelper
{
public static void SetFloatEntry(ItemInstanceData data, DataEntryKey key, float value)
{
//IL_0002: 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_001e: Expected O, but got Unknown
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
FloatItemData val = default(FloatItemData);
if (data.TryGetDataEntry<FloatItemData>(key, ref val))
{
val.Value = value;
return;
}
FloatItemData val2 = new FloatItemData();
((DataEntryValue)val2).Init();
val2.Value = value;
data.RegisterEntry<FloatItemData>(key, val2);
}
}
internal static class SpliceInventory
{
private const byte TempInventorySlotId = 250;
public static bool IsRopeSpoolPrefab(Item prefab)
{
if ((Object)(object)prefab == (Object)null)
{
return false;
}
if (prefab.itemID == 65 || prefab.itemID == 1)
{
return true;
}
if ((Object)(object)((Component)prefab).GetComponent<RopeShooter>() != (Object)null)
{
return false;
}
if ((Object)(object)((Component)prefab).GetComponent<RopeSpool>() != (Object)null)
{
return true;
}
string text = (((Object)(object)((Component)prefab).gameObject != (Object)null) ? ((Object)((Component)prefab).gameObject).name : string.Empty);
return !string.IsNullOrEmpty(text) && text.IndexOf("Rope Spool", StringComparison.OrdinalIgnoreCase) >= 0;
}
public static bool IsAntiRopeSpoolPrefab(Item prefab)
{
if ((Object)(object)prefab == (Object)null)
{
return false;
}
if (prefab.itemID == 1)
{
return true;
}
RopeSpool component = ((Component)prefab).GetComponent<RopeSpool>();
if ((Object)(object)component != (Object)null && component.isAntiRope)
{
return true;
}
string text = ((Object)((Component)prefab).gameObject).name ?? string.Empty;
return text.IndexOf("Anti-Rope Spool", StringComparison.OrdinalIgnoreCase) >= 0;
}
public static List<ItemSlot> GetRopeSpoolSlots(Character character)
{
List<ItemSlot> list = new List<ItemSlot>();
if ((Object)(object)((character != null) ? character.player : null) == (Object)null)
{
return list;
}
AppendRopeSlots(character.player.itemSlots, list);
if (character.player.tempFullSlot != null && !character.player.tempFullSlot.IsEmpty() && IsRopeSpoolPrefab(character.player.tempFullSlot.prefab))
{
list.Add(character.player.tempFullSlot);
}
if (SpliceSpoolsPlugin.IncludeBackpackConfig.Value)
{
AppendBackpackRopeSlots(character, list);
}
return list;
}
private static void AppendRopeSlots(ItemSlot[] slots, List<ItemSlot> ropeSlots)
{
if (slots == null)
{
return;
}
foreach (ItemSlot val in slots)
{
if (val != null && !val.IsEmpty() && IsRopeSpoolPrefab(val.prefab))
{
ropeSlots.Add(val);
}
}
}
private static void AppendBackpackRopeSlots(Character character, List<ItemSlot> ropeSlots)
{
if (character.player.backpackSlot != null && !((ItemSlot)character.player.backpackSlot).IsEmpty())
{
ItemInstanceData data = ((ItemSlot)character.player.backpackSlot).data;
BackpackData val = default(BackpackData);
if (data != null && data.TryGetDataEntry<BackpackData>((DataEntryKey)7, ref val))
{
AppendRopeSlots(val.itemSlots, ropeSlots);
}
}
}
public static bool IsBackpackSlot(Character character, ItemSlot slot)
{
if ((Object)(object)((character != null) ? character.player : null) == (Object)null || slot == null || character.player.backpackSlot == null || ((ItemSlot)character.player.backpackSlot).IsEmpty())
{
return false;
}
ItemInstanceData data = ((ItemSlot)character.player.backpackSlot).data;
BackpackData val = default(BackpackData);
if (data == null || !data.TryGetDataEntry<BackpackData>((DataEntryKey)7, ref val) || val.itemSlots == null)
{
return false;
}
ItemSlot[] itemSlots = val.itemSlots;
foreach (ItemSlot val2 in itemSlots)
{
if (val2 == slot)
{
return true;
}
}
return false;
}
public static bool TryGetHeldSpool(Character character, out Item item, out RopeSpool spool)
{
object obj;
if (character == null)
{
obj = null;
}
else
{
CharacterData data = character.data;
obj = ((data != null) ? data.currentItem : null);
}
item = (Item)obj;
spool = (((Object)(object)item != (Object)null) ? ((Component)item).GetComponent<RopeSpool>() : null);
return (Object)(object)spool != (Object)null;
}
public static bool IsHeldSpoolBusy(Character character, bool isAntiRope)
{
if (!TryGetHeldSpool(character, out var item, out var spool))
{
return false;
}
if (spool.isAntiRope != isAntiRope)
{
return false;
}
RopeTier component = ((Component)item).GetComponent<RopeTier>();
return item.isUsingPrimary || ((Object)(object)component != (Object)null && component.LookingToPlaceAnchor);
}
public static ItemSlot GetHeldSpoolSlot(Character character)
{
//IL_0063: 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_0076: Unknown result type (might be due to invalid IL or missing references)
if (!TryGetHeldSpool(character, out var item, out var _))
{
return null;
}
ItemSlot val = FindSlotForItem(character, item);
if (val != null)
{
return val;
}
Optionable<byte> valueOrDefault = (character.refs?.items?.currentSelectedSlot).GetValueOrDefault();
if (valueOrDefault.IsSome)
{
ItemSlot itemSlot = character.player.GetItemSlot(valueOrDefault.Value);
if (itemSlot != null && !itemSlot.IsEmpty() && IsRopeSpoolPrefab(itemSlot.prefab))
{
return itemSlot;
}
}
if (character.player?.itemSlots != null)
{
ItemSlot[] itemSlots = character.player.itemSlots;
foreach (ItemSlot val2 in itemSlots)
{
if (val2 != null && !val2.IsEmpty() && (Object)(object)val2.prefab != (Object)null && val2.prefab.itemID == item.itemID)
{
return val2;
}
}
}
return null;
}
public static float GetRemainingSegmentsLive(Character character, ItemSlot slot)
{
object obj;
if (character == null)
{
obj = null;
}
else
{
CharacterData data = character.data;
obj = ((data != null) ? data.currentItem : null);
}
Item val = (Item)obj;
if ((Object)(object)val != (Object)null && SlotMatchesHeldItem(character, slot))
{
RopeSpool component = ((Component)val).GetComponent<RopeSpool>();
if ((Object)(object)component != (Object)null)
{
return Mathf.Max(0f, component.RopeFuel);
}
return RopeSpoolLengthHelper.GetRemainingSegments(val, val.data);
}
return RopeSpoolLengthHelper.GetRemainingSegments(slot);
}
public static ItemSlot FindLongestSpool(Character character)
{
return FindLongestSpool(character, GetRopeSpoolSlots(character));
}
public static ItemSlot FindLongestSpool(Character character, IEnumerable<ItemSlot> slots)
{
ItemSlot val = null;
float num = 0f;
if (slots == null)
{
return null;
}
foreach (ItemSlot slot in slots)
{
if (slot != null && !slot.IsEmpty())
{
float remainingSegmentsLive = GetRemainingSegmentsLive(character, slot);
if (RopeSpoolLengthHelper.HasSplicableLength(remainingSegmentsLive) && (val == null || remainingSegmentsLive > num))
{
val = slot;
num = remainingSegmentsLive;
}
}
}
return val;
}
public static ItemSlot FindSlotForItem(Character character, Item item)
{
if ((Object)(object)((character != null) ? character.player : null) == (Object)null || (Object)(object)item == (Object)null)
{
return null;
}
if (item.data != null && item.data.guid != Guid.Empty)
{
ItemSlot val = FindSlotByGuid(character, item.data.guid);
if (val != null)
{
return val;
}
}
foreach (ItemSlot ropeSpoolSlot in GetRopeSpoolSlots(character))
{
if (SlotMatchesHeldItem(character, ropeSpoolSlot))
{
return ropeSpoolSlot;
}
}
return null;
}
private static ItemSlot FindSlotByGuid(Character character, Guid guid)
{
ItemSlot val = FindSlotByGuid(character.player.itemSlots, guid);
if (val != null)
{
return val;
}
if (SlotHasGuid(character.player.tempFullSlot, guid))
{
return character.player.tempFullSlot;
}
BackpackData val2 = default(BackpackData);
if (character.player.backpackSlot != null && !((ItemSlot)character.player.backpackSlot).IsEmpty() && ((ItemSlot)character.player.backpackSlot).data != null && ((ItemSlot)character.player.backpackSlot).data.TryGetDataEntry<BackpackData>((DataEntryKey)7, ref val2))
{
return FindSlotByGuid(val2.itemSlots, guid);
}
return null;
}
private static ItemSlot FindSlotByGuid(ItemSlot[] slots, Guid guid)
{
if (slots == null)
{
return null;
}
foreach (ItemSlot val in slots)
{
if (SlotHasGuid(val, guid))
{
return val;
}
}
return null;
}
private static bool SlotHasGuid(ItemSlot slot, Guid guid)
{
return slot != null && !slot.IsEmpty() && slot.data != null && slot.data.guid == guid;
}
public static bool SlotMatchesHeldItem(Character character, ItemSlot slot)
{
//IL_00c4: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
object obj;
if (character == null)
{
obj = null;
}
else
{
CharacterData data = character.data;
obj = ((data != null) ? data.currentItem : null);
}
Item val = (Item)obj;
if ((Object)(object)val == (Object)null || slot == null || slot.IsEmpty() || (Object)(object)slot.prefab == (Object)null)
{
return false;
}
if (val.data != null && slot.data != null && val.data.guid != Guid.Empty && val.data.guid == slot.data.guid)
{
return true;
}
Optionable<byte> valueOrDefault = (character.refs?.items?.currentSelectedSlot).GetValueOrDefault();
return valueOrDefault.IsSome && valueOrDefault.Value == slot.itemSlotID && slot.prefab.itemID == val.itemID;
}
public static void ApplyFuelToSlot(ItemSlot slot, float remaining, float startFuel)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Expected O, but got Unknown
if (slot.data == null)
{
slot.data = new ItemInstanceData(Guid.NewGuid());
}
ItemDataHelper.SetFloatEntry(slot.data, (DataEntryKey)10, remaining);
float value = ((startFuel > 0f) ? Mathf.Clamp01(remaining / startFuel) : 0f);
ItemDataHelper.SetFloatEntry(slot.data, (DataEntryKey)11, value);
}
public static void ApplyFuelToHeldItem(Item item, float remaining, float startFuel)
{
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Expected O, but got Unknown
if (!((Object)(object)item == (Object)null))
{
if (item.data == null)
{
item.data = new ItemInstanceData(Guid.NewGuid());
}
ItemDataHelper.SetFloatEntry(item.data, (DataEntryKey)10, remaining);
RopeSpool component = ((Component)item).GetComponent<RopeSpool>();
if ((Object)(object)component != (Object)null)
{
((ItemComponent)component).OnInstanceDataSet();
}
float useRemainingPercentage = ((startFuel > 0f) ? Mathf.Clamp01(remaining / startFuel) : 0f);
item.SetUseRemainingPercentage(useRemainingPercentage);
}
}
public static void EmptySlotLocal(Character character, ItemSlot slot)
{
if (slot == null)
{
return;
}
if (IsBackpackSlot(character, slot) || slot.itemSlotID == 250)
{
slot.EmptyOut();
return;
}
ItemSlot itemSlot = character.player.GetItemSlot(slot.itemSlotID);
if (itemSlot != null)
{
itemSlot.EmptyOut();
}
}
public static void SyncInventory(Character character)
{
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)((character != null) ? character.player : null) == (Object)null || !PhotonNetwork.InRoom)
{
return;
}
PhotonView component = ((Component)character.player).GetComponent<PhotonView>();
if ((Object)(object)component == (Object)null)
{
return;
}
try
{
InventorySyncData val = default(InventorySyncData);
((InventorySyncData)(ref val))..ctor(character.player.itemSlots, character.player.backpackSlot, character.player.tempFullSlot);
byte[] array = IBinarySerializable.ToManagedArray<InventorySyncData>(val);
component.RPC("SyncInventoryRPC", (RpcTarget)1, new object[2]
{
array,
!PhotonNetwork.IsMasterClient
});
if (!PhotonNetwork.IsMasterClient)
{
component.RPC("SyncInventoryRPC", (RpcTarget)2, new object[2] { array, true });
}
}
catch (Exception ex)
{
SpliceSpoolsPlugin.Log.LogWarning((object)("Inventory sync skipped: " + ex.Message));
}
}
public static void SyncAfterChange(Character character, Item held)
{
SyncInventory(character);
if ((Object)(object)held != (Object)null)
{
PushHeldItemData(held);
}
if ((Object)(object)character?.refs?.items != (Object)null)
{
character.refs.items.RefreshAllCharacterCarryWeightRPC();
}
if (((character == null) ? null : character.player?.itemsChangedAction) != null)
{
character.player.itemsChangedAction(character.player.itemSlots);
}
}
public static int CountEmptyStorageSlots(ItemSlot ignore = null)
{
Character localCharacter = Character.localCharacter;
if ((Object)(object)((localCharacter != null) ? localCharacter.player : null) == (Object)null)
{
return 0;
}
int num = 0;
if (localCharacter.player.itemSlots != null)
{
ItemSlot[] itemSlots = localCharacter.player.itemSlots;
foreach (ItemSlot val in itemSlots)
{
if (val != null && val != ignore && val.IsEmpty())
{
num++;
}
}
}
BackpackData val2 = default(BackpackData);
if (!SpliceSpoolsPlugin.IncludeBackpackConfig.Value || localCharacter.player.backpackSlot == null || ((ItemSlot)localCharacter.player.backpackSlot).IsEmpty() || ((ItemSlot)localCharacter.player.backpackSlot).data == null || !((ItemSlot)localCharacter.player.backpackSlot).data.TryGetDataEntry<BackpackData>((DataEntryKey)7, ref val2) || val2.itemSlots == null)
{
return num;
}
ItemSlot[] itemSlots2 = val2.itemSlots;
foreach (ItemSlot val3 in itemSlots2)
{
if (val3 != null && val3 != ignore && val3.IsEmpty())
{
num++;
}
}
return num;
}
public static bool TryAddSpool(Character character, Item prefab, float segments, float startFuel, int dropIndex, out bool dropped)
{
dropped = false;
if ((Object)(object)((character != null) ? character.player : null) == (Object)null || (Object)(object)prefab == (Object)null)
{
return false;
}
ItemInstanceData val = CreateSpoolData(segments, startFuel);
if (character.player.itemSlots != null)
{
ItemSlot[] itemSlots = character.player.itemSlots;
foreach (ItemSlot val2 in itemSlots)
{
if (val2 != null && val2.IsEmpty())
{
val2.SetItem(prefab, val);
return true;
}
}
}
BackpackData val3 = default(BackpackData);
if (SpliceSpoolsPlugin.IncludeBackpackConfig.Value && character.player.backpackSlot != null && !((ItemSlot)character.player.backpackSlot).IsEmpty() && ((ItemSlot)character.player.backpackSlot).data != null && ((ItemSlot)character.player.backpackSlot).data.TryGetDataEntry<BackpackData>((DataEntryKey)7, ref val3) && val3.itemSlots != null)
{
for (byte b = 0; b < val3.itemSlots.Length; b++)
{
ItemSlot val4 = val3.itemSlots[b];
if (val4 != null && val4.IsEmpty())
{
val3.AddItem(prefab, val, b);
return !val3.itemSlots[b].IsEmpty();
}
}
}
dropped = TryDropSpool(character, prefab, val, dropIndex);
return dropped;
}
private static ItemInstanceData CreateSpoolData(float segments, float startFuel)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Expected O, but got Unknown
ItemInstanceData val = new ItemInstanceData(Guid.NewGuid());
ItemInstanceDataHandler.AddInstanceData(val);
ItemDataHelper.SetFloatEntry(val, (DataEntryKey)10, segments);
float value = ((startFuel > 0f) ? Mathf.Clamp01(segments / startFuel) : 0f);
ItemDataHelper.SetFloatEntry(val, (DataEntryKey)11, value);
return val;
}
private static bool TryDropSpool(Character character, Item prefab, ItemInstanceData data, int dropIndex)
{
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
string text = PrefabObjectName(prefab);
if (string.IsNullOrEmpty(text))
{
return false;
}
Vector3 pos = DropPosition(character, 1.2f + (float)dropIndex * 0.15f, 0.35f, dropIndex);
Quaternion rot = Quaternion.Euler(0f, (float)dropIndex * 35f, 0f);
GameObject val = TryInstantiateItem(text, pos, rot);
if ((Object)(object)val == (Object)null)
{
return false;
}
try
{
Item component = val.GetComponent<Item>();
if ((Object)(object)component != (Object)null)
{
component.data = data;
RopeSpool component2 = ((Component)component).GetComponent<RopeSpool>();
if ((Object)(object)component2 != (Object)null)
{
((ItemComponent)component2).OnInstanceDataSet();
}
}
PhotonView component3 = val.GetComponent<PhotonView>();
if ((Object)(object)component3 != (Object)null)
{
component3.RPC("SetItemInstanceDataRPC", (RpcTarget)0, new object[1] { data });
component3.RPC("SetKinematicRPC", (RpcTarget)3, new object[3]
{
false,
val.transform.position,
val.transform.rotation
});
}
}
catch (Exception ex)
{
ManualLogSource log = SpliceSpoolsPlugin.Log;
if (log != null)
{
log.LogWarning((object)("Dropped spool but failed to write length: " + ex.Message));
}
}
return true;
}
private static string PrefabObjectName(Item prefab)
{
if ((Object)(object)prefab == (Object)null)
{
return string.Empty;
}
string text = (((Object)(object)((Component)prefab).gameObject != (Object)null) ? ((Object)((Component)prefab).gameObject).name : ((Object)prefab).name);
if (string.IsNullOrEmpty(text))
{
return string.Empty;
}
if (text.EndsWith("(Clone)", StringComparison.Ordinal))
{
text = text.Substring(0, text.Length - "(Clone)".Length).TrimEnd(Array.Empty<char>());
}
return text;
}
private static Vector3 DropPosition(Character character, float forward, float up, int index)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: 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_006c: 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_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_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)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
try
{
Transform transform = character.GetBodypart((BodypartType)2).transform;
return transform.position + transform.TransformVector(Vector3.forward * forward + Vector3.right * ((float)index * 0.4f)) + Vector3.up * up;
}
catch
{
}
return character.Center + ((Component)character).transform.forward * forward + ((Component)character).transform.right * ((float)index * 0.4f) + Vector3.up * up;
}
private static GameObject TryInstantiateItem(string prefabName, Vector3 pos, Quaternion rot)
{
//IL_0003: Unknown result type (might be due to invalid IL or missing references)
//IL_0004: 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_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
try
{
GameObject val = PhotonNetwork.InstantiateItemRoom(prefabName, pos, rot, true);
if ((Object)(object)val != (Object)null)
{
return val;
}
}
catch
{
}
try
{
GameObject val2 = PhotonNetwork.Instantiate("0_Items/" + prefabName, pos, rot, (byte)0, (object[])null);
if ((Object)(object)val2 != (Object)null)
{
return val2;
}
}
catch
{
}
try
{
return PhotonNetwork.Instantiate(prefabName, pos, rot, (byte)0, (object[])null);
}
catch (Exception ex)
{
ManualLogSource log = SpliceSpoolsPlugin.Log;
if (log != null)
{
log.LogWarning((object)("Could not drop rope spool '" + prefabName + "': " + ex.Message));
}
return null;
}
}
public static void PushHeldItemData(Item item)
{
if (item?.data == null || !PhotonNetwork.InRoom)
{
return;
}
PhotonView component = ((Component)item).GetComponent<PhotonView>();
if ((Object)(object)component == (Object)null || (!component.IsMine && !PhotonNetwork.IsMasterClient))
{
return;
}
try
{
component.RPC("SetItemInstanceDataRPC", (RpcTarget)1, new object[1] { item.data });
}
catch (Exception ex)
{
SpliceSpoolsPlugin.Log.LogWarning((object)("Held spool sync skipped: " + ex.Message));
}
}
}
internal static class SpliceExecutor
{
public static bool TrySplice(Character character, out string message, out bool hadMatchingPair)
{
CollectSplicableGroups(character, out var normal, out var anti);
hadMatchingPair = normal.Count >= 2 || anti.Count >= 2;
bool flag = false;
bool flag2 = false;
float combinedMeters = 0f;
float combinedMeters2 = 0f;
int spoolCount = 0;
int spoolCount2 = 0;
if (normal.Count >= 2)
{
if (SpliceInventory.IsHeldSpoolBusy(character, isAntiRope: false))
{
message = "Finish placing your rope before splicing.";
return false;
}
flag = TrySpliceGroup(character, normal, isAntiRope: false, out combinedMeters, out spoolCount);
}
if (anti.Count >= 2)
{
if (SpliceInventory.IsHeldSpoolBusy(character, isAntiRope: true))
{
if (flag)
{
SpliceInventory.SyncAfterChange(character, null);
message = BuildResultMessage(splicedNormal: true, spoolCount, combinedMeters, splicedAnti: false, 0, 0f) + " Anti-grav spool is in use.";
return true;
}
message = "Finish placing your anti-grav rope before splicing.";
return false;
}
flag2 = TrySpliceGroup(character, anti, isAntiRope: true, out combinedMeters2, out spoolCount2);
}
if (!flag && !flag2)
{
message = ((normal.Count + anti.Count == 0) ? "No leftover rope spools to splice." : "Need at least two matching rope spools to splice.");
return false;
}
SpliceInventory.TryGetHeldSpool(character, out var item, out var _);
SpliceInventory.SyncAfterChange(character, item);
message = BuildResultMessage(flag, spoolCount, combinedMeters, flag2, spoolCount2, combinedMeters2);
return true;
}
private static void CollectSplicableGroups(Character character, out List<ItemSlot> normal, out List<ItemSlot> anti)
{
normal = new List<ItemSlot>();
anti = new List<ItemSlot>();
foreach (ItemSlot ropeSpoolSlot in SpliceInventory.GetRopeSpoolSlots(character))
{
AddSplicable(character, ropeSpoolSlot, normal, anti);
}
ItemSlot heldSpoolSlot = SpliceInventory.GetHeldSpoolSlot(character);
if (heldSpoolSlot != null)
{
AddSplicable(character, heldSpoolSlot, normal, anti);
}
}
private static void AddSplicable(Character character, ItemSlot slot, List<ItemSlot> normal, List<ItemSlot> anti)
{
if (slot == null || slot.IsEmpty() || ContainsSlot(normal, slot) || ContainsSlot(anti, slot))
{
return;
}
float remainingSegmentsLive = SpliceInventory.GetRemainingSegmentsLive(character, slot);
if (RopeSpoolLengthHelper.HasSplicableLength(remainingSegmentsLive))
{
if (SpliceInventory.IsAntiRopeSpoolPrefab(slot.prefab))
{
anti.Add(slot);
}
else
{
normal.Add(slot);
}
}
}
private static bool ContainsSlot(List<ItemSlot> slots, ItemSlot slot)
{
for (int i = 0; i < slots.Count; i++)
{
if (slots[i] == slot)
{
return true;
}
}
return false;
}
private static bool TrySpliceGroup(Character character, List<ItemSlot> slots, bool isAntiRope, out float combinedMeters, out int spoolCount)
{
combinedMeters = 0f;
spoolCount = slots.Count;
if (slots.Count < 2)
{
return false;
}
ItemSlot val = ChooseTargetSlot(character, slots, isAntiRope);
if (val == null)
{
return false;
}
float num = 0f;
foreach (ItemSlot slot in slots)
{
num += SpliceInventory.GetRemainingSegmentsLive(character, slot);
}
if (!RopeSpoolLengthHelper.HasSplicableLength(num))
{
return false;
}
float spoolStartFuel = RopeSpoolLengthHelper.GetSpoolStartFuel(val);
SpliceInventory.ApplyFuelToSlot(val, num, spoolStartFuel);
if (SpliceInventory.SlotMatchesHeldItem(character, val))
{
SpliceInventory.ApplyFuelToHeldItem(character.data.currentItem, num, spoolStartFuel);
}
foreach (ItemSlot slot2 in slots)
{
if (slot2 != val)
{
SpliceInventory.EmptySlotLocal(character, slot2);
}
}
combinedMeters = RopeSpoolLengthHelper.SegmentsToMeters(num);
return true;
}
private static ItemSlot ChooseTargetSlot(Character character, List<ItemSlot> slots, bool isAntiRope)
{
ItemSlot heldSpoolSlot = SpliceInventory.GetHeldSpoolSlot(character);
if (heldSpoolSlot != null && SpliceInventory.IsAntiRopeSpoolPrefab(heldSpoolSlot.prefab) == isAntiRope)
{
foreach (ItemSlot slot in slots)
{
if (slot == heldSpoolSlot || SpliceInventory.SlotMatchesHeldItem(character, slot))
{
return slot;
}
}
}
foreach (ItemSlot slot2 in slots)
{
if (SpliceInventory.SlotMatchesHeldItem(character, slot2) && SpliceInventory.IsAntiRopeSpoolPrefab(slot2.prefab) == isAntiRope)
{
return slot2;
}
}
return SpliceInventory.FindLongestSpool(character, slots) ?? slots[0];
}
private static string BuildResultMessage(bool splicedNormal, int normalCount, float normalMeters, bool splicedAnti, int antiCount, float antiMeters)
{
if (splicedNormal && splicedAnti)
{
return $"Spliced {normalCount} rope spools into {normalMeters:0.##}m and {antiCount} anti-grav spools into {antiMeters:0.##}m.";
}
if (splicedAnti)
{
return $"Spliced {antiCount} anti-grav spools into {antiMeters:0.##}m.";
}
return $"Spliced {normalCount} rope spools into {normalMeters:0.##}m.";
}
}
internal sealed class CutHoverTarget : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler
{
internal Func<float> GetSegments;
public void OnPointerEnter(PointerEventData eventData)
{
if (GetSegments != null)
{
CutMenu.SetHover(GetSegments());
}
}
public void OnPointerExit(PointerEventData eventData)
{
CutMenu.ClearHover();
}
}
internal sealed class CutButtonBind : MonoBehaviour
{
internal float Segments;
internal bool IsPreset;
internal string LastLabel;
internal Button Button;
internal TextMeshProUGUI Label;
private void Awake()
{
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Expected O, but got Unknown
Button = ((Component)this).GetComponent<Button>();
Label = ((Component)this).GetComponentInChildren<TextMeshProUGUI>(true);
CutHoverTarget component = ((Component)this).GetComponent<CutHoverTarget>();
if ((Object)(object)component != (Object)null)
{
component.GetSegments = () => Segments;
}
if ((Object)(object)Button != (Object)null)
{
((UnityEvent)Button.onClick).AddListener((UnityAction)delegate
{
CutMenu.ClickBound(this);
});
}
}
}
internal sealed class CutMenu : MonoBehaviour
{
private const int SortOrder = 9400;
private const float ButtonHeight = 38f;
private const float SourceCheckSeconds = 0.35f;
private static CutMenu _instance;
private static float _hoverSegments = -1f;
private bool _visible;
private bool _built;
private CursorLockMode _prevLock;
private bool _prevCursorVisible;
private Vector2 _frozenLookValues;
private bool _hasFrozenLook;
private Coroutine _menuRoutine;
private ItemSlot _source;
private bool _layoutDirty;
private bool _previewDirty;
private float _placeable;
private float _cachedRemaining = float.MinValue;
private float _cachedVanilla = float.MinValue;
private float _cachedHover = float.MinValue;
private int _cachedEmpty = int.MinValue;
private string _cachedCustom = null;
private string _cachedRemembered = null;
private string _cachedTitle;
private string _cachedStatus;
private string _cachedPreview;
private TextMeshProUGUI _title;
private TextMeshProUGUI _status;
private TextMeshProUGUI _preview;
private Button _fullVanilla;
private Button _halfVanilla;
private Button _maxPlaceable;
private Button _halfCurrent;
private Button _quarterCurrent;
private Button _thirdCurrent;
private Button _remembered;
private Button _custom;
private TMP_InputField _rememberedField;
private TMP_InputField _customField;
private string _customText = string.Empty;
public static bool IsOpen => (Object)(object)_instance != (Object)null && _instance._visible && ((Component)_instance).gameObject.activeInHierarchy;
public static void EnsureCreated()
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
if (!((Object)(object)_instance != (Object)null))
{
GameObject val = new GameObject("SpliceSpools_CutMenu");
Object.DontDestroyOnLoad((Object)(object)val);
_instance = val.AddComponent<CutMenu>();
val.SetActive(false);
}
}
public static void Open()
{
EnsureCreated();
_instance.OpenInternal();
}
public static void Close()
{
if ((Object)(object)_instance != (Object)null)
{
_instance.CloseInternal();
}
}
public static void DestroyInstance()
{
if (!((Object)(object)_instance == (Object)null))
{
_instance.CloseInternal();
Object.Destroy((Object)(object)((Component)_instance).gameObject);
_instance = null;
}
}
public static void SetHover(float segments)
{
if (!(Mathf.Abs(_hoverSegments - segments) <= 0.01f))
{
_hoverSegments = segments;
if ((Object)(object)_instance != (Object)null)
{
_instance._previewDirty = true;
}
}
}
public static void ClearHover()
{
if (!(_hoverSegments < 0f))
{
_hoverSegments = -1f;
if ((Object)(object)_instance != (Object)null)
{
_instance._previewDirty = true;
}
}
}
internal static void ClickBound(CutButtonBind bind)
{
if (!((Object)(object)_instance == (Object)null) && !((Object)(object)bind == (Object)null))
{
_instance.TryCutClicked(bind.Segments);
}
}
private void OpenInternal()
{
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
Character localCharacter = Character.localCharacter;
if (!CutExecutor.TryGetSource(localCharacter, out var source, out var message))
{
SpliceSpoolsPlugin.Instance?.ShowToast(message);
ManualLogSource log = SpliceSpoolsPlugin.Log;
if (log != null)
{
log.LogInfo((object)message);
}
return;
}
CutUi.EnsureEventSystem();
Build();
_source = source;
_visible = true;
((Component)this).gameObject.SetActive(true);
_prevLock = Cursor.lockState;
_prevCursorVisible = Cursor.visible;
Cursor.lockState = (CursorLockMode)0;
Cursor.visible = true;
ApplyMenuInputBlock(block: true);
CaptureFrozenLook();
if ((Object)(object)_customField != (Object)null)
{
_customField.text = _customText ?? string.Empty;
}
if ((Object)(object)_rememberedField != (Object)null && SpliceSpoolsPlugin.RememberedCutMetersConfig != null)
{
_rememberedField.text = SpliceSpoolsPlugin.RememberedCutMetersConfig.Value.ToString("0.##", CultureInfo.InvariantCulture);
}
_placeable = RopeSpoolLengthHelper.GetPlaceableSegments();
InvalidateCache();
Refresh(force: true);
if (_menuRoutine == null)
{
_menuRoutine = ((MonoBehaviour)this).StartCoroutine(MenuRoutine());
}
}
private void CloseInternal()
{
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
if (_visible)
{
_visible = false;
_hoverSegments = -1f;
_hasFrozenLook = false;
_source = null;
_menuRoutine = null;
if ((Object)(object)_rememberedField != (Object)null)
{
_rememberedField.DeactivateInputField(false);
}
if ((Object)(object)_customField != (Object)null)
{
_customField.DeactivateInputField(false);
}
CutUi.ReleaseUiFocus();
ApplyMenuInputBlock(block: false);
Cursor.lockState = _prevLock;
Cursor.visible = _prevCursorVisible;
((Component)this).gameObject.SetActive(false);
}
}
private IEnumerator MenuRoutine()
{
float sourceCheck = 0f;
while (_visible)
{
if (Input.GetKeyDown((KeyCode)27) || (SpliceSpoolsPlugin.SpliceKeyConfig != null && Input.GetKeyDown(SpliceSpoolsPlugin.SpliceKeyConfig.Value)))
{
CloseInternal();
yield break;
}
sourceCheck += Time.unscaledDeltaTime;
if (sourceCheck >= 0.35f)
{
sourceCheck = 0f;
if (!TryRefreshSource())
{
yield break;
}
}
if (_layoutDirty)
{
Refresh(force: true);
}
else if (_previewDirty)
{
RefreshPreview();
}
yield return null;
}
_menuRoutine = null;
}
private void LateUpdate()
{
if (_visible)
{
HoldFrozenLook();
}
}
private bool TryRefreshSource()
{
if (!CutExecutor.TryGetSource(Character.localCharacter, out var source, out var message))
{
CloseInternal();
SpliceSpoolsPlugin.Instance?.ShowToast(message);
return false;
}
if (_source != source)
{
_source = source;
_layoutDirty = true;
return true;
}
float remainingSegmentsLive = SpliceInventory.GetRemainingSegmentsLive(Character.localCharacter, source);
if (Mathf.Abs(remainingSegmentsLive - _cachedRemaining) > 0.05f)
{
_layoutDirty = true;
}
return true;
}
private void Build()
{
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Expected O, but got Unknown
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
//IL_01f1: Expected O, but got Unknown
if (!_built)
{
CutUi.CreateOverlayCanvas(((Component)this).gameObject, 9400);
RectTransform val = CutUi.CreatePanel(((Component)this).transform, "Panel", new Vector2(560f, 720f), CutUi.PanelColor);
CutUi.AddVertical(((Component)val).gameObject, 8f, new RectOffset(22, 22, 18, 18));
_title = CutUi.CreateLabel((Transform)(object)val, "Title", "Cut Rope", 26f, (FontStyles)1, (TextAlignmentOptions)514);
AddFixedHeight(((Component)_title).gameObject, 34f);
_status = CutUi.CreateLabel((Transform)(object)val, "Status", string.Empty, 16f, (FontStyles)0, (TextAlignmentOptions)514);
AddFixedHeight(((Component)_status).gameObject, 48f);
_preview = CutUi.CreateLabel((Transform)(object)val, "Preview", "Hover a cut to preview.", 16f, (FontStyles)0, (TextAlignmentOptions)514);
((Graphic)_preview).color = CutUi.CreamDim;
AddFixedHeight(((Component)_preview).gameObject, 72f);
_fullVanilla = AddCutButton((Transform)(object)val, "Full vanilla spool", preset: true);
_halfVanilla = AddCutButton((Transform)(object)val, "Half vanilla spool", preset: true);
_maxPlaceable = AddCutButton((Transform)(object)val, "Max placeable length", preset: true);
_halfCurrent = AddCutButton((Transform)(object)val, "Half of this spool", preset: true);
_quarterCurrent = AddCutButton((Transform)(object)val, "1/4 of this spool", preset: true);
_thirdCurrent = AddCutButton((Transform)(object)val, "1/3 of this spool", preset: true);
AddAmountRow((Transform)(object)val, "Remembered meters", "Cut remembered", remembered: true, out _rememberedField, out _remembered);
AddAmountRow((Transform)(object)val, "Custom meters", "Cut custom", remembered: false, out _customField, out _custom);
Button val2 = CutUi.CreateButton((Transform)(object)val, "Close", new UnityAction(CloseInternal), new Vector2(200f, 38f));
((Component)val2).transform.SetAsLastSibling();
_built = true;
}
}
private Button AddCutButton(Transform parent, string label, bool preset)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
Button val = CutUi.CreateButton(parent, label, null, new Vector2(500f, 38f));
((Component)val).gameObject.AddComponent<CutHoverTarget>();
CutButtonBind cutButtonBind = ((Component)val).gameObject.AddComponent<CutButtonBind>();
cutButtonBind.IsPreset = preset;
return val;
}
private void AddAmountRow(Transform parent, string placeholder, string buttonLabel, bool remembered, out TMP_InputField field, out Button button)
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Expected O, but got Unknown
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject(remembered ? "RememberedRow" : "CustomRow", new Type[1] { typeof(RectTransform) });
val.transform.SetParent(parent, false);
LayoutElement val2 = val.AddComponent<LayoutElement>();
val2.minHeight = 38f;
val2.preferredHeight = 38f;
CutUi.AddHorizontal(val, 8f);
string initial = string.Empty;
if (remembered && SpliceSpoolsPlugin.RememberedCutMetersConfig != null)
{
initial = SpliceSpoolsPlugin.RememberedCutMetersConfig.Value.ToString("0.##", CultureInfo.InvariantCulture);
}
UnityAction<string> onChanged = (remembered ? new UnityAction<string>(OnRememberedChanged) : new UnityAction<string>(OnCustomChanged));
field = CutUi.CreateNumberField(val.transform, placeholder, initial, onChanged);
button = CutUi.CreateButton(val.transform, buttonLabel, null, new Vector2(180f, 38f));
LayoutElement component = ((Component)button).GetComponent<LayoutElement>();
component.flexibleWidth = 0f;
component.preferredWidth = 180f;
component.minWidth = 180f;
((Component)button).gameObject.AddComponent<CutHoverTarget>();
CutButtonBind cutButtonBind = ((Component)button).gameObject.AddComponent<CutButtonBind>();
cutButtonBind.IsPreset = false;
}
private static void AddFixedHeight(GameObject go, float height)
{
LayoutElement val = go.GetComponent<LayoutElement>() ?? go.AddComponent<LayoutElement>();
val.minHeight = height;
val.preferredHeight = height;
}
private void OnRememberedChanged(string value)
{
if (TryParseMeters(value, out var meters) && SpliceSpoolsPlugin.RememberedCutMetersConfig != null)
{
SpliceSpoolsPlugin.RememberedCutMetersConfig.Value = meters;
}
_layoutDirty = true;
}
private void OnCustomChanged(string value)
{
_customText = value ?? string.Empty;
_layoutDirty = true;
}
private void InvalidateCache()
{
_cachedRemaining = float.MinValue;
_cachedVanilla = float.MinValue;
_cachedHover = float.MinValue;
_cachedEmpty = int.MinValue;
_cachedCustom = null;
_cachedRemembered = null;
_layoutDirty = true;
_previewDirty = true;
}
private void Refresh(bool force)
{
if (_source != null && !_source.IsEmpty())
{
float remainingSegmentsLive = SpliceInventory.GetRemainingSegmentsLive(Character.localCharacter, _source);
float spoolStartFuel = RopeSpoolLengthHelper.GetSpoolStartFuel(_source);
string text = (((Object)(object)_rememberedField != (Object)null) ? _rememberedField.text : string.Empty);
if (force || Mathf.Abs(remainingSegmentsLive - _cachedRemaining) > 0.01f || Mathf.Abs(spoolStartFuel - _cachedVanilla) > 0.01f || !string.Equals(_cachedCustom, _customText, StringComparison.Ordinal) || !string.Equals(_cachedRemembered, text, StringComparison.Ordinal))
{
_cachedRemaining = remainingSegmentsLive;
_cachedVanilla = spoolStartFuel;
_cachedCustom = _customText;
_cachedRemembered = text;
WriteStatus(remainingSegmentsLive, spoolStartFuel);
WriteButtons(remainingSegmentsLive, spoolStartFuel);
_previewDirty = true;
}
RefreshPreview();
_layoutDirty = false;
}
}
private void WriteStatus(float remaining, float vanilla)
{
string text = (SpliceInventory.IsAntiRopeSpoolPrefab(_source.prefab) ? "Anti-grav rope" : "Rope");
string text2 = "Cut " + text;
string text3 = string.Format(CultureInfo.InvariantCulture, "{0} • {1:0.##}m now\nVanilla full {2:0.##}m • Placeable {3:0.##}m", text, RopeSpoolLengthHelper.SegmentsToMeters(remaining), RopeSpoolLengthHelper.SegmentsToMeters(vanilla), RopeSpoolLengthHelper.SegmentsToMeters(_placeable));
if (_cachedTitle != text2)
{
_cachedTitle = text2;
((TMP_Text)_title).text = text2;
}
if (_cachedStatus != text3)
{
_cachedStatus = text3;
((TMP_Text)_status).text = text3;
}
}
private void WriteButtons(float remaining, float vanilla)
{
ApplyPreset(_fullVanilla, "Full vanilla spool ({0:0.##}m)", vanilla, remaining);
ApplyPreset(_halfVanilla, "Half vanilla spool ({0:0.##}m)", vanilla * 0.5f, remaining);
ApplyPreset(_maxPlaceable, "Max placeable ({0:0.##}m)", _placeable, remaining);
ApplyPreset(_halfCurrent, "Half of this spool ({0:0.##}m)", remaining * 0.5f, remaining);
ApplyPreset(_quarterCurrent, "1/4 of this spool ({0:0.##}m)", remaining * 0.25f, remaining);
ApplyPreset(_thirdCurrent, "1/3 of this spool ({0:0.##}m)", remaining / 3f, remaining);
float meters = 0f;
bool flag = TryParseMeters(_cachedRemembered, out meters);
ApplyTyped(_remembered, flag ? RopeSpoolLengthHelper.MetersToSegments(meters) : (-1f), remaining);
float meters2 = 0f;
bool flag2 = TryParseMeters(_customText, out meters2);
ApplyTyped(_custom, flag2 ? RopeSpoolLengthHelper.MetersToSegments(meters2) : (-1f), remaining);
}
private void RefreshPreview()
{
if (_source == null || _source.IsEmpty() || (Object)(object)_preview == (Object)null)
{
_previewDirty = false;
return;
}
float num = ResolvePreviewSegments();
int num2 = SpliceInventory.CountEmptyStorageSlots(_source);
if (!_previewDirty && Mathf.Abs(num - _cachedHover) <= 0.01f && num2 == _cachedEmpty)
{
_previewDirty = false;
return;
}
_cachedHover = num;
_cachedEmpty = num2;
string text = CutExecutor.BuildPreview(_source, num, _cachedRemaining, _cachedVanilla, num2);
if (_cachedPreview != text)
{
_cachedPreview = text;
((TMP_Text)_preview).text = text;
}
_previewDirty = false;
}
private float ResolvePreviewSegments()
{
if (_hoverSegments >= 0f)
{
return _hoverSegments;
}
if ((Object)(object)EventSystem.current == (Object)null)
{
return -1f;
}
GameObject currentSelectedGameObject = EventSystem.current.currentSelectedGameObject;
if ((Object)(object)currentSelectedGameObject != (Object)null && (Object)(object)_rememberedField != (Object)null && currentSelectedGameObject.transform.IsChildOf(((Component)_rememberedField).transform) && TryParseMeters(_cachedRemembered, out var meters))
{
return RopeSpoolLengthHelper.MetersToSegments(meters);
}
if ((Object)(object)currentSelectedGameObject != (Object)null && (Object)(object)_customField != (Object)null && currentSelectedGameObject.transform.IsChildOf(((Component)_customField).transform) && TryParseMeters(_customText, out meters))
{
return RopeSpoolLengthHelper.MetersToSegments(meters);
}
return -1f;
}
private static void ApplyPreset(Button button, string labelFormat, float cutSegments, float remaining)
{
CutButtonBind component = ((Component)button).GetComponent<CutButtonBind>();
bool flag = CutExecutor.CanCut(remaining, cutSegments);
if ((Object)(object)component != (Object)null)
{
component.Segments = cutSegments;
}
if (((Component)button).gameObject.activeSelf != flag)
{
((Component)button).gameObject.SetActive(flag);
}
if (flag)
{
string text = string.Format(CultureInfo.InvariantCulture, labelFormat, RopeSpoolLengthHelper.SegmentsToMeters(cutSegments));
if ((Object)(object)component != (Object)null && (Object)(object)component.Label != (Object)null && component.LastLabel != text)
{
component.LastLabel = text;
((TMP_Text)component.Label).text = text;
}
}
}
private static void ApplyTyped(Button button, float cutSegments, float remaining)
{
CutButtonBind component = ((Component)button).GetComponent<CutButtonBind>();
if ((Object)(object)component != (Object)null)
{
component.Segments = cutSegments;
}
bool flag = cutSegments > 0f && CutExecutor.CanCut(remaining, cutSegments);
if (((Selectable)button).interactable != flag)
{
((Selectable)button).interactable = flag;
}
}
private void TryCutClicked(float cutSegments)
{
Character localCharacter = Character.localCharacter;
string message;
bool flag = CutExecutor.TryCut(localCharacter, cutSegments, out message);
SpliceSpoolsPlugin.Instance?.ShowToast(message);
ManualLogSource log = SpliceSpoolsPlugin.Log;
if (log != null)
{
log.LogInfo((object)message);
}
if (flag && TryRefreshSource())
{
InvalidateCache();
Refresh(force: true);
}
}
private static bool TryParseMeters(string text, out float meters)
{
meters = 0f;
if (string.IsNullOrEmpty(text))
{
return false;
}
return float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out meters) || float.TryParse(text, NumberStyles.Float, CultureInfo.CurrentCulture, out meters);
}
private void CaptureFrozenLook()
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
Character localCharacter = Character.localCharacter;
if (!((Object)(object)localCharacter?.data == (Object)null))
{
_frozenLookValues = localCharacter.data.lookValues;
_hasFrozenLook = true;
}
}
private void HoldFrozenLook()
{
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
if (_hasFrozenLook)
{
Character localCharacter = Character.localCharacter;
if (!((Object)(object)localCharacter?.data == (Object)null))
{
localCharacter.data.lookValues = _frozenLookValues;
}
}
}
internal static void ApplyMenuInputBlock(bool block)
{
GUIManager instance = GUIManager.instance;
if ((Object)(object)instance == (Object)null)
{
return;
}
try
{
instance.windowBlockingInput = block;
instance.windowShowingCursor = block;
}
catch
{
}
}
}
internal static class CutExecutor
{
public static bool TryGetSource(Character character, out ItemSlot source, out string message)
{
source = null;
if ((Object)(object)((character != null) ? character.player : null) == (Object)null || !character.IsLocal)
{
message = "No local scout to cut rope from.";
return false;
}
if (SpliceInventory.TryGetHeldSpool(character, out var _, out var spool))
{
if (SpliceInventory.IsHeldSpoolBusy(character, spool.isAntiRope))
{
message = "Finish placing your rope before cutting.";
return false;
}
source = SpliceInventory.GetHeldSpoolSlot(character);
if (source != null && RopeSpoolLengthHelper.HasSplicableLength(SpliceInventory.GetRemainingSegmentsLive(character, source)))
{
message = string.Empty;
return true;
}
}
source = SpliceInventory.FindLongestSpool(character);
if (source == null)
{
message = "Hold a rope spool, or keep one in your inventory, to cut.";
return false;
}
message = string.Empty;
return true;
}
public static bool CanCut(float remaining, float cutSegments)
{
if (cutSegments <= 2.01f)
{
return false;
}
float num = remaining - cutSegments;
return num > 2.01f;
}
public static string BuildPreview(ItemSlot source, float cutSegments, float remaining, float vanilla, int empty)
{
if (source == null || source.IsEmpty())
{
return "No rope selected.";
}
if (cutSegments <= 0f)
{
return "Hover or select a cut to preview the result.";
}
if (!CanCut(remaining, cutSegments))
{
return "That cut is not possible. Leave more than a few meters on this spool.";
}
List<float> list = PackPieces(cutSegments, vanilla);
int num = Mathf.Max(0, list.Count - empty);
float segments = remaining - cutSegments;
string text = ((num > 0) ? string.Format(CultureInfo.InvariantCulture, "{0} drop at your feet", num) : "all fit in inventory");
return string.Format(CultureInfo.InvariantCulture, "After cut: {0:0.##}m left on this spool\nCreates {1} spool{2} ({3})\n{4} free slot{5} • {6}", RopeSpoolLengthHelper.SegmentsToMeters(segments), list.Count, (list.Count == 1) ? string.Empty : "s", FormatPieces(list), empty, (empty == 1) ? string.Empty : "s", text);
}
public static bool TryCut(Character character, float cutSegments, out string message)
{
if (!TryGetSource(character, out var source, out message))
{
return false;
}
float remainingSegmentsLive = SpliceInventory.GetRemainingSegmentsLive(character, source);
float spoolStartFuel = RopeSpoolLengthHelper.GetSpoolStartFuel(source);
if (!CanCut(remainingSegmentsLive, cutSegments))
{
message = "That cut would leave too little rope on this spool.";
return false;
}
List<float> list = PackPieces(cutSegments, spoolStartFuel);
if (list.Count == 0)
{
message = "Nothing to cut.";
return false;
}
float num = 0f;
int num2 = 0;
int num3 = 0;
for (int i = 0; i < list.Count; i++)
{
if (SpliceInventory.TryAddSpool(character, source.prefab, list[i], spoolStartFuel, i, out var dropped))
{
num += list[i];
if (dropped)
{
num3++;
}
else
{
num2++;
}
}
}
if (num <= 0f)
{
message = "Could not create the cut rope. Inventory is full and the drop failed.";
return false;
}
float num4 = Mathf.Max(0f, remainingSegmentsLive - num);
SpliceInventory.ApplyFuelToSlot(source, num4, spoolStartFuel);
Item val = (((Object)(object)character.data != (Object)null) ? character.data.currentItem : null);
if ((Object)(object)val != (Object)null && (SpliceInventory.SlotMatchesHeldItem(character, source) || source == SpliceInventory.GetHeldSpoolSlot(character)))
{
SpliceInventory.ApplyFuelToHeldItem(val, num4, spoolStartFuel);
}
else
{
val = null;
}
SpliceInventory.SyncAfterChange(character, val);
string text = ((num3 > 0 && num2 > 0) ? string.Format(CultureInfo.InvariantCulture, "{0} in inventory, {1} on the ground", num2, num3) : ((num3 <= 0) ? string.Empty : ((num3 == 1) ? "Dropped at your feet." : string.Format(CultureInfo.InvariantCulture, "Dropped {0} at your feet.", num3))));
message = string.Format(CultureInfo.InvariantCulture, "Cut {0:0.##}m into {1} spool{2}. {3:0.##}m left.{4}{5}", RopeSpoolLengthHelper.SegmentsToMeters(num), num2 + num3, (num2 + num3 == 1) ? string.Empty : "s", RopeSpoolLengthHelper.SegmentsToMeters(num4), string.IsNullOrEmpty(text) ? string.Empty : " ", text);
return true;
}
internal static List<float> PackPieces(float cutSegments, float vanillaFull)
{
List<float> list = new List<float>();
if (cutSegments <= 0f)
{
return list;
}
if (vanillaFull <= 0.01f)
{
list.Add(cutSegments);
return list;
}
float num = cutSegments;
float num2 = 2.01f;
while (num >= vanillaFull)
{
list.Add(vanillaFull);
num -= vanillaFull;
}
if (num > 0.01f)
{
if (list.Count > 0 && num <= num2)
{
list[list.Count - 1] += num;
}
else
{
list.Add(num);
}
}
else if (num > 0f)
{
if (list.Count > 0)
{
list[list.Count - 1] += num;
}
else
{
list.Add(cutSegments);
}
}
return list;
}
private static string FormatPieces(List<float> pieces)
{
if (pieces == null || pieces.Count == 0)
{
return "none";
}
string[] array = new string[pieces.Count];
for (int i = 0; i < pieces.Count; i++)
{
array[i] = RopeSpoolLengthHelper.SegmentsToMeters(pieces[i]).ToString("0.##", CultureInfo.InvariantCulture) + "m";
}
return string.Join(" + ", array);
}
}
internal static class CutUi
{
internal static readonly Color PanelColor = new Color(0.08f, 0.06f, 0.05f, 0.94f);
internal static readonly Color ButtonColor = new Color(0.179f, 0.125f, 0.09f, 0.73f);
internal static readonly Color ButtonHover = new Color(0.26f, 0.18f, 0.13f, 0.92f);
internal static readonly Color Cream = new Color(0.95f, 0.93f, 0.88f, 1f);
internal static readonly Color CreamDim = new Color(0.82f, 0.78f, 0.72f, 0.92f);
internal static readonly Color FieldWell = new Color(0.06f, 0.05f, 0.04f, 0.95f);
internal static readonly Color Accent = new Color(0.55f, 0.42f, 0.22f, 0.95f);
private static Sprite _whiteSprite;
private static TMP_FontAsset _cachedFont;
private static int _cachedSceneHandle = -1;
internal static Canvas CreateOverlayCanvas(GameObject root, int sortingOrder)
{
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
Canvas val = root.GetComponent<Canvas>() ?? root.AddComponent<Canvas>();
val.renderMode = (RenderMode)0;
val.sortingOrder = sortingOrder;
val.additionalShaderChannels = (AdditionalCanvasShaderChannels)25;
CanvasScaler val2 = root.GetComponent<CanvasScaler>() ?? root.AddComponent<CanvasScaler>();
val2.uiScaleMode = (ScaleMode)1;
val2.referenceResolution = new Vector2(1920f, 1080f);
val2.matchWidthOrHeight = 1f;
if ((Object)(object)root.GetComponent<GraphicRaycaster>() == (Object)null)
{
root.AddComponent<GraphicRaycaster>();
}
return val;
}
internal static RectTransform CreatePanel(Transform parent, string name, Vector2 size, Color color)
{
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Expected O, but got Unknown
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject(name, new Type[3]
{
typeof(RectTransform),
typeof(CanvasRenderer),
typeof(Image)
});
val.transform.SetParent(parent, false);
RectTransform component = val.GetComponent<RectTransform>();
Vector2 val2 = default(Vector2);
((Vector2)(ref val2))..ctor(0.5f, 0.5f);
component.anchorMax = val2;
component.anchorMin = val2;
component.pivot = new Vector2(0.5f, 0.5f);
component.sizeDelta = size;
Image component2 = val.GetComponent<Image>();
component2.sprite = WhiteSprite();
((Graphic)component2).color = color;
((Graphic)component2).raycastTarget = true;
return component;
}
internal static TextMeshProUGUI CreateLabel(Transform parent, string name, string text, float fontSize, FontStyles style = (FontStyles)0, TextAlignmentOptions align = (TextAlignmentOptions)513)
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Expected O, but got Unknown
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject(name, new Type[2]
{
typeof(RectTransform),
typeof(CanvasRenderer)
});
val.transform.SetParent(parent, false);
TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
((TMP_Text)val2).text = text ?? string.Empty;
((TMP_Text)val2).fontSize = fontSize;
((TMP_Text)val2).fontStyle = style;
((TMP_Text)val2).alignment = align;
((Graphic)val2).color = Cream;
((Graphic)val2).raycastTarget = false;
((TMP_Text)val2).enableWordWrapping = true;
((TMP_Text)val2).overflowMode = (TextOverflowModes)0;
ApplyFont(val2);
return val2;
}
internal static Button CreateButton(Transform parent, string label, UnityAction onClick, Vector2 preferredSize)
{
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Expected O, but got Unknown
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_0157: Unknown result type (might be due to invalid IL or missing references)
//IL_0165: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("Btn_" + label, new Type[4]
{
typeof(RectTransform),
typeof(CanvasRenderer),
typeof(Image),
typeof(Button)
});
val.transform.SetParent(parent, false);
Image component = val.GetComponent<Image>();
component.sprite = WhiteSprite();
((Graphic)component).color = ButtonColor;
Button component2 = val.GetComponent<Button>();
((Selectable)component2).targetGraphic = (Graphic)(object)component;
ColorBlock colors = ((Selectable)component2).colors;
((ColorBlock)(ref colors)).normalColor = ButtonColor;
((ColorBlock)(ref colors)).highlightedColor = ButtonHover;
((ColorBlock)(ref colors)).pressedColor = Accent;
((ColorBlock)(ref colors)).selectedColor = ButtonHover;
((ColorBlock)(ref colors)).disabledColor = new Color(0.2f, 0.16f, 0.12f, 0.5f);
((Selectable)component2).colors = colors;
TextMeshProUGUI val2 = CreateLabel(val.transform, "Text", label, 18f, (FontStyles)0, (TextAlignmentOptions)514);
Stretch(((TMP_Text)val2).rectTransform, 10f, 4f);
((Graphic)val2).raycastTarget = false;
((TMP_Text)val2).enableAutoSizing = true;
((TMP_Text)val2).fontSizeMin = 14f;
((TMP_Text)val2).fontSizeMax = 20f;
LayoutElement val3 = val.AddComponent<LayoutElement>();
val3.minHeight = preferredSize.y;
val3.preferredHeight = preferredSize.y;
val3.flexibleWidth = 1f;
if (onClick != null)
{
((UnityEvent)component2.onClick).AddListener(onClick);
}
return component2;
}
internal static TMP_InputField CreateNumberField(Transform parent, string placeholder, string initial, UnityAction<string> onChanged)
{
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Expected O, but got Unknown
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: Expected O, but got Unknown
//IL_0175: Unknown result type (might be due to invalid IL or missing references)
//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("NumberField", new Type[3]
{
typeof(RectTransform),
typeof(CanvasRenderer),
typeof(Image)
});
val.transform.SetParent(parent, false);
Image component = val.GetComponent<Image>();
component.sprite = WhiteSprite();
((Graphic)component).color = FieldWell;
LayoutElement val2 = val.AddComponent<LayoutElement>();
val2.minHeight = 36f;
val2.preferredHeight = 36f;
val2.flexibleWidth = 1f;
GameObject val3 = new GameObject("Text Area", new Type[2]
{
typeof(RectTransform),
typeof(RectMask2D)
});
val3.transform.SetParent(val.transform, false);
Stretch(val3.GetComponent<RectTransform>(), 10f, 6f);
TextMeshProUGUI val4 = CreateLabel(val3.transform, "Text", initial ?? string.Empty, 18f, (FontStyles)0, (TextAlignmentOptions)513);
Stretch(((TMP_Text)val4).rectTransform, 0f, 0f);
((Graphic)val4).raycastTarget = true;
TextMeshProUGUI val5 = CreateLabel(val3.transform, "Placeholder", placeholder, 18f, (FontStyles)2, (TextAlignmentOptions)513);
Stretch(((TMP_Text)val5).rectTransform, 0f, 0f);
((Graphic)val5).color = CreamDim;
TMP_InputField val6 = val.AddComponent<TMP_InputField>();
val6.textViewport = val3.GetComponent<RectTransform>();
val6.textComponent = (TMP_Text)(object)val4;
val6.placeholder = (Graphic)(object)val5;
val6.contentType = (ContentType)3;
val6.caretColor = Cream;
val6.customCaretColor = true;
val6.selectionColor = new Color(0.45f, 0.35f, 0.2f, 0.45f);
val6.onFocusSelectAll = false;
val6.restoreOriginalTextOnEscape = false;
val6.text = initial ?? string.Empty;
((UnityEvent<string>)(object)val6.onValueChanged).AddListener((UnityAction<string>)delegate(string s)
{
onChanged?.Invoke(s);
});
if ((Object)(object)((TMP_Text)val4).font != (Object)null)
{
val6.fontAsset = ((TMP_Text)val4).font;
}
return val6;
}
internal static VerticalLayoutGroup AddVertical(GameObject go, float spacing, RectOffset padding)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
VerticalLayoutGroup val = go.GetComponent<VerticalLayoutGroup>() ?? go.AddComponent<VerticalLayoutGroup>();
((HorizontalOrVerticalLayoutGroup)val).spacing = spacing;
((LayoutGroup)val).padding = (RectOffset)(((object)padding) ?? ((object)new RectOffset()));
((LayoutGroup)val).childAlignment = (TextAnchor)1;
((HorizontalOrVerticalLayoutGroup)val).childControlHeight = true;
((HorizontalOrVerticalLayoutGroup)val).childControlWidth = true;
((HorizontalOrVerticalLayoutGroup)val).childForceExpandHeight = false;
((HorizontalOrVerticalLayoutGroup)val).childForceExpandWidth = true;
return val;
}
internal static HorizontalLayoutGroup AddHorizontal(GameObject go, float spacing)
{
HorizontalLayoutGroup val = go.GetComponent<HorizontalLayoutGroup>() ?? go.AddComponent<HorizontalLayoutGroup>();
((HorizontalOrVerticalLayoutGroup)val).spacing = spacing;
((LayoutGroup)val).childAlignment = (TextAnchor)3;
((HorizontalOrVerticalLayoutGroup)val).childControlHeight = true;
((HorizontalOrVerticalLayoutGroup)val).childControlWidth = true;
((HorizontalOrVerticalLayoutGroup)val).childForceExpandHeight = false;
((HorizontalOrVerticalLayoutGroup)val).childForceExpandWidth = true;
return val;
}
internal static void Stretch(RectTransform rt, float padX, float padY)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
rt.anchorMin = Vector2.zero;
rt.anchorMax = Vector2.one;
rt.offsetMin = new Vector2(padX, padY);
rt.offsetMax = new Vector2(0f - padX, 0f - padY);
}
internal static void ApplyFont(TextMeshProUGUI text)
{
if (!((Object)(object)text == (Object)null))
{
TMP_FontAsset gameFont = GetGameFont();
if ((Object)(object)gameFont != (Object)null)
{
((TMP_Text)text).font = gameFont;
}
}
}
internal static void ReleaseUiFocus()
{
try
{
EventSystem current = EventSystem.current;
if ((Object)(object)current != (Object)null)
{
current.SetSelectedGameObject((GameObject)null);
}
}
catch
{
}
}
internal static void EnsureEventSystem()
{
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Expected O, but got Unknown
if (!((Object)(object)EventSystem.current != (Object)null))
{
GameObject val = new GameObject("SpliceSpools_EventSystem", new Type[2]
{
typeof(EventSystem),
typeof(StandaloneInputModule)
});
Object.DontDestroyOnLoad((Object)(object)val);
}
}
private static Sprite WhiteSprite()
{
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_whiteSprite != (Object)null)
{
return _whiteSprite;
}
Texture2D whiteTexture = Texture2D.whiteTexture;
_whiteSprite = Sprite.Create(whiteTexture, new Rect(0f, 0f, (float)((Texture)whiteTexture).width, (float)((Texture)whiteTexture).height), new Vector2(0.5f, 0.5f), 100f);
return _whiteSprite;
}
private static TMP_FontAsset GetGameFont()
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
Scene activeScene = SceneManager.GetActiveScene();
int num = SceneHandle.op_Implicit(((Scene)(ref activeScene)).handle);
if ((Object)(object)_cachedFont != (Object)null && _cachedSceneHandle == num)
{
return _cachedFont;
}
try
{
if ((Object)(object)GUIManager.instance != (Object)null)
{
TextMeshProUGUI componentInChildren = ((Component)GUIManager.instance).GetComponentInChildren<TextMeshProUGUI>(true);
if ((Object)(object)componentInChildren != (Object)null && (Object)(object)((TMP_Text)componentInChildren).font != (Object)null)
{
_cachedFont = ((TMP_Text)componentInChildren).font;
_cachedSceneHandle = num;
return _cachedFont;
}
}
}
catch
{
}
return _cachedFont;
}
}
[HarmonyPatch(typeof(Item), "GetItemName")]
internal static class Item_GetItemName_Splice_Patch
{
private static void Postfix(Item __instance, ItemInstanceData data, ref string __result)
{
try
{
if (SpliceInventory.IsRopeSpoolPrefab(__instance) && !string.IsNullOrEmpty(__result))
{
ItemInstanceData data2 = data ?? __instance.data;
float remainingMeters = RopeSpoolLengthHelper.GetRemainingMeters(__instance, data2);
__result = $"{__result} ({remainingMeters:0.#}m)";
}
}
catch (Exception ex)
{
ManualLogSource log = SpliceSpoolsPlugin.Log;
if (log != null)
{
log.LogWarning((object)("Name patch skipped: " + ex.Message));
}
}
}
}
[HarmonyPatch(typeof(CharacterAfflictions), "UpdateWeight")]
internal static class CharacterAfflictions_UpdateWeight_Splice_Patch
{
private static void Postfix(CharacterAfflictions __instance)
{
try
{
Character character = __instance.character;
if (!((Object)(object)((character != null) ? character.player : null) == (Object)null))
{
int vanilla = 0;
int scaled = 0;
AddSpoolWeights(character.player.itemSlots, ref vanilla, ref scaled);
AddSpoolWeights(GetBackpackInnerSlots(character), ref vanilla, ref scaled);
AddSpoolWeight(character.player.GetItemSlot((byte)250), ref vanilla, ref scaled);
if (vanilla != scaled)
{
float currentStatus = __instance.GetCurrentStatus((STATUSTYPE)7);
int num = Mathf.RoundToInt(currentStatus / 0.025f);
__instance.SetStatus((STATUSTYPE)7, 0.025f * (float)(num - vanilla + scaled), true);
}
}
}
catch (Exception ex)
{
ManualLogSource log = SpliceSpoolsPlugin.Log;
if (log != null)
{
log.LogWarning((object)("Weight patch skipped: " + ex.Message));
}
}
}
private static void AddSpoolWeights(ItemSlot[] slots, ref int vanilla, ref int scaled)
{
if (slots != null)
{
foreach (ItemSlot slot in slots)
{
AddSpoolWeight(slot, ref vanilla, ref scaled);
}
}
}
private static void AddSpoolWeight(ItemSlot slot, ref int vanilla, ref int scaled)
{
if (slot != null && !slot.IsEmpty() && SpliceInventory.IsRopeSpoolPrefab(slot.prefab))
{
vanilla += slot.prefab.CarryWeight;
scaled += RopeSpoolLengthHelper.GetScaledCarryWeight(slot.prefab, slot.data);
}
}
private static ItemSlot[] GetBackpackInnerSlots(Character character)
{
if (character.player.backpackSlot == null || ((ItemSlot)character.player.backpackSlot).IsEmpty())
{
return null;
}
ItemInstanceData data = ((ItemSlot)character.player.backpackSlot).data;
BackpackData val = default(BackpackData);
if (data == null || !data.TryGetDataEntry<BackpackData>((DataEntryKey)7, ref val))
{
return null;
}
return val.itemSlots;
}
}
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
internal static class RopeSpool_RopeFuel_Splice_Patch
{
private static void Postfix(RopeSpool __instance, float value)
{
try
{
Item item = ((ItemComponent)__instance).item;
Character val = (((Object)(object)item != (Object)null) ? item.holderCharacter : null);
if (!((Object)(object)val == (Object)null) && val.IsLocal)
{
ItemSlot val2 = SpliceInventory.FindSlotForItem(val, item);
if (val2 != null && val2.data != item.data)
{
SpliceInventory.ApplyFuelToSlot(val2, value, RopeSpoolLengthHelper.GetSpoolStartFuel(val2));
}
SpliceSpoolsPlugin.RequestWeightRefresh();
}
}
catch (Exception ex)
{
ManualLogSource log = SpliceSpoolsPlugin.Log;
if (log != null)
{
log.LogWarning((object)("Fuel sync skipped: " + ex.Message));
}
}
}
}
[HarmonyPatch(typeof(GUIManager), "UpdateWindowStatus")]
internal static class GUIManager_UpdateWindowStatus_CutMenu_Patch
{
private static void Postfix(GUIManager __instance)
{
if ((Object)(object)__instance != (Object)null && CutMenu.IsOpen)
{
CutMenu.ApplyMenuInputBlock(block: true);
}
}
}
[HarmonyPatch(typeof(Character), "CanDoInput")]
internal static class Character_CanDoInput_CutMenu_Patch
{
private static void Postfix(ref bool __result)
{
if (CutMenu.IsOpen)
{
__result = false;
}
}
}
[HarmonyPatch(typeof(CursorHandler), "Update")]
internal static class CursorHandler_Update_CutMenu_Patch
{
private static void Postfix()
{
if (CutMenu.IsOpen)
{
Cursor.lockState = (CursorLockMode)0;
Cursor.visible = true;
}
}
}
}