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 WorkbenchRange v0.5.0
WorkbenchRange.dll
Decompiled 8 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JG224.ModCore.API; using JG224.WorkbenchRange.Core; using JG224.WorkbenchRange.Patches; using Microsoft.CodeAnalysis; using UnityEngine; [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("WorkbenchRange")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.5.0.0")] [assembly: AssemblyInformationalVersion("0.5.0")] [assembly: AssemblyProduct("WorkbenchRange")] [assembly: AssemblyTitle("WorkbenchRange")] [assembly: AssemblyVersion("0.5.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 JG224.WorkbenchRange { [BepInPlugin("jg224.WorkbenchRange", "WorkbenchRange", "0.5.0")] [BepInProcess("valheim.exe")] [BepInDependency("com.jg224.modcore", "0.5.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "jg224.WorkbenchRange"; public const string PluginName = "WorkbenchRange"; public const string PluginVersion = "0.5.0"; public const string ModCoreGuid = "com.jg224.modcore"; public const string GeneralTweaksGuid = "JG224.GeneralTweaks"; public const int ProtocolVersion = 1; public static readonly ModuleId ModuleId = new ModuleId("workbenchrange"); private readonly List<IDisposable> _registrations = new List<IDisposable>(); private Harmony _harmony; private bool _active; private bool _shutDown; internal static ManualLogSource Log { get; private set; } internal static WorkbenchRangeConfig Settings { get; private set; } internal static ICoreServices Core { get; private set; } private void Awake() { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Settings = WorkbenchRangeConfig.Load((BaseUnityPlugin)(object)this, Paths.ConfigPath, ((BaseUnityPlugin)this).Logger); try { if (!ModCoreApi.IsAvailable) { throw new InvalidOperationException("ModCore did not initialize before WorkbenchRange."); } Core = ModCoreApi.Services; RegisterWithCore(); if (TryGetLegacyOwner(out var version)) { string text = "GeneralTweaks " + version?.ToString() + " still contains Workbench Range; WorkbenchRange is paused to prevent duplicate mutations."; Core.Modules.SetState(ModuleId, (ModuleRuntimeState)3, text); ((BaseUnityPlugin)this).Logger.LogWarning((object)(text + " Update GeneralTweaks to 3.0.0 or newer.")); return; } _harmony = new Harmony("jg224.WorkbenchRange"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); _active = true; Core.Modules.SetState(ModuleId, (ModuleRuntimeState)2, "Client-local construction range ready."); Game.isModded = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("WorkbenchRange 0.5.0 loaded; client-local settings, protocol " + 1 + ".")); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("WorkbenchRange failed to initialize safely: " + ex)); if (Core != null) { Core.Modules.SetState(ModuleId, (ModuleRuntimeState)5, ex.Message); } Shutdown(); throw; } } private void Update() { if (_active) { WorkbenchRuntime.Tick(Time.unscaledTimeAsDouble); } } private void OnDestroy() { Shutdown(); } private void RegisterWithCore() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) SemanticVersion val = default(SemanticVersion); if (!SemanticVersion.TryParse("0.5.0", ref val)) { throw new InvalidOperationException("Invalid plugin version."); } _registrations.Add(Core.Modules.Register(new ModuleDescriptor(ModuleId, "jg224.WorkbenchRange", "WorkbenchRange", val, 1, (ModuleSide)1, (ModuleRequirement)1, 0uL, 1, 1))); foreach (IDisposable item in Settings.RegisterMetadata(Core, ModuleId)) { _registrations.Add(item); } _registrations.Add(Core.Lifecycle.Subscribe(ModuleId, (LifecycleEventKind)9, (Action<LifecycleEvent>)delegate { ResetRuntime(); }, 0)); _registrations.Add(Core.Lifecycle.Subscribe(ModuleId, (LifecycleEventKind)3, (Action<LifecycleEvent>)delegate { ResetRuntime(); }, 0)); } private static bool TryGetLegacyOwner(out Version version) { version = null; if (!Chainloader.PluginInfos.TryGetValue("JG224.GeneralTweaks", out var value)) { return false; } version = value.Metadata.Version; if (version != null) { return version.CompareTo(new Version(3, 0, 0)) < 0; } return false; } private void ResetRuntime() { WorkbenchRuntime.RestoreAll(); } private void Shutdown() { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) if (_shutDown) { return; } _shutDown = true; _active = false; Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _harmony = null; ResetRuntime(); for (int num = _registrations.Count - 1; num >= 0; num--) { try { _registrations[num].Dispose(); } catch (Exception ex) { ManualLogSource logger = ((BaseUnityPlugin)this).Logger; if (logger != null) { logger.LogWarning((object)("Registration cleanup failed: " + ex.Message)); } } } _registrations.Clear(); if (Core != null) { Core.Metrics.RemoveOwner(ModuleId); } Core = null; Settings = null; Log = null; } internal static void Debug(string message) { WorkbenchRangeConfig settings = Settings; if (settings != null && settings.DebugLogging.Value) { ManualLogSource log = Log; if (log != null) { log.LogDebug((object)message); } } } } internal sealed class WorkbenchRangeConfig { private readonly ConfigFile _file; private readonly List<Tuple<ConfigEntryBase, ConfigScope>> _entries = new List<Tuple<ConfigEntryBase, ConfigScope>>(); internal ConfigEntry<bool> Enabled { get; } internal ConfigEntry<float> ConstructionRadius { get; } internal ConfigEntry<ConstructionRangeMode> RangeMode { get; } internal ConfigEntry<bool> NeverReduce { get; } internal ConfigEntry<string> StationOverrides { get; } internal ConfigEntry<bool> DebugLogging { get; } private WorkbenchRangeConfig(ConfigFile file) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown _file = file; Enabled = Add<bool>(file.Bind<bool>("Workbench", "Enabled", true, "Apply this client's configured construction radius to vanilla crafting stations."), (ConfigScope)1); ConstructionRadius = Add<float>(file.Bind<float>("Workbench", "ConstructionRadius", 30f, new ConfigDescription("Construction radius in metres; RangeMode chooses base or final radius. Vanilla's usual base is 20.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 100f), Array.Empty<object>())), (ConfigScope)1); RangeMode = Add<ConstructionRangeMode>(file.Bind<ConstructionRangeMode>("Workbench", "RangeMode", ConstructionRangeMode.Base, "Base preserves vanilla extension bonuses; Final subtracts those bonuses to target the final radius (bonuses alone remain a lower bound)."), (ConfigScope)1); NeverReduce = Add<bool>(file.Bind<bool>("Workbench", "NeverReduce", false, "Never reduce a station below its original range, including current extension bonuses."), (ConfigScope)1); StationOverrides = Add<string>(file.Bind<string>("Workbench", "StationOverrides", "", "Per-prefab settings: piece_workbench=40;forge=35;custom_station=off. Radius 5-100m; off preserves that station."), (ConfigScope)1); DebugLogging = Add<bool>(file.Bind<bool>("Diagnostics", "DebugLogging", false, "Enable verbose WorkbenchRange diagnostics."), (ConfigScope)5); } internal static WorkbenchRangeConfig Load(BaseUnityPlugin plugin, string configDirectory, ManualLogSource log) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown if (!Directory.Exists(configDirectory)) { Directory.CreateDirectory(configDirectory); } string text = LegacyWorkbenchConfigRules.FindImportSource(Directory.GetFiles(configDirectory, "*.cfg", SearchOption.TopDirectoryOnly)); WorkbenchRangeConfig workbenchRangeConfig = new WorkbenchRangeConfig(PluginConfigFiles.Attach(plugin, new ConfigFile(Path.Combine(configDirectory, "jg224.WorkbenchRange.cfg"), true, plugin.Info.Metadata))); if (text != null) { workbenchRangeConfig.ImportLegacy(text, log); } return workbenchRangeConfig; } internal IEnumerable<IDisposable> RegisterMetadata(ICoreServices services, ModuleId owner) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) foreach (Tuple<ConfigEntryBase, ConfigScope> pair in _entries) { yield return services.Configuration.Register(new ConfigSettingDescriptor(owner, pair.Item1.Definition.Section, pair.Item1.Definition.Key, pair.Item2, (Func<string>)(() => Convert.ToString(pair.Item1.BoxedValue, CultureInfo.InvariantCulture)), 1)); } } private void ImportLegacy(string path, ManualLogSource log) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown try { ConfigFile val = new ConfigFile(path, false); Enabled.Value = val.Bind<bool>("Workbench", "Enabled", Enabled.Value, (ConfigDescription)null).Value; ConstructionRadius.Value = val.Bind<float>("Workbench", "ConstructionRadius", ConstructionRadius.Value, (ConfigDescription)null).Value; _file.Save(); if (log != null) { log.LogInfo((object)("Imported Workbench Range settings from " + Path.GetFileName(path) + ".")); } } catch (Exception ex) { if (log != null) { log.LogWarning((object)("Could not import GeneralTweaks Workbench settings; using defaults. " + ex.Message)); } } } private ConfigEntry<T> Add<T>(ConfigEntry<T> entry, ConfigScope scope) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) _entries.Add(Tuple.Create<ConfigEntryBase, ConfigScope>((ConfigEntryBase)(object)entry, scope)); return entry; } } } namespace JG224.WorkbenchRange.Patches { internal static class WorkbenchRuntime { private sealed class Record { internal CraftingStation Station; internal float OriginalRange; internal float Applied = float.NaN; } private static readonly Dictionary<int, Record> Records = new Dictionary<int, Record>(); private static readonly List<int> Dead = new List<int>(); private static Dictionary<string, float> _overrides = WorkbenchRules.ParseOverrides(""); private static string _raw; private static readonly FieldRef<CraftingStation, float> UpdateTimer = AccessTools.FieldRefAccess<CraftingStation, float>("m_updateExtensionTimer"); private static readonly FieldRef<CraftingStation, CircleProjector> MarkerCircle = AccessTools.FieldRefAccess<CraftingStation, CircleProjector>("m_areaMarkerCircle"); private static double _nextScan; internal static void Invalidate() { _nextScan = 0.0; } internal static void TrackAndApply(CraftingStation station) { if (Object.op_Implicit((Object)(object)station)) { int instanceID = ((Object)station).GetInstanceID(); if (!Records.TryGetValue(instanceID, out var value) || (Object)(object)value.Station != (Object)(object)station) { value = new Record { Station = station, OriginalRange = station.m_rangeBuild }; Records[instanceID] = value; } RefreshOverrides(); Apply(value); } } internal static void Tick(double now) { if (now < _nextScan) { return; } _nextScan = now + 1.0; RefreshOverrides(); List<IMonoUpdater> instances = CraftingStation.Instances; for (int i = 0; i < instances.Count; i++) { IMonoUpdater obj = instances[i]; CraftingStation val = (CraftingStation)(object)((obj is CraftingStation) ? obj : null); if (Object.op_Implicit((Object)(object)val)) { TrackAndApply(val); } } Dead.Clear(); foreach (KeyValuePair<int, Record> record in Records) { if (!Object.op_Implicit((Object)(object)record.Value.Station)) { Dead.Add(record.Key); } } for (int j = 0; j < Dead.Count; j++) { Records.Remove(Dead[j]); } } internal static void RestoreAll() { foreach (Record value in Records.Values) { Restore(value); } Records.Clear(); Dead.Clear(); _raw = null; _nextScan = 0.0; } private static void RefreshOverrides() { string text = Plugin.Settings?.StationOverrides.Value ?? ""; if (!(_raw == text)) { _raw = text; _overrides = WorkbenchRules.ParseOverrides(text); } } private static void Apply(Record record) { WorkbenchRangeConfig settings = Plugin.Settings; float num = settings?.ConstructionRadius.Value ?? 30f; string key = ((Object)((Component)record.Station).gameObject).name.Replace("(Clone)", "").Trim(); if (_overrides.TryGetValue(key, out var value)) { num = value; } if (settings == null || !settings.Enabled.Value || num < 0f) { Restore(record); } else if (CanRefresh(record.Station)) { if (float.IsNaN(record.Applied) || !WorkbenchRules.OwnsValue(record.Station.m_rangeBuild, record.Applied)) { record.OriginalRange = record.Station.m_rangeBuild; } float extensionBonus = (float)record.Station.GetExtentionCount(false) * record.Station.m_extraRangePerLevel; float num2 = WorkbenchRules.ResolveBaseRange(num, record.OriginalRange, extensionBonus, settings.RangeMode.Value, settings.NeverReduce.Value); if (!WorkbenchRules.OwnsValue(record.Station.m_rangeBuild, num2)) { record.Station.m_rangeBuild = num2; record.Applied = num2; Refresh(record.Station); } } } private static void Restore(Record record) { if (Object.op_Implicit((Object)(object)record.Station) && WorkbenchRules.OwnsValue(record.Station.m_rangeBuild, record.Applied)) { record.Station.m_rangeBuild = record.OriginalRange; Refresh(record.Station); } record.Applied = float.NaN; } private static void Refresh(CraftingStation station) { try { UpdateTimer.Invoke(station) = 2f; if (CanRefresh(station)) { station.GetStationBuildRange(); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("Could not refresh crafting-station range marker: " + ex)); } } } private static bool CanRefresh(CraftingStation station) { if (Object.op_Implicit((Object)(object)station.m_areaMarker)) { return Object.op_Implicit((Object)(object)MarkerCircle.Invoke(station)); } return true; } } [HarmonyPatch(typeof(CraftingStation), "Start")] internal static class WorkbenchStartPatch { [HarmonyPostfix] private static void Postfix(CraftingStation __instance) { WorkbenchRuntime.TrackAndApply(__instance); } } } namespace JG224.WorkbenchRange.Core { internal enum ConstructionRangeMode { Base, Final } internal static class WorkbenchRules { internal static bool IsValidRange(float range) { if (!float.IsNaN(range) && !float.IsInfinity(range) && range >= 5f) { return range <= 100f; } return false; } internal static float ResolveBaseRange(float requested, float original, float extensionBonus, ConstructionRangeMode mode, bool neverReduce) { if (!IsValidRange(requested) || !Finite(original) || !Finite(extensionBonus)) { return original; } extensionBonus = Math.Max(0f, extensionBonus); float num = ((mode == ConstructionRangeMode.Final) ? Math.Max(0f, requested - extensionBonus) : requested); if (!neverReduce) { return num; } return Math.Max(original, num); } internal static Dictionary<string, float> ParseOverrides(string raw) { Dictionary<string, float> dictionary = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase); string[] array = (raw ?? "").Split(new char[1] { ';' }); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { '=' }); if (array2.Length == 2 && array2[0].Trim().Length != 0) { float result; if (string.Equals(array2[1].Trim(), "off", StringComparison.OrdinalIgnoreCase)) { dictionary[array2[0].Trim()] = -1f; } else if (float.TryParse(array2[1], NumberStyles.Float, CultureInfo.InvariantCulture, out result) && IsValidRange(result)) { dictionary[array2[0].Trim()] = result; } } } return dictionary; } internal static bool OwnsValue(float current, float applied) { if (Finite(current) && Finite(applied)) { return Math.Abs(current - applied) < 0.001f; } return false; } private static bool Finite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } internal static class LegacyWorkbenchConfigRules { internal const string CurrentFileName = "jg224.WorkbenchRange.cfg"; internal const string GeneralTweaksFileName = "jg224.GeneralTweaks.cfg"; internal const string LegacyGeneralTweaksFileName = "JG224.GeneralTweaks.cfg"; internal static string FindImportSource(IEnumerable<string> candidatePaths) { string[] paths = ((candidatePaths == null) ? Array.Empty<string>() : candidatePaths.ToArray()); if (FindExact(paths, "jg224.WorkbenchRange.cfg") != null) { return null; } return FindExact(paths, "jg224.GeneralTweaks.cfg") ?? FindExact(paths, "JG224.GeneralTweaks.cfg"); } private static string FindExact(IEnumerable<string> paths, string fileName) { return paths.FirstOrDefault((string path) => string.Equals(Path.GetFileName(path), fileName, StringComparison.Ordinal)); } } }