Decompiled source of TraderCompass v1.21.1

TraderCompass_v1.21.1.dll

Decompiled 9 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("TraderCompass")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.21.1.0")]
[assembly: AssemblyInformationalVersion("1.21.1")]
[assembly: AssemblyProduct("TraderCompass")]
[assembly: AssemblyTitle("TraderCompass")]
[assembly: AssemblyVersion("1.21.1.0")]
namespace TraderCompass;

[BepInPlugin("frost.tradercompass", "TraderCompass", "1.21.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class TraderCompassPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "frost.tradercompass";

	public const string PluginName = "TraderCompass";

	public const string PluginVersion = "1.21.1";

	public const string ItemPrefabName = "Compass_Trader";

	public const string ItemName = "Компас";

	internal static ManualLogSource Log;

	private void Awake()
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		Log = ((BaseUnityPlugin)this).Logger;
		new Harmony("frost.tradercompass").PatchAll();
		PrefabManager.OnVanillaPrefabsAvailable += CreateCompassItem;
		CompassCommand.Register();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"TraderCompass 1.21.1 загружен (Jötunn)");
	}

	private void CreateCompassItem()
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Expected O, but got Unknown
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Expected O, but got Unknown
		PrefabManager.OnVanillaPrefabsAvailable -= CreateCompassItem;
		try
		{
			ItemConfig val = new ItemConfig();
			val.Name = "Компас";
			val.Description = "Странный компас, стрелка которого всегда тянется к торговцу.\nВозьми в руку и нажми <color=yellow>ПКМ</color> — он покажет путь к Халдору.\nДля запуска нужно 1 ядро суртлинга. Перезарядка 10 минут.";
			val.Icons = (Sprite[])(object)new Sprite[1] { CompassIcon.Create() };
			val.Weight = 0.5f;
			val.StackSize = 1;
			ItemConfig val2 = val;
			GameObject obj = PrefabManager.Instance.CreateClonedPrefab("Compass_Trader", "Crystal");
			CompassModel.Apply(obj);
			CustomItem val3 = new CustomItem(obj, false, val2);
			ItemManager.Instance.AddItem(val3);
			Log.LogInfo((object)"Компас зарегистрирован через Jötunn");
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[TraderCompass] Ошибка создания предмета: " + ex));
		}
	}
}
internal static class CompassModel
{
	private const float TargetSize = 0.5f;

	private static AssetBundle _bundle;

