diff --git a/MinecraftClient/Mapping/EntityMetadataPalette.cs b/MinecraftClient/Mapping/EntityMetadataPalette.cs index a6999063..56e2d76f 100644 --- a/MinecraftClient/Mapping/EntityMetadataPalette.cs +++ b/MinecraftClient/Mapping/EntityMetadataPalette.cs @@ -22,7 +22,7 @@ public abstract class EntityMetadataPalette <= Protocol18Handler.MC_1_12_2_Version => new EntityMetadataPalette1122(), // 1.9 - 1.12.2 <= Protocol18Handler.MC_1_19_2_Version => new EntityMetadataPalette1191(), // 1.13 - 1.19.2 <= Protocol18Handler.MC_1_19_3_Version => new EntityMetadataPalette1193(), // 1.19.3 - <= Protocol18Handler.MC_1_20_Version => new EntityMetadataPalette1194(), // 1.19.4 - 1.20 + + <= Protocol18Handler.MC_1_20_2_Version => new EntityMetadataPalette1194(), // 1.19.4 - 1.20.2 + _ => throw new NotImplementedException() }; } diff --git a/MinecraftClient/Program.cs b/MinecraftClient/Program.cs index a3919751..445996bd 100644 --- a/MinecraftClient/Program.cs +++ b/MinecraftClient/Program.cs @@ -46,7 +46,7 @@ namespace MinecraftClient public const string Version = MCHighestVersion; public const string MCLowestVersion = "1.4.6"; - public const string MCHighestVersion = "1.20.1"; + public const string MCHighestVersion = "1.20.2"; public static readonly string? BuildInfo = null; private static Tuple? offlinePrompt = null; diff --git a/MinecraftClient/Protocol/Handlers/PacketPalettes/PacketPalette1193.cs b/MinecraftClient/Protocol/Handlers/PacketPalettes/PacketPalette1193.cs index e1cae885..39c4760f 100644 --- a/MinecraftClient/Protocol/Handlers/PacketPalettes/PacketPalette1193.cs +++ b/MinecraftClient/Protocol/Handlers/PacketPalettes/PacketPalette1193.cs @@ -55,7 +55,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes { 0x2E, PacketTypesIn.Ping }, // (Wiki name: Ping (play)) { 0x2F, PacketTypesIn.CraftRecipeResponse }, // (Wiki name: Place Ghost Recipe) { 0x30, PacketTypesIn.PlayerAbilities }, // - { 0x31, PacketTypesIn.ChatMessage }, // Changed in 1.19 (Completely changed) (Wiki name: Player Chat Message) - TODO + { 0x31, PacketTypesIn.ChatMessage }, // Changed in 1.19 (Completely changed) (Wiki name: Player Chat Message) { 0x32, PacketTypesIn.EndCombatEvent }, // (Wiki name: Player Combat End) { 0x33, PacketTypesIn.EnterCombatEvent }, // (Wiki name: Player Combat Enter) { 0x34, PacketTypesIn.DeathCombatEvent }, // (Wiki name: Player Combat Kill) diff --git a/MinecraftClient/Protocol/Handlers/PacketPalettes/PacketPalette1194.cs b/MinecraftClient/Protocol/Handlers/PacketPalettes/PacketPalette1194.cs index 78bffe47..8dd9f994 100644 --- a/MinecraftClient/Protocol/Handlers/PacketPalettes/PacketPalette1194.cs +++ b/MinecraftClient/Protocol/Handlers/PacketPalettes/PacketPalette1194.cs @@ -59,7 +59,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes { 0x32, PacketTypesIn.Ping }, // (Wiki name: Ping (play)) { 0x33, PacketTypesIn.CraftRecipeResponse }, // (Wiki name: Place Ghost Recipe) { 0x34, PacketTypesIn.PlayerAbilities }, // - { 0x35, PacketTypesIn.ChatMessage }, // Changed in 1.19 (Completely changed) (Wiki name: Player Chat Message) - TODO + { 0x35, PacketTypesIn.ChatMessage }, // Changed in 1.19 (Completely changed) (Wiki name: Player Chat Message) { 0x36, PacketTypesIn.EndCombatEvent }, // (Wiki name: Player Combat End) { 0x37, PacketTypesIn.EnterCombatEvent }, // (Wiki name: Player Combat Enter) { 0x38, PacketTypesIn.DeathCombatEvent }, // (Wiki name: Player Combat Kill) diff --git a/MinecraftClient/Protocol/Handlers/PacketPalettes/PacketPalette1202.cs b/MinecraftClient/Protocol/Handlers/PacketPalettes/PacketPalette1202.cs new file mode 100644 index 00000000..63331486 --- /dev/null +++ b/MinecraftClient/Protocol/Handlers/PacketPalettes/PacketPalette1202.cs @@ -0,0 +1,192 @@ +using System.Collections.Generic; + +namespace MinecraftClient.Protocol.Handlers.PacketPalettes +{ + public class PacketPalette1202 : PacketTypePalette + { + private readonly Dictionary typeIn = new() + { + { 0x00, PacketTypesIn.Bundle }, // Added in 1.19.4 + { 0x01, PacketTypesIn.SpawnEntity }, // Changed in 1.19 (Wiki name: Spawn Entity) + { 0x02, PacketTypesIn.SpawnExperienceOrb }, // (Wiki name: Spawn Exeprience Orb) + { 0x03, PacketTypesIn.EntityAnimation }, // (Wiki name: Entity Animation (clientbound)) + { 0x04, PacketTypesIn.Statistics }, // (Wiki name: Award Statistics) + { 0x05, PacketTypesIn.BlockChangedAck }, // Added 1.19 (Wiki name: Acknowledge Block Change) + { 0x06, PacketTypesIn.BlockBreakAnimation }, // (Wiki name: Set Block Destroy Stage) + { 0x07, PacketTypesIn.BlockEntityData }, // + { 0x08, PacketTypesIn.BlockAction }, // + { 0x09, PacketTypesIn.BlockChange }, // (Wiki name: Block Update) + { 0x0A, PacketTypesIn.BossBar }, // + { 0x0B, PacketTypesIn.ServerDifficulty }, // (Wiki name: Change Difficulty) + { 0x0C, PacketTypesIn.ChunkBatchFinished }, // Added in 1.20.2 - TODO + { 0x0D, PacketTypesIn.ChunkBatchStarted }, // Added in 1.20.2 - TODO + { 0x0E, PacketTypesIn.ChunksBiomes }, // Added in 1.19.4 + { 0x0F, PacketTypesIn.ClearTiles }, // + { 0x10, PacketTypesIn.TabComplete }, // (Wiki name: Command Suggestions Response) + { 0x11, PacketTypesIn.DeclareCommands }, // (Wiki name: Commands) + { 0x12, PacketTypesIn.CloseWindow }, // (Wiki name: Close Container (clientbound)) + { 0x13, PacketTypesIn.WindowItems }, // (Wiki name: Set Container Content) + { 0x14, PacketTypesIn.WindowProperty }, // (Wiki name: Set Container Property) + { 0x15, PacketTypesIn.SetSlot }, // (Wiki name: Set Container Slot) + { 0x16, PacketTypesIn.SetCooldown }, // + { 0x17, PacketTypesIn.ChatSuggestions }, // Added in 1.19.1 + { 0x18, PacketTypesIn.PluginMessage }, // (Wiki name: Plugin Message (clientbound)) + { 0x19, PacketTypesIn.DamageEvent }, // Added in 1.19.4 + { 0x1A, PacketTypesIn.HideMessage }, // Added in 1.19.1 + { 0x1B, PacketTypesIn.Disconnect }, // + { 0x1C, PacketTypesIn.ProfilelessChatMessage }, // Added in 1.19.3 (Wiki name: Disguised Chat Message) + { 0x1D, PacketTypesIn.EntityStatus }, // (Wiki name: Entity Event) + { 0x1E, PacketTypesIn.Explosion }, // Changed in 1.19 (Location fields are now Double instead of Float) (Wiki name: Explosion) + { 0x1F, PacketTypesIn.UnloadChunk }, // (Wiki name: Forget Chunk) + { 0x20, PacketTypesIn.ChangeGameState }, // (Wiki name: Game Event) + { 0x21, PacketTypesIn.OpenHorseWindow }, // (Wiki name: Horse Screen Open) + { 0x22, PacketTypesIn.HurtAnimation }, // Added in 1.19.4 + { 0x23, PacketTypesIn.InitializeWorldBorder }, // + { 0x24, PacketTypesIn.KeepAlive }, // + { 0x25, PacketTypesIn.ChunkData }, // + { 0x26, PacketTypesIn.Effect }, // (Wiki name: World Event) + { 0x27, PacketTypesIn.Particle }, // Changed in 1.19 ("Particle Data" field is now "Max Speed", it's the same Float data type) (Wiki name: Level Particle) (No need to be implemented) + { 0x28, PacketTypesIn.UpdateLight }, // (Wiki name: Light Update) + { 0x29, PacketTypesIn.JoinGame }, // Changed in 1.20.2 (Wiki name: Login (play)) - TODO + { 0x2A, PacketTypesIn.MapData }, // (Wiki name: Map Item Data) + { 0x2B, PacketTypesIn.TradeList }, // (Wiki name: Merchant Offers) + { 0x2C, PacketTypesIn.EntityPosition }, // (Wiki name: Move Entity Position) + { 0x2D, PacketTypesIn.EntityPositionAndRotation }, // (Wiki name: Move Entity Position and Rotation) + { 0x2E, PacketTypesIn.EntityRotation }, // (Wiki name: Move Entity Rotation) + { 0x2F, PacketTypesIn.VehicleMove }, // (Wiki name: Move Vehicle) + { 0x30, PacketTypesIn.OpenBook }, // + { 0x31, PacketTypesIn.OpenWindow }, // (Wiki name: Open Screen) + { 0x32, PacketTypesIn.OpenSignEditor }, // + { 0x33, PacketTypesIn.Ping }, // (Wiki name: Ping (play)) + { 0x34, PacketTypesIn.PingResponse }, // Added in 1.20.2 - TODO + { 0x35, PacketTypesIn.CraftRecipeResponse }, // (Wiki name: Place Ghost Recipe) + { 0x36, PacketTypesIn.PlayerAbilities }, // + { 0x37, PacketTypesIn.ChatMessage }, // Changed in 1.19 (Completely changed) (Wiki name: Player Chat Message) + { 0x38, PacketTypesIn.EndCombatEvent }, // (Wiki name: End Combat) + { 0x39, PacketTypesIn.EnterCombatEvent }, // (Wiki name: Enter Combat) + { 0x3A, PacketTypesIn.DeathCombatEvent }, // (Wiki name: Combat Death) + { 0x3B, PacketTypesIn.PlayerRemove }, // Added in 1.19.3 (Not used) + { 0x3C, PacketTypesIn.PlayerInfo }, // Changed in 1.19 (Heavy changes) + { 0x3D, PacketTypesIn.FacePlayer }, // (Wiki name: Player Look At) + { 0x3E, PacketTypesIn.PlayerPositionAndLook }, // (Wiki name: Synchronize Player Position) + { 0x3F, PacketTypesIn.UnlockRecipes }, // (Wiki name: Update Recipe Book) + { 0x40, PacketTypesIn.DestroyEntities }, // (Wiki name: Remove Entites) + { 0x41, PacketTypesIn.RemoveEntityEffect }, // + { 0x42, PacketTypesIn.ResourcePackSend }, // (Wiki name: Resource Pack) + { 0x43, PacketTypesIn.Respawn }, // Changed in 1.20.2 - TODO + { 0x44, PacketTypesIn.EntityHeadLook }, // (Wiki name: Set Head Rotation) + { 0x45, PacketTypesIn.MultiBlockChange }, // (Wiki name: Update Section Blocks) + { 0x46, PacketTypesIn.SelectAdvancementTab }, // + { 0x47, PacketTypesIn.ServerData }, // Added in 1.19 + { 0x48, PacketTypesIn.ActionBar }, // (Wiki name: Set Action Bar Text) + { 0x49, PacketTypesIn.WorldBorderCenter }, // (Wiki name: Set Border Center) + { 0x4A, PacketTypesIn.WorldBorderLerpSize }, // + { 0x4B, PacketTypesIn.WorldBorderSize }, // (Wiki name: Set World Border Size) + { 0x4C, PacketTypesIn.WorldBorderWarningDelay }, // (Wiki name: Set World Border Warning Delay) + { 0x4D, PacketTypesIn.WorldBorderWarningReach }, // (Wiki name: Set Border Warning Distance) + { 0x4E, PacketTypesIn.Camera }, // (Wiki name: Set Camera) + { 0x4F, PacketTypesIn.HeldItemChange }, // (Wiki name: Set Held Item) + { 0x50, PacketTypesIn.UpdateViewPosition }, // (Wiki name: Set Center Chunk) + { 0x51, PacketTypesIn.UpdateViewDistance }, // (Wiki name: Set Render Distance) + { 0x52, PacketTypesIn.SpawnPosition }, // (Wiki name: Set Default Spawn Position) + { 0x53, PacketTypesIn.DisplayScoreboard }, // (Wiki name: Set Display Objective) - TODO + { 0x54, PacketTypesIn.EntityMetadata }, // (Wiki name: Set Entity Metadata) + { 0x55, PacketTypesIn.AttachEntity }, // (Wiki name: Link Entities) + { 0x56, PacketTypesIn.EntityVelocity }, // (Wiki name: Set Entity Velocity) + { 0x57, PacketTypesIn.EntityEquipment }, // (Wiki name: Set Equipment) + { 0x58, PacketTypesIn.SetExperience }, // Changed in 1.20.2 - TODO + { 0x59, PacketTypesIn.UpdateHealth }, // (Wiki name: Set Health) + { 0x5A, PacketTypesIn.ScoreboardObjective }, // (Wiki name: Update Objectives) + { 0x5B, PacketTypesIn.SetPassengers }, // + { 0x5C, PacketTypesIn.Teams }, // (Wiki name: Update Teams) + { 0x5D, PacketTypesIn.UpdateScore }, // (Wiki name: Update Score) + { 0x5E, PacketTypesIn.UpdateSimulationDistance }, // (Wiki name: Set Simulation Distance) + { 0x5F, PacketTypesIn.SetTitleSubTitle }, // (Wiki name: Set Subtitle Test) + { 0x60, PacketTypesIn.TimeUpdate }, // (Wiki name: Set Time) + { 0x61, PacketTypesIn.SetTitleText }, // (Wiki name: Set Title) + { 0x62, PacketTypesIn.SetTitleTime }, // (Wiki name: Set Title Animation Times) + { 0x63, PacketTypesIn.EntitySoundEffect }, // (Wiki name: Sound Entity) + { 0x64, PacketTypesIn.SoundEffect }, // Changed in 1.19 (Added "Seed" field) (Wiki name: Sound Effect) (No need to be implemented) + { 0x65, PacketTypesIn.StartConfiguration }, // Added in 1.20.2 - TODO + { 0x66, PacketTypesIn.StopSound }, // + { 0x67, PacketTypesIn.SystemChat }, // Added in 1.19 (Wiki name: System Chat Message) + { 0x68, PacketTypesIn.PlayerListHeaderAndFooter }, // (Wiki name: Set Tab List Header And Footer) + { 0x69, PacketTypesIn.NBTQueryResponse }, // (Wiki name: Tag Query Response) + { 0x6A, PacketTypesIn.CollectItem }, // (Wiki name: Pickup Item) + { 0x6B, PacketTypesIn.EntityTeleport }, // (Wiki name: Teleport Entity) + { 0x6C, PacketTypesIn.Advancements }, // (Wiki name: Update Advancements) (Unused) + { 0x6D, PacketTypesIn.EntityProperties }, // (Wiki name: Update Attributes) + { 0x6E, PacketTypesIn.EntityEffect }, // Changed in 1.19 (Added "Has Factor Data" and "Factor Codec" fields) (Wiki name: Entity Effect) + { 0x6F, PacketTypesIn.DeclareRecipes }, // (Wiki name: Update Recipes) (Unused) + { 0x70, PacketTypesIn.Tags }, // (Wiki name: Update Tags) + }; + + private readonly Dictionary typeOut = new() + { + { 0x00, PacketTypesOut.TeleportConfirm }, // (Wiki name: Confirm Teleportation) + { 0x01, PacketTypesOut.QueryBlockNBT }, // (Wiki name: Query Block Entity Tag) + { 0x02, PacketTypesOut.SetDifficulty }, // (Wiki name: Change Difficulty) + { 0x03, PacketTypesOut.MessageAcknowledgment }, // Added in 1.19.1 + { 0x04, PacketTypesOut.ChatCommand }, // Added in 1.19 + { 0x05, PacketTypesOut.ChatMessage }, // Changed in 1.19 (Completely changed) (Wiki name: Chat) + { 0x06, PacketTypesOut.PlayerSession }, // Added in 1.19.3 + { 0x07, PacketTypesOut.ChunkBatchReceived }, // Added in 1.20.2 - TODO + { 0x08, PacketTypesOut.ClientStatus }, // (Wiki name: Client Command) + { 0x09, PacketTypesOut.ClientSettings }, // (Wiki name: Client Information) + { 0x0A, PacketTypesOut.TabComplete }, // (Wiki name: Command Suggestions Request) + { 0x0B, PacketTypesOut.AcknowledgeConfiguration }, // Added in 1.20.2 - TODO + { 0x0C, PacketTypesOut.ClickWindowButton }, // (Wiki name: Click Container Button) + { 0x0D, PacketTypesOut.ClickWindow }, // (Wiki name: Click Container) + { 0x0E, PacketTypesOut.CloseWindow }, // (Wiki name: Close Container (serverbound)) + { 0x0F, PacketTypesOut.PluginMessage }, // (Wiki name: Serverbound Plugin Message) + { 0x10, PacketTypesOut.EditBook }, // + { 0x11, PacketTypesOut.EntityNBTRequest }, // (Wiki name: Query Entity Tag) + { 0x12, PacketTypesOut.InteractEntity }, // (Wiki name: Interact) + { 0x13, PacketTypesOut.GenerateStructure }, // (Wiki name: Jigsaw Generate) + { 0x14, PacketTypesOut.KeepAlive }, // (Wiki name: Serverbound Keep Alive (play)) + { 0x15, PacketTypesOut.LockDifficulty }, // + { 0x16, PacketTypesOut.PlayerPosition }, // (Wiki name: Move Player Position) + { 0x17, PacketTypesOut.PlayerPositionAndRotation }, // (Wiki name: Set Player Position and Rotation) + { 0x18, PacketTypesOut.PlayerRotation }, // (Wiki name: Set Player Rotation) + { 0x19, PacketTypesOut.PlayerMovement }, // (Wiki name: Set Player On Ground) + { 0x1A, PacketTypesOut.VehicleMove }, // (Wiki name: Move Vehicle (serverbound)) + { 0x1B, PacketTypesOut.SteerBoat }, // (Wiki name: Paddle Boat) + { 0x1C, PacketTypesOut.PickItem }, // + { 0x1D, PacketTypesOut.PingRequest }, // Added in 1.20.2 - TODO + { 0x1E, PacketTypesOut.CraftRecipeRequest }, // (Wiki name: Place recipe) + { 0x1F, PacketTypesOut.PlayerAbilities }, // + { 0x20, PacketTypesOut.PlayerDigging }, // Changed in 1.19 (Added a "Sequence" field) (Wiki name: Player Action) + { 0x21, PacketTypesOut.EntityAction }, // (Wiki name: Player Command) + { 0x22, PacketTypesOut.SteerVehicle }, // (Wiki name: Player Input) + { 0x23, PacketTypesOut.Pong }, // (Wiki name: Pong (play)) + { 0x24, PacketTypesOut.SetDisplayedRecipe }, // (Wiki name: Recipe Book Change Settings) + { 0x25, PacketTypesOut.SetRecipeBookState }, // (Wiki name: Recipe Book Seen Recipe) + { 0x26, PacketTypesOut.NameItem }, // (Wiki name: Rename Item) + { 0x27, PacketTypesOut.ResourcePackStatus }, // (Wiki name: Resource Pack (serverbound)) + { 0x28, PacketTypesOut.AdvancementTab }, // (Wiki name: Seen Advancements) + { 0x29, PacketTypesOut.SelectTrade }, // + { 0x2A, PacketTypesOut.SetBeaconEffect }, // Changed in 1.19 (Added a "Secondary Effect Present" and "Secondary Effect" fields) (Wiki name: Set Beacon) - (No need to be implemented) + { 0x2B, PacketTypesOut.HeldItemChange }, // (Wiki name: Set Carried Item (serverbound)) + { 0x2C, PacketTypesOut.UpdateCommandBlock }, // (Wiki name: Program Command Block) + { 0x2D, PacketTypesOut.UpdateCommandBlockMinecart }, // (Wiki name: Program Command Block Minecart) + { 0x2E, PacketTypesOut.CreativeInventoryAction }, // (Wiki name: Set Creative Mode Slot) + { 0x2F, PacketTypesOut.UpdateJigsawBlock }, // (Wiki name: Program Jigsaw Block) + { 0x30, PacketTypesOut.UpdateStructureBlock }, // (Wiki name: Program Structure Block) + { 0x31, PacketTypesOut.UpdateSign }, // (Wiki name: Update Sign) + { 0x32, PacketTypesOut.Animation }, // (Wiki name: Swing Arm) + { 0x33, PacketTypesOut.Spectate }, // (Wiki name: Teleport To Entity) + { 0x34, PacketTypesOut.PlayerBlockPlacement }, // Changed in 1.19 (Added a "Sequence" field) (Wiki name: Use Item On) + { 0x35, PacketTypesOut.UseItem }, // Changed in 1.19 (Added a "Sequence" field) (Wiki name: Use Item) + }; + + protected override Dictionary GetListIn() + { + return typeIn; + } + + protected override Dictionary GetListOut() + { + return typeOut; + } + } +} \ No newline at end of file diff --git a/MinecraftClient/Protocol/Handlers/PacketType18Handler.cs b/MinecraftClient/Protocol/Handlers/PacketType18Handler.cs index d1610a62..006c94ae 100644 --- a/MinecraftClient/Protocol/Handlers/PacketType18Handler.cs +++ b/MinecraftClient/Protocol/Handlers/PacketType18Handler.cs @@ -48,7 +48,7 @@ namespace MinecraftClient.Protocol.Handlers { PacketTypePalette p = protocol switch { - > Protocol18Handler.MC_1_20_Version => throw new NotImplementedException(Translations + > Protocol18Handler.MC_1_20_2_Version => throw new NotImplementedException(Translations .exception_palette_packet), <= Protocol18Handler.MC_1_8_Version => new PacketPalette17(), <= Protocol18Handler.MC_1_11_2_Version => new PacketPalette110(), @@ -64,7 +64,8 @@ namespace MinecraftClient.Protocol.Handlers <= Protocol18Handler.MC_1_19_Version => new PacketPalette119(), <= Protocol18Handler.MC_1_19_2_Version => new PacketPalette1192(), <= Protocol18Handler.MC_1_19_3_Version => new PacketPalette1193(), - _ => new PacketPalette1194() + < Protocol18Handler.MC_1_20_2_Version => new PacketPalette1194(), + _ => new PacketPalette1202() }; p.SetForgeEnabled(forgeEnabled); diff --git a/MinecraftClient/Protocol/Handlers/PacketTypesIn.cs b/MinecraftClient/Protocol/Handlers/PacketTypesIn.cs index 3b13f499..61f7e811 100644 --- a/MinecraftClient/Protocol/Handlers/PacketTypesIn.cs +++ b/MinecraftClient/Protocol/Handlers/PacketTypesIn.cs @@ -21,6 +21,8 @@ ChatMessage, // ChatPreview, // Added in 1.19 ChatSuggestions, // Added in 1.19.1 (1.19.2) + ChunkBatchFinished, // Added in 1.20.2 + ChunkBatchStarted, // Added in 1.12.2 ChunksBiomes, // Added in 1.19.4 ChunkData, // ClearTiles, // @@ -73,6 +75,7 @@ OpenWindow, // Particle, // Ping, // + PingResponse, // Added in 1.20.2 PlayerAbilities, // PlayerInfo, // PlayerListHeaderAndFooter, // @@ -105,6 +108,7 @@ SpawnPlayer, // SpawnPosition, // SpawnWeatherEntity, // + StartConfiguration, // Added in 1.20.2 Statistics, // StopSound, // SystemChat, // Added in 1.19 diff --git a/MinecraftClient/Protocol/Handlers/PacketTypesOut.cs b/MinecraftClient/Protocol/Handlers/PacketTypesOut.cs index fd3fe7c9..01a70f79 100644 --- a/MinecraftClient/Protocol/Handlers/PacketTypesOut.cs +++ b/MinecraftClient/Protocol/Handlers/PacketTypesOut.cs @@ -5,11 +5,13 @@ /// public enum PacketTypesOut { + AcknowledgeConfiguration, // Added in 1.20.2 AdvancementTab, // Animation, // ChatCommand, // Added in 1.19 ChatMessage, // ChatPreview, // Added in 1.19 + ChunkBatchReceived, // Added in 1.20.2 ClickWindow, // ClickWindowButton, // ClientSettings, // @@ -29,6 +31,7 @@ MessageAcknowledgment, // Added in 1.19.1 (1.19.2) NameItem, // PickItem, // + PingRequest, // Added in 1.20.2 PlayerAbilities, // PlayerBlockPlacement, // PlayerDigging, // diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index f96affae..cfd0a988 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -24,7 +24,6 @@ using MinecraftClient.Protocol.ProfileKey; using MinecraftClient.Protocol.Session; using MinecraftClient.Proxy; using MinecraftClient.Scripting; -using Newtonsoft.Json; using static MinecraftClient.Settings; namespace MinecraftClient.Protocol.Handlers @@ -68,6 +67,7 @@ namespace MinecraftClient.Protocol.Handlers internal const int MC_1_19_3_Version = 761; internal const int MC_1_19_4_Version = 762; internal const int MC_1_20_Version = 763; + internal const int MC_1_20_2_Version = 764; private int compression_treshold = 0; private int autocomplete_transaction_id = 0; @@ -78,6 +78,7 @@ namespace MinecraftClient.Protocol.Handlers private bool isOnlineMode = false; private readonly BlockingCollection>> packetQueue = new(); private float LastYaw, LastPitch; + private long lastCHunkBatchStartedAt; private bool receiveDeclareCommands = false, receivePlayerInfo = false; private object MessageSigningLock = new(); @@ -138,7 +139,7 @@ namespace MinecraftClient.Protocol.Handlers Block.Palette = protocolVersion switch { // Block palette - > MC_1_20_Version when handler.GetTerrainEnabled() => + > MC_1_20_Version when handler.GetTerrainEnabled() => throw new NotImplementedException(Translations.exception_palette_block), MC_1_20_Version => new Palette120(), MC_1_19_4_Version => new Palette1194(), @@ -155,7 +156,7 @@ namespace MinecraftClient.Protocol.Handlers entityPalette = protocolVersion switch { // Entity palette - > MC_1_20_Version when handler.GetEntityHandlingEnabled() => + > MC_1_20_Version when handler.GetEntityHandlingEnabled() => throw new NotImplementedException(Translations.exception_palette_entity), MC_1_20_Version => new EntityPalette120(), MC_1_19_4_Version => new EntityPalette1194(), @@ -176,7 +177,7 @@ namespace MinecraftClient.Protocol.Handlers itemPalette = protocolVersion switch { // Item palette - > MC_1_20_Version when handler.GetInventoryEnabled() => + > MC_1_20_Version when handler.GetInventoryEnabled() => throw new NotImplementedException(Translations.exception_palette_item), MC_1_20_Version => new ItemPalette120(), MC_1_19_4_Version => new ItemPalette1194(), @@ -402,81 +403,112 @@ namespace MinecraftClient.Protocol.Handlers } handler.OnGameJoined(isOnlineMode); - int playerEntityID = dataTypes.ReadNextInt(packetData); - handler.OnReceivePlayerEntityID(playerEntityID); + var playerEntityId = dataTypes.ReadNextInt(packetData); + handler.OnReceivePlayerEntityID(playerEntityId); if (protocolVersion >= MC_1_16_2_Version) dataTypes.ReadNextBool(packetData); // Is hardcore - 1.16.2 and above - handler.OnGamemodeUpdate(Guid.Empty, dataTypes.ReadNextByte(packetData)); + if (protocolVersion < MC_1_20_2_Version) + handler.OnGamemodeUpdate(Guid.Empty, dataTypes.ReadNextByte(packetData)); if (protocolVersion >= MC_1_16_Version) { - dataTypes.ReadNextByte(packetData); // Previous Gamemode - 1.16 and above - int worldCount = + if (protocolVersion < MC_1_20_2_Version) + dataTypes.ReadNextByte(packetData); // Previous Gamemode - 1.16 - 1.20.2 + + var worldCount = dataTypes.ReadNextVarInt( packetData); // Dimension Count (World Count) - 1.16 and above - for (int i = 0; i < worldCount; i++) + for (var i = 0; i < worldCount; i++) dataTypes.ReadNextString( packetData); // Dimension Names (World Names) - 1.16 and above - var registryCodec = - dataTypes.ReadNextNbt( - packetData); // Registry Codec (Dimension Codec) - 1.16 and above - if (protocolVersion >= MC_1_19_Version) - ChatParser.ReadChatType(registryCodec); - if (handler.GetTerrainEnabled()) - World.StoreDimensionList(registryCodec); - } - // Current dimension - // String: 1.19 and above - // NBT Tag Compound: [1.16.2 to 1.18.2] - // String identifier: 1.16 and 1.16.1 - // varInt: [1.9.1 to 1.15.2] - // byte: below 1.9.1 - string? dimensionTypeName = null; - Dictionary? dimensionType = null; - if (protocolVersion >= MC_1_16_Version) - { - if (protocolVersion >= MC_1_19_Version) - dimensionTypeName = - dataTypes.ReadNextString(packetData); // Dimension Type: Identifier - else if (protocolVersion >= MC_1_16_2_Version) - dimensionType = - dataTypes.ReadNextNbt(packetData); // Dimension Type: NBT Tag Compound - else - dataTypes.ReadNextString(packetData); - currentDimension = 0; - } - else if (protocolVersion >= MC_1_9_1_Version) - currentDimension = dataTypes.ReadNextInt(packetData); - else - currentDimension = (sbyte)dataTypes.ReadNextByte(packetData); - - if (protocolVersion < MC_1_14_Version) - dataTypes.ReadNextByte(packetData); // Difficulty - 1.13 and below - - if (protocolVersion >= MC_1_16_Version) - { - string dimensionName = - dataTypes.ReadNextString( - packetData); // Dimension Name (World Name) - 1.16 and above - if (handler.GetTerrainEnabled()) + if (protocolVersion < MC_1_20_2_Version) { - if (protocolVersion >= MC_1_16_2_Version && protocolVersion <= MC_1_18_2_Version) + var registryCodec = + dataTypes.ReadNextNbt( + packetData); // Registry Codec (Dimension Codec) - 1.16 and above + if (protocolVersion >= MC_1_19_Version) + ChatParser.ReadChatType(registryCodec); + if (handler.GetTerrainEnabled()) + World.StoreDimensionList(registryCodec); + } + } + + if (protocolVersion < MC_1_20_2_Version) + { + // Current dimension + // String: 1.19 and above + // NBT Tag Compound: [1.16.2 to 1.18.2] + // String identifier: 1.16 and 1.16.1 + // varInt: [1.9.1 to 1.15.2] + // byte: below 1.9.1 + string? dimensionTypeName = null; + Dictionary? dimensionType = null; + switch (protocolVersion) + { + case >= MC_1_16_Version: { - World.StoreOneDimension(dimensionName, dimensionType!); - World.SetDimension(dimensionName); + switch (protocolVersion) + { + case >= MC_1_19_Version: + dimensionTypeName = + dataTypes.ReadNextString(packetData); // Dimension Type: Identifier + break; + case >= MC_1_16_2_Version: + dimensionType = + dataTypes.ReadNextNbt( + packetData); // Dimension Type: NBT Tag Compound + break; + default: + dataTypes.ReadNextString(packetData); + break; + } + + currentDimension = 0; + break; } - else if (protocolVersion >= MC_1_19_Version) + case >= MC_1_9_1_Version: + currentDimension = dataTypes.ReadNextInt(packetData); + break; + default: + currentDimension = (sbyte)dataTypes.ReadNextByte(packetData); + break; + } + + switch (protocolVersion) + { + case < MC_1_14_Version: + dataTypes.ReadNextByte(packetData); // Difficulty - 1.13 and below + break; + case >= MC_1_16_Version: { - World.SetDimension(dimensionTypeName!); + var dimensionName = + dataTypes.ReadNextString( + packetData); // Dimension Name (World Name) - 1.16 and above + + if (handler.GetTerrainEnabled()) + { + switch (protocolVersion) + { + case >= MC_1_16_2_Version and <= MC_1_18_2_Version: + World.StoreOneDimension(dimensionName, dimensionType!); + World.SetDimension(dimensionName); + break; + default: + World.SetDimension(dimensionTypeName!); + break; + } + } + + break; } } } - if (protocolVersion >= MC_1_15_Version) - dataTypes.ReadNextLong(packetData); // Hashed world seed - 1.15 and above + if (protocolVersion is >= MC_1_15_Version and < MC_1_20_2_Version) + dataTypes.ReadNextLong(packetData); // Hashed world seed - 1.15 - 1.20.2 if (protocolVersion >= MC_1_16_2_Version) dataTypes.ReadNextVarInt(packetData); // Max Players - 1.16.2 and above else @@ -491,25 +523,52 @@ namespace MinecraftClient.Protocol.Handlers dataTypes.ReadNextBool(packetData); // Reduced debug info - 1.8 and above if (protocolVersion >= MC_1_15_Version) dataTypes.ReadNextBool(packetData); // Enable respawn screen - 1.15 and above - if (protocolVersion >= MC_1_16_Version) - { - dataTypes.ReadNextBool(packetData); // Is Debug - 1.16 and above - dataTypes.ReadNextBool(packetData); // Is Flat - 1.16 and above - } - if (protocolVersion >= MC_1_19_Version) + if (protocolVersion < MC_1_20_2_Version) { - bool hasDeathLocation = dataTypes.ReadNextBool(packetData); // Has death location + if (protocolVersion >= MC_1_16_Version) + { + dataTypes.ReadNextBool(packetData); // Is Debug - 1.16 and 1.20.2 + dataTypes.ReadNextBool(packetData); // Is Flat - 1.16 and 1.20.2 + } + + if (protocolVersion >= MC_1_19_Version) + { + if (dataTypes.ReadNextBool(packetData)) // Has death location + { + dataTypes.SkipNextString(packetData); // Death dimension name: Identifier + dataTypes.ReadNextLocation(packetData); // Death location + } + } + + if (protocolVersion >= MC_1_20_Version) + dataTypes.ReadNextVarInt(packetData); // Portal Cooldown - 1.20 and above + } + else + { + dataTypes.ReadNextBool(packetData); // Do limited crafting + var dimensionTypeName = + dataTypes.ReadNextString(packetData); // Dimension Type: Identifier + dataTypes.ReadNextString(packetData); // Dimension Name (World Name) - 1.16 and above + + if (handler.GetTerrainEnabled()) + World.SetDimension(dimensionTypeName); + + dataTypes.ReadNextLong(packetData); // Hashed world seed + handler.OnGamemodeUpdate(Guid.Empty, dataTypes.ReadNextByte(packetData)); + dataTypes.ReadNextByte(packetData); // Previous Gamemode + dataTypes.ReadNextBool(packetData); // Is Debug + dataTypes.ReadNextBool(packetData); // Is Flat + var hasDeathLocation = dataTypes.ReadNextBool(packetData); // Has death location if (hasDeathLocation) { dataTypes.SkipNextString(packetData); // Death dimension name: Identifier dataTypes.ReadNextLocation(packetData); // Death location } + + dataTypes.ReadNextVarInt(packetData); // Portal Cooldown } - - if (protocolVersion >= MC_1_20_Version) - dataTypes.ReadNextVarInt(packetData); // Portal Cooldown - 1.20 and above - + break; case PacketTypesIn.SpawnPainting: // Just skip, no need for this return true; @@ -780,12 +839,11 @@ namespace MinecraftClient.Protocol.Handlers verifyResult = true; else { - PlayerInfo? player = handler.GetPlayerInfo(senderUUID); + var player = handler.GetPlayerInfo(senderUUID); if (player == null || !player.IsMessageChainLegal()) verifyResult = false; else { - verifyResult = false; verifyResult = player.VerifyMessage(message, senderUUID, player.ChatUuid, index, timestamp, salt, ref messageSignature, previousMessageSignatures); @@ -800,6 +858,19 @@ namespace MinecraftClient.Protocol.Handlers handler.OnTextReceived(chat); } + break; + case PacketTypesIn.ChunkBatchFinished: + dataTypes.ReadNextVarInt(packetData); // Number of chunks received + SendChunkBatchReceived( + // ReSharper disable once PossibleLossOfFraction + 25 / (DateTimeOffset.Now.ToUnixTimeMilliseconds() - lastCHunkBatchStartedAt) + ); + break; + case PacketTypesIn.ChunkBatchStarted: + lastCHunkBatchStartedAt = DateTimeOffset.Now.ToUnixTimeMilliseconds(); + break; + case PacketTypesIn.StartConfiguration: + SendAcknowledgeConfiguration(); break; case PacketTypesIn.HideMessage: byte[] hideMessageSignature = dataTypes.ReadNextByteArray(packetData); @@ -983,13 +1054,14 @@ namespace MinecraftClient.Protocol.Handlers { dataTypes.ReadNextBool(packetData); // Is Debug - 1.16 and above dataTypes.ReadNextBool(packetData); // Is Flat - 1.16 and above - dataTypes.ReadNextBool(packetData); // Copy metadata - 1.16 and above + + if (protocolVersion < MC_1_20_2_Version) + dataTypes.ReadNextBool(packetData); // Copy metadata (Data Kept) - 1.16 - 1.20.2 } if (protocolVersion >= MC_1_19_Version) { - bool hasDeathLocation = dataTypes.ReadNextBool(packetData); // Has death location - if (hasDeathLocation) + if (dataTypes.ReadNextBool(packetData)) // Has death location { dataTypes.ReadNextString(packetData); // Death dimension name: Identifier dataTypes.ReadNextLocation(packetData); // Death location @@ -999,6 +1071,9 @@ namespace MinecraftClient.Protocol.Handlers if (protocolVersion >= MC_1_20_Version) dataTypes.ReadNextVarInt(packetData); // Portal Cooldown + if (protocolVersion >= MC_1_20_2_Version) + dataTypes.ReadNextBool(packetData); // Copy metadata (Data Kept) - 1.20.2 and above + handler.OnRespawn(); break; case PacketTypesIn.PlayerPositionAndLook: @@ -1350,10 +1425,10 @@ namespace MinecraftClient.Protocol.Handlers int sectionX = (int)(chunkSection >> 42); int sectionY = (int)((chunkSection << 44) >> 44); int sectionZ = (int)((chunkSection << 22) >> 42); - - if(protocolVersion < MC_1_20_Version) + + if (protocolVersion < MC_1_20_Version) dataTypes.ReadNextBool(packetData); // Useless boolean (Related to light update) - + int blocksSize = dataTypes.ReadNextVarInt(packetData); for (int i = 0; i < blocksSize; i++) { @@ -2135,7 +2210,7 @@ namespace MinecraftClient.Protocol.Handlers float _yaw = dataTypes.ReadNextByte(packetData) * (1F / 256) * 360; - float _pitch = dataTypes.ReadNextByte(packetData)* (1F / 256) * 360; + float _pitch = dataTypes.ReadNextByte(packetData) * (1F / 256) * 360; bool OnGround = dataTypes.ReadNextBool(packetData); handler.OnEntityRotation(EntityID, _yaw, _pitch, OnGround); @@ -2352,28 +2427,28 @@ namespace MinecraftClient.Protocol.Handlers } break; - + case PacketTypesIn.OpenSignEditor: var signLocation = dataTypes.ReadNextLocation(packetData); var isFrontText = true; - + if (protocolVersion >= MC_1_20_Version) isFrontText = dataTypes.ReadNextBool(packetData); - + // TODO: Use break; - + // Temporarily disabled until I find a fix /*case PacketTypesIn.BlockEntityData: var location_ = dataTypes.ReadNextLocation(packetData); var type_ = dataTypes.ReadNextInt(packetData); var nbt = dataTypes.ReadNextNbt(packetData); var nbtJson = JsonConvert.SerializeObject(nbt["messages"]); - + //log.Info($"BLOCK ENTITY DATA -> {location_.ToString()} [{type_}] -> NBT: {nbtJson}"); - + break;*/ - + default: return false; //Ignored packet } @@ -2382,7 +2457,8 @@ namespace MinecraftClient.Protocol.Handlers } catch (Exception innerException) { - if (innerException is ThreadAbortException || innerException is SocketException || innerException.InnerException is SocketException) + if (innerException is ThreadAbortException || innerException is SocketException || + innerException.InnerException is SocketException) throw; //Thread abort or Connection lost rather than invalid data throw new System.IO.InvalidDataException( string.Format(Translations.exception_packet_process, @@ -2532,17 +2608,29 @@ namespace MinecraftClient.Protocol.Handlers } } - if (protocolVersion >= MC_1_19_2_Version) + var uuid = handler.GetUserUuid(); + switch (protocolVersion) { - Guid uuid = handler.GetUserUuid(); - - if (uuid == Guid.Empty) - fullLoginPacket.AddRange(dataTypes.GetBool(false)); // Has UUID - else + case >= MC_1_19_2_Version and < MC_1_20_2_Version: { - fullLoginPacket.AddRange(dataTypes.GetBool(true)); // Has UUID - fullLoginPacket.AddRange(DataTypes.GetUUID(uuid)); // UUID + if (uuid == Guid.Empty) + fullLoginPacket.AddRange(dataTypes.GetBool(false)); // Has UUID + else + { + fullLoginPacket.AddRange(dataTypes.GetBool(true)); // Has UUID + fullLoginPacket.AddRange(DataTypes.GetUUID(uuid)); // UUID + } + + break; } + case >= MC_1_20_2_Version: + uuid = handler.GetUserUuid(); + + if (uuid == Guid.Empty) + uuid = Guid.NewGuid(); + + fullLoginPacket.AddRange(DataTypes.GetUUID(uuid)); // UUID + break; } SendPacket(0x00, fullLoginPacket); @@ -2570,6 +2658,8 @@ namespace MinecraftClient.Protocol.Handlers log.Info("§8" + Translations.mcc_server_offline); login_phase = false; + SendPacket(0x03, new List()); + if (!pForge.CompleteForgeHandshake()) { log.Error("§8" + Translations.error_forge); @@ -2699,6 +2789,7 @@ namespace MinecraftClient.Protocol.Handlers } } + SendPacket(0x03, new List()); handler.OnLoginSuccess(uuidReceived, userName, playerProperty); login_phase = false; @@ -3891,6 +3982,50 @@ namespace MinecraftClient.Protocol.Handlers } } + public bool SendChunkBatchReceived(float desiredNumberOfChunksPerBatch) + { + try + { + List packet = new(); + packet.AddRange(dataTypes.GetFloat(desiredNumberOfChunksPerBatch)); + SendPacket(PacketTypesOut.ChunkBatchReceived, packet); + return true; + } + catch (SocketException) + { + return false; + } + catch (System.IO.IOException) + { + return false; + } + catch (ObjectDisposedException) + { + return false; + } + } + + public bool SendAcknowledgeConfiguration() + { + try + { + SendPacket(PacketTypesOut.ChunkBatchReceived, new List()); + return true; + } + catch (SocketException) + { + return false; + } + catch (System.IO.IOException) + { + return false; + } + catch (ObjectDisposedException) + { + return false; + } + } + public bool ClickContainerButton(int windowId, int buttonId) { try @@ -3986,7 +4121,8 @@ namespace MinecraftClient.Protocol.Handlers } } - public bool SendUpdateSign(Location sign, string line1, string line2, string line3, string line4, bool isFrontText = true) + public bool SendUpdateSign(Location sign, string line1, string line2, string line3, string line4, + bool isFrontText = true) { try { @@ -4001,7 +4137,7 @@ namespace MinecraftClient.Protocol.Handlers List packet = new(); packet.AddRange(dataTypes.GetLocation(sign)); - if(protocolVersion >= MC_1_20_Version) + if (protocolVersion >= MC_1_20_Version) packet.AddRange(dataTypes.GetBool((isFrontText))); packet.AddRange(dataTypes.GetString(line1)); packet.AddRange(dataTypes.GetString(line2)); @@ -4218,4 +4354,4 @@ namespace MinecraftClient.Protocol.Handlers return salt; } } -} +} \ No newline at end of file diff --git a/MinecraftClient/Protocol/ProtocolHandler.cs b/MinecraftClient/Protocol/ProtocolHandler.cs index de7c104a..86fd8ce7 100644 --- a/MinecraftClient/Protocol/ProtocolHandler.cs +++ b/MinecraftClient/Protocol/ProtocolHandler.cs @@ -41,32 +41,39 @@ namespace MinecraftClient.Protocol if (!String.IsNullOrEmpty(domain) && domain.Any(c => char.IsLetter(c))) { AutoTimeout.Perform(() => - { - try { - ConsoleIO.WriteLine(string.Format(Translations.mcc_resolve, domainVal)); - var lookupClient = new LookupClient(); - var response = lookupClient.Query(new DnsQuestion($"_minecraft._tcp.{domainVal}", QueryType.SRV)); - if (response.HasError != true && response.Answers.SrvRecords().Any()) + try { - //Order SRV records by priority and weight, then randomly - var result = response.Answers.SrvRecords() - .OrderBy(record => record.Priority) - .ThenByDescending(record => record.Weight) - .ThenBy(record => Guid.NewGuid()) - .First(); - string target = result.Target.Value.Trim('.'); - ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.mcc_found, target, result.Port, domainVal)); - domainVal = target; - portVal = result.Port; - foundService = true; + ConsoleIO.WriteLine(string.Format(Translations.mcc_resolve, domainVal)); + var lookupClient = new LookupClient(); + var response = + lookupClient.Query(new DnsQuestion($"_minecraft._tcp.{domainVal}", QueryType.SRV)); + if (response.HasError != true && response.Answers.SrvRecords().Any()) + { + //Order SRV records by priority and weight, then randomly + var result = response.Answers.SrvRecords() + .OrderBy(record => record.Priority) + .ThenByDescending(record => record.Weight) + .ThenBy(record => Guid.NewGuid()) + .First(); + string target = result.Target.Value.Trim('.'); + ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.mcc_found, target, + result.Port, domainVal)); + domainVal = target; + portVal = result.Port; + foundService = true; + } } - } - catch (Exception e) - { - ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.mcc_not_found, domainVal, e.GetType().FullName, e.Message)); - } - }, TimeSpan.FromSeconds(Config.Main.Advanced.ResolveSrvRecords == MainConfigHealper.MainConfig.AdvancedConfig.ResolveSrvRecordType.fast ? 10 : 30)); + catch (Exception e) + { + ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.mcc_not_found, domainVal, + e.GetType().FullName, e.Message)); + } + }, + TimeSpan.FromSeconds(Config.Main.Advanced.ResolveSrvRecords == + MainConfigHealper.MainConfig.AdvancedConfig.ResolveSrvRecordType.fast + ? 10 + : 30)); } domain = domainVal; @@ -81,28 +88,34 @@ namespace MinecraftClient.Protocol /// Server Port to ping /// Will contain protocol version, if ping successful /// TRUE if ping was successful - public static bool GetServerInfo(string serverIP, ushort serverPort, ref int protocolversion, ref ForgeInfo? forgeInfo) + public static bool GetServerInfo(string serverIP, ushort serverPort, ref int protocolversion, + ref ForgeInfo? forgeInfo) { bool success = false; int protocolversionTmp = 0; ForgeInfo? forgeInfoTmp = null; if (AutoTimeout.Perform(() => - { - try - { - if (Protocol18Handler.DoPing(serverIP, serverPort, ref protocolversionTmp, ref forgeInfoTmp) - || Protocol16Handler.DoPing(serverIP, serverPort, ref protocolversionTmp)) { - success = true; - } - else - ConsoleIO.WriteLineFormatted("§8" + Translations.error_unexpect_response, acceptnewlines: true); - } - catch (Exception e) - { - ConsoleIO.WriteLineFormatted(String.Format("§8{0}: {1}", e.GetType().FullName, e.Message)); - } - }, TimeSpan.FromSeconds(Config.Main.Advanced.ResolveSrvRecords == MainConfigHealper.MainConfig.AdvancedConfig.ResolveSrvRecordType.fast ? 10 : 30))) + try + { + if (Protocol18Handler.DoPing(serverIP, serverPort, ref protocolversionTmp, ref forgeInfoTmp) + || Protocol16Handler.DoPing(serverIP, serverPort, ref protocolversionTmp)) + { + success = true; + } + else + ConsoleIO.WriteLineFormatted("§8" + Translations.error_unexpect_response, + acceptnewlines: true); + } + catch (Exception e) + { + ConsoleIO.WriteLineFormatted(String.Format("§8{0}: {1}", e.GetType().FullName, e.Message)); + } + }, + TimeSpan.FromSeconds(Config.Main.Advanced.ResolveSrvRecords == + MainConfigHealper.MainConfig.AdvancedConfig.ResolveSrvRecordType.fast + ? 10 + : 30))) { if (protocolversion != 0 && protocolversion != protocolversionTmp) ConsoleIO.WriteLineFormatted("§8" + Translations.error_version_different, acceptnewlines: true); @@ -127,14 +140,19 @@ namespace MinecraftClient.Protocol /// Protocol version to handle /// Handler with the appropriate callbacks /// - public static IMinecraftCom GetProtocolHandler(TcpClient Client, int ProtocolVersion, ForgeInfo? forgeInfo, IMinecraftComHandler Handler) + public static IMinecraftCom GetProtocolHandler(TcpClient Client, int ProtocolVersion, ForgeInfo? forgeInfo, + IMinecraftComHandler Handler) { int[] supportedVersions_Protocol16 = { 51, 60, 61, 72, 73, 74, 78 }; if (Array.IndexOf(supportedVersions_Protocol16, ProtocolVersion) > -1) return new Protocol16Handler(Client, ProtocolVersion, Handler); - int[] supportedVersions_Protocol18 = { 4, 5, 47, 107, 108, 109, 110, 210, 315, 316, 335, 338, 340, 393, 401, 404, 477, 480, 485, 490, 498, 573, 575, 578, 735, 736, 751, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763 }; + int[] supportedVersions_Protocol18 = + { + 4, 5, 47, 107, 108, 109, 110, 210, 315, 316, 335, 338, 340, 393, 401, 404, 477, 480, 485, 490, 498, 573, + 575, 578, 735, 736, 751, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764 + }; if (Array.IndexOf(supportedVersions_Protocol18, ProtocolVersion) > -1) return new Protocol18Handler(Client, ProtocolVersion, Handler, forgeInfo); @@ -320,6 +338,8 @@ namespace MinecraftClient.Protocol case "1.20": case "1.20.1": return 763; + case "1.20.2": + return 764; default: return 0; } @@ -399,6 +419,7 @@ namespace MinecraftClient.Protocol 761 => "1.19.3", 762 => "1.19.4", 763 => "1.20", + 764 => "1.20.2", _ => "0.0" }; } @@ -423,8 +444,27 @@ namespace MinecraftClient.Protocol return Protocol18Forge.ServerForceForge(protocol); } - public enum LoginResult { OtherError, ServiceUnavailable, SSLError, Success, WrongPassword, AccountMigrated, NotPremium, LoginRequired, InvalidToken, InvalidResponse, NullError, UserCancel }; - public enum AccountType { Mojang, Microsoft }; + public enum LoginResult + { + OtherError, + ServiceUnavailable, + SSLError, + Success, + WrongPassword, + AccountMigrated, + NotPremium, + LoginRequired, + InvalidToken, + InvalidResponse, + NullError, + UserCancel + }; + + public enum AccountType + { + Mojang, + Microsoft + }; /// /// Allows to login to a premium Minecraft account using the Yggdrasil authentication scheme. @@ -463,7 +503,9 @@ namespace MinecraftClient.Protocol try { string result = ""; - string json_request = "{\"agent\": { \"name\": \"Minecraft\", \"version\": 1 }, \"username\": \"" + JsonEncode(user) + "\", \"password\": \"" + JsonEncode(pass) + "\", \"clientToken\": \"" + JsonEncode(session.ClientID) + "\" }"; + string json_request = "{\"agent\": { \"name\": \"Minecraft\", \"version\": 1 }, \"username\": \"" + + JsonEncode(user) + "\", \"password\": \"" + JsonEncode(pass) + + "\", \"clientToken\": \"" + JsonEncode(session.ClientID) + "\" }"; int code = DoHTTPSPost("authserver.mojang.com", "/authenticate", json_request, ref result); if (code == 200) { @@ -481,7 +523,8 @@ namespace MinecraftClient.Protocol { session.ID = loginResponse.Properties["accessToken"].StringValue; session.PlayerID = loginResponse.Properties["selectedProfile"].Properties["id"].StringValue; - session.PlayerName = loginResponse.Properties["selectedProfile"].Properties["name"].StringValue; + session.PlayerName = loginResponse.Properties["selectedProfile"].Properties["name"] + .StringValue; return LoginResult.Success; } else return LoginResult.InvalidResponse; @@ -511,6 +554,7 @@ namespace MinecraftClient.Protocol { ConsoleIO.WriteLineFormatted("§8" + e.ToString()); } + return LoginResult.SSLError; } catch (System.IO.IOException e) @@ -519,6 +563,7 @@ namespace MinecraftClient.Protocol { ConsoleIO.WriteLineFormatted("§8" + e.ToString()); } + if (e.Message.Contains("authentication")) { return LoginResult.SSLError; @@ -531,6 +576,7 @@ namespace MinecraftClient.Protocol { ConsoleIO.WriteLineFormatted("§8" + e.ToString()); } + return LoginResult.OtherError; } } @@ -560,6 +606,7 @@ namespace MinecraftClient.Protocol { ConsoleIO.WriteLineFormatted("§c" + e.StackTrace); } + return LoginResult.WrongPassword; // Might not always be wrong password } } @@ -630,6 +677,7 @@ namespace MinecraftClient.Protocol { ConsoleIO.WriteLineFormatted("§c" + e.StackTrace); } + return LoginResult.WrongPassword; // Might not always be wrong password } } @@ -643,13 +691,15 @@ namespace MinecraftClient.Protocol { var payload = JwtPayloadDecode.GetPayload(session.ID); var json = Json.ParseJson(payload); - var expTimestamp = long.Parse(json.Properties["exp"].StringValue, NumberStyles.Any, CultureInfo.CurrentCulture); + var expTimestamp = long.Parse(json.Properties["exp"].StringValue, NumberStyles.Any, + CultureInfo.CurrentCulture); var now = DateTime.Now; var tokenExp = UnixTimeStampToDateTime(expTimestamp); if (Settings.Config.Logging.DebugMessages) { ConsoleIO.WriteLine("Access token expiration time is " + tokenExp.ToString()); } + if (now < tokenExp) { // Still valid @@ -674,7 +724,10 @@ namespace MinecraftClient.Protocol try { string result = ""; - string json_request = "{ \"accessToken\": \"" + JsonEncode(currentsession.ID) + "\", \"clientToken\": \"" + JsonEncode(currentsession.ClientID) + "\", \"selectedProfile\": { \"id\": \"" + JsonEncode(currentsession.PlayerID) + "\", \"name\": \"" + JsonEncode(currentsession.PlayerName) + "\" } }"; + string json_request = "{ \"accessToken\": \"" + JsonEncode(currentsession.ID) + + "\", \"clientToken\": \"" + JsonEncode(currentsession.ClientID) + + "\", \"selectedProfile\": { \"id\": \"" + JsonEncode(currentsession.PlayerID) + + "\", \"name\": \"" + JsonEncode(currentsession.PlayerName) + "\" } }"; int code = DoHTTPSPost("authserver.mojang.com", "/refresh", json_request, ref result); if (code == 200) { @@ -692,7 +745,8 @@ namespace MinecraftClient.Protocol { session.ID = loginResponse.Properties["accessToken"].StringValue; session.PlayerID = loginResponse.Properties["selectedProfile"].Properties["id"].StringValue; - session.PlayerName = loginResponse.Properties["selectedProfile"].Properties["name"].StringValue; + session.PlayerName = loginResponse.Properties["selectedProfile"].Properties["name"] + .StringValue; return LoginResult.Success; } else return LoginResult.InvalidResponse; @@ -726,11 +780,15 @@ namespace MinecraftClient.Protocol try { string result = ""; - string json_request = "{\"accessToken\":\"" + accesstoken + "\",\"selectedProfile\":\"" + uuid + "\",\"serverId\":\"" + serverhash + "\"}"; + string json_request = "{\"accessToken\":\"" + accesstoken + "\",\"selectedProfile\":\"" + uuid + + "\",\"serverId\":\"" + serverhash + "\"}"; int code = DoHTTPSPost("sessionserver.mojang.com", "/session/minecraft/join", json_request, ref result); return (code >= 200 && code < 300); } - catch { return false; } + catch + { + return false; + } } /// @@ -746,7 +804,8 @@ namespace MinecraftClient.Protocol try { string result = ""; - string cookies = String.Format("sid=token:{0}:{1};user={2};version={3}", accesstoken, uuid, username, Program.MCHighestVersion); + string cookies = String.Format("sid=token:{0}:{1};user={2};version={3}", accesstoken, uuid, username, + Program.MCHighestVersion); DoHTTPSGet("pc.realms.minecraft.net", "/worlds", cookies, ref result); Json.JSONData realmsWorlds = Json.ParseJson(result); if (realmsWorlds.Properties.ContainsKey("servers") @@ -773,6 +832,7 @@ namespace MinecraftClient.Protocol } } } + if (availableWorlds.Count > 0) { ConsoleIO.WriteLine(Translations.mcc_realms_available); @@ -781,7 +841,6 @@ namespace MinecraftClient.Protocol ConsoleIO.WriteLine(Translations.mcc_realms_join); } } - } catch (Exception e) { @@ -791,6 +850,7 @@ namespace MinecraftClient.Protocol ConsoleIO.WriteLineFormatted("§8" + e.StackTrace); } } + return realmsWorldsResult; } @@ -802,13 +862,16 @@ namespace MinecraftClient.Protocol /// Player UUID /// Access token /// Server address (host:port) or empty string if failure - public static string GetRealmsWorldServerAddress(string worldId, string username, string uuid, string accesstoken) + public static string GetRealmsWorldServerAddress(string worldId, string username, string uuid, + string accesstoken) { try { string result = ""; - string cookies = String.Format("sid=token:{0}:{1};user={2};version={3}", accesstoken, uuid, username, Program.MCHighestVersion); - int statusCode = DoHTTPSGet("pc.realms.minecraft.net", "/worlds/v1/" + worldId + "/join/pc", cookies, ref result); + string cookies = String.Format("sid=token:{0}:{1};user={2};version={3}", accesstoken, uuid, username, + Program.MCHighestVersion); + int statusCode = DoHTTPSGet("pc.realms.minecraft.net", "/worlds/v1/" + worldId + "/join/pc", cookies, + ref result); if (statusCode == 200) { Json.JSONData serverAddress = Json.ParseJson(result); @@ -833,6 +896,7 @@ namespace MinecraftClient.Protocol { ConsoleIO.WriteLineFormatted("§8" + e.StackTrace); } + return ""; } } @@ -909,7 +973,8 @@ namespace MinecraftClient.Protocol TcpClient client = ProxyHandler.NewTcpClient(host, 443, true); SslStream stream = new(client.GetStream()); - stream.AuthenticateAsClient(host, null, SslProtocols.Tls12, true); // Enable TLS 1.2. Hotfix for #1780 + stream.AuthenticateAsClient(host, null, SslProtocols.Tls12, + true); // Enable TLS 1.2. Hotfix for #1780 if (Settings.Config.Logging.DebugMessages) foreach (string line in headers) @@ -988,4 +1053,4 @@ namespace MinecraftClient.Protocol return dateTime; } } -} +} \ No newline at end of file