#1279: Back Particle by a minecraft registry

By: DerFrZocker <derrieple@gmail.com>
This commit is contained in:
CraftBukkit/Spigot
2023-10-21 13:42:09 +11:00
parent 17c30fd4e2
commit e84271b31b
6 changed files with 456 additions and 230 deletions

View File

@@ -1,11 +1,10 @@
package org.bukkit.craftbukkit;
import com.google.common.base.Preconditions;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.core.BlockPosition;
import java.util.function.BiFunction;
import net.minecraft.core.IRegistry;
import net.minecraft.core.particles.DustColorTransitionOptions;
import net.minecraft.core.particles.ParticleParam;
import net.minecraft.core.particles.ParticleParamBlock;
@@ -15,15 +14,17 @@ import net.minecraft.core.particles.ParticleType;
import net.minecraft.core.particles.SculkChargeParticleOptions;
import net.minecraft.core.particles.ShriekParticleOption;
import net.minecraft.core.particles.VibrationParticleOption;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.MinecraftKey;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.gameevent.BlockPositionSource;
import net.minecraft.world.level.gameevent.EntityPositionSource;
import net.minecraft.world.level.gameevent.PositionSource;
import org.bukkit.Color;
import org.bukkit.Keyed;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.Particle;
import org.bukkit.Registry;
import org.bukkit.Vibration;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.block.data.CraftBlockData;
@@ -31,205 +32,184 @@ import org.bukkit.craftbukkit.entity.CraftEntity;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.util.CraftLocation;
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.MaterialData;
import org.joml.Vector3f;
public enum CraftParticle {
public abstract class CraftParticle<D> implements Keyed {
EXPLOSION_NORMAL("poof"),
EXPLOSION_LARGE("explosion"),
EXPLOSION_HUGE("explosion_emitter"),
FIREWORKS_SPARK("firework"),
WATER_BUBBLE("bubble"),
WATER_SPLASH("splash"),
WATER_WAKE("fishing"),
SUSPENDED("underwater"),
SUSPENDED_DEPTH("underwater"),
CRIT("crit"),
CRIT_MAGIC("enchanted_hit"),
SMOKE_NORMAL("smoke"),
SMOKE_LARGE("large_smoke"),
SPELL("effect"),
SPELL_INSTANT("instant_effect"),
SPELL_MOB("entity_effect"),
SPELL_MOB_AMBIENT("ambient_entity_effect"),
SPELL_WITCH("witch"),
DRIP_WATER("dripping_water"),
DRIP_LAVA("dripping_lava"),
VILLAGER_ANGRY("angry_villager"),
VILLAGER_HAPPY("happy_villager"),
TOWN_AURA("mycelium"),
NOTE("note"),
PORTAL("portal"),
ENCHANTMENT_TABLE("enchant"),
FLAME("flame"),
LAVA("lava"),
CLOUD("cloud"),
REDSTONE("dust"),
SNOWBALL("item_snowball"),
SNOW_SHOVEL("item_snowball"),
SLIME("item_slime"),
HEART("heart"),
ITEM_CRACK("item"),
BLOCK_CRACK("block"),
BLOCK_DUST("block"),
WATER_DROP("rain"),
MOB_APPEARANCE("elder_guardian"),
DRAGON_BREATH("dragon_breath"),
END_ROD("end_rod"),
DAMAGE_INDICATOR("damage_indicator"),
SWEEP_ATTACK("sweep_attack"),
FALLING_DUST("falling_dust"),
TOTEM("totem_of_undying"),
SPIT("spit"),
SQUID_INK("squid_ink"),
BUBBLE_POP("bubble_pop"),
CURRENT_DOWN("current_down"),
BUBBLE_COLUMN_UP("bubble_column_up"),
NAUTILUS("nautilus"),
DOLPHIN("dolphin"),
SNEEZE("sneeze"),
CAMPFIRE_COSY_SMOKE("campfire_cosy_smoke"),
CAMPFIRE_SIGNAL_SMOKE("campfire_signal_smoke"),
COMPOSTER("composter"),
FLASH("flash"),
FALLING_LAVA("falling_lava"),
LANDING_LAVA("landing_lava"),
FALLING_WATER("falling_water"),
DRIPPING_HONEY("dripping_honey"),
FALLING_HONEY("falling_honey"),
LANDING_HONEY("landing_honey"),
FALLING_NECTAR("falling_nectar"),
SOUL_FIRE_FLAME("soul_fire_flame"),
ASH("ash"),
CRIMSON_SPORE("crimson_spore"),
WARPED_SPORE("warped_spore"),
SOUL("soul"),
DRIPPING_OBSIDIAN_TEAR("dripping_obsidian_tear"),
FALLING_OBSIDIAN_TEAR("falling_obsidian_tear"),
LANDING_OBSIDIAN_TEAR("landing_obsidian_tear"),
REVERSE_PORTAL("reverse_portal"),
WHITE_ASH("white_ash"),
DUST_COLOR_TRANSITION("dust_color_transition"),
VIBRATION("vibration"),
FALLING_SPORE_BLOSSOM("falling_spore_blossom"),
SPORE_BLOSSOM_AIR("spore_blossom_air"),
SMALL_FLAME("small_flame"),
SNOWFLAKE("snowflake"),
DRIPPING_DRIPSTONE_LAVA("dripping_dripstone_lava"),
FALLING_DRIPSTONE_LAVA("falling_dripstone_lava"),
DRIPPING_DRIPSTONE_WATER("dripping_dripstone_water"),
FALLING_DRIPSTONE_WATER("falling_dripstone_water"),
GLOW_SQUID_INK("glow_squid_ink"),
GLOW("glow"),
WAX_ON("wax_on"),
WAX_OFF("wax_off"),
ELECTRIC_SPARK("electric_spark"),
SCRAPE("scrape"),
BLOCK_MARKER("block_marker"),
SONIC_BOOM("sonic_boom"),
SCULK_SOUL("sculk_soul"),
SCULK_CHARGE("sculk_charge"),
SCULK_CHARGE_POP("sculk_charge_pop"),
SHRIEK("shriek"),
CHERRY_LEAVES("cherry_leaves"),
EGG_CRACK("egg_crack"),
// ----- Legacy Separator -----
LEGACY_BLOCK_CRACK("block"),
LEGACY_BLOCK_DUST("block"),
LEGACY_FALLING_DUST("falling_dust");
private final MinecraftKey minecraftKey;
private final Particle bukkit;
private static final BiMap<Particle, MinecraftKey> particles;
private static final Map<Particle, Particle> aliases;
static {
particles = HashBiMap.create();
aliases = new HashMap<>();
for (CraftParticle particle : CraftParticle.values()) {
if (particles.containsValue(particle.minecraftKey)) {
aliases.put(particle.bukkit, particles.inverse().get(particle.minecraftKey));
} else {
particles.put(particle.bukkit, particle.minecraftKey);
}
}
}
private CraftParticle(String minecraftKey) {
this.minecraftKey = new MinecraftKey(minecraftKey);
this.bukkit = Particle.valueOf(this.name());
Preconditions.checkState(bukkit != null, "Bukkit particle %s does not exist", this.name());
}
public static ParticleParam toNMS(Particle bukkit) {
return toNMS(bukkit, null);
}
public static <T> ParticleParam toNMS(Particle particle, T obj) {
Particle canonical = particle;
if (aliases.containsKey(particle)) {
canonical = aliases.get(particle);
}
net.minecraft.core.particles.Particle nms = BuiltInRegistries.PARTICLE_TYPE.get(particles.get(canonical));
Preconditions.checkArgument(nms != null, "No NMS particle %s", particle);
if (particle.getDataType().equals(Void.class)) {
return (ParticleType) nms;
}
Preconditions.checkArgument(obj != null, "Particle %s requires data, null provided", particle);
if (particle.getDataType().equals(ItemStack.class)) {
ItemStack itemStack = (ItemStack) obj;
return new ParticleParamItem((net.minecraft.core.particles.Particle<ParticleParamItem>) nms, CraftItemStack.asNMSCopy(itemStack));
}
if (particle.getDataType() == MaterialData.class) {
MaterialData data = (MaterialData) obj;
return new ParticleParamBlock((net.minecraft.core.particles.Particle<ParticleParamBlock>) nms, CraftMagicNumbers.getBlock(data));
}
if (particle.getDataType() == BlockData.class) {
BlockData data = (BlockData) obj;
return new ParticleParamBlock((net.minecraft.core.particles.Particle<ParticleParamBlock>) nms, ((CraftBlockData) data).getState());
}
if (particle.getDataType() == Particle.DustOptions.class) {
Particle.DustOptions data = (Particle.DustOptions) obj;
Color color = data.getColor();
return new ParticleParamRedstone(new Vector3f(color.getRed() / 255.0f, color.getGreen() / 255.0f, color.getBlue() / 255.0f), data.getSize());
}
if (particle.getDataType() == Particle.DustTransition.class) {
Particle.DustTransition data = (Particle.DustTransition) obj;
Color from = data.getColor();
Color to = data.getToColor();
return new DustColorTransitionOptions(new Vector3f(from.getRed() / 255.0f, from.getGreen() / 255.0f, from.getBlue() / 255.0f), new Vector3f(to.getRed() / 255.0f, to.getGreen() / 255.0f, to.getBlue() / 255.0f), data.getSize());
}
if (particle.getDataType() == Vibration.class) {
Vibration vibration = (Vibration) obj;
PositionSource source;
if (vibration.getDestination() instanceof Vibration.Destination.BlockDestination) {
Location destination = ((Vibration.Destination.BlockDestination) vibration.getDestination()).getLocation();
source = new BlockPositionSource(CraftLocation.toBlockPosition(destination));
} else if (vibration.getDestination() instanceof Vibration.Destination.EntityDestination) {
Entity destination = ((CraftEntity) ((Vibration.Destination.EntityDestination) vibration.getDestination()).getEntity()).getHandle();
source = new EntityPositionSource(destination, destination.getEyeHeight());
} else {
throw new IllegalArgumentException("Unknown vibration destination " + vibration.getDestination());
}
return new VibrationParticleOption(source, vibration.getArrivalTime());
}
if (particle.getDataType() == Float.class) {
return new SculkChargeParticleOptions((Float) obj);
}
if (particle.getDataType() == Integer.class) {
return new ShriekParticleOption((Integer) obj);
}
throw new IllegalArgumentException(particle.getDataType().toString());
}
private static final Registry<CraftParticle<?>> CRAFT_PARTICLE_REGISTRY = new CraftParticleRegistry(CraftRegistry.getMinecraftRegistry(Registries.PARTICLE_TYPE));
public static Particle minecraftToBukkit(net.minecraft.core.particles.Particle<?> minecraft) {
return particles.inverse().get(BuiltInRegistries.PARTICLE_TYPE.getKey(minecraft));
Preconditions.checkArgument(minecraft != null);
IRegistry<net.minecraft.core.particles.Particle<?>> registry = CraftRegistry.getMinecraftRegistry(Registries.PARTICLE_TYPE);
Particle bukkit = Registry.PARTICLE_TYPE.get(CraftNamespacedKey.fromMinecraft(registry.getResourceKey(minecraft).orElseThrow().location()));
Preconditions.checkArgument(bukkit != null);
return bukkit;
}
public static net.minecraft.core.particles.Particle<?> bukkitToMinecraft(Particle bukkit) {
Preconditions.checkArgument(bukkit != null);
return CraftRegistry.getMinecraftRegistry(Registries.PARTICLE_TYPE)
.getOptional(CraftNamespacedKey.toMinecraft(bukkit.getKey())).orElseThrow();
}
public static <D> ParticleParam createParticleParam(Particle particle, D data) {
Preconditions.checkArgument(particle != null);
CraftParticle<D> craftParticle = (CraftParticle<D>) CRAFT_PARTICLE_REGISTRY.get(particle.getKey());
Preconditions.checkArgument(craftParticle != null);
return craftParticle.createParticleParam(data);
}
public static <T> T convertLegacy(T object) {
if (object instanceof MaterialData mat) {
return (T) CraftBlockData.fromData(CraftMagicNumbers.getBlock(mat));
}
return object;
}
public static Particle convertLegacy(Particle particle) {
return switch (particle) {
case LEGACY_BLOCK_DUST -> Particle.BLOCK_DUST;
case LEGACY_FALLING_DUST -> Particle.FALLING_DUST;
case LEGACY_BLOCK_CRACK -> Particle.BLOCK_CRACK;
default -> particle;
};
}
private final NamespacedKey key;
private final net.minecraft.core.particles.Particle<?> particle;
private final Class<D> clazz;
public CraftParticle(NamespacedKey key, net.minecraft.core.particles.Particle<?> particle, Class<D> clazz) {
this.key = key;
this.particle = particle;
this.clazz = clazz;
}
public net.minecraft.core.particles.Particle<?> getHandle() {
return particle;
}
public abstract ParticleParam createParticleParam(D data);
@Override
public NamespacedKey getKey() {
return key;
}
public static class CraftParticleRegistry extends CraftRegistry<CraftParticle<?>, net.minecraft.core.particles.Particle<?>> {
private static final Map<NamespacedKey, BiFunction<NamespacedKey, net.minecraft.core.particles.Particle<?>, CraftParticle<?>>> PARTICLE_MAP = new HashMap<>();
private static final BiFunction<NamespacedKey, net.minecraft.core.particles.Particle<?>, CraftParticle<?>> VOID_FUNCTION = (name, particle) -> new CraftParticle<>(name, particle, Void.class) {
@Override
public ParticleParam createParticleParam(Void data) {
return (ParticleType) getHandle();
}
};
static {
BiFunction<NamespacedKey, net.minecraft.core.particles.Particle<?>, CraftParticle<?>> dustOptionsFunction = (name, particle) -> new CraftParticle<>(name, particle, Particle.DustOptions.class) {
@Override
public ParticleParam createParticleParam(Particle.DustOptions data) {
Color color = data.getColor();
return new ParticleParamRedstone(new Vector3f(color.getRed() / 255.0f, color.getGreen() / 255.0f, color.getBlue() / 255.0f), data.getSize());
}
};
BiFunction<NamespacedKey, net.minecraft.core.particles.Particle<?>, CraftParticle<?>> itemStackFunction = (name, particle) -> new CraftParticle<>(name, particle, ItemStack.class) {
@Override
public ParticleParam createParticleParam(ItemStack data) {
return new ParticleParamItem((net.minecraft.core.particles.Particle<ParticleParamItem>) getHandle(), CraftItemStack.asNMSCopy(data));
}
};
BiFunction<NamespacedKey, net.minecraft.core.particles.Particle<?>, CraftParticle<?>> blockDataFunction = (name, particle) -> new CraftParticle<>(name, particle, BlockData.class) {
@Override
public ParticleParam createParticleParam(BlockData data) {
return new ParticleParamBlock((net.minecraft.core.particles.Particle<ParticleParamBlock>) getHandle(), ((CraftBlockData) data).getState());
}
};
BiFunction<NamespacedKey, net.minecraft.core.particles.Particle<?>, CraftParticle<?>> dustTransitionFunction = (name, particle) -> new CraftParticle<>(name, particle, Particle.DustTransition.class) {
@Override
public ParticleParam createParticleParam(Particle.DustTransition data) {
Color from = data.getColor();
Color to = data.getToColor();
return new DustColorTransitionOptions(new Vector3f(from.getRed() / 255.0f, from.getGreen() / 255.0f, from.getBlue() / 255.0f), new Vector3f(to.getRed() / 255.0f, to.getGreen() / 255.0f, to.getBlue() / 255.0f), data.getSize());
}
};
BiFunction<NamespacedKey, net.minecraft.core.particles.Particle<?>, CraftParticle<?>> vibrationFunction = (name, particle) -> new CraftParticle<>(name, particle, Vibration.class) {
@Override
public ParticleParam createParticleParam(Vibration data) {
PositionSource source;
if (data.getDestination() instanceof Vibration.Destination.BlockDestination) {
Location destination = ((Vibration.Destination.BlockDestination) data.getDestination()).getLocation();
source = new BlockPositionSource(CraftLocation.toBlockPosition(destination));
} else if (data.getDestination() instanceof Vibration.Destination.EntityDestination) {
Entity destination = ((CraftEntity) ((Vibration.Destination.EntityDestination) data.getDestination()).getEntity()).getHandle();
source = new EntityPositionSource(destination, destination.getEyeHeight());
} else {
throw new IllegalArgumentException("Unknown vibration destination " + data.getDestination());
}
return new VibrationParticleOption(source, data.getArrivalTime());
}
};
BiFunction<NamespacedKey, net.minecraft.core.particles.Particle<?>, CraftParticle<?>> floatFunction = (name, particle) -> new CraftParticle<>(name, particle, Float.class) {
@Override
public ParticleParam createParticleParam(Float data) {
return new SculkChargeParticleOptions(data);
}
};
BiFunction<NamespacedKey, net.minecraft.core.particles.Particle<?>, CraftParticle<?>> integerFunction = (name, particle) -> new CraftParticle<>(name, particle, Integer.class) {
@Override
public ParticleParam createParticleParam(Integer data) {
return new ShriekParticleOption(data);
}
};
add("dust", dustOptionsFunction);
add("item", itemStackFunction);
add("block", blockDataFunction);
add("falling_dust", blockDataFunction);
add("dust_color_transition", dustTransitionFunction);
add("vibration", vibrationFunction);
add("sculk_charge", floatFunction);
add("shriek", integerFunction);
add("block_marker", blockDataFunction);
}
private static void add(String name, BiFunction<NamespacedKey, net.minecraft.core.particles.Particle<?>, CraftParticle<?>> function) {
PARTICLE_MAP.put(NamespacedKey.fromString(name), function);
}
public CraftParticleRegistry(IRegistry<net.minecraft.core.particles.Particle<?>> minecraftRegistry) {
super(CraftParticle.class, minecraftRegistry, null);
}
@Override
public CraftParticle<?> createBukkit(NamespacedKey namespacedKey, net.minecraft.core.particles.Particle<?> particle) {
if (particle == null) {
return null;
}
BiFunction<NamespacedKey, net.minecraft.core.particles.Particle<?>, CraftParticle<?>> function = PARTICLE_MAP.getOrDefault(namespacedKey, VOID_FUNCTION);
return function.apply(namespacedKey, particle);
}
}
}

View File

@@ -67,13 +67,13 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
return null;
}
private final Class<B> bukkitClass;
private final Class<? super B> bukkitClass;
private final Map<NamespacedKey, B> cache = new HashMap<>();
private final IRegistry<M> minecraftRegistry;
private final BiFunction<NamespacedKey, M, B> minecraftToBukkit;
private boolean init;
public CraftRegistry(Class<B> bukkitClass, IRegistry<M> minecraftRegistry, BiFunction<NamespacedKey, M, B> minecraftToBukkit) {
public CraftRegistry(Class<? super B> bukkitClass, IRegistry<M> minecraftRegistry, BiFunction<NamespacedKey, M, B> minecraftToBukkit) {
this.bukkitClass = bukkitClass;
this.minecraftRegistry = minecraftRegistry;
this.minecraftToBukkit = minecraftToBukkit;

View File

@@ -1788,12 +1788,14 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public <T> void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data, boolean force) {
particle = CraftParticle.convertLegacy(particle);
data = CraftParticle.convertLegacy(data);
if (data != null) {
Preconditions.checkArgument(particle.getDataType().isInstance(data), "data (%s) should be %s", data.getClass(), particle.getDataType());
}
getHandle().sendParticles(
null, // Sender
CraftParticle.toNMS(particle, data), // Particle
CraftParticle.createParticleParam(particle, data), // Particle
x, y, z, // Position
count, // Count
offsetX, offsetY, offsetZ, // Random offset

View File

@@ -121,7 +121,12 @@ public class CraftAreaEffectCloud extends CraftEntity implements AreaEffectCloud
@Override
public <T> void setParticle(Particle particle, T data) {
getHandle().setParticle(CraftParticle.toNMS(particle, data));
particle = CraftParticle.convertLegacy(particle);
data = CraftParticle.convertLegacy(data);
if (data != null) {
Preconditions.checkArgument(particle.getDataType().isInstance(data), "data (%s) should be %s", data.getClass(), particle.getDataType());
}
getHandle().setParticle(CraftParticle.createParticleParam(particle, data));
}
@Override

View File

@@ -2080,10 +2080,12 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
@Override
public <T> void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data) {
particle = CraftParticle.convertLegacy(particle);
data = CraftParticle.convertLegacy(data);
if (data != null) {
Preconditions.checkArgument(particle.getDataType().isInstance(data), "data (%s) should be %s", data.getClass(), particle.getDataType());
}
PacketPlayOutWorldParticles packetplayoutworldparticles = new PacketPlayOutWorldParticles(CraftParticle.toNMS(particle, data), true, (float) x, (float) y, (float) z, (float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, count);
PacketPlayOutWorldParticles packetplayoutworldparticles = new PacketPlayOutWorldParticles(CraftParticle.createParticleParam(particle, data), true, (float) x, (float) y, (float) z, (float) offsetX, (float) offsetY, (float) offsetZ, (float) extra, count);
getHandle().connection.send(packetplayoutworldparticles);
}