Decompiled source of BloodyEncounters v3.0.0

BloodyEncounters.dll

Decompiled 5 months ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.Json;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Bloodstone.API;
using Bloody.Core;
using Bloody.Core.API.v1;
using Bloody.Core.GameData.v1;
using Bloody.Core.Helper.v1;
using Bloody.Core.Methods;
using Bloody.Core.Models.v1;
using Bloody.Core.Models.v1.Base;
using Bloody.Core.Patch.Server;
using BloodyEncounters.Data;
using BloodyEncounters.Data.Models;
using BloodyEncounters.EventsHandler;
using BloodyEncounters.Exceptions;
using HarmonyLib;
using ProjectM;
using ProjectM.Shared;
using Stunlock.Core;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using VampireCommandFramework;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("BloodyEncounters")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A server side mod for V Rising which spawns a random NPC near a random online player at random intervals, and the player wins a random item reward if the NPC is killed within the given time limit.")]
[assembly: AssemblyFileVersion("3.0.1.0")]
[assembly: AssemblyInformationalVersion("3.0.1+1.Branch.master.Sha.aae5bc66d36eaa365dfdb46f68203648d9aa1445")]
[assembly: AssemblyProduct("BloodyEncounters")]
[assembly: AssemblyTitle("BloodyEncounters")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("3.0.1.0")]
[module: UnverifiableCode]
namespace BloodyEncounters
{
	internal class EncounterSystem
	{
		public static bool EncounterStarted = false;

		private static readonly ConcurrentDictionary<ulong, ConcurrentDictionary<int, ItemEncounterModel>> RewardsMap = new ConcurrentDictionary<ulong, ConcurrentDictionary<int, ItemEncounterModel>>();

		private static readonly ConcurrentDictionary<int, UserModel> NpcPlayerMap = new ConcurrentDictionary<int, UserModel>();

		private static PrefabCollectionSystem _prefabCollectionSystem = Plugin.SystemsCore.PrefabCollectionSystem;

		internal static Dictionary<long, (float actualDuration, Action<Entity> Actions)> PostActions = new Dictionary<long, (float, Action<Entity>)>();

		public static Random Random = new Random();

		public static Action encounterAction;

		internal static void Initialize()
		{
			if (Config.Enabled.Value)
			{
				GenerateStats();
				StartEncounterTimer();
			}
		}

		internal static void GenerateStats()
		{
			foreach (NpcEncounterModel item in Database.NPCS.Where((NpcEncounterModel x) => x.unitStats == null).ToList())
			{
				item.GenerateStats();
			}
			Database.saveDatabase();
		}

		public static void StartEncounterTimer()
		{
			Plugin.Logger.LogInfo("Start Timner for encounters");
			encounterAction = delegate
			{
				if (Config.Enabled.Value)
				{
					ActionScheduler.RunActionOnMainThread((Action)delegate
					{
						StartEncounter();
					});
				}
			};
			CoroutineHandler.StartRandomIntervalCoroutine(encounterAction, (float)Config.EncounterTimerMin.Value, (float)Config.EncounterTimerMax.Value);
		}

