Skip to content

Commit

Permalink
Implement enchantment effect component types
Browse files Browse the repository at this point in the history
  • Loading branch information
booky10 committed Jul 1, 2024
1 parent 31447cb commit 8908cce
Show file tree
Hide file tree
Showing 9 changed files with 340 additions and 72 deletions.
2 changes: 2 additions & 0 deletions api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ mappingCompression {

compress("command/argument_parser_mappings.json")

compress("enchantment/effect_component_type.json")

compress("entity/entity_data_type_mappings.json")
compress("entity/painting_mappings.json")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,31 @@
package com.github.retrooper.packetevents.protocol.component;

import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;

public interface ComponentType<T> extends MappedEntity {

T read(PacketWrapper<?> wrapper);

void write(PacketWrapper<?> wrapper, T content);

default T decode(NBT nbt, ClientVersion version) {
throw new UnsupportedOperationException();
}

default NBT encode(T value, ClientVersion version) {
throw new UnsupportedOperationException();
}

interface Decoder<T> {

T decode(NBT nbt, ClientVersion version);
}

interface Encoder<T> {

NBT encode(T value, ClientVersion version);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,85 +56,51 @@
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.util.Dummy;
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.PacketWrapper.Reader;
import com.github.retrooper.packetevents.wrapper.PacketWrapper.Writer;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;

public class ComponentTypes {
/**
* Contains all item data component types.
*
* @see EnchantEffectComponentTypes
*/
public final class ComponentTypes {

private static final VersionedRegistry<ComponentType<?>> REGISTRY = new VersionedRegistry<>(
"data_component_type", "item/item_component_mappings");

private static final Map<String, ComponentType<?>> COMPONENT_TYPE_MAP = new HashMap<>();
private static final Map<Byte, Map<Integer, ComponentType<?>>> COMPONENT_TYPE_ID_MAP = new HashMap<>();
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("item/item_component_mappings");
private ComponentTypes() {
}

@ApiStatus.Internal
public static <T> ComponentType<T> define(String key) {
return define(key, null, null);
}

@ApiStatus.Internal
public static <T> ComponentType<T> define(String key, @Nullable Reader<T> reader, @Nullable Writer<T> writer) {
TypesBuilderData data = TYPES_BUILDER.define(key);
ComponentType<T> type = new ComponentType<T>() {
@Override
public T read(PacketWrapper<?> wrapper) {
return reader == null ? null : reader.apply(wrapper);
}

@Override
public void write(PacketWrapper<?> wrapper, T content) {
if (writer != null) {
writer.accept(wrapper, content);
}
}

@Override
public ResourceLocation getName() {
return data.getName();
}

@Override
public int getId(ClientVersion version) {
return MappingHelper.getId(version, TYPES_BUILDER, data);
}

@Override
public boolean equals(Object obj) {
if (obj instanceof ComponentType<?>) {
return this.getName().equals(((ComponentType<?>) obj).getName());
}
return false;
}

@Override
public String toString() {
return "Component[" + this.getName() + "]";
}
};
return REGISTRY.define(key, data -> new StaticComponentType<>(data, reader, writer));
}

MappingHelper.registerMapping(TYPES_BUILDER, COMPONENT_TYPE_MAP, COMPONENT_TYPE_ID_MAP, type);
return type;
public static VersionedRegistry<ComponentType<?>> getRegistry() {
return REGISTRY;
}

// with key
public static ComponentType<?> getByName(String name) {
return COMPONENT_TYPE_MAP.get(name);
return REGISTRY.getByName(name);
}

public static ComponentType<?> getById(ClientVersion version, int id) {
int index = TYPES_BUILDER.getDataIndex(version);
Map<Integer, ComponentType<?>> idMap = COMPONENT_TYPE_ID_MAP.get((byte) index);
return idMap.get(id);
return REGISTRY.getById(version, id);
}

// item component types
public static final ComponentType<NBTCompound> CUSTOM_DATA = define("custom_data",
// mojang wraps their "persistent" codec as a stream codec just here,
// so packetevents has to handle nbt strings
Expand Down Expand Up @@ -260,16 +226,10 @@ public static ComponentType<?> getById(ClientVersion version, int id) {
* @return Component Types
*/
public static Collection<ComponentType<?>> values() {
return Collections.unmodifiableCollection(COMPONENT_TYPE_MAP.values());
return REGISTRY.getEntries();
}

static {
TYPES_BUILDER.unloadFileMappings();
REGISTRY.unloadMappings();
}

@FunctionalInterface
public interface Reader<T> extends Function<PacketWrapper<?>, T> {}

@FunctionalInterface
public interface Writer<T> extends BiConsumer<PacketWrapper<?>, T> {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* 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.component;

import com.github.retrooper.packetevents.protocol.component.ComponentType.Decoder;
import com.github.retrooper.packetevents.protocol.component.ComponentType.Encoder;
import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;

/**
* Contains all enchantment effect component types.
*
* @see ComponentTypes
*/
public final class EnchantEffectComponentTypes {

private static final VersionedRegistry<ComponentType<?>> REGISTRY = new VersionedRegistry<>(
"enchantment_effect_component_type", "enchantment/effect_component_type");

private EnchantEffectComponentTypes() {
}

@ApiStatus.Internal
public static <T> ComponentType<T> define(String key) {
return define(key, null, null);
}

@ApiStatus.Internal
public static <T> ComponentType<T> define(String key, @Nullable Decoder<T> reader, @Nullable Encoder<T> writer) {
return REGISTRY.define(key, data -> new StaticComponentType<>(data, reader, writer));
}

public static VersionedRegistry<ComponentType<?>> getRegistry() {
return REGISTRY;
}

// just pass everything through for now
public static ComponentType<NBT> DAMAGE_PROTECTION = define("damage_protection",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> DAMAGE_IMMUNITY = define("damage_immunity",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> DAMAGE = define("damage",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> SMASH_DAMAGE_PER_FALLEN_BLOCK = define("smash_damage_per_fallen_block",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> KNOCKBACK = define("knockback",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> ARMOR_EFFECTIVENESS = define("armor_effectiveness",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> POST_ATTACK = define("post_attack",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> HIT_BLOCK = define("hit_block",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> ITEM_DAMAGE = define("item_damage",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> ATTRIBUTES = define("attributes",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> EQUIPMENT_DROPS = define("equipment_drops",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> LOCATION_CHANGED = define("location_changed",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> TICK = define("tick",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> AMMO_USE = define("ammo_use",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> PROJECTILE_PIERCING = define("projectile_piercing",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> PROJECTILE_SPAWNED = define("projectile_spawned",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> PROJECTILE_SPREAD = define("projectile_spread",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> PROJECTILE_COUNT = define("projectile_count",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> TRIDENT_RETURN_ACCELERATION = define("trident_return_acceleration",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> FISHING_TIME_REDUCTION = define("fishing_time_reduction",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> FISHING_LUCK_BONUS = define("fishing_luck_bonus",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> BLOCK_EXPERIENCE = define("block_experience",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> MOB_EXPERIENCE = define("mob_experience",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> REPAIR_WITH_XP = define("repair_with_xp",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> CROSSBOW_CHARGE_TIME = define("crossbow_charge_time",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> CROSSBOW_CHARGING_SOUNDS = define("crossbow_charging_sounds",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> TRIDENT_SOUND = define("trident_sound",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> PREVENT_EQUIPMENT_DROP = define("prevent_equipment_drop",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> PREVENT_ARMOR_CHANGE = define("prevent_armor_change",
(nbt, version) -> nbt, (val, version) -> val);
public static ComponentType<NBT> TRIDENT_SPIN_ATTACK_STRENGTH = define("trident_spin_attack_strength",
(nbt, version) -> nbt, (val, version) -> val);

static {
REGISTRY.unloadMappings();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,44 @@

package com.github.retrooper.packetevents.protocol.component;

import com.github.retrooper.packetevents.protocol.nbt.NBT;
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.util.mappings.IRegistry;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;

import java.util.Map;
import java.util.Optional;

public interface IComponentMap {

@SuppressWarnings("unchecked") // safe in this case
static StaticComponentMap decode(NBT nbt, ClientVersion version, IRegistry<? extends ComponentType<?>> registry) {
NBTCompound compound = (NBTCompound) nbt;
StaticComponentMap.Builder components = StaticComponentMap.builder();
for (Map.Entry<String, NBT> entry : compound.getTags().entrySet()) {
ComponentType<?> type = registry.getByName(entry.getKey());
if (type == null) {
throw new IllegalStateException("Unknown component type named " + entry.getKey() + " encountered");
}
Object value = type.decode(entry.getValue(), version);
components.set((ComponentType<? super Object>) type, value);
}
return components.build();
}

@SuppressWarnings("unchecked") // safe in this case
static NBT encode(StaticComponentMap components, ClientVersion version) {
NBTCompound compound = new NBTCompound();
for (Map.Entry<ComponentType<?>, ?> entry : components.getDelegate().entrySet()) {
String key = entry.getKey().getName().toString();
NBT value = ((ComponentType<? super Object>) entry.getKey()).encode(entry.getValue(), version);
compound.setTag(key, value);
}
return compound;
}

default <T> Optional<T> getOptional(ComponentType<T> type) {
return Optional.ofNullable(this.get(type));
}
Expand Down
Loading

0 comments on commit 8908cce

Please sign in to comment.