- Introduced a new `ServerStatusInfo` class to encapsulate server status data including MOTD, player counts, and version information.
- Implemented `ServerStatusDisplay` to format and display server status information in both classic and TUI modes.
- Added protocol version upgrade logic in `ProtocolHandler` to determine the highest supported protocol version for multi-version servers.
- Updated translations to support new server status labels and messages.
- Created `ServerStatusPanelBuilder` for TUI to visually represent server status with player information and connection details.
- Updated explosion packet processing to accommodate changes in Minecraft protocol versions, specifically for versions 1.21.2 and 1.20.4.
- Removed obsolete fields such as explosion strength and block records for newer versions, and added support for optional knockback and particle data.
- Enhanced backward compatibility for earlier versions by maintaining existing logic for explosion data retrieval.
- Updated the Container class to include a protocol version parameter for accurate container type mapping.
- Modified the GetContainerType method to account for changes in container types introduced in Minecraft 1.20.4.
- Added new container types, including Crafter, to the ContainerType enum.
- Adjusted ContainerTypeExtensions to reflect the new container mappings and ensure compatibility with the updated protocol.
- Added support for the new world border hit flag in Protocol18 for protocol version 1.21.2.
- Updated SocketWrapper to throw a SocketException if SendDataRAW is called when not connected, improving error handling.
These changes enhance the protocol handling and error management in the Minecraft Console Client.
Adds a MaxChatMessageLength config option under [Main.Advanced] that allows
users to override the protocol-defined maximum chat message length. Default is
0 (auto: 100 for MC 1.10 and below, 256 for MC 1.11+). Some servers like
Hypixel support longer messages on older versions, so this lets users set a
custom limit (e.g. 256 on 1.8.9). Includes a warning about potential kicks
if set incorrectly.
Closes#2947
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/MCCTeam/Minecraft-Console-Client/sessions/39c78e6a-f748-4f41-a905-2f5d27f99eff
- DirectionExtensions.cs: Convert GetOpposite() to switch expression,
use file-scoped namespace, use collection expression for HORIZONTAL
- McClient.cs: Convert InteractType switch to expression, use collection
expressions for array literals
- Protocol18.cs: Replace Array.Empty<byte>() with [], use collection
expressions for byte/int array literals
- DataTypes.cs: Use collection expression for TAG_End byte array
- ChatBot.cs: Use collection expressions for string/char arrays
- Location.cs: Use collection expressions and modernize null check
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/milutinke/Minecraft-Console-Client/sessions/4e9bd25b-22c5-47c2-98f9-6025d927b1d6
Replace '== null' with 'is null' and '!= null' with 'is not null'
for all 25 null comparisons in the file, following modern C# pattern
matching conventions.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace all lock object declarations using 'object' type with the C# 13
System.Threading.Lock type across 12 files. The Lock type provides a
more efficient locking mechanism - when used with lock(), the compiler
automatically uses Lock.EnterScope() instead of Monitor.Enter/Exit.
Also made two previously non-readonly lock fields readonly:
- McClient.DigLock
- Protocol18.MessageSigningLock
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Rewrite Json.cs to use System.Text.Json.Nodes (JsonNode, JsonObject, JsonArray)
- Add JsonNodeExtensions.GetStringValue() for backward-compatible string access
- Update all 14 consumer files to use the new JsonNode API
- Remove ~300 lines of hand-rolled JSON parsing code from 2013
- Replace KeyUtils.EscapeString with delegation to Json.EscapeString
Co-authored-by: milutinke <441903+milutinke@users.noreply.github.com>
Agent-Logs-Url: https://github.com/milutinke/Minecraft-Console-Client/sessions/afcd1b7b-ea23-4a0d-bb46-a90b623406fc
- Protocol18: add MC_26_1_Version constant (775), version-gated palette
routing for blocks/items/entities/metadata, and new TimeUpdate packet
format (WorldClock map replaces dayTime+tickDayTime)
- Protocol18Terrain: read new fluidCount short in chunk sections (26.1+)
- DataTypes: add CatSoundVariant to entity metadata VarInt readers
- ProtocolHandler: add NormalizeSnapshotProtocol() to map RC/snapshot
protocol numbers (e.g. 0x4000012E → 775) to release versions, pass
raw protocol version through for server handshake compatibility
Made-with: Cursor
- Introduced a comprehensive physics engine that replicates Minecraft's movement mechanics, including player input handling, gravity, and collision detection.
- Added classes for player physics, movement input, and collision detection, ensuring accurate simulation of player interactions with the game world.
- Integrated AABB (Axis-Aligned Bounding Box) structures for precise collision detection against blocks.
- Enhanced movement capabilities with support for jumping, sneaking, and sprinting, along with step-up mechanics for navigating terrain.
These changes significantly improve the realism and responsiveness of player movement within the game environment.
Two bugs fixed:
1. EnchantmentsComponent was reading a trailing ShowTooltip boolean that
was removed from the wire format in MC 1.21.5. Created
EnchantmentsComponent1215 and StoredEnchantmentsComponent1215 that
omit the boolean. Used by StructuredComponentsRegistry1215 and 12111.
2. MC 1.21.5+ changed ServerboundContainerClickPacket to use HashedStack
(item holder id + count + hashed component patch map) instead of full
ItemStack for changed slots and carried item. Added GetHashedItemSlot()
in DataTypes.cs and gated SendWindowAction in Protocol18.cs to use it
for 1.21.5+. Since MCC doesn't track component hashes, an empty
HashedPatchMap is sent; the server detects stateId mismatch and resyncs.
Tested: AutoFishing bot successfully catches fish on MC 1.21.11 with
enchanted fishing rods (Lure III + Luck of the Sea III).
Made-with: Cursor
Register protocol 773 for Minecraft 1.21.9 and 1.21.10 (which share the
same protocol as a hotfix release). Update MCHighestVersion to 1.21.10.
Add 49 new item types (copper tools/armor, shelves, copper chests,
copper golem statue variants, oxidized lightning rods, iron chain, etc.),
2 new entity types (CopperGolem, Mannequin), 38 new block materials,
3 new entity metadata serializer types (CopperGolemState,
WeatheringCopperState, ResolvableProfile), and 6 new packet types
(DebugBlockValue, DebugChunkValue, DebugEntityValue, DebugEvent,
GameTestHighlightPos, CodeOfConduct, AcceptCodeOfConduct).
Chain item/block renamed to IronChain in 1.21.9; old enum values
retained for backward compatibility with older palettes.
Made-with: Cursor
1.21.7 and 1.21.8 share protocol 772. The only registry change from
1.21.6 is one new item (music_disc_lava_chicken). All other palettes
(blocks, entities, packets, entity metadata, structured components)
are unchanged and reuse 1.21.6 versions.
Changes:
- Add MC_1_21_7_Version (772) constant
- Add "1.21.7" / "1.21.8" version mappings in ProtocolHandler
- Add MusicDiscLavaChicken to ItemType enum
- Generate ItemPalette1217 (1416 items) for the new item palette
- Update all version upper-bound checks from MC_1_21_6 to MC_1_21_7
- Update MCHighestVersion to "1.21.8"
Made-with: Cursor
- ItemPalette1216: 1415 items (generated from decompiled Items.java)
- EntityPalette1216: 151 entities (HappyGhast at index 56, all after +1)
- Palette1216: block states (DriedGhast 32 states at 13826-13857, all after +32)
- PacketPalette1216: clientbound +3 (Waypoint, ClearDialog, ShowDialog),
serverbound +2 (ChangeGameMode at 0x04 shifting all after, CustomClickAction at end),
config clientbound +2 (ClearDialog, ShowDialog),
config serverbound +1 (CustomClickAction)
- Version routing in Protocol18.cs, PacketType18Handler.cs, EntityMetadataPalette.cs
updated to select 1216 palettes for protocol >= 771
- EntityMetadataPalette reuses 1215 (EntityDataSerializers unchanged)
Made-with: Cursor
1.21.5 changed LastSeenMessages.Update to include a trailing checksum
byte (0 = skip verification). This affects serverbound chat and signed
chat command packets.
Additionally, the clientbound PlayerChat packet now has a globalIndex
VarInt prepended before the sender UUID.
Without these fixes:
- Sending plain chat messages causes DecoderException on the server
- Receiving player chat messages causes Queue empty crash in MCC
Made-with: Cursor
In 1.21.5, two wire format changes in level chunk packets:
1. Heightmaps changed from NBT CompoundTag to map<VarInt, long[]> encoding
2. PalettedContainer data arrays no longer have VarInt length prefix
(uses writeFixedSizeLongArray instead of writeLongArray)
Both changes affect ChunkData (level_chunk_with_light) packet parsing.
Without this fix, MCC crashes with "Queue empty" when processing chunks.
Made-with: Cursor
Add complete protocol 769 support for Minecraft 1.21.4:
- Version constants: Add 769 to supported versions, MC_1_21_4_Version constant,
and version string mappings (including 1.21.3 -> 768 compatibility)
- Item palette: 10 new items (Resin series + Eyeblossom), generated ItemPalette1214
- Entity palette: Remove CreakingTransient (149 entities, down from 150)
- Block palette: 10 new blocks with correct blockstate ID ranges from server data
- Packet palette: Serverbound packet ID reshuffling - PickItem split into
PickItemFromBlock/PickItemFromEntity, new PlayerLoaded packet inserted after
PlayerInput, subsequent IDs shifted accordingly. Clientbound unchanged.
- PlayerLoaded: Send empty PlayerLoaded packet after JoinGame processing (>= 1.21.4)
- EntityMetadata/DataComponents: Reuse 1.20.6 palettes (unchanged registries)
- Update all version guard checks from MC_1_21_2 to MC_1_21_4
Made-with: Cursor
The previous commits added palette files, packet IDs, and structured components
for MC 1.21.2 (protocol 768), but terrain/inventory/entity features were still
disabled at runtime because the version guards in the constructor checked
> MC_1_21_Version (767) instead of > MC_1_21_2_Version (768).
This commit completes the 1.21.2 adaptation with the following changes:
- Update feature-disable guards from > MC_1_21_Version to > MC_1_21_2_Version
so terrain, inventory, and entity handling are enabled for protocol 768
- Update healthField metadata index guard to > MC_1_21_2_Version
- Handle container ID encoding change: byte -> VarInt for 1.21.2+ in both
clientbound reads (CloseWindow, WindowItems, WindowProperty, SetSlot) and
serverbound sends (ClickWindow, CloseWindow)
- Handle EntityTeleport format change: 1.21.2 uses PositionMoveRotation
(pos + delta + float angles) + relative flags bitmask (int) + onGround
- Handle TimeUpdate format change: 1.21.2 appends a tickDayTime boolean
- Add handlers for new 1.21.2 packets: EntityPositionSync, PlayerRotation,
SetCursorItem, SetPlayerInventory, MoveMinecartAlongTrack, and
RecipeBookAdd/Remove/Settings (ignored, MCC doesn't track recipes)
Tested: successful connection to 1.21.2 vanilla server with inventory,
entity tracking, and chat all working correctly.
Made-with: Cursor
- SpawnEntity packet handler now registers non-player entities via OnSpawnEntity
for protocol >= 1.20.2 (previously only players were tracked, causing 'entity near'
to find nothing)
- PlaceBlock gains lookAtBlock option that sends a position/rotation update before the
block placement packet, fixing containers not opening via useblock
- Enchantment registry IDs are now dynamically parsed from server RegistryData
(minecraft:enchantment), fixing incorrect enchantment name display in 1.21
- AttributeModifiersComponent uses base SubComponent type to avoid InvalidCastException
when parsing 1.21-specific attribute subcomponents
Made-with: Cursor
Fix the Explosion packet handler that was truncating reads at the
knockback fields, leaving BlockInteraction, particles, and SoundEvent
bytes unconsumed for 1.20.4+. The old commented-out code had three bugs:
conditional particle read (should always read both small and large),
reading SoundEvent as a plain string (it's a Holder<SoundEvent> encoded
as VarInt id + optional inline DIRECT_STREAM_CODEC), and an incorrect
fixedRange version gate. Verified against decompiled ClientboundExplodePacket
from both 1.20.6 and 1.21.1 — the wire format is identical across versions.
Update LoadDefaultAttributes() fallback to match the 1.21.1 registry
order (31 attributes), adding 9 new entries: burning_time,
explosion_knockback_resistance, mining_efficiency, movement_efficiency,
oxygen_bonus, sneaking_speed, submerged_mining_speed,
sweeping_damage_ratio, and water_movement_efficiency. This fallback is
only used when the server omits the attribute RegistryData packet.
Made-with: Cursor
- Add AttributeSubComponent121 that uses ResourceLocation(string) instead
of UUID+Name, matching the 1.21 attribute modifier wire format change.
Register it in SubComponentRegistry121 via new ReplaceSubComponent method.
- Add ProjectilePower packet handler: reads 1 double (accelerationPower)
for 1.21+, or 3 doubles (xPower/yPower/zPower) for 1.20.6.
- Add CustomReportDetails and ServerLinks packet handlers in both Play
and Configuration phases, consuming all fields to prevent byte offset
errors on 1.21 servers.
Made-with: Cursor
After the previous commit (99ac3d0) moved attribute lookup from a hardcoded
dictionary to the dynamic RegistryData, MCC would crash immediately upon
joining a vanilla 1.20.6 server with:
System.ArgumentException: An item with the same key has already been added.
Key: unknown
Root cause: When KnownDataPacks negotiation tells the server that MCC already
has the "minecraft" data pack, the server skips sending RegistryData for
registries it considers "known" — including minecraft:attribute. This left
the dynamic attribute map empty, so every VarInt attribute ID resolved to
"unknown". The EntityProperties packet often contains multiple attributes
(e.g. armor, max_health, movement_speed), and `keys.Add("unknown", ...)` on
the second "unknown" attribute threw ArgumentException.
Two fixes applied:
1. World.GetAttributeNameById(): When the dynamic attribute map is empty
(server didn't send the registry), automatically load the vanilla 1.20.6
default attribute order (22 entries matching Attributes.java registration
order). This mirrors the pattern used for dimensions where defaults are
loaded when RegistryData is not sent. If a modded server sends a custom
attribute registry, the dynamic map takes precedence.
2. Protocol18.cs EntityProperties handler: Change `keys.Add(propertyKey,
propertyValue2)` to `keys[propertyKey] = propertyValue2` to tolerate
duplicate keys defensively, in case an unknown attribute ID still appears.
Tested: MCC now connects to a vanilla 1.20.6 offline-mode server, stays
online for 6+ minutes with no crashes or disconnections. Verified: chat
messages received, inventory listing (item names/counts correct), entity
detection, TPS query, and health query all work correctly.
Made-with: Cursor
In 1.20.6+, EntityProperties packets reference attributes by VarInt registry
IDs instead of string names. Previously, a hardcoded dictionary of 22 attribute
entries (matching the vanilla 1.20.6 registry) was used to map these IDs back
to names. This works for vanilla servers but would fail silently for modded
servers that add custom attributes — any unknown ID would be reported as
"unknown".
This commit replaces the hardcoded attribute dictionary with dynamic registry
parsing, following the same pattern already used for dimension_type and
chat_type registries:
- World.cs: Add static `attributeIdMap` field, `SetAttributeIdMap()` and
`GetAttributeNameById()` methods for storing/querying attribute names by
their VarInt registry IDs.
- Protocol18.cs (RegistryData handler): When the server sends a
`minecraft:attribute` registry during the Configuration phase, parse all
entries and store the ID→name mapping. The `minecraft:` prefix is stripped
from entry names to match the format used in EntityProperties packets
(e.g. "minecraft:generic.armor" → "generic.armor").
- Protocol18.cs (EntityProperties handler): Remove the hardcoded 22-entry
`attributeDictionary` and use `World.GetAttributeNameById()` instead.
Unknown IDs still fall back to "unknown" for safety.
Also closes issue #4 (Disconnect packet extra boolean) — verified that both
Play and Configuration phase Disconnect handlers already use `ReadNextChat()`
(NBT format since 1.20.4+), matching the 1.20.6 protocol spec. No code
changes needed; updated tracking document to mark as closed.
Made-with: Cursor
The JoinGame and Respawn packet handlers for 1.20.6+ used hardcoded
switch expressions to map dimension type VarInt IDs to names:
0 => overworld, 1 => overworld_caves, 2 => the_end, 3 => the_nether
This only works for vanilla servers with exactly 4 default dimensions.
Modded servers (Forge/Fabric/NeoForge) or servers with custom
datapacks can register additional dimensions with IDs beyond 0-3,
causing the switch to fall through to the default "overworld" for
any non-vanilla dimension. This means players in modded dimensions
would have incorrect world parameters (height, lighting, etc.).
Fix: Replace both hardcoded switch expressions with
World.GetDimensionNameById(), which looks up the VarInt ID in
the dimension ID map populated during the RegistryData phase.
Also fixes two pre-existing issues in the SetDimension dispatch:
- JoinGame (pre-1.20.2 path): The `case < MC_1_20_6_Version` guard
was technically correct within its enclosing `if` block, but
changed to `default` for clarity and future-proofing.
- Respawn: The `case <= MC_1_20_6_Version` guard excluded protocol
versions above 766 (e.g. 1.21 / protocol 767), meaning
SetDimension was never called for those versions. Changed to
`default` so all versions >= 1.19 properly update the dimension.
Made-with: Cursor
Two critical issues in the 1.20.6 configuration phase that could cause
connection instability and packet desync:
1. RegistryData: The handler used an early `break` when it encountered
a registryId other than "minecraft:dimension_type" or
"minecraft:chat_type". This skipped reading the remaining entries
for that registry, leaving unconsumed data in the packet buffer.
Subsequent packet reads would start at the wrong offset, causing
cascading parse failures and eventual disconnection.
Fix: Always read all entries (entryId + hasData + optional NBT)
for every registry, regardless of whether we process it. For
dimension_type entries, if the server sends inline NBT data (i.e.
non-vanilla dimensions from mods/datapacks), parse and store
the dimension directly via World.StoreOneDimension(). Only fall
back to hardcoded defaults when no dimension data was received.
2. KnownDataPacks: The client echoed back ALL packs the server
listed, including non-vanilla ones. This told the server "I have
these packs cached" when the client actually did not, so the
server would skip sending full registry data for those packs.
The result: incomplete registries for modded/datapack content.
Fix: Filter the response to only include packs with the
"minecraft" namespace. Non-vanilla packs are omitted, forcing
the server to send their full registry data inline.
Also adds supporting methods to World.cs:
- SetDimensionIdMap(): Store VarInt ID -> dimension name mapping
from RegistryData entries (needed by JoinGame/Respawn)
- GetDimensionNameById(): Look up dimension name by numeric ID
- HasAnyDimension(): Check if any dimensions were loaded from
server-provided data
Made-with: Cursor