		internal static void StartEncounter(UserModel user = null)
		{
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			if (EncounterStarted)
			{
				return;
			}
			_ = Core.World;
			if (user == null)
			{
				IEnumerable<UserModel> source = GameData.Users.Online.Where((UserModel u) => GameData.Users.FromEntity(((EntityModel)u).Entity).Character.Equipment.Level >= (float)Config.EncounterMinLevel.Value);
				if (Config.SkipPlayersInCastle.Value)
				{
					source = source.Where((UserModel u) => !UserModelMethods.IsInCastle(u));
				}
				if (Config.SkipPlayersInCombat.Value)
				{
					source = source.Where((UserModel u) => !UserModelMethods.IsInCombat(u));
				}
				user = source.OrderBy((UserModel _) => Random.Next()).FirstOrDefault();
			}
			if (user == null)
			{
				Plugin.Logger.LogMessage("Could not find any eligible players for a random encounter...");
				return;
			}
			NpcEncounterModel npc = DataFactory.GetRandomNpc();
			if (npc == null)
			{
				Plugin.Logger.LogWarning("Could not find any NPCs");
				return;
			}
			Plugin.Logger.LogMessage("Attempting to start a new encounter for " + user.CharacterName);
			try
			{
				string empty = string.Empty;
				NpcPlayerMap[npc.PrefabGUID] = user;
				if (npc.Group != "")
				{
					foreach (NpcEncounterModel item in Database.NPCS.Where((NpcEncounterModel x) => x.Group == npc.Group).ToList())
					{
						item.Spawn(((EntityModel)user).Entity, user.Position, npc.Lifetime);
					}
					empty = string.Format(Config.EncounterMessageGroupTemplate.Value, npc.Group, npc.Lifetime);
				}
				else
				{
					npc.Spawn(((EntityModel)user).Entity, user.Position);
					empty = string.Format(Config.EncounterMessageTemplate.Value, npc.name, npc.Lifetime);
				}
				UserModelMethods.SendSystemMessage(user, empty);
				EncounterStarted = true;
				CoroutineHandler.StartRepeatingCoroutine((Action)delegate
				{
					//IL_009a: Unknown result type (might be due to invalid IL or missing references)
					//IL_0064: Unknown result type (might be due to invalid IL or missing references)
					if (EncounterStarted)
					{
						if (npc.Group != "")
						{
							foreach (NpcEncounterModel item2 in Database.NPCS.Where((NpcEncounterModel x) => x.Group == npc.Group).ToList())
							{
								item2.KillNpc(((EntityModel)user).Entity);
							}
							EncounterStarted = false;
						}
						else
						{
							npc.KillNpc(((EntityModel)user).Entity);
							EncounterStarted = false;
						}
					}
				}, npc.Lifetime, 1);
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError(ex);
				EncounterStarted = false;
			}
		}
	}
	[BepInPlugin("BloodyEncounters", "BloodyEncounters", "3.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[Reloadable]
	public class Plugin : BasePlugin, IRunOnInitialized
	{
		private Harmony _harmony;

		public static Logger Logger;

		public static SystemsCore SystemsCore;

		public override void Load()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			ManualLogSource log = ((BasePlugin)this).Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(27, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Plugin ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("BloodyEncounters");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" version ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("3.0.1");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" is loaded!");
			}
			log.LogInfo(val);
			Logger = new Logger(((BasePlugin)this).Log);
			_harmony = new Harmony("BloodyEncounters");
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			EventsHandlerSystem.OnInitialize += new OnGameDataInitializedEventHandler(GameDataOnInitialize);
			EventsHandlerSystem.OnDestroy += new OnGameDataDestroyedEventHandler(GameDataOnDestroy);
			CommandRegistry.RegisterAll();
		}

		public override bool Unload()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			EventsHandlerSystem.OnInitialize -= new OnGameDataInitializedEventHandler(GameDataOnInitialize);
			EventsHandlerSystem.OnDestroy -= new OnGameDataDestroyedEventHandler(GameDataOnDestroy);
			EventsHandlerSystem.OnDeath -= new DeathEventHandler(OnDeath.OnDeathEvent);
			CommandRegistry.UnregisterAssembly();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			return true;
		}

		public void OnGameInitialized()
		{
		}

		private static void GameDataOnInitialize(World world)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			SystemsCore = Core.SystemsCore;
			Logger.LogInfo("Loading main data");
			Database.Initialize();
			Logger.LogInfo("Binding configuration");
			Config.Initialize();
			EventsHandlerSystem.OnDeath += new DeathEventHandler(OnDeath.OnDeathEvent);
			EncounterSystem.Initialize();
		}

		private static void GameDataOnDestroy()
		{
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "BloodyEncounters";

		public const string PLUGIN_NAME = "BloodyEncounters";

		public const string PLUGIN_VERSION = "3.0.1";
	}
}
namespace BloodyEncounters.Exceptions
{
	internal class NPCDontExistException : Exception
	{
		public NPCDontExistException()
		{
		}

		public NPCDontExistException(string message)
			: base(message)
		{
		}

		public NPCDontExistException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		protected NPCDontExistException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}
	}
	internal class NPCExistException : Exception
	{
		public NPCExistException()
		{
		}

		public NPCExistException(string message)
			: base(message)
		{
		}

		public NPCExistException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		protected NPCExistException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}
	}
	internal class ProductDontExistException : Exception
	{
		public ProductDontExistException()
		{
		}

		public ProductDontExistException(string message)
			: base(message)
		{
		}

		public ProductDontExistException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		protected ProductDontExistException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}
	}
	internal class ProductExistException : Exception
	{
		public ProductExistException()
		{
		}

		public ProductExistException(string message)
			: base(message)
		{
		}

		public ProductExistException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		protected ProductExistException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}
	}
}
namespace BloodyEncounters.EventsHandler
{
	internal class OnDeath
	{
		public static void OnDeathEvent(DeathEventListenerSystem sender, NativeArray<DeathEvent> deathEvents)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: 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_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			PrefabCollectionSystem prefabCollectionSystem = Plugin.SystemsCore.PrefabCollectionSystem;
			Enumerator<DeathEvent> enumerator = deathEvents.GetEnumerator();
			PrefabGUID val2 = default(PrefabGUID);
			Entity val3 = default(Entity);
			while (enumerator.MoveNext())
			{
				DeathEvent current = enumerator.Current;
				if (!ECSExtensions.Has<PlayerCharacter>(current.Killer) || !ECSExtensions.Has<NameableInteractable>(current.Died))
				{
					continue;
				}
				EntityManager entityManager = ((ComponentSystemBase)sender).EntityManager;
				PlayerCharacter componentData = ((EntityManager)(ref entityManager)).GetComponentData<PlayerCharacter>(current.Killer);
				UserModel userModel = GameData.Users.FromEntity(componentData.UserEntity);
				PrefabGUID val = ECSExtensions.Read<PrefabGUID>(current.Died);
				FixedString128Bytes npc = prefabCollectionSystem._PrefabDataLookup[val].AssetName;
				NpcEncounterModel npcEncounterModel = Database.NPCS.Where((NpcEncounterModel x) => x.AssetName == ((object)(FixedString128Bytes)(ref npc)).ToString()).FirstOrDefault();
				if (npcEncounterModel == null)
				{
					EncounterSystem.EncounterStarted = false;
				}
				else
				{
					if (!npcEncounterModel.GetNPCEntity())
					{
						continue;
					}
					ItemEncounterModel randomItem = DataFactory.GetRandomItem(npcEncounterModel);
					((PrefabGUID)(ref val2))..ctor(randomItem.ItemID);
					int stack = randomItem.Stack;
					if (!UserModelMethods.TryGiveItem(userModel, val2, stack, ref val3))
					{
						Plugin.Logger.LogError(userModel.CharacterName + " Error Drop " + randomItem.name);
					}
					string text = string.Format(Config.RewardMessageTemplate.Value, randomItem.Color, randomItem.name);
					UserModelMethods.SendSystemMessage(userModel, text);
					Plugin.Logger.LogDebug(userModel.CharacterName + " earned reward: " + randomItem.name);
					string text2 = string.Format(Config.RewardAnnouncementMessageTemplate.Value, userModel.CharacterName, randomItem.Color, randomItem.name);
					if (Config.NotifyAllPlayersAboutRewards.Value)
					{
						foreach (UserModel item in GameData.Users.Online.Where((UserModel u) => u.PlatformId != userModel.PlatformId))
						{
							UserModelMethods.SendSystemMessage(item, text2);
						}
					}
					else if (Config.NotifyAdminsAboutEncountersAndRewards.Value)
					{
						foreach (UserModel item2 in GameData.Users.Online.Where((UserModel x) => x.IsAdmin))
						{
							UserModelMethods.SendSystemMessage(item2, $"{userModel.CharacterName} earned an encounter reward: <color={randomItem.Color}>{randomItem.name}</color>");
						}
					}
					EncounterSystem.EncounterStarted = false;
				}
			}
		}
	}
}
namespace BloodyEncounters.Data
{
	internal class Config
	{
		private static ConfigFile _mainConfig;

