Implement more component types

This commit is contained in:
booky10 committed 2024-04-16 13:28:28 +02:00
1 parent 4a5382b14c
commit 5eb7d5b3fc
12 files changed
+655 -81

No files matched your search

@@ -0,0 +1,26 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.attribute;
// Created by booky10 in packetevents (12:55 16.04.2024.)
public enum AttributeOperation {
ADDITION,
MULTIPLY_BASE,
MULTIPLY_TOTAL,
}
@@ -18,9 +18,13 @@
package com.github.retrooper.packetevents.protocol.item.component;
import com.github.retrooper.packetevents.protocol.item.component.builtin.AdventureModePredicate;
import com.github.retrooper.packetevents.protocol.item.component.builtin.ItemAdventurePredicate;
import com.github.retrooper.packetevents.protocol.item.component.builtin.ItemAttributeModifiers;
import com.github.retrooper.packetevents.protocol.item.component.builtin.ItemDyeColor;
import com.github.retrooper.packetevents.protocol.item.component.builtin.ItemEnchantments;
import com.github.retrooper.packetevents.protocol.item.component.builtin.ItemFoodProperties;
import com.github.retrooper.packetevents.protocol.item.component.builtin.ItemRarity;
import com.github.retrooper.packetevents.protocol.item.component.builtin.ItemTool;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
@@ -115,31 +119,39 @@ public class ComponentTypes {
(wrapper, lines) -> wrapper.writeList(lines, PacketWrapper::writeComponent)
);
public static final ComponentType<ItemRarity> RARITY = define("rarity",
wrapper -> ItemRarity.values()[wrapper.readVarInt()],
(wrapper, rarity) -> wrapper.writeVarInt(rarity.ordinal())
);
wrapper -> wrapper.readEnum(ItemRarity.values()), PacketWrapper::writeEnum);
public static final ComponentType<ItemEnchantments> ENCHANTMENTS = define("enchantments",
ItemEnchantments::read, ItemEnchantments::write);
public static final ComponentType<AdventureModePredicate> CAN_PLACE_ON = define("can_place_on",
AdventureModePredicate::read, AdventureModePredicate::write);
public static final ComponentType<AdventureModePredicate> CAN_BREAK = define("can_break",
AdventureModePredicate::read, AdventureModePredicate::write);
public static final ComponentType<Void> ATTRIBUTE_MODIFIERS = define("attribute_modifiers");
public static final ComponentType<Void> CUSTOM_MODEL_DATA = define("custom_model_data");
public static final ComponentType<ItemAdventurePredicate> CAN_PLACE_ON = define("can_place_on",
ItemAdventurePredicate::read, ItemAdventurePredicate::write);
public static final ComponentType<ItemAdventurePredicate> CAN_BREAK = define("can_break",
ItemAdventurePredicate::read, ItemAdventurePredicate::write);
public static final ComponentType<ItemAttributeModifiers> ATTRIBUTE_MODIFIERS = define("attribute_modifiers",
ItemAttributeModifiers::read, ItemAttributeModifiers::write);
public static final ComponentType<Integer> CUSTOM_MODEL_DATA = define("custom_model_data",
PacketWrapper::readVarInt, PacketWrapper::writeVarInt);
public static final ComponentType<Void> HIDE_ADDITIONAL_TOOLTIP = define("hide_additional_tooltip");
public static final ComponentType<Void> HIDE_TOOLTIP = define("hide_tooltip");
public static final ComponentType<Void> REPAIR_COST = define("repair_cost");
public static final ComponentType<Integer> REPAIR_COST = define("repair_cost",
PacketWrapper::readVarInt, PacketWrapper::writeVarInt);
public static final ComponentType<Void> CREATIVE_SLOT_LOCK = define("creative_slot_lock");
public static final ComponentType<Void> ENCHANTMENT_GLINT_OVERRIDE = define("enchantment_glint_override");
public static final ComponentType<Void> INTANGIBLE_PROJECTILE = define("intangible_projectile");
public static final ComponentType<Void> FOOD = define("food");
public static final ComponentType<Boolean> ENCHANTMENT_GLINT_OVERRIDE = define("enchantment_glint_override",
PacketWrapper::readBoolean, PacketWrapper::writeBoolean);
public static final ComponentType<Void> INTANGIBLE_PROJECTILE = define("intangible_projectile"); // not synchronized
public static final ComponentType<ItemFoodProperties> FOOD = define("food",
ItemFoodProperties::read, ItemFoodProperties::write);
public static final ComponentType<Void> FIRE_RESISTANT = define("fire_resistant");
public static final ComponentType<Void> TOOL = define("tool");
public static final ComponentType<Void> STORED_ENCHANTMENTS = define("stored_enchantments");
public static final ComponentType<Void> DYED_COLOR = define("dyed_color");
public static final ComponentType<Void> MAP_COLOR = define("map_color");
public static final ComponentType<Void> MAP_ID = define("map_id");
public static final ComponentType<Void> MAP_DECORATIONS = define("map_decorations");
public static final ComponentType<ItemTool> TOOL = define("tool",
ItemTool::read, ItemTool::write);
public static final ComponentType<ItemEnchantments> STORED_ENCHANTMENTS = define("stored_enchantments",
ItemEnchantments::read, ItemEnchantments::write);
public static final ComponentType<ItemDyeColor> DYED_COLOR = define("dyed_color",
ItemDyeColor::read, ItemDyeColor::write);
public static final ComponentType<Integer> MAP_COLOR = define("map_color",
PacketWrapper::readInt, PacketWrapper::writeInt);
public static final ComponentType<Integer> MAP_ID = define("map_id",
PacketWrapper::readVarInt, PacketWrapper::writeVarInt);
public static final ComponentType<Void> MAP_DECORATIONS = define("map_decorations"); // not synchronized
public static final ComponentType<Void> MAP_POST_PROCESSING = define("map_post_processing");
public static final ComponentType<Void> CHARGED_PROJECTILES = define("charged_projectiles");
public static final ComponentType<Void> BUNDLE_CONTENTS = define("bundle_contents");
@@ -148,13 +160,13 @@ public class ComponentTypes {
public static final ComponentType<Void> WRITABLE_BOOK_CONTENT = define("writable_book_content");
public static final ComponentType<Void> WRITTEN_BOOK_CONTENT = define("written_book_content");
public static final ComponentType<Void> TRIM = define("trim");
public static final ComponentType<Void> DEBUG_STICK_STATE = define("debug_stick_state");
public static final ComponentType<Void> DEBUG_STICK_STATE = define("debug_stick_state"); // not synchronized
public static final ComponentType<Void> ENTITY_DATA = define("entity_data");
public static final ComponentType<Void> BUCKET_ENTITY_DATA = define("bucket_entity_data");
public static final ComponentType<Void> BLOCK_ENTITY_DATA = define("block_entity_data");
public static final ComponentType<Void> INSTRUMENT = define("instrument");
public static final ComponentType<Void> OMINOUS_BOTTLE_AMPLIFIER = define("ominous_bottle_amplifier");
public static final ComponentType<Void> RECIPES = define("recipes");
public static final ComponentType<Void> RECIPES = define("recipes"); // not synchronized
public static final ComponentType<Void> LODESTONE_TRACKER = define("lodestone_tracker");
public static final ComponentType<Void> FIREWORK_EXPLOSION = define("firework_explosion");
public static final ComponentType<Void> FIREWORKS = define("fireworks");
@@ -166,8 +178,8 @@ public class ComponentTypes {
public static final ComponentType<Void> CONTAINER = define("container");
public static final ComponentType<Void> BLOCK_STATE = define("block_state");
public static final ComponentType<Void> BEES = define("bees");
public static final ComponentType<Void> LOCK = define("lock");
public static final ComponentType<Void> CONTAINER_LOOT = define("container_loot");
public static final ComponentType<Void> LOCK = define("lock"); // not synchronized
public static final ComponentType<Void> CONTAINER_LOOT = define("container_loot"); // not synchronized
static {
TYPES_BUILDER.unloadFileMappings();
@@ -18,46 +18,44 @@
package com.github.retrooper.packetevents.protocol.item.component.builtin;
import com.github.retrooper.packetevents.protocol.mapper.GenericMappedEntity;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
// comment before implementing this: why do I have to implement this mess, I just want to deserialize items
// comment after implementing this: why did I have to implement this mess, I just want to deserialize items
public class AdventureModePredicate {
// why do I have to implement this mess, I just want to deserialize items
public class ItemAdventurePredicate {
private final List<BlockPredicate> predicates;
private final boolean showInTooltip;
public AdventureModePredicate(List<BlockPredicate> predicates, boolean showInTooltip) {
public ItemAdventurePredicate(List<BlockPredicate> predicates, boolean showInTooltip) {
this.predicates = predicates;
this.showInTooltip = showInTooltip;
}
public static AdventureModePredicate read(PacketWrapper<?> wrapper) {
public static ItemAdventurePredicate read(PacketWrapper<?> wrapper) {
List<BlockPredicate> predicates = wrapper.readList(BlockPredicate::read);
boolean showInTooltip = wrapper.readBoolean();
return new AdventureModePredicate(predicates, showInTooltip);
return new ItemAdventurePredicate(predicates, showInTooltip);
}
public static void write(PacketWrapper<?> wrapper, AdventureModePredicate predicate) {
public static void write(PacketWrapper<?> wrapper, ItemAdventurePredicate predicate) {
wrapper.writeList(predicate.predicates, BlockPredicate::write);
wrapper.writeBoolean(predicate.showInTooltip);
}
public static class BlockPredicate {
private final Optional<GenericHolderSet> blocks;
private final Optional<MappedEntitySet> blocks;
private final Optional<List<PropertyMatcher>> properties;
private final Optional<NBTCompound> nbt;
public BlockPredicate(
Optional<GenericHolderSet> blocks,
Optional<MappedEntitySet> blocks,
Optional<List<PropertyMatcher>> properties,
Optional<NBTCompound> nbt
) {
@@ -67,8 +65,9 @@ public class AdventureModePredicate {
}
public static BlockPredicate read(PacketWrapper<?> wrapper) {
Optional<GenericHolderSet> blocks = Optional.ofNullable(
wrapper.readOptional(GenericHolderSet::read));
Optional<MappedEntitySet> blocks = Optional.ofNullable(
wrapper.readOptional(ew -> MappedEntitySet.read(ew,
GenericMappedEntity::getById)));
Optional<List<PropertyMatcher>> properties = Optional.ofNullable(
wrapper.readList(PropertyMatcher::read));
Optional<NBTCompound> nbt = Optional.ofNullable(wrapper.readNBT());
@@ -76,53 +75,13 @@ public class AdventureModePredicate {
}
public static void write(PacketWrapper<?> wrapper, BlockPredicate predicate) {
wrapper.writeOptional(predicate.blocks.orElse(null), GenericHolderSet::write);
wrapper.writeOptional(predicate.blocks.orElse(null), MappedEntitySet::write);
wrapper.writeOptional(predicate.properties.orElse(null),
(ew, val) -> ew.writeList(val, PropertyMatcher::write));
wrapper.writeOptional(predicate.nbt.orElse(null), PacketWrapper::writeNBT);
}
}
public static class GenericHolderSet {
private final @Nullable ResourceLocation tagLoc;
private final @Nullable List<Integer> holderIds;
public GenericHolderSet(@Nullable ResourceLocation tagLoc, @Nullable List<Integer> holderIds) {
if (tagLoc == null && holderIds == null) {
throw new IllegalArgumentException("Illegal generic holder set: one of tagLoc or holderIds has to be set");
}
this.tagLoc = tagLoc;
this.holderIds = holderIds;
}
public static GenericHolderSet read(PacketWrapper<?> wrapper) {
int count = wrapper.readVarInt() - 1;
if (count == -1) {
return new GenericHolderSet(wrapper.readIdentifier(), null);
}
List<Integer> holderIds = new ArrayList<>(Math.min(count, 65536));
for (int i = 0; i < count; i++) {
holderIds.add(wrapper.readVarInt());
}
return new GenericHolderSet(null, holderIds);
}
public static void write(PacketWrapper<?> wrapper, GenericHolderSet set) {
if (set.tagLoc != null) {
wrapper.writeByte(0);
wrapper.writeIdentifier(set.tagLoc);
return;
}
assert set.holderIds != null; // can't be null, verified in ctor
wrapper.writeVarInt(set.holderIds.size() + 1);
for (int holderId : set.holderIds) {
wrapper.writeVarInt(holderId);
}
}
}
public static class PropertyMatcher {
private final String name;
@@ -0,0 +1,118 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.item.component.builtin;
import com.github.retrooper.packetevents.protocol.attribute.Attribute;
import com.github.retrooper.packetevents.protocol.attribute.AttributeOperation;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.List;
import java.util.UUID;
public class ItemAttributeModifiers {
private final List<ModifierEntry> modifiers;
private final boolean showInTooltip;
public ItemAttributeModifiers(List<ModifierEntry> modifiers, boolean showInTooltip) {
this.modifiers = modifiers;
this.showInTooltip = showInTooltip;
}
public static ItemAttributeModifiers read(PacketWrapper<?> wrapper) {
List<ModifierEntry> modifiers = wrapper.readList(ModifierEntry::read);
boolean showInTooltip = wrapper.readBoolean();
return new ItemAttributeModifiers(modifiers, showInTooltip);
}
public static void write(PacketWrapper<?> wrapper, ItemAttributeModifiers modifiers) {
wrapper.writeList(modifiers.modifiers, ModifierEntry::write);
wrapper.writeBoolean(modifiers.showInTooltip);
}
public static class ModifierEntry {
private final Attribute attribute;
private final Modifier modifier;
private final EquipmentSlotGroup slotGroup;
public ModifierEntry(Attribute attribute, Modifier modifier, EquipmentSlotGroup slotGroup) {
this.attribute = attribute;
this.modifier = modifier;
this.slotGroup = slotGroup;
}
public static ModifierEntry read(PacketWrapper<?> wrapper) {
Attribute attribute = wrapper.readMappedEntity(Attributes::getById);
Modifier modifier = Modifier.read(wrapper);
EquipmentSlotGroup slot = wrapper.readEnum(EquipmentSlotGroup.values());
return new ModifierEntry(attribute, modifier, slot);
}
public static void write(PacketWrapper<?> wrapper, ModifierEntry entry) {
wrapper.writeMappedEntity(entry.attribute);
Modifier.write(wrapper, entry.modifier);
wrapper.writeEnum(entry.slotGroup);
}
}
public static class Modifier {
private final UUID id;
private final String name;
private final double value;
private final AttributeOperation operation;
public Modifier(UUID id, String name, double value, AttributeOperation operation) {
this.id = id;
this.name = name;
this.value = value;
this.operation = operation;
}
public static Modifier read(PacketWrapper<?> wrapper) {
UUID id = wrapper.readUUID();
String name = wrapper.readString();
double value = wrapper.readDouble();
AttributeOperation operation = wrapper.readEnum(AttributeOperation.values());
return new Modifier(id, name, value, operation);
}
public static void write(PacketWrapper<?> wrapper, Modifier modifier) {
wrapper.writeUUID(modifier.id);
wrapper.writeString(modifier.name);
wrapper.writeDouble(modifier.value);
wrapper.writeEnum(modifier.operation);
}
}
public enum EquipmentSlotGroup {
ANY,
MAINHAND,
OFFHAND,
HAND,
FEET,
LEGS,
CHEST,
HEAD,
ARMOR,
BODY,
}
}
@@ -0,0 +1,43 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.item.component.builtin;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
public class ItemDyeColor {
private final int rgb;
private final boolean showInTooltip;
public ItemDyeColor(int rgb, boolean showInTooltip) {
this.rgb = rgb;
this.showInTooltip = showInTooltip;
}
public static ItemDyeColor read(PacketWrapper<?> wrapper) {
int rgb = wrapper.readInt();
boolean showInTooltip = wrapper.readBoolean();
return new ItemDyeColor(rgb, showInTooltip);
}
public static void write(PacketWrapper<?> wrapper, ItemDyeColor color) {
wrapper.writeInt(color.rgb);
wrapper.writeBoolean(color.showInTooltip);
}
}
@@ -0,0 +1,82 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.item.component.builtin;
import com.github.retrooper.packetevents.protocol.potion.PotionEffect;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import java.util.List;
public class ItemFoodProperties {
private final int nutrition;
private final float saturation;
private final boolean canAlwaysEat;
private final float eatSeconds;
private final List<PossibleEffect> effects;
public ItemFoodProperties(int nutrition, float saturation, boolean canAlwaysEat, float eatSeconds, List<PossibleEffect> effects) {
this.nutrition = nutrition;
this.saturation = saturation;
this.canAlwaysEat = canAlwaysEat;
this.eatSeconds = eatSeconds;
this.effects = effects;
}
public static ItemFoodProperties read(PacketWrapper<?> wrapper) {
int nutrition = wrapper.readVarInt();
float saturation = wrapper.readFloat();
boolean canAlwaysEat = wrapper.readBoolean();
float eatSeconds = wrapper.readFloat();
List<PossibleEffect> effects = wrapper.readList(PossibleEffect::read);
return new ItemFoodProperties(nutrition, saturation, canAlwaysEat, eatSeconds, effects);
}
public static void write(PacketWrapper<?> wrapper, ItemFoodProperties props) {
wrapper.writeVarInt(props.nutrition);
wrapper.writeFloat(props.saturation);
wrapper.writeBoolean(props.canAlwaysEat);
wrapper.writeFloat(props.eatSeconds);
wrapper.writeList(props.effects, PossibleEffect::write);
}
public static class PossibleEffect {
private final PotionEffect effect;
private final float probability;
public PossibleEffect(PotionEffect effect, float probability) {
this.effect = effect;
this.probability = probability;
}
public static PossibleEffect read(PacketWrapper<?> wrapper) {
PotionEffect effect = PotionEffect.read(wrapper);
float probability = wrapper.readFloat();
return new PossibleEffect(effect, probability);
}
public static void write(PacketWrapper<?> wrapper, PossibleEffect effect) {
PotionEffect.write(wrapper, effect.effect);
wrapper.writeFloat(effect.probability);
}
}
}
@@ -0,0 +1,78 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.item.component.builtin;
import com.github.retrooper.packetevents.protocol.mapper.GenericMappedEntity;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.List;
public class ItemTool {
private final List<Rule> rules;
private final float defaultMiningSpeed;
private final int damagePerBlock;
public ItemTool(List<Rule> rules, float defaultMiningSpeed, int damagePerBlock) {
this.rules = rules;
this.defaultMiningSpeed = defaultMiningSpeed;
this.damagePerBlock = damagePerBlock;
}
public static ItemTool read(PacketWrapper<?> wrapper) {
List<Rule> rules = wrapper.readList(Rule::read);
float defaultMiningSpeed = wrapper.readFloat();
int damagePerBlock = wrapper.readVarInt();
return new ItemTool(rules, defaultMiningSpeed, damagePerBlock);
}
public static void write(PacketWrapper<?> wrapper, ItemTool tool) {
wrapper.writeList(tool.rules, Rule::write);
wrapper.writeFloat(tool.defaultMiningSpeed);
wrapper.writeVarInt(tool.damagePerBlock);
}
public static class Rule {
private final MappedEntitySet blocks;
private final @Nullable Float speed;
private final @Nullable Boolean correctForDrops;
public Rule(MappedEntitySet blocks, @Nullable Float speed, @Nullable Boolean correctForDrops) {
this.blocks = blocks;
this.speed = speed;
this.correctForDrops = correctForDrops;
}
public static Rule read(PacketWrapper<?> wrapper) {
MappedEntitySet blocks = MappedEntitySet.read(wrapper, GenericMappedEntity::getById);
Float speed = wrapper.readOptional(PacketWrapper::readFloat);
Boolean correctForDrops = wrapper.readOptional(PacketWrapper::readBoolean);
return new Rule(blocks, speed, correctForDrops);
}
public static void write(PacketWrapper<?> wrapper, Rule rule) {
MappedEntitySet.write(wrapper, rule.blocks);
wrapper.writeOptional(rule.speed, PacketWrapper::writeFloat);
wrapper.writeOptional(rule.correctForDrops, PacketWrapper::writeBoolean);
}
}
}
@@ -0,0 +1,58 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.mapper;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
public class GenericMappedEntity implements StaticMappedEntity {
private final int id;
public GenericMappedEntity(ClientVersion ignoredVersion, int id) {
this(id);
}
public GenericMappedEntity(int id) {
this.id = id;
}
public static GenericMappedEntity getById(ClientVersion version, int id) {
return new GenericMappedEntity(version, id);
}
public static GenericMappedEntity read(PacketWrapper<?> wrapper) {
return wrapper.readMappedEntity(GenericMappedEntity::new);
}
public static void write(PacketWrapper<?> wrapper, GenericMappedEntity entity) {
wrapper.writeMappedEntity(entity);
}
@Override
public int getId() {
return this.id;
}
@Override
public ResourceLocation getName() {
throw new UnsupportedOperationException();
}
}
@@ -0,0 +1,75 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.mapper;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
/**
* Either a key to a specific tag or a list of possible entities.
*/
public class MappedEntitySet {
private final @Nullable ResourceLocation tagKey;
private final @Nullable List<MappedEntity> entities;
public MappedEntitySet(
@Nullable ResourceLocation tagKey,
@Nullable List<MappedEntity> entities
) {
if (tagKey == null && entities == null) {
throw new IllegalArgumentException("Illegal generic holder set: either tag key or holder ids have to be set");
}
this.tagKey = tagKey;
this.entities = entities;
}
public static <Z extends MappedEntity> MappedEntitySet read(
PacketWrapper<?> wrapper, BiFunction<ClientVersion, Integer, Z> getter) {
int count = wrapper.readVarInt() - 1;
if (count == -1) {
return new MappedEntitySet(wrapper.readIdentifier(), null);
}
List<MappedEntity> entities = new ArrayList<>(Math.min(count, 65536));
for (int i = 0; i < count; i++) {
entities.add(wrapper.readMappedEntity(getter));
}
return new MappedEntitySet(null, entities);
}
public static void write(PacketWrapper<?> wrapper, MappedEntitySet set) {
if (set.tagKey != null) {
wrapper.writeByte(0);
wrapper.writeIdentifier(set.tagKey);
return;
}
assert set.entities != null; // can't be null, verified in ctor
wrapper.writeVarInt(set.entities.size() + 1);
for (MappedEntity entity : set.entities) {
wrapper.writeMappedEntity(entity);
}
}
}
@@ -0,0 +1,97 @@
/*
* This file is part of packetevents - https://github.com/retrooper/packetevents
* Copyright (C) 2024 retrooper and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.retrooper.packetevents.protocol.potion;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Optional;
public class PotionEffect {
private final PotionType type;
private final Properties properties;
public PotionEffect(PotionType type, Properties properties) {
this.type = type;
this.properties = properties;
}
public static PotionEffect read(PacketWrapper<?> wrapper) {
PotionType type = wrapper.readMappedEntity(PotionTypes::getById);
Properties props = Properties.read(wrapper);
return new PotionEffect(type, props);
}
public static void write(PacketWrapper<?> wrapper, PotionEffect effect) {
wrapper.writeMappedEntity(effect.type);
Properties.write(wrapper, effect.properties);
}
public static class Properties {
private final int amplifier;
private final int duration;
private final boolean ambient;
private final boolean showParticles;
private final boolean showIcon;
private final @Nullable Properties hiddenEffect;
public Properties(
int amplifier, int duration, boolean ambient, boolean showParticles,
boolean showIcon, Optional<Properties> hiddenEffect
) {
this(
amplifier, duration, ambient, showParticles,
showIcon, hiddenEffect.orElse(null)
);
}
public Properties(
int amplifier, int duration, boolean ambient, boolean showParticles,
boolean showIcon, @Nullable Properties hiddenEffect
) {
this.amplifier = amplifier;
this.duration = duration;
this.ambient = ambient;
this.showParticles = showParticles;
this.showIcon = showIcon;
this.hiddenEffect = hiddenEffect;
}
public static Properties read(PacketWrapper<?> wrapper) {
int amplifier = wrapper.readVarInt();
int duration = wrapper.readVarInt();
boolean ambient = wrapper.readBoolean();
boolean showParticles = wrapper.readBoolean();
boolean showIcon = wrapper.readBoolean();
Properties hiddenEffect = wrapper.readOptional(Properties::read);
return new Properties(amplifier, duration, ambient, showParticles, showIcon, hiddenEffect);
}
public static void write(PacketWrapper<?> wrapper, Properties props) {
wrapper.writeVarInt(props.amplifier);
wrapper.writeVarInt(props.duration);
wrapper.writeBoolean(props.ambient);
wrapper.writeBoolean(props.showParticles);
wrapper.writeBoolean(props.showIcon);
wrapper.writeOptional(props.hiddenEffect, Properties::write);
}
}
}
@@ -96,6 +96,10 @@ public class PotionTypes {
return getById(id, version.toClientVersion());
}
public static @Nullable PotionType getById(ClientVersion version, int id) {
return getById(id, version);
}
public static @Nullable PotionType getById(int id, ClientVersion version) {
int index = TYPES_BUILDER.getDataIndex(version);
Map<Integer, PotionType> idMap = POTION_TYPE_ID_MAP.get((byte) index);
@@ -49,6 +49,7 @@ import com.github.retrooper.packetevents.protocol.item.component.ComponentTypes;
import com.github.retrooper.packetevents.protocol.item.component.PatchableComponentMap;
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.nbt.codec.NBTCodec;
@@ -90,6 +91,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.IntFunction;
@@ -1305,11 +1307,11 @@ public class PacketWrapper<T extends PacketWrapper<T>> {
}
}
public <R> R readOptional(Reader<R> reader) {
public <R> @Nullable R readOptional(Reader<R> reader) {
return this.readBoolean() ? reader.apply(this) : null;
}
public <V> void writeOptional(V value, Writer<V> writer) {
public <V> void writeOptional(@Nullable V value, Writer<V> writer) {
if (value != null) {
this.writeBoolean(true);
writer.accept(this, value);
@@ -1346,6 +1348,26 @@ public class PacketWrapper<T extends PacketWrapper<T>> {
}
}
public <Z extends Enum<?>> Z readEnum(Class<Z> clazz) {
return this.readEnum(clazz.getEnumConstants());
}
public <Z extends Enum<?>> Z readEnum(Z[] values) {
return values[this.readVarInt()];
}
public void writeEnum(Enum<?> value) {
this.writeVarInt(value.ordinal());
}
public <Z extends MappedEntity> Z readMappedEntity(BiFunction<ClientVersion, Integer, Z> getter) {
return getter.apply(this.serverVersion.toClientVersion(), this.readVarInt());
}
public void writeMappedEntity(MappedEntity entity) {
this.writeVarInt(entity.getId(this.serverVersion.toClientVersion()));
}
@FunctionalInterface
public interface Reader<T> extends Function<PacketWrapper<?>, T> {
}