	public static void Apply(GameObject clone)
	{
		//IL_018b: Unknown result type (might be due to invalid IL or missing references)
		//IL_019b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0255: Unknown result type (might be due to invalid IL or missing references)
		//IL_025a: Unknown result type (might be due to invalid IL or missing references)
		//IL_025e: Unknown result type (might be due to invalid IL or missing references)
		//IL_026a: Unknown result type (might be due to invalid IL or missing references)
		//IL_026f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0274: Unknown result type (might be due to invalid IL or missing references)
		//IL_0278: Unknown result type (might be due to invalid IL or missing references)
		//IL_027f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0286: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Stream manifestResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("compass_bundle");
			if (manifestResourceStream == null)
			{
				TraderCompassPlugin.Log.LogWarning((object)"compass_bundle не найден в ресурсах — ванильный вид");
				return;
			}
			byte[] array = new byte[manifestResourceStream.Length];
			using (MemoryStream memoryStream = new MemoryStream())
			{
				manifestResourceStream.CopyTo(memoryStream);
				array = memoryStream.ToArray();
			}
			string text = Path.Combine(Path.GetTempPath(), "frost.tradercompass.bundle");
			File.WriteAllBytes(text, array);
			_bundle = AssetBundle.LoadFromFile(text);
			if ((Object)(object)_bundle == (Object)null)
			{
				_bundle = AssetBundle.LoadFromMemory(array);
			}
			if ((Object)(object)_bundle == (Object)null)
			{
				TraderCompassPlugin.Log.LogWarning((object)("Бандл не загрузился (" + array.Length + " байт, header: " + BitConverter.ToString(array, 0, 8) + ") — ванильный вид"));
				return;
			}
			TraderCompassPlugin.Log.LogInfo((object)("Бандл загружен, ассеты: " + string.Join(", ", _bundle.GetAllAssetNames())));
			GameObject val = null;
			string[] allAssetNames = _bundle.GetAllAssetNames();
			foreach (string text2 in allAssetNames)
			{
				val = _bundle.LoadAsset<GameObject>(text2);
				if ((Object)(object)val != (Object)null)
				{
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				TraderCompassPlugin.Log.LogWarning((object)"В бандле нет префаба — ванильный вид");
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, clone.transform);
			((Object)val2).name = "custom_visual";
			val2.transform.localPosition = Vector3.zero;
			val2.transform.localRotation = Quaternion.identity;
			Renderer[] componentsInChildren = clone.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val3 in componentsInChildren)
			{
				if (!((Component)val3).transform.IsChildOf(val2.transform))
				{
					val3.enabled = false;
				}
			}
			Light[] componentsInChildren2 = clone.GetComponentsInChildren<Light>(true);
			foreach (Light val4 in componentsInChildren2)
			{
				if (!((Component)val4).transform.IsChildOf(val2.transform))
				{
					((Behaviour)val4).enabled = false;
				}
			}
			float num = 0f;
			MeshFilter[] componentsInChildren3 = val2.GetComponentsInChildren<MeshFilter>(true);
			foreach (MeshFilter val5 in componentsInChildren3)
			{
				if (!((Object)(object)val5.sharedMesh == (Object)null))
				{
					Bounds bounds = val5.sharedMesh.bounds;
					Vector3 val6 = Vector3.Scale(((Bounds)(ref bounds)).size, ((Component)val5).transform.lossyScale);
					num = Mathf.Max(num, Mathf.Max(val6.x, Mathf.Max(val6.y, val6.z)));
				}
			}
			if (num > 0.0001f)
			{
				float num2 = 0.5f / num;
				val2.transform.localScale = val2.transform.localScale * num2;
			}
			TraderCompassPlugin.Log.LogInfo((object)$"3D-модель компаса применена (габарит {0.5f:F2} м, масштаб x{((num > 0.0001f) ? (0.5f / num) : 1f):F2})");
		}
		catch (Exception ex)
		{
			TraderCompassPlugin.Log.LogWarning((object)("3D-модель не применилась — остаётся ванильный вид: " + ex));
		}
	}
}
[HarmonyPatch(typeof(Game), "Start")]
internal static class Game_Start_LootPatch
{
	private const float LootChancePercent = 4f;

