-
-
Notifications
You must be signed in to change notification settings - Fork 729
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
The removal of default item components can now be specified in definitions under the |
@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? |
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) |
Make predicates in API abstract
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. |
@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 |
api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineCustomItemsEvent.java
Show resolved
Hide resolved
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.
- Some more thoughts, will continue later
core/src/main/resources/mappings
Outdated
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 looks accidental, should target GeyserMC/mappings@f4be123
customModelDataInt = customModelData.floats().get(0); | ||
} | ||
Key itemModel = components.getOrDefault(DataComponentTypes.ITEM_MODEL, FALLBACK_MODEL); | ||
Collection<GeyserCustomMappingData> customItems = allCustomItems.get(itemModel); |
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 sounds like it would be possible to register a custom item override for the air model.. how does java handle that? or should we return if ITEM_MODEL isn't set? (or is this handled elsewhere?)
if (!value) { | ||
allMatch = false; | ||
break; | ||
} else if (needsOnlyOneMatch) { |
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.
Shouldnt this return the definition here?
Otherwise, allMatch can be false at this point (if the first predicate wasnt a match), and no definition would be returned
/** | ||
* A map of item models and all of their custom items, sorted from most definition predicates to least, which is important when matching predicates. | ||
*/ | ||
SortedSetMultimap<Key, GeyserCustomMappingData> customItemDefinitions; |
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.
Given that this used to be NonNull, let's mark this nullable
int customProtocolId = nextFreeBedrockId++; | ||
|
||
String customItemName = customItem instanceof NonVanillaCustomItemData nonVanillaItem ? nonVanillaItem.identifier() : Constants.GEYSER_CUSTOM_NAMESPACE + ":" + customItem.name(); | ||
if (!registeredItemNames.add(customItemName)) { | ||
Identifier customItemIdentifier = customItem.bedrockIdentifier(); // TODO don't forget to check if this works for non vanilla too, it probably does |
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.
just marking the TODO
/** | ||
* The display name of the item. If none is set, the display name is taken from the item's Bedrock identifier. | ||
*/ | ||
@NonNull String displayName(); |
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.
Thoughts of moving this to CustomItemBedrockOptions?
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.
further - can this be set to a bedrock translatable string? if yes, that's worth documenting here
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 a build by clicking on "Checks", then "Artifacts", and then selecting your platform. This will download a ZIP-file, which you can then unzip to obtain a
.jar
file.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.Documentation for the new JSON mappings format is available below. Example mappings making use of this PR's format, including a bedrock resourcepack, are available here. If you have any questions regarding the format, please ask those in the aforementioned Discord channel.
There are no public resourcepack converters available that support this PR's format.
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.
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_model
item 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
Currently, the new format for JSON-mappings looks somewhat like this:
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 custom item definitions for that Java item, or an object specifying a group of such.Specifically, each value in the array can either look like this:
Which is a single custom item definition for a Java item model definition, or like this:
Which is a group of custom item definitions. All 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.
Note that, when the
type
key is not specified, it is defaulted todefinition
.The
bedrock_identifier
key of a custom item definition determines its identifier on Bedrock, which is also used in e.g. Bedrock attachables. If no namespace is given here, then thegeyser_custom
namespace is used. Every item definition is required to have a unique Bedrock identifier.Alongside these 3 keys, there are 4 more keys item definitions can have:
bedrock_options
components
predicate
predicate_strategy
priority
display_name
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_item
turns intogeyser_mc.a_cool_item
).allow_offhand
: if the item should be allowed in the offhand slot. Defaults totrue
.creative_category
: sets the item's creative category (for the recipe book). Can benone
,construction
,nature
,equipment
, oritems
. Defaults tonone
.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.tags
: Bedrock tags the item has, can be used in Molang.The
render_offsets
andtexture_size
options have been removed.render_offsets
has been deprecated for a long time, and is longer functional on the bedrock client, andtexture_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:food
minecraft:max_damage
minecraft:max_stack_size
minecraft:use_cooldown
minecraft:enchantable
minecraft:enchantable
component withslot=all
. This should, but does not guarantee, allow for compatibility with vanilla enchantments. Non-vanilla enchantments are unlikely to work.minecraft:enchantment_glint_override
Some components, like
minecraft:rarity
andminecraft:attribute_modifiers
, are already automatically translated and don't need to be specified here.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 theminecraft
namespace, there can't be an item definition without a predicate.Each predicate has a
type
and aproperty
key. Currently, there are 3 predicate types:condition
match
range_dispatch
The
condition
predicate type checks for a boolean property and returnstrue
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).unbreakable
: if the item is unbreakable.fishing_rod_cast
: if the player is currently holding a cast fishing rod.custom_model_data
: checks the item's custom model data flags. Defaults tofalse
.The
condition
predicate also has theexpected
key, which specifies if the property has to betrue
orfalse
for this predicate to betrue
. Defaults totrue
.The
match
predicate type checks for a text-like property and returnstrue
if it matches the given value. It has 4 possible properties:charge_type
: the item currently charged in the crossbow (in theminecraft:charged_projectiles
component). 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 thevalue
key.The
range_dispatch
predicate type checks for a numeric property and returnstrue
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_contents
component).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 to0
.Some may notice these predicates are similar to the ones possible in Java 1.21.4's item model definitions. I plan to possibly extend the current predicates. Some examples of how predicates can look:
There is also a
predicate_strategy
key, which can beand
oror
and 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_dispatch
predicates, or using them in combination with other predicates), thepriority
key can be used to specify which definitions should be checked first.This new format has a few key benefits over the current format:
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 somewhat well. Just as the v1 JSON mappings format will continue to be usable, the old item API can also continue to be used for the time being.
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:tool
Java componentequippable
is set since Bedrock doesn't support armour with a stack size above 1, also validate other components (e.g. damage and stack size combination)registeredItemNames
may be identifiers,identifierToKey
method needs to go elsewhere,customItemName
is 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
,equippable
anduse_cooldown
and use thecondition
andmatch
predicates. This seemed to work decent so far. Testing that still has to be done:minecraft:
(vanilla) item model with a predicateError handling(To do: add more here)