		public static ConfigEntry<bool> Enabled { get; private set; }

		public static ConfigEntry<bool> SkipPlayersInCastle { get; private set; }

		public static ConfigEntry<int> EncounterTimerMin { get; private set; }

		public static ConfigEntry<int> EncounterTimerMax { get; private set; }

		public static ConfigEntry<int> EncounterMinLevel { get; private set; }

		public static ConfigEntry<string> EncounterMessageTemplate { get; private set; }

		public static ConfigEntry<string> EncounterMessageGroupTemplate { get; private set; }

		public static ConfigEntry<string> RewardMessageTemplate { get; private set; }

		public static ConfigEntry<string> RewardAnnouncementMessageTemplate { get; private set; }

		public static ConfigEntry<bool> NotifyAdminsAboutEncountersAndRewards { get; private set; }

		public static ConfigEntry<bool> NotifyAllPlayersAboutRewards { get; private set; }

		public static ConfigEntry<bool> SkipPlayersInCombat { get; private set; }

		public static void Initialize()
		{
			//IL_0051: 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_005b: Expected O, but got Unknown
			string text = Path.Combine(Paths.ConfigPath ?? Path.Combine("BepInEx", "config"), "BloodyEncounters");
			if (!Directory.Exists(text))
			{
				Directory.CreateDirectory(text);
			}
			string text2 = Path.Combine(text, "BloodyEncounters.cfg");
			_mainConfig = (File.Exists(text2) ? new ConfigFile(text2, false) : new ConfigFile(text2, true));
			Enabled = _mainConfig.Bind<bool>("Main", "Enabled", true, "Determines whether the random encounter timer is enabled or not.");
			SkipPlayersInCastle = _mainConfig.Bind<bool>("Main", "SkipPlayersInCastle", true, "When enabled, players who are in a castle are excluded from encounters");
			SkipPlayersInCombat = _mainConfig.Bind<bool>("Main", "SkipPlayersInCombat", false, "When enabled, players who are in combat are excluded from the random encounters.");
			EncounterTimerMin = _mainConfig.Bind<int>("Main", "EncounterTimerMin", 1200, "Minimum seconds before a new encounter is initiated. This value is divided by the online users count.");
			EncounterTimerMax = _mainConfig.Bind<int>("Main", "EncounterTimerMax", 2400, "Maximum seconds before a new encounter is initiated. This value is divided by the online users count.");
			EncounterMinLevel = _mainConfig.Bind<int>("Main", "EncounterMinLevel", 10, "The lower value for the Player level for encounter.");
			EncounterMessageTemplate = _mainConfig.Bind<string>("Main", "EncounterMessageTemplate", "You have encountered a <color=#daa520>{0}</color>. You have <color=#daa520>{1}</color> seconds to kill it for a chance of a random reward.", "System message template for the encounter.");
			EncounterMessageGroupTemplate = _mainConfig.Bind<string>("Main", "EncounterMessageGroupTemplate", "You have encountered with a group called <color=#daa520>{0}</color>. You have <color=#daa520>{1}</color> seconds to kill it for a chance of a random reward.", "System message template for the group encounter.");
			RewardMessageTemplate = _mainConfig.Bind<string>("Main", "RewardMessageTemplate", "Congratulations. Your reward: <color={0}>{1}</color>.", "System message template for the reward.");
			RewardAnnouncementMessageTemplate = _mainConfig.Bind<string>("Main", "RewardAnnouncementMessageTemplate", "{0} earned an encounter reward: <color={1}>{2}</color>.", "System message template for the reward announcement.");
			NotifyAdminsAboutEncountersAndRewards = _mainConfig.Bind<bool>("Main", "NotifyAdminsAboutEncountersAndRewards", true, "If enabled, all online admins are notified about encounters and rewards.");
			NotifyAllPlayersAboutRewards = _mainConfig.Bind<bool>("Main", "NotifyAllPlayersAboutRewards", false, "When enabled, all online players are notified about any player's rewards.");
		}

