Decompiled source of AmmoCounter v1.0.3

BepInEx/plugins/AmmoCounter/AmmoCounter.dll

Decompiled 5 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using AmmoCounter.Configuration;
using AmmoCounter.Localization;
using AmmoCounter.UI;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using FishNet;
using FishNet.Broadcast;
using FishNet.Connection;
using FishNet.Object;
using FishNet.Serializing;
using FishNet.Transporting;
using HarmonyLib;
using HowtoFishIdentityAPI.Api;
using HowtoFishLocalizationAPI.Api;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("AmmoCounter")]
[assembly: AssemblyDescription("Weapon ammo HUD for How to Fish by Ice Box Studio")]
[assembly: AssemblyCompany("Ice Box Studio")]
[assembly: AssemblyProduct("AmmoCounter")]
[assembly: AssemblyCopyright("Copyright © 2026 Ice Box Studio All rights reserved.")]
[assembly: ComVisible(false)]
[assembly: Guid("54e4d8be-3a42-4a63-8cd2-6b1d8f9ce1b7")]
[assembly: AssemblyFileVersion("1.0.3.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.3.0")]
namespace AmmoCounter
{
	[BepInPlugin("IceBoxStudio.HowToFish.AmmoCounter", "AmmoCounter", "1.0.3")]
	[BepInDependency("IceBoxStudio.HowToFish.LocalizationAPI", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class AmmoCounterPlugin : BaseUnityPlugin
	{
		private Harmony _harmony;

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				Log.LogInfo((object)"=============================================");
				Log.LogInfo((object)("AmmoCounter " + I18n.Text("plugin.initializing")));
				Log.LogInfo((object)(I18n.Text("plugin.author_prefix") + "Ice Box Studio(https://steamcommunity.com/id/ibox666/)"));
				ConfigManager.Init(((BaseUnityPlugin)this).Config);
				AmmoRuntime.Init(((BaseUnityPlugin)this).Logger);
				_harmony = new Harmony("IceBoxStudio.HowToFish.AmmoCounter");
				_harmony.PatchAll(Assembly.GetExecutingAssembly());
				Log.LogInfo((object)("AmmoCounter " + I18n.Text("plugin.initialized")));
				Log.LogInfo((object)"=============================================");
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Failed to initialize AmmoCounter: {arg}");
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "IceBoxStudio.HowToFish.AmmoCounter";

		public const string PLUGIN_NAME = "AmmoCounter";

		public const string PLUGIN_VERSION = "1.0.3";
	}
	internal static class AmmoRuntime
	{
		internal static void Init(ManualLogSource log)
		{
			StatTrakRuntime.Init(log);
		}

		internal static void Start(Player player)
		{
			StatTrakRuntime.Start(player);
			if (!((Object)(object)player == (Object)null) && !(((NetworkBehaviour)player).Owner == (NetworkConnection)null) && ((NetworkBehaviour)player).Owner.IsLocalClient)
			{
				AmmoUi.Attach();
			}
		}

		internal static void Stop(Player player)
		{
			StatTrakRuntime.Stop(player);
			if (!((Object)(object)player == (Object)null) && !(((NetworkBehaviour)player).Owner == (NetworkConnection)null) && ((NetworkBehaviour)player).Owner.IsLocalClient)
			{
				AmmoUi.Stop();
			}
		}

		internal static void Tick()
		{
			StatTrakRuntime.Tick();
			AmmoUi.Tick();
		}

		internal static void Kill()
		{
			StatTrakRuntime.AddKill();
		}
	}
	public struct StatTrakKillBroadcast : IBroadcast
	{
		public int ItemId;

		public StatTrakKillBroadcast(int itemId)
		{
			ItemId = itemId;
		}
	}
	public struct StatTrakSyncBroadcast : IBroadcast
	{
		public int ItemId;

		public int Kills;

		public StatTrakSyncBroadcast(int itemId, int kills)
		{
			ItemId = itemId;
			Kills = kills;
		}
	}
	internal static class StatTrakRuntime
	{
		[Serializable]
		private sealed class SaveData
		{
			public List<SaveEntry> Entries = new List<SaveEntry>();
		}

		[Serializable]
		private sealed class SaveEntry
		{
			public string PlayerKey;

			public int ItemId;

			public int Kills;
		}

		private static readonly Dictionary<string, Dictionary<int, int>> ServerKills = new Dictionary<string, Dictionary<int, int>>();

		private static readonly Dictionary<int, int> ClientKills = new Dictionary<int, int>();

		private static ManualLogSource _log;

		private static string _path;

		private static bool _serverReady;

		private static bool _serverDirty;

		private static bool _clientRegistered;

		private static bool _serverRegistered;

		private static bool _serializersReady;

		private static bool _identityHook;

		internal static void Init(ManualLogSource log)
		{
			_log = log;
		}

		internal static void Start(Player player)
		{
			if (!ConfigManager.ShowStatTrak || !HasIdentity())
			{
				return;
			}
			SetupNet();
			if (InstanceFinder.IsServerStarted)
			{
				if (!_serverReady)
				{
					ServerStart();
				}
				if ((Object)(object)player != (Object)null && ((NetworkBehaviour)player).Owner != (NetworkConnection)null && IdentityApi.IsVerified(((NetworkBehaviour)player).Owner))
				{
					IdentityReady(((NetworkBehaviour)player).Owner);
				}
			}
		}

		internal static void Stop(Player player)
		{
			if (!((Object)(object)player == (Object)null) && !(((NetworkBehaviour)player).Owner == (NetworkConnection)null) && ((NetworkBehaviour)player).Owner.IsLocalClient)
			{
				ClientKills.Clear();
			}
		}

		internal static void Tick()
		{
			if (ConfigManager.ShowStatTrak && HasIdentity())
			{
				SetupNet();
				if (InstanceFinder.IsServerStarted && !_serverReady)
				{
					ServerStart();
				}
			}
		}

		internal static int Get(Item item)
		{
			if (!ConfigManager.ShowStatTrak || !Object.op_Implicit((Object)(object)item))
			{
				return 0;
			}
			int num = ItemKey(item.ID);
			string playerKey = default(string);
			if (InstanceFinder.IsServerStarted && (Object)(object)Player.LocalPlayer != (Object)null && HasIdentity() && IdentityApi.TryGetKey(Player.LocalPlayer, ref playerKey))
			{
				return GetServer(playerKey, num);
			}
			if (!ClientKills.TryGetValue(num, out var value))
			{
				return 0;
			}
			return value;
		}

		internal static void AddKill()
		{
			if (!ConfigManager.ShowStatTrak || !HasIdentity())
			{
				return;
			}
			Player localPlayer = Player.LocalPlayer;
			Item val = ((Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)localPlayer.Holding)) ? localPlayer.Holding.HeldItem : null);
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.Weapon))
			{
				return;
			}
			if (InstanceFinder.IsServerStarted)
			{
				AddServerKill(localPlayer, val.ID);
				return;
			}
			SetupNet();
			if (_clientRegistered && (Object)(object)InstanceFinder.ClientManager != (Object)null)
			{
				InstanceFinder.ClientManager.Broadcast<StatTrakKillBroadcast>(new StatTrakKillBroadcast(val.ID), (Channel)0);
			}
		}

		internal static void Save()
		{
			if (_serverReady)
			{
				Write();
			}
		}

		internal static void ServerStop()
		{
			Write();
			ServerKills.Clear();
			_path = null;
			_serverReady = false;
			_serverDirty = false;
			_serverRegistered = false;
		}

		internal static void SetupNet()
		{
			if (ConfigManager.ShowStatTrak && HasIdentity())
			{
				HookIdentity();
				SetupSerializers();
				if (!_clientRegistered && (Object)(object)InstanceFinder.ClientManager != (Object)null)
				{
					InstanceFinder.ClientManager.RegisterBroadcast<StatTrakSyncBroadcast>((Action<StatTrakSyncBroadcast, Channel>)GotSync);
					_clientRegistered = true;
				}
				if (!_serverRegistered && (Object)(object)InstanceFinder.ServerManager != (Object)null)
				{
					InstanceFinder.ServerManager.RegisterBroadcast<StatTrakKillBroadcast>((Action<NetworkConnection, StatTrakKillBroadcast, Channel>)GotKill, true);
					_serverRegistered = true;
				}
			}
		}

		internal static void ServerStart()
		{
			if (!_serverReady && ConfigManager.ShowStatTrak && HasIdentity() && InstanceFinder.IsServerStarted && SaveManager.CurServerSave != null && !string.IsNullOrEmpty(SaveManager.CurServerSave.Name))
			{
				ServerKills.Clear();
				_path = PathFor(SaveManager.CurServerSave.Name);
				_serverReady = true;
				_serverDirty = false;
				SetupNet();
				Load();
			}
		}

		private static void IdentityReady(NetworkConnection connection)
		{
			string key = default(string);
			if (!ConfigManager.ShowStatTrak || !HasIdentity() || !_serverReady || !InstanceFinder.IsServerStarted || connection == (NetworkConnection)null || !IdentityApi.IsVerified(connection) || !IdentityApi.TryGetKey(connection, ref key))
			{
				return;
			}
			Player val = FindPlayer(connection);
			if ((Object)(object)val == (Object)null || (Object)(object)InstanceFinder.ServerManager == (Object)null || !ServerKills.TryGetValue(key, out var value))
			{
				return;
			}
			foreach (KeyValuePair<int, int> item in value)
			{
				Send(val, item.Key, item.Value);
			}
		}

		private static void GotKill(NetworkConnection connection, StatTrakKillBroadcast message, Channel channel)
		{
			if (ConfigManager.ShowStatTrak && _serverReady && HasIdentity() && !(connection == (NetworkConnection)null) && IdentityApi.IsVerified(connection))
			{
				Player val = FindPlayer(connection);
				Item val2 = ((Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.Holding)) ? val.Holding.HeldItem : null);
				if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.Weapon) && val2.ID == message.ItemId)
				{
					AddServerKill(val, message.ItemId);
				}
			}
		}

		private static void AddServerKill(Player player, int itemId)
		{
			string key = default(string);
			if (_serverReady && HasIdentity() && !((Object)(object)player == (Object)null) && !(((NetworkBehaviour)player).Owner == (NetworkConnection)null) && IdentityApi.TryGetKey(player, ref key))
			{
				int key2 = ItemKey(itemId);
				if (!ServerKills.TryGetValue(key, out var value))
				{
					value = new Dictionary<int, int>();
					ServerKills[key] = value;
				}
				int value2;
				int num = (value.TryGetValue(key2, out value2) ? value2 : 0);
				int kills = (value[key2] = ((num == int.MaxValue) ? num : (num + 1)));
				_serverDirty = true;
				Write();
				Send(player, itemId, kills);
			}
		}

		private static void Send(Player player, int itemId, int kills)
		{
			if (HasIdentity() && !((Object)(object)player == (Object)null) && !(((NetworkBehaviour)player).Owner == (NetworkConnection)null) && !((Object)(object)InstanceFinder.ServerManager == (Object)null) && IdentityApi.IsVerified(((NetworkBehaviour)player).Owner))
			{
				InstanceFinder.ServerManager.Broadcast<StatTrakSyncBroadcast>(((NetworkBehaviour)player).Owner, new StatTrakSyncBroadcast(itemId, kills), true, (Channel)0);
			}
		}

		private static void GotSync(StatTrakSyncBroadcast message, Channel channel)
		{
			if (ConfigManager.ShowStatTrak)
			{
				ClientKills[ItemKey(message.ItemId)] = Mathf.Max(0, message.Kills);
			}
		}

		private static int GetServer(string playerKey, int itemKey)
		{
			if (!ServerKills.TryGetValue(playerKey, out var value) || !value.TryGetValue(itemKey, out var value2))
			{
				return 0;
			}
			return value2;
		}

		private static Player FindPlayer(NetworkConnection connection)
		{
			if (connection == (NetworkConnection)null)
			{
				return null;
			}
			foreach (Player player in PlayerManager.Players)
			{
				if ((Object)(object)player != (Object)null && ((NetworkBehaviour)player).Owner != (NetworkConnection)null && ((NetworkBehaviour)player).Owner.ClientId == connection.ClientId)
				{
					return player;
				}
			}
			return null;
		}

		private static int ItemKey(int itemId)
		{
			return itemId & 0xFF;
		}

		private static void Load()
		{
			if (!File.Exists(_path))
			{
				return;
			}
			try
			{
				SaveData saveData = JsonConvert.DeserializeObject<SaveData>(File.ReadAllText(_path));
				if (saveData == null || saveData.Entries == null)
				{
					return;
				}
				for (int i = 0; i < saveData.Entries.Count; i++)
				{
					SaveEntry saveEntry = saveData.Entries[i];
					if (saveEntry != null && !string.IsNullOrEmpty(saveEntry.PlayerKey))
					{
						if (!ServerKills.TryGetValue(saveEntry.PlayerKey, out var value))
						{
							value = new Dictionary<int, int>();
							ServerKills[saveEntry.PlayerKey] = value;
						}
						int key = ItemKey(saveEntry.ItemId);
						int value2;
						int num = (value.TryGetValue(key, out value2) ? value2 : 0);
						int num2 = Mathf.Max(0, saveEntry.Kills);
						value[key] = ((num > int.MaxValue - num2) ? int.MaxValue : (num + num2));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogError((object)("Failed to load StatTrak save: " + ex));
				}
			}
		}

		private static void Write()
		{
			if (!_serverDirty || string.IsNullOrEmpty(_path))
			{
				return;
			}
			try
			{
				string directoryName = Path.GetDirectoryName(_path);
				if (!Directory.Exists(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				SaveData saveData = new SaveData();
				foreach (KeyValuePair<string, Dictionary<int, int>> serverKill in ServerKills)
				{
					foreach (KeyValuePair<int, int> item in serverKill.Value)
					{
						saveData.Entries.Add(new SaveEntry
						{
							PlayerKey = serverKill.Key,
							ItemId = item.Key,
							Kills = item.Value
						});
					}
				}
				File.WriteAllText(_path, JsonConvert.SerializeObject((object)saveData));
				_serverDirty = false;
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogError((object)("Failed to save StatTrak data: " + ex));
				}
			}
		}

		private static string PathFor(string name)
		{
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			foreach (char oldChar in invalidFileNameChars)
			{
				name = name.Replace(oldChar, '_');
			}
			return Path.Combine(Application.persistentDataPath, "Saves", name + ".AmmoCounter.StatTrak.json");
		}

		private static bool HasIdentity()
		{
			return Chainloader.PluginInfos.ContainsKey("IceBoxStudio.HowToFish.IdentityAPI");
		}

		private static void HookIdentity()
		{
			if (!_identityHook && HasIdentity())
			{
				IdentityApi.Verified += IdentityReady;
				_identityHook = true;
			}
		}

		private static void SetupSerializers()
		{
			if (!_serializersReady)
			{
				GenericWriter<StatTrakKillBroadcast>.SetWrite((Action<Writer, StatTrakKillBroadcast>)WriteKill);
				GenericReader<StatTrakKillBroadcast>.SetRead((Func<Reader, StatTrakKillBroadcast>)ReadKill);
				GenericWriter<StatTrakSyncBroadcast>.SetWrite((Action<Writer, StatTrakSyncBroadcast>)WriteSync);
				GenericReader<StatTrakSyncBroadcast>.SetRead((Func<Reader, StatTrakSyncBroadcast>)ReadSync);
				_serializersReady = true;
			}
		}

		private static void WriteKill(Writer writer, StatTrakKillBroadcast message)
		{
			writer.WriteInt32(message.ItemId);
		}

		private static StatTrakKillBroadcast ReadKill(Reader reader)
		{
			return new StatTrakKillBroadcast(reader.ReadInt32());
		}

		private static void WriteSync(Writer writer, StatTrakSyncBroadcast message)
		{
			writer.WriteInt32(message.ItemId);
			writer.WriteInt32(message.Kills);
		}

		private static StatTrakSyncBroadcast ReadSync(Reader reader)
		{
			return new StatTrakSyncBroadcast(reader.ReadInt32(), reader.ReadInt32());
		}
	}
}
namespace AmmoCounter.UI
{
	internal sealed class AmmoUi : MonoBehaviour
	{
		private const int PreviewSize = 64;

