using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("AutoQueueBuild")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: AssemblyInformationalVersion("1.1.1")]
[assembly: AssemblyProduct("AutoQueueBuild")]
[assembly: AssemblyTitle("AutoQueueBuild")]
[assembly: AssemblyVersion("1.1.1.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 AutoQueueBuild
{
internal static class ForgeInfo
{
internal static int QueuedCrafts(MechaForge forge, int recipeId)
{
List<ForgeTask> list = forge?.tasks;
if (list == null)
{
return 0;
}
int num = 0;
for (int i = 0; i < list.Count; i++)
{
ForgeTask val = list[i];
if (val != null && val.parentTaskIndex < 0 && val.recipeId == recipeId)
{
num += val.count;
}
}
return num;
}
internal static float SecondsUntilDone(MechaForge forge, Mecha mecha, int recipeId)
{
List<ForgeTask> list = forge?.tasks;
if (list == null || mecha == null)
{
return 0f;
}
int num = -1;
for (int i = 0; i < list.Count; i++)
{
ForgeTask val = list[i];
if (val != null && val.parentTaskIndex < 0 && val.recipeId == recipeId)
{
num = i;
}
}
if (num < 0)
{
return 0f;
}
double num2 = 0.0;
for (int j = 0; j <= num && j < list.Count; j++)
{
ForgeTask val2 = list[j];
if (val2 != null)
{
num2 += (double)val2.tickSpend * (double)val2.count - (double)val2.tick;
}
}
float num3 = mecha.replicateSpeed;
if (num3 <= 0.0001f)
{
num3 = 1f;
}
return (float)(num2 / 600000.0 / (double)num3);
}
internal static string FormatSeconds(float s)
{
if (s <= 0f)
{
return "";
}
if (s < 1f)
{
return "<1s";
}
if (s < 60f)
{
return Mathf.RoundToInt(s) + "s";
}
int num = Mathf.FloorToInt(s / 60f);
if (num < 60)
{
return num + "m";
}
return num / 60 + "h";
}
}
[HarmonyPatch(typeof(UIBuildMenu))]
internal static class BuildBarOverlayPatch
{
private const int Slots = 12;
private static readonly Text[] Overlays = (Text[])(object)new Text[12];
private static UIBuildMenu _boundTo;
private static long _lastUpdateTick = long.MinValue;
private static readonly Color OverlayColor = new Color(1f, 0.72f, 0.2f, 1f);
private static bool _loggedShow;
private static bool _loggedCreate;
[HarmonyPostfix]
[HarmonyPatch("_OnUpdate")]
private static void OnUpdate_Postfix(UIBuildMenu __instance)
{
if (Plugin.Enabled == null || !Plugin.Enabled.Value)
{
HideAll();
return;
}
if (Plugin.ShowBarOverlay == null || !Plugin.ShowBarOverlay.Value)
{
HideAll();
return;
}
Player mainPlayer = GameMain.mainPlayer;
if (mainPlayer == null || mainPlayer.mecha == null || mainPlayer.mecha.forge == null)
{
HideAll();
return;
}
EnsureOverlays(__instance);
int currentCategory = __instance.currentCategory;
if (currentCategory < 1 || currentCategory > 9)
{
HideAll();
return;
}
long gameTick = GameMain.gameTick;
if (_lastUpdateTick != long.MinValue)
{
long num = gameTick - _lastUpdateTick;
if (num >= 0 && num < 6)
{
return;
}
}
_lastUpdateTick = gameTick;
ItemProto[,] array = BuildMenuClickPatch.ProtosValue();
if (array == null)
{
return;
}
MechaForge forge = mainPlayer.mecha.forge;
int length = array.GetLength(1);
for (int i = 0; i < 12; i++)
{
Text val = Overlays[i];
if ((Object)(object)val == (Object)null)
{
continue;
}
ItemProto val2 = ((currentCategory < array.GetLength(0) && i < length) ? array[currentCategory, i] : null);
RecipeProto val3 = val2?.handcraft;
if (val3 == null)
{
val.text = "";
continue;
}
int num2 = ForgeInfo.QueuedCrafts(forge, ((Proto)val3).ID);
if (num2 <= 0)
{
val.text = "";
continue;
}
string text = ForgeInfo.FormatSeconds(ForgeInfo.SecondsUntilDone(forge, mainPlayer.mecha, ((Proto)val3).ID));
val.text = ((text.Length > 0) ? ("+" + num2 + " (" + text + ")") : ("+" + num2));
if (Plugin.DebugLog != null && Plugin.DebugLog.Value && !_loggedShow)
{
_loggedShow = true;
Plugin.Log.LogInfo((object)("[overlay] slot " + i + " item " + ((Proto)val2).ID + " -> \"" + val.text.Replace("\n", " ") + "\""));
}
}
}
private static void EnsureOverlays(UIBuildMenu menu)
{
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
//IL_0135: 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)
//IL_0140: Unknown result type (might be due to invalid IL or missing references)
//IL_014b: Unknown result type (might be due to invalid IL or missing references)
//IL_0155: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_016a: Unknown result type (might be due to invalid IL or missing references)
//IL_0175: Unknown result type (might be due to invalid IL or missing references)
//IL_017f: Unknown result type (might be due to invalid IL or missing references)
//IL_018a: Unknown result type (might be due to invalid IL or missing references)
//IL_019e: Unknown result type (might be due to invalid IL or missing references)
//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_boundTo == (Object)(object)menu && (Object)(object)Overlays[0] != (Object)null)
{
return;
}
if ((Object)(object)_boundTo != (Object)(object)menu)
{
for (int i = 0; i < 12; i++)
{
Overlays[i] = null;
}
_boundTo = menu;
}
Text[] childNumTexts = menu.childNumTexts;
if (childNumTexts == null)
{
return;
}
for (int j = 0; j < 12 && j < childNumTexts.Length; j++)
{
if (!((Object)(object)Overlays[j] != (Object)null))
{
Text val = childNumTexts[j];
if (!((Object)(object)val == (Object)null) && !((Object)(object)val.font == (Object)null))
{
GameObject val2 = new GameObject("aqb-queue-overlay", new Type[2]
{
typeof(RectTransform),
typeof(CanvasRenderer)
});
val2.transform.SetParent(((Component)val).transform.parent, false);
Text val3 = val2.AddComponent<Text>();
val3.font = val.font;
val3.fontStyle = (FontStyle)1;
val3.fontSize = Mathf.Max(2, val.fontSize - 1);
((Graphic)val3).color = OverlayColor;
val3.alignment = (TextAnchor)7;
val3.horizontalOverflow = (HorizontalWrapMode)1;
val3.verticalOverflow = (VerticalWrapMode)1;
((Graphic)val3).raycastTarget = false;
val3.text = "";
RectTransform val4 = (RectTransform)val2.transform;
val4.sizeDelta = new Vector2(90f, 18f);
val4.anchorMin = new Vector2(0.5f, 1f);
val4.anchorMax = new Vector2(0.5f, 1f);
val4.pivot = new Vector2(0.5f, 0f);
val4.anchoredPosition = new Vector2(0f, 2f);
Outline obj = val2.AddComponent<Outline>();
((Shadow)obj).effectColor = new Color(0f, 0f, 0f, 0.9f);
((Shadow)obj).effectDistance = new Vector2(1.2f, -1.2f);
Overlays[j] = val3;
}
}
}
if (Plugin.DebugLog == null || !Plugin.DebugLog.Value || _loggedCreate)
{
return;
}
_loggedCreate = true;
int num = 0;
for (int k = 0; k < 12; k++)
{
if ((Object)(object)Overlays[k] != (Object)null)
{
num++;
}
}
Plugin.Log.LogInfo((object)("[overlay] created " + num + "/" + 12 + " overlay texts (baseTexts=" + ((childNumTexts != null) ? childNumTexts.Length.ToString() : "null") + ")"));
}
private static void HideAll()
{
for (int i = 0; i < 12; i++)
{
if ((Object)(object)Overlays[i] != (Object)null)
{
Overlays[i].text = "";
}
}
}
}
[HarmonyPatch(typeof(UIBuildMenu))]
internal static class BuildMenuClickPatch
{
private static readonly FieldInfo ProtosField = AccessTools.Field(typeof(UIBuildMenu), "protos");
private static readonly FieldRef<UIBuildMenu, int> DblClickIndexRef = AccessTools.FieldRefAccess<UIBuildMenu, int>("dblClickIndex");
private static readonly FieldRef<UIBuildMenu, double> DblClickTimeRef = AccessTools.FieldRefAccess<UIBuildMenu, double>("dblClickTime");
private const double DoubleClickWindow = 0.33000001311302185;
internal static ItemProto[,] ProtosValue()
{
return ProtosField.GetValue(null) as ItemProto[,];
}
[HarmonyPrefix]
[HarmonyPatch("OnChildButtonClick")]
private static bool OnChildButtonClick_Prefix(UIBuildMenu __instance, int index)
{
//IL_021e: Unknown result type (might be due to invalid IL or missing references)
if (Plugin.Enabled == null || !Plugin.Enabled.Value)
{
return true;
}
Player mainPlayer = GameMain.mainPlayer;
if (mainPlayer == null || mainPlayer.package == null)
{
return true;
}
if (!(ProtosField.GetValue(null) is ItemProto[,] array))
{
return true;
}
int currentCategory = __instance.currentCategory;
if (currentCategory < 0 || currentCategory >= array.GetLength(0) || index < 0 || index >= array.GetLength(1))
{
return true;
}
ItemProto val = array[currentCategory, index];
if (val == null)
{
return true;
}
int iD = ((Proto)val).ID;
if (!__instance.showButtonsAnyways && !GameMain.history.ItemUnlocked(iD))
{
return true;
}
if (mainPlayer.package.GetItemCount(iD) > 0)
{
return true;
}
if (currentCategory == 9 && index == 1)
{
return true;
}
if (index == DblClickIndexRef.Invoke(__instance) && GameMain.gameTime - DblClickTimeRef.Invoke(__instance) < 0.33000001311302185)
{
return true;
}
RecipeProto handcraft = val.handcraft;
if (handcraft == null || !GameMain.history.RecipeUnlocked(((Proto)handcraft).ID))
{
return true;
}
Mecha mecha = mainPlayer.mecha;
if (mecha == null || mecha.forge == null)
{
return true;
}
int num = CraftsForClick();
MechaForge forge = mecha.forge;
int num2 = ForgeInfo.QueuedCrafts(forge, ((Proto)handcraft).ID);
int num3 = forge.PredictTaskCount(((Proto)handcraft).ID, num, false);
if (num3 > num)
{
num3 = num;
}
if (num3 > 0)
{
forge.AddTask(((Proto)handcraft).ID, num3);
}
int num4 = ForgeInfo.QueuedCrafts(forge, ((Proto)handcraft).ID);
if (num4 <= 0)
{
return true;
}
DblClickIndexRef.Invoke(__instance) = index;
DblClickTimeRef.Invoke(__instance) = GameMain.gameTime;
if (Plugin.ShowTip == null || Plugin.ShowTip.Value)
{
string text = ForgeInfo.FormatSeconds(ForgeInfo.SecondsUntilDone(forge, mecha, ((Proto)handcraft).ID));
string text2 = ((num4 > num2) ? "Added to queue" : "In queue");
ShowTipAtCursor((text.Length > 0) ? (text2 + " (" + text + ")") : text2);
}
if (Plugin.PlaySound == null || Plugin.PlaySound.Value)
{
VFAudio.Create("build-menu-child", (Transform)null, Vector3.zero, false, 0, -1, -1L).Play();
}
return false;
}
private static int CraftsForClick()
{
if (VFInput.shift)
{
if (Plugin.ShiftClickCrafts == null)
{
return 5;
}
return Mathf.Max(1, Plugin.ShiftClickCrafts.Value);
}
if (VFInput.control)
{
if (Plugin.CtrlClickCrafts == null)
{
return 1;
}
return Mathf.Max(1, Plugin.CtrlClickCrafts.Value);
}
if (Plugin.CraftsPerClick == null)
{
return 1;
}
return Mathf.Max(1, Plugin.CraftsPerClick.Value);
}
private static void ShowTipAtCursor(string text)
{
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: 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_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
UIGame val = (((Object)(object)UIRoot.instance != (Object)null) ? UIRoot.instance.uiGame : null);
if ((Object)(object)val == (Object)null || (Object)(object)val.generalTips == (Object)null)
{
UIRealtimeTip.Popup(text, false, 0);
return;
}
Rect panelRect = val.generalTips.panelRect;
float num = Input.mousePosition.x / (float)Screen.width * ((Rect)(ref panelRect)).width;
float num2 = Input.mousePosition.y / (float)Screen.height * ((Rect)(ref panelRect)).height + 40f;
UIRealtimeTip.Popup(text, new Vector2(num, num2), false);
}
}
[HarmonyPatch(typeof(PlayerAction_Build))]
internal static class PlacementCraftPatch
{
private static long _lastLogTick = long.MinValue;
private static bool Dbg
{
get
{
if (Plugin.DebugLog != null)
{
return Plugin.DebugLog.Value;
}
return false;
}
}
private static void Log(long tick, string msg)
{
if (Dbg && (_lastLogTick == long.MinValue || tick - _lastLogTick < 0 || tick - _lastLogTick >= 30))
{
_lastLogTick = tick;
Plugin.Log.LogInfo((object)("[placement] " + msg));
}
}
[HarmonyPostfix]
[HarmonyPatch("GameTick")]
private static void GameTick_Postfix(PlayerAction_Build __instance, long timei)
{
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: Invalid comparison between Unknown and I4
if (Plugin.Enabled == null || !Plugin.Enabled.Value || Plugin.PlacementCraft == null || !Plugin.PlacementCraft.Value)
{
return;
}
int num = ((Plugin.PlacementCheckInterval != null) ? Plugin.PlacementCheckInterval.Value : 10);
if (num > 1 && timei % num != 0L)
{
return;
}
Player player = ((PlayerAction)__instance).player;
if (player == null || player.package == null)
{
return;
}
int inhandItemId = player.inhandItemId;
if (inhandItemId <= 0 || player.package.GetItemCount(inhandItemId) > 0)
{
return;
}
BuildTool val = (BuildTool)(((object)__instance.activeTool) ?? ((object)__instance.noneTool));
List<BuildPreview> list = ((val != null) ? val.buildPreviews : null);
bool flag = false;
int num2 = 0;
if (list != null)
{
for (int i = 0; i < list.Count; i++)
{
BuildPreview val2 = list[i];
if (val2 != null && (int)val2.condition == 2)
{
num2++;
if (val2.item != null && ((Proto)val2.item).ID == inhandItemId)
{
flag = true;
}
}
}
}
if (Dbg)
{
Log(timei, string.Format("hand={0} have=0 tool={1} previews={2} notEnough={3} shortForHand={4}", inhandItemId, (val != null) ? ((object)val).GetType().Name : "null", list?.Count ?? (-1), num2, flag));
}
if (!flag)
{
return;
}
RecipeProto val3 = ((ProtoSet<ItemProto>)(object)LDB.items).Select(inhandItemId)?.handcraft;
if (val3 == null || !GameMain.history.RecipeUnlocked(((Proto)val3).ID))
{
Log(timei, "no unlocked handcraft recipe for item " + inhandItemId);
return;
}
Mecha mecha = player.mecha;
if (mecha == null || mecha.forge == null)
{
return;
}
int num3 = ((Plugin.PlacementBuffer != null) ? Plugin.PlacementBuffer.Value : 5) - ForgeInfo.QueuedCrafts(mecha.forge, ((Proto)val3).ID);
if (num3 <= 0)
{
return;
}
int num4 = mecha.forge.PredictTaskCount(((Proto)val3).ID, num3, false);
if (num4 > num3)
{
num4 = num3;
}
if (num4 <= 0)
{
Log(timei, "recipe " + ((Proto)val3).ID + " wanted " + num3 + " but affordable=0 (missing raw mats)");
return;
}
ForgeTask val4 = mecha.forge.AddTask(((Proto)val3).ID, num4);
if (Plugin.DebugLog != null && Plugin.DebugLog.Value)
{
Plugin.Log.LogInfo((object)("[placement] queued " + num4 + " x recipe " + ((Proto)val3).ID + " (task=" + ((val4 != null) ? "ok" : "null") + ")"));
}
}
}
[BepInPlugin("com.livinginstinkt.dsp.autoqueuebuild", "AutoQueueBuild", "1.1.1")]
public class Plugin : BaseUnityPlugin
{
public const string Guid = "com.livinginstinkt.dsp.autoqueuebuild";
public const string Name = "AutoQueueBuild";
public const string Version = "1.1.1";
internal static ManualLogSource Log;
internal static ConfigEntry<bool> Enabled;
internal static ConfigEntry<int> CraftsPerClick;
internal static ConfigEntry<int> ShiftClickCrafts;
internal static ConfigEntry<int> CtrlClickCrafts;
internal static ConfigEntry<bool> ShowTip;
internal static ConfigEntry<bool> PlaySound;
internal static ConfigEntry<bool> PlacementCraft;
internal static ConfigEntry<int> PlacementBuffer;
internal static ConfigEntry<int> PlacementCheckInterval;
internal static ConfigEntry<bool> ShowBarOverlay;
internal static ConfigEntry<bool> DebugLog;
private Harmony _harmony;
private void Awake()
{
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Expected O, but got Unknown
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Expected O, but got Unknown
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00bc: Expected O, but got Unknown
//IL_0144: Unknown result type (might be due to invalid IL or missing references)
//IL_014e: Expected O, but got Unknown
//IL_0177: Unknown result type (might be due to invalid IL or missing references)
//IL_0181: Expected O, but got Unknown
//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
//IL_01d6: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. When off, the build bar behaves exactly like vanilla.");
CraftsPerClick = ((BaseUnityPlugin)this).Config.Bind<int>("General", "CraftsPerClick", 1, new ConfigDescription("How many handcraft executions to queue per plain click (1 = one craft of the building).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
CtrlClickCrafts = ((BaseUnityPlugin)this).Config.Bind<int>("General", "CtrlClickCrafts", 1, new ConfigDescription("How many to queue on Ctrl+click.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
ShiftClickCrafts = ((BaseUnityPlugin)this).Config.Bind<int>("General", "ShiftClickCrafts", 5, new ConfigDescription("How many to queue on Shift+click.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
ShowTip = ((BaseUnityPlugin)this).Config.Bind<bool>("Feedback", "ShowTip", true, "Show an on-screen tip when a build is queued to the replicator.");
PlaySound = ((BaseUnityPlugin)this).Config.Bind<bool>("Feedback", "PlaySound", true, "Play the build-menu click sound when a build is queued.");
PlacementCraft = ((BaseUnityPlugin)this).Config.Bind<bool>("Placement", "AutoCraftWhilePlacing", false, "OPT-IN. When true, running out of a building mid-placement auto-queues more (up to PlacementBuffer) so you can keep building. Off by default; the build-bar click is the only automatic queue.");
PlacementBuffer = ((BaseUnityPlugin)this).Config.Bind<int>("Placement", "PlacementBuffer", 5, new ConfigDescription("How many of the building to keep queued in the replicator while placing on empty inventory.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), Array.Empty<object>()));
PlacementCheckInterval = ((BaseUnityPlugin)this).Config.Bind<int>("Placement", "CheckIntervalTicks", 10, new ConfigDescription("Game ticks between placement top-up checks (higher = less frequent, cheaper).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 60), Array.Empty<object>()));
ShowBarOverlay = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowBarOverlay", true, "Show queued quantity and build ETA on the build-bar icons.");
DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLog", false, "Verbose diagnostic logging to the BepInEx console/log. Leave off for normal play.");
_harmony = new Harmony("com.livinginstinkt.dsp.autoqueuebuild");
_harmony.PatchAll();
Log.LogInfo((object)"AutoQueueBuild v1.1.1 loaded.");
}
private void OnDestroy()
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
_harmony = null;
}
}
}