-
-
Couldn't load subscription status.
- Fork 774
Custom item API v2 #5189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Custom item API v2 #5189
Conversation
|
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 Geyser would then automatically sort them from most predicates to least, so that it'll match them in this order: This way no matter the order you put predicates in the mappings, they'd always be checked in the right order so that the 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 {
"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. |
# Conflicts: # core/src/main/java/org/geysermc/geyser/item/type/Item.java # core/src/main/java/org/geysermc/geyser/registry/type/ItemMapping.java # core/src/main/java/org/geysermc/geyser/translator/item/CustomItemTranslator.java # core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCooldownTranslator.java
2b03c8f to
7fabf0c
Compare
| * | ||
| * @return the item's base data components and the "additional" ones that may exist. | ||
| */ | ||
| public @Nullable DataComponents getAllComponents() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How practical/reasonable would it be to remove the componentCache field and replace this with a getAllComponents(GeyserSession) call? Having all items defined with a session parameter still rubs me the wrong way. Defining EMPTY above with a null session solidifies that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would also require getComponent() to also require passing a GeyserSession.. 40 usages there alone. Bigger issue would be that helper methods, such as e.g. GeyserItemStack#isDamageable would then also require passing GeyserSession everywhere - and so would every other method checking item components.
fwiw the session is not stored directly either, the ComponentCache field is - passing around ComponentCache there would be a bit iffy as that would require each caller null-checking the session before getting the componentcache

|
any chance of getting an updated build for this with the changes in master? |
|
The next build will have master's latest changes. |
# Conflicts: # core/src/main/java/org/geysermc/geyser/registry/populator/CustomItemRegistryPopulator.java # core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java # core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockBlockActions.java
…line/custom-item-api-v2 # Conflicts: # api/src/main/java/org/geysermc/geyser/api/util/Identifier.java # core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEggEntity.java # core/src/main/java/org/geysermc/geyser/impl/IdentifierImpl.java # core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java # core/src/main/java/org/geysermc/geyser/level/block/type/SkullBlock.java # core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java # core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java
|
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 |
# Conflicts: # core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java
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:
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-packschannel. 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:
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.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
itemskey, 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
typekey. All definition types will be explained in detail below.Note: standard definitions (of type
definition) are used by default, meaning that when notypekey is present within a definition, Geyser assumes it's a standard definition.Standard (normal) definitions and legacy definitions
Both the
definitionandlegacydefinition 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_identifierkey. This determines its identifier on Bedrock, which is also used in e.g. Bedrock attachables. If no namespace is given here, thegeyser_customnamespace is used. Note that every custom item definition, across mapping files too, is required to have a unique Bedrock identifier.Standard definitions expect a
modelkey, noting the value of theminecraft:item_modelcomponent for this custom item. Legacy definitions however, expect acustom_model_datakey, an integer describing the custom model number of this custom item.These two keys, along with the
typekey, 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_nameThese 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
groupdefinition 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_optionskey 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_offsetsandtexture_sizeoptions from v1 have been removed.render_offsetshas been deprecated for a long time, and is longer functional on the bedrock client, andtexture_sizedepended on it. As an alternative, use attachables in your bedrock resourcepack instead.Custom item definition components
The
componentskey 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:enchantableminecraft:enchantablecomponent withslot=all. This should, but does not guarantee, allow for compatibility with vanilla enchantments. Non-vanilla enchantments are unlikely to work.minecraft:toolminecraft:repairableminecraft:enchantment_glint_overrideSome components, like
minecraft:rarityandminecraft: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:Custom item definition predicates
predicateis 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 theminecraftnamespace, there can't be an item definition without a predicate.Each predicate has a
typeand apropertykey. Currently, there are 3 predicate types:conditionmatchrange_dispatchThe
conditionpredicate type checks for a boolean property and returnstrueif 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
conditionpredicate also has theexpectedkey, which specifies if the property has to betrueorfalsefor this predicate to betrue. Defaults totrue.The
matchpredicate type checks for a text-like property and returnstrueif 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
matchpredicate requires a value to be specified in thevaluekey.The
range_dispatchpredicate type checks for a numeric property and returnstrueif 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_dispatchpredicate 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
indexkey, which determines which index to use when using a custom model data property. Defaults to0.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_strategykey, which can beandororand defaults toand. 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:
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_dispatchpredicates, or using them in combination with other predicates), theprioritykey 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.v2package 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.
Possibly main hand match propertynot possibleusing item,has componentcast fishing rod,selected bundle itemcondition propertiesConsumable component properties (sound, consume particles, etc.) if those are possibleMight be server side, checkTested, 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.minecraft:toolJava componentequippableis set since Bedrock doesn't support armour with a stack size above 1, also validate other components (e.g. damage and stack size combination)registeredItemNamesmay be identifiers,identifierToKeymethod needs to go elsewhere,customItemNameis always the bedrock identifierAlthough 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,equippableanduse_cooldownand use theconditionandmatchpredicates. This seemed to work decent so far. Testing that still has to be done:minecraft:(vanilla) item model with a predicate