		private const float PreviewDistance = 10f;

		private const float PanelWidth = 238f;

		private const float PanelHeight = 104f;

		private const float ContentRight = 16f;

		private const float AttachmentBaseSize = 20f;

		private const float AttachmentBaseGap = 4f;

		private const float AttachmentTopGap = 6f;

		private static readonly int PreviewLayer = LayerMask.NameToLayer("UI");

		private static AmmoUi _current;

		private RectTransform _root;

		private CanvasGroup _canvas;

		private Image _background;

		private Color _backgroundColor;

		private TextMeshProUGUI _weaponName;

		private TextMeshProUGUI _statTrakText;

		private TextMeshProUGUI _ammoText;

		private RawImage[] _attachmentImages;

		private Camera _previewCamera;

		private Light _previewLight;

		private Weapon _lastWeapon;

		private int _lastAmmo = -1;

		private int _lastKills = -1;

		private int _lastAttachments = -1;

		private bool _visible;

		private bool _built;

		internal static void Attach()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			if (Object.op_Implicit((Object)(object)_current))
			{
				return;
			}
			Transform fXCanvasTrans = PlayerUI.FXCanvasTrans;
			if (Object.op_Implicit((Object)(object)fXCanvasTrans))
			{
				GameObject val = new GameObject("AmmoCounter UI", new Type[1] { typeof(RectTransform) });
				val.transform.SetParent(fXCanvasTrans, false);
				_current = val.AddComponent<AmmoUi>();
				if (!_current.Build())
				{
					Object.Destroy((Object)(object)val);
					_current = null;
				}
			}
		}

