using System;
using System.Collections.Generic;
using System.Diagnostics;
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 UnityEngine;
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.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.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.0.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.0.0";
internal static ConfigEntry<KeyCode> SpliceKeyConfig;
internal static ConfigEntry<bool> IncludeBackpackConfig;
private Harmony _harmony;
private string _toastText;
private float _toastUntil;
internal static bool PendingWeightRefresh;
internal static SpliceSpoolsPlugin Instance { get; private set; }
internal static ManualLogSource Log { get; private set; }
private void Awake()
{
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Expected O, but got Unknown
//IL_0081: 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)103, "Press this key to splice matching rope spools in your inventory into one longer spool per rope type.");
IncludeBackpackConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Splice", "Include Backpack", true, "When true, leftover rope in a worn backpack is included when splicing.");
_harmony = new Harmony("tony4twentys.Splice_Spools");
_harmony.PatchAll();
((BaseUnityPlugin)this).Logger.LogInfo((object)($"Splice Spools loaded. Splice key: {SpliceKeyConfig.Value}. " + "Backpack: " + (IncludeBackpackConfig.Value ? "included" : "ignored") + "."));
}
private void Update()
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
if (PendingWeightRefresh)
{
PendingWeightRefresh = false;
TryRefreshLocalWeight();
}
if ((int)SpliceKeyConfig.Value != 0 && Input.GetKeyDown(SpliceKeyConfig.Value) && !IsGameplayInputBlocked())
{
Character localCharacter = Character.localCharacter;
if (!((Object)(object)((localCharacter != null) ? localCharacter.player : null) == (Object)null) && localCharacter.IsLocal)
{
SpliceExecutor.TrySplice(localCharacter, out var message);
ShowToast(message);
((BaseUnityPlugin)this).Logger.LogInfo((object)message);
}
}
}
private void OnGUI()
{
//IL_0064: 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_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: 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)
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Expected O, but got Unknown
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
if (!string.IsNullOrEmpty(_toastText) && !(Time.unscaledTime > _toastUntil))
{
Rect val = default(Rect);
((Rect)(ref val))..ctor(((float)Screen.width - 520f) * 0.5f, 72f, 520f, 36f);
GUI.color = new Color(0f, 0f, 0f, 0.55f);
GUI.Box(val, GUIContent.none);
GUI.color = Color.white;
GUIStyle val2 = new GUIStyle(GUI.skin.label)
{
alignment = (TextAnchor)4,
fontSize = 16,
fontStyle = (FontStyle)1
};
GUI.Label(val, _toastText, val2);
}
}
private void OnDestroy()
{
if (_harmony != null)
{
_harmony.UnpatchSelf();
}
if ((Object)(object)Instance == (Object)(object)this)
{
Instance = null;
}
Log = null;
}
internal static void TryRefreshLocalWeight()
{
Character localCharacter = Character.localCharacter;
if ((Object)(object)localCharacter?.refs?.items == (Object)null)
{
return;
}
try
{
localCharacter.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 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 || (Object)(object)((Component)prefab).GetComponent<RopeShooter>() != (Object)null)
{
return false;
}
if ((Object)(object)((Component)prefab).GetComponent<RopeSpool>() != (Object)null)
{
return true;
}
if (prefab.itemID == 65 || prefab.itemID == 1)
{
return true;
}
string text = ((Object)((Component)prefab).gameObject).name ?? string.Empty;
return text.IndexOf("Rope Spool", StringComparison.OrdinalIgnoreCase) >= 0;
}
public static bool IsAntiRopeSpoolPrefab(Item prefab)
{
if ((Object)(object)prefab == (Object)null)
{
return false;
}
RopeSpool component = ((Component)prefab).GetComponent<RopeSpool>();
if ((Object)(object)component != (Object)null && component.isAntiRope)
{
return true;
}
if (prefab.itemID == 1)
{
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;
}
return (Object)(object)spool.ropeInstance != (Object)null || (Object)(object)spool.rope != (Object)null || item.isUsingPrimary;
}
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 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)
{
List<ItemSlot> ropeSpoolSlots = SpliceInventory.GetRopeSpoolSlots(character);
List<ItemSlot> list = new List<ItemSlot>();
List<ItemSlot> list2 = new List<ItemSlot>();
CollectSplicable(ropeSpoolSlots, list, list2);
bool flag = false;
bool flag2 = false;
float combinedMeters = 0f;
float combinedMeters2 = 0f;
int spoolCount = 0;
int spoolCount2 = 0;
if (list.Count >= 2)
{
if (SpliceInventory.IsHeldSpoolBusy(character, isAntiRope: false))
{
message = "Finish placing your rope before splicing.";
return false;
}
flag = TrySpliceGroup(character, list, isAntiRope: false, out combinedMeters, out spoolCount);
}
if (list2.Count >= 2)
{
if (SpliceInventory.IsHeldSpoolBusy(character, isAntiRope: true))
{
if (flag)
{
SyncAfterSplice(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, list2, isAntiRope: true, out combinedMeters2, out spoolCount2);
}
if (!flag && !flag2)
{
message = ((list.Count + list2.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 _);
SyncAfterSplice(character, item);
message = BuildResultMessage(flag, spoolCount, combinedMeters, flag2, spoolCount2, combinedMeters2);
return true;
}
private static void CollectSplicable(List<ItemSlot> allSpools, List<ItemSlot> normal, List<ItemSlot> anti)
{
foreach (ItemSlot allSpool in allSpools)
{
float remainingSegments = RopeSpoolLengthHelper.GetRemainingSegments(allSpool);
if (RopeSpoolLengthHelper.HasSplicableLength(remainingSegments))
{
if (SpliceInventory.IsAntiRopeSpoolPrefab(allSpool.prefab))
{
anti.Add(allSpool);
}
else
{
normal.Add(allSpool);
}
}
}
}
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 += RopeSpoolLengthHelper.GetRemainingSegments(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)
{
foreach (ItemSlot slot in slots)
{
if (SpliceInventory.SlotMatchesHeldItem(character, slot) && SpliceInventory.IsAntiRopeSpoolPrefab(slot.prefab) == isAntiRope)
{
return slot;
}
}
return slots[0];
}
private static void SyncAfterSplice(Character character, Item held)
{
SpliceInventory.SyncInventory(character);
if ((Object)(object)held != (Object)null)
{
SpliceInventory.PushHeldItemData(held);
}
if ((Object)(object)character.refs?.items != (Object)null)
{
character.refs.items.RefreshAllCharacterCarryWeightRPC();
}
if (character.player?.itemsChangedAction != null)
{
character.player.itemsChangedAction(character.player.itemSlots);
}
}
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.";
}
}
[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);
AddSpoolWeights((ItemSlot[])(object)new ItemSlot[1] { 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)
{
return;
}
foreach (ItemSlot val in slots)
{
if (val != null && !val.IsEmpty() && SpliceInventory.IsRopeSpoolPrefab(val.prefab))
{
vanilla += val.prefab.CarryWeight;
scaled += RopeSpoolLengthHelper.GetScaledCarryWeight(val.prefab, val.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.PendingWeightRefresh = true;
}
}
catch (Exception ex)
{
ManualLogSource log = SpliceSpoolsPlugin.Log;
if (log != null)
{
log.LogWarning((object)("Fuel sync skipped: " + ex.Message));
}
}
}
}
}