GeyserMappingIdentity
Computes the identity under which Geyser considers two custom-item definitions to be in conflict: same Java item, same model, and predicate lists that parse to equal predicate objects (CustomItemRegistryPopulator.checkPredicate, verified against Geyser 2.11.2-b1233). Geyser registers only the first such definition and logs "Not registering custom item definition (...): conflicts with custom item definition (...): both entries have the same predicates" for every later one.
This is deliberately NOT the same thing as the bedrock_identifier: RSPM's identifier hash includes the resolved Java model ref, which Geyser never compares. Two mappings with different identifiers (different source models) can still be one identity here — e.g. two merged packs claiming the same custom_model_data on the same item, or a dual-format pack whose modern items definition and legacy override describe the same matcher. Both the backend registry and the proxy-side mappings merger deduplicate by this identity so Geyser never has to reject an entry at boot.
Canonicalisation mirrors Geyser's mappings readers exactly where equality depends on parse-time folding:
type=legacyparses to model = the Java item itself plus a singlerange_dispatchpredicate on custom_model_data (LegacyDefinitionReader→ItemRangeDispatchPredicate.legacyCustomModelData).range_dispatchfoldsthreshold / scale(scale defaults to 1) into a single value (ItemRangeDispatchProperty.readThreshold); custom_model_data additionally casts to float and keys onindex(default 0); damage/count cast to int whennormalizeis false (the default).condition'sexpecteddefaults to true.- Predicate-list comparison is order-insensitive (Geyser checks size + containsAll), so canonical predicate strings are sorted before joining.
Functions
null when the entry is malformed enough that no identity can be computed — callers must then leave it un-deduplicated rather than guess.