Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of PaceControl v0.1.0
PaceControl.dll
Decompiled 2 days agousing System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; 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: AssemblyVersion("0.0.0.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 PaceControl { internal static class Net { private const byte EvNeeded = 195; private static bool initialized; internal static void Init() { if (!initialized) { initialized = true; PhotonNetwork.NetworkingClient.EventReceived += OnEvent; } } internal static void Announce(int needed, int built) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown PaceState.Apply(needed, built); if (SemiFunc.IsMultiplayer() && SemiFunc.IsMasterClient() && !PhotonNetwork.RaiseEvent((byte)195, (object)new int[2] { needed, built }, new RaiseEventOptions { Receivers = (ReceiverGroup)0 }, SendOptions.SendReliable)) { Plugin.Log.LogError((object)"Could not send the extraction count to the other players; their HUD and truck healer will use the game's own count."); } } private static void OnEvent(EventData data) { try { if (data.Code == 195 && PhotonNetwork.MasterClient != null && data.Sender == PhotonNetwork.MasterClient.ActorNumber) { int[] array = (int[])data.CustomData; PaceState.Apply(array[0], (array.Length > 1) ? array[1] : array[0]); } } catch (Exception ex) { Plugin.Log.LogError((object)("Handling a pace-control network event failed: " + ex)); } } } internal static class PaceState { internal static int need; internal static int built; internal static int lastScaled = -1; internal static bool allowEnd; private static bool endTriggered; private static RoundDirector director; internal static bool Optional { get { if (Plugin.Enabled.Value && need > 0) { return built > need; } return false; } } internal static void Apply(int needed, int builtCount) { need = needed; built = builtCount; } internal static void Tick() { RoundDirector instance = RoundDirector.instance; if ((Object)(object)instance == (Object)null) { return; } if (instance != director) { director = instance; need = 0; built = 0; lastScaled = -1; allowEnd = false; endTriggered = false; } else { if (need <= 0 || !Plugin.Enabled.Value || !SemiFunc.RunIsLevel()) { return; } int num = Mathf.Max(need, Refs.ExtractionPointsCompleted.Invoke(instance)); if (Refs.ExtractionPoints.Invoke(instance) != num) { Refs.ExtractionPoints.Invoke(instance) = num; } if (!endTriggered && Optional && SemiFunc.IsMasterClientOrSingleplayer() && Refs.ExtractionPointsCompleted.Invoke(instance) >= need && SemiFunc.PlayersAllInTruck()) { endTriggered = true; allowEnd = true; try { instance.ExtractionCompletedAllCheck(); } finally { allowEnd = false; } } } } } internal sealed class PaceWatcher : MonoBehaviour { private void Awake() { Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); } private void Update() { PaceState.Tick(); } } [HarmonyPatch(typeof(RunManager), "Awake")] internal static class RunManagerAwakePatch { private static void Postfix() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) try { Net.Init(); if ((Object)(object)Object.FindObjectOfType<PaceWatcher>() == (Object)null) { new GameObject("PaceControl watcher").AddComponent<PaceWatcher>(); } } catch (Exception ex) { Plugin.Log.LogError((object)("Could not start up: " + ex)); } } } [HarmonyPatch(typeof(RoundDirector), "StartRoundLogic")] internal static class StartRoundLogicPatch { private static void Prefix(RoundDirector __instance, ref int value) { if (!Plugin.Enabled.Value || value <= 0 || !SemiFunc.RunIsLevel() || !SemiFunc.IsMasterClientOrSingleplayer() || value == PaceState.lastScaled) { return; } try { int num = Refs.ExtractionPoints.Invoke(__instance); if (num > 0) { int value2 = Plugin.RequiredExtractions.Value; int num2 = ((value2 > 0) ? Mathf.Clamp(value2, 1, num) : num); float num3 = (float)num2 / (float)num * (Plugin.HaulGoalPercent.Value / 100f); int num4 = Mathf.Max(1, Mathf.RoundToInt((float)value * num3)); Plugin.Log.LogInfo((object)("Level needs " + num2 + " of its " + num + " extraction point(s); haul goal " + value + " -> " + num4 + " (" + num4 / num2 + " each).")); PaceState.lastScaled = num4; value = num4; Net.Announce(num2, num); } } catch (Exception ex) { Plugin.Log.LogError((object)("Could not set this level's pace: " + ex)); } } } [HarmonyPatch(typeof(RoundDirector), "ExtractionCompletedAllCheck")] internal static class ExtractionCompletedAllCheckPatch { private static bool Prefix(RoundDirector __instance) { if (!Plugin.Enabled.Value) { return true; } if (Refs.AllExtractionPointsCompleted.Invoke(__instance)) { return false; } if (PaceState.Optional) { return PaceState.allowEnd; } return true; } } [BepInPlugin("vibez.PaceControl", "PaceControl", "0.1.0")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "vibez.PaceControl"; public const string Name = "PaceControl"; public const string Version = "0.1.0"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<int> RequiredExtractions; internal static ConfigEntry<float> HaulGoalPercent; private void Awake() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Turns the whole mod on or off. Off gives you the game's own pacing back. The host's setting is the one that counts - it tells everyone else how many the level needs."); RequiredExtractions = ((BaseUnityPlugin)this).Config.Bind<int>("Extractions", "RequiredExtractions", 0, new ConfigDescription("How many of a level's extraction points you actually have to complete before the level is done. 0 means all of them, the way the game plays normally (it builds one more every time levels get bigger, reaching 5 by level 15). Every extraction point is still built and still works: the ones past this number are simply optional, there to keep hauling if you want the money. Asking for more than the level has changes nothing.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 6), Array.Empty<object>())); HaulGoalPercent = ((BaseUnityPlugin)this).Config.Bind<float>("General", "HaulGoalPercent", 100f, new ConfigDescription("A further multiplier on what each extraction asks for, in percent (60 means every extraction wants 60% of what it otherwise would). Separate from the setting above, and useful on its own if you would rather keep every extraction but make each one lighter. It lowers what you MUST bring in, never what you can: anything beyond the quota is still money.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 200f), Array.Empty<object>())); new Harmony("vibez.PaceControl").PatchAll(); Log.LogInfo((object)"PaceControl 0.1.0 loaded."); } } internal static class Refs { internal static readonly FieldRef<RoundDirector, int> ExtractionPoints = AccessTools.FieldRefAccess<RoundDirector, int>("extractionPoints"); internal static readonly FieldRef<RoundDirector, int> ExtractionPointsCompleted = AccessTools.FieldRefAccess<RoundDirector, int>("extractionPointsCompleted"); internal static readonly FieldRef<RoundDirector, bool> AllExtractionPointsCompleted = AccessTools.FieldRefAccess<RoundDirector, bool>("allExtractionPointsCompleted"); } }