Decompiled source of MinMaxPrices v0.1.1

plugins/MinMaxPrices/MinMaxPrices.dll

Decompiled a week ago
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 HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("saya")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyInformationalVersion("0.1.1")]
[assembly: AssemblyProduct("MinMaxPrices")]
[assembly: AssemblyTitle("MinMaxPrices")]
[assembly: AssemblyVersion("0.1.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 MinMaxPrices
{
	internal sealed class DeferredPrices
	{
		internal sealed class Scope
		{
			internal readonly Scope? Parent;

			internal readonly List<Action> Changes = new List<Action>();

			internal bool Closed;

			internal Scope(Scope? parent)
			{
				Parent = parent;
			}
		}

		private Scope? _current;

		public Scope Begin()
		{
			return _current = new Scope(_current);
		}

		public void ApplyOrDefer(Action change)
		{
			if (_current == null)
			{
				change();
			}
			else
			{
				_current.Changes.Add(change);
			}
		}

		public void End(Scope scope, bool success)
		{
			if (scope.Closed)
			{
				return;
			}
			scope.Closed = true;
			_current = scope.Parent;
			if (!success)
			{
				return;
			}
			if (_current != null)
			{
				_current.Changes.AddRange(scope.Changes);
				return;
			}
			foreach (Action change in scope.Changes)
			{
				change();
			}
		}
	}
	[BepInPlugin("saya.MinMaxPrices", "MinMaxPrices", "0.1.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "saya.MinMaxPrices";

		public const string PluginName = "MinMaxPrices";

		public const string PluginVersion = "0.1.1";

		private readonly Harmony _harmony = new Harmony("saya.MinMaxPrices");

		private static ConfigEntry<PriceMode>? _valuableMode;

		private static ConfigEntry<PriceMode>? _shopMode;

		internal static PriceMode ValuableMode => _valuableMode?.Value ?? PriceMode.Normal;

		internal static PriceMode ShopMode => _shopMode?.Value ?? PriceMode.Normal;

		internal static bool IsAuthority
		{
			get
			{
				if ((Object)(object)GameManager.instance != (Object)null)
				{
					if (GameManager.Multiplayer())
					{
						return PhotonNetwork.IsMasterClient;
					}
					return true;
				}
				return false;
			}
		}

		private void Awake()
		{
			((Component)this).transform.SetParent((Transform)null);
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			_valuableMode = ((BaseUnityPlugin)this).Config.Bind<PriceMode>("Prices", "ValuablePrice", PriceMode.Normal, "Normal keeps random valuable prices. Min or Max selects each valuable's own range endpoint, including enemy orbs. Applies to newly spawned valuables only; damage and fixed-value rewards are unchanged. Spawn budgeting keeps the original roll, but the extraction goal follows the selected prices. Only the host's setting is used.");
			_shopMode = ((BaseUnityPlugin)this).Config.Bind<PriceMode>("Prices", "ShopPrice", PriceMode.Normal, "Normal keeps random shop prices. Min or Max selects each item's base range endpoint before vanilla multipliers and rounding. Applies to newly generated shop stock only; existing prices and carried items are unchanged. Only the host's setting is used.");
			try
			{
				_harmony.PatchAll(typeof(ValuablePricePatch));
				_harmony.PatchAll(typeof(ValuableSpawnPatch));
				_harmony.PatchAll(typeof(ShopPricePatch));
				((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} v{1} loaded. ValuablePrice={2}, ShopPrice={3}.", "MinMaxPrices", "0.1.1", ValuableMode, ShopMode));
			}
			catch (Exception arg)
			{
				_harmony.UnpatchSelf();
				((Behaviour)this).enabled = false;
				((BaseUnityPlugin)this).Logger.LogError((object)$"MinMaxPrices initialization failed: {arg}");
			}
		}

		private void OnDestroy()
		{
			_harmony.UnpatchSelf();
			_valuableMode = null;
			_shopMode = null;
		}
	}
	public enum PriceMode
	{
		Normal,
		Min,
		Max
	}
	internal static class PriceSelection
	{
		public static bool TrySelect(PriceMode mode, float minimum, float maximum, out float value)
		{
			value = 0f;
			if ((mode != PriceMode.Min && mode != PriceMode.Max) || float.IsNaN(minimum) || float.IsInfinity(minimum) || float.IsNaN(maximum) || float.IsInfinity(maximum) || minimum < 0f || maximum < minimum)
			{
				return false;
			}
			value = ((mode == PriceMode.Min) ? minimum : maximum);
			return true;
		}

		public static float RoundValuable(float value)
		{
			return (float)Math.Round((float)Math.Round(value) / 100f) * 100f;
		}
	}
	[HarmonyPatch(typeof(ItemAttributes), "GetValue")]
	internal static class ShopPricePatch
	{
		private readonly struct SavedRange
		{
			public readonly float Minimum;

			public readonly float Maximum;

			public SavedRange(float minimum, float maximum)
			{
				Minimum = minimum;
				Maximum = maximum;
			}
		}

		[HarmonyPrefix]
		private static void Prefix(bool ___shopItem, ref float ___itemValueMin, ref float ___itemValueMax, out SavedRange? __state)
		{
			__state = null;
			if (Plugin.IsAuthority && ___shopItem && PriceSelection.TrySelect(Plugin.ShopMode, ___itemValueMin, ___itemValueMax, out var value))
			{
				__state = new SavedRange(___itemValueMin, ___itemValueMax);
				___itemValueMin = value;
				___itemValueMax = value;
			}
		}

		[HarmonyFinalizer]
		private static void Finalizer(ref float ___itemValueMin, ref float ___itemValueMax, SavedRange? __state)
		{
			if (__state.HasValue)
			{
				___itemValueMin = __state.Value.Minimum;
				___itemValueMax = __state.Value.Maximum;
			}
		}
	}
	[HarmonyPatch(typeof(ValuableObject), "DollarValueSetLogic")]
	internal static class ValuablePricePatch
	{
		internal static readonly DeferredPrices Pending = new DeferredPrices();

		private static readonly FieldRef<ValuableObject, float> Original = AccessTools.FieldRefAccess<ValuableObject, float>("dollarValueOriginal");

		private static readonly FieldRef<ValuableObject, float> Current = AccessTools.FieldRefAccess<ValuableObject, float>("dollarValueCurrent");

		[HarmonyPrefix]
		private static void Prefix(ValuableObject __instance, bool ___dollarValueSet, int ___dollarValueOverride, out float? __state)
		{
			__state = null;
			if (!(!Plugin.IsAuthority || ___dollarValueSet) && ___dollarValueOverride == 0 && !((Object)(object)__instance.valuePreset == (Object)null) && PriceSelection.TrySelect(Plugin.ValuableMode, __instance.valuePreset.valueMin, __instance.valuePreset.valueMax, out var value))
			{
				__state = PriceSelection.RoundValuable(value);
			}
		}

		[HarmonyPostfix]
		private static void Postfix(ValuableObject __instance, bool ___dollarValueSet, bool __runOriginal, float? __state)
		{
			if (!__runOriginal || !___dollarValueSet || !__state.HasValue)
			{
				return;
			}
			float price = __state.Value;
			Pending.ApplyOrDefer(delegate
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					Original.Invoke(__instance) = price;
					Current.Invoke(__instance) = price;
				}
			});
		}
	}
	[HarmonyPatch(typeof(ValuableDirector), "SpawnValuable")]
	internal static class ValuableSpawnPatch
	{
		[HarmonyPrefix]
		private static void Prefix(out DeferredPrices.Scope? __state)
		{
			__state = (Plugin.IsAuthority ? ValuablePricePatch.Pending.Begin() : null);
		}

		[HarmonyFinalizer]
		private static void Finalizer(DeferredPrices.Scope? __state, Exception? __exception)
		{
			if (__state != null)
			{
				ValuablePricePatch.Pending.End(__state, __exception == null);
			}
		}
	}
}