		public static void Destroy()
		{
			_mainConfig.Clear();
		}

		private static string CleanupName(string name)
		{
			return new Regex("[^a-zA-Z0-9 -]").Replace(name, "");
		}
	}
	internal class Database
	{
		private static readonly Random Random = new Random();

		public static readonly string ConfigPath = Path.Combine(Paths.ConfigPath, "BloodyEncounters");

		public static string NPCSListFile = Path.Combine(ConfigPath, "NPCS.json");

		public static List<NpcEncounterModel> NPCS { get; set; } = new List<NpcEncounterModel>();


		public static void Initialize()
		{
			createDatabaseFiles();
			loadDatabase();
		}

		public static bool createDatabaseFiles()
		{
			if (!Directory.Exists(ConfigPath))
			{
				Directory.CreateDirectory(ConfigPath);
			}
			if (!File.Exists(NPCSListFile))
			{
				File.WriteAllText(NPCSListFile, "[]");
			}
			Plugin.Logger.LogDebug("Create Database: OK");
			return true;
		}

		public static bool saveDatabase()
		{
			try
			{
				string contents = JsonSerializer.Serialize(NPCS, new JsonSerializerOptions
				{
					WriteIndented = true
				});
				File.WriteAllText(NPCSListFile, contents);
				Plugin.Logger.LogDebug("Save Database: OK");
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError("Error SaveDatabase: " + ex.Message);
				return false;
			}
		}

		public static bool loadDatabase()
		{
			try
			{
				List<NpcEncounterModel> list = JsonSerializer.Deserialize<List<NpcEncounterModel>>(File.ReadAllText(NPCSListFile));
				foreach (NpcEncounterModel item in list)
				{
					item.nameHash = item.name.GetHashCode().ToString();
				}
				NPCS = list;
				Plugin.Logger.LogDebug("Load Database: OK");
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError("Error LoadDatabase: " + ex.Message);
				return false;
			}
		}

		public static bool GetNPC(string NPCName, out NpcEncounterModel npc)
		{
			npc = NPCS.Where((NpcEncounterModel x) => x.name == NPCName).FirstOrDefault();
			if (npc == null)
			{
				return false;
			}
			return true;
		}

		public static bool GetNPCFromEntity(Entity npcEntity, out NpcEncounterModel npc)
		{
			//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)
			npc = NPCS.Where((NpcEncounterModel x) => ((Entity)(ref x.npcEntity)).Equals(npcEntity)).FirstOrDefault();
			if (npc == null)
			{
				return false;
			}
			return true;
		}

		public static bool AddNPC(string NPCName, int prefabGUIDOfNPC, int levelAbove, int lifetime, string group)
		{
			//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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			if (GetNPC(NPCName, out var npc))
			{
				throw new NPCExistException();
			}
			ConvertedAssetData val = Plugin.SystemsCore.PrefabCollectionSystem._PrefabDataLookup[new PrefabGUID(prefabGUIDOfNPC)];
			string assetName = ((object)(FixedString128Bytes)(ref val.AssetName)).ToString();
			Entity val2 = Plugin.SystemsCore.PrefabCollectionSystem._PrefabGuidToEntityMap[new PrefabGUID(prefabGUIDOfNPC)];
			npc = new NpcEncounterModel();
			npc.AssetName = assetName;
			npc.name = NPCName;
			npc.nameHash = NPCName.GetHashCode().ToString();
			npc.PrefabGUID = prefabGUIDOfNPC;
			npc.levelAbove = levelAbove;
			npc.Lifetime = lifetime;
			npc.Group = group;
			UnitStats stats = ECSExtensions.Read<UnitStats>(val2);
			npc.unitStats = new UnitStatsModel();
			npc.unitStats.SetStats(stats);
			NPCS.Add(npc);
			saveDatabase();
			return true;
		}

		public static bool RemoveNPC(string NPCName)
		{
			if (GetNPC(NPCName, out var npc))
			{
				NPCS.Remove(npc);
				saveDatabase();
				return true;
			}
			throw new NPCDontExistException();
		}
	}
	internal static class DataFactory
	{
		private static readonly Random Random = new Random();

		private static List<NpcEncounterModel> _npcs;

		private static List<ItemEncounterModel> _items;

		internal static NpcEncounterModel GetRandomNpc()
		{
			_npcs = Database.NPCS;
			return _npcs.GetRandomItem();
		}

		internal static ItemEncounterModel GetRandomItem(NpcEncounterModel npc)
		{
			_items = npc.items;
			return _items.GetRandomItem();
		}

