The 1.20.6 update for Minestom comes (as usual) with some breaking changes both from the protocol and api improvements for the library. The major changes are as follows:
- Hephaistos removed in favor of Adventure NBT.
- Item components
- Pathfinding
- Dynamic registry improvements
The Inventory Rework PR was previously part of the 1.20.5 branch. It is in the middle of a rework, and is not quite ready for this version. We are still planning to include it in a later version (most likely 1.21.1). If you already updated and have to revert, sorry for the trouble!
We are now using adventure-nbt as the NBT library internally. As a nice side effect, Minestom does not ship with the Kotlin standard library anymore :). In many cases this change should not affect existing codebases using the Tag
api, which is unchanged. A brief overview of the api is provided below:
// Like Hephaistos, all adventure-nbt types are immutable.
// The basic primitive is BinaryTag, as opposed to the NBT type in Hephaistos
// The basic types are all constructed with a similarly named static factory function.
ByteBinaryTag myByte = ByteBinaryTag.byteBinaryTag((byte) 2);
StringBinaryTag myString = StringBinaryTag.stringBinaryTag("Hello, Adventure!!");
IntArrayBinaryTag myIntArray = IntArrayBinaryTag.intArrayBinaryTag(new int[]{1, 2, 3});
// Compounds can be constructed either with a factory function or builder
CompoundBinaryTag myCompound = CompoundBinaryTag.from(Map.of("key", myString));
CompoundBinaryTag myCompound = CompoundBinaryTag.builder()
.putString("key", "value")
.build();
// Lists can be constructed similarly
ListBinaryTag myList = ListBinaryTag.from(List.of(myString));
ListBinaryTag myList = ListBinaryTag.builder(BinaryTagTypes.STRING)
.add(myString)
.build();
// In the builder example, passing the list type is optional and will be inferred otherwise.
Serialization in adventure-nbt currently only supports serialization to and from compounds (known issues, should be fixed in a future version). Minestom provides a small api on top to handle extra cases. This api will be removed in the future when adventure-nbt has proper support.
// Binary
BinaryTagReader reader = new BinaryTagReader(someDataInput);
BinaryTag tag = reader.readNameless(); // throws IOException
Map.Entry<String, BinaryTag> namedTag = reader.readNamed(); // throws IOException
BinaryTagWriter writer = new BinaryTagWriter(someDataOutput);
writer.writeNameless(IntBinaryTag.intBinaryTag(1)); // throws IOException
writer.writeNamed(Map.entry("key", IntBinaryTag.intBinaryTag(1))); // throws IOException
// SNBT
BinaryTag tag = TagStringIOExt.readTag("1"); // throws IOException
String raw = TagStringIOExt.writeTag(IntBinaryTag.intBinaryTag(1));
The Anvil loader has been rewritten (it used many components from Hephaistos). In basic testing the new version takes around 1/5 the time to load chunks. It targets the current anvil version only (as opposed to Hephaistos which handled upgrades in some cases but not others), so please make sure to upgrade your world using a vanilla client/server first if you run into issues. If you do encounter issues, please report them on GitHub or in Discord!
As of Snapshot 24w09a (should read for more context if you have not), notable item meta NBT tags are removed in favor of typed item components. Accordingly, ItemMeta
and all related types have been removed, and ItemComponent
has been added.
Note: ItemComponent
holds all of the definitions related to items, however DataComponent
is the underlying type for all components. This was done under the assumption that Mojang will reuse DataComponent
for other data similar to on Bedrock Edition (this is semi-confirmed by Mojang mappings calling it net.minecraft.core.component.DataComponent
). The terms ItemComponent
, DataComponent
and component
are used interchangeably below.
The api for working with components on items is based on the following relevant functions. All DataComponent
implementation classes are immutable (records):
ItemStack#get(DataComponent<T>) // @Nullable T
ItemStack#get(DataComponent<T>, T) // @NotNull T
ItemStack#with(DataComponent<T>, T)
ItemStack#without(DataComponent)
ItemStack.Builder#set(DataComponent<T>)
ItemStack.Builder#remove(DataComponent<T>)
A full list of item components can be found on the Minecraft wiki, however I will highlight some of the notable ones below:
// Custom name
itemStack.withDisplayName(myComponent); // Old
itemStack.with(ItemComponent.CUSTOM_NAME, myComponent); // New
// Lore
itemStack.withLore(myComponentList); // Old
itemStack.with(ItemComponent.LORE, myComponentList); // New
// Custom model data
itemStack.with(meta -> meta.customModelData(1)); // Old
itemStack.with(ItemComponent.CUSTOM_MODEL_DATA, 1); // New
// Item hide flags
itemStack.with(meta -> meta.hideFlag(ItemHideFlag.HIDE_ENCHANTS)); // Old
itemStack.with(ItemComponent.ENCHANTMENTS, new EnchantmentList(myEnchantmentMap, false));
// Note that the hide flag is always inside of the associated component, rather than together in one bit flag.
// A shorthand for modifying a component (without adding it if not present) is using ItemStack#with(ItemComponent<T>, UnaryOperator<T>):
itemStack.with(ItemComponent.ENCHANTMENTS, enchants -> enchants.withTooltip(false));
The old NBT tag used for user defined data is now in the CUSTOM_DATA
component. The old ItemStack
functions for interacting with the Tag
api have been preserved, and read from/write to the CUSTOM_DATA
component.
We have removed the current pathfinding library Hydrazine in favor of our own implementation. The high-level pathfinding API has not been changed, so unless you depend on some internals or hydrazine specifics, this should not affect your code. You should see significantly better pathing results now, however this is a first version and pathfinders have a lot of specifics/edge cases so we are expecting to find some issues.
As a nice side effect of this change, we now no longer have any dependencies on Jitpack, so you can remove that from your repositories! Also that pesky (irrelevant) CVE is now gone :)
Dynamic registries (Chat type, dimension type, biome, damage type, trim material, trim pattern, banner pattern, wolf variant) are now all instances of DynamicRegistry
, which replace the old manager style. All of these registries now load the vanilla data by default (eg for biomes, all of the vanilla biomes will be loaded by default), and all associated types have generated constants (some did not previously).
Dynamic registry entries are now no longer represented by their record, instead a wrapper around a namespace id is used to reference the object with that ID. All generated constants are now DynamicRegistry.Key<T>
instances, and relevant methods take the same type. For example, biome usage has changed in the following way:
void setBiome(Point pos, Biome biome); // Old
void setBiome(Point pos, DynamicRegistry.Key<Biome>); // New
DynamicRegistry
has an api for registering new entries. You can also overwrite and remove entries but you must first set a system property because these operations are inherently unsafe. See the associated method for more details.
In all cases the APIs of the dynamic registry types (like Biome
) have been standardized. This has resulted in some breaking field renames and cleanup to match vanilla naming.
The following are some smaller but still notable changes:
- Minestom always enables the new optional
strictErrorHandling
flag sent during login. This will be removed in 1.21 so does not seem worth adding a flag for. If you get a client disconnect forNetwork Protocol Error
, this is the reason. StackingRule
has been removed and all checks are now based on theMAX_STACK_SIZE
component andItemStack#isSimilar
tests.- Particle data types now have their own concrete Particle implementations with some utility functions for adding the relevant data. For example, block particles now can be created with
Particle.BLOCK.withBlock(Block.STONE)
. - Attribute types are now generated from vanilla data. In the API this just means some names have been adjusted, generally including
GENERIC_
at the start, egAttribute.MOVEMENT_SPEED
->Attribute.GENERIC_MOVEMENT_SPEED
. They are also now located inside theentity
package. Enchantment
is now inside theitem.enchant
package.- LivingEntity fire state is now based on ticks instead of wall-clock time.
- Food/potion eat duration now matches vanilla by default and is based on ticks instead of wall-clock time. Player
defaultEatingTime
has been removed. - Cookies may be set on the player connection using
PlayerConnection#storeCookie
andPlayerConnection#fetchCookie
. RecipeType
s are now generated from vanilla data. Some names have been adjusted.- The current game data version is now present as a constant in
MinecraftServer
. SoundEvent
now encapsulates both custom (resource pack) sounds and vanilla sounds. Cases where both were taken (usually as@Nullable SoundEvent, @Nullable String, @Nullable Float
) should be replaced by the associatedSoundEvent
constant orSoundEvent.of(String, Float)
for custom sounds.EquipmentSlot#fromAttributeSlot
has been removed in favor ofAttributeSlot#equipmentSlots
which can return multiple entries.EntityPropertiesPacket
was renamed toEntityAttributesPacket
to better represent the content and match the Mojang mapping name.- Living entity meta potion color has been replaced with a list of
Particle
s inline with the associated protocol change. TextDisplayMeta#getTextOpacity
is now a byte inline with the protocol.- The old
ChunkGenerator
api has been removed. The newGenerator
should be used instead. BlockPlacementRule
now receives theItemStack
used to place the block, rather than theItemMeta
which has been removed.- Inline with the related protocol change, it is now invalid to put air in a Recipe and doing so will generate an exception.
- Factor data is gone in Potion effects (previously used for the darkness effect).
- By default chat will no longer be cleared during the configuration phase, use
AsyncPlayerConfigurationEvent#setClearChat(boolean)
to reenable this behavior. - The anvil input packet (
ClientNameItemPacket
) is now handled and calls the associatedPlayerAnvilInputEvent
. - Instance time synchronization methods are now based on ticks instead of wall time. The new methods are
Instance#getTimeSynchronizationTicks
andInstance#setTimeSynchronizationTicks
. LivingEntity
fire is now based on ticks instead of wall time. The old fire event is now split intoEntitySetFireEvent
andEntityExtinguishFireEvent
for each end of it.WorldBorder
is now an immutable record. You can reuse the same world border safely, and apply to anInstance
with a transition period. When comparing against the world border, you should always fetch the most up to date value withInstance#getWorldBorder
in case it is mid-transition.BlockDisplayMeta
now usesBlock
directly rather than a state id as an integer.Block#stateId
andBlock#fromStateId
now work with integers instead of floats.- Entities are no longer tracked globally. To fetch an entity by its ID or UUID, use
Instance#getEntityById
orInstance#getEntityByUuid
respectively. This means that two different entities with the same UUID may exist in two different instances at the same time. It is never valid for two entities to have the same UUID in the same instance. Entity#setUuid
has been removed, along withAsyncPlayerPreLoginEvent#setUuid
. AUuidProvider
or online mode/proxy forwarding should be used to set a player UUID. Entity UUIDs should be set upon construction and constant.- Removed the
minestom.experiment.pose-updates
system property. Player pose updates are now handled by default.
An API has been added internally for de/serializing from NBT (particularly, item components). This API should not be considered ready for external use, it will almost certainly have breaking changes without warning. (Don’t) Use at your own risk.
- Receiving transfers from other servers is not currently supported in Minestom. This will be added in a future PR. It is possible to transfer a player from a Minestom server by sending the packet, eg
player.sendPacket(new TransferPacket(“localhost”, 25566));
. - We are now capable of more properly handling passenger/vehicle offsets on entities. The relevant data is now present in the data repository, however it is not in use in Minestom yet. This will be done in the future, and should be a non-breaking change.
Big thank you to all the people who tried the unstable branch, and as always if you run into bugs please report them on GitHub or in the Discord server!
How can I install factions plugin?