Custom item API v2
If you are planning to use a build from this PR to create custom items making use of the 1.21.4+ format, please read the following:
To use the format described in this PR, you have to use a build from it. You can download the experimental preview builds here:
- Geyser-Bungeecord.jar
- Geyser-Fabric.jar
- Geyser-NeoForge.jar
- Geyser-Spigot.jar
- Geyser-Standalone.jar
- Geyser-Velocity.jar
- Geyser-ViaProxy.jar
Again, this PR is experimental, and bugs will likely occur. You are free to report any either here or on the GeyserMC Discord, in the #custom-resource-packs channel. Breaking changes can still be made, but we try to keep these to a minimum!
Documentation for the new JSON mappings format is available below. Example mappings making use of this PR's format, as well as a bedrock resourcepack, are available here. If you have any questions regarding the format, please ask those in the aforementioned Discord channel.
Rainbow is a Fabric Minecraft mod capable of generating JSON mappings for this PR, as well as generating a bedrock resourcepack to go with those mappings.
This PR adds a new API for (vanilla and non-vanilla) custom items, along with a new JSON mappings format for it.
This new API was necessary to incorporate the amount of changes made recently to items in Minecraft Java, primarily the introduction of new item components and item model definitions, adding a new predicate system. The new API is designed to be somewhat similar to the component system and item model definitions.
The currently existing API and JSON mappings format will be deprecated, but will continue to be usable. Custom items made using the existing API will automatically be translated at runtime to the objects from the new API.
Along with introducing a new API for custom items, this PR also cleans up the custom item registry populator a bit and makes use of default item components to get the properties of vanilla items, and makes some other minor changes as well. These changes together should enhance the experience with custom items by a lot.
Before going into the specification, here is some vocabulary used in custom items on Java and Bedrock:
- Java item: any real, existing item on vanilla Java. Java datapacks make custom items by overriding the components of a Java item.
- Java item component: Java items have their properties and behaviour defined in item components. Every Java item has a set of default components, and item stacks can override these components.
- Bedrock item component: Bedrock items also have components that determine item behaviour, similar to Java, however unlike Java items, these components can't be changed at runtime for item stacks, which is one of the major reasons a custom item API is required in the first place.
- Java legacy custom model data: this system was used before Java 1.21.4. Before 1.21.4, each custom item had a custom model data number, used to decide which model a Java item should use.
- Java item model definition: these were introduced in Java 1.21.4 and exist in the
assets/<namespace>/items/resource pack directory. They decide which model a Java item should use based on a set of rules and item properties. Every Java item stores its item model definition in itsminecraft:item_modelitem component, which can in term be overridden on an item stack by a datapack to use a custom item model definition defined in a resource pack. - Custom item definition: a custom item definition is a Geyser term. It represents a single Bedrock custom item that is used to map (part of) a Java item model definition. It contains info on the item's properties on Java and Bedrock.
- Multiple custom item definitions, and thus multiple Bedrock items, can exist for the same Java item model definition, but for every combination of a Java item and Java item model definition, there can only be one custom item definition without predicates.
- Non-vanilla custom item definition: also a Geyser term. Represents a Bedrock custom item that maps a Java non-vanilla item, and is as such only used for modded items. Like normal custom item definitions, it contains info on the item's properties on Java and Bedrock.
- At the moment, there can only be one non-vanilla custom item definition per Java non-vanilla item. In the future, this might be changed to add support for non-vanilla custom item definitions making use out of predicates.
- Non-vanilla custom item definitions have some additional features on top of normal custom item definitions to allow configuring options that are not possible to configure for custom items made with Java vanilla items. These include options like chargeable (shooter) items.
The new format
The new format for JSON-mappings looks somewhat like this:
{
"format_version": 2,
"items": {
"minecraft:flint": [
{
"type": "definition",
"model": "geyser_mc:test_item",
"bedrock_identifier": "geyser_mc:test_item",
"display_name": "An Example Item!",
"bedrock_options": {
"icon": "potato",
"creative_category": "items"
}
},
{
"type": "legacy",
"custom_model_data": 42,
"bedrock_identifier": "geyser_mc:test_legacy_item",
"display_name": "A Very Old Item!",
"bedrock_options": {
"icon": "cobweb"
}
},
{
"type": "group",
"model": "geyser_mc:another_test_item",
"definitions": [
{
"bedrock_identifier": "geyser_mc:another_test_item",
"bedrock_options": {
"icon": "carrot"
},
"components": {
"minecraft:consumable": {
"animation": "drink",
"consume_seconds": 10
}
}
},
{
"bedrock_identifier": "geyser_mc:another_test_item_nether",
"bedrock_options": {
"icon": "carrot"
},
"predicate": {
"type": "match",
"property": "context_dimension",
"value": "minecraft:the_nether"
},
"components": {
"minecraft:consumable": {
"animation": "drink",
"consume_seconds": 10
}
}
}
]
}
]
}
}
The start of the format is similar to the current format. There is an items key, which is an object in which keys are Java items, and in which each value is an array of objects, specifying custom item definitions for that Java item.
There are multiple types of custom item definitions:
definition: a single custom item, defined for a Java item model definition.legacy: a single custom item, defined for a Java custom item making use of legacy custom model data numbers.group: a group of custom item definitions.
The type of a definition is defined in the type key. All definition types will be explained in detail below.
Note: standard definitions (of type definition) are used by default, meaning that when no type key is present within a definition, Geyser assumes it's a standard definition.
Standard (normal) definitions and legacy definitions
Both the definition and legacy definition types are quite similar. They share a couple of keys, and only have one major difference.
The difference between standard and legacy definitions is the version of Minecraft they should be used for. As is said in the name, legacy definitions should be used for legacy custom items. Legacy in this context means anything making use of custom model data numbers below Java 1.21.4. For all custom items created for Java 1.21.4 or later, standard definitions should be used.
Both definition types expect a bedrock_identifier key. This determines its identifier on Bedrock, which is also used in e.g. Bedrock attachables. If no namespace is given here, the geyser_custom namespace is used. Note that every custom item definition, across mapping files too, is required to have a unique Bedrock identifier.
Standard definitions expect a model key, noting the value of the minecraft:item_model component for this custom item. Legacy definitions however, expect a custom_model_data key, an integer describing the custom model number of this custom item.
These two keys, along with the type key, are the only required keys for standard and legacy definitions. There are however a few additional keys that can be used to further customise the custom item definition, which are:
bedrock_optionscomponentspredicatepredicate_strategyprioritydisplay_name
These will be explained in detail further below.
Before going to group definitions, here's how a standard definition looks like in JSON:
{
"type": "definition",
"model": "geyser_mc:a_cool_item_model",
"bedrock_identifier": "geyser_mc:a_cool_item"
}
And the same for a legacy one:
{
"type": "legacy",
"custom_model_data": 42,
"bedrock_identifier": "geyser_mc:a_cool_item"
}
Group definitions
A group definition is, well, a group of custom item definitions. These can both be standard or legacy definitions. All standard definitions in the group inherit the Java model definition of the group, if any (so, a group is not required to have a model, in which case the definitions in the group have to specify the model themselves). Definitions in a group are also allowed to be a group, and definitions in a group can also override the Java model definition of the group.
A group definition can look something like this:
{
"type": "group",
"model": "geyser_mc:a_cool_item_model", // Optional
"definitions": [...]
}
Custom item definition bedrock options
The bedrock_options key is an object that sets options for the item on Bedrock, that cannot be set using Java item components. Possible keys are:
icon: determines the icon to use for the item. If not set, the item's bedrock identifier is used,:replaced with.and/with_(for example,geyser_mc:a_cool_itemturns intogeyser_mc.a_cool_item).allow_offhand: if the item should be allowed in the offhand slot. Defaults totrue.display_handheld: if the item should display handheld, like a tool or weapon. Defaults tofalse.protection_value: determines how many armour points should be shown when this item is worn. This is purely visual. Only has an effect when the item is equippable, and defaults to 0.creative_category: sets the item's creative category (for the recipe book). Can benone,construction,nature,equipment, oritems. Defaults tonone.creative_group: sets the item's creative group (for the recipe book). See this page for possible values.tags: Bedrock tags the item has, can be used in Molang.
The render_offsets and texture_size options from v1 have been removed. render_offsets has been deprecated for a long time, and is longer functional on the bedrock client, and texture_size depended on it. As an alternative, use attachables in your bedrock resourcepack instead.
Custom item definition components
The components key defines properties for the item, in the Java item component format. It is expected that the item will always have these components when the custom item definition is used. Currently, the following components are supported:
minecraft:consumable: doesn't support consume particles/sounds.minecraft:equippable: doesn't support the camera overlay or swappable properties.minecraft:foodminecraft:max_damageminecraft:max_stack_sizeminecraft:use_cooldownminecraft:enchantable- On Bedrock, this will be mapped to the
minecraft:enchantablecomponent withslot=all. This should, but does not guarantee, allow for compatibility with vanilla enchantments. Non-vanilla enchantments are unlikely to work.
- On Bedrock, this will be mapped to the
minecraft:toolminecraft:repairableminecraft:enchantment_glint_override
Some components, like minecraft:rarity and minecraft:attribute_modifiers, are already automatically translated and don't need to be specified here.
Along with the components listed here, default component removals can also be specified by prefixing a component with a !, like is done in Java:
"components": {
"!minecraft:consumable": {}
}
Custom item definition predicates
predicate is either an object (single predicate) or an array of objects (multiple predicates). For each combination of a Java item and a Java item model definition, there can be one item definition without a predicate, and one or multiple definitions with a predicate. There can't be multiple item definitions with the same predicates for the same Java item and Java item model definition. If the Java item model definition is in the minecraft namespace, there can't be an item definition without a predicate.
Each predicate has a type and a property key. Currently, there are 3 predicate types:
conditionmatchrange_dispatch
The condition predicate type checks for a boolean property and returns true if the property matches the expected value. It has 4 possible properties:
broken: if the item is broken (has only 1 durability point left).damaged: if the item is damaged (not at full durability).custom_model_data: checks the item's custom model data flags. Defaults tofalse.has_component: if the item has the component set in thecomponentkey. Includes default components.fishing_rod_cast: if the player is currently holding a cast fishing rod.
The condition predicate also has the expected key, which specifies if the property has to be true or false for this predicate to be true. Defaults to true.
The match predicate type checks for a text-like property and returns true if it matches the given value. It has 4 possible properties:
charge_type: the item currently charged in the crossbow (in theminecraft:charged_projectilescomponent). Can benone,arrow, orrocket.trim_material: the trim material (resource location) of this item.context_dimension: the dimension (resource location) the player is currently in.custom_model_data: fetches a string from the item's custom model data strings.
The match predicate requires a value to be specified in the value key.
The range_dispatch predicate type checks for a numeric property and returns true if it is above the specified threshold. It has 4 possible properties:
bundle_fullness: checks the item's bundle fullness. Returns the total stack count of all the items in a bundle (in theminecraft:bundle_contentscomponent).damage: checks the item's damage value. Can be normalised.count: checks the item's count. Can be normalised.custom_model_data: checks the item's custom model data floats. Defaults to0.0.
The range_dispatch predicate has 3 extra keys, one of them required:
threshold: the threshold required to return true (required).scale: the factor to scale the property value by before comparing it with the threshold. Defaults to1.0.normalize: if the property value should be normalized before scaling it and comparing it with the threshold. Defaults tofalse, only works for certain properties.
All predicates can also have an index key, which determines which index to use when using a custom model data property. Defaults to 0.
Some may notice these predicates are similar to the ones possible in Java 1.21.4's item model definitions. Here are some examples of how predicates can look:
{
"type": "match",
"property": "charge_type",
"value": "arrow"
}
{
"type": "condition",
"property": "custom_model_data",
"index": 1
}
{
"type": "match",
"property": "context_dimension",
"value": "minecraft:overworld"
}
{
"type": "condition",
"property": "has_component",
"component": "minecraft:unbreakable"
}
There is also a predicate_strategy key, which can be and or or and defaults to and. This was inspired by the advancement requirement strategies, and decides if all predicates (and), or only one predicate (or) of an item definition has to match for it to be used.
Custom item definition sorting and priority
Custom item definitions are automatically sorted so that the definitions' predicates are checked in a correct order when translating items. Specifically, Geyser sorts custom item definitions like this:
- First custom item definitions with a higher priority value are sorted above definitions with lower ones.
- Custom item definitions with similar range dispatch predicates are sorted by their threshold, with higher thresholds going first.
- Custom item definitions with more predicates are sorted over definitions with less.
This system ensures that in most cases, item definitions with predicates are checked in proper order, no matter which order they are put in the mappings. In the few cases that Geyser does not sort definitions correctly (that will most likely occur when using multiple range_dispatch predicates, or using them in combination with other predicates), the priority key can be used to specify which definitions should be checked first.
The API and non-vanilla custom items
Along with the introduction of a new JSON mappings format, the entire custom item API has received an overhaul too. Detailed changes won't be described here, but there are Javadocs documenting all the functionality pretty well. Just as the v1 JSON mappings format will continue to be usable, the old custom item API can also continue to be used for the time being.
You can experiment with the new API for extensions by including a JitPack build of this branch of the Geyser API, instead of the main build. You can do so as follows in your build.gradle:
repositories {
maven {
url = "https://jitpack.io"
}
}
dependencies {
implementation 'com.github.eclipseisoffline:geyser:custom-item-api-v2-SNAPSHOT'
}
Javadocs for the new API are available here. The classes in the org.geysermc.geyser.api.item.custom.v2 package are the important ones.
TODOs
A lot of the TODOs for this PR are now finished. There are still some left on this list and in the code, but none are of a very significant magnitude.
- [x] Range dispatch predicate
- [x] Non vanilla custom items
- [x] ~~Possibly main hand match property~~ not possible
- [x] Possibly ~~using item,~~ has component ~~cast fishing rod,~~ ~~selected bundle item~~ condition properties
- Only has component and cast fishing rod were possible.
- [x] ~~Consumable component properties (sound, consume particles, etc.) if those are possible~~
- ~~Might be server side, check~~ Tested, consume particles are done entirely client side, and the sound is only sent to clients other than the client consuming the item. Doesn't seem possible to emulate this to me.
- [x] Fix consumable animations/, use animation/use duration properties on bedrock which seem to be randomly used with magic numbers
- [x] Fix protection value/enchantment value properties
- [x] Check and possibly fix Bedrock tool, chargeable, throwable and possibly other components that may have changed and not properly updated in the custom item registry populator
- [x] Check what to do with the
minecraft:toolJava component - [x] Make sure stack size is 1 when an
equippableis set since Bedrock doesn't support armour with a stack size above 1, also validate other components (e.g. damage and stack size combination) - [x] Add a custom model data predicate when converting v1 to v2 at runtime (when range dispatch predicate is added)
- [x] Unbreakable condition predicate, also implement in v1 to v2 converter
- [x] Custom item definition priority
- [x] Don't use MCPL in API module, when creating component classes in API make sure to do proper validation
- [x] Cleanup item registry populator:
registeredItemNamesmay be identifiers,identifierToKeymethod needs to go elsewhere,customItemNameis always the bedrock identifier - [x] Don't use adventure in API module
- [x] More proper PR description of code changes
- [x] Block mapping reading in the V2 reader
- [x] Better error handling/printing when mapping reading/custom item registry populator fails
- [x] Clean up mapping reader/data component JSON reader with helper methods to lessen code duplication
- [x] Fix the broken/damaged conditional predicates
- [x] Take range dispatch scaling into account when sorting predicates
- [x] Map food nutrition/saturation properties, if bedrock sends them to the client
- [x] Update PR description for range dispatch predicates, unbreakable condition predicate and priority
- [x] Maybe predicate caching, so that predicates that occur in multiple definitions for the same item/item model aren't recalculated multiple times
- [x] Move predicate stuff in API to core
- [x] Replace unbreakable predicate with has unbreakable component once has component predicate is a thing
- [x] Predicates AND/OR strategy
- [x] Predicate validation: check if indices are non negative
- [x] Predicate/bedrock options node reader?
- [x] Custom model data arrows/projectiles (by defining projectile component, also make this an option for non-vanilla items)
- [x] Some components need fixing (block placer, chargeable (animation))
- [x] Predicate abstraction: eclipseisoffline/Geyser#2
- [x] Documentation
- [x] Other TODOs left in the code
- [ ] A lot of testing, probably
Although the PR is not finished yet, the code is decently clean, and (especially the API module), somewhat well documented. Reviews are welcome!
Testing
Some testing has been done already with a lot of (relatively simple) custom items that make use out of components like consumable, equippable and use_cooldown and use the condition and match predicates. This seemed to work decent so far. Testing that still has to be done:
- Verify that v1 mappings convert over correctly and can be used without much downsides
- Range dispatch predicates
- Creating custom item definitions that for a
minecraft:(vanilla) item model with a predicate - Error handling
- Predicate strategies
- Anything you can think of that should work with this new system
FYI I believe that the plan for items on Bedrock itself is to eventually deprecate render offsets on items in favor of attachables/texture meshes, so we should probably note that in any documentation.
Also as long as you're adding stuff, it might be nice to add some sort of a priority value at the top level of the mappings file for specifying the load order of files since I've seen a lot of cases where people want to separate the same item across files for organizational reasons, but cannot because it results in predicates being applied incorrectly.
Otherwise I think the plan for the format is solid. Haven't reviewed the code yet since it sounds like that's still a WIP.
I had a feeling that might be the case - maybe we should just mark the whole render offsets option as deprecated all together, telling users to use attachables/texture meshes instead?
As for priority values, I've been working on automatically sorting predicates. For example, let's say you have 3 item definitions for the same item model:
- one with predicate A
- one with predicates A and B (A && B)
- one with predicates A and C (A && C)
- one without predicates (fallback)
Geyser would then automatically sort them from most predicates to least, so that it'll match them in this order:
- A && B
- A && C
- A
- Fallback, if no predicates match
This way no matter the order you put predicates in the mappings, they'd always be checked in the right order so that the A predicate won't be used if A && C also matches.
This worked pretty well until I got to range dispatch predicates - I made these sort by comparing their threshold value, and predicates with higher threshold values will be checked first. This doesn't always work properly however, for example when you have a definition with multiple range dispatch predicates checking for different properties with different thresholds.
It might be a good idea to add an optional priority key to item definitions themself, for example like this:
{
"type": "group",
"model": "geyser_mc:test_item",
"definitions": [
{
"bedrock_identifier": "geyser_mc:test_item_1",
"priority": 1,
"predicate": [
{
"type": "range_dispatch",
"property": "custom_model_data",
"threshold": 100.0,
"index": 0
},
{
"type": "range_dispatch",
"property": "custom_model_data",
"threshold": 50.0,
"index": 1
}
]
},
{
"bedrock_identifier": "geyser_mc:test_item_2",
"priority": 2,
"predicate": [
{
"type": "range_dispatch",
"property": "custom_model_data",
"threshold": 20.0,
"index": 1
},
{
"type": "range_dispatch",
"property": "custom_model_data",
"threshold": 30.0,
"index": 2
}
]
}
]
}
This way the second custom item definition would be checked first.
And yeah - code is definitely still WIP.
An example of how mappings can be created with this new API can be found in this repository.
Sorry to comment here, but how is this PR going?
Nearing completion. There are still a couple of things to do, as can be seen in the TO DO list at the top. You're free to test the PR and give feedback or report bugs, but be careful with using it in production servers.
can you do some kind of ETA
It'll be done when it's done. Once we have documentation and are ready for testing, you'll find out about that in the Geyser discord.
Hello, not sure if this is something that this PR intends to address, but items that use the item_model component, even without a resource pack, aren't displayed correctly in Bedrock clients.
For example, on my vanilla server with no resource packs or data packs, I have a custom item that is a poisonous potato (because it is a good dummy item), but has the appearance of a netherite hoe, but on Bedrock clients it still looks like a poisonous potato.
Is there a way around this without needing a resource pack, or is this something that this PR will eventually address? If so, is there an ETA?
Thanks for reporting this! In my opinion, this should be a feature of this PR, but it isn't yet. I'll add it to the TO DO list. It shouldn't be much work, I'll hopefully get to it within a week or so.
Hi, I'm not sure If I should report this here or somewhere else, so... Someone let me know if this is not the right place to report issues.
Ahemg, ignoring that. I was using the custom model data from the version 1 of mapping and was something that worked really smooth. Now on my testing server I tried to map all my resource pack from java to bedrock using the formar 2, but I noticed that at the monent you have a mapped item in hand, you can't break or interact with any block.
I tried to add components to the mapped items and still having this issue. https://github.com/user-attachments/assets/c5048bc5-a7a5-472a-a518-e66143766362
Mapping: held.json Geyser version: Geyser - Bump https://dump.geysermc.org/mxDeB8aVAHi05kJrt2KfdYKLHuZWYnFx Server Software: Minecraft 1.21.4 - PurpurMC 1.21.4-2408-5d1df70
Thanks for reporting this! In my opinion, this should be a feature of this PR, but it isn't yet. I'll add it to the TO DO list. It shouldn't be much work, I'll hopefully get to it within a week or so.
That would be amazing, thank you so much! I will be happy to test if/when needed!
@MinecraftNight4, thanks for reporting. I will look into this hopefully soon, I'm currently on a trip but on my way home.
Negative components (like !minecraft:consumable) don't work
The removal of default item components can now be specified in definitions under the components key. Non-vanilla custom items cannot specify component removals, as they are specifying default item components, not a component patch.
@TheosisOfficial the feature you requested should now be implemented in the latest build of this PR. For every item that uses another vanilla item's model, you have to define a definition in a mapping file, like so:
{
"format_version": 2,
"items": {
"minecraft:poisonous_potato": [
{
"type": "definition",
"model": "minecraft:iron_ingot",
"bedrock_identifier": "poisonous_iron",
"bedrock_options": {
"icon": "iron_ingot"
}
}
]
}
}
@MinecraftNight4 could you please check if the issue you reported still occurs on the latest PR build?
@TheosisOfficial the feature you requested should now be implemented in the latest build of this PR. For every item that uses another vanilla item's model, you have to define a definition in a mapping file, like so:
{ "format_version": 2, "items": { "minecraft:poisonous_potato": [ { "type": "definition", "model": "minecraft:iron_ingot", "bedrock_identifier": "poisonous_iron", "bedrock_options": { "icon": "iron_ingot" } } ] } }
Will we always have to define a definition in a mapping file, rather than just having the item model be what is in its components already?
How would I make my custom items obey the mappings? (Sorry, I am inexperienced with resource pack stuff)
Marking this PR as ready to review. While there are still some small TODOs to be checked, almost all of the code is now in a mostly finished state, with almost all planned features implemented.
Will we always have to define a definition in a mapping file, rather than just having the item model be what is in its components already?
How would I make my custom items obey the mappings? (Sorry, I am inexperienced with resource pack stuff)
@TheosisOfficial Yes, unfortunately. Geyser needs to know which custom items it can expect from the server, so it can tell bedrock players that information when they join the server, since they don't support dynamically changing item components. Other than creating these mappings, no bedrock resourcepack should be required as long as you're using vanilla icons (which is what I did in my mappings example).
Will we always have to define a definition in a mapping file, rather than just having the item model be what is in its components already? How would I make my custom items obey the mappings? (Sorry, I am inexperienced with resource pack stuff)
@TheosisOfficial Yes, unfortunately. Geyser needs to know which custom items it can expect from the server, so it can tell bedrock players that information when they join the server, since they don't support dynamically changing item components. Other than creating these mappings, no bedrock resourcepack should be required as long as you're using vanilla icons (which is what I did in my mappings example).
How would I reference my custom items in the mapping file, so it only affects those items, and not all items of the same type? My custom items are all just a minecraft:music_disc_13 with a PDC to identify them, and its jukebox_playable component removed using Paper's data component API. Something to do with the bedrock_identifier? Do I put that somewhere in my custom item's metadata?
Wait for this update, :)
Music disc component for non-vanilla pls, I really need it for my epic project Hydraulic
(for anyone viewing, Eclipse just wanted a reminder for this)
Hello. It has been about 6 months since I sent my issue #5303 for item model components.
My intentions are simple: "I just want a way to hide the appearance of armour on java and bedrock geyser server through a datapack (item data) not a resourcepack."
There is a method that I have found to make the armour pieces disappear on java using "item_model" and "model" but they appear as unchanged on bedrock/geyser
I do not have any intentions on adding "custom new armour and appearances" like with a datapack, I am just looking to hide the armour as a whole.
That is all. Thank you for your hard work!
any chance of getting an updated build for this with the changes in master?
The next build will have master's latest changes.
How far are the tests? Would it be added soon in the master? Hopefully soon
How far are the tests? Would it be added soon in the master? Hopefully soon
Eventually, it will be. Just no ETAs lol.
Does this get updated with the latest 1.21.10 and support for copper age? Just curious
it's already been updated