		private static T GetRandomItem<T>(this List<T> items)
		{
			if (items == null || items.Count == 0)
			{
				return default(T);
			}
			return items[Random.Next(items.Count)];
		}
	}
}
namespace BloodyEncounters.Data.Models
{
	internal class ItemEncounterModel
	{
		public string name { get; set; }

		public int ItemID { get; set; }

		public int Stack { get; set; }

		public int Chance { get; set; } = 1;


		public string Color { get; set; } = "#daa520";

	}
	internal class NpcEncounterModel
	{
		internal string nameHash;

		public NpcModel npcModel;

		public Entity npcEntity;

		public string name { get; set; } = string.Empty;


		public int PrefabGUID { get; set; }

		public string AssetName { get; set; } = string.Empty;


		public int levelAbove { get; set; }

		public List<ItemEncounterModel> items { get; set; } = new List<ItemEncounterModel>();


		public float Lifetime { get; set; }

		public string Group { get; set; } = string.Empty;


		public UnitStatsModel unitStats { get; set; }

		public List<ItemEncounterModel> GetItems()
		{
			return items;
		}

		public bool GetItem(int itemPrefabID, out ItemEncounterModel item)
		{
			item = items.Where((ItemEncounterModel x) => x.ItemID == itemPrefabID).FirstOrDefault();
			if (item == null)
			{
				return false;
			}
			return true;
		}

		public bool GetItemFromName(string ItemName, out ItemEncounterModel item)
		{
			item = items.Where((ItemEncounterModel x) => x.name == ItemName).FirstOrDefault();
			if (item == null)
			{
				return false;
			}
			return true;
		}

		public bool AddItem(string ItemName, int ItemPrefabID, int Stack)
		{
			if (!GetItem(ItemPrefabID, out var item))
			{
				item = new ItemEncounterModel();
				item.name = ItemName;
				item.ItemID = ItemPrefabID;
				item.Stack = Stack;
				items.Add(item);
				Database.saveDatabase();
				return true;
			}
			throw new ProductExistException();
		}

		public bool RemoveItem(string ItemName)
		{
			if (GetItemFromName(ItemName, out var item))
			{
				items.Remove(item);
				Database.saveDatabase();
				return true;
			}
			throw new ProductDontExistException();
		}