	private static void Postfix()
	{
		//IL_015b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0160: Unknown result type (might be due to invalid IL or missing references)
		//IL_0162: Unknown result type (might be due to invalid IL or missing references)
		//IL_0178: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
		RegisterRPC();
		try
		{
			ZNetScene instance = ZNetScene.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			ObjectDB instance2 = ObjectDB.instance;
			if ((Object)(object)instance2 == (Object)null)
			{
				return;
			}
			GameObject val = null;
			foreach (GameObject prefab in instance.m_prefabs)
			{
				if ((Object)(object)prefab != (Object)null && ((Object)prefab).name == "Compass_Trader")
				{
					val = prefab;
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				TraderCompassPlugin.Log.LogWarning((object)"Компас не найден в ZNetScene — лут сундуков не добавлен");
				return;
			}
			EnsureCompassRecipe(instance, instance2, val);
			int num = 0;
			foreach (GameObject prefab2 in instance.m_prefabs)
			{
				if ((Object)(object)prefab2 == (Object)null)
				{
					continue;
				}
				string name = ((Object)prefab2).name;
				if (name.IndexOf("TreasureChest", StringComparison.OrdinalIgnoreCase) < 0 || (name.IndexOf("blackforest", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("dungeon", StringComparison.OrdinalIgnoreCase) < 0))
				{
					continue;
				}
				Container component = prefab2.GetComponent<Container>();
				if ((Object)(object)component == (Object)null || component.m_defaultItems == null)
				{
					continue;
				}
				bool flag = false;
				float num2 = 0f;
				foreach (DropData drop in component.m_defaultItems.m_drops)
				{
					if ((Object)(object)drop.m_item == (Object)(object)val)
					{
						flag = true;
						break;
					}
					num2 += drop.m_weight;
				}
				if (!flag)
				{
					float weight = num2 * 0.04f / 0.96f;
					component.m_defaultItems.m_drops.Add(new DropData
					{
						m_item = val,
						m_stackMin = 1,
						m_stackMax = 1,
						m_weight = weight,
						m_dontScale = true
					});
					num++;
				}
			}
			if (num > 0)
			{
				TraderCompassPlugin.Log.LogInfo((object)("Компас добавлен в лут сундуков: " + num + " шт"));
			}
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[TraderCompass] Ошибка добавления лута: " + ex));
		}
	}

	private static void RegisterRPC()
	{
		CompassCache.Reset();
		TraderPosSync.Reset();
		if (ZRoutedRpc.instance == null)
		{
			TraderCompassPlugin.Log.LogWarning((object)"ZRoutedRpc недоступен при старте мира — RPC не зарегистрированы");
			return;
		}
		ZRoutedRpc.instance.Register("TraderCompass_RequestPos", (Action<long>)TraderCompassRPC.OnPosRequested);
		ZRoutedRpc.instance.Register<Vector3, bool, bool>("TraderCompass_Pos", (Action<long, Vector3, bool, bool>)TraderCompassRPC.OnPosReceived);
		TraderCompassPlugin.Log.LogInfo((object)"RPC зарегистрированы (запрос позиции и ответ)");
	}

	private static ItemDrop FindItemBySharedName(ObjectDB db, string sharedName)
	{
		foreach (GameObject item in db.m_items)
		{
			if (!((Object)(object)item == (Object)null))
			{
				ItemDrop component = item.GetComponent<ItemDrop>();
				if ((Object)(object)component != (Object)null && component.m_itemData != null && component.m_itemData.m_shared != null && component.m_itemData.m_shared.m_name == sharedName)
				{
					return component;
				}
			}
		}
		return null;
	}

	private static void EnsureCompassRecipe(ZNetScene zns, ObjectDB db, GameObject compassPrefab)
	{
		//IL_021d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0222: Unknown result type (might be due to invalid IL or missing references)
		//IL_022e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0236: Expected O, but got Unknown
		//IL_0238: Unknown result type (might be due to invalid IL or missing references)
		//IL_023d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0249: Unknown result type (might be due to invalid IL or missing references)
		//IL_0251: Expected O, but got Unknown
		//IL_0253: Unknown result type (might be due to invalid IL or missing references)
		//IL_0258: 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_026d: Expected O, but got Unknown
		//IL_026f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0274: Unknown result type (might be due to invalid IL or missing references)
		//IL_0281: Unknown result type (might be due to invalid IL or missing references)
		//IL_0289: Expected O, but got Unknown
		foreach (Recipe recipe in db.m_recipes)
		{
			if ((Object)(object)recipe != (Object)null && (Object)(object)recipe.m_item != (Object)null && ((Object)((Component)recipe.m_item).gameObject).name == "Compass_Trader")
			{
				return;
			}
		}
		GameObject val = (((Object)(object)zns != (Object)null) ? zns.GetPrefab("piece_forge") : null);
		CraftingStation val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<CraftingStation>() : null);
		if ((Object)(object)val2 == (Object)null)
		{
			foreach (Recipe recipe2 in db.m_recipes)
			{
				if (!((Object)(object)recipe2 == (Object)null) && !((Object)(object)recipe2.m_craftingStation == (Object)null) && recipe2.m_craftingStation.m_name == "$piece_forge")
				{
					val2 = recipe2.m_craftingStation;
					break;
				}
			}
		}
		GameObject itemPrefab = db.GetItemPrefab("Bronze");
		ItemDrop val3 = FindItemBySharedName(db, "$item_silver");
		GameObject itemPrefab2 = db.GetItemPrefab("Crystal");
		GameObject itemPrefab3 = db.GetItemPrefab("SurtlingCore");
		List<string> list = new List<string>();
		if ((Object)(object)val2 == (Object)null)
		{
			list.Add("кузница");
		}
		if ((Object)(object)itemPrefab == (Object)null)
		{
			list.Add("бронза");
		}
		if ((Object)(object)val3 == (Object)null)
		{
			list.Add("серебро");
		}
		if ((Object)(object)itemPrefab2 == (Object)null)
		{
			list.Add("кристалл");
		}
		if ((Object)(object)itemPrefab3 == (Object)null)
		{
			list.Add("ядро");
		}
		if (list.Count > 0)
		{
			TraderCompassPlugin.Log.LogWarning((object)("Рецепт компаса: не найдены компоненты — " + string.Join(", ", list)));
			return;
		}
		Recipe val4 = ScriptableObject.CreateInstance<Recipe>();
		((Object)val4).name = "Recipe_Compass_Trader";
		val4.m_item = compassPrefab.GetComponent<ItemDrop>();
		val4.m_amount = 1;
		val4.m_craftingStation = val2;
		val4.m_minStationLevel = 1;
		val4.m_resources = (Requirement[])(object)new Requirement[4]
		{
			new Requirement
			{
				m_resItem = itemPrefab.GetComponent<ItemDrop>(),
				m_amount = 4
			},
			new Requirement
			{
				m_resItem = ((Component)val3).GetComponent<ItemDrop>(),
				m_amount = 4
			},
			new Requirement
			{
				m_resItem = itemPrefab2.GetComponent<ItemDrop>(),
				m_amount = 1
			},
			new Requirement
			{
				m_resItem = itemPrefab3.GetComponent<ItemDrop>(),
				m_amount = 1
			}
		};
		db.m_recipes.Add(val4);
		TraderCompassPlugin.Log.LogInfo((object)"Рецепт компаса создан: кузница, 4 бронзы + 4 серебра + 1 кристалл + 1 ядро");
	}
}
[HarmonyPatch(typeof(Humanoid), "UseItem", new Type[]
{
	typeof(Inventory),
	typeof(ItemData),
	typeof(bool)
})]
internal static class Humanoid_UseItem_Patch
{
	private const float CooldownSeconds = 600f;