		internal static void Tick()
		{
			if (Object.op_Implicit((Object)(object)_current))
			{
				_current.Run();
			}
		}

		internal static void Stop()
		{
			if (Object.op_Implicit((Object)(object)_current))
			{
				Object.Destroy((Object)(object)((Component)_current).gameObject);
			}
			_current = null;
		}

		private bool Build()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI canvasTextPrefab = PlayerUI.CanvasTextPrefab;
			if (!Object.op_Implicit((Object)(object)canvasTextPrefab))
			{
				return false;
			}
			_root = ((Component)this).GetComponent<RectTransform>();
			_root.anchorMin = new Vector2(1f, 0f);
			_root.anchorMax = new Vector2(1f, 0f);
			_root.pivot = new Vector2(1f, 0f);
			_root.sizeDelta = new Vector2(238f, 104f);
			AddBackground();
			_canvas = ((Component)this).gameObject.AddComponent<CanvasGroup>();
			_canvas.alpha = 0f;
			_canvas.blocksRaycasts = false;
			_canvas.interactable = false;
			float num = 206f;
			_weaponName = AddText(canvasTextPrefab, "WeaponName", 19f, new Vector2(0f, 27f), new Vector2(num, 24f), (TextAlignmentOptions)516);
			_statTrakText = AddText(canvasTextPrefab, "StatTrak", 15f, new Vector2(0f, 4f), new Vector2(num, 18f), (TextAlignmentOptions)516);
			_ammoText = AddText(canvasTextPrefab, "Ammo", 34f, new Vector2(0f, -28f), new Vector2(num, 40f), (TextAlignmentOptions)516);
			_attachmentImages = (RawImage[])(object)new RawImage[4]
			{
				AddImage("Sight"),
				AddImage("Barrel"),
				AddImage("Laser"),
				AddImage("Magazine")
			};
			_previewCamera = MakeCamera();
			_previewLight = MakeLight();
			if (!Object.op_Implicit((Object)(object)_weaponName) || !Object.op_Implicit((Object)(object)_statTrakText) || !Object.op_Implicit((Object)(object)_ammoText) || !Object.op_Implicit((Object)(object)_previewCamera) || !Object.op_Implicit((Object)(object)_previewLight))
			{
				return false;
			}
			_built = true;
			LocalizationApi.LanguageChanged += OnLanguageChanged;
			Layout();
			Show(to: false);
			return true;
		}

		private void Run()
		{
			if (!_built || !Object.op_Implicit((Object)(object)Player.LocalPlayer))
			{
				Show(to: false);
				return;
			}
			AddBackground();
			Layout();
			Player localPlayer = Player.LocalPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer.Holding) || !Object.op_Implicit((Object)(object)localPlayer.Holding.HeldItem) || !Object.op_Implicit((Object)(object)localPlayer.Holding.HeldItem.Weapon) || localPlayer.Dying.IsDead || PauseManager.IsPaused || PlayerThinking.IsThinking || PlayerUI.UIDisabled)
			{
				Show(to: false);
				return;
			}
			Weapon weapon = localPlayer.Holding.HeldItem.Weapon;
			if (ConfigManager.HideWhileAiming && weapon.IsAds)
			{
				Show(to: false);
				return;
			}
			int num = AttachmentState(weapon.Attachments);
			Item heldItem = localPlayer.Holding.HeldItem;
			int num2 = StatTrakRuntime.Get(heldItem);
			if ((Object)(object)_lastWeapon != (Object)(object)weapon || _lastAmmo != weapon.Ammo || _lastKills != num2)
			{
				_lastWeapon = weapon;
				_lastAmmo = weapon.Ammo;
				_lastKills = num2;
				SetText(heldItem, weapon, num2);
			}
			if (_lastAttachments != num)
			{
				_lastAttachments = num;
				SetAttachments(weapon);
			}
			LayoutAttachments();
			SetColors(weapon);
			Show(to: true);
		}

		private void SetText(Item item, Weapon weapon, int kills)
		{
			((TMP_Text)_weaponName).text = I18n.Text("ammo.ui.weapon", item.GetName());
			((TMP_Text)_statTrakText).text = I18n.Text("ammo.ui.stattrak", kills);
			((TMP_Text)_ammoText).text = I18n.Text("ammo.ui.ammo", weapon.Ammo);
			((Component)_weaponName).gameObject.SetActive(ConfigManager.ShowWeaponName);
			((Component)_statTrakText).gameObject.SetActive(ConfigManager.ShowStatTrak);
		}

		private void SetColors(Weapon weapon)
		{
			//IL_0051: 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_004a: 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_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Max(1, weapon.Attachments.AmmoPerMag);
			bool num2 = weapon.Ammo <= 1;
			bool flag = !num2 && weapon.Ammo <= Mathf.CeilToInt((float)num * ConfigManager.LowAmmoThreshold);
			Color val = (num2 ? ConfigManager.LastBulletColor : (flag ? ConfigManager.LowAmmoColor : ConfigManager.NormalColor));
			float num3 = ((num2 && ConfigManager.FlashLastRound) ? Mathf.Lerp(0.35f, 1f, Mathf.PingPong(Time.unscaledTime * 4f, 1f)) : 1f);
			val.a = Mathf.Clamp01(val.a * ConfigManager.Opacity * num3);
			((Graphic)_ammoText).color = val;
			Color normalColor = ConfigManager.NormalColor;
			normalColor.a = Mathf.Clamp01(normalColor.a * ConfigManager.Opacity);
			((Graphic)_weaponName).color = normalColor;
			((Component)_weaponName).gameObject.SetActive(ConfigManager.ShowWeaponName);
			((Graphic)_statTrakText).color = normalColor;
			((Component)_statTrakText).gameObject.SetActive(ConfigManager.ShowStatTrak);
			for (int i = 0; i < _attachmentImages.Length; i++)
			{
				if (((Component)_attachmentImages[i]).gameObject.activeSelf)
				{
					((Graphic)_attachmentImages[i]).color = new Color(1f, 1f, 1f, ConfigManager.Opacity);
				}
			}
		}

		private void Layout()
		{
			//IL_0011: 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_002b: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			_root.anchoredPosition = new Vector2(0f - ConfigManager.OffsetX, ConfigManager.OffsetY);
			((Transform)_root).localScale = Vector3.one * ConfigManager.Scale;
			if (Object.op_Implicit((Object)(object)_background))
			{
				Color backgroundColor = _backgroundColor;
				backgroundColor.a = Mathf.Clamp01(backgroundColor.a * ConfigManager.Opacity);
				((Graphic)_background).color = backgroundColor;
			}
		}

		private void Show(bool to)
		{
			if (_visible != to)
			{
				_visible = to;
				_canvas.alpha = (to ? 1f : 0f);
			}
		}

		private void SetAttachments(Weapon weapon)
		{
			Attachments attachments = weapon.Attachments;
			DrawAttachment(0, (attachments.Sight == 0) ? null : ((Component)GetSight(attachments)).gameObject, temporary: false);
			DrawAttachment(1, (attachments.BarrelAttachment == 0) ? null : ((Component)GetBarrel(attachments)).gameObject, temporary: false);
			DrawAttachment(2, attachments.LaserSight ? ((Component)GetLaser(attachments)).gameObject : null, temporary: false);
			DrawAttachment(3, attachments.ExtendedMag ? WeaponPreview(weapon) : null, temporary: true);
			LayoutAttachments();
		}

		private void DrawAttachment(int index, GameObject model, bool temporary)
		{
			//IL_0045: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: 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_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Expected O, but got Unknown
			RawImage val = _attachmentImages[index];
			((Component)val).gameObject.SetActive((Object)(object)model != (Object)null);
			if (!Object.op_Implicit((Object)(object)model))
			{
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(model);
			if (temporary)
			{
				Object.Destroy((Object)(object)model);
			}
			((Object)val2).name = "AmmoCounter Preview Model";
			val2.transform.position = Vector3.down * 10000f;
			val2.transform.rotation = Quaternion.Euler(20f, 145f, 0f);
			SetLayer(val2.transform, PreviewLayer);
			DisableScripts(val2);
			MeshRenderer[] componentsInChildren = val2.GetComponentsInChildren<MeshRenderer>(true);
			if (componentsInChildren.Length == 0)
			{
				((Component)val).gameObject.SetActive(false);
				Object.Destroy((Object)(object)val2);
				return;
			}
			Bounds bounds = ((Renderer)componentsInChildren[0]).bounds;
			for (int i = 1; i < componentsInChildren.Length; i++)
			{
				((Bounds)(ref bounds)).Encapsulate(((Renderer)componentsInChildren[i]).bounds);
			}
			((Component)_previewCamera).transform.position = ((Bounds)(ref bounds)).center - Vector3.forward * 10f;
			((Component)_previewCamera).transform.rotation = Quaternion.identity;
			_previewCamera.orthographicSize = Mathf.Max(((Bounds)(ref bounds)).extents.x, ((Bounds)(ref bounds)).extents.y) * 1.3f;
			_previewCamera.targetTexture = (RenderTexture)val.texture;
			_previewCamera.Render();
			_previewCamera.targetTexture = null;
			val2.SetActive(false);
			Object.Destroy((Object)(object)val2);
		}

		private static Sight GetSight(Attachments attachments)
		{
			return (AccessTools.Field(typeof(Attachments), "_sights").GetValue(attachments) as List<Sight>)[attachments.Sight];
		}

		private static BarrelAttachment GetBarrel(Attachments attachments)
		{
			return (AccessTools.Field(typeof(Attachments), "_barrelAttachments").GetValue(attachments) as List<BarrelAttachment>)[attachments.BarrelAttachment];
		}

		private static LaserSight GetLaser(Attachments attachments)
		{
			object? value = AccessTools.Field(typeof(Attachments), "_laserSight").GetValue(attachments);
			return (LaserSight)((value is LaserSight) ? value : null);
		}

		private static GameObject WeaponPreview(Weapon weapon)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			GameObject val = new GameObject("AmmoCounter Weapon Preview", new Type[2]
			{
				typeof(MeshFilter),
				typeof(MeshRenderer)
			});
			val.GetComponent<MeshFilter>().sharedMesh = ((Item)weapon).Mesh;
			List<Renderer> list = AccessTools.Field(typeof(Item), "_renderers").GetValue(weapon) as List<Renderer>;
			((Renderer)val.GetComponent<MeshRenderer>()).sharedMaterials = list[0].sharedMaterials;
			return val;
		}

		private static int AttachmentState(Attachments attachments)
		{
			return attachments.Sight | (attachments.BarrelAttachment << 8) | (attachments.LaserSight ? 65536 : 0) | (attachments.ExtendedMag ? 131072 : 0);
		}

		private void OnLanguageChanged(string language)
		{
			_lastWeapon = null;
			_lastKills = -1;
		}

		private void OnDestroy()
		{
			LocalizationApi.LanguageChanged -= OnLanguageChanged;
			if (Object.op_Implicit((Object)(object)_previewCamera))
			{
				Object.Destroy((Object)(object)((Component)_previewCamera).gameObject);
			}
			if (Object.op_Implicit((Object)(object)_previewLight))
			{
				Object.Destroy((Object)(object)((Component)_previewLight).gameObject);
			}
			int num = 0;
			while (_attachmentImages != null && num < _attachmentImages.Length)
			{
				Texture texture = _attachmentImages[num].texture;
				RenderTexture val = (RenderTexture)(object)((texture is RenderTexture) ? texture : null);
				if (val != null)
				{
					val.Release();
					Object.Destroy((Object)(object)val);
				}
				num++;
			}
			if ((Object)(object)_current == (Object)(object)this)
			{
				_current = null;
			}
		}

		private static TextMeshProUGUI AddText(TextMeshProUGUI template, string name, float size, Vector2 position, Vector2 dimensions, TextAlignmentOptions alignment)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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_0097: 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)
			TextMeshProUGUI obj = Object.Instantiate<TextMeshProUGUI>(template, ((Component)_current).transform, false);
			((Object)((Component)obj).gameObject).name = name;
			((Component)obj).gameObject.SetActive(true);
			DisableScripts(((Component)obj).gameObject);
			((TMP_Text)obj).fontSize = size;
			((TMP_Text)obj).alignment = alignment;
			((Graphic)obj).raycastTarget = false;
			((TMP_Text)obj).textWrappingMode = (TextWrappingModes)0;
			RectTransform rectTransform = ((TMP_Text)obj).rectTransform;
			rectTransform.anchorMin = new Vector2(0.5f, 0.5f);
			rectTransform.anchorMax = new Vector2(0.5f, 0.5f);
			rectTransform.pivot = new Vector2(0.5f, 0.5f);
			rectTransform.anchoredPosition = position;
			rectTransform.sizeDelta = dimensions;
			return obj;
		}

		private RawImage AddImage(string name)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			//IL_006b: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(RawImage)
			});
			val.transform.SetParent(((Component)this).transform, false);
			RawImage component = val.GetComponent<RawImage>();
			((Graphic)component).raycastTarget = false;
			component.texture = (Texture)new RenderTexture(64, 64, 16, (RenderTextureFormat)0);
			((RenderTexture)component.texture).Create();
			RectTransform rectTransform = ((Graphic)component).rectTransform;
			rectTransform.anchorMin = new Vector2(0.5f, 0.5f);
			rectTransform.anchorMax = new Vector2(0.5f, 0.5f);
			rectTransform.pivot = new Vector2(0.5f, 0.5f);
			rectTransform.anchoredPosition = new Vector2(52f, 10f);
			rectTransform.sizeDelta = new Vector2(20f, 20f);
			val.SetActive(false);
			return component;
		}

		private void LayoutAttachments()
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			for (int i = 0; i < _attachmentImages.Length; i++)
			{
				if (((Component)_attachmentImages[i]).gameObject.activeSelf)
				{
					num++;
				}
			}
			float num2 = 20f * ConfigManager.AttachmentScale;
			float num3 = 4f * ConfigManager.AttachmentScale;
			float num4 = 52f + num2 * 0.5f + 6f;
			float num5 = (float)num * num2 + (float)(num - 1) * num3;
			float num6 = 103f - num5 + num2 * 0.5f;
			for (int j = 0; j < _attachmentImages.Length; j++)
			{
				if (((Component)_attachmentImages[j]).gameObject.activeSelf)
				{
					((Graphic)_attachmentImages[j]).rectTransform.sizeDelta = new Vector2(num2, num2);
					((Graphic)_attachmentImages[j]).rectTransform.anchoredPosition = new Vector2(num6, num4);
					num6 += num2 + num3;
				}
			}
		}

		private void AddBackground()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)_background))
			{
				Image val = FindBackground();
				if (Object.op_Implicit((Object)(object)val))
				{
					_background = ((Component)this).gameObject.AddComponent<Image>();
					CopyImage(val, _background);
					((Graphic)_background).raycastTarget = false;
					_backgroundColor = ((Graphic)_background).color;
				}
			}
		}

		private static Image FindBackground()
		{
			Player localPlayer = Player.LocalPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)localPlayer.Inventory))
			{
				return null;
			}
			if (!(AccessTools.Field(typeof(PlayerInventory), "_itemSlots").GetValue(localPlayer.Inventory) is List<InventorySlot> list))
			{
				return null;
			}
			for (int i = 0; i < list.Count; i++)
			{
				if (!Object.op_Implicit((Object)(object)list[i]))
				{
					continue;
				}
				Image[] componentsInChildren = ((Component)list[i]).GetComponentsInChildren<Image>(true);
				foreach (Image val in componentsInChildren)
				{
					if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)((Graphic)val).material) && ((Object)((Graphic)val).material).name == "UIBlur")
					{
						return val;
					}
				}
			}
			return null;
		}

		private static void CopyImage(Image source, Image target)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			target.sprite = source.sprite;
			target.type = source.type;
			target.preserveAspect = source.preserveAspect;
			target.fillCenter = source.fillCenter;
			target.fillMethod = source.fillMethod;
			target.fillAmount = source.fillAmount;
			target.fillClockwise = source.fillClockwise;
			target.fillOrigin = source.fillOrigin;
			target.pixelsPerUnitMultiplier = source.pixelsPerUnitMultiplier;
			((Graphic)target).material = ((Graphic)source).material;
			((Graphic)target).color = ((Graphic)source).color;
		}

		private static Camera MakeCamera()
		{
			//IL_0018: 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)
			Camera component = new GameObject("AmmoCounter Preview Camera", new Type[1] { typeof(Camera) }).GetComponent<Camera>();
			((Behaviour)component).enabled = false;
			component.orthographic = true;
			component.clearFlags = (CameraClearFlags)2;
			component.backgroundColor = Color.clear;
			component.cullingMask = 1 << PreviewLayer;
			component.nearClipPlane = 0.01f;
			component.farClipPlane = 20f;
			return component;
		}

		private static Light MakeLight()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			Light component = new GameObject("AmmoCounter Preview Light", new Type[1] { typeof(Light) }).GetComponent<Light>();
			component.type = (LightType)1;
			component.intensity = 1.2f;
			component.cullingMask = 1 << PreviewLayer;
			((Component)component).transform.rotation = Quaternion.Euler(35f, -35f, 0f);
			return component;
		}

		private static void SetLayer(Transform root, int layer)
		{
			((Component)root).gameObject.layer = layer;
			for (int i = 0; i < root.childCount; i++)
			{
				SetLayer(root.GetChild(i), layer);
			}
		}

		private static void DisableScripts(GameObject root)
		{
			MonoBehaviour[] componentsInChildren = root.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren)
			{
				if (!(val is Graphic) && !(val is Selectable) && !(val is TMP_Text) && !(val is Shadow) && !(val is LayoutGroup) && !(val is LayoutElement) && !(val is ContentSizeFitter) && !(val is RectMask2D))
				{
					((Behaviour)val).enabled = false;
				}
			}
		}
	}
}
namespace AmmoCounter.Patches
{
	[HarmonyPatch(typeof(PlayerUI), "Update")]
	internal static class AmmoInputPatch
	{
		private static void Postfix()
		{
			AmmoRuntime.Tick();
		}
	}
	[HarmonyPatch(typeof(Player), "OnStartClient")]
	internal static class PlayerStartPatch
	{
		private static void Postfix(Player __instance)
		{
			AmmoRuntime.Start(__instance);
		}
	}
	[HarmonyPatch(typeof(Player), "OnStopClient")]
	internal static class PlayerStopPatch
	{
		private static void Postfix(Player __instance)
		{
			AmmoRuntime.Stop(__instance);
		}
	}
	[HarmonyPatch(typeof(PlayerSkills), "OnKill")]
	internal static class StatTrakPatch
	{
		private static void Postfix()
		{
			AmmoRuntime.Kill();
		}
	}
	[HarmonyPatch(typeof(MoneyManager), "OnStartServer")]
	internal static class StatTrakServerStartPatch
	{
		private static void Postfix()
		{
			StatTrakRuntime.ServerStart();
		}
	}
	[HarmonyPatch(typeof(MoneyManager), "OnStartClient")]
	internal static class StatTrakClientStartPatch
	{
		private static void Postfix()
		{
			StatTrakRuntime.SetupNet();
		}
	}
	[HarmonyPatch(typeof(SaveManager), "SaveServer")]
	internal static class StatTrakSavePatch
	{
		private static void Prefix()
		{
			StatTrakRuntime.Save();
		}
	}
	[HarmonyPatch(typeof(Server), "OnStopServer")]
	internal static class StatTrakStopPatch
	{
		private static void Postfix()
		{
			StatTrakRuntime.ServerStop();
		}
	}
}
namespace AmmoCounter.Localization
{
	internal static class I18n
	{
		private const string FileName = "AmmoCounter.Localization.json";

