Decompiled source of ServerTaming v1.1.6

plugins/ServerTaming.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("ServerTaming")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+1908868251c689d0a9ff071b0cfbc94108a893e1")]
[assembly: AssemblyProduct("ServerTaming")]
[assembly: AssemblyTitle("ServerTaming")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ServerTaming
{
	[BepInPlugin("Tie.ServerTaming", "ServerTaming", "1.1.6")]
	public sealed class ServerTamingPlugin : BaseUnityPlugin
	{
		private enum PrefabKind
		{
			Other,
			Chest,
			Sign
		}

		private sealed class Feeding
		{
			public bool FromTameAssist;

			public bool Containers;

			public float Range;

			public Regex SignRange;

			public int MaxRange = 64;

			public int LeaveAtLeast;

			public float TamingMultiplier = 1f;

			public float FedMultiplier = 1f;

			public string ProgressMessageType = "";
		}

		private sealed class Species
		{
			public string Prefab;

			public ConfigEntry<bool> Enabled;

			public ConfigEntry<string> Foods;

			public ConfigEntry<float> TamingMinutes;

			public ConfigEntry<float> FedMinutes;

			public ConfigEntry<bool> Breeding;

			public ConfigEntry<float> PregnancyMinutes;

			public ConfigEntry<int> MaxCreatures;

			public int Hash;

			public string Name;

			public HashSet<int> FoodHashes = new HashSet<int>();

			public ZNetView View;
		}

		private sealed class Orphan
		{
			public int Prefab;

			public Vector3 Pos;

			public int Level;

			public float At;

			public ZDOID From;

			public State State;
		}

		private sealed class State
		{
			public float TameLeft;

			public double FedUntil;

			public int Love;

			public double Pregnant;

			public double NextBreedCheck;

			public bool TameAnnounced;
		}

		[HarmonyPatch(typeof(ZDOMan), "DestroyZDO")]
		private static class DestroyPatch
		{
			private static void Prefix(ZDO zdo)
			{
				try
				{
					if (zdo != null && (Object)(object)_instance != (Object)null && _instance._speciesByPrefab.ContainsKey(zdo.GetPrefab()))
					{
						_instance.Orphaned(zdo);
					}
				}
				catch (Exception ex)
				{
					ServerTamingPlugin instance = _instance;
					if (instance != null)
					{
						((BaseUnityPlugin)instance).Logger.LogError((object)ex);
					}
				}
			}
		}

		[HarmonyPatch(typeof(ZDOMan), "PrepareSave")]
		private static class SavePatch
		{
			private static void Prefix()
			{
				try
				{
					_instance?.WriteToZdos();
				}
				catch (Exception ex)
				{
					ServerTamingPlugin instance = _instance;
					if (instance != null)
					{
						((BaseUnityPlugin)instance).Logger.LogError((object)ex);
					}
				}
			}
		}

		public const string Guid = "Tie.ServerTaming";

		public const string Version = "1.1.6";

		private static readonly int KeyTameLeft = StringExtensionMethods.GetStableHashCode("ServerTaming_tameLeft");

		private static readonly int KeyFedUntil = StringExtensionMethods.GetStableHashCode("ServerTaming_fedUntil");

		private static readonly int KeyLove = StringExtensionMethods.GetStableHashCode("ServerTaming_love");

		private static readonly int KeyPregnant = StringExtensionMethods.GetStableHashCode("ServerTaming_pregnant");

		private const string TameAssistGuid = "ArgusMagnus.ServersideQoL.TameAssist";

		private static ServerTamingPlugin _instance;

		private ConfigEntry<float> _tickSeconds;

		private ConfigEntry<float> _feedRadius;

		private ConfigEntry<bool> _requireCalm;

		private ConfigEntry<float> _messageRange;

		private ConfigEntry<bool> _progressMessages;

		private ConfigEntry<int> _maxTameStars;

		private ConfigEntry<bool> _useTameAssist;

		private ConfigEntry<bool> _feedWildFromContainers;

		private ConfigEntry<float> _containerRange;

		private ConfigEntry<int> _leaveAtLeast;

		private ConfigEntry<float> _breedCheckSeconds;

		private ConfigEntry<float> _loveChance;

		private ConfigEntry<int> _requiredLovePoints;

		private ConfigEntry<float> _partnerRange;

		private ConfigEntry<float> _populationRange;

		private ConfigEntry<int> _maxCreatures;

		private ConfigEntry<int> _maxTamedNearby;

		private ConfigEntry<bool> _debugLog;

		private readonly List<Species> _species = new List<Species>();

		private readonly Dictionary<int, Species> _speciesByPrefab = new Dictionary<int, Species>();

		private readonly HashSet<int> _foodPrefabs = new HashSet<int>();

		private readonly Dictionary<ZDOID, State> _states = new Dictionary<ZDOID, State>();

		private readonly List<Orphan> _orphans = new List<Orphan>();

		private readonly List<ZDO> _sectorObjects = new List<ZDO>();

		private readonly HashSet<ZDOID> _seen = new HashSet<ZDOID>();

		private readonly List<ZDO> _animals = new List<ZDO>();

		private readonly List<ZDO> _foods = new List<ZDO>();

		private readonly HashSet<ZDOID> _eaten = new HashSet<ZDOID>();

		private readonly List<ZDO> _chests = new List<ZDO>();

		private readonly List<ZDO> _signs = new List<ZDO>();

		private readonly Dictionary<ZDOID, float> _chestRanges = new Dictionary<ZDOID, float>();

		private readonly Dictionary<int, PrefabKind> _kinds = new Dictionary<int, PrefabKind>();

		private Feeding _feeding = new Feeding();

		private bool _resolved;

		private float _timer;

		private double _lastTick = -1.0;

		private int _ticks;

		private void Awake()
		{
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Expected O, but got Unknown
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			//IL_0357: Unknown result type (might be due to invalid IL or missing references)
			_instance = this;
			string text = Path.Combine(Paths.ConfigPath, "local.servertaming.cfg");
			if (!File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath) && File.Exists(text))
			{
				File.Move(text, ((BaseUnityPlugin)this).Config.ConfigFilePath);
				((BaseUnityPlugin)this).Config.Reload();
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Moved local.servertaming.cfg to " + Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath) + "."));
			}
			_tickSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "TickSeconds", 5f, "How often (seconds) animals near players are checked.");
			_feedRadius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "FeedRadius", 8f, "Animals eat matching food lying within this many metres. They do not walk to it, so keep them penned with the food inside.");
			_requireCalm = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RequireCalm", true, "Taming and breeding pause while the animal is alerted (fleeing or fighting), like vanilla.");
			_messageRange = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MessageRange", 30f, "Players within this many metres see taming and birth messages.");
			_progressMessages = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ProgressMessages", true, "Show taming progress to nearby players: at 25/50/75%, or with TameAssist's TamingProgressMessageType when TameAssist is used.");
			_debugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLog", false, "Log feeding, love and breeding decisions for every animal near players (verbose; for troubleshooting).");
			_maxTameStars = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxTameStars", -1, "Highest star count that can be tamed; -1 means any (including the 3+ star creatures from level mods such as ServersideQoL CreatureLevelUp). Offspring keep their parent's stars.");
			_useTameAssist = ((BaseUnityPlugin)this).Config.Bind<bool>("Containers", "UseTameAssistSettings", true, "When ServersideQoL TameAssist is installed, use its FeedFromContainers settings (range, chest sign range, LeaveAtLeast), its TamingTimeMultiplier and FedDurationMultiplier, and its TamingProgressMessageType. The two settings below are then ignored.");
			_containerRange = ((BaseUnityPlugin)this).Config.Bind<float>("Containers", "FeedFromContainersRange", 0f, "Without TameAssist: animals eat from chests within this many metres (0 = off).");
			_leaveAtLeast = ((BaseUnityPlugin)this).Config.Bind<int>("Containers", "LeaveAtLeast", 1, "Without TameAssist: keep at least this many of each food in a chest.");
			_feedWildFromContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("Containers", "FeedWildFromContainers", true, "Wild animals being tamed also eat from chests (TameAssist itself only feeds tamed animals from chests, but deer and necks can't walk to food).");
			_breedCheckSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "CheckSeconds", 30f, "How often each fed tamed animal tries to gain a love point.");
			_loveChance = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "LoveChance", 0.5f, "Chance (0-1) of gaining a love point on each check when a partner is near.");
			_requiredLovePoints = ((BaseUnityPlugin)this).Config.Bind<int>("Breeding", "RequiredLovePoints", 4, "Love points needed to become pregnant.");
			_partnerRange = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "PartnerRange", 5f, "A tamed partner of the same kind must be within this many metres.");
			_populationRange = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "PopulationRange", 15f, "Radius used to count animals of the same kind for MaxCreatures.");
			_maxCreatures = ((BaseUnityPlugin)this).Config.Bind<int>("Breeding", "MaxCreatures", 8, "No new love points when this many animals of the same kind are within PopulationRange. Each animal's own MaxCreatures setting overrides this.");
			_maxTamedNearby = ((BaseUnityPlugin)this).Config.Bind<int>("Breeding", "MaxTamedNearby", 30, "No breeding when this many tamed animals of the same kind are anywhere in the area loaded around players, wherever they wandered (0 = no limit). A safety net for animals that leave the pen, where MaxCreatures only sees their small group.");
			AddSpecies("Deer", "Raspberry,Blueberries,Cloudberry,Carrot,Turnip,Onion,Mushroom,MushroomYellow", 25f, 5f, 10f);
			AddSpecies("Neck", "FishRaw", 25f, 5f, 10f);
			new ConsoleCommand("tamestatus", "[radius] - show server taming/breeding progress of animals near you; use through 'server tamestatus'", new ConsoleEvent(Status), false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			Harmony val = new Harmony("Tie.ServerTaming");
			val.PatchAll(typeof(SavePatch));
			val.PatchAll(typeof(DestroyPatch));
		}

		private void AddSpecies(string prefab, string foods, float taming, float fed, float pregnancy)
		{
			_species.Add(new Species
			{
				Prefab = prefab,
				Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>(prefab, "Enabled", true, "Make " + prefab + " tameable and breedable."),
				Foods = ((BaseUnityPlugin)this).Config.Bind<string>(prefab, "Foods", foods, "Comma-separated item prefab names it eats."),
				TamingMinutes = ((BaseUnityPlugin)this).Config.Bind<float>(prefab, "TamingMinutes", taming, "Minutes of being fed (and calm) needed to tame it."),
				FedMinutes = ((BaseUnityPlugin)this).Config.Bind<float>(prefab, "FedMinutes", fed, "Minutes one food item keeps it fed."),
				Breeding = ((BaseUnityPlugin)this).Config.Bind<bool>(prefab, "Breeding", true, "Tamed ones breed and give birth to tamed adults."),
				PregnancyMinutes = ((BaseUnityPlugin)this).Config.Bind<float>(prefab, "PregnancyMinutes", pregnancy, "Minutes from pregnancy to birth."),
				MaxCreatures = ((BaseUnityPlugin)this).Config.Bind<int>(prefab, "MaxCreatures", -1, "No new love points when this many " + prefab + " are within [Breeding] PopulationRange; -1 uses [Breeding] MaxCreatures.")
			});
		}

		private void Resolve()
		{
			_resolved = true;
			foreach (Species item in _species)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(item.Prefab);
				if (!item.Enabled.Value || (Object)(object)prefab == (Object)null || (Object)(object)prefab.GetComponent<Character>() == (Object)null)
				{
					if (item.Enabled.Value)
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)("Creature prefab '" + item.Prefab + "' not found; it is disabled."));
					}
					continue;
				}
				item.Hash = StringExtensionMethods.GetStableHashCode(item.Prefab);
				item.Name = prefab.GetComponent<Character>().m_name;
				item.View = prefab.GetComponent<ZNetView>();
				foreach (string item2 in from f in item.Foods.Value.Split(new char[1] { ',' })
					select f.Trim() into f
					where f.Length > 0
					select f)
				{
					GameObject prefab2 = ZNetScene.instance.GetPrefab(item2);
					if ((Object)(object)prefab2 == (Object)null || (Object)(object)prefab2.GetComponent<ItemDrop>() == (Object)null)
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)("Food '" + item2 + "' for " + item.Prefab + " is not an item prefab; ignored."));
					}
					else
					{
						item.FoodHashes.Add(StringExtensionMethods.GetStableHashCode(item2));
						_foodPrefabs.Add(StringExtensionMethods.GetStableHashCode(item2));
					}
				}
				_speciesByPrefab[item.Hash] = item;
				((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0}: {1} food(s), taming {2} min, breeding {3}.", item.Prefab, item.FoodHashes.Count, item.TamingMinutes.Value, item.Breeding.Value ? "on" : "off"));
			}
		}

		private void Update()
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				_resolved = false;
				_states.Clear();
				_orphans.Clear();
				_lastTick = -1.0;
				return;
			}
			_timer += Time.deltaTime;
			if (_timer < Mathf.Max(1f, _tickSeconds.Value))
			{
				return;
			}
			_timer = 0f;
			try
			{
				if (!_resolved)
				{
					Resolve();
				}
				Tick();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		private void Tick()
		{
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			double timeSeconds = ZNet.instance.GetTimeSeconds();
			float dt = ((_lastTick < 0.0) ? 0f : Mathf.Clamp((float)(timeSeconds - _lastTick), 0f, Mathf.Max(1f, _tickSeconds.Value) * 3f));
			_lastTick = timeSeconds;
			if (_speciesByPrefab.Count == 0)
			{
				return;
			}
			_feeding = ReadFeeding();
			Collect();
			UpdateChestRanges();
			_eaten.Clear();
			foreach (ZDO animal in _animals)
			{
				Species species = _speciesByPrefab[animal.GetPrefab()];
				State state = GetState(animal);
				bool flag = animal.GetBool(ZDOVars.s_tamed, false);
				if (flag || CanTame(animal))
				{
					bool flag2 = !_requireCalm.Value || !animal.GetBool(ZDOVars.s_alert, false);
					if (timeSeconds >= state.FedUntil)
					{
						TryEat(animal, species, state, timeSeconds, flag);
					}
					bool flag3 = timeSeconds < state.FedUntil;
					if (!flag)
					{
						UpdateTaming(animal, species, state, flag3, flag2, dt);
					}
					else if (species.Breeding.Value)
					{
						UpdateBreeding(animal, species, state, flag3 && flag2, timeSeconds);
					}
				}
			}
			if (++_ticks % 60 != 0)
			{
				return;
			}
			foreach (ZDOID item in _states.Keys.Where((ZDOID id) => ZDOMan.instance.GetZDO(id) == null).ToList())
			{
				_states.Remove(item);
			}
		}

		private void Collect()
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: 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)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			_animals.Clear();
			_foods.Clear();
			_chests.Clear();
			_signs.Clear();
			_seen.Clear();
			SimulationDistance syncedSimulationDistance = ZNet.instance.GetSyncedSimulationDistance();
			SimulationDistance val = default(SimulationDistance);
			((SimulationDistance)(ref val))..ctor(((SimulationDistance)(ref syncedSimulationDistance)).NearSimulationDistance, 0, ((SimulationDistance)(ref syncedSimulationDistance)).IsClassic);
			List<Vector3> list = (from p in ZNet.instance.GetPeers()
				select p.GetRefPos()).ToList();
			if (!ZNet.instance.IsDedicated())
			{
				list.Add(ZNet.instance.GetReferencePosition());
			}
			foreach (Vector3 item in list)
			{
				_sectorObjects.Clear();
				ZDOMan.instance.FindSectorObjects(ZoneSystem.GetZone(item), val, _sectorObjects, (List<ZDO>)null);
				foreach (ZDO sectorObject in _sectorObjects)
				{
					if (!sectorObject.IsValid() || !_seen.Add(sectorObject.m_uid))
					{
						continue;
					}
					int prefab = sectorObject.GetPrefab();
					if (_speciesByPrefab.ContainsKey(prefab))
					{
						_animals.Add(sectorObject);
					}
					else if (_foodPrefabs.Contains(prefab) && !sectorObject.GetBool(ZDOVars.s_piece, false))
					{
						_foods.Add(sectorObject);
					}
					else if (_feeding.Containers)
					{
						switch (Classify(prefab))
						{
						case PrefabKind.Chest:
							_chests.Add(sectorObject);
							break;
						case PrefabKind.Sign:
							_signs.Add(sectorObject);
							break;
						}
					}
				}
			}
		}

		private State GetState(ZDO zdo)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			if (!_states.TryGetValue(zdo.m_uid, out var value) && (value = Adopt(zdo)) == null)
			{
				value = new State
				{
					TameLeft = zdo.GetFloat(KeyTameLeft, -1f),
					FedUntil = (double)zdo.GetLong(KeyFedUntil, 0L) / 1000.0,
					Love = zdo.GetInt(KeyLove, 0),
					Pregnant = (double)zdo.GetLong(KeyPregnant, 0L) / 1000.0
				};
				_states[zdo.m_uid] = value;
			}
			return value;
		}

		private void Orphaned(ZDO zdo)
		{
			//IL_0007: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			if (_states.TryGetValue(zdo.m_uid, out var value))
			{
				_states.Remove(zdo.m_uid);
				_orphans.RemoveAll((Orphan o) => Time.time - o.At > 60f);
				_orphans.Add(new Orphan
				{
					Prefab = zdo.GetPrefab(),
					Pos = zdo.GetPosition(),
					Level = zdo.GetInt(ZDOVars.s_level, 1),
					At = Time.time,
					From = zdo.m_uid,
					State = value
				});
			}
		}

		private State Adopt(ZDO zdo)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_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)
			if (_orphans.Count == 0)
			{
				return null;
			}
			int prefab = zdo.GetPrefab();
			int level = zdo.GetInt(ZDOVars.s_level, 1);
			Vector3 pos = zdo.GetPosition();
			Orphan orphan = _orphans.Where(delegate(Orphan o)
			{
				//IL_0030: 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_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				if (o.Prefab == prefab && o.Level == level && Time.time - o.At <= 60f)
				{
					Vector3 val = o.Pos - pos;
					return ((Vector3)(ref val)).sqrMagnitude <= 100f;
				}
				return false;
			}).OrderBy(delegate(Orphan o)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: 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)
				Vector3 val = o.Pos - pos;
				return ((Vector3)(ref val)).sqrMagnitude;
			}).FirstOrDefault();
			if (orphan == null)
			{
				return null;
			}
			_orphans.Remove(orphan);
			_states[zdo.m_uid] = orphan.State;
			Debug($"{zdo.m_uid}: took over the state of replaced {orphan.From} (level {level}).");
			return orphan.State;
		}

		private string Describe(ZDO zdo)
		{
			//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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = zdo.GetPosition();
			return string.Format("{0} {1} ({2} star(s), {3}, owner {4}) at ({5:0}, {6:0}, {7:0})", _speciesByPrefab[zdo.GetPrefab()].Prefab, zdo.m_uid, zdo.GetInt(ZDOVars.s_level, 1) - 1, zdo.GetBool(ZDOVars.s_tamed, false) ? "tamed" : "wild", zdo.GetOwner(), position.x, position.y, position.z);
		}

		private void Debug(string text)
		{
			if (_debugLog.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)text);
			}
		}

		private PrefabKind Classify(int prefab)
		{
			if (!_kinds.TryGetValue(prefab, out var value))
			{
				GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab);
				value = ((!((Object)(object)prefab2 == (Object)null)) ? (((Object)(object)prefab2.GetComponent<Container>() != (Object)null && (Object)(object)prefab2.GetComponent<Piece>() != (Object)null) ? PrefabKind.Chest : (((Object)(object)prefab2.GetComponent<Sign>() != (Object)null) ? PrefabKind.Sign : PrefabKind.Other)) : PrefabKind.Other);
				_kinds[prefab] = value;
			}
			return value;
		}

		private Feeding ReadFeeding()
		{
			Feeding feeding = new Feeding();
			List<ConfigFile> list = ((!_useTameAssist.Value || !Chainloader.PluginInfos.ContainsKey("ArgusMagnus.ServersideQoL.TameAssist")) ? null : (from i in Chainloader.PluginInfos.Values
				where i.Metadata.GUID.StartsWith("ArgusMagnus.ServersideQoL", StringComparison.Ordinal) && (Object)(object)i.Instance != (Object)null
				select i.Instance.Config).ToList());
			if (list != null && Get(list, "Enabled", fallback: true))
			{
				feeding.FromTameAssist = true;
				feeding.Containers = Get(list, "FeedFromContainers", fallback: false);
				feeding.Range = Get(list, "FeedFromContainersRange", 0f);
				feeding.MaxRange = Get(list, "FeedFromContainersMaxRange", 64);
				feeding.LeaveAtLeast = Get(list, "FeedFromContainersLeaveAtLeast", 1);
				feeding.TamingMultiplier = Get(list, "TamingTimeMultiplier", 1f);
				feeding.FedMultiplier = Get(list, "FedDurationMultiplier", 1f);
				feeding.ProgressMessageType = Get(list, "TamingProgressMessageType", (object)"").ToString();
				string text = Get(list, "FeedFromContainersRangeSignPrefix", "");
				string text2 = text.Replace("\ufe0f", "");
				if (text.Length > 0)
				{
					feeding.SignRange = new Regex(((text == text2) ? Regex.Escape(text) : ("(?:" + Regex.Escape(text) + "|" + Regex.Escape(text2) + ")")) + "(?<R>\\d+)");
				}
			}
			else
			{
				feeding.Range = _containerRange.Value;
				feeding.Containers = feeding.Range > 0f;
				feeding.LeaveAtLeast = _leaveAtLeast.Value;
			}
			return feeding;
		}

		private static T Get<T>(List<ConfigFile> configs, string key, T fallback)
		{
			foreach (ConfigFile config in configs)
			{
				foreach (ConfigDefinition key2 in config.Keys)
				{
					if (key2.Key == key && (key2.Section == "TameAssist" || key2.Section.EndsWith(".TameAssist", StringComparison.Ordinal)))
					{
						object boxedValue = config[key2].BoxedValue;
						if (boxedValue is T)
						{
							return (T)boxedValue;
						}
					}
				}
			}
			return fallback;
		}

		private void UpdateChestRanges()
		{
			//IL_004f: 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_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			_chestRanges.Clear();
			if (!_feeding.Containers)
			{
				return;
			}
			foreach (ZDO chest in _chests)
			{
				int? num = SignRange(chest);
				if (num.HasValue)
				{
					int valueOrDefault = num.GetValueOrDefault();
					_chestRanges[chest.m_uid] = Mathf.Min(valueOrDefault, _feeding.MaxRange);
				}
				else if (_feeding.Range > 0f)
				{
					_chestRanges[chest.m_uid] = _feeding.Range;
				}
			}
			foreach (ZDO sign in _signs)
			{
				int? num = SignRange(sign);
				if (num.HasValue)
				{
					int valueOrDefault2 = num.GetValueOrDefault();
					Vector3 pos = sign.GetPosition();
					ZDO val = _chests.Where(delegate(ZDO c)
					{
						//IL_0001: Unknown result type (might be due to invalid IL or missing references)
						//IL_0007: Unknown result type (might be due to invalid IL or missing references)
						//IL_000c: 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)
						Vector3 val2 = c.GetPosition() - pos;
						return ((Vector3)(ref val2)).sqrMagnitude <= 9f;
					}).OrderBy(delegate(ZDO c)
					{
						//IL_0001: Unknown result type (might be due to invalid IL or missing references)
						//IL_0007: Unknown result type (might be due to invalid IL or missing references)
						//IL_000c: 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)
						Vector3 val2 = c.GetPosition() - pos;
						return ((Vector3)(ref val2)).sqrMagnitude;
					}).FirstOrDefault();
					if (val != null && !SignRange(val).HasValue)
					{
						_chestRanges[val.m_uid] = Mathf.Min(valueOrDefault2, _feeding.MaxRange);
					}
				}
			}
		}

		private int? SignRange(ZDO zdo)
		{
			if (_feeding.SignRange == null)
			{
				return null;
			}
			Match match = _feeding.SignRange.Match(zdo.GetString(ZDOVars.s_text, ""));
			if (!match.Success || !int.TryParse(match.Groups["R"].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return null;
			}
			return result;
		}

		private float TamingSeconds(Species s)
		{
			return Mathf.Max(1f, s.TamingMinutes.Value * 60f * _feeding.TamingMultiplier);
		}

		private void TryEat(ZDO animal, Species s, State st, double now, bool tamed)
		{
			string text = (TryEatFromGround(animal, s) ? "the ground" : (((tamed || _feedWildFromContainers.Value) && TryEatFromChest(animal, s)) ? "a chest" : null));
			if (text != null)
			{
				st.FedUntil = now + (double)s.FedMinutes.Value * 60.0 * (double)_feeding.FedMultiplier;
			}
			if (_debugLog.Value)
			{
				Debug(Describe(animal) + " is hungry: " + ((text != null) ? ("ate from " + text + ".") : $"no food found ({_chests.Count((ZDO c) => _chestRanges.ContainsKey(c.m_uid))} feeding chest(s) loaded)."));
			}
		}

		private bool TryEatFromChest(ZDO animal, Species s)
		{
			//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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			if (!_feeding.Containers)
			{
				return false;
			}
			Vector3 pos = animal.GetPosition();
			foreach (ZDO item in _chests.OrderBy(delegate(ZDO c)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: 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)
				Vector3 val2 = c.GetPosition() - pos;
				return ((Vector3)(ref val2)).sqrMagnitude;
			}))
			{
				if (_chestRanges.TryGetValue(item.m_uid, out var value))
				{
					Vector3 val = item.GetPosition() - pos;
					if (((Vector3)(ref val)).sqrMagnitude <= value * value && TakeOneFood(item, s.FoodHashes, _feeding.LeaveAtLeast))
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool TakeOneFood(ZDO chest, HashSet<int> foods, int leaveAtLeast)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			if (chest.GetBool(ZDOVars.s_inUse, false))
			{
				return false;
			}
			byte[] byteArray = chest.GetByteArray(ZDOVars.s_items, (byte[])null);
			if (byteArray == null || byteArray.Length == 0)
			{
				return false;
			}
			List<(int, int, int, int)> list = new List<(int, int, int, int)>();
			int num2;
			byte[] array;
			try
			{
				ZPackage val = new ZPackage(byteArray);
				int num = val.ReadInt();
				if (num < 108)
				{
					return false;
				}
				num2 = val.ReadUShort();
				for (int i = 0; i < num2; i++)
				{
					int pos = val.GetPos();
					ItemData val2 = new ItemData();
					int item = ItemData.Load(val, val2, (Item)num);
					list.Add((pos, val.GetPos(), item, val2.m_stack));
				}
				array = val.GetArray();
			}
			catch (Exception)
			{
				return false;
			}
			foreach (int food in foods)
			{
				List<(int, int, int, int)> list2 = (from x in list
					where x.Hash == food && x.Stack > 0
					orderby x.Stack
					select x).ToList();
				if (list2.Sum<(int, int, int, int)>(((int Start, int End, int Hash, int Stack) x) => x.Stack) - 1 >= Math.Max(0, leaveAtLeast))
				{
					(int, int, int, int) tuple = list2[0];
					byte b = array[tuple.Item1 + 7];
					byte[] array2;
					if (tuple.Item4 > 1 && (b & 8) != 0)
					{
						array2 = (byte[])array.Clone();
						int num3 = tuple.Item1 + 8 + (((b & 4) != 0) ? 2 : 0);
						ushort num4 = (ushort)(tuple.Item4 - 1);
						array2[num3] = (byte)(num4 & 0xFF);
						array2[num3 + 1] = (byte)(num4 >> 8);
					}
					else
					{
						array2 = new byte[array.Length - (tuple.Item2 - tuple.Item1)];
						Buffer.BlockCopy(array, 0, array2, 0, tuple.Item1);
						Buffer.BlockCopy(array, tuple.Item2, array2, tuple.Item1, array.Length - tuple.Item2);
						ushort num5 = (ushort)(num2 - 1);
						array2[4] = (byte)(num5 & 0xFF);
						array2[5] = (byte)(num5 >> 8);
					}
					if (!chest.IsOwner())
					{
						chest.SetOwner(ZDOMan.GetSessionID());
					}
					chest.Set(ZDOVars.s_items, array2);
					return true;
				}
			}
			return false;
		}

		private bool TryEatFromGround(ZDO animal, Species s)
		{
			//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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_0070: 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_008a: 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)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = animal.GetPosition();
			float num = _feedRadius.Value * _feedRadius.Value;
			ZDO val = null;
			foreach (ZDO food in _foods)
			{
				if (!s.FoodHashes.Contains(food.GetPrefab()) || _eaten.Contains(food.m_uid))
				{
					continue;
				}
				Vector3 val2 = food.GetPosition() - position;
				if (!(Mathf.Abs(val2.y) > 4f))
				{
					float num2 = val2.x * val2.x + val2.z * val2.z;
					if (num2 <= num)
					{
						num = num2;
						val = food;
					}
				}
			}
			if (val == null)
			{
				return false;
			}
			if (!val.IsOwner())
			{
				val.SetOwner(ZDOMan.GetSessionID());
			}
			int num3 = val.GetInt(ZDOVars.s_stack, 1);
			if (num3 > 1)
			{
				val.Set(ZDOVars.s_stack, num3 - 1, false);
			}
			else
			{
				_eaten.Add(val.m_uid);
				ZDOMan.instance.DestroyZDO(val);
			}
			return true;
		}

		private void UpdateTaming(ZDO zdo, Species s, State st, bool fed, bool calm, float dt)
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			float num = TamingSeconds(s);
			if (st.TameLeft < 0f || st.TameLeft > num)
			{
				st.TameLeft = num;
			}
			if (fed && calm && st.TameLeft > 0f)
			{
				int num2 = Step(st.TameLeft, num);
				st.TameLeft = Mathf.Max(0f, st.TameLeft - dt);
				int num3 = Step(st.TameLeft, num);
				if (_progressMessages.Value && !_feeding.FromTameAssist && num3 > num2 && num3 < 4)
				{
					Message(zdo.GetPosition(), (MessageType)1, $"{s.Name}: taming {num3 * 25}%");
				}
			}
			if (_progressMessages.Value && _feeding.FromTameAssist && st.TameLeft > 0f && st.TameLeft < num)
			{
				string text = string.Format(fed ? "$hud_tameness {0:P0}" : "$hud_tameness {0:P0}, $hud_tamehungry", 1f - st.TameLeft / num);
				TameAssistMessage(zdo.GetPosition(), text);
			}
			if (st.TameLeft <= 0f)
			{
				Tame(zdo, s, st);
			}
		}

		private bool CanTame(ZDO zdo)
		{
			if (_maxTameStars.Value >= 0)
			{
				return zdo.GetInt(ZDOVars.s_level, 1) - 1 <= _maxTameStars.Value;
			}
			return true;
		}

		private static int Step(float left, float total)
		{
			return (int)((1f - left / total) * 4f);
		}

		private void Tame(ZDO zdo, Species s, State st)
		{
			//IL_0027: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			long owner = zdo.GetOwner();
			if (owner == 0L || owner == ZDOMan.GetSessionID())
			{
				zdo.Set(ZDOVars.s_tamed, true);
			}
			else
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(owner, zdo.m_uid, "RPC_SetTamed", new object[1] { true });
			}
			if (!st.TameAnnounced)
			{
				st.TameAnnounced = true;
				Message(zdo.GetPosition(), (MessageType)2, s.Name + " $hud_tamedone");
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Tamed " + s.Prefab + " at " + Format(zdo.GetPosition()) + "."));
			}
		}

		private void UpdateBreeding(ZDO zdo, Species s, State st, bool ready, double now)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			if (st.Pregnant > 0.0)
			{
				if (now - st.Pregnant >= (double)s.PregnancyMinutes.Value * 60.0)
				{
					st.Pregnant = 0.0;
					string text = Crowded(zdo, s, atBirth: true);
					if (text != null)
					{
						((BaseUnityPlugin)this).Logger.LogInfo((object)(s.Prefab + " birth at " + Format(zdo.GetPosition()) + " skipped: " + text + "."));
					}
					else
					{
						Birth(zdo, s);
					}
				}
			}
			else
			{
				if (!ready || now < st.NextBreedCheck)
				{
					return;
				}
				float num = Mathf.Max(1f, _breedCheckSeconds.Value);
				st.NextBreedCheck = now + (double)(num * Random.Range(1f, 1.5f));
				if (Random.value > _loveChance.Value)
				{
					return;
				}
				string text2 = Crowded(zdo, s, atBirth: false);
				if (text2 != null)
				{
					Debug(Describe(zdo) + ": no love point (" + text2 + ").");
					return;
				}
				Debug($"{Describe(zdo)}: love {st.Love + 1}/{Mathf.Max(1, _requiredLovePoints.Value)}.");
				if (++st.Love >= Mathf.Max(1, _requiredLovePoints.Value))
				{
					st.Love = 0;
					st.Pregnant = now;
				}
			}
		}

		private string Crowded(ZDO zdo, Species s, bool atBirth)
		{
			//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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: 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)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = zdo.GetPosition();
			float num = _populationRange.Value * _populationRange.Value;
			float num2 = _partnerRange.Value * _partnerRange.Value;
			int num3 = 0;
			int num4 = 0;
			bool flag = false;
			foreach (ZDO animal in _animals)
			{
				if (animal.GetPrefab() != s.Hash)
				{
					continue;
				}
				bool flag2 = animal.GetBool(ZDOVars.s_tamed, false);
				if (flag2)
				{
					num4++;
				}
				Vector3 val = animal.GetPosition() - position;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				if (sqrMagnitude <= num)
				{
					num3++;
					if (!atBirth && animal != zdo && _states.TryGetValue(animal.m_uid, out var value) && value.Pregnant > 0.0)
					{
						num3++;
					}
				}
				if (animal != zdo && sqrMagnitude <= num2 && flag2)
				{
					flag = true;
				}
			}
			int num5 = ((s.MaxCreatures.Value >= 0) ? s.MaxCreatures.Value : _maxCreatures.Value);
			if (!atBirth && !flag)
			{
				return "no tamed partner in range";
			}
			if (num3 >= num5)
			{
				return string.Format("{0} of MaxCreatures {1} nearby{2}", num3, num5, atBirth ? "" : ", counting pregnancies");
			}
			if (_maxTamedNearby.Value > 0 && num4 >= _maxTamedNearby.Value)
			{
				return $"{num4} tamed {s.Prefab} around players, MaxTamedNearby {_maxTamedNearby.Value}";
			}
			return null;
		}

		private void Birth(ZDO parent, Species s)
		{
			//IL_001b: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 mother = parent.GetPosition();
			ZDO val = _animals.Where(delegate(ZDO a)
			{
				//IL_002b: 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_003b: Unknown result type (might be due to invalid IL or missing references)
				if (a != parent && a.GetPrefab() == s.Hash && a.GetBool(ZDOVars.s_tamed, false))
				{
					Vector3 val4 = a.GetPosition() - mother;
					return ((Vector3)(ref val4)).sqrMagnitude <= 100f;
				}
				return false;
			}).OrderBy(delegate(ZDO a)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: 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)
				Vector3 val4 = a.GetPosition() - mother;
				return ((Vector3)(ref val4)).sqrMagnitude;
			}).FirstOrDefault();
			Vector3 val2 = ((val == null) ? mother : Vector3.Lerp(mother, val.GetPosition(), Random.Range(0.3f, 0.7f)));
			val2.y += 0.5f;
			ZDO val3 = ZDOMan.instance.CreateNewZDO(val2, s.Hash);
			val3.Persistent = s.View.m_persistent;
			val3.Type = s.View.m_type;
			val3.Distant = s.View.m_distant;
			val3.SetPrefab(s.Hash);
			val3.SetRotation(Quaternion.Euler(0f, Random.Range(0f, 360f), 0f));
			val3.Set(ZDOVars.s_tamed, true);
			int num = parent.GetInt(ZDOVars.s_level, 1);
			if (num > 1)
			{
				val3.Set(ZDOVars.s_level, num, false);
			}
			val3.SetOwner(0L);
			Message(val2, (MessageType)2, "A new " + s.Name + " was born");
			((BaseUnityPlugin)this).Logger.LogInfo((object)(s.Prefab + " born at " + Format(val2) + "."));
		}

		private void TameAssistMessage(Vector3 pos, string text)
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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)
			//IL_006d: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			string progressMessageType = _feeding.ProgressMessageType;
			if (progressMessageType == "InWorld")
			{
				float num = _messageRange.Value * _messageRange.Value;
				{
					foreach (ZNetPeer peer in ZNet.instance.GetPeers())
					{
						Vector3 val = peer.GetRefPos() - pos;
						if (((Vector3)(ref val)).sqrMagnitude <= num)
						{
							ZPackage val2 = new ZPackage();
							val2.Write(0);
							val2.Write(pos);
							val2.Write(text);
							val2.Write(false);
							ZRoutedRpc.instance.InvokeRoutedRPC(peer.m_uid, "RPC_DamageText", new object[1] { val2 });
						}
					}
					return;
				}
			}
			if (progressMessageType.StartsWith("TopLeft", StringComparison.Ordinal))
			{
				Message(pos, (MessageType)1, text);
			}
			else if (progressMessageType.StartsWith("Center", StringComparison.Ordinal))
			{
				Message(pos, (MessageType)2, text);
			}
		}

		private void Message(Vector3 pos, MessageType type, string text)
		{
			//IL_0033: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected I4, but got Unknown
			float num = _messageRange.Value * _messageRange.Value;
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				Vector3 val = peer.GetRefPos() - pos;
				if (((Vector3)(ref val)).sqrMagnitude <= num)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(peer.m_uid, "ShowMessage", new object[2]
					{
						(int)type,
						text
					});
				}
			}
		}

		private void WriteToZdos()
		{
			//IL_0020: 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_004f: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<ZDOID, State> state in _states)
			{
				if (ZDOMan.instance.GetZDO(state.Key) != null)
				{
					ZDOExtraData.Set(state.Key, KeyTameLeft, state.Value.TameLeft);
					ZDOExtraData.Set(state.Key, KeyFedUntil, (long)(state.Value.FedUntil * 1000.0));
					ZDOExtraData.Set(state.Key, KeyLove, state.Value.Love);
					ZDOExtraData.Set(state.Key, KeyPregnant, (long)(state.Value.Pregnant * 1000.0));
				}
			}
		}

		private void Status(ConsoleEventArgs args)
		{
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_045e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0496: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a1: Unknown result type (might be due to invalid IL or missing references)
			Terminal context = args.Context;
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				Print(context, "tamestatus must run on the server: type 'server tamestatus' instead.");
				return;
			}
			float radius = 30f;
			if (args.Args.Length > 1 && float.TryParse(args.Args[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && result > 0f)
			{
				radius = result;
			}
			Vector3? center = CallerPosition();
			if (!center.HasValue)
			{
				Print(context, "Could not find your position.");
				return;
			}
			if (!_resolved)
			{
				Resolve();
			}
			_feeding = ReadFeeding();
			Collect();
			UpdateChestRanges();
			double timeSeconds = ZNet.instance.GetTimeSeconds();
			List<ZDO> list = _animals.Where(delegate(ZDO z)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: 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)
				Vector3 val = z.GetPosition() - center.Value;
				return ((Vector3)(ref val)).sqrMagnitude <= radius * radius;
			}).OrderBy(delegate(ZDO z)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: 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)
				Vector3 val = z.GetPosition() - center.Value;
				return ((Vector3)(ref val)).sqrMagnitude;
			}).ToList();
			Print(context, $"{list.Count} tameable animal(s) within {radius:0} m.");
			foreach (ZDO item in list.Take(20))
			{
				Species species = _speciesByPrefab[item.GetPrefab()];
				State state = GetState(item);
				float num = Vector3.Distance(item.GetPosition(), center.Value);
				string text = ((timeSeconds < state.FedUntil) ? $"fed {(state.FedUntil - timeSeconds) / 60.0:0.0} min" : "hungry");
				int num2 = item.GetInt(ZDOVars.s_level, 1) - 1;
				string text2;
				if (!item.GetBool(ZDOVars.s_tamed, false) && !CanTame(item))
				{
					text2 = $"wild, {num2} star(s): above MaxTameStars, cannot be tamed";
				}
				else if (!item.GetBool(ZDOVars.s_tamed, false))
				{
					float num3 = TamingSeconds(species);
					float num4 = ((state.TameLeft < 0f) ? num3 : state.TameLeft);
					text2 = $"wild, taming {(1f - num4 / num3) * 100f:0}% ({num4 / 60f:0.0} min left), {text}";
				}
				else
				{
					text2 = ((!(state.Pregnant > 0.0)) ? $"tamed, love {state.Love}/{_requiredLovePoints.Value}, {text}" : $"tamed, pregnant ({((double)species.PregnancyMinutes.Value * 60.0 - (timeSeconds - state.Pregnant)) / 60.0:0.0} min left), {text}");
				}
				Print(context, $"{species.Prefab} {new string('*', Math.Max(0, num2))} {num:0} m: {text2}");
			}
			Print(context, string.Format("Chest feeding: {0}{1}, global range {2:0} m, leave at least {3}, wild animals {4}.", _feeding.Containers ? "on" : "off", _feeding.FromTameAssist ? " (TameAssist settings)" : "", _feeding.Range, _feeding.LeaveAtLeast, _feedWildFromContainers.Value ? "yes" : "no"));
			HashSet<int> foods = new HashSet<int>(_species.SelectMany((Species x) => x.FoodHashes));
			foreach (ZDO item2 in _chests.Where(delegate(ZDO c)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: 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)
				Vector3 val = c.GetPosition() - center.Value;
				return ((Vector3)(ref val)).sqrMagnitude <= (radius + 64f) * (radius + 64f);
			}).OrderBy(delegate(ZDO c)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: 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)
				Vector3 val = c.GetPosition() - center.Value;
				return ((Vector3)(ref val)).sqrMagnitude;
			}).Take(10))
			{
				float value;
				string text3 = (_chestRanges.TryGetValue(item2.m_uid, out value) ? $"range {value:0} m" : "no range (no sign number, global range 0)");
				Print(context, string.Format("Chest {0:0} m: {1}, {2}food: {3}", Vector3.Distance(item2.GetPosition(), center.Value), text3, item2.GetBool(ZDOVars.s_inUse, false) ? "OPEN (skipped), " : "", DescribeFood(item2, foods)));
			}
		}

		private static string DescribeFood(ZDO chest, HashSet<int> foods)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			byte[] byteArray = chest.GetByteArray(ZDOVars.s_items, (byte[])null);
			if (byteArray == null || byteArray.Length == 0)
			{
				return "empty";
			}
			try
			{
				ZPackage val = new ZPackage(byteArray);
				int num = val.ReadInt();
				if (num < 108)
				{
					return $"old inventory format {num}, skipped";
				}
				int num2 = val.ReadUShort();
				Dictionary<int, int> dictionary = new Dictionary<int, int>();
				for (int i = 0; i < num2; i++)
				{
					ItemData val2 = new ItemData();
					int num3 = ItemData.Load(val, val2, (Item)num);
					if (foods.Contains(num3))
					{
						dictionary[num3] = (dictionary.TryGetValue(num3, out var value) ? value : 0) + val2.m_stack;
					}
				}
				return (dictionary.Count == 0) ? $"none ({num2} other item stacks)" : string.Join(", ", dictionary.Select(delegate(KeyValuePair<int, int> x)
				{
					GameObject prefab = ZNetScene.instance.GetPrefab(x.Key);
					return (((prefab != null) ? ((Object)prefab).name : null) ?? x.Key.ToString(CultureInfo.InvariantCulture)) + " " + x.Value;
				}));
			}
			catch (Exception ex)
			{
				return "unreadable (" + ex.Message + ")";
			}
		}

		private static Vector3? CallerPosition()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			object obj = AccessTools.TypeByName("ServerDevcommands.RedirectOutput")?.GetField("Target", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
			ZRpc rpc = (ZRpc)((obj is ZRpc) ? obj : null);
			if (rpc == null)
			{
				return null;
			}
			ZNetPeer? obj2 = ((IEnumerable<ZNetPeer>)ZNet.instance.GetPeers()).FirstOrDefault((Func<ZNetPeer, bool>)((ZNetPeer p) => p.m_rpc == rpc));
			if (obj2 == null)
			{
				return null;
			}
			return obj2.GetRefPos();
		}

		private static void Print(Terminal output, string text)
		{
			object obj = ((object)output) ?? ((object)Console.instance);
			if (obj != null)
			{
				((Terminal)obj).AddString(text);
			}
		}

		private static string Format(Vector3 pos)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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)
			return $"({pos.x:0}, {pos.y:0}, {pos.z:0})";
		}
	}
}