using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using Zen; using Zen.Lib; using Zen.Lib.Config; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ZenDistributor")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ZenDistributor")] [assembly: AssemblyCopyright("Copyright \ufffd 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("0.0.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ZenDistributor { [HarmonyPatch] internal class CartPatch { [HarmonyPrefix] [HarmonyPatch(typeof(Vagon), "CanAttach")] private static void Vagon_CanAttach(Vagon __instance, GameObject go, ref bool __result, ref bool __runOriginal) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) if (Configs.SnapToPlayer.Value) { Catapult val = default(Catapult); if (((Component)__instance).TryGetComponent(ref val) && val.m_lockedLegs) { __result = false; __runOriginal = false; } else if (Configs.IgnoreUpsideDown.Value || !(((Component)__instance).transform.up.y < 0.1f)) { Humanoid component = go.GetComponent(); bool flag = MathExt.AlignmentRatioTo(((Component)__instance).transform, ((Component)component).transform.position) > 0f; __result = !Object.op_Implicit((Object)(object)component) || ((flag & !((Character)component).IsTeleporting()) && !((Character)component).InDodge() && !((Character)component).IsBlocking() && !((Character)component).IsCrouching() && !((Character)component).InEmote() && !((Character)component).IsDrawingBow() && !ZInput.GetButtonDown("JoyButtonB") && MathExt.DistanceTo((MonoBehaviour)(object)component, ((Component)__instance).transform.position) < Configs.AttachDistance.Value); __runOriginal = false; } } } } internal static class Configs { public static readonly ConfigEntry AllowedDistributors; public static readonly ConfigEntry AllowedContainers; public static readonly ConfigEntry MaxRange; public static readonly ConfigEntry HighlightDuration; public static readonly ConfigEntry SnapToPlayer; public static readonly ConfigEntry AttachDistance; public static readonly ConfigEntry IgnoreUpsideDown; static Configs() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_0046: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown StringList val = new StringList(); ((List)val).Add("Cart"); ((List)val).Add("Karve"); ((List)val).Add("VikingShip"); ((List)val).Add("VikingShip_Ashlands"); AllowedDistributors = Config.Define(true, "General", "Allowed Distributor Prefabs", val, "Comma separated list of prefabs that can be used as a distribution source.\r\nThey must have a Container component or they will not work."); AllowedContainers = Config.Define(true, "General", "Allowed Container Prefabs", new StringList(Config.ContainersCommon.Append("Cart")), "Only distribute into these container prefab names.\r\nThey must have a Container component or they will not work."); MaxRange = Config.Define(true, "General", "Max Distribution Range", 10f, Config.AcceptRange(3f, 25f), "How far away to search for containers from the cart's location"); HighlightDuration = Config.Define(true, "General", "Higlight Duration", 5f, Config.AcceptRange(0f, 30f), "Highlight duration for chests that had items distributed into them (in seconds)"); SnapToPlayer = Config.Define(true, "Cart", "Snap To Player", true, "Attach the cart to the player much more easily. (Vanilla: false)"); AttachDistance = Config.Define(true, "Cart", "Attach Distance", 7f, Config.AcceptRange(1f, 10f), "Minimum distance the player must be from the cart in order to attach it. (Vanilla: 2)"); IgnoreUpsideDown = Config.Define(true, "Cart", "Ignore Upside Down", true, "The cart will not prevent attach when upside down. (Vanilla: false)"); } } [HarmonyPatch] internal static class Distribute { [CompilerGenerated] private sealed class <>c__DisplayClass12_0 { public Container source; public Func <>9__0; internal float b__0(Container c) { return MathExt.DistanceTo((MonoBehaviour)(object)c, (MonoBehaviour)(object)source); } } [CompilerGenerated] private sealed class d__12 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Container source; public IEnumerable nearbyContainers; private <>c__DisplayClass12_0 <>8__1; public bool isSourceShip; private int 5__2; private IEnumerator <>7__wrap2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__12(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>8__1 = null; <>7__wrap2 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>8__1 = new <>c__DisplayClass12_0(); <>8__1.source = source; 5__2 = <>8__1.source.GetInventory().CountItems((string)null, -1, true); <>7__wrap2 = nearbyContainers.OrderBy((Container c) => MathExt.DistanceTo((MonoBehaviour)(object)c, (MonoBehaviour)(object)<>8__1.source)).GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap2.MoveNext()) { Container current = <>7__wrap2.Current; if (Object.op_Implicit((Object)(object)current) && current.m_nview.IsValid() && !current.IsInUse()) { Logging.Info((object)("Processing target: " + ((Object)current).name), 0); PendingContainersRPC.Add(current, <>8__1.source); Logging.Debug((object)$"Added container to rpc pending list, count: {PendingContainersRPC.Count}", 0); current.StackAll(); if (isSourceShip && current.IsCart(out Vagon cart) && !cart.InUse() && current.GetInventory().HaveEmptySlot()) { current.m_nview.ClaimOwnership(); current.GetInventory().MoveAll(<>8__1.source.GetInventory()); current.ShowHighlight(); } <>2__current = null; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap2 = null; int num = 5__2 - <>8__1.source.GetInventory().CountItems((string)null, -1, true); if (num > 0) { ((Character)Player.m_localPlayer).Message((MessageType)2, $"$msg_stackall {num}", 0, (Sprite)null); } return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap2 != null) { <>7__wrap2.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public const float Cooldown = 3f; private static float _lastDistributeTime; private static readonly Dictionary PendingContainersRPC = new Dictionary(); private static bool IsReady { get { if (Time.time > _lastDistributeTime + 3f) { return PendingContainersRPC.Count == 0; } return false; } } private static bool IsCart(this Container c) { Vagon cart; return c.IsCart(out cart); } private static bool IsCart(this Container c, out Vagon cart) { return Object.op_Implicit((Object)(object)(cart = c.m_wagon)); } private static bool IsShip(this Container c) { return Object.op_Implicit((Object)(object)((Component)c).GetComponentInParent()); } private static bool TryGetPiece(this Container c, out Piece? piece) { return Object.op_Implicit((Object)(object)(piece = (Object.op_Implicit((Object)(object)c.m_piece) ? c.m_piece : ((Component)c).GetComponentInParent()))); } private static void ShowHighlight(this Container c) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (c.TryGetPiece(out Piece piece)) { Highlight.Select(piece, Configs.HighlightDuration.Value, false, default(Color), (Action)null); } } private static IEnumerable GetNearbyContainers(this Container self, float range) { Container self2 = self; return from container in GameObjectExt.GetNearbyPiecesXZ(((Component)self2).gameObject, range) where Configs.AllowedContainers.Value.Contains(container.m_nview.GetPrefabName(), true) where WardAccessExt.CanAccessWard(container, false) orderby MathExt.DistanceTo((MonoBehaviour)(object)container, (MonoBehaviour)(object)self2) select container; } private static void SendFrom(Container source) { if (!IsReady) { Logging.Warning((object)"Cooldown has not elapsed, too soon to distribute again", 0); return; } _lastDistributeTime = Time.time; if (PendingContainersRPC.Count != 0) { Logging.Error((object)"RPC containers pending stacking list is not empty, rpc send/recv mismatch?", (ushort)0); PendingContainersRPC.Clear(); } if (Logging.IsEnabled) { Logging.Info((object)("Inventory Items: " + GeneralExtensions.Join((IEnumerable)source.GetInventory().GetAllItems(), (Func)((ItemData item) => ItemDataExt.GetPrefabName(item)), ", ")), 0); } Highlight.None(); IEnumerable nearbyContainers = source.GetNearbyContainers(Configs.MaxRange.Value); bool isSourceShip = source.IsShip(); ((MonoBehaviour)source).StartCoroutine(ProcessSend(source, nearbyContainers, isSourceShip)); } [IteratorStateMachine(typeof(d__12))] private static IEnumerator ProcessSend(Container source, IEnumerable nearbyContainers, bool isSourceShip) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__12(0) { source = source, nearbyContainers = nearbyContainers, isSourceShip = isSourceShip }; } private static bool IsDistributor(this Container container) { if (Object.op_Implicit((Object)(object)container.m_nview)) { return Configs.AllowedDistributors.Value.Contains(container.m_nview.GetPrefabName(), true); } return false; } private static bool IsValidSource(Container container) { if (!IsReady) { return false; } if (((List)(object)Configs.AllowedContainers.Value).Count == 0) { return false; } if (container.GetInventory().NrOfItems() == 0) { return false; } if (container.IsInUse()) { return false; } if (!container.IsDistributor()) { return false; } if (container.IsCart(out Vagon cart) && cart.InUse()) { return cart.IsAttached((Character)(object)Player.m_localPlayer); } return true; } [HarmonyPrefix] [HarmonyPatch(typeof(Container), "Interact")] private static void Container_Interact(Container __instance, bool alt, bool hold, ref bool __result, ref bool __runOriginal) { if (!(!alt || hold)) { __runOriginal = false; if (WardAccessExt.CanAccessWard(__instance, true) && IsValidSource(__instance)) { SendFrom(__instance); __result = true; } } } [HarmonyPostfix] [HarmonyPatch(typeof(Container), "GetHoverText")] [HarmonyPriority(100)] private static void Container_GetHoverText(Container __instance, ref string __result) { if (IsValidSource(__instance)) { __result = StringExt.Localize(UI.InsertInteractAlt(__result, "$inventory_transfer")); } } [HarmonyPrefix] [HarmonyPatch(typeof(Container), "RPC_StackResponse")] private static void Container_RPC_StackResponse(Container __instance, bool granted, ref bool __runOriginal) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) if (!PendingContainersRPC.TryGetValue(__instance, out Container value)) { return; } __runOriginal = false; if (granted && Object.op_Implicit((Object)(object)value)) { if (WardAccessExt.CanAccessWard(__instance, false)) { value.m_nview.ClaimOwnership(); __instance.m_nview.ClaimOwnership(); int num = __instance.GetInventory().StackAll(value.GetInventory(), false); if (num > 0) { Logging.Info((object)$"Stacked {num} items to {((Object)__instance).name} at {MathExt.XZY(((Component)__instance).transform.position)}", 0); __instance.ShowHighlight(); } } else { Logging.Info((object)"Distribution target container is warded, skipping.", 0); } } PendingContainersRPC.Remove(__instance); Logging.Debug((object)$"Remaining containers: {PendingContainersRPC.Count}", 0); } [HarmonyTranspiler] [HarmonyPatch(typeof(Inventory), "StackAll")] private static IEnumerable Inventory_StackAll_Transpiler(IEnumerable codes) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return new CodeMatcher(codes, (ILGenerator)null).MatchStartForward((CodeMatch[])(object)new CodeMatch[1] { CodeMatch.op_Implicit(OpCodes.Ldarg_2) }).ThrowIfInvalid("Unable to find matching IL").Set(OpCodes.Ldc_I4_1, (object)null) .InstructionEnumeration(); } } [BepInPlugin("ZenDragon.ZenDistributor", "ZenDistributor", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [SynchronizationMode(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal class Plugin : ZenMod { public const string PluginGUID = "ZenDragon.ZenDistributor"; public const string PluginName = "ZenDistributor"; public const string PluginVersion = "1.1.0"; protected override void Setup() { } protected override void TitleScene(bool isFirstBoot) { } protected override void WorldStart() { } protected override void Shutdown() { } protected override HelpInfo? GetHelpInfo() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(HelpInfo.Format("Description", "Carts and ships can distribute their cargo to nearby containers", (string)null, true, true)); if (Configs.SnapToPlayer.Value) { stringBuilder.AppendLine(HelpInfo.Format(Configs.SnapToPlayer, false, true, true)); } if (Configs.IgnoreUpsideDown.Value) { stringBuilder.AppendLine(HelpInfo.Format(Configs.IgnoreUpsideDown, false, true, true)); } return new HelpInfo("Distributor", stringBuilder.ToString()); } } }