using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; 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("ExtractionRandomizerPlus")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1")] [assembly: AssemblyProduct("ExtractionRandomizerPlus")] [assembly: AssemblyTitle("ExtractionRandomizerPlus")] [assembly: AssemblyVersion("1.0.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 ExtractionRandomizerPlus { [HarmonyPatch] [HarmonyPriority(0)] internal static class LevelGeneratorExtractionAmountPatch { private static readonly FieldInfo ExtractionAmount = AccessTools.Field(typeof(LevelGenerator), "ExtractionAmount"); private static MethodBase TargetMethod() { Type type = typeof(LevelGenerator).GetNestedTypes(BindingFlags.NonPublic).FirstOrDefault((Type t) => t.Name.StartsWith("d__", StringComparison.Ordinal)); if (!(type == null)) { return AccessTools.Method(type, "MoveNext", (Type[])null, (Type[])null); } return null; } private static IEnumerable Transpiler(IEnumerable instructions) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown List list = instructions.ToList(); MethodInfo methodInfo = AccessTools.Method(typeof(LevelGeneratorExtractionAmountPatch), "ApplyExtractionCount", (Type[])null, (Type[])null); int num = list.FindIndex((CodeInstruction code) => code.opcode == OpCodes.Call && (code.operand as MethodInfo)?.Name == "IsLevelShop"); if (num >= 0) { list.Insert(num, new CodeInstruction(OpCodes.Ldloc_1, (object)null)); list.Insert(num + 1, new CodeInstruction(OpCodes.Call, (object)methodInfo)); } else { Plugin.Log.LogWarning((object)"[ExtractionRandomizerPlus] Could not find IsLevelShop in TileGeneration; ExtractionAmount will not be raised."); } return list; } private static void ApplyExtractionCount(LevelGenerator generator) { try { if (!((Object)(object)generator == (Object)null) && SemiFunc.IsMasterClientOrSingleplayer() && SemiFunc.RunIsLevel() && !SemiFunc.IsLevelShop(generator.Level)) { int num = (int)ExtractionAmount.GetValue(generator); int num2 = Plugin.EnsureTargetCount(); int num3 = Math.Max(0, num2 - 1); if (num == num3) { Plugin.Log.LogInfo((object)($"[ExtractionRandomizerPlus] ExtractionAmount already {num3} " + $"(total {num2} incl. truck extraction)")); return; } ExtractionAmount.SetValue(generator, num3); Plugin.Log.LogInfo((object)($"[ExtractionRandomizerPlus] ExtractionAmount: {num} -> {num3} " + $"(total {num2} incl. truck extraction)")); } } catch (Exception ex) { Plugin.Log.LogError((object)("[ExtractionRandomizerPlus] Could not set ExtractionAmount: " + ex)); } } } internal static class LevelSeed { internal static string Describe() { return RoomName() + "|" + LevelName() + "|" + SemiFunc.RunGetLevelsCompleted(); } private static string LevelName() { RunManager instance = RunManager.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.levelCurrent == (Object)null) { return "unknown-level"; } return ((Object)instance.levelCurrent).name; } private static string RoomName() { try { Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom != null && !string.IsNullOrEmpty(currentRoom.Name)) { return currentRoom.Name; } } catch { } return "offline"; } } [HarmonyPatch(typeof(ExtractionPoint), "HaulGoalSet")] internal static class HaulGoalPatch { private static void Prefix(ref int value) { if (SemiFunc.IsMasterClientOrSingleplayer() && SemiFunc.RunIsLevel()) { float value2 = Plugin.HaulGoalMultiplier.Value; int num = Mathf.Max(1, (int)((float)value * value2)); Plugin.Log.LogInfo((object)$"[ExtractionRandomizerPlus] HaulGoal scaled on host: {value} * {value2} -> {num}"); value = num; } } } [HarmonyPatch(typeof(LevelGenerator), "TileGeneration")] internal static class LevelGeneratorTileGenerationResetPatch { private static void Prefix() { Plugin.TargetCount = -1; Plugin.Log.LogInfo((object)"[ExtractionRandomizerPlus] New level - target count reset"); } } [BepInPlugin("firenyth.extractionrandomizerplus", "Extraction Randomizer Plus", "1.0.1")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "firenyth.extractionrandomizerplus"; public const string PluginVersion = "1.0.1"; public static ConfigEntry MinExtractionPoints; public static ConfigEntry MaxExtractionPoints; public static ConfigEntry HaulGoalMultiplier; internal static int TargetCount = -1; internal static Plugin Instance { get; private set; } internal static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger; internal static int EnsureTargetCount() { int num = MinExtractionPoints.Value; int value = MaxExtractionPoints.Value; if (num > value) { num = value; } if (TargetCount == -1) { string text = LevelSeed.Describe(); int num2 = StableHash.Of(text); TargetCount = new Random(num2).Next(num, value + 1); Log.LogInfo((object)($"[ExtractionRandomizerPlus] Level: {text}, Seed: {num2}, " + $"Target: {TargetCount} total extraction points (range {num}-{value})")); } return TargetCount; } private void Awake() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_00ac: Unknown result type (might be due to invalid IL or missing references) Instance = this; MinExtractionPoints = ((BaseUnityPlugin)this).Config.Bind("Extraction Points", "Minimum", 1, new ConfigDescription("Minimum total extraction points per level (the truck extraction counts toward this)", (AcceptableValueBase)(object)new AcceptableValueRange(1, 10), Array.Empty())); MaxExtractionPoints = ((BaseUnityPlugin)this).Config.Bind("Extraction Points", "Maximum", 3, new ConfigDescription("Maximum total extraction points per level (the truck extraction counts toward this)", (AcceptableValueBase)(object)new AcceptableValueRange(1, 10), Array.Empty())); HaulGoalMultiplier = ((BaseUnityPlugin)this).Config.Bind("Rewards", "Haul Goal Multiplier", 0.33f, new ConfigDescription("Host-side haul goal multiplier. 0.33 is one third of vanilla.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 2f), Array.Empty())); new Harmony("firenyth.extractionrandomizerplus").PatchAll(); Log.LogInfo((object)(string.Format("ExtractionRandomizerPlus {0} loaded! Min={1}, ", "1.0.1", MinExtractionPoints.Value) + $"Max={MaxExtractionPoints.Value}, HaulGoalMultiplier={HaulGoalMultiplier.Value}. " + "The host decides extraction count by setting LevelGenerator.ExtractionAmount.")); } } internal static class StableHash { internal static int Of(string value) { uint num = 5381u; for (int i = 0; i < value.Length; i++) { num = ((num << 5) + num) ^ value[i]; } return (int)(num & 0x7FFFFFFF); } } }