diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/DataComponentHashers.java b/core/src/main/java/org/geysermc/geyser/item/hashing/DataComponentHashers.java index d45ea5ffc..9d7fa3dc0 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/DataComponentHashers.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/DataComponentHashers.java @@ -52,6 +52,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.GlobalPos; import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; import org.geysermc.mcprotocollib.protocol.data.game.item.HashedStack; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.AttackRange; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BlockStateProperties; import org.geysermc.mcprotocollib.protocol.data.game.item.component.BlocksAttacks; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Consumable; @@ -68,15 +69,19 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import org.geysermc.mcprotocollib.protocol.data.game.item.component.IntComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemAttributeModifiers; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.KineticWeapon; import org.geysermc.mcprotocollib.protocol.data.game.item.component.LodestoneTracker; import org.geysermc.mcprotocollib.protocol.data.game.item.component.MobEffectDetails; import org.geysermc.mcprotocollib.protocol.data.game.item.component.MobEffectInstance; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.PiercingWeapon; import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.SwingAnimation; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ToolData; import org.geysermc.mcprotocollib.protocol.data.game.item.component.TooltipDisplay; import org.geysermc.mcprotocollib.protocol.data.game.item.component.TypedEntityData; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Unit; import org.geysermc.mcprotocollib.protocol.data.game.item.component.UseCooldown; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.UseEffects; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Weapon; import org.geysermc.mcprotocollib.protocol.data.game.item.component.WritableBookContent; import org.geysermc.mcprotocollib.protocol.data.game.item.component.WrittenBookContent; @@ -101,8 +106,14 @@ public class DataComponentHashers { registerInt(DataComponentTypes.MAX_DAMAGE); registerInt(DataComponentTypes.DAMAGE); registerUnit(DataComponentTypes.UNBREAKABLE); + registerMap(DataComponentTypes.USE_EFFECTS, builder -> builder + .optional("can_sprint", MinecraftHasher.BOOL, UseEffects::canSprint, false) + .optional("interact_vibrations", MinecraftHasher.BOOL, UseEffects::interactVibrations, true) + .optional("speed_multiplier", MinecraftHasher.FLOAT, UseEffects::speedMultiplier, 0.2F)); // TODO test 1.21.11 register(DataComponentTypes.CUSTOM_NAME, ComponentHasher.COMPONENT); + register(DataComponentTypes.MINIMUM_ATTACK_CHARGE, MinecraftHasher.FLOAT); + register(DataComponentTypes.DAMAGE_TYPE, RegistryHasher.eitherHolderHasher(JavaRegistries.DAMAGE_TYPE)); register(DataComponentTypes.ITEM_NAME, ComponentHasher.COMPONENT); register(DataComponentTypes.ITEM_MODEL, MinecraftHasher.KEY); register(DataComponentTypes.LORE, ComponentHasher.COMPONENT.list()); @@ -154,6 +165,21 @@ public class DataComponentHashers { registerMap(DataComponentTypes.WEAPON, builder -> builder .optional("item_damage_per_attack", MinecraftHasher.INT, Weapon::itemDamagePerAttack, 1) .optional("disable_blocking_for_seconds", MinecraftHasher.FLOAT, Weapon::disableBlockingForSeconds, 0.0F)); + registerMap(DataComponentTypes.PIERCING_WEAPON, builder -> builder + .optional("deals_knockback", MinecraftHasher.BOOL, PiercingWeapon::dealsKnockback, true) + .optional("dismounts", MinecraftHasher.BOOL, PiercingWeapon::dealsKnockback, false) + .optionalNullable("sound", RegistryHasher.SOUND_EVENT, PiercingWeapon::sound) + .optionalNullable("hit_sound", RegistryHasher.SOUND_EVENT, PiercingWeapon::hitSound)); // TODO test 1.21.11 + registerMap(DataComponentTypes.ATTACK_RANGE, builder -> builder + .optional("min_reach", MinecraftHasher.FLOAT, AttackRange::minRange, 0.0F) + .optional("max_reach", MinecraftHasher.FLOAT, AttackRange::maxRange, 3.0F) + .optional("min_creative_reach", MinecraftHasher.FLOAT, AttackRange::minCreativeRange, 0.0F) + .optional("max_creative_reach", MinecraftHasher.FLOAT, AttackRange::maxCreativeRange, 5.0F) + .optional("hitbox_margin", MinecraftHasher.FLOAT, AttackRange::hitboxMargin, 0.3F) + .optional("mob_factor", MinecraftHasher.FLOAT, AttackRange::mobFactor, 1.0F)); // TODO test 1.21.11 + registerMap(DataComponentTypes.SWING_ANIMATION, builder -> builder + .optional("type", RegistryHasher.SWING_ANIMATION_TYPE, SwingAnimation::type, SwingAnimation.Type.WHACK) + .optional("duration", MinecraftHasher.INT, SwingAnimation::duration, 6)); // TODO test 1.21.11 registerMap(DataComponentTypes.ENCHANTABLE, builder -> builder .accept("value", MinecraftHasher.INT, Function.identity())); registerMap(DataComponentTypes.EQUIPPABLE, builder -> builder @@ -184,6 +210,16 @@ public class DataComponentHashers { .optionalNullable("bypassed_by", MinecraftHasher.TAG, BlocksAttacks::bypassedBy) .optionalNullable("block_sound", RegistryHasher.SOUND_EVENT, BlocksAttacks::blockSound) .optionalNullable("disabled_sound", RegistryHasher.SOUND_EVENT, BlocksAttacks::disableSound)); // TODO needs tests + registerMap(DataComponentTypes.KINETIC_WEAPON, builder -> builder + .optional("contact_cooldown_ticks", MinecraftHasher.INT, KineticWeapon::contactCooldownTicks, 10) + .optional("delay_ticks", MinecraftHasher.INT, KineticWeapon::contactCooldownTicks, 0) + .optionalNullable("dismount_conditions", RegistryHasher.KINETIC_WEAPON_CONDITION, KineticWeapon::dismountConditions) + .optionalNullable("knockback_conditions", RegistryHasher.KINETIC_WEAPON_CONDITION, KineticWeapon::knockbackConditions) + .optionalNullable("damage_conditions", RegistryHasher.KINETIC_WEAPON_CONDITION, KineticWeapon::damageConditions) + .optional("forward_movement", MinecraftHasher.FLOAT, KineticWeapon::forwardMovement, 0.0F) + .optional("damage_multiplier", MinecraftHasher.FLOAT, KineticWeapon::damageMultiplier, 1.0F) + .optionalNullable("sound", RegistryHasher.SOUND_EVENT, KineticWeapon::sound) + .optionalNullable("hit_sound", RegistryHasher.SOUND_EVENT, KineticWeapon::hitSound)); // TODO test 1.21.11 register(DataComponentTypes.STORED_ENCHANTMENTS, RegistryHasher.ITEM_ENCHANTMENTS); registerInt(DataComponentTypes.DYED_COLOR); @@ -267,8 +303,8 @@ public class DataComponentHashers { register(DataComponentTypes.RABBIT_VARIANT, RegistryHasher.RABBIT_VARIANT); register(DataComponentTypes.PIG_VARIANT, RegistryHasher.PIG_VARIANT); register(DataComponentTypes.COW_VARIANT, RegistryHasher.COW_VARIANT); - register(DataComponentTypes.CHICKEN_VARIANT, MinecraftHasher.KEY - .registryCast((session, holder) -> holder.getOrCompute(id -> JavaRegistries.CHICKEN_VARIANT.key(session, id)))); // Why, Mojang? + register(DataComponentTypes.CHICKEN_VARIANT, RegistryHasher.eitherHolderHasher(JavaRegistries.CHICKEN_VARIANT)); + register(DataComponentTypes.ZOMBIE_NAUTILUS_VARIANT, RegistryHasher.eitherHolderHasher(JavaRegistries.ZOMBIE_NAUTILUS_VARIANT)); // TODO test 1.21.11 register(DataComponentTypes.FROG_VARIANT, RegistryHasher.FROG_VARIANT); register(DataComponentTypes.HORSE_VARIANT, RegistryHasher.HORSE_VARIANT); register(DataComponentTypes.PAINTING_VARIANT, RegistryHasher.PAINTING_VARIANT.cast(Holder::id)); // This can and will throw when a direct holder was received, which is still possible due to a bug in 1.21.6. diff --git a/core/src/main/java/org/geysermc/geyser/item/hashing/RegistryHasher.java b/core/src/main/java/org/geysermc/geyser/item/hashing/RegistryHasher.java index f25d43480..aaadebe1c 100644 --- a/core/src/main/java/org/geysermc/geyser/item/hashing/RegistryHasher.java +++ b/core/src/main/java/org/geysermc/geyser/item/hashing/RegistryHasher.java @@ -67,10 +67,12 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.InstrumentCo import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemAttributeModifiers; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments; import org.geysermc.mcprotocollib.protocol.data.game.item.component.JukeboxPlayable; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.KineticWeapon; import org.geysermc.mcprotocollib.protocol.data.game.item.component.MobEffectDetails; import org.geysermc.mcprotocollib.protocol.data.game.item.component.MobEffectInstance; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ProvidesTrimMaterial; import org.geysermc.mcprotocollib.protocol.data.game.item.component.SuspiciousStewEffect; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.SwingAnimation; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ToolData; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Unit; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; @@ -328,6 +330,13 @@ public interface RegistryHasher extends MinecraftHasher { .accept("base", FLOAT, BlocksAttacks.ItemDamageFunction::base) .accept("factor", FLOAT, BlocksAttacks.ItemDamageFunction::factor)); + MinecraftHasher KINETIC_WEAPON_CONDITION = MinecraftHasher.mapBuilder(builder -> builder + .accept("max_duration_ticks", MinecraftHasher.INT, KineticWeapon.Condition::maxDurationTicks) + .optional("min_speed", MinecraftHasher.FLOAT, KineticWeapon.Condition::minSpeed, 0.0F) + .optional("min_relative_speed", MinecraftHasher.FLOAT, KineticWeapon.Condition::minRelativeSpeed, 0.0F)); + + MinecraftHasher SWING_ANIMATION_TYPE = MinecraftHasher.fromEnum(); + MinecraftHasher PROVIDES_TRIM_MATERIAL = MinecraftHasher.either(TRIM_MATERIAL.holder(), ProvidesTrimMaterial::materialHolder, KEY, ProvidesTrimMaterial::materialLocation); MinecraftHasher ARMOR_TRIM = MinecraftHasher.mapBuilder(builder -> builder @@ -455,6 +464,18 @@ public interface RegistryHasher extends MinecraftHasher { return hasher::hash; } + /** + * Creates a hasher that hashes a {@code Holder}, also known as an {@code EitherHolder} in Mojmap. + * + *

Please note that a {@code Holder} is only a valid representation of an {@code EitherHolder} in MCPL if the stream codec of the {@code EitherHolder} does not support directly encoding unregistered values.

+ * + * @param registry the registry the {@code Holder} is for. + * @return a hasher that hashes a {@code Holder} for the given registry. + */ + static MinecraftHasher> eitherHolderHasher(JavaRegistryKey registry) { + return MinecraftHasher.KEY.registryCast((registries, holder) -> holder.getOrCompute(id -> registry.key(registries, id))); + } + class RegistryHasherWithDirectHasher implements RegistryHasher { private final MinecraftHasher id; private final MinecraftHasher> holderHasher;