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 AzuCraftyBoxesBuildingOnly v1.1.0
AzuCraftyBoxesBuildingOnly.dll
Decompiled 12 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [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 AzuCraftyBoxesBuildingOnly { public enum CraftyBoxesMode { Full, BuildingOnly, Disabled } [BepInPlugin("local.valheim.azucraftyboxesbuildingonly", "AzuCraftyBoxes Building Only", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInIncompatibility("local.valheim.compatibilityfixes")] public sealed class Plugin : BaseUnityPlugin { private static class AzuShouldPreventPatch { public static void Postfix(ref bool __result) { if (ModEnabled.Value && Mode.Value != CraftyBoxesMode.Full && !AzuCallContext.InInfrastructure && (Mode.Value != CraftyBoxesMode.BuildingOnly || !AzuCallContext.InBuilding)) { __result = true; } } } public const string PluginGuid = "local.valheim.azucraftyboxesbuildingonly"; public const string PluginName = "AzuCraftyBoxes Building Only"; public const string PluginVersion = "1.1.0"; public const string AzuCraftyBoxesGuid = "Azumatt.AzuCraftyBoxes"; public const string CombinedPluginGuid = "local.valheim.compatibilityfixes"; internal static ConfigEntry<bool> LockConfiguration; internal static ConfigEntry<bool> ModEnabled; internal static ConfigEntry<CraftyBoxesMode> Mode; internal static ConfigEntry<KeyboardShortcut> ToggleMode; internal static ManualLogSource Log; private Harmony _harmony; private FileSystemWatcher _configWatcher; private readonly object _configReloadLock = new object(); private DateTime _lastConfigReloadTime; private const long ConfigReloadDelayTicks = 10000000L; private void Awake() { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; LockConfiguration = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Lock Configuration", true, "If true, synchronized gameplay settings are controlled by the server and can be changed only by server admins. [Synced with Server]"); ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Mod Enabled", true, "Master switch for this add-on. When off, AzuCraftyBoxes behaves normally. [Synced with Server]"); Mode = ((BaseUnityPlugin)this).Config.Bind<CraftyBoxesMode>("2 - AzuCraftyBoxes", "Mode", CraftyBoxesMode.BuildingOnly, "Full: normal AzuCraftyBoxes. BuildingOnly: nearby containers work only for placing structures; crafting, cooking, smelting, fermenting, fueling, turrets, and similar actions require carried items. Disabled: block all AzuCraftyBoxes pulling while keeping its container registry ready for a runtime mode change. [Synced with Server]"); ToggleMode = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("2 - AzuCraftyBoxes", "Toggle Full and Building Only", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Local input hotkey that requests a synchronized switch between Full and BuildingOnly. It works for the server, server admins, or anyone when Lock Configuration is false. It does nothing while Mode is Disabled. [Not Synced with Server]"); if (!AzuServerSyncBridge.Initialize(LockConfiguration, ModEnabled, Mode, ((BaseUnityPlugin)this).Logger)) { ((BaseUnityPlugin)this).Logger.LogError((object)"AzuCraftyBoxes' bundled ServerSync could not be initialized. This add-on is disabled to avoid unsynchronized multiplayer behavior."); return; } _harmony = new Harmony("local.valheim.azucraftyboxesbuildingonly"); _harmony.PatchAll(typeof(BuildingOperationContextPatch)); _harmony.PatchAll(typeof(AzuInfrastructureContextPatch)); InstallAzuCraftyBoxesGate(); SetupConfigWatcher(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded AzuCraftyBoxes Building Only 1.1.0. Mode: " + Mode.Value.ToString() + ". Server and all clients are required.")); } private void Update() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!ModEnabled.Value) { return; } KeyboardShortcut value = ToggleMode.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { if (!AzuServerSyncBridge.CanEditSynchronizedSettings()) { ShowModeMessage("AzuCraftyBoxes mode is controlled by the server."); return; } if (Mode.Value == CraftyBoxesMode.Disabled) { ShowModeMessage("AzuCraftyBoxes mode is Disabled; change it in config before using the toggle hotkey."); return; } Mode.Value = ((Mode.Value == CraftyBoxesMode.Full) ? CraftyBoxesMode.BuildingOnly : CraftyBoxesMode.Full); ShowModeMessage("AzuCraftyBoxes mode: " + Mode.Value); } } private void SetupConfigWatcher() { _configWatcher = new FileSystemWatcher(Paths.ConfigPath, "local.valheim.azucraftyboxesbuildingonly.cfg"); _configWatcher.Changed += ReloadConfig; _configWatcher.Created += ReloadConfig; _configWatcher.Renamed += ReloadConfig; _configWatcher.IncludeSubdirectories = false; _configWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; _configWatcher.EnableRaisingEvents = true; } private void ReloadConfig(object sender, FileSystemEventArgs args) { DateTime now = DateTime.Now; if (now.Ticks - _lastConfigReloadTime.Ticks < 10000000) { return; } _lastConfigReloadTime = now; if (!AzuServerSyncBridge.CanEditSynchronizedSettings()) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Ignored a local config-file change because synchronized settings are locked by the server."); return; } lock (_configReloadLock) { try { ((BaseUnityPlugin)this).Config.Reload(); ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Reloaded AzuCraftyBoxes Building Only configuration."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Failed to reload configuration: " + ex.Message)); } } } private void OnDestroy() { if (_configWatcher != null) { _configWatcher.Dispose(); } } private static void ShowModeMessage(string message) { Log.LogInfo((object)message); if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, message, 0, (Sprite)null); } } private void InstallAzuCraftyBoxesGate() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method("AzuCraftyBoxes.Util.Functions.MiscFunctions:ShouldPrevent", (Type[])null, (Type[])null); if (methodInfo == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"AzuCraftyBoxes ShouldPrevent was not found. Building-only mode cannot be enforced with this AzuCraftyBoxes version."); return; } HarmonyMethod val = new HarmonyMethod(typeof(AzuShouldPreventPatch), "Postfix", (Type[])null); val.priority = 0; val.after = new string[1] { "Azumatt.AzuCraftyBoxes" }; HarmonyMethod val2 = val; _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Installed the AzuCraftyBoxes Full/BuildingOnly/Disabled runtime gate."); } } internal static class AzuServerSyncBridge { private static object _configSync; private static PropertyInfo _isSourceOfTruth; private static PropertyInfo _isLocked; private static PropertyInfo _isAdmin; internal static bool Initialize(ConfigEntry<bool> lockingConfig, ConfigEntry<bool> enabledConfig, ConfigEntry<CraftyBoxesMode> modeConfig, ManualLogSource log) { try { Type type = AccessTools.TypeByName("AzuCraftyBoxes.AzuCraftyBoxesPlugin"); if (type == null) { throw new TypeLoadException("AzuCraftyBoxes.AzuCraftyBoxesPlugin was not found."); } Type type2 = type.Assembly.GetType("ServerSync.ConfigSync", throwOnError: false); if (type2 == null) { throw new TypeLoadException("AzuCraftyBoxes' bundled ServerSync.ConfigSync was not found."); } _configSync = Activator.CreateInstance(type2, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new object[1] { "local.valheim.azucraftyboxesbuildingonly" }, null); if (_configSync == null) { throw new InvalidOperationException("ServerSync.ConfigSync could not be created."); } SetMember(type2, "DisplayName", "AzuCraftyBoxes Building Only"); SetMember(type2, "CurrentVersion", "1.1.0"); SetMember(type2, "MinimumRequiredVersion", "1.1.0"); SetMember(type2, "ModRequired", true); RegisterEntry(type2, "AddLockingConfigEntry", (ConfigEntryBase)(object)lockingConfig); RegisterEntry(type2, "AddConfigEntry", (ConfigEntryBase)(object)enabledConfig); RegisterEntry(type2, "AddConfigEntry", (ConfigEntryBase)(object)modeConfig); _isSourceOfTruth = type2.GetProperty("IsSourceOfTruth", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _isLocked = type2.GetProperty("IsLocked", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _isAdmin = type2.GetProperty("IsAdmin", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (_isSourceOfTruth == null || _isLocked == null || _isAdmin == null) { throw new MissingMemberException("Required ServerSync ownership properties were not found."); } log.LogInfo((object)"Registered required-mod version checking and server-synchronized gameplay settings through AzuCraftyBoxes' bundled ServerSync."); return true; } catch (Exception ex) { _configSync = null; log.LogError((object)("ServerSync initialization failed: " + ex)); return false; } } internal static bool CanEditSynchronizedSettings() { if (_configSync == null) { return false; } bool boolean = GetBoolean(_isSourceOfTruth, fallback: true); bool boolean2 = GetBoolean(_isLocked, fallback: true); bool boolean3 = GetBoolean(_isAdmin, fallback: false); if (!(boolean || boolean3)) { return !boolean2; } return true; } private static void SetMember(Type configSyncType, string name, object value) { FieldInfo field = configSyncType.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { field.SetValue(_configSync, value); return; } PropertyInfo? property = configSyncType.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property == null) { throw new MissingMemberException(configSyncType.FullName, name); } property.SetValue(_configSync, value, null); } private static void RegisterEntry(Type configSyncType, string methodName, ConfigEntryBase entry) { MethodInfo methodInfo = null; MethodInfo[] methods = configSyncType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo2 in methods) { if (methodInfo2.Name == methodName && methodInfo2.IsGenericMethodDefinition && methodInfo2.GetParameters().Length == 1) { methodInfo = methodInfo2; break; } } if (methodInfo == null) { throw new MissingMethodException(configSyncType.FullName, methodName); } Type[] genericArguments = ((object)entry).GetType().GetGenericArguments(); if (genericArguments.Length != 1) { throw new InvalidOperationException("Could not determine the config entry's value type."); } object obj = methodInfo.MakeGenericMethod(genericArguments[0]).Invoke(_configSync, new object[1] { entry }); if (obj == null) { throw new InvalidOperationException(methodName + " returned no synchronized entry."); } FieldInfo field = obj.GetType().GetField("SynchronizedConfig", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { field.SetValue(obj, true); } } private static bool GetBoolean(PropertyInfo property, bool fallback) { if (property == null || _configSync == null) { return fallback; } object value = property.GetValue(_configSync, null); if (value is bool) { return (bool)value; } return false; } } internal static class AzuCallContext { [ThreadStatic] private static int _buildingDepth; [ThreadStatic] private static int _infrastructureDepth; internal static bool InBuilding => _buildingDepth > 0; internal static bool InInfrastructure => _infrastructureDepth > 0; internal static void EnterBuilding() { _buildingDepth++; } internal static void ExitBuilding() { if (_buildingDepth > 0) { _buildingDepth--; } } internal static void EnterInfrastructure() { _infrastructureDepth++; } internal static void ExitInfrastructure() { if (_infrastructureDepth > 0) { _infrastructureDepth--; } } } [HarmonyPatch] internal static class BuildingOperationContextPatch { private static IEnumerable<MethodBase> TargetMethods() { MethodBase methodBase = AccessTools.Method(typeof(Player), "HaveRequirements", new Type[2] { typeof(Piece), typeof(RequirementMode) }, (Type[])null); if (methodBase != null) { yield return methodBase; } methodBase = AccessTools.Method(typeof(Player), "PlacePiece", new Type[4] { typeof(Piece), typeof(Vector3), typeof(Quaternion), typeof(bool) }, (Type[])null); if (methodBase != null) { yield return methodBase; } methodBase = AccessTools.Method(typeof(Hud), "SetupPieceInfo", new Type[1] { typeof(Piece) }, (Type[])null); if (methodBase != null) { yield return methodBase; } } [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix() { AzuCallContext.EnterBuilding(); } [HarmonyFinalizer] [HarmonyPriority(0)] private static Exception Finalizer(Exception __exception) { AzuCallContext.ExitBuilding(); return __exception; } } [HarmonyPatch] internal static class AzuInfrastructureContextPatch { private static IEnumerable<MethodBase> TargetMethods() { MethodBase[] array = new MethodBase[9] { AccessTools.Method(typeof(Container), "Awake", (Type[])null, (Type[])null), AccessTools.Method(typeof(Container), "Load", (Type[])null, (Type[])null), AccessTools.Method(typeof(Container), "OnDestroyed", (Type[])null, (Type[])null), AccessTools.Method(typeof(WearNTear), "OnDestroy", (Type[])null, (Type[])null), AccessTools.Method(typeof(Player), "UpdateTeleport", (Type[])null, (Type[])null), AccessTools.Method(typeof(ObjectDB), "Awake", (Type[])null, (Type[])null), AccessTools.Method(typeof(Player), "SetLocalPlayer", (Type[])null, (Type[])null), AccessTools.Method(typeof(Player), "OnSpawned", (Type[])null, (Type[])null), AccessTools.Method(typeof(Player), "OnRespawn", (Type[])null, (Type[])null) }; MethodBase[] array2 = array; foreach (MethodBase methodBase in array2) { if (methodBase != null) { yield return methodBase; } } } [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix() { AzuCallContext.EnterInfrastructure(); } [HarmonyFinalizer] [HarmonyPriority(0)] private static Exception Finalizer(Exception __exception) { AzuCallContext.ExitInfrastructure(); return __exception; } } }