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 SpawnRestrictions v0.2.0
BepInEx/plugins/SpawnRestrictions.dll
Decompiled 3 weeks agousing System; 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 SpawnRestrictions.Configuration; using SpawnRestrictions.Patches; using SpawnRestrictions.Services; 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: 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 SpawnRestrictions { [BepInPlugin("spawnrestrictions.valheim", "Spawn Restrictions", "0.2.0")] public sealed class SpawnRestrictionsPlugin : BaseUnityPlugin { public const string PluginGuid = "spawnrestrictions.valheim"; public const string PluginName = "Spawn Restrictions"; public const string PluginVersion = "0.2.0"; private Harmony _harmony; private ServerRuleSync _sync; private float _nextUpdate; private void Awake() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown BossRestrictionState state = new BossRestrictionState(); _sync = new ServerRuleSync(new BossRestrictionSettings(((BaseUnityPlugin)this).Config), state); BossPatches.Initialize(state, _sync); _harmony = new Harmony("spawnrestrictions.valheim"); _harmony.CreateClassProcessor(typeof(BossPatches)).Patch(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Spawn Restrictions loaded. Install this version on the host/server and every client."); } private void Update() { if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.HaveStopped && !(Time.unscaledTime < _nextUpdate)) { _nextUpdate = Time.unscaledTime + 0.5f; _sync.Broadcast(); } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } BossPatches.Clear(); } } } namespace SpawnRestrictions.Services { internal static class BossMessages { public static void Show(Humanoid player, BossRestrictionState state) { if (!((Object)(object)player == (Object)null)) { string text = (state.IsReady ? $"Bosses require {state.RequiredPlayers} players online ({state.OnlinePlayers} online)." : "Waiting for the server's boss restrictions."); ((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false); } } } internal static class BossProgressionService { public static bool IsDefeated(GameObject bossPrefab) { if ((Object)(object)bossPrefab == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null) { return false; } Character component = bossPrefab.GetComponent<Character>(); if ((Object)(object)component != (Object)null && !string.IsNullOrEmpty(component.m_defeatSetGlobalKey)) { return ZoneSystem.instance.GetGlobalKey(component.m_defeatSetGlobalKey); } return false; } } internal sealed class BossRestrictionState { public bool IsReady { get; private set; } public int RequiredPlayers { get; private set; } public int OnlinePlayers { get; private set; } public bool AllowDefeatedBosses { get; private set; } public bool AllowsSummoning(bool defeatedInWorld) { if (IsReady) { if (RequiredPlayers != 0 && OnlinePlayers < RequiredPlayers) { return AllowDefeatedBosses && defeatedInWorld; } return true; } return false; } public void Set(int requiredPlayers, int onlinePlayers, bool allowDefeatedBosses) { if (requiredPlayers >= 0 && onlinePlayers >= 0) { RequiredPlayers = requiredPlayers; OnlinePlayers = onlinePlayers; AllowDefeatedBosses = allowDefeatedBosses; IsReady = true; } } public void Reset() { IsReady = false; RequiredPlayers = 0; OnlinePlayers = 0; AllowDefeatedBosses = false; } } internal sealed class ServerRuleSync { private const string StateRpc = "SpawnRestrictions.State.v2"; private readonly BossRestrictionSettings _settings; private readonly BossRestrictionState _state; public ServerRuleSync(BossRestrictionSettings settings, BossRestrictionState state) { _settings = settings; _state = state; } public void RegisterPeer(ZNetPeer peer) { peer.m_rpc.Register<int, int, bool>("SpawnRestrictions.State.v2", (Action<ZRpc, int, int, bool>)ReceiveState); } public void RefreshHost() { ZNet instance = ZNet.instance; if ((Object)(object)instance != (Object)null && instance.IsServer()) { _state.Set(_settings.RequiredOnlinePlayers.Value, instance.GetNrOfPlayers(), _settings.AllowDefeatedBosses.Value); } } public void Broadcast() { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || !instance.IsServer()) { return; } RefreshHost(); foreach (ZNetPeer peer in instance.GetPeers()) { if (peer.IsReady()) { peer.m_rpc.Invoke("SpawnRestrictions.State.v2", new object[3] { _state.RequiredPlayers, _state.OnlinePlayers, _state.AllowDefeatedBosses }); } } } private void ReceiveState(ZRpc rpc, int requiredPlayers, int onlinePlayers, bool allowDefeatedBosses) { ZNet instance = ZNet.instance; if (!((Object)(object)instance == (Object)null) && !instance.IsServer() && rpc == instance.GetServerRPC()) { _state.Set(requiredPlayers, onlinePlayers, allowDefeatedBosses); } } } } namespace SpawnRestrictions.Patches { [HarmonyPatch] internal static class BossPatches { private static BossRestrictionState _state; private static ServerRuleSync _sync; public static void Initialize(BossRestrictionState state, ServerRuleSync sync) { _state = state; _sync = sync; } public static void Clear() { _state = null; _sync = null; } [HarmonyPatch(typeof(ZNet), "Awake")] [HarmonyPrefix] private static void BeginSession() { _state.Reset(); } [HarmonyPatch(typeof(ZNet), "OnDestroy")] [HarmonyPostfix] private static void EndSession() { _state.Reset(); } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] [HarmonyPrefix] private static void RegisterPeer(ZNetPeer peer) { _sync.RegisterPeer(peer); } [HarmonyPatch(typeof(OfferingBowl), "UseItem")] [HarmonyPrefix] private static bool UseItem(OfferingBowl __instance, Humanoid user, ItemData item, ref bool __result) { if (__instance.m_useItemStands || (Object)(object)__instance.m_bossPrefab == (Object)null || (Object)(object)__instance.m_bossItem == (Object)null || item == null || item.m_shared.m_name != __instance.m_bossItem.m_itemData.m_shared.m_name || AllowsBosses(__instance)) { return true; } BossMessages.Show(user, _state); __result = true; return false; } [HarmonyPatch(typeof(OfferingBowl), "Interact")] [HarmonyPrefix] private static bool Interact(OfferingBowl __instance, Humanoid user, bool hold, ref bool __result) { if (hold || !__instance.m_useItemStands || (Object)(object)__instance.m_bossPrefab == (Object)null || AllowsBosses(__instance)) { return true; } BossMessages.Show(user, _state); __result = false; return false; } [HarmonyPatch(typeof(OfferingBowl), "RPC_SpawnBoss")] [HarmonyPrefix] private static bool SpawnBoss(OfferingBowl __instance) { if (!((Object)(object)__instance.m_bossPrefab == (Object)null)) { return AllowsBosses(__instance); } return true; } private static bool AllowsBosses(OfferingBowl bowl) { _sync.RefreshHost(); bool defeatedInWorld = _state.AllowDefeatedBosses && BossProgressionService.IsDefeated(bowl.m_bossPrefab); return _state.AllowsSummoning(defeatedInWorld); } } } namespace SpawnRestrictions.Configuration { internal sealed class BossRestrictionSettings { public ConfigEntry<int> RequiredOnlinePlayers { get; } public ConfigEntry<bool> AllowDefeatedBosses { get; } public BossRestrictionSettings(ConfigFile config) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown RequiredOnlinePlayers = config.Bind<int>("Boss restrictions", "Required online players", 2, new ConfigDescription("Minimum online players to summon bosses at altars. Only the host/server value is used. 0 disables the restriction. Existing bosses are unaffected.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, int.MaxValue), Array.Empty<object>())); AllowDefeatedBosses = config.Bind<bool>("Boss restrictions", "Allow defeated bosses", true, "Allow bosses already defeated in the current world to be summoned regardless of player count. Only the host/server value is used. False applies the player requirement to every boss."); } } }