		private static readonly ModLocalizer _localizer = Load();

		internal static string Text(string key, params object[] args)
		{
			return _localizer.GetLocalizedText(key, args);
		}

		private static ModLocalizer Load()
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			ModLocalizer obj = LocalizationApi.For("IceBoxStudio.HowToFish.AmmoCounter");
			obj.RegisterJson(Path.Combine(directoryName, "AmmoCounter.Localization.json"));
			return obj;
		}
	}
}
namespace AmmoCounter.Configuration
{
	internal static class ConfigManager
	{
		private static ConfigEntry<float> _offsetX;

		private static ConfigEntry<float> _offsetY;

		private static ConfigEntry<float> _scale;

		private static ConfigEntry<float> _attachmentScale;

		private static ConfigEntry<float> _opacity;

		private static ConfigEntry<float> _lowAmmoThreshold;

		private static ConfigEntry<bool> _showWeaponName;

		private static ConfigEntry<bool> _showStatTrak;

		private static ConfigEntry<bool> _hideWhileAiming;

		private static ConfigEntry<bool> _flashLastRound;

		private static ConfigEntry<Color> _normalColor;

		private static ConfigEntry<Color> _lowAmmoColor;

		private static ConfigEntry<Color> _lastBulletColor;

		internal static float OffsetX => Mathf.Max(0f, _offsetX.Value);

