using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalAPI.LibTerminal;
using LethalAPI.LibTerminal.Attributes;
using LethalAPI.LibTerminal.Models;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Events;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("BetterTerminal")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BetterTerminal")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e8857ce3-5d85-4646-b810-d07713a6c929")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
public class TerminalNetworkHandler : NetworkBehaviour
{
public static TerminalNetworkHandler Instance;
private void Awake()
{
Instance = this;
}
public void SyncOrderedItems(List<int> orderedItems)
{
if (((NetworkBehaviour)this).IsServer)
{
SyncOrderedItemsClientRpc(orderedItems);
}
else
{
SyncOrderedItemsServerRpc(orderedItems);
}
}
[ClientRpc]
private void SyncOrderedItemsClientRpc(List<int> orderedItems)
{
Terminal val = Object.FindObjectOfType<Terminal>();
if ((Object)(object)val != (Object)null)
{
val.orderedItemsFromTerminal = orderedItems;
}
}
[ServerRpc(RequireOwnership = false)]
private void SyncOrderedItemsServerRpc(List<int> orderedItems)
{
SyncOrderedItemsClientRpc(orderedItems);
}
}
namespace BetterTerminal;
internal class Alias
{
private MainBetterTerminal instance = new MainBetterTerminal();
[TerminalCommand("scan", true)]
public string ScanAlias(string scanspot)
{
if (scanspot == "inside")
{
return instance.ScanInsideCommand();
}
if (scanspot == "ship")
{
return instance.ItemsCommand();
}
return "[There was no scan type supplied with that word.]";
}
[TerminalCommand("light", true)]
public string LightAlias()
{
return instance.LightsCommand();
}
[TerminalCommand("teleport", true)]
public string TpAlias()
{
return instance.TpCommand();
}
[TerminalCommand("doors", true)]
public string DoorAlias()
{
return instance.ToggleDoorCommand();
}
[TerminalCommand("Land", true)]
public string LaunchAlias()
{
return instance.LaunchCommand();
}
[TerminalCommand("Go", true)]
public string LaunchAlias2()
{
return instance.LaunchCommand();
}
[TerminalCommand("InverseTp", true)]
public string InverseAlias()
{
return instance.InverseCommand();
}
}
[Serializable]
public class BetterTerminalConfig : SyncedInstance<BetterTerminalConfig>
{
public ConfigEntry<bool> restartCommandDisable;
public ConfigEntry<bool> cancelDeliveryDisable;
public ConfigEntry<bool> itpDisable;
public ConfigEntry<bool> itpHost;
public ConfigEntry<bool> launchDisable;
public ConfigEntry<bool> launchHost;
public ConfigEntry<bool> doorDisable;
public ConfigEntry<bool> doorHost;
public ConfigEntry<bool> teleportDisable;
public ConfigEntry<bool> teleportHost;
public ConfigEntry<bool> lightsDisable;
public ConfigEntry<bool> lightsHost;
public ConfigEntry<bool> itemsDisable;
public ConfigEntry<bool> itemsHost;
public ConfigEntry<bool> scanInsideDisable;
public ConfigEntry<bool> scanInsideHost;
public BetterTerminalConfig(ConfigFile cfg)
{
InitInstance(this);
restartCommandDisable = cfg.Bind<bool>("Commands.Restart", "Disable", false, "Disables the restart command");
itpDisable = cfg.Bind<bool>("Commands.itp", "Disable", false, "Disables the ITP (Inverse Teleporter) command");
itpHost = cfg.Bind<bool>("Commands.itp", "Host Only", false, "Makes the ITP (Inverse Teleporter) command for hosts only");
launchDisable = cfg.Bind<bool>("Commands.Launch", "Disable", false, "Disables the Launch command");
launchHost = cfg.Bind<bool>("Commands.Launch", "Host Only", false, "Makes the Launch command for hosts only");
doorDisable = cfg.Bind<bool>("Commands.Door", "Disable", false, "Disables the Door command");
doorHost = cfg.Bind<bool>("Commands.Door", "Host Only", false, "Makes the Door command for hosts only");
teleportDisable = cfg.Bind<bool>("Commands.Teleport", "Disable", false, "Disables the Door command");
teleportHost = cfg.Bind<bool>("Commands.Teleport", "Host Only", false, "Makes the Door command for hosts only");
lightsDisable = cfg.Bind<bool>("Commands.Lights", "Disable", false, "Disables the Lights command");
lightsHost = cfg.Bind<bool>("Commands.Lights", "Host Only", false, "Makes the Lights command for hosts only");
cancelDeliveryDisable = cfg.Bind<bool>("Commands.CancelDelivery", "Disable", false, "Disables the Cancel Delivery command");
itemsDisable = cfg.Bind<bool>("Commands.Items", "Disable", false, "Disables the Items command");
itemsHost = cfg.Bind<bool>("Commands.Items", "Host Only", false, "Makes the Items command for hosts only");
scanInsideDisable = cfg.Bind<bool>("Commands.ScanInside", "Disable", false, "Disables the Scan Inside command");
scanInsideHost = cfg.Bind<bool>("Commands.ScanInside", "Host Only", false, "Makes the Scan Inside command for hosts only");
}
}
[BepInPlugin("zg.BetterTerminal", "BetterTerminal", "1.1.1")]
[HarmonyPatch(typeof(Terminal))]
public class MainBetterTerminal : BaseUnityPlugin
{
private const string modVersion = "1.1.1";
private const string modGUID = "zg.BetterTerminal";
private const string modName = "BetterTerminal";
private readonly Harmony harmony = new Harmony("zg.BetterTerminal");
private TerminalModRegistry Commands;
internal ManualLogSource pnt;
public static BetterTerminalConfig Config { get; internal set; }
public static MainBetterTerminal instance { get; internal set; }
public ManualLogSource getLogger()
{
return ((BaseUnityPlugin)this).Logger;
}
private void Awake()
{
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Expected O, but got Unknown
if ((Object)(object)instance == (Object)null)
{
instance = this;
}
Config = new BetterTerminalConfig(((BaseUnityPlugin)this).Config);
Commands = TerminalRegistry.CreateTerminalRegistry();
Commands.RegisterFrom<MainBetterTerminal>(this);
Commands.RegisterFrom<Alias>();
GameObject val = new GameObject("TerminalNetworkHandler");
TerminalNetworkHandler terminalNetworkHandler = val.AddComponent<TerminalNetworkHandler>();
TerminalNetworkHandler.Instance = terminalNetworkHandler;
pnt = Logger.CreateLogSource("zg.BetterTerminal");
pnt.LogInfo((object)"BetterTerminal Enabled");
pnt.LogInfo((object)"Make sure to review BetterTerminal");
harmony.PatchAll(typeof(MainBetterTerminal));
harmony.PatchAll(typeof(TerminalNetworkHandler));
}
[TerminalCommand("ScanInside", true)]
[CommandInfo("See how many items are INSIDE the facility", "")]
public string ScanInsideCommand()
{
if (Config.scanInsideDisable.Value)
{
return "This command is Disabled";
}
if (Config.scanInsideHost.Value && !isHost())
{
return "This command is Host Only";
}
Debug.Log((object)"Got to debug 1");
Random random = new Random(StartOfRound.Instance.randomMapSeed + 91);
int num = 0;
int num2 = 0;
int num3 = 0;
GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>();
for (int i = 0; i < array.Length; i++)
{
Debug.Log((object)"Got to debug 2");
if (array[i].itemProperties.isScrap && array[i].isInFactory)
{
Debug.Log((object)"Got to debug 3");
num3 += array[i].itemProperties.maxValue - array[i].itemProperties.minValue;
num2 += Mathf.Clamp(random.Next(array[i].itemProperties.minValue, array[i].itemProperties.maxValue), array[i].scrapValue - 6 * i, array[i].scrapValue + 9 * i);
num++;
}
Debug.Log((object)"Got to debug 4");
}
Debug.Log((object)"Got to debug 5");
return "There are currently " + num + " items inside the facility";
}
[TerminalCommand("Items", true)]
[CommandInfo("See the value of items inside of the ship", "")]
public string ItemsCommand()
{
if (Config.itemsDisable.Value)
{
return "This command is Disabled";
}
if (Config.itemsHost.Value && !isHost())
{
return "This command is Host Only";
}
GameObject val = GameObject.Find("/Environment/HangarShip");
if ((Object)(object)val == (Object)null)
{
return "0";
}
List<GrabbableObject> source = (from obj in val.GetComponentsInChildren<GrabbableObject>()
where ((Object)obj).name != "ClipboardManual" && ((Object)obj).name != "StickyNoteItem" && ((Object)obj).name != "KeyItem"
select obj).ToList();
float num = source.Sum((GrabbableObject scrap) => scrap.scrapValue);
Debug.Log((object)$"There is currently ${num} value of scrap inside the ship");
return $"There is currently ${num} value of scrap inside of the ship";
}
[TerminalCommand("CancelDelivery", true)]
[AllowedCaller(/*Could not decode attribute arguments.*/)]
[CommandInfo("Cancel purchased items for a refund before delivery", "")]
public string CancelDeliveryCommand()
{
if (Config.cancelDeliveryDisable.Value)
{
return "This command is Disabled";
}
Terminal val = Object.FindObjectOfType<Terminal>();
if (val.numberOfItemsInDropship > 0)
{
TerminalNetworkHandler.Instance.SyncOrderedItems(val.orderedItemsFromTerminal);
int num = 0;
foreach (int item in val.orderedItemsFromTerminal)
{
if (item >= 0 && item < val.buyableItemsList.Count())
{
num += val.buyableItemsList[item].creditsWorth;
}
else
{
Debug.LogError((object)"Why is this happening?!?");
}
}
int num2 = (val.groupCredits += num);
Debug.Log((object)num);
num = 0;
val.orderedItemsFromTerminal.Clear();
val.numberOfItemsInDropship = 0;
val.SyncGroupCreditsClientRpc(num2, val.numberOfItemsInDropship);
val.SyncGroupCreditsServerRpc(num2, val.numberOfItemsInDropship);
return "Purchase cancelled and items refunded";
}
return "No items in delivery to cancel.";
}
[TerminalCommand("bettermods", true)]
[CommandInfo("Info about BetterMods", "")]
public string BetterModsCommand()
{
return "BetterSpec and BetterTerminal were made by Higgins, You can get them both on Thunderstore";
}
[TerminalCommand("lights", true)]
[CommandInfo("Use this to toggle ship lights remotely", "")]
public string LightsCommand()
{
if (Config.lightsDisable.Value)
{
return "This command is Disabled";
}
if (Config.lightsHost.Value && !isHost())
{
return "This command is Host Only";
}
StartOfRound.Instance.shipRoomLights.ToggleShipLights();
return "You've toggled the lights inside of the ship";
}
[TerminalCommand("tp", true)]
[CommandInfo("Teleport the player currently on the monitor", "")]
public string TpCommand()
{
if (Config.teleportDisable.Value)
{
return "This command is Disabled";
}
if (Config.teleportHost.Value && !isHost())
{
return "This command is Host Only";
}
ShipTeleporter component = GameObject.Find("Teleporter(Clone)").GetComponent<ShipTeleporter>();
FieldInfo field = ((object)component).GetType().GetField("cooldownTime", BindingFlags.Instance | BindingFlags.NonPublic);
float num = (float)field.GetValue(component);
if (num > 0f)
{
return "The teleporter is currently on cooldown";
}
if ((Object)(object)component == (Object)null)
{
return "You must purchase a Teleporter to teleport";
}
((UnityEvent<PlayerControllerB>)(object)component.buttonTrigger.onInteract).Invoke(GameNetworkManager.Instance.localPlayerController);
return "Teleporting";
}
[TerminalCommand("door", true)]
[CommandInfo("Safely toggle the Ship Door", "")]
public string ToggleDoorCommand()
{
if (Config.doorDisable.Value)
{
return "This command is Disabled";
}
if (Config.doorHost.Value && !isHost())
{
return "This command is Host Only";
}
InteractTrigger componentInChildren = GameObject.Find(StartOfRound.Instance.hangarDoorsClosed ? "StartButton" : "StopButton").GetComponentInChildren<InteractTrigger>();
((UnityEvent<PlayerControllerB>)(object)componentInChildren.onInteract).Invoke(GameNetworkManager.Instance.localPlayerController);
if (StartOfRound.Instance.hangarDoorsClosed)
{
return "Opened the doors";
}
return "Closed the doors, stay safe";
}
[TerminalCommand("Launch", true)]
[CommandInfo("Use this to land or launch the ship", "")]
public string LaunchCommand()
{
if (Config.launchDisable.Value)
{
return "This command is Disabled";
}
if (Config.launchHost.Value && !isHost())
{
return "This command is Host Only";
}
if ((Object)(object)GameObject.Find("StartGameLever") == (Object)null)
{
return "Error finding the Lever";
}
StartMatchLever component = GameObject.Find("StartGameLever").GetComponent<StartMatchLever>();
if (StartOfRound.Instance.shipDoorsEnabled && !StartOfRound.Instance.shipHasLanded && !StartOfRound.Instance.shipIsLeaving)
{
return "Contact the Pilot someone's already done this!";
}
if (!StartOfRound.Instance.shipDoorsEnabled && StartOfRound.Instance.travellingToNewLevel)
{
return "Contact the Pilot someone's already done this!";
}
component.PullLever();
component.LeverAnimation();
if (component.leverHasBeenPulled)
{
component.StartGame();
return "Copy that Pilot ship is heading there now";
}
if (!component.leverHasBeenPulled)
{
component.EndGame();
return "Copy that Pilot, Leaving the moon now";
}
return "If you see this run the command again";
}
[TerminalCommand("itp", true)]
[CommandInfo("Uses the inverse teleporter", "")]
public string InverseCommand()
{
if (Config.itpDisable.Value)
{
return "This command is Disabled";
}
if (Config.itpHost.Value && !isHost())
{
return "This command is Host Only";
}
if (!StartOfRound.Instance.shipHasLanded)
{
return "You can't teleport in space you'll die!";
}
if ((Object)(object)GameObject.Find("InverseTeleporter(Clone)") == (Object)null)
{
return "You need to purchase a inverse teleporter";
}
ShipTeleporter component = GameObject.Find("InverseTeleporter(Clone)").GetComponent<ShipTeleporter>();
FieldInfo field = ((object)component).GetType().GetField("cooldownTime", BindingFlags.Instance | BindingFlags.NonPublic);
float num = (float)field.GetValue(component);
if (num > 0f)
{
return "The inverse teleporter is currently on cooldown";
}
if ((Object)(object)component == (Object)null)
{
return "You need to purchase a inverse teleporter";
}
((UnityEvent<PlayerControllerB>)(object)component.buttonTrigger.onInteract).Invoke(GameNetworkManager.Instance.localPlayerController);
return "You sent him to die, Goodluck!";
}
[TerminalCommand("Restart", true)]
[AllowedCaller(/*Could not decode attribute arguments.*/)]
[CommandInfo("Resets all the ships furniture", "")]
public string RestartCommand()
{
if (Config.restartCommandDisable.Value)
{
return "This command is Disabled";
}
if (!StartOfRound.Instance.shipDoorsEnabled)
{
StartOfRound.Instance.ResetShip();
return "The company has shunned you, Go back to square 1";
}
return "You must be in space to restart, the company wants you working on the moon";
}
private bool isHost()
{
return ((NetworkBehaviour)RoundManager.Instance).NetworkManager.IsHost;
}
}
[Serializable]
public class SyncedInstance<T>
{
[NonSerialized]
protected static int IntSize = 4;
internal static CustomMessagingManager MessageManager => NetworkManager.Singleton.CustomMessagingManager;
internal static bool IsClient => NetworkManager.Singleton.IsClient;
internal static bool IsHost => NetworkManager.Singleton.IsHost;
public static T Default { get; private set; }
public static T Instance { get; private set; }
public static bool Synced { get; internal set; }
protected void InitInstance(T instance)
{
Default = instance;
Instance = instance;
IntSize = 4;
}
internal static void SyncInstance(byte[] data)
{
Instance = DeserializeFromBytes(data);
Synced = true;
}
internal static void RevertSync()
{
Instance = Default;
Synced = false;
}
public static byte[] SerializeToBytes(T val)
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
using MemoryStream memoryStream = new MemoryStream();
try
{
binaryFormatter.Serialize(memoryStream, val);
return memoryStream.ToArray();
}
catch (Exception arg)
{
MainBetterTerminal.instance.getLogger().LogError((object)$"Error serializing instance: {arg}");
return null;
}
}
public static T DeserializeFromBytes(byte[] data)
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
using MemoryStream serializationStream = new MemoryStream(data);
try
{
return (T)binaryFormatter.Deserialize(serializationStream);
}
catch (Exception arg)
{
MainBetterTerminal.instance.getLogger().LogError((object)$"Error deserializing instance: {arg}");
return default(T);
}
}
public static void RequestSync()
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
if (!IsClient)
{
return;
}
FastBufferWriter val = default(FastBufferWriter);
((FastBufferWriter)(ref val))..ctor(IntSize, (Allocator)2, -1);
try
{
MessageManager.SendNamedMessage("BetterTerminal_OnRequestConfigSync", 0uL, val, (NetworkDelivery)3);
}
finally
{
((IDisposable)(FastBufferWriter)(ref val)).Dispose();
}
}
public static void OnRequestSync(ulong clientId, FastBufferReader _)
{
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
if (!IsHost)
{
return;
}
MainBetterTerminal.instance.getLogger().LogInfo((object)$"Config sync request received from client: {clientId}");
byte[] array = SerializeToBytes(Instance);
int num = array.Length;
FastBufferWriter val = default(FastBufferWriter);
((FastBufferWriter)(ref val))..ctor(num + IntSize, (Allocator)2, -1);
try
{
((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
((FastBufferWriter)(ref val)).WriteBytesSafe(array, -1, 0);
MessageManager.SendNamedMessage("BetterTerminal_OnReceiveConfigSync", clientId, val, (NetworkDelivery)3);
}
catch (Exception arg)
{
MainBetterTerminal.instance.getLogger().LogInfo((object)$"Error occurred syncing config with client: {clientId}\n{arg}");
}
finally
{
((IDisposable)(FastBufferWriter)(ref val)).Dispose();
}
}
public static void OnReceiveSync(ulong _, FastBufferReader reader)
{
//IL_0032: 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)
if (!((FastBufferReader)(ref reader)).TryBeginRead(IntSize))
{
MainBetterTerminal.instance.getLogger().LogError((object)"Config sync error: Could not begin reading buffer.");
return;
}
int num = default(int);
((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
if (!((FastBufferReader)(ref reader)).TryBeginRead(num))
{
MainBetterTerminal.instance.getLogger().LogError((object)"Config sync error: Host could not sync.");
return;
}
byte[] data = new byte[num];
((FastBufferReader)(ref reader)).ReadBytesSafe(ref data, num, 0);
SyncInstance(data);
MainBetterTerminal.instance.getLogger().LogInfo((object)"Successfully synced config with host.");
}
[HarmonyPostfix]
[HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")]
public static void InitializeLocalPlayer()
{
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Expected O, but got Unknown
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Expected O, but got Unknown
if (IsHost)
{
MessageManager.RegisterNamedMessageHandler("BetterTerminal_OnRequestConfigSync", new HandleNamedMessageDelegate(OnRequestSync));
Synced = true;
}
else
{
Synced = false;
MessageManager.RegisterNamedMessageHandler("BetterTerminal_OnReceiveConfigSync", new HandleNamedMessageDelegate(OnReceiveSync));
RequestSync();
}
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "BetterTerminal";
public const string PLUGIN_NAME = "";
public const string PLUGIN_VERSION = "1.0.0.0";
}