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.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("CantTouchThis")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CantTouchThis")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("0.0.1")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.1.0")]
namespace CantTouchThis;
[BepInPlugin("de.sirskunkalot.CantTouchThis", "CantTouchThis", "0.0.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
internal class CantTouchThis : BaseUnityPlugin
{
[CompilerGenerated]
private sealed class <DelayedMessage>d__33 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public string message;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <DelayedMessage>d__33(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>2__current = null;
<>1__state = 1;
return true;
case 1:
{
<>1__state = -1;
Player localPlayer = Player.m_localPlayer;
if (localPlayer != null)
{
((Character)localPlayer).Message((MessageType)2, message, 0, (Sprite)null);
}
return false;
}
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
public const string PluginGUID = "de.sirskunkalot.CantTouchThis";
public const string PluginName = "CantTouchThis";
public const string PluginVersion = "0.0.1";
private static CantTouchThis _instance;
private static readonly CustomLocalization Localization = LocalizationManager.Instance.GetLocalization();
private static readonly string[] MessageKeys = (from i in Enumerable.Range(1, 14)
select $"message{i}").ToArray();
private static ConfigEntry<string> _forbiddenItemsConfig;
private static ConfigEntry<bool> _removeRecipesFromUIConfig;
private static HashSet<string> _forbiddenItemsSet;
private static HashSet<string> _forbiddenItemsCache;
private static HashSet<string> _allowedItemsCache;
private void Awake()
{
//IL_011c: 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_0129: Expected O, but got Unknown
//IL_0129: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Expected O, but got Unknown
//IL_0185: Unknown result type (might be due to invalid IL or missing references)
//IL_018a: Unknown result type (might be due to invalid IL or missing references)
//IL_0192: Expected O, but got Unknown
//IL_0192: Unknown result type (might be due to invalid IL or missing references)
//IL_019c: Expected O, but got Unknown
_instance = this;
CustomLocalization localization = Localization;
string text = "English";
localization.AddTranslation(ref text, new Dictionary<string, string>
{
{ "message1", "Odin forbids {item_name}" },
{ "message2", "Even Loki wouldn't touch {item_name}" },
{ "message3", "The gods frown upon your desire for {item_name}" },
{ "message4", "{item_name}? Not in this realm" },
{ "message5", "Valhalla has {item_name}. You do not" },
{ "message6", "A raven whispers: {item_name} is not for you" },
{ "message7", "The Allfather says no to {item_name}" },
{ "message8", "You stare at {item_name}. It stares back. You walk away" },
{ "message9", "You can look at {item_name} but you can't touch" },
{ "message10", "Can't touch this" },
{ "message11", "Stop! {item_name} time. Oh wait..." },
{ "message12", "You shall not {item_name}" },
{ "message13", "Imagine using {item_name}" },
{ "message14", "{item_name}? In this economy?" }
});
_forbiddenItemsConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Config", "Forbidden Items", (string)null, new ConfigDescription("Comma separated list of forbidden items. Syncs from server. Evaluated at runtime when changed.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
{
IsAdminOnly = true
} }));
_forbiddenItemsConfig.SettingChanged += delegate
{
ResetForbiddenItems();
};
ResetForbiddenItems();
_removeRecipesFromUIConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Config", "Hide Forbidden Items in UI", false, new ConfigDescription("Forbidden items will not show up in the crafting and building menu when enabled. Client side only.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
{
IsAdminOnly = false
} }));
Harmony.CreateAndPatchAll(typeof(CantTouchThis), "de.sirskunkalot.CantTouchThis");
}
[HarmonyPatch(typeof(Game), "Start")]
[HarmonyPostfix]
private static void PostfixGameStart()
{
CraftingDataCache.Build();
}
[HarmonyPatch(typeof(Game), "OnDestroy")]
[HarmonyPostfix]
private static void PostfixGameDestroy()
{
CraftingDataCache.Invalidate();
}
[HarmonyPatch(typeof(Player), "CanConsumeItem")]
[HarmonyPrefix]
private static bool PrefixPlayerCanConsumeItem(Player __instance, ItemData item)
{
return CheckConsumption(__instance, item);
}
[HarmonyPatch(typeof(Player), "ConsumeItem")]
[HarmonyPrefix]
private static bool PrefixPlayerConsumeItem(Player __instance, ItemData item)
{
return CheckConsumption(__instance, item);
}
private static bool CheckConsumption(Player player, ItemData item)
{
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Invalid comparison between Unknown and I4
if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || (Object)(object)Player.m_localPlayer != (Object)(object)player)
{
return true;
}
if ((int)item.m_shared.m_itemType != 2)
{
return true;
}
if (IsForbidden(item.m_shared.m_name))
{
Message(item.m_shared.m_name);
return false;
}
return true;
}
[HarmonyPatch(typeof(InventoryGui), "OnCraftPressed")]
[HarmonyPrefix]
private static bool PrefixOnCraftPressed(InventoryGui __instance)
{
Recipe recipe = ((RecipeDataPair)(ref __instance.m_selectedRecipe)).Recipe;
if ((Object)(object)recipe?.m_item == (Object)null)
{
return true;
}
string name = recipe.m_item.m_itemData.m_shared.m_name;
if (IsForbidden(name))
{
Message(name);
return false;
}
return true;
}
[HarmonyPatch(typeof(Player), "GetAvailableRecipes")]
[HarmonyPostfix]
private static void PostfixGetAvailableRecipes(ref List<Recipe> available)
{
if (_removeRecipesFromUIConfig.Value)
{
available.RemoveAll((Recipe recipe) => !((Object)(object)recipe?.m_item == (Object)null) && IsForbidden(recipe.m_item.m_itemData.m_shared.m_name));
}
}
[HarmonyPatch(typeof(Player), "TryPlacePiece")]
[HarmonyPrefix]
private static bool PrefixTryPlacePiece(Player __instance, Piece piece)
{
if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || (Object)(object)Player.m_localPlayer != (Object)(object)__instance)
{
return true;
}
if ((Object)(object)piece == (Object)null)
{
return true;
}
if (IsPieceForbidden(piece))
{
Message(piece.m_name);
return false;
}
return true;
}
[HarmonyPatch(typeof(PieceTable), "UpdateAvailable")]
[HarmonyPostfix]
private static void PostfixUpdateAvailable(PieceTable __instance)
{
if (!_removeRecipesFromUIConfig.Value)
{
return;
}
foreach (List<Piece> availablePiece in __instance.m_availablePieces)
{
availablePiece.RemoveAll((Piece piece) => IsPieceForbidden(piece));
}
}
private static bool IsPieceForbidden(Piece piece)
{
if ((Object)(object)piece == (Object)null)
{
return false;
}
if (IsForbidden(piece.m_name))
{
return true;
}
foreach (string pieceRequirement in CraftingDataCache.Get().GetPieceRequirements(piece.m_name))
{
if (IsForbidden(pieceRequirement))
{
return true;
}
}
return false;
}
[HarmonyPatch(typeof(CookingStation), "OnUseItem")]
[HarmonyPrefix]
private static bool PrefixCookingStationUseItem(Humanoid user, ItemData item)
{
return CheckStationInput((Player)(object)((user is Player) ? user : null), item);
}
[HarmonyPatch(typeof(CookingStation), "OnAddFuelSwitch")]
[HarmonyPrefix]
private static bool PrefixCookingStationAddFuel(CookingStation __instance, Humanoid user)
{
Player val = (Player)(object)((user is Player) ? user : null);
if (val == null)
{
return true;
}
if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || (Object)(object)Player.m_localPlayer != (Object)(object)val)
{
return true;
}
if ((Object)(object)__instance.m_fuelItem == (Object)null)
{
return true;
}
if (!IsForbidden(__instance.m_fuelItem.m_itemData.m_shared.m_name))
{
return true;
}
Message(__instance.m_fuelItem.m_itemData.m_shared.m_name, delayed: true);
return false;
}
[HarmonyPatch(typeof(Fermenter), "AddItem")]
[HarmonyPrefix]
private static bool PrefixFermenterAddItem(Humanoid user, ItemData item)
{
return CheckStationInput((Player)(object)((user is Player) ? user : null), item);
}
[HarmonyPatch(typeof(Smelter), "OnAddOre")]
[HarmonyPrefix]
private static bool PrefixSmelterAddOre(Humanoid user, ItemData item)
{
if (item == null)
{
return true;
}
return CheckStationInput((Player)(object)((user is Player) ? user : null), item);
}
[HarmonyPatch(typeof(Smelter), "FindCookableItem")]
[HarmonyPostfix]
private static void PostfixFindCookableItem(Smelter __instance, Inventory inventory, ref ItemData __result)
{
if (__result == null || !IsForbidden(__result.m_shared.m_name))
{
return;
}
string name = __result.m_shared.m_name;
foreach (ItemData allItem in inventory.GetAllItems())
{
if (allItem != __result && !(allItem.m_shared.m_name == __result.m_shared.m_name) && __instance.IsItemAllowed(((Object)allItem.m_dropPrefab).name) && !IsForbidden(allItem.m_shared.m_name))
{
__result = allItem;
return;
}
}
__result = null;
Message(name, delayed: true);
}
[HarmonyPatch(typeof(Smelter), "OnAddFuel")]
[HarmonyPrefix]
private static bool PrefixSmelterAddFuel(Smelter __instance, Humanoid user)
{
Player val = (Player)(object)((user is Player) ? user : null);
if (val == null)
{
return true;
}
if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || (Object)(object)Player.m_localPlayer != (Object)(object)val)
{
return true;
}
if ((Object)(object)__instance.m_fuelItem == (Object)null)
{
return true;
}
if (!IsForbidden(__instance.m_fuelItem.m_itemData.m_shared.m_name))
{
return true;
}
Message(__instance.m_fuelItem.m_itemData.m_shared.m_name, delayed: true);
return false;
}
private static bool CheckStationInput(Player player, ItemData item)
{
if ((Object)(object)player == (Object)null || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || (Object)(object)Player.m_localPlayer != (Object)(object)player)
{
return true;
}
if (item == null)
{
return true;
}
if (IsForbidden(item.m_shared.m_name))
{
Message(item.m_shared.m_name);
return false;
}
return true;
}
private static void ResetForbiddenItems()
{
_forbiddenItemsCache = new HashSet<string>();
_allowedItemsCache = new HashSet<string>();
if (string.IsNullOrEmpty(_forbiddenItemsConfig.Value))
{
_forbiddenItemsSet = new HashSet<string>();
}
else
{
_forbiddenItemsSet = (from s in _forbiddenItemsConfig.Value.Split(new char[1] { ',' })
select s.Trim() into s
where !string.IsNullOrEmpty(s)
select s).ToHashSet<string>(StringComparer.Ordinal);
}
Logger.LogDebug((object)$"Forbidden items: {_forbiddenItemsSet.Count}");
}
private static bool IsForbidden(string itemName)
{
if (_forbiddenItemsCache.Contains(itemName))
{
return true;
}
if (_allowedItemsCache.Contains(itemName))
{
return false;
}
bool num = ResolveItemForbidden(itemName, new HashSet<string>());
if (num)
{
_forbiddenItemsCache.Add(itemName);
return num;
}
_allowedItemsCache.Add(itemName);
return num;
}
private static bool ResolveItemForbidden(string itemName, HashSet<string> visited)
{
if (!visited.Add(itemName))
{
return false;
}
if (_forbiddenItemsSet.Contains(itemName))
{
return true;
}
CraftingDataCache craftingDataCache = CraftingDataCache.Get();
foreach (string recipeIngredient in craftingDataCache.GetRecipeIngredients(itemName))
{
if (ResolveItemForbidden(recipeIngredient, visited))
{
return true;
}
}
foreach (string conversionSource in craftingDataCache.GetConversionSources(itemName))
{
if (ResolveItemForbidden(conversionSource, visited))
{
return true;
}
}
return false;
}
private static void Message(string itemName, bool delayed = false)
{
Player localPlayer = Player.m_localPlayer;
if (!((Object)(object)localPlayer == (Object)null))
{
string message = GetMessage(itemName);
if (delayed)
{
((MonoBehaviour)_instance).StartCoroutine(DelayedMessage(message));
}
else
{
((Character)localPlayer).Message((MessageType)2, message, 0, (Sprite)null);
}
}
}
[IteratorStateMachine(typeof(<DelayedMessage>d__33))]
private static IEnumerator DelayedMessage(string message)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <DelayedMessage>d__33(0)
{
message = message
};
}
private static string GetMessage(string itemName)
{
string text = MessageKeys[Random.Range(0, MessageKeys.Length)];
return Localization.TryTranslate("$" + text).Replace("{item_name}", itemName);
}
}
internal class CraftingDataCache
{
private static CraftingDataCache _instance;
private readonly Dictionary<string, List<string>> _recipeIngredients;
private readonly Dictionary<string, List<string>> _conversionSources;
private readonly Dictionary<string, List<string>> _pieceRequirements;
private CraftingDataCache()
{
_recipeIngredients = BuildRecipeCache();
_conversionSources = BuildConversionCache();
_pieceRequirements = BuildPieceCache();
}
public static void Build()
{
_instance = new CraftingDataCache();
}
public static CraftingDataCache Get()
{
if (_instance == null)
{
_instance = new CraftingDataCache();
}
return _instance;
}
public static void Invalidate()
{
_instance = null;
}
public IEnumerable<string> GetRecipeIngredients(string outputItemName)
{
if (_recipeIngredients.TryGetValue(outputItemName, out var value))
{
return value;
}
return Enumerable.Empty<string>();
}
public IEnumerable<string> GetConversionSources(string outputItemName)
{
if (_conversionSources.TryGetValue(outputItemName, out var value))
{
return value;
}
return Enumerable.Empty<string>();
}
public IEnumerable<string> GetPieceRequirements(string pieceName)
{
if (_pieceRequirements.TryGetValue(pieceName, out var value))
{
return value;
}
return Enumerable.Empty<string>();
}
private static Dictionary<string, List<string>> BuildRecipeCache()
{
Logger.LogDebug((object)"Creating RecipeCache");
Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>(StringComparer.Ordinal);
if ((Object)(object)ObjectDB.instance == (Object)null)
{
return dictionary;
}
foreach (Recipe recipe in ObjectDB.instance.m_recipes)
{
if ((Object)(object)recipe.m_item == (Object)null)
{
continue;
}
string name = recipe.m_item.m_itemData.m_shared.m_name;
Requirement[] resources = recipe.m_resources;
foreach (Requirement val in resources)
{
if (!((Object)(object)val.m_resItem == (Object)null))
{
string name2 = val.m_resItem.m_itemData.m_shared.m_name;
AddEntry(dictionary, name, name2);
}
}
}
return dictionary;
}
private static Dictionary<string, List<string>> BuildConversionCache()
{
Logger.LogDebug((object)"Creating ConversionDataCache");
Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>(StringComparer.Ordinal);
if ((Object)(object)ZNetScene.instance == (Object)null)
{
return dictionary;
}
CookingStation val = default(CookingStation);
Fermenter val2 = default(Fermenter);
Smelter val3 = default(Smelter);
foreach (GameObject value in ZNetScene.instance.m_namedPrefabs.Values)
{
if (!Object.op_Implicit((Object)(object)value))
{
continue;
}
if (value.TryGetComponent<CookingStation>(ref val))
{
foreach (ItemConversion item in val.m_conversion)
{
if (!((Object)(object)item.m_from == (Object)null) && !((Object)(object)item.m_to == (Object)null))
{
AddEntry(dictionary, item.m_to.m_itemData.m_shared.m_name, item.m_from.m_itemData.m_shared.m_name);
}
}
}
if (value.TryGetComponent<Fermenter>(ref val2))
{
foreach (ItemConversion item2 in val2.m_conversion)
{
if (!((Object)(object)item2.m_from == (Object)null) && !((Object)(object)item2.m_to == (Object)null))
{
AddEntry(dictionary, item2.m_to.m_itemData.m_shared.m_name, item2.m_from.m_itemData.m_shared.m_name);
}
}
}
if (!value.TryGetComponent<Smelter>(ref val3))
{
continue;
}
foreach (ItemConversion item3 in val3.m_conversion)
{
if (!((Object)(object)item3.m_from == (Object)null) && !((Object)(object)item3.m_to == (Object)null))
{
AddEntry(dictionary, item3.m_to.m_itemData.m_shared.m_name, item3.m_from.m_itemData.m_shared.m_name);
}
}
}
return dictionary;
}
private static Dictionary<string, List<string>> BuildPieceCache()
{
Logger.LogDebug((object)"Creating PieceCache");
Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>(StringComparer.Ordinal);
if ((Object)(object)ZNetScene.instance == (Object)null)
{
return dictionary;
}
Piece val = default(Piece);
foreach (GameObject value in ZNetScene.instance.m_namedPrefabs.Values)
{
if (!Object.op_Implicit((Object)(object)value) || !value.TryGetComponent<Piece>(ref val) || val.m_resources == null || val.m_resources.Length == 0)
{
continue;
}
Requirement[] resources = val.m_resources;
foreach (Requirement val2 in resources)
{
if (!((Object)(object)val2.m_resItem == (Object)null))
{
AddEntry(dictionary, val.m_name, val2.m_resItem.m_itemData.m_shared.m_name);
}
}
}
return dictionary;
}
private static void AddEntry(Dictionary<string, List<string>> dict, string key, string value)
{
Logger.LogDebug((object)("Adding " + key + ": " + value));
if (!dict.TryGetValue(key, out var value2))
{
value2 = (dict[key] = new List<string>());
}
value2.Add(value);
}
}