	private static float _nextUseTime;

	private static bool Prefix(Humanoid __instance, ItemData item)
	{
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		if (item == null || item.m_shared == null || item.m_shared.m_name != "Компас")
		{
			return true;
		}
		Player val = (Player)(object)((__instance is Player) ? __instance : null);
		if ((Object)(object)val == (Object)null)
		{
			return true;
		}
		if (Time.time < _nextUseTime)
		{
			float num = _nextUseTime - Time.time;
			((Character)val).Message((MessageType)2, $"Компас остывает: ещё {(int)(num / 60f)} мин {(int)(num % 60f)} с", 0, (Sprite)null, false);
			return false;
		}
		if (!TryFindTrader(((Component)val).transform.position, out var pos, out var traderPlaced))
		{
			RequestTraderPosFromServer(val);
			return false;
		}
		if (!TryConsumeSurtlingCore(val))
		{
			((Character)val).Message((MessageType)2, "Для запуска компаса нужно 1 ядро суртлинга", 0, (Sprite)null, false);
			return false;
		}
		ShowTraderDirection(val, pos, traderPlaced);
		_nextUseTime = Time.time + 600f;
		return false;
	}

	private static bool TryConsumeSurtlingCore(Player player)
	{
		foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems())
		{
			if (allItem != null && (Object)(object)allItem.m_dropPrefab != (Object)null && ((Object)allItem.m_dropPrefab).name == "SurtlingCore")
			{
				((Humanoid)player).GetInventory().RemoveItem(allItem, 1);
				return true;
			}
		}
		return false;
	}

