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 PlanBuildDupeFix v1.0.1
PlanBuildDupeFix.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Splatform; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("PlanBuildDupeFix")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1+13f792a862a96ff7f354c9cd85f4c5cfdb005caf")] [assembly: AssemblyProduct("PlanBuildDupeFix")] [assembly: AssemblyTitle("PlanBuildDupeFix")] [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 PlanBuildDupeFix { [BepInPlugin("qua8ion.valheim.planbuilddupefix", "PlanBuildDupeFix", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class PlanBuildDupeFixPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(TeleportWorld), "SetText")] private static class TeleportWorldSetTextPatch { private static bool Prefix(string text, ZNetView ___m_nview) { if (HasLocalUser()) { return true; } if ((Object)(object)___m_nview != (Object)null && ___m_nview.IsValid()) { ___m_nview.InvokeRPC("RPC_SetTag", new object[2] { text, "" }); CountText("portal"); } return false; } } [HarmonyPatch(typeof(Sign), "SetText")] private static class SignSetTextPatch { private static bool Prefix(string text, ZNetView ___m_nview) { if (HasLocalUser()) { return true; } if ((Object)(object)___m_nview != (Object)null && ___m_nview.IsValid()) { ___m_nview.ClaimOwnership(); ___m_nview.GetZDO().Set(ZDOVars.s_text, text); ___m_nview.GetZDO().Set(ZDOVars.s_author, ""); CountText("sign"); } return false; } } [HarmonyPatch(typeof(ZDOMan), "LoadChunks")] private static class LoadChunksPatch { private static void Postfix() { //IL_011c: Unknown result type (might be due to invalid IL or missing references) if (!removeStackedCopies.Value || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } List<ZDO> list = (from val in ZDOMan.instance.GetPortalList() where val.GetLong(ZDOVars.s_creator, 0L) == 0 select val).ToList(); HashSet<ZDO> hashSet = new HashSet<ZDO>(); foreach (ZDO zdo in list) { if (hashSet.Contains(zdo)) { continue; } List<ZDO> list2 = list.Where((ZDO other) => other.GetPrefab() == zdo.GetPrefab() && Vector3.Distance(other.GetPosition(), zdo.GetPosition()) < 0.05f).ToList(); hashSet.UnionWith(list2); if (list2.Count < 2) { continue; } foreach (ZDO item in list2) { item.SetOwner(ZDOMan.GetSessionID()); ZDOMan.instance.DestroyZDO(item); } log.LogInfo((object)$"Removed {list2.Count} portal copies without a creator stacked at {zdo.GetPosition()}"); } } } private static class XPortalList { private static object manager; private static MethodInfo getList; private static PropertyInfo portalId; private static Func<ZDOID, bool> isKnown; private static Action<long, ZDOID> removeRequest; private static readonly HashSet<ZDOID> destroyed = new HashSet<ZDOID>(); internal static bool Ready { get; private set; } internal static bool Init() { Type type = AccessTools.TypeByName("XPortal.KnownPortalsManager"); Type type2 = AccessTools.TypeByName("XPortal.KnownPortal"); MethodInfo methodInfo = AccessTools.Method("XPortal.RPC.Server.ServerEvents:RPC_RemoveRequest", (Type[])null, (Type[])null); if (type == null || type2 == null || methodInfo == null) { return false; } manager = AccessTools.Property(type, "Instance")?.GetValue(null); getList = AccessTools.Method(type, "GetList", (Type[])null, (Type[])null); portalId = AccessTools.Property(type2, "Id"); MethodInfo methodInfo2 = AccessTools.Method(type, "ContainsId", (Type[])null, (Type[])null); if (manager == null || getList == null || portalId == null || methodInfo2 == null) { return false; } isKnown = AccessTools.MethodDelegate<Func<ZDOID, bool>>(methodInfo2, manager, true); removeRequest = AccessTools.MethodDelegate<Action<long, ZDOID>>(methodInfo, (object)null, true); Ready = true; return true; } internal static void OnDestroyed(ZDOID id) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (Ready && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && isKnown(id)) { destroyed.Add(id); } } internal static void RemoveNonPortals() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) Dictionary<ZDOID, string> dictionary = new Dictionary<ZDOID, string>(); foreach (ZDOID item in destroyed) { dictionary[item] = "its object was removed"; } destroyed.Clear(); foreach (object item2 in (IEnumerable)getList.Invoke(manager, null)) { ZDOID val = (ZDOID)portalId.GetValue(item2); ZDO zDO = ZDOMan.instance.GetZDO(val); GameObject val2 = ((zDO != null) ? ZNetScene.instance.GetPrefab(zDO.GetPrefab()) : null); if ((Object)(object)val2 != (Object)null && ((Object)val2).name.EndsWith("_planned", StringComparison.Ordinal)) { dictionary[val] = "it is a plan (" + ((Object)val2).name + ")"; } } foreach (KeyValuePair<ZDOID, string> item3 in dictionary) { if (isKnown(item3.Key)) { removeRequest(ZDOMan.GetSessionID(), item3.Key); log.LogInfo((object)$"Removed {item3.Key} from the XPortal list: {item3.Value}"); } } } } [HarmonyPatch(typeof(ZDOMan), "HandleDestroyedZDO")] private static class HandleDestroyedZDOPatch { private static void Prefix(ZDOID uid) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) XPortalList.OnDestroyed(uid); } } [HarmonyPatch] private static class SpawnPieceAndDestroyPatch { internal static MethodBase Target; private static bool Prepare() { Target = AccessTools.Method("PlanBuild.Plans.PlanPiece:RPC_SpawnPieceAndDestroy", (Type[])null, (Type[])null); return Target != null; } private static MethodBase TargetMethod() { return Target; } private static Exception Finalizer(Exception __exception, MonoBehaviour __instance) { if (__exception == null) { return null; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid() && component.IsOwner()) { ZNetScene.instance.Destroy(((Component)__instance).gameObject); log.LogWarning((object)$"Building {((Object)__instance).name} failed, the plan is removed so it cannot be built again: {__exception}"); } else { log.LogWarning((object)$"Building {((Object)__instance).name} failed: {__exception}"); } return null; } } public const string PluginGuid = "qua8ion.valheim.planbuilddupefix"; public const string PluginName = "PlanBuildDupeFix"; public const string PluginVersion = "1.0.1"; private const string PlanBuildGuid = "marcopogo.PlanBuild"; private const string XPortalGuid = "yay.spikehimself.xportal"; private const string SpawnPieceAndDestroyMethod = "PlanBuild.Plans.PlanPiece:RPC_SpawnPieceAndDestroy"; private const float StackDistance = 0.05f; private const float XPortalCheckInterval = 2f; private static ConfigEntry<bool> removeStackedCopies; private static ConfigEntry<bool> cleanXPortalList; private static ManualLogSource log; private static int textCount; private float nextXPortalCheck; private void Awake() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) log = ((BaseUnityPlugin)this).Logger; removeStackedCopies = ((BaseUnityPlugin)this).Config.Bind<bool>("Cleanup", "RemoveStackedPortalCopies", true, "When the world loads, remove portals that have no creator and stand two or more at one spot. These are copies left by the bug; portals placed by players always have a creator."); cleanXPortalList = ((BaseUnityPlugin)this).Config.Bind<bool>("Cleanup", "CleanXPortalList", true, "On the server, keep PlanBuild plans and removed objects out of the XPortal portal list. XPortal lists a portal plan as a portal and keeps the entry after the plan is built."); new Harmony("qua8ion.valheim.planbuilddupefix").PatchAll(typeof(PlanBuildDupeFixPlugin).Assembly); bool flag = cleanXPortalList.Value && XPortalList.Init(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Portal and sign text is set without a platform user; " + ((SpawnPieceAndDestroyPatch.Target != null) ? "a plan whose build fails is removed" : "PlanBuild not found, plans are not guarded") + (removeStackedCopies.Value ? "; stacked portal copies are removed on world load" : "") + (flag ? "; plans are kept out of the XPortal list" : ""))); } private void Update() { if (XPortalList.Ready && !(Time.time < nextXPortalCheck)) { nextXPortalCheck = Time.time + 2f; if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && ZDOMan.instance != null && (Object)(object)ZNetScene.instance != (Object)null) { XPortalList.RemoveNonPortals(); } } } private static bool HasLocalUser() { IDistributionPlatform distributionPlatform = PlatformManager.DistributionPlatform; return ((distributionPlatform != null) ? distributionPlatform.LocalUser : null) != null; } private static void CountText(string what) { textCount++; if (textCount <= 20 || textCount % 100 == 0) { log.LogInfo((object)$"Set {what} text without a platform user ({textCount} so far)"); } } } }