using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using Boombox.ItemUtils;
using HarmonyLib;
using ShopUtils;
using ShopUtils.Language;
using ShopUtils.Network;
using Steamworks;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using Zorro.Core;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ShopUtils")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ShopUtils")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("1f772b7c-6b54-49f8-ba67-0c7e9aa1e152")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Boombox.ItemUtils
{
[HarmonyPatch(typeof(ItemInstanceData))]
internal static class ItemInstanceDataPatch
{
internal static int EntryCount;
[HarmonyPrefix]
[HarmonyPatch("GetEntryIdentifier")]
private static bool GetEntryIdentifier(ref byte __result, Type type)
{
if (!Entries.registerEntries.Contains(type))
{
return true;
}
int num = EntryCount;
foreach (Type registerEntry in Entries.registerEntries)
{
if (num == 255)
{
throw new ShopUtilsException("Item Instance Data Out of range > 255");
}
num++;
if (registerEntry == type)
{
__result = (byte)num;
return false;
}
}
return true;
}
[HarmonyPrefix]
[HarmonyPatch("GetEntryType")]
private static bool GetEntryType(ref ItemDataEntry __result, byte identifier)
{
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Expected O, but got Unknown
int num = EntryCount;
foreach (Type registerEntry in Entries.registerEntries)
{
num++;
if (identifier == (byte)num)
{
__result = (ItemDataEntry)registerEntry.GetConstructor(new Type[0]).Invoke(null);
return false;
}
}
return true;
}
}
}
namespace ShopUtils
{
public static class Entries
{
internal static List<Type> registerEntries = new List<Type>();
public static void RegisterEntry(Type type)
{
if (!type.IsSubclassOf(typeof(ItemDataEntry)))
{
throw new Exception("Unknown Item Data Entry: " + type.Name);
}
if (!registerEntries.Contains(type))
{
registerEntries.Add(type);
}
}
public static void UnRegisterEntry(Type type)
{
if (registerEntries.Contains(type))
{
registerEntries.Remove(type);
}
}
private static Type[] GetTypesFromAssembly(Assembly assembly)
{
try
{
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
UtilsLogger.LogWarning($"ItemDataEntry Register: {assembly} => {ex}");
return ex.Types.Where((Type type) => type != null).ToArray();
}
}
public static void RegisterAll(Assembly assembly)
{
Type[] typesFromAssembly = GetTypesFromAssembly(assembly);
foreach (Type type in typesFromAssembly)
{
if (type.IsSubclassOf(typeof(ItemDataEntry)) && !registerEntries.Contains(type))
{
registerEntries.Add(type);
UtilsLogger.LogInfo($"Found ItemDataEntry: {type.Name}, Id: {registerEntries.Count + ItemInstanceDataPatch.EntryCount}");
}
}
}
public static void RegisterAll()
{
RegisterAll(Assembly.GetCallingAssembly());
}
internal static void InitEntryCount()
{
ItemInstanceDataPatch.EntryCount = -1;
Type[] typesFromAssembly = GetTypesFromAssembly(Assembly.GetAssembly(typeof(ItemDataEntry)));
Type[] array = typesFromAssembly;
foreach (Type type in array)
{
if (type.IsSubclassOf(typeof(ItemDataEntry)))
{
ItemInstanceDataPatch.EntryCount++;
}
}
}
}
public static class Items
{
internal static List<Item> registerItems = new List<Item>();
public static void RegisterShopItem(Item item, ShopItemCategory category = 0, int price = -1)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)item == (Object)null)
{
throw new ShopUtilsException("Item is null");
}
if (price >= 0)
{
item.price = price;
}
if ((int)category != 0)
{
item.Category = category;
}
if ((int)item.Category == 0)
{
throw new ShopUtilsException("Error Category Invalid \nItems Name: " + item.displayName + " \n");
}
if (item.price < 0)
{
throw new ShopUtilsException("Error Item Price \nItems Name: " + item.displayName + " \n");
}
item.purchasable = true;
RegisterItem(item);
}
public static void RegisterSpawnableItem(Item item, float Rarity = 1f, int BudgetCost = 1)
{
if ((Object)(object)item == (Object)null)
{
throw new ShopUtilsException("Item is null");
}
item.rarity = Rarity;
item.budgetCost = BudgetCost;
item.spawnable = true;
RegisterItem(item);
}
public static void UnRegisterItem(Item item)
{
if (registerItems.Contains(item))
{
registerItems.Remove(item);
}
}
internal static void RegisterItem(Item item)
{
if (!registerItems.Contains(item))
{
registerItems.Add(item);
}
}
internal static void InitAllItems()
{
registerItems.ForEach(delegate(Item item)
{
item.id = 0;
});
foreach (Item registerItem in registerItems)
{
if (TryGetMaxItemID(out var itemId))
{
registerItem.id = itemId;
UtilsLogger.LogInfo("[Item: " + registerItem.displayName + ", " + $"ItemId: {registerItem.id}, " + "Guid: " + registerItem.persistentID + "]");
continue;
}
UtilsLogger.LogError("Max Item Id Out of range > 255");
break;
}
}
internal static bool TryGetMaxItemID(out byte itemId)
{
int num = 0;
Item[] objects = ((DatabaseAsset<ItemDatabase, Item>)(object)SingletonAsset<ItemDatabase>.Instance).Objects;
foreach (Item val in objects)
{
num = Math.Max(val.id, num);
}
foreach (Item registerItem in registerItems)
{
num = Math.Max(registerItem.id, num);
}
if (num == 255)
{
itemId = 0;
return false;
}
itemId = (byte)(num + 1);
return true;
}
}
public static class Languages
{
internal static Dictionary<Locale, Dictionary<string, string>> languages = new Dictionary<Locale, Dictionary<string, string>>();
public static void AddLanguage(string key, string language, Locale locale)
{
if ((Object)(object)locale == (Object)null)
{
throw new ShopUtilsException("Locale is null, key: " + key);
}
if (!languages.ContainsKey(locale))
{
languages.Add(locale, new Dictionary<string, string>());
}
if (languages[locale].ContainsKey(key))
{
UtilsLogger.LogError("Language: " + locale.LocaleName + " Has Already Key: " + key);
}
else
{
languages[locale].Add(key, language);
}
}
public static void AddLanguage(this Locale locale, string key, string language)
{
AddLanguage(key, language, locale);
}
public static void AddLanguage(this Locale locale, params LanguageInstance[] languages)
{
foreach (LanguageInstance languageInstance in languages)
{
locale.AddLanguage(languageInstance.key, languageInstance.language);
}
}
public static Locale GetLanguage(LanguageEnum language)
{
foreach (Locale locale in LocalizationSettings.AvailableLocales.Locales)
{
string value = language.ToString().Replace("Chinese", "");
if (locale.LocaleName.Contains(value))
{
return locale;
}
}
return null;
}
public static bool TryGetLanguage(string key, out string language)
{
if (languages.TryGetValue(LocalizationSettings.SelectedLocale, out var value) && value.ContainsKey(key))
{
language = value[key];
return true;
}
language = null;
return false;
}
public static void DebugLanguage()
{
foreach (Locale locale in LocalizationSettings.AvailableLocales.Locales)
{
UtilsLogger.LogInfo("Language: " + locale.LocaleName);
}
}
}
public class LanguageInstance
{
public string key;
public string language;
public LanguageInstance(string key, string language)
{
this.key = key;
this.language = language;
}
}
public static class UtilsLogger
{
private static ManualLogSource logger;
internal static void InitLogger(ManualLogSource souce)
{
logger = souce;
}
public static void LogInfo(string message)
{
logger.LogInfo((object)message);
}
public static void LogError(string message)
{
logger.LogError((object)message);
}
public static void LogWarning(string message)
{
logger.LogWarning((object)message);
}
}
public class ShopUtilsException : Exception
{
public ShopUtilsException(string message)
: base(message)
{
}
}
[BepInPlugin("hyydsz-ShopUtils", "ShopUtils", "1.0.8")]
public class PluginInfo : BaseUnityPlugin
{
public const string ModGUID = "hyydsz-ShopUtils";
public const string ModName = "ShopUtils";
public const string ModVersion = "1.0.8";
private Harmony harmony = new Harmony("hyydsz-ShopUtils");
private void Awake()
{
UtilsLogger.InitLogger(((BaseUnityPlugin)this).Logger);
Entries.InitEntryCount();
Networks.InitNetwork();
harmony.PatchAll();
}
}
}
namespace ShopUtils.Network
{
public static class Networks
{
private static CSteamID steamID;
private static bool LobbyCreated;
private static bool inLobby;
public static Action OnLobbyCreated;
public static Action OnLobbyEnter;
public static Action OnLobbyLeave;
public static Action OnLobbyCreateFailure;
internal static void InitNetwork()
{
Callback<LobbyCreated_t>.Create((DispatchDelegate<LobbyCreated_t>)m_LobbyCreated);
Callback<LobbyEnter_t>.Create((DispatchDelegate<LobbyEnter_t>)m_LobbyEnter);
}
private static void m_LobbyCreated(LobbyCreated_t lobby)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Invalid comparison between Unknown and I4
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
if ((int)lobby.m_eResult == 1)
{
steamID = new CSteamID(lobby.m_ulSteamIDLobby);
LobbyCreated = true;
UtilsLogger.LogInfo("LobbyCreated.");
OnLobbyCreated?.Invoke();
}
else
{
OnLobbyCreateFailure?.Invoke();
}
}
private static void m_LobbyEnter(LobbyEnter_t lobby)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
steamID = new CSteamID(lobby.m_ulSteamIDLobby);
inLobby = true;
UtilsLogger.LogInfo("LobbyEntered.");
OnLobbyEnter?.Invoke();
}
internal static void m_LobbyLeave()
{
((CSteamID)(ref steamID)).Clear();
LobbyCreated = false;
inLobby = false;
OnLobbyLeave?.Invoke();
}
public static void RegisterItemPrice(Item item)
{
if ((Object)(object)item == (Object)null)
{
throw new ShopUtilsException("Item is null");
}
string itemName = "Item-" + item.persistentID;
OnLobbyCreated = (Action)Delegate.Combine(OnLobbyCreated, (Action)delegate
{
SetLobbyData(itemName, item.price.ToString());
});
OnLobbyEnter = (Action)Delegate.Combine(OnLobbyEnter, (Action)delegate
{
try
{
item.price = int.Parse(GetLobbyData(itemName));
}
catch
{
UtilsLogger.LogError("Sync Item Price Error. Item: " + item.displayName);
}
});
}
public static void SetLobbyData(string key, object value)
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
if (!LobbyCreated)
{
UtilsLogger.LogError("Cannot set lobby data when not create lobby");
}
else if (!SteamMatchmaking.SetLobbyData(steamID, key, value.ToString()))
{
UtilsLogger.LogError("Set lobby key Failure. Key: " + key);
}
}
public static string GetLobbyData(string key)
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
if (!inLobby)
{
UtilsLogger.LogError("Cannot get lobby data when not in lobby");
return null;
}
return SteamMatchmaking.GetLobbyData(steamID, key);
}
public static void SetNetworkSync(Dictionary<string, object> input, Action<Dictionary<string, string>> Action)
{
OnLobbyCreated = (Action)Delegate.Combine(OnLobbyCreated, (Action)delegate
{
foreach (KeyValuePair<string, object> item in input)
{
SetLobbyData(item.Key, item.Value);
}
});
OnLobbyEnter = (Action)Delegate.Combine(OnLobbyEnter, (Action)delegate
{
Dictionary<string, string> dictionary = new Dictionary<string, string>();
foreach (KeyValuePair<string, object> item2 in input)
{
dictionary.Add(item2.Key, GetLobbyData(item2.Key));
}
Action(dictionary);
});
}
}
[HarmonyPatch(typeof(SteamLobbyHandler))]
internal static class SteamLobbyHandlerPatches
{
[HarmonyPostfix]
[HarmonyPatch("LeaveLobby")]
private static void LeaveLobby()
{
Networks.m_LobbyLeave();
}
}
}
namespace ShopUtils.Language
{
public enum LanguageEnum
{
ChineseSimplified,
ChineseTraditional,
English,
French,
German,
Italian,
Japanese,
Portuguese,
Russian,
Spanish,
Ukrainian,
Korean,
Swedish
}
[HarmonyPatch(typeof(Item))]
internal static class LanguagePatch
{
[HarmonyPrefix]
[HarmonyPatch("GetTootipData")]
private static bool GetTootipData(Item __instance, ref IEnumerable<IHaveUIData> __result)
{
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Expected O, but got Unknown
if (Items.registerItems.Contains(__instance) && __instance.Tooltips.Count > 0)
{
string key = ((Object)__instance).name.Trim().Replace(" ", "") + "_ToolTips";
if (Languages.TryGetLanguage(key, out var language))
{
string[] array = language.Split(new char[1] { ';' });
__instance.Tooltips = new List<ItemKeyTooltip>();
string[] array2 = array;
foreach (string text in array2)
{
__instance.Tooltips.Add(new ItemKeyTooltip(text));
}
}
__result = (IEnumerable<IHaveUIData>)__instance.Tooltips;
return false;
}
return true;
}
[HarmonyPrefix]
[HarmonyPatch("GetLocalizedDisplayName")]
private static bool GetLocalizedDisplayName(Item __instance, ref string __result)
{
if (Items.registerItems.Contains(__instance))
{
string key = ((Object)__instance).name.Trim().Replace(" ", "");
if (Languages.TryGetLanguage(key, out var language))
{
__result = language;
return false;
}
__result = __instance.displayName;
return false;
}
return true;
}
}
[HarmonyPatch(typeof(ShopItem))]
internal static class ShopItemPatches
{
[HarmonyTranspiler]
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
private static IEnumerable<CodeInstruction> ShopItem(IEnumerable<CodeInstruction> instructions)
{
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Expected O, but got Unknown
FieldInfo display = AccessTools.Field(typeof(Item), "displayName");
MethodInfo methodInfo = AccessTools.Method(typeof(Item), "GetLocalizedDisplayName", (Type[])null, (Type[])null);
MethodInfo methodInfo2 = AccessTools.Method(typeof(Debug), "LogError", new Type[1] { typeof(object) }, (Type[])null);
return new CodeMatcher(instructions, (ILGenerator)null).SearchForward((Func<CodeInstruction, bool>)((CodeInstruction code) => code.opcode == OpCodes.Ldfld && (FieldInfo)code.operand == display)).ThrowIfInvalid("Couldn't find displayName").SetInstructionAndAdvance(new CodeInstruction(OpCodes.Call, (object)methodInfo))
.SearchForward((Func<CodeInstruction, bool>)((CodeInstruction code) => code.opcode == OpCodes.Ldstr))
.ThrowIfInvalid("Couldn't find LogError")
.RemoveInstructions(5)
.InstructionEnumeration();
}
}
}
namespace ShopUtils.ItemUtils
{
[HarmonyPatch(typeof(GameHandler))]
internal static class GameHandlerPatches
{
[HarmonyPostfix]
[HarmonyPatch("Initialize")]
private static void Initialize()
{
Items.InitAllItems();
ItemDatabase instance = SingletonAsset<ItemDatabase>.Instance;
((DatabaseAsset<ItemDatabase, Item>)(object)instance).Objects = CollectionExtensions.AddRangeToArray<Item>(((DatabaseAsset<ItemDatabase, Item>)(object)instance).Objects, Items.registerItems.Where((Item i) => i.id != 0).ToArray());
}
}
[HarmonyPatch(typeof(RoundArtifactSpawner))]
internal static class RoundArtifactSpawnerPatch
{
[HarmonyPrefix]
[HarmonyPatch("SpawnRound")]
private static void SpawnRound(RoundArtifactSpawner __instance)
{
__instance.possibleSpawns = CollectionExtensions.AddRangeToArray<Item>(__instance.possibleSpawns, Items.registerItems.Where((Item i) => i.id != 0 && i.spawnable).ToArray());
}
}
}