	private static void ShowTraderDirection(Player player, Vector3 traderPos, bool traderPlaced)
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)player == (Object)null))
		{
			Vector3 val = traderPos - ((Component)player).transform.position;
			float magnitude = ((Vector3)(ref val)).magnitude;
			((Character)player).SetLookDir(val, 3.5f);
			string arg = (traderPlaced ? "Торговец" : "Торговец (возможная точка)");
			((Character)player).Message((MessageType)1, $"{arg}: {BearingHelper.BearingName(val)} ({magnitude:F0} м)", 0, (Sprite)null, false);
		}
	}

	private static bool TryFindTrader(Vector3 near, out Vector3 pos, out bool traderPlaced)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//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_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: 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)
		//IL_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_014e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0153: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_0199: Unknown result type (might be due to invalid IL or missing references)
		//IL_019e: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
		pos = Vector3.zero;
		traderPlaced = false;
		if (CompassCache.Valid && CompassCache.Placed)
		{
			pos = CompassCache.Pos;
			traderPlaced = true;
			return true;
		}
		if (TraderPosSync.SyncedValid)
		{
			pos = TraderPosSync.SyncedPos;
			traderPlaced = TraderPosSync.Placed;
			return true;
		}
		if (CompassCache.Valid && Time.time < CompassCache.NextScanTime)
		{
			pos = CompassCache.Pos;
			traderPlaced = CompassCache.Placed;
			return true;
		}
		CompassCache.NextScanTime = Time.time + 2f;
		ZoneSystem instance = ZoneSystem.instance;
		if ((Object)(object)instance == (Object)null)
		{
			return false;
		}
		LocationInstance? val = null;
		float num = float.MaxValue;
		LocationInstance? val2 = null;
		float num2 = float.MaxValue;
		foreach (LocationInstance value2 in instance.m_locationInstances.Values)
		{
			if (!IsTraderLocation(value2.m_location))
			{
				continue;
			}
			float num3 = Vector3.Distance(value2.m_position, near);
			if (value2.m_placed)
			{
				if (num3 < num)
				{
					num = num3;
					val = value2;
				}
			}
			else if (num3 < num2)
			{
				num2 = num3;
				val2 = value2;
			}
		}
		LocationInstance value;
		if (val.HasValue)
		{
			value = val.Value;
			traderPlaced = true;
		}
		else
		{
			if (!val2.HasValue)
			{
				if (!CompassCache.DumpLogged)
				{
					CompassCache.DumpLogged = true;
					TraderCompassPlugin.Log.LogInfo((object)$"Локация торговца не найдена локально (локаций в списке: {instance.m_locationInstances.Count}) — при ПКМ будет запрошена позиция у сервера");
				}
				return false;
			}
			value = val2.Value;
		}
		CompassCache.Valid = true;
		CompassCache.Placed = traderPlaced;
		CompassCache.Pos = value.m_position;
		pos = value.m_position;
		return true;
	}

	private static bool IsTraderLocation(ZoneLocation zoneLocation)
	{
		if (zoneLocation == null)
		{
			return false;
		}
		string prefabName = zoneLocation.m_prefabName;
		if (prefabName != null)
		{
			if (prefabName.IndexOf("vendor_blackforest", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return prefabName.IndexOf("haldor", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}
		return false;
	}

	private static void RequestTraderPosFromServer(Player player)
	{
		if (!(Time.time < TraderPosSync.NextRequestTime))
		{
			TraderPosSync.NextRequestTime = Time.time + 5f;
			if (ZRoutedRpc.instance == null)
			{
				TraderCompassPlugin.Log.LogWarning((object)"ZRoutedRpc недоступен — запрос позиции не отправлен");
				return;
			}
			((Character)player).Message((MessageType)2, "Запрашиваю позицию торговца у сервера...", 0, (Sprite)null, false);
			TraderCompassPlugin.Log.LogInfo((object)"Локально торговец не найден — отправляю запрос на сервер");
			ZRoutedRpc.instance.InvokeRoutedRPC("TraderCompass_RequestPos", Array.Empty<object>());
		}
	}
}
internal static class TraderCompassRPC
{
	public static void OnPosRequested(long sender)
	{
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: 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_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//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_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_0215: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_014c: 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)
		//IL_0165: Unknown result type (might be due to invalid IL or missing references)
		//IL_016a: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			ZoneSystem instance = ZoneSystem.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			LocationInstance? val = null;
			float num = float.MaxValue;
			float num2 = float.MaxValue;
			int num3 = 0;
			Vector3 val2 = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Component)Player.m_localPlayer).transform.position : Vector3.zero);
			foreach (LocationInstance value in instance.m_locationInstances.Values)
			{
				if (!IsTraderLocation(value.m_location))
				{
					continue;
				}
				num3++;
				float num4 = Vector3.Distance(value.m_position, val2);
				if (value.m_placed)
				{
					if (num4 < num)
					{
						num = num4;
						val = value;
					}
				}
				else if (num4 < num2)
				{
					num2 = num4;
					if (!val.HasValue)
					{
						val = value;
					}
				}
			}
			if (val.HasValue)
			{
				bool placed = val.Value.m_placed;
				TraderCompassPlugin.Log.LogInfo((object)$"RPC: отвечаю клиенту {sender}: позиция ({val.Value.m_position.x:F0}, {val.Value.m_position.y:F0}, {val.Value.m_position.z:F0}), размещён={placed} (торговых локаций: {num3})");
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "TraderCompass_Pos", new object[3]
				{
					val.Value.m_position,
					placed,
					true
				});
			}
			else
			{
				TraderCompassPlugin.Log.LogWarning((object)$"RPC: торговец не найден среди {instance.m_locationInstances.Count} локаций мира (торговых: {num3}) — мир ещё генерируется?");
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "TraderCompass_Pos", new object[3]
				{
					Vector3.zero,
					false,
					false
				});
			}
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[TraderCompass] Ошибка ответа на запрос: " + ex));
		}
	}

	public static void OnPosReceived(long sender, Vector3 pos, bool placed, bool found)
	{
		//IL_0037: 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_005b: 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_0077: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (!found)
			{
				TraderCompassPlugin.Log.LogInfo((object)"RPC: сервер ответил — торговец пока не найден в мире");
				if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					((Character)Player.m_localPlayer).Message((MessageType)2, "Торговец пока не известен серверу — мир ещё генерируется, попробуй позже", 0, (Sprite)null, false);
				}
				return;
			}
			TraderPosSync.SyncedPos = pos;
			TraderPosSync.Placed = placed;
			TraderPosSync.SyncedValid = true;
			TraderCompassPlugin.Log.LogInfo((object)$"RPC: получена позиция торговца ({pos.x:F0}, {pos.y:F0}, {pos.z:F0}), размещён={placed}");
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, "Позиция торговца получена — нажми ПКМ ещё раз", 0, (Sprite)null, false);
			}
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[TraderCompass] Ошибка приёма позиции: " + ex));
		}
	}

	private static bool IsTraderLocation(ZoneLocation location)
	{
		if (location == null)
		{
			return false;
		}
		string prefabName = location.m_prefabName;
		if (prefabName != null)
		{
			if (prefabName.IndexOf("vendor_blackforest", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return prefabName.IndexOf("haldor", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}
		return false;
	}
}
internal static class RpcNames
{
	public const string Request = "TraderCompass_RequestPos";

	public const string Pos = "TraderCompass_Pos";
}
internal static class TraderPosSync
{
	public static Vector3 SyncedPos;

	public static bool SyncedValid;

	public static bool Placed;

	public static float NextRequestTime;

	public static void Reset()
	{
		SyncedValid = false;
		Placed = false;
		NextRequestTime = 0f;
	}
}
internal static class CompassCache
{
	public static Vector3 Pos;

	public static bool Valid;

	public static bool Placed;

	public static float NextScanTime;

	public static bool DumpLogged;

	public static void Reset()
	{
		Valid = false;
		Placed = false;
		DumpLogged = false;
	}
}
internal static class BearingHelper
{
	public static string BearingName(Vector3 dir)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		float num = Mathf.Atan2(dir.x, 0f - dir.z) * 57.29578f;
		if (num < 0f)
		{
			num += 360f;
		}
		return (new string[8] { "С", "СВ", "В", "ЮВ", "Ю", "ЮЗ", "З", "СЗ" })[(int)Mathf.Round(num / 45f) % 8];
	}
}
[HarmonyPatch(typeof(Player), "Load")]
internal static class Player_Load_Patch
{
	private static void Postfix(Player __instance)
	{
		try
		{
			ObjectDB instance = ObjectDB.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				RecipeUnlocker.UnlockFor(__instance, instance);
			}
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[TraderCompass] Ошибка выдачи рецепта (загрузка): " + ex));
		}
	}
}
[HarmonyPatch(typeof(Player), "OnSpawned")]
internal static class Player_OnSpawned_Patch
{
	private static void Postfix(Player __instance)
	{
		try
		{
			ObjectDB instance = ObjectDB.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				RecipeUnlocker.UnlockFor(__instance, instance);
			}
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[TraderCompass] Ошибка выдачи рецепта: " + ex));
		}
	}
}
[HarmonyPatch(typeof(InventoryGui), "UpdateCraftingPanel")]
internal static class InventoryGui_UpdateCraftingPanel_Patch
{
	private static int _diagCalls;

