ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/WrappedParticle.java

170 lines
4.9 KiB
Java

package com.comphenix.protocol.wrappers;
import java.lang.reflect.Modifier;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.mojang.math.Vector3fa;
import org.bukkit.Color;
import org.bukkit.Particle;
import org.bukkit.inventory.ItemStack;
/**
* Represents an immutable wrapped ParticleParam in 1.13
*/
public class WrappedParticle<T> {
private static MethodAccessor toBukkit;
private static MethodAccessor toNMS;
private static MethodAccessor toCraftData;
private static void ensureMethods() {
if (toBukkit != null && toNMS != null) {
return;
}
FuzzyReflection fuzzy = FuzzyReflection.fromClass(MinecraftReflection.getCraftBukkitClass("CraftParticle"));
FuzzyMethodContract contract = FuzzyMethodContract
.newBuilder()
.requireModifier(Modifier.STATIC)
.returnTypeExact(Particle.class)
.parameterExactType(MinecraftReflection.getParticleParam())
.build();
toBukkit = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
contract = FuzzyMethodContract
.newBuilder()
.requireModifier(Modifier.STATIC)
.returnTypeExact(MinecraftReflection.getParticleParam())
.parameterCount(2)
.build();
toNMS = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
Class<?> cbData = MinecraftReflection.getCraftBukkitClass("block.data.CraftBlockData");
fuzzy = FuzzyReflection.fromClass(cbData);
contract = FuzzyMethodContract
.newBuilder()
.requireModifier(Modifier.STATIC)
.returnTypeExact(cbData)
.parameterExactArray(MinecraftReflection.getIBlockDataClass())
.build();
toCraftData = Accessors.getMethodAccessor(fuzzy.getMethod(contract));
}
private final Particle particle;
private final T data;
private final Object handle;
private WrappedParticle(Object handle, Particle particle, T data) {
this.handle = handle;
this.particle = particle;
this.data = data;
}
/**
* @return This particle's Bukkit type
*/
public Particle getParticle() {
return particle;
}
/**
* Gets this Particle's Bukkit/ProtocolLib data. The type of this data depends on the
* {@link #getParticle() Particle type}. For Block particles it will be {@link WrappedBlockData},
* for Item crack particles, it will be an {@link ItemStack}, and for redstone particles it will
* be {@link Particle.DustOptions}
*
* @return The particle data
*/
public T getData() {
return data;
}
/**
* @return NMS handle
*/
public Object getHandle() {
return handle;
}
public static WrappedParticle fromHandle(Object handle) {
ensureMethods();
Particle bukkit = (Particle) toBukkit.invoke(null, handle);
Object data = null;
switch (bukkit) {
case BLOCK_CRACK:
case BLOCK_DUST:
case FALLING_DUST:
data = getBlockData(handle);
break;
case ITEM_CRACK:
data = getItem(handle);
break;
case REDSTONE:
data = getRedstone(handle);
break;
default:
break;
}
return new WrappedParticle<>(handle, bukkit, data);
}
private static WrappedBlockData getBlockData(Object handle) {
return new StructureModifier<>(handle.getClass())
.withTarget(handle)
.withType(MinecraftReflection.getIBlockDataClass(), BukkitConverters.getWrappedBlockDataConverter())
.read(0);
}
private static Object getItem(Object handle) {
return new StructureModifier<>(handle.getClass())
.withTarget(handle)
.withType(MinecraftReflection.getItemStackClass(), BukkitConverters.getItemStackConverter())
.read(0);
}
private static Object getRedstone(Object handle) {
int r, g, b;
float alpha;
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
StructureModifier<Object> modifier = new StructureModifier<>(handle.getClass()).withTarget(handle);
Vector3fa rgb = (Vector3fa) modifier.withType(Vector3fa.class).read(0);
r = (int) (rgb.a() * 255);
g = (int) (rgb.b() * 255);
b = (int) (rgb.c() * 255);
alpha = (float) modifier.withType(float.class).read(0);
} else {
StructureModifier<Float> modifier = new StructureModifier<>(handle.getClass()).withTarget(handle).withType(float.class);
r = (int) (modifier.read(0) * 255);
g = (int) (modifier.read(1) * 255);
b = (int) (modifier.read(2) * 255);
alpha = modifier.read(3);
}
return new Particle.DustOptions(Color.fromRGB(r, g, b), alpha);
}
public static <T> WrappedParticle<T> create(Particle particle, T data) {
ensureMethods();
Object bukkitData = data;
if (data instanceof WrappedBlockData) {
WrappedBlockData blockData = (WrappedBlockData) data;
bukkitData = toCraftData.invoke(null, blockData.getHandle());
}
Object handle = toNMS.invoke(null, particle, bukkitData);
return new WrappedParticle<>(handle, particle, data);
}
}