Decompiled source of PVESieges v1.0.363
PVESieges.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using HarmonyLib; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Microsoft.CodeAnalysis; using ProjectM; using ProjectM.CastleBuilding; using ProjectM.Network; using ProjectM.Pathfinding; using ProjectM.Scripting; using ProjectM.Shared; using ProjectM.Tiles; using SemanticVersioning; using Stunlock.Core; using Stunlock.Network; using Unity.Collections; using Unity.Entities; using Unity.Mathematics; using Unity.Transforms; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("PVESieges")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.363.0")] [assembly: AssemblyInformationalVersion("1.0.363")] [assembly: AssemblyProduct("PVESieges")] [assembly: AssemblyTitle("PVESieges")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.363.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] internal sealed class IsUnmanagedAttribute : Attribute { } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace CastleSieges { [HarmonyPatch(typeof(ChatMessageSystem), "OnUpdate")] internal static class ChatCommand { private static void Prefix() { if (Plugin.Off) { return; } long t = Prof.Start(); try { Check(); } finally { Prof.Stop("chat hook (every frame)", t); Prof.AddToFrame(t); } } private unsafe static void Check() { //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Expected O, but got Unknown //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_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_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_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) //IL_007e: 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_00a1: 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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) try { if (!Ecs.FindServerWorld()) { return; } foreach (Entity item in Ecs.Query(Ecs.RO<ChatMessageEvent>(), Ecs.RO<FromCharacter>())) { ChatMessageEvent val = item.Read<ChatMessageEvent>(); string text = ((object)(*(FixedString512Bytes*)(&val.MessageText))/*cast due to .constrained prefix*/).ToString().Trim(); if (text.Equals("!siegehelp", StringComparison.OrdinalIgnoreCase) || text.Equals("!siege help", StringComparison.OrdinalIgnoreCase)) { Help(item.Read<FromCharacter>().User); } else if (text.StartsWith("!siegestop", StringComparison.OrdinalIgnoreCase)) { SiegeDirector.RequestStop(item.Read<FromCharacter>().User, text.Substring(10).Trim()); } else if (text.Equals("!siegeoptout", StringComparison.OrdinalIgnoreCase) || text.Equals("!siegeoptin", StringComparison.OrdinalIgnoreCase)) { SiegeDirector.RequestOptOut(item.Read<FromCharacter>().User, text.Equals("!siegeoptout", StringComparison.OrdinalIgnoreCase)); } else if (text.StartsWith("!siegemsg", StringComparison.OrdinalIgnoreCase)) { SiegeDirector.RequestMessages(item.Read<FromCharacter>().User, text.Substring(9).Trim()); } else if (text.StartsWith("!siege", StringComparison.OrdinalIgnoreCase)) { string text2 = ((text.Length > 6) ? text.Substring(6) : ""); if (text2.Length <= 0 || char.IsWhiteSpace(text2[0])) { SiegeDirector.RequestSiege(item.Read<FromCharacter>().User, text2.Trim()); } } } } catch (Exception ex) { ManualLogSource l = Plugin.L; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(38, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("PVESieges: chat command check failed: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message); } l.LogWarning(val2); } } private static void Help(Entity user) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0011: 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_0017: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) EntityManager eM = Ecs.EM; if (!((EntityManager)(ref eM)).Exists(user)) { return; } User val = user.Read<User>(); bool num = Settings.B("ChatCommand"); bool flag = num && (!Settings.B("ChatCommandAdminOnly") || val.IsAdmin); List<string> list = new List<string> { "<color=#c0392b>[Castle Siege]</color> Commands:" }; list.Add("!siegemsg [on|off] - show or hide raid messages for yourself"); if (Settings.B("AllowOptOut")) { list.Add("!siegeoptout / !siegeoptin - your clan gets no raids / gets them again"); } if (flag) { list.Add("!siege [faction] - call a siege on your castle (stand near your heart)"); list.Add("!siegestop - end the siege on your castle (or the nearest one)"); } if (num && val.IsAdmin) { list.Add("!siege all [faction] - a siege on every castle whose clan is online"); list.Add("!siege [all] [faction] <number> - that many raiders in every wave (max 200)"); list.Add("!siegestop all - end every siege"); list.Add("!siege terrain - a map of the ground round you, in the server log (testing)"); list.Add("!siege pieces - the castle pieces within 4 m of you and how the raid sees them (testing)"); list.Add("!siege vfx [name|id] - show the heart-lost effect (or crimsonnova, bloodsoul, feeddracula, ringofblood, fountain)"); list.Add("Factions: " + string.Join(", ", Sheets.Factions.Select((FactionRow f) => f.Id))); } else if (flag) { list.Add("Factions: " + string.Join(", ", Sheets.Factions.Select((FactionRow f) => f.Id))); } list.Add("!siegehelp - this list"); FixedString512Bytes val2 = default(FixedString512Bytes); foreach (string item in list) { ((FixedString512Bytes)(ref val2))..ctor(item); ServerChatUtils.SendSystemMessageToClient(Ecs.EM, val, ref val2); } } } internal static class Ecs { private static class CT<T> { public static readonly ComponentType R = ComponentType.ReadOnly(Il2CppType.Of<T>()); public static readonly ComponentType W = ComponentType.ReadWrite(Il2CppType.Of<T>()); } private static class Fast<T> where T : unmanaged { public static int State; } public static World Server; private static readonly Dictionary<(int, int, int), EntityQuery> Queries = new Dictionary<(int, int, int), EntityQuery>(); private static World _queriesWorld; private static readonly List<Entity> Empty = new List<Entity>(); private static bool _bulkFailed; public static EntityManager EM => Server.EntityManager; public static bool FindServerWorld() { if (Server != null && Server.IsCreated) { return true; } Enumerator<World> enumerator = World.s_AllWorlds.GetEnumerator(); while (enumerator.MoveNext()) { World current = enumerator.Current; if (current.Name == "Server") { Server = current; return true; } } return false; } public static ComponentType RO<T>() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return CT<T>.R; } public static ComponentType RW<T>() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return CT<T>.W; } public unsafe static T Read<T>(this Entity e) where T : unmanaged { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_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_0010: Unknown result type (might be due to invalid IL or missing references) ComponentType val = RO<T>(); EntityManager eM = EM; return *(T*)((EntityManager)(ref eM)).GetComponentDataRawRO(e, val.TypeIndex); } public unsafe static void Write<T>(this Entity e, T value) where T : unmanaged { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_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_0010: Unknown result type (might be due to invalid IL or missing references) ComponentType w = CT<T>.W; EntityManager eM = EM; ((EntityManager)(ref eM)).SetComponentDataRaw(e, w.TypeIndex, (void*)(&value), sizeof(T)); } public unsafe static void WriteField<T, TField>(this Entity e, string field, TField value) where T : unmanaged where TField : unmanaged { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_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_0010: Unknown result type (might be due to invalid IL or missing references) ComponentType w = CT<T>.W; EntityManager eM = EM; byte* componentDataRawRW = (byte*)((EntityManager)(ref eM)).GetComponentDataRawRW(e, w.TypeIndex); int num = Marshal.OffsetOf<T>(field).ToInt32(); *(TField*)(componentDataRawRW + num) = value; } public static bool Has<T>(this Entity e) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0009: Unknown result type (might be due to invalid IL or missing references) EntityManager eM = EM; return ((EntityManager)(ref eM)).HasComponent(e, RO<T>()); } public unsafe static T* Ptr<T>(NativeArray<T> a) where T : unmanaged { //IL_0015: 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_009a: Expected O, but got Unknown if (Fast<T>.State == 2 || a.Length == 0) { return null; } try { T* buffer = (T*)a.m_Buffer; if (buffer == null) { return null; } int num; int state; if (Fast<T>.State == 0) { T val = a[0]; T val2 = a[a.Length - 1]; if (UnsafeEq(&val, buffer)) { num = (UnsafeEq(&val2, buffer + a.Length - 1) ? 1 : 0); if (num != 0) { state = 1; goto IL_0082; } } else { num = 0; } state = 2; goto IL_0082; } goto IL_00d8; IL_0082: Fast<T>.State = state; if (num == 0) { ManualLogSource l = Plugin.L; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(74, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("PVESieges: reading "); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(typeof(T).Name); ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" arrays directly isn't available; using the slower way."); } l.LogInfo(val3); return null; } goto IL_00d8; IL_00d8: return buffer; } catch { Fast<T>.State = 2; return null; } } private unsafe static bool UnsafeEq<T>(T* a, T* b) where T : unmanaged { for (int i = 0; i < sizeof(T); i++) { if (((byte*)a)[i] != ((byte*)b)[i]) { return false; } } return true; } public static EntityQuery Q(ComponentType[] types) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return GetQuery(types); } private static EntityQuery GetQuery(ComponentType[] types) { //IL_0030: 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_0064: 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_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) if (_queriesWorld != Server) { Queries.Clear(); _queriesWorld = Server; } (int, int, int) key = ((types.Length != 0) ? TypeIndex.op_Implicit(types[0].TypeIndex) : (-1), (types.Length > 1) ? TypeIndex.op_Implicit(types[1].TypeIndex) : (-1), (types.Length > 2) ? TypeIndex.op_Implicit(types[2].TypeIndex) : (-1)); if (types.Length > 3 || !Queries.TryGetValue(key, out var value)) { EntityManager eM = EM; value = ((EntityManager)(ref eM)).CreateEntityQuery(types); if (types.Length <= 3) { Queries[key] = value; } } return value; } public unsafe static (List<Entity> ents, List<float3> pos) QueryPos(params ComponentType[] types) { //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_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Expected O, but got Unknown //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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: 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_00a9: 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_007a: 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_00ce: 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) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013b: 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) EntityQuery query = GetQuery(types); List<Entity> list = new List<Entity>(); List<float3> list2 = new List<float3>(); if (((EntityQuery)(ref query)).IsEmptyIgnoreFilter) { if (types.Length > 3) { ((EntityQuery)(ref query)).Dispose(); } return (ents: list, pos: list2); } NativeArray<Entity> a = ((EntityQuery)(ref query)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2)); try { list.Capacity = a.Length; list2.Capacity = a.Length; Entity* ptr = Ecs.Ptr<Entity>(a); if (ptr != null) { for (int i = 0; i < a.Length; i++) { list.Add(((Entity*)ptr)[i]); } } else { Enumerator<Entity> enumerator = a.GetEnumerator(); while (enumerator.MoveNext()) { Entity current = enumerator.Current; list.Add(current); } } if (!_bulkFailed) { try { NativeArray<Translation> a2 = ((EntityQuery)(ref query)).ToComponentDataArray<Translation>(AllocatorHandle.op_Implicit((Allocator)2)); try { if (a2.Length == a.Length) { Translation* ptr2 = Ecs.Ptr<Translation>(a2); if (ptr2 != null) { for (int j = 0; j < a2.Length; j++) { list2.Add(((Translation)((byte*)ptr2 + (nint)j * (nint)Unsafe.SizeOf<Translation>())).Value); } } else { Enumerator<Translation> enumerator2 = a2.GetEnumerator(); while (enumerator2.MoveNext()) { Translation current2 = enumerator2.Current; list2.Add(current2.Value); } } } } finally { a2.Dispose(); } } catch (Exception ex) { _bulkFailed = true; list2.Clear(); ManualLogSource l = Plugin.L; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(81, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PVESieges: reading positions in bulk isn't available ("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("); reading them one by one."); } l.LogInfo(val); } } if (list2.Count != list.Count) { list2.Clear(); foreach (Entity item in list) { list2.Add(item.Read<Translation>().Value); } } } finally { a.Dispose(); if (types.Length > 3) { ((EntityQuery)(ref query)).Dispose(); } } return (ents: list, pos: list2); } public unsafe static List<Entity> Query(params ComponentType[] types) { //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_0026: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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_008e: 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) EntityQuery query = GetQuery(types); if (((EntityQuery)(ref query)).IsEmptyIgnoreFilter) { if (types.Length > 3) { ((EntityQuery)(ref query)).Dispose(); } return Empty; } NativeArray<Entity> a = ((EntityQuery)(ref query)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2)); List<Entity> list = new List<Entity>(a.Length); try { Entity* ptr = Ecs.Ptr<Entity>(a); if (ptr != null) { for (int i = 0; i < a.Length; i++) { list.Add(((Entity*)ptr)[i]); } } else { Enumerator<Entity> enumerator = a.GetEnumerator(); while (enumerator.MoveNext()) { Entity current = enumerator.Current; list.Add(current); } } } finally { a.Dispose(); if (types.Length > 3) { ((EntityQuery)(ref query)).Dispose(); } } return list; } } [HarmonyPatch(typeof(ServerBootstrapSystem), "OnUserConnected")] internal static class JoinHook { public static bool Hooked; public static volatile bool Unknown; public static readonly Queue<Entity> Joined = new Queue<Entity>(); private static void Postfix(ServerBootstrapSystem __instance, NetConnectionId netConnectionId) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_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_004d: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Off) { return; } try { int num = default(int); if (__instance._NetEndPointToApprovedUserIndex.TryGetValue(netConnectionId, ref num)) { Entity userEntity = ((Il2CppArrayBase<ServerClient>)(object)__instance._ApprovedUsersLookup)[num].UserEntity; if (userEntity != Entity.Null) { lock (Joined) { Joined.Enqueue(userEntity); return; } } } } catch { } Unknown = true; } } internal static class PieceIndex { public enum Kind { Wall, Door, Pillar, Railing, Stairs, Floor, All } private sealed class Snap { public readonly Dictionary<(int, int), List<(Entity e, float3 p)>>[] Cells = new Dictionary<(int, int), List<(Entity, float3)>>[7]; public readonly int[] Counts = new int[7]; public Snap() { for (int i = 0; i < 7; i++) { Cells[i] = new Dictionary<(int, int), List<(Entity, float3)>>(); } } } private const int Kinds = 7; private const float Cell = 32f; private static Snap _live; private static Snap _build; private static World _world; private static int _kind; private static int _cursor; private static bool _open; private static bool _posOk; private static NativeArray<Entity> _ents; private static NativeArray<Translation> _pos; private static float _sweepStart = -1000f; private static bool _versionsFailed; private static float _allAt = -1000f; private static readonly int[] _sweptVersion = new int[7] { -1, -1, -1, -1, -1, -1, -1 }; private static readonly int[] _buildVersion = new int[7]; private static bool _bulkFailed; private unsafe static Entity* _ep; private unsafe static Translation* _pp; public static bool Ready { get { if (_live != null) { return _world == Ecs.Server; } return false; } } public static int Count(Kind k) { Snap live = _live; if (live == null) { return 0; } return live.Counts[(int)k]; } private static ComponentType[] Types(int kind) { //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_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) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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_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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008b: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_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_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: 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_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: 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) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) return kind switch { 0 => (ComponentType[])(object)new ComponentType[3] { Ecs.RO<CastleWall>(), Ecs.RO<CastleHeartConnection>(), Ecs.RO<Translation>() }, 1 => (ComponentType[])(object)new ComponentType[3] { Ecs.RO<Door>(), Ecs.RO<CastleHeartConnection>(), Ecs.RO<Translation>() }, 2 => (ComponentType[])(object)new ComponentType[3] { Ecs.RO<CastleWallPillar>(), Ecs.RO<CastleHeartConnection>(), Ecs.RO<Translation>() }, 3 => (ComponentType[])(object)new ComponentType[3] { Ecs.RO<CastleRailing>(), Ecs.RO<CastleHeartConnection>(), Ecs.RO<Translation>() }, 4 => (ComponentType[])(object)new ComponentType[3] { Ecs.RO<CastleStairs>(), Ecs.RO<CastleHeartConnection>(), Ecs.RO<Translation>() }, 5 => (ComponentType[])(object)new ComponentType[3] { Ecs.RO<CastleFloor>(), Ecs.RO<CastleHeartConnection>(), Ecs.RO<Translation>() }, _ => (ComponentType[])(object)new ComponentType[2] { Ecs.RO<CastleHeartConnection>(), Ecs.RO<Translation>() }, }; } private static ComponentType Marker(int kind) { //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_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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_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_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_0056: 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) return (ComponentType)(kind switch { 0 => Ecs.RO<CastleWall>(), 1 => Ecs.RO<Door>(), 2 => Ecs.RO<CastleWallPillar>(), 3 => Ecs.RO<CastleRailing>(), 4 => Ecs.RO<CastleStairs>(), 5 => Ecs.RO<CastleFloor>(), _ => Ecs.RO<CastleHeartConnection>(), }); } private static int KindVersion(int kind) { //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_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) if (_versionsFailed) { return -1; } try { EntityQuery val = Ecs.Q((ComponentType[])(object)new ComponentType[1] { Marker(kind) }); return ((EntityQuery)(ref val)).GetCombinedComponentOrderVersion(); } catch { _versionsFailed = true; return -1; } } public static long StructureVersion() { long num = 0L; for (int i = 0; i < 6; i++) { int num2 = KindVersion(i); if (num2 < 0) { return -1L; } num = num * 1000003 + num2; } return num; } private unsafe static void Close() { _ep = null; _pp = null; if (!_open) { return; } try { _ents.Dispose(); } catch { } if (_posOk) { try { _pos.Dispose(); } catch { } } _open = false; _posOk = false; } private unsafe static void OpenKind() { //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_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_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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) //IL_0092: Unknown result type (might be due to invalid IL or missing references) EntityQuery val = Ecs.Q(Types(_kind)); _ents = ((EntityQuery)(ref val)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)4)); _posOk = false; if (!_bulkFailed) { try { _pos = ((EntityQuery)(ref val)).ToComponentDataArray<Translation>(AllocatorHandle.op_Implicit((Allocator)4)); _posOk = _pos.Length == _ents.Length; if (!_posOk) { _pos.Dispose(); } } catch { _bulkFailed = true; } } _ep = Ecs.Ptr<Entity>(_ents); _pp = (_posOk ? Ecs.Ptr<Translation>(_pos) : null); _open = true; _cursor = 0; } public static void Step(float now, bool busy, float budgetMs) { if (_world != Ecs.Server) { Close(); _build = null; _live = null; _world = Ecs.Server; } if (_build == null) { if (_live != null && now - _sweepStart < (busy ? 5f : 30f)) { return; } _build = new Snap(); _kind = 0; _sweepStart = now; } long timestamp = Stopwatch.GetTimestamp(); long budget = (long)((double)(budgetMs * (float)Stopwatch.Frequency) / 1000.0); Run(timestamp, budget); } private static void BuildNow(float now) { if (_world != Ecs.Server) { Close(); _build = null; _live = null; _world = Ecs.Server; } if (_build == null) { _build = new Snap(); _kind = 0; _sweepStart = now; } Run(Stopwatch.GetTimestamp(), 2305843009213693951L); } private unsafe static void Run(long t0, long budget) { //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Expected O, but got Unknown //IL_0144: 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_0149: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0196: 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_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) try { int num = 0; while (_build != null) { if (!_open) { int num2 = KindVersion(_kind); _buildVersion[_kind] = num2; int num3; if (_kind == 6 && _live != null) { num3 = ((Time.time - _allAt < 30f) ? 1 : 0); if (num3 != 0) { num2 = _sweptVersion[_kind]; _buildVersion[_kind] = num2; } } else { num3 = 0; } if (num3 != 0 || (num2 >= 0 && _live != null && num2 == _sweptVersion[_kind])) { _build.Cells[_kind] = _live.Cells[_kind]; _build.Counts[_kind] = _live.Counts[_kind]; if (++_kind >= 7) { Finish(); break; } continue; } if (_kind == 6) { _allAt = Time.time; } OpenKind(); } Dictionary<(int, int), List<(Entity, float3)>> dictionary = _build.Cells[_kind]; int length = _ents.Length; while (_cursor < length) { Entity val = (Entity)((_ep != null) ? ((Entity*)_ep)[_cursor] : _ents[_cursor]); float3 val2; if (_posOk) { val2 = ((_pp != null) ? ((Translation)((byte*)_pp + (nint)_cursor * (nint)Unsafe.SizeOf<Translation>())).Value : _pos[_cursor].Value); } else { EntityManager eM = Ecs.EM; if (!((EntityManager)(ref eM)).Exists(val)) { _cursor++; continue; } val2 = val.Read<Translation>().Value; } (int, int) key = ((int)math.floor(val2.x / 32f), (int)math.floor(val2.z / 32f)); if (!dictionary.TryGetValue(key, out var value)) { value = (dictionary[key] = new List<(Entity, float3)>()); } value.Add((val, val2)); _build.Counts[_kind]++; _cursor++; num++; if ((num & 0x7F) == 0 && Stopwatch.GetTimestamp() - t0 > budget) { return; } } Close(); _kind++; if (_kind >= 7) { Finish(); break; } if (Stopwatch.GetTimestamp() - t0 > budget) { break; } } } catch (Exception ex) { Close(); _build = null; ManualLogSource l = Plugin.L; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(31, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("PVESieges: castle piece index: "); ((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(ex.Message); } l.LogWarning(val3); } } private static void Finish() { for (int i = 0; i < 7; i++) { _sweptVersion[i] = _buildVersion[i]; } _live = _build; _build = null; } public static List<(Entity e, float3 p)> Near(Kind kind, IEnumerable<float2> centres, float radius, Func<float3, bool> keep = null, bool alive = true) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) if (!Ready) { long t = Prof.Start(); BuildNow(Time.time); Prof.Stop("castle piece index (first, all at once)", t); } List<(Entity, float3)> list = new List<(Entity, float3)>(); if (_live == null) { return list; } Dictionary<(int, int), List<(Entity, float3)>> dictionary = _live.Cells[(int)kind]; HashSet<(int, int)> hashSet = new HashSet<(int, int)>(); float num = radius * radius; int num2 = (int)math.ceil(radius / 32f); List<float2> list2 = new List<float2>(centres); float2 val3 = default(float2); foreach (float2 item in list2) { int num3 = (int)math.floor(item.x / 32f); int num4 = (int)math.floor(item.y / 32f); for (int i = num3 - num2; i <= num3 + num2; i++) { for (int j = num4 - num2; j <= num4 + num2; j++) { if (!hashSet.Add((i, j)) || !dictionary.TryGetValue((i, j), out var value)) { continue; } foreach (var (val, val2) in value) { ((float2)(ref val3))..ctor(val2.x, val2.z); bool flag = false; foreach (float2 item2 in list2) { if (math.distancesq(val3, item2) <= num) { flag = true; break; } } if (!flag || (keep != null && !keep(val2))) { continue; } if (alive) { EntityManager eM = Ecs.EM; if (!((EntityManager)(ref eM)).Exists(val)) { continue; } } list.Add((val, val2)); } } } } return list; } public static List<(Entity e, float3 p)> Near(Kind kind, float2 centre, float radius, Func<float3, bool> keep = null, bool alive = true) { //IL_0009: 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) return Near(kind, (IEnumerable<float2>)(object)new float2[1] { centre }, radius, keep, alive); } } internal sealed class PlotMap { public const int Half = 120; public int N = 240; public int NN = 57600; public const float DoorCost = 30f; public const int OutsideSteps = 8; public const int OutsideStepsNarrow = 20; public const int OutsideStepsTerrain = 75; public int OutSteps = 8; public const float Depth = 20f; public const int MaxLower = 6; public float2 O; public float Y; public float[] Ys; public int L; public bool[][] Floor; public sbyte[] Lowest; public bool[] Blocked; public bool[] Wall; public const float WallCost = 500f; public bool ShutIn; public bool Terrain; public float[] GroundH; public bool[] TerrDone; public bool[] Castle; public const float MaxRise = 1.5f; public const float MaxEdgeStep = 2f; public short[] DoorAt; public float[] Dist; public byte[] Out; public readonly Dictionary<int, List<int>> Links = new Dictionary<int, List<int>>(); public readonly List<Entity> Doors = new List<Entity>(); public readonly List<bool> DoorOpen = new List<bool>(); public readonly List<(Entity e, int2 lo, int2 hi)> Blockers = new List<(Entity, int2, int2)>(); public bool Done; public float StartedAt; public float DoneAt; public long Ver; public int BrokenCount; public int[] Next; public int PostStage; public long Sig; public float SigAt; public readonly HashSet<Entity> DoorSet = new HashSet<Entity>(); public int BlocksSeen; public int Stairs; public int TerrBlocked; public bool FootDone; public bool Raised; public float3? Foot; public string FootWhy; public bool GateDone; public float3? Gate; public byte[] PlotBlock; public PriorityQueue<int, float> Pq; public int Steps; public readonly Dictionary<int, Entity> DoorMemo = new Dictionary<int, Entity>(); public readonly HashSet<Entity> DoorMemoAll = new HashSet<Entity>(); public long DoorMemoKey = -1L; public long SealedKey = -1L; public bool SealedCache; public int Thick; public void Alloc(int layers, PlotMap reuse = null) { L = layers; int num = (L + 1) * NN; if (reuse != null && reuse.N == N && reuse.L == L && reuse.Dist != null) { Floor = reuse.Floor; bool[][] floor = Floor; for (int i = 0; i < floor.Length; i++) { Array.Clear(floor[i]); } Lowest = reuse.Lowest; PlotBlock = reuse.PlotBlock; Array.Clear(PlotBlock); Blocked = reuse.Blocked; Array.Clear(Blocked); Wall = reuse.Wall; Array.Clear(Wall); DoorAt = reuse.DoorAt; Array.Clear(DoorAt); Dist = reuse.Dist; Out = reuse.Out; Array.Clear(Out); GroundH = reuse.GroundH; TerrDone = reuse.TerrDone; Array.Clear(TerrDone); Castle = reuse.Castle; Array.Clear(Castle); reuse.Dist = null; } else { Floor = new bool[L][]; for (int j = 0; j < L; j++) { Floor[j] = new bool[NN]; } Lowest = new sbyte[NN]; PlotBlock = new byte[(N / 2 + 1) * (N / 2 + 1)]; Blocked = new bool[num]; Wall = new bool[num]; DoorAt = new short[num]; Dist = new float[num]; Out = new byte[num]; GroundH = new float[NN]; TerrDone = new bool[NN]; Castle = new bool[NN]; } Array.Fill(GroundH, float.NaN); Array.Fill(Dist, float.MaxValue); } public int Cell(float3 p) { //IL_0000: 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) int num = (int)math.floor(p.x - O.x); int num2 = (int)math.floor(p.z - O.y); if (num < 0 || num2 < 0 || num >= N || num2 >= N) { return -1; } return num * N + num2; } public int Node(float3 p) { //IL_0001: 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) int num = Cell(p); if (num < 0) { return -1; } int num2 = -1; float num3 = 2.5f; for (int i = 0; i < L; i++) { if (Floor[i][num]) { float num4 = math.abs(p.y - Ys[i]); if (num4 <= num3) { num3 = num4; num2 = i; } } } if (num2 >= 0) { return num2 * NN + num; } if (Lowest[num] >= 0) { return -1; } return L * NN + num; } public bool Ground(int node) { return node / NN == L; } public float3 Center(int node, float y) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) int num = node / NN; int num2 = node % NN; float num3 = ((num < L) ? Ys[num] : (float.IsNaN(GroundH[num2]) ? y : GroundH[num2])); return new float3(O.x + (float)(num2 / N) + 0.5f, num3, O.y + (float)(num2 % N) + 0.5f); } public void Edges(int node, List<(int n, float len)> into) { into.Clear(); int num = node / NN; int num2 = node % NN; int num3 = num2 / N; int num4 = num2 % N; bool flag = num == L; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (i == 0 && j == 0) { continue; } int num5 = num3 + i; int num6 = num4 + j; if (num5 < 0 || num6 < 0 || num5 >= N || num6 >= N) { continue; } int num7 = num5 * N + num6; bool flag2 = i != 0 && j != 0; float num8 = (flag2 ? 1.4142f : 1f); int num9; if (!flag && Floor[num][num7]) { num9 = num * NN + num7; } else if (!flag) { if (flag2 || Lowest[num7] >= 0 || Lowest[num2] != num || Blocked[num * NN + num7] || (!float.IsNaN(GroundH[num7]) && math.abs(GroundH[num7] - Ys[num]) > 2f)) { continue; } num9 = L * NN + num7; } else if (Lowest[num7] < 0) { float num10 = GroundH[num2]; float num11 = GroundH[num7]; if (!float.IsNaN(num10) && !float.IsNaN(num11) && math.abs(num10 - num11) > 1.5f * num8) { continue; } num9 = L * NN + num7; } else { if (flag2 || Blocked[L * NN + num7] || (!float.IsNaN(GroundH[num2]) && math.abs(GroundH[num2] - Ys[Lowest[num7]]) > 2f)) { continue; } num9 = Lowest[num7] * NN + num7; } if (Blocked[num9]) { continue; } if (flag2) { int num12 = num9 / NN; if (Blocked[num12 * NN + num3 * N + num6] || Blocked[num12 * NN + num5 * N + num4]) { continue; } } into.Add((num9, num8)); } } if (!Links.TryGetValue(node, out var value)) { return; } foreach (int item in value) { into.Add((item, 3f)); } } } [BepInPlugin("pvesieges", "PVESieges", "1.0.363")] public class Plugin : BasePlugin { public const string Guid = "pvesieges"; public const string OldGuid = "melty.castlesieges"; internal static bool Off; public const string Name = "PVESieges"; public const string Version = "1.0.363"; internal static ManualLogSource L; internal static Plugin Instance; private Harmony _harmony; public const string ConfigName = "PVESieges.cfg"; public const string OldConfigName = "melty.castlesieges.cfg"; public static bool IsClient => Application.productName == "VRising"; public override void Load() { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown Instance = this; L = ((BasePlugin)this).Log; if (IsClient) { L.LogInfo((object)"PVESieges: game client: nothing to do here; sieges run on the server. For private / hosted games, install BepInEx and this mod into VRising_Server (see the README)."); return; } Settings.Bind(OpenConfig()); if (OldCopyRunning()) { return; } ((BasePlugin)this).AddComponent<SiegeTicker>(); _harmony = new Harmony("pvesieges"); _harmony.PatchAll(typeof(ChatCommand)); _harmony.PatchAll(typeof(VBloodKills)); bool flag = default(bool); try { _harmony.PatchAll(typeof(JoinHook)); JoinHook.Hooked = true; } catch (Exception ex) { ManualLogSource l = L; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(86, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PVESieges: couldn't hook players joining ("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("); the join message looks every 5 s instead."); } l.LogWarning(val); } ManualLogSource l2 = L; BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(62, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("PVESieges: server loaded ("); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(Sheets.Factions.Length); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" factions, "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(Sheets.Units.Length); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" unit types, "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(Sheets.Waves.Length); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" wave rows)."); } l2.LogInfo(val2); } internal static bool OldCopyRunning() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown if (Off) { return true; } try { if (((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.TryGetValue("melty.castlesieges", out var value) && value != null) { Off = true; ManualLogSource l = L; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(158, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PVESieges: an older copy of this mod ("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Version>(value.Metadata.Version); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", id "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("melty.castlesieges"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(") is loaded as well, from "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(value.Location); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; this copy stays off so they don't run twice. Remove the older file and restart to run "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.0.363"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("."); } l.LogWarning(val); return true; } } catch { } return false; } private ConfigFile OpenConfig() { //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown string text = Path.Combine(Paths.ConfigPath, "PVESieges.cfg"); string text2 = Path.Combine(Paths.ConfigPath, "melty.castlesieges.cfg"); bool flag = default(bool); try { if (!File.Exists(text) && File.Exists(text2)) { File.Move(text2, text); ManualLogSource l = L; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(36, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PVESieges: settings moved from "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("melty.castlesieges.cfg"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" to "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("PVESieges.cfg"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("."); } l.LogInfo(val); } } catch (Exception ex) { ManualLogSource l2 = L; BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(31, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("PVESieges: couldn't move "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("melty.castlesieges.cfg"); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" to "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("PVESieges.cfg"); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message); } l2.LogWarning(val2); } return new ConfigFile(text, true, MetadataHelper.GetMetadata((object)this)); } internal static void Dbg(string msg) { if (Settings.B("DebugLog")) { L.LogInfo((object)msg); } } public override bool Unload() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } return true; } } public static class Settings { private static readonly Dictionary<string, ConfigEntry<bool>> Bools = new Dictionary<string, ConfigEntry<bool>>(); private static readonly Dictionary<string, ConfigEntry<int>> Ints = new Dictionary<string, ConfigEntry<int>>(); private static readonly Dictionary<string, ConfigEntry<float>> Floats = new Dictionary<string, ConfigEntry<float>>(); private static readonly Dictionary<string, ConfigEntry<string>> Strings = new Dictionary<string, ConfigEntry<string>>(); private static readonly HashSet<string> Regular = new HashSet<string> { "Enabled", "DayChance", "NightChance", "NightFactions", "TreantRaidChance", "TreantWaveSize", "VBloodRaidChance", "Waves", "AllAtOnce", "NightStartDelaySeconds", "WarningSeconds", "WaveSeconds", "WaveTimeLimitSeconds", "HeartHoldSeconds", "RareWeaponShardChance", "CommonWeaponShardChance", "ExtraRaidersPerDefender", "Wave1Size", "Wave2Size", "Wave3Size", "FodderPercentWave1", "FodderPercentWave2", "FodderPercentWave3", "ScaleToPlayerLevel" }; private const string RegularSection = "Castle Sieges"; private const string AdvancedSection = "Castle Sieges - Advanced (only change these if you know what you are doing)"; public static void Bind(ConfigFile cfg) { //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Expected O, but got Unknown //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Expected O, but got Unknown Dictionary<ConfigDefinition, string> dictionary = null; try { dictionary = typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(cfg) as Dictionary<ConfigDefinition, string>; } catch { } int num = 0; SettingRow[] settings = Sheets.Settings; for (int i = 0; i < settings.Length; i++) { SettingRow settingRow = settings[i]; bool flag = Regular.Contains(settingRow.Id); string text = (flag ? "Castle Sieges" : "Castle Sieges - Advanced (only change these if you know what you are doing)"); string text2 = (flag ? settingRow.Description : ("ADVANCED: only change this if you know what you're doing. " + settingRow.Description)); ConfigEntryBase val3; switch (settingRow.Type) { case "bool": { ConfigEntry<bool> val8 = (Bools[settingRow.Id] = cfg.Bind<bool>(text, settingRow.Id, settingRow.Value == "true", text2)); val3 = (ConfigEntryBase)(object)val8; break; } case "int": { ConfigEntry<int> val6 = (Ints[settingRow.Id] = cfg.Bind<int>(text, settingRow.Id, int.Parse(settingRow.Value, CultureInfo.InvariantCulture), text2)); val3 = (ConfigEntryBase)(object)val6; break; } case "string": { ConfigEntry<string> val4 = (Strings[settingRow.Id] = cfg.Bind<string>(text, settingRow.Id, settingRow.Value, text2)); val3 = (ConfigEntryBase)(object)val4; break; } default: { ConfigEntry<float> val = (Floats[settingRow.Id] = cfg.Bind<float>(text, settingRow.Id, float.Parse(settingRow.Value, CultureInfo.InvariantCulture), text2)); val3 = (ConfigEntryBase)(object)val; break; } } if (flag || dictionary == null) { continue; } ConfigDefinition key = new ConfigDefinition("Castle Sieges", settingRow.Id); if (dictionary.TryGetValue(key, out var value)) { try { val3.SetSerializedValue(value); num++; } catch { } dictionary.Remove(key); } } int num2 = 0; if (dictionary != null) { foreach (ConfigDefinition item in new List<ConfigDefinition>(dictionary.Keys)) { if (item.Section == "Castle Sieges" || item.Section == "Castle Sieges - Advanced (only change these if you know what you are doing)") { dictionary.Remove(item); num2++; } } } if (num > 0 || num2 > 0) { cfg.Save(); ManualLogSource l = Plugin.L; bool flag2 = default(bool); BepInExInfoLogInterpolatedStringHandler val10 = new BepInExInfoLogInterpolatedStringHandler(136, 2, ref flag2); if (flag2) { ((BepInExLogInterpolatedStringHandler)val10).AppendLiteral("PVESieges: config tidied: "); ((BepInExLogInterpolatedStringHandler)val10).AppendFormatted<int>(num); ((BepInExLogInterpolatedStringHandler)val10).AppendLiteral(" advanced setting(s) moved to their own section (values kept), "); ((BepInExLogInterpolatedStringHandler)val10).AppendFormatted<int>(num2); ((BepInExLogInterpolatedStringHandler)val10).AppendLiteral(" setting(s) that no longer do anything removed."); } l.LogInfo(val10); } } public static bool B(string id) { return Bools[id].Value; } public static int I(string id) { if (!Ints.TryGetValue(id, out var value)) { return (int)Floats[id].Value; } return value.Value; } public static float F(string id) { if (!Floats.TryGetValue(id, out var value)) { return Ints[id].Value; } return value.Value; } public static string S(string id) { return Strings[id].Value; } } internal static class Prof { private sealed class Part { public long Ticks; public long Worst; public int Runs; public string Within; } public static bool On; public static float SpikeMs = 5f; private static readonly Dictionary<string, Part> Parts = new Dictionary<string, Part>(); private static readonly Dictionary<string, Part> AllTime = new Dictionary<string, Part>(); private static readonly Dictionary<string, long> ThisFrame = new Dictionary<string, long>(); private static long _frameStart; private static long _frameTicks; private static long _worstFrame; private static long _hookTicks; private static int _frames; private static int _spikesThisMinute; private static float _nextReport = -1f; private static long _recordFrame; private static string _recordFrameWhat = ""; private static string _recordFrameWhen = ""; private static long _recordRun; private static string _recordRunWhat = ""; private static string _recordRunWhen = ""; private static int _spikesAllTime; private static float _lastSpikeLog = -10f; private static int _spikesHeld; private static double Ms(long ticks) { return (double)ticks * 1000.0 / (double)Stopwatch.Frequency; } private static string Clock() { return DateTime.Now.ToString("HH:mm:ss"); } public static long Start() { if (!On) { return 0L; } return Stopwatch.GetTimestamp(); } public static void Stop(string name, long t0, string within = null) { if (On && t0 != 0L) { long num = Stopwatch.GetTimestamp() - t0; Add(Parts, name, num, within); Add(AllTime, name, num, within); ThisFrame[name] = (ThisFrame.TryGetValue(name, out var value) ? value : 0) + num; if (num > _recordRun) { _recordRun = num; _recordRunWhat = name; _recordRunWhen = Clock(); } } } private static void Add(Dictionary<string, Part> into, string name, long dt, string within) { if (!into.TryGetValue(name, out var value)) { Part obj = new Part { Within = within }; value = obj; into[name] = obj; } value.Ticks += dt; value.Runs++; if (dt > value.Worst) { value.Worst = dt; } } private static bool IsInner(string name) { if (AllTime.TryGetValue(name, out var value)) { return value.Within != null; } return false; } public static void FrameBegin() { if (On) { _frameStart = Stopwatch.GetTimestamp(); } } public static void AddToFrame(long t0) { if (On && t0 != 0L) { _hookTicks += Stopwatch.GetTimestamp() - t0; } } public static void FrameEnd(float now) { //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Expected O, but got Unknown if (!On || _frameStart == 0L) { ThisFrame.Clear(); _hookTicks = 0L; return; } long num = Stopwatch.GetTimestamp() - _frameStart + _hookTicks; _hookTicks = 0L; _frameStart = 0L; _frameTicks += num; _frames++; if (num > _worstFrame) { _worstFrame = num; } if (num > _recordFrame) { KeyValuePair<string, long> keyValuePair = (from kv in ThisFrame where !IsInner(kv.Key) orderby kv.Value descending select kv).FirstOrDefault(); _recordFrame = num; _recordFrameWhen = Clock(); _recordFrameWhat = ((keyValuePair.Key != null) ? $"mostly {keyValuePair.Key} {Ms(keyValuePair.Value):F2} ms" : "no single part"); } if (Ms(num) >= (double)SpikeMs) { _spikesThisMinute++; _spikesAllTime++; if (now - _lastSpikeLog >= 1f) { _lastSpikeLog = now; IEnumerable<string> enumerable = from kv in ThisFrame.OrderByDescending((KeyValuePair<string, long> kv) => kv.Value).Take(4) select $"{kv.Key}{(IsInner(kv.Key) ? (" (within " + AllTime[kv.Key].Within + ")") : "")} {Ms(kv.Value):F2} ms"; string text = ((_spikesHeld > 0) ? $" ({_spikesHeld} more spike(s) in the second before)" : ""); ManualLogSource l = Plugin.L; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(73, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PVESieges: [ms] spike: the mod took "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(Ms(num), "F2"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ms this frame (SpikeMs "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(SpikeMs, "0.#"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("); biggest: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(enumerable.Any() ? string.Join(", ", enumerable) : "nothing timed"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("."); } l.LogInfo(val); _spikesHeld = 0; } else { _spikesHeld++; } } ThisFrame.Clear(); } public static void MaybeReport(float now) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Expected O, but got Unknown //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Expected O, but got Unknown //IL_042f: Unknown result type (might be due to invalid IL or missing references) //IL_0435: Expected O, but got Unknown //IL_053e: Unknown result type (might be due to invalid IL or missing references) //IL_0544: Expected O, but got Unknown if (!On) { Parts.Clear(); _frameTicks = (_worstFrame = 0L); _frames = (_spikesThisMinute = 0); _nextReport = -1f; } else if (_nextReport < 0f) { _nextReport = now + 60f; } else { if (now < _nextReport) { return; } _nextReport = now + 60f; ManualLogSource l = Plugin.L; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(114, 6, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PVESieges: [ms] last 60 s: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(Ms(_frameTicks), "F1"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ms in all over "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_frames); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" frames (avg "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>((_frames > 0) ? (Ms(_frameTicks) / (double)_frames) : 0.0, "F3"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ms per frame, worst frame "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(Ms(_worstFrame), "F2"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ms, "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_spikesThisMinute); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" spike(s) of "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(SpikeMs, "0.#"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ms or more)."); } l.LogInfo(val); foreach (KeyValuePair<string, Part> item in Parts.OrderByDescending((KeyValuePair<string, Part> kv) => kv.Value.Ticks)) { ManualLogSource l2 = Plugin.L; val = new BepInExInfoLogInterpolatedStringHandler(45, 5, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PVESieges: [ms] "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(item.Key); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((item.Value.Within != null) ? (" (within " + item.Value.Within + ")") : ""); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(Ms(item.Value.Ticks), "F1"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ms in "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(item.Value.Runs); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" run(s), worst "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(Ms(item.Value.Worst), "F2"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ms"); } l2.LogInfo(val); } List<KeyValuePair<string, Part>> list = Parts.Where((KeyValuePair<string, Part> kv) => kv.Key.StartsWith("castle scan:")).ToList(); if (list.Count > 0) { long ticks = list.Where((KeyValuePair<string, Part> kv) => !kv.Key.Contains("doors of a raided castle") && !kv.Key.Contains("heart floor") && !kv.Key.Contains("structure around")).Sum((KeyValuePair<string, Part> kv) => kv.Value.Ticks); ManualLogSource l3 = Plugin.L; val = new BepInExInfoLogInterpolatedStringHandler(75, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PVESieges: [ms] castle scans: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(Ms(ticks), "F1"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ms in all in "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(list.Sum((KeyValuePair<string, Part> kv) => kv.Value.Runs)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" run(s), worst single scan "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(Ms(list.Max((KeyValuePair<string, Part> kv) => kv.Value.Worst)), "F2"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ms."); } l3.LogInfo(val); } KeyValuePair<string, Part> keyValuePair = (from kv in Parts where kv.Value.Within == null orderby kv.Value.Ticks descending select kv).FirstOrDefault(); if (keyValuePair.Key != null) { ManualLogSource l4 = Plugin.L; val = new BepInExInfoLogInterpolatedStringHandler(75, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PVESieges: [ms] highest generator this minute: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(keyValuePair.Key); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(Ms(keyValuePair.Value.Ticks), "F1"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ms, "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>((_frameTicks > 0) ? (100.0 * (double)keyValuePair.Value.Ticks / (double)_frameTicks) : 0.0, "F0"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("% of the mod's time)."); } l4.LogInfo(val); } KeyValuePair<string, Part> keyValuePair2 = (from kv in AllTime where kv.Value.Within == null orderby kv.Value.Ticks descending select kv).FirstOrDefault(); if (keyValuePair2.Key != null) { ManualLogSource l5 = Plugin.L; val = new BepInExInfoLogInterpolatedStringHandler(127, 10, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PVESieges: [ms] since start: highest generator "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(keyValuePair2.Key); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(Ms(keyValuePair2.Value.Ticks), "F0"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ms in "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(keyValuePair2.Value.Runs); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" runs); slowest single run "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(_recordRunWhat); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(Ms(_recordRun), "F2"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ms at "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(_recordRunWhen); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; worst frame "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(Ms(_recordFrame), "F2"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ms at "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(_recordFrameWhen); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(_recordFrameWhat); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("); "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_spikesAllTime); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" spike(s)."); } l5.LogInfo(val); } Parts.Clear(); _frameTicks = (_worstFrame = 0L); _frames = (_spikesThisMinute = 0); } } } internal static class RewardItems { public static readonly (int guid, string name, int tier)[] Books = new(int, string, int)[187] { (362386181, "Armor Boots T04 Brute", 1), (-383004511, "Armor Boots T04 Rogue", 1), (-1601304786, "Armor Boots T04 Scholar", 1), (-668460646, "Armor Boots T04 Warrior", 1), (1529216919, "Armor Boots T06 Brute", 2), (762038154, "Armor Boots T06 Rogue", 2), (-1147510581, "Armor Boots T06 Scholar", 2), (-1788912715, "Armor Boots T06 Warrior", 2), (-534142437, "Armor Boots T08 Brute", 3), (-706178162, "Armor Boots T08 Rogue", 3), (-1958602686, "Armor Boots T08 Scholar", 3), (1192629421, "Armor Boots T08 Warrior", 3), (1850873910, "Armor Chest T04 Brute", 1), (-849449432, "Armor Chest T04 Rogue", 1), (2025615662, "Armor Chest T04 Scholar", 1), (1753801067, "Armor Chest T04 Warrior", 1), (626083889, "Armor Chest T06 Brute", 2), (-1595316636, "Armor Chest T06 Rogue", 2), (-2066262923, "Armor Chest T06 Scholar", 2), (1561721357, "Armor Chest T06 Warrior", 2), (-1261118965, "Armor Chest T08 Brute", 3), (502133568, "Armor Chest T08 Rogue", 3), (-1840162782, "Armor Chest T08 Scholar", 3), (-1161279574, "Armor Chest T08 Warrior", 3), (-764630320, "Armor Gloves T04 Brute", 1), (1014370193, "Armor Gloves T04 Rogue", 1), (1840869087, "Armor Gloves T04 Scholar", 1), (-1242910338, "Armor Gloves T04 Warrior", 1), (-1344118299, "Armor Gloves T06 Brute", 2), (735880687, "Armor Gloves T06 Rogue", 2), (-46006079, "Armor Gloves T06 Scholar", 2), (-777417289, "Armor Gloves T06 Warrior", 2), (2020764183, "Armor Gloves T08 Brute", 3), (1485993952, "Armor Gloves T08 Rogue", 3), (-1512099553, "Armor Gloves T08 Scholar", 3), (-196284663, "Armor Gloves T08 Warrior", 3), (1172935197, "Armor Legs T04 Brute", 1), (1364444719, "Armor Legs T04 Rogue", 1), (-117205517, "Armor Legs T04 Scholar", 1), (347441899, "Armor Legs T04 Warrior", 1), (1328323768, "Armor Legs T06 Brute", 2), (1912738568, "Armor Legs T06 Rogue", 2), (-595456862, "Armor Legs T06 Scholar", 2), (-1718233147, "Armor Legs T06 Warrior", 2), (-996201260, "Armor Legs T08 Brute", 3), (-1260890289, "Armor Legs T08 Rogue", 3), (-2049321404, "Armor Legs T08 Scholar", 3), (-2104396934, "Armor Legs T08 Warrior", 3), (-895015382, "Consumable BloodRoseBrew T01", 1), (2114304481, "Consumable FireResistance T02", 1), (791584738, "Consumable GarlicResistance T02", 1), (1556544548, "Consumable PhysicalPower T01", 1), (-2013887729, "Consumable PhysicalPower T03", 1), (-1269116849, "Consumable SilverBrew T01", 1), (492964298, "Consumable SpellPower T01", 1), (-1563178470, "Consumable SpellPower T03", 1), (756555009, "Consumable SunResistance T01", 1), (-1242947472, "Consumable Wranglers T02", 1), (978074988, "Floor AlchemyLab", 1), (-1233700610, "Floor Forge", 1), (626118128, "Floor Jewelcrafting", 1), (-946177070, "Floor Library", 1), (1718353003, "Floor Prison", 1), (-137886670, "Floor Tailor", 1), (1906638073, "Floor Workshop", 1), (1336896559, "Interior Planters", 1), (-293419350, "MagicSource T04 Duskwatcher", 1), (-1542642288, "MagicSource T04 EmberChain", 1), (-1913800363, "MagicSource T04 FrozenEye", 1), (1310923765, "MagicSource T04 MistSignet", 1), (350769859, "MagicSource T04 RubyRing", 1), (1458090717, "MagicSource T04 SorcererRing", 1), (587164554, "MagicSource T06 AmethystPendant", 2), (-224716062, "MagicSource T06 EmeraldNecklace", 2), (759775881, "MagicSource T06 MistStoneNecklace", 2), (-1658630722, "MagicSource T06 RubyPendant", 2), (1939500376, "MagicSource T06 SapphirePendant", 2), (1474515294, "MagicSource T06 TopazAmulet", 2), (1702347530, "MagicSource T08 Beast", 3), (-1063966176, "MagicSource T08 CrimsonSky", 3), (-1803818846, "MagicSource T08 Delusion", 3), (-749171183, "MagicSource T08 FrozenCrypt", 3), (-1424521314, "MagicSource T08 Madness", 3), (860383634, "MagicSource T08 WickedProphet", 3), (-1221174479, "Structure ArtisanTable", 1), (742900616, "Structure Braziers T02", 1), (835610037, "Structure Braziers T03", 1), (1341367867, "Structure CandleStands T02", 1), (1383064284, "Structure Carpets T01", 1), (-96701352, "Structure Carpets T02 Dux", 1), (-1696677607, "Structure Carpets T03 Distinguished", 1), (389446538, "Structure Chairs Desk T02", 1), (-1929817673, "Structure Chairs Red T02", 1), (285318201, "Structure Curtains T03 Royal", 1), (-840839363, "Structure Desks T02", 1), (-1676748911, "Structure DressingTablesFoldingWalls T03", 1), (879103343, "Structure EnchantedTorches", 1), (679755989, "Structure FenceFountains T02", 1), (-946597284, "Structure Fireplaces T02", 1), (1594270493, "Structure FlyingCandles T03", 1), (-1171060793, "Structure Fountain T03", 1), (-1060453249, "Structure GardenFurniture T02", 1), (776216743, "Structure GardenLampPosts T03", 1), (1307976528, "Structure GardenPlanters T01", 1), (-1383718976, "Structure GardenPlanters T02", 1), (-1645899934, "Structure GardenPlanters T03", 1), (-452767162, "Structure HangingLanterns T02", 1), (38319072, "Structure Paintings T01", 1), (2094602185, "Structure Path Cobblestone T02", 1), (-94650344, "Structure Path Dirt T01", 1), (-1321865795, "Structure PillarBanners T02", 1), (2053574378, "Structure Sofas T03", 1), (-449615886, "Structure StoneOrnaments T01", 1), (11798247, "Structure Storage Alchemy T02", 1), (-67943596, "Structure Storage Alchemy T03", 1), (207381334, "Structure Storage Armor T02", 1), (-130369231, "Structure Storage BloodCase T02", 1), (489001758, "Structure Storage BloodCase T03", 1), (-832387204, "Structure Storage Coins T02", 1), (-1624005683, "Structure Storage Consumable T02", 1), (824237901, "Structure Storage Consumable T03", 1), (-205820651, "Structure Storage Fishing T02", 1), (1455590675, "Structure Storage Gems T01", 1), (1150376281, "Structure Storage Gems T02", 1), (-853559619, "Structure Storage Herbs T01", 1), (473545520, "Structure Storage Herbs T02", 1), (-1870194782, "Structure Storage Jewels T02", 1), (-1394295910, "Structure Storage Knowledge T02", 1), (1823379076, "Structure Storage Knowledge T03", 1), (-513865346, "Structure Storage Minerals T01", 1), (-1061940339, "Structure Storage Minerals T02", 1), (1249076837, "Structure Storage Pack Equipment T02", 1), (686122001, "Structure Storage Pack T01", 1), (1519475093, "Structure Storage Pack T02", 1), (-651642571, "Structure Storage T01", 1), (-999518496, "Structure Storage T02", 1), (1691702273, "Structure Storage T03", 1), (-1304625582, "Structure Storage Tailoring T02", 1), (-63123159, "Structure Storage Tailoring T03", 1), (-1564741377, "Structure Storage Weapons T02", 1), (1040245278, "Structure Storage Woodworking T01", 1), (206151993, "Structure Storage Woodworking T02", 1), (-1236809045, "Structure Tables T02", 1), (1428883363, "Structure Vases T01", 1), (-1957642407, "Structure Wallpaper Bricks T01", 1), (1884115881, "Structure Wallpaper Classical T03", 1), (-581757157, "Structure Wallpaper Cordial T02", 1), (-2086890414, "Structure Wallpaper Prison T02", 1), (-2017255390, "Structure Wallpaper Stone T01", 1), (-106224889, "Structure Wallpaper WoodPanel T01", 1), (-1205373095, "Structure Well T01", 1), (1905539368, "Structure Windows T01", 1), (1413772406, "Structure WorkshopDecoration T02", 1), (660670410, "Weapon Axe T04", 1), (-1596352033, "Weapon Axe T06", 2), (-1519267007, "Weapon Axe T08", 3), (574313564, "Weapon Claws T06", 2), (-213056154, "Weapon Claws T08", 3), (-192381912, "Weapon Crossbow T04", 1), (937375187, "Weapon Crossbow T06", 2), (1856338018, "Weapon Crossbow T08", 3), (1253216070, "Weapon Daggers T06", 2), (1271236919, "Weapon Daggers T08", 3), (1126901893, "Weapon GreatSword T06", 2), (730869315, "Weapon GreatSword T08", 3), (460843266, "Weapon Longbow T04", 1), (-1793793429, "Weapon Longbow T06", 2), (722498174, "Weapon Longbow T08", 3), (-1003381140, "Weapon Mace T04", 1), (1526542305, "Weapon Mace T06", 2), (-567468235, "Weapon Mace T08", 3), (1370998844, "Weapon Pistols T06", 2), (-349470582, "Weapon Pistols T08", 3), (-977419819, "Weapon Reaper T06", 2), (1350548439, "Weapon Reaper T08", 3), (1942009728, "Weapon Slashers T06", 2), (615301463, "Weapon Slashers T08", 3), (-1690985210, "Weapon Spear T04", 1), (-1783670291, "Weapon Spear T06", 2), (-1396190808, "Weapon Spear T08", 3), (-1455124124, "Weapon Sword T04", 1), (1427084419, "Weapon Sword T06", 2), (1075465533, "Weapon Sword T08", 3), (-457986654, "Weapon TwinBlades T06", 2), (1200302278, "Weapon TwinBlades T08", 3), (710159072, "Weapon Whip T06", 2), (-1033721040, "Weapon Whip T08", 3) }; public static readonly (int guid, string name)[] JewelsT1 = new(int, string)[6] { (-113436752, "Blood jewel (tier 1)"), (2130810069, "Chaos jewel (tier 1)"), (1908312304, "Frost jewel (tier 1)"), (1387124262, "Illusion jewel (tier 1)"), (-560146452, "Storm jewel (tier 1)"), (803445709, "Unholy jewel (tier 1)") }; public static readonly (int guid, string name, bool purple)[] Shattered = new(int, string, bool)[28] { (-2147445292, "shattered blue ancestral Axe", false), (442700150, "shattered purple ancestral Axe", true), (-1746159915, "shattered blue ancestral Claws", false), (-655493979, "shattered purple ancestral Claws", true), (572026243, "shattered blue ancestral Crossbow", false), (2061238391, "shattered purple ancestral Crossbow", true), (-1075670534, "shattered blue ancestral Daggers", false), (-2137269775, "shattered purple ancestral Daggers", true), (747911021, "shattered blue ancestral GreatSword", false), (-1638796801, "shattered purple ancestral GreatSword", true), (649637190, "shattered blue ancestral Longbow", false), (285875674, "shattered purple ancestral Longbow", true), (1963988265, "shattered blue ancestral Mace", false), (-1810734832, "shattered purple ancestral Mace", true), (-1038642372, "shattered blue ancestral Pistols", false), (1040125618, "shattered purple ancestral Pistols", true), (-413259500, "shattered blue ancestral Reaper", false), (886814985, "shattered purple ancestral Reaper", true), (3759455, "shattered blue ancestral Slashers", false), (1271087499, "shattered purple ancestral Slashers", true), (2142983740, "shattered blue ancestral Spear", false), (1717016192, "shattered purple ancestral Spear", true), (-1421775051, "shattered blue ancestral Sword", false), (1048769481, "shattered purple ancestral Sword", true), (1579758125, "shattered blue ancestral TwinBlades", false), (1479621167, "shattered purple ancestral TwinBlades", true), (-1222824286, "shattered blue ancestral Whip", false), (1490846791, "shattered purple ancestral Whip", true) }; } public readonly record struct FactionRow(string Id, string Name, string Color, int MinHeartLevel, int Weight, string Warning, string Victory, string Defeat, string HeartLevels); public readonly record struct JewelRow(string Id, int Tier, string School, string Ability, string PrefabName, int PrefabGuid); public readonly record struct UnitRow(string Id, string Faction, string PrefabName, int PrefabGuid, string Role); public readonly record struct WaveRow(string Id, string Faction, int Wave, string Unit, int Count); public readonly record struct BossRow(string Id, string Faction, string PrefabName, int PrefabGuid, string Title, int MinHeartLevel); public readonly record struct CaptainRow(string Id, string Faction, string Unit); public readonly record struct SettingRow(string Id, string Type, string Value, string Description); public static class Sheets { public static readonly FactionRow[] Factions = new FactionRow[11] { new FactionRow("bandits", "Bandits", "#d9a441", 0, 3, "Torches on the horizon... a bandit gang is coming to loot your castle! They attack in {s} seconds.", "The bandits are routed! Your castle holds.", "The bandits slink back into the woods with what they could grab.", "0,1"), new FactionRow("skeletons", "Restless Dead", "#b8c4c9", 0, 2, "The ground shakes... the restless dead are rising to storm your castle! They attack in {s} seconds.", "The dead fall silent again. Your castle holds.", "The dead sink back into the earth, unsatisfied.", "0,1"), new FactionRow("militia", "Militia", "#6f9fd8", 2, 3, "Bells ring in the villages... a militia muster marches on your castle! They attack in {s} seconds.", "The militia breaks and flees! Your castle holds.", "The militia falls back to regroup.", "2"), new FactionRow("dunley", "Dunley Dead", "#9fb3a3", 2, 2, "Bones rattle in the Dunley fields... the dead of the farmlands march on your castle! They attack in {s} seconds.", "The Dunley dead crumble back into the soil. Your castle holds.", "The Dunley dead shamble back to their graves.", "2"), new FactionRow("army", "Army of the Church", "#f2e6a0", 4, 3, "Trumpets sound... the Church's army has come to burn the vampire's nest! They attack in {s} seconds.", "The holy army is shattered! Your castle holds.", "The army withdraws in good order. They will be back.", "4"), new FactionRow("legion", "Dracula's Legion", "#c0392b", 4, 2, "The sky turns red... Dracula's Legion has come to test the new blood! They attack in {s} seconds.", "The Legion bows to a worthy rival. Your castle holds.", "The Legion vanishes into the night, laughing.", "4"), new FactionRow("venom", "Venom Blades", "#7bc043", 4, 3, "A sickly green mist rolls in... the Blackfang's Venom Blades have come for your castle! They attack in {s} seconds.", "The Venom Blades are cut down! Your castle holds.", "The Venom Blades melt back into the mist.", "4"), new FactionRow("transcendum", "the Transcendum", "#3fa9f5", 3, 3, "Sparks crackle on the wind... the Transcendum of Gloomrot march on your castle with their machines! They attack in {s} seconds.", "The Transcendum's engines fall silent. Your castle holds.", "The Transcendum withdraw, dragging their wreckage behind them.", "3"), new FactionRow("lesserlegion", "Dracula's Vanguard", "#8e44ad", 3, 3, "Bats blot out the sky... Dracula's vanguard comes for your castle! They strike in {s} seconds.", "The vanguard is broken. Your castle holds.", "The vanguard withdraws into the night.", "3"), new FactionRow("ghosts", "Restless Spirits", "#7fd6e8", 3, 2, "A cold mist rolls in... restless spirits drift toward your castle! They arrive in {s} seconds.", "The spirits fade away. Your castle holds.", "The spirits drift back into the mist.", "3"), new FactionRow("treants", "Treants", "#6aa84f", 99, 0, "The forest stirs... ancient treants are marching on your castle! They arrive in {s} seconds.", "The treants crash down like felled trees. Your castle holds.", "The treants trample your castle heart and wander back into the woods.", "-1") }; public static readonly UnitRow[] Units = new UnitRow[78] { new UnitRow("bandit_thug", "bandits", "CHAR_Bandit_Thug", -301730941, "fodder"), new UnitRow("bandit_deadeye", "bandits", "CHAR_Bandit_Deadeye", -1030822544, "tough"), new UnitRow("bandit_stalker", "bandits", "CHAR_Bandit_Stalker", -309264723, "tough"), new UnitRow("bandit_bomber", "bandits", "CHAR_Bandit_Bomber", -1128238456, "tough"), new UnitRow("bandit_trapper", "bandits", "CHAR_Bandit_Trapper", -589412777, "tough"), new UnitRow("undead_skeletonsoldier_base", "skeletons", "CHAR_Undead_SkeletonSoldier_Base", -603934060, "fodder"), new UnitRow("undead_skeletoncrossbow_base", "skeletons", "CHAR_Undead_SkeletonCrossbow_Base", 597386568, "fodder"), new UnitRow("undead_skeletonmage", "skeletons", "CHAR_Undead_SkeletonMage", -1287507270, "tough"), new UnitRow("undead_rottingghoul", "dunley", "CHAR_Undead_RottingGhoul", -1722506709, "fodder"), new UnitRow("undead_skeletongolem", "dunley", "CHAR_Undead_SkeletonGolem", -1380216646, "tough"), new UnitRow("militia_light", "militia", "CHAR_Militia_Light", -63435588, "fodder"), new UnitRow("militia_heavy", "militia", "CHAR_Militia_Heavy", 2005508157, "tough"), new UnitRow("militia_crossbow", "militia", "CHAR_Militia_Crossbow", 956965183, "fodder"), new UnitRow("militia_bomber", "militia", "CHAR_Militia_Bomber", 847893333, "tough"), new UnitRow("militia_longbowman", "militia", "CHAR_Militia_Longbowman", 203103783, "tough"), new UnitRow("churchoflight_footman", "army", "CHAR_ChurchOfLight_Footman", 2128996433, "fodder"), new UnitRow("churchoflight_archer", "army", "CHAR_ChurchOfLight_Archer", 426583055, "fodder"), new UnitRow("churchoflight_rifleman", "army", "CHAR_ChurchOfLight_Rifleman", 1148936156, "fodder"), new UnitRow("churchoflight_knight_shield", "army", "CHAR_ChurchOfLight_Knight_Shield", 794228023, "tough"), new UnitRow("churchoflight_knight_2h", "army", "CHAR_ChurchOfLight_Knight_2H", -930333806, "tough"), new UnitRow("churchoflight_paladin", "army", "CHAR_ChurchOfLight_Paladin", 1728773109, "tough"), new UnitRow("churchoflight_cleric", "army", "CHAR_ChurchOfLight_Cleric", -1464869978, "tough"), new UnitRow("churchoflight_lightweaver", "army", "CHAR_ChurchOfLight_Lightweaver", 1185952775, "tough"), new UnitRow("legion_shadowkin", "legion", "CHAR_Legion_Shadowkin", 1980594081, "fodder"), new UnitRow("legion_vargulf", "legion", "CHAR_Legion_Vargulf", -653348998, "tough"), new UnitRow("legion_nightmaiden", "legion", "CHAR_Legion_NightMaiden", -494298686, "tough"), new UnitRow("legion_bloodprophet", "legion", "CHAR_Legion_BloodProphet", 1912966420, "tough"), new UnitRow("legion_dreadhorn", "legion", "CHAR_Legion_Dreadhorn", 981369753, "tough"), new UnitRow("blackfang_venomblade", "venom", "CHAR_Blackfang_Venomblade", 1864177126, "tough"), new UnitRow("blackfang_striker", "venom", "CHAR_Blackfang_Striker", 761646020, "tough"), new UnitRow("blackfang_viper", "venom", "CHAR_Blackfang_Viper", -436956599, "tough"), new UnitRow("blackfang_dartflinger", "venom", "CHAR_Blackfang_DartFlinger", 1209580976, "fodder"), new UnitRow("blackfang_lurker", "venom", "CHAR_Blackfang_Lurker", -1733829912, "fodder"), new UnitRow("blackfang_sentinel", "venom", "CHAR_Blackfang_Sentinel", 1531777139, "tough"), new UnitRow("blackfang_alchemist", "venom", "CHAR_Blackfang_Alchemist", 326501064, "tough"), new UnitRow("undead_ghostmilitia_light", "ghosts", "CHAR_Undead_GhostMilitia_Light", -1618703048, "fodder"), new UnitRow("undead_ghostmilitia_crossbow", "ghosts", "CHAR_Undead_GhostMilitia_Crossbow", -85729652, "fodder"), new UnitRow("undead_ghostguardian", "ghosts", "CHAR_Undead_GhostGuardian", -458883491, "tough"), new UnitRow("undead_ghostbanshee", "ghosts", "CHAR_Undead_GhostBanshee", -1146194149, "tough"), new UnitRow("bandit_hunter", "bandits", "CHAR_Bandit_Hunter", -1301144178, "fodder"), new UnitRow("militia_guard", "militia", "CHAR_Militia_Guard", 1730498275, "tough"), new UnitRow("undead_guardian", "dunley", "CHAR_Undead_Guardian", -1967480038, "tough"), new UnitRow("undead_skeletonsoldier_armored_dunley", "dunley", "CHAR_Undead_SkeletonSoldier_Armored_Dunley", 952695804, "fodder"), new UnitRow("undead_skeletonsoldier_armored_farbane", "skeletons", "CHAR_Undead_SkeletonSoldier_Armored_Farbane", -837329073, "fodder"), new UnitRow("undead_armoredskeletoncrossbow_farbane", "skeletons", "CHAR_Undead_ArmoredSkeletonCrossbow_Farbane", -195077008, "fodder"), new UnitRow("undead_assassin", "skeletons", "CHAR_Undead_Assassin", -1365627158, "tough"), new UnitRow("undead_skeletonapprentice", "skeletons", "CHAR_Undead_SkeletonApprentice", -1789347076, "tough"), new UnitRow("legion_shadowkin_lesser", "legion", "CHAR_Legion_Shadowkin_Lesser", -1200074387, "fodder"), new UnitRow("legion_vargulf_lesser", "legion", "CHAR_Legion_Vargulf_Lesser", 2049379982, "tough"), new UnitRow("legion_nightmaiden_lesser", "legion", "CHAR_Legion_NightMaiden_Lesser", 2111003460, "tough"), new UnitRow("legion_bloodprophet_lesser", "legion", "CHAR_Legion_BloodProphet_Lesser", -2080231735, "tough"), new UnitRow("legion_dreadhorn_lesser", "legion", "CHAR_Legion_DreadHorn_Lesser", -1140588645, "tough"), new UnitRow("undead_priest", "skeletons", "CHAR_Undead_Priest", -1653554504, "tough"), new UnitRow("gloomrot_technician", "transcendum", "CHAR_Gloomrot_Technician", 820492683, "fodder"), new UnitRow("gloomrot_tazer", "transcendum", "CHAR_Gloomrot_Tazer", 674807351, "fodder"), new UnitRow("gloomrot_batoon", "transcendum", "CHAR_Gloomrot_Batoon", -1707267769, "fodder"), new UnitRow("gloomrot_pyro", "transcendum", "CHAR_Gloomrot_Pyro", -322293503, "tough"), new UnitRow("gloomrot_railgunner", "transcendum", "CHAR_Gloomrot_Railgunner", 1732477970, "tough"), new UnitRow("gloomrot_tractorbeamer", "transcendum", "CHAR_Gloomrot_TractorBeamer", -293507834, "tough"), new UnitRow("gloomrot_sentryofficer", "transcendum", "CHAR_Gloomrot_SentryOfficer", 1401026468, "tough"), new UnitRow("gloomrot_aceincinerator", "transcendum", "CHAR_Gloomrot_AceIncinerator", 1756241788, "tough"), new UnitRow("legion_vampire_cultist", "legion", "CHAR_Vampire_Cultist_Patrolling", 2018586909, "fodder"), new UnitRow("legion_vampire_cultist_female", "legion", "CHAR_Vampire_Cultist_Patrolling_Female", -1610391169, "fodder"), new UnitRow("legion_nightmare", "legion", "CHAR_Legion_Nightmare", -1009917656, "fodder"), new UnitRow("legion_exsanguinator", "legion", "CHAR_Legion_Assassin", -1076780215, "tough"), new UnitRow("treant", "treants", "CHAR_Treant", -1089337069, "fodder"), new UnitRow("dunley_armoredskeletoncrossbow", "dunley", "CHAR_Undead_ArmoredSkeletonCrossbow_Dunley", -861407720, "fodder"), new UnitRow("dunley_skeletonmage", "dunley", "CHAR_Undead_SkeletonMage", -1287507270, "tough"), new UnitRow("dunley_skeletonbishop", "dunley", "CHAR_Undead_Priest", -1653554504, "tough"), new UnitRow("ghost_assassin", "ghosts", "CHAR_Undead_GhostAssassin", 849891426, "tough"), new UnitRow("vanguard_shadowkin", "lesserlegion", "CHAR_Legion_Shadowkin_Lesser", -1200074387, "fodder"), new UnitRow("vanguard_vargulf", "lesserlegion", "CHAR_Legion_Vargulf_Lesser", 2049379982, "tough"), new UnitRow("vanguard_nightmaiden", "lesserlegion", "CHAR_Legion_NightMaiden_Lesser", 2111003460, "tough"), new UnitRow("vanguard_bloodprophet", "lesserlegion", "CHAR_Legion_BloodProphet_Lesser", -2080231735, "tough"), new UnitRow("vanguard_dreadhorn", "lesserlegion", "CHAR_Legion_DreadHorn_Lesser", -1140588645, "tough"), new UnitRow("vanguard_cultist", "lesserlegion", "CHAR_Vampire_Cultist_Patrolling", 2018586909, "fodder"), new UnitRow("vanguard_cultist_female", "lesserlegion", "CHAR_Vampire_Cultist_Patrolling_Female", -1610391169, "fodder"), new UnitRow("dunley_skeletonapprentice", "dunley", "CHAR_Undead_SkeletonApprentice", -1789347076, "fodder") }; public static readonly WaveRow[] Waves = new WaveRow[118] { new WaveRow("bandits_w1_bandit_thug", "bandits", 1, "bandit_thug", 5), new WaveRow("bandits_w1_bandit_deadeye", "bandits", 1, "bandit_deadeye", 4), new WaveRow("bandits_w2_bandit_thug", "bandits", 2, "bandit_thug", 7), new WaveRow("bandits_w2_bandit_stalker", "bandits", 2, "bandit_stalker", 3), new WaveRow("bandits_w3_bandit_thug", "bandits", 3, "bandit_thug", 3), new WaveRow("bandits_w3_bandit_bomber", "bandits", 3, "bandit_bomber", 2), new WaveRow("bandits_w3_bandit_trapper", "bandits", 3, "bandit_trapper", 2), new WaveRow("bandits_w3_bandit_deadeye", "bandits", 3, "bandit_deadeye", 2), new WaveRow("militia_w1_militia_light", "militia", 1, "militia_light", 7), new WaveRow("militia_w1_militia_crossbow", "militia", 1, "militia_crossbow", 4), new WaveRow("militia_w2_militia_light", "militia", 2, "militia_light", 8), new WaveRow("militia_w2_militia_longbowman", "militia", 2, "militia_longbowman", 3), new WaveRow("militia_w3_militia_heavy", "militia", 3, "militia_heavy", 3), new WaveRow("militia_w3_militia_bomber", "militia", 3, "militia_bomber", 2), new WaveRow("militia_w3_militia_crossbow", "militia", 3, "militia_crossbow", 2), new WaveRow("militia_w3_militia_light", "militia", 3, "militia_light", 2), new WaveRow("army_w1_churchoflight_footman", "army", 1, "churchoflight_footman", 7), new WaveRow("army_w1_churchoflight_archer", "army", 1, "churchoflight_archer", 4), new WaveRow("army_w2_chur