	private static void Postfix(InventoryGui __instance)
	{
		try
		{
			Player localPlayer = Player.m_localPlayer;
			ObjectDB instance = ObjectDB.instance;
			if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)instance == (Object)null))
			{
				RecipeUnlocker.UnlockFor(localPlayer, instance);
				if (_diagCalls < 2)
				{
					_diagCalls++;
					LogCraftingMenuDiagnostics(localPlayer, instance);
				}
			}
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[TraderCompass] Ошибка выдачи рецепта (меню): " + ex));
		}
	}

	private static void LogCraftingMenuDiagnostics(Player player, ObjectDB db)
	{
		try
		{
			List<Recipe> list = new List<Recipe>();
			player.GetAvailableRecipes(ref list);
			bool flag = false;
			foreach (Recipe item in list)
			{
				if ((Object)(object)item != (Object)null && (Object)(object)item.m_item != (Object)null && ((Object)((Component)item.m_item).gameObject).name == "Compass_Trader")
				{
					flag = true;
					break;
				}
			}
			bool flag2 = false;
			foreach (GameObject item2 in db.m_items)
			{
				if ((Object)(object)item2 != (Object)null && ((Object)item2).name == "Compass_Trader")
				{
					flag2 = true;
					break;
				}
			}
			TraderCompassPlugin.Log.LogInfo((object)string.Format("Меню крафта: компас в доступных: {0} из {1}, предмет в БД: {2}, рецепт изучен: {3}", flag, list.Count, flag2, player.IsRecipeKnown("Компас")));
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[TraderCompass] Ошибка диагностики меню: " + ex));
		}
	}
}
[HarmonyPatch(typeof(InventoryGui), "AddRecipeToList")]
internal static class InventoryGui_AddRecipeToList_Patch
{
	private static void Postfix(InventoryGui __instance, Recipe recipe, ItemData item, bool canCraft)
	{
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if ((Object)(object)recipe == (Object)null || (Object)(object)recipe.m_item == (Object)null || ((Object)((Component)recipe.m_item).gameObject).name != "Compass_Trader" || !(AccessTools.Field(typeof(InventoryGui), "m_availableRecipes")?.GetValue(__instance) is IEnumerable enumerable))
			{
				return;
			}
			object obj = null;
			foreach (object item2 in enumerable)
			{
				obj = item2;
			}
			object member = TraderCompassAccess.GetMember(obj, "InterfaceElement");
			GameObject val = (GameObject)((member is GameObject) ? member : null);
			object obj2;
			if (!((Object)(object)val != (Object)null))
			{
				obj2 = null;
			}
			else
			{
				Transform obj3 = val.transform.Find("icon");
				obj2 = ((obj3 != null) ? ((Component)obj3).GetComponent<Image>() : null);
			}
			Image val2 = (Image)obj2;
			if (!((Object)(object)val2 == (Object)null))
			{
				((Graphic)val2).color = (Color)(canCraft ? Color.white : new Color(1f, 1f, 1f, 0.4f));
			}
		}
		catch
		{
		}
	}
}
internal static class TraderCompassAccess
{
	public static object GetMember(object obj, string name)
	{
		Type type = obj.GetType();
		PropertyInfo propertyInfo = AccessTools.Property(type, name);
		if (propertyInfo != null)
		{
			return propertyInfo.GetValue(obj);
		}
		return AccessTools.Field(type, name)?.GetValue(obj);
	}
}
internal static class RecipeUnlocker
{
	public static void UnlockFor(Player player, ObjectDB db)
	{
		if (player.IsRecipeKnown("Компас"))
		{
			return;
		}
		Recipe val = null;
		foreach (Recipe recipe in db.m_recipes)
		{
			if ((Object)(object)recipe != (Object)null && (Object)(object)recipe.m_item != (Object)null && ((Object)((Component)recipe.m_item).gameObject).name == "Compass_Trader")
			{
				val = recipe;
				break;
			}
		}
		if (!((Object)(object)val == (Object)null))
		{
			AccessTools.Method(typeof(Player), "AddKnownRecipe", (Type[])null, (Type[])null)?.Invoke(player, new object[1] { val });
			TraderCompassPlugin.Log.LogInfo((object)("Рецепт выдан игроку " + player.GetPlayerName()));
		}
	}
}
internal static class CompassCommand
{
	[Serializable]
	[CompilerGenerated]
	private sealed class <>c
	{
		public static readonly <>c <>9 = new <>c();

