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] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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), "SetMass")] private static void Vagon_SetMass(Vagon __instance, ref float mass) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) int num = 0; if (((List)(object)Configs.CartAssistBuffs.Value).Count > 0 && __instance.IsAttached((Character)(object)Player.m_localPlayer)) { SEMan sEMan = ((Character)Player.m_localPlayer).GetSEMan(); bool flag = default(bool); foreach (string item in (List)(object)Configs.CartAssistBuffs.Value) { if (sEMan.HaveStatusEffect(StringExtensionMethods.GetStableHashCode(item))) { InterpolatedString val = new InterpolatedString(35, 1, ref flag); if (flag) { val.AppendFormatted(item); val.AppendLiteral(" makes the cart much easier to pull"); } Logging.Info(val, 0); num = Mathf.Clamp(Configs.CartMassCeiling.Value / 3, 1, 35); break; } } } if (num == 0) { num = Configs.CartMassCeiling.Value; } if (num > 0) { mass = Mathf.Min(mass, (float)num); } } [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; public static readonly ConfigEntry CartMassCeiling; public static readonly ConfigEntry CartAssistBuffs; 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 //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Expected O, but got Unknown //IL_0185: 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)"); CartMassCeiling = Config.Define(true, "Cart", "Mass Ceiling", 100, Config.AcceptRange(0, 1000), "The maximum computed mass of the cart, anything above this will be ignored.\r\nThis makes it possible to haul extra heavy cargo up a hill without the cart becomming immovable.\r\n[Set to 0 to disable this feature] \r\n(vanilla: 0)"); StringList val2 = new StringList(); ((List)val2).Add("Potion_strength"); CartAssistBuffs = Config.Define(true, "Cart", "Assist Buffs", val2, "If any of these effects are active the cart is much easier to pull.\r\n(vanilla: false)"); } } [HarmonyPatch] internal static class Distribute { private const double Cooldown = 3.0; private static readonly Dictionary PendingContainersRPC = new Dictionary(); private static double _lastDistributeTime; private static int _stackItemTotal; private static bool IsCooldownExpired => Time.timeAsDouble > _lastDistributeTime + 3.0; private static bool IsReady { get { if (IsCooldownExpired) { 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()))); } internal static void RegisterRPC() { ZRoutedRpc.instance.Register("RPC_DistributeContainerRequest", (Action)RPC_DistributeContainerRequest); ZRoutedRpc.instance.Register("RPC_DistributeContainerResponse", (Action)RPC_DistributeContainerResponse); } internal static void UnregisterRPC() { ZRoutedRpcExt.Unregister(ZRoutedRpc.instance, "RPC_DistributeContainerRequest"); ZRoutedRpcExt.Unregister(ZRoutedRpc.instance, "RPC_DistributeContainerResponse"); } 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) { return from container in GameObjectExt.GetNearbyPiecesXZ(((Component)self).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)self) select container; } private static void SendFrom(Container source, Player user) { //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_00a2: Unknown result type (might be due to invalid IL or missing references) if (IsCooldownExpired) { PendingContainersRPC.Clear(); } if (!IsReady) { ((Character)user).Message((MessageType)2, "$menu_pleasewait", 0, (Sprite)null); Logging.Info("Cooldown has not elapsed, too soon to distribute again", 0); return; } _lastDistributeTime = Time.timeAsDouble; PendingContainersRPC.Clear(); if (Logging.IsEnabled) { bool flag = default(bool); InterpolatedString val = new InterpolatedString(17, 1, ref flag); if (flag) { val.AppendLiteral("Inventory Items: "); val.AppendFormatted(GeneralExtensions.Join((IEnumerable)source.GetInventory().GetAllItems(), (Func)((ItemData item) => ItemDataExt.GetPrefabName(item)), ", ")); } Logging.Info(val, 0); } Highlight.None(); IEnumerable nearbyContainers = source.GetNearbyContainers(Configs.MaxRange.Value); bool isSourceShip = source.IsShip(); ((MonoBehaviour)source).StartCoroutine(ProcessSend(source, user, nearbyContainers, isSourceShip)); } private static IEnumerator ProcessSend(Container source, Player user, IEnumerable nearbyContainers, bool isSourceShip) { _stackItemTotal = 0; bool flag = default(bool); foreach (Container item in nearbyContainers.OrderBy((Container c) => MathExt.DistanceTo((MonoBehaviour)(object)c, (MonoBehaviour)(object)source))) { if (Object.op_Implicit((Object)(object)item) && item.m_nview.IsValid() && !item.IsInUse()) { InterpolatedString val = new InterpolatedString(19, 1, ref flag); if (flag) { val.AppendLiteral("Processing target: "); val.AppendFormatted(((Object)item).name); } Logging.Info(val, 0); PendingContainersRPC.Add(item, source); val = new InterpolatedString(44, 1, ref flag); if (flag) { val.AppendLiteral("Added container to rpc pending list, count: "); val.AppendFormatted(PendingContainersRPC.Count); } Logging.Debug(val, 0); item.StackAll(); if (isSourceShip && item.IsCart(out Vagon cart) && !cart.InUse() && item.GetInventory().HaveEmptySlot()) { item.m_nview.ClaimOwnership(); item.GetInventory().MoveAll(source.GetInventory()); item.ShowHighlight(); } yield return null; } } yield return (object)new WaitUntil((Func)(() => PendingContainersRPC.Count <= 0 || IsCooldownExpired)); if (Object.op_Implicit((Object)(object)user)) { ((Character)user).Message((MessageType)2, $"$msg_stackall {_stackItemTotal}", 0, (Sprite)null); } } 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, Player? user, bool showMsg) { if (((List)(object)Configs.AllowedContainers.Value).Count == 0) { return false; } if (!container.IsDistributor()) { return false; } if (!IsReady) { MsgUser("$menu_pleasewait"); return false; } if (container.GetInventory().NrOfItems() == 0) { MsgUser("$msg_stackall_none"); return false; } if (container.IsInUse()) { MsgUser("$msg_inuse"); return false; } if (!container.IsCart(out Vagon cart)) { return true; } if (cart.InUse()) { if (Object.op_Implicit((Object)(object)user) && cart.IsAttached((Character)(object)user)) { return true; } MsgUser("$msg_inuse"); return false; } return true; void MsgUser(string msg) { if (Object.op_Implicit((Object)(object)user) && showMsg) { ((Character)user).Message((MessageType)2, msg, 0, (Sprite)null); } } } private static Container? GetContainerFromZDOID(ZDOID zid) { //IL_0005: 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_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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) GameObject val = ZNetScene.instance.FindInstance(zid); if (!Object.op_Implicit((Object)(object)val)) { bool flag = default(bool); InterpolatedString val2 = new InterpolatedString(29, 1, ref flag); if (flag) { val2.AppendLiteral("Scene instance not found for "); val2.AppendFormatted(zid); } Logging.Info(val2, 0); return null; } Container componentInChildren = val.GetComponentInChildren(); if (Object.op_Implicit((Object)(object)componentInChildren)) { return componentInChildren; } Logging.Info("Container component missing from scene object", 0); return null; } private static void RPC_DistributeContainerRequest(long sender, ZDOID containerID, long requesterID) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_0079: Unknown result type (might be due to invalid IL or missing references) Container containerFromZDOID = GetContainerFromZDOID(containerID); Player player = Player.GetPlayer(requesterID); if (!Object.op_Implicit((Object)(object)player)) { bool flag = default(bool); InterpolatedString val = new InterpolatedString(38, 1, ref flag); if (flag) { val.AppendLiteral("Player "); val.AppendFormatted(requesterID); val.AppendLiteral(" not found, or no longer nearby"); } Logging.Info(val, 0); } bool flag2 = Object.op_Implicit((Object)(object)player) && Object.op_Implicit((Object)(object)containerFromZDOID) && IsValidSource(containerFromZDOID, player, showMsg: true); if (flag2 && Object.op_Implicit((Object)(object)containerFromZDOID)) { ZDOMan.instance.ForceSendZDO(sender, containerID); containerFromZDOID.m_nview.GetZDO().SetOwner(sender); } ZRoutedRpc.instance.InvokeRoutedRPC(sender, "RPC_DistributeContainerResponse", new object[2] { containerID, flag2 }); } private static void RPC_DistributeContainerResponse(long sender, ZDOID containerID, bool isGranted) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) if (isGranted) { Container containerFromZDOID = GetContainerFromZDOID(containerID); if (Object.op_Implicit((Object)(object)containerFromZDOID)) { SendFrom(containerFromZDOID, Player.m_localPlayer); } } } [HarmonyPrefix] [HarmonyPatch(typeof(Container), "Interact")] private static void Container_Interact(Container __instance, bool alt, bool hold, ref bool __result, ref bool __runOriginal) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (!alt) { return; } __runOriginal = false; if (!hold) { __result = true; if (WardAccessExt.CanAccessWard(__instance, true)) { ZDO zDO = __instance.m_nview.GetZDO(); long playerID = Player.m_localPlayer.GetPlayerID(); ZRoutedRpc.instance.InvokeRoutedRPC(zDO.GetOwner(), "RPC_DistributeContainerRequest", new object[2] { zDO.m_uid, playerID }); } } } [HarmonyPostfix] [HarmonyPatch(typeof(Container), "GetHoverText")] [HarmonyPriority(100)] private static void Container_GetHoverText(Container __instance, ref string __result) { if (IsValidSource(__instance, Player.m_localPlayer, showMsg: false)) { __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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) if (!PendingContainersRPC.TryGetValue(__instance, out Container value)) { return; } PendingContainersRPC.Remove(__instance); bool flag = default(bool); InterpolatedString val = new InterpolatedString(22, 1, ref flag); if (flag) { val.AppendLiteral("Remaining containers: "); val.AppendFormatted(PendingContainersRPC.Count); } Logging.Debug(val, 0); __runOriginal = false; if (!granted || !Object.op_Implicit((Object)(object)value)) { return; } if (WardAccessExt.CanAccessWard(__instance, false)) { value.m_nview.ClaimOwnership(); __instance.m_nview.ClaimOwnership(); int num = __instance.GetInventory().StackAll(value.GetInventory(), false); _stackItemTotal += num; if (num > 0) { val = new InterpolatedString(22, 3, ref flag); if (flag) { val.AppendLiteral("Stacked "); val.AppendFormatted(num); val.AppendLiteral(" items to "); val.AppendFormatted(((Object)__instance).name); val.AppendLiteral(" at "); val.AppendFormatted(MathExt.XZY(((Component)__instance).transform.position)); } Logging.Info(val, 0); __instance.ShowHighlight(); } } else { Logging.Info("Distribution target container is warded, skipping.", 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.2.2")] [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.2.2"; protected override void Setup() { } protected override void TitleScene(bool isFirstBoot) { } protected override void WorldStart() { Distribute.RegisterRPC(); } protected override void Shutdown() { Distribute.UnregisterRPC(); } protected override HelpInfo? GetHelpInfo() { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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)); } if (((List)(object)Configs.CartAssistBuffs.Value).Count > 0) { stringBuilder.AppendLine(HelpInfo.Format(Configs.CartAssistBuffs, true, true, true)); } return new HelpInfo("Distributor", stringBuilder.ToString()); } } }