Decompiled source of SaerimnerBallista v0.7.2

SaerimnerBallista.dll

Decompiled 6 days ago
using System;
using System.Collections;
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.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: AssemblyCompany("SaerimnerBallista")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SaerimnerBallista")]
[assembly: AssemblyTitle("SaerimnerBallista")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 SaerimnerBallista
{
	[BepInPlugin("SaerimnerBallista", "SaerimnerBallista", "0.7.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string ModGuid = "SaerimnerBallista";

		public const string ModName = "SaerimnerBallista";

		public const string ModVersion = "0.7.2";

		internal const string TrophyId = "TrophyUllr_SB";

		internal const string FlagKey = "SB_Ullr";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> UllrTrophy;

		internal static ConfigEntry<bool> AllBallistasHostilesOnly;

		internal static ConfigEntry<bool> BlockFriendlyBolts;

		internal static ConfigEntry<bool> RefillFromChests;

		internal static ConfigEntry<float> RefillRange;

		internal static ConfigEntry<bool> UnlimitedAmmo;

		internal static ConfigEntry<string> UnlimitedAmmoType;

		internal static ConfigEntry<float> TuneRange;

		internal static ConfigEntry<float> TuneScanArc;

		internal static ConfigEntry<float> TuneSweepInterval;

		internal static ConfigEntry<float> TuneTurnRate;

		internal static ConfigEntry<float> TuneMaxAmmo;

		internal static ConfigEntry<float> TuneMaxTrophies;

		internal static ConfigEntry<string> TrophyModel;

		internal static ConfigEntry<string> TrophyRotation;

		internal static ConfigEntry<string> TrophyOffset;

		internal static ConfigEntry<float> TrophyScale;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			UllrTrophy = Bind("1 - Ullr Trophy", "Enabled", def: true, "Possibility 1 (default). The Ullr Trophy (based on the Skeleton Trophy, no default drop, spawn it with 'spawn TrophyUllr_SB'). Use the trophy on a ballista, like any trophy: that ballista then only shoots at hostile creatures, never at players or tamed animals. Use the trophy on it again to take the blessing away. The item itself always exists (so the server and the players match); this setting only decides whether the trophy does anything. On a server, the server's value is used.");
			AllBallistasHostilesOnly = Bind("2 - Hostiles only", "All ballistas", def: false, "Possibility 2. Every ballista only shoots at hostile creatures, never at players or tamed animals, without any trophy. Default off.");
			BlockFriendlyBolts = Bind("2 - Hostiles only", "Bolts pass through friends", def: true, "A ballista that is hostiles-only (by the trophy or by 'All ballistas') also does not hurt players and tamed animals that stand in the way of its bolts.");
			RefillFromChests = Bind("3 - Chest refill", "Enabled", def: true, "When a ballista has run out of ammo, it takes ammo (that it accepts) from a chest nearby and is filled up again. On by default. Works with any chest, also one with a lock or a ward.");
			RefillRange = Bind("3 - Chest refill", "Range (meters)", 10f, "How far from the ballista a chest can be, in meters. Default 10.");
			UnlimitedAmmo = Bind("4 - Unlimited ammo", "Enabled", def: false, "Every ballista has unlimited ammo: it is filled up again all the time, and it needs no ammo item at all (it uses the kind it used last, or its default). Default off. With this on, the chest refill is not used.");
			UnlimitedAmmoType = Bind("4 - Unlimited ammo", "Ammo", "", "Which ammo the ballistas have when unlimited ammo is on: the prefab name of the ammo, for example TurretBoltWood. The vanilla ballista accepts TurretBolt, TurretBoltWood, TurretBoltFlametal and TurretBoltBloodgold (the log lists what yours accepts). Empty: the kind that the ballista used last, or its default. A name that the ballista does not accept is ignored (the log says so).");
			TuneRange = Bind("5 - Tuning", "Range (meters)", 0f, "How far a ballista sees and shoots, in meters. 0 = as the game has it.");
			TuneScanArc = Bind("5 - Tuning", "Scan arc (degrees)", 0f, "The total angle a ballista sweeps through when it has no target (at most 178). 0 = as the game has it.");
			TuneSweepInterval = Bind("5 - Tuning", "Sweep interval (seconds)", 0f, "How long one sweep back and forth takes when it has no target. 0 = as the game has it.");
			TuneTurnRate = Bind("5 - Tuning", "Turn rate", 0f, "How fast a ballista turns when it has no target. 0 = as the game has it.");
			TuneMaxAmmo = Bind("5 - Tuning", "Maximum ammo", 0f, "How much ammo a ballista can hold. 0 = as the game has it (40). Also used by the chest refill and by unlimited ammo.");
			TuneMaxTrophies = Bind("5 - Tuning", "Maximum target trophies", 0f, "How many (vanilla) trophies can be loaded to choose what a ballista shoots at. 0 = as the game has it.");
			TrophyModel = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Look", "Trophy model", "Viking", "What the Ullr Trophy looks like: Viking (the head of a Viking with a helmet and a braided beard, made for this mod) or Skeleton (the Skeleton Trophy that it is made from). Only what you see, so it is not synced from the server. Needs a restart. Default Viking.");
			TrophyScale = ((BaseUnityPlugin)this).Config.Bind<float>("6 - Look", "Trophy model scale", 1f, "How big the head is, 1 = as made (about 0.36 m high). Needs a restart. Default 1.");
			TrophyOffset = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Look", "Trophy model offset (meters x,y,z)", "0,0,0", "Moves the head, for example 0,-0.03,0 to lower it 3 cm on a trophy mount (the middle of the head is where the trophy is held). Needs a restart. Default 0,0,0.");
			TrophyRotation = ((BaseUnityPlugin)this).Config.Bind<string>("6 - Look", "Trophy model rotation (degrees x,y,z)", "0,0,0", "Turns the head, for example 0,180,0 if it faces the wrong way on a trophy stand. Needs a restart. Default 0,0,0.");
			PrefabManager.OnVanillaPrefabsAvailable += AddTrophy;
			harmony = new Harmony("SaerimnerBallista");
			Patches.Install(harmony);
			ChestRefill.Install(harmony);
			Log.LogInfo((object)string.Format("{0} {1} loaded (Ullr Trophy: {2}, all ballistas hostiles only: {3}, chest refill: {4}, unlimited ammo: {5})", "SaerimnerBallista", "0.7.2", UllrTrophy.Value, AllBallistasHostilesOnly.Value, RefillFromChests.Value, UnlimitedAmmo.Value));
		}

		private void OnDestroy()
		{
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private ConfigEntry<T> Bind<T>(string section, string key, T def, string desc)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			return ((BaseUnityPlugin)this).Config.Bind<T>(section, key, def, new ConfigDescription(desc, (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
		}

		private void AddTrophy()
		{
			//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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable -= AddTrophy;
			try
			{
				ItemConfig val = new ItemConfig
				{
					Name = "Ullr Trophy",
					Description = "A trophy of Ullr, the god of the hunt. Use it on a ballista, and the ballista only shoots at the hostile."
				};
				CustomItem val2 = new CustomItem("TrophyUllr_SB", "TrophySkeleton", val);
				ApplyArtwork(val2);
				ItemManager.Instance.AddItem(val2);
				Log.LogInfo((object)"Added the Ullr Trophy (TrophyUllr_SB)");
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Could not add the Ullr Trophy: " + ex.Message));
			}
		}

		private static bool LoadImage(Texture2D texture, byte[] bytes)
		{
			Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule");
			MethodInfo methodInfo = ((type != null) ? type.GetMethod("LoadImage", new Type[2]
			{
				typeof(Texture2D),
				typeof(byte[])
			}) : null);
			if (methodInfo == null)
			{
				Log.LogWarning((object)"UnityEngine.ImageConversion.LoadImage was not found: the Ullr Trophy's own pictures cannot be read");
				return false;
			}
			return (bool)methodInfo.Invoke(null, new object[2] { texture, bytes });
		}

		private static byte[] ReadAsset(string folder, string ownFile, string embeddedName)
		{
			string path = Path.Combine(folder, ownFile);
			if (File.Exists(path))
			{
				return File.ReadAllBytes(path);
			}
			if (embeddedName == null)
			{
				return null;
			}
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(embeddedName);
			if (stream == null)
			{
				return null;
			}
			byte[] array = new byte[stream.Length];
			int num;
			for (int i = 0; i < array.Length; i += num)
			{
				num = stream.Read(array, i, array.Length - i);
				if (num <= 0)
				{
					break;
				}
			}
			return array;
		}

		private static float Number(string text)
		{
			return float.Parse(text, CultureInfo.InvariantCulture);
		}

		private static Mesh ParseObj(string text)
		{
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Expected O, but got Unknown
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: 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)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = new List<Vector3>();
			List<Vector2> list2 = new List<Vector2>();
			List<Vector3> list3 = new List<Vector3>();
			List<Vector3> list4 = new List<Vector3>();
			List<Vector2> list5 = new List<Vector2>();
			List<Vector3> list6 = new List<Vector3>();
			List<int> list7 = new List<int>();
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			string[] array = text.Split(new char[1] { '\n' });
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length == 0 || text2[0] == '#')
				{
					continue;
				}
				string[] array2 = text2.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
				if (array2[0] == "v")
				{
					list.Add(new Vector3(Number(array2[1]), Number(array2[2]), Number(array2[3])));
				}
				else if (array2[0] == "vt")
				{
					list2.Add(new Vector2(Number(array2[1]), Number(array2[2])));
				}
				else if (array2[0] == "vn")
				{
					list3.Add(new Vector3(Number(array2[1]), Number(array2[2]), Number(array2[3])));
				}
				else
				{
					if (!(array2[0] == "f"))
					{
						continue;
					}
					List<int> list8 = new List<int>();
					for (int j = 1; j < array2.Length; j++)
					{
						if (!dictionary.TryGetValue(array2[j], out var value))
						{
							string[] array3 = array2[j].Split(new char[1] { '/' });
							list4.Add(list[int.Parse(array3[0]) - 1]);
							list5.Add((array3.Length > 1 && array3[1].Length > 0) ? list2[int.Parse(array3[1]) - 1] : Vector2.zero);
							list6.Add((array3.Length > 2 && array3[2].Length > 0) ? list3[int.Parse(array3[2]) - 1] : Vector3.up);
							value = list4.Count - 1;
							dictionary[array2[j]] = value;
						}
						list8.Add(value);
					}
					for (int k = 2; k < list8.Count; k++)
					{
						list7.Add(list8[0]);
						list7.Add(list8[k - 1]);
						list7.Add(list8[k]);
					}
				}
			}
			if (list4.Count == 0 || list7.Count == 0)
			{
				return null;
			}
			Mesh val = new Mesh
			{
				name = "UllrTrophy"
			};
			if (list4.Count > 65000)
			{
				val.indexFormat = (IndexFormat)1;
			}
			val.SetVertices(list4);
			val.SetUVs(0, list5);
			val.SetNormals(list6);
			val.SetTriangles(list7, 0);
			val.RecalculateBounds();
			return val;
		}

		private unsafe static void ApplyArtwork(CustomItem item)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: 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_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Expected O, but got Unknown
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Expected O, but got Unknown
			//IL_034a: Unknown result type (might be due to invalid IL or missing references)
			//IL_035a: Expected O, but got Unknown
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Expected O, but got Unknown
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Expected O, but got Unknown
			//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0405: Unknown result type (might be due to invalid IL or missing references)
			//IL_040a: Unknown result type (might be due to invalid IL or missing references)
			//IL_048a: Unknown result type (might be due to invalid IL or missing references)
			//IL_048f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0516: Unknown result type (might be due to invalid IL or missing references)
			//IL_0524: Unknown result type (might be due to invalid IL or missing references)
			//IL_0526: Unknown result type (might be due to invalid IL or missing references)
			//IL_0537: Unknown result type (might be due to invalid IL or missing references)
			//IL_0550: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0601: Unknown result type (might be due to invalid IL or missing references)
			//IL_0603: Unknown result type (might be due to invalid IL or missing references)
			if (Application.isBatchMode)
			{
				return;
			}
			try
			{
				string text = Path.Combine(Paths.ConfigPath, "SaerimnerBallista");
				Directory.CreateDirectory(text);
				bool flag = string.Equals((TrophyModel.Value ?? "").Trim(), "Viking", StringComparison.OrdinalIgnoreCase);
				byte[] array = ReadAsset(text, "ullr_icon.png", flag ? "ullr_icon.png" : null);
				if (array != null)
				{
					Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false)
					{
						filterMode = (FilterMode)1
					};
					if (LoadImage(val, array))
					{
						item.ItemDrop.m_itemData.m_shared.m_icons = (Sprite[])(object)new Sprite[1] { Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)) };
						Log.LogInfo((object)("Ullr Trophy: the icon is read (" + ((Texture)val).width + " x " + ((Texture)val).height + ")"));
					}
					else
					{
						Log.LogWarning((object)"Ullr Trophy: the icon could not be read");
					}
				}
				byte[] array2 = ReadAsset(text, "ullr_model.obj", flag ? "ullr_viking.obj" : null);
				byte[] array3 = ReadAsset(text, "ullr_texture.png", flag ? "ullr_viking.png" : null);
				if (array3 == null)
				{
					return;
				}
				Texture2D val2 = new Texture2D(2, 2, (TextureFormat)4, true)
				{
					filterMode = (FilterMode)1,
					wrapMode = (TextureWrapMode)1
				};
				if (!LoadImage(val2, array3))
				{
					Log.LogWarning((object)"Ullr Trophy: the colours of the model could not be read");
					return;
				}
				if (array2 == null)
				{
					Renderer[] componentsInChildren = item.ItemPrefab.GetComponentsInChildren<Renderer>(true);
					foreach (Renderer val3 in componentsInChildren)
					{
						Material[] sharedMaterials = val3.sharedMaterials;
						for (int j = 0; j < sharedMaterials.Length; j++)
						{
							if ((Object)(object)sharedMaterials[j] != (Object)null)
							{
								sharedMaterials[j] = new Material(sharedMaterials[j])
								{
									mainTexture = (Texture)(object)val2
								};
							}
						}
						val3.sharedMaterials = sharedMaterials;
					}
					Log.LogInfo((object)"Ullr Trophy: the colours of the model were replaced");
					return;
				}
				Mesh val4 = ParseObj(Encoding.UTF8.GetString(array2));
				if ((Object)(object)val4 == (Object)null)
				{
					Log.LogWarning((object)"Ullr Trophy: the model could not be read");
					return;
				}
				MeshFilter[] componentsInChildren2 = item.ItemPrefab.GetComponentsInChildren<MeshFilter>(true);
				if (componentsInChildren2.Length == 0)
				{
					Log.LogWarning((object)"Ullr Trophy: the trophy it is made from has no model to replace");
					return;
				}
				MeshFilter val5 = componentsInChildren2[0];
				MeshFilter[] array4 = componentsInChildren2;
				foreach (MeshFilter val6 in array4)
				{
					if (!((Object)(object)val6 == (Object)(object)val5))
					{
						Renderer component = ((Component)val6).GetComponent<Renderer>();
						if ((Object)(object)component != (Object)null)
						{
							component.enabled = false;
						}
					}
				}
				LODGroup[] componentsInChildren3 = item.ItemPrefab.GetComponentsInChildren<LODGroup>(true);
				for (int i = 0; i < componentsInChildren3.Length; i++)
				{
					componentsInChildren3[i].enabled = false;
				}
				MeshRenderer component2 = ((Component)val5).GetComponent<MeshRenderer>();
				if ((Object)(object)component2 == (Object)null)
				{
					Log.LogWarning((object)"Ullr Trophy: the model of the trophy has no renderer");
					return;
				}
				Material[] sharedMaterials2 = ((Renderer)component2).sharedMaterials;
				Material val7 = new Material((Material)((sharedMaterials2.Length != 0 && (Object)(object)sharedMaterials2[0] != (Object)null) ? ((object)sharedMaterials2[0]) : ((object)new Material(Shader.Find("Standard")))));
				string[] texturePropertyNames = val7.GetTexturePropertyNames();
				foreach (string text2 in texturePropertyNames)
				{
					val7.SetTexture(text2, (Texture)null);
				}
				val7.mainTexture = (Texture)(object)val2;
				if (val7.HasProperty("_Color"))
				{
					val7.color = Color.white;
				}
				if (val7.HasProperty("_Metallic"))
				{
					val7.SetFloat("_Metallic", 0f);
				}
				if (val7.HasProperty("_Glossiness"))
				{
					val7.SetFloat("_Glossiness", 0.15f);
				}
				val5.sharedMesh = val4;
				((Renderer)component2).sharedMaterials = (Material[])(object)new Material[1] { val7 };
				Vector3 zero = Vector3.zero;
				string[] array5 = (TrophyRotation.Value ?? "").Split(new char[1] { ',' });
				if (array5.Length >= 3 && float.TryParse(array5[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array5[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array5[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
				{
					((Vector3)(ref zero))..ctor(result, result2, result3);
				}
				Vector3 zero2 = Vector3.zero;
				string[] array6 = (TrophyOffset.Value ?? "").Split(new char[1] { ',' });
				if (array6.Length >= 3 && float.TryParse(array6[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result4) && float.TryParse(array6[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result5) && float.TryParse(array6[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result6))
				{
					((Vector3)(ref zero2))..ctor(result4, result5, result6);
				}
				((Component)val5).transform.localPosition = zero2;
				((Component)val5).transform.localRotation = Quaternion.Euler(zero);
				((Component)val5).transform.localScale = Vector3.one * Mathf.Max(0.05f, TrophyScale.Value);
				ManualLogSource log = Log;
				string[] obj = new string[12]
				{
					"Ullr Trophy: the model is ",
					flag ? "the head of a Viking" : "your own",
					" (",
					val4.vertexCount.ToString(),
					" points, ",
					(val4.triangles.Length / 3).ToString(),
					" triangles), scale ",
					TrophyScale.Value.ToString(),
					", rotation ",
					null,
					null,
					null
				};
				Vector3 val8 = zero;
				obj[9] = ((object)(*(Vector3*)(&val8))/*cast due to .constrained prefix*/).ToString();
				obj[10] = ", offset ";
				val8 = zero2;
				obj[11] = ((object)(*(Vector3*)(&val8))/*cast due to .constrained prefix*/).ToString();
				log.LogInfo((object)string.Concat(obj));
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Ullr Trophy: the look could not be set: " + ex.Message));
			}
		}
	}
	internal static class Patches
	{
		private static Turret shooting;

		private static readonly ConditionalWeakTable<Projectile, object> friendlyBolts = new ConditionalWeakTable<Projectile, object>();

		private static readonly string[] SettingNames = new string[8] { "m_targetPlayers", "m_targetTamed", "m_viewDistance", "m_horizontalAngle", "m_turnRate", "m_noTargetScanRate", "m_maxAmmo", "m_maxConfigTargets" };

		private static readonly Dictionary<string, FieldInfo> settingFields = new Dictionary<string, FieldInfo>();

		private static readonly ConditionalWeakTable<Turret, Dictionary<string, object>> originals = new ConditionalWeakTable<Turret, Dictionary<string, object>>();

		private static FieldInfo targetField;

		private static FieldInfo eyeField;

		private static FieldInfo viewField;

		private static bool fieldsLooked;

		private static int corrections;

		public static void Install(Harmony harmony)
		{
			InstallTargeting(harmony);
			InstallTrophyUse(harmony);
			InstallHoverText(harmony);
			InstallBolts(harmony);
		}

		internal static bool IsBallista(Turret turret)
		{
			if ((Object)(object)turret != (Object)null)
			{
				return turret.m_name == "$piece_turret";
			}
			return false;
		}

		private static bool HasUllr(Turret turret)
		{
			if ((Object)(object)turret == (Object)null)
			{
				return false;
			}
			ZNetView component = ((Component)turret).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null && component.IsValid())
			{
				return component.GetZDO().GetBool("SB_Ullr", false);
			}
			return false;
		}

		private static bool HostilesOnly(Turret turret)
		{
			if (!IsBallista(turret))
			{
				return false;
			}
			if (Plugin.AllBallistasHostilesOnly.Value)
			{
				return true;
			}
			if (Plugin.UllrTrophy.Value)
			{
				return HasUllr(turret);
			}
			return false;
		}

		private static void LookUpFields()
		{
			if (!fieldsLooked)
			{
				fieldsLooked = true;
				string[] settingNames = SettingNames;
				foreach (string text in settingNames)
				{
					settingFields[text] = AccessTools.Field(typeof(Turret), text);
				}
				targetField = AccessTools.Field(typeof(Turret), "m_target");
				eyeField = AccessTools.Field(typeof(Turret), "m_eye");
				viewField = settingFields["m_viewDistance"];
				Plugin.Log.LogInfo((object)("Turret settings found: " + string.Join(", ", settingFields.Select((KeyValuePair<string, FieldInfo> k) => k.Key + ((k.Value != null) ? "" : " (MISSING)")).ToArray()) + "; m_target " + ((targetField != null) ? targetField.FieldType.Name : "MISSING")));
			}
		}

		private static Dictionary<string, object> CaptureOriginals(Turret turret)
		{
			Dictionary<string, object> dictionary = new Dictionary<string, object>();
			foreach (KeyValuePair<string, FieldInfo> settingField in settingFields)
			{
				if (settingField.Value != null)
				{
					dictionary[settingField.Key] = settingField.Value.GetValue(turret);
				}
			}
			return dictionary;
		}

		private static void Put(Turret turret, Dictionary<string, object> original, string name, object value)
		{
			if (settingFields.TryGetValue(name, out var value2) && !(value2 == null))
			{
				if (value == null)
				{
					original.TryGetValue(name, out value);
				}
				if (value != null)
				{
					value2.SetValue(turret, Convert.ChangeType(value, value2.FieldType));
				}
			}
		}

		private static void Tune(Turret turret, Dictionary<string, object> original, string name, float value)
		{
			Put(turret, original, name, (value > 0f) ? ((object)value) : null);
		}

		private static void ApplySettings(Turret turret)
		{
			if (IsBallista(turret))
			{
				LookUpFields();
				Dictionary<string, object> value = originals.GetValue(turret, CaptureOriginals);
				bool flag = HostilesOnly(turret);
				Put(turret, value, "m_targetPlayers", flag ? ((object)false) : null);
				Put(turret, value, "m_targetTamed", flag ? ((object)false) : null);
				Tune(turret, value, "m_viewDistance", Plugin.TuneRange.Value);
				Tune(turret, value, "m_horizontalAngle", Mathf.Clamp(Plugin.TuneScanArc.Value / 2f, 0f, 89f));
				Tune(turret, value, "m_noTargetScanRate", Plugin.TuneSweepInterval.Value);
				Tune(turret, value, "m_turnRate", Plugin.TuneTurnRate.Value);
				Tune(turret, value, "m_maxAmmo", Mathf.Round(Plugin.TuneMaxAmmo.Value));
				Tune(turret, value, "m_maxConfigTargets", Mathf.Round(Plugin.TuneMaxTrophies.Value));
			}
		}

		private static void InstallTargeting(Harmony harmony)
		{
			//IL_006f: 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_0091: Expected O, but got Unknown
			//IL_0091: Expected O, but got Unknown
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Turret), "UpdateTarget", (Type[])null, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.Method(typeof(Turret), "UpdateTurretRotation", (Type[])null, (Type[])null);
				if (methodInfo == null && methodInfo2 == null)
				{
					Plugin.Log.LogWarning((object)"Turret.UpdateTarget and UpdateTurretRotation not found: the ballista's targeting is not changed");
					return;
				}
				if (methodInfo != null)
				{
					harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Patches), "BeforeUpdate", (Type[])null), new HarmonyMethod(typeof(Patches), "FixFriendlyTarget", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Plugin.Log.LogInfo((object)"Ballista targeting (switches and a friend is never kept as the target): set up");
				}
				if (methodInfo2 != null)
				{
					harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(Patches), "BeforeUpdate", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Plugin.Log.LogInfo((object)"Ballista tuning (range, arc, turn rate ...): set up");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not set up the ballista's targeting: " + ex.Message));
			}
		}

		private static void BeforeUpdate(Turret __instance)
		{
			ApplySettings(__instance);
		}

		private static bool IsFriendly(Character character)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			if (!character.IsPlayer() && !character.IsTamed())
			{
				return (int)character.GetFaction() == 0;
			}
			return true;
		}

		private static void FixFriendlyTarget(Turret __instance)
		{
			if ((Object)(object)__instance == (Object)null || !HostilesOnly(__instance))
			{
				return;
			}
			LookUpFields();
			if (targetField == null)
			{
				return;
			}
			object? value = targetField.GetValue(__instance);
			Character val = (Character)((value is Character) ? value : null);
			if (!((Object)(object)val == (Object)null) && IsFriendly(val))
			{
				Character val2 = FindHostile(__instance);
				targetField.SetValue(__instance, val2);
				if (corrections++ < 5)
				{
					Plugin.Log.LogInfo((object)("A hostiles-only ballista was about to shoot at " + ((Object)val).name + " (a friend): now " + (((Object)(object)val2 != (Object)null) ? ((Object)val2).name : "no target")));
				}
			}
		}

		private static Character FindHostile(Turret turret)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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_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_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((Component)turret).transform.position + Vector3.up * 2f;
			if (eyeField != null)
			{
				object? value = eyeField.GetValue(turret);
				GameObject val2 = (GameObject)((value is GameObject) ? value : null);
				if (val2 != null && (Object)(object)val2 != (Object)null)
				{
					val = val2.transform.position;
					goto IL_008d;
				}
			}
			if (eyeField != null)
			{
				object? value2 = eyeField.GetValue(turret);
				Transform val3 = (Transform)((value2 is Transform) ? value2 : null);
				if (val3 != null && (Object)(object)val3 != (Object)null)
				{
					val = val3.position;
				}
			}
			goto IL_008d;
			IL_008d:
			float num = 50f;
			if (viewField != null && viewField.GetValue(turret) is float num2 && num2 > 1f)
			{
				num = num2;
			}
			int mask = LayerMask.GetMask(new string[2] { "static_solid", "terrain" });
			Character result = null;
			float num3 = float.MaxValue;
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if (!((Object)(object)allCharacter == (Object)null) && !allCharacter.IsDead() && !IsFriendly(allCharacter))
				{
					Vector3 centerPoint = allCharacter.GetCenterPoint();
					float num4 = Vector3.Distance(val, centerPoint);
					if (!(num4 > num) && !(num4 >= num3) && !Physics.Linecast(val, centerPoint, mask))
					{
						result = allCharacter;
						num3 = num4;
					}
				}
			}
			return result;
		}

		private static void InstallTrophyUse(Harmony harmony)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Turret), "UseItem", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					Plugin.Log.LogWarning((object)"Turret.UseItem not found: the Ullr Trophy cannot be used on a ballista");
					return;
				}
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Patches), "UseItemPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.Log.LogInfo((object)"Ullr Trophy on the ballista: set up");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not set up the use of the Ullr Trophy: " + ex.Message));
			}
		}

		private static bool UseItemPrefix(Turret __instance, object[] __args, ref bool __result)
		{
			if (!Plugin.UllrTrophy.Value || __args == null)
			{
				return true;
			}
			Humanoid val = null;
			ItemData val2 = null;
			foreach (object obj in __args)
			{
				Humanoid val3 = (Humanoid)((obj is Humanoid) ? obj : null);
				if (val3 != null)
				{
					val = val3;
					continue;
				}
				ItemData val4 = (ItemData)((obj is ItemData) ? obj : null);
				if (val4 != null)
				{
					val2 = val4;
				}
			}
			if (val2 == null || (Object)(object)val2.m_dropPrefab == (Object)null || ((Object)val2.m_dropPrefab).name != "TrophyUllr_SB")
			{
				return true;
			}
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				__result = true;
				return false;
			}
			bool flag = !component.GetZDO().GetBool("SB_Ullr", false);
			if (!component.IsOwner())
			{
				component.ClaimOwnership();
			}
			component.GetZDO().Set("SB_Ullr", flag);
			if ((Object)(object)val != (Object)null)
			{
				((Character)val).Message((MessageType)2, flag ? "Ullr guides the ballista: it only shoots at the hostile" : "Ullr's blessing is taken from the ballista", 0, (Sprite)null, false);
			}
			__result = true;
			return false;
		}

		private static void InstallHoverText(Harmony harmony)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Turret), "GetHoverText", (Type[])null, (Type[])null);
				if (!(methodInfo == null))
				{
					harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "AddHoverText", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not set up the ballista's hover text: " + ex.Message));
			}
		}

		private static void AddHoverText(Turret __instance, ref string __result)
		{
			if (__result != null)
			{
				if (Plugin.AllBallistasHostilesOnly.Value)
				{
					__result += "\n<color=#7fd4ff>Only shoots at the hostile</color>";
				}
				else if (Plugin.UllrTrophy.Value && HasUllr(__instance))
				{
					__result += "\n<color=#7fd4ff>Ullr's blessing: only shoots at the hostile</color>";
				}
			}
		}

		private static void InstallBolts(Harmony harmony)
		{
			//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: Expected O, but got Unknown
			//IL_00a8: Expected O, but got Unknown
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Turret), "ShootProjectile", (Type[])null, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.Method(typeof(Projectile), "Setup", (Type[])null, (Type[])null);
				MethodInfo methodInfo3 = AccessTools.Method(typeof(Projectile), "OnHit", (Type[])null, (Type[])null);
				if (methodInfo == null || methodInfo2 == null || methodInfo3 == null)
				{
					Plugin.Log.LogWarning((object)"Turret.ShootProjectile / Projectile.Setup / Projectile.OnHit not all found: bolts are not made to pass through friends");
					return;
				}
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Patches), "BeginShooting", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "EndShooting", (Type[])null), (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "MarkBolt", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(Patches), "SkipFriendlyHit", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.Log.LogInfo((object)"Ballista bolts: set up");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not set up the ballista's bolts: " + ex.Message));
			}
		}

		private static void BeginShooting(Turret __instance)
		{
			shooting = __instance;
		}

		private static Exception EndShooting(Exception __exception)
		{
			shooting = null;
			return __exception;
		}

		private static void MarkBolt(Projectile __instance)
		{
			if ((Object)(object)shooting != (Object)null && Plugin.BlockFriendlyBolts.Value && HostilesOnly(shooting))
			{
				friendlyBolts.GetOrCreateValue(__instance);
			}
		}

		private static bool SkipFriendlyHit(Projectile __instance, object[] __args)
		{
			if (!Plugin.BlockFriendlyBolts.Value || __args == null || !friendlyBolts.TryGetValue(__instance, out var _))
			{
				return true;
			}
			foreach (object obj in __args)
			{
				Collider val = (Collider)((obj is Collider) ? obj : null);
				if (!((Object)(object)val == (Object)null))
				{
					Character componentInParent = ((Component)val).GetComponentInParent<Character>();
					if (!((Object)(object)componentInParent != (Object)null) || (!componentInParent.IsPlayer() && !componentInParent.IsTamed()))
					{
						break;
					}
					return false;
				}
			}
			return true;
		}
	}
	internal class BallistaRefill : MonoBehaviour
	{
		private Turret turret;

		private ZNetView nview;

		private float timer;

		private void Awake()
		{
			turret = ((Component)this).GetComponent<Turret>();
			nview = ((Component)this).GetComponent<ZNetView>();
			timer = Random.Range(0f, 2f);
		}

		private void Update()
		{
			timer -= Time.deltaTime;
			if (timer > 0f)
			{
				return;
			}
			timer = 2f;
			if ((Object)(object)turret == (Object)null || (Object)(object)nview == (Object)null || !nview.IsValid() || !nview.IsOwner())
			{
				return;
			}
			if (Plugin.UnlimitedAmmo.Value)
			{
				ChestRefill.KeepFull(turret, nview);
				return;
			}
			ChestRefill.TakeMadeUpAmmoAway(nview);
			if (Plugin.RefillFromChests.Value)
			{
				ChestRefill.Check(turret, nview);
			}
		}
	}
	internal static class ChestRefill
	{
		private class Pick
		{
			public Container container;

			public ItemData item;

			public int take;
		}

		private static bool looked;

		private static bool broken;

		private static bool listedAmmo;

		private static FieldInfo maxAmmoField;

		private static FieldInfo allowedField;

		private static FieldInfo defaultAmmoField;

		private static MethodInfo getAmmo;

		private static MethodInfo getAmmoType;

		private const string AmmoKey = "ammo";

		private const string AmmoTypeKey = "ammoType";

		private const string MadeUpKey = "SB_Unlimited";

		private static bool destroyLogged;

		private static bool unlimitedLogged;

		private static bool wrongAmmoWarned;

		public static void Install(Harmony harmony)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Turret), "Awake", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					Plugin.Log.LogWarning((object)"Turret.Awake not found: the refill from chests is off");
					return;
				}
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(ChestRefill), "AddRefill", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.Log.LogInfo((object)("Ballista refill from chests: set up (on: " + Plugin.RefillFromChests.Value + ", range " + Plugin.RefillRange.Value + " m)"));
				List<string> list = new List<string>();
				foreach (MethodInfo item in from m in AccessTools.GetDeclaredMethods(typeof(WearNTear))
					where m.Name == "Destroy" || m.Name == "Remove"
					select m)
				{
					harmony.Patch((MethodBase)item, new HarmonyMethod(typeof(ChestRefill), "BeforeDestroy", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					list.Add("WearNTear." + item.Name);
				}
				if (list.Count > 0)
				{
					Plugin.Log.LogInfo((object)("Ballista destroyed with unlimited ammo (no bolts are dropped): set up in " + string.Join(", ", list.ToArray())));
				}
				else
				{
					Plugin.Log.LogWarning((object)"WearNTear.Destroy/Remove were not found: a ballista with unlimited ammo may drop bolts when it is destroyed");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not set up the refill from chests: " + ex.Message));
			}
		}

		private static void BeforeDestroy(WearNTear __instance)
		{
			try
			{
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				Turret component = ((Component)__instance).GetComponent<Turret>();
				if ((Object)(object)component == (Object)null || !Patches.IsBallista(component))
				{
					return;
				}
				ZNetView component2 = ((Component)__instance).GetComponent<ZNetView>();
				if ((Object)(object)component2 == (Object)null || !component2.IsValid())
				{
					return;
				}
				ZDO zDO = component2.GetZDO();
				if (Plugin.UnlimitedAmmo.Value || zDO.GetBool("SB_Unlimited", false))
				{
					if (!component2.IsOwner())
					{
						component2.ClaimOwnership();
					}
					zDO.Set("ammo", 0);
					zDO.Set("SB_Unlimited", false);
					if (!destroyLogged)
					{
						destroyLogged = true;
						Plugin.Log.LogInfo((object)"Unlimited ammo: a ballista that was destroyed was emptied first, so it drops no bolts");
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Unlimited ammo: could not empty a ballista that is destroyed: " + ex.Message));
			}
		}

		public static void TakeMadeUpAmmoAway(ZNetView nview)
		{
			ZDO zDO = nview.GetZDO();
			if (zDO.GetBool("SB_Unlimited", false))
			{
				zDO.Set("ammo", 0);
				zDO.Set("SB_Unlimited", false);
			}
		}

		private static void AddRefill(Turret __instance)
		{
			if (Patches.IsBallista(__instance) && (Object)(object)((Component)__instance).GetComponent<BallistaRefill>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<BallistaRefill>();
			}
		}

		private static void Look()
		{
			if (!looked)
			{
				looked = true;
				maxAmmoField = AccessTools.Field(typeof(Turret), "m_maxAmmo");
				allowedField = AccessTools.Field(typeof(Turret), "m_allowedAmmo");
				defaultAmmoField = AccessTools.Field(typeof(Turret), "m_defaultAmmo");
				getAmmo = AccessTools.Method(typeof(Turret), "GetAmmo", (Type[])null, (Type[])null);
				getAmmoType = AccessTools.Method(typeof(Turret), "GetAmmoType", (Type[])null, (Type[])null);
				Plugin.Log.LogInfo((object)("Turret ammo parts: m_maxAmmo " + (maxAmmoField != null) + ", m_allowedAmmo " + (allowedField != null) + ", m_defaultAmmo " + (defaultAmmoField != null) + ", GetAmmo " + (getAmmo != null) + ", GetAmmoType " + (getAmmoType != null)));
				if (getAmmo == null || (allowedField == null && defaultAmmoField == null))
				{
					broken = true;
					Plugin.Log.LogWarning((object)"The ballista's ammo could not be read in this game version: the refill from chests is off");
				}
			}
		}

		private static int ReadAmmo(Turret turret)
		{
			return (int)getAmmo.Invoke(turret, null);
		}

		private static List<string> AllowedAmmo(Turret turret)
		{
			List<string> list = new List<string>();
			if (allowedField != null && allowedField.GetValue(turret) is IEnumerable enumerable)
			{
				foreach (object item in enumerable)
				{
					if (item != null)
					{
						FieldInfo field = item.GetType().GetField("m_ammo", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
						ItemDrop val = (ItemDrop)((field != null) ? /*isinst with value type is only supported in some contexts*/: null);
						if ((Object)(object)val != (Object)null && !list.Contains(((Object)((Component)val).gameObject).name))
						{
							list.Add(((Object)((Component)val).gameObject).name);
						}
					}
				}
			}
			if (list.Count == 0 && defaultAmmoField != null)
			{
				object? value = defaultAmmoField.GetValue(turret);
				ItemDrop val2 = (ItemDrop)((value is ItemDrop) ? value : null);
				if (val2 != null)
				{
					list.Add(((Object)((Component)val2).gameObject).name);
				}
			}
			return list;
		}

		private static string WantedAmmo(List<string> allowed)
		{
			string asked = (Plugin.UnlimitedAmmoType.Value ?? "").Trim();
			if (asked.Length == 0)
			{
				return "";
			}
			string text = allowed.FirstOrDefault((string a) => string.Equals(a, asked, StringComparison.OrdinalIgnoreCase));
			if (text == null && !wrongAmmoWarned)
			{
				wrongAmmoWarned = true;
				Plugin.Log.LogWarning((object)("Unlimited ammo: the ballista does not accept '" + asked + "' (it accepts " + string.Join(", ", allowed.ToArray()) + "): the setting is ignored"));
			}
			return text ?? "";
		}

		public static void KeepFull(Turret turret, ZNetView nview)
		{
			if (broken)
			{
				return;
			}
			Look();
			if (broken)
			{
				return;
			}
			List<string> list = AllowedAmmo(turret);
			if (list.Count == 0)
			{
				return;
			}
			int num = ((maxAmmoField != null && maxAmmoField.GetValue(turret) is int num2 && num2 > 0) ? num2 : 40);
			ZDO zDO = nview.GetZDO();
			string text = zDO.GetString("ammoType", "");
			string text2 = WantedAmmo(list);
			if (ReadAmmo(turret) >= num && (text2.Length == 0 || text2 == text))
			{
				return;
			}
			string text3 = text2;
			object obj;
			if (text3.Length == 0)
			{
				text3 = text;
				if (string.IsNullOrEmpty(text3) || !list.Contains(text3))
				{
					if (defaultAmmoField != null)
					{
						object? value = defaultAmmoField.GetValue(turret);
						ItemDrop val = (ItemDrop)((value is ItemDrop) ? value : null);
						if (val != null)
						{
							obj = ((Object)((Component)val).gameObject).name;
							goto IL_00f3;
						}
					}
					obj = "";
					goto IL_00f3;
				}
			}
			goto IL_010c;
			IL_00f3:
			string text4 = (string)obj;
			text3 = (list.Contains(text4) ? text4 : list[0]);
			goto IL_010c;
			IL_010c:
			zDO.Set("ammo", num);
			zDO.Set("SB_Unlimited", true);
			if (text3 != text)
			{
				zDO.Set("ammoType", text3);
			}
			bool flag = ReadAmmo(turret) == num;
			if (flag && getAmmoType != null)
			{
				flag = getAmmoType.Invoke(turret, null) as string == text3;
			}
			if (!flag)
			{
				zDO.Set("ammo", 0);
				zDO.Set("ammoType", text);
				broken = true;
				Plugin.Log.LogWarning((object)"The ballista does not read the ammo that was written to it (the data names are different in this game version): unlimited ammo and the refill from chests are off");
			}
			else if (!unlimitedLogged)
			{
				unlimitedLogged = true;
				Plugin.Log.LogInfo((object)("Unlimited ammo: a ballista was filled up to " + num + " (" + text3 + ")"));
			}
		}

		public static void Check(Turret turret, ZNetView nview)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			if (broken)
			{
				return;
			}
			Look();
			if (broken || ReadAmmo(turret) > 0)
			{
				return;
			}
			List<string> list = AllowedAmmo(turret);
			if (list.Count == 0)
			{
				return;
			}
			if (!listedAmmo)
			{
				listedAmmo = true;
				Plugin.Log.LogInfo((object)("A ballista accepts this ammo (in the game's order): " + string.Join(", ", list.ToArray())));
			}
			float range = Mathf.Max(0f, Plugin.RefillRange.Value);
			List<Container> list2 = ChestsInRange(((Component)turret).transform.position, range);
			if (list2.Count == 0)
			{
				return;
			}
			string last = nview.GetZDO().GetString("ammoType", "");
			List<string> list3 = list.OrderBy((string a) => (!(a == last)) ? 1 : 0).ToList();
			int num = ((maxAmmoField != null && maxAmmoField.GetValue(turret) is int num2 && num2 > 0) ? num2 : 40);
			foreach (string item in list3)
			{
				List<Pick> list4 = new List<Pick>();
				int num3 = 0;
				foreach (Container item2 in list2)
				{
					Inventory inventory = item2.GetInventory();
					if (inventory == null)
					{
						continue;
					}
					foreach (ItemData allItem in inventory.GetAllItems())
					{
						if (num3 >= num)
						{
							break;
						}
						if (!((Object)(object)allItem.m_dropPrefab == (Object)null) && !(((Object)allItem.m_dropPrefab).name != item))
						{
							int num4 = Mathf.Min(allItem.m_stack, num - num3);
							if (num4 > 0)
							{
								list4.Add(new Pick
								{
									container = item2,
									item = allItem,
									take = num4
								});
								num3 += num4;
							}
						}
					}
					if (num3 >= num)
					{
						break;
					}
				}
				if (num3 != 0)
				{
					Fill(turret, nview, item, num3, list4);
					break;
				}
			}
		}

		private static void Fill(Turret turret, ZNetView nview, string type, int total, List<Pick> picks)
		{
			ZDO zDO = nview.GetZDO();
			string text = zDO.GetString("ammoType", "");
			zDO.Set("ammo", total);
			zDO.Set("ammoType", type);
			bool flag = ReadAmmo(turret) == total;
			if (flag && getAmmoType != null)
			{
				flag = getAmmoType.Invoke(turret, null) as string == type;
			}
			if (!flag)
			{
				zDO.Set("ammo", 0);
				zDO.Set("ammoType", text);
				broken = true;
				Plugin.Log.LogWarning((object)"The ballista does not read the ammo that was written to it (the data names are different in this game version): the refill from chests is off, nothing was taken from a chest");
				return;
			}
			foreach (Pick pick in picks)
			{
				if ((Object)(object)pick.container.m_nview != (Object)null && pick.container.m_nview.IsValid() && !pick.container.m_nview.IsOwner())
				{
					pick.container.m_nview.ClaimOwnership();
				}
				pick.container.GetInventory().RemoveItem(pick.item, pick.take);
			}
			Plugin.Log.LogInfo((object)$"A ballista ran out of ammo: {total} x {type} taken from {picks.Select((Pick p) => p.container).Distinct().Count()} chest(s) within {Plugin.RefillRange.Value} m");
		}

		private static List<Container> ChestsInRange(Vector3 position, float range)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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)
			List<Container> list = new List<Container>();
			Collider[] array = Physics.OverlapSphere(position, range);
			for (int i = 0; i < array.Length; i++)
			{
				Container componentInParent = ((Component)array[i]).GetComponentInParent<Container>();
				if (!((Object)(object)componentInParent == (Object)null) && !list.Contains(componentInParent) && !(Vector3.Distance(position, ((Component)componentInParent).transform.position) > range) && !componentInParent.IsInUse() && componentInParent.GetInventory() != null)
				{
					list.Add(componentInParent);
				}
			}
			return list.OrderBy((Container c) => Vector3.Distance(position, ((Component)c).transform.position)).ToList();
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}