using 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 MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using MimesisItemSpawner;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "MimesisItemSpawner", "1.0.0", "corbyn.barker", null)]
[assembly: MelonGame("ReLUGames", "MIMESIS")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("MimesisItemSpawner")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("MimesisItemSpawner")]
[assembly: AssemblyTitle("MimesisItemSpawner")]
[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 MimesisItemSpawner
{
public class Core : MelonMod
{
private MelonPreferences_Entry<string> _toggleKeyPref;
private MelonPreferences_Entry<string> _reasonPref;
private MelonPreferences_Entry<int> _amountPref;
private bool _open;
private bool _itemsLoaded;
private string _search = "";
private string _amountText = "1";
private string _status = "Press the toggle key in-game to open.";
private Vector2 _scroll;
private Rect _window = new Rect(40f, 40f, 480f, 600f);
private readonly List<GameBridge.ItemEntry> _allItems = new List<GameBridge.ItemEntry>();
private readonly List<GameBridge.ItemEntry> _filtered = new List<GameBridge.ItemEntry>();
private string _lastSearch;
private int _pendingSpawnId = -1;
private const int MaxRows = 300;
private const int WindowId = 1296651088;
public override void OnInitializeMelon()
{
MelonPreferences_Category val = MelonPreferences.CreateCategory("MimesisItemSpawner");
_toggleKeyPref = val.CreateEntry<string>("HotKey", "F6", "Toggle key (Input System key name, e.g. F6, Backquote, F1..F12)", (string)null, false, false, (ValueValidator)null, (string)null);
_reasonPref = val.CreateEntry<string>("ReasonOfSpawn", "Admin", "Spawn reason (None/Spawn/Admin/ItemSpawn/...)", (string)null, false, false, (ValueValidator)null, (string)null);
_amountPref = val.CreateEntry<int>("DefaultAmount", 1, "Default stack amount", (string)null, false, false, (ValueValidator)null, (string)null);
_amountText = _amountPref.Value.ToString();
MelonLogger.Msg("MimesisItemSpawner loaded. Toggle key: " + _toggleKeyPref.Value);
}
public override void OnUpdate()
{
if (GameBridge.WasKeyPressed(_toggleKeyPref.Value))
{
_open = !_open;
if (_open && !_itemsLoaded)
{
TryLoadItems();
}
}
if (_pendingSpawnId >= 0)
{
int pendingSpawnId = _pendingSpawnId;
_pendingSpawnId = -1;
DoSpawn(pendingSpawnId);
}
}
public override void OnGUI()
{
//IL_0010: 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_002b: Expected O, but got Unknown
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
if (_open)
{
_window = GUI.Window(1296651088, _window, new WindowFunction(DrawWindow), "Mimesis Item Spawner");
}
}
private void TryLoadItems()
{
if (!GameBridge.EnsureReady(out var error))
{
_status = "Cannot load items: " + error;
return;
}
try
{
_allItems.Clear();
_allItems.AddRange(GameBridge.GetAllItems());
_itemsLoaded = _allItems.Count > 0;
_lastSearch = null;
_status = (_itemsLoaded ? $"Loaded {_allItems.Count} items." : "Item table not ready yet (enter a session, then Refresh).");
}
catch (Exception ex)
{
_status = "Error loading items: " + ex.Message;
MelonLogger.Error((object)ex);
}
}
private void RebuildFilter()
{
if (_lastSearch == _search)
{
return;
}
_lastSearch = _search;
_filtered.Clear();
string text = _search?.Trim();
bool flag = string.IsNullOrEmpty(text);
string value = (flag ? null : text.ToLowerInvariant());
foreach (GameBridge.ItemEntry allItem in _allItems)
{
if (flag || allItem.Id.ToString().Contains(text) || (allItem.Name != null && allItem.Name.ToLowerInvariant().Contains(value)) || (allItem.Display != null && allItem.Display.ToLowerInvariant().Contains(value)))
{
_filtered.Add(allItem);
if (_filtered.Count >= 300)
{
break;
}
}
}
}
private void DrawWindow(int id)
{
//IL_0175: Unknown result type (might be due to invalid IL or missing references)
//IL_018d: Unknown result type (might be due to invalid IL or missing references)
//IL_0192: Unknown result type (might be due to invalid IL or missing references)
GUILayout.Space(4f);
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
GUILayout.Label("Search:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) });
_search = GUILayout.TextField(_search ?? "", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(250f) });
if (GUILayout.Button("Refresh", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }))
{
TryLoadItems();
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
GUILayout.Label("Amount:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) });
_amountText = GUILayout.TextField(_amountText ?? "1", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
GUILayout.FlexibleSpace();
GUILayout.Label(_itemsLoaded ? $"{_allItems.Count} items" : "not loaded", Array.Empty<GUILayoutOption>());
GUILayout.EndHorizontal();
GUILayout.Space(4f);
GUILayout.Label(_status, Array.Empty<GUILayoutOption>());
GUILayout.Space(2f);
RebuildFilter();
if (_filtered.Count >= 300)
{
GUILayout.Label($"Showing first {300} matches — refine search.", Array.Empty<GUILayoutOption>());
}
_scroll = GUILayout.BeginScrollView(_scroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(440f) });
foreach (GameBridge.ItemEntry item in _filtered)
{
if (GUILayout.Button($"[{item.Id}] {item.Display}", Array.Empty<GUILayoutOption>()))
{
_pendingSpawnId = item.Id;
_status = $"Spawning [{item.Id}] {item.Display} ...";
}
}
if (_filtered.Count == 0)
{
GUILayout.Label(_itemsLoaded ? "No matches." : "Open a session and press Refresh.", Array.Empty<GUILayoutOption>());
}
GUILayout.EndScrollView();
GUILayout.Space(4f);
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
if (GUILayout.Button("Close", Array.Empty<GUILayoutOption>()))
{
_open = false;
}
GUILayout.EndHorizontal();
GUI.DragWindow();
}
private void DoSpawn(int id)
{
int result = 1;
int.TryParse(_amountText, out result);
if (result < 1)
{
result = 1;
}
if (!GameBridge.EnsureReady(out var error))
{
_status = "Not ready: " + error;
return;
}
string message;
bool flag = GameBridge.SpawnItem(id, result, _reasonPref.Value, out message);
_status = message ?? (flag ? "Spawned." : "Spawn failed.");
if (flag)
{
MelonLogger.Msg(message);
}
else
{
MelonLogger.Warning(message);
}
}
}
internal static class GameBridge
{
public struct ItemEntry
{
public int Id;
public string Name;
public string Display;
}
private const BindingFlags AnyInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
private const BindingFlags AnyStatic = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
private static Assembly _gameAsm;
private static Type _hubType;
private static Type _ivroomType;
private static Type _posWithRotType;
private static Type _reasonType;
private static bool _inputResolved;
private static Type _keyboardType;
private static Type _keyEnumType;
private static PropertyInfo _keyboardCurrent;
private static MethodInfo _keyboardIndexer;
private static void ResolveInput()
{
if (_inputResolved)
{
return;
}
_inputResolved = true;
Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "Unity.InputSystem");
if (!(assembly == null))
{
_keyboardType = assembly.GetType("UnityEngine.InputSystem.Keyboard");
_keyEnumType = assembly.GetType("UnityEngine.InputSystem.Key");
if (!(_keyboardType == null) && !(_keyEnumType == null))
{
_keyboardCurrent = _keyboardType.GetProperty("current", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
_keyboardIndexer = _keyboardType.GetMethod("get_Item", new Type[1] { _keyEnumType });
}
}
}
public static bool WasKeyPressed(string keyName)
{
ResolveInput();
if (_keyboardCurrent == null || _keyboardIndexer == null)
{
return false;
}
try
{
object value = _keyboardCurrent.GetValue(null);
if (value == null)
{
return false;
}
object obj;
try
{
obj = Enum.Parse(_keyEnumType, keyName, ignoreCase: true);
}
catch
{
obj = Enum.Parse(_keyEnumType, "F6", ignoreCase: true);
}
object obj3 = _keyboardIndexer.Invoke(value, new object[1] { obj });
if (obj3 == null)
{
return false;
}
PropertyInfo property = obj3.GetType().GetProperty("wasPressedThisFrame", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
return property != null && (bool)property.GetValue(obj3);
}
catch
{
return false;
}
}
public static bool EnsureReady(out string error)
{
error = null;
if (_gameAsm == null)
{
_gameAsm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "Assembly-CSharp");
if (_gameAsm == null)
{
error = "Assembly-CSharp not loaded yet.";
return false;
}
}
if ((object)_hubType == null)
{
_hubType = _gameAsm.GetType("Hub");
}
if ((object)_ivroomType == null)
{
_ivroomType = _gameAsm.GetType("IVroom");
}
if ((object)_posWithRotType == null)
{
_posWithRotType = _gameAsm.GetType("ReluProtocol.PosWithRot");
}
if ((object)_reasonType == null)
{
_reasonType = _gameAsm.GetType("ReluProtocol.Enum.ReasonOfSpawn");
}
if (_hubType == null)
{
error = "Hub type not found.";
return false;
}
if (_ivroomType == null)
{
error = "IVroom type not found.";
return false;
}
if (_posWithRotType == null)
{
error = "PosWithRot type not found.";
return false;
}
if (_reasonType == null)
{
error = "ReasonOfSpawn type not found.";
return false;
}
return true;
}
private static object GetHub()
{
return _hubType.GetField("s", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null);
}
private static object GetField(object obj, string name)
{
if (obj == null)
{
return null;
}
Type type = obj.GetType();
while (type != null)
{
FieldInfo field = type.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field != null)
{
return field.GetValue(obj);
}
type = type.BaseType;
}
return null;
}
private static object GetFieldOn(Type declaring, object obj, string name)
{
return declaring.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj);
}
private static object GetProp(object obj, string name)
{
if (obj == null)
{
return null;
}
Type type = obj.GetType();
while (type != null)
{
PropertyInfo property = type.GetProperty(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (property != null)
{
return property.GetValue(obj);
}
type = type.BaseType;
}
return null;
}
private static object GetVWorld()
{
return GetField(GetHub(), "<vworld>k__BackingField");
}
private static int GetMyActorId(out object hub, out object pdata)
{
hub = GetHub();
pdata = GetField(hub, "pdata");
if (pdata == null)
{
return 0;
}
FieldInfo field = pdata.GetType().GetField("MyActorID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (!(field != null))
{
return 0;
}
return (int)field.GetValue(pdata);
}
private static bool GetLocalRoomAndPlayer(out object room, out object player, out string error)
{
room = null;
player = null;
error = null;
object vWorld = GetVWorld();
if (vWorld == null)
{
error = "Not in game yet (no VWorld). Join/host a session first.";
return false;
}
object field = GetField(vWorld, "_vRoomManager");
if (field == null)
{
error = "No room manager (host the session to spawn).";
return false;
}
if (!(GetField(field, "_vrooms") is IDictionary { Count: not 0 } dictionary))
{
error = "No active rooms found.";
return false;
}
object hub;
object pdata;
int myActorId = GetMyActorId(out hub, out pdata);
if (myActorId == 0)
{
error = "Local actor id is 0 (not spawned in a room yet).";
return false;
}
foreach (object value in dictionary.Values)
{
object fieldOn = GetFieldOn(_ivroomType, value, "_vPlayerDict");
if (fieldOn == null)
{
continue;
}
MethodInfo method = fieldOn.GetType().GetMethod("FindActor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (!(method == null))
{
object obj = method.Invoke(fieldOn, new object[1] { myActorId });
if (obj != null)
{
room = value;
player = obj;
return true;
}
}
}
IEnumerator enumerator = dictionary.Values.GetEnumerator();
try
{
if (enumerator.MoveNext())
{
object current2 = enumerator.Current;
room = current2;
}
}
finally
{
IDisposable disposable = enumerator as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
if (room == null)
{
error = "Could not resolve a room for the local player.";
return false;
}
return true;
}
public static List<ItemEntry> GetAllItems()
{
List<ItemEntry> list = new List<ItemEntry>();
object hub = GetHub();
object field = GetField(hub, "<dataman>k__BackingField");
if (field == null)
{
return list;
}
object prop = GetProp(field, "ExcelDataManager");
if (prop == null)
{
return list;
}
if (!(GetProp(prop, "ItemInfoDict") is IEnumerable enumerable))
{
return list;
}
object field2 = GetField(hub, "pdata");
MethodInfo methodInfo = field2?.GetType().GetMethod("GetItemDisplayName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
MethodInfo method = _hubType.GetMethod("GetL10NText", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
foreach (object item in enumerable)
{
Type type = item.GetType();
object obj = type.GetProperty("Key")?.GetValue(item);
object obj2 = type.GetProperty("Value")?.GetValue(item);
if (obj == null || obj2 == null)
{
continue;
}
int num = (int)obj;
string text = (obj2.GetType().GetField("Name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj2) as string) ?? num.ToString();
string text2 = text;
try
{
if (methodInfo != null)
{
string text3 = methodInfo.Invoke(field2, new object[2] { num, text }) as string;
if (!string.IsNullOrEmpty(text3))
{
text2 = text3;
}
}
if (method != null)
{
string text4 = method.Invoke(null, new object[1] { text2 }) as string;
if (!string.IsNullOrEmpty(text4))
{
text2 = text4;
}
}
}
catch
{
}
list.Add(new ItemEntry
{
Id = num,
Name = text,
Display = text2
});
}
list.Sort((ItemEntry a, ItemEntry b) => a.Id.CompareTo(b.Id));
return list;
}
public static bool SpawnItem(int masterId, int qty, string reasonName, out string message)
{
message = null;
try
{
if (!GetLocalRoomAndPlayer(out var room, out var player, out var error))
{
message = error;
return false;
}
MethodInfo method = _ivroomType.GetMethod("GetNewItemElement", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (method == null)
{
message = "GetNewItemElement not found.";
return false;
}
object obj = method.Invoke(room, new object[6]
{
masterId,
false,
Math.Max(1, qty),
0,
0,
0
});
if (obj == null)
{
message = $"Item {masterId} is invalid (GetNewItemElement returned null).";
return false;
}
object obj2 = Activator.CreateInstance(_posWithRotType);
bool flag = false;
if (player != null)
{
object prop = GetProp(player, "PositionVector");
if (prop != null)
{
_posWithRotType.GetMethod("set_pos", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(obj2, new object[1] { prop });
}
if (GetProp(player, "IsIndoor") is bool flag2)
{
flag = flag2;
}
}
object obj3;
try
{
obj3 = Enum.Parse(_reasonType, reasonName, ignoreCase: true);
}
catch
{
obj3 = Enum.ToObject(_reasonType, 8);
}
MethodInfo method2 = _ivroomType.GetMethod("SpawnLootingObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (method2 == null)
{
message = "SpawnLootingObject not found.";
return false;
}
int num = ((method2.Invoke(room, new object[9] { obj, obj2, flag, obj3, 0, 0, 0L, false, false }) is int num2) ? num2 : 0);
if (num == 0)
{
message = $"Spawn rejected by game for item {masterId}.";
return false;
}
message = $"Spawned item {masterId} x{Math.Max(1, qty)} (objId {num}).";
return true;
}
catch (Exception ex)
{
message = "Spawn error: " + ex.Message;
MelonLogger.Error((object)ex);
return false;
}
}
}
}