From f12d911871f1d0bb7d326053b6d46a46b4a33b26 Mon Sep 17 00:00:00 2001
From: "@Someone" <45270312+Someone-193@users.noreply.github.com>
Date: Mon, 23 Jun 2025 14:44:42 -0400
Subject: [PATCH 1/5] Required fix (for me)
---
ProjectMER.csproj | 1 +
1 file changed, 1 insertion(+)
diff --git a/ProjectMER.csproj b/ProjectMER.csproj
index 18ec451..cf39bfb 100644
--- a/ProjectMER.csproj
+++ b/ProjectMER.csproj
@@ -22,6 +22,7 @@
+
From a8240c50010516ffc7cedeaf036e4c0eae3f0330 Mon Sep 17 00:00:00 2001
From: "@Someone" <45270312+Someone-193@users.noreply.github.com>
Date: Sat, 6 Sep 2025 19:18:37 -0400
Subject: [PATCH 2/5] Add the actual features
---
Features/Extensions/ExiledExtensions.cs | 135 ++++++++++++++++++
.../Schematics/SchematicBlockData.cs | 12 +-
.../SerializableItemSpawnpoint.cs | 10 +-
ProjectMER.cs | 4 +
4 files changed, 159 insertions(+), 2 deletions(-)
create mode 100644 Features/Extensions/ExiledExtensions.cs
diff --git a/Features/Extensions/ExiledExtensions.cs b/Features/Extensions/ExiledExtensions.cs
new file mode 100644
index 0000000..651a613
--- /dev/null
+++ b/Features/Extensions/ExiledExtensions.cs
@@ -0,0 +1,135 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+using InventorySystem.Items.Pickups;
+using LabApi.Features.Wrappers;
+using LabApi.Loader;
+using LabApi.Loader.Features.Plugins;
+using UnityEngine;
+namespace ProjectMER.Features.Extensions
+{
+ public static class ExiledExtensions
+ {
+ private static Assembly? ExiledLoaderAssembly;
+
+ private static MethodInfo? CustomItemTrySpawnMethodInfo;
+
+ private static MethodInfo? PickupGetBaseMethodInfo;
+
+ public static Pickup? TrySpawn(string customItemName, Vector3 position, Quaternion rotation, Vector3 scale)
+ {
+ if (!TrySpawnCustomItem(customItemName, position, out Pickup? pickup))
+ return null;
+
+ pickup.Rotation = rotation;
+ pickup.Transform.localScale = scale;
+
+ return pickup;
+ }
+
+ internal static bool TrySpawnCustomItem(string name, Vector3 position, [NotNullWhen(true)] out Pickup? pickup)
+ {
+ pickup = null;
+
+ if (CustomItemTrySpawnMethodInfo is null)
+ return false;
+
+ object?[] args = [name, position, null];
+
+ CustomItemTrySpawnMethodInfo.Invoke(null, args);
+
+ if (args[2] is null)
+ return false;
+
+ pickup = GetPickupFromExiledPickup(args[2]!);
+
+ return pickup is not null;
+ }
+
+
+ internal static Pickup? GetPickupFromExiledPickup(object pickup)
+ {
+ if (PickupGetBaseMethodInfo is null)
+ return null;
+
+ object obj = PickupGetBaseMethodInfo.Invoke(pickup, []);
+
+ if (obj is not ItemPickupBase pickupBase)
+ {
+ Logger.Warn("Failed to get ItemPickupBase from Exiled Pickup");
+ return null;
+ }
+
+ return Pickup.Get(pickupBase);
+ }
+
+ internal static void TryInitialize()
+ {
+ const string ErrorMessage = "Failed to find a component of Exiled! This can be ignored if you do not use Exiled Custom Items in ProjectMER. Cause: ";
+
+ KeyValuePair kvp = PluginLoader.Plugins.FirstOrDefault(kvp => kvp.Key.Name is "Exiled Loader");
+
+ if (kvp.Value is null)
+ {
+ // No debug in config :(
+ // not printed because ppl can just not use Exiled, but having Exiled.Loader and not API / CI is suspicious
+ // Logger.Debug(ErrorMessage + "Failed to get ExiledLoader Plugin");
+ return;
+ }
+
+ ExiledLoaderAssembly = kvp.Value;
+
+ object? plugin = ExiledLoaderAssembly.GetType("Exiled.Loader.Loader")?.GetMethod("GetPlugin")?.Invoke(null, ["exiled_custom_items"]);
+
+ if (plugin is null)
+ {
+ // It's possible people use Exiled without CI, so I'll leave this out too
+ // Logger.Debug(ErrorMessage + "Failed to get CustomItems Plugin");
+ return;
+ }
+
+ object? nullableAssembly = plugin.GetType().GetProperty("Assembly")?.GetValue(plugin);
+
+ if (nullableAssembly is not Assembly customItemAssembly)
+ {
+ Logger.Warn(ErrorMessage + "Failed to get CustomItems Assembly");
+ return;
+ }
+
+ Type? customItem = customItemAssembly.GetType("Exiled.CustomItems.API.Features.CustomItem");
+
+ if (customItem is null)
+ {
+ Logger.Warn(ErrorMessage + "Failed to get CustomItem Type");
+ return;
+ }
+
+ CustomItemTrySpawnMethodInfo = customItem.GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault(method => method.Name is "TrySpawn" && method.GetParameters().Any(parameter => parameter.ParameterType == typeof(string)));
+
+ if (CustomItemTrySpawnMethodInfo is null)
+ Logger.Warn(ErrorMessage + "Failed to get CustomItem.TrySpawn method");
+
+ Assembly? apiAssembly = PluginLoader.Dependencies.FirstOrDefault(assembly => assembly.GetName().Name is "Exiled.API");
+
+ if (apiAssembly is null)
+ {
+ Logger.Warn(ErrorMessage + "Failed to get Exiled.API Assembly");
+ return;
+ }
+
+ Type? pickupType = apiAssembly.GetType("Exiled.API.Features.Pickups.Pickup");
+
+ if (pickupType is null)
+ {
+ Logger.Warn(ErrorMessage + "Failed to get Pickup Type");
+ return;
+ }
+
+ PickupGetBaseMethodInfo = pickupType.GetProperty("Base")?.GetGetMethod();
+
+ if (PickupGetBaseMethodInfo is null)
+ {
+ Logger.Warn(ErrorMessage + "Failed to get Pickup::Base getter method");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Features/Serializable/Schematics/SchematicBlockData.cs b/Features/Serializable/Schematics/SchematicBlockData.cs
index 5e2ae64..1878fb1 100644
--- a/Features/Serializable/Schematics/SchematicBlockData.cs
+++ b/Features/Serializable/Schematics/SchematicBlockData.cs
@@ -143,7 +143,17 @@ private GameObject CreatePickup(SchematicObject schematicObject)
if (Properties.TryGetValue("Chance", out object property) && UnityEngine.Random.Range(0, 101) > Convert.ToSingle(property))
return new("Empty Pickup");
- Pickup pickup = Pickup.Create((ItemType)Convert.ToInt32(Properties["ItemType"]), Vector3.zero)!;
+ Pickup? pickup = null;
+ if (Properties["CustomItem"] is string str && str != string.Empty)
+ {
+ ExiledExtensions.TrySpawnCustomItem(str, Vector3.zero, out pickup);
+ }
+
+ pickup ??= Pickup.Create((ItemType)Convert.ToInt32(Properties["ItemType"]), Vector3.zero);
+
+ if (pickup is null)
+ return new("Empty Pickup");
+
if (Properties.ContainsKey("Locked"))
PickupEventsHandler.ButtonPickups.Add(pickup.Serial, schematicObject);
diff --git a/Features/Serializable/SerializableItemSpawnpoint.cs b/Features/Serializable/SerializableItemSpawnpoint.cs
index d1eae85..f412c84 100644
--- a/Features/Serializable/SerializableItemSpawnpoint.cs
+++ b/Features/Serializable/SerializableItemSpawnpoint.cs
@@ -14,6 +14,7 @@ namespace ProjectMER.Features.Serializable;
public class SerializableItemSpawnpoint : SerializableObject, IIndicatorDefinition
{
public ItemType ItemType { get; set; } = ItemType.Lantern;
+ public string CustomItem { get; set; } = string.Empty;
public float Weight { get; set; } = -1;
public string AttachmentsCode { get; set; } = "-1";
public uint NumberOfItems { get; set; } = 1;
@@ -41,7 +42,14 @@ public class SerializableItemSpawnpoint : SerializableObject, IIndicatorDefiniti
for (int i = 0; i < NumberOfItems; i++)
{
- Pickup pickup = Pickup.Create(ItemType, position, rotation, Scale)!;
+ Pickup? pickup = CustomItem != string.Empty ? ExiledExtensions.TrySpawn(CustomItem, position, rotation, Scale) : Pickup.Create(ItemType, position, rotation, Scale);
+
+ if (pickup is null)
+ {
+ // there is no Debug config option?
+ // Logger.Debug($"Failed to spawn an item with CustomItem: {CustomItem}", true);
+ continue;
+ }
pickup.Transform.parent = itemSpawnPoint.transform;
if (Weight != -1)
diff --git a/ProjectMER.cs b/ProjectMER.cs
index 330c7bb..78b6521 100644
--- a/ProjectMER.cs
+++ b/ProjectMER.cs
@@ -8,6 +8,7 @@
using ProjectMER.Configs;
using ProjectMER.Events.Handlers.Internal;
using ProjectMER.Features;
+using ProjectMER.Features.Extensions;
namespace ProjectMER;
@@ -90,6 +91,9 @@ public override void Enable()
Logger.Debug("FileSystemWatcher enabled!");
}
+
+ // plugin loading is synchronous (minus exiled delaying 1 tick), so after all plugins loaded, try checking for Exiled and Exiled CI
+ Timing.CallDelayed(1, ExiledExtensions.TryInitialize);
}
private void OnMapFileChanged(object _, FileSystemEventArgs ev)
From 0b81c92cfac371ef24ce72de8654f66e77ed887a Mon Sep 17 00:00:00 2001
From: "@Someone" <45270312+Someone-193@users.noreply.github.com>
Date: Sat, 6 Sep 2025 19:19:38 -0400
Subject: [PATCH 3/5] remove fix :(
---
ProjectMER.csproj | 1 -
1 file changed, 1 deletion(-)
diff --git a/ProjectMER.csproj b/ProjectMER.csproj
index cf39bfb..18ec451 100644
--- a/ProjectMER.csproj
+++ b/ProjectMER.csproj
@@ -22,7 +22,6 @@
-
From 26ac1053e84702d7984fa9ce7ea4d9c1bc74224e Mon Sep 17 00:00:00 2001
From: "@Someone" <45270312+Someone-193@users.noreply.github.com>
Date: Sat, 6 Sep 2025 19:23:48 -0400
Subject: [PATCH 4/5] remove unnecessary static field
---
Features/Extensions/ExiledExtensions.cs | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/Features/Extensions/ExiledExtensions.cs b/Features/Extensions/ExiledExtensions.cs
index 651a613..00d65ff 100644
--- a/Features/Extensions/ExiledExtensions.cs
+++ b/Features/Extensions/ExiledExtensions.cs
@@ -9,8 +9,6 @@ namespace ProjectMER.Features.Extensions
{
public static class ExiledExtensions
{
- private static Assembly? ExiledLoaderAssembly;
-
private static MethodInfo? CustomItemTrySpawnMethodInfo;
private static MethodInfo? PickupGetBaseMethodInfo;
@@ -76,9 +74,9 @@ internal static void TryInitialize()
return;
}
- ExiledLoaderAssembly = kvp.Value;
+ Assembly? exiledLoaderAssembly = kvp.Value;
- object? plugin = ExiledLoaderAssembly.GetType("Exiled.Loader.Loader")?.GetMethod("GetPlugin")?.Invoke(null, ["exiled_custom_items"]);
+ object? plugin = exiledLoaderAssembly.GetType("Exiled.Loader.Loader")?.GetMethod("GetPlugin")?.Invoke(null, ["exiled_custom_items"]);
if (plugin is null)
{
From 40e97f8fcdf2d250b2e941bf6c2764ee4d3f2563 Mon Sep 17 00:00:00 2001
From: "@Someone" <45270312+Someone-193@users.noreply.github.com>
Date: Tue, 9 Dec 2025 12:04:20 -0500
Subject: [PATCH 5/5] Squashed commit of the following:
commit f04e2684613cc570bd80dc741981d687dcb207ee
Author: Michal78900 <75911188+Michal78900@users.noreply.github.com>
Date: Sun Nov 2 12:54:54 2025 +0100
Bump
commit 70072702ccba252e114672fd55a02ef4f68bb3ac
Author: Michal78900 <75911188+Michal78900@users.noreply.github.com>
Date: Wed Sep 17 14:26:36 2025 +0200
Bump
---
ProjectMER.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ProjectMER.cs b/ProjectMER.cs
index 78b6521..bf43646 100644
--- a/ProjectMER.cs
+++ b/ProjectMER.cs
@@ -135,7 +135,7 @@ public override void Disable()
public override string Author => "Michal78900";
- public override Version Version => new Version(2025, 8, 4, 2);
+ public override Version Version => new Version(2025, 11, 2, 1);
public override Version RequiredApiVersion => new Version(1, 0, 0, 0);
}