using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("CustomItemSpawner")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CustomItemSpawner")]
[assembly: AssemblyTitle("CustomItemSpawner")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 CustomItemSpawner
{
internal struct ItemDirectoryEntry
{
internal int Index;
internal string Name;
}
internal static class CreateItemDirectory
{
internal static ItemDirectoryEntry[] Create()
{
GameObject[] array = (((Object)(object)PrefabsDirectory.instance == (Object)null) ? null : PrefabsDirectory.instance.directory);
if (array == null)
{
return new ItemDirectoryEntry[0];
}
ItemDirectoryEntry[] array2 = new ItemDirectoryEntry[array.Length];
for (int i = 0; i < array.Length; i++)
{
GameObject val = array[i];
array2[i] = new ItemDirectoryEntry
{
Index = i,
Name = (((Object)(object)val == (Object)null) ? null : ((Object)val).name)
};
}
return array2;
}
}
[BepInPlugin("com.Exocet.customitemspawner", "Custom Item Spawner", "1.2.0")]
public sealed class CustomItemSpawnerPlugin : BaseUnityPlugin
{
public const string PLUGIN_GUID = "com.Exocet.customitemspawner";
public const string PLUGIN_NAME = "Custom Item Spawner";
public const string PLUGIN_VERSION = "1.2.0";
internal static ConfigEntry<string> CrateDirectoryItem;
internal static ConfigEntry<string> ItemKeywordSearch;
internal static ConfigEntry<bool> ClearItemKeywordSearch;
internal static ConfigEntry<KeyCode> SpawnKey;
internal static ConfigEntry<bool> CustomBallastObject;
internal static ConfigEntry<int> CustomObjectMass;
internal static ManualLogSource Log;
internal static ConfigFile PluginConfig;
internal static ItemDirectoryEntry[] ItemDirectory;
internal static Dictionary<string, int> ItemIndices;
private static bool itemDirectoryCreated;
private static bool configurationManagerRefreshRequested;
private void Awake()
{
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Expected O, but got Unknown
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Expected O, but got Unknown
//IL_0172: Unknown result type (might be due to invalid IL or missing references)
Log = ((BaseUnityPlugin)this).Logger;
PluginConfig = ((BaseUnityPlugin)this).Config;
CrateDirectoryItem = ((BaseUnityPlugin)this).Config.Bind<string>("General", "CrateDirectoryItem", "(Loading item directory...)", new ConfigDescription("Prefab name from PrefabsDirectory.directory used as the custom object.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[1] { "(Loading item directory...)" }), Array.Empty<object>()));
ItemKeywordSearch = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Item Keyword Search", string.Empty, "Filter the game item directory by a case-insensitive keyword.");
ClearItemKeywordSearch = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Clear Item Keyword Search", false, "Set to true to clear the keyword search and show the full game item list. This button resets itself after use.");
CustomBallastObject = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "CustomBallastObject", false, "Apply the custom mass and name to spawned objects.");
CustomObjectMass = ((BaseUnityPlugin)this).Config.Bind<int>("General", "CustomObjectMass", 10000, new ConfigDescription("User defined mass value for this spawned object.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100000), Array.Empty<object>()));
SpawnKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "SpawnKey", (KeyCode)287, "Key used to spawn the custom object.");
ItemKeywordSearch.SettingChanged += delegate
{
UpdateGameItemDropdown();
};
ClearItemKeywordSearch.SettingChanged += delegate
{
ClearItemKeywordSearchIfRequested();
};
new Harmony("com.Exocet.customitemspawner").PatchAll();
((MonoBehaviour)this).StartCoroutine(InitializeItemDirectoryWhenReady());
((BaseUnityPlugin)this).Logger.LogInfo((object)"Custom object spawner loaded.");
}
private void Update()
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
if (configurationManagerRefreshRequested)
{
RefreshConfigurationManagerSettings();
}
if (Input.GetKeyDown(SpawnKey.Value))
{
CustomItemSpawner.Spawn();
}
}
internal static void CreateItemDirectoryOnce()
{
if (!itemDirectoryCreated)
{
RebuildItemDirectory();
}
}
private static void RebuildItemDirectory()
{
if ((Object)(object)PrefabsDirectory.instance == (Object)null || PrefabsDirectory.instance.directory == null || PrefabsDirectory.instance.directory.Length == 0)
{
return;
}
ItemDirectoryEntry[] array = CreateItemDirectory.Create();
List<string> list = new List<string>();
Dictionary<string, int> dictionary = new Dictionary<string, int>();
for (int i = 0; i < array.Length; i++)
{
string name = array[i].Name;
if (name != null && !dictionary.ContainsKey(name))
{
list.Add(name);
dictionary.Add(name, array[i].Index);
}
}
if (list.Count != 0)
{
ItemDirectory = array;
ItemIndices = dictionary;
string text = ((array.Length > 23) ? array[23].Name : null);
if (text == null || !ItemIndices.ContainsKey(text))
{
text = list[0];
}
itemDirectoryCreated = true;
UpdateGameItemDropdown(text);
Log.LogDebug((object)$"Rebuilt item directory with {ItemDirectory.Length} entries.");
}
}
private static void UpdateGameItemDropdown(string preferredSelection = null)
{
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_012b: Expected O, but got Unknown
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_0145: Expected O, but got Unknown
//IL_016b: Unknown result type (might be due to invalid IL or missing references)
//IL_0175: Expected O, but got Unknown
if (!itemDirectoryCreated)
{
return;
}
List<string> list = new List<string>();
string text = ((ItemKeywordSearch.Value == null) ? string.Empty : ItemKeywordSearch.Value.Trim());
for (int i = 0; i < ItemDirectory.Length; i++)
{
string name = ItemDirectory[i].Name;
if (name != null && ItemIndices[name] == ItemDirectory[i].Index && (text.Length == 0 || name.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0))
{
list.Add(name);
}
}
if (list.Count == 0)
{
list.Add("(No matching game items)");
}
string text2 = ((CrateDirectoryItem == null) ? null : CrateDirectoryItem.Value);
string text3 = (list.Contains(text2) ? text2 : (list.Contains(preferredSelection) ? preferredSelection : list[0]));
PluginConfig.Remove(new ConfigDefinition("General", "CrateDirectoryItem"));
PluginConfig.Remove(new ConfigDefinition("General", "Game Item Directory"));
CrateDirectoryItem = PluginConfig.Bind<string>("General", "Game Item Directory", text3, new ConfigDescription("Game object to spawn.", (AcceptableValueBase)(object)new AcceptableValueList<string>(list.ToArray()), Array.Empty<object>()));
if (CrateDirectoryItem.Value != text3)
{
CrateDirectoryItem.Value = text3;
}
configurationManagerRefreshRequested = true;
}
private static void RefreshConfigurationManagerSettings()
{
configurationManagerRefreshRequested = false;
if (Chainloader.PluginInfos.TryGetValue("com.bepis.bepinex.configurationmanager", out var value) && !((Object)(object)value.Instance == (Object)null))
{
MethodInfo method = ((object)value.Instance).GetType().GetMethod("BuildSettingList", BindingFlags.Instance | BindingFlags.Public);
if (method == null)
{
Log.LogWarning((object)"Configuration Manager was found but does not expose BuildSettingList; reopen its window to refresh the game item dropdown.");
return;
}
method.Invoke(value.Instance, null);
Log.LogDebug((object)"Refreshed Configuration Manager settings after updating the game item dropdown.");
}
}
private static void ClearItemKeywordSearchIfRequested()
{
if (ClearItemKeywordSearch.Value)
{
ItemKeywordSearch.Value = string.Empty;
ClearItemKeywordSearch.Value = false;
}
}
private static IEnumerator InitializeItemDirectoryWhenReady()
{
while (!itemDirectoryCreated)
{
CreateItemDirectoryOnce();
yield return null;
}
if (ClearItemKeywordSearch.Value)
{
ClearItemKeywordSearchIfRequested();
}
}
}
internal static class CustomItemSpawner
{
private const string ModDataPrefix = "CustomItemSpawner.item.";
private const string MarkerSuffix = ".customObject";
private const string MassSuffix = ".mass";
private const string NameSuffix = ".name";
internal static void Spawn()
{
//IL_0103: Unknown result type (might be due to invalid IL or missing references)
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
//IL_0112: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
PrefabsDirectory val = (((Object)(object)SaveLoadManager.instance == (Object)null) ? null : ((Component)SaveLoadManager.instance).GetComponent<PrefabsDirectory>());
string text = ((CustomItemSpawnerPlugin.CrateDirectoryItem == null) ? null : CustomItemSpawnerPlugin.CrateDirectoryItem.Value);
int value;
int num = ((CustomItemSpawnerPlugin.ItemIndices == null || text == null || !CustomItemSpawnerPlugin.ItemIndices.TryGetValue(text, out value)) ? (-1) : value);
if ((Object)(object)val == (Object)null || val.directory == null || num < 0 || num >= val.directory.Length)
{
CustomItemSpawnerPlugin.Log.LogError((object)("Cannot spawn custom object: prefab '" + text + "' is unavailable."));
return;
}
GameObject val2 = val.directory[num];
if ((Object)(object)val2 == (Object)null)
{
CustomItemSpawnerPlugin.Log.LogError((object)$"Cannot spawn custom object: PrefabsDirectory index {num} is empty.");
return;
}
if ((Object)(object)Refs.ovrCameraRig == (Object)null)
{
CustomItemSpawnerPlugin.Log.LogError((object)"Cannot spawn custom object: the camera rig is unavailable.");
return;
}
GameObject val3 = Object.Instantiate<GameObject>(val2, Refs.ovrCameraRig.position + Refs.ovrCameraRig.forward, Refs.ovrCameraRig.rotation);
ShipItem component = val3.GetComponent<ShipItem>();
SaveablePrefab component2 = val3.GetComponent<SaveablePrefab>();
Good component3 = val3.GetComponent<Good>();
if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null)
{
Object.Destroy((Object)(object)val3);
CustomItemSpawnerPlugin.Log.LogError((object)"Cannot spawn custom object: the selected prefab is missing required components.");
return;
}
component.sold = true;
component2.RegisterToSave();
if (CustomItemSpawnerPlugin.CustomBallastObject.Value)
{
int value2 = CustomItemSpawnerPlugin.CustomObjectMass.Value;
component.mass = value2;
component.name = $"{value2} Mass Custom Object";
SaveCustomObjectProperties(component2.instanceId, component);
}
if ((Object)(object)component3 != (Object)null)
{
component3.RegisterAsMissionless();
}
RestoreLoadedCustomObject(component);
CustomItemSpawnerPlugin.Log.LogInfo((object)$"Spawned custom object '{((Object)val2).name}' from PrefabsDirectory index {num}.");
}
internal static void RestoreLoadedCustomObject(ShipItem item)
{
if ((Object)(object)item == (Object)null)
{
return;
}
SaveablePrefab component = ((Component)item).GetComponent<SaveablePrefab>();
if (!((Object)(object)component == (Object)null) && IsCustomObject(component.instanceId))
{
string modDataKey = GetModDataKey(component.instanceId);
if (int.TryParse(GetModDataValue(modDataKey + ".mass", ((int)item.mass).ToString(CultureInfo.InvariantCulture)), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
{
item.mass = result;
}
item.name = GetModDataValue(modDataKey + ".name", item.name);
}
}
internal static void RestoreLoadedCustomObjects()
{
if ((Object)(object)SaveLoadManager.instance == (Object)null)
{
return;
}
List<SaveablePrefab> currentPrefabs = SaveLoadManager.instance.GetCurrentPrefabs();
if (currentPrefabs == null)
{
return;
}
foreach (SaveablePrefab item in currentPrefabs)
{
if (!((Object)(object)item == (Object)null))
{
RestoreLoadedCustomObject(((Component)item).GetComponent<ShipItem>());
}
}
}
internal static IEnumerator RestoreLoadedCustomObjectsAfterLoad()
{
for (int frame = 0; frame < 2; frame++)
{
yield return null;
RestoreLoadedCustomObjects();
}
}
private static void SaveCustomObjectProperties(int instanceId, ShipItem item)
{
if (GameState.modData == null)
{
CustomItemSpawnerPlugin.Log.LogWarning((object)"Custom object spawned, but save data is unavailable; custom properties cannot persist.");
return;
}
string modDataKey = GetModDataKey(instanceId);
GameState.modData[modDataKey + ".customObject"] = "1";
GameState.modData[modDataKey + ".mass"] = item.mass.ToString(CultureInfo.InvariantCulture);
GameState.modData[modDataKey + ".name"] = item.name;
}
private static bool IsCustomObject(int instanceId)
{
return GameState.modData != null && GameState.modData.ContainsKey(GetModDataKey(instanceId) + ".customObject");
}
private static string GetModDataKey(int instanceId)
{
return "CustomItemSpawner.item." + instanceId;
}
private static string GetModDataValue(string key, string fallback)
{
string value;
return GameState.modData.TryGetValue(key, out value) ? value : fallback;
}
}
[HarmonyPatch(typeof(SaveLoadManager), "LoadModData")]
internal static class CustomObjectLoadPatch
{
private static void Postfix()
{
CustomItemSpawnerPlugin.CreateItemDirectoryOnce();
CustomItemSpawner.RestoreLoadedCustomObjects();
if ((Object)(object)SaveLoadManager.instance != (Object)null)
{
((MonoBehaviour)SaveLoadManager.instance).StartCoroutine(CustomItemSpawner.RestoreLoadedCustomObjectsAfterLoad());
}
CustomItemSpawnerPlugin.Log.LogDebug((object)"Save data loaded; item directory initialized and custom object properties restored.");
}
}
[HarmonyPatch(typeof(ShipItem), "OnLoad")]
internal static class CustomObjectShipItemLoadPatch
{
private static void Postfix(ShipItem __instance)
{
CustomItemSpawner.RestoreLoadedCustomObject(__instance);
}
}
[HarmonyPatch(typeof(ShipItem), "ProcessSaveable")]
internal static class CustomObjectProcessSaveablePatch
{
private static void Postfix(ShipItem __instance)
{
CustomItemSpawner.RestoreLoadedCustomObject(__instance);
}
}
[HarmonyPatch(typeof(ItemRigidbody), "UpdateMass")]
internal static class CustomObjectMassUpdatePatch
{
private static void Prefix(ItemRigidbody __instance)
{
if ((Object)(object)__instance != (Object)null)
{
CustomItemSpawner.RestoreLoadedCustomObject(__instance.GetShipItem());
}
}
}
}