Start rewriting plugin

This commit is contained in:
FlorianMichael 2023-09-22 15:10:11 +02:00
parent 2fb7cbeed0
commit c94fd13c1c
No known key found for this signature in database
GPG Key ID: C2FB87E71C425126
11 changed files with 590 additions and 978 deletions

View File

@ -9,6 +9,7 @@ import com.viaversion.viarewind.legacysupport.listener.BrewingListener;
import com.viaversion.viarewind.legacysupport.listener.ElytraListener;
import com.viaversion.viarewind.legacysupport.listener.EnchantingListener;
import com.viaversion.viarewind.legacysupport.listener.SoundListener;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
@ -18,12 +19,22 @@ public class BukkitPlugin extends JavaPlugin {
private static BukkitPlugin instance;
@Override
public void onEnable() {
public void onLoad() {
instance = this;
}
protected void makeConfig() {
saveDefaultConfig();
getConfig().options().copyDefaults(true);
saveConfig();
}
@Override
public void onEnable() {
makeConfig();
final FileConfiguration config = getConfig();
new BukkitRunnable() {
@Override
public void run() {
@ -31,16 +42,42 @@ public class BukkitPlugin extends JavaPlugin {
if (serverProtocol == -1) return;
cancel();
if (serverProtocol > 5 && config.getBoolean("enchanting-gui-fix")) Bukkit.getPluginManager().registerEvents(new EnchantingListener(), BukkitPlugin.this);
if (serverProtocol > 78 && config.getBoolean("brewing-stand-gui-fix")) Bukkit.getPluginManager().registerEvents(new BrewingListener(), BukkitPlugin.this);
if (serverProtocol > 84 && config.getBoolean("lily-pad-fix")) BoundingBoxFixer.fixLilyPad();
if (serverProtocol > 404 && config.getBoolean("carpet-fix")) // 1.14+ only BoundingBoxFixer.fixCarpet();
if (serverProtocol > 48 && config.getBoolean("ladder-fix")) BoundingBoxFixer.fixLadder();
if (serverProtocol > 47 && config.getBoolean("sound-fix")) Bukkit.getPluginManager().registerEvents(new SoundListener(), BukkitPlugin.this);
if (serverProtocol > 5 && config.getBoolean("slime-fix")) Bukkit.getPluginManager().registerEvents(new BounceListener(), BukkitPlugin.this);
if (serverProtocol > 76 && config.getBoolean("elytra-fix")) Bukkit.getPluginManager().registerEvents(new ElytraListener(), BukkitPlugin.this);
if (serverProtocol > 54 && config.getBoolean("area-effect-cloud-particles")) Bukkit.getPluginManager().registerEvents(new AreaEffectCloudListener(), BukkitPlugin.this);
if (config.getBoolean("versioninfo.active")) new VersionInformer();
if (serverProtocol >= ProtocolVersion.v1_8.getVersion() && config.getBoolean("enchanting-gui-fix")) {
Bukkit.getPluginManager().registerEvents(new EnchantingListener(), BukkitPlugin.this);
}
if (serverProtocol >= ProtocolVersion.v1_8.getVersion() && config.getBoolean("slime-fix")) {
Bukkit.getPluginManager().registerEvents(new BounceListener(), BukkitPlugin.this);
}
if (serverProtocol >= ProtocolVersion.v1_9.getVersion() && config.getBoolean("sound-fix")) {
Bukkit.getPluginManager().registerEvents(new SoundListener(), BukkitPlugin.this);
}
// Added in 15w31a (1.9)
if (serverProtocol >= ProtocolVersion.v1_9.getVersion() && config.getBoolean("ladder-fix")) {
BoundingBoxFixer.fixLadder(serverProtocol);
}
// Added in 15w32c (1.9)
if (serverProtocol >= ProtocolVersion.v1_9.getVersion() && config.getBoolean("area-effect-cloud-particles")) {
Bukkit.getPluginManager().registerEvents(new AreaEffectCloudListener(), BukkitPlugin.this);
}
// Added in 15w40b (1.9)
if (serverProtocol > ProtocolVersion.v1_9.getVersion() && config.getBoolean("elytra-fix")) {
Bukkit.getPluginManager().registerEvents(new ElytraListener(), BukkitPlugin.this);
}
// Added in 15w41b (1.9)
if (serverProtocol >= ProtocolVersion.v1_9.getVersion() && config.getBoolean("brewing-stand-gui-fix")) {
Bukkit.getPluginManager().registerEvents(new BrewingListener(), BukkitPlugin.this);
}
// Added in 15w44b (1.9)
if (serverProtocol >= ProtocolVersion.v1_9.getVersion() && config.getBoolean("lily-pad-fix")) {
BoundingBoxFixer.fixLilyPad();
}
if (serverProtocol >= ProtocolVersion.v1_14_4.getVersion() && config.getBoolean("carpet-fix")) {
BoundingBoxFixer.fixCarpet(serverProtocol);
}
if (config.getBoolean("versioninfo.active")) {
new VersionInformer();
}
}
}.runTaskTimer(this, 1L, 1L);
}

View File

@ -1,8 +1,8 @@
package com.viaversion.viarewind.legacysupport.injector;
import com.viaversion.viarewind.legacysupport.reflection.ReflectionAPI;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viarewind.legacysupport.BukkitPlugin;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@ -12,140 +12,115 @@ import java.util.logging.Level;
public class BoundingBoxFixer {
public static void fixLilyPad() {
try {
Class<?> blockWaterLilyClass = NMSReflection.getNMSBlock("BlockWaterLily");
Field boundingBoxField = ReflectionAPI.getFieldAccessible(blockWaterLilyClass, "a");
Object boundingBox = boundingBoxField.get(null);
public static void fixLilyPad() {
try {
final Field boundingBoxField = ReflectionAPI.getFieldAccessible(NMSReflection.getNMSBlock("BlockWaterLily"), "a");
setBoundingBox(boundingBox, 0.0625, 0.0, 0.0625, 0.9375, 0.015625, 0.9375);
} catch (Exception ex) {
BukkitPlugin.getInstance().getLogger().log(Level.SEVERE, "Could not fix lily pad bounding box.", ex);
}
}
setBoundingBox(boundingBoxField.get(null), 0.0625, 0.0, 0.0625, 0.9375, 0.015625, 0.9375);
} catch (Exception ex) {
BukkitPlugin.getInstance().getLogger().log(Level.SEVERE, "Could not fix lily pad bounding box.", ex);
}
}
public static void fixCarpet() {
try {
int serverProtocol = Via.getAPI().getServerVersion().lowestSupportedVersion();
Class<?> blockCarpetClass;
if (serverProtocol <= 754) { // 1.16.5
blockCarpetClass = NMSReflection.getNMSBlock("BlockCarpet");
} else {
blockCarpetClass = NMSReflection.getNMSBlock("CarpetBlock");
}
Field boundingBoxField = ReflectionAPI.getFieldAccessible(blockCarpetClass, "a");
setBoundingBox(boundingBoxField.get(0), 0.0D, -0.0000001D, 0.0D, 1.0D, 0.0000001D, 1.0D);
} catch (Exception ex) {
BukkitPlugin.getInstance().getLogger().log(Level.SEVERE, "Could not fix carpet bounding box.", ex);
}
}
public static void fixCarpet(final int serverVersion) {
try {
final Class<?> blockCarpetClass = serverVersion <= ProtocolVersion.v1_16_4.getVersion() ? NMSReflection.getNMSBlock("BlockCarpet") : NMSReflection.getNMSBlock("CarpetBlock");
public static void fixLadder() {
try {
Class<?> blockLadderClass = NMSReflection.getNMSBlock("BlockLadder");
final Field boundingBoxField = ReflectionAPI.getFieldAccessible(blockCarpetClass, "a");
setBoundingBox(boundingBoxField.get(0), 0.0D, -0.0000001D, 0.0D, 1.0D, 0.0000001D, 1.0D);
} catch (Exception ex) {
BukkitPlugin.getInstance().getLogger().log(Level.SEVERE, "Could not fix carpet bounding box.", ex);
}
}
Field boundingBoxNorthField, boundingBoxSouthField, boundingBoxWestField, boundingBoxEastField;
public static void fixLadder(final int serverVersion) {
try {
final boolean pre1_12_2 = serverVersion <= ProtocolVersion.v1_12_2.getVersion();
final boolean pre1_13_2 = serverVersion <= ProtocolVersion.v1_13_2.getVersion();
final boolean pre1_16_4 = serverVersion <= ProtocolVersion.v1_16_4.getVersion();
int serverProtocol = Via.getAPI().getServerVersion().lowestSupportedVersion();
if (serverProtocol <= 340) {
boundingBoxEastField = ReflectionAPI.getFieldAccessible(blockLadderClass, "b");
boundingBoxWestField = ReflectionAPI.getFieldAccessible(blockLadderClass, "c");
boundingBoxSouthField = ReflectionAPI.getFieldAccessible(blockLadderClass, "d");
boundingBoxNorthField = ReflectionAPI.getFieldAccessible(blockLadderClass, "e");
} else if (serverProtocol <= 404) {
boundingBoxEastField = ReflectionAPI.getFieldAccessible(blockLadderClass, "c");
boundingBoxWestField = ReflectionAPI.getFieldAccessible(blockLadderClass, "o");
boundingBoxSouthField = ReflectionAPI.getFieldAccessible(blockLadderClass, "p");
boundingBoxNorthField = ReflectionAPI.getFieldAccessible(blockLadderClass, "q");
} else if (serverProtocol <= 754) {
boundingBoxEastField = ReflectionAPI.getFieldAccessible(blockLadderClass, "c");
boundingBoxWestField = ReflectionAPI.getFieldAccessible(blockLadderClass, "d");
boundingBoxSouthField = ReflectionAPI.getFieldAccessible(blockLadderClass, "e");
boundingBoxNorthField = ReflectionAPI.getFieldAccessible(blockLadderClass, "f");
} else {
boundingBoxEastField = ReflectionAPI.getFieldAccessible(blockLadderClass, "d");
boundingBoxWestField = ReflectionAPI.getFieldAccessible(blockLadderClass, "e");
boundingBoxSouthField = ReflectionAPI.getFieldAccessible(blockLadderClass, "f");
boundingBoxNorthField = ReflectionAPI.getFieldAccessible(blockLadderClass, "g");
}
final Class<?> blockLadderClass = NMSReflection.getNMSBlock("BlockLadder");
setBoundingBox(boundingBoxEastField.get(null), 0.0D, 0.0D, 0.0D, 0.125D, 1.0D, 1.0D);
setBoundingBox(boundingBoxWestField.get(null), 0.875D, 0.0D, 0.0D, 1.0D, 1.0D, 1.0D);
setBoundingBox(boundingBoxSouthField.get(null), 0.0D, 0.0D, 0.0D, 1.0D, 1.0D, 0.125D);
setBoundingBox(boundingBoxNorthField.get(null), 0.0D, 0.0D, 0.875D, 1.0D, 1.0D, 1.0D);
} catch (Exception ex) {
BukkitPlugin.getInstance().getLogger().log(Level.SEVERE, "Could not fix ladder bounding box.", ex);
}
}
final Field boundingBoxEastField = ReflectionAPI.getFieldAccessible(blockLadderClass, pre1_12_2 ? "b" : pre1_13_2 ? "c" : pre1_16_4 ? "c" : "d");
final Field boundingBoxWestField = ReflectionAPI.getFieldAccessible(blockLadderClass, pre1_12_2 ? "c" : pre1_13_2 ? "o" : pre1_16_4 ? "d" : "e");
final Field boundingBoxSouthField = ReflectionAPI.getFieldAccessible(blockLadderClass, pre1_12_2 ? "d" : pre1_13_2 ? "p" : pre1_16_4 ? "e" : "f");
final Field boundingBoxNorthField = ReflectionAPI.getFieldAccessible(blockLadderClass, pre1_12_2 ? "e" : pre1_13_2 ? "q" : pre1_16_4 ? "f" : "g");
private static void setBoundingBox(Object boundingBox, double... values) throws ReflectiveOperationException {
if (boundingBox.getClass().getSimpleName().equals("VoxelShapeArray")) {
setVoxelShapeArray(boundingBox, values);
return;
}
setBoundingBox(boundingBoxEastField.get(null), 0.0D, 0.0D, 0.0D, 0.125D, 1.0D, 1.0D);
setBoundingBox(boundingBoxWestField.get(null), 0.875D, 0.0D, 0.0D, 1.0D, 1.0D, 1.0D);
setBoundingBox(boundingBoxSouthField.get(null), 0.0D, 0.0D, 0.0D, 1.0D, 1.0D, 0.125D);
setBoundingBox(boundingBoxNorthField.get(null), 0.0D, 0.0D, 0.875D, 1.0D, 1.0D, 1.0D);
} catch (Exception ex) {
BukkitPlugin.getInstance().getLogger().log(Level.SEVERE, "Could not fix ladder bounding box.", ex);
}
}
if (boundingBox.getClass().getSimpleName().equals("AxisAlignedBB")) {
setAxisAlignedBB(boundingBox, values);
return;
}
private static void setBoundingBox(Object boundingBox, double... values) throws ReflectiveOperationException {
if (boundingBox.getClass().getSimpleName().equals("VoxelShapeArray")) {
setVoxelShapeArray(boundingBox, values);
return;
}
// Tuinity support
if (boundingBox.getClass().getSimpleName().equals("AABBVoxelShape")) {
setAABBVoxelShape(boundingBox, values);
return;
}
if (boundingBox.getClass().getSimpleName().equals("AxisAlignedBB")) {
setAxisAlignedBB(boundingBox, values);
return;
}
throw new IllegalStateException("Unknown bounding box type: " + boundingBox.getClass().getName());
}
// Tuinity support
if (boundingBox.getClass().getSimpleName().equals("AABBVoxelShape")) {
setAABBVoxelShape(boundingBox, values);
return;
}
private static void setAABBVoxelShape(Object boundingBox, double[] values) throws ReflectiveOperationException {
for (Field field : boundingBox.getClass().getFields()) {
// Set data for internally used AxisAlignedBB
if (field.getType().getSimpleName().equals("AxisAlignedBB")) {
setBoundingBox(field.get(boundingBox), values);
}
// Clear the cache
if (field.getType().getSimpleName().equals("DoubleList")) {
Object doubleList = field.get(boundingBox);
doubleList.getClass().getMethod("clear").invoke(doubleList);
}
}
}
throw new IllegalStateException("Unknown bounding box type: " + boundingBox.getClass().getName());
}
private static void setAxisAlignedBB(Object boundingBox, double[] values) throws ReflectiveOperationException {
Field[] doubleFields = Arrays.stream(boundingBox.getClass().getDeclaredFields())
.filter(f -> f.getType() == double.class && !Modifier.isStatic(f.getModifiers()))
.toArray(Field[]::new);
private static void setAABBVoxelShape(Object boundingBox, double[] values) throws ReflectiveOperationException {
for (Field field : boundingBox.getClass().getFields()) {
// Set data for internally used AxisAlignedBB
if (field.getType().getSimpleName().equals("AxisAlignedBB")) {
setBoundingBox(field.get(boundingBox), values);
}
// Clear the cache
if (field.getType().getSimpleName().equals("DoubleList")) {
final Object doubleList = field.get(boundingBox);
if (doubleFields.length < 6) {
throw new IllegalStateException("Invalid field count for " + boundingBox.getClass().getName() + ": " + doubleFields.length);
}
doubleList.getClass().getMethod("clear").invoke(doubleList);
}
}
}
for (int i = 0; i < 6; i++) {
Field currentField = doubleFields[i];
currentField.setAccessible(true);
currentField.setDouble(boundingBox, values[i]);
}
}
private static void setAxisAlignedBB(final Object boundingBox, final double[] values) throws ReflectiveOperationException {
final Field[] doubleFields = Arrays.stream(boundingBox.getClass().getDeclaredFields()).filter(f -> f.getType() == double.class && !Modifier.isStatic(f.getModifiers())).toArray(Field[]::new);
private static void setVoxelShapeArray(Object voxelShapeArray, double[] values) throws ReflectiveOperationException {
Field[] doubleListFields = Arrays.stream(voxelShapeArray.getClass().getDeclaredFields())
.filter(f -> f.getType().getSimpleName().equals("DoubleList"))
.toArray(Field[]::new);
if (doubleFields.length < 6) {
throw new IllegalStateException("Invalid field count for " + boundingBox.getClass().getName() + ": " + doubleFields.length);
}
if (doubleListFields.length < 3) {
throw new IllegalStateException("Invalid field count for " + voxelShapeArray.getClass().getName() + ": " + doubleListFields.length);
}
for (int i = 0; i < 6; i++) {
Field currentField = doubleFields[i];
currentField.setAccessible(true);
currentField.setDouble(boundingBox, values[i]);
}
}
// fastutil is relocated on Spigot but not on Paper
String doubleArrayListClass = doubleListFields[0].getType().getName().replace("DoubleList", "DoubleArrayList");
Method wrapMethod = Class.forName(doubleArrayListClass).getMethod("wrap", double[].class);
private static void setVoxelShapeArray(final Object voxelShapeArray, final double[] values) throws ReflectiveOperationException {
final Field[] doubleListFields = Arrays.stream(voxelShapeArray.getClass().getDeclaredFields()).filter(f -> f.getType().getSimpleName().equals("DoubleList")).toArray(Field[]::new);
for (int i = 0; i < 3; i++) {
double[] array = {values[i], values[i + 3]};
Field field = doubleListFields[i];
field.setAccessible(true);
field.set(voxelShapeArray, wrapMethod.invoke(null, (Object) array));
}
}
if (doubleListFields.length < 3) {
throw new IllegalStateException("Invalid field count for " + voxelShapeArray.getClass().getName() + ": " + doubleListFields.length);
}
// FastUtil is relocated on Spigot but not on Paper
final String doubleArrayListClass = doubleListFields[0].getType().getName().replace("DoubleList", "DoubleArrayList");
final Method wrapMethod = Class.forName(doubleArrayListClass).getMethod("wrap", double[].class);
for (int i = 0; i < 3; i++) {
final double[] array = {values[i], values[i + 3]};
final Field field = doubleListFields[i];
field.setAccessible(true);
field.set(voxelShapeArray, wrapMethod.invoke(null, (Object) array));
}
}
}

View File

@ -10,9 +10,8 @@ import java.lang.reflect.Field;
import java.util.Arrays;
public class NMSReflection {
private static int protocolVersion = -1;
private static final int PROTOCOL_1_17 = 755;
private static int protocolVersion = -1;
private static String version;
private static Field playerConnectionField;
@ -22,21 +21,7 @@ public class NMSReflection {
}
public static int getProtocolVersion() {
return protocolVersion == -1 ?
protocolVersion = Via.getAPI().getServerVersion().lowestSupportedVersion() :
protocolVersion;
}
public static Class<?> getBlockDataClass() {
try {
if (getProtocolVersion() >= PROTOCOL_1_17) {
return Class.forName("net.minecraft.world.level.block.state.IBlockData");
}
return getLegacyNMSClass("IBlockData");
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
return null;
return protocolVersion == -1 ? protocolVersion = Via.getAPI().getServerVersion().lowestSupportedVersion() : protocolVersion;
}
public static Class<?> getBlockPositionClass() {
@ -116,15 +101,6 @@ public class NMSReflection {
return Class.forName("net.minecraft.server." + getVersion() + "." + name);
}
public static Class<?> getCraftBukkitClass(String name) {
try {
return Class.forName("org.bukkit.craftbukkit." + getVersion() + "." + name);
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
return null;
}
public static void sendPacket(Player player, Object packet) {
try {
Object nmsPlayer = player.getClass().getMethod("getHandle").invoke(player);

View File

@ -2,6 +2,7 @@ package com.viaversion.viarewind.legacysupport.listener;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viarewind.legacysupport.BukkitPlugin;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Particle;
@ -16,50 +17,50 @@ import java.util.ArrayList;
import java.util.Set;
import java.util.stream.Collectors;
@SuppressWarnings("unchecked")
public class AreaEffectCloudListener implements Listener {
private ArrayList<AreaEffectCloud> effectClouds = new ArrayList<>();
private final ArrayList<AreaEffectCloud> effectClouds = new ArrayList<>();
public AreaEffectCloudListener() {
Bukkit.getScheduler().runTaskTimer(BukkitPlugin.getInstance(), () -> {
Set<Player> players = Bukkit.getOnlinePlayers()
.stream()
.filter(p -> Via.getAPI().getPlayerVersion(p) <= 54)
.collect(Collectors.toSet());
effectClouds.removeIf(e -> !e.isValid());
effectClouds.forEach(cloud -> {
World world = cloud.getWorld();
Particle particle = cloud.getParticle();
Location loc = cloud.getLocation();
public AreaEffectCloudListener() {
Bukkit.getScheduler().runTaskTimer(BukkitPlugin.getInstance(), () -> {
final Set<Player> affectedPlayers = Bukkit.getOnlinePlayers().stream().filter(p -> Via.getAPI().getPlayerVersion(p) <= ProtocolVersion.v1_8.getVersion()).collect(Collectors.toSet());
effectClouds.removeIf(e -> !e.isValid());
effectClouds.forEach(cloud -> {
final Location location = cloud.getLocation();
final float radius = cloud.getRadius();
float radius = cloud.getRadius();
float area = (float) Math.PI * radius * radius;
float area = (float) Math.PI * radius * radius;
for(int i = 0; i < area; i++) {
float f1 = (float)Math.random() * 6.2831855F;
float f2 = (float)Math.sqrt(Math.random()) * radius;
float f3 = (float)Math.cos(f1) * f2;
float f6 = (float)Math.sin(f1) * f2;
if (particle == Particle.SPELL_MOB) {
int color = cloud.getColor().asRGB();
int r = color >> 16 & 255;
int g = color >> 8 & 255;
int b = color & 255;
players.forEach(player -> {
if (player.getWorld()!=loc.getWorld()) return;
player.spawnParticle(particle, loc.getX() + f3, loc.getY(), loc.getZ() + f6, 0, r / 255f, g / 255f, b / 255f);
});
} else {
//TODO particles with data
//world.spawnParticle(particle, loc.getX() + f3, loc.getY(), loc.getZ() + f6, 1, (0.5 - Math.random()) * 0.15, 0.009999999776482582D, (0.5 - Math.random()) * 0.15d, );
}
}
});
}, 1L, 1L);
}
for (int i = 0; i < area; i++) {
float f1 = (float) Math.random() * 6.2831855F;
float f2 = (float) Math.sqrt(Math.random()) * radius;
float f3 = (float) Math.cos(f1) * f2;
float f6 = (float) Math.sin(f1) * f2;
@EventHandler
public void onEntitySpawn(LingeringPotionSplashEvent e) {
effectClouds.add(e.getAreaEffectCloud());
}
if (cloud.getParticle() == Particle.SPELL_MOB) {
final int color = cloud.getColor().asRGB();
final int r = color >> 16 & 255;
final int g = color >> 8 & 255;
final int b = color & 255;
affectedPlayers.stream().filter(player -> player.getWorld() == location.getWorld()).forEach(player -> {
player.spawnParticle(
cloud.getParticle(),
location.getX() + f3, location.getY(), location.getZ() + f6,
0,
r / 255f, g / 255f, b / 255f
);
});
}
}
});
}, 1L, 1L);
}
@EventHandler
public void onEntitySpawn(LingeringPotionSplashEvent e) {
effectClouds.add(e.getAreaEffectCloud());
}
}

View File

@ -1,6 +1,7 @@
package com.viaversion.viarewind.legacysupport.listener;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
@ -9,21 +10,29 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.util.Vector;
@SuppressWarnings({"unchecked", "DataFlowIssue"})
public class BounceListener implements Listener {
@EventHandler
public void onPlayerMove(PlayerMoveEvent e) {
if (e.getTo().getY()>=e.getFrom().getY()) return;
Player player = e.getPlayer();
if (Via.getAPI().getPlayerVersion(player)>5) return;
if (e.getTo().getY() >= e.getFrom().getY()) return; // Only check upwards motion
final Player player = e.getPlayer();
if (Via.getAPI().getPlayerVersion(player) >= ProtocolVersion.v1_8.getVersion()) return; // Only apply for 1.7 and below players
if (Math.floor(e.getTo().getY()) + 0.01 < e.getTo().getY()) return;
if (player.isSneaking()) return;
Block block = e.getTo().clone().add(0, -0.1, 0).getBlock();
if (block.getType()!=Material.SLIME_BLOCK) return;
Vector velocity = player.getVelocity();
double motY = (e.getTo().getY()-e.getFrom().getY());
if (motY>-0.11) return;
velocity.setY(-motY * 1.05);
player.setVelocity(velocity);
final Block block = e.getTo().clone().add(0, -0.1, 0).getBlock();
if (block.getType() != Material.SLIME_BLOCK) return;
final Vector newVelocity = player.getVelocity();
final double deltaY = (e.getTo().getY() - e.getFrom().getY());
if (deltaY >- 0.11) return; // Only bounce if the player is falling down
newVelocity.setY(-deltaY * 1.05);
player.setVelocity(newVelocity);
}
}
}

View File

@ -15,58 +15,58 @@ import org.bukkit.inventory.ItemStack;
public class BrewingListener implements Listener {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onPlayerInteract(PlayerInteractEvent e) {
if (!e.hasBlock() || e.getClickedBlock().getType()!=Material.BREWING_STAND) return;
Player player = (Player) e.getPlayer();
int version = Via.getAPI().getPlayerVersion(player);
if (version>79) return;
ItemStack blazePowder = new ItemStack(Material.BLAZE_POWDER);
ItemStack playerItem = e.getItem();
if (playerItem==null) playerItem = new ItemStack(Material.AIR);
BrewingStand brewingStand = (BrewingStand)e.getClickedBlock().getState();
BrewerInventory inventory = brewingStand.getInventory();
ItemStack fuel = inventory.getFuel();
if (fuel==null) fuel = new ItemStack(Material.AIR);
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onPlayerInteract(PlayerInteractEvent e) {
if (!e.hasBlock() || e.getClickedBlock().getType() != Material.BREWING_STAND) return;
Player player = (Player) e.getPlayer();
int version = Via.getAPI().getPlayerVersion(player);
if (version > 79) return;
ItemStack blazePowder = new ItemStack(Material.BLAZE_POWDER);
ItemStack playerItem = e.getItem();
if (playerItem == null) playerItem = new ItemStack(Material.AIR);
BrewingStand brewingStand = (BrewingStand) e.getClickedBlock().getState();
BrewerInventory inventory = brewingStand.getInventory();
ItemStack fuel = inventory.getFuel();
if (fuel == null) fuel = new ItemStack(Material.AIR);
if (e.getAction()==Action.RIGHT_CLICK_BLOCK) {
if (!blazePowder.isSimilar(playerItem)) return;
if (fuel.getType()!=Material.AIR && !fuel.isSimilar(playerItem)) return;
if (fuel.getAmount()>=64) return;
int amount = player.isSneaking() ? Math.min(playerItem.getAmount(), 64-fuel.getAmount()) : 1;
if (playerItem.getAmount()==amount) {
playerItem = new ItemStack(Material.AIR);
} else {
playerItem.setAmount(playerItem.getAmount()-amount);
}
if (fuel.getType()==Material.AIR) {
fuel = new ItemStack(Material.BLAZE_POWDER, amount);
} else {
fuel.setAmount(fuel.getAmount()+amount);
}
inventory.setFuel(fuel);
} else {
if (!blazePowder.isSimilar(fuel)) return;
if (!blazePowder.isSimilar(playerItem) && playerItem.getType()!=Material.AIR) return;
if (playerItem.getAmount()>=64) return;
int amount = player.isSneaking() ? Math.min(fuel.getAmount(), 64-playerItem.getAmount()) : 1;
if (fuel.getAmount()==amount) {
fuel = new ItemStack(Material.AIR);
} else {
fuel.setAmount(fuel.getAmount()-amount);
}
if (playerItem.getType()==Material.AIR) {
playerItem = new ItemStack(Material.BLAZE_POWDER, amount);
} else {
playerItem.setAmount(playerItem.getAmount()+amount);
}
inventory.setFuel(fuel);
}
if (e.getHand()==EquipmentSlot.HAND) {
player.getInventory().setItemInMainHand(playerItem);
} else {
player.getInventory().setItemInOffHand(playerItem);
}
e.setCancelled(true);
}
if (e.getAction() == Action.RIGHT_CLICK_BLOCK) {
if (!blazePowder.isSimilar(playerItem)) return;
if (fuel.getType() != Material.AIR && !fuel.isSimilar(playerItem)) return;
if (fuel.getAmount() >= 64) return;
int amount = player.isSneaking() ? Math.min(playerItem.getAmount(), 64 - fuel.getAmount()) : 1;
if (playerItem.getAmount() == amount) {
playerItem = new ItemStack(Material.AIR);
} else {
playerItem.setAmount(playerItem.getAmount() - amount);
}
if (fuel.getType() == Material.AIR) {
fuel = new ItemStack(Material.BLAZE_POWDER, amount);
} else {
fuel.setAmount(fuel.getAmount() + amount);
}
inventory.setFuel(fuel);
} else {
if (!blazePowder.isSimilar(fuel)) return;
if (!blazePowder.isSimilar(playerItem) && playerItem.getType() != Material.AIR) return;
if (playerItem.getAmount() >= 64) return;
int amount = player.isSneaking() ? Math.min(fuel.getAmount(), 64 - playerItem.getAmount()) : 1;
if (fuel.getAmount() == amount) {
fuel = new ItemStack(Material.AIR);
} else {
fuel.setAmount(fuel.getAmount() - amount);
}
if (playerItem.getType() == Material.AIR) {
playerItem = new ItemStack(Material.BLAZE_POWDER, amount);
} else {
playerItem.setAmount(playerItem.getAmount() + amount);
}
inventory.setFuel(fuel);
}
if (e.getHand() == EquipmentSlot.HAND) {
player.getInventory().setItemInMainHand(playerItem);
} else {
player.getInventory().setItemInOffHand(playerItem);
}
e.setCancelled(true);
}
}

View File

@ -11,48 +11,48 @@ import org.bukkit.util.Vector;
public class ElytraListener implements Listener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerMove(PlayerMoveEvent e) {
Player p = e.getPlayer();
if (!p.isGliding()) return;
if (Via.getAPI().getPlayerVersion(p)>76) return;
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerMove(PlayerMoveEvent e) {
Player p = e.getPlayer();
if (!p.isGliding()) return;
if (Via.getAPI().getPlayerVersion(p) > 76) return;
Location loc = p.getLocation();
Vector velocity = p.getVelocity();
Vector direction = loc.getDirection();
double motionX = velocity.getX();
double motionY = velocity.getY();
double motionZ = velocity.getZ();
Location loc = p.getLocation();
Vector velocity = p.getVelocity();
Vector direction = loc.getDirection();
double motionX = velocity.getX();
double motionY = velocity.getY();
double motionZ = velocity.getZ();
float pitch = loc.getPitch() * 0.017453292F;
double directionH = Math.sqrt(direction.getX() * direction.getX() + direction.getZ() * direction.getZ());
double speedH = Math.sqrt(motionX * motionX + motionZ * motionZ);
float speedV = (float) Math.cos(pitch);
speedV = (float)(speedV * speedV * Math.min(1.0D, direction.length() / 0.4D));
motionY += -0.08D + speedV * 0.06D;
if ((motionY < 0.0D) && (directionH > 0.0D)) {
double d2 = motionY * -0.1D * speedV;
motionY += d2;
motionX += direction.getX() * d2 / directionH;
motionZ += direction.getZ() * d2 / directionH;
}
if (pitch < 0.0F) {
double speed = speedH * -Math.sin(pitch) * 0.04D;
motionY += speed * 3.2D;
motionX -= direction.getX() * speed / directionH;
motionZ -= direction.getZ() * speed / directionH;
}
if (directionH > 0.0D) {
motionX += (direction.getX() / directionH * speedH - motionX) * 0.1D;
motionZ += (direction.getZ() / directionH * speedH - motionZ) * 0.1D;
}
motionX *= 0.9900000095367432D;
motionY *= 0.9800000190734863D;
motionZ *= 0.9900000095367432D;
velocity.setX(motionX);
velocity.setY(motionY);
velocity.setZ(motionZ);
float pitch = loc.getPitch() * 0.017453292F;
double directionH = Math.sqrt(direction.getX() * direction.getX() + direction.getZ() * direction.getZ());
double speedH = Math.sqrt(motionX * motionX + motionZ * motionZ);
float speedV = (float) Math.cos(pitch);
speedV = (float) (speedV * speedV * Math.min(1.0D, direction.length() / 0.4D));
motionY += -0.08D + speedV * 0.06D;
if ((motionY < 0.0D) && (directionH > 0.0D)) {
double d2 = motionY * -0.1D * speedV;
motionY += d2;
motionX += direction.getX() * d2 / directionH;
motionZ += direction.getZ() * d2 / directionH;
}
if (pitch < 0.0F) {
double speed = speedH * -Math.sin(pitch) * 0.04D;
motionY += speed * 3.2D;
motionX -= direction.getX() * speed / directionH;
motionZ -= direction.getZ() * speed / directionH;
}
if (directionH > 0.0D) {
motionX += (direction.getX() / directionH * speedH - motionX) * 0.1D;
motionZ += (direction.getZ() / directionH * speedH - motionZ) * 0.1D;
}
motionX *= 0.9900000095367432D;
motionY *= 0.9800000190734863D;
motionZ *= 0.9900000095367432D;
velocity.setX(motionX);
velocity.setY(motionY);
velocity.setZ(motionZ);
p.setVelocity(velocity);
}
p.setVelocity(velocity);
}
}

View File

@ -19,50 +19,50 @@ public class EnchantingListener implements Listener {
private final boolean newMaterialNames = Material.getMaterial("LAPIS_LAZULI") != null;
private final Material lapisMaterial = newMaterialNames ? Material.LAPIS_LAZULI : Material.getMaterial("INK_SACK");
@EventHandler
public void onInventoryOpen(InventoryOpenEvent e) {
if (!(e.getInventory() instanceof EnchantingInventory)) return;
Player player = (Player) e.getPlayer();
if (Via.getAPI().getPlayerVersion(player)>5) return;
PlayerInventory playerInventory = player.getInventory();
ItemStack lapis = newMaterialNames ? new ItemStack(lapisMaterial) : new ItemStack(lapisMaterial, 1, (short) 4);
int amount = 0;
for (int i = 0; i<playerInventory.getSize(); i++) {
ItemStack item = playerInventory.getItem(i);
if (item==null || !item.isSimilar(lapis)) continue;
if (amount + item.getAmount() > 64) {
item.setAmount(amount + item.getAmount() - 64);
amount = 64;
} else {
amount += item.getAmount();
item = new ItemStack(Material.AIR);
}
playerInventory.setItem(i, item);
if (amount==64) break;
}
if (amount==0) return;
EnchantingInventory inventory = (EnchantingInventory) e.getInventory();
lapis.setAmount(amount);
inventory.setSecondary(lapis);
}
@EventHandler
public void onInventoryOpen(InventoryOpenEvent e) {
if (!(e.getInventory() instanceof EnchantingInventory)) return;
Player player = (Player) e.getPlayer();
if (Via.getAPI().getPlayerVersion(player) > 5) return;
PlayerInventory playerInventory = player.getInventory();
ItemStack lapis = newMaterialNames ? new ItemStack(lapisMaterial) : new ItemStack(lapisMaterial, 1, (short) 4);
int amount = 0;
for (int i = 0; i < playerInventory.getSize(); i++) {
ItemStack item = playerInventory.getItem(i);
if (item == null || !item.isSimilar(lapis)) continue;
if (amount + item.getAmount() > 64) {
item.setAmount(amount + item.getAmount() - 64);
amount = 64;
} else {
amount += item.getAmount();
item = new ItemStack(Material.AIR);
}
playerInventory.setItem(i, item);
if (amount == 64) break;
}
if (amount == 0) return;
EnchantingInventory inventory = (EnchantingInventory) e.getInventory();
lapis.setAmount(amount);
inventory.setSecondary(lapis);
}
@EventHandler
public void onInventoryClose(InventoryCloseEvent e) {
if (!(e.getInventory() instanceof EnchantingInventory)) return;
Player player = (Player) e.getPlayer();
int version = Via.getAPI().getPlayerVersion(player);
if (version>5) return;
PlayerInventory playerInventory = player.getInventory();
EnchantingInventory inventory = (EnchantingInventory) e.getInventory();
ItemStack item = inventory.getSecondary();
if (item==null || item.getType()==Material.AIR) return;
inventory.setSecondary(new ItemStack(Material.AIR));
Map<Integer, ItemStack> remaining = playerInventory.addItem(item);
if (!remaining.isEmpty()) {
Location location = player.getLocation();
for (ItemStack value : remaining.values()) {
player.getWorld().dropItem(location, value);
}
}
}
@EventHandler
public void onInventoryClose(InventoryCloseEvent e) {
if (!(e.getInventory() instanceof EnchantingInventory)) return;
Player player = (Player) e.getPlayer();
int version = Via.getAPI().getPlayerVersion(player);
if (version > 5) return;
PlayerInventory playerInventory = player.getInventory();
EnchantingInventory inventory = (EnchantingInventory) e.getInventory();
ItemStack item = inventory.getSecondary();
if (item == null || item.getType() == Material.AIR) return;
inventory.setSecondary(new ItemStack(Material.AIR));
Map<Integer, ItemStack> remaining = playerInventory.addItem(item);
if (!remaining.isEmpty()) {
Location location = player.getLocation();
for (ItemStack value : remaining.values()) {
player.getWorld().dropItem(location, value);
}
}
}
}

View File

@ -24,167 +24,167 @@ import java.lang.reflect.Method;
public class SoundListener implements Listener {
private static boolean isSoundCategory = false;
private static boolean isSoundCategory = false;
static {
try {
Class.forName("org.bukkit.SoundCategory");
isSoundCategory = true;
} catch (ClassNotFoundException ignored) {
static {
try {
Class.forName("org.bukkit.SoundCategory");
isSoundCategory = true;
} catch (ClassNotFoundException ignored) {
}
}
}
public SoundListener() {
try {
Class.forName("org.bukkit.event.entity.EntityPickupItemEvent");
public SoundListener() {
try {
Class.forName("org.bukkit.event.entity.EntityPickupItemEvent");
Bukkit.getPluginManager().registerEvents(new Listener() {
Bukkit.getPluginManager().registerEvents(new Listener() {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onItemPickUp(EntityPickupItemEvent e) {
if (!(e.getEntity() instanceof Player))
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onItemPickUp(EntityPickupItemEvent e) {
if (!(e.getEntity() instanceof Player))
return;
SoundListener.this.onItemPickUp((Player) e.getEntity());
}
}, BukkitPlugin.getInstance());
} catch (Exception ex) {
Bukkit.getPluginManager().registerEvents(new Listener() {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onItemPickUp(PlayerPickupItemEvent e) {
SoundListener.this.onItemPickUp(e.getPlayer());
}
}, BukkitPlugin.getInstance());
}
}
@EventHandler
public void onBlockPlace(BlockPlaceEvent e) {
Player player = e.getPlayer();
if (Via.getAPI().getPlayerVersion(player) > 47)
return;
SoundListener.this.onItemPickUp((Player) e.getEntity());
if (Via.getAPI().getServerVersion().lowestSupportedVersion() >= 755) {
player.playSound(e.getBlockPlaced().getLocation(), e.getBlock().getBlockData().getSoundGroup().getPlaceSound(), 1.0f, 0.8f);
} else {
playBlockPlaceSoundNMS(player, e.getBlock());
}
}
}, BukkitPlugin.getInstance());
} catch (Exception ex) {
Bukkit.getPluginManager().registerEvents(new Listener() {
private void onItemPickUp(Player player) {
float volume = 0.2f;
float pitch = (float) ((Math.random() - Math.random()) * 0.7f + 1.0f) * 2.0f;
Location loc = player.getLocation();
playSound(loc, Sound.ENTITY_ITEM_PICKUP, "PLAYERS", volume, pitch, 16, 47);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onItemPickUp(PlayerPickupItemEvent e) {
SoundListener.this.onItemPickUp(e.getPlayer());
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
private void onExperienceOrbPickup(PlayerExpChangeEvent e) {
float volume = 0.1f;
float pitch = (float) (0.5f * ((Math.random() - Math.random()) * 0.7f + 1.8f));
playSound(e.getPlayer().getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, "PLAYERS", volume, pitch, 16, 47);
}
private static void playSound(Location loc, Sound sound, String category, float volume, float pitch, double dist, int version) {
Bukkit.getOnlinePlayers().stream()
.filter(p -> p.getWorld() == loc.getWorld())
.filter(p -> p.getLocation().distanceSquared(loc) < dist * dist)
.filter(p -> Via.getAPI().getPlayerVersion(p) <= version)
.forEach(p -> {
if (isSoundCategory) {
p.playSound(loc, sound, SoundCategory.valueOf(category), volume, pitch);
} else {
p.playSound(loc, sound, volume, pitch);
}
});
}
// 1.8.8 -> 1.16.5
private static void playBlockPlaceSoundNMS(Player player, Block block) {
try {
World world = block.getWorld();
Object nmsWorld = world.getClass().getMethod("getHandle").invoke(world);
Class<?> blockPositionClass = NMSReflection.getBlockPositionClass();
Object blockPosition = null;
if (blockPositionClass != null)
blockPosition = blockPositionClass.getConstructor(int.class, int.class, int.class).newInstance(block.getX(), block.getY(), block.getZ());
Method getTypeMethod = nmsWorld.getClass().getMethod("getType", blockPositionClass);
getTypeMethod.setAccessible(true);
Object blockData = getTypeMethod.invoke(nmsWorld, blockPosition);
Method getBlock = blockData.getClass().getMethod("getBlock");
getBlock.setAccessible(true);
Object nmsBlock = getBlock.invoke(blockData);
Method getStepSound = ReflectionAPI.pickMethod(
nmsBlock.getClass(),
new MethodSignature("w"), // 1.9 -> 1.10
new MethodSignature("getStepSound", blockData.getClass()), // 1.14 -> 1.16
new MethodSignature("getStepSound") // 1.11 -> 1.12
);
getStepSound.setAccessible(true);
Object soundType;
if (getStepSound.getParameterCount() == 0) {
soundType = getStepSound.invoke(nmsBlock); // 1.9 -> 1.13
} else {
soundType = getStepSound.invoke(nmsBlock, blockData); // 1.14 -> 1.16.5
}
Method soundEffectMethod;
Method volumeMethod;
Method pitchMethod;
try {
// 1.16.5
soundEffectMethod = soundType.getClass().getMethod("getPlaceSound");
volumeMethod = soundType.getClass().getMethod("getVolume");
pitchMethod = soundType.getClass().getMethod("getPitch");
} catch (NoSuchMethodException ex) {
// 1.9 -> 1.16.4
soundEffectMethod = soundType.getClass().getMethod("e");
volumeMethod = soundType.getClass().getMethod("a");
pitchMethod = soundType.getClass().getMethod("b");
}
Object soundEffect = soundEffectMethod.invoke(soundType);
float volume = (float) volumeMethod.invoke(soundType);
float pitch = (float) pitchMethod.invoke(soundType);
Object soundCategory = Enum.valueOf(NMSReflection.getSoundCategoryClass(), "BLOCKS");
volume = (volume + 1.0f) / 2.0f;
pitch *= 0.8;
playSound(player, soundEffect, soundCategory, block.getX() + 0.5, block.getY() + 0.5, block.getZ() + 0.5, volume, pitch);
} catch (Exception ex) {
ex.printStackTrace();
}
}, BukkitPlugin.getInstance());
}
}
@EventHandler
public void onBlockPlace(BlockPlaceEvent e) {
Player player = e.getPlayer();
// 1.8.8 -> 1.16.5
private static void playSound(Player player, Object soundEffect, Object soundCategory, double x, double y, double z, float volume, float pitch) {
try {
Object packet = NMSReflection.getGamePacketClass("PacketPlayOutNamedSoundEffect").getConstructor(
soundEffect.getClass(), soundCategory.getClass(),
double.class, double.class, double.class,
float.class, float.class
).newInstance(
soundEffect, soundCategory,
x, y, z,
volume, pitch
);
if (Via.getAPI().getPlayerVersion(player) > 47)
return;
if(Via.getAPI().getServerVersion().lowestSupportedVersion() >= 755) {
player.playSound(e.getBlockPlaced().getLocation(), e.getBlock().getBlockData().getSoundGroup().getPlaceSound(), 1.0f, 0.8f);
} else {
playBlockPlaceSoundNMS(player, e.getBlock());
// Volume = 1
// Pitch = .8
NMSReflection.sendPacket(player, packet);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
private void onItemPickUp(Player player) {
float volume = 0.2f;
float pitch = (float) ((Math.random() - Math.random()) * 0.7f + 1.0f) * 2.0f;
Location loc = player.getLocation();
playSound(loc, Sound.ENTITY_ITEM_PICKUP, "PLAYERS", volume, pitch, 16, 47);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
private void onExperienceOrbPickup(PlayerExpChangeEvent e) {
float volume = 0.1f;
float pitch = (float) (0.5f * ((Math.random() - Math.random()) * 0.7f + 1.8f));
playSound(e.getPlayer().getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, "PLAYERS", volume, pitch, 16, 47);
}
private static void playSound(Location loc, Sound sound, String category, float volume, float pitch, double dist, int version) {
Bukkit.getOnlinePlayers().stream()
.filter(p -> p.getWorld() == loc.getWorld())
.filter(p -> p.getLocation().distanceSquared(loc) < dist * dist)
.filter(p -> Via.getAPI().getPlayerVersion(p) <= version)
.forEach(p -> {
if (isSoundCategory) {
p.playSound(loc, sound, SoundCategory.valueOf(category), volume, pitch);
} else {
p.playSound(loc, sound, volume, pitch);
}
});
}
// 1.8.8 -> 1.16.5
private static void playBlockPlaceSoundNMS(Player player, Block block) {
try {
World world = block.getWorld();
Object nmsWorld = world.getClass().getMethod("getHandle").invoke(world);
Class<?> blockPositionClass = NMSReflection.getBlockPositionClass();
Object blockPosition = null;
if (blockPositionClass != null)
blockPosition = blockPositionClass.getConstructor(int.class, int.class, int.class).newInstance(block.getX(), block.getY(), block.getZ());
Method getTypeMethod = nmsWorld.getClass().getMethod("getType", blockPositionClass);
getTypeMethod.setAccessible(true);
Object blockData = getTypeMethod.invoke(nmsWorld, blockPosition);
Method getBlock = blockData.getClass().getMethod("getBlock");
getBlock.setAccessible(true);
Object nmsBlock = getBlock.invoke(blockData);
Method getStepSound = ReflectionAPI.pickMethod(
nmsBlock.getClass(),
new MethodSignature("w"), // 1.9 -> 1.10
new MethodSignature("getStepSound", blockData.getClass()), // 1.14 -> 1.16
new MethodSignature("getStepSound") // 1.11 -> 1.12
);
getStepSound.setAccessible(true);
Object soundType;
if (getStepSound.getParameterCount() == 0) {
soundType = getStepSound.invoke(nmsBlock); // 1.9 -> 1.13
} else {
soundType = getStepSound.invoke(nmsBlock, blockData); // 1.14 -> 1.16.5
}
Method soundEffectMethod;
Method volumeMethod;
Method pitchMethod;
try {
// 1.16.5
soundEffectMethod = soundType.getClass().getMethod("getPlaceSound");
volumeMethod = soundType.getClass().getMethod("getVolume");
pitchMethod = soundType.getClass().getMethod("getPitch");
} catch (NoSuchMethodException ex) {
// 1.9 -> 1.16.4
soundEffectMethod = soundType.getClass().getMethod("e");
volumeMethod = soundType.getClass().getMethod("a");
pitchMethod = soundType.getClass().getMethod("b");
}
Object soundEffect = soundEffectMethod.invoke(soundType);
float volume = (float) volumeMethod.invoke(soundType);
float pitch = (float) pitchMethod.invoke(soundType);
Object soundCategory = Enum.valueOf(NMSReflection.getSoundCategoryClass(), "BLOCKS");
volume = (volume + 1.0f) / 2.0f;
pitch *= 0.8;
playSound(player, soundEffect, soundCategory, block.getX() + 0.5, block.getY() + 0.5, block.getZ() + 0.5, volume, pitch);
} catch (Exception ex) {
ex.printStackTrace();
}
}
// 1.8.8 -> 1.16.5
private static void playSound(Player player, Object soundEffect, Object soundCategory, double x, double y, double z, float volume, float pitch) {
try {
Object packet = NMSReflection.getGamePacketClass("PacketPlayOutNamedSoundEffect").getConstructor(
soundEffect.getClass(), soundCategory.getClass(),
double.class, double.class, double.class,
float.class, float.class
).newInstance(
soundEffect, soundCategory,
x, y, z,
volume, pitch
);
// Volume = 1
// Pitch = .8
NMSReflection.sendPacket(player, packet);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

View File

@ -13,26 +13,22 @@ import java.util.Map;
import java.util.Objects;
public class ReflectionAPI {
private static Map<String, Field> fields = new HashMap<>();
private static Map<String, Method> methods = new HashMap<>();
private static boolean staticFinalModificationBlocked;
private static Map<String, Field> fields = new HashMap<>();
private static boolean staticFinalModificationBlocked;
static {
try {
static {
try {
Field.class.getDeclaredField("modifiers");
} catch (NoSuchFieldException ex) {
staticFinalModificationBlocked = true;
} catch (NoSuchFieldException ex) {
staticFinalModificationBlocked = true;
}
}
public static Method pickMethod(Class<?> holder, String... names) {
return pickMethod(holder, Arrays.stream(names).map(MethodSignature::new).toArray(MethodSignature[]::new));
}
/**
* Recursively searches for (declared) methods at a specific class and all it's superclasses
* @param holder The base class where to start searching
* @param signatures Possible method signatures consisting of method name and parameters
*
* @param holder The base class where to start searching
* @param signatures Possible method signatures consisting of method name and parameters
* @return The found {@link Method} or {@code null}
* @throws RuntimeException If no method was found
*/
@ -42,9 +38,9 @@ public class ReflectionAPI {
for (MethodSignature signature : signatures) {
try {
Method method = depth.getDeclaredMethod(signature.name(), signature.parameterTypes());
if (signature.returnType() != null && !Objects.equals(method.getReturnType(), signature.returnType())) {
continue;
}
if (signature.returnType() != null && !Objects.equals(method.getReturnType(), signature.returnType())) {
continue;
}
if (!method.isAccessible()) {
method.setAccessible(true);
}
@ -56,452 +52,70 @@ public class ReflectionAPI {
throw new RuntimeException("Failed to resolve method in " + holder + " using " + Arrays.toString(signatures));
}
public static Field getField(Class clazz, String fieldname) {
String key = clazz.getName() + ":" + fieldname;
Field field = null;
if (fields.containsKey(key)) {
field = fields.get(key);
} else {
try {
field = clazz.getDeclaredField(fieldname);
} catch (NoSuchFieldException ignored) {}
fields.put(key, field);
}
return field;
}
public static Field getField(Class clazz, String fieldname) {
String key = clazz.getName() + ":" + fieldname;
Field field = null;
if (fields.containsKey(key)) {
field = fields.get(key);
} else {
try {
field = clazz.getDeclaredField(fieldname);
} catch (NoSuchFieldException ignored) {
}
fields.put(key, field);
}
return field;
}
public static boolean hasField(Class clazz, String fieldname) {
return getField(clazz, fieldname) != null;
}
public static Field getFieldAccessible(Class clazz, String fieldname) {
Field field = getField(clazz, fieldname);
if (field != null) field.setAccessible(true);
return field;
}
public static Field getFieldAccessible(Class clazz, String fieldname) {
Field field = getField(clazz, fieldname);
if (field != null) field.setAccessible(true);
return field;
}
public static void setFieldNotFinal(Field field) {
int modifiers = field.getModifiers();
if (!Modifier.isFinal(modifiers)) return;
public static void setFieldNotFinal(Field field) {
int modifiers = field.getModifiers();
if (!Modifier.isFinal(modifiers)) return;
if (staticFinalModificationBlocked) {
try {
Method getDeclaredFields0 = Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class);
getDeclaredFields0.setAccessible(true);
Field[] fields = (Field[]) getDeclaredFields0.invoke(Field.class, false);
for (Field classField : fields) {
if ("modifiers".equals(classField.getName())) {
classField.setAccessible(true);
classField.set(field, modifiers & ~Modifier.FINAL);
break;
}
}
} catch (ReflectiveOperationException ex) {
ex.printStackTrace();
}
if (staticFinalModificationBlocked) {
try {
Method getDeclaredFields0 = Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class);
getDeclaredFields0.setAccessible(true);
Field[] fields = (Field[]) getDeclaredFields0.invoke(Field.class, false);
for (Field classField : fields) {
if ("modifiers".equals(classField.getName())) {
classField.setAccessible(true);
classField.set(field, modifiers & ~Modifier.FINAL);
break;
}
}
} catch (ReflectiveOperationException ex) {
ex.printStackTrace();
}
} else {
setValuePrintException(Field.class, field, "modifiers", modifiers & ~Modifier.FINAL);
}
}
}
public static <E> Constructor<E> getEmptyConstructor(Class<E> clazz) {
try {
return getConstructor(clazz, Object.class.getDeclaredConstructor());
} catch (NoSuchMethodException ex) {
ex.printStackTrace();
}
return null;
}
public static <E> Constructor<E> getConstructor(Class<E> clazz, Constructor<? super E> superConstructor) {
return (Constructor<E>) ReflectionFactory.getReflectionFactory().newConstructorForSerialization(clazz, superConstructor);
}
public static <E> Constructor<E> getConstructor(Class<E> clazz, Constructor<? super E> superConstructor) {
return (Constructor<E>) ReflectionFactory.getReflectionFactory().newConstructorForSerialization(clazz, superConstructor);
}
public static void setValue(Class clazz, Object object, String fieldname, Object value, boolean isFinal) throws NoSuchFieldException, IllegalAccessException {
Field field = getFieldAccessible(clazz, fieldname);
if (isFinal) setFieldNotFinal(field);
field.set(object, value);
}
public static <E> E getEmptyObject(Class<E> clazz) {
Constructor<E> constructor = getEmptyConstructor(clazz);
try {
return clazz.cast(constructor.newInstance());
} catch (InstantiationException | IllegalArgumentException | InvocationTargetException | IllegalAccessException ex) {
ex.printStackTrace();
}
return null;
}
public static void setValue(Class clazz, Object object, String fieldname, Object value) throws NoSuchFieldException, IllegalAccessException {
setValue(clazz, object, fieldname, value, false);
}
public static <O, E extends O> E copyAndExtendObject(O object, Class<E> clazz) {
if (!object.getClass().isAssignableFrom(clazz)) throw new IllegalArgumentException(clazz.getName() + " is not compatible to " + object.getClass().getName());
E copy = getEmptyObject(clazz);
Class<?> current = object.getClass();
do {
for (Field f : current.getDeclaredFields()) {
int modifiers = f.getModifiers();
if (Modifier.isStatic(modifiers)) continue;
if (Modifier.isFinal(modifiers)) setFieldNotFinal(f);
if (!f.isAccessible()) f.setAccessible(true);
try {
f.set(copy, f.get(object));
} catch (IllegalAccessException ex) {
ex.printStackTrace();
}
}
} while (((current = current.getSuperclass()) != Object.class));
return copy;
}
public static <E> E invokeMethod(Object object, Method method, Class<E> returnType, Object... params) {
try {
return (E) method.invoke(object, params);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static <E> E invokeMethod(Method method, Class<E> returnType, Object... params) {
return invokeMethod(null, method, returnType, params);
}
public static <E> E invokeMethod(Object object, Method method, Object... params) {
try {
return (E) method.invoke(object, params);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static <E> E invokeMethod(Method method, Object... params) {
return invokeMethod(null, method, params);
}
public static Method getMethod(Class clazz, String methodname, Class<?>... params) throws NoSuchMethodException {
if (clazz == null) throw new NullPointerException();
NoSuchMethodException exception = null;
while (clazz != null) {
try {
Method method = clazz.getDeclaredMethod(methodname, params);
method.setAccessible(true);
return method;
} catch (NoSuchMethodException ex) {
exception = ex;
}
clazz = clazz.getSuperclass();
}
if (exception != null) {
throw exception;
} else {
throw new IllegalStateException();
}
}
public static Method getMethodPrintException(Class clazz, String methodname, Class<?>... params) {
try {
return getMethod(clazz, methodname, params);
} catch (NoSuchMethodException ex) {
ex.printStackTrace();
}
return null;
}
public static Method getMethodOrNull(Class clazz, String methodname, Class<?>... params) {
try {
return getMethod(clazz, methodname, params);
} catch (NoSuchMethodException ex) {
return null;
}
}
public static <E> E getValue(Class clazz, Object object, String fieldname) throws NoSuchFieldException, IllegalAccessException {
return (E) getFieldAccessible(clazz, fieldname).get(object);
}
public static <E> E getValue(Object object, String fieldname) throws NoSuchFieldException, IllegalAccessException {
return getValue(object.getClass(), object, fieldname);
}
public static <E> E getValue(Class clazz, String fieldname) throws NoSuchFieldException, IllegalAccessException {
return getValue(clazz, null, fieldname);
}
public static <E> E getValue(Field field) throws IllegalAccessException {
return (E) field.get(null);
}
public static <E> E getValue(Object object, Field field) throws IllegalAccessException {
return (E) field.get(object);
}
public static <E> E getValuePrintException(Class clazz, Object object, String fieldname) {
try {
return getValue(clazz, object, fieldname);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static <E> E getValuePrintException(Object object, String fieldname) {
try {
return getValue(object, fieldname);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static <E> E getValuePrintException(Class clazz, String fieldname) {
try {
return getValue(clazz, fieldname);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static <E> E getValuePrintException(Field field) {
try {
return (E) field.get(null);
} catch (IllegalAccessException ex) {
ex.printStackTrace();
}
return null;
}
public static <E> E getValuePrintException(Object object, Field field) {
try {
return (E) field.get(object);
} catch (IllegalAccessException ex) {
ex.printStackTrace();
}
return null;
}
public static <E> E getValueIgnoreException(Class clazz, Object object, String fieldname) {
try {
return getValue(clazz, object, fieldname);
} catch (Exception ignored) {}
return null;
}
public static <E> E getValueIgnoreException(Object object, String fieldname) {
try {
return getValue(object, fieldname);
} catch (Exception ignored) {}
return null;
}
public static <E> E getValueIgnoreException(Class clazz, String fieldname) {
try {
return getValue(clazz, fieldname);
} catch (Exception ignored) {}
return null;
}
public static <E> E getValueIgnoreException(Field field) {
try {
return (E) field.get(null);
} catch (IllegalAccessException ignored) {}
return null;
}
public static <E> E getValueIgnoreException(Object object, Field field) {
try {
return (E) field.get(object);
} catch (IllegalAccessException ignored) {}
return null;
}
public static void setValue(Class clazz, Object object, String fieldname, Object value, boolean isFinal) throws NoSuchFieldException, IllegalAccessException {
Field field = getFieldAccessible(clazz, fieldname);
if (isFinal) setFieldNotFinal(field);
field.set(object, value);
}
public static void setValue(Class clazz, Object object, String fieldname, Object value) throws NoSuchFieldException, IllegalAccessException {
setValue(clazz, object, fieldname, value, false);
}
public static void setValue(Object object, String fieldname, Object value) throws NoSuchFieldException, IllegalAccessException {
setValue(object.getClass(), object, fieldname, value, false);
}
public static void setValue(Class clazz, String fieldname, Object value) throws NoSuchFieldException, IllegalAccessException {
setValue(clazz, null, fieldname, value, false);
}
public static void setValue(Field field, Object value) throws IllegalAccessException {
field.set(null, value);
}
public static void setValue(Object object, Field field, Object value) throws IllegalAccessException {
field.set(object, value);
}
public static void setFinalValue(Class clazz, Object object, String fieldname, Object value) throws NoSuchFieldException, IllegalAccessException {
setValue(clazz, object, fieldname, value, true);
}
public static void setFinalValue(Object object, String fieldname, Object value) throws NoSuchFieldException, IllegalAccessException {
setValue(object.getClass(), object, fieldname, value, true);
}
public static void setFinalValue(Class clazz, String fieldname, Object value) throws NoSuchFieldException, IllegalAccessException {
setValue(clazz, null, fieldname, value, true);
}
public static void setFinalValue(Field field, Object value) throws IllegalAccessException {
setFieldNotFinal(field);
field.set(null, value);
}
public static void setFinalValue(Object object, Field field, Object value) throws IllegalAccessException {
setFieldNotFinal(field);
field.set(object, value);
}
public static void setValuePrintException(Class clazz, Object object, String fieldname, Object value) {
try {
setValue(clazz, object, fieldname, value);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void setValuePrintException(Object object, String fieldname, Object value) {
try {
setValue(object, fieldname, value);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void setValuePrintException(Class clazz, String fieldname, Object value) {
try {
setValue(clazz, fieldname, value);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void setValuePrintException(Field field, Object value) {
try {
field.set(null, value);
} catch (IllegalAccessException ex) {
ex.printStackTrace();
}
}
public static void setValuePrintException(Object object, Field field, Object value) {
try {
field.set(object, value);
} catch (IllegalAccessException ex) {
ex.printStackTrace();
}
}
public static void setFinalValuePrintException(Class clazz, Object object, String fieldname, Object value) {
try {
setFinalValue(clazz, object, fieldname, value);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void setFinalValuePrintException(Object object, String fieldname, Object value) {
try {
setFinalValue(object, fieldname, value);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void setFinalValuePrintException(Class clazz, String fieldname, Object value) {
try {
setFinalValue(clazz, fieldname, value);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void setFinalValuePrintException(Field field, Object value) {
setFieldNotFinal(field);
try {
field.set(null, value);
} catch (IllegalAccessException ex) {
ex.printStackTrace();
}
}
public static void setFinalValuePrintException(Object object, Field field, Object value) {
setFieldNotFinal(field);
try {
field.set(object, value);
} catch (IllegalAccessException ex) {
ex.printStackTrace();
}
}
public static void setValueIgnoreException(Class clazz, Object object, String fieldname, Object value) {
try {
setValue(clazz, object, fieldname, value);
} catch (Exception ignored) {}
}
public static void setValueIgnoreException(Object object, String fieldname, Object value) {
try {
setValue(object, fieldname, value);
} catch (Exception ignored) {}
}
public static void setValueIgnoreException(Class clazz, String fieldname, Object value) {
try {
setValue(clazz, fieldname, value);
} catch (Exception ignored) {}
}
public static void setValueIgnoreException(Field field, Object value) {
try {
field.set(null, value);
} catch (IllegalAccessException ignored) {}
}
public static void setValueIgnoreException(Object object, Field field, Object value) {
try {
field.set(object, value);
} catch (IllegalAccessException ignored) {}
}
public static void setFinalValueIgnoreException(Class clazz, Object object, String fieldname, Object value) {
try {
setFinalValue(clazz, object, fieldname, value);
} catch (Exception ignored) {}
}
public static void setFinalValueIgnoreException(Object object, String fieldname, Object value) {
try {
setFinalValue(object, fieldname, value);
} catch (Exception ignored) {}
}
public static void setFinalValueIgnoreException(Class clazz, String fieldname, Object value) {
try {
setFinalValue(clazz, fieldname, value);
} catch (Exception ignored) {}
}
public static void setFinalValueIgnoreException(Field field, Object value) {
setFieldNotFinal(field);
try {
field.set(null, value);
} catch (IllegalAccessException ignored) {}
}
public static void setFinalValueIgnoreException(Object object, Field field, Object value) {
setFieldNotFinal(field);
try {
field.set(object, value);
} catch (IllegalAccessException ignored) {}
}
public static void setValuePrintException(Class clazz, Object object, String fieldname, Object value) {
try {
setValue(clazz, object, fieldname, value);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

View File

@ -9,35 +9,35 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
public class VersionInformer implements Listener {
private String[] versionMessage;
private int maxVersion;
private final String[] versionMessage;
private final int maxVersion;
public VersionInformer() {
String message = BukkitPlugin.getInstance().getConfig().getString("versioninfo.message");
message = ChatColor.translateAlternateColorCodes('&', message);
message = message.replace("%version%", Bukkit.getVersion().split(" ")[2].replace(")", ""));
this.versionMessage = message.split(System.lineSeparator());
public VersionInformer() {
String message = BukkitPlugin.getInstance().getConfig().getString("versioninfo.message");
message = ChatColor.translateAlternateColorCodes('&', message);
message = message.replace("%version%", Bukkit.getVersion().split(" ")[2].replace(")", ""));
this.versionMessage = message.split(System.lineSeparator());
maxVersion = BukkitPlugin.getInstance().getConfig().getInt("versioninfo.max-version");
String interval = BukkitPlugin.getInstance().getConfig().getString("versioninfo.interval");
if (interval.equalsIgnoreCase("JOIN")) {
Bukkit.getPluginManager().registerEvents(this, BukkitPlugin.getInstance());
} else {
long ticks = Long.parseLong(interval);
Bukkit.getScheduler().runTaskTimer(BukkitPlugin.getInstance(), () -> {
Bukkit.getOnlinePlayers().forEach(player -> {
int version = Via.getAPI().getPlayerVersion(player);
if (version>maxVersion) return;
player.sendMessage(this.versionMessage);
});
}, ticks, ticks);
}
}
maxVersion = BukkitPlugin.getInstance().getConfig().getInt("versioninfo.max-version");
String interval = BukkitPlugin.getInstance().getConfig().getString("versioninfo.interval");
if (interval.equalsIgnoreCase("JOIN")) {
Bukkit.getPluginManager().registerEvents(this, BukkitPlugin.getInstance());
} else {
long ticks = Long.parseLong(interval);
Bukkit.getScheduler().runTaskTimer(BukkitPlugin.getInstance(), () -> {
Bukkit.getOnlinePlayers().forEach(player -> {
int version = Via.getAPI().getPlayerVersion(player);
if (version > maxVersion) return;
player.sendMessage(this.versionMessage);
});
}, ticks, ticks);
}
}
@EventHandler
public void onJoin(PlayerJoinEvent e) {
int version = Via.getAPI().getPlayerVersion(e.getPlayer());
if (version>maxVersion) return;
e.getPlayer().sendMessage(this.versionMessage);
}
@EventHandler
public void onJoin(PlayerJoinEvent e) {
int version = Via.getAPI().getPlayerVersion(e.getPlayer());
if (version > maxVersion) return;
e.getPlayer().sendMessage(this.versionMessage);
}
}