using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using ProjectM;
using ProjectM.CastleBuilding;
using ProjectM.Network;
using ProjectM.Scripting;
using Stunlock.Core;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using VCF.Core.Basics;
using VampireCommandFramework;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("NpcSpawner")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Server-side V Rising mod: spawns configured NPC groups around a random online player at random times and gives configurable loot on kill.")]
[assembly: AssemblyFileVersion("1.7.1.0")]
[assembly: AssemblyInformationalVersion("1.7.1")]
[assembly: AssemblyProduct("NpcSpawner")]
[assembly: AssemblyTitle("NpcSpawner")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.7.1.0")]
[module: UnverifiableCode]
namespace NpcSpawner
{
internal sealed class SpawnGroup
{
[JsonPropertyName("RandomAround")]
public float RandomAround { get; set; } = 8f;
[JsonPropertyName("Prefabs")]
public Dictionary<string, int> Prefabs { get; set; } = new Dictionary<string, int>();
}
internal sealed class LootEntry
{
[JsonPropertyName("ItemId")]
public int ItemId { get; set; }
[JsonPropertyName("Amount")]
public int Amount { get; set; } = 1;
[JsonPropertyName("Chance")]
public float Chance { get; set; } = 1f;
}
[BepInPlugin("agenthere.npcspawner", "NPC Spawner", "1.7.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BasePlugin
{
public const string PluginGuid = "agenthere.npcspawner";
public const string PluginName = "NPC Spawner";
public const string PluginVersion = "1.7.1";
public const string VcfGuid = "gg.deca.VampireCommandFramework";
internal static Plugin Instance;
internal static Harmony Harmony;
internal static ManualLogSource Logger;
public override void Load()
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Expected O, but got Unknown
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Expected O, but got Unknown
//IL_0153: Unknown result type (might be due to invalid IL or missing references)
//IL_0159: Expected O, but got Unknown
//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
//IL_01aa: Expected O, but got Unknown
//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
//IL_01fc: Expected O, but got Unknown
//IL_0245: Unknown result type (might be due to invalid IL or missing references)
//IL_024b: Expected O, but got Unknown
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Expected O, but got Unknown
//IL_0273: Unknown result type (might be due to invalid IL or missing references)
//IL_0279: Expected O, but got Unknown
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Expected O, but got Unknown
//IL_017d: Unknown result type (might be due to invalid IL or missing references)
//IL_0187: Expected O, but got Unknown
//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
//IL_01d8: Expected O, but got Unknown
//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Expected O, but got Unknown
Instance = this;
Logger = ((BasePlugin)this).Log;
ManualLogSource logger = Logger;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(26, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("NPC Spawner");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" v");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.7.1");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loading...");
}
logger.LogInfo(val);
try
{
Directory.CreateDirectory(SpawnConfig.Dir);
Settings.Init(new ConfigFile(Path.Combine(SpawnConfig.Dir, "NpcSpawner.cfg"), true));
}
catch (Exception ex)
{
ManualLogSource logger2 = Logger;
BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(23, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[NpcSpawner] settings: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
}
logger2.LogError(val2);
}
try
{
SpawnConfig.LoadAll();
ManualLogSource logger3 = Logger;
val = new BepInExInfoLogInterpolatedStringHandler(25, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] config dir: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(SpawnConfig.Dir);
}
logger3.LogInfo(val);
ManualLogSource logger4 = Logger;
val = new BepInExInfoLogInterpolatedStringHandler(49, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] configs: npcs=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(SpawnConfig.Groups.Count);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" groups, loot=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(SpawnConfig.Loot.Count);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" entries");
}
logger4.LogInfo(val);
}
catch (Exception ex2)
{
ManualLogSource logger5 = Logger;
BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(21, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[NpcSpawner] config: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex2);
}
logger5.LogError(val2);
}
try
{
Harmony = new Harmony("agenthere.npcspawner");
Harmony.PatchAll(Assembly.GetExecutingAssembly());
}
catch (Exception ex3)
{
ManualLogSource logger6 = Logger;
BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(29, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[NpcSpawner] patches failed: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex3);
}
logger6.LogError(val2);
}
try
{
CommandRegistry.Middlewares.Add((CommandMiddleware)new BasicAdminCheck());
Logger.LogInfo((object)"[NpcSpawner] VCF admin-only middleware installed.");
}
catch (Exception ex4)
{
ManualLogSource logger7 = Logger;
BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(39, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[NpcSpawner] middleware not installed: ");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex4.Message);
}
logger7.LogWarning(val3);
}
try
{
CommandRegistry.RegisterAll();
Logger.LogInfo((object)"[NpcSpawner] chat commands registered (.npcs help)");
}
catch (Exception ex5)
{
ManualLogSource logger8 = Logger;
BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(30, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[NpcSpawner] commands failed: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex5);
}
logger8.LogError(val2);
}
ManualLogSource logger9 = Logger;
val = new BepInExInfoLogInterpolatedStringHandler(23, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("NPC Spawner");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" v");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.7.1");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded.");
}
logger9.LogInfo(val);
}
public override bool Unload()
{
try
{
SpawnerService.Shutdown();
}
catch (Exception ex)
{
Logger.LogError((object)ex);
}
try
{
CommandRegistry.UnregisterAssembly();
}
catch (Exception ex2)
{
Logger.LogError((object)ex2);
}
try
{
Harmony harmony = Harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
catch (Exception ex3)
{
Logger.LogError((object)ex3);
}
return true;
}
}
internal static class Settings
{
public static ConfigEntry<bool> Enabled;
public static ConfigEntry<float> IntervalMin;
public static ConfigEntry<float> IntervalMax;
public static ConfigEntry<bool> IntervalScalesWithPlayers;
public static ConfigEntry<float> LifetimeSeconds;
public static ConfigEntry<bool> BlockNearCastles;
public static ConfigEntry<float> CastleBlockRadius;
public static ConfigEntry<float> CastleHeartRadius;
public static ConfigEntry<bool> SkipPlayersInCombat;
public static ConfigEntry<string> CombatBuffGuids;
public static ConfigEntry<bool> Announce;
public static ConfigEntry<string> AnnounceMessage;
public static ConfigEntry<bool> GlobalAnnounce;
public static ConfigEntry<string> GlobalSpawnMessage;
public static ConfigEntry<bool> LootEnabled;
public static ConfigEntry<bool> NotifyKiller;
public static ConfigEntry<string> NotifyMessage;
public static ConfigEntry<bool> SuccessAnnounce;
public static ConfigEntry<string> SuccessMessage;
public static void Init(ConfigFile cfg)
{
Enabled = cfg.Bind<bool>("General", "Enabled", true, "Включён ли автоматический случайный спавн НПС.");
IntervalMin = cfg.Bind<float>("General", "IntervalMinSeconds", 300f, "Минимальный интервал между случайными спавнами, секунды.");
IntervalMax = cfg.Bind<float>("General", "IntervalMaxSeconds", 600f, "Максимальный интервал между случайными спавнами, секунды.");
IntervalScalesWithPlayers = cfg.Bind<bool>("General", "IntervalScalesWithPlayers", false, "Если true — интервал делится на число игроков онлайн (больше игроков -> чаще спавн).");
LifetimeSeconds = cfg.Bind<float>("General", "LifetimeSeconds", 0f, "Сколько секунд живёт заспавненный НПС. 0 или меньше — бессрочно (до убийства).");
BlockNearCastles = cfg.Bind<bool>("Spawn", "BlockNearCastles", true, "Запрещать спавн в замках игроков и под крышами (рядом со плитами замка).");
CastleBlockRadius = cfg.Bind<float>("Spawn", "CastleBlockRadius", 4f, "Радиус в метрах вокруг плит замка, где спавн запрещён (при BlockNearCastles = true).");
CastleHeartRadius = cfg.Bind<float>("Spawn", "CastleHeartRadius", 30f, "Радиус в метрах вокруг СЕРДЦА замка, где спавн запрещён (любой этаж). Основная защита от спавна в замках.");
SkipPlayersInCombat = cfg.Bind<bool>("Spawn", "SkipPlayersInCombat", true, "Не давать спавнить НПС у игрока, который находится в бою.");
CombatBuffGuids = cfg.Bind<string>("Spawn", "CombatBuffGuids", "581443919,697095869", "Список id баффов 'в бою' через запятую (обычный бой и PvP-бой). Менять только если игра обновила их.");
Announce = cfg.Bind<bool>("Messages", "Announce", true, "Сообщать ЛИЧНО игроку, что рядом появилась группа НПС.");
AnnounceMessage = cfg.Bind<string>("Messages", "AnnounceMessage", "<color=#ff9d00>Рядом появилась группа «{0}»: врагов {1}. Убей их ради добычи!</color>", "Шаблон личного анонса. {0} — имя группы, {1} — число врагов.");
GlobalAnnounce = cfg.Bind<bool>("Messages", "GlobalAnnounce", true, "Сообщать ВСЕМ игрокам, что у кого-то произошёл случайный спавн группы.");
GlobalSpawnMessage = cfg.Bind<string>("Messages", "GlobalSpawnMessage", "<color=#ff5a5a>Случайный спавн! У игрока {0} появилась группа «{1}» — врагов {2}.</color>", "Шаблон сообщения всем игрокам о случайном спавне. {0} — ник игрока, {1} — имя группы, {2} — число врагов.");
LootEnabled = cfg.Bind<bool>("Loot", "Enabled", true, "Выдавать настраиваемый лут за убийство НПС (см. loot.json).");
NotifyKiller = cfg.Bind<bool>("Loot", "NotifyKiller", true, "Сообщать игроку в чат, какой лут он получил.");
NotifyMessage = cfg.Bind<string>("Loot", "NotifyMessage", "<color=#ffd700>Добыча: {0} шт. (id {1}).</color>", "Шаблон сообщения о добыче. {0} — количество, {1} — id предмета.");
SuccessAnnounce = cfg.Bind<bool>("Messages", "SuccessAnnounce", true, "Сообщать ВСЕМ игрокам, что игрок справился с задачей (убил всю группу).");
SuccessMessage = cfg.Bind<string>("Messages", "SuccessMessage", "<color=#3cff8a>{0} справился с задачей — группа «{1}» уничтожена!</color>", "Шаблон сообщения об успехе. {0} — ник игрока, {1} — имя группы.");
}
}
internal static class SpawnConfig
{
internal static readonly string Dir = Path.Combine(Paths.ConfigPath, "NpcSpawner");
internal static readonly string NpcsFile = Path.Combine(Dir, "npcs.json");
internal static readonly string LootFile = Path.Combine(Dir, "loot.json");
internal static Dictionary<string, SpawnGroup> Groups { get; private set; } = new Dictionary<string, SpawnGroup>();
internal static Dictionary<string, List<LootEntry>> Loot { get; private set; } = new Dictionary<string, List<LootEntry>>();
internal static JsonSerializerOptions Options()
{
return new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip,
AllowTrailingCommas = true,
WriteIndented = true
};
}
internal static void LoadAll()
{
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Expected O, but got Unknown
try
{
Directory.CreateDirectory(Dir);
EnsureFile(NpcsFile, "NpcSpawner.npcs.default.json", "{ }");
EnsureFile(LootFile, "NpcSpawner.loot.default.json", "{ }");
Groups = LoadGroups();
Loot = LoadLoot();
}
catch (Exception ex)
{
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(39, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] ошибка загрузки конфигов: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
}
logger.LogError(val);
}
}
private static Dictionary<string, SpawnGroup> LoadGroups()
{
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Expected O, but got Unknown
try
{
return JsonSerializer.Deserialize<Dictionary<string, SpawnGroup>>(File.ReadAllText(NpcsFile), Options()) ?? new Dictionary<string, SpawnGroup>();
}
catch (Exception ex)
{
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(36, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] npcs.json не прочитан: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
logger.LogError(val);
return new Dictionary<string, SpawnGroup>();
}
}
private static Dictionary<string, List<LootEntry>> LoadLoot()
{
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Expected O, but got Unknown
try
{
return JsonSerializer.Deserialize<Dictionary<string, List<LootEntry>>>(File.ReadAllText(LootFile), Options()) ?? new Dictionary<string, List<LootEntry>>();
}
catch (Exception ex)
{
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(36, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] loot.json не прочитан: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
logger.LogError(val);
return new Dictionary<string, List<LootEntry>>();
}
}
internal static List<LootEntry> GetLoot(string npcGuid)
{
if (npcGuid != null && Loot.TryGetValue(npcGuid, out var value))
{
return value;
}
return null;
}
private static void EnsureFile(string path, string resourceName, string fallback)
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
if (!File.Exists(path))
{
string contents = ReadResource(resourceName) ?? fallback;
File.WriteAllText(path, contents);
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(39, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] создан файл по умолчанию: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(path);
}
logger.LogInfo(val);
}
}
private static string ReadResource(string name)
{
try
{
using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name);
if (stream == null)
{
return null;
}
using StreamReader streamReader = new StreamReader(stream);
return streamReader.ReadToEnd();
}
catch
{
return null;
}
}
}
internal static class SpawnerService
{
internal sealed class Batch
{
public string GroupName;
public string PlayerName;
public readonly List<Entity> Alive = new List<Entity>();
}
private sealed class Spawned
{
public string GuidKey;
public Batch Batch;
}
private sealed class Pickup
{
public int Guid;
public string GuidKey;
public Batch Batch;
public float3 Center;
public float Radius;
public DateTime DueAt;
}
private struct PlayerRef
{
public Entity UserEntity;
public Entity Character;
public float3 Position;
}
private static readonly Random Rng = new Random();
private static readonly Dictionary<Entity, Spawned> Tracked = new Dictionary<Entity, Spawned>();
private static readonly List<Pickup> _pickups = new List<Pickup>();
private static readonly List<int> _combatBuffs = new List<int>();
private static DateTime _nextSpawnAt = DateTime.MinValue;
private static bool _initialized;
private static EntityQuery _userQuery;
private static EntityQuery _prefabQuery;
private static EntityQuery _castleFloorQuery;
private static EntityQuery _castleHeartQuery;
private static bool _queriesCreated;
internal static IReadOnlyList<string> GroupNames
{
get
{
List<string> list = new List<string>();
if (SpawnConfig.Groups != null)
{
foreach (KeyValuePair<string, SpawnGroup> group in SpawnConfig.Groups)
{
if (group.Value != null && group.Value.Prefabs != null && group.Value.Prefabs.Count > 0)
{
list.Add(group.Key);
}
}
}
return list;
}
}
internal static void Initialize()
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//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)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_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_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Expected O, but got Unknown
//IL_013f: Unknown result type (might be due to invalid IL or missing references)
//IL_0145: Expected O, but got Unknown
if (!_initialized && Svc.Ready)
{
_initialized = true;
SpawnConfig.LoadAll();
_userQuery = ((EntityManager)(ref Svc.EM)).CreateEntityQuery((ComponentType[])(object)new ComponentType[1] { ComponentType.ReadOnly<User>() });
_prefabQuery = ((EntityManager)(ref Svc.EM)).CreateEntityQuery((ComponentType[])(object)new ComponentType[1] { ComponentType.ReadOnly<PrefabGUID>() });
_castleFloorQuery = ((EntityManager)(ref Svc.EM)).CreateEntityQuery((ComponentType[])(object)new ComponentType[2]
{
ComponentType.ReadOnly<CastleFloor>(),
ComponentType.ReadOnly<LocalToWorld>()
});
_castleHeartQuery = ((EntityManager)(ref Svc.EM)).CreateEntityQuery((ComponentType[])(object)new ComponentType[2]
{
ComponentType.ReadOnly<CastleHeart>(),
ComponentType.ReadOnly<LocalToWorld>()
});
_queriesCreated = true;
ReloadCombatBuffs();
ScheduleNext("init");
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(44, 3, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] ready. groups=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(SpawnConfig.Groups.Count);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", loot=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(SpawnConfig.Loot.Count);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", enabled=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(Settings.Enabled.Value);
}
logger.LogInfo(val);
ManualLogSource logger2 = Plugin.Logger;
val = new BepInExInfoLogInterpolatedStringHandler(43, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] castle floors=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(((EntityQuery)(ref _castleFloorQuery)).CalculateEntityCount());
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", castle hearts=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(((EntityQuery)(ref _castleHeartQuery)).CalculateEntityCount());
}
logger2.LogInfo(val);
}
}
internal static void Shutdown()
{
try
{
if (_queriesCreated && Svc.Ready)
{
((EntityQuery)(ref _userQuery)).Dispose();
((EntityQuery)(ref _prefabQuery)).Dispose();
((EntityQuery)(ref _castleFloorQuery)).Dispose();
((EntityQuery)(ref _castleHeartQuery)).Dispose();
}
}
catch
{
}
_queriesCreated = false;
Tracked.Clear();
_pickups.Clear();
_initialized = false;
}
internal static void Tick()
{
if (!Svc.Ready)
{
return;
}
if (!_initialized)
{
Initialize();
return;
}
CollectPickups();
PruneTracked();
if (!Settings.Enabled.Value || DateTime.UtcNow < _nextSpawnAt)
{
return;
}
ScheduleNext("auto");
try
{
SpawnRandomGroup();
}
catch (Exception ex)
{
Plugin.Logger.LogError((object)ex);
}
}
private static void ScheduleNext(string reason)
{
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Expected O, but got Unknown
float num = Math.Max(5f, Settings.IntervalMin.Value);
float num2 = Math.Max(num, Settings.IntervalMax.Value);
double num3 = (double)num + Rng.NextDouble() * (double)(num2 - num);
if (Settings.IntervalScalesWithPlayers.Value)
{
List<PlayerRef> players = GetPlayers();
num3 /= (double)Math.Max(1, players.Count);
}
_nextSpawnAt = DateTime.UtcNow.AddSeconds(num3);
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(43, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] следующий спавн через ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(num3, "0");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" сек (");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(reason);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(").");
}
logger.LogInfo(val);
}
private static void CollectPickups()
{
if (_pickups.Count == 0)
{
return;
}
DateTime utcNow = DateTime.UtcNow;
for (int num = _pickups.Count - 1; num >= 0; num--)
{
Pickup pickup = _pickups[num];
if (!(utcNow < pickup.DueAt))
{
_pickups.RemoveAt(num);
try
{
CollectOne(pickup);
}
catch (Exception ex)
{
Plugin.Logger.LogError((object)ex);
}
}
}
}
private static void CollectOne(Pickup p)
{
//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_002d: 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_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: 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_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: 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_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
NativeArray<Entity> val = ((EntityQuery)(ref _prefabQuery)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
try
{
float num = (p.Radius + 6f) * (p.Radius + 6f);
Enumerator<Entity> enumerator = val.GetEnumerator();
while (enumerator.MoveNext())
{
Entity current = enumerator.Current;
if (Tracked.ContainsKey(current))
{
continue;
}
PrefabGUID componentData;
try
{
componentData = ((EntityManager)(ref Svc.EM)).GetComponentData<PrefabGUID>(current);
}
catch
{
continue;
}
if (((PrefabGUID)(ref componentData)).GuidHash == p.Guid && TryGetPosition(current, out var pos))
{
float num2 = pos.x - p.Center.x;
float num3 = pos.z - p.Center.z;
if (!(num2 * num2 + num3 * num3 > num))
{
Tracked[current] = new Spawned
{
GuidKey = p.GuidKey,
Batch = p.Batch
};
p.Batch?.Alive.Add(current);
}
}
}
}
finally
{
val.Dispose();
}
}
private static void PruneTracked()
{
//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_002e: 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_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: 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_00a4: 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)
if (Tracked.Count == 0)
{
return;
}
List<Entity> list = null;
foreach (Entity key in Tracked.Keys)
{
if (!((EntityManager)(ref Svc.EM)).Exists(key))
{
if (list == null)
{
list = new List<Entity>();
}
list.Add(key);
}
}
if (list == null)
{
return;
}
foreach (Entity item in list)
{
if (Tracked.TryGetValue(item, out var value))
{
value.Batch?.Alive.Remove(item);
}
Tracked.Remove(item);
}
}
private static List<PlayerRef> GetPlayers()
{
//IL_001c: 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_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: 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_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: 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_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
List<PlayerRef> list = new List<PlayerRef>();
if (!Svc.Ready || !_queriesCreated)
{
return list;
}
NativeArray<Entity> val = ((EntityQuery)(ref _userQuery)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
try
{
Enumerator<Entity> enumerator = val.GetEnumerator();
while (enumerator.MoveNext())
{
Entity current = enumerator.Current;
User componentData;
try
{
componentData = ((EntityManager)(ref Svc.EM)).GetComponentData<User>(current);
}
catch
{
continue;
}
if (componentData.IsConnected && !componentData.IsBot)
{
Entity entity = componentData.LocalCharacter._Entity;
if (!(entity == Entity.Null) && ((EntityManager)(ref Svc.EM)).Exists(entity) && TryGetPosition(entity, out var pos))
{
list.Add(new PlayerRef
{
UserEntity = current,
Character = entity,
Position = pos
});
}
}
}
return list;
}
finally
{
val.Dispose();
}
}
private static bool TryGetPosition(Entity e, out float3 pos)
{
//IL_0005: 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_0013: 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_001c: 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_004e: 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_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
if (((EntityManager)(ref Svc.EM)).HasComponent<LocalToWorld>(e))
{
LocalToWorld componentData = ((EntityManager)(ref Svc.EM)).GetComponentData<LocalToWorld>(e);
pos = ((LocalToWorld)(ref componentData)).Position;
return true;
}
if (((EntityManager)(ref Svc.EM)).HasComponent<Translation>(e))
{
pos = ((EntityManager)(ref Svc.EM)).GetComponentData<Translation>(e).Value;
return true;
}
pos = default(float3);
return false;
}
internal static bool IsInCombat(Entity character)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: 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)
if (!Svc.Ready || character == Entity.Null)
{
return false;
}
foreach (int combatBuff in _combatBuffs)
{
try
{
if (BuffUtility.GetBuffInstanceCount<EntityManager>(Svc.EM, character, new PrefabGUID(combatBuff)) > 0)
{
return true;
}
}
catch
{
}
}
return false;
}
internal static void ReloadCombatBuffs()
{
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Expected O, but got Unknown
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Expected O, but got Unknown
_combatBuffs.Clear();
string[] array = (Settings.CombatBuffGuids.Value ?? string.Empty).Split(',');
bool flag = default(bool);
for (int i = 0; i < array.Length; i++)
{
if (!int.TryParse(array[i].Trim(), out var result))
{
continue;
}
string text = Svc.PrefabName(result);
if (string.IsNullOrEmpty(text))
{
ManualLogSource logger = Plugin.Logger;
BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(73, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] бафф '");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(result);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' не найден в префабах — пропускаю его в проверке боя.");
}
logger.LogWarning(val);
continue;
}
_combatBuffs.Add(result);
ManualLogSource logger2 = Plugin.Logger;
BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(26, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[NpcSpawner] бафф боя: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(result);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" = ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
}
logger2.LogInfo(val2);
}
if (_combatBuffs.Count == 0)
{
Plugin.Logger.LogWarning((object)"[NpcSpawner] список баффов боя пуст — игроки в бою пропускаться НЕ будут.");
}
}
private static List<PlayerRef> GetSpawnablePlayers()
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
List<PlayerRef> players = GetPlayers();
if (!Settings.SkipPlayersInCombat.Value)
{
return players;
}
List<PlayerRef> list = new List<PlayerRef>();
foreach (PlayerRef item in players)
{
if (!IsInCombat(item.Character))
{
list.Add(item);
}
}
return list;
}
private static void SpawnRandomGroup()
{
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: Expected O, but got Unknown
List<PlayerRef> spawnablePlayers = GetSpawnablePlayers();
if (spawnablePlayers.Count == 0)
{
Plugin.Logger.LogInfo((object)"[NpcSpawner] нет подходящих игроков (онлайн и не в бою) — ждём.");
return;
}
IReadOnlyList<string> groupNames = GroupNames;
if (groupNames.Count == 0)
{
Plugin.Logger.LogWarning((object)"[NpcSpawner] в npcs.json нет ни одной группы с Prefabs.");
return;
}
string text = groupNames[Rng.Next(groupNames.Count)];
SpawnGroup spawnGroup = SpawnConfig.Groups[text];
int num = Math.Min(3, spawnablePlayers.Count);
bool flag = default(bool);
for (int i = 0; i < num; i++)
{
PlayerRef playerRef = spawnablePlayers[Rng.Next(spawnablePlayers.Count)];
string text2 = SafeUserName(playerRef.UserEntity);
int num2 = SpawnGroupFor(playerRef.UserEntity, playerRef.Character, playerRef.Position, text, spawnGroup, announce: true);
if (num2 > 0)
{
ManualLogSource logger = Plugin.Logger;
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(50, 3, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] группа '");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': заспавнено ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num2);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" НПС у игрока ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
}
logger.LogInfo(val);
if (Settings.GlobalAnnounce.Value)
{
Broadcast(string.Format(Settings.GlobalSpawnMessage.Value, text2, text, num2));
}
return;
}
}
Plugin.Logger.LogInfo((object)"[NpcSpawner] не нашлось свободного места (замки/крыши) — пропускаем спавн.");
}
internal static int SpawnGroupFor(Entity userEntity, Entity character, float3 center, string groupName, SpawnGroup group, bool announce)
{
//IL_0028: 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_007d: Expected O, but got Unknown
//IL_0189: Unknown result type (might be due to invalid IL or missing references)
//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
//IL_011a: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
int num = 0;
float num2 = Settings.LifetimeSeconds.Value;
if (num2 <= 0f)
{
num2 = -1f;
}
Batch batch = new Batch
{
GroupName = groupName,
PlayerName = SafeUserName(userEntity)
};
bool flag = default(bool);
foreach (KeyValuePair<string, int> prefab in group.Prefabs)
{
if (prefab.Value <= 0)
{
continue;
}
if (!int.TryParse(prefab.Key, out var result))
{
ManualLogSource logger = Plugin.Logger;
BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(37, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] некорректный id НПС: '");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(prefab.Key);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'.");
}
logger.LogWarning(val);
continue;
}
for (int i = 0; i < prefab.Value; i++)
{
if (!TryFindFreePosition(center, group.RandomAround, out var flat))
{
break;
}
if (SpawnOne(character, result, prefab.Key, flat, num2))
{
num++;
}
}
_pickups.Add(new Pickup
{
Guid = result,
GuidKey = prefab.Key,
Batch = batch,
Center = center,
Radius = Math.Max(1f, group.RandomAround),
DueAt = DateTime.UtcNow.AddSeconds(1.5)
});
}
if (num > 0 && announce && Settings.Announce.Value)
{
SendToUser(userEntity, string.Format(Settings.AnnounceMessage.Value, groupName, num));
}
return num;
}
private static bool SpawnOne(Entity character, int guid, string guidKey, float2 flat, float lifetime)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Expected O, but got Unknown
//IL_0011: 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_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
try
{
float3 pos;
float num = (TryGetPosition(character, out pos) ? pos.y : 0f);
float3 val = default(float3);
((float3)(ref val))..ctor(flat.x, num, flat.y);
Svc.UnitSpawner.SpawnUnit(Entity.Null, new PrefabGUID(guid), val, 1, 1f, 1f, lifetime);
return true;
}
catch (Exception ex)
{
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(41, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[NpcSpawner] не удалось заспавнить НПС ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(guid);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
}
logger.LogError(val2);
return false;
}
}
private static float2 RandomAround(float3 center, float radius)
{
//IL_0041: 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_0061: Unknown result type (might be due to invalid IL or missing references)
if (radius < 1f)
{
radius = 1f;
}
double num = Rng.NextDouble() * Math.PI * 2.0;
double num2 = Math.Sqrt(Rng.NextDouble()) * (double)radius;
return new float2(center.x + (float)(Math.Cos(num) * num2), center.z + (float)(Math.Sin(num) * num2));
}
private static bool TryFindFreePosition(float3 center, float radius, out float2 flat)
{
//IL_0004: 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_000b: 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_0012: 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_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: 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_002c: Unknown result type (might be due to invalid IL or missing references)
for (int i = 0; i < 15; i++)
{
float2 val = RandomAround(center, radius);
if (!IsInsideCastleOrRoof(new float3(val.x, center.y, val.y)))
{
flat = val;
return true;
}
}
flat = default(float2);
return false;
}
private static bool IsInsideCastleOrRoof(float3 pos)
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: 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_0107: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: 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_0058: 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_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_00ef: 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_0113: Unknown result type (might be due to invalid IL or missing references)
//IL_0115: Unknown result type (might be due to invalid IL or missing references)
//IL_011a: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_0123: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: 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_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0101: Unknown result type (might be due to invalid IL or missing references)
//IL_012a: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_013a: Unknown result type (might be due to invalid IL or missing references)
//IL_0141: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
if (!Settings.BlockNearCastles.Value)
{
return false;
}
if (!_queriesCreated)
{
return false;
}
float num = Math.Max(1f, Settings.CastleBlockRadius.Value);
float num2 = num * num;
NativeArray<Entity> val = ((EntityQuery)(ref _castleFloorQuery)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
LocalToWorld componentData;
try
{
Enumerator<Entity> enumerator = val.GetEnumerator();
while (enumerator.MoveNext())
{
Entity current = enumerator.Current;
float3 position;
try
{
componentData = ((EntityManager)(ref Svc.EM)).GetComponentData<LocalToWorld>(current);
position = ((LocalToWorld)(ref componentData)).Position;
}
catch
{
continue;
}
float num3 = position.x - pos.x;
float num4 = position.z - pos.z;
if (!(num3 * num3 + num4 * num4 > num2) && !(Math.Abs(position.y - pos.y) > 12f))
{
return true;
}
}
}
finally
{
val.Dispose();
}
float num5 = Math.Max(4f, Settings.CastleHeartRadius.Value);
float num6 = num5 * num5;
NativeArray<Entity> val2 = ((EntityQuery)(ref _castleHeartQuery)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
try
{
Enumerator<Entity> enumerator = val2.GetEnumerator();
while (enumerator.MoveNext())
{
Entity current2 = enumerator.Current;
float3 position2;
try
{
componentData = ((EntityManager)(ref Svc.EM)).GetComponentData<LocalToWorld>(current2);
position2 = ((LocalToWorld)(ref componentData)).Position;
}
catch
{
continue;
}
float num7 = position2.x - pos.x;
float num8 = position2.z - pos.z;
if (num7 * num7 + num8 * num8 <= num6)
{
return true;
}
}
}
finally
{
val2.Dispose();
}
return false;
}
internal static void OnDeath(DeathEventListenerSystem system)
{
//IL_000e: 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_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: 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_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: 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_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
if (Tracked.Count == 0)
{
return;
}
EntityManager entityManager = ((ComponentSystemBase)system).EntityManager;
EntityQuery deathEventQuery = system._DeathEventQuery;
NativeArray<DeathEvent> val = ((EntityQuery)(ref deathEventQuery)).ToComponentDataArray<DeathEvent>(AllocatorHandle.op_Implicit((Allocator)2));
try
{
Enumerator<DeathEvent> enumerator = val.GetEnumerator();
while (enumerator.MoveNext())
{
DeathEvent current = enumerator.Current;
Entity died = current.Died;
if (!Tracked.TryGetValue(died, out var value))
{
continue;
}
Tracked.Remove(died);
value.Batch?.Alive.Remove(died);
Entity killer = current.Killer;
if (!(killer == Entity.Null) && ((EntityManager)(ref entityManager)).HasComponent<PlayerCharacter>(killer))
{
if (Settings.LootEnabled.Value)
{
DropLoot(entityManager, killer, value.GuidKey);
}
if (value.Batch != null && value.Batch.Alive.Count == 0 && Settings.SuccessAnnounce.Value)
{
Broadcast(string.Format(Settings.SuccessMessage.Value, value.Batch.PlayerName, value.Batch.GroupName));
}
}
}
}
finally
{
val.Dispose();
}
}
private static void DropLoot(EntityManager em, Entity killer, string npcGuid)
{
//IL_0149: Unknown result type (might be due to invalid IL or missing references)
//IL_0150: Expected O, but got Unknown
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: 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)
List<LootEntry> loot = SpawnConfig.GetLoot(npcGuid);
if (loot == null || loot.Count == 0)
{
return;
}
int num = 0;
int num2 = 0;
PrefabGUID val = default(PrefabGUID);
foreach (LootEntry item in loot)
{
if (item.ItemId == 0 || (item.Chance < 1f && Rng.NextDouble() > (double)item.Chance))
{
continue;
}
int num3 = ((item.Amount <= 0) ? 1 : item.Amount);
((PrefabGUID)(ref val))..ctor(item.ItemId);
bool flag = false;
try
{
AddItemResponse val2 = ((ServerGameManager)(ref Svc.GameManager)).TryAddInventoryItem(killer, val, num3);
flag = ((AddItemResponse)(ref val2)).Success;
}
catch (Exception ex)
{
Plugin.Logger.LogError((object)ex);
}
if (!flag)
{
try
{
((ServerGameManager)(ref Svc.GameManager)).CreateDroppedItemEntity(killer, val, num3);
}
catch (Exception ex2)
{
Plugin.Logger.LogError((object)ex2);
}
}
num += num3;
num2 = item.ItemId;
}
if (num <= 0 || !Settings.NotifyKiller.Value)
{
return;
}
try
{
SendToUser(((EntityManager)(ref em)).GetComponentData<PlayerCharacter>(killer).UserEntity, string.Format(Settings.NotifyMessage.Value, num, num2));
}
catch (Exception ex3)
{
ManualLogSource logger = Plugin.Logger;
bool flag2 = default(bool);
BepInExDebugLogInterpolatedStringHandler val3 = new BepInExDebugLogInterpolatedStringHandler(47, 1, ref flag2);
if (flag2)
{
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[NpcSpawner] сообщение о добыче не отправлено: ");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex3.Message);
}
logger.LogDebug(val3);
}
}
internal static bool TryResolveGroup(string input, out string key)
{
key = null;
if (string.IsNullOrWhiteSpace(input))
{
return false;
}
string text = input.Trim();
string text2 = RepairMojibake(text);
if (SpawnConfig.Groups.ContainsKey(text))
{
key = text;
return true;
}
if (SpawnConfig.Groups.ContainsKey(text2))
{
key = text2;
return true;
}
string text3 = null;
foreach (string groupName in GroupNames)
{
string text4 = groupName.Trim();
if (string.Equals(text4, text, StringComparison.OrdinalIgnoreCase) || string.Equals(text4, text2, StringComparison.OrdinalIgnoreCase) || text4.StartsWith(text, StringComparison.OrdinalIgnoreCase) || text4.StartsWith(text2, StringComparison.OrdinalIgnoreCase))
{
if (string.Equals(text4, text, StringComparison.OrdinalIgnoreCase) || string.Equals(text4, text2, StringComparison.OrdinalIgnoreCase))
{
key = groupName;
return true;
}
if (text3 != null)
{
return false;
}
text3 = groupName;
}
}
if (text3 != null)
{
key = text3;
return true;
}
return false;
}
private static string RepairMojibake(string s)
{
try
{
return Encoding.UTF8.GetString(Encoding.GetEncoding("ISO-8859-1").GetBytes(s));
}
catch
{
return s;
}
}
internal static List<string> DebugSnapshot()
{
//IL_011a: Unknown result type (might be due to invalid IL or missing references)
//IL_0128: Unknown result type (might be due to invalid IL or missing references)
//IL_0142: Unknown result type (might be due to invalid IL or missing references)
List<string> list = new List<string>();
if (!Svc.Ready)
{
list.Add("мир ещё не готов");
return list;
}
List<PlayerRef> players = GetPlayers();
list.Add($"игроков онлайн: {players.Count}; групп: {GroupNames.Count}");
list.Add($"плит замка видно: {(_queriesCreated ? ((EntityQuery)(ref _castleFloorQuery)).CalculateEntityCount() : 0)}; сердец замка: {(_queriesCreated ? ((EntityQuery)(ref _castleHeartQuery)).CalculateEntityCount() : 0)}");
list.Add($"баффов боя в списке: {_combatBuffs.Count}");
foreach (PlayerRef item in players)
{
bool value = IsInCombat(item.Character);
bool value2 = IsInsideCastleOrRoof(item.Position);
list.Add($"{SafeUserName(item.UserEntity)}: в бою={value}, в замке/под крышей={value2}");
}
return list;
}
internal static bool TrySpawnForCharacter(Entity character, string groupName, out int spawned, out string error)
{
//IL_0123: Unknown result type (might be due to invalid IL or missing references)
//IL_0124: Unknown result type (might be due to invalid IL or missing references)
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: 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_0042: Expected O, but got Unknown
//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0112: Unknown result type (might be due to invalid IL or missing references)
//IL_0117: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
spawned = 0;
error = null;
if (!Svc.Ready)
{
error = "мод ещё не готов (мир не загружен)";
return false;
}
if (string.IsNullOrWhiteSpace(groupName))
{
error = "не указана группа";
return false;
}
if (!TryResolveGroup(groupName, out var key))
{
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(41, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] группа '");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(groupName);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' не найдена. Есть: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(string.Join(", ", GroupNames));
}
logger.LogWarning(val);
error = "группа '" + groupName + "' не найдена — смотри .npcs list";
return false;
}
SpawnGroup spawnGroup = SpawnConfig.Groups[key];
groupName = key;
if (character == Entity.Null || !((EntityManager)(ref Svc.EM)).Exists(character))
{
error = "персонаж не найден";
return false;
}
if (!TryGetPosition(character, out var pos))
{
error = "не удалось определить позицию игрока";
return false;
}
if (Settings.SkipPlayersInCombat.Value && IsInCombat(character))
{
error = "игрок сейчас в бою — спавн запрещён";
return false;
}
Entity userEntity = Entity.Null;
try
{
if (((EntityManager)(ref Svc.EM)).HasComponent<PlayerCharacter>(character))
{
userEntity = ((EntityManager)(ref Svc.EM)).GetComponentData<PlayerCharacter>(character).UserEntity;
}
}
catch
{
}
spawned = SpawnGroupFor(userEntity, character, pos, groupName, spawnGroup, announce: true);
if (spawned <= 0)
{
error = "рядом нет свободного места — тут замок или крыша";
return false;
}
return true;
}
internal static bool TryFindOnlineCharacter(string name, out Entity character)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_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_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
character = Entity.Null;
if (string.IsNullOrWhiteSpace(name))
{
return false;
}
string text = name.Trim();
string text2 = RepairMojibake(text);
Entity val = Entity.Null;
int num = 0;
foreach (PlayerRef player in GetPlayers())
{
string text3 = SafeUserName(player.UserEntity);
if (string.Equals(text3, text, StringComparison.OrdinalIgnoreCase) || string.Equals(text3, text2, StringComparison.OrdinalIgnoreCase))
{
character = player.Character;
return true;
}
if (text3.StartsWith(text, StringComparison.OrdinalIgnoreCase) || text3.StartsWith(text2, StringComparison.OrdinalIgnoreCase))
{
val = player.Character;
num++;
}
}
if (num == 1)
{
character = val;
return true;
}
return false;
}
internal static bool TrySpawnRandomNow(out string info)
{
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
info = null;
List<PlayerRef> spawnablePlayers = GetSpawnablePlayers();
if (spawnablePlayers.Count == 0)
{
info = "нет игроков онлайн (или все в бою)";
return false;
}
IReadOnlyList<string> groupNames = GroupNames;
if (groupNames.Count == 0)
{
info = "нет групп в npcs.json";
return false;
}
PlayerRef playerRef = spawnablePlayers[Rng.Next(spawnablePlayers.Count)];
string text = groupNames[Rng.Next(groupNames.Count)];
int value = SpawnGroupFor(playerRef.UserEntity, playerRef.Character, playerRef.Position, text, SpawnConfig.Groups[text], announce: true);
info = $"группа '{text}' ({value} НПС) у игрока {SafeUserName(playerRef.UserEntity)}";
ScheduleNext("manual");
return true;
}
private static void SendToUser(Entity userEntity, string message)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Expected O, but got Unknown
//IL_0012: 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_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: 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)
try
{
if (!(userEntity == Entity.Null) && ((EntityManager)(ref Svc.EM)).Exists(userEntity) && !string.IsNullOrEmpty(message))
{
User componentData = ((EntityManager)(ref Svc.EM)).GetComponentData<User>(userEntity);
FixedString512Bytes val = FixedString512Bytes.op_Implicit(Truncate(message, 480));
ServerChatUtils.SendSystemMessageToClient(Svc.EM, componentData, ref val);
}
}
catch (Exception ex)
{
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(38, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[NpcSpawner] сообщение не отправлено: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
}
logger.LogWarning(val2);
}
}
private static string Truncate(string s, int maxBytes)
{
try
{
if (Encoding.UTF8.GetByteCount(s) <= maxBytes)
{
return s;
}
int num = s.Length;
while (num > 0 && Encoding.UTF8.GetByteCount(s.Substring(0, num)) > maxBytes)
{
num--;
}
return s.Substring(0, num);
}
catch
{
return s;
}
}
private static void Broadcast(string message)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
foreach (PlayerRef player in GetPlayers())
{
SendToUser(player.UserEntity, message);
}
}
private unsafe static string SafeUserName(Entity userEntity)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0001: 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_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)
try
{
if (userEntity == Entity.Null || !((EntityManager)(ref Svc.EM)).Exists(userEntity))
{
return "?";
}
User componentData = ((EntityManager)(ref Svc.EM)).GetComponentData<User>(userEntity);
return ((object)(*(FixedString64Bytes*)(&componentData.CharacterName))/*cast due to .constrained prefix*/).ToString();
}
catch
{
return "?";
}
}
}
internal static class Svc
{
internal static World Server;
internal static EntityManager EM;
internal static UnitSpawnerUpdateSystem UnitSpawner;
internal static ServerGameManager GameManager;
internal static PrefabCollectionSystem Prefabs;
internal static bool Ready
{
get
{
if (Server != null)
{
return Server.IsCreated;
}
return false;
}
}
internal static void Init(World world)
{
//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_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)
Server = world;
EM = world.EntityManager;
UnitSpawner = world.GetExistingSystemManaged<UnitSpawnerUpdateSystem>();
GameManager = world.GetExistingSystemManaged<ServerScriptMapper>().GetServerGameManager();
try
{
Prefabs = world.GetExistingSystemManaged<PrefabCollectionSystem>();
}
catch
{
Prefabs = null;
}
}
internal unsafe static string PrefabName(int guid)
{
//IL_0010: 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_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
try
{
if (Prefabs == null)
{
return null;
}
FixedString128Bytes assetName = Prefabs._PrefabDataLookup[new PrefabGUID(guid)].AssetName;
return ((object)(*(FixedString128Bytes*)(&assetName))/*cast due to .constrained prefix*/).ToString();
}
catch
{
return null;
}
}
}
}
namespace NpcSpawner.Patches
{
[HarmonyPatch(typeof(DeathEventListenerSystem), "OnUpdate")]
internal static class DeathPatch
{
[HarmonyPostfix]
internal static void Postfix(DeathEventListenerSystem __instance)
{
try
{
SpawnerService.OnDeath(__instance);
}
catch (Exception ex)
{
Plugin.Logger.LogError((object)ex);
}
}
}
[HarmonyPatch(typeof(ServerBootstrapSystem), "OnUserConnected")]
internal static class InitPatch
{
[HarmonyPostfix]
internal static void Postfix(ServerBootstrapSystem __instance)
{
try
{
if (!Svc.Ready)
{
Svc.Init(((ComponentSystemBase)__instance).World);
}
SpawnerService.Initialize();
}
catch (Exception ex)
{
Plugin.Logger.LogError((object)ex);
}
}
}
[HarmonyPatch(typeof(ServerBootstrapSystem), "OnUpdate")]
internal static class TickPatch
{
[HarmonyPostfix]
internal static void Postfix()
{
try
{
SpawnerService.Tick();
}
catch (Exception ex)
{
Plugin.Logger.LogError((object)ex);
}
}
}
}
namespace NpcSpawner.Commands
{
[CommandGroup("npcs", "npcspawner")]
internal static class NpcCommands
{
private const string DenyText = "<color=#ff4d4d>Команда доступна только администраторам.</color>";
private const int MaxMessageBytes = 300;
private static bool Deny(ChatCommandContext ctx)
{
//IL_0003: Unknown result type (might be due to invalid IL or missing references)
bool flag = false;
try
{
flag = ctx.User.IsAdmin;
}
catch
{
}
if (flag)
{
return false;
}
ctx.Reply("<color=#ff4d4d>Команда доступна только администраторам.</color>");
return true;
}
private static void Reply(ChatCommandContext ctx, string text)
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Expected O, but got Unknown
try
{
ctx.Reply(TruncateBytes(text, 450));
}
catch (Exception ex)
{
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(27, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] reply failed: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
}
logger.LogError(val);
}
}
private static void Run(ChatCommandContext ctx, string command, Action body)
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Expected O, but got Unknown
try
{
body();
}
catch (Exception ex)
{
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(25, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] команда '");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(command);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
}
logger.LogError(val);
Reply(ctx, "<color=#ff8080>Ошибка команды: " + ex.Message + " (подробности в логе)</color>");
}
}
private static string TruncateBytes(string s, int maxBytes)
{
try
{
if (string.IsNullOrEmpty(s))
{
return s;
}
if (Encoding.UTF8.GetByteCount(s) <= maxBytes)
{
return s;
}
int num = s.Length;
while (num > 0 && Encoding.UTF8.GetByteCount(s.Substring(0, num)) > maxBytes)
{
num--;
}
return s.Substring(0, num);
}
catch
{
return s;
}
}
private static List<string> BuildChunks(string header, IReadOnlyList<string> items, int maxBytes)
{
List<string> list = new List<string>();
StringBuilder stringBuilder = new StringBuilder(header);
bool flag = false;
foreach (string item in items)
{
string s = (flag ? (stringBuilder.ToString() + ", " + item) : (stringBuilder.ToString() + item));
if (Encoding.UTF8.GetByteCount(s) > maxBytes && flag)
{
list.Add(stringBuilder.ToString());
stringBuilder.Clear();
stringBuilder.Append(item);
flag = true;
continue;
}
if (flag)
{
stringBuilder.Append(", ");
}
stringBuilder.Append(item);
flag = true;
}
if (flag || stringBuilder.Length > 0)
{
list.Add(stringBuilder.ToString());
}
if (list.Count == 0)
{
list.Add(header);
}
return list;
}
private static void ReplyList(ChatCommandContext ctx, string header, IReadOnlyList<string> items)
{
List<string> list = BuildChunks(header, items, 300);
for (int i = 0; i < list.Count; i++)
{
string text = ((list.Count > 1) ? $"({i + 1}/{list.Count}) " : string.Empty);
Reply(ctx, text + list[i]);
}
}
private static Entity ResolveCharacter(ChatCommandContext ctx)
{
//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_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: 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_0025: 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_003f: 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_004a: 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_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_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: 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)
try
{
Entity senderUserEntity = ctx.Event.SenderUserEntity;
if (senderUserEntity != Entity.Null && Svc.Ready && ((EntityManager)(ref Svc.EM)).Exists(senderUserEntity) && ((EntityManager)(ref Svc.EM)).HasComponent<User>(senderUserEntity))
{
Entity entity = ((EntityManager)(ref Svc.EM)).GetComponentData<User>(senderUserEntity).LocalCharacter._Entity;
if (entity != Entity.Null && ((EntityManager)(ref Svc.EM)).Exists(entity))
{
return entity;
}
}
}
catch
{
}
return ctx.Event.SenderCharacterEntity;
}
[Command("help", null, null, "Справка по командам NPC Spawner", null, true)]
public static void Help(ChatCommandContext ctx)
{
if (!Deny(ctx))
{
Run(ctx, "help", delegate
{
Reply(ctx, "--- NPC Spawner (только для админов) ---");
Reply(ctx, ".npcs list — список групп из npcs.json");
Reply(ctx, ".npcs spawn <группа> — заспавнить у себя");
Reply(ctx, ".npcs spawnme <группа> — то же самое");
Reply(ctx, ".npcs spawnfor <ник> <группа> — заспавнить у игрока");
Reply(ctx, ".npcs random — случайный спавн сейчас");
Reply(ctx, ".npcs loot <id НПС> — лут для НПС");
Reply(ctx, ".npcs reload — перечитать конфиги");
Reply(ctx, ".npcs debug — диагностика");
});
}
}
[Command("list", null, null, "Список групп НПС", null, true)]
public static void List(ChatCommandContext ctx)
{
if (Deny(ctx))
{
return;
}
Run(ctx, "list", delegate
{
IReadOnlyList<string> groupNames = SpawnerService.GroupNames;
if (groupNames.Count == 0)
{
Reply(ctx, "Групп нет. Проверь BepInEx/config/NpcSpawner/npcs.json");
}
else
{
ReplyList(ctx, $"Группы ({groupNames.Count}): ", groupNames);
}
});
}
[Command("spawn", null, "<группа>", "Заспавнить группу НПС рядом с собой", null, true)]
public static void Spawn(ChatCommandContext ctx, string group)
{
if (!Deny(ctx))
{
SpawnSelf(ctx, group);
}
}
[Command("spawnme", null, "<группа>", "Заспавнить группу НПС рядом с собой", null, true)]
public static void SpawnMe(ChatCommandContext ctx, string group)
{
if (!Deny(ctx))
{
SpawnSelf(ctx, group);
}
}
private static void SpawnSelf(ChatCommandContext ctx, string group)
{
Run(ctx, "spawn", delegate
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Expected O, but got Unknown
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(33, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] команда spawn '");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(group);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' от ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(SafeName(ctx));
}
logger.LogInfo(val);
if (SpawnerService.TrySpawnForCharacter(ResolveCharacter(ctx), group, out var spawned, out var error))
{
Reply(ctx, $"<color=#3cff8a>Заспавнено {spawned} НПС из группы '{group}'.</color>");
}
else
{
Reply(ctx, "<color=#ff8080>Не вышло: " + error + "</color>");
}
});
}
[Command("spawnfor", null, "<ник> <группа>", "Заспавнить группу НПС у другого игрока", null, true)]
public static void SpawnFor(ChatCommandContext ctx, string playerName, string group)
{
if (Deny(ctx))
{
return;
}
Run(ctx, "spawnfor", delegate
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Expected O, but got Unknown
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(39, 3, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[NpcSpawner] команда spawnfor '");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(playerName);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' '");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(group);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' от ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(SafeName(ctx));
}
logger.LogInfo(val);
int spawned;
string error;
if (!SpawnerService.TryFindOnlineCharacter(playerName, out var character))
{
Reply(ctx, "<color=#ff8080>Игрок '" + playerName + "' не в сети.</color>");
}
else if (SpawnerService.TrySpawnForCharacter(character, group, out spawned, out error))
{
Reply(ctx, $"<color=#3cff8a>Заспавнено {spawned} НПС из группы '{group}' у {playerName}.</color>");
}
else
{
Reply(ctx, "<color=#ff8080>Не вышло: " + error + "</color>");
}
});
}
[Command("random", null, null, "Случайный спавн как по таймеру (сейчас)", null, true)]
public static void Random(ChatCommandContext ctx)
{
if (Deny(ctx))
{
return;
}
Run(ctx, "random", delegate
{
if (SpawnerService.TrySpawnRandomNow(out var info))
{
Reply(ctx, "<color=#3cff8a>Случайный спавн: " + info + "</color>");
}
else
{
Reply(ctx, "<color=#ff8080>Не вышло: " + info + "</color>");
}
});
}
[Command("loot", null, "<id НПС>", "Показать настроенный лут для НПС", null, true)]
public static void Loot(ChatCommandContext ctx, string npcId)
{
if (Deny(ctx))
{
return;
}
Run(ctx, "loot", delegate
{
List<LootEntry> loot = SpawnConfig.GetLoot(npcId);
if (loot == null || loot.Count == 0)
{
Reply(ctx, "Для '" + npcId + "' лут не настроен (см. BepInEx/config/NpcSpawner/loot.json)");
}
else
{
List<string> list = new List<string>();
foreach (LootEntry item in loot)
{
list.Add($"{item.ItemId} x{item.Amount} ({item.Chance * 100f:0.#}%)");
}
ReplyList(ctx, npcId + ": ", list);
}
});
}
[Command("reload", null, null, "Перечитать npcs.json и loot.json без рестарта", null, true)]
public static void Reload(ChatCommandContext ctx)
{
if (!Deny(ctx))
{
Run(ctx, "reload", delegate
{
SpawnConfig.LoadAll();
SpawnerService.ReloadCombatBuffs();
Reply(ctx, $"<color=#3cff8a>Перечитано: групп {SpawnConfig.Groups.Count}, записей лута {SpawnConfig.Loot.Count}.</color>");
});
}
}
[Command("debug", null, null, "Диагностика: кто в бою, где найдены замки", null, true)]
public static void Debug(ChatCommandContext ctx)
{
if (Deny(ctx))
{
return;
}
Run(ctx, "debug", delegate
{
foreach (string item in SpawnerService.DebugSnapshot())
{
Reply(ctx, item);
}
});
}
private static string SafeName(ChatCommandContext ctx)
{
try
{
return ctx.Name;
}
catch
{
return "?";
}
}
}
}