		public bool Spawn(Entity sender, float3 pos)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			SpawnSystem.SpawnUnitWithCallback(sender, new PrefabGUID(PrefabGUID), new float2(pos.x, pos.z), Lifetime, (Action<Entity>)delegate(Entity e)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: 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_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_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0084: Unknown result type (might be due to invalid IL or missing references)
				//IL_0089: Unknown result type (might be due to invalid IL or missing references)
				npcEntity = e;
				if (ECSExtensions.Has<VBloodUnit>(npcEntity))
				{
					CoroutineHandler.StartFrameCoroutine((Action)delegate
					{
						//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_0010: Unknown result type (might be due to invalid IL or missing references)
						//IL_001c: Unknown result type (might be due to invalid IL or missing references)
						//IL_0024: Unknown result type (might be due to invalid IL or missing references)
						//IL_002f: Unknown result type (might be due to invalid IL or missing references)
						//IL_0034: Unknown result type (might be due to invalid IL or missing references)
						VBloodUnit val = ECSExtensions.Read<VBloodUnit>(npcEntity);
						val.CanBeTracked = false;
						val.UnlocksTrophyOnFeed = (Trophy)(-1);
						val.UnlocksTrophyOnFeedBrutal = (Trophy)(-1);
						ECSExtensions.Write<VBloodUnit>(npcEntity, val);
					}, 3, 1);
				}
				ECSExtensions.ReadBuffer<DropTableBuffer>(npcEntity).Clear();
				npcModel = GameData.Npcs.FromEntity(npcEntity);
				ModifyNPC(sender, e);
			});
			return true;
		}

		public bool Spawn(Entity sender, float3 pos, float lifetime)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			SpawnSystem.SpawnUnitWithCallback(sender, new PrefabGUID(PrefabGUID), new float2(pos.x, pos.z), lifetime, (Action<Entity>)delegate(Entity e)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: 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_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_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0084: Unknown result type (might be due to invalid IL or missing references)
				//IL_0089: Unknown result type (might be due to invalid IL or missing references)
				npcEntity = e;
				if (ECSExtensions.Has<VBloodUnit>(npcEntity))
				{
					CoroutineHandler.StartFrameCoroutine((Action)delegate
					{
						//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_0010: Unknown result type (might be due to invalid IL or missing references)
						//IL_001c: Unknown result type (might be due to invalid IL or missing references)
						//IL_0024: Unknown result type (might be due to invalid IL or missing references)
						//IL_002f: Unknown result type (might be due to invalid IL or missing references)
						//IL_0034: Unknown result type (might be due to invalid IL or missing references)
						VBloodUnit val = ECSExtensions.Read<VBloodUnit>(npcEntity);
						val.CanBeTracked = false;
						val.UnlocksTrophyOnFeed = (Trophy)(-1);
						val.UnlocksTrophyOnFeedBrutal = (Trophy)(-1);
						ECSExtensions.Write<VBloodUnit>(npcEntity, val);
					}, 3, 1);
				}
				ECSExtensions.ReadBuffer<DropTableBuffer>(npcEntity).Clear();
				npcModel = GameData.Npcs.FromEntity(npcEntity);
				ModifyNPC(sender, e);
			});
			return true;
		}

		public void ModifyNPC(Entity user, Entity npc)
		{
			//IL_0005: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			float level = GameData.Users.FromEntity(user).Character.Equipment.Level;
			EntityManager entityManager = Core.World.EntityManager;
			UnitLevel componentData = ((EntityManager)(ref entityManager)).GetComponentData<UnitLevel>(npc);
			int num = (int)(level + (float)levelAbove);
			componentData.Level = new ModifiableInt(num);
			UnitStats stats = ECSExtensions.Read<UnitStats>(npc);
			if (unitStats == null)
			{
				GenerateStats();
			}
			ECSExtensions.Write<UnitStats>(npc, unitStats.FillStats(stats));
			entityManager = Core.World.EntityManager;
			((EntityManager)(ref entityManager)).SetComponentData<UnitLevel>(npc, componentData);
			RenameNPC(npc);
		}

		public void GenerateStats()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			UnitStats stats = ECSExtensions.Read<UnitStats>(Plugin.SystemsCore.PrefabCollectionSystem._PrefabGuidToEntityMap[new PrefabGUID(PrefabGUID)]);
			unitStats = new UnitStatsModel();
			unitStats.SetStats(stats);
		}

		private void RenameNPC(Entity boss)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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)
			ECSExtensions.Add<NameableInteractable>(boss);
			NameableInteractable val = ECSExtensions.Read<NameableInteractable>(boss);
			val.Name = new FixedString64Bytes(nameHash + "be");
			ECSExtensions.Write<NameableInteractable>(boss, val);
		}

		public bool GetNPCEntity()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_0019: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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)
			NativeArray<Entity> entitiesByComponentTypes = QueryComponents.GetEntitiesByComponentTypes<NameableInteractable, LifeTime>((EntityQueryOptions)2, false);
			Enumerator<Entity> enumerator = entitiesByComponentTypes.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Entity current = enumerator.Current;
				NameableInteractable val = ECSExtensions.Read<NameableInteractable>(current);
				if (((FixedString64Bytes)(ref val.Name)).Value == nameHash + "be")
				{
					npcEntity = current;
					entitiesByComponentTypes.Dispose();
					return true;
				}
			}
			entitiesByComponentTypes.Dispose();
			return false;
		}

		internal void KillNpc(Entity user)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: 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)
			if (GetNPCEntity())
			{
				StatChangeUtility.KillOrDestroyEntity(Plugin.SystemsCore.EntityManager, npcEntity, user, user, 0.0, (StatChangeReason)0, true);
			}
		}
	}
	internal class UnitStatsModel
	{
		public float PhysicalCriticalStrikeChance { get; set; }

		public float PhysicalCriticalStrikeDamage { get; set; }

		public float SpellCriticalStrikeChance { get; set; }

		public float SpellCriticalStrikeDamage { get; set; }

		public float PhysicalPower { get; set; }

		public float SpellPower { get; set; }

		public float ResourcePower { get; set; }

		public float SiegePower { get; set; }

		public float ResourceYieldModifier { get; set; }

		public float ReducedResourceDurabilityLoss { get; set; }

		public float PhysicalResistance { get; set; }

		public float SpellResistance { get; set; }

		public int SunResistance { get; set; }

		public int FireResistance { get; set; }

		public int HolyResistance { get; set; }

		public int SilverResistance { get; set; }

		public int SilverCoinResistance { get; set; }

		public int GarlicResistance { get; set; }

		public float PassiveHealthRegen { get; set; }

		public int CCReduction { get; set; }

		public float HealthRecovery { get; set; }

		public float DamageReduction { get; set; }

		public float HealingReceived { get; set; }

		public float ShieldAbsorbModifier { get; set; }

		public float BloodEfficiency { get; set; }

		public void SetStats(UnitStats stats)
		{
			PhysicalCriticalStrikeChance = ((ModifiableFloat)(ref stats.PhysicalCriticalStrikeChance)).Value;
			PhysicalCriticalStrikeDamage = ((ModifiableFloat)(ref stats.PhysicalCriticalStrikeDamage)).Value;
			SpellCriticalStrikeChance = ((ModifiableFloat)(ref stats.SpellCriticalStrikeChance)).Value;
			SpellCriticalStrikeDamage = ((ModifiableFloat)(ref stats.SpellCriticalStrikeDamage)).Value;
			PhysicalPower = ((ModifiableFloat)(ref stats.PhysicalPower)).Value;
			SpellPower = ((ModifiableFloat)(ref stats.SpellPower)).Value;
			ResourcePower = ((ModifiableFloat)(ref stats.ResourcePower)).Value;
			SiegePower = ((ModifiableFloat)(ref stats.SiegePower)).Value;
			ResourceYieldModifier = ((ModifiableFloat)(ref stats.ResourceYieldModifier)).Value;
			ReducedResourceDurabilityLoss = ((ModifiableFloat)(ref stats.ReducedResourceDurabilityLoss)).Value;
			PhysicalResistance = ((ModifiableFloat)(ref stats.PhysicalResistance)).Value;
			SpellResistance = ((ModifiableFloat)(ref stats.SpellResistance)).Value;
			SunResistance = ((ModifiableInt)(ref stats.SunResistance)).Value;
			FireResistance = ((ModifiableInt)(ref stats.FireResistance)).Value;
			HolyResistance = ((ModifiableInt)(ref stats.HolyResistance)).Value;
			SilverResistance = ((ModifiableInt)(ref stats.SilverResistance)).Value;
			SilverCoinResistance = ((ModifiableInt)(ref stats.SilverCoinResistance)).Value;
			GarlicResistance = ((ModifiableInt)(ref stats.GarlicResistance)).Value;
			PassiveHealthRegen = ((ModifiableFloat)(ref stats.PassiveHealthRegen)).Value;
			CCReduction = ((ModifiableInt)(ref stats.CCReduction)).Value;
			HealthRecovery = ((ModifiableFloat)(ref stats.HealthRecovery)).Value;
			DamageReduction = ((ModifiableFloat)(ref stats.DamageReduction)).Value;
			HealingReceived = ((ModifiableFloat)(ref stats.HealingReceived)).Value;
			ShieldAbsorbModifier = ((ModifiableFloat)(ref stats.ShieldAbsorbModifier)).Value;
			BloodEfficiency = ((ModifiableFloat)(ref stats.BloodEfficiency)).Value;
		}

		public UnitStats FillStats(UnitStats stats)
		{
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			stats.PhysicalCriticalStrikeChance._Value = PhysicalCriticalStrikeChance;
			stats.PhysicalCriticalStrikeDamage._Value = PhysicalCriticalStrikeDamage;
			stats.SpellCriticalStrikeChance._Value = SpellCriticalStrikeChance;
			stats.SpellCriticalStrikeDamage._Value = SpellCriticalStrikeDamage;
			stats.PhysicalPower._Value = PhysicalPower;
			stats.SpellPower._Value = SpellPower;
			stats.ResourcePower._Value = ResourcePower;
			stats.SiegePower._Value = SiegePower;
			stats.ResourceYieldModifier._Value = ResourceYieldModifier;
			stats.ReducedResourceDurabilityLoss._Value = ReducedResourceDurabilityLoss;
			stats.PhysicalResistance._Value = PhysicalResistance;
			stats.SpellResistance._Value = SpellResistance;
			stats.SunResistance._Value = SunResistance;
			stats.FireResistance._Value = FireResistance;
			stats.HolyResistance._Value = HolyResistance;
			stats.SilverResistance._Value = SilverResistance;
			stats.SilverCoinResistance._Value = SilverCoinResistance;
			stats.GarlicResistance._Value = GarlicResistance;
			stats.PassiveHealthRegen._Value = PassiveHealthRegen;
			stats.CCReduction._Value = CCReduction;
			stats.HealthRecovery._Value = HealthRecovery;
			stats.DamageReduction._Value = DamageReduction;
			stats.HealingReceived._Value = HealingReceived;
			stats.ShieldAbsorbModifier._Value = ShieldAbsorbModifier;
			stats.BloodEfficiency._Value = BloodEfficiency;
			return stats;
		}
	}
}
namespace BloodyEncounters.Commands
{
	[CommandGroup("be", null)]
	internal class EncountersCommand
	{
		[Command("reload", null, "", "Reload Database Boss", null, true)]
		public static void ReloadDatabase(ChatCommandContext ctx)
		{
			try
			{
				Database.loadDatabase();
				ctx.Reply("Boss database reload successfully");
			}
			catch (Exception ex)
			{
				throw ctx.Error("Error: " + ex.Message);
			}
		}

