Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LandoriaModPack v1.0.42
Landoria.LandoriaModPack.dll
Decompiled 6 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Data; using System.Data.SqlTypes; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Dynamic; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Numerics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Landoria.ServerShield.Shared; using Landoria.ServerShield.Shared.Models; using Landoria.ServerShield.Shared.Network; using Landoria.ServerShield.Shared.Serialization; using Landoria.ServerShield.Shared.World; using Landoria.SharedLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Bson; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq.JsonPath; using Newtonsoft.Json.Schema; using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Utilities; using PlayFab.Party; using Splatform; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Landoria.LandoriaModPack")] [assembly: AssemblyDescription("Installs the Landoria modpack dependencies.")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Landoria.LandoriaModPack")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: ComVisible(false)] [assembly: Guid("BD9DB129-FFA6-414E-95AD-10EA8CE362C4")] [assembly: AssemblyFileVersion("1.0.42")] [assembly: AssemblyInformationalVersion("1.0.42")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = "")] [assembly: AssemblyVersion("1.0.42.17079")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Landoria.ServerShield.Shared { internal static class Constants { internal static class Movement { internal const int Portal = 0; internal const int Dungeon = 1; internal const float RequestInterval = 2f; internal const float SpawnRetrySeconds = 1f; internal const float ArrivalTolerance = 2f; internal const float ArrivalToleranceSquared = 4f; internal const float ObservationSeconds = 5f; internal const float ObservationFactor = 4f; internal const float ObservationLogInterval = 30f; internal const int TeleportRequestBytes = 28; internal const float SourceDistance = 5f; internal const float SourceHintToleranceSquared = 1f; internal const float LogoutHeightOffset = 0.25f; internal const float StartHeightOffset = 2f; internal const float BedSearchDistance = 5f; internal const int ConnectionsFlag = 1; internal const int FloatsFlag = 2; internal const int VectorsFlag = 4; internal const int QuaternionsFlag = 8; internal const int IntegersFlag = 16; } internal static class Rpc { internal const string Admission = "Landoria.ServerShield.Admission"; internal const string Rejection = "Landoria.ServerShield.Rejection"; internal const string RejectionAck = "Landoria.ServerShield.RejectionAck"; internal const string TeleportComplete = "Landoria.ServerShield.TeleportDone"; internal const string SpawnAnchor = "Landoria.ServerShield.SpawnAnchor"; internal const string TeleportRequest = "Landoria.ServerShield.Teleport"; internal const string TeleportResult = "Landoria.ServerShield.TeleportResult"; internal const string RejectedObjects = "Landoria.ServerShield.RejectedObjects"; internal const string SkillProgress = "Landoria.ServerShield.SkillProgress"; internal const string PickupResult = "Landoria.ServerShield.PickupResult"; internal const string ContainerSnapshot = "Landoria.ServerShield.ContainerSnapshot"; internal const string WorldAction = "Landoria.ServerShield.WorldAction"; internal const string WorldActionResult = "Landoria.ServerShield.WorldActionResult"; internal const string ReservePlayer = "Landoria.ServerShield.ReservePlayer"; internal const string ReservedPlayer = "Landoria.ServerShield.ReservedPlayer"; internal const string Spawn = "Landoria.ServerShield.Spawn"; internal const string SpawnResult = "Landoria.ServerShield.SpawnResult"; internal const string Discoveries = "Landoria.ServerShield.Discoveries"; internal const string MapState = "Landoria.ServerShield.MapState"; internal const string MapExplore = "Landoria.ServerShield.MapExplore"; internal const string MapPinRequest = "Landoria.ServerShield.MapPinRequest"; internal const string MapPinResult = "Landoria.ServerShield.MapPinResult"; internal const string Attack = "Landoria.ServerShield.Attack"; internal const string CombatResult = "Landoria.ServerShield.CombatResult"; internal const string PlayerHealth = "Landoria.ServerShield.PlayerHealth"; internal const string FoodState = "Landoria.ServerShield.FoodState"; internal const string CombatInventory = "Landoria.ServerShield.CombatInventory"; internal const string Response = "Landoria.ServerShield.Profile"; } internal static class Serialization { internal const int MaximumBytes = 67108864; internal const int MaximumEntries = 100000; internal const string CharacterFormat = "Landoria.ServerShield.character"; internal const int ProfileVersion = 46; internal const int PlayerVersion = 33; internal const int InventoryVersion = 109; internal const int SkillsVersion = 2; internal const int JsonSchemaVersion = 1; internal const int MaximumJsonDepth = 64; internal const int FchEnvelopeBytes = 72; internal const long JsonSizeMultiplier = 4L; internal const int CompactCountContinuationBit = 128; internal const int CompactCountHighMask = 127; internal const int MaximumCompactCount = 32767; internal const int ByteMask = 255; internal const int BitsPerByte = 8; internal const float DurabilityScale = 100f; internal const int FirstPrintableAscii = 32; internal const int PrintableAsciiEnd = 127; } internal static class Combat { internal const float HealthSnapshotSeconds = 1f; internal const int MaximumHealthPlayers = 1024; internal const string AttackSoundKey = "Landoria.ServerShield.attackSound"; internal const int MaximumPredictedImpacts = 4096; internal const float AudioLogRange = 12f; internal const float AudioLogWindowSeconds = 5f; internal const int MaximumAudioLogsPerWindow = 80; internal const float MinimumAudioPitch = 0.01f; internal const float MinimumReverbPitch = 0.5f; internal const float AudioCleanupDelaySeconds = 0.1f; internal const float ImpactAngleStepDegrees = 4f; internal const int MaximumAttackRequests = 100000; internal const float MinimumMovementNoiseSpeed = 0.1f; internal const float PerceptionSampleSeconds = 0.5f; internal const float WalkingNoiseRange = 15f; internal const float RunningNoiseRange = 30f; } internal static class Plugin { internal const string ClientGuid = "Landoria.ServerShield.Client"; internal const string ServerGuid = "Landoria.ServerShield.Server"; } internal static class ItemFlags { internal const int Quality = 4; internal const int Quantity = 8; internal const int Variant = 16; internal const int Crafter = 32; internal const int PrefabHash = 64; internal const int CustomData = 128; internal const int Equipped = 2; } internal static class Map { internal const int MaximumPins = 10000; internal const int MaximumPinNameLength = 128; internal const int MaximumPinRequestJsonLength = 2048; internal const int MaximumPinRequestsPerSession = 100000; internal const int MaximumSize = 4096; internal const int MaximumPinRequestsPerSecond = 16; internal const int FormatVersion = 8; } internal static class World { internal const int MaximumUpdateBytes = 2097152; internal const int MaximumInvalidations = 100000; internal const int RejectedObjectHistory = 4096; internal const int MaximumRejectedObjectLogs = 20; internal const float RejectedObjectLogWindowSeconds = 5f; internal const int MaximumTracedCreatures = 256; internal const float CreatureTraceWaitSeconds = 5f; internal const float MaximumCoordinateMagnitude = 100000f; internal const int MaximumRpcBytes = 65536; internal const int MaximumActionJsonLength = 8192; internal const int MaximumActionRequests = 100000; internal const int RotationFlag = 4096; internal const int ObjectHeaderBytes = 6; } internal static class Compression { internal const int MaximumUncompressedControlBytes = 5; internal const int HeaderByteShift = 8; internal const int CompressionMethodMask = 15; internal const int DeflateCompressionMethod = 8; internal const int HeaderChecksumDivisor = 31; } internal static class Timing { internal const float RejectionTimeoutSeconds = 2f; internal const float CharacterRequestTimeoutSeconds = 30f; internal const float CharacterSaveIntervalSeconds = 30f; internal const double CharacterCacheIdleSeconds = 600.0; internal const float MinimumAttackIntervalSeconds = 0.15f; internal const float MinimumAttackLifetimeSeconds = 5f; internal const float AttackLifetimeGraceSeconds = 2f; internal const float LoadingPickupTimeoutSeconds = 10f; internal const float PickupTimeoutSeconds = 2f; internal const float PinRateWindowSeconds = 1f; } internal static class Building { internal const float RemovalRayDistance = 50f; internal const float PlacementNoiseRange = 50f; internal const float PlacementRayDistance = 50f; internal const float MaximumCameraDistance = 8f; internal const float MinimumAimMagnitude = 0.0001f; internal const float SurfaceProbeOffset = 50f; internal const float WaterPlacementOffset = 3f; internal const float SnapSearchRadius = 10f; internal const float SnapDistance = 0.5f; internal const float OverlapDistance = 0.05f; internal const float OverlapAngle = 10f; internal const float MaximumAshlandsVegetationMask = 0.1f; internal const float MinimumVegetationMask = 0.25f; internal const float MinimumFlatSurfaceNormalY = 0.8f; internal const float MaximumCeilingNormalY = -0.5f; internal const float MaximumNonFloorNormalY = 0.1f; internal const float MaximumClippingPenetration = 0.2f; } internal static class Spawn { internal const int MaximumCommandLength = 256; internal const float DefaultRadius = 0.5f; internal const int MaximumAmount = 100; internal const int MaximumLevel = 9; internal const int MaximumRadius = 20; } internal static class Inventory { internal const int MaximumRepairStationLevel = 4; internal const int MaximumPickupReports = 256; internal const int MaximumPendingPickups = 4096; internal const int MaximumPendingPickupsPerPeer = 64; internal const float HeavyItemWeight = 300f; internal const float HeavyItemDropSpeed = 0.5f; internal const float ItemDropSpeed = 5f; internal const float MaximumInteractionDistance = 4f; internal const int MaximumCraftCount = 100; } internal static class Character { internal const int MaximumDiscoveryNameLength = 256; internal const int MaximumStationLevel = 10000; internal const int MaximumDiscoveriesJsonLength = 262144; internal const int MaximumAccessoryNameLength = 128; internal const int MaximumAppearanceJsonLength = 4096; internal const int MaximumDiscoveries = 4096; internal const float InitialHealth = 25f; internal const float InitialStamina = 75f; internal const string StarterTorchPrefab = "Torch"; internal const string StarterChestPrefab = "ArmorRagsChest"; } } internal static class PluginPatches { internal static Type[] For(Type pluginType) { List<Type> list = new List<Type>(); Type[] types = pluginType.Assembly.GetTypes(); foreach (Type type in types) { if (!(type.Namespace == pluginType.Namespace) && !(type.Namespace == typeof(PluginPatches).Namespace)) { string? text = type.Namespace; if (text == null || !text.StartsWith(typeof(PluginPatches).Namespace + ".", StringComparison.Ordinal)) { continue; } } list.Add(type); } return list.ToArray(); } } } namespace Landoria.ServerShield.Shared.World { internal static class WorldInteractions { internal static bool Supported(Component component) { if (!(component is Pickable) && !(component is PickableItem) && !(component is Beehive) && !(component is Fermenter) && !(component is CookingStation) && !(component is Fireplace)) { if (component is Switch) { if (!((Object)(object)component.GetComponentInParent<Smelter>() != (Object)null)) { return (Object)(object)component.GetComponentInParent<CookingStation>() != (Object)null; } return true; } return false; } return true; } } } namespace Landoria.ServerShield.Shared.Serialization { internal sealed class BinaryJson : IDisposable { private readonly MemoryStream stream; private readonly BinaryReader reader; private readonly BinaryWriter writer; internal bool Writing => writer != null; internal BinaryJson(byte[] data = null) { if (data != null && data.Length > 67108864) { throw new InvalidDataException("Character data is too large."); } stream = ((data == null) ? new MemoryStream() : new MemoryStream(data, writable: false)); UTF8Encoding encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); if (data == null) { writer = new BinaryWriter(stream, encoding, leaveOpen: true); } else { reader = new BinaryReader(stream, encoding, leaveOpen: true); } } internal byte[] Finish() { ValidateComplete(); return stream.ToArray(); } internal void ValidateComplete(int reservedBytes = 0) { if (!Writing && stream.Position != stream.Length) { throw new InvalidDataException("Trailing character data."); } if (stream.Length > 67108864 - reservedBytes) { throw new InvalidDataException("Character data is too large."); } } private T Field<T>(JObject obj, string name, Func<T> read, Action<T> write, Func<JToken, T> parse) { if (!Writing) { T val = read(); obj[name] = JToken.FromObject(val); return val; } T val2 = parse(Required(obj, name)); write(val2); if (stream.Length > 67108864) { throw new InvalidDataException("Character data is too large."); } return val2; } internal static JToken Required(JObject obj, string name) { return obj[name] ?? throw new InvalidDataException("Missing JSON field: " + name); } internal static long Integer(JToken token) { if (token.Type != JTokenType.Integer) { throw new InvalidDataException("Expected an integer."); } return token.Value<long>(); } internal static bool Boolean(JToken token) { if (token.Type != JTokenType.Boolean) { throw new InvalidDataException("Expected a boolean."); } return token.Value<bool>(); } internal static string Text(JToken token) { if (token.Type != JTokenType.String) { throw new InvalidDataException("Expected a string."); } return token.Value<string>(); } internal int Int(JObject obj, string name) { return Field(obj, name, (reader == null) ? null : new Func<int>(reader.ReadInt32), (writer == null) ? null : new Action<int>(writer.Write), (JToken t) => checked((int)Integer(t))); } internal byte Byte(JObject obj, string name) { return Field(obj, name, (reader == null) ? null : new Func<byte>(reader.ReadByte), (writer == null) ? null : new Action<byte>(writer.Write), (JToken t) => checked((byte)Integer(t))); } internal ushort UShort(JObject obj, string name) { return Field(obj, name, (reader == null) ? null : new Func<ushort>(reader.ReadUInt16), (writer == null) ? null : new Action<ushort>(writer.Write), (JToken t) => checked((ushort)Integer(t))); } internal bool Bool(JObject obj, string name) { return Field(obj, name, (reader == null) ? null : new Func<bool>(reader.ReadBoolean), (writer == null) ? null : new Action<bool>(writer.Write), Boolean); } internal string String(JObject obj, string name) { return Field(obj, name, (reader == null) ? null : new Func<string>(reader.ReadString), (writer == null) ? null : new Action<string>(writer.Write), Text); } internal void Long(JObject obj, string name) { if (!Writing) { obj[name] = reader.ReadInt64().ToString(CultureInfo.InvariantCulture); } else { writer.Write(long.Parse(Text(Required(obj, name)), CultureInfo.InvariantCulture)); } } internal void Float(JObject obj, string name) { if (Writing) { WriteFloat(Required(obj, name)); } else { obj[name] = ReadFloat(); } } private JToken ReadFloat() { int num = reader.ReadInt32(); float num2 = BitConverter.ToSingle(BitConverter.GetBytes(num), 0); if (!float.IsNaN(num2) && !float.IsInfinity(num2) && num != int.MinValue) { return new JValue((double)num2); } object[] array = new object[1]; uint num3 = (uint)num; array[0] = num3.ToString("X8", CultureInfo.InvariantCulture); return JsonTemplate.Object(FormattableStringFactory.Create("{{\n \"floatBits\": {0}\n}}", array)); } private void WriteFloat(JToken token) { if (token is JObject obj) { writer.Write(uint.Parse(Text(Required(obj, "floatBits")), NumberStyles.HexNumber, CultureInfo.InvariantCulture)); return; } if (token.Type != JTokenType.Float && token.Type != JTokenType.Integer) { throw new InvalidDataException("Expected a number or floatBits."); } float num = token.Value<float>(); if (float.IsInfinity(num) || float.IsNaN(num)) { throw new InvalidDataException("Non-finite float requires floatBits."); } writer.Write(num); } internal void Version(JObject obj, int expected) { if (Int(obj, "version") != expected) { throw new InvalidDataException("Unsupported format version; expected " + expected); } } internal void Object(JObject obj, string name, Action<JObject> visit) { JObject jObject = (Writing ? (Required(obj, name) as JObject) : new JObject()); if (jObject == null) { throw new InvalidDataException("Expected object: " + name); } visit(jObject); if (!Writing) { obj[name] = jObject; } } internal void List(JObject obj, string name, Action<JObject> visit, bool shortCount = false, int fixedCount = -1) { JArray jArray = (Writing ? (Required(obj, name) as JArray) : new JArray()); if (jArray == null) { throw new InvalidDataException("Expected array: " + name); } int num = (Writing ? jArray.Count : ((fixedCount >= 0) ? fixedCount : (shortCount ? reader.ReadUInt16() : reader.ReadInt32()))); if (num < 0 || num > 100000) { throw new InvalidDataException("Invalid array size."); } if (Writing && fixedCount >= 0 && num != fixedCount) { throw new InvalidDataException("Invalid fixed array size."); } if (Writing && fixedCount < 0) { if (shortCount) { writer.Write(checked((ushort)num)); } else { writer.Write(num); } } for (int i = 0; i < num; i++) { JObject jObject = (Writing ? (jArray[i] as JObject) : new JObject()); if (jObject == null) { throw new InvalidDataException("Expected array entry object."); } visit(jObject); if (!Writing) { jArray.Add(jObject); } } if (!Writing) { obj[name] = jArray; } } internal void Vector(JObject obj, string name) { Object(obj, name, delegate(JObject v) { Float(v, "x"); Float(v, "y"); Float(v, "z"); }); } internal void Blob(JObject obj, string name, Action<BinaryJson, JObject> visit = null) { if (!Writing) { int num = reader.ReadInt32(); if (num < 0 || num > 67108864 || num > stream.Length - stream.Position) { throw new InvalidDataException("Invalid binary block size."); } byte[] array = reader.ReadBytes(num); if (visit == null) { obj[name] = Convert.ToBase64String(array); return; } JObject jObject = new JObject(); using (BinaryJson binaryJson = new BinaryJson(array)) { visit(binaryJson, jObject); binaryJson.Finish(); } obj[name] = jObject; return; } byte[] array2; if (visit == null) { array2 = Convert.FromBase64String(Text(Required(obj, name))); } else { JObject arg = (Required(obj, name) as JObject) ?? throw new InvalidDataException("Expected package object."); using BinaryJson binaryJson2 = new BinaryJson(); visit(binaryJson2, arg); array2 = binaryJson2.Finish(); } if (array2.Length > 67108864) { throw new InvalidDataException("Binary block is too large."); } writer.Write(array2.Length); writer.Write(array2); } internal int CompactCount(JObject obj, string name) { if (!Writing) { int num = reader.ReadByte(); if ((num & 0x80) != 0) { num = ((num & 0x7F) << 8) | reader.ReadByte(); } obj[name] = num; return num; } int num2 = checked((int)Integer(Required(obj, name))); if (num2 < 0 || num2 > 32767) { throw new InvalidDataException("Invalid compact count."); } if (num2 >= 128) { writer.Write((byte)((num2 >> 8) | 0x80)); } writer.Write((byte)(num2 & 0xFF)); return num2; } public void Dispose() { reader?.Dispose(); writer?.Dispose(); stream.Dispose(); } } internal static class CharacterBinary { internal static CharacterPlayerData ReadPlayer(byte[] bytes) { return Read<CharacterPlayerData>(bytes, CharacterSchema.Player); } internal static CharacterInventory ReadInventory(byte[] bytes) { return Read<CharacterInventory>(bytes, CharacterSchema.Inventory); } internal static byte[] WriteInventory(CharacterInventory inventory) { return Write(inventory, CharacterSchema.Inventory); } internal static CharacterSkills ReadSkills(byte[] bytes) { return Read<CharacterSkills>(bytes, CharacterSchema.Skills); } internal static byte[] WriteSkills(CharacterSkills skills) { return Write(skills, CharacterSchema.Skills); } private static T Read<T>(byte[] bytes, Action<BinaryJson, JObject> visit) where T : CharacterData { JObject jObject = new JObject(); using (BinaryJson binaryJson = new BinaryJson(bytes)) { visit(binaryJson, jObject); binaryJson.ValidateComplete(); } return CharacterDocument.FromJson<T>(jObject); } private static byte[] Write(CharacterData data, Action<BinaryJson, JObject> visit) { using BinaryJson binaryJson = new BinaryJson(); visit(binaryJson, CharacterDocument.ToJson(data)); return binaryJson.Finish(); } } internal static class CharacterDocument { internal static Character Read(string json) { JObject jObject = CharacterJson.ReadDocument(json); CharacterJson.ValidateProfile((JObject)jObject["profile"]); return FromJson<Character>(jObject); } internal static JObject ToJson(CharacterData character) { return JObject.FromObject(character, Serializer()); } internal static T FromJson<T>(JObject document) where T : CharacterData { return document.ToObject<T>(Serializer()); } internal static string Serialize(CharacterData character, Formatting formatting = Formatting.Indented) { using StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); using JsonTextWriter jsonWriter = new JsonTextWriter(stringWriter) { Formatting = formatting }; Serializer().Serialize(jsonWriter, character); return stringWriter.ToString(); } internal static bool Equivalent(CharacterData first, CharacterData second) { return JToken.DeepEquals(ToJson(first), ToJson(second)); } private static JsonSerializer Serializer() { JsonSerializer jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings { Culture = CultureInfo.InvariantCulture, CheckAdditionalContent = true, DateParseHandling = DateParseHandling.None }); jsonSerializer.Converters.Add(new CharacterFloatConverter()); return jsonSerializer; } } internal sealed class CharacterFloatConverter : JsonConverter<float> { public override float ReadJson(JsonReader reader, Type objectType, float existingValue, bool hasExistingValue, JsonSerializer serializer) { JToken jToken = JToken.Load(reader); if (jToken is JObject obj) { return BitConverter.ToSingle(BitConverter.GetBytes(uint.Parse(BinaryJson.Text(BinaryJson.Required(obj, "floatBits")), NumberStyles.HexNumber, CultureInfo.InvariantCulture)), 0); } return jToken.Value<float>(); } public override void WriteJson(JsonWriter writer, float value, JsonSerializer serializer) { int num = BitConverter.ToInt32(BitConverter.GetBytes(value), 0); if (float.IsNaN(value) || float.IsInfinity(value) || num == int.MinValue) { writer.WriteStartObject(); writer.WritePropertyName("floatBits"); uint num2 = (uint)num; writer.WriteValue(num2.ToString("X8", CultureInfo.InvariantCulture)); writer.WriteEndObject(); } else { writer.WriteValue((double)value); } } } internal static class CharacterJson { internal static JObject ReadProfile(string json) { return (JObject)ReadDocument(json)["profile"]; } internal static JObject ReadDocument(string json) { if (json == null) { throw new ArgumentNullException("json"); } if ((long)json.Length > 268435456L) { throw new InvalidDataException("JSON is too large."); } JObject jObject; using (JsonTextReader jsonTextReader = new JsonTextReader(new StringReader(json)) { DateParseHandling = DateParseHandling.None, MaxDepth = 64 }) { jObject = JObject.Load(jsonTextReader, new JsonLoadSettings { DuplicatePropertyNameHandling = DuplicatePropertyNameHandling.Error }); if (jsonTextReader.Read()) { throw new InvalidDataException("Trailing JSON content."); } } if ((string?)jObject["format"] != "Landoria.ServerShield.character" || (int?)jObject["schemaVersion"] != 1) { throw new InvalidDataException("Unsupported JSON format."); } if (!(jObject["profile"] is JObject)) { throw new InvalidDataException("Missing profile."); } return jObject; } internal static void Validate(string json) { ValidateProfile(ReadProfile(json)); } internal static void ValidateProfile(JObject profile) { using BinaryJson binaryJson = new BinaryJson(); CharacterSchema.Profile(binaryJson, profile); binaryJson.ValidateComplete(72); } } internal static class CharacterSchema { internal static void Profile(BinaryJson io, JObject obj) { io.Version(obj, 46); int stats = io.Int(obj, "statCount"); io.List(obj, "statGroups", delegate(JObject group) { Stats(io, group, stats); }); io.Bool(obj, "firstSpawn"); io.List(obj, "worlds", delegate(JObject world) { World(io, world); }); io.String(obj, "playerName"); io.Long(obj, "playerId"); io.String(obj, "startSeed"); io.Bool(obj, "usedCheats"); io.Long(obj, "dateCreated"); if (io.Bool(obj, "hasPlayerData")) { io.Blob(obj, "playerData", Player); } } private static void Stats(BinaryJson io, JObject obj, int count) { if (count < 0 || count > 100000) { throw new InvalidDataException("Invalid stat count."); } io.List(obj, "values", delegate(JObject value) { io.Float(value, "value"); }, shortCount: false, count); Floats(io, obj, "knownWorlds"); Floats(io, obj, "knownWorldKeys"); Floats(io, obj, "knownCommands"); io.List(obj, "enemyStats", delegate(JObject group) { Floats(io, group, "values"); }); string[] array = new string[5] { "itemPickupStats", "itemCraftStats", "pickableStats", "foodEatenStats", "piecesPlacedStats" }; foreach (string name in array) { Floats(io, obj, name); } } private static void World(BinaryJson io, JObject obj) { io.Long(obj, "worldId"); io.Bool(obj, "haveCustomSpawnPoint"); io.Vector(obj, "spawnPoint"); io.Bool(obj, "haveLogoutPoint"); io.Vector(obj, "logoutPoint"); io.Bool(obj, "haveDeathPoint"); io.Vector(obj, "deathPoint"); io.Vector(obj, "homePoint"); if (io.Bool(obj, "hasMapData")) { io.Blob(obj, "mapData"); } } internal static void Player(BinaryJson io, JObject obj) { io.Version(obj, 33); string[] array = new string[4] { "maxHealth", "health", "maxStamina", "timeSinceDeath" }; foreach (string name in array) { io.Float(obj, name); } io.String(obj, "guardianPower"); io.Float(obj, "guardianPowerCooldown"); io.Object(obj, "inventory", delegate(JObject inventory) { Inventory(io, inventory); }); Strings(io, obj, "knownRecipes"); io.List(obj, "knownStations", delegate(JObject entry) { io.String(entry, "key"); io.Int(entry, "value"); }); array = new string[5] { "knownMaterial", "shownTutorials", "uniques", "trophies", "knownBiome" }; foreach (string name2 in array) { Strings(io, obj, name2); } Pairs(io, obj, "knownTexts"); io.String(obj, "beardItem"); io.String(obj, "hairItem"); io.Vector(obj, "skinColor"); io.Vector(obj, "hairColor"); io.Int(obj, "modelIndex"); io.List(obj, "foods", delegate(JObject food) { io.String(food, "name"); io.Float(food, "time"); }); io.Object(obj, "skills", delegate(JObject skills) { Skills(io, skills); }); Pairs(io, obj, "customData"); array = new string[3] { "stamina", "maxEitr", "eitr" }; foreach (string name3 in array) { io.Float(obj, name3); } io.Blob(obj, "buildUi"); } internal static void Inventory(BinaryJson io, JObject obj) { io.Version(obj, 109); io.List(obj, "items", delegate(JObject item) { Item(io, item); }, shortCount: true); } internal static void Item(BinaryJson io, JObject obj) { io.Int(obj, "durabilityHundredths"); io.Byte(obj, "slotX"); io.Byte(obj, "slotY"); io.Byte(obj, "worldLevel"); byte num = io.Byte(obj, "flags"); if ((num & 4) != 0) { io.UShort(obj, "quality"); } if ((num & 8) != 0) { io.UShort(obj, "quantity"); } if ((num & 0x10) != 0) { io.Int(obj, "variant"); } if ((num & 0x20) != 0) { io.Long(obj, "crafterId"); io.String(obj, "crafterName"); } if ((num & 0x40) != 0) { io.Int(obj, "prefabHash"); } if ((num & 0x80) != 0) { if (io.Writing) { obj["customDataCount"] = ((JArray)BinaryJson.Required(obj, "customData")).Count; } int fixedCount = io.CompactCount(obj, "customDataCount"); io.List(obj, "customData", delegate(JObject entry) { io.String(entry, "key"); io.String(entry, "value"); }, shortCount: false, fixedCount); } io.Byte(obj, "extraFlags"); } internal static void Skills(BinaryJson io, JObject obj) { io.Version(obj, 2); io.List(obj, "values", delegate(JObject skill) { io.Int(skill, "type"); io.Float(skill, "level"); io.Float(skill, "accumulator"); }); } private static void Strings(BinaryJson io, JObject obj, string name) { io.List(obj, name, delegate(JObject entry) { io.String(entry, "value"); }); } private static void Floats(BinaryJson io, JObject obj, string name) { io.List(obj, name, delegate(JObject entry) { io.String(entry, "key"); io.Float(entry, "value"); }); } private static void Pairs(BinaryJson io, JObject obj, string name) { io.List(obj, name, delegate(JObject entry) { io.String(entry, "key"); io.String(entry, "value"); }); } } public static class FchJsonConverter { public static string ToJson(byte[] fch) { if (fch == null) { throw new ArgumentNullException("fch"); } JObject jObject = new JObject(); using (BinaryJson binaryJson = new BinaryJson(fch)) { binaryJson.Blob(jObject, "payload"); binaryJson.Blob(jObject, "hash"); binaryJson.Finish(); } byte[] array = Convert.FromBase64String((string?)jObject["payload"]); using (SHA512 sHA = SHA512.Create()) { if (!sHA.ComputeHash(array).SequenceEqual(Convert.FromBase64String((string?)jObject["hash"]))) { throw new InvalidDataException("Character SHA-512 checksum does not match."); } } JObject jObject2 = new JObject(); using (BinaryJson binaryJson2 = new BinaryJson(array)) { CharacterSchema.Profile(binaryJson2, jObject2); binaryJson2.Finish(); } return JsonTemplate.Object(FormattableStringFactory.Create("{{\n \"format\": {0},\n \"schemaVersion\": {1},\n \"profile\": {2}\n}}", "Landoria.ServerShield.character", 1, jObject2)).ToString(Formatting.Indented); } public static byte[] FromJson(string json) { JObject obj = CharacterJson.ReadProfile(json); byte[] array; using (BinaryJson binaryJson = new BinaryJson()) { CharacterSchema.Profile(binaryJson, obj); array = binaryJson.Finish(); } JObject jObject = JsonTemplate.Object($"{{\n \"payload\": {Convert.ToBase64String(array)}\n}}"); using (SHA512 sHA = SHA512.Create()) { jObject["hash"] = Convert.ToBase64String(sHA.ComputeHash(array)); } using BinaryJson binaryJson2 = new BinaryJson(); binaryJson2.Blob(jObject, "payload"); binaryJson2.Blob(jObject, "hash"); return binaryJson2.Finish(); } } internal static class JsonTemplate { internal static JObject Object(FormattableString template) { object[] arguments = template.GetArguments(); object[] array = new object[arguments.Length]; for (int i = 0; i < arguments.Length; i++) { array[i] = Serialize(arguments[i]); } using JsonTextReader jsonTextReader = new JsonTextReader(new StringReader(string.Format(CultureInfo.InvariantCulture, template.Format, array))); jsonTextReader.DateParseHandling = DateParseHandling.None; jsonTextReader.MaxDepth = null; return JObject.Load(jsonTextReader); } private static string Serialize(object value) { using StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); using JsonTextWriter jsonWriter = new JsonTextWriter(stringWriter); JsonSerializer.Create(new JsonSerializerSettings { Culture = CultureInfo.InvariantCulture, FloatFormatHandling = FloatFormatHandling.Symbol }).Serialize(jsonWriter, value); return stringWriter.ToString(); } } internal static class WireJson { internal static T Read<T>(string json) where T : class { using JsonTextReader jsonTextReader = new JsonTextReader(new StringReader(json)); jsonTextReader.DateParseHandling = DateParseHandling.None; jsonTextReader.MaxDepth = 64; return Serializer().Deserialize<T>(jsonTextReader) ?? throw new InvalidDataException("Missing JSON object."); } internal static string Write(object value) { using StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); using JsonTextWriter jsonWriter = new JsonTextWriter(stringWriter); Serializer().Serialize(jsonWriter, value); return stringWriter.ToString(); } private static JsonSerializer Serializer() { JsonSerializer jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings { Culture = CultureInfo.InvariantCulture, DateParseHandling = DateParseHandling.None, CheckAdditionalContent = true, TypeNameHandling = TypeNameHandling.None, FloatFormatHandling = FloatFormatHandling.Symbol }); jsonSerializer.Converters.Add(new StrictPrimitiveConverter()); jsonSerializer.Converters.Add(new StringEnumConverter { AllowIntegerValues = false }); return jsonSerializer; } } internal sealed class StrictPrimitiveConverter : JsonConverter { public override bool CanWrite => false; public override bool CanConvert(Type type) { type = Nullable.GetUnderlyingType(type) ?? type; if (!(type == typeof(string)) && !(type == typeof(bool)) && !(type == typeof(int)) && !(type == typeof(uint)) && !(type == typeof(float))) { return type == typeof(double); } return true; } public override object ReadJson(JsonReader reader, Type type, object existingValue, JsonSerializer serializer) { Type underlyingType = Nullable.GetUnderlyingType(type); if (reader.TokenType == JsonToken.Null && (underlyingType != null || type == typeof(string))) { return null; } type = underlyingType ?? type; bool num; if (!(type == typeof(string))) { if (!(type == typeof(bool))) { if (reader.TokenType == JsonToken.Integer) { goto IL_00c6; } if (!(type == typeof(float)) && !(type == typeof(double))) { goto IL_00b0; } num = reader.TokenType == JsonToken.Float; } else { num = reader.TokenType == JsonToken.Boolean; } } else { num = reader.TokenType == JsonToken.String; } if (!num) { goto IL_00b0; } goto IL_00c6; IL_00b0: throw new JsonSerializationException("Unexpected JSON value at " + reader.Path); IL_00c6: return Convert.ChangeType(reader.Value, type, CultureInfo.InvariantCulture); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotSupportedException(); } } } namespace Landoria.ServerShield.Shared.Network { internal static class ActionRejectionLog { private static readonly Dictionary<string, long> counts = new Dictionary<string, long>(); private static readonly Stopwatch clock = Stopwatch.StartNew(); private static double nextFlush; internal static bool Record(string action, string reason) { string text = "action=" + action + " reason=" + reason; if (counts.TryGetValue(text, out var value)) { counts[text] = value + 1; } else { counts.Add(text, 0L); NetworkLog.Log.LogDebug("ActionRejected " + text + " count=1"); } return false; } internal static void Tick() { if (!(clock.Elapsed.TotalSeconds < nextFlush)) { Flush(); nextFlush = clock.Elapsed.TotalSeconds + 5.0; } } internal static void Flush() { foreach (KeyValuePair<string, long> count in counts) { if (count.Value > 0) { NetworkLog.Log.LogDebug("ActionRejected " + count.Key + " " + $"count={count.Value} repeated=true"); } } counts.Clear(); } } internal static class BuildTrace { internal static string Resources(Piece piece, Inventory inventory) { return Resources(piece?.m_resources, inventory); } internal static string Resources(Requirement[] requirements, Inventory inventory, int quality = 0, int multiplier = 1) { if (requirements == null || inventory == null) { return "unavailable"; } return string.Join(",", from value in requirements where (Object)(object)value.m_resItem != (Object)null select ((Object)value.m_resItem).name + ":" + $"{inventory.CountItems(value.m_resItem.m_itemData.m_shared.m_name, -1, true)}" + $"/cost={value.GetAmount(quality) * multiplier}"); } internal static Piece Piece(int prefab) { ZNetScene instance = ZNetScene.instance; if (instance == null) { return null; } GameObject prefab2 = instance.GetPrefab(prefab); if (prefab2 == null) { return null; } return prefab2.GetComponent<Piece>(); } } internal sealed class FoodSnapshot { internal ZDOID Character; internal float Health; internal float Maximum; internal float Stamina; internal float Eitr; internal List<Food> Foods = new List<Food>(); internal static FoodSnapshot Capture(Player player) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return new FoodSnapshot { Character = ((Character)player).GetZDOID(), Health = ((Character)player).GetHealth(), Maximum = ((Character)player).GetMaxHealth(), Stamina = ((Character)player).GetMaxStamina(), Eitr = ((Character)player).GetMaxEitr(), Foods = player.GetFoods().Select(Clone).ToList() }; } private static Food Clone(Food food) { //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_0011: 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_0029: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown return new Food { m_name = food.m_name, m_item = food.m_item, m_time = food.m_time, m_health = food.m_health, m_stamina = food.m_stamina, m_eitr = food.m_eitr }; } internal void Apply(Player player, bool flash) { player.GetFoods().Clear(); player.GetFoods().AddRange(Foods.Select(Clone)); player.SetMaxHealth(Maximum, flash); ((Character)player).SetHealth(Health); player.SetMaxStamina(Stamina, flash); NativeFood.SetMaxEitr(player, Eitr, flash); } internal ZPackage Write() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0008: Unknown result type (might be due to invalid IL or missing references) ZPackage val = new ZPackage(); val.Write(Character); val.Write(Health); val.Write(Maximum); val.Write(Stamina); val.Write(Eitr); val.Write(Foods.Count); foreach (Food food in Foods) { val.Write(food.m_name); val.Write(food.m_time); val.Write(food.m_health); val.Write(food.m_stamina); val.Write(food.m_eitr); } return val; } internal static FoodSnapshot Read(ZPackage package) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) FoodSnapshot foodSnapshot = new FoodSnapshot { Character = package.ReadZDOID(), Health = Number(package), Maximum = Number(package), Stamina = Number(package), Eitr = Number(package) }; int num = package.ReadInt(); if (((ZDOID)(ref foodSnapshot.Character)).IsNone() || foodSnapshot.Maximum <= 0f || foodSnapshot.Health > foodSnapshot.Maximum || foodSnapshot.Stamina <= 0f || num < 0 || num > 3) { throw new InvalidDataException("Invalid food snapshot."); } for (int i = 0; i < num; i++) { Food val = Resolve(package.ReadString(), Number(package)); val.m_health = Number(package); val.m_stamina = Number(package); val.m_eitr = Number(package); foodSnapshot.Foods.Add(val); } if (package.GetPos() != package.Size() || foodSnapshot.Foods.Select((Food food) => food.m_name).Distinct().Count() != num) { throw new InvalidDataException("Invalid food snapshot contents."); } return foodSnapshot; } private static float Number(ZPackage package) { float num = package.ReadSingle(); if (float.IsNaN(num) || float.IsInfinity(num) || num < 0f) { throw new InvalidDataException("Invalid food value."); } return num; } internal static Food Resolve(string name, float time) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(name); ItemData val = (((Object)(object)itemPrefab == (Object)null) ? null : itemPrefab.GetComponent<ItemDrop>()?.m_itemData); if (val == null || val.m_shared.m_food <= 0f || float.IsNaN(time) || float.IsInfinity(time) || time < 0f) { throw new InvalidDataException("Unknown or invalid saved food."); } return new Food { m_name = name, m_item = val, m_time = time, m_health = val.m_shared.m_food, m_stamina = val.m_shared.m_foodStamina, m_eitr = val.m_shared.m_foodEitr }; } internal static List<CharacterFood> Saved(Player player) { return (from food in player.GetFoods() select new CharacterFood { Name = food.m_name, Time = food.m_time }).ToList(); } } [HarmonyPatch] internal static class InventorySnapshot { internal static void Apply(Player player, ZPackage package) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = ((Humanoid)player).GetInventory(); Inventory val = new Inventory("Server snapshot", (Sprite)null, inventory.GetWidth(), inventory.GetHeight()); val.Load(package); List<ItemData> list = inventory.GetAllItems().ToList(); List<ItemData> allItems = val.GetAllItems(); Dictionary<ItemData, ItemData> dictionary = new Dictionary<ItemData, ItemData>(); foreach (ItemData item in allItems) { Match(item, list, dictionary, sameSlot: true); } foreach (ItemData item2 in allItems) { if (!dictionary.ContainsKey(item2)) { Match(item2, list, dictionary, sameSlot: false); } } foreach (ItemData item3 in list) { ((Humanoid)player).UnequipItem(item3, false); } List<ItemData> collection = Reconcile(player, allItems, dictionary); inventory.GetAllItems().Clear(); inventory.GetAllItems().AddRange(collection); NotifyChanged(inventory, success: false, cheatedStateChanged: false); } private static List<ItemData> Reconcile(Player player, List<ItemData> incoming, Dictionary<ItemData, ItemData> matches) { List<ItemData> list = new List<ItemData>(); foreach (ItemData item in incoming) { if (!matches.TryGetValue(item, out var value)) { item.m_equipped = false; value = item; } else { CopyState(value, item); } if (value.m_shared.m_useDurability && value.m_durability <= 0f) { ((Humanoid)player).UnequipItem(value, false); } list.Add(value); } return list; } private static void Match(ItemData incoming, List<ItemData> available, Dictionary<ItemData, ItemData> matches, bool sameSlot) { ItemData val = ((IEnumerable<ItemData>)available).FirstOrDefault((Func<ItemData, bool>)((ItemData item) => SameItem(item, incoming) && (!sameSlot || ((Vector2i)(ref item.m_gridPos)).Equals(incoming.m_gridPos)))); if (val != null) { available.Remove(val); matches.Add(incoming, val); } } private static bool SameItem(ItemData left, ItemData right) { string value; if ((Object)(object)left.m_dropPrefab == (Object)(object)right.m_dropPrefab && left.m_quality == right.m_quality && left.m_variant == right.m_variant && left.m_worldLevel == right.m_worldLevel && left.m_crafterID == right.m_crafterID && left.m_crafterName == right.m_crafterName && left.m_customData.Count == right.m_customData.Count) { return left.m_customData.All((KeyValuePair<string, string> pair) => right.m_customData.TryGetValue(pair.Key, out value) && value == pair.Value); } return false; } private static void CopyState(ItemData current, ItemData incoming) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) current.m_stack = incoming.m_stack; current.m_durability = incoming.m_durability; current.m_gridPos = incoming.m_gridPos; current.m_pickedUp = incoming.m_pickedUp; current.m_cheated = incoming.m_cheated; } [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(Inventory), "Changed")] private static void NotifyChanged(Inventory instance, bool success, bool cheatedStateChanged) { throw new NotImplementedException("Native inventory notification was not patched."); } } [HarmonyPatch] internal static class NativeFood { [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(Player), "UpdateFood")] internal static void Update(Player player, float dt, bool forceUpdate) { throw new NotImplementedException("Native food update was not patched."); } [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(Player), "SetMaxEitr")] internal static void SetMaxEitr(Player player, float eitr, bool flashBar) { throw new NotImplementedException("Native food eitr was not patched."); } [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(Humanoid), "SetUseHandVisual")] internal static void ShowItem(Humanoid player, GameObject item, float seconds) { throw new NotImplementedException("Native food visual was not patched."); } } internal static class NetworkLog { internal static ModLog Log; } internal static class ObjectTraceLog { private static readonly HashSet<string> seen = new HashSet<string>(); private static readonly Queue<string> order = new Queue<string>(); private static readonly Stopwatch clock = Stopwatch.StartNew(); private static double window; private static int count; private static long suppressed; internal static bool IsCreature(int hash) { ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.GetPrefab(hash) : null); if ((Object)(object)val != (Object)null && (Object)(object)val.GetComponent<Character>() != (Object)null) { return (Object)(object)val.GetComponent<Player>() == (Object)null; } return false; } internal unsafe static void Write(string stage, ZDOID id, int hash, string details) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) ZDOID val = id; string item = stage + "/" + ((object)(*(ZDOID*)(&val))/*cast due to .constrained prefix*/).ToString(); if (!seen.Add(item)) { return; } order.Enqueue(item); if (order.Count > 4096) { seen.Remove(order.Dequeue()); } if (CanWrite()) { ZNetScene instance = ZNetScene.instance; object obj; if (instance == null) { obj = null; } else { GameObject prefab = instance.GetPrefab(hash); obj = ((prefab != null) ? ((Object)prefab).name : null); } if (obj == null) { obj = "unknown"; } string arg = (string)obj; NetworkLog.Log.LogDebug($"ObjectTrace stage={stage} object={id} " + $"prefab={arg} prefabHash={hash} {details}"); } } private static bool CanWrite() { double totalSeconds = clock.Elapsed.TotalSeconds; if (totalSeconds - window >= 5.0) { if (suppressed > 0) { NetworkLog.Log.LogDebug($"ObjectTrace suppressed={suppressed}"); } window = totalSeconds; count = 0; suppressed = 0L; } if (count >= 20) { suppressed++; return false; } count++; return true; } } [HarmonyPatch(typeof(ZPlayFabSocket), "ProcessAck")] internal static class PlayFabAckDiagnostics { private static void Prefix(ZPlayFabSocket __instance, uint msgId, InFlightQueue ___m_inFlightQueue, bool ___m_isClient) { if (__instance.IsConnected()) { uint num = ___m_inFlightQueue.Head - ___m_inFlightQueue.Tail; if (msgId - ___m_inFlightQueue.Tail > num) { NetworkLog.Log.LogError($"PlayFab ACK outside the send window: ack={msgId}, " + $"tail={___m_inFlightQueue.Tail}, head={___m_inFlightQueue.Head}, " + "side=" + (___m_isClient ? "client" : "server") + ". Native processing will close the socket. Call stack: " + Environment.StackTrace); } } } } [HarmonyPatch(typeof(ZPlayFabSocket), "OnDataMessageReceived")] internal static class PlayFabEarlyCompression { private sealed class Report { internal bool Written; } private static readonly ConditionalWeakTable<ZPlayFabSocket, Report> reports = new ConditionalWeakTable<ZPlayFabSocket, Report>(); private static bool Prefix(ZPlayFabSocket __instance, PlayFabPlayer from, byte[] compressedBuffer, bool ___m_isClient, bool ___m_useCompression, PlayFabZLibWorkQueue ___m_zlibWorkQueue) { if (___m_useCompression || ((from == null) ? null : from.EntityKey?.Id) != __instance.m_remotePlayerId || !IsEarlyCompressedBuffer(compressedBuffer)) { return true; } Report orCreateValue = reports.GetOrCreateValue(__instance); if (!orCreateValue.Written) { orCreateValue.Written = true; NetworkLog.Log.LogWarning("PlayFab compressed buffer arrived before VersionMatch; selective decompression enabled for early buffers, side=" + (___m_isClient ? "client" : "server") + ". Reported once per socket."); } ___m_zlibWorkQueue.Decompress(compressedBuffer); return false; } private static bool IsEarlyCompressedBuffer(byte[] buffer) { if (buffer == null || buffer.Length <= 5) { return false; } int num = (buffer[0] << 8) | buffer[1]; if ((buffer[0] & 0xF) == 8) { return num % 31 == 0; } return false; } } [HarmonyPatch(typeof(ZPlayFabSocket), "LateUpdateAllSocket")] internal static class PlayFabSocketUpdate { private static bool Prefix(Dictionary<string, ZPlayFabSocket> ___s_connectSockets) { KeyValuePair<string, ZPlayFabSocket>[] array = ___s_connectSockets.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair<string, ZPlayFabSocket> keyValuePair = array[i]; if (___s_connectSockets.TryGetValue(keyValuePair.Key, out var value) && value == keyValuePair.Value) { try { UpdateSocket(value); } catch (Exception message) { NetworkLog.Log.LogError(message); } } } return false; } [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(ZPlayFabSocket), "LateUpdate")] private static void UpdateSocket(ZPlayFabSocket instance) { throw new NotImplementedException("Native PlayFab socket update was not patched."); } } [HarmonyPatch] internal static class TerrainCompilerLifecycle { private static readonly HashSet<TerrainComp> waiting = new HashSet<TerrainComp>(); [HarmonyPrefix] [HarmonyPatch(typeof(TerrainComp), "Awake")] private static bool BeforeAwake(TerrainComp __instance) { if (CanInitialize(__instance)) { return true; } ((Behaviour)__instance).enabled = false; waiting.Add(__instance); return false; } private static bool CanInitialize(TerrainComp compiler) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)compiler).transform.position; if ((Object)(object)Heightmap.FindHeightmap(position) != (Object)null) { return (Object)(object)TerrainComp.FindTerrainCompiler(position) == (Object)null; } return false; } internal static void Tick() { if (waiting.Count == 0) { return; } foreach (TerrainComp item in new List<TerrainComp>(waiting)) { if ((Object)(object)item == (Object)null) { waiting.Remove(item); continue; } ZNetView component = ((Component)item).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid() && CanInitialize(item)) { waiting.Remove(item); try { AwakeNative(item); ((Behaviour)item).enabled = true; } catch (Exception message) { NetworkLog.Log.LogError(message); } } } } [HarmonyPostfix] [HarmonyPatch(typeof(TerrainComp), "OnDestroy")] private static void AfterDestroy(TerrainComp __instance) { waiting.Remove(__instance); } [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(TerrainComp), "Awake")] private static void AwakeNative(TerrainComp instance) { throw new NotSupportedException("Native terrain awake was not patched."); } } [HarmonyPatch] internal static class TerrainCompilerReuse { [HarmonyPrefix] [HarmonyPatch(typeof(Heightmap), "GetAndCreateTerrainCompiler")] private static bool Prefix(Heightmap __instance, GameObject ___m_terrainCompilerPrefab, ref TerrainComp __result) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)__instance).transform.position; if ((Object)(object)TerrainComp.FindTerrainCompiler(position) != (Object)null) { return true; } int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)___m_terrainCompilerPrefab).name); List<ZDO> list = new List<ZDO>(); ZDOMan.instance.FindSectorObjects(ZoneSystem.GetZone(position), new SimulationDistance(0, 0, false), list, (List<ZDO>)null); foreach (ZDO item in list) { if (item.GetPrefab() == stableHashCode && !(item.GetPosition() != position)) { ZNetView val = ZNetScene.instance.FindInstance(item); GameObject val2 = (((Object)(object)val == (Object)null) ? CreateNative(ZNetScene.instance, item) : ((Component)val).gameObject); TerrainCompilerLifecycle.Tick(); __result = val2.GetComponent<TerrainComp>(); if (!((Behaviour)__result).enabled) { throw new InvalidOperationException("Terrain is not ready."); } return false; } } return true; } [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(ZNetScene), "CreateObject")] private static GameObject CreateNative(ZNetScene instance, ZDO zdo) { throw new NotSupportedException("Native terrain creation was not patched."); } } [HarmonyPatch(typeof(TerrainComp), "Awake")] internal static class TerrainCompilerTrace { private static readonly HashSet<string> reported = new HashSet<string>(); private static ZNetScene scene; private static void Prefix(TerrainComp __instance) { try { Inspect(__instance); } catch (Exception message) { NetworkLog.Log.LogError(message); } } private static void Inspect(TerrainComp compiler) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: 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) if ((Object)(object)scene != (Object)(object)ZNetScene.instance) { scene = ZNetScene.instance; reported.Clear(); } if (reported.Count >= 64) { return; } Vector3 position = ((Component)compiler).transform.position; TerrainComp val = TerrainComp.FindTerrainCompiler(position); bool flag = (Object)(object)Heightmap.FindHeightmap(position) != (Object)null; if (!((Object)(object)val == (Object)(object)compiler) && !((Object)(object)val == (Object)null && flag)) { ZNetView component = ((Component)compiler).GetComponent<ZNetView>(); ZDO val2 = ((component != null) ? component.GetZDO() : null); object obj; if (val == null) { obj = null; } else { ZNetView component2 = ((Component)val).GetComponent<ZNetView>(); obj = ((component2 != null) ? component2.GetZDO() : null); } ZDO val3 = (ZDO)obj; string item = $"{val2?.m_uid}/{val3?.m_uid}/{flag}"; if (reported.Add(item)) { Report(compiler, val, val2, val3, flag); } } } private static void Report(TerrainComp compiler, TerrainComp existing, ZDO incoming, ZDO previous, bool heightmap) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) string text = (((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) ? "server" : "client"); NetworkLog.Log.LogWarning("TerrainCompilerTrace side=" + text + $" heightmap={heightmap} position={((Component)compiler).transform.position}" + $" existingPosition={((existing != null) ? new Vector3?(((Component)existing).transform.position) : ((Vector3?)null))}" + " incoming=[" + Describe(incoming) + "] previous=[" + Describe(previous) + "]"); } private static string Describe(ZDO zdo) { //IL_0053: 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) if (zdo == null) { return "no_zdo"; } byte[] byteArray = zdo.GetByteArray(ZDOVars.s_TCData, (byte[])null); string text = "absent"; if (byteArray != null) { using SHA256 sHA = SHA256.Create(); text = BitConverter.ToString(sHA.ComputeHash(byteArray)).Replace("-", ""); } return $"id={zdo.m_uid} owner={zdo.GetOwner()} revision={zdo.DataRevision}" + $" position={zdo.GetPosition()} bytes={((byteArray != null) ? byteArray.Length : 0)}" + " sha256=" + text; } } } namespace Landoria.ServerShield.Shared.Models { [JsonObject(MemberSerialization.OptIn)] internal sealed class BuildRay { [JsonProperty("x", Required = Required.Always)] public float X { get; set; } [JsonProperty("y", Required = Required.Always)] public float Y { get; set; } [JsonProperty("z", Required = Required.Always)] public float Z { get; set; } [JsonProperty("dx", Required = Required.Always)] public float DX { get; set; } [JsonProperty("dy", Required = Required.Always)] public float DY { get; set; } [JsonProperty("dz", Required = Required.Always)] public float DZ { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class Character : CharacterData { [JsonProperty("format", NullValueHandling = NullValueHandling.Ignore)] public string Format { get; set; } [JsonProperty("schemaVersion", NullValueHandling = NullValueHandling.Ignore)] public int SchemaVersion { get; set; } [JsonProperty("profile", NullValueHandling = NullValueHandling.Ignore)] public CharacterProfile Profile { get; set; } [JsonProperty("lastTombstoneCharacter", NullValueHandling = NullValueHandling.Ignore)] public string LastTombstoneCharacter { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterProfile : CharacterData { [JsonProperty("version", NullValueHandling = NullValueHandling.Ignore)] public int Version { get; set; } [JsonProperty("statCount", NullValueHandling = NullValueHandling.Ignore)] public int StatCount { get; set; } [JsonProperty("statGroups", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterStats> StatGroups { get; set; } [JsonProperty("firstSpawn", NullValueHandling = NullValueHandling.Ignore)] public bool FirstSpawn { get; set; } [JsonProperty("worlds", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterWorld> Worlds { get; set; } [JsonProperty("playerName", NullValueHandling = NullValueHandling.Ignore)] public string PlayerName { get; set; } [JsonProperty("playerId", NullValueHandling = NullValueHandling.Ignore)] public string PlayerId { get; set; } [JsonProperty("startSeed", NullValueHandling = NullValueHandling.Ignore)] public string StartSeed { get; set; } [JsonProperty("usedCheats", NullValueHandling = NullValueHandling.Ignore)] public bool UsedCheats { get; set; } [JsonProperty("dateCreated", NullValueHandling = NullValueHandling.Ignore)] public string DateCreated { get; set; } [JsonProperty("hasPlayerData", NullValueHandling = NullValueHandling.Ignore)] public bool HasPlayerData { get; set; } [JsonProperty("playerData", NullValueHandling = NullValueHandling.Ignore)] public CharacterPlayerData PlayerData { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterWorld : CharacterData { [JsonProperty("worldId", NullValueHandling = NullValueHandling.Ignore)] public string WorldId { get; set; } [JsonProperty("haveCustomSpawnPoint", NullValueHandling = NullValueHandling.Ignore)] public bool HaveCustomSpawnPoint { get; set; } [JsonProperty("spawnPoint", NullValueHandling = NullValueHandling.Ignore)] public CharacterVector SpawnPoint { get; set; } [JsonProperty("haveLogoutPoint", NullValueHandling = NullValueHandling.Ignore)] public bool HaveLogoutPoint { get; set; } [JsonProperty("logoutPoint", NullValueHandling = NullValueHandling.Ignore)] public CharacterVector LogoutPoint { get; set; } [JsonProperty("haveDeathPoint", NullValueHandling = NullValueHandling.Ignore)] public bool HaveDeathPoint { get; set; } [JsonProperty("deathPoint", NullValueHandling = NullValueHandling.Ignore)] public CharacterVector DeathPoint { get; set; } [JsonProperty("homePoint", NullValueHandling = NullValueHandling.Ignore)] public CharacterVector HomePoint { get; set; } [JsonProperty("hasMapData", NullValueHandling = NullValueHandling.Ignore)] public bool HasMapData { get; set; } [JsonProperty("mapData", NullValueHandling = NullValueHandling.Ignore)] public string MapData { get; set; } [JsonProperty("mapPinIds", NullValueHandling = NullValueHandling.Ignore)] public List<string> MapPinIds { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterPlayerData : CharacterData { [JsonProperty("version", NullValueHandling = NullValueHandling.Ignore)] public int Version { get; set; } [JsonProperty("maxHealth", NullValueHandling = NullValueHandling.Ignore)] public float MaxHealth { get; set; } [JsonProperty("health", NullValueHandling = NullValueHandling.Ignore)] public float Health { get; set; } [JsonProperty("maxStamina", NullValueHandling = NullValueHandling.Ignore)] public float MaxStamina { get; set; } [JsonProperty("timeSinceDeath", NullValueHandling = NullValueHandling.Ignore)] public float TimeSinceDeath { get; set; } [JsonProperty("guardianPower", NullValueHandling = NullValueHandling.Ignore)] public string GuardianPower { get; set; } [JsonProperty("guardianPowerCooldown", NullValueHandling = NullValueHandling.Ignore)] public float GuardianPowerCooldown { get; set; } [JsonProperty("inventory", NullValueHandling = NullValueHandling.Ignore)] public CharacterInventory Inventory { get; set; } [JsonProperty("knownRecipes", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterString> KnownRecipes { get; set; } [JsonProperty("knownStations", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterStation> KnownStations { get; set; } [JsonProperty("knownMaterial", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterString> KnownMaterial { get; set; } [JsonProperty("shownTutorials", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterString> ShownTutorials { get; set; } [JsonProperty("uniques", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterString> Uniques { get; set; } [JsonProperty("trophies", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterString> Trophies { get; set; } [JsonProperty("knownBiome", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterString> KnownBiome { get; set; } [JsonProperty("knownTexts", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterText> KnownTexts { get; set; } [JsonProperty("beardItem", NullValueHandling = NullValueHandling.Ignore)] public string BeardItem { get; set; } [JsonProperty("hairItem", NullValueHandling = NullValueHandling.Ignore)] public string HairItem { get; set; } [JsonProperty("skinColor", NullValueHandling = NullValueHandling.Ignore)] public CharacterVector SkinColor { get; set; } [JsonProperty("hairColor", NullValueHandling = NullValueHandling.Ignore)] public CharacterVector HairColor { get; set; } [JsonProperty("modelIndex", NullValueHandling = NullValueHandling.Ignore)] public int ModelIndex { get; set; } [JsonProperty("foods", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterFood> Foods { get; set; } [JsonProperty("skills", NullValueHandling = NullValueHandling.Ignore)] public CharacterSkills Skills { get; set; } [JsonProperty("customData", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterText> CustomData { get; set; } [JsonProperty("stamina", NullValueHandling = NullValueHandling.Ignore)] public float Stamina { get; set; } [JsonProperty("maxEitr", NullValueHandling = NullValueHandling.Ignore)] public float MaxEitr { get; set; } [JsonProperty("eitr", NullValueHandling = NullValueHandling.Ignore)] public float Eitr { get; set; } [JsonProperty("buildUi", NullValueHandling = NullValueHandling.Ignore)] public string BuildUi { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterInventory : CharacterData { [JsonProperty("version", NullValueHandling = NullValueHandling.Ignore)] public int Version { get; set; } [JsonProperty("items", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterItem> Items { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterItem : CharacterData { [JsonProperty("durabilityHundredths", NullValueHandling = NullValueHandling.Ignore)] public int DurabilityHundredths { get; set; } [JsonProperty("slotX", NullValueHandling = NullValueHandling.Ignore)] public byte SlotX { get; set; } [JsonProperty("slotY", NullValueHandling = NullValueHandling.Ignore)] public byte SlotY { get; set; } [JsonProperty("worldLevel", NullValueHandling = NullValueHandling.Ignore)] public byte WorldLevel { get; set; } [JsonProperty("flags", NullValueHandling = NullValueHandling.Ignore)] public byte Flags { get; set; } [JsonProperty("quality", NullValueHandling = NullValueHandling.Ignore)] public ushort? Quality { get; set; } [JsonProperty("quantity", NullValueHandling = NullValueHandling.Ignore)] public ushort? Quantity { get; set; } [JsonProperty("variant", NullValueHandling = NullValueHandling.Ignore)] public int? Variant { get; set; } [JsonProperty("crafterId", NullValueHandling = NullValueHandling.Ignore)] public string CrafterId { get; set; } [JsonProperty("crafterName", NullValueHandling = NullValueHandling.Ignore)] public string CrafterName { get; set; } [JsonProperty("prefabHash", NullValueHandling = NullValueHandling.Ignore)] public int? PrefabHash { get; set; } [JsonProperty("customDataCount", NullValueHandling = NullValueHandling.Ignore)] public int? CustomDataCount { get; set; } [JsonProperty("customData", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterText> CustomData { get; set; } [JsonProperty("extraFlags", NullValueHandling = NullValueHandling.Ignore)] public byte ExtraFlags { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterVector : CharacterData { [JsonProperty("x", Required = Required.Always)] public float X { get; set; } [JsonProperty("y", Required = Required.Always)] public float Y { get; set; } [JsonProperty("z", Required = Required.Always)] public float Z { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterString : CharacterData { [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] public string Value { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterText : CharacterData { [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] public string Key { get; set; } [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] public string Value { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterStation : CharacterData { [JsonProperty("key", Required = Required.Always)] public string Key { get; set; } [JsonProperty("value", Required = Required.Always)] public int Value { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterFood : CharacterData { [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] public string Name { get; set; } [JsonProperty("time", NullValueHandling = NullValueHandling.Ignore)] public float Time { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterSkills : CharacterData { [JsonProperty("version", NullValueHandling = NullValueHandling.Ignore)] public int Version { get; set; } [JsonProperty("values", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterSkill> Values { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterSkill : CharacterData { [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] public int Type { get; set; } [JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)] public float Level { get; set; } [JsonProperty("accumulator", NullValueHandling = NullValueHandling.Ignore)] public float Accumulator { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterStats : CharacterData { [JsonProperty("values", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterFloat> Values { get; set; } [JsonProperty("knownWorlds", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterFloatPair> KnownWorlds { get; set; } [JsonProperty("knownWorldKeys", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterFloatPair> KnownWorldKeys { get; set; } [JsonProperty("knownCommands", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterFloatPair> KnownCommands { get; set; } [JsonProperty("enemyStats", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterEnemyStats> EnemyStats { get; set; } [JsonProperty("itemPickupStats", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterFloatPair> ItemPickupStats { get; set; } [JsonProperty("itemCraftStats", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterFloatPair> ItemCraftStats { get; set; } [JsonProperty("pickableStats", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterFloatPair> PickableStats { get; set; } [JsonProperty("foodEatenStats", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterFloatPair> FoodEatenStats { get; set; } [JsonProperty("piecesPlacedStats", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterFloatPair> PiecesPlacedStats { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterFloat : CharacterData { [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] public float Value { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterFloatPair : CharacterData { [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] public string Key { get; set; } [JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)] public float Value { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterEnemyStats : CharacterData { [JsonProperty("values", NullValueHandling = NullValueHandling.Ignore)] public List<CharacterFloatPair> Values { get; set; } } internal abstract class CharacterData { [JsonExtensionData] public IDictionary<string, JToken> AdditionalData { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterAppearanceData : CharacterData { [JsonProperty("modelIndex", Required = Required.Always)] public int ModelIndex { get; set; } [JsonProperty("beardItem", Required = Required.Always)] public string BeardItem { get; set; } [JsonProperty("hairItem", Required = Required.Always)] public string HairItem { get; set; } [JsonProperty("skinColor", Required = Required.Always)] public CharacterVector SkinColor { get; set; } [JsonProperty("hairColor", Required = Required.Always)] public CharacterVector HairColor { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CharacterDiscoveries : CharacterData { [JsonProperty("knownRecipes", Required = Required.Always)] public List<string> KnownRecipes { get; set; } [JsonProperty("knownMaterial", Required = Required.Always)] public List<string> KnownMaterial { get; set; } [JsonProperty("knownStations", Required = Required.Always)] public List<CharacterStation> KnownStations { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal class MapPinData { [JsonProperty("name")] public string Name { get; set; } [JsonProperty("x")] public float? X { get; set; } [JsonProperty("y")] public float? Y { get; set; } [JsonProperty("z")] public float? Z { get; set; } [JsonProperty("type")] public int? Type { get; set; } [JsonProperty("checked")] public bool? Checked { get; set; } internal bool SameAs(MapPinData other) { if (other != null && Name == other.Name && X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z) && Type == other.Type) { return Checked == other.Checked; } return false; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class MapPinRequest : MapPinData { [JsonProperty("request", Required = Required.Always)] public string Request { get; set; } [JsonProperty("kind", Required = Required.Always)] public MapPinOperation Kind { get; set; } [JsonProperty("id")] public string Id { get; set; } } internal enum MapPinOperation { [EnumMember(Value = "create")] Create, [EnumMember(Value = "update")] Update, [EnumMember(Value = "delete")] Delete } [JsonObject(MemberSerialization.OptIn)] internal abstract class WorldAction { [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] public string Id { get; set; } [JsonProperty("kind")] public abstract string Kind { get; } } [JsonObject(MemberSerialization.OptIn)] internal abstract class TargetAction : WorldAction { [JsonProperty("user", Required = Required.Always)] public string User { get; set; } [JsonProperty("object", Required = Required.Always)] public uint Object { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class PickupAction : TargetAction { public override string Kind => "pickup"; [JsonProperty("automatic", NullValueHandling = NullValueHandling.Ignore)] public bool? Automatic { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class RepairAction : TargetAction { public override string Kind => "repair"; } [JsonObject(MemberSerialization.OptIn)] internal sealed class ContainerAction : TargetAction { public override string Kind => "container"; [JsonProperty("operation", Required = Required.Always)] public ContainerOperation Operation { get; set; } [JsonProperty("deposit", NullValueHandling = NullValueHandling.Ignore)] public bool? Deposit { get; set; } [JsonProperty("x", NullValueHandling = NullValueHandling.Ignore)] public int? X { get; set; } [JsonProperty("y", NullValueHandling = NullValueHandling.Ignore)] public int? Y { get; set; } [JsonProperty("amount", NullValueHandling = NullValueHandling.Ignore)] public int? Amount { get; set; } [JsonProperty("prefab", NullValueHandling = NullValueHandling.Ignore)] public int? Prefab { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class TradeAction : TargetAction { public override string Kind => "trade"; [JsonProperty("sell", NullValueHandling = NullValueHandling.Ignore)] public bool? Sell { get; set; } [JsonProperty("offer", NullValueHandling = NullValueHandling.Ignore)] public int? Offer { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class InteractAction : TargetAction { public override string Kind => "interact"; [JsonProperty("component", Required = Required.Always)] public int Component { get; set; } [JsonProperty("alt", NullValueHandling = NullValueHandling.Ignore)] public bool? Alt { get; set; } [JsonProperty("useItem", NullValueHandling = NullValueHandling.Ignore)] public bool? UseItem { get; set; } [JsonProperty("x", NullValueHandling = NullValueHandling.Ignore)] public int? X { get; set; } [JsonProperty("y", NullValueHandling = NullValueHandling.Ignore)] public int? Y { get; set; } [JsonProperty("prefab", NullValueHandling = NullValueHandling.Ignore)] public int? Prefab { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class CraftAction : WorldAction { public override string Kind => "craft"; [JsonProperty("prefab", Required = Required.Always)] public int Prefab { get; set; } [JsonProperty("count", NullValueHandling = NullValueHandling.Ignore)] public int? Count { get; set; } [JsonProperty("variant", NullValueHandling = NullValueHandling.Ignore)] public int? Variant { get; set; } [JsonProperty("upgrade", NullValueHandling = NullValueHandling.Ignore)] public bool? Upgrade { get; set; } [JsonProperty("x", NullValueHandling = NullValueHandling.Ignore)] public int? X { get; set; } [JsonProperty("y", NullValueHandling = NullValueHandling.Ignore)] public int? Y { get; set; } [JsonProperty("quality", NullValueHandling = NullValueHandling.Ignore)] public int? Quality { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class EatAction : WorldAction { public override string Kind => "eat"; [JsonProperty("prefab", Required = Required.Always)] public int Prefab { get; set; } [JsonProperty("quality", Required = Required.Always)] public int Quality { get; set; } [JsonProperty("x", Required = Required.Always)] public int X { get; set; } [JsonProperty("y", Required = Required.Always)] public int Y { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class DropAction : WorldAction { public override string Kind => "drop"; [JsonProperty("prefab", Required = Required.Always)] public int Prefab { get; set; } [JsonProperty("amount", Required = Required.Always)] public int Amount { get; set; } [JsonProperty("quality", Required = Required.Always)] public int Quality { get; set; } [JsonProperty("variant", Required = Required.Always)] public int Variant { get; set; } [JsonProperty("x", Required = Required.Always)] public int X { get; set; } [JsonProperty("y", Required = Required.Always)] public int Y { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class RearrangeAction : WorldAction { public override string Kind => "rearrange"; [JsonProperty("x", Required = Required.Always)] public int X { get; set; } [JsonProperty("y", Required = Required.Always)] public int Y { get; set; } [JsonProperty("toX", Required = Required.Always)] public int ToX { get; set; } [JsonProperty("toY", Required = Required.Always)] public int ToY { get; set; } [JsonProperty("amount", Required = Required.Always)] public int Amount { get; set; } [JsonProperty("prefab", Required = Required.Always)] public int Prefab { get; set; } [JsonProperty("quality", Required = Required.Always)] public int Quality { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class RemovePieceAction : TargetAction { public override string Kind => "removePiece"; } [JsonObject(MemberSerialization.OptIn)] internal sealed class BuildAction : WorldAction { public override string Kind => "build"; [JsonProperty("ray", Required = Required.Always)] public BuildRay Ray { get; set; } [JsonProperty("prefab", Required = Required.Always)] public int Prefab { get; set; } [JsonProperty("snap", Required = Required.Always)] public int Snap { get; set; } [JsonProperty("alt", Required = Required.Always)] public bool Alt { get; set; } [JsonProperty("yaw", Required = Required.Always)] public float Yaw { get; set; } } [JsonObject(MemberSerialization.OptIn)] internal sealed class TombstoneAction : WorldAction { public override string Kind => "tombstone"; } internal enum ContainerOperation { [EnumMember(Value = "open")] Open, [EnumMember(Value = "item")] Item, [EnumMember(Value = "stack")] Stack, [EnumMember(Value = "all")] All } } namespace Landoria.ServerShield.Client { [HarmonyPatch(typeof(Game), "UpdateRespawn")] internal static class CharacterLoad { internal static PlayerProfile Profile; internal static byte[] LoadingPayload; private static PlayerProfile loadingProfile; private static string requestId; private static ZRpc connection; private static float requestedAt; internal static bool Rejected; private static bool Prefix(ref PlayerProfile ___m_playerProfile, ref bool ___m_queuedIntro, ref bool ___m_inIntro) { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || instance.IsServer()) { return true; } ZNetPeer serverPeer = instance.GetServerPeer(); if (serverPeer == null) { return false; } if (!instance.IsCurrentServerDedicated()) { return true; } if (connection != serverPeer.m_rpc) { Reset(serverPeer.m_rpc); } if (Profile != null) { ApplyProfile(ref ___m_playerProfile, ref ___m_queuedIntro, ref ___m_inIntro); return true; } if (!Rejected) { Request(); } return false; } private static void ApplyProfile(ref PlayerProfile profile, ref bool queuedIntro, ref bool inIntro) { if (profile != Profile) { profile = Profile; queuedIntro = false; inIntro = false; } } private static void Request() { if (requestId == null) { requestId = Guid.NewGuid().ToString("D"); requestedAt = Time.realtimeSinceStartup; NetworkLog.Log.LogDebug("Requesting the server character profile."); try { PlayerProfile playerProfile = Game.instance.GetPlayerProfile(); bool flag = playerProfile.m_firstSpawn && playerProfile.m_playerStats.All((PlayerStats stats) => stats.m_knownWorlds.Count == 0); connection.Invoke("Landoria.ServerShield.Admission", new object[3] { requestId, InitialAppearance.Read(playerProfile), flag }); return; } catch (Exception message) { NetworkLog.Log.LogError(message); Game.instance.Logout(false, true); return; } } if (Time.realtimeSinceStartup - requestedAt > 30f) { NetworkLog.Log.LogError("Server character load timed out; no local character was used."); Game.instance.Logout(false, true); } } internal static bool IsPending(ZRpc rpc, string id) { if (!Rejected && rpc == connection && id == requestId && Profile == null) { ZNet instance = ZNet.instance; return rpc == ((instance != null) ? instance.GetServerRPC() : null); } return false; } internal static void Receive(ZRpc rpc, string id, ZPackage package) { if (!IsPending(rpc, id)) { return; } try { LoadProfile(package); } catch (Exception message) { NetworkLog.Log.LogError(message); Game.instance.Logout(false, true); } finally { loadingProfile = null; LoadingPayload = null; } } private static void LoadProfile(ZPackage package) { //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_004b: Expected O, but got Unknown byte[] array = package.ReadByteArray(); FchJsonConverter.ToJson(array); NetworkLog.Log.LogDebug($"Character checksum and schema validated: bytes={array.Length}."); PlayerProfile playerProfile = Game.instance.GetPlayerProfile(); loadingProfile = new PlayerProfile(playerProfile.m_filename, playerProfile.m_fileSource); using (BinaryReader binaryReader = new BinaryReader(new MemoryStream(array))) { LoadingPayload = binaryReader.ReadBytes(binaryReader.ReadInt32()); } if (!loadingProfile.Load()) { throw new InvalidDataException("Server character could not be loaded."); } Profile = loadingProfile; NetworkLog.Log.LogInfo("Server character received; spawn can proceed."); } internal static bool IsLoading(PlayerProfile profile) { return profile == loadingProfile; } internal static void Reset(ZRpc rpc = null) { if (connection != null || Profile != null || requestId != null) { NetworkLog.Log.LogDebug("Clearing the client character session."); } ClientMap.Reset(); PlayerHealth.Reset(); PlayerCreation.Reset(); Profile = null; loadingProfile = null; LoadingPayload = null; requestId = null; connection = rpc; Rejected = false; } } [HarmonyPatch(typeof(PlayerProfile), "LoadPlayerDataFromDisk")] internal static class ServerProfileDataPatch { private static bool Prefix(PlayerProfile __instance, ref ZPackage __result) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown if (!CharacterLoad.IsLoading(__instance)) { return true; } __result = new ZPackage(CharacterLoad.LoadingPayload); return false; } } [HarmonyPatch(typeof(Game), "Update")] internal static class CharacterIntroPatch { private static void Prefix(ref bool ___m_queuedIntro, ref bool ___m_inIntro) { if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer() && ZNet.instance.IsCurrentServerDedicated()) { ___m_queuedIntro = false; ___m_inIntro = false; } } } [HarmonyPatch(typeof(Game), "Awake")] internal static class CharacterSessionPatch { private static void Prefix() { CharacterLoad.Reset(); } } internal static class CharacterRejection { internal static void Register(ZRpc rpc) { ConnectionFailureMessages.Clear("Landoria.ServerShield.Client"); rpc.Register<string, string>("Landoria.ServerShield.Rejection", (Action<ZRpc, string, string>)Receive); } private static void Receive(ZRpc rpc, string requestId, string message) { if (!CharacterLoad.IsPending(rpc, requestId)) { return; } CharacterLoad.Rejected = true; ConnectionFailureMessages.Push("Landoria.ServerShield.Client", message); try { rpc.Invoke("Landoria.ServerShield.RejectionAck", new object[1] { requestId }); } catch (Exception message2) { NetworkLog.Log.LogError(message2); } } } [HarmonyPatch] internal static class ClientMap { private static ZPackage snapshot; private static readonly Queue<Tuple<Vector3, float>> exploration = new Queue<Tuple<Vector3, float>>(); internal static bool Ready; private static bool applying; internal static bool Active { get { if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) { return ZNet.instance.IsCurrentServerDedicated(); } return false; } } internal static void Reset() { snapshot = null; exploration.Clear(); Ready = false; ClientMapPins.Reset(); } internal static void Receive(ZRpc rpc, ZPackage package) { if (Active && rpc == ZNet.instance.GetServerRPC()) { snapshot = package; exploration.Clear(); Ready = false; } } internal static void ReceiveExplore(ZRpc rpc, Vector3 position, float radius) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (Active && rpc == ZNet.instance.GetServerRPC()) { exploration.Enqueue(Tuple.Create<Vector3, float>(position, radius)); } } [HarmonyPostfix] [HarmonyPatch(typeof(Minimap), "Update")] private static void Update(Minimap __instance, bool ___m_hasGenerated, List<PinData> ___m_pins) { //IL_00be: Unknown result type (might be due to invalid IL or missing references) if (!Active || !___m_hasGenerated || CharacterLoad.Profile == null) { return; } try { applying = true; if (snapshot != null) { byte[] data = snapshot.ReadByteArray(); int num = snapshot.ReadInt(); if (num < 0 || num > 10000) { throw new InvalidOperationException("Invalid server pin count."); } List<string> list = new List<string>(); for (int i = 0; i < num; i++) { list.Add(snapshot.ReadString()); } Apply(__instance, data); ClientMapPins.Bind(___m_pins, list); snapshot = null; Ready = true; NetworkLog.Log.LogInfo($"Restored server map and {num} pins."); } if (Ready) { while (exploration.Count > 0) { Tuple<Vector3, float> tuple = exploration.Dequeue(); Explore(__instance, tuple.Item1, tuple.Item2); } ClientMapPins.Update(___m_pins); } } catch (Exception message) { NetworkLog.Log.LogError(message); snapshot = null; Ready = false; exploration.Clear(); } finally { applying = false; } } [HarmonyPrefix] [HarmonyPatch(typeof(Minimap), "LoadMapData")] private static bool LocalLoad() { return !Active; } [HarmonyPrefix] [HarmonyPatch(typeof(Minimap), "SaveMapData")] private static bool LocalSave() { return !Active; } [HarmonyPrefix] [HarmonyPatch(typeof(Minimap), "Explore", new Type[] { typeof(int), typeof(int) })] private static bool LocalExploration() { if (Active) { return applying; } return true; } [HarmonyPrefix] [HarmonyPatch(typeof(Minimap), "ExploreOthers")] private static bool SharedExploration() { if (Active) { return applying; } return true; } [HarmonyPrefix] [HarmonyPatch(typeof(Minimap), "AddSharedMapData")] private static bool SharedImport() { return !Active; } [HarmonyPrefix] [HarmonyPatch(typeof(Minimap), "UpdateExplore")] private static bool AutoExplore() { return !Active; } [HarmonyPrefix] [HarmonyPatch(typeof(Minimap), "SetMapData")] private static bool LocalMapReplacement() { if (Active) { return applying; } return true; } [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(Minimap), "SetMapData")] private static void Apply(Minimap instance, byte[] data) { throw new NotImplementedException(); } [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(Minimap), "Explore", new Type[] { typeof(Vector3), typeof(float) })] private static void Explore(Minimap instance, Vector3 position, float radius) { throw new NotImplementedException(); } } internal static class ClientMapPins { private sealed class Pin { internal PinData Visual; internal string Id; internal MapPinData Saved; } private static readonly List<Pin> pins = new List<Pin>(); private static Pin pendingPin; private static MapPinData pendingData; private static string pendingId; private static MapPinOperation operation; internal static void Reset() { pins.Clear(); pendingPin = null; pendingData = null; pendingId = null; } internal static void Bind(List<PinData> visuals, List<string> ids) { Reset(); List<PinData> list = visuals.Where((PinData pin) => pin.m_save).ToList(); if (list.Count != ids.Count) { throw new InvalidOperationException("Server pins do not match the map snapshot."); } for (int num = 0; num < list.Count; num++) { pins.Add(new Pin { Visual = list[num], Id = ids[num], Saved = Data(list[num]) }); } } internal static void Update(List<PinData> visuals) { if (pendingId != null) { return; } foreach (Pin pin in pins) { if (!visuals.Contains(pin.Visual)) { Send(pin, MapPinOperation.Delete, pin.Saved); return; } MapPinData mapPinData = Data(pin.Visual); if (!mapPinData.SameAs(pin.Saved)) { Send(pin, MapPinOperation.Update, mapPinData); return; } } PinData val = ((IEnumerable<PinData>)visuals).FirstOrDefault((Func<PinData, bool>)((PinData pin) => pin.m_save && !pins.Any((Pin known) => known.Visual == pin))); if (val != null) { Send(new Pin { Visual = val }, MapPinOperation.Create, Data(val)); } } private static void Send(Pin pin, MapPinOperation kind, MapPinData data) { ZRpc serverRPC = ZNet.instance.GetServerRPC(); if (serverRPC == null || !serverRPC.IsConnected()) { return; } MapPinRequest mapPinRequest = new MapPinRequest { Name = data.Name, X = data.X, Y = data.Y, Z = data.Z, Type = data.Type, Checked = data.Checked }; pendingId = Guid.NewGuid().ToString("D"); pendingPin = pin; pendingData = data; operation = kind; mapPinRequest.Request = pendingId; mapPinRequest.Kind = kind; mapPinRequest.Id = pin.Id; try { serverRPC.Invoke("Landoria.ServerShield.MapPinRequest", new object[1] { WireJson.Write(mapPinRequest) }); } catch (Exception message) { NetworkLog.Log.LogError(message); pendingId = null; } } internal static void Receive(ZRpc rpc, string request, bool success, string result) { if (!ClientMap.Active || rpc != ZNet.instance.GetServerRPC() || request != pendingId || pendingPin == null) { return; } if (!success) { ClientMap.Ready = false; MessageHud instance = MessageHud.instance; if (instance != null) { instance.ShowMessage((MessageType)2, result, 0, (Sprite)null, false, true); } } else if (operation == MapPinOperation.Delete) { pins.Remove(pendingPin); } else { pendingPin.Id = result; pendingPin.Saved = pendingData; if (operation == MapPinOperation.Create) { pins.Add(pendingPin); } } pendingId = null; pendingPin = null; pendingData = null; } private static MapPinData Data(PinData pin) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected I4, but got Unknown return new MapPinData { Name = (pin.m_name ?? ""), X = pin.m_pos.x, Y = pin.m_pos.y, Z = pin.m_pos.z, Type = (int)pin.m_type, Checked = pin.m_checked }; } } [HarmonyPatch] internal static class ClientSpawnArea { internal static bool IsReady(Vector3 point, ZDO reserved) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) Vector2s zone = ZoneSystem.GetZone(point); if (!ZoneSystem.instance.IsZoneLoaded(zone)) { return false; } List<ZDO> list = new List<ZDO>(); ZDOMan.instance.FindSectorObjects(zone, new SimulationDistance(1, 0, false), list, (List