		public static ConsoleEvent <>9__0_0;

		internal void <Register>b__0_0(ConsoleEventArgs <p0>)
		{
			Player localPlayer = Player.m_localPlayer;
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)instance == (Object)null)
			{
				return;
			}
			ItemDrop val = null;
			foreach (GameObject item in instance.m_items)
			{
				if ((Object)(object)item != (Object)null && ((Object)item).name == "Compass_Trader")
				{
					val = item.GetComponent<ItemDrop>();
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				((Character)localPlayer).Message((MessageType)2, "Компас ещё не готов, попробуй через секунду", 0, (Sprite)null, false);
			}
			else if (((Humanoid)localPlayer).GetInventory().AddItem(((Component)val).gameObject, 1))
			{
				((Character)localPlayer).Message((MessageType)1, "Компас торговца получен", 0, (Sprite)null, false);
			}
			else
			{
				((Character)localPlayer).Message((MessageType)2, "В инвентаре нет места", 0, (Sprite)null, false);
			}
		}
	}

	public static void Register()
	{
		//IL_0033: 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_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Expected O, but got Unknown
		object obj = <>c.<>9__0_0;
		if (obj == null)
		{
			ConsoleEvent val = delegate
			{
				Player localPlayer = Player.m_localPlayer;
				ObjectDB instance = ObjectDB.instance;
				if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)instance == (Object)null))
				{
					ItemDrop val2 = null;
					foreach (GameObject item in instance.m_items)
					{
						if ((Object)(object)item != (Object)null && ((Object)item).name == "Compass_Trader")
						{
							val2 = item.GetComponent<ItemDrop>();
							break;
						}
					}
					if ((Object)(object)val2 == (Object)null)
					{
						((Character)localPlayer).Message((MessageType)2, "Компас ещё не готов, попробуй через секунду", 0, (Sprite)null, false);
					}
					else if (((Humanoid)localPlayer).GetInventory().AddItem(((Component)val2).gameObject, 1))
					{
						((Character)localPlayer).Message((MessageType)1, "Компас торговца получен", 0, (Sprite)null, false);
					}
					else
					{
						((Character)localPlayer).Message((MessageType)2, "В инвентаре нет места", 0, (Sprite)null, false);
					}
				}
			};
			<>c.<>9__0_0 = val;
			obj = (object)val;
		}
		new ConsoleCommand("compass", "выдать компас торговца в инвентарь", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
	}
}
internal static class CompassIcon
{
	private static Sprite _sprite;