		[Command("start", null, "", "Starts an encounter for a random online user.", null, true)]
		public static void StartCommand(ChatCommandContext ctx)
		{
			EncounterSystem.StartEncounter();
			ctx.Reply("The hunt has begun...");
		}

		[Command("me", null, "", "Starts an encounter for the admin who sends the command.", null, true)]
		public static void MeCommand(ChatCommandContext ctx)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			EncounterSystem.StartEncounter(GameData.Users.FromEntity(ctx.Event.SenderUserEntity));
			ctx.Reply("Prepare for the fight...");
		}

		[Command("player", null, "<PlayerName>", "Starts an encounter for the given player, for example.", null, true)]
		public static void PlayerCommand(ChatCommandContext ctx, string PlayerName)
		{
			UserModel obj = GameData.Users.GetUserByCharacterName(PlayerName) ?? throw ctx.Error("Player not found");
			if (!obj.IsConnected)
			{
				throw ctx.Error("Could not find an online player with name " + PlayerName);
			}
			EncounterSystem.StartEncounter(obj);
			ctx.Reply("Sending an ambush to " + PlayerName + ".");
		}

		[Command("enable", null, "", "Enables the random encounter timer.", null, true)]
		public static void EnableCommand(ChatCommandContext ctx)
		{
			if (Config.Enabled.Value)
			{
				throw ctx.Error("Already enabled.");
			}
			Config.Enabled.Value = true;
			ctx.Reply("Enabled");
		}