		internal static float OffsetY => Mathf.Max(0f, _offsetY.Value);

		internal static float Scale => Mathf.Clamp(_scale.Value, 0.5f, 2f);

		internal static float AttachmentScale => Mathf.Clamp(_attachmentScale.Value, 0.5f, 3f);

		internal static float Opacity => Mathf.Clamp01(_opacity.Value);

		internal static float LowAmmoThreshold => Mathf.Clamp01(_lowAmmoThreshold.Value);

		internal static bool ShowWeaponName => _showWeaponName.Value;

		internal static bool ShowStatTrak => _showStatTrak.Value;

		internal static bool HideWhileAiming => _hideWhileAiming.Value;

		internal static bool FlashLastRound => _flashLastRound.Value;

		internal static Color NormalColor => _normalColor.Value;

		internal static Color LowAmmoColor => _lowAmmoColor.Value;

		internal static Color LastBulletColor => _lastBulletColor.Value;

		internal static void Init(ConfigFile config)
		{
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			_offsetX = config.Bind<float>("UI", "OffsetX", 32f, I18n.Text("ammo.config.offset_x"));
			_offsetY = config.Bind<float>("UI", "OffsetY", 32f, I18n.Text("ammo.config.offset_y"));
			_scale = config.Bind<float>("UI", "Scale", 1f, I18n.Text("ammo.config.scale"));
			_attachmentScale = config.Bind<float>("UI", "AttachmentScale", 1f, I18n.Text("ammo.config.attachment_scale"));
			_opacity = config.Bind<float>("UI", "Opacity", 0.86f, I18n.Text("ammo.config.opacity"));
			_lowAmmoThreshold = config.Bind<float>("UI", "LowAmmoThreshold", 0.25f, I18n.Text("ammo.config.low_threshold"));
			_showWeaponName = config.Bind<bool>("UI", "ShowWeaponName", true, I18n.Text("ammo.config.show_weapon_name"));
			_showStatTrak = config.Bind<bool>("UI", "ShowStatTrak", true, I18n.Text("ammo.config.show_stattrak"));
			_hideWhileAiming = config.Bind<bool>("UI", "HideWhileAiming", false, I18n.Text("ammo.config.hide_aiming"));
			_flashLastRound = config.Bind<bool>("UI", "FlashLastRound", true, I18n.Text("ammo.config.flash_last_round"));
			_normalColor = config.Bind<Color>("Colors", "NormalColor", new Color(0.86f, 0.94f, 1f, 1f), I18n.Text("ammo.config.normal_color"));
			_lowAmmoColor = config.Bind<Color>("Colors", "LowAmmoColor", new Color(1f, 0.82f, 0.35f, 1f), I18n.Text("ammo.config.low_color"));
			_lastBulletColor = config.Bind<Color>("Colors", "LastBulletColor", new Color(1f, 0.38f, 0.24f, 1f), I18n.Text("ammo.config.last_color"));
			config.Save();
		}
	}
}