using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("coddingcat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Spam Space while restocking shelves in Shift At Midnight.")]
[assembly: AssemblyFileVersion("2.3.0.0")]
[assembly: AssemblyInformationalVersion("2.3.0")]
[assembly: AssemblyProduct("SpaceRefillMod")]
[assembly: AssemblyTitle("SpaceRefillMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.3.0.0")]
[module: UnverifiableCode]
[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 SpaceRefillMod
{
internal static class PluginInfo
{
internal const string Guid = "com.coddingcat.shiftatm.spacerefill";
internal const string Name = "Space Refill";
internal const string Version = "2.3.0";
}
[BepInPlugin("com.coddingcat.shiftatm.spacerefill", "Space Refill", "2.3.0")]
public sealed class SpaceRefillPlugin : BasePlugin
{
private Harmony _harmony;
private static ConfigEntry<float> _boostPerPress;
private static ConfigEntry<float> _drainPerSecond;
internal static ManualLogSource LogSource { get; private set; }
internal static float BoostPerPress => Mathf.Clamp(_boostPerPress?.Value ?? 0.12f, 0.01f, 1f);
internal static float DrainPerSecond => Mathf.Max(0f, _drainPerSecond?.Value ?? 0.5f);
public override void Load()
{
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Expected O, but got Unknown
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Expected O, but got Unknown
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Expected O, but got Unknown
LogSource = ((BasePlugin)this).Log;
_boostPerPress = ((BasePlugin)this).Config.Bind<float>("Meter", "BoostPerPress", 0.12f, "Amount added to the meter by each Space press.");
_drainPerSecond = ((BasePlugin)this).Config.Bind<float>("Meter", "DrainPerSecond", 0.5f, "Meter power lost per second. Lower values make each press last longer.");
bool flag = default(bool);
try
{
if (!ShelfGameAccess.Validate(out var error))
{
throw new InvalidOperationException(error);
}
SpamMeterUi.Create();
_harmony = new Harmony("com.coddingcat.shiftatm.spacerefill");
_harmony.PatchAll(typeof(RestockShelfPatches));
ManualLogSource log = ((BasePlugin)this).Log;
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(10, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("Space Refill");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" v");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("2.3.0");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded.");
}
log.LogInfo(val);
((BasePlugin)this).Log.LogInfo((object)"Interact with a shelf and spam Space. A full meter places one item.");
}
catch (Exception ex)
{
SpamMeterUi.Destroy();
ManualLogSource log2 = ((BasePlugin)this).Log;
BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(23, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Failed to initialise ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("Space Refill");
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
}
log2.LogError(val2);
throw;
}
}
public override bool Unload()
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
RefillController.Reset();
SpamMeterUi.Destroy();
LogSource = null;
return true;
}
}
internal static class RefillController
{
private const float PlacementRetryDelay = 0.5f;
private const float FailureLogCooldown = 5f;
private static RestockShelf _activeShelf;
private static float _meterPower;
private static float _retryAt;
private static float _nextFailureLogAt;
internal static void Start(RestockShelf shelf)
{
if (ShelfGameAccess.IsInteracting(shelf))
{
_activeShelf = shelf;
_meterPower = 0f;
_retryAt = 0f;
SpamMeterUi.SetLevel(0f);
SpamMeterUi.SetVisible(visible: true);
}
}
internal static void Stop(RestockShelf shelf)
{
if (IsActiveShelf(shelf))
{
Reset();
}
}
internal static void Tick(RestockShelf shelf)
{
if (!IsActiveShelf(shelf))
{
return;
}
if (!ShelfGameAccess.IsInteracting(shelf))
{
Reset();
return;
}
if (Input.GetKeyDown((KeyCode)32))
{
HandleSpacePress(shelf);
}
float num = Mathf.Clamp(Time.unscaledDeltaTime, 0f, 0.25f);
_meterPower = Mathf.Max(0f, _meterPower - SpaceRefillPlugin.DrainPerSecond * num);
SpamMeterUi.SetLevel(_meterPower);
}
internal static void Reset()
{
_activeShelf = null;
_meterPower = 0f;
_retryAt = 0f;
SpamMeterUi.SetLevel(0f);
SpamMeterUi.SetVisible(visible: false);
}
private static void HandleSpacePress(RestockShelf shelf)
{
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Expected O, but got Unknown
_meterPower = Mathf.Clamp01(_meterPower + SpaceRefillPlugin.BoostPerPress);
if (_meterPower < 1f || Time.unscaledTime < _retryAt)
{
return;
}
string error;
PlacementResult placementResult = ShelfGameAccess.TryPlaceNextItem(shelf, out error);
if (placementResult == PlacementResult.Success || placementResult == PlacementResult.ShelfEmpty)
{
_meterPower = 0f;
SpamMeterUi.SetLevel(0f);
return;
}
_retryAt = Time.unscaledTime + 0.5f;
if (Time.unscaledTime < _nextFailureLogAt)
{
return;
}
ManualLogSource logSource = SpaceRefillPlugin.LogSource;
if (logSource != null)
{
bool flag = default(bool);
BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(37, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Could not place the next shelf item: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(error);
}
logSource.LogWarning(val);
}
_nextFailureLogAt = Time.unscaledTime + 5f;
}
private static bool IsActiveShelf(RestockShelf shelf)
{
if ((Object)(object)shelf != (Object)null && (Object)(object)_activeShelf != (Object)null)
{
return ((Il2CppObjectBase)_activeShelf).Pointer == ((Il2CppObjectBase)shelf).Pointer;
}
return false;
}
}
internal enum PlacementResult
{
Success,
ShelfEmpty,
Failed
}
internal static class ShelfGameAccess
{
private const BindingFlags InstanceFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
private static readonly PropertyInfo InteractingProperty = typeof(RestockShelf).GetProperty("interacting", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
private static readonly PropertyInfo ProductsQueueProperty = typeof(ShelfManager).GetProperty("productsQueue", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
private static readonly PropertyInfo LastShelfItemProperty = typeof(ShelfManager).GetProperty("lastShelfItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
private static readonly MethodInfo CompleteItemMethod = typeof(ShelfManager).GetMethod("CompleteItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
private static Type _cachedQueueType;
private static PropertyInfo _queueCountProperty;
private static MethodInfo _queuePeekMethod;
internal static bool Validate(out string error)
{
if (InteractingProperty == null)
{
error = "RestockShelf.interacting was not found. The game may have been updated.";
return false;
}
if (ProductsQueueProperty == null || LastShelfItemProperty == null || CompleteItemMethod == null)
{
error = "Required ShelfManager members were not found. The game may have been updated.";
return false;
}
error = null;
return true;
}
internal static bool IsInteracting(RestockShelf shelf)
{
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Expected O, but got Unknown
if ((Object)(object)shelf == (Object)null)
{
return false;
}
try
{
object value = InteractingProperty.GetValue(shelf);
bool flag = default(bool);
int num;
if (value is bool)
{
flag = (bool)value;
num = 1;
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
catch (Exception ex)
{
ManualLogSource logSource = SpaceRefillPlugin.LogSource;
if (logSource != null)
{
bool flag2 = default(bool);
BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(41, 1, ref flag2);
if (flag2)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Could not read RestockShelf.interacting: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
logSource.LogDebug(val);
}
return false;
}
}
internal static PlacementResult TryPlaceNextItem(RestockShelf shelf, out string error)
{
error = null;
try
{
ShelfManager val = ((shelf != null) ? shelf.shelfMan : null);
if ((Object)(object)val == (Object)null)
{
return Fail("the shelf manager is missing", out error);
}
object value = ProductsQueueProperty.GetValue(val);
if (value == null)
{
return Fail("the product queue is not ready", out error);
}
if (!TryPrepareQueueAccess(value.GetType(), out error))
{
return PlacementResult.Failed;
}
if (Convert.ToInt32(_queueCountProperty.GetValue(value)) <= 0)
{
return PlacementResult.ShelfEmpty;
}
object? obj = _queuePeekMethod.Invoke(value, null);
object? obj2 = ((obj is GameObject) ? obj : null);
DragItem val2 = ((obj2 != null) ? ((GameObject)obj2).GetComponent<DragItem>() : null);
if ((Object)(object)val2 == (Object)null)
{
return Fail("the next product has no DragItem component", out error);
}
ShelfItemManager val3 = FindMatchingSlot(val, val2.itemIndex);
if ((Object)(object)val3 == (Object)null)
{
return Fail($"no shelf slot accepts item index {val2.itemIndex}", out error);
}
LastShelfItemProperty.SetValue(val, val3);
CompleteItemMethod.Invoke(val, null);
return PlacementResult.Success;
}
catch (TargetInvocationException ex)
{
return Fail(ex.InnerException?.Message ?? ex.Message, out error);
}
catch (Exception ex2)
{
return Fail(ex2.Message, out error);
}
}
private static bool TryPrepareQueueAccess(Type queueType, out string error)
{
if (_cachedQueueType == queueType && _queueCountProperty != null && _queuePeekMethod != null)
{
error = null;
return true;
}
_cachedQueueType = queueType;
_queueCountProperty = queueType.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
_queuePeekMethod = queueType.GetMethod("Peek", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
if (_queueCountProperty != null && _queuePeekMethod != null)
{
error = null;
return true;
}
error = "the product queue API was not found";
return false;
}
private static ShelfItemManager FindMatchingSlot(ShelfManager manager, int itemIndex)
{
ShelfItemManager[] array = Il2CppArrayBase<ShelfItemManager>.op_Implicit((Il2CppArrayBase<ShelfItemManager>)(object)manager.shelfItemManagers);
if (array == null)
{
return null;
}
foreach (ShelfItemManager val in array)
{
if ((Object)(object)val != (Object)null && val.itemIndex == itemIndex)
{
return val;
}
}
return null;
}
private static PlacementResult Fail(string message, out string error)
{
error = (string.IsNullOrWhiteSpace(message) ? "unknown game error" : message);
return PlacementResult.Failed;
}
}
internal static class SpamMeterUi
{
private static GameObject _canvasObject;
private static RectTransform _fillRect;
internal static void Create()
{
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_0112: Unknown result type (might be due to invalid IL or missing references)
//IL_014e: Unknown result type (might be due to invalid IL or missing references)
//IL_0167: Unknown result type (might be due to invalid IL or missing references)
//IL_0180: Unknown result type (might be due to invalid IL or missing references)
//IL_018f: 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_01ae: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)_canvasObject != (Object)null))
{
_canvasObject = CreateUiObject<Canvas, CanvasScaler>("SpaceRefill_Canvas");
Object.DontDestroyOnLoad((Object)(object)_canvasObject);
Canvas component = _canvasObject.GetComponent<Canvas>();
component.renderMode = (RenderMode)0;
component.sortingOrder = 999;
CanvasScaler component2 = _canvasObject.GetComponent<CanvasScaler>();
component2.uiScaleMode = (ScaleMode)1;
component2.referenceResolution = new Vector2(1920f, 1080f);
component2.matchWidthOrHeight = 0.5f;
GameObject val = CreateUiObject<Image>("SpaceRefill_Background");
val.transform.SetParent(_canvasObject.transform, false);
RectTransform component3 = val.GetComponent<RectTransform>();
component3.anchorMin = new Vector2(0.92f, 0.5f);
component3.anchorMax = new Vector2(0.92f, 0.5f);
component3.pivot = new Vector2(0.5f, 0.5f);
component3.anchoredPosition = Vector2.zero;
component3.sizeDelta = new Vector2(32f, 260f);
Image component4 = val.GetComponent<Image>();
((Graphic)component4).color = new Color(0.02f, 0.02f, 0.02f, 0.82f);
((Graphic)component4).raycastTarget = false;
GameObject obj = CreateUiObject<Image>("SpaceRefill_Fill");
obj.transform.SetParent(val.transform, false);
_fillRect = obj.GetComponent<RectTransform>();
_fillRect.anchorMin = Vector2.zero;
_fillRect.anchorMax = new Vector2(1f, 0f);
_fillRect.pivot = new Vector2(0.5f, 0f);
_fillRect.offsetMin = Vector2.zero;
_fillRect.offsetMax = Vector2.zero;
Image component5 = obj.GetComponent<Image>();
((Graphic)component5).color = Color.white;
((Graphic)component5).raycastTarget = false;
SetVisible(visible: false);
}
}
internal static void Destroy()
{
if ((Object)(object)_canvasObject != (Object)null)
{
Object.Destroy((Object)(object)_canvasObject);
}
_canvasObject = null;
_fillRect = null;
}
internal static void SetVisible(bool visible)
{
if ((Object)(object)_canvasObject != (Object)null && _canvasObject.activeSelf != visible)
{
_canvasObject.SetActive(visible);
}
}
internal static void SetLevel(float amount)
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: 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 (!((Object)(object)_fillRect == (Object)null))
{
Vector2 anchorMax = _fillRect.anchorMax;
anchorMax.x = 1f;
anchorMax.y = Mathf.Clamp01(amount);
_fillRect.anchorMax = anchorMax;
}
}
private static GameObject CreateUiObject<TComponent>(string name) where TComponent : Component
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Expected O, but got Unknown
return new GameObject(name, (Type[])(object)new Type[2]
{
Il2CppType.Of<RectTransform>(),
Il2CppType.Of<TComponent>()
});
}
private static GameObject CreateUiObject<TFirst, TSecond>(string name) where TFirst : Component where TSecond : Component
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Expected O, but got Unknown
return new GameObject(name, (Type[])(object)new Type[3]
{
Il2CppType.Of<RectTransform>(),
Il2CppType.Of<TFirst>(),
Il2CppType.Of<TSecond>()
});
}
}
[HarmonyPatch]
internal static class RestockShelfPatches
{
[HarmonyPatch(typeof(RestockShelf), "Interact")]
[HarmonyPostfix]
private static void AfterInteract(RestockShelf __instance)
{
RefillController.Start(__instance);
}
[HarmonyPatch(typeof(RestockShelf), "StopInteract")]
[HarmonyPostfix]
private static void AfterStopInteract(RestockShelf __instance)
{
RefillController.Stop(__instance);
}
[HarmonyPatch(typeof(RestockShelf), "Update")]
[HarmonyPostfix]
private static void AfterUpdate(RestockShelf __instance)
{
RefillController.Tick(__instance);
}
}
}