Decompiled source of Travel Totems v0.1.0

Plugins/VentureValheim.TravelTotems.dll

Decompiled 13 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
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.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Splatform;
using UnityEngine;
using UnityEngine.SceneManagement;
using VentureValheim.MultiplayerTweaks;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("VentureValheim.TravelTotems")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VentureValheim.TravelTotems")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("D150132C-BA5F-41DA-9A9C-29FD189CDE71")]
[assembly: AssemblyFileVersion("0.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace VentureValheim.TravelTotems
{
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.orianaventure.mod.TravelTotems", "TravelTotems", "0.1.0")]
	public class TravelTotemsPlugin : BaseUnityPlugin
	{
		private const string ModName = "TravelTotems";

		private const string ModVersion = "0.1.0";

		private const string Author = "com.orianaventure.mod";

		private const string ModGUID = "com.orianaventure.mod.TravelTotems";

		private static string ConfigFileName = "com.orianaventure.mod.TravelTotems.cfg";

		private static string ConfigFileFullPath;

		private const string VVMTGUID = "com.orianaventure.mod.MultiplayerTweaks";

		private const string VVMTAPI = "VentureValheim.MultiplayerTweaks.API";

		private readonly Harmony HarmonyInstance = new Harmony("com.orianaventure.mod.TravelTotems");

		public static readonly ManualLogSource TravelTotemsLogger;

		private static ConfigEntry<bool> CE_AdminBypass;

		private static ConfigEntry<bool> CE_ShowTotemID;

		private static ConfigEntry<bool> CE_TotemNamingAccess;

		private static ConfigEntry<bool> CE_ShowMapPins;

		private static ConfigEntry<string> CE_TotemAccessDefault;

		private static ConfigEntry<string> CE_TotemUnlockRequirementsString;

		private static ConfigEntry<bool> CE_AllowSelectDefaultSpawn;

		private static ConfigEntry<bool> CE_AllowSelectTraders;

		private static ConfigEntry<bool> CE_AllowSelectBed;

		private static ConfigEntry<bool> CE_AllowTotemClaiming;

		private static ConfigEntry<bool> CE_TradersSellTotemBomb;

		private static ConfigEntry<int> CE_TradersSellTotemBombCost;

		private static ConfigEntry<int> CE_LocationAmountDefault;

		private static ConfigEntry<int> CE_LocationAmountMeadows;

		private static ConfigEntry<int> CE_LocationAmountBlackForest;

		private static ConfigEntry<int> CE_LocationAmountSwamp;

		private static ConfigEntry<int> CE_LocationAmountMountain;

		private static ConfigEntry<int> CE_LocationAmountPlains;

		private static ConfigEntry<int> CE_LocationAmountMistlands;

		private static ConfigEntry<int> CE_LocationAmountAshlands;

		private static ConfigEntry<int> CE_LocationSpacing;

		private static ConfigEntry<bool> CE_PieceRecipesEnabled;

		private static ConfigEntry<string> CE_TravelTotemPieceCost;

		private static ConfigEntry<string> CE_TravelTotemPieceMistlandsCost;

		private static ConfigEntry<string> CE_TravelTotemPieceAshlandsCost;

		private static ConfigEntry<bool> CE_ItemRecipesEnabled;

		private static ConfigEntry<string> CE_TotemBombCraftCost;

		private readonly ConfigurationManagerAttributes AdminConfig = new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		};

		private readonly ConfigurationManagerAttributes ClientConfig = new ConfigurationManagerAttributes
		{
			IsAdminOnly = false
		};

		private DateTime _lastReloadTime;

		private const long RELOAD_DELAY = 10000000L;

		public static bool MultiplayerTweaksInstalled { get; private set; }

		internal static AssetBundle TotemBundle { get; private set; }

		private static bool AdminAccess()
		{
			if (CE_AdminBypass.Value)
			{
				return SynchronizationManager.Instance.PlayerIsAdmin;
			}
			return false;
		}

		public static bool GetOverrideTotemAccess(bool isCreator)
		{
			if (isCreator || AdminAccess())
			{
				return true;
			}
			return false;
		}

		public static bool GetTotemNamingAccess(bool isCreator, bool isPublic)
		{
			if (isCreator || AdminAccess() || (CE_TotemNamingAccess.Value && isPublic))
			{
				return true;
			}
			return false;
		}

		public static bool GetShowMapPins()
		{
			return CE_ShowMapPins.Value;
		}

		public static bool GetShowTotemID()
		{
			return CE_ShowTotemID.Value;
		}

		public static TravelTotemType GetTravelTotemType()
		{
			return CE_TotemAccessDefault.Value.ToLower() switch
			{
				"alwaysunlock" => TravelTotemType.AlwaysUnlock, 
				"alwayslock" => TravelTotemType.AlwaysLock, 
				"findunlock" => TravelTotemType.FindUnlock, 
				_ => TravelTotemType.Undefined, 
			};
		}

		public static string GetTotemUnlockRequirementsString()
		{
			return CE_TotemUnlockRequirementsString.Value;
		}

		public static bool GetAllowSelectDefaultSpawn()
		{
			return CE_AllowSelectDefaultSpawn.Value;
		}

		public static bool GetAllowSelectTraders()
		{
			return CE_AllowSelectTraders.Value;
		}

		public static bool GetAllowSelectBed()
		{
			return CE_AllowSelectBed.Value;
		}

		public static bool GetAllowTotemClaiming()
		{
			return CE_AllowTotemClaiming.Value;
		}

		public static bool GetTradersSellTotemBomb()
		{
			return CE_TradersSellTotemBomb.Value;
		}

		public static int GetTradersSellTotemBombCost()
		{
			return CE_TradersSellTotemBombCost.Value;
		}

		public static int GetLocationAmountDefault()
		{
			return CE_LocationAmountDefault.Value;
		}

		public static int GetLocationAmountMeadows()
		{
			return CE_LocationAmountMeadows.Value;
		}

		public static int GetLocationAmountBlackForest()
		{
			return CE_LocationAmountBlackForest.Value;
		}

		public static int GetLocationAmountSwamp()
		{
			return CE_LocationAmountSwamp.Value;
		}

		public static int GetLocationAmountMountain()
		{
			return CE_LocationAmountMountain.Value;
		}

		public static int GetLocationAmountPlains()
		{
			return CE_LocationAmountPlains.Value;
		}

		public static int GetLocationAmountMistlands()
		{
			return CE_LocationAmountMistlands.Value;
		}

		public static int GetLocationAmountAshlands()
		{
			return CE_LocationAmountAshlands.Value;
		}

		public static int GetLocationSpacing()
		{
			return CE_LocationSpacing.Value;
		}

		public static bool GetTravelTotemPieceRecipesEnabled()
		{
			return CE_PieceRecipesEnabled.Value;
		}

		public static string GetTravelTotemPieceCost()
		{
			return CE_TravelTotemPieceCost.Value;
		}

		public static string GetTravelTotemPieceMistlandsCost()
		{
			return CE_TravelTotemPieceMistlandsCost.Value;
		}

		public static string GetTravelTotemPieceAshlandsCost()
		{
			return CE_TravelTotemPieceAshlandsCost.Value;
		}

		public static bool GetTotemItemRecipesEnabled()
		{
			return CE_ItemRecipesEnabled.Value;
		}

		public static string GetTotemBombItemCost()
		{
			return CE_TotemBombCraftCost.Value;
		}

		private void AddConfig<T>(string key, string section, string description, bool synced, T value, ref ConfigEntry<T> configEntry)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			string extendedDescription = GetExtendedDescription(description, synced);
			configEntry = ((BaseUnityPlugin)this).Config.Bind<T>(section, key, value, new ConfigDescription(extendedDescription, (AcceptableValueBase)null, new object[1] { synced ? AdminConfig : ClientConfig }));
		}

		public string GetExtendedDescription(string description, bool synchronizedSetting)
		{
			return description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]");
		}

		public void Awake()
		{
			AddConfig("TotemNamingAccess", "General", "When false allow only admins (using AdminBypass) to rename public travel totems (boolean).", synced: true, value: false, ref CE_TotemNamingAccess);
			AddConfig("TotemAccessDefault", "General", "Default access type for new totems: AlwaysUnlock, FindUnlock, AlwaysLock (string).", synced: true, "FindUnlock", ref CE_TotemAccessDefault);
			AddConfig("TotemUnlockRequirements", "General", "Prefab amount pairs of required items to unlock a portal when access is set to TouchUnlock. For example: Wood:2,SurtlingCore:2 (A comma-separated list of ITEM:QUANTITY pairs).", synced: true, "", ref CE_TotemUnlockRequirementsString);
			AddConfig("AllowSelectDefaultSpawn", "General", "When true allow teleporting to the starting stones icon when using totems (boolean).", synced: true, value: true, ref CE_AllowSelectDefaultSpawn);
			AddConfig("AllowSelectTraders", "General", "When true allow teleporting to discovered trader icons when using totems (boolean).", synced: true, value: true, ref CE_AllowSelectTraders);
			AddConfig("AllowSelectBed", "General", "When true allow teleporting to bed icons when using totems (boolean).", synced: true, value: true, ref CE_AllowSelectBed);
			AddConfig("AllowTotemClaiming", "General", "When true allow players to claim public totems they unlock as if they built them (boolean).", synced: true, value: false, ref CE_AllowTotemClaiming);
			AddConfig("AdminBypass", "Client", "Allow local admins to access and change all travel totems at all times (boolean).", synced: false, value: false, ref CE_AdminBypass);
			AddConfig("ShowMapPins", "Client", "Always show map pins of available Totems on the Player minimap (boolean).", synced: false, value: true, ref CE_ShowMapPins);
			AddConfig("ShowTotemID", "Client", "Display the Totem ID when looking at a Totem (boolean).", synced: false, value: false, ref CE_ShowTotemID);
			AddConfig("TradersSellTotemBomb", "Trader", "Adds Totem Bombs for sale by the traders (boolean).", synced: false, value: true, ref CE_TradersSellTotemBomb);
			AddConfig("TradersSellTotemBombCost", "Trader", "Coins cost of the Totem Bomb (boolean).", synced: false, 100, ref CE_TradersSellTotemBombCost);
			AddConfig("LocationAmountDefault", "Location", "Maximum number of undecorated, biome universal locations to add during world generation. Set to 0 to disable (int).", synced: true, 0, ref CE_LocationAmountDefault);
			AddConfig("LocationAmountMeadows", "Location", "Maximum number of Meadows locations to add during world generation. Set to 0 to disable (int).", synced: true, 20, ref CE_LocationAmountMeadows);
			AddConfig("LocationAmountBlackForest", "Location", "Maximum number of BlackForest locations to add during world generation. Set to 0 to disable (int).", synced: true, 20, ref CE_LocationAmountBlackForest);
			AddConfig("LocationAmountSwamp", "Location", "Maximum number of Swamp locations to add during world generation. Set to 0 to disable (int).", synced: true, 20, ref CE_LocationAmountSwamp);
			AddConfig("LocationAmountMountain", "Location", "Maximum number of Mountain locations to add during world generation. Set to 0 to disable (int).", synced: true, 20, ref CE_LocationAmountMountain);
			AddConfig("LocationAmountPlains", "Location", "Maximum number of Plains locations to add during world generation. Set to 0 to disable (int).", synced: true, 20, ref CE_LocationAmountPlains);
			AddConfig("LocationAmountMistlands", "Location", "Maximum number of Mistlands locations to add during world generation. Set to 0 to disable (int).", synced: true, 20, ref CE_LocationAmountMistlands);
			AddConfig("LocationAmountAshlands", "Location", "Maximum number of Ashlands locations to add during world generation. Set to 0 to disable (int).", synced: true, 10, ref CE_LocationAmountAshlands);
			AddConfig("LocationSpacing", "Location", "Minimum world distance between similar totems. Setting also commonly known as \"MinDistanceFromSimilar\" (int).", synced: true, 1500, ref CE_LocationSpacing);
			AddConfig("PieceRecipeOverridesEnabled", "Pieces", "True to use these cost configurations. Set to false if using another mod to customize this (boolean).", synced: true, value: true, ref CE_PieceRecipesEnabled);
			AddConfig("PieceCost", "Pieces", "Default Totem build cost, if left blank will be disabled (A comma-separated list of ITEM:QUANTITY pairs).", synced: true, AssetManager.TravelTotemPiece_Cost, ref CE_TravelTotemPieceCost);
			AddConfig("PieceMistlandsCost", "Pieces", "Mistlands Totem build cost, if left blank will be disabled (A comma-separated list of ITEM:QUANTITY pairs).", synced: true, AssetManager.TravelTotemPieceMistlands_Cost, ref CE_TravelTotemPieceMistlandsCost);
			AddConfig("PieceAshlandsCost", "Pieces", "Ashlands Totem build cost, if left blank will be disabled (A comma-separated list of ITEM:QUANTITY pairs).", synced: true, AssetManager.TravelTotemPieceAshlands_Cost, ref CE_TravelTotemPieceAshlandsCost);
			AddConfig("ItemRecipeOverridesEnabled", "Items", "True to use these cost configurations. Set to false if using another mod to customize this (boolean).", synced: true, value: true, ref CE_ItemRecipesEnabled);
			AddConfig("TotemBombCraftCost", "Items", "Totem Bomb crafting cost, if left blank will be disabled (A comma-separated list of ITEM:QUANTITY pairs).", synced: true, AssetManager.TotemBombCraft_Cost, ref CE_TotemBombCraftCost);
			TravelTotemsLogger.LogInfo((object)"Praise be to the gods.");
			CheckForMultiplayerTweaks();
			ZoneManager.OnVanillaLocationsAvailable += AssetManager.AddTotemLocations;
			PrefabManager.OnVanillaPrefabsAvailable += AssetManager.AddPrefabs;
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			HarmonyInstance.PatchAll(executingAssembly);
			SetupWatcher();
			TotemBundle = AssetUtils.LoadAssetBundleFromResources("vv_traveltotems", Assembly.GetExecutingAssembly());
			ItemManager.OnItemsRegistered += AssetManager.UpdateItemConfigurations;
			PieceManager.OnPiecesRegistered += AssetManager.UpdatePieceConfigurations;
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private void CheckForMultiplayerTweaks()
		{
			try
			{
				MultiplayerTweaksInstalled = Chainloader.PluginInfos.TryGetValue("com.orianaventure.mod.MultiplayerTweaks", out var value);
				if (MultiplayerTweaksInstalled)
				{
					Type type = Assembly.GetAssembly(((object)value.Instance).GetType()).GetType("VentureValheim.MultiplayerTweaks.API");
					if (type != null && AccessTools.Method(type, "GetHaldorPinIndex", (Type[])null, (Type[])null) != null)
					{
						TravelTotemsLogger.LogInfo((object)"Multiplayer Tweaks installed. Personal Trader pins can be tracked for teleportation!");
						return;
					}
					MultiplayerTweaksInstalled = false;
					TravelTotemsLogger.LogWarning((object)"Multiplayer Tweaks version mismatch! Please update Multiplayer Tweaks.");
				}
			}
			catch
			{
				MultiplayerTweaksInstalled = false;
			}
			if (!MultiplayerTweaksInstalled)
			{
				TravelTotemsLogger.LogDebug((object)"Multiplayer Tweaks is not installed. Will not check pins for compatibility.");
			}
		}

		private void OnDestroy()
		{
			((BaseUnityPlugin)this).Config.Save();
		}

		private void SetupWatcher()
		{
			_lastReloadTime = DateTime.Now;
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
			fileSystemWatcher.Changed += ReadConfigValues;
			fileSystemWatcher.Created += ReadConfigValues;
			fileSystemWatcher.Renamed += ReadConfigValues;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			DateTime now = DateTime.Now;
			long num = now.Ticks - _lastReloadTime.Ticks;
			if (!File.Exists(ConfigFileFullPath) || num < 10000000)
			{
				return;
			}
			try
			{
				TravelTotemsLogger.LogInfo((object)"Attempting to reload configuration...");
				((BaseUnityPlugin)this).Config.Reload();
			}
			catch
			{
				TravelTotemsLogger.LogError((object)("There was an issue loading " + ConfigFileName));
				return;
			}
			_lastReloadTime = now;
			if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsDedicated())
			{
				TravelTotems.UpdateSettings();
				AssetManager.UpdateConfigurations();
				TravelTotemMap.RefreshMapPins();
				if (Object.op_Implicit((Object)(object)ZoneSystem.instance))
				{
					TravelTotemMap.RefreshLocationIcons();
				}
			}
		}

		public static bool IsInTheMainScene()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			return ((Scene)(ref activeScene)).name.Equals("main");
		}

		static TravelTotemsPlugin()
		{
			string configPath = Paths.ConfigPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName;
			TravelTotemsLogger = Logger.CreateLogSource("TravelTotems");
			CE_AdminBypass = null;
			CE_ShowTotemID = null;
			CE_TotemNamingAccess = null;
			CE_ShowMapPins = null;
			CE_TotemAccessDefault = null;
			CE_TotemUnlockRequirementsString = null;
			CE_AllowSelectDefaultSpawn = null;
			CE_AllowSelectTraders = null;
			CE_AllowSelectBed = null;
			CE_AllowTotemClaiming = null;
			CE_TradersSellTotemBomb = null;
			CE_TradersSellTotemBombCost = null;
			CE_LocationAmountDefault = null;
			CE_LocationAmountMeadows = null;
			CE_LocationAmountBlackForest = null;
			CE_LocationAmountSwamp = null;
			CE_LocationAmountMountain = null;
			CE_LocationAmountPlains = null;
			CE_LocationAmountMistlands = null;
			CE_LocationAmountAshlands = null;
			CE_LocationSpacing = null;
			CE_PieceRecipesEnabled = null;
			CE_TravelTotemPieceCost = null;
			CE_TravelTotemPieceMistlandsCost = null;
			CE_TravelTotemPieceAshlandsCost = null;
			CE_ItemRecipesEnabled = null;
			CE_TotemBombCraftCost = null;
		}
	}
	public class AssetManager
	{
		public static string TravelTotemTrackerPrefabName = "VV_TravelTotemTracker";

		public static int TravelTotemTrackerHash = StringExtensionMethods.GetStableHashCode(TravelTotemTrackerPrefabName);

		private static string TravelTotem_PrefabName = "VV_TravelTotem";

		private static string TravelTotemMistlands_PrefabName = "VV_TravelTotemMistlands";

		private static string TravelTotemAshlands_PrefabName = "VV_TravelTotemAshlands";

		private static int TravelTotemHash = StringExtensionMethods.GetStableHashCode(TravelTotem_PrefabName);

		private static int TravelTotemMistlandsHash = StringExtensionMethods.GetStableHashCode(TravelTotemMistlands_PrefabName);

		private static int TravelTotemAshlandsHash = StringExtensionMethods.GetStableHashCode(TravelTotemAshlands_PrefabName);

		private static string TravelTotemPiece_PrefabName = "VV_TravelTotemPiece";

		private static string TravelTotemPieceMistlands_PrefabName = "VV_TravelTotemPieceMistlands";

		private static string TravelTotemPieceAshlands_PrefabName = "VV_TravelTotemPieceAshlands";

		private static int TravelTotemPieceHash = StringExtensionMethods.GetStableHashCode(TravelTotemPiece_PrefabName);

		private static int TravelTotemPieceMistlandsHash = StringExtensionMethods.GetStableHashCode(TravelTotemPieceMistlands_PrefabName);

		private static int TravelTotemPieceAshlandsHash = StringExtensionMethods.GetStableHashCode(TravelTotemPieceAshlands_PrefabName);

		public static string TravelTotemPiece_Cost = "GreydwarfEye:10,Stone:20,SurtlingCore:5";

		public static string TravelTotemPieceMistlands_Cost = "GreydwarfEye:10,BlackMarble:20,SurtlingCore:5";

		public static string TravelTotemPieceAshlands_Cost = "GreydwarfEye:10,Grausten:20,SurtlingCore:5";

		private static string TravelTotemArea_PrefabName = "VV_TravelTotemArea";

		public static string TravelTotemBomb_PrefabName = "VV_BombTotem";

		private static string TravelTotemBombSpawn_PrefabName = "VV_BombTotem_projectile";

		public static string TotemBombCraft_Cost = "GreydwarfEye:10,Resin:10,SurtlingCore:2";

		private static string TotemMapSprite_Name = "VV_TravelTotemMapSprite";

		public static Material TotemMaterialDefault { get; private set; }

		public static Material TotemMaterialMistlands { get; private set; }

		public static Material TotemMaterialAshlands { get; private set; }

		public static Sprite TotemMapSprite { get; private set; }

		public static bool IsTravelTotem(int prefabHash)
		{
			if (prefabHash != TravelTotemHash && prefabHash != TravelTotemMistlandsHash && prefabHash != TravelTotemAshlandsHash && prefabHash != TravelTotemPieceHash && prefabHash != TravelTotemPieceMistlandsHash)
			{
				return prefabHash == TravelTotemPieceAshlandsHash;
			}
			return true;
		}

		public static bool IsTravelTotemTracker(int prefabHash)
		{
			return prefabHash == TravelTotemTrackerHash;
		}

		public static void AddPrefabs()
		{
			CreateMaterials();
			AddPrefab(TravelTotem_PrefabName);
			AddPrefab(TravelTotemMistlands_PrefabName);
			AddPrefab(TravelTotemAshlands_PrefabName);
			AddPrefab(TravelTotemTrackerPrefabName);
			CreatePieces();
			CreateItems();
			TotemMapSprite = TravelTotemsPlugin.TotemBundle.LoadAsset<Sprite>(TotemMapSprite_Name);
			PrefabManager.OnVanillaPrefabsAvailable -= AddPrefabs;
		}

		private static void AddPrefab(string name)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			CustomPrefab val = new CustomPrefab(TravelTotemsPlugin.TotemBundle, name, true);
			PrefabManager.Instance.AddPrefab(val);
		}

		private static void CreateItems()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Expected O, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			AddPrefab(TravelTotemArea_PrefabName);
			AddPrefab(TravelTotemBombSpawn_PrefabName);
			GameObject val = TravelTotemsPlugin.TotemBundle.LoadAsset<GameObject>(TravelTotemBomb_PrefabName);
			ItemConfig val2 = new ItemConfig();
			val2.Name = "Totem Bomb";
			val2.Description = "An unstable burst energy that can temporarily access a teleportation network.";
			val2.CraftingStation = CraftingStations.Workbench;
			val2.Requirements = (RequirementConfig[])(object)new RequirementConfig[3]
			{
				new RequirementConfig
				{
					Item = "GreydwarfEye",
					Amount = 10,
					Recover = true
				},
				new RequirementConfig
				{
					Item = "Resin",
					Amount = 10,
					Recover = true
				},
				new RequirementConfig
				{
					Item = "SurtlingCore",
					Amount = 2,
					Recover = true
				}
			};
			ItemConfig val3 = val2;
			CustomItem val4 = new CustomItem(val, true, val3);
			ItemManager.Instance.AddItem(val4);
		}

		private static void CreatePieces()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Expected O, but got Unknown
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Expected O, but got Unknown
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Expected O, but got Unknown
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Expected O, but got Unknown
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Expected O, but got Unknown
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Expected O, but got Unknown
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Expected O, but got Unknown
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Expected O, but got Unknown
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Expected O, but got Unknown
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Expected O, but got Unknown
			GameObject val = TravelTotemsPlugin.TotemBundle.LoadAsset<GameObject>(TravelTotemPiece_PrefabName);
			PieceConfig val2 = new PieceConfig();
			val2.PieceTable = PieceTables.Hammer;
			val2.Category = PieceCategories.Misc;
			val2.Name = "Travel Totem";
			val2.Description = "A mystical relic that can form a teleportation network. CANNOT BE REMOVED ONCE PLACED!";
			val2.CraftingStation = CraftingStations.Stonecutter;
			val2.Requirements = (RequirementConfig[])(object)new RequirementConfig[3]
			{
				new RequirementConfig
				{
					Item = "GreydwarfEye",
					Amount = 10,
					Recover = true
				},
				new RequirementConfig
				{
					Item = "Stone",
					Amount = 20,
					Recover = true
				},
				new RequirementConfig
				{
					Item = "SurtlingCore",
					Amount = 5,
					Recover = true
				}
			};
			PieceConfig val3 = val2;
			CustomPiece val4 = new CustomPiece(val, true, val3);
			PieceManager.Instance.AddPiece(val4);
			GameObject val5 = TravelTotemsPlugin.TotemBundle.LoadAsset<GameObject>(TravelTotemPieceMistlands_PrefabName);
			val2 = new PieceConfig();
			val2.PieceTable = PieceTables.Hammer;
			val2.Category = PieceCategories.Misc;
			val2.Name = "Travel Totem BlackMarble";
			val2.Description = "A mystical relic that can form a teleportation network. CANNOT BE REMOVED ONCE PLACED!";
			val2.CraftingStation = CraftingStations.Stonecutter;
			val2.Requirements = (RequirementConfig[])(object)new RequirementConfig[3]
			{
				new RequirementConfig
				{
					Item = "GreydwarfEye",
					Amount = 10,
					Recover = true
				},
				new RequirementConfig
				{
					Item = "BlackMarble",
					Amount = 20,
					Recover = true
				},
				new RequirementConfig
				{
					Item = "SurtlingCore",
					Amount = 5,
					Recover = true
				}
			};
			PieceConfig val6 = val2;
			CustomPiece val7 = new CustomPiece(val5, true, val6);
			PieceManager.Instance.AddPiece(val7);
			GameObject val8 = TravelTotemsPlugin.TotemBundle.LoadAsset<GameObject>(TravelTotemPieceAshlands_PrefabName);
			val2 = new PieceConfig();
			val2.PieceTable = PieceTables.Hammer;
			val2.Category = PieceCategories.Misc;
			val2.Name = "Travel Totem Grausten";
			val2.Description = "A mystical relic that can form a teleportation network. CANNOT BE REMOVED ONCE PLACED!";
			val2.CraftingStation = CraftingStations.Stonecutter;
			val2.Requirements = (RequirementConfig[])(object)new RequirementConfig[3]
			{
				new RequirementConfig
				{
					Item = "GreydwarfEye",
					Amount = 10,
					Recover = true
				},
				new RequirementConfig
				{
					Item = "Grausten",
					Amount = 20,
					Recover = true
				},
				new RequirementConfig
				{
					Item = "SurtlingCore",
					Amount = 5,
					Recover = true
				}
			};
			PieceConfig val9 = val2;
			CustomPiece val10 = new CustomPiece(val8, true, val9);
			PieceManager.Instance.AddPiece(val10);
		}

		public static void UpdateConfigurations()
		{
			UpdatePieceConfigurations();
			UpdateItemConfigurations();
		}

		public static void UpdateItemConfigurations()
		{
			if (TravelTotemsPlugin.GetTotemItemRecipesEnabled())
			{
				UpdateItemConfiguration(TravelTotemBomb_PrefabName, TravelTotemsPlugin.GetTotemBombItemCost());
			}
		}

		public static void UpdatePieceConfigurations()
		{
			if (TravelTotemsPlugin.GetTravelTotemPieceRecipesEnabled())
			{
				UpdatePieceConfiguration(TravelTotemPiece_PrefabName, TravelTotemsPlugin.GetTravelTotemPieceCost());
				UpdatePieceConfiguration(TravelTotemPieceMistlands_PrefabName, TravelTotemsPlugin.GetTravelTotemPieceMistlandsCost());
				UpdatePieceConfiguration(TravelTotemPieceAshlands_PrefabName, TravelTotemsPlugin.GetTravelTotemPieceAshlandsCost());
			}
		}

		public static void UpdatePieceConfiguration(string name, string cost)
		{
			bool flag = !Utility.IsNullOrWhiteSpace(cost);
			Requirement[] resources = MakeRequirementFromConfig(name, cost).ToArray();
			GameObject prefab = PrefabManager.Instance.GetPrefab(name);
			if ((Object)(object)prefab == (Object)null)
			{
				TravelTotemsPlugin.TravelTotemsLogger.LogError((object)("Could not find prefab for piece " + name + "."));
				return;
			}
			Piece pieceComp = prefab.GetComponent<Piece>();
			if ((Object)(object)pieceComp == (Object)null)
			{
				TravelTotemsPlugin.TravelTotemsLogger.LogError((object)("Could not find Piece for piece " + name + "."));
				return;
			}
			pieceComp.m_resources = resources;
			PieceTable val = null;
			GameObject prefab2 = PrefabManager.Instance.GetPrefab("Hammer");
			ItemDrop val2 = default(ItemDrop);
			if ((Object)(object)prefab2 == (Object)null || !prefab2.TryGetComponent<ItemDrop>(ref val2))
			{
				TravelTotemsPlugin.TravelTotemsLogger.LogWarning((object)"Hammer not found, will not add build piece.");
				return;
			}
			val = val2.m_itemData.m_shared.m_buildPieces;
			GameObject val3 = val.m_pieces.Find((GameObject x) => ((Object)x).name == Utils.GetPrefabName(((Object)pieceComp).name));
			if (!flag && (Object)(object)val3 != (Object)null)
			{
				val.m_pieces.Remove(val3);
			}
			else if (flag && (Object)(object)val3 == (Object)null)
			{
				val.m_pieces.Add(prefab);
			}
			TravelTotemsPlugin.TravelTotemsLogger.LogDebug((object)("Updated piece " + name + "."));
		}

		public static void UpdateItemConfiguration(string name, string recipe)
		{
			bool enabled = !Utility.IsNullOrWhiteSpace(recipe);
			Requirement[] resources = MakeRequirementFromConfig(name, recipe).ToArray();
			Recipe val = ((IEnumerable<Recipe>)ObjectDB.instance.m_recipes).FirstOrDefault((Func<Recipe, bool>)((Recipe x) => (Object)(object)x.m_item != (Object)null && (Object)(object)x.m_item.m_itemData.m_dropPrefab != (Object)null && ((Object)x.m_item.m_itemData.m_dropPrefab).name == name));
			if ((Object)(object)val == (Object)null)
			{
				TravelTotemsPlugin.TravelTotemsLogger.LogError((object)("Could not find recipe for item " + name + "."));
				return;
			}
			val.m_enabled = enabled;
			val.m_resources = resources;
		}

		public static List<Requirement> MakeRequirementFromConfig(string itemName, string configString)
		{
			List<RequirementConfig> list = MakeRecipeFromConfig(configString);
			List<Requirement> list2 = new List<Requirement>();
			foreach (RequirementConfig item in list)
			{
				Requirement requirement = item.GetRequirement();
				GameObject prefab = PrefabManager.Instance.GetPrefab(item.Item);
				if ((Object)(object)prefab == (Object)null)
				{
					TravelTotemsPlugin.TravelTotemsLogger.LogError((object)("Could not add requirement " + item.Item + ", for " + itemName + ". Prefab not found."));
					continue;
				}
				ItemDrop component = prefab.GetComponent<ItemDrop>();
				if ((Object)(object)component != (Object)null)
				{
					requirement.m_resItem = component;
					list2.Add(requirement);
					continue;
				}
				TravelTotemsPlugin.TravelTotemsLogger.LogError((object)("Could not add requirement " + item.Item + ", for " + itemName + "."));
			}
			return list2;
		}

		private static List<RequirementConfig> MakeRecipeFromConfig(string configString)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			string[] array = configString.Replace(" ", "").Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			List<RequirementConfig> list = new List<RequirementConfig>();
			string[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				string[] array3 = array2[i].Split(new char[1] { ':' }, StringSplitOptions.RemoveEmptyEntries);
				if (array3.Length != 2)
				{
					PrintRecipeErrorMessage(configString);
					continue;
				}
				string item = array3[0];
				if (!int.TryParse(array3[1], out var result))
				{
					PrintRecipeErrorMessage(configString);
					continue;
				}
				list.Add(new RequirementConfig
				{
					Item = item,
					Amount = result,
					Recover = true
				});
			}
			return list;
		}

		public static void PrintRecipeErrorMessage(string entry)
		{
			TravelTotemsPlugin.TravelTotemsLogger.LogError((object)("Incorrectly formatted recipe: " + entry + "! Should be 'ITEM:QUANITY,ITEM2:QUANTITY' etc."));
		}

		public static void AddTotemLocations()
		{
			CreateMaterials();
			int locationSpacing = TravelTotemsPlugin.GetLocationSpacing();
			AddTotemLocation("VV_TravelTotemLocation_Default", (Biome)895, TravelTotemsPlugin.GetLocationAmountDefault(), locationSpacing);
			AddTotemLocation("VV_TravelTotemLocation_Meadows", (Biome)1, TravelTotemsPlugin.GetLocationAmountMeadows(), locationSpacing);
			AddTotemLocation("VV_TravelTotemLocation_BlackForest", (Biome)8, TravelTotemsPlugin.GetLocationAmountBlackForest(), locationSpacing);
			AddTotemLocation("VV_TravelTotemLocation_Swamp", (Biome)2, TravelTotemsPlugin.GetLocationAmountSwamp(), locationSpacing);
			AddTotemLocation("VV_TravelTotemLocation_Mountain", (Biome)4, TravelTotemsPlugin.GetLocationAmountMountain(), locationSpacing);
			AddTotemLocation("VV_TravelTotemLocation_Plains", (Biome)16, TravelTotemsPlugin.GetLocationAmountPlains(), locationSpacing);
			AddTotemLocation("VV_TravelTotemLocation_Mistlands", (Biome)512, TravelTotemsPlugin.GetLocationAmountMistlands(), locationSpacing, 15);
			AddTotemLocation("VV_TravelTotemLocation_Ashlands", (Biome)32, TravelTotemsPlugin.GetLocationAmountAshlands(), locationSpacing, 15, 5);
			ZoneManager.OnVanillaLocationsAvailable -= AddTotemLocations;
		}

		private static void AddTotemLocation(string locationName, Biome biome, int quantity, int distance, int radius = 7, int minAltitude = 3)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			GameObject obj = ZoneManager.Instance.CreateLocationContainer(TravelTotemsPlugin.TotemBundle, locationName);
			LocationConfig val = new LocationConfig();
			val.Biome = biome;
			val.Quantity = quantity;
			val.ExteriorRadius = radius;
			val.HasInterior = false;
			val.InteriorRadius = 5f;
			val.MinAltitude = minAltitude;
			val.MaxAltitude = 1000f;
			val.Priotized = true;
			val.MinDistanceFromSimilar = distance;
			val.ClearArea = true;
			CustomLocation val2 = new CustomLocation(obj, true, val);
			ZoneManager.Instance.AddCustomLocation(val2);
		}

		public static void CreateMaterials()
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Expected O, but got Unknown
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)TotemMaterialDefault != (Object)null)
			{
				return;
			}
			Material prefab = Cache.GetPrefab<Material>("startplatform");
			if ((Object)(object)prefab == (Object)null)
			{
				TravelTotemsPlugin.TravelTotemsLogger.LogWarning((object)"Material \"startplatform\" could not be found. Could not replace.");
				return;
			}
			Texture val = TravelTotemsPlugin.TotemBundle.LoadAsset<Texture>("VV_startstone_emission");
			if ((Object)(object)val == (Object)null)
			{
				TravelTotemsPlugin.TravelTotemsLogger.LogWarning((object)"Could not load emission texture data.");
			}
			Vector4 val2 = default(Vector4);
			((Vector4)(ref val2))..ctor(0f, 0f, 0f, 1f);
			Material prefab2 = Cache.GetPrefab<Material>("rock_mistlands");
			Material prefab3 = Cache.GetPrefab<Material>("AshlandsRockTest_mat");
			CreateDefaultMaterial(prefab, val, Vector4.op_Implicit(val2));
			if ((Object)(object)prefab2 == (Object)null)
			{
				TotemMaterialMistlands = new Material(TotemMaterialDefault);
				((Object)TotemMaterialMistlands).name = "VV_TotemMaterialMistlands";
				TravelTotemsPlugin.TravelTotemsLogger.LogWarning((object)"Material \"rock_mistlands\" could not be found. Could not replace.");
			}
			else
			{
				CreateMistlandsMaterial(prefab, prefab2, val, Vector4.op_Implicit(val2));
			}
			if ((Object)(object)prefab3 == (Object)null)
			{
				TotemMaterialAshlands = new Material(TotemMaterialDefault);
				((Object)TotemMaterialAshlands).name = "VV_TotemMaterialAshlands";
				TravelTotemsPlugin.TravelTotemsLogger.LogWarning((object)"Material \"AshlandsRockTest_mat\" could not be found. Could not replace.");
			}
			else
			{
				CreateAshlandsMaterial(prefab, prefab3, val, Vector4.op_Implicit(val2));
			}
			AssetManager.Instance.AddAsset((Object)(object)TotemMaterialDefault);
			AssetManager.Instance.AddAsset((Object)(object)TotemMaterialMistlands);
			AssetManager.Instance.AddAsset((Object)(object)TotemMaterialAshlands);
		}

		private static void CreateDefaultMaterial(Material originalPlatform, Texture emission, Vector3 emissionColor)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			TotemMaterialDefault = new Material(originalPlatform);
			((Object)TotemMaterialDefault).name = "VV_TotemMaterialDefault";
			TotemMaterialDefault.SetTexture("_EmissiveTex", emission);
			TotemMaterialDefault.SetVector("_EmissionColor", Vector4.op_Implicit(emissionColor));
			TotemMaterialDefault.SetFloat("_MossBlend", 5f);
		}

		private static void CreateMistlandsMaterial(Material originalPlatform, Material originalMaterial, Texture emission, Vector3 emissionColor)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			TotemMaterialMistlands = new Material(originalMaterial);
			((Object)TotemMaterialMistlands).name = "VV_TotemMaterialMistlands";
			CopyBasics(originalPlatform, TotemMaterialMistlands, emission, Vector4.op_Implicit(emissionColor));
			CopyMoss(originalPlatform, TotemMaterialMistlands);
			TotemMaterialMistlands.SetVector("_Color", new Vector4(27f / 106f, 27f / 106f, 27f / 106f, 1f));
		}

		private static void CreateAshlandsMaterial(Material originalPlatform, Material originalMaterial, Texture emission, Vector3 emissionColor)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			TotemMaterialAshlands = new Material(originalMaterial);
			((Object)TotemMaterialAshlands).name = "VV_TotemMaterialAshlands";
			CopyBasics(originalPlatform, TotemMaterialAshlands, emission, Vector4.op_Implicit(emissionColor));
			TotemMaterialAshlands.SetVector("_Color", new Vector4(0.02f, 0.04f, 0.06f, 1f));
		}

		private static void CopyBasics(Material original, Material newMaterial, Texture emission, Vector4 emissionColor)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			newMaterial.SetTexture("_MainTex", original.GetTexture("_MainTex"));
			newMaterial.SetTextureScale("_MainTex", original.GetTextureScale("_MainTex"));
			newMaterial.SetTextureOffset("_MainTex", original.GetTextureOffset("_MainTex"));
			newMaterial.SetTexture("_BumpMap", original.GetTexture("_BumpMap"));
			newMaterial.SetTextureScale("_BumpMap", original.GetTextureScale("_BumpMap"));
			newMaterial.SetTextureOffset("_BumpMap", original.GetTextureOffset("_BumpMap"));
			newMaterial.SetFloat("_BumpScale", original.GetFloat("_BumpScale"));
			newMaterial.SetTexture("_EmissiveTex", emission);
			newMaterial.SetVector("_EmissionColor", emissionColor);
		}

		private static void CopyMoss(Material original, Material material)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			material.SetTextureScale("_MossTex", original.GetTextureScale("_MossTex"));
			material.SetTextureOffset("_MossTex", original.GetTextureOffset("_MossTex"));
			material.SetFloat("_MossBlend", 5f);
			material.SetFloat("_MossNormal", original.GetFloat("_MossNormal"));
			material.SetFloat("_MossTransition", original.GetFloat("_MossTransition"));
		}
	}
	public static class CodeMatcherExtensions
	{
		public static CodeMatcher ExtractOperand(this CodeMatcher matcher, out object operand)
		{
			operand = matcher.Operand;
			return matcher;
		}
	}
	public class TerminalCommands
	{
		[HarmonyPatch(typeof(Terminal), "InitTerminal")]
		private static class Patch_Terminal_InitTerminal
		{
			[Serializable]
			[CompilerGenerated]
			private sealed class <>c
			{
				public static readonly <>c <>9 = new <>c();

				public static ConsoleEvent <>9__1_0;

				public static ConsoleEvent <>9__1_1;

				internal void <Postfix>b__1_0(ConsoleEventArgs args)
				{
					if (args.Length > 1)
					{
						TravelTotemPlayer.TryRemoveTotem(args[1]);
					}
					else
					{
						TravelTotemPlayer.ClearKnownTotems();
					}
				}

				internal void <Postfix>b__1_1(ConsoleEventArgs args)
				{
					if (args.Length > 1)
					{
						TravelTotemPlayer.TryAddTotem(args[1]);
					}
					else
					{
						args.Context.AddString("Syntax: addknowntraveltotem [ID such as 0:4]");
					}
				}
			}

			[HarmonyPriority(800)]
			private static void Prefix(out bool __state)
			{
				__state = Terminal.m_terminalInitialized;
			}

			private static void Postfix(bool __state)
			{
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Expected O, but got Unknown
				//IL_007d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				//IL_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0074: Expected O, but got Unknown
				if (__state)
				{
					return;
				}
				TravelTotemsPlugin.TravelTotemsLogger.LogInfo((object)"Adding Terminal Commands for totem management.");
				try
				{
					object obj = <>c.<>9__1_0;
					if (obj == null)
					{
						ConsoleEvent val = delegate(ConsoleEventArgs args)
						{
							if (args.Length > 1)
							{
								TravelTotemPlayer.TryRemoveTotem(args[1]);
							}
							else
							{
								TravelTotemPlayer.ClearKnownTotems();
							}
						};
						<>c.<>9__1_0 = val;
						obj = (object)val;
					}
					new ConsoleCommand("clearknowntraveltotems", "[optional: ID]", (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
					object obj2 = <>c.<>9__1_1;
					if (obj2 == null)
					{
						ConsoleEvent val2 = delegate(ConsoleEventArgs args)
						{
							if (args.Length > 1)
							{
								TravelTotemPlayer.TryAddTotem(args[1]);
							}
							else
							{
								args.Context.AddString("Syntax: addknowntraveltotem [ID such as 0:4]");
							}
						};
						<>c.<>9__1_1 = val2;
						obj2 = (object)val2;
					}
					new ConsoleCommand("addknowntraveltotem", "[ID]", (ConsoleEvent)obj2, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
				}
				catch (Exception ex)
				{
					TravelTotemsPlugin.TravelTotemsLogger.LogWarning((object)"Error, could not add terminal command. This can happen when two mods add the same command. The rest of this mod should work as expected.");
					TravelTotemsPlugin.TravelTotemsLogger.LogWarning((object)ex);
				}
			}
		}
	}
	public class TraderPatches
	{
		[HarmonyPatch(typeof(Trader), "Start")]
		public static class Patch_Trader_Start
		{
			private static void Postfix(Trader __instance)
			{
				//IL_0049: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0055: Unknown result type (might be due to invalid IL or missing references)
				//IL_0061: Expected O, but got Unknown
				if (!TravelTotemsPlugin.GetTradersSellTotemBomb())
				{
					return;
				}
				GameObject prefab = Cache.GetPrefab<GameObject>(AssetManager.TravelTotemBomb_PrefabName);
				if (!Object.op_Implicit((Object)(object)prefab))
				{
					TravelTotemsPlugin.TravelTotemsLogger.LogWarning((object)"Could not add Totem Bomb to trader: Prefab not found.");
					return;
				}
				ItemDrop component = prefab.GetComponent<ItemDrop>();
				if (!Object.op_Implicit((Object)(object)component))
				{
					TravelTotemsPlugin.TravelTotemsLogger.LogWarning((object)"Could not add Totem Bomb to trader: ItemDrop undefined.");
					return;
				}
				TradeItem item = new TradeItem
				{
					m_prefab = component,
					m_price = TravelTotemsPlugin.GetTradersSellTotemBombCost()
				};
				__instance.m_items.Add(item);
			}
		}
	}
	public static class TravelTotemMap
	{
		[HarmonyPatch(typeof(Minimap), "UpdateDynamicPins")]
		public static class Patch_Minimap_UpdateDynamicPins
		{
			private static void Postfix()
			{
				UpdateMapPins();
			}
		}

		[HarmonyPatch(typeof(Minimap), "UpdateMap")]
		private static class Patch_Minimap_UpdateMap
		{
			[HarmonyTranspiler]
			internal static IEnumerable<CodeInstruction> MinimapUpdateMapTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
			{
				//IL_0002: 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)
				//IL_002a: Expected O, but got Unknown
				//IL_004d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0053: Expected O, but got Unknown
				//IL_008b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0091: Expected O, but got Unknown
				return new CodeMatcher(instructions, generator).Start().MatchStartForward((CodeMatch[])(object)new CodeMatch[2]
				{
					new CodeMatch((OpCode?)OpCodes.Ldstr, (object)"JoyTabLeft", (string)null),
					new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(ZInput), "GetButtonDown", (Type[])null, (Type[])null), (string)null)
				}).ThrowIfInvalid("Could not patch Minimap.UpdateMap!")
					.Advance(3)
					.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1]
					{
						new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(TravelTotemMap), "TryTriggerTeleportGamepad", (Type[])null, (Type[])null))
					})
					.InstructionEnumeration();
			}
		}

		[HarmonyPatch(typeof(Minimap), "OnMapLeftClick")]
		private static class Patch_Minimap_OnMapLeftClick
		{
			private static bool Prefix()
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				if (!TravelMapActive)
				{
					return true;
				}
				TryTriggerTeleport(GetClosestTravelLocation(Minimap.instance.ScreenToWorldPoint(ZInput.mousePosition), Minimap.instance.m_removeRadius * (Minimap.instance.m_largeZoom * 2f), out var isTotem), isTotem);
				return false;
			}
		}

		private static bool TravelMapPinsAdded = false;

		private static List<PinData> TotemMapPins = new List<PinData>();

		private static List<Vector3> LocationMapPins = new List<Vector3>();

		private const string START_LOC = "StartTemple";

		private const string HALDOR_LOC = "Vendor_BlackForest";

		private const string HILDIR_LOC = "Hildir_camp";

		private const string BOGWITCH_LOC = "BogWitch_Camp";

		public static bool TravelMapActive { get; private set; } = false;

		public static bool TotemTeleportActive { get; private set; } = false;

		public static void SetTravelMapActive(bool active)
		{
			TravelMapActive = active;
		}

		public static void SetTotemTeleportActive(bool active)
		{
			TotemTeleportActive = active;
		}

		public static void AddMapPin(ZDO totem)
		{
			//IL_0017: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (totem != null && !((Object)(object)Minimap.instance == (Object)null))
			{
				PinData item = Minimap.instance.AddPin(totem.GetPosition(), TravelTotemMapPin.GetTotemPinType(), totem.GetString("VV_TotemName", ""), false, false, 0L, default(PlatformUserID));
				TotemMapPins.Add(item);
			}
		}

		public static void RefreshMapPins()
		{
			if (Object.op_Implicit((Object)(object)Minimap.instance))
			{
				ClearPins();
				UpdateMapPins();
			}
		}

		private static void UpdateMapPins()
		{
			if ((TravelMapActive || TravelTotemsPlugin.GetShowMapPins()) && !TravelMapPinsAdded)
			{
				foreach (ZDO validTotem in TravelTotemPlayer.GetValidTotems())
				{
					AddMapPin(validTotem);
				}
				TravelMapPinsAdded = true;
			}
			else if (!TravelMapActive && TravelMapPinsAdded && !TravelTotemsPlugin.GetShowMapPins())
			{
				ClearPins();
			}
		}

		private static void ClearPins()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			PinType totemPinType = TravelTotemMapPin.GetTotemPinType();
			foreach (PinData totemMapPin in TotemMapPins)
			{
				if (totemMapPin.m_type == totemPinType)
				{
					Minimap.instance.RemovePin(totemMapPin);
				}
			}
			TotemMapPins.Clear();
			TravelMapPinsAdded = false;
		}

		public static void TryTriggerTeleportGamepad()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			if (TravelMapActive)
			{
				TryTriggerTeleport(GetClosestTravelLocation(Minimap.instance.ScreenToWorldPoint(new Vector3((float)(Screen.width / 2), (float)(Screen.height / 2))), Minimap.instance.m_removeRadius * (Minimap.instance.m_largeZoom * 2f), out var isTotem), isTotem);
			}
		}

		private static void TryTriggerTeleport(Vector3 position, bool isTotem)
		{
			//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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (!(position == Vector3.zero))
			{
				StopTotemMap();
				SetTotemTeleportActive(isTotem);
				((Character)Player.m_localPlayer).TeleportTo(position, Quaternion.identity, true);
			}
		}

		private static bool AllowedPinType(int pinType)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between I4 and Unknown
			if (pinType == (int)TravelTotemMapPin.GetTotemPinType())
			{
				return true;
			}
			if (pinType == 5)
			{
				return TravelTotemsPlugin.GetAllowSelectBed();
			}
			if (TravelTotemsPlugin.GetAllowSelectTraders() && TravelTotemsPlugin.MultiplayerTweaksInstalled)
			{
				return IsMultiplayerTweaksTraderPin(pinType);
			}
			return false;
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static bool IsMultiplayerTweaksTraderPin(int pinType)
		{
			try
			{
				int haldorPinIndex = API.GetHaldorPinIndex();
				int hildirPinIndex = API.GetHildirPinIndex();
				int bogWitchPinIndex = API.GetBogWitchPinIndex();
				if (pinType == haldorPinIndex || pinType == hildirPinIndex || pinType == bogWitchPinIndex)
				{
					return true;
				}
			}
			catch
			{
				TravelTotemsPlugin.TravelTotemsLogger.LogWarning((object)"Multiplayer Tweaks version mismatch! Update or contact the author for more help.");
			}
			return false;
		}

		private static Vector3 GetClosestTravelLocation(Vector3 pos, float radius, out bool isTotem)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected I4, but got Unknown
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.zero;
			float num = 999999f;
			foreach (PinData pin in Minimap.instance.m_pins)
			{
				if (AllowedPinType((int)pin.m_type) && Object.op_Implicit((Object)(object)pin.m_uiElement) && ((Component)pin.m_uiElement).gameObject.activeInHierarchy)
				{
					float num2 = Utils.DistanceXZ(pos, pin.m_pos);
					if (num2 < radius && (num2 < num || val == Vector3.zero))
					{
						val = pin.m_pos;
						num = num2;
						isTotem = pin.m_type == TravelTotemMapPin.GetTotemPinType();
					}
				}
			}
			isTotem = false;
			if (LocationMapPins.Count > 0)
			{
				foreach (Vector3 locationMapPin in LocationMapPins)
				{
					float num3 = Utils.DistanceXZ(pos, locationMapPin);
					if (num3 < radius && num3 < num)
					{
						val = locationMapPin;
						num = num3;
					}
				}
			}
			return val;
		}

		public static void HandleTotemOnTriggerEnter(TravelTotemPortal totem = null)
		{
			if (TotemTeleportActive)
			{
				SetTotemTeleportActive(active: false);
				StopTotemMap();
			}
			else if (Object.op_Implicit((Object)(object)totem) && !totem.TryTrackTotem(consumeResources: false))
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, "$msg_blocked", 0, (Sprite)null);
			}
			else if (((Humanoid)Player.m_localPlayer).IsTeleportable())
			{
				StartTotemMap();
			}
			else
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, "$msg_noteleport", 0, (Sprite)null);
			}
		}

		public static void HandleTotemOnTriggerExit(TravelTotemPortal totem = null)
		{
			StopTotemMap();
		}

		public static void StartTotemMap()
		{
			RefreshLocationIcons();
			SetTravelMapActive(active: true);
			SetMapMode((MapMode)2);
		}

		public static void StopTotemMap()
		{
			SetTravelMapActive(active: false);
			SetMapMode((MapMode)(!Game.m_noMap));
		}

		private static void SetMapMode(MapMode mode)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			bool noMap = Game.m_noMap;
			Game.m_noMap = false;
			Minimap.instance.SetMapMode(mode);
			Game.m_noMap = noMap;
		}

		public static void RefreshLocationIcons()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<Vector3, string> dictionary = new Dictionary<Vector3, string>();
			ZoneSystem.instance.GetLocationIcons(dictionary);
			LocationMapPins.Clear();
			foreach (KeyValuePair<Vector3, string> item in dictionary)
			{
				switch (item.Value)
				{
				case "StartTemple":
					if (TravelTotemsPlugin.GetAllowSelectDefaultSpawn())
					{
						LocationMapPins.Add(item.Key);
					}
					break;
				case "Vendor_BlackForest":
				case "Hildir_camp":
				case "BogWitch_Camp":
					if (TravelTotemsPlugin.GetAllowSelectTraders())
					{
						LocationMapPins.Add(item.Key);
					}
					break;
				}
			}
		}
	}
	public class TravelTotemMapPin
	{
		[HarmonyPatch(typeof(Minimap))]
		private static class Patch_Minimap_GetMapData
		{
			[HarmonyPriority(700)]
			[HarmonyPatch("GetSharedMapData")]
			[HarmonyPatch("GetMapData")]
			private static void Prefix(ref Minimap __instance)
			{
				TransformPinIdsToSave(ref __instance.m_pins);
			}

			[HarmonyPriority(100)]
			[HarmonyPatch("GetSharedMapData")]
			[HarmonyPatch("GetMapData")]
			private static void Postfix(ref Minimap __instance)
			{
				TransformPinIdsToPlay(ref __instance.m_pins);
			}
		}

		[HarmonyPatch(typeof(Minimap), "Start")]
		private static class Patch_Minimap_Start
		{
			[HarmonyPriority(100)]
			private static void Postfix(Minimap __instance)
			{
				bool[] array = new bool[__instance.m_visibleIconTypes.Length + 1];
				for (int i = 0; i < __instance.m_visibleIconTypes.Length; i++)
				{
					array[i] = __instance.m_visibleIconTypes[i];
				}
				TotemIndex = __instance.m_visibleIconTypes.Length;
				array[TotemIndex] = true;
				__instance.m_visibleIconTypes = array;
			}
		}

		[HarmonyPatch(typeof(Minimap), "AddPin")]
		private static class Patch_Minimap_AddPin
		{
			[HarmonyPriority(800)]
			private static void Prefix(ref PinType type)
			{
				if ((int)type == 126)
				{
					type = (PinType)TotemIndex;
				}
				if ((int)type >= Minimap.instance.m_visibleIconTypes.Length)
				{
					TravelTotemsPlugin.TravelTotemsLogger.LogWarning((object)"Minimap conversion type out of range of visible icons.");
				}
				else if ((int)type < 0)
				{
					TravelTotemsPlugin.TravelTotemsLogger.LogWarning((object)"Minimap conversion type less than icon 0.");
				}
			}
		}

		[HarmonyPatch(typeof(Minimap), "GetSprite")]
		private static class Patch_Minimap_GetSprite
		{
			[HarmonyPriority(800)]
			private static bool Prefix(ref PinType type, ref Sprite __result)
			{
				if ((int)type == TotemIndex)
				{
					__result = AssetManager.TotemMapSprite;
					return false;
				}
				__result = null;
				return true;
			}
		}

		private const int TOTEM_INT = 126;

		internal static int TotemIndex = -1;

		public static PinType GetTotemPinType()
		{
			return (PinType)TotemIndex;
		}

		private static void TransformPinIdsToSave(ref List<PinData> pins)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			foreach (PinData pin in pins)
			{
				if ((int)pin.m_type == TotemIndex)
				{
					pin.m_type = (PinType)126;
				}
			}
		}

		private static void TransformPinIdsToPlay(ref List<PinData> pins)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			foreach (PinData pin in pins)
			{
				if ((int)pin.m_type == 126)
				{
					pin.m_type = (PinType)TotemIndex;
				}
			}
		}
	}
	public static class TravelTotemPlayer
	{
		private readonly struct FileData
		{
			public List<int> TravelTotemIDs { get; }

			public FileData(List<int> totems)
			{
				TravelTotemIDs = totems;
			}

			public FileData(string saveString)
			{
				TravelTotemIDs = new List<int>();
				if (saveString == null)
				{
					return;
				}
				string[] array = saveString.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
				if (array == null)
				{
					return;
				}
				for (int i = 0; i < array.Length; i++)
				{
					if (int.TryParse(array[i], out var result))
					{
						TravelTotemIDs.Add(result);
						continue;
					}
					TravelTotemsPlugin.TravelTotemsLogger.LogWarning((object)$"Unable to parse travel totem save data for bin: {i}");
					TravelTotemIDs.Add(0);
				}
			}

			public override string ToString()
			{
				string text = "";
				foreach (int travelTotemID in TravelTotemIDs)
				{
					text = text + travelTotemID + ";";
				}
				return text;
			}
		}

		[HarmonyPatch(typeof(Player), "Save")]
		public static class Patch_Player_Save
		{
			private static void Prefix(Player __instance)
			{
				if (TravelTotemsPlugin.IsInTheMainScene())
				{
					TravelTotemsPlugin.TravelTotemsLogger.LogDebug((object)("Attempting to save data with key: " + CurrentSaveString));
					FileData data = new FileData(KnownTravelTotemIDs);
					SaveData(ref __instance, data);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Load")]
		public static class Patch_Player_Load
		{
			private static void Postfix(Player __instance)
			{
				if (!TravelTotemsPlugin.IsInTheMainScene())
				{
					CurrentSaveString = string.Empty;
					return;
				}
				KnownTravelTotemIDs.Clear();
				long uid = WorldGenerator.instance.m_world.m_uid;
				if (uid == 0L)
				{
					TravelTotemsPlugin.TravelTotemsLogger.LogError((object)"World key not set! Will not be able to retrieve saved data.");
					return;
				}
				CurrentSaveString = "VV_TD_" + uid;
				TravelTotemsPlugin.TravelTotemsLogger.LogDebug((object)("Attempting to load data with key: " + CurrentSaveString));
				FileData? fileData = LoadData(ref __instance);
				if (!fileData.HasValue)
				{
					return;
				}
				FileData value = fileData.Value;
				if (value.TravelTotemIDs != null)
				{
					for (int i = 0; i < value.TravelTotemIDs.Count; i++)
					{
						KnownTravelTotemIDs.Add(value.TravelTotemIDs[i]);
					}
				}
				TravelTotemMap.RefreshMapPins();
			}
		}

		private const string PLAYER_SAVE_KEY_PREFIX = "VV_TD_";

		private static List<int> KnownTravelTotemIDs = new List<int>();

		private static string CurrentSaveString = string.Empty;

		private static bool IsValid(int bin)
		{
			if (bin < 0 || bin >= KnownTravelTotemIDs.Count)
			{
				return false;
			}
			return true;
		}

		public static bool ContainsID(int bin, int id)
		{
			if (!IsValid(bin))
			{
				return false;
			}
			return ContainsIDInternal(bin, id);
		}

		private static bool ContainsIDInternal(int bin, int id)
		{
			return (KnownTravelTotemIDs[bin] & id) != 0;
		}

		public static bool AddKnownTotem(int bin, int id)
		{
			if (bin < 0)
			{
				return false;
			}
			if (bin >= KnownTravelTotemIDs.Count)
			{
				for (int i = KnownTravelTotemIDs.Count; i <= bin; i++)
				{
					KnownTravelTotemIDs.Add(0);
				}
			}
			KnownTravelTotemIDs[bin] |= id;
			TravelTotemMap.RefreshMapPins();
			return true;
		}

		public static void TryRemoveTotem(string idString)
		{
			if (TryGetTotemID(idString, out var bin, out var id))
			{
				RemoveTotem(bin, id);
			}
		}

		public static void TryAddTotem(string idString)
		{
			idString.Split(new string[1] { ":" }, StringSplitOptions.RemoveEmptyEntries);
			if (TryGetTotemID(idString, out var bin, out var id))
			{
				AddKnownTotem(bin, id);
			}
		}

		private static bool TryGetTotemID(string idString, out int bin, out int id)
		{
			string[] array = idString.Split(new string[1] { ":" }, StringSplitOptions.RemoveEmptyEntries);
			if (array.Length == 2 && int.TryParse(array[0].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out bin) && int.TryParse(array[1].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out id))
			{
				return true;
			}
			bin = -1;
			id = 0;
			return false;
		}

		public static bool RemoveTotem(int bin, int id)
		{
			if (!IsValid(bin))
			{
				return false;
			}
			if (ContainsIDInternal(bin, id))
			{
				KnownTravelTotemIDs[bin] -= id;
			}
			TravelTotemMap.RefreshMapPins();
			return true;
		}

		public static void ClearKnownTotems()
		{
			KnownTravelTotemIDs.Clear();
			ClearData(ref Player.m_localPlayer);
			TravelTotemMap.RefreshMapPins();
		}

		public static bool TotemUnlocked(bool isCreator, TravelTotemType type, int bin, int id)
		{
			if (isCreator)
			{
				return true;
			}
			if (type == TravelTotemType.AlwaysUnlock)
			{
				return true;
			}
			return ContainsID(bin, id);
		}

		public static List<ZDO> GetValidTotems()
		{
			long playerID = Game.instance.GetPlayerProfile().GetPlayerID();
			List<ZDO> list = new List<ZDO>();
			foreach (ZDO travelTotem in TravelTotems.GetTravelTotems())
			{
				if (travelTotem == null)
				{
					continue;
				}
				bool isCreator = travelTotem.GetLong(ZDOVars.s_creator, 0L) == playerID;
				if (!TravelTotemsPlugin.GetOverrideTotemAccess(isCreator))
				{
					TravelTotemType totemType = TravelTotemPortal.GetTotemType(travelTotem);
					if (!TotemUnlocked(isCreator, totemType, travelTotem.GetInt("VV_TotemIDBin", 0), travelTotem.GetInt("VV_TotemID", 0)))
					{
						continue;
					}
				}
				list.Add(travelTotem);
			}
			return list;
		}

		private static void SaveData(ref Player player, FileData data)
		{
			if (!((Object)(object)player == (Object)null) && !Utility.IsNullOrWhiteSpace(CurrentSaveString) && data.TravelTotemIDs.Count >= 1)
			{
				if (player.m_customData.ContainsKey(CurrentSaveString))
				{
					player.m_customData[CurrentSaveString] = data.ToString();
				}
				else
				{
					player.m_customData.Add(CurrentSaveString, data.ToString());
				}
			}
		}

		private static void ClearData(ref Player player)
		{
			if ((Object)(object)player != (Object)null && player.m_customData.ContainsKey(CurrentSaveString))
			{
				player.m_customData[CurrentSaveString] = "";
			}
		}

		private static FileData? LoadData(ref Player player)
		{
			if ((Object)(object)player != (Object)null && player.m_customData.ContainsKey(CurrentSaveString))
			{
				return new FileData(player.m_customData[CurrentSaveString]);
			}
			return null;
		}
	}
	public class TravelTotemPortal : MonoBehaviour, Hoverable, Interactable, TextReceiver
	{
		public ZNetView ZNetView;

		public const string TOTEM_ID_BIN = "VV_TotemIDBin";

		public const string TOTEM_ID = "VV_TotemID";

		public const string TOTEM_NAME = "VV_TotemName";

		public const string TOTEM_TYPE = "VV_TotemType";

		public const string RPCNAME_SetupAccess = "VV_SetupAccess";

		public EffectFade EnabledEffects;

		public EffectFade DisabledEffects;

		public EffectFade PortalEffects;

		public float ActivationRange = 5f;

		public Light UnlockedLight;

		public MeshRenderer EmissionRenderer;

		public Color EmissionColor;

		private float EmissionAlpha;

		private float LastUseTime = -1f;

		private bool IsPlacementGhost;

		private bool IsCreator;

		private bool IsPublic;

		private bool IsPiece;

		private void Awake()
		{
			ZNetView = ((Component)this).GetComponent<ZNetView>();
			ZNetView.Register<long>("VV_SetupAccess", (Action<long, long>)RPC_SetupAccess);
			IsPiece = (Object)(object)((Component)this).GetComponent<Piece>() != (Object)null;
		}

		private void Start()
		{
			if (Player.IsPlacementGhost(((Component)this).gameObject))
			{
				IsPlacementGhost = true;
				EnabledEffects.SetActive(false);
				DisabledEffects.SetActive(false);
				PortalEffects.SetActive(false);
				((Component)UnlockedLight).gameObject.SetActive(false);
				return;
			}
			int num = ZNetView.GetZDO().GetInt("VV_TotemIDBin", -1);
			int num2 = ZNetView.GetZDO().GetInt("VV_TotemID", -1);
			if (num == -1 || num2 == -1)
			{
				TravelTotems.AssignTotemID(ZNetView.GetZDO());
			}
			int num3 = 0;
			if (ZNetView.GetZDO().GetInt("VV_TotemType", num3) == num3)
			{
				SetTotemType(TravelTotemType.ServerDefault);
			}
			SnapToGround component = ((Component)this).GetComponent<SnapToGround>();
			if (Object.op_Implicit((Object)(object)component))
			{
				component.Snap();
			}
			UpdateEffects();
			long creator = ZNetView.GetZDO().GetLong(ZDOVars.s_creator, 0L);
			SetupAccess(creator);
			TravelTotems.AddTotem(ZNetView.GetZDO());
			TravelTotemMap.RefreshMapPins();
		}

		private void Update()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (ZNetView.IsValid() && !IsPlacementGhost)
			{
				Player closestPlayer = Player.GetClosestPlayer(((Component)this).transform.position, ActivationRange);
				bool travelPossible = Object.op_Implicit((Object)(object)closestPlayer) && ((Humanoid)closestPlayer).IsTeleportable();
				UpdateEffects(travelPossible);
			}
		}

		private void SetupAccess(long creator)
		{
			IsPublic = creator == 0;
			if (ZNet.instance.IsDedicated())
			{
				IsCreator = false;
			}
			else
			{
				IsCreator = creator == Game.instance.GetPlayerProfile().GetPlayerID();
			}
		}

		private void RPC_SetupAccess(long sender, long creator)
		{
			if (ZNetView.IsOwner())
			{
				ZNetView.GetZDO().Set(ZDOVars.s_creator, creator);
			}
			SetupAccess(creator);
		}

		private void UpdateEffects(bool travelPossible = false)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			bool flag = Unlocked();
			bool active = flag && !travelPossible;
			bool active2 = !flag;
			bool active3 = flag && travelPossible;
			EnabledEffects.SetActive(active);
			DisabledEffects.SetActive(active2);
			PortalEffects.SetActive(active3);
			EmissionAlpha = Mathf.MoveTowards(EmissionAlpha, flag ? 1f : 0f, Time.deltaTime);
			((Renderer)EmissionRenderer).material.SetColor("_EmissionColor", Color.Lerp(Color.black, EmissionColor, EmissionAlpha));
			((Component)UnlockedLight).gameObject.SetActive(flag);
		}

		public string GetHoverText()
		{
			if (!ZNetView.IsValid())
			{
				return "";
			}
			bool num = Unlocked();
			string text = (num ? "$piece_portal_connected" : "$piece_portal_unconnected");
			string text2 = GetText() + "[" + text + "]";
			if (TravelTotemsPlugin.GetOverrideTotemAccess(isCreator: false) || TravelTotemsPlugin.GetShowTotemID())
			{
				text2 += $"[<color=yellow>ID {GetTotemIDBin()}:{GetTotemID()}</color>]";
			}
			if (!num && GetTotemType() == TravelTotemType.FindUnlock)
			{
				text2 += "\n[<color=yellow><b>$KEY_Use</b></color>] Activate";
				if (RequiresPayment())
				{
					text2 = text2 + " [<color=green><b>" + TravelTotemsPlugin.GetTotemUnlockRequirementsString() + "</b></color>]";
				}
			}
			if (TravelTotemsPlugin.GetTotemNamingAccess(IsCreator, IsPublic))
			{
				string text3 = ((ZInput.IsNonClassicFunctionality() && ZInput.IsGamepadActive()) ? "$KEY_AltKeys" : "$KEY_AltPlace");
				text2 = text2 + "\n[<color=yellow><b>" + text3 + " + $KEY_Use</b></color>] $piece_portal_settag";
			}
			if (TravelTotemsPlugin.GetOverrideTotemAccess(IsCreator))
			{
				text2 += $"\n[<color=yellow><b>Hold $KEY_Use</b></color>] Cycle Access: [{GetTotemType(resolveDefault: false)}]";
			}
			return Localization.instance.Localize(text2);
		}

		public string GetHoverName()
		{
			return "TravelTotem";
		}

		public bool Interact(Humanoid human, bool hold, bool alt)
		{
			if (!ZNetView.IsValid())
			{
				return false;
			}
			if (hold)
			{
				if (TravelTotemsPlugin.GetOverrideTotemAccess(IsCreator) && Time.time - LastUseTime > 0.5f)
				{
					CycleTotemAccess();
					LastUseTime = Time.time;
					return true;
				}
				return false;
			}
			LastUseTime = Time.time;
			if (alt)
			{
				if (TravelTotemsPlugin.GetTotemNamingAccess(IsCreator, IsPublic))
				{
					TextInput.instance.RequestText((TextReceiver)(object)this, "$piece_sign_input", 50);
				}
				return true;
			}
			if (!TryTrackTotem(consumeResources: true))
			{
				return false;
			}
			return true;
		}

		private void CycleTotemAccess()
		{
			switch (GetTotemType(resolveDefault: false))
			{
			case TravelTotemType.AlwaysUnlock:
				SetTotemType(TravelTotemType.FindUnlock);
				break;
			case TravelTotemType.FindUnlock:
				SetTotemType(TravelTotemType.AlwaysLock);
				break;
			case TravelTotemType.AlwaysLock:
				SetTotemType(TravelTotemType.ServerDefault);
				break;
			case TravelTotemType.ServerDefault:
				SetTotemType(TravelTotemType.AlwaysUnlock);
				break;
			default:
				SetTotemType(TravelTotemType.ServerDefault);
				break;
			}
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			return false;
		}

		public string GetText()
		{
			string text = ZNetView.GetZDO().GetString("VV_TotemName", "");
			if (!Utility.IsNullOrWhiteSpace(text))
			{
				text += " ";
			}
			return text;
		}

		public void SetText(string name)
		{
			ZNetView.ClaimOwnership();
			ZNetView.GetZDO().Set("VV_TotemName", name);
		}

		public void SetTotemType(TravelTotemType type)
		{
			ZNetView.ClaimOwnership();
			ZNetView.GetZDO().Set("VV_TotemType", (int)type);
		}

		public bool Unlocked()
		{
			return TravelTotemPlayer.TotemUnlocked(IsCreator, GetTotemType(), GetTotemIDBin(), GetTotemID());
		}

		public bool RequiresPayment()
		{
			if (!IsPiece && IsPublic)
			{
				return TravelTotems.HasUnlockRequirements();
			}
			return false;
		}

		public int GetTotemIDBin()
		{
			return ZNetView.GetZDO().GetInt("VV_TotemIDBin", -1);
		}

		public int GetTotemID()
		{
			return ZNetView.GetZDO().GetInt("VV_TotemID", -1);
		}

		public static TravelTotemType GetTotemType(ZDO zdo)
		{
			return ResolveTotemType((TravelTotemType)zdo.GetInt("VV_TotemType", 0));
		}

		public TravelTotemType GetTotemType(bool resolveDefault = true)
		{
			TravelTotemType travelTotemType = (TravelTotemType)ZNetView.GetZDO().GetInt("VV_TotemType", 0);
			if (resolveDefault)
			{
				travelTotemType = ResolveTotemType(travelTotemType);
			}
			return travelTotemType;
		}

		private static TravelTotemType ResolveTotemType(TravelTotemType type)
		{
			if (type == TravelTotemType.ServerDefault)
			{
				type = TravelTotemsPlugin.GetTravelTotemType();
			}
			if (type == TravelTotemType.Undefined)
			{
				return TravelTotemType.FindUnlock;
			}
			return type;
		}

		public bool TryTrackTotem(bool consumeResources)
		{
			if (Unlocked())
			{
				TryClaimTotem();
			}
			else
			{
				TravelTotemType totemType = GetTotemType();
				bool overrideTotemAccess = TravelTotemsPlugin.GetOverrideTotemAccess(isCreator: false);
				switch (totemType)
				{
				case TravelTotemType.AlwaysLock:
					if (!overrideTotemAccess)
					{
						((Character)Player.m_localPlayer).Message((MessageType)2, "$piece_noaccess", 0, (Sprite)null);
					}
					return overrideTotemAccess;
				case TravelTotemType.FindUnlock:
					if (RequiresPayment())
					{
						if (!consumeResources)
						{
							return overrideTotemAccess;
						}
						if (!TravelTotems.TryConsumeUnlockRequirements())
						{
							((Character)Player.m_localPlayer).Message((MessageType)2, "$msg_incompleteoffering", 0, (Sprite)null);
							return false;
						}
					}
					TryClaimTotem();
					break;
				}
			}
			TravelTotemPlayer.AddKnownTotem(GetTotemIDBin(), GetTotemID());
			return true;
		}

		public void TryClaimTotem()
		{
			if (!IsPiece && IsPublic && TravelTotemsPlugin.GetAllowTotemClaiming())
			{
				long playerID = Game.instance.GetPlayerProfile().GetPlayerID();
				RPC_SetupAccess(playerID, playerID);
				ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "VV_SetupAccess", new object[1] { playerID });
			}
		}
	}
	public class TravelTotemPortalArea : MonoBehaviour
	{
		private void Awake()
		{
		}

		private void OnTriggerEnter(Collider colliderIn)
		{
			Player component = ((Component)colliderIn).GetComponent<Player>();
			if (Object.op_Implicit((Object)(object)component) && (Object)(object)Player.m_localPlayer == (Object)(object)component)
			{
				TravelTotemMap.HandleTotemOnTriggerEnter();
			}
		}

		private void OnTriggerExit(Collider colliderIn)
		{
			Player component = ((Component)colliderIn).GetComponent<Player>();
			if (Object.op_Implicit((Object)(object)component) && (Object)(object)Player.m_localPlayer == (Object)(object)component)
			{
				TravelTotemMap.HandleTotemOnTriggerExit();
			}
		}
	}
	public class TravelTotemPortalTrigger : MonoBehaviour
	{
		private TravelTotemPortal Trigger;

		private void Awake()
		{
			Trigger = ((Component)this).GetComponentInParent<TravelTotemPortal>();
		}

		private void OnTriggerEnter(Collider colliderIn)
		{
			Player component = ((Component)colliderIn).GetComponent<Player>();
			if (Object.op_Implicit((Object)(object)component) && (Object)(object)Player.m_localPlayer == (Object)(object)component)
			{
				TravelTotemMap.HandleTotemOnTriggerEnter(Trigger);
			}
		}

		private void OnTriggerExit(Collider colliderIn)
		{
			Player component = ((Component)colliderIn).GetComponent<Player>();
			if (Object.op_Implicit((Object)(object)component) && (Object)(object)Player.m_localPlayer == (Object)(object)component)
			{
				TravelTotemMap.HandleTotemOnTriggerExit();
			}
		}
	}
	public static class TravelTotems
	{
		[HarmonyPatch(typeof(ZNet), "Start")]
		private static class Patch_ZNet_Start
		{
			private static void Postfix()
			{
				StartTravelTotems();
			}
		}

		[HarmonyPatch(typeof(ZDOMan), "RPC_ZDOData")]
		private static class Patch_ZDOMan_RPC_ZDOData
		{
			[HarmonyTranspiler]
			internal static IEnumerable<CodeInstruction> ZDOManRPC_ZDODataTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Expected O, but got Unknown
				//IL_0049: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Expected O, but got Unknown
				//IL_0068: Unknown result type (might be due to invalid IL or missing references)
				//IL_006e: Expected O, but got Unknown
				//IL_0098: Unknown result type (might be due to invalid IL or missing references)
				//IL_009e: Expected O, but got Unknown
				//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c1: Expected O, but got Unknown
				object operand;
				return new CodeMatcher(instructions, generator).Start().MatchStartForward((CodeMatch[])(object)new CodeMatch[2]
				{
					new CodeMatch((OpCode?)OpCodes.Ldloc_3, (object)null, (string)null),
					new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(ZDO), "Deserialize", (Type[])null, (Type[])null), (string)null)
				}).MatchStartBackwards((CodeMatch[])(object)new CodeMatch[1]
				{
					new CodeMatch((OpCode?)OpCodes.Ldloc_S, (object)null, (string)null)
				})
					.ExtractOperand(out operand)
					.ThrowIfInvalid("Could not patch ZDOMan.RPC_ZDOData!")
					.Advance(3)
					.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[2]
					{
						new CodeInstruction(OpCodes.Ldloc_S, operand),
						new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Patch_ZDOMan_RPC_ZDOData), "TryAddTotem", (Type[])null, (Type[])null))
					})
					.InstructionEnumeration();
			}

			private static void TryAddTotem(ZDO zdoObject)
			{
				if (AssetManager.IsTravelTotem(zdoObject.m_prefab))
				{
					AddTotem(zdoObject);
				}
			}
		}

		[HarmonyPatch(typeof(ZDOMan), "ShutDown")]
		private static class Patch_ZDOMan_ShutDown
		{
			private static void Postfix()
			{
				Reset();
			}
		}

		[HarmonyPatch(typeof(ZDOPeer), "ShouldSend")]
		private static class Patch_ZDOMan_ZDOPeer_ShouldSend
		{
			private static bool Prefix(ZDO zdo, ref bool __result)
			{
				if (AssetManager.IsTravelTotem(zdo.m_prefab))
				{
					__result = true;
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(ZDOPeer), "ZDOSectorInvalidated")]
		private static class Patch_ZDOMan_ZDOPeer_ZDOSectorInvalidated
		{
			private static bool Prefix(ZDO zdo)
			{
				if (AssetManager.IsTravelTotem(zdo.m_prefab))
				{
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(ZDOMan), "HandleDestroyedZDO")]
		private static class Patch_ZDOMan_HandleDestroyedZDO
		{
			private static void Prefix(ZDOID uid)
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				ZDO zDO = ZDOMan.instance.GetZDO(uid);
				if (zDO != null && AssetManager.IsTravelTotem(zDO.GetPrefab()))
				{
					RemoveTotem(zDO);
				}
			}
		}

		[HarmonyPatch(typeof(ZDOMan), "AddPeer")]
		private static class Patch_ZDOMan_AddPeer2
		{
			private static void Postfix(ZNetPeer netPeer)
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Expected O, but got Unknown
				if (ZNet.instance.IsServer())
				{
					netPeer.m_rpc.Register("VV_RequestTotems", new Method(RPC_RequestTotems));
				}
				if (!ZNet.instance.IsDedicated())
				{
					netPeer.m_rpc.Register<ZPackage>("VV_SendTotems", (Action<ZRpc, ZPackage>)RPC_SendTotems);
					netPeer.m_rpc.Invoke("VV_RequestTotems", Array.Empty<object>());
				}
			}
		}

		[HarmonyPatch(typeof(Piece), "CanBeRemoved")]
		private static class Patch_Piece_CanBeRemoved
		{
			private static void Postfix(Piece __instance, ref bool __result)
			{
				if (__result)
				{
					ZDO zDO = __instance.m_nview.GetZDO();
					if (zDO != null && AssetManager.IsTravelTotem(zDO.GetPrefab()) && !TravelTotemsPlugin.GetOverrideTotemAccess(__instance.IsCreator()))
					{
						__result = false;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Game), "Start")]
		private static class Patch_Game_Start
		{
			private static void Postfix()
			{
				try
				{
					ZRoutedRpc.instance.Register("VV_ConsumeTotemID", (Action<long>)RPC_ConsumeTotemID);
					ZRoutedRpc.instance.Register<int, int>("VV_ConsumeTotemIDResponse", (Action<long, int, int>)RPC_ConsumeTotemIDResponse);
				}
				catch
				{
					TravelTotemsPlugin.TravelTotemsLogger.LogDebug((object)"Totem RPCs have already been registered. Skipping.");
				}
			}
		}

		public const string TOTEM_MAX_ID_BIN = "VV_MaxTotemIDBin";

		public const string TOTEM_MAX_ID = "VV_MaxTotemID";

		public const string RPCNAME_RequestTotems = "VV_RequestTotems";

		public const string RPCNAME_SendTotems = "VV_SendTotems";

		public const string RPCNAME_ConsumeTotemID = "VV_ConsumeTotemID";

		public const string RPCNAME_ConsumeTotemIDResponse = "VV_ConsumeTotemIDResponse";

		private static List<ZDO> TravelTotemZDOs = new List<ZDO>();

		private static Queue<ZDO> UnassignedTravelTotemZDOs = new Queue<ZDO>();

		public static ZDO TravelTotemTrackerZDO;

		private static List<UnlockRequirement> TotemUnlockCost = new List<UnlockRequirement>();

		private static void Reset()
		{
			TravelTotemZDOs.Clear();
			TravelTotemTrackerZDO = null;
			UnassignedTravelTotemZDOs.Clear();
		}

		public static void SetRecipeFromConfig(string configString)
		{
			TotemUnlockCost.Clear();
			string[] array = configString.Replace(" ", "").Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { ':' }, StringSplitOptions.RemoveEmptyEntries);
				if (array2.Length != 2)
				{
					AssetManager.PrintRecipeErrorMessage(configString);
					continue;
				}
				string prefabName = array2[0];
				if (!int.TryParse(array2[1], out var result))
				{
					AssetManager.PrintRecipeErrorMessage(configString);
					continue;
				}
				TotemUnlockCost.Add(new UnlockRequirement
				{
					PrefabName = prefabName,
					Amount = result
				});
			}
		}

		public static void UpdateSettings()
		{
			SetRecipeFromConfig(TravelTotemsPlugin.GetTotemUnlockRequirementsString());
			if (TravelTotemsPlugin.GetTravelTotemType() == TravelTotemType.Undefined)
			{
				TravelTotemsPlugin.TravelTotemsLogger.LogWarning((object)"Default totem type is undefined. Please check your configuration for spelling errors!New totems may behave strangely until fixed.");
			}
		}

		public static bool HasUnlockRequirements()
		{
			return TotemUnlockCost.Count > 0;
		}

		public static bool TryConsumeUnlockRequirements()
		{
			if (TotemUnlockCost.Count > 0)
			{
				foreach (UnlockRequirement item in TotemUnlockCost)
				{
					if (((Humanoid)Player.m_localPlayer).m_inventory.CountItems(item.GetItemDropName(), -1, true) < item.Amount)
					{
						return false;
					}
				}
				foreach (UnlockRequirement item2 in TotemUnlockCost)
				{
					((Humanoid)Player.m_localPlayer).m_inventory.RemoveItem(item2.GetItemDropName(), item2.Amount, -1, true);
				}
				((Character)Player.m_localPlayer).Message((MessageType)2, "$msg_offerdone", 0, (Sprite)null);
			}
			return true;
		}

		public static void AddTotem(ZDO totem)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (totem != null && !TravelTotemZDOs.Contains(totem))
			{
				TravelTotemZDOs.Add(totem);
				if (ZNet.instance.IsServer())
				{
					ZDOMan.instance.ForceSendZDO(totem.m_uid);
				}
			}
		}

		public static void RemoveTotem(ZDO totem)
		{
			if (totem != null)
			{
				TravelTotemZDOs.Remove(totem);
			}
			TravelTotemMap.RefreshMapPins();
		}

		public static List<ZDO> GetTravelTotems()
		{
			return TravelTotemZDOs;
		}

		private static void StartTravelTotems()
		{
			TravelTotemsPlugin.TravelTotemsLogger.LogDebug((object)"Loading travel totems...");
			if (ZNet.instance.IsServer())
			{
				StartTravelTotemsServer();
				if (!ZNet.instance.IsDedicated())
				{
					UpdateSettings();
				}
			}
			else
			{
				StartTravelTotemsClient();
			}
		}

		private static void StartTravelTotemsClient()
		{
			Reset();
		}

		public static void RPC_ConsumeTotemIDResponse(long sender, int bin, int id)
		{
			ZDO val = UnassignedTravelTotemZDOs.Dequeue();
			if (val != null)
			{
				if (!val.IsOwner())
				{
					val.SetOwner(ZDOMan.GetSessionID());
				}
				val.Set("VV_TotemIDBin", bin);
				val.Set("VV_TotemID", id);
				val.Set("VV_TotemType", 4);
			}
		}

		public static void ProcessUnassignedTotems()
		{
			int count = UnassignedTravelTotemZDOs.Count;
			for (int i = 0; i < count; i++)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC("VV_ConsumeTotemID", Array.Empty<object>());
			}
		}

		public static void AssignTotemID(ZDO zdo)
		{
			if (zdo != null)
			{
				UnassignedTravelTotemZDOs.Enqueue(zdo);
				ZRoutedRpc.instance.InvokeRoutedRPC("VV_ConsumeTotemID", Array.Empty<object>());
			}
		}

		public static void RPC_RequestTotems(ZRpc rpc)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			ZNetPeer peer = ZNet.instance.GetPeer(rpc);
			if (peer == null)
			{
				TravelTotemsPlugin.TravelTotemsLogger.LogWarning((object)"Recieved a request for totem data but peer was not found!");
				return;
			}
			ZPackage val = new ZPackage();
			val.Write(TravelTotemZDOs.Count);
			foreach (ZDO travelTotemZDO in TravelTotemZDOs)
			{
				val.Write(travelTotemZDO.m_uid);
				ZDOMan.instance.ForceSendZDO(peer.m_uid, travelTotemZDO.m_uid);
			}
			rpc.Invoke("VV_SendTotems", new object[1] { val });
		}

		public static void RPC_SendTotems(ZRpc rpc, ZPackage package)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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)
			int num = package.ReadInt();
			int num2 = 0;
			for (int i = 0; i < num; i++)
			{
				ZDOID val = package.ReadZDOID();
				ZDO zDO = ZDOMan.instance.GetZDO(val);
				if (zDO == null)
				{
					ZDOMan.instance.RequestZDO(val);
					continue;
				}
				num2++;
				TravelTotemZDOs.Add(zDO);
			}
		}

		private static void StartTravelTotemsServer()
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			Reset();
			foreach (KeyValuePair<ZDOID, ZDO> item in ZDOMan.instance.m_objectsByID)
			{
				int prefab = item.Value.GetPrefab();
				if (AssetManager.IsTravelTotemTracker(prefab))
				{
					flag = true;
					TravelTotemTrackerZDO = item.Value;
				}
				else if (AssetManager.IsTravelTotem(prefab))
				{
					TravelTotemZDOs.Add(item.Value);
					int num = item.Value.GetInt("VV_TotemIDBin", -1);
					int num2 = item.Value.GetInt("VV_TotemID", -1);
					if (num == -1 || num2 == -1)
					{
						UnassignedTravelTotemZDOs.Enqueue(item.Value);
					}
				}
			}
			if (!flag)
			{
				Object.Instantiate<GameObject>(Cache.GetPrefab<GameObject>(AssetManager.TravelTotemTrackerPrefabName), Vector3.zero, Quaternion.identity);
			}
			else
			{
				InitializeTracker();
			}
			TravelTotemsPlugin.TravelTotemsLogger.LogDebug((object)($"Tracking {TravelTotemZDOs.Count} travel totems. " + $"{UnassignedTravelTotemZDOs.Count} need assignment."));
			ProcessUnassignedTotems();
		}

		public static void InitializeTracker()
		{
			if (TravelTotemTrackerZDO == null)
			{
				TravelTotemsPlugin.TravelTotemsLogger.LogError((object)"Tracker is null! Will not be able to assign new totem ids.");
				return;
			}
			int num = TravelTotemTrackerZDO.GetInt("VV_MaxTotemIDBin", -1);
			int num2 = TravelTotemTrackerZDO.GetInt("VV_MaxTotemID", -1);
			if (num == -1 || num2 == -1)
			{
				FindMaxTotemID(out var maxBin, out var maxID);
				UpdateMaxTotemIndexes(maxBin, maxID);
			}
		}

		public static bool FindMaxTotemID(out int maxBin, out int maxID)
		{
			bool result = false;
			maxBin = 0;
			maxID = 0;
			foreach (KeyValuePair<ZDOID, ZDO> item in ZDOMan.instance.m_objectsByID)
			{
				if (AssetManager.IsTravelTotem(item.Value.GetPrefab()))
				{
					int num = item.Value.GetInt("VV_TotemIDBin", -1);
					int num2 = item.Value.GetInt("VV_TotemID", -1);
					if (num > maxBin)
					{
						result = true;
						maxBin = num;
						maxID = num2;
					}
					else if (num == maxBin && num2 > maxID)
					{
						result = true;
						maxID = num2;
					}
				}
			}
			return result;
		}

		private static void IncrementIDMax()
		{
			int num = GetMaxTotemIDBin();
			int maxTotemID = GetMaxTotemID();
			if (maxTotemID != 1073741824)
			{
				maxTotemID = ((maxTotemID <= 0) ? 1 : (maxTotemID << 1));
			}
			else
			{
				num++;
				maxTotemID = 1;
			}
			UpdateMaxTotemIndexes(num, maxTotemID);
		}

		public static void RPC_ConsumeTotemID(long sender)
		{
			if (ZNet.instance.IsServer() && TravelTotemTrackerZDO != null)
			{
				IncrementIDMax();
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "VV_ConsumeTotemIDResponse", new object[2]
				{
					GetMaxTotemIDBin(),
					GetMaxTotemID()
				});
			}
		}

		private static void UpdateMaxTotemIndexes(int bin, int id)
		{
			if (TravelTotemTrackerZDO != null && TravelTotemTrackerZDO.IsValid())
			{
				TravelTotemTrackerZDO.SetOwner(ZDOMan.GetSessionID());
				TravelTotemTrackerZDO.Set("VV_MaxTotemIDBin", bin);
				TravelTotemTrackerZDO.Set("VV_MaxTotemID", id);
			}
		}

		public static int GetMaxTotemIDBin()
		{
			return TravelTotemTrackerZDO.GetInt("VV_MaxTotemIDBin", 0);
		}

		public static int GetMaxTotemID()
		{
			return TravelTotemTrackerZDO.GetInt("VV_MaxTotemID", 0);
		}
	}
	public class TravelTotemTracker : MonoBehaviour
	{
		public static TravelTotemTracker Instance;

		public ZNetView ZNetView;

		private void Awake()
		{
			ZNetView = ((Component)this).GetComponent<ZNetView>();
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			else
			{
				TravelTotemsPlugin.TravelTotemsLogger.LogWarning((object)"Multiple Totem trackers found! IDs may not be tracked accurately!");
			}
		}

		private void Start()
		{
			if (TravelTotems.TravelTotemTrackerZDO == null)
			{
				TravelTotems.TravelTotemTrackerZDO = Instance.ZNetView.GetZDO();
				TravelTotems.InitializeTracker();
			}
		}

		private void OnDestroy()
		{
			Instance = null;
		}
	}
	[Flags]
	public enum TravelTotemType
	{
		Undefined = 0,
		AlwaysUnlock = 1,
		FindUnlock = 2,
		AlwaysLock = 3,
		ServerDefault = 4
	}
	public struct UnlockRequirement
	{
		public string PrefabName;

		public int Amount;

		private string ItemDropName;

		public UnlockRequirement(string prefab, int amount)
		{
			PrefabName = prefab;
			Amount = amount;
			ItemDropName = null;
		}

		public string GetItemDropName()
		{
			if (ItemDropName == null)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(PrefabName);
				if ((Object)(object)itemPrefab == (Object)null)
				{
					return string.Empty;
				}
				ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
				if ((Object)(object)component == (Object)null)
				{
					return string.Empty;
				}
				ItemDropName = component.m_itemData.m_shared.m_name;
			}
			return ItemDropName;
		}
	}
	[PublicAPI]
	public class API
	{
		public static int GetTotemPinIndex()
		{
			return TravelTotemMapPin.TotemIndex;
		}
	}
}