	public static Sprite Create()
	{
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_sprite != (Object)null)
		{
			return _sprite;
		}
		Texture2D val = LoadEmbeddedTexture();
		if ((Object)(object)val == (Object)null)
		{
			val = CreateProceduralTexture();
		}
		((Texture)val).wrapMode = (TextureWrapMode)1;
		((Texture)val).filterMode = (FilterMode)1;
		val.Apply(true, true);
		_sprite = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
		return _sprite;
	}

	private static Texture2D LoadEmbeddedTexture()
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Expected O, but got Unknown
		try
		{
			Stream manifestResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("compass_icon.png");
			if (manifestResourceStream == null)
			{
				return null;
			}
			using (manifestResourceStream)
			{
				byte[] array = new byte[manifestResourceStream.Length];
				using (MemoryStream memoryStream = new MemoryStream())
				{
					manifestResourceStream.CopyTo(memoryStream);
					array = memoryStream.ToArray();
				}
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true);
				return ImageConversion.LoadImage(val, array) ? val : null;
			}
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[TraderCompass] Не удалось загрузить иконку: " + ex));
			return null;
		}
	}

	private static Texture2D CreateProceduralTexture()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
		((Texture)val).wrapMode = (TextureWrapMode)1;
		Color32[] array = (Color32[])(object)new Color32[4096];
		float num = 31.5f;
		float num2 = 30f;
		Color32 val2 = default(Color32);
		for (int i = 0; i < 64; i++)
		{
			for (int j = 0; j < 64; j++)
			{
				float num3 = (float)j - num;
				float num4 = (float)i - num;
				float num5 = Mathf.Sqrt(num3 * num3 + num4 * num4);
				((Color32)(ref val2))..ctor((byte)0, (byte)0, (byte)0, (byte)0);
				if (num5 <= num2)
				{
					((Color32)(ref val2))..ctor((byte)52, (byte)48, (byte)56, byte.MaxValue);
					if (num5 > num2 - 4f)
					{
						((Color32)(ref val2))..ctor((byte)198, (byte)156, (byte)82, byte.MaxValue);
					}
					float num6 = 7f * (1f - Mathf.Abs(num4) / 28f);
					if (Mathf.Abs(num4) <= 28f && Mathf.Abs(num3) <= num6)
					{
						val2 = ((num4 > 0f) ? new Color32((byte)214, (byte)62, (byte)48, byte.MaxValue) : new Color32((byte)232, (byte)228, (byte)220, byte.MaxValue));
					}
				}
				array[i * 64 + j] = val2;
			}
		}
		val.SetPixels32(array);
		((Texture)val).filterMode = (FilterMode)1;
		val.Apply(false, true);
		return val;
	}
}