Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of VSS ValheimStorageSystem v0.4.0
plugins/VSS/VSS.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using SoftReferenceableAssets; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 VSS { public sealed class VssAccessStand : MonoBehaviour, Interactable, Hoverable { internal static readonly HashSet<VssAccessStand> Instances = new HashSet<VssAccessStand>(); internal const string AutoKey = "vss_auto_refill"; internal const string CollectKey = "vss_auto_collect"; private bool _registered; internal static int Searches; internal bool AutoRefill { get { ZNetView component = ((Component)this).GetComponent<ZNetView>(); return component != null && component.IsValid() && component.GetZDO().GetBool("vss_auto_refill", false); } } internal bool AutoCollect { get { ZNetView component = ((Component)this).GetComponent<ZNetView>(); return component != null && component.IsValid() && component.GetZDO().GetBool("vss_auto_collect", false); } } private void Awake() { ZNetView component = ((Component)this).GetComponent<ZNetView>(); Register(component); } private void OnDestroy() { Instances.Remove(this); } private void Start() { ZNetView component = ((Component)this).GetComponent<ZNetView>(); Register(component); } private void Register(ZNetView view) { if ((Object)(object)view == (Object)null || !view.IsValid()) { return; } Instances.Add(this); if (!_registered) { _registered = true; view.Register<long, bool>("VSS_SetAutoRefill", (Action<long, long, bool>)SetAutoRefill); view.Register<long, bool>("VSS_SetAutoCollect", (Action<long, long, bool>)delegate(long sender, long actor, bool enabled) { SetMaster(sender, actor, enabled, "vss_auto_collect"); }); } } internal void ToggleAutoRefill(Player player) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player == (Object)null) && VssSettings.Ready) { Vector3 val = ((Component)player).transform.position - ((Component)this).transform.position; if (!(((Vector3)(ref val)).sqrMagnitude > 25f)) { ((Component)this).GetComponent<ZNetView>().InvokeRPC("VSS_SetAutoRefill", new object[2] { player.GetPlayerID(), !AutoRefill }); } } } private void SetAutoRefill(long sender, long actor, bool enabled) { SetMaster(sender, actor, enabled, "vss_auto_refill"); } internal void ToggleAutoCollect(Player player) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player == (Object)null) && VssSettings.Ready) { Vector3 val = ((Component)player).transform.position - ((Component)this).transform.position; if (!(((Vector3)(ref val)).sqrMagnitude > 25f)) { ((Component)this).GetComponent<ZNetView>().InvokeRPC("VSS_SetAutoCollect", new object[2] { player.GetPlayerID(), !AutoCollect }); } } } private void SetMaster(long sender, long actor, bool enabled, string key) { //IL_00e3: 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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: 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_00ac: Unknown result type (might be due to invalid IL or missing references) ZNetView component = ((Component)this).GetComponent<ZNetView>(); Player val = ((IEnumerable<Player>)Player.GetAllPlayers()).FirstOrDefault((Func<Player, bool>)((Player p) => (Object)(object)p != (Object)null && p.GetPlayerID() == actor)); ZNetView val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<ZNetView>() : null); if (component.IsOwner() && VssSettings.Ready && !((Object)(object)val2 == (Object)null) && val2.IsValid() && val2.GetZDO().GetOwner() == sender && !((Character)val).IsDead()) { Vector3 val3 = ((Component)val).transform.position - ((Component)this).transform.position; if (!(((Vector3)(ref val3)).sqrMagnitude > 25f) && HasWardAccess(actor, ((Component)this).transform.position)) { component.GetZDO().Set(key, enabled); VssGame.ForceSend(ZDOMan.instance, component.GetZDO().m_uid); } } } internal static VssAccessStand FindAutomatic(Vector3 origin) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) VssAccessStand vssAccessStand = null; float num = VssSettings.Radius * VssSettings.Radius; foreach (VssAccessStand instance in Instances) { if (!((Object)(object)instance == (Object)null) && ((Component)instance).gameObject.activeInHierarchy) { ZNetView component = ((Component)instance).GetComponent<ZNetView>(); Piece component2 = ((Component)instance).GetComponent<Piece>(); Vector3 val = ((Component)instance).transform.position - origin; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (!((Object)(object)component == (Object)null) && component.IsValid() && !((Object)(object)component2 == (Object)null) && !(sqrMagnitude > num) && HasWardAccess(component2.GetCreator(), origin) && HasWardAccess(component2.GetCreator(), ((Component)instance).transform.position) && (sqrMagnitude != num || !((Object)(object)vssAccessStand != (Object)null) || StringComparer.Ordinal.Compare(((object)Unsafe.As<ZDOID, ZDOID>(ref component.GetZDO().m_uid)/*cast due to .constrained prefix*/).ToString(), ((object)Unsafe.As<ZDOID, ZDOID>(ref ((Component)vssAccessStand).GetComponent<ZNetView>().GetZDO().m_uid)/*cast due to .constrained prefix*/).ToString()) < 0)) { vssAccessStand = instance; num = sqrMagnitude; } } } return vssAccessStand; } internal static VssAccessStand Find(Vector3 origin, long actor, bool automatic = false) { //IL_001a: 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_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) Searches++; if (Instances.Count == 0 || !HasWardAccess(actor, origin)) { return null; } float num = VssSettings.Radius * VssSettings.Radius; VssAccessStand vssAccessStand = null; float num2 = float.MaxValue; foreach (VssAccessStand instance in Instances) { if ((Object)(object)instance == (Object)null || !((Component)instance).gameObject.activeInHierarchy) { continue; } Vector3 val = ((Component)instance).transform.position - origin; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (!(sqrMagnitude > num) && !(sqrMagnitude > num2)) { ZNetView component = ((Component)instance).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid() && (!automatic || instance.AutoRefill) && HasWardAccess(actor, ((Component)instance).transform.position) && (sqrMagnitude != num2 || !((Object)(object)vssAccessStand != (Object)null) || StringComparer.Ordinal.Compare(((object)Unsafe.As<ZDOID, ZDOID>(ref component.GetZDO().m_uid)/*cast due to .constrained prefix*/).ToString(), ((object)Unsafe.As<ZDOID, ZDOID>(ref ((Component)vssAccessStand).GetComponent<ZNetView>().GetZDO().m_uid)/*cast due to .constrained prefix*/).ToString()) < 0)) { vssAccessStand = instance; num2 = sqrMagnitude; } } } return vssAccessStand; } public string GetHoverText() { return Localization.instance.Localize("Storage Inventory\n[<color=yellow><b>$KEY_Use</b></color>] Open storage"); } public string GetHoverName() { return "Storage Inventory"; } public float GetHoverOffset() { return 0.75f; } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!hold) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer)) { if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return true; } VssUi.Open(val, this); return true; } } return false; } public bool UseItem(Humanoid user, ItemData item) { return false; } internal static bool HasWardAccess(long playerId, Vector3 point) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) List<PrivateArea> wards = VssGame.Wards; bool flag = false; foreach (PrivateArea item in wards) { if (!((Object)(object)item == (Object)null) && VssGame.WardEnabled(item) && VssGame.WardInside(item, point, 0f)) { flag = true; Piece component = ((Component)item).GetComponent<Piece>(); if (((Object)(object)component != (Object)null && component.GetCreator() == playerId) || VssGame.WardPermitted(item, playerId)) { return true; } } } return !flag; } } internal static class VssAssets { private const string BundleName = "vss_assets"; private const string StandPrefabName = "vss_access_stand"; private static GameObject _standModel; private static AssetBundle _bundle; internal static Sprite Panel; internal static Sprite Wood; internal static Sprite Inset; internal static Sprite ControllerIcon; internal static Sprite ChestIcon; internal static bool HasStandModel => (Object)(object)_standModel != (Object)null; public static GameObject GetStandModel() { return ((Object)(object)_standModel != (Object)null) ? Object.Instantiate<GameObject>(_standModel) : VssProceduralStand.CreateModel(); } public static void Load(ManualLogSource log) { string directoryName = Path.GetDirectoryName(typeof(VssPlugin).Assembly.Location); if (string.IsNullOrEmpty(directoryName)) { return; } string path = Path.Combine(directoryName, "ui"); Texture2D val = LoadTexture(Path.Combine(directoryName, "icons", "controller.png"), log); if ((Object)(object)val != (Object)null) { ControllerIcon = WholeSprite(val, "Controller icon"); } Texture2D val2 = LoadTexture(Path.Combine(directoryName, "icons", "chest-preference.png"), log); if ((Object)(object)val2 != (Object)null) { ChestIcon = WholeSprite(val2, "Chest preference icon"); } Texture2D val3 = LoadTexture(Path.Combine(path, "outer-frame.png"), log); if ((Object)(object)val3 != (Object)null) { float num = Mathf.Ceil((float)Mathf.Min(((Texture)val3).width, ((Texture)val3).height) * 0.16f); Panel = WholeSprite(val3, "Outer frame", num * 100f / 72f, num); } Texture2D val4 = LoadTexture(Path.Combine(path, "backing.png"), log); if ((Object)(object)val4 != (Object)null) { Wood = WholeSprite(val4, "Continuous oak backing"); } Texture2D val5 = LoadTexture(Path.Combine(path, "panel-skin.png"), log); if ((Object)(object)val5 != (Object)null) { Inset = WholeSprite(val5, "Blank panel skin", 1000f, Mathf.Ceil((float)((Texture)val5).width * 0.055f)); } string text = Path.Combine(directoryName, "vss_assets"); if (!File.Exists(text)) { log.LogInfo((object)"No vss_assets bundle found; using generated access stand model."); return; } _bundle = AssetBundle.LoadFromFile(text); if ((Object)(object)_bundle == (Object)null) { log.LogWarning((object)"Could not load vss_assets bundle; using generated access stand model."); return; } _standModel = _bundle.LoadAsset<GameObject>("vss_access_stand"); if ((Object)(object)_standModel == (Object)null) { log.LogWarning((object)"vss_assets did not contain prefab vss_access_stand; using generated access stand model."); } else { log.LogInfo((object)"Loaded VSS_StorageInventory_001 pedestal model from vss_assets."); } } private static Texture2D LoadTexture(string path, ManualLogSource log) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown if (!File.Exists(path)) { log.LogWarning((object)("Missing UI layer: " + path)); return null; } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val, File.ReadAllBytes(path))) { Object.Destroy((Object)(object)val); return null; } ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; ((Object)val).name = "VSS " + Path.GetFileNameWithoutExtension(path); return val; } private static Sprite WholeSprite(Texture2D texture, string name, float pixelsPerUnit = 100f, float border = 0f) { //IL_001a: 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) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) Sprite val = Sprite.Create(texture, new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), new Vector2(0.5f, 0.5f), pixelsPerUnit, 0u, (SpriteMeshType)0, Vector4.one * border); ((Object)val).name = "VSS " + name; return val; } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] internal static class VssBuildingPatch { private static readonly FieldRef<Player, GameObject> Ghost = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost"); private static readonly FieldRef<Player, float> LastTool = AccessTools.FieldRefAccess<Player, float>("m_lastToolUseTime"); private static readonly FieldRef<Player, int> Debt = AccessTools.FieldRefAccess<Player, int>("m_buildRemoveDebt"); private static readonly Func<Player, float> Stamina = AccessTools.MethodDelegate<Func<Player, float>>(AccessTools.Method(typeof(Player), "GetBuildStamina", (Type[])null, (Type[])null), (object)null, true); private static readonly Func<Player, ItemData, float> Durability = AccessTools.MethodDelegate<Func<Player, ItemData, float>>(AccessTools.Method(typeof(Player), "GetPlaceDurability", (Type[])null, (Type[])null), (object)null, true); private static bool Prefix(Player __instance, Piece piece, ref bool __result) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || VssResources.Current != null || __instance.NoCostCheat() || ZoneSystem.instance.GetGlobalKey(piece.FreeBuildKey())) { return true; } VssAccessStand vssAccessStand = VssAccessStand.Find(((Component)__instance).transform.position, __instance.GetPlayerID()); if ((Object)(object)vssAccessStand == (Object)null) { return true; } VssContext context = new VssContext { Stand = vssAccessStand, Player = __instance, Actor = __instance.GetPlayerID(), Mode = VssAccessMode.Resources }; List<Container> source = VssStorageScanner.Sources(context); List<VssNeed> needs = VssMaterialPlan.Needs(__instance, piece.m_resources, 0, 1); VssMaterialPlan plan = VssMaterialPlan.Build(((Humanoid)__instance).GetInventory(), source.Select((Container c) => c.GetInventory()), needs); if (plan == null) { __result = false; return false; } if (!plan.UsesStorage) { return true; } if (VssTransfer.Busy) { __result = false; return false; } Player player = __instance; ItemData tool = ((Humanoid)player).RightItem; GameObject ghost = Ghost.Invoke(player); if (tool == null || (Object)(object)ghost == (Object)null) { __result = false; return false; } Vector3 position = ghost.transform.position; Quaternion rotation = ghost.transform.rotation; VssTransactions.Start(context, source.Where((Container c) => plan.ChestInventories.Contains(c.GetInventory())), Guard, delegate(List<Container> locked) { //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Invalid comparison between Unknown and I4 //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Invalid comparison between Unknown and I4 //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Invalid comparison between Unknown and I4 VssMaterialPlan vssMaterialPlan = VssMaterialPlan.Build(((Humanoid)player).GetInventory(), locked.Select((Container c) => c.GetInventory()), needs); if (vssMaterialPlan != null && vssMaterialPlan.Validate()) { vssMaterialPlan.Player = player; vssMaterialPlan.Requirements = piece.m_resources; VssResources.Current = vssMaterialPlan; try { if (!player.HaveRequirements(piece, (RequirementMode)0)) { return false; } if (!player.TryPlacePiece(piece)) { return false; } vssMaterialPlan.Pay(); Hud instance = Hud.instance; if (instance != null) { instance.m_buildUi.AddRecentPiece(piece); } LastTool.Invoke(player) = Time.time; ((Character)player).UseStamina(Stamina(player)); PieceTable buildPieces = tool.m_shared.m_buildPieces; if ((Object)(object)buildPieces != (Object)null && (int)buildPieces.m_skill > 0) { if ((int)buildPieces.m_skill == 107) { Game.instance.IncrementPlayerStat((PlayerStatType)168, 1f, false); } if (Debt.Invoke(player) > 0) { Debt.Invoke(player)--; } else { ((Character)player).RaiseSkill(buildPieces.m_skill, 1f); if ((int)buildPieces.m_skill == 107) { Game.instance.IncrementPlayerStat((PlayerStatType)169, 1f, false); } } } if (tool.m_shared.m_useDurability) { ItemData obj = tool; obj.m_durability -= Durability(player, tool) * Game.m_durabilityRate; } tool.m_shared.m_buildEffect.Create(((Component)player).transform.position, Quaternion.identity, (Transform)null, 1f, -1, ((Character)player).GetZDOID()); return true; } finally { VssResources.Current = null; } } return false; }, delegate(string error) { if (!string.IsNullOrEmpty(error) && (Object)(object)player != (Object)null) { ((Character)player).Message((MessageType)1, error, 0, (Sprite)null, false); } }); __result = false; return false; bool Guard() { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) int result; if ((Object)(object)player.GetSelectedPiece() == (Object)(object)piece && ((Humanoid)player).RightItem == tool && (Object)(object)Ghost.Invoke(player) == (Object)(object)ghost && !InventoryGui.IsVisible() && (Object)(object)ghost != (Object)null) { Vector3 val = ghost.transform.position - position; if (((Vector3)(ref val)).sqrMagnitude < 0.0025f && Quaternion.Angle(ghost.transform.rotation, rotation) < 1f) { result = (((Character)player).HaveStamina(Stamina(player)) ? 1 : 0); goto IL_00ce; } } result = 0; goto IL_00ce; IL_00ce: return (byte)result != 0; } } } public sealed class VssChestBridge : MonoBehaviour { internal const string TokenKey = "vss_lease_token"; internal const string UntilKey = "vss_lease_until"; private Container _chest; private ZNetView _view; private string _pendingToken; private long _expectedOwner; internal bool Rejected { get; private set; } internal bool Granted { get; private set; } internal static long Now => ((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTime().Ticks : 0; internal static bool IsLeased(ZDO zdo) { return zdo != null && VssLeaseRules.Active(zdo.GetLong("vss_lease_until", 0L), Now); } private void Awake() { _chest = ((Component)this).GetComponent<Container>(); _view = (((Object)(object)_chest != (Object)null) ? VssGame.View.Invoke(_chest) : null); if ((Object)(object)_view == (Object)null || !_view.IsValid()) { ((Behaviour)this).enabled = false; return; } _view.Register<ZPackage>("VSS_AcquireV3", (Action<long, ZPackage>)Request); _view.Register<string, bool>("VSS_Grant", (Action<long, string, bool>)Reply); } internal string Begin(Player player, VssAccessStand stand) { return Begin(new VssContext { Player = player, Actor = player.GetPlayerID(), Stand = stand, Mode = VssAccessMode.Grid }); } internal string Begin(VssContext context) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) Granted = false; Rejected = false; _pendingToken = Guid.NewGuid().ToString("N"); _expectedOwner = _view.GetZDO().GetOwner(); string pendingToken = _pendingToken; ZPackage val = new ZPackage(); val.Write(context.Actor); val.Write(context.StandId); val.Write(context.TargetId); val.Write((int)context.Mode); val.Write(pendingToken); _view.InvokeRPC("VSS_AcquireV3", new object[1] { val }); return pendingToken; } private void Request(long sender, ZPackage package) { //IL_0024: 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) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) if (!_view.IsOwner()) { return; } long num; ZDOID val; ZDOID val2; VssAccessMode mode; string text; try { num = package.ReadLong(); val = package.ReadZDOID(); val2 = package.ReadZDOID(); mode = (VssAccessMode)package.ReadInt(); text = package.ReadString(); } catch { return; } ZDO zDO = _view.GetZDO(); if (!VssSettings.Ready || string.IsNullOrEmpty(text) || text.Length > 64 || _chest.IsInUse() || IsLeased(zDO) || !VssStorageScanner.Supported(_chest) || !VssGame.CheckAccess(_chest, num)) { Deny(sender, text); return; } ZDO zDO2 = ZDOMan.instance.GetZDO(val); ZDO target = ((val2 == ZDOID.None) ? null : ZDOMan.instance.GetZDO(val2)); if (VssContext.Authorize(sender, num, zDO2, target, mode)) { Vector3 val3 = zDO2.GetPosition() - ((Component)this).transform.position; if (!(((Vector3)(ref val3)).sqrMagnitude > VssSettings.Radius * VssSettings.Radius) && (!_chest.m_checkGuardStone || VssAccessStand.HasWardAccess(num, ((Component)this).transform.position)) && VssAccessStand.HasWardAccess(num, zDO2.GetPosition())) { VssGame.Load(_chest); zDO.Set("vss_lease_token", text); zDO.Set("vss_lease_until", Now + TimeSpan.FromSeconds(10.0).Ticks); zDO.SetOwner(sender); ZDOMan.instance.ForceSendZDO(sender, zDO.m_uid); _view.InvokeRPC(sender, "VSS_Grant", new object[2] { text, true }); return; } } Deny(sender, text); } private void Deny(long sender, string token) { _view.InvokeRPC(sender, "VSS_Grant", new object[2] { token ?? "", false }); } private void Reply(long sender, string token, bool accepted) { if (!(token != _pendingToken) && sender == _expectedOwner) { Granted = accepted; Rejected = !accepted; } } internal bool CanCommit(string token) { return (Object)(object)_view != (Object)null && _view.IsValid() && VssLeaseRules.CanCommit(_view.IsOwner(), _view.GetZDO().GetString("vss_lease_token", ""), token, _view.GetZDO().GetLong("vss_lease_until", 0L), Now); } internal void Release(string token) { //IL_00be: Unknown result type (might be due to invalid IL or missing references) if (_pendingToken == token) { _pendingToken = null; } if (!((Object)(object)_view == (Object)null) && _view.IsValid() && _view.IsOwner() && !(_view.GetZDO().GetString("vss_lease_token", "") != token)) { _chest.SetInUse(false); _view.GetZDO().Set("vss_lease_until", 0L); _view.GetZDO().Set("vss_lease_token", ""); VssGame.ForceSend(ZDOMan.instance, _view.GetZDO().m_uid); } } } [HarmonyPatch(typeof(Container), "Awake")] internal static class VssContainerAwakePatch { private static void Postfix(Container __instance) { if (VssStorageScanner.Supported(__instance)) { VssStorageScanner.Containers.Add(__instance); if ((Object)(object)((Component)__instance).GetComponent<VssChestBridge>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<VssChestBridge>(); } } } } [HarmonyPatch] internal static class VssVanillaChestLeasePatch { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(Container), "RPC_RequestOpen", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Container), "RPC_RequestStack", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Container), "RPC_RequestTakeAll", (Type[])null, (Type[])null); } private static bool Prefix(Container __instance, long __0, MethodBase __originalMethod) { ZNetView val = VssGame.View.Invoke(__instance); if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner() || !VssChestBridge.IsLeased(val.GetZDO())) { return true; } string text = ((__originalMethod.Name == "RPC_RequestOpen") ? "RPC_OpenResponse" : ((__originalMethod.Name == "RPC_RequestStack") ? "RPC_StackResponse" : "RPC_TakeAllResponse")); val.InvokeRPC(__0, text, new object[1] { false }); return false; } } public sealed class VssRefillBridge : MonoBehaviour { internal const string CollectKey = "vss_object_auto_collect"; private string _collectRequest; private long _collectOwner; private float _collectUntil; private static float _nextCollect; private static int _collectCursor; private static readonly MethodInfo SetCookingSlot = AccessTools.Method(typeof(CookingStation), "SetSlot", (Type[])null, (Type[])null); private static readonly object EmptySlotStatus = Enum.ToObject(SetCookingSlot.GetParameters()[3].ParameterType, 0); internal const string AutoKey = "vss_object_auto_refill"; internal static readonly HashSet<VssRefillBridge> Instances = new HashSet<VssRefillBridge>(); private ZNetView _view; private Smelter _smelter; private Fireplace _fire; private CookingStation _cooking; private ShieldGenerator _shield; private string _request; private long _expectedOwner; private float _requestUntil; private float _lastUse; private string _autoRequest; private long _autoOwner; private float _autoUntil; private Player _hintPlayer; private VssAccessStand _hintStand; private Vector3 _hintPosition; private float _hintUntil; private float _hintRadius; private bool _hintAuto; private bool _hintMaster; private bool _hintCollect; private bool _hintCollectMaster; private KeyboardShortcut _hintRefillKey; private KeyboardShortcut _hintCollectKey; private string _hintText; private static float _nextAuto; private static int _cursor; private static readonly Func<CookingStation, bool> CookingFire = AccessTools.MethodDelegate<Func<CookingStation, bool>>(AccessTools.Method(typeof(CookingStation), "IsFireLit", (Type[])null, (Type[])null), (object)null, true); private static readonly Func<CookingStation, int> FreeSlot = AccessTools.MethodDelegate<Func<CookingStation, int>>(AccessTools.Method(typeof(CookingStation), "GetFreeSlot", (Type[])null, (Type[])null), (object)null, true); private static readonly Func<CookingStation, bool> DoneFood = AccessTools.MethodDelegate<Func<CookingStation, bool>>(AccessTools.Method(typeof(CookingStation), "HaveDoneItem", (Type[])null, (Type[])null), (object)null, true); private static readonly Action<Smelter, long> SmelterFuel = AccessTools.MethodDelegate<Action<Smelter, long>>(AccessTools.Method(typeof(Smelter), "RPC_AddFuel", (Type[])null, (Type[])null), (object)null, true); private static readonly Action<Smelter, long, string, bool> SmelterInput = AccessTools.MethodDelegate<Action<Smelter, long, string, bool>>(AccessTools.Method(typeof(Smelter), "RPC_AddOre", (Type[])null, (Type[])null), (object)null, true); private static readonly Action<Fireplace, long> FireFuel = AccessTools.MethodDelegate<Action<Fireplace, long>>(AccessTools.Method(typeof(Fireplace), "RPC_AddFuel", (Type[])null, (Type[])null), (object)null, true); private static readonly Action<CookingStation, long> CookingFuel = AccessTools.MethodDelegate<Action<CookingStation, long>>(AccessTools.Method(typeof(CookingStation), "RPC_AddFuel", (Type[])null, (Type[])null), (object)null, true); private static readonly Action<CookingStation, long, string, bool> CookingInput = AccessTools.MethodDelegate<Action<CookingStation, long, string, bool>>(AccessTools.Method(typeof(CookingStation), "RPC_AddItem", (Type[])null, (Type[])null), (object)null, true); private static readonly Action<ShieldGenerator, long> ShieldFuel = AccessTools.MethodDelegate<Action<ShieldGenerator, long>>(AccessTools.Method(typeof(ShieldGenerator), "RPC_AddFuel", (Type[])null, (Type[])null), (object)null, true); internal bool AutoCollect => (Object)(object)_view != (Object)null && _view.IsValid() && _view.GetZDO().GetBool("vss_object_auto_collect", false); internal bool CanAutoCollect => ((Object)(object)_smelter != (Object)null && _smelter.m_conversion.Any((ItemConversion c) => (Object)(object)c.m_to != (Object)null)) || ((Object)(object)_cooking != (Object)null && _cooking.m_slots != null && _cooking.m_slots.Length != 0 && _cooking.m_conversion.Any((ItemConversion c) => (Object)(object)c.m_to != (Object)null)); internal bool AutoRefill => (Object)(object)_view != (Object)null && _view.IsValid() && _view.GetZDO().GetBool("vss_object_auto_refill", false); internal bool CanAutoRefill => ((Object)(object)_smelter != (Object)null && ((_smelter.m_maxFuel > 0 && (Object)(object)_smelter.m_fuelItem != (Object)null) || (_smelter.m_maxOre > 0 && _smelter.m_conversion.Count > 0))) || ((Object)(object)_fire != (Object)null && _fire.m_canRefill && !_fire.m_infiniteFuel && _fire.m_maxFuel > 0f && (Object)(object)_fire.m_fuelItem != (Object)null) || ((Object)(object)_cooking != (Object)null && _cooking.m_useFuel && _cooking.m_maxFuel > 0 && (Object)(object)_cooking.m_fuelItem != (Object)null) || ((Object)(object)_shield != (Object)null && _shield.m_maxFuel > 0 && _shield.m_fuelItems.Count > 0); internal static bool CollectEnabled(ZDO controller, ZDO target) { return controller != null && target != null && controller.GetBool("vss_auto_collect", false) && target.GetBool("vss_object_auto_collect", false); } internal static bool CollectSupportedPrefab(int hash) { ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.GetPrefab(hash) : null); return (Object)(object)val != (Object)null && ((Object)(object)val.GetComponentInChildren<Smelter>(true) != (Object)null || (Object)(object)val.GetComponentInChildren<CookingStation>(true) != (Object)null); } private void RegisterCollectRpc() { _view.Register<long, bool, string>("VSS_SetObjectCollect", (Action<long, long, bool, string>)SetAutoCollect); _view.Register<string, bool, bool>("VSS_ObjectCollectResult", (Action<long, string, bool, bool>)CollectReply); } private bool CanToggleCollect(Player player) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) int result; if ((Object)(object)player != (Object)null && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && VssSettings.Ready && (Object)(object)_view != (Object)null && _view.IsValid() && CanAutoCollect) { Vector3 val = ((Component)player).transform.position - ((Component)this).transform.position; if (((Vector3)(ref val)).sqrMagnitude <= 25f && VssAccessStand.HasWardAccess(player.GetPlayerID(), ((Component)this).transform.position)) { result = (((Object)(object)VssAccessStand.Find(((Component)this).transform.position, player.GetPlayerID()) != (Object)null) ? 1 : 0); goto IL_00b1; } } result = 0; goto IL_00b1; IL_00b1: return (byte)result != 0; } internal bool ToggleAutoCollect(Player player) { if ((Object)(object)player != (Object)(object)Player.m_localPlayer || !CanToggleCollect(player)) { return false; } if (_collectRequest != null && Time.unscaledTime < _collectUntil) { return true; } _collectRequest = Guid.NewGuid().ToString("N"); _collectOwner = _view.GetZDO().GetOwner(); _collectUntil = Time.unscaledTime + 3f; _view.InvokeRPC("VSS_SetObjectCollect", new object[3] { player.GetPlayerID(), !AutoCollect, _collectRequest }); return true; } private void SetAutoCollect(long sender, long actor, bool enabled, string token) { //IL_00e0: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_view == (Object)null) && _view.IsValid() && _view.IsOwner() && !string.IsNullOrEmpty(token) && token.Length <= 64) { Player val = ((IEnumerable<Player>)Player.GetAllPlayers()).FirstOrDefault((Func<Player, bool>)((Player p) => (Object)(object)p != (Object)null && p.GetPlayerID() == actor)); ZNetView val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<ZNetView>() : null); bool flag = (Object)(object)val2 != (Object)null && val2.IsValid() && val2.GetZDO().GetOwner() == sender && CanToggleCollect(val); if (flag) { _view.GetZDO().Set("vss_object_auto_collect", enabled); VssGame.ForceSend(ZDOMan.instance, _view.GetZDO().m_uid); } _view.InvokeRPC(sender, "VSS_ObjectCollectResult", new object[3] { token, flag, AutoCollect }); } } private void CollectReply(long sender, string token, bool accepted, bool enabled) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) if (sender == _collectOwner && !(token != _collectRequest)) { _collectRequest = null; Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { VssAccessStand vssAccessStand = VssAccessStand.Find(((Component)this).transform.position, localPlayer.GetPlayerID()); ((Character)localPlayer).Message((MessageType)1, (!accepted) ? "Cannot change VSS auto-collect here." : ("VSS auto-collect: " + (enabled ? "On" : "Off") + ((enabled && ((Object)(object)vssAccessStand == (Object)null || !vssAccessStand.AutoCollect)) ? " (collection master Off)." : ".")), 0, (Sprite)null, false); } } } internal static void CollectTick() { //IL_00eb: Unknown result type (might be due to invalid IL or missing references) if (!VssSettings.Ready || VssTransfer.Busy || Time.unscaledTime < _nextCollect || (Object)(object)ZNetScene.instance == (Object)null) { return; } _nextCollect = Time.unscaledTime + 0.5f; Instances.RemoveWhere((VssRefillBridge s) => (Object)(object)s == (Object)null); List<VssRefillBridge> list = Instances.Where((VssRefillBridge s) => (Object)(object)s._view != (Object)null && s._view.IsValid() && s._view.IsOwner() && ((Component)s).gameObject.activeInHierarchy && s.AutoCollect && s.CanAutoCollect).OrderBy<VssRefillBridge, string>((VssRefillBridge s) => ((object)Unsafe.As<ZDOID, ZDOID>(ref s._view.GetZDO().m_uid)/*cast due to .constrained prefix*/).ToString(), StringComparer.Ordinal).ToList(); for (int num = 0; num < list.Count; num++) { int num2 = (_collectCursor + num) % list.Count; VssRefillBridge vssRefillBridge = list[num2]; VssAccessStand vssAccessStand = VssAccessStand.FindAutomatic(((Component)vssRefillBridge).transform.position); if (!((Object)(object)vssAccessStand == (Object)null) && vssAccessStand.AutoCollect) { VssContext context = new VssContext { Stand = vssAccessStand, Actor = ((Component)vssAccessStand).GetComponent<Piece>().GetCreator(), Target = vssRefillBridge._view, Mode = VssAccessMode.AutomaticCollect }; if (vssRefillBridge.RunCollect(context)) { _collectCursor = (num2 + 1) % list.Count; break; } } } } internal ItemData CookedOutput(int slot, out string name, out int status, out bool cheated) { name = _view.GetZDO().GetString("slot" + slot, ""); status = _view.GetZDO().GetInt("slotstatus" + slot, 0); cheated = _view.GetZDO().GetBool(ZDOVars.s_cheatedQueued + slot, false); if (string.IsNullOrEmpty(name) || status == 0) { return null; } string itemName = name; ItemDrop val = (ItemDrop)(((Object)(object)_cooking.m_overCookedItem != (Object)null && itemName == ((Object)_cooking.m_overCookedItem).name) ? ((object)_cooking.m_overCookedItem) : ((object)_cooking.m_conversion.Select((ItemConversion c) => c.m_to).FirstOrDefault((Func<ItemDrop, bool>)((ItemDrop d) => (Object)(object)d != (Object)null && ((Object)d).name == itemName)))); if ((Object)(object)val == (Object)null) { return null; } ItemData val2 = val.m_itemData.Clone(); val2.m_dropPrefab = ((Component)val).gameObject; val2.m_stack = 1; val2.m_equipped = false; val2.m_worldLevel = (byte)Game.m_worldLevel; val2.m_cheated = cheated; if (_cooking.m_spawnFullDurability) { val2.m_durability = val2.m_shared.m_maxDurability; } return val2; } internal bool CommitCooked(VssContext context, int slot, Inventory destination) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_012c: Unknown result type (might be due to invalid IL or missing references) if (!context.Valid() || (Object)(object)_cooking == (Object)null || slot < 0 || slot >= _cooking.m_slots.Length) { return false; } string name; int status; bool cheated; ItemData val = CookedOutput(slot, out name, out status, out cheated); if (val == null || VssInventoryOps.Capacity(destination, val) < 1) { return false; } Inventory val2 = new Inventory("VSS cooking output", (Sprite)null, 1, 1); val2.GetAllItems().Add(val); if (VssInventoryOps.Move(val2, destination, val, 1) != 1) { return false; } SetCookingSlot.Invoke(_cooking, new object[5] { slot, "", 0f, EmptySlotStatus, false }); _view.InvokeRPC(ZNetView.Everybody, "RPC_SetSlotVisual", new object[2] { slot, "" }); VssGame.ForceSend(ZDOMan.instance, _view.GetZDO().m_uid); return true; } internal bool RunCollect(VssContext context) { //IL_0165: Unknown result type (might be due to invalid IL or missing references) if (VssTransfer.Busy || !context.Valid()) { return false; } if ((Object)(object)_cooking != (Object)null) { for (int i = 0; i < _cooking.m_slots.Length; i++) { string name; int status; bool cheated; ItemData val = CookedOutput(i, out name, out status, out cheated); if (val != null) { List<Container> sources = VssStorageScanner.Sources(context); Container destination = Destination(sources, val); if ((Object)(object)destination == (Object)null) { return false; } int selected = i; return VssTransactions.Start(context, (IEnumerable<Container>)(object)new Container[1] { destination }, () => (Object)(object)this != (Object)null && context.Valid(), (List<Container> locked) => CommitCooked(context, selected, destination.GetInventory()), null); } } return false; } VssCollectOutput[] array = VssCollectOutput.For(_view.GetZDO().m_uid); foreach (VssCollectOutput output in array) { if ((Object)(object)output == (Object)null || !output.Eligible(this)) { continue; } Container destination2 = Destination(VssStorageScanner.Sources(context), output.Item.m_itemData); if (!((Object)(object)destination2 == (Object)null)) { return VssTransactions.Start(context, (IEnumerable<Container>)(object)new Container[1] { destination2 }, () => (Object)(object)this != (Object)null && (Object)(object)output != (Object)null && context.Valid() && output.Eligible(this), (List<Container> locked) => output.Commit(this, context, destination2.GetInventory()), null); } } return false; } internal static Container Destination(List<Container> sources, ItemData item) { return (from c in sources where VssInventoryOps.Capacity(c.GetInventory(), item) > 0 orderby (VssInventoryOps.Capacity(c.GetInventory(), item, stacksOnly: true) <= 0) ? 1 : 0, VssPreferences.Rank(c, item) select c).FirstOrDefault(); } internal static bool AutoEnabled(ZDO controller, ZDO target) { return controller != null && target != null && controller.GetBool("vss_auto_refill", false) && target.GetBool("vss_object_auto_refill", false); } internal static bool SupportedPrefab(int hash) { ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.GetPrefab(hash) : null); return (Object)(object)val != (Object)null && ((Object)(object)val.GetComponentInChildren<Smelter>(true) != (Object)null || (Object)(object)val.GetComponentInChildren<Fireplace>(true) != (Object)null || (Object)(object)val.GetComponentInChildren<CookingStation>(true) != (Object)null || (Object)(object)val.GetComponentInChildren<ShieldGenerator>(true) != (Object)null); } private void Awake() { _view = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)_view == (Object)null || !_view.IsValid()) { ((Behaviour)this).enabled = false; return; } _smelter = ((Component)this).GetComponentInChildren<Smelter>(true); _fire = ((Component)this).GetComponentInChildren<Fireplace>(true); _cooking = ((Component)this).GetComponentInChildren<CookingStation>(true); _shield = ((Component)this).GetComponentInChildren<ShieldGenerator>(true); RegisterRpc(); Instances.Add(this); } private void RegisterRpc() { _view.Register<ZPackage>("VSS_Refill", (Action<long, ZPackage>)Request); _view.Register<string, int, string>("VSS_RefillResult", (Action<long, string, int, string>)Reply); _view.Register<long, bool, string>("VSS_SetObjectAuto", (Action<long, long, bool, string>)SetAutoRefill); _view.Register<string, bool, bool>("VSS_ObjectAutoResult", (Action<long, string, bool, bool>)AutoReply); RegisterCollectRpc(); } private bool CanToggle(Player player) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) int result; if ((Object)(object)player != (Object)null && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && VssSettings.Ready && (Object)(object)_view != (Object)null && _view.IsValid() && CanAutoRefill) { Vector3 val = ((Component)player).transform.position - ((Component)this).transform.position; if (((Vector3)(ref val)).sqrMagnitude <= 25f && VssAccessStand.HasWardAccess(player.GetPlayerID(), ((Component)this).transform.position)) { result = (((Object)(object)VssAccessStand.Find(((Component)this).transform.position, player.GetPlayerID()) != (Object)null) ? 1 : 0); goto IL_00b1; } } result = 0; goto IL_00b1; IL_00b1: return (byte)result != 0; } internal bool ToggleAutoRefill(Player player) { if ((Object)(object)player != (Object)(object)Player.m_localPlayer || !CanToggle(player)) { return false; } if (_autoRequest != null && Time.unscaledTime < _autoUntil) { return true; } _autoRequest = Guid.NewGuid().ToString("N"); _autoOwner = _view.GetZDO().GetOwner(); _autoUntil = Time.unscaledTime + 3f; _view.InvokeRPC("VSS_SetObjectAuto", new object[3] { player.GetPlayerID(), !AutoRefill, _autoRequest }); return true; } private void SetAutoRefill(long sender, long actor, bool enabled, string token) { //IL_00e0: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_view == (Object)null) && _view.IsValid() && _view.IsOwner() && !string.IsNullOrEmpty(token) && token.Length <= 64) { Player val = ((IEnumerable<Player>)Player.GetAllPlayers()).FirstOrDefault((Func<Player, bool>)((Player p) => (Object)(object)p != (Object)null && p.GetPlayerID() == actor)); ZNetView val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<ZNetView>() : null); bool flag = (Object)(object)val2 != (Object)null && val2.IsValid() && val2.GetZDO().GetOwner() == sender && CanToggle(val); if (flag) { _view.GetZDO().Set("vss_object_auto_refill", enabled); VssGame.ForceSend(ZDOMan.instance, _view.GetZDO().m_uid); } _view.InvokeRPC(sender, "VSS_ObjectAutoResult", new object[3] { token, flag, AutoRefill }); } } private void AutoReply(long sender, string token, bool accepted, bool enabled) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) if (sender == _autoOwner && !(token != _autoRequest)) { _autoRequest = null; Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { VssAccessStand vssAccessStand = VssAccessStand.Find(((Component)this).transform.position, localPlayer.GetPlayerID()); ((Character)localPlayer).Message((MessageType)1, (!accepted) ? "Cannot change VSS auto-refill here." : ("VSS auto-refill: " + (enabled ? "On" : "Off") + ((enabled && ((Object)(object)vssAccessStand == (Object)null || !vssAccessStand.AutoRefill)) ? " (controller master Off)." : ".")), 0, (Sprite)null, false); } } } internal static string AutoHint(bool enabled, bool master, string key) { return "\n[<color=yellow><b>" + key + "</b></color>] VSS auto-refill: " + (enabled ? "On" : "Off") + ((enabled && !master) ? " <color=#b0a58d>(master Off)</color>" : ""); } internal unsafe string HoverHint(Player player) { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player == (Object)null) && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && VssSettings.Ready && !((Object)(object)_view == (Object)null) && _view.IsValid() && (CanAutoRefill || CanAutoCollect)) { Vector3 val = ((Component)player).transform.position - ((Component)this).transform.position; if (!(((Vector3)(ref val)).sqrMagnitude > 25f)) { if (!((Object)(object)_hintPlayer != (Object)(object)player) && !(Time.unscaledTime >= _hintUntil) && _hintRadius == VssSettings.Radius) { val = ((Component)this).transform.position - _hintPosition; if (!(((Vector3)(ref val)).sqrMagnitude > 0.25f)) { goto IL_013d; } } _hintPlayer = player; _hintPosition = ((Component)this).transform.position; _hintRadius = VssSettings.Radius; _hintStand = VssAccessStand.Find(((Component)this).transform.position, player.GetPlayerID()); _hintUntil = Time.unscaledTime + 0.25f; _hintText = null; goto IL_013d; } } return ""; IL_029e: return _hintText; IL_013d: if ((Object)(object)_hintStand == (Object)null) { return ""; } bool autoRefill = AutoRefill; bool autoRefill2 = _hintStand.AutoRefill; bool autoCollect = AutoCollect; bool autoCollect2 = _hintStand.AutoCollect; KeyboardShortcut value = VssPlugin.ModConfig.AutoRefillToggleKey.Value; KeyboardShortcut value2 = VssPlugin.ModConfig.AutoCollectToggleKey.Value; if (_hintText != null && _hintAuto == autoRefill && _hintMaster == autoRefill2 && _hintCollect == autoCollect && _hintCollectMaster == autoCollect2) { ref KeyboardShortcut hintRefillKey = ref _hintRefillKey; object obj = value; if (((object)Unsafe.As<KeyboardShortcut, KeyboardShortcut>(ref hintRefillKey)/*cast due to .constrained prefix*/).Equals(obj)) { ref KeyboardShortcut hintCollectKey = ref _hintCollectKey; object obj2 = value2; if (((object)Unsafe.As<KeyboardShortcut, KeyboardShortcut>(ref hintCollectKey)/*cast due to .constrained prefix*/).Equals(obj2)) { goto IL_029e; } } } _hintAuto = autoRefill; _hintMaster = autoRefill2; _hintCollect = autoCollect; _hintCollectMaster = autoCollect2; _hintRefillKey = value; _hintCollectKey = value2; _hintText = (CanAutoRefill ? AutoHint(autoRefill, autoRefill2, ((object)(*(KeyboardShortcut*)(&value))/*cast due to .constrained prefix*/).ToString()) : "") + (CanAutoCollect ? AutoHint(autoCollect, autoCollect2, ((object)(*(KeyboardShortcut*)(&value2))/*cast due to .constrained prefix*/).ToString()).Replace("auto-refill", "auto-collect") : ""); goto IL_029e; } private void OnDestroy() { Instances.Remove(this); } internal static int FuelRoom(float fuel, float maximum, bool ceil) { return Math.Max(0, Mathf.FloorToInt(maximum - (ceil ? Mathf.Ceil(fuel) : fuel))); } internal int Room(VssRefillKind kind) { if ((Object)(object)_view == (Object)null || !_view.IsValid()) { return 0; } if (kind == VssRefillKind.Fuel) { if ((Object)(object)_fire != (Object)null && (!_fire.m_canRefill || _fire.m_infiniteFuel || (Object)(object)_fire.m_fuelItem == (Object)null)) { return 0; } if (((Object)(object)_smelter != (Object)null && (Object)(object)_smelter.m_fuelItem == (Object)null) || ((Object)(object)_cooking != (Object)null && (!_cooking.m_useFuel || (Object)(object)_cooking.m_fuelItem == (Object)null)) || ((Object)(object)_shield != (Object)null && _shield.m_fuelItems.Count == 0)) { return 0; } float maximum = (((Object)(object)_smelter != (Object)null) ? ((float)_smelter.m_maxFuel) : (((Object)(object)_fire != (Object)null) ? _fire.m_maxFuel : ((float)(((Object)(object)_cooking != (Object)null) ? _cooking.m_maxFuel : (((Object)(object)_shield != (Object)null) ? _shield.m_maxFuel : 0))))); return FuelRoom(_view.GetZDO().GetFloat(ZDOVars.s_fuel, ((Object)(object)_shield != (Object)null) ? ((float)_shield.m_defaultFuel) : 0f), maximum, (Object)(object)_fire != (Object)null); } if ((Object)(object)_smelter != (Object)null) { return Math.Max(0, _smelter.m_maxOre - _view.GetZDO().GetInt(ZDOVars.s_queued, 0)); } if ((Object)(object)_cooking != (Object)null && (!_cooking.m_requireFire || CookingFire(_cooking))) { return (FreeSlot(_cooking) >= 0) ? 1 : 0; } return 0; } internal bool Allows(ItemData item, VssRefillKind kind, bool automatic) { if (item == null || item.m_equipped || item.m_stack <= 0 || item.m_worldLevel < Game.m_worldLevel || VssSettings.ProtectedWood(VssItemKey.Prefab(item)) || (automatic && VssSettings.AutoExcluded(VssItemKey.Prefab(item)))) { return false; } if (kind == VssRefillKind.Fuel) { ItemDrop val = _smelter?.m_fuelItem ?? _fire?.m_fuelItem ?? _cooking?.m_fuelItem; return ((Object)(object)val != (Object)null) ? (val.m_itemData.m_shared.m_name == item.m_shared.m_name) : ((Object)(object)_shield != (Object)null && _shield.m_fuelItems.Any((ItemDrop f) => (Object)(object)f != (Object)null && f.m_itemData.m_shared.m_name == item.m_shared.m_name)); } string prefab = VssItemKey.Prefab(item); if ((Object)(object)_smelter != (Object)null) { return _smelter.m_conversion.Any((ItemConversion c) => (Object)(object)c.m_from != (Object)null && ((Object)c.m_from).name == prefab); } return !automatic && (Object)(object)_cooking != (Object)null && _cooking.m_conversion.Any((ItemConversion c) => (Object)(object)c.m_from != (Object)null && ((Object)c.m_from).name == prefab); } private int Measure(VssRefillKind kind) { return (kind == VssRefillKind.Fuel) ? Mathf.RoundToInt(_view.GetZDO().GetFloat(ZDOVars.s_fuel, 0f) * 10000f) : (((Object)(object)_smelter != (Object)null) ? _view.GetZDO().GetInt(ZDOVars.s_queued, 0) : (((Object)(object)_cooking != (Object)null) ? ((FreeSlot(_cooking) < 0) ? _cooking.m_slots.Length : FreeSlot(_cooking)) : 0)); } private bool AddOne(ItemData item, VssRefillKind kind) { if (!_view.IsOwner() || Room(kind) <= 0) { return false; } int num = Measure(kind); try { if (kind == VssRefillKind.Input) { if ((Object)(object)_smelter != (Object)null) { SmelterInput(_smelter, _view.GetZDO().GetOwner(), VssItemKey.Prefab(item), item.m_cheated); } else if ((Object)(object)_cooking != (Object)null) { CookingInput(_cooking, _view.GetZDO().GetOwner(), VssItemKey.Prefab(item), item.m_cheated); } } else if ((Object)(object)_smelter != (Object)null) { SmelterFuel(_smelter, _view.GetZDO().GetOwner()); } else if ((Object)(object)_fire != (Object)null) { FireFuel(_fire, _view.GetZDO().GetOwner()); } else if ((Object)(object)_cooking != (Object)null) { CookingFuel(_cooking, _view.GetZDO().GetOwner()); } else if ((Object)(object)_shield != (Object)null) { ShieldFuel(_shield, _view.GetZDO().GetOwner()); } } catch (Exception ex) { VssPlugin.Log.LogError((object)ex); } return Measure(kind) > num; } internal bool SupplyOne(Inventory inventory, ItemData item, VssRefillKind kind, bool automatic) { if (inventory == null || !inventory.ContainsItem(item) || (automatic && !AutoRefill) || !Allows(item, kind, automatic) || !AddOne(item, kind)) { return false; } inventory.RemoveOneItem(item); return true; } internal bool Manual(Player player, VssRefillKind kind) { //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Expected O, but got Unknown //IL_021c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || !VssSettings.Ready || (Object)(object)_view == (Object)null || !_view.IsValid() || Room(kind) <= 0 || ((Humanoid)player).GetInventory().GetAllItems().Any((ItemData i) => Allows(i, kind, automatic: false))) { return false; } if ((Object)(object)_cooking != (Object)null && kind == VssRefillKind.Input && DoneFood(_cooking)) { return false; } VssAccessStand vssAccessStand = VssAccessStand.Find(((Component)this).transform.position, player.GetPlayerID()); if (!((Object)(object)vssAccessStand == (Object)null)) { Vector3 val = ((Component)player).transform.position - ((Component)this).transform.position; if (!(((Vector3)(ref val)).sqrMagnitude > 25f)) { if ((_request != null && Time.unscaledTime < _requestUntil) || Time.unscaledTime - _lastUse < 0.2f) { return true; } VssContext context = new VssContext { Player = player, Actor = player.GetPlayerID(), Stand = vssAccessStand, Target = _view, Mode = VssAccessMode.Resources }; if (!VssStorageScanner.Sources(context).Any((Container c) => c.GetInventory().GetAllItems().Any((ItemData i) => Allows(i, kind, automatic: false)))) { return false; } _lastUse = Time.unscaledTime; _request = Guid.NewGuid().ToString("N"); _requestUntil = Time.unscaledTime + 8f; _expectedOwner = _view.GetZDO().GetOwner(); ZPackage val2 = new ZPackage(); val2.Write(player.GetPlayerID()); val2.Write(((Component)vssAccessStand).GetComponent<ZNetView>().GetZDO().m_uid); val2.Write((int)kind); val2.Write((!Input.GetKey((KeyCode)304) && !Input.GetKey((KeyCode)303)) ? 1 : Math.Min(50, Room(kind))); val2.Write(_request); _view.InvokeRPC("VSS_Refill", new object[1] { val2 }); return true; } } return false; } private void Request(long sender, ZPackage packet) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) if (!_view.IsOwner() || !VssSettings.Ready) { return; } long actor; ZDOID standId; VssRefillKind vssRefillKind; int num; string token; try { actor = packet.ReadLong(); standId = packet.ReadZDOID(); vssRefillKind = (VssRefillKind)packet.ReadInt(); num = packet.ReadInt(); token = packet.ReadString(); } catch { return; } if (!Enum.IsDefined(typeof(VssRefillKind), vssRefillKind) || num < 1 || num > 50 || string.IsNullOrEmpty(token) || token.Length > 64) { return; } Player val = ((IEnumerable<Player>)Player.GetAllPlayers()).FirstOrDefault((Func<Player, bool>)((Player p) => (Object)(object)p != (Object)null && p.GetPlayerID() == actor && !((Character)p).IsDead() && !((Character)p).IsTeleporting())); ZNetView val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<ZNetView>() : null); VssAccessStand vssAccessStand = VssAccessStand.Instances.FirstOrDefault((VssAccessStand s) => (Object)(object)s != (Object)null && ((Component)s).GetComponent<ZNetView>().IsValid() && ((Component)s).GetComponent<ZNetView>().GetZDO().m_uid == standId); if ((Object)(object)val2 == (Object)null || !val2.IsValid() || val2.GetZDO().GetOwner() != sender || (Object)(object)vssAccessStand == (Object)null) { return; } Vector3 val3 = ((Component)val).transform.position - ((Component)this).transform.position; if (!(((Vector3)(ref val3)).sqrMagnitude > 25f) && VssAccessStand.HasWardAccess(actor, ((Component)this).transform.position)) { VssContext context = new VssContext { Stand = vssAccessStand, Player = val, Actor = actor, Target = _view, Mode = VssAccessMode.Station }; if (!Run(context, vssRefillKind, num, delegate(int count, string message) { if ((Object)(object)_view != (Object)null && _view.IsValid()) { _view.InvokeRPC(sender, "VSS_RefillResult", new object[3] { token, count, message }); } })) { _view.InvokeRPC(sender, "VSS_RefillResult", new object[3] { token, 0, "Storage is empty or busy." }); } } } private void Reply(long sender, string token, int amount, string message) { if (sender == _expectedOwner && !(token != _request)) { _request = null; Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)1, (amount > 0) ? $"Added {amount} from storage." : message, 0, (Sprite)null, false); } } } private bool Run(VssContext context, VssRefillKind kind, int maximum, Action<int, string> complete) { if (VssTransfer.Busy || !context.Valid() || Room(kind) <= 0) { return false; } bool automatic = context.Mode == VssAccessMode.Automatic; Container source = ((IEnumerable<Container>)VssStorageScanner.Sources(context)).FirstOrDefault((Func<Container, bool>)((Container c) => c.GetInventory().GetAllItems().Any((ItemData i) => Allows(i, kind, automatic)))); if ((Object)(object)source == (Object)null) { return false; } int added = 0; return VssTransactions.Start(context, (IEnumerable<Container>)(object)new Container[1] { source }, () => (Object)(object)this != (Object)null && (Object)(object)_view != (Object)null && _view.IsValid() && _view.IsOwner(), delegate { //IL_0143: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = source.GetInventory(); foreach (ItemData item in inventory.GetAllItems().ToList()) { for (; added < maximum; added++) { if (Room(kind) <= 0) { break; } if (!inventory.ContainsItem(item)) { break; } if (!Allows(item, kind, automatic)) { break; } if (automatic && !context.Valid()) { break; } if (!SupplyOne(inventory, item, kind, automatic)) { break; } } if (added >= maximum || Room(kind) <= 0) { break; } } if (added > 0) { VssGame.ForceSend(ZDOMan.instance, _view.GetZDO().m_uid); } return added > 0; }, delegate(string error) { complete?.Invoke(added, error); }); } internal static void Tick() { //IL_00eb: Unknown result type (might be due to invalid IL or missing references) if (!VssSettings.Ready || VssTransfer.Busy || Time.unscaledTime < _nextAuto || (Object)(object)ZNetScene.instance == (Object)null) { return; } _nextAuto = Time.unscaledTime + 1f; Instances.RemoveWhere((VssRefillBridge s) => (Object)(object)s == (Object)null); List<VssRefillBridge> list = Instances.Where((VssRefillBridge s) => (Object)(object)s._view != (Object)null && s._view.IsValid() && s._view.IsOwner() && ((Component)s).gameObject.activeInHierarchy && s.AutoRefill && s.CanAutoRefill).OrderBy<VssRefillBridge, string>((VssRefillBridge s) => ((object)Unsafe.As<ZDOID, ZDOID>(ref s._view.GetZDO().m_uid)/*cast due to .constrained prefix*/).ToString(), StringComparer.Ordinal).ToList(); for (int num = 0; num < list.Count; num++) { int num2 = (_cursor + num) % list.Count; VssRefillBridge vssRefillBridge = list[num2]; VssAccessStand vssAccessStand = VssAccessStand.FindAutomatic(((Component)vssRefillBridge).transform.position); if ((Object)(object)vssAccessStand == (Object)null || !vssAccessStand.AutoRefill) { continue; } VssContext context = new VssContext { Stand = vssAccessStand, Actor = ((Component)vssAccessStand).GetComponent<Piece>().GetCreator(), Target = vssRefillBridge._view, Mode = VssAccessMode.Automatic }; VssRefillKind[] array = new VssRefillKind[2] { VssRefillKind.Fuel, VssRefillKind.Input }; foreach (VssRefillKind vssRefillKind in array) { if ((!((Object)(object)vssRefillBridge._cooking != (Object)null) || vssRefillKind != VssRefillKind.Input) && vssRefillBridge.Run(context, vssRefillKind, 50, null)) { _cursor = (num2 + 1) % list.Count; return; } } } } internal static VssRefillBridge From(Component station) { ZNetView val = station.GetComponent<ZNetView>() ?? station.GetComponentInParent<ZNetView>(); return ((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<VssRefillBridge>() : null; } } public sealed class VssCollectOutput : MonoBehaviour { internal const string SourceKey = "vss_output_machine"; private static readonly Dictionary<ZDOID, HashSet<VssCollectOutput>> Outputs = new Dictionary<ZDOID, HashSet<VssCollectOutput>>(); internal static VssRefillBridge Spawning; internal ItemDrop Item; private ZNetView _view; private ZDOID _source; private static readonly Action<ItemDrop> Load = AccessTools.MethodDelegate<Action<ItemDrop>>(AccessTools.Method(typeof(ItemDrop), "Load", (Type[])null, (Type[])null), (object)null, true); private static readonly Action<ItemDrop> Save = AccessTools.MethodDelegate<Action<ItemDrop>>(AccessTools.Method(typeof(ItemDrop), "Save", (Type[])null, (Type[])null), (object)null, true); private void Awake() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) Item = ((Component)this).GetComponent<ItemDrop>(); _view = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)_view == (Object)null || !_view.IsValid()) { return; } _source = _view.GetZDO().GetZDOID("vss_output_machine"); if (!(_source == ZDOID.None)) { if (!Outputs.TryGetValue(_source, out var value)) { value = (Outputs[_source] = new HashSet<VssCollectOutput>()); } value.Add(this); } } private void OnDestroy() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) if (Outputs.TryGetValue(_source, out var value)) { value.Remove(this); if (value.Count == 0) { Outputs.Remove(_source); } } } internal static VssCollectOutput[] For(ZDOID id) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) HashSet<VssCollectOutput> value; return Outputs.TryGetValue(id, out value) ? value.ToArray() : Array.Empty<VssCollectOutput>(); } internal static bool Tagged(ItemDrop item) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) int result; if ((Object)(object)item != (Object)null) { ZNetView component = ((Component)item).GetComponent<ZNetView>(); if (component != null && component.IsValid()) { result = ((component.GetZDO().GetZDOID("vss_output_machine") != ZDOID.None) ? 1 : 0); goto IL_0038; } } result = 0; goto IL_0038; IL_0038: return (byte)result != 0; } internal static ItemDrop StackCandidate(ItemDrop item) { return Tagged(item) ? null : item; } internal static void Track(ItemDrop item) { if (Tagged(item) && (Object)(object)((Component)item).GetComponent<VssCollectOutput>() == (Object)null) { ((Component)item).gameObject.AddComponent<VssCollectOutput>(); } } internal bool Eligible(VssRefillBridge machine) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_0074: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Item == (Object)null) && ((Component)this).gameObject.activeInHierarchy && !((Object)(object)_view == (Object)null) && _view.IsValid() && !(_view.GetZDO().GetZDOID("vss_output_machine") != _source)) { Vector3 val = ((Component)this).transform.position - ((Component)machine).transform.position; if (!(((Vector3)(ref val)).sqrMagnitude > 100f)) { if (!_view.IsOwner()) { Item.RequestOwn(); return false; } Load(Item); return Item.m_itemData.m_stack > 0; } } return false; } internal bool Commit(VssRefillBridge machine, VssContext context, Inventory destination) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) if (!context.Valid() || !Eligible(machine)) { return false; } Inventory val = new Inventory("VSS machine output", (Sprite)null, 1, 1); val.GetAllItems().Add(Item.m_itemData); int num = VssInventoryOps.Move(val, destination, Item.m_itemData, Item.m_itemData.m_stack); if (num <= 0) { return false; } if (Item.m_itemData.m_stack <= 0) { _view.Destroy(); } else { Save(Item); VssGame.ForceSend(ZDOMan.instance, _view.GetZDO().m_uid); } return true; } } [HarmonyPatch(typeof(Smelter), "Spawn")] internal static class VssSmelterOutputPatch { private static void Prefix(Smelter __instance, out VssRefillBridge __state) { __state = VssCollectOutput.Spawning; VssCollectOutput.Spawning = VssRefillBridge.From((Component)(object)__instance); } private static Exception Finalizer(Exception __exception, VssRefillBridge __state) { VssCollectOutput.Spawning = __state; return __exception; } } [HarmonyPatch(typeof(ItemDrop), "OnCreateNew", new Type[] { typeof(ItemDrop), typeof(bool) })] internal static class VssOutputCreatedPatch { private static void Postfix(ItemDrop item) { //IL_008b: Unknown result type (might be due to invalid IL or missing references) VssRefillBridge spawning = VssCollectOutput.Spawning; ZNetView val = (((Object)(object)spawning != (Object)null) ? ((Component)spawning).GetComponent<ZNetView>() : null); ZNetView val2 = (((Object)(object)item != (Object)null) ? ((Component)item).GetComponent<ZNetView>() : null); if (!((Object)(object)spawning == (Object)null) && spawning.AutoCollect && !((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner() && !((Object)(object)val2 == (Object)null) && val2.IsValid() && val2.IsOwner()) { val2.GetZDO().Set("vss_output_machine", val.GetZDO().m_uid); ItemDrop.SaveToZDO(item.m_itemData, val2.GetZDO(), -1); VssCollectOutput.Track(item); } } } [HarmonyPatch(typeof(ItemDrop), "Awake")] internal static class VssOutputLoadedPatch { private static void Postfix(ItemDrop __instance) { VssCollectOutput.Track(__instance); } } [HarmonyPatch(typeof(ItemDrop), "Load")] internal static class VssOutputRefreshedPatch { private static void Postfix(ItemDrop __instance) { VssCollectOutput.Track(__instance); } } [HarmonyPatch(typeof(ItemDrop), "SlowUpdate")] internal static class VssOutputOwnershipPatch { private static void Prefix(ItemDrop __instance) { VssCollectOutput.Track(__instance); } } [HarmonyPatch(typeof(ItemDrop), "AutoStackItems")] internal static class VssOutputStackPatch { private static bool Prefix(ItemDrop __instance) { return !VssCollectOutput.Tagged(__instance); } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { foreach (CodeInstruction instruction in instructions) { yield return instruction; object operand = instruction.operand; if (operand is MethodInfo { Name: "GetComponent" } method && method.ReturnType == typeof(ItemDrop)) { yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(VssCollectOutput), "StackCandidate", (Type[])null, (Type[])null)); } } } } internal static class VssCollectTests { internal static void Run(Action<bool, string> check, ZNetScene vanilla, GameObject root, ZDOMan manager, ZNetScene scene, Player actor, VssAccessStand controller) { //IL_000f: 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) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Expected O, but got Unknown //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_047f: Unknown result type (might be due to invalid IL or missing references) //IL_04c0: Unknown result type (might be due to invalid IL or missing references) //IL_04cb: Unknown result type (might be due to invalid IL or missing references) //IL_04d2: Expected O, but got Unknown //IL_04dd: Unknown result type (might be due to invalid IL or missing references) //IL_04f7: Unknown result type (might be due to invalid IL or missing references) //IL_0501: Expected O, but got Unknown //IL_05d2: Unknown result type (might be due to invalid IL or missing references) //IL_05d9: Expected O, but got Unknown //IL_077a: Unknown result type (might be due to invalid IL or missing references) //IL_0784: Expected O, but got Unknown //IL_0855: Unknown result type (might be due to invalid IL or missing references) //IL_085c: Expected O, but got Unknown check(((object)VssConfig.MigrateRefillKey(new KeyboardShortcut((KeyCode)103, Array.Empty<KeyCode>()))/*cast due to .constrained prefix*/).Equals((object)new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>())), "legacy G default migrates to F6"); check(((object)VssConfig.MigrateRefillKey(new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()))/*cast due to .constrained prefix*/).Equals((object)new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>())), "custom refill key remains intact"); check(((object)VssConfig.MigrateRefillKey(new KeyboardShortcut((KeyCode)103, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }))/*cast due to .constrained prefix*/).Equals((object)new KeyboardShortcut((KeyCode)103, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 })), "custom modified G shortcut remains intact"); ZDO zDO = ((Component)controller).GetComponent<ZNetView>().GetZDO(); zDO.Set(ZDOVars.s_creator, actor.GetPlayerID()); check(!controller.AutoCollect, "collection master starts Off independently of refill"); controller.ToggleAutoCollect(actor); check(controller.AutoCollect && controller.AutoRefill, "native collection master RPC does not alter refill master"); string[] array = new string[7] { "charcoal_kiln", "smelter", "blastfurnace", "windmill", "piece_spinningwheel", "piece_cookingstation", "piece_oven" }; foreach (string text in array) { check(VssRefillBridge.CollectSupportedPrefab(StringExtensionMethods.GetStableHashCode(text)), "native collection machine supported: " + text); } check(!VssRefillBridge.CollectSupportedPrefab(StringExtensionMethods.GetStableHashCode("piece_groundtorch")), "lamps offer only refill, not collection"); CookingStation component = vanilla.GetPrefab("piece_cookingstation").GetComponent<CookingStation>(); GameObject val = new GameObject("VSS isolated collector grill"); val.transform.SetParent(root.transform); ZNetView val2 = val.AddComponent<ZNetView>(); CookingStation val3 = val.AddComponent<CookingStation>(); ZDO val4 = manager.CreateNewZDO(Vector3.zero, StringExtensionMethods.GetStableHashCode("piece_cookingstation")); val4.SetPrefab(StringExtensionMethods.GetStableHashCode("piece_cookingstation")); AccessTools.Field(typeof(ZNetView), "m_zdo").SetValue(val2, val4); AccessTools.Field(typeof(CookingStation), "m_nview").SetValue(val3, val2); scene.AddInstance(val4, val2); val3.m_conversion = component.m_conversion; val3.m_overCookedItem = component.m_overCookedItem; val3.m_slots = (Transform[])(object)new Transform[2] { val.transform, val.transform }; val3.m_useFuel = false; VssRefillBridge vssRefillBridge = val.AddComponent<VssRefillBridge>(); AccessTools.Field(typeof(VssRefillBridge), "_view").SetValue(vssRefillBridge, val2); AccessTools.Field(typeof(VssRefillBridge), "_cooking").SetValue(vssRefillBridge, val3); AccessTools.Method(typeof(VssRefillBridge), "RegisterRpc", (Type[])null, (Type[])null).Invoke(vssRefillBridge, null); int visuals = 0; val2.Register<int, string>("RPC_SetSlotVisual", (Action<long, int, string>)delegate { visuals++; }); check(!vssRefillBridge.AutoCollect && vssRefillBridge.CanAutoCollect && !vssRefillBridge.CanAutoRefill, "wood grill supports independent collection without an oven fuel control"); check(vssRefillBridge.ToggleAutoCollect(actor) && vssRefillBridge.AutoCollect && VssRefillBridge.CollectEnabled(zDO, val4), "native authenticated object collection toggle works"); VssContext vssContext = new VssContext { Stand = controller, Actor = actor.GetPlayerID(), Target = val2, Mode = VssAccessMode.AutomaticCollect }; check(vssContext.Valid() && VssContext.Authorize(ZDOMan.GetSessionID(), actor.GetPlayerID(), zDO, val4, VssAccessMode.AutomaticCollect), "owner-side collection authorization uses separate saved switches"); check(!VssContext.Authorize(ZDOMan.GetSessionID() + 1, actor.GetPlayerID(), zDO, val4, VssAccessMode.AutomaticCollect), "remote non-owner cannot collect output"); Action<VssRefillBridge, long, long, bool, string> action = AccessTools.MethodDelegate<Action<VssRefillBridge, long, long, bool, string>>(AccessTools.Method(typeof(VssRefillBridge), "SetAutoCollect", (Type[])null, (Type[])null), (object)null, true); action(vssRefillBridge, ZDOMan.GetSessionID() + 1, actor.GetPlayerID(), arg4: false, "spoofed"); check(vssRefillBridge.AutoCollect, "spoofed toggle cannot turn off collection"); ((Component)actor).transform.position = new Vector3(0f, 0f, 6f); action(vssRefillBridge, ZDOMan.GetSessionID(), actor.GetPlayerID(), arg4: false, "too-far"); check(vssRefillBridge.AutoCollect, "collection toggle requires interaction distance"); ((Component)actor).transform.position = Vector3.zero; ZPackage val5 = new ZPackage(); val4.Serialize(val5); ZDO val6 = manager.CreateNewZDO(Vector3.zero, 88888); val6.Deserialize(new ZPackage(val5.GetArray())); check(val6.GetBool("vss_object_auto_collect", false), "collection switch survives native save replication"); ItemDrop to = val3.m_conversion[0].m_to; ItemDrop val7 = val3.m_conversion[0].m_from; Dictionary<int, GameObject> dictionary = (Dictionary<int, GameObject>)AccessTools.Field(typeof(ObjectDB), "m_itemByHash").GetValue(ObjectDB.instance); dictionary[StringExtensionMethods.GetStableHashCode(((Object)to).name)] = ((Component)to).gameObject; dictionary[StringExtensionMethods.GetStableHashCode(((Object)val3.m_overCookedItem).name)] = ((Component)val3.m_overCookedItem).gameObject; val4.Set("slot0", ((Object)val7).name); val4.Set("slotstatus0", 0); Inventory val8 = new Inventory("VSS cooked-output destination", (Sprite)null, 1, 1); check(!vssRefillBridge.CommitCooked(vssContext, 0, val8) && val8.NrOfItems() == 0, "uncooked food cannot be collected"); val4.Set("slot0", ((Object)to).name); val4.Set("slotstatus0", 1); val4.Set(ZDOVars.s_cheatedQueued, true); string name; int status; bool cheated; ItemData val9 = vssRefillBridge.CookedOutput(0, out name, out status, out cheated); val9.m_stack = val9.m_shared.m_maxStackSize - 1; val8.GetAllItems().Add(val9); check(vssRefillBridge.CommitCooked(vssContext, 0, val8) && val9.m_stack == val9.m_shared.m_maxStackSize && val4.GetString("slot0", "") == "" && visuals == 1, "finished food stacks exactly once before native slot and visuals clear"); check(val9.m_cheated && val9.m_worldLevel == Game.m_worldLevel, "cooked output preserves native cheat and world flags"); check(!vssRefillBridge.CommitCooked(vssContext, 0, val8), "cleared cooking slot cannot duplicate food"); val4.Set("slot0", ((Object)to).name); val4.Set("slotstatus0", 1); check(!vssRefillBridge.CommitCooked(vssContext, 0, val8) && val4.GetString("slot0", "") == ((Object)to).name, "full storage leaves finished food on the grill"); controller.ToggleAutoCollect(actor); check(!vssContext.Valid() && !vssRefillBridge.CommitCooked(vssContext, 0, new Inventory("empty", (Sprite)null, 1, 1)) && vssRefillBridge.AutoCollect, "master Off cancels pending collection while retaining object choice"); check(vssRefillBridge.HoverHint(actor).Contains("F7") && vssRefillBridge.HoverHint(actor).Contains("VSS auto-collect: On") && vssRefillBridge.HoverHint(actor).Contains("master Off"), "grill hover explains separate F7 collection master"); controller.ToggleAutoCollect(actor); ItemDrop[] array2 = (ItemDrop[])(object)new ItemDrop[2] { to, val3.m_overCookedItem }; ItemDrop[] array3 = array2; foreach (ItemDrop val10 in array3) { val4.Set("slot0", ((Object)val10).name); val4.Set("slotstatus0", ((Object)(object)val10 == (Object)(object)to) ? 1 : 2); Inventory val11 = new Inventory("VSS cooked or already burnt output", (Sprite)null, 1, 1); check(vssRefillBridge.CommitCooked(vssContext, 0, val11) && val11.NrOfItems() == 1 && val11.GetAllItems()[0].m_shared.m_name == val10.m_itemData.m_shared.m_name, "native cooked/burnt output identity is preserved: " + ((Object)val10).name); } LeasedCooking(check, manager, val4, vssRefillBridge, vssContext, to); OutputDrop(check, root, manager, scene, vanilla, controller, actor); controller.ToggleAutoCollect(actor); check(!controller.AutoCollect && controller.AutoRefill, "collection master restores Off without changing refill"); } private static void LeasedCooking(Action<bool, string> check, ZDOMan manager, ZDO grillZdo, VssRefillBridge bridge, VssContext context, ItemDrop cooked) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Expected O, but got Unknown //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Expected O, but got Unknown List<Container> list = new List<Container>(); try { for (int i = 0; i < 2; i++) { GameObject val = new GameObject("piece_chest_vss_collection_test"); val.SetActive(false); val.transform.position = new Vector3((float)(i + 1), 0f, 0f); ZNetView obj = val.AddComponent<ZNetView>(); ZDO val2 = manager.CreateNewZDO(val.transform.position, 44444); val2.SetPrefab(44444); AccessTools.Field(typeof(ZNetView), "m_zdo").SetValue(obj, val2); Container val3 = val.AddComponent<Container>(); val3.m_width = 1; val3.m_height = 1; list.Add(val3); ZNetView.m_initZDO = val2; val.SetActive(true); } ItemData val4 = cooked.m_itemData.Clone(); val4.m_dropPrefab = ((Component)cooked).gameObject; val4.m_worldLevel = (byte)Game.m_worldLevel; val4.m_stack = val4.m_shared.m_maxStackSize - 1; list[1].GetInventory().GetAllItems().Add(val4); VssGame.Notify(list[1].GetInventory()); grillZdo.Set("slot0", ((Object)cooked).name); grillZdo.Set("slotstatus0", 1); check(bridge.RunCollect(context), "collection starts the real exclusive chest lease transaction"); check(!VssTransactions.Busy && list[1].GetInventory().CountItems(val4.m_shared.m_name, -1, true) == val4.m_shared.m_maxStackSize && list[0].GetInventory().NrOfItems() == 0 && grillZdo.GetString("slot0", "") == "", "leased collection stacks in a farther existing stack before a nearer empty chest"); check(!VssChestBridge.IsLeased(VssGame.View.Invoke(list[1]).GetZDO()), "collection releases its chest lease after commit"); Inventory val5 = new Inventory("VSS saved collection", (Sprite)null, 1, 1); val5.Load(new ZPackage(VssGame.View.Invoke(list[1]).GetZDO().GetByteArray(ZDOVars.s_items, (byte[])null))); check(val5.CountItems(val4.m_shared.m_name, -1, true) == val4.m_shared.m_maxStackSize, "leased collected food persists in native chest save"); grillZdo.Set("slot0", ((Object)cooked).name); grillZdo.Set("slotstatus0", 1); list[0].SetInUse(true); check(!bridge.RunCollect(context) && grillZdo.GetString("slot0", "") == ((Object)cooked).name, "busy and full destinations leave output untouched"); list[0].SetInUse(false); } finally { foreach (Container item in list) { VssStorageScanner.Containers.Remove(item); Object.DestroyImmediate((Object)(object)((Component)item).gameObject); } } } private static void OutputDrop(Action<bool, string> check, GameObject root, ZDOMan manager, ZNetScene scene, ZNetScene vanilla, VssAccessStand controller, Player actor) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Expected O, but got Unknown //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Expected O, but got Unknown //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Expected O, but got Unknown //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_03b7: Unknown result type (might be due to invalid IL or missing references) //IL_03be: Expected O, but got Unknown //IL_047b: Unknown result type (might be due to invalid IL or missing references) //IL_0485: Expected O, but got Unknown //IL_04b6: Unknown result type (might be due to invalid IL or missing references) //IL_04d0: Unknown result type (might be due to invalid IL or missing references) //IL_04da: Expected O, but got Unknown //IL_04ef: Unknown result type (might be due to invalid IL or missing references) //IL_0502: Unknown result type (might be due to invalid IL or missing references) //IL_0509: Expected O, but got Unknown //IL_05b4: Unknown result type (might be due to invalid IL or missing references) //IL_0611: Unknown result type (might be due to invalid IL or missing references) //IL_0616: Unknown result type (might be due to invalid IL or missing references) //IL_06d3: Unknown result type (might be due to invalid IL or missing references) //IL_06da: Expected O, but got Unknown GameObject val = new GameObject("VSS isolated collector kiln"); val.transform.SetParent(root.transform); ZNetView val2 = val.AddComponent<ZNetView>(); Smelter val3 = val.AddComponent<Smelter>(); ZDO val4 = manager.CreateNewZDO(Vector3.zero, StringExtensionMethods.GetStableHashCode("charcoal_kiln")); val4.SetPrefab(StringExtensionMethods.GetStableHashCode("charcoal_kiln")); AccessTools.Field(typeof(ZNetView), "m_zdo").SetValue(val2, val4); AccessTools.Field(typeof(Smelter), "m_nview").SetValue(val3, val2); scene.AddInstance(val4, val2); val3.m_conversion = vanilla.GetPrefab("charcoal_kiln").GetComponent<Smelter>().m_conversion; VssRefillBridge vssRefillBridge = val.AddComponent<VssRefillBridge>(); AccessTools.Field(typeof(VssRefillBridge), "_view").SetValue(vssRefillBridge, val2); AccessTools.Field(typeof(VssRefillBridge), "_smelter").SetValue(vssRefillBridge, val3); val4.Set("vss_object_auto_collect", true); ItemDrop to = val3.m_conversion[0].m_to; GameObject val5 = new GameObject(((Object)to).name); val5.SetActive(false); ZNetView val6 = val5.AddComponent<ZNetView>(); ZDO val7 = manager.CreateNewZDO(Vector3.zero, StringExtensionMethods.GetStableHashCode(((Object)to).name)); val7.SetPrefab(StringExtensionMethods.GetStableHashCode(((Object)to).name)); AccessTools.Field(typeof(ZNetView), "m_zdo").SetValue(val6, val7); val5.SetActive(false); ItemDrop val8 = val5.AddComponent<ItemDrop>(); val8.m_itemData = to.m_itemData.Clone(); val8.m_itemData.m_dropPrefab = ((Component)to).gameObject; val8.m_itemData.m_stack = 7; AccessTools.Field(typeof(ItemDrop), "m_nview").SetValue(val8, val6); VssCollectOutput.Spawning = vssRefillBridge; ItemDrop.OnCreateNew(val8, true); VssCollectOutput.Spawning = null; check(VssCollectOutput.Tagged(val8) && val7.GetZDOID("vss_output_machine") == val4.m_uid, "native output creation tags exact source machine"); check((Object)(object)VssCollectOutput.StackCandidate(val8) == (Object)null, "ordinary loose piles cannot absorb tagged output"); VssCollectOutput component = ((Component)val8).GetComponent<VssCollectOutput>(); AccessTools.Method(typeof(VssCollectOutput), "Awake", (Type[])null, (Type[])null).Invoke(component, null); check(VssCollectOutput.For(val4.m_uid).Contains(component), "output provenance is indexed by machine without scene searches"); GameObject val9 = new GameObject("ordinary untagged coal"); val9.transform.SetParent(root.transform); ItemDrop val10 = val9.AddComponent<ItemDrop>(); check((Object)(object)VssCollectOutput.StackCandidate(val10) == (Object)(object)val10, "unrelated loose loot retains vanilla stacking"); ZPackage val11 = new ZPackage(); val7.Serialize(val11); ZDO val12 = manager.CreateNewZDO(Vector3.zero, 99999); val12.Deserialize(new ZPackage(val11.GetArray())); check(val12.GetZDOID("vss_output_machine") == val4.m_uid, "output provenance survives native save replication"); Dictionary<int, GameObject> dictionary = (Dictionary<int, GameObject>)AccessTools.Field(typeof(ObjectDB), "m_itemByHash").GetValue(ObjectDB.instance); dictionary[StringExtensionMethods.GetStableHashCode(((Object)to).name)] = ((Component)to).gameObject; ((Behaviour)val8).enabled = false; ZNetView.m_initZDO = val7; val5.SetActive(true); scene.AddInstance(val7, val6); try { VssContext context = new VssContext { Stand = controller, Actor = actor.GetPlayerID(), Target = val2, Mode = VssAccessMode.AutomaticCollect }; Inventory val13 = new Inventory("VSS output chest", (Sprite)null, 1, 1); ItemData val14 = val8.m_itemData.Clone(); val14.m_stack = val14.m_shared.m_maxStackSize - 2; val13.GetAllItems().Add(val14); check(component.Commit(vssRefillBridge, context, val13) && val14.m_stack == val14.m_shared.m_maxStackSize && val8.m_itemData.m_stack == 5, "machine output deposits only available capacity and leaves remaining loose stack"); check(!component.Commit(vssRefillBridge, context, val13) && val8.m_itemData.m_stack == 5, "full chest cannot lose or duplicate remaining output"); val4.Set("vss_object_auto_collect", false); check(!component.Commit(vssRefillBridge, context, new Inventory("empty", (Sprite)null, 1, 1)), "object Off cancels pending output deposit"); val4.Set("vss_object_auto_collect", true); val5.transform.position = new Vector3(11f, 0f, 0f); check(!component.Commit(vssRefillBridge, context, new Inventory("empty", (Sprite)null, 1, 1)), "output moved away from its machine is not collected"); val5.transform.position = Vector3.zero; Inventory val15 = new Inventory("VSS final output destination", (Sprite)null, 1, 1); check(component.Commit(vssRefillBridge, context, val15) && val15.CountItems(to.m_itemData.m_shared.m_name, -1, true) == 5, "remaining output moves exactly once before native world drop is destroyed"); check(!val6.IsValid(), "depleted output no longer has an active native network view"); } finally { Object.DestroyImmediate((Object)(object)val5); } val3.m_outputPoint = val.transform; Action<Smelter, string, int> action = AccessTools.MethodDelegate<Action<Smelter, string, int>>(AccessTools.Method(typeof(Smelter), "Spawn", (Type[])null, (Type[])null), (object)null, true); action(val3, ((Object)val3.m_conversion[0].m_from).name, 3); VssCollectOutput vssCollectOutput = VssCollectOutput.For(val4.m_uid).Single(); GameObject val16 = null; try { check(vssCollectOutput.Item.m_itemData.m_stack == 3 && !vssCollectOutput.Item.m_itemData.m_cheated && (Object)(object)VssCollectOutput.Spawning == (Object)null, "actual native smelter Spawn is captured with exact stack and restored scope"); val16 = Object.Instantiate<GameObject>(((Component)to).gameObject, Vector3.zero, Quaternion.identity); ItemDrop component2 = val16.GetComponent<ItemDrop>(); component2.m_itemData.m_stack = 4; ItemDrop.OnCreateNew(component2, false); ItemDrop.SaveToZDO(component2.m_itemData, ((Component)component2).GetComponent<ZNetView>().GetZDO(), -1); Physics.SyncTransforms(); Action<ItemDrop> action2 = AccessTools.MethodDelegate<Action<ItemDrop>>(AccessTools.Method(typeof(ItemDrop), "AutoStackItems", (Type[])null, (Type[])null), (object)null, true); action2(component2); action2(vssCollectOutput.Item); check(component2.m_itemData.m_stack == 4 && vssCollectOutput.Item.m_itemData.m_stack == 3, "patched native ground auto-stack keeps machine output separate from unrelated loose loot"); Inventory val17 = new Inventory("VSS native produced output", (Sprite)null, 1, 1); VssContext context2 = new VssContext { Stand = controller, Actor = actor.GetPlayerID(), Target = val2, Mode = VssAccessMode.AutomaticCollect }; check(vssCollectOutput.Commit(vssRefillBridge, context2, val17) && val17.CountItems(to.m_itemData.m_shared.m_name, -1, true) == 3