mirror of
https://github.com/GeyserMC/Geyser.git
synced 2026-01-06 15:41:50 +00:00
Item stack, use remainder component hashers, update mappings
This commit is contained in:
@@ -38,10 +38,12 @@ import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.EquipmentSlot;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.Consumable;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.CustomModelData;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.Equippable;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.FoodProperties;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet;
|
||||
@@ -112,7 +114,7 @@ public class ComponentHashers {
|
||||
.optional("sound", RegistryHasher.SOUND_EVENT, Consumable::sound, BuiltinSound.ENTITY_GENERIC_EAT)
|
||||
.optional("has_consume_particles", MinecraftHasher.BOOL, Consumable::hasConsumeParticles, true)); // TODO consume effect needs identifier in MCPL
|
||||
|
||||
// TODO use remainder needs item stack codec, recursion go brr
|
||||
register(DataComponentTypes.USE_REMAINDER, RegistryHasher.ITEM_STACK);
|
||||
|
||||
registerMap(DataComponentTypes.USE_COOLDOWN, builder -> builder
|
||||
.accept("seconds", MinecraftHasher.FLOAT, UseCooldown::seconds)
|
||||
@@ -120,7 +122,7 @@ public class ComponentHashers {
|
||||
registerMap(DataComponentTypes.DAMAGE_RESISTANT, builder -> builder
|
||||
.accept("types", MinecraftHasher.TAG, Function.identity()));
|
||||
registerMap(DataComponentTypes.TOOL, builder -> builder
|
||||
.acceptList("rules", MinecraftHasher.TOOL_RULE, ToolData::getRules)
|
||||
.acceptList("rules", RegistryHasher.TOOL_RULE, ToolData::getRules)
|
||||
.optional("default_mining_speed", MinecraftHasher.FLOAT, ToolData::getDefaultMiningSpeed, 1.0F)
|
||||
.optional("damage_per_block", MinecraftHasher.INT, ToolData::getDamagePerBlock, 1)
|
||||
.optional("can_destroy_blocks_in_creative", MinecraftHasher.BOOL, ToolData::isCanDestroyBlocksInCreative, true));
|
||||
@@ -160,7 +162,7 @@ public class ComponentHashers {
|
||||
registerMap(DataComponentTypes.POTION_CONTENTS, builder -> builder
|
||||
.optional("potion", RegistryHasher.POTION, PotionContents::getPotionId, -1)
|
||||
.optional("custom_color", MinecraftHasher.INT, PotionContents::getCustomColor, -1)
|
||||
.optionalList("custom_effects", MinecraftHasher.MOB_EFFECT_INSTANCE, PotionContents::getCustomEffects)
|
||||
.optionalList("custom_effects", RegistryHasher.MOB_EFFECT_INSTANCE, PotionContents::getCustomEffects)
|
||||
.optionalNullable("custom_name", MinecraftHasher.STRING, PotionContents::getCustomName));
|
||||
|
||||
register(DataComponentTypes.POTION_DURATION_SCALE, MinecraftHasher.FLOAT);
|
||||
@@ -185,10 +187,18 @@ public class ComponentHashers {
|
||||
hashers.put(component, hasher);
|
||||
}
|
||||
|
||||
public static <T> MinecraftHasher<T> hasherOrEmpty(DataComponentType<T> component) {
|
||||
MinecraftHasher<T> hasher = (MinecraftHasher<T>) hashers.get(component);
|
||||
if (hasher == null) {
|
||||
return MinecraftHasher.UNIT.convert(value -> Unit.INSTANCE);
|
||||
}
|
||||
return hasher;
|
||||
}
|
||||
|
||||
public static <T> HashCode hash(GeyserSession session, DataComponentType<T> component, T value) {
|
||||
MinecraftHasher<T> hasher = (MinecraftHasher<T>) hashers.get(component);
|
||||
if (hasher == null) {
|
||||
throw new IllegalStateException("Unregistered hasher for component " + component + "!");
|
||||
throw new IllegalStateException("Unregistered hasher for component " + component + "!"); // TODO we might not have hashers for every component, in which case, fix this
|
||||
}
|
||||
return hasher.hash(value, new MinecraftHashEncoder(session));
|
||||
}
|
||||
@@ -241,6 +251,13 @@ public class ComponentHashers {
|
||||
testHash(session, DataComponentTypes.FOOD, new FoodProperties(3, 5.7F, true), 1917653498);
|
||||
testHash(session, DataComponentTypes.FOOD, new FoodProperties(7, 0.15F, false), -184166204);
|
||||
|
||||
testHash(session, DataComponentTypes.USE_REMAINDER, new ItemStack(Items.MELON.javaId(), 52), -1279684916);
|
||||
|
||||
DataComponents specialComponents = new DataComponents(new HashMap<>());
|
||||
specialComponents.put(DataComponentTypes.ITEM_MODEL, MinecraftKey.key("testing"));
|
||||
specialComponents.put(DataComponentTypes.MAX_STACK_SIZE, 44);
|
||||
testHash(session, DataComponentTypes.USE_REMAINDER, new ItemStack(Items.PUMPKIN.javaId(), 32, specialComponents), 1991032843);
|
||||
|
||||
testHash(session, DataComponentTypes.DAMAGE_RESISTANT, MinecraftKey.key("testing"), -1230493835);
|
||||
|
||||
testHash(session, DataComponentTypes.TOOL, new ToolData(List.of(), 5.0F, 3, false), -1789071928);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
package org.geysermc.geyser.item.hashing;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.hash.HashCode;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
@@ -32,14 +33,13 @@ import org.geysermc.geyser.item.components.Rarity;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.EquipmentSlot;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.Consumable;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.MobEffectInstance;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.ToolData;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.Unit;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -75,21 +75,8 @@ public interface MinecraftHasher<T> {
|
||||
|
||||
MinecraftHasher<Consumable.ItemUseAnimation> ITEM_USE_ANIMATION = fromEnum();
|
||||
|
||||
MinecraftHasher<ToolData.Rule> TOOL_RULE = mapBuilder(builder -> builder
|
||||
.accept("blocks", RegistryHasher.BLOCK.holderSet(), ToolData.Rule::getBlocks)
|
||||
.optionalNullable("speed", MinecraftHasher.FLOAT, ToolData.Rule::getSpeed)
|
||||
.optionalNullable("correct_for_drops", MinecraftHasher.BOOL, ToolData.Rule::getCorrectForDrops));
|
||||
|
||||
MinecraftHasher<EquipmentSlot> EQUIPMENT_SLOT = fromEnum(); // FIXME MCPL enum constants aren't right
|
||||
|
||||
MinecraftHasher<MobEffectInstance> MOB_EFFECT_INSTANCE = mapBuilder(builder -> builder
|
||||
.accept("id", RegistryHasher.EFFECT, MobEffectInstance::getEffect)
|
||||
.optional("amplifier", BYTE, instance -> (byte) instance.getDetails().getAmplifier(), (byte) 0)
|
||||
.optional("duration", INT, instance -> instance.getDetails().getDuration(), 0)
|
||||
.optional("ambient", BOOL, instance -> instance.getDetails().isAmbient(), false)
|
||||
.optional("show_particles", BOOL, instance -> instance.getDetails().isShowParticles(), true)
|
||||
.accept("show_icon", BOOL, instance -> instance.getDetails().isShowIcon())); // TODO check this, also hidden effect but is recursive
|
||||
|
||||
HashCode hash(T value, MinecraftHashEncoder encoder);
|
||||
|
||||
default MinecraftHasher<List<T>> list() {
|
||||
@@ -97,11 +84,15 @@ public interface MinecraftHasher<T> {
|
||||
}
|
||||
|
||||
default <F> MinecraftHasher<F> convert(Function<F, T> converter) {
|
||||
return (object, encoder) -> hash(converter.apply(object), encoder);
|
||||
return (value, encoder) -> hash(converter.apply(value), encoder);
|
||||
}
|
||||
|
||||
default <F> MinecraftHasher<F> sessionConvert(BiFunction<GeyserSession, F, T> converter) {
|
||||
return (object, encoder) -> hash(converter.apply(encoder.session(), object), encoder);
|
||||
return (value, encoder) -> hash(converter.apply(encoder.session(), value), encoder);
|
||||
}
|
||||
|
||||
static <T> MinecraftHasher<T> recursive(UnaryOperator<MinecraftHasher<T>> delegate) {
|
||||
return new Recursive<>(delegate);
|
||||
}
|
||||
|
||||
static <T extends Enum<T>> MinecraftHasher<Integer> fromIdEnum(T[] values, Function<T, String> toName) {
|
||||
@@ -114,7 +105,7 @@ public interface MinecraftHasher<T> {
|
||||
}
|
||||
|
||||
static <T> MinecraftHasher<T> mapBuilder(UnaryOperator<MapHasher<T>> builder) {
|
||||
return (object, encoder) -> builder.apply(new MapHasher<>(object, encoder)).build();
|
||||
return (value, encoder) -> builder.apply(new MapHasher<>(value, encoder)).build();
|
||||
}
|
||||
|
||||
static <K, V> MinecraftHasher<Map<K, V>> map(MinecraftHasher<K> keyHasher, MinecraftHasher<V> valueHasher) {
|
||||
@@ -122,4 +113,17 @@ public interface MinecraftHasher<T> {
|
||||
.map(entry -> Map.entry(keyHasher.hash(entry.getKey(), encoder), valueHasher.hash(entry.getValue(), encoder)))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
|
||||
}
|
||||
|
||||
class Recursive<T> implements MinecraftHasher<T> {
|
||||
private final Supplier<MinecraftHasher<T>> delegate;
|
||||
|
||||
public Recursive(UnaryOperator<MinecraftHasher<T>> delegate) {
|
||||
this.delegate = Suppliers.memoize(() -> delegate.apply(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashCode hash(T value, MinecraftHashEncoder encoder) {
|
||||
return delegate.get().hash(value, encoder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,13 @@ import org.geysermc.geyser.session.cache.registry.JavaRegistryKey;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.Effect;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponent;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.MobEffectInstance;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.ToolData;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.sound.BuiltinSound;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.sound.CustomSound;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.level.sound.Sound;
|
||||
@@ -49,11 +54,32 @@ public interface RegistryHasher extends MinecraftHasher<Integer> {
|
||||
|
||||
RegistryHasher ENCHANTMENT = registry(JavaRegistries.ENCHANTMENT);
|
||||
|
||||
MinecraftHasher<DataComponentType<?>> DATA_COMPONENT_TYPE = KEY.convert(DataComponentType::getKey);
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"}) // Java generics :(
|
||||
MinecraftHasher<DataComponent<?, ?>> DATA_COMPONENT = (component, encoder) -> {
|
||||
MinecraftHasher hasher = ComponentHashers.hasherOrEmpty(component.getType());
|
||||
return hasher.hash(component.getValue(), encoder);
|
||||
};
|
||||
|
||||
MinecraftHasher<DataComponents> DATA_COMPONENTS = MinecraftHasher.map(RegistryHasher.DATA_COMPONENT_TYPE, DATA_COMPONENT).convert(DataComponents::getDataComponents); // TODO component removals (needs unit value and ! component prefix)
|
||||
|
||||
MinecraftHasher<ItemStack> ITEM_STACK = MinecraftHasher.mapBuilder(builder -> builder
|
||||
.accept("id", ITEM, ItemStack::getId)
|
||||
.accept("count", INT, ItemStack::getAmount)
|
||||
.optionalNullable("components", DATA_COMPONENTS, ItemStack::getDataComponentsPatch));
|
||||
|
||||
MinecraftHasher<Effect> EFFECT = enumRegistry();
|
||||
|
||||
RegistryHasher POTION = enumIdRegistry(Potion.values());
|
||||
MinecraftHasher<MobEffectInstance> MOB_EFFECT_INSTANCE = MinecraftHasher.mapBuilder(builder -> builder
|
||||
.accept("id", RegistryHasher.EFFECT, MobEffectInstance::getEffect)
|
||||
.optional("amplifier", BYTE, instance -> (byte) instance.getDetails().getAmplifier(), (byte) 0)
|
||||
.optional("duration", INT, instance -> instance.getDetails().getDuration(), 0)
|
||||
.optional("ambient", BOOL, instance -> instance.getDetails().isAmbient(), false)
|
||||
.optional("show_particles", BOOL, instance -> instance.getDetails().isShowParticles(), true)
|
||||
.accept("show_icon", BOOL, instance -> instance.getDetails().isShowIcon())); // TODO check this, also hidden effect but is recursive
|
||||
|
||||
MinecraftHasher<DataComponentType<?>> DATA_COMPONENT_TYPE = KEY.convert(DataComponentType::getKey);
|
||||
RegistryHasher POTION = enumIdRegistry(Potion.values());
|
||||
|
||||
MinecraftHasher<BuiltinSound> BUILTIN_SOUND = KEY.convert(sound -> MinecraftKey.key(sound.getName()));
|
||||
|
||||
@@ -68,6 +94,11 @@ public interface RegistryHasher extends MinecraftHasher<Integer> {
|
||||
return CUSTOM_SOUND.hash((CustomSound) sound, encoder);
|
||||
};
|
||||
|
||||
MinecraftHasher<ToolData.Rule> TOOL_RULE = MinecraftHasher.mapBuilder(builder -> builder
|
||||
.accept("blocks", RegistryHasher.BLOCK.holderSet(), ToolData.Rule::getBlocks)
|
||||
.optionalNullable("speed", MinecraftHasher.FLOAT, ToolData.Rule::getSpeed)
|
||||
.optionalNullable("correct_for_drops", MinecraftHasher.BOOL, ToolData.Rule::getCorrectForDrops));
|
||||
|
||||
static RegistryHasher registry(JavaRegistryKey<?> registry) {
|
||||
MinecraftHasher<Integer> hasher = KEY.sessionConvert(registry::keyFromNetworkId);
|
||||
return hasher::hash;
|
||||
|
||||
Submodule core/src/main/resources/mappings updated: 7654aabd95...a3a2a30fe9
Reference in New Issue
Block a user