		[Command("disable", null, "", "Disables the random encounter timer.", null, true)]
		public static void DisableCommand(ChatCommandContext ctx)
		{
			if (!Config.Enabled.Value)
			{
				throw ctx.Error("Already disabled.");
			}
			Config.Enabled.Value = false;
			ctx.Reply("Disabled.");
		}
	}
	[CommandGroup("be items", null)]
	internal class ItemsCommand
	{
		[Command("list", null, "", "List items of NPC drop", null, true)]
		public void ListNPCItems(ChatCommandContext ctx, string NPCName)
		{
			try
			{
				if (Database.GetNPC(NPCName, out var npc))
				{
					ctx.Reply(npc.name + " Items List");
					ctx.Reply("----------------------------");
					ctx.Reply("--");
					foreach (ItemEncounterModel item in npc.GetItems())
					{
						ctx.Reply($"Item {item.ItemID}");
						ctx.Reply($"Stack {item.Stack}");
						ctx.Reply("--");
					}
					ctx.Reply("----------------------------");
					return;
				}
				throw new NPCDontExistException();
			}
			catch (NPCDontExistException)
			{
				throw ctx.Error("NPC with name '" + NPCName + "' does not exist.");
			}
			catch (ProductExistException)
			{
				throw ctx.Error("This item configuration already exists at merchant '" + NPCName + "'");
			}
			catch (Exception ex3)
			{
				throw ctx.Error("Error: " + ex3.Message);
			}
		}

		[Command("add", null, "<NameOfNPC> <ItemName> <ItemPrefabID> <Stack>", "Add a item to a NPC drop", null, true)]
		public void CreateItem(ChatCommandContext ctx, string NPCName, string ItemName, int ItemPrefabID, int Stack)
		{
			try
			{
				if (Database.GetNPC(NPCName, out var npc))
				{
					npc.AddItem(ItemName, ItemPrefabID, Stack);
					ctx.Reply("Item successfully added to NPC '" + NPCName + "'");
					return;
				}
				throw new NPCDontExistException();
			}
			catch (NPCDontExistException)
			{
				throw ctx.Error("NPC with name '" + NPCName + "' does not exist.");
			}
			catch (ProductExistException)
			{
				throw ctx.Error("This item configuration already exists at merchant '" + NPCName + "'");
			}
			catch (Exception ex3)
			{
				throw ctx.Error("Error: " + ex3.Message);
			}
		}

		[Command("remove", null, "<NameOfNPC> <ItemName>", "Remove a item to a NPC", null, true)]
		public void RemoveProduct(ChatCommandContext ctx, string NPCName, string ItemName)
		{
			try
			{
				if (Database.GetNPC(NPCName, out var npc))
				{
					npc.RemoveItem(ItemName);
					ctx.Reply("NPC '" + NPCName + "''s item has been successfully removed");
					return;
				}
				throw new NPCDontExistException();
			}
			catch (NPCDontExistException)
			{
				throw ctx.Error("NPC with name '" + NPCName + "' does not exist.");
			}
			catch (ProductDontExistException)
			{
				throw ctx.Error("This item does not exist at NPC '" + NPCName + "'");
			}
			catch (Exception ex3)
			{
				throw ctx.Error("Error: " + ex3.Message);
			}
		}
	}
	[CommandGroup("be npc", null)]
	internal class NpcCommand
	{
		[Command("list", null, "", "List of npc", null, true)]
		public void ListMerchant(ChatCommandContext ctx)
		{
			List<NpcEncounterModel> nPCS = Database.NPCS;
			if (nPCS.Count == 0)
			{
				throw ctx.Error("There are no npcs created");
			}
			ctx.Reply("NPCS List");
			ctx.Reply("----------------------------");
			ctx.Reply("--");
			foreach (NpcEncounterModel item in nPCS)
			{
				ctx.Reply("NPC " + item.name);
				ctx.Reply("Group " + item.Group);
				ctx.Reply("--");
			}
			ctx.Reply("----------------------------");
		}

		[Command("create", null, "<NameOfNPC> <PrefabGUIDOfNPC> <LevelsAbovePlayer> <LifeTime> <Group>", "Create a NPC", null, true)]
		public void CreateNPC(ChatCommandContext ctx, string npcName, int prefabGUID, int levelAbove, int lifeTime, string group = "")
		{
			try
			{
				if (Database.AddNPC(npcName, prefabGUID, levelAbove, lifeTime, group))
				{
					ctx.Reply("NPC '" + npcName + "' created successfully");
				}
			}
			catch (NPCExistException)
			{
				throw ctx.Error("NPC with name '" + npcName + "' exist.");
			}
			catch (Exception ex2)
			{
				throw ctx.Error("Error: " + ex2.Message);
			}
		}

		[Command("remove", null, "<NameOfNPC>", "Remove a NPC", null, true)]
		public void RemoveMerchant(ChatCommandContext ctx, string npcName)
		{
			try
			{
				if (Database.RemoveNPC(npcName))
				{
					ctx.Reply("NPC '" + npcName + "' remove successfully");
				}
			}
			catch (NPCDontExistException)
			{
				throw ctx.Error("NPC with name '" + npcName + "' does not exist.");
			}
			catch (Exception ex2)
			{
				throw ctx.Error("Error: " + ex2.Message);
			}
		}
	}
}