using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("ClientNetworkTransform")]
[assembly: IgnoresAccessChecksTo("DissonanceVoip")]
[assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")]
[assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")]
[assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")]
[assembly: IgnoresAccessChecksTo("Unity.Burst")]
[assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")]
[assembly: IgnoresAccessChecksTo("Unity.Collections")]
[assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")]
[assembly: IgnoresAccessChecksTo("Unity.Jobs")]
[assembly: IgnoresAccessChecksTo("Unity.Mathematics")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")]
[assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")]
[assembly: IgnoresAccessChecksTo("Unity.Services.QoS")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Relay")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("Unity.Timeline")]
[assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: AssemblyCompany("kylethescientist.scrapmagic")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("A client-sided mod for organizing and selling items ")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ScrapMagic")]
[assembly: AssemblyTitle("kylethescientist.scrapmagic")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace ScrapMagic
{
public abstract class Argument
{
public string name;
}
public class Argument<T> : Argument
{
public T value;
public Argument(string name, T value)
{
base.name = name;
this.value = value;
}
public static implicit operator T(Argument<T> arg)
{
return arg.value;
}
}
public struct ChatArgs
{
public Argument[] arguments;
public string help;
public int Length => arguments.Length;
public bool Empty => arguments.Length == 0;
public bool this[string name] => Get<bool>(name);
public string this[int name] => Get<string>(name);
public T Get<T>(string name)
{
Argument[] array = arguments;
foreach (Argument argument in array)
{
if (argument.name == name)
{
return ((Argument<T>)argument).value;
}
}
return default(T);
}
public T Get<T>(int name)
{
Argument[] array = arguments;
foreach (Argument argument in array)
{
if (argument.name == name.ToString())
{
return ((Argument<T>)argument).value;
}
}
return default(T);
}
}
public class ChatCommand
{
public static List<ChatCommand> Commands = new List<ChatCommand>();
public string keyword;
public Action<ChatArgs> action;
public string help;
public ChatCommand(string keyword, string help, Action<ChatArgs> action)
{
this.keyword = keyword;
this.help = help;
this.action = action;
}
public static ChatCommand New(string keyword, string help, Action<ChatArgs> action)
{
ChatCommand chatCommand = new ChatCommand(keyword, help, action);
Commands.Add(chatCommand);
return chatCommand;
}
public ChatArgs GetArgs(string raw)
{
List<Argument> list = new List<Argument>();
string[] array = raw.Split(' ');
keyword = array[0];
for (int i = 1; i < array.Length; i++)
{
if (array[i].StartsWith("-"))
{
string name = array[i].Substring(1);
list.Add(new Argument<bool>(name, value: true));
}
else
{
list.Add(new Argument<string>((i - 1).ToString(), array[i]));
}
}
ChatArgs result = default(ChatArgs);
result.arguments = list.ToArray();
result.help = help;
return result;
}
public override string ToString()
{
return keyword;
}
}
public static class Extensions
{
private static Dictionary<string, Vector3> itemOffsets = new Dictionary<string, Vector3>
{
{
"weed_killer",
Vector3.forward * 0.5f
},
{
"stun_grenade",
Vector3.forward * 0.05f
},
{
"walkie_talkie",
Vector3.forward * 0.025f
},
{
"spray_paint",
Vector3.forward * 0.05f
},
{
"belt_bag",
Vector3.forward * 0.05f + Vector3.right * 0.01f
},
{
"zap_gun",
Vector3.right * 0.25f
},
{
"jetpack",
Vector3.forward * 0.35f + Vector3.up * -0.6f
}
};
public static string Name(this GrabbableObject item)
{
return item.itemProperties.Name();
}
public static string Name(this Item item)
{
return item.itemName.ToLower().Replace(" ", "_").Replace("-", "_");
}
public static float AvgValue(this GrabbableObject item)
{
return (item.itemProperties.maxValue + item.itemProperties.minValue) / 2;
}
public static Vector3 PlacementOffset(this GrabbableObject item)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
return itemOffsets.GetValueOrDefault(item.Name());
}
public static string AddToList(this string s, string t)
{
t = t.Trim().ToLower().Replace(" ", "_")
.Replace("-", "_");
List<string> list = (from s in s.Split(',')
select s.Trim()).ToList();
list.Add(t);
return string.Join(", ", list);
}
public static string RemoveFromList(this string s, string t)
{
t = t.Trim().ToLower().Replace(" ", "_")
.Replace("-", "_");
List<string> list = (from s in s.Split(',')
select s.Trim()).ToList();
list.Remove(t);
return string.Join(", ", list);
}
public static bool ContainsItem(this string s, string t)
{
t = t.Trim().ToLower().Replace(" ", "_")
.Replace("-", "_");
List<string> list = (from s in s.Split(',')
select s.Trim()).ToList();
return list.Contains(t);
}
public static GrabbableObject[] ItemsOnCounter(this DepositItemsDesk desk)
{
return ((Component)desk).GetComponentsInChildren<GrabbableObject>();
}
}
public class Log
{
private static ManualLogSource _log;
public static void Init(ManualLogSource log)
{
_log = log;
}
private static string JoinObjects(params object[] objects)
{
string text = "";
foreach (object obj in objects)
{
text = text + obj.ToString() + " ";
}
return text;
}
public static void NotifyPlayer(string header, string body = "", bool isWarning = false)
{
HUDManager.Instance.DisplayTip(header, body, isWarning, false, "LC_Tip1");
Debug(header);
Debug(body);
}
public static void Chat(string body, string color = "FFFFFF")
{
HUDManager.Instance.AddChatMessage("<color=#" + color + ">[SM] " + body + "</color>", "");
Debug(body);
NeutralSound();
}
public static void ConfirmSound()
{
HUDManager.Instance.UIAudio.PlayOneShot(GameNetworkManager.Instance.buttonTuneSFX);
}
public static void ErrorSound()
{
HUDManager.Instance.UIAudio.PlayOneShot(GameNetworkManager.Instance.buttonSelectSFX);
}
public static void NeutralSound()
{
HUDManager.Instance.UIAudio.PlayOneShot(GameNetworkManager.Instance.buttonCancelSFX);
}
public static void PlaySound(int sound)
{
HUDManager instance = HUDManager.Instance;
AudioSource uIAudio = instance.UIAudio;
GameNetworkManager instance2 = GameNetworkManager.Instance;
switch (sound)
{
case 0:
uIAudio.PlayOneShot(instance2.buttonSelectSFX);
break;
case 1:
uIAudio.PlayOneShot(instance2.buttonCancelSFX);
break;
case 2:
uIAudio.PlayOneShot(instance2.buttonPressSFX);
break;
case 3:
uIAudio.PlayOneShot(instance2.buttonTuneSFX);
break;
case 4:
uIAudio.PlayOneShot(instance.addToScrapTotalSFX);
break;
case 5:
uIAudio.PlayOneShot(instance.decreaseXPSFX);
break;
case 6:
uIAudio.PlayOneShot(instance.displayCollectedScrapSFX);
break;
case 7:
uIAudio.PlayOneShot(instance.displayCollectedScrapSFXSmall);
break;
case 8:
uIAudio.PlayOneShot(instance.finishAddingToTotalSFX);
break;
case 9:
uIAudio.PlayOneShot(instance.globalNotificationSFX);
break;
case 10:
uIAudio.PlayOneShot(instance.increaseXPSFX);
break;
case 11:
uIAudio.PlayOneShot(instance.levelDecreaseSFX);
break;
case 12:
uIAudio.PlayOneShot(instance.levelIncreaseSFX);
break;
case 13:
uIAudio.PlayOneShot(instance.newProfitQuotaSFX);
break;
case 14:
uIAudio.PlayOneShot(instance.OneDayToMeetQuotaSFX);
break;
case 15:
uIAudio.PlayOneShot(instance.profitQuotaDaysLeftCalmSFX);
break;
case 16:
uIAudio.PlayOneShot(instance.reachedQuotaSFX);
break;
case 17:
uIAudio.PlayOneShot(instance.scanSFX);
break;
}
}
public static void Exception(Exception e)
{
string message = e.Message;
string stackTrace = e.StackTrace;
_log.LogError((object)message);
_log.LogError((object)stackTrace);
}
public static void Fatal(params object[] objects)
{
_log.LogFatal((object)JoinObjects(objects));
}
public static void Error(params object[] objects)
{
_log.LogError((object)JoinObjects(objects));
}
public static void Warning(params object[] objects)
{
_log.LogWarning((object)JoinObjects(objects));
}
public static void Message(params object[] objects)
{
_log.LogMessage((object)JoinObjects(objects));
}
public static void Info(params object[] objects)
{
_log.LogInfo((object)JoinObjects(objects));
}
public static void Debug(params object[] objects)
{
_log.LogDebug((object)JoinObjects(objects));
}
}
public static class Patches
{
public static void Init()
{
Harmony.CreateAndPatchAll(typeof(Ship), (string)null);
Harmony.CreateAndPatchAll(typeof(Chat), (string)null);
Harmony.CreateAndPatchAll(typeof(Startup), (string)null);
}
}
public static class Startup
{
[HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")]
[HarmonyPostfix]
private static void OnLocalPlayerCreated(PlayerControllerB __instance)
{
((Component)__instance).gameObject.AddComponent<Sorter>();
((Component)__instance).gameObject.AddComponent<Seller>();
}
[HarmonyPatch(typeof(GrabbableObject), "OnHitGround")]
[HarmonyPostfix]
private static void OnItemHitGround(GrabbableObject __instance)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
if (Sorter.inProgress)
{
__instance.floorYRot = -1;
((Component)__instance).transform.eulerAngles = Vector3.zero;
}
}
}
public static class Ship
{
public static Action OnShipOrbit;
public static Action OnShipTouchdown;
public static Action OnShipAscent;
public static Action OnShipDescent;
public static bool InOrbit { get; private set; }
public static bool Stationary => InOrbit || StartOfRound.Instance.shipHasLanded;
[HarmonyPatch(typeof(StartOfRound), "SwitchMapMonitorPurpose")]
[HarmonyPostfix]
[HarmonyWrapSafe]
public static void OnShipStateChanged(bool displayInfo)
{
InOrbit = displayInfo;
if (displayInfo)
{
OnShipOrbit?.Invoke();
}
else
{
OnShipDescent?.Invoke();
}
}
[HarmonyPatch(typeof(StartOfRound), "ShipLeave")]
[HarmonyPostfix]
[HarmonyWrapSafe]
public static void OnShipLeave()
{
OnShipAscent?.Invoke();
}
[HarmonyPatch(typeof(StartOfRound), "OnShipLandedMiscEvents")]
[HarmonyPostfix]
[HarmonyWrapSafe]
public static void OnShipLanded()
{
OnShipTouchdown?.Invoke();
}
}
public static class Chat
{
[HarmonyPatch(typeof(HUDManager), "SubmitChat_performed")]
[HarmonyPrefix]
[HarmonyWrapSafe]
public static bool OnChatSubmit(HUDManager __instance, CallbackContext context)
{
if (!((CallbackContext)(ref context)).performed)
{
return true;
}
string text = __instance.chatTextField.text;
if (text == "/help")
{
string text2 = "Commands: ";
text2 += string.Join(", ", ChatCommand.Commands);
Log.Chat(text2);
CloseChat(__instance);
}
text = text.Substring(1).Trim();
foreach (ChatCommand command in ChatCommand.Commands)
{
if (text.StartsWith(command.keyword))
{
CloseChat(__instance);
try
{
command.action(command.GetArgs(text));
}
catch (Exception e)
{
Log.Exception(e);
}
return false;
}
}
return true;
}
public static void CloseChat(HUDManager instance)
{
instance.localPlayer.isTypingChat = false;
instance.chatTextField.text = "";
EventSystem.current.SetSelectedGameObject((GameObject)null);
((Behaviour)instance.typingIndicator).enabled = false;
}
public static void Reset()
{
ChatCommand.Commands.Clear();
}
[HarmonyPatch(typeof(HUDManager), "Start")]
[HarmonyPostfix]
public static void OnHUDStart(HUDManager __instance)
{
try
{
Log.Info("Hud started");
((TMP_Text)__instance.chatText).fontSize = 11f;
}
catch (Exception e)
{
Log.Exception(e);
}
}
}
public static class Player
{
public static PlayerControllerB Local => StartOfRound.Instance?.localPlayerController;
public static bool CanGrabObject(GrabbableObject item)
{
List<GrabbableObject> list = Seller.desk?.itemsOnCounter;
if (!Object.op_Implicit((Object)(object)item) || !item.grabbable || item.deactivated || item.isHeld || item.isPocketed || (list != null && list.Contains(item)))
{
Log.Debug(" Can't grab object");
return false;
}
if (Local.isPlayerDead || Local.isTypingChat || Local.inTerminalMenu || Local.throwingObject || Local.IsInspectingItem || Local.isGrabbingObjectAnimation || Object.op_Implicit((Object)(object)Local.inAnimationWithEnemy) || Local.inSpecialInteractAnimation || Local.jetpackControls || Local.disablingJetpackControls || Local.activatingItem || Local.waitingToDropItem || Local.FirstEmptyItemSlot() == -1)
{
Log.Debug(" Player is busy");
return false;
}
return true;
}
public static IEnumerator DefuseEgg(StunGrenadeItem egg)
{
if (Object.op_Implicit((Object)(object)egg))
{
if (egg.explodeOnThrow)
{
Local.SwitchToItemSlot(Local.NextItemSlot(true), (GrabbableObject)null);
yield return (object)new WaitForSeconds(0.5f);
Local.SwitchToItemSlot(Local.NextItemSlot(false), (GrabbableObject)null);
}
int retry = 20;
while (egg.explodeOnThrow && retry > 0)
{
Local.SwitchToItemSlot(Local.NextItemSlot(true), (GrabbableObject)null);
yield return (object)new WaitForSeconds(0.5f);
Local.SwitchToItemSlot(Local.NextItemSlot(false), (GrabbableObject)null);
Log.Chat("Egg will pop if placed! Stand somewhere else!");
retry--;
}
if (retry == 0)
{
Log.Chat("Skipping egg.");
}
}
}
public static IEnumerator StartGrabbingObject(GrabbableObject grabbableObject)
{
Log.Debug("Grabbing " + grabbableObject.itemProperties.itemName);
if (CanGrabObject(grabbableObject))
{
Local.currentlyGrabbingObject = grabbableObject;
Local.grabInvalidated = false;
Local.currentlyGrabbingObject.InteractItem();
Local.playerBodyAnimator.SetBool("GrabInvalidated", false);
Local.playerBodyAnimator.SetBool("GrabValidated", false);
Local.playerBodyAnimator.SetBool("cancelHolding", false);
Local.playerBodyAnimator.ResetTrigger("Throw");
Local.SetSpecialGrabAnimationBool(true, (GrabbableObject)null);
Local.isGrabbingObjectAnimation = true;
((Behaviour)Local.cursorIcon).enabled = false;
((TMP_Text)Local.cursorTip).text = "";
Local.twoHanded = Local.currentlyGrabbingObject.itemProperties.twoHanded;
Local.carryWeight = Mathf.Clamp(Local.carryWeight + (Local.currentlyGrabbingObject.itemProperties.weight - 1f), 1f, 10f);
if (Local.currentlyGrabbingObject.itemProperties.grabAnimationTime > 0f)
{
Local.grabObjectAnimationTime = Local.currentlyGrabbingObject.itemProperties.grabAnimationTime;
}
else
{
Local.grabObjectAnimationTime = 0.4f;
}
if (Local.grabObjectCoroutine != null)
{
((MonoBehaviour)Local).StopCoroutine(Local.grabObjectCoroutine);
}
Local.GrabObjectServerRpc(NetworkObjectReference.op_Implicit(((NetworkBehaviour)grabbableObject).NetworkObject));
yield return Local.GrabObject();
}
}
public static IEnumerator StartMovingObject(GrabbableObject item, Vector3 position, NetworkObject parent = null)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
yield return StartGrabbingObject(item);
Log.Debug($"Moving {item.itemProperties.itemName} to {position}");
yield return DefuseEgg(((Component)item).GetComponent<StunGrenadeItem>());
try
{
Log.Debug("Placing " + item.itemProperties.itemName);
item.floorYRot = -1;
Local.DiscardHeldObject(true, parent, position, false);
}
catch (Exception e)
{
Log.Exception(e);
}
}
}
[BepInPlugin("kylethescientist.scrapmagic", "ScrapMagic", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
public static ConfigFile config;
private static Harmony harmony;
public static Plugin Instance { get; private set; }
private void Awake()
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Expected O, but got Unknown
Instance = this;
config = new ConfigFile(Paths.ConfigPath + "\\kylethescientist.scrapmagic.cfg", true);
Log.Init(((BaseUnityPlugin)this).Logger);
Patches.Init();
Log.Info("kylethescientist.scrapmagic v1.0.0 has loaded!");
}
}
public class Seller : MonoBehaviour
{
public ConfigEntry<string> skippedItems;
public static DepositItemsDesk desk;
private InteractTrigger bell;
private List<GrabbableObject> toSell;
public static bool InProgress { get; private set; }
private void FindDesk()
{
if (!Object.op_Implicit((Object)(object)desk))
{
desk = Object.FindObjectOfType<DepositItemsDesk>();
}
}
private void Awake()
{
Log.Info("Initializing Seller");
skippedItems = Plugin.config.Bind<string>("Seller", "skippedItems", "body, knife, shotgun, zed_dog", "Which items should be skipped when selling");
Ship.OnShipDescent = (Action)Delegate.Combine(Ship.OnShipDescent, new Action(FindDesk));
ChatCommand.New("sell", "Usage: /sell <$amount|all|quota|skip|unskip>", Sell);
ChatCommand.New("ring", "Rings the company bell until the door opens", delegate
{
if (!InProgress)
{
((MonoBehaviour)this).StartCoroutine(OpenDoor());
}
else
{
Log.NotifyPlayer("Error", "Selling in progress. Press escape to cancel.");
}
});
Log.Info("Seller initialized");
}
private void Update()
{
if (InProgress && ((ButtonControl)Keyboard.current.escapeKey).wasPressedThisFrame)
{
InProgress = false;
Log.ErrorSound();
}
}
private void Configure(ChatArgs args)
{
if (args.Empty || args.Length == 1)
{
Log.Chat("", "FFFF00");
Log.NeutralSound();
}
else if (args[0] == "skip")
{
Skip(args[1]);
}
else if (args[0] == "unskip")
{
Unskip(args[1]);
}
}
private void Skip(string name)
{
if (skippedItems.Value.ContainsItem(name))
{
Log.Chat("Item " + name + " already skipped", "FFFF00");
Log.NeutralSound();
}
else
{
skippedItems.Value = skippedItems.Value.AddToList(name);
Log.Chat("Skipping " + name, "FFFF00");
Log.ConfirmSound();
}
}
private void Unskip(string name)
{
if (!skippedItems.Value.ContainsItem(name))
{
Log.Chat("Item " + name + " not skipped", "FFFF00");
Log.NeutralSound();
}
else
{
skippedItems.Value = skippedItems.Value.RemoveFromList(name);
Log.Chat("Unskipping " + name, "FFFF00");
Log.ConfirmSound();
}
}
private void Sell(ChatArgs args)
{
if (!((NetworkBehaviour)Player.Local).IsServer)
{
Log.Chat("This command is for hosts only", "FF0000");
Log.ErrorSound();
return;
}
if (args.Empty || args[0] == "help")
{
Log.Chat(args.help, "FFFF00");
Log.NeutralSound();
return;
}
if (args[0] == "skip" || args[0] == "unskip")
{
Configure(args);
return;
}
if (args[0] == "quota")
{
Sell(-1);
return;
}
if (args[0] == "all")
{
Sell(-2);
return;
}
string text = args[0].ToLower();
int num = 1;
if (text.EndsWith('k'))
{
num = 1000;
text = text.Substring(0, text.Length - 1);
}
if (!int.TryParse(text, out var result))
{
Log.NotifyPlayer("Error", "Amount must be a number");
Log.ErrorSound();
}
else if (result <= 0)
{
Log.NotifyPlayer("Error", "Amount must be greater than 0");
Log.ErrorSound();
}
else
{
Sell(result * num);
}
}
private void Sell(int amount)
{
if (InProgress)
{
Log.NotifyPlayer("Seller Error", "Selling in progress. Press escape to cancel.", isWarning: true);
return;
}
if (!Object.op_Implicit((Object)(object)bell))
{
GameObject obj = GameObject.Find("BellDinger/Trigger");
bell = ((obj != null) ? obj.GetComponent<InteractTrigger>() : null);
}
if (!Object.op_Implicit((Object)(object)desk) || !Object.op_Implicit((Object)(object)bell))
{
Log.NotifyPlayer("Seller Error", "Not at the company", isWarning: true);
}
else
{
((MonoBehaviour)this).StartCoroutine(SellTo(amount));
}
}
public IEnumerator SellTo(int total)
{
InProgress = true;
if (!Object.op_Implicit((Object)(object)desk) || !Object.op_Implicit((Object)(object)bell))
{
InProgress = false;
yield break;
}
yield return GetItemsToFillQuota(total);
if (toSell.Count == 0)
{
InProgress = false;
yield break;
}
int counter = 0;
foreach (GrabbableObject item in toSell)
{
counter++;
if (!InProgress)
{
Log.Chat("Selling cancelled", "FF0000");
yield break;
}
if (item.isHeld)
{
continue;
}
yield return Player.StartGrabbingObject(item);
while (true)
{
yield return PlaceItemOnCounter(item);
if (!item.isHeld)
{
break;
}
yield return (object)new WaitForSeconds(0.15f);
Log.Warning("--- Failed to place item. Counter full?");
}
}
yield return OpenDoor();
InProgress = false;
Player.Local.carryWeight = 1f;
}
private IEnumerator PlaceItemOnCounter(GrabbableObject item)
{
if ((Object)(object)Player.Local.currentlyHeldObjectServer != (Object)(object)item)
{
Log.Warning("Item was not picked up");
yield break;
}
yield return Player.DefuseEgg(((Component)item).GetComponent<StunGrenadeItem>());
desk.AddObjectToDeskServerRpc(NetworkObjectReference.op_Implicit(((Component)item).gameObject.GetComponent<NetworkObject>()));
Vector3 vector2 = RoundManager.RandomPointInBounds(((Collider)desk.triggerCollider).bounds);
Bounds bounds = ((Collider)desk.triggerCollider).bounds;
vector2.y = ((Bounds)(ref bounds)).min.y;
RaycastHit raycastHit = default(RaycastHit);
if (Physics.Raycast(new Ray(vector2 + Vector3.up * 3f, Vector3.down), ref raycastHit, 8f, 1048640, (QueryTriggerInteraction)2))
{
vector2 = ((RaycastHit)(ref raycastHit)).point;
}
yield return Player.DefuseEgg(((Component)item).GetComponent<StunGrenadeItem>());
vector2.y += item.itemProperties.verticalOffset;
vector2 = ((Component)desk.deskObjectsContainer).transform.InverseTransformPoint(vector2);
Player.Local.DiscardHeldObject(true, desk.deskObjectsContainer, vector2, false);
}
private IEnumerator OpenDoor()
{
while (!desk.doorOpen)
{
bell.Interact(((Component)Player.Local).transform);
yield return (object)new WaitForSeconds(0.5f);
}
while (desk.doorOpen)
{
yield return (object)new WaitForSeconds(1f);
}
}
public IEnumerator GetItemsToFillQuota(float quota)
{
float buyRate = StartOfRound.Instance.companyBuyingRate;
bool sellingToQuota = quota == -1f;
bool sellingAll = quota == -2f;
toSell = new List<GrabbableObject>();
float alreadySold = 0f;
if (sellingToQuota)
{
quota = TimeOfDay.Instance.profitQuota;
alreadySold += (float)TimeOfDay.Instance.quotaFulfilled;
alreadySold += (float)desk.itemsOnCounter.Sum((GrabbableObject i) => i.scrapValue) * buyRate;
if (alreadySold >= quota)
{
Log.NotifyPlayer("Done", "Quota already fulfilled");
Log.ConfirmSound();
if (desk.itemsOnCounter.Count > 0)
{
yield return OpenDoor();
}
yield break;
}
}
GiftBoxItem[] boxes = Object.FindObjectsOfType<GiftBoxItem>();
GiftBoxItem[] array = boxes;
foreach (GiftBoxItem box in array)
{
if (!box.hasUsedGift && Object.op_Implicit((Object)(object)((Component)box).GetComponent<Renderer>()))
{
yield return Player.StartGrabbingObject((GrabbableObject)(object)box);
((GrabbableObject)box).ItemActivate(true, true);
yield return (object)new WaitForSeconds(0.2f);
}
}
List<GrabbableObject> sellableItems = new List<GrabbableObject>();
GrabbableObject[] onCounter = desk.ItemsOnCounter();
GrabbableObject[] array2 = onCounter;
foreach (GrabbableObject item in array2)
{
Log.Chat($"On counter: {item.Name()} ${item.scrapValue}");
}
GrabbableObject[] array3 = Object.FindObjectsOfType<GrabbableObject>();
foreach (GrabbableObject obj in array3)
{
if (obj.itemProperties.isScrap && !obj.isHeld && !obj.deactivated && !((IEnumerable<GrabbableObject>)(object)boxes).Contains(obj) && !onCounter.Contains(obj) && !IsSkipped(obj.Name()))
{
sellableItems.Add(obj);
}
}
sellableItems.Sort((GrabbableObject a, GrabbableObject b) => b.scrapValue.CompareTo(a.scrapValue));
string sellable = string.Join("\n\t", sellableItems.Select((GrabbableObject i) => i.Name() + $" ${i.scrapValue}"));
Log.Debug("Sellable items:\n" + sellable);
if (sellingToQuota)
{
Log.Debug($"Quota: {quota}");
if (buyRate != 1f)
{
quota = Mathf.CeilToInt(quota / buyRate);
Log.Debug($"Adjusted quota: {quota}");
}
if (alreadySold > 0f)
{
Log.Debug($"Already sold: {alreadySold}");
}
}
int target = (int)(quota - alreadySold);
if (!sellingAll)
{
int sum = 0;
int[] scrapValues = sellableItems.Select((GrabbableObject i) => i.scrapValue).ToArray();
for (int j = 0; j < scrapValues.Length; j++)
{
if (sum >= target - 200)
{
break;
}
sum += scrapValues[j];
toSell.Add(sellableItems[j]);
}
foreach (GrabbableObject item2 in toSell)
{
sellableItems.Remove(item2);
}
Log.Debug($"Pre-knapsack sum: {sum}/{target}, remaining to fill: {target - sum}");
scrapValues = sellableItems.Select((GrabbableObject i) => i.scrapValue).ToArray();
Task task = Task.Run(delegate
{
List<int> list = Knapsack(scrapValues, target - sum);
if (list.Count == 0)
{
Log.NotifyPlayer("Sell Error", $"Only ${scrapValues.Sum()} available to sell", isWarning: true);
}
list.ForEach(delegate(int i)
{
toSell.Add(sellableItems[i]);
});
});
Log.Chat("Calculating items to sell...", "FFFF00");
yield return (object)new WaitUntil((Func<bool>)(() => task.IsCompleted));
}
else
{
toSell.AddRange(sellableItems);
}
if (toSell.Count == 0)
{
Log.NotifyPlayer("Error", "No items to sell");
Log.ErrorSound();
yield break;
}
float total = toSell.Sum((GrabbableObject i) => i.scrapValue);
Log.NotifyPlayer($"Selling ${total}.", $"{toSell.Count} items");
string items = string.Join(", ", toSell.Select((GrabbableObject i) => i.Name() + $" ${i.scrapValue}"));
Log.Debug("Items to sell: " + items);
Log.ConfirmSound();
}
public static List<int> Knapsack(int[] nums, int target)
{
Log.Debug("Knapsack: " + string.Join(", ", nums));
int num = nums.Length;
int num2 = nums.Sum();
int[,] array = new int[num + 1, num2 + 1];
int i;
int j;
for (i = 0; i <= num; i++)
{
for (j = 0; j <= num2; j++)
{
array[i, j] = 1000000000;
}
}
array[0, 0] = 0;
for (i = 1; i <= num; i++)
{
if (!InProgress)
{
return new List<int>();
}
for (j = 0; j <= num2; j++)
{
array[i, j] = array[i - 1, j];
if (j >= nums[i - 1])
{
array[i, j] = Mathf.Min(array[i, j], array[i - 1, j - nums[i - 1]] + nums[i - 1]);
}
}
}
int num3 = 1000000000;
int num4 = -1;
for (j = target; j <= num2; j++)
{
if (array[num, j] >= target && array[num, j] < num3)
{
num3 = array[num, j];
num4 = j;
}
}
List<int> list = new List<int>();
i = num;
j = num4;
while (i > 0 && j > 0)
{
if (array[i, j] != array[i - 1, j])
{
list.Add(i - 1);
j -= nums[i - 1];
}
i--;
}
return list;
}
public bool IsSkipped(string s)
{
return skippedItems.Value.ContainsItem(s);
}
private void OnDestroy()
{
Ship.OnShipDescent = (Action)Delegate.Remove(Ship.OnShipDescent, new Action(FindDesk));
}
}
public class Sorter : MonoBehaviour
{
public ConfigEntry<string> doorframeItems;
public ConfigEntry<string> summonCircleItems;
public ConfigEntry<string> skippedItems;
public ConfigEntry<string> cupboardTop;
public ConfigEntry<string> cupboardShelfA;
public ConfigEntry<string> cupboardShelfB;
public ConfigEntry<string> cupboardShelfC;
public ConfigEntry<string> cupboardShelfD;
public ConfigEntry<bool> fixedLayout;
private List<Item> allScrap;
private List<GrabbableObject> scrap;
private List<GrabbableObject> cupboardT;
private List<GrabbableObject> cupboardA;
private List<GrabbableObject> cupboardB;
private List<GrabbableObject> cupboardC;
private List<GrabbableObject> cupboardD;
private List<GrabbableObject> summonCircle;
private List<GrabbableObject> doorframe;
public static bool inProgress;
private bool force = false;
private Vector3 originPosition = new Vector3(-5.8f, 0.5f, -5f);
private Vector3 duckCenter = new Vector3(7f, 0.01f, -6.78f);
private Vector3 shelfMinPosition = new Vector3(-6.78f, 4.23f, -8.62f);
private Vector3 shelfMaxPosition = new Vector3(-6.82f, 4.354f, -4.97f);
private bool CanSort => Ship.InOrbit || (Ship.Stationary && StartOfRound.Instance.currentLevel.PlanetName == "71 Gordion");
private void Awake()
{
fixedLayout = Plugin.config.Bind<bool>("Sorter", "fixedLayout", false, "Whether each item will have a designated spot on the wall. This can reduce the amount of resorting that needs to be done upon obtaining a new item type");
skippedItems = Plugin.config.Bind<string>("Sorter", "skippedItems", "body, clipboard, sticky_note, boombox", "Which items should be skipped when organizing");
doorframeItems = Plugin.config.Bind<string>("Sorter", "doorframeItems", "apparatus, soccer_ball, whoopie_cushion", "Which items should be put on the doorframe");
summonCircleItems = Plugin.config.Bind<string>("Sorter", "summonCircleItems", "", "Which items should be put in the summoning circle");
cupboardTop = Plugin.config.Bind<string>("Sorter", "cupboardTop", "extension_ladder, radar_booster, jetpack", "Which items should be put on top of the cupboard");
cupboardShelfA = Plugin.config.Bind<string>("Sorter", "cupboardShelfA", "kitchen_knife, shotgun, shovel", "Which items should be put on the cupboard's 1st shelf");
cupboardShelfB = Plugin.config.Bind<string>("Sorter", "cupboardShelfB", "key, ammo, flashlight, pro_flashlight", "Which items should be put on the cupboard's 2st shelf");
cupboardShelfC = Plugin.config.Bind<string>("Sorter", "cupboardShelfC", "belt_bag, stun_grenade, walkie_talkie, spray_paint", "Which items should be put on the cupboard's 3st shelf");
cupboardShelfD = Plugin.config.Bind<string>("Sorter", "cupboardShelfD", "lockpicker, tzp_inhalant, weed_killer, zap_gun", "Which items should be put on the cupboard's 4st shelf");
ChatCommand.New("sort", "Usage: /sort <scrap|cupboard|circle|doorframe|fixed|compact|skip|unskip> [-r|-redo] [help]", Organize);
ChatCommand.New("pile", "Usage: /pile <item_name>", Pile);
}
private void Start()
{
GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>();
foreach (GrabbableObject val in array)
{
val.isInShipRoom = true;
}
}
private void Update()
{
if (inProgress && ((ButtonControl)Keyboard.current.escapeKey).wasPressedThisFrame)
{
inProgress = false;
Log.ErrorSound();
}
}
private void Configure(ChatArgs args)
{
if (args.Empty || args.Length == 1)
{
Log.Chat("Usage: /sort <skip|unskip> <item_name>", "FFFF00");
Log.NeutralSound();
}
else if (args[0] == "skip")
{
Skip(args[1]);
}
else if (args[0] == "unskip")
{
Unskip(args[1]);
}
}
private void Skip(string name)
{
if (skippedItems.Value.ContainsItem(name))
{
Log.Chat("Item " + name + " already skipped", "FFFF00");
Log.NeutralSound();
}
else
{
skippedItems.Value = skippedItems.Value.AddToList(name);
Log.Chat("Skipping " + name, "FFFF00");
Log.ConfirmSound();
}
}
private void Unskip(string name)
{
if (!skippedItems.Value.ContainsItem(name))
{
Log.Chat("Item " + name + " not skipped", "FFFF00");
Log.NeutralSound();
}
else
{
skippedItems.Value = skippedItems.Value.RemoveFromList(name);
Log.Chat("Unskipping " + name, "FFFF00");
Log.ConfirmSound();
}
}
private void Organize(ChatArgs args)
{
if (!((NetworkBehaviour)Player.Local).IsServer)
{
Log.Chat("This command is for hosts only", "FF0000");
Log.ErrorSound();
return;
}
if (args[0] == "skip" || args[0] == "unskip")
{
Configure(args);
return;
}
if (!CanSort)
{
Log.NotifyPlayer("Sorter Error", "Must be in orbit or stationary at company", isWarning: true);
return;
}
if (inProgress)
{
Log.NotifyPlayer("Sorter Error", "Operation in progress", isWarning: true);
return;
}
CategorizeItems();
Log.ConfirmSound();
if (args[0] == "help")
{
Log.Chat(args.help, "FFFF00");
return;
}
if (args[0] == "fixed" || args[0] == "compact")
{
fixedLayout.Value = args[0] == "fixed";
if (fixedLayout.Value)
{
Log.Chat("Fixed layout enabled", "FFFF00");
}
else
{
Log.Chat("Compact layout enabled", "FFFF00");
}
return;
}
force = args["r"] || args["redo"];
bool flag = args[0] == null || args[0] == "scrap";
bool flag2 = args[0] == null || args[0] == "cupboard";
bool flag3 = args[0] == null || args[0] == "circle";
bool flag4 = args[0] == null || args[0] == "doorframe";
Log.Debug($"Organizing - Scrap: {flag}, Cupboard: {flag2}, Circle: {flag3}, Doorframe: {flag4}");
((MonoBehaviour)this).StartCoroutine(Organize(flag, flag2, flag3, flag4));
}
private IEnumerator Organize(bool scrap, bool cupboard, bool circle, bool doorframe)
{
inProgress = true;
Log.Chat("Press [Escape] to cancel sorting", "FFFF00");
if (scrap && inProgress)
{
yield return Scrap();
}
if (doorframe && inProgress)
{
yield return Doorframe();
}
if (circle && inProgress)
{
yield return Circle();
}
if (cupboard && inProgress)
{
yield return Cupboard();
}
Log.NeutralSound();
inProgress = false;
}
private IEnumerator Scrap()
{
inProgress = true;
Transform parent = StartOfRound.Instance.elevatorTransform;
Vector3 start = Vector3.zero;
Vector3 shipOffset = parent.TransformPoint(originPosition) - ((Component)parent).transform.position;
if (Player.Local.FirstEmptyItemSlot() < 0)
{
Log.NotifyPlayer("Sorter Error", "Inventory full", isWarning: true);
inProgress = false;
yield break;
}
new Vector2(0.8f, 0.8f);
Dictionary<string, int> itemCounts = new Dictionary<string, int>();
List<Item> propList = (fixedLayout.Value ? allScrap : scrap.Select((GrabbableObject i) => i.itemProperties).ToList());
Dictionary<string, Vector2> layout = CreateScrapLayout(propList);
foreach (GrabbableObject item in scrap)
{
itemCounts[item.Name()] = ((!itemCounts.ContainsKey(item.Name())) ? 1 : (itemCounts[item.Name()] + 1));
if (ShouldBreak(item))
{
Log.NotifyPlayer("Sorter Stopping", "Operation cancelled or ship is in motion", isWarning: true);
inProgress = false;
yield break;
}
if (!layout.ContainsKey(item.Name()))
{
Log.Debug("No position for " + item.Name());
continue;
}
Vector2 offset = layout[item.Name()];
int gy = itemCounts[item.Name()] / 5;
int gz = itemCounts[item.Name()] % 5;
Vector3 position2 = start + new Vector3(offset.x, offset.y);
position2 += new Vector3(0f, (float)gy * 0.05f, (float)gz * 0.05f);
Vector3 worldPos = position2 + shipOffset + ((Component)parent).transform.position;
if (!force && Vector3.Distance(worldPos, ((Component)item).transform.position) < 0.25f)
{
continue;
}
yield return GrabbableRetry(item);
if (!ShouldSkip(item))
{
yield return Player.StartMovingObject(item, worldPos);
int retry = 15;
while (!Player.CanGrabObject(item) && retry > 0)
{
yield return (object)new WaitForEndOfFrame();
retry--;
}
}
}
}
private IEnumerator Circle()
{
foreach (GrabbableObject item in summonCircle)
{
if (ShouldBreak(item))
{
Log.NotifyPlayer("Sorter Stopping", "Operation cancelled or ship is in motion", isWarning: true);
inProgress = false;
yield break;
}
if (!Player.CanGrabObject(item) || !item.isInShipRoom)
{
continue;
}
float p = 0.5f;
if (summonCircle.Count > 1)
{
p = (float)summonCircle.IndexOf(item) / (float)summonCircle.Count;
}
float diameter = 1f;
float x = Mathf.Cos(p * MathF.PI * 2f) * diameter;
float z = Mathf.Sin(p * MathF.PI * 2f) * diameter;
Vector3 duckPos = duckCenter + new Vector3(x, 0f, z);
Log.Debug($"Putting duck in a row. {duckPos}");
Transform parent = StartOfRound.Instance.elevatorTransform;
Vector3 worldPos = parent.TransformPoint(duckPos);
if (force || !(Vector3.Distance(worldPos, ((Component)item).transform.position) < 0.05f))
{
yield return Player.StartMovingObject(item, worldPos);
int retry = 15;
while (!Player.CanGrabObject(item) && retry > 0)
{
yield return (object)new WaitForEndOfFrame();
retry--;
}
}
}
}
private IEnumerator Doorframe()
{
Dictionary<string, int> counts = CountGroups(doorframe);
int seen = 0;
string lastName = "";
foreach (GrabbableObject item in doorframe)
{
if (ShouldBreak(item))
{
Log.NotifyPlayer("Sorter Stopping", "Operation cancelled or ship is in motion", isWarning: true);
inProgress = false;
yield break;
}
if (ShouldSkip(item))
{
continue;
}
if (item.Name() != lastName)
{
seen = 0;
item.Name();
}
else
{
seen++;
}
lastName = item.Name();
float p = 0.5f;
int count = counts[item.Name()];
if (count > 1)
{
p = (float)seen / (float)(count - 1);
}
Vector3 shelfPos = Vector3.Lerp(shelfMinPosition, shelfMaxPosition, p);
Log.Debug($"Moving {((Object)item).name} to doorframe. {shelfPos}");
Transform parent = StartOfRound.Instance.elevatorTransform;
Vector3 worldPos = parent.TransformPoint(shelfPos);
if (force || !(Vector3.Distance(worldPos, ((Component)item).transform.position) < 0.05f))
{
yield return Player.StartMovingObject(item, worldPos);
int retry = 15;
while (!Player.CanGrabObject(item) && retry > 0)
{
yield return (object)new WaitForEndOfFrame();
retry--;
}
}
}
}
public static Dictionary<string, int> CountGroups(List<GrabbableObject> items)
{
Dictionary<string, int> dictionary = new Dictionary<string, int>();
foreach (GrabbableObject item in items)
{
if (dictionary.ContainsKey(item.Name()))
{
dictionary[item.Name()]++;
}
else
{
dictionary[item.Name()] = 1;
}
}
return dictionary;
}
private IEnumerator Cupboard(bool standalone = false)
{
if (standalone)
{
inProgress = true;
Log.Chat("Storing items in cupboard");
}
GameObject closet = GameObject.Find("Environment/HangarShip/StorageCloset");
if (StartOfRound.Instance.unlockablesList.unlockables[7].inStorage)
{
if (standalone)
{
Log.Chat("No cupboard found. Return it from storage from the terminal.", "FFFF00");
}
yield break;
}
PlaceableObjectsSurface[] surfaces = closet.GetComponentsInChildren<PlaceableObjectsSurface>();
Array.Sort(surfaces, (PlaceableObjectsSurface a, PlaceableObjectsSurface b) => ((Component)b).transform.position.y.CompareTo(((Component)a).transform.position.y));
Log.Debug($"Found {surfaces.Length} shelves");
yield return PlaceOnShelf(cupboardT, surfaces[0], Vector3.up * 0.6f);
yield return PlaceOnShelf(cupboardA, surfaces[0]);
yield return PlaceOnShelf(cupboardB, surfaces[1]);
yield return PlaceOnShelf(cupboardC, surfaces[2]);
yield return PlaceOnShelf(cupboardD, surfaces[3]);
if (standalone)
{
inProgress = false;
}
}
private IEnumerator PlaceOnShelf(List<GrabbableObject> items, PlaceableObjectsSurface shelf, Vector3 offset = default(Vector3))
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
if (items.Count == 0)
{
yield break;
}
Vector3 min = ((Component)shelf).transform.TransformPoint(Vector3.left * 0.6f) + offset;
Vector3 max = ((Component)shelf).transform.TransformPoint(Vector3.right * 0.6f) + offset;
int unique = items.Select((GrabbableObject i) => i.Name()).Distinct().Count();
Vector3 margin = (max - min) / (float)(unique + 1);
Vector3 forward = ((Component)shelf).transform.TransformDirection(Vector3.forward);
string lastName = "";
int x = 0;
int y = 0;
int z = 0;
for (int j = 0; j < items.Count; j++)
{
GrabbableObject item = items[j];
if (ShouldBreak(items[j]))
{
Log.NotifyPlayer("Sorter Stopping", "Operation cancelled or ship is in motion", isWarning: true);
inProgress = false;
break;
}
if (item.Name() != lastName)
{
x++;
y = 0;
z = 0;
}
else
{
y++;
if (y > 5)
{
y = 0;
z++;
}
}
lastName = item.Name();
Vector3 worldPos2 = min + margin * (float)x + Vector3.up * ((float)y * 0.05f) + forward * ((float)z * 0.05f);
worldPos2 += ((Component)shelf).transform.TransformDirection(item.PlacementOffset());
if (force || !(Vector3.Distance(worldPos2, ((Component)item).transform.position) < 0.05f))
{
Vector3 parentPos = ((Component)shelf.parentTo).transform.InverseTransformPoint(worldPos2);
Vector3 rotation = new Vector3(0f, ((Component)shelf).transform.localEulerAngles.y - 45f, 0f);
if (rotation.y < 0f)
{
rotation.y += 360f;
}
yield return Player.StartMovingObject(item, parentPos, shelf.parentTo);
yield return GrabbableRetry(item);
}
}
}
private void Pile(ChatArgs args)
{
if (args[0] == "help")
{
Log.Chat(args.help, "FFFF00");
}
else if (!((NetworkBehaviour)Player.Local).IsServer)
{
Log.Chat("This command is for hosts only", "FF0000");
Log.ErrorSound();
}
else if (!CanSort)
{
Log.NotifyPlayer("Sorter Error", "Must be in orbit or stationary at company", isWarning: true);
}
else if (inProgress)
{
Log.NotifyPlayer("Sorter Error", "Operation in progress. Press escape to cancel.", isWarning: true);
}
else
{
((MonoBehaviour)this).StartCoroutine(Pile(args[0]));
Log.ConfirmSound();
}
}
private IEnumerator Pile(string target)
{
inProgress = true;
Log.Chat("Press Escape to cancel", "FFFF00");
if (target == null)
{
GrabbableObject first = Player.Local.currentlyHeldObjectServer;
target = first.itemProperties.itemName;
Player.Local.DiscardHeldObject(false, (NetworkObject)null, default(Vector3), true);
}
IEnumerable<GrabbableObject> objs = from item in Object.FindObjectsOfType<GrabbableObject>()
where item.Name() == target && item.isInShipRoom
select item;
Log.Chat($"{target} x{objs.Count()}", "00FFFF");
foreach (GrabbableObject item2 in objs)
{
int retry = 10;
while (!Player.CanGrabObject(item2) && retry > 0)
{
retry--;
yield return (object)new WaitForSeconds(0.1f);
}
if (retry > 0)
{
yield return Player.StartGrabbingObject(item2);
Player.Local.DiscardHeldObject(false, (NetworkObject)null, default(Vector3), true);
if (!inProgress)
{
break;
}
}
}
inProgress = false;
}
private void CategorizeItems()
{
scrap = new List<GrabbableObject>();
cupboardT = new List<GrabbableObject>();
cupboardA = new List<GrabbableObject>();
cupboardB = new List<GrabbableObject>();
cupboardC = new List<GrabbableObject>();
cupboardD = new List<GrabbableObject>();
summonCircle = new List<GrabbableObject>();
doorframe = new List<GrabbableObject>();
allScrap = StartOfRound.Instance.allItemsList.itemsList.ToList();
GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>();
Array.Sort(array, (GrabbableObject a, GrabbableObject b) => a.scrapValue.CompareTo(b.scrapValue));
Array.Sort(array, delegate(GrabbableObject a, GrabbableObject b)
{
if (a.itemProperties.twoHanded != b.itemProperties.twoHanded)
{
return -a.itemProperties.twoHanded.CompareTo(b.itemProperties.twoHanded);
}
if (a.itemProperties.isDefensiveWeapon != b.itemProperties.isDefensiveWeapon)
{
return -a.itemProperties.isDefensiveWeapon.CompareTo(b.itemProperties.isDefensiveWeapon);
}
return (a.AvgValue() != b.AvgValue()) ? a.AvgValue().CompareTo(b.AvgValue()) : a.Name().CompareTo(b.Name());
});
GrabbableObject[] array2 = array;
foreach (GrabbableObject val in array2)
{
if (!ShouldSkip(val))
{
string t = val.Name();
if (skippedItems.Value.ContainsItem(t))
{
allScrap.Remove(val.itemProperties);
}
else if (summonCircleItems.Value.ContainsItem(t))
{
allScrap.Remove(val.itemProperties);
summonCircle.Add(val);
}
else if (cupboardTop.Value.ContainsItem(t))
{
allScrap.Remove(val.itemProperties);
cupboardT.Add(val);
}
else if (cupboardShelfA.Value.ContainsItem(t))
{
allScrap.Remove(val.itemProperties);
cupboardA.Add(val);
}
else if (cupboardShelfB.Value.ContainsItem(t))
{
allScrap.Remove(val.itemProperties);
cupboardB.Add(val);
}
else if (cupboardShelfC.Value.ContainsItem(t))
{
allScrap.Remove(val.itemProperties);
cupboardC.Add(val);
}
else if (cupboardShelfD.Value.ContainsItem(t))
{
allScrap.Remove(val.itemProperties);
cupboardD.Add(val);
}
else if (doorframeItems.Value.ContainsItem(t))
{
allScrap.Remove(val.itemProperties);
doorframe.Add(val);
}
else
{
scrap.Add(val);
}
}
}
}
private IEnumerator GrabbableRetry(GrabbableObject item)
{
int retry = 15;
while (!Player.CanGrabObject(item) && retry > 0)
{
yield return (object)new WaitForEndOfFrame();
retry--;
}
}
private bool ShouldBreak(GrabbableObject item)
{
return !inProgress || !Ship.Stationary || Player.Local.beamOutParticle.isPlaying || Player.Local.beamUpParticle.isPlaying;
}
private bool ShouldSkip(GrabbableObject item)
{
if (!Player.CanGrabObject(item) || item.Name() == "body")
{
return true;
}
if (!item.isInShipRoom)
{
return true;
}
return false;
}
private Dictionary<string, Vector2> CreateScrapLayout(List<Item> items)
{
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_0115: Unknown result type (might be due to invalid IL or missing references)
//IL_011a: Unknown result type (might be due to invalid IL or missing references)
//IL_011f: Unknown result type (might be due to invalid IL or missing references)
//IL_015a: Unknown result type (might be due to invalid IL or missing references)
//IL_015f: Unknown result type (might be due to invalid IL or missing references)
//IL_0161: Unknown result type (might be due to invalid IL or missing references)
//IL_0166: Unknown result type (might be due to invalid IL or missing references)
Dictionary<string, Vector2> dictionary = new Dictionary<string, Vector2>();
IEnumerable<Item> source = (from i in items
where i.isScrap
orderby i.Name()
orderby (float)(i.minValue + i.maxValue) / 2f
select i).Distinct();
Item[] array = source.Where((Item i) => i.twoHanded).ToArray();
Item[] array2 = source.Where((Item i) => !i.twoHanded).ToArray();
for (int j = 0; j < array.Length; j++)
{
dictionary[array[j].Name()] = new Vector2((float)j * 0.7f, 3f);
}
Vector3 val = Vector2.op_Implicit(new Vector2(0.6f, 0.7f));
for (int k = 0; k < array2.Length; k++)
{
int num = k / 4;
int num2 = k % 4;
float num3 = ((num % 2 == 0) ? 0f : 0.5f);
dictionary[array2[k].Name()] = new Vector2((float)num, (float)num2 + num3) * Vector2.op_Implicit(val);
}
return dictionary;
}
private void OnDestroy()
{
ChatCommand.Commands.Clear();
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "kylethescientist.scrapmagic";
public const string PLUGIN_NAME = "ScrapMagic";
public const string PLUGIN_VERSION = "1.0.0";
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}