geforkt von Mirrors/AxiomPaperPlugin
Dieser Commit ist enthalten in:
Ursprung
7d82fed462
Commit
6f44fad535
@ -18,8 +18,6 @@ java {
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
|
||||||
maven("https://jitpack.io")
|
|
||||||
maven("https://maven.enginehub.org/repo/")
|
maven("https://maven.enginehub.org/repo/")
|
||||||
maven("https://repo.papermc.io/repository/maven-public/")
|
maven("https://repo.papermc.io/repository/maven-public/")
|
||||||
maven("https://repo.viaversion.com")
|
maven("https://repo.viaversion.com")
|
||||||
@ -27,7 +25,6 @@ repositories {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
paperweight.paperDevBundle("1.20.1-R0.1-SNAPSHOT")
|
paperweight.paperDevBundle("1.20.1-R0.1-SNAPSHOT")
|
||||||
implementation("xyz.jpenilla:reflection-remapper:0.1.0-SNAPSHOT")
|
|
||||||
|
|
||||||
// Zstd Compression Library
|
// Zstd Compression Library
|
||||||
implementation("com.github.luben:zstd-jni:1.5.5-4")
|
implementation("com.github.luben:zstd-jni:1.5.5-4")
|
||||||
|
@ -7,10 +7,16 @@ public class AxiomConstants {
|
|||||||
public static final long MIN_POSITION_LONG = 0b1000000000000000000000000010000000000000000000000000100000000000L;
|
public static final long MIN_POSITION_LONG = 0b1000000000000000000000000010000000000000000000000000100000000000L;
|
||||||
|
|
||||||
public static final int API_VERSION = 5;
|
public static final int API_VERSION = 5;
|
||||||
public static final NamespacedKey ACTIVE_HOTBAR_INDEX = new NamespacedKey("axiom", "active_hotbar_index");
|
|
||||||
public static final NamespacedKey HOTBAR_DATA = new NamespacedKey("axiom", "hotbar_data");
|
|
||||||
|
|
||||||
public static final NamespacedKey ACTIVE_VIEW = new NamespacedKey("axiom", "active_view");
|
public static final String PERMISSION = "axiom.*";
|
||||||
public static final NamespacedKey VIEWS = new NamespacedKey("axiom", "views");
|
|
||||||
|
|
||||||
|
public static final NamespacedKey ACTIVE_HOTBAR_INDEX = axiomKey("active_hotbar_index");
|
||||||
|
public static final NamespacedKey HOTBAR_DATA = axiomKey("hotbar_data");
|
||||||
|
|
||||||
|
public static final NamespacedKey ACTIVE_VIEW = axiomKey("active_view");
|
||||||
|
public static final NamespacedKey VIEWS = axiomKey("views");
|
||||||
|
|
||||||
|
public static NamespacedKey axiomKey(String key) {
|
||||||
|
return new NamespacedKey("axiom", key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,12 @@ package com.moulberry.axiom;
|
|||||||
|
|
||||||
import com.moulberry.axiom.integration.PaperFailMoveListener;
|
import com.moulberry.axiom.integration.PaperFailMoveListener;
|
||||||
import com.moulberry.axiom.packet.*;
|
import com.moulberry.axiom.packet.*;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
@ -14,19 +18,22 @@ import java.util.logging.Level;
|
|||||||
|
|
||||||
public class AxiomPaper extends JavaPlugin implements Listener {
|
public class AxiomPaper extends JavaPlugin implements Listener {
|
||||||
|
|
||||||
public static final String PERMISSION = "axiom.*";
|
|
||||||
|
|
||||||
private static AxiomPaper instance;
|
private static AxiomPaper instance;
|
||||||
public static Plugin getPlugin() {
|
public static Plugin getPlugin() {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Map<String, AxiomPacketListener> listeners = new ConcurrentHashMap<>();
|
private static final Map<String, AxiomPacketListener> listeners = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public static AxiomPacketListener getListener(String channel) {
|
public static AxiomPacketListener getListener(String channel) {
|
||||||
return listeners.get(channel);
|
return listeners.get(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Class<Player> CraftPlayer = Reflection.getClass("org.bukkit.craftbukkit.entity.CraftPlayer");
|
||||||
|
private static final Reflection.Method<Player, ServerPlayer> getHandle = Reflection.getTypedMethod(CraftPlayer, "getHandle", ServerPlayer.class);
|
||||||
|
public static ServerPlayer convert(Player player) {
|
||||||
|
return getHandle.invoke(player);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
instance = this;
|
instance = this;
|
||||||
@ -41,26 +48,28 @@ public class AxiomPaper extends JavaPlugin implements Listener {
|
|||||||
Bukkit.getMessenger().registerOutgoingPluginChannel(this, channel.getChannel());
|
Bukkit.getMessenger().registerOutgoingPluginChannel(this, channel.getChannel());
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO multiversion (Except setGamemode)
|
registerInChannel("hello", new HelloPacketListener(new AxiomPlayerManager()));
|
||||||
registerInChannel("hello", new HelloPacketListener());
|
|
||||||
registerInChannel("set_gamemode", new SetGamemodePacketListener());
|
registerInChannel("set_gamemode", new SetGamemodePacketListener());
|
||||||
registerInChannel("set_fly_speed", new SetFlySpeedPacketListener());
|
registerInChannel("set_fly_speed", new SetFlySpeedPacketListener());
|
||||||
registerInChannel("set_block", new SetBlockPacketListener());
|
registerInChannel("set_block", new SetBlockPacketListener()); //TODO multiversion
|
||||||
registerInChannel("set_hotbar_slot", new SetHotbarSlotPacketListener());
|
registerInChannel("set_hotbar_slot", new SetHotbarSlotPacketListener());
|
||||||
registerInChannel("switch_active_hotbar", new SwitchActiveHotbarPacketListener());
|
registerInChannel("switch_active_hotbar", new SwitchActiveHotbarPacketListener());
|
||||||
registerInChannel("teleport", new TeleportPacketListener());
|
registerInChannel("teleport", new TeleportPacketListener());
|
||||||
registerInChannel("set_editor_views", new SetEditorViewsPacketListener());
|
registerInChannel("set_editor_views", new SetEditorViewsPacketListener());
|
||||||
registerInChannel("request_block_entity", new RequestBlockEntityPacketListener());
|
registerInChannel("request_block_entity", new RequestBlockEntityPacketListener());
|
||||||
registerInChannel("handle_big_payload", new SetBlockBufferPacketListener());
|
registerInChannel("handle_big_payload", new SetBlockBufferPacketListener()); //TODO multiversion
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerInChannel(String channel, AxiomPacketListener handler) {
|
private void registerInChannel(String channel, AxiomPacketListener handler) {
|
||||||
listeners.put(channel, handler);
|
listeners.put(channel, handler);
|
||||||
Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:" + channel, (ch, player, message) -> {
|
Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:" + channel, (ch, player, message) -> {
|
||||||
if (!player.hasPermission(PERMISSION))
|
ByteBuf buf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||||
|
if (!player.hasPermission(AxiomConstants.PERMISSION)) {
|
||||||
|
handler.onMissingPerm(player, buf);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
handler.onMessage(player, Unpooled.wrappedBuffer(message));
|
handler.onMessage(player, buf);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
38
src/main/java/com/moulberry/axiom/AxiomPlayerManager.java
Normale Datei
38
src/main/java/com/moulberry/axiom/AxiomPlayerManager.java
Normale Datei
@ -0,0 +1,38 @@
|
|||||||
|
package com.moulberry.axiom;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class AxiomPlayerManager implements Listener {
|
||||||
|
|
||||||
|
private final Set<Player> axiomPlayers = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||||
|
|
||||||
|
public AxiomPlayerManager() {
|
||||||
|
Bukkit.getPluginManager().registerEvents(this, AxiomPaper.getPlugin());
|
||||||
|
Bukkit.getScheduler().scheduleSyncRepeatingTask(AxiomPaper.getPlugin(), () -> axiomPlayers.removeIf(player -> {
|
||||||
|
if (!player.hasPermission(AxiomConstants.PERMISSION)) {
|
||||||
|
OutChannel.ENABLE.send(player, new byte[] { 0 });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}), 20, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(Player player) {
|
||||||
|
axiomPlayers.add(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
|
axiomPlayers.remove(event.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
137
src/main/java/com/moulberry/axiom/Reflection.java
Normale Datei
137
src/main/java/com/moulberry/axiom/Reflection.java
Normale Datei
@ -0,0 +1,137 @@
|
|||||||
|
package com.moulberry.axiom;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
|
import java.lang.reflect.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class Reflection {
|
||||||
|
private Reflection() {}
|
||||||
|
|
||||||
|
public interface Field<T, R> {
|
||||||
|
R get(T target);
|
||||||
|
void set(T target, R value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, R> Field<T, R> getField(Class<T> target, Class<R> fieldType, Class<?>... parameters) {
|
||||||
|
return getField(target, fieldType, 0, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, R> Field<T, R> getField(Class<T> target, Class<R> fieldType, int index, Class<?>... parameters) {
|
||||||
|
for (final java.lang.reflect.Field field : target.getDeclaredFields()) {
|
||||||
|
if(matching(field, fieldType, parameters) && index-- <= 0) {
|
||||||
|
field.setAccessible(true);
|
||||||
|
|
||||||
|
return new Field<>() {
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public R get(T target) {
|
||||||
|
try {
|
||||||
|
return (R) field.get(target);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new IllegalArgumentException("Cannot access reflection.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(T target, R value) {
|
||||||
|
try {
|
||||||
|
field.set(target, value);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new IllegalArgumentException("Cannot access reflection.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.getSuperclass() != null) {
|
||||||
|
try {
|
||||||
|
return getField((Class<T>) target.getSuperclass(), fieldType, index, parameters);
|
||||||
|
} catch (ClassCastException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("Cannot find field with type " + fieldType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> boolean matching(java.lang.reflect.Field field, Class<T> fieldType, Class<?>... parameters) {
|
||||||
|
if(!fieldType.isAssignableFrom(field.getType()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(parameters.length > 0) {
|
||||||
|
Type[] arguments = ((ParameterizedType)field.getGenericType()).getActualTypeArguments();
|
||||||
|
|
||||||
|
for(int i = 0; i < parameters.length; i++) {
|
||||||
|
if(arguments[i] instanceof ParameterizedType ? ((ParameterizedType) arguments[i]).getRawType() != parameters[i] : arguments[i] != parameters[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface Method<T, R> {
|
||||||
|
R invoke(T target, Object... arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Method<T, Object> getMethod(Class<T> clazz, Class<?>... params) {
|
||||||
|
return getTypedMethod(clazz, null, null, 0, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Method<T, Object> getMethod(Class<T> clazz, String methodName, Class<?>... params) {
|
||||||
|
return getTypedMethod(clazz, methodName, null, 0, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, R> Method<T, R> getTypedMethod(Class<T> clazz, Class<R> returnType, Class<?>... params) {
|
||||||
|
return getTypedMethod(clazz, null, returnType, 0, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, R> Method<T, R> getTypedMethod(Class<T> clazz, Class<R> returnType, int index, Class<?>... params) {
|
||||||
|
return getTypedMethod(clazz, null, returnType, index, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, R> Method<T, R> getTypedMethod(Class<T> clazz, String methodName, Class<R> returnType, Class<?>... params) {
|
||||||
|
return getTypedMethod(clazz, methodName, returnType, 0, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T, R> Method<T, R> getTypedMethod(Class<T> clazz, String methodName, Class<R> returnType, int index, Class<?>... params) {
|
||||||
|
for (final java.lang.reflect.Method method : clazz.getDeclaredMethods()) {
|
||||||
|
if ((methodName == null || method.getName().equals(methodName))
|
||||||
|
&& (returnType == null || method.getReturnType().equals(returnType))
|
||||||
|
&& Arrays.equals(method.getParameterTypes(), params)
|
||||||
|
&& index-- <= 0) {
|
||||||
|
method.setAccessible(true);
|
||||||
|
|
||||||
|
return (target, arguments) -> {
|
||||||
|
try {
|
||||||
|
return (R) method.invoke(target, arguments);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalArgumentException("Cannot invoke method " + method, e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clazz.getSuperclass() != null) {
|
||||||
|
try {
|
||||||
|
return getTypedMethod((Class<T>) clazz.getSuperclass(), methodName, returnType, index, params);
|
||||||
|
} catch (ClassCastException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException(String.format("Unable to find method %s (%s).", methodName, Arrays.asList(params)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static final String ORG_BUKKIT_CRAFTBUKKIT = Bukkit.getServer().getClass().getPackage().getName();
|
||||||
|
public static <T> Class<T> getClass(String name) {
|
||||||
|
if(name.startsWith("org.bukkit.craftbukkit"))
|
||||||
|
name = ORG_BUKKIT_CRAFTBUKKIT + name.substring(22);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return (Class<T>) Class.forName(name);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new IllegalArgumentException("Cannot find " + name, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,13 +1,12 @@
|
|||||||
package com.moulberry.axiom;
|
package com.moulberry.axiom;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.buffer.MojBuf;
|
||||||
import com.moulberry.axiom.persistence.UUIDDataType;
|
import com.moulberry.axiom.persistence.UUIDDataType;
|
||||||
import net.minecraft.core.registries.Registries;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import org.bukkit.Bukkit;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import org.bukkit.Location;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
import net.minecraft.world.phys.Vec3;
|
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.persistence.PersistentDataContainer;
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
|
|
||||||
@ -15,73 +14,76 @@ import java.util.UUID;
|
|||||||
|
|
||||||
public final class View {
|
public final class View {
|
||||||
|
|
||||||
public String name;
|
private final String name;
|
||||||
public final UUID uuid;
|
private final UUID uuid;
|
||||||
public boolean pinLevel = false;
|
private boolean pinLevel = false;
|
||||||
public boolean pinLocation = false;
|
private boolean pinLocation = false;
|
||||||
private ResourceKey<Level> level = null;
|
private World level = null;
|
||||||
private Vec3 position = null;
|
private Location location = null;
|
||||||
private float yaw;
|
|
||||||
private float pitch;
|
|
||||||
|
|
||||||
public View(String name, UUID uuid) {
|
public View(String name, UUID uuid) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(FriendlyByteBuf byteBuf) {
|
public void write(ByteBuf buf) {
|
||||||
byteBuf.writeUtf(this.name, 64);
|
MojBuf.writeUtf(buf, this.name, 64);
|
||||||
byteBuf.writeUUID(this.uuid);
|
MojBuf.writeUUID(buf, this.uuid);
|
||||||
|
|
||||||
byteBuf.writeBoolean(this.pinLevel);
|
buf.writeBoolean(this.pinLevel);
|
||||||
if (this.pinLevel && this.level != null) {
|
if (this.pinLevel && this.level != null) {
|
||||||
byteBuf.writeBoolean(true);
|
buf.writeBoolean(true);
|
||||||
byteBuf.writeResourceKey(this.level);
|
MojBuf.writeKey(buf, this.level.getKey());
|
||||||
} else {
|
} else {
|
||||||
byteBuf.writeBoolean(false);
|
buf.writeBoolean(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
byteBuf.writeBoolean(this.pinLocation);
|
buf.writeBoolean(this.pinLocation);
|
||||||
if (this.position != null) {
|
if (this.location != null) {
|
||||||
byteBuf.writeBoolean(true);
|
buf.writeBoolean(true);
|
||||||
byteBuf.writeDouble(this.position.x);
|
buf.writeDouble(this.location.getX());
|
||||||
byteBuf.writeDouble(this.position.y);
|
buf.writeDouble(this.location.getY());
|
||||||
byteBuf.writeDouble(this.position.z);
|
buf.writeDouble(this.location.getZ());
|
||||||
byteBuf.writeFloat(this.yaw);
|
buf.writeFloat(this.location.getYaw());
|
||||||
byteBuf.writeFloat(this.pitch);
|
buf.writeFloat(this.location.getPitch());
|
||||||
} else {
|
} else {
|
||||||
byteBuf.writeBoolean(false);
|
buf.writeBoolean(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static View read(FriendlyByteBuf byteBuf) {
|
public static View read(ByteBuf buf) {
|
||||||
View view = new View(byteBuf.readUtf(64), byteBuf.readUUID());
|
View view = new View(MojBuf.readUtf(buf, 64), MojBuf.readUUID(buf));
|
||||||
|
|
||||||
view.pinLevel = byteBuf.readBoolean();
|
view.pinLevel = buf.readBoolean();
|
||||||
if (byteBuf.readBoolean()) {
|
if (buf.readBoolean()) {
|
||||||
view.level = byteBuf.readResourceKey(Registries.DIMENSION);
|
view.level = Bukkit.getWorld(MojBuf.readKey(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
view.pinLocation = byteBuf.readBoolean();
|
view.pinLocation = buf.readBoolean();
|
||||||
if (byteBuf.readBoolean()) {
|
if (buf.readBoolean()) {
|
||||||
view.position = new Vec3(byteBuf.readDouble(), byteBuf.readDouble(), byteBuf.readDouble());
|
view.location = new Location(view.level,
|
||||||
view.yaw = byteBuf.readFloat();
|
buf.readDouble(),
|
||||||
view.pitch = byteBuf.readFloat();
|
buf.readDouble(),
|
||||||
|
buf.readDouble(),
|
||||||
|
buf.readFloat(),
|
||||||
|
buf.readFloat()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final NamespacedKey NAME_KEY = new NamespacedKey("axiom", "view_name");
|
|
||||||
private static final NamespacedKey UUID_KEY = new NamespacedKey("axiom", "view_uuid");
|
private static final NamespacedKey NAME_KEY = AxiomConstants.axiomKey("view_name");
|
||||||
private static final NamespacedKey PIN_LEVEL_KEY = new NamespacedKey("axiom", "view_pin_level");
|
private static final NamespacedKey UUID_KEY = AxiomConstants.axiomKey("view_uuid");
|
||||||
private static final NamespacedKey LEVEL_KEY = new NamespacedKey("axiom", "view_level");
|
private static final NamespacedKey PIN_LEVEL_KEY = AxiomConstants.axiomKey("view_pin_level");
|
||||||
private static final NamespacedKey PIN_LOCATION_KEY = new NamespacedKey("axiom", "view_pin_location");
|
private static final NamespacedKey LEVEL_KEY = AxiomConstants.axiomKey("view_level");
|
||||||
private static final NamespacedKey X_KEY = new NamespacedKey("axiom", "view_x");
|
private static final NamespacedKey PIN_LOCATION_KEY = AxiomConstants.axiomKey("view_pin_location");
|
||||||
private static final NamespacedKey Y_KEY = new NamespacedKey("axiom", "view_y");
|
private static final NamespacedKey X_KEY = AxiomConstants.axiomKey("view_x");
|
||||||
private static final NamespacedKey Z_KEY = new NamespacedKey("axiom", "view_z");
|
private static final NamespacedKey Y_KEY = AxiomConstants.axiomKey("view_y");
|
||||||
private static final NamespacedKey YAW_KEY = new NamespacedKey("axiom", "view_yaw");
|
private static final NamespacedKey Z_KEY = AxiomConstants.axiomKey("view_z");
|
||||||
private static final NamespacedKey PITCH_KEY = new NamespacedKey("axiom", "view_pitch");
|
private static final NamespacedKey YAW_KEY = AxiomConstants.axiomKey("view_yaw");
|
||||||
|
private static final NamespacedKey PITCH_KEY = AxiomConstants.axiomKey("view_pitch");
|
||||||
|
|
||||||
public void save(PersistentDataContainer container) {
|
public void save(PersistentDataContainer container) {
|
||||||
container.set(NAME_KEY, PersistentDataType.STRING, this.name);
|
container.set(NAME_KEY, PersistentDataType.STRING, this.name);
|
||||||
@ -89,16 +91,16 @@ public final class View {
|
|||||||
|
|
||||||
container.set(PIN_LEVEL_KEY, PersistentDataType.BOOLEAN, this.pinLevel);
|
container.set(PIN_LEVEL_KEY, PersistentDataType.BOOLEAN, this.pinLevel);
|
||||||
if (this.pinLevel && this.level != null) {
|
if (this.pinLevel && this.level != null) {
|
||||||
container.set(LEVEL_KEY, PersistentDataType.STRING, this.level.location().toString());
|
container.set(LEVEL_KEY, PersistentDataType.STRING, this.level.getKey().asString());
|
||||||
}
|
}
|
||||||
|
|
||||||
container.set(PIN_LOCATION_KEY, PersistentDataType.BOOLEAN, this.pinLocation);
|
container.set(PIN_LOCATION_KEY, PersistentDataType.BOOLEAN, this.pinLocation);
|
||||||
if (this.position != null) {
|
if (this.location != null) {
|
||||||
container.set(X_KEY, PersistentDataType.DOUBLE, this.position.x);
|
container.set(X_KEY, PersistentDataType.DOUBLE, this.location.getX());
|
||||||
container.set(Y_KEY, PersistentDataType.DOUBLE, this.position.y);
|
container.set(Y_KEY, PersistentDataType.DOUBLE, this.location.getY());
|
||||||
container.set(Z_KEY, PersistentDataType.DOUBLE, this.position.z);
|
container.set(Z_KEY, PersistentDataType.DOUBLE, this.location.getZ());
|
||||||
container.set(YAW_KEY, PersistentDataType.FLOAT, this.yaw);
|
container.set(YAW_KEY, PersistentDataType.FLOAT, this.location.getYaw());
|
||||||
container.set(PITCH_KEY, PersistentDataType.FLOAT, this.pitch);
|
container.set(PITCH_KEY, PersistentDataType.FLOAT, this.location.getPitch());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,17 +113,18 @@ public final class View {
|
|||||||
view.pinLevel = tag.getOrDefault(PIN_LEVEL_KEY, PersistentDataType.BOOLEAN, false);
|
view.pinLevel = tag.getOrDefault(PIN_LEVEL_KEY, PersistentDataType.BOOLEAN, false);
|
||||||
if (tag.has(LEVEL_KEY)) {
|
if (tag.has(LEVEL_KEY)) {
|
||||||
String level = tag.get(LEVEL_KEY, PersistentDataType.STRING);
|
String level = tag.get(LEVEL_KEY, PersistentDataType.STRING);
|
||||||
view.level = ResourceKey.create(Registries.DIMENSION, new ResourceLocation(level));
|
view.level = Bukkit.getWorld(NamespacedKey.fromString(level));
|
||||||
}
|
}
|
||||||
|
|
||||||
view.pinLocation = tag.getOrDefault(PIN_LOCATION_KEY, PersistentDataType.BOOLEAN, false);
|
view.pinLocation = tag.getOrDefault(PIN_LOCATION_KEY, PersistentDataType.BOOLEAN, false);
|
||||||
if (tag.has(X_KEY) && tag.has(Y_KEY) && tag.has(Z_KEY)) {
|
if (tag.has(X_KEY) && tag.has(Y_KEY) && tag.has(Z_KEY)) {
|
||||||
double x = tag.getOrDefault(X_KEY, PersistentDataType.DOUBLE, 0.0);
|
view.location = new Location(view.level,
|
||||||
double y = tag.getOrDefault(Y_KEY, PersistentDataType.DOUBLE, 0.0);
|
tag.getOrDefault(X_KEY, PersistentDataType.DOUBLE, 0.0),
|
||||||
double z = tag.getOrDefault(Z_KEY, PersistentDataType.DOUBLE, 0.0);
|
tag.getOrDefault(Y_KEY, PersistentDataType.DOUBLE, 0.0),
|
||||||
view.position = new Vec3(x, y, z);
|
tag.getOrDefault(Z_KEY, PersistentDataType.DOUBLE, 0.0),
|
||||||
view.yaw = tag.getOrDefault(YAW_KEY, PersistentDataType.FLOAT, 0.0f);
|
tag.getOrDefault(YAW_KEY, PersistentDataType.FLOAT, 0.0f),
|
||||||
view.pitch = tag.getOrDefault(PITCH_KEY, PersistentDataType.FLOAT, 0.0f);
|
tag.getOrDefault(PITCH_KEY, PersistentDataType.FLOAT, 0.0f)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.moulberry.axiom.buffer;
|
package com.moulberry.axiom.buffer;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
@ -15,14 +16,14 @@ public class BiomeBuffer {
|
|||||||
this.palette = palette;
|
this.palette = palette;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BiomeBuffer load(FriendlyByteBuf friendlyByteBuf) {
|
public static BiomeBuffer load(ByteBuf buf) {
|
||||||
int paletteSize = friendlyByteBuf.readByte();
|
int paletteSize = buf.readByte();
|
||||||
ResourceKey<Biome>[] palette = new ResourceKey[255];
|
ResourceKey<Biome>[] palette = new ResourceKey[255];
|
||||||
for (int i = 0; i < paletteSize; i++) {
|
for (int i = 0; i < paletteSize; i++) {
|
||||||
ResourceKey<Biome> key = friendlyByteBuf.readResourceKey(Registries.BIOME);
|
ResourceKey<Biome> key = buf.readResourceKey(Registries.BIOME);
|
||||||
palette[i] = key;
|
palette[i] = key;
|
||||||
}
|
}
|
||||||
Position2ByteMap map = Position2ByteMap.load(friendlyByteBuf);
|
Position2ByteMap map = Position2ByteMap.load(buf);
|
||||||
return new BiomeBuffer(map, palette);
|
return new BiomeBuffer(map, palette);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.moulberry.axiom.buffer;
|
package com.moulberry.axiom.buffer;
|
||||||
|
|
||||||
import com.moulberry.axiom.AxiomConstants;
|
import com.moulberry.axiom.AxiomConstants;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
||||||
@ -27,22 +28,22 @@ public class BlockBuffer {
|
|||||||
this.values = new Long2ObjectOpenHashMap<>();
|
this.values = new Long2ObjectOpenHashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlockBuffer load(FriendlyByteBuf friendlyByteBuf) {
|
public static BlockBuffer load(ByteBuf buf) {
|
||||||
BlockBuffer buffer = new BlockBuffer();
|
BlockBuffer buffer = new BlockBuffer();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
long index = friendlyByteBuf.readLong();
|
long index = buf.readLong();
|
||||||
if (index == AxiomConstants.MIN_POSITION_LONG) break;
|
if (index == AxiomConstants.MIN_POSITION_LONG) break;
|
||||||
|
|
||||||
PalettedContainer<BlockState> palettedContainer = buffer.getOrCreateSection(index);
|
PalettedContainer<BlockState> palettedContainer = buffer.getOrCreateSection(index);
|
||||||
palettedContainer.read(friendlyByteBuf);
|
palettedContainer.read((FriendlyByteBuf) buf);
|
||||||
|
|
||||||
int blockEntitySize = Math.min(4096, friendlyByteBuf.readVarInt());
|
int blockEntitySize = Math.min(4096, MojBuf.readVarInt(buf));
|
||||||
if (blockEntitySize > 0) {
|
if (blockEntitySize > 0) {
|
||||||
Short2ObjectMap<CompressedBlockEntity> map = new Short2ObjectOpenHashMap<>(blockEntitySize);
|
Short2ObjectMap<CompressedBlockEntity> map = new Short2ObjectOpenHashMap<>(blockEntitySize);
|
||||||
for (int i = 0; i < blockEntitySize; i++) {
|
for (int i = 0; i < blockEntitySize; i++) {
|
||||||
short offset = friendlyByteBuf.readShort();
|
short offset = buf.readShort();
|
||||||
CompressedBlockEntity blockEntity = CompressedBlockEntity.read(friendlyByteBuf);
|
CompressedBlockEntity blockEntity = CompressedBlockEntity.read(buf);
|
||||||
map.put(offset, blockEntity);
|
map.put(offset, blockEntity);
|
||||||
}
|
}
|
||||||
buffer.blockEntities.put(index, map);
|
buffer.blockEntities.put(index, map);
|
||||||
|
@ -3,9 +3,10 @@ package com.moulberry.axiom.buffer;
|
|||||||
import com.github.luben.zstd.Zstd;
|
import com.github.luben.zstd.Zstd;
|
||||||
import com.github.luben.zstd.ZstdDictCompress;
|
import com.github.luben.zstd.ZstdDictCompress;
|
||||||
import com.github.luben.zstd.ZstdDictDecompress;
|
import com.github.luben.zstd.ZstdDictDecompress;
|
||||||
|
import com.moulberry.axiom.Reflection;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.NbtIo;
|
import net.minecraft.nbt.NbtIo;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -24,41 +25,35 @@ public record CompressedBlockEntity(int originalSize, byte compressionDict, byte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Reflection.Method<NbtIo, Object> write = Reflection.getMethod(NbtIo.class, CompoundTag.class, DataOutput.class);
|
||||||
public static CompressedBlockEntity compress(CompoundTag tag, ByteArrayOutputStream baos) {
|
public static CompressedBlockEntity compress(CompoundTag tag, ByteArrayOutputStream baos) {
|
||||||
try {
|
|
||||||
baos.reset();
|
baos.reset();
|
||||||
DataOutputStream dos = new DataOutputStream(baos);
|
DataOutputStream dos = new DataOutputStream(baos);
|
||||||
NbtIo.write(tag, dos);
|
write.invoke(null, tag, dos);
|
||||||
byte[] uncompressed = baos.toByteArray();
|
byte[] uncompressed = baos.toByteArray();
|
||||||
byte[] compressed = Zstd.compress(uncompressed, zstdDictCompress);
|
byte[] compressed = Zstd.compress(uncompressed, zstdDictCompress);
|
||||||
return new CompressedBlockEntity(uncompressed.length, (byte) 0, compressed);
|
return new CompressedBlockEntity(uncompressed.length, (byte) 0, compressed);
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Reflection.Method<NbtIo, CompoundTag> read = Reflection.getTypedMethod(NbtIo.class, CompoundTag.class, DataInput.class);
|
||||||
public CompoundTag decompress() {
|
public CompoundTag decompress() {
|
||||||
if (this.compressionDict != 0) throw new UnsupportedOperationException("Unknown compression dict: " + this.compressionDict);
|
if (this.compressionDict != 0) throw new UnsupportedOperationException("Unknown compression dict: " + this.compressionDict);
|
||||||
|
|
||||||
try {
|
|
||||||
byte[] nbt = Zstd.decompress(this.compressed, zstdDictDecompress, this.originalSize);
|
byte[] nbt = Zstd.decompress(this.compressed, zstdDictDecompress, this.originalSize);
|
||||||
return NbtIo.read(new DataInputStream(new ByteArrayInputStream(nbt)));
|
return read.invoke(null, new DataInputStream(new ByteArrayInputStream(nbt)));
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompressedBlockEntity read(FriendlyByteBuf friendlyByteBuf) {
|
public static CompressedBlockEntity read(ByteBuf buf) {
|
||||||
int originalSize = friendlyByteBuf.readVarInt();
|
int originalSize = MojBuf.readVarInt(buf);
|
||||||
byte compressionDict = friendlyByteBuf.readByte();
|
byte compressionDict = buf.readByte();
|
||||||
byte[] compressed = friendlyByteBuf.readByteArray();
|
byte[] compressed = MojBuf.readByteArray(buf);
|
||||||
return new CompressedBlockEntity(originalSize, compressionDict, compressed);
|
return new CompressedBlockEntity(originalSize, compressionDict, compressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(FriendlyByteBuf friendlyByteBuf) {
|
public void write(ByteBuf buf) {
|
||||||
friendlyByteBuf.writeVarInt(this.originalSize);
|
MojBuf.writeVarInt(buf, this.originalSize);
|
||||||
friendlyByteBuf.writeByte(this.compressionDict);
|
buf.writeByte(this.compressionDict);
|
||||||
friendlyByteBuf.writeByteArray(this.compressed);
|
MojBuf.writeByteArray(buf, this.compressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
116
src/main/java/com/moulberry/axiom/buffer/MojBuf.java
Normale Datei
116
src/main/java/com/moulberry/axiom/buffer/MojBuf.java
Normale Datei
@ -0,0 +1,116 @@
|
|||||||
|
package com.moulberry.axiom.buffer;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.Reflection;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class MojBuf {
|
||||||
|
private MojBuf() {}
|
||||||
|
|
||||||
|
public static ByteBuf unpooled() {
|
||||||
|
return new FriendlyByteBuf(Unpooled.buffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Reflection.Method<FriendlyByteBuf, String> readUtf = Reflection.getTypedMethod(FriendlyByteBuf.class, String.class, int.class);
|
||||||
|
public static String readUtf(ByteBuf buf, int maxLength) {
|
||||||
|
return readUtf.invoke((FriendlyByteBuf) buf, maxLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String readUtf(ByteBuf buf) {
|
||||||
|
return readUtf(buf, Short.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NamespacedKey readKey(ByteBuf buf) {
|
||||||
|
return NamespacedKey.fromString(readUtf(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Reflection.Method<FriendlyByteBuf, FriendlyByteBuf> writeUtf = Reflection.getTypedMethod(FriendlyByteBuf.class, FriendlyByteBuf.class, String.class, int.class);
|
||||||
|
public static void writeUtf(ByteBuf buf, String string, int maxLength) {
|
||||||
|
writeUtf.invoke((FriendlyByteBuf) buf, string, maxLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeUtf(ByteBuf buf, String string) {
|
||||||
|
writeUtf(buf, string, Short.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeKey(ByteBuf buf, NamespacedKey key) {
|
||||||
|
writeUtf(buf, key.asString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// is the first method returning an int with no arguments in 1.20.1
|
||||||
|
private static final Reflection.Method<FriendlyByteBuf, Integer> readVarInt = Reflection.getTypedMethod(FriendlyByteBuf.class, int.class);
|
||||||
|
public static int readVarInt(ByteBuf buf) {
|
||||||
|
return readVarInt.invoke((FriendlyByteBuf) buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Reflection.Method<FriendlyByteBuf, FriendlyByteBuf> writeVarInt = Reflection.getTypedMethod(FriendlyByteBuf.class, FriendlyByteBuf.class, int.class);
|
||||||
|
public static void writeVarInt(ByteBuf buf, int value) {
|
||||||
|
writeVarInt.invoke((FriendlyByteBuf) buf, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static final Reflection.Method<FriendlyByteBuf, CompoundTag> readNbt = Reflection.getTypedMethod(FriendlyByteBuf.class, CompoundTag.class);
|
||||||
|
public static CompoundTag readNbt(ByteBuf buf) {
|
||||||
|
return readNbt.invoke((FriendlyByteBuf) buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Reflection.Method<FriendlyByteBuf, UUID> readUUID = Reflection.getTypedMethod(FriendlyByteBuf.class, UUID.class);
|
||||||
|
public static UUID readUUID(ByteBuf buf) {
|
||||||
|
return readUUID.invoke((FriendlyByteBuf) buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Reflection.Method<FriendlyByteBuf, FriendlyByteBuf> writeUUID = Reflection.getTypedMethod(FriendlyByteBuf.class, FriendlyByteBuf.class, UUID.class);
|
||||||
|
public static void writeUUID(ByteBuf buf, UUID uuid) {
|
||||||
|
writeUUID.invoke((FriendlyByteBuf) buf, uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Class<ItemStack> CraftItemStack = Reflection.getClass("org.bukkit.craftbukkit.inventory.CraftItemStack");
|
||||||
|
private static final Reflection.Method<ItemStack, ItemStack> asCraftMirror = Reflection.getTypedMethod(CraftItemStack, "asCraftMirror", CraftItemStack, net.minecraft.world.item.ItemStack.class);
|
||||||
|
public static ItemStack toBukkit(net.minecraft.world.item.ItemStack stack) {
|
||||||
|
return asCraftMirror.invoke(null, stack);
|
||||||
|
}
|
||||||
|
private static final Reflection.Method<ItemStack, net.minecraft.world.item.ItemStack> asNMSCopy = Reflection.getTypedMethod(CraftItemStack, net.minecraft.world.item.ItemStack.class, ItemStack.class);
|
||||||
|
public static net.minecraft.world.item.ItemStack toMojang(ItemStack stack) {
|
||||||
|
return asNMSCopy.invoke(null, stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Reflection.Method<FriendlyByteBuf, net.minecraft.world.item.ItemStack> readItem = Reflection.getTypedMethod(FriendlyByteBuf.class, net.minecraft.world.item.ItemStack.class);
|
||||||
|
public static ItemStack readItem(ByteBuf buf) {
|
||||||
|
return toBukkit(readItem.invoke((FriendlyByteBuf) buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Reflection.Method<FriendlyByteBuf, FriendlyByteBuf> writeItem = Reflection.getTypedMethod(FriendlyByteBuf.class, FriendlyByteBuf.class, net.minecraft.world.item.ItemStack.class);
|
||||||
|
public static void writeItem(ByteBuf buf, ItemStack stack) {
|
||||||
|
writeItem.invoke((FriendlyByteBuf) buf, toMojang(stack));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] readByteArray(ByteBuf buf) {
|
||||||
|
byte[] array = new byte[readVarInt(buf)];
|
||||||
|
buf.readBytes(array);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeByteArray(ByteBuf buf, byte[] array) {
|
||||||
|
writeVarInt(buf, array.length);
|
||||||
|
buf.writeBytes(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> List<T> readList(ByteBuf buf, Function<ByteBuf, T> reader) {
|
||||||
|
int length = readVarInt(buf);
|
||||||
|
|
||||||
|
List<T> list = new ArrayList<>(length);
|
||||||
|
for(int i = 0; i < length; i++)
|
||||||
|
list.add(reader.apply(buf));
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package com.moulberry.axiom.integration;
|
package com.moulberry.axiom.integration;
|
||||||
|
|
||||||
import com.moulberry.axiom.AxiomPaper;
|
import com.moulberry.axiom.AxiomConstants;
|
||||||
import io.papermc.paper.event.player.PlayerFailMoveEvent;
|
import io.papermc.paper.event.player.PlayerFailMoveEvent;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
@ -9,7 +9,7 @@ public class PaperFailMoveListener implements Listener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onFailMove(PlayerFailMoveEvent event) {
|
public void onFailMove(PlayerFailMoveEvent event) {
|
||||||
if (event.getPlayer().hasPermission(AxiomPaper.PERMISSION) &&
|
if (event.getPlayer().hasPermission(AxiomConstants.PERMISSION) &&
|
||||||
event.getFailReason() == PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY) {
|
event.getFailReason() == PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY) {
|
||||||
event.setAllowed(true);
|
event.setAllowed(true);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.AxiomConstants;
|
||||||
import com.moulberry.axiom.AxiomPaper;
|
import com.moulberry.axiom.AxiomPaper;
|
||||||
|
import com.moulberry.axiom.buffer.MojBuf;
|
||||||
|
import com.moulberry.axiom.Reflection;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandler;
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
@ -8,25 +11,36 @@ import io.netty.channel.ChannelInboundHandlerAdapter;
|
|||||||
import io.papermc.paper.network.ConnectionEvent;
|
import io.papermc.paper.network.ConnectionEvent;
|
||||||
import net.minecraft.network.ConnectionProtocol;
|
import net.minecraft.network.ConnectionProtocol;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
import net.minecraft.network.protocol.PacketFlow;
|
import net.minecraft.network.protocol.PacketFlow;
|
||||||
import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket;
|
import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@ChannelHandler.Sharable
|
@ChannelHandler.Sharable
|
||||||
public class AxiomBigPayloadHandler extends ChannelInboundHandlerAdapter {
|
public class AxiomBigPayloadHandler extends ChannelInboundHandlerAdapter {
|
||||||
|
|
||||||
private static final int PLUGINMESSAGE_PACKETID = ConnectionProtocol.PLAY.getPacketId(PacketFlow.SERVERBOUND, new ServerboundCustomPayloadPacket(null, null));
|
private static final Reflection.Method<ConnectionProtocol, Integer> getPacketId = Reflection.getTypedMethod(ConnectionProtocol.class, int.class, PacketFlow.class, Packet.class);
|
||||||
|
private static final int PLUGINMESSAGE_PACKETID = getPacketId.invoke(ConnectionProtocol.PLAY, PacketFlow.SERVERBOUND, new ServerboundCustomPayloadPacket(null, null));
|
||||||
|
|
||||||
private final Player player;
|
private final Player player;
|
||||||
|
|
||||||
|
private final List<QueuedPacket> packets = new ArrayList<>();
|
||||||
|
private final BukkitTask task;
|
||||||
|
|
||||||
public AxiomBigPayloadHandler(Player player) {
|
public AxiomBigPayloadHandler(Player player) {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
|
this.task = Bukkit.getScheduler().runTaskTimer(AxiomPaper.getPlugin(), this::runHandlers, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelRead(@NotNull ChannelHandlerContext ctx, @NotNull Object msg) throws Exception {
|
public void channelRead(@NotNull ChannelHandlerContext ctx, @NotNull Object msg) {
|
||||||
if(!(msg instanceof ByteBuf in)) {
|
if(!(msg instanceof ByteBuf in)) {
|
||||||
ctx.fireChannelRead(msg);
|
ctx.fireChannelRead(msg);
|
||||||
return;
|
return;
|
||||||
@ -35,15 +49,13 @@ public class AxiomBigPayloadHandler extends ChannelInboundHandlerAdapter {
|
|||||||
int readerIndexBackup = in.readerIndex();
|
int readerIndexBackup = in.readerIndex();
|
||||||
|
|
||||||
if(in.readableBytes() != 0) {
|
if(in.readableBytes() != 0) {
|
||||||
FriendlyByteBuf buf = new FriendlyByteBuf((ByteBuf) msg);
|
ByteBuf buf = new FriendlyByteBuf(in);
|
||||||
|
if (MojBuf.readVarInt(buf) == PLUGINMESSAGE_PACKETID) {
|
||||||
if (buf.readVarInt() == PLUGINMESSAGE_PACKETID) {
|
NamespacedKey id = MojBuf.readKey(buf);
|
||||||
ResourceLocation identifier = buf.readResourceLocation();
|
if (id.getNamespace().equals("axiom") && player.hasPermission(AxiomConstants.PERMISSION)) {
|
||||||
if (identifier.getNamespace().equals("axiom") && player.hasPermission(AxiomPaper.PERMISSION)) {
|
synchronized (packets) {
|
||||||
AxiomPacketListener listener = AxiomPaper.getListener(identifier.getPath());
|
packets.add(new QueuedPacket(id.getKey(), buf));
|
||||||
//TODO sync!
|
}
|
||||||
listener.onMessage(player, in);
|
|
||||||
in.release();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,4 +74,29 @@ public class AxiomBigPayloadHandler extends ChannelInboundHandlerAdapter {
|
|||||||
super.userEventTriggered(ctx, evt);
|
super.userEventTriggered(ctx, evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelInactive(@NotNull ChannelHandlerContext ctx) {
|
||||||
|
if(!task.isCancelled())
|
||||||
|
task.cancel();
|
||||||
|
|
||||||
|
ctx.fireChannelInactive();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runHandlers() {
|
||||||
|
List<QueuedPacket> queue;
|
||||||
|
synchronized (packets) {
|
||||||
|
if(packets.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
queue = new ArrayList<>(packets);
|
||||||
|
packets.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
for(QueuedPacket packet : queue) {
|
||||||
|
AxiomPaper.getListener(packet.name).onMessage(player, packet.in);
|
||||||
|
packet.in.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private record QueuedPacket(String name, ByteBuf in) {}
|
||||||
}
|
}
|
||||||
|
@ -7,4 +7,6 @@ public interface AxiomPacketListener {
|
|||||||
|
|
||||||
void onMessage(Player player, ByteBuf buf);
|
void onMessage(Player player, ByteBuf buf);
|
||||||
|
|
||||||
|
default void onMissingPerm(Player player, ByteBuf buf) {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,60 +1,42 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
import com.moulberry.axiom.AxiomConstants;
|
import com.moulberry.axiom.*;
|
||||||
import com.moulberry.axiom.AxiomPaper;
|
import com.moulberry.axiom.buffer.MojBuf;
|
||||||
import com.moulberry.axiom.OutChannel;
|
|
||||||
import com.moulberry.axiom.View;
|
|
||||||
import com.moulberry.axiom.event.AxiomHandshakeEvent;
|
import com.moulberry.axiom.event.AxiomHandshakeEvent;
|
||||||
import com.moulberry.axiom.persistence.ItemStackDataType;
|
import com.moulberry.axiom.persistence.ItemStackDataType;
|
||||||
import com.moulberry.axiom.persistence.UUIDDataType;
|
import com.moulberry.axiom.persistence.UUIDDataType;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.channel.Channel;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.Connection;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.persistence.PersistentDataContainer;
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
public class HelloPacketListener implements AxiomPacketListener, Listener {
|
public class HelloPacketListener implements AxiomPacketListener, Listener {
|
||||||
|
|
||||||
private final Set<Player> axiomPlayers = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
private static final Reflection.Field<ServerPlayer, ServerGamePacketListenerImpl> serverPlayerConnection = Reflection.getField(ServerPlayer.class, ServerGamePacketListenerImpl.class);
|
||||||
|
private static final Reflection.Field<ServerGamePacketListenerImpl, Connection> packetListenerConnection = Reflection.getField(ServerGamePacketListenerImpl.class, Connection.class);
|
||||||
|
private static final Reflection.Field<Connection, Channel> channel = Reflection.getField(Connection.class, Channel.class);
|
||||||
|
|
||||||
public HelloPacketListener() {
|
private final AxiomPlayerManager axiomPlayers;
|
||||||
//TODO cleanup (side effects of class)
|
|
||||||
Bukkit.getPluginManager().registerEvents(this, AxiomPaper.getPlugin());
|
|
||||||
Bukkit.getScheduler().scheduleSyncRepeatingTask(AxiomPaper.getPlugin(), () -> axiomPlayers.removeIf(player -> {
|
|
||||||
if (!player.hasPermission(AxiomPaper.PERMISSION)) {
|
|
||||||
OutChannel.ENABLE.send(player, new byte[] { 0 });
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
public HelloPacketListener(AxiomPlayerManager axiomPlayers) {
|
||||||
}), 20, 20);
|
this.axiomPlayers = axiomPlayers;
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
|
||||||
axiomPlayers.remove(event.getPlayer());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(Player player, ByteBuf buf) {
|
public void onMessage(Player player, ByteBuf buf) {
|
||||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
|
int apiVersion = MojBuf.readVarInt(buf);
|
||||||
int apiVersion = friendlyByteBuf.readVarInt();
|
MojBuf.readNbt(buf); // Discard
|
||||||
friendlyByteBuf.readNbt(); // Discard
|
|
||||||
|
|
||||||
if (apiVersion != AxiomConstants.API_VERSION) {
|
if (apiVersion != AxiomConstants.API_VERSION) {
|
||||||
player.sendMessage(Component.text("Unsupported Axiom API Version. Server supports " + AxiomConstants.API_VERSION + ", while client is " + apiVersion));
|
player.sendMessage(Component.text("Unsupported Axiom API Version. Server supports " + AxiomConstants.API_VERSION + ", while client is " + apiVersion));
|
||||||
@ -69,18 +51,24 @@ public class HelloPacketListener implements AxiomPacketListener, Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
axiomPlayers.add(player);
|
axiomPlayers.add(player);
|
||||||
//TODO thread safety
|
// Welcome to multiversioning!
|
||||||
((CraftPlayer)player).getHandle().connection.connection.channel.pipeline().addBefore("decoder", "axiom-big-payload-handler", new AxiomBigPayloadHandler(player));
|
channel.get(
|
||||||
|
packetListenerConnection.get(
|
||||||
|
serverPlayerConnection.get(
|
||||||
|
AxiomPaper.convert(player)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).pipeline().addBefore("decoder", "axiom-big-payload-handler", new AxiomBigPayloadHandler(player));
|
||||||
|
|
||||||
// Enable
|
// Enable
|
||||||
FriendlyByteBuf out = new FriendlyByteBuf(Unpooled.buffer());
|
ByteBuf out = MojBuf.unpooled();
|
||||||
out.writeBoolean(true);
|
out.writeBoolean(true);
|
||||||
out.writeByte(0); // todo: world properties
|
out.writeByte(0); // todo: world properties
|
||||||
out.writeInt(handshakeEvent.getMaxBufferSize()); // Max Buffer Size
|
out.writeInt(handshakeEvent.getMaxBufferSize()); // Max Buffer Size
|
||||||
out.writeBoolean(false); // No source info
|
out.writeBoolean(false); // No source info
|
||||||
out.writeBoolean(false); // No source settings
|
out.writeBoolean(false); // No source settings
|
||||||
out.writeVarInt(5); // Maximum Reach
|
MojBuf.writeVarInt(buf, 5); // Maximum Reach
|
||||||
out.writeVarInt(16); // Max editor views
|
MojBuf.writeVarInt(buf, 16); // Max editor views
|
||||||
out.writeBoolean(true); // Editable Views
|
out.writeBoolean(true); // Editable Views
|
||||||
OutChannel.ENABLE.send(player, out);
|
OutChannel.ENABLE.send(player, out);
|
||||||
|
|
||||||
@ -89,15 +77,15 @@ public class HelloPacketListener implements AxiomPacketListener, Listener {
|
|||||||
int activeHotbarIndex = container.getOrDefault(AxiomConstants.ACTIVE_HOTBAR_INDEX, PersistentDataType.BYTE, (byte) 0);
|
int activeHotbarIndex = container.getOrDefault(AxiomConstants.ACTIVE_HOTBAR_INDEX, PersistentDataType.BYTE, (byte) 0);
|
||||||
PersistentDataContainer hotbarItems = container.get(AxiomConstants.HOTBAR_DATA, PersistentDataType.TAG_CONTAINER);
|
PersistentDataContainer hotbarItems = container.get(AxiomConstants.HOTBAR_DATA, PersistentDataType.TAG_CONTAINER);
|
||||||
if (hotbarItems != null) {
|
if (hotbarItems != null) {
|
||||||
out = new FriendlyByteBuf(Unpooled.buffer());
|
out = MojBuf.unpooled();
|
||||||
out.writeByte((byte) activeHotbarIndex);
|
out.writeByte((byte) activeHotbarIndex);
|
||||||
for (int i=0; i<9*9; i++) {
|
for (int i=0; i<9*9; i++) {
|
||||||
// Ignore selected hotbar
|
// Ignore selected hotbar
|
||||||
if (i / 9 == activeHotbarIndex) {
|
if (i / 9 == activeHotbarIndex) {
|
||||||
out.writeItem(net.minecraft.world.item.ItemStack.EMPTY);
|
MojBuf.writeItem(out, new ItemStack(Material.AIR, 0));
|
||||||
} else {
|
} else {
|
||||||
ItemStack stack = hotbarItems.get(new NamespacedKey("axiom", "slot_"+i), ItemStackDataType.INSTANCE);
|
ItemStack stack = hotbarItems.get(AxiomConstants.axiomKey("slot_"+i), ItemStackDataType.INSTANCE);
|
||||||
out.writeItem(CraftItemStack.asNMSCopy(stack));
|
MojBuf.writeItem(out, stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OutChannel.INITIALIZE_HOTBARS.send(player, out);
|
OutChannel.INITIALIZE_HOTBARS.send(player, out);
|
||||||
@ -106,11 +94,11 @@ public class HelloPacketListener implements AxiomPacketListener, Listener {
|
|||||||
// Initialize Views
|
// Initialize Views
|
||||||
UUID activeView = container.get(AxiomConstants.ACTIVE_VIEW, UUIDDataType.INSTANCE);
|
UUID activeView = container.get(AxiomConstants.ACTIVE_VIEW, UUIDDataType.INSTANCE);
|
||||||
if (activeView != null) {
|
if (activeView != null) {
|
||||||
out = new FriendlyByteBuf(Unpooled.buffer());
|
out = MojBuf.unpooled();
|
||||||
out.writeUUID(activeView);
|
MojBuf.writeUUID(buf, activeView);
|
||||||
|
|
||||||
PersistentDataContainer[] views = container.get(AxiomConstants.VIEWS, PersistentDataType.TAG_CONTAINER_ARRAY);
|
PersistentDataContainer[] views = container.get(AxiomConstants.VIEWS, PersistentDataType.TAG_CONTAINER_ARRAY);
|
||||||
out.writeVarInt(views.length);
|
MojBuf.writeVarInt(out, views.length);
|
||||||
for (PersistentDataContainer view : views) {
|
for (PersistentDataContainer view : views) {
|
||||||
View.load(view).write(out);
|
View.load(view).write(out);
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,19 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
import com.moulberry.axiom.OutChannel;
|
import com.moulberry.axiom.OutChannel;
|
||||||
|
import com.moulberry.axiom.Reflection;
|
||||||
import com.moulberry.axiom.buffer.CompressedBlockEntity;
|
import com.moulberry.axiom.buffer.CompressedBlockEntity;
|
||||||
|
import com.moulberry.axiom.buffer.MojBuf;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.registries.Registries;
|
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@ -24,50 +21,43 @@ import java.io.ByteArrayOutputStream;
|
|||||||
|
|
||||||
public class RequestBlockEntityPacketListener implements AxiomPacketListener {
|
public class RequestBlockEntityPacketListener implements AxiomPacketListener {
|
||||||
|
|
||||||
|
private static final Class<World> CraftWorld = Reflection.getClass("org.bukkit.craftbukkit.CraftWorld");
|
||||||
|
private static final Reflection.Method<World, ServerLevel> getHandle = Reflection.getTypedMethod(CraftWorld, ServerLevel.class);
|
||||||
|
|
||||||
|
private static final Reflection.Method<BlockPos, BlockPos> of = Reflection.getTypedMethod(BlockPos.class, BlockPos.class, long.class);
|
||||||
|
private static final Reflection.Method<ServerLevel, BlockEntity> getBlockEntity = Reflection.getTypedMethod(ServerLevel.class, BlockEntity.class, BlockPos.class);
|
||||||
|
|
||||||
|
private static final Reflection.Method<BlockEntity, CompoundTag> saveWithoutMetadata = Reflection.getTypedMethod(BlockEntity.class, CompoundTag.class, 2);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(@NotNull Player bukkitPlayer, @NotNull ByteBuf buf) {
|
public void onMessage(@NotNull Player bukkitPlayer, @NotNull ByteBuf buf) {
|
||||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
|
long id = buf.readLong();
|
||||||
long id = friendlyByteBuf.readLong();
|
|
||||||
|
|
||||||
if (!bukkitPlayer.hasPermission("axiom.*")) {
|
World world = Bukkit.getWorld(MojBuf.readKey(buf));
|
||||||
// We always send an 'empty' response in order to make the client happy
|
if (world == null) {
|
||||||
sendEmptyResponse(bukkitPlayer, id); //TODO
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ServerPlayer player = ((CraftPlayer)bukkitPlayer).getHandle();
|
|
||||||
MinecraftServer server = player.getServer();
|
|
||||||
if (server == null) {
|
|
||||||
sendEmptyResponse(bukkitPlayer, id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceKey<Level> worldKey = friendlyByteBuf.readResourceKey(Registries.DIMENSION);
|
|
||||||
ServerLevel level = server.getLevel(worldKey);
|
|
||||||
if (level == null) {
|
|
||||||
sendEmptyResponse(bukkitPlayer, id);
|
sendEmptyResponse(bukkitPlayer, id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ServerLevel level = getHandle.invoke(world);
|
||||||
Long2ObjectMap<CompressedBlockEntity> map = new Long2ObjectOpenHashMap<>();
|
Long2ObjectMap<CompressedBlockEntity> map = new Long2ObjectOpenHashMap<>();
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
|
||||||
|
|
||||||
// Save and compress block entities
|
// Save and compress block entities
|
||||||
int count = friendlyByteBuf.readVarInt();
|
int count = MojBuf.readVarInt(buf);
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
long pos = friendlyByteBuf.readLong();
|
long pos = buf.readLong();
|
||||||
BlockEntity blockEntity = level.getBlockEntity(mutableBlockPos.set(pos));
|
BlockEntity blockEntity = getBlockEntity.invoke(level, of.invoke(null, pos));
|
||||||
if (blockEntity != null) {
|
if (blockEntity != null) {
|
||||||
CompoundTag tag = blockEntity.saveWithoutMetadata();
|
CompoundTag tag = saveWithoutMetadata.invoke(blockEntity);
|
||||||
map.put(pos, CompressedBlockEntity.compress(tag, baos));
|
map.put(pos, CompressedBlockEntity.compress(tag, baos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send response packet
|
// Send response packet
|
||||||
FriendlyByteBuf out = new FriendlyByteBuf(Unpooled.buffer(16));
|
ByteBuf out = MojBuf.unpooled();
|
||||||
out.writeLong(id);
|
out.writeLong(id);
|
||||||
out.writeVarInt(map.size());
|
MojBuf.writeVarInt(buf, map.size());
|
||||||
for (Long2ObjectMap.Entry<CompressedBlockEntity> entry : map.long2ObjectEntrySet()) {
|
for (Long2ObjectMap.Entry<CompressedBlockEntity> entry : map.long2ObjectEntrySet()) {
|
||||||
out.writeLong(entry.getLongKey());
|
out.writeLong(entry.getLongKey());
|
||||||
entry.getValue().write(out);
|
entry.getValue().write(out);
|
||||||
@ -75,6 +65,11 @@ public class RequestBlockEntityPacketListener implements AxiomPacketListener {
|
|||||||
OutChannel.BLOCK_ENTITIES.send(bukkitPlayer, out);
|
OutChannel.BLOCK_ENTITIES.send(bukkitPlayer, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMissingPerm(Player player, ByteBuf buf) {
|
||||||
|
sendEmptyResponse(player, buf.readLong());
|
||||||
|
}
|
||||||
|
|
||||||
private void sendEmptyResponse(Player player, long id) {
|
private void sendEmptyResponse(Player player, long id) {
|
||||||
ByteBuf buf = Unpooled.buffer(16);
|
ByteBuf buf = Unpooled.buffer(16);
|
||||||
buf.writeLong(id);
|
buf.writeLong(id);
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.Reflection;
|
||||||
import com.moulberry.axiom.buffer.BiomeBuffer;
|
import com.moulberry.axiom.buffer.BiomeBuffer;
|
||||||
import com.moulberry.axiom.buffer.BlockBuffer;
|
import com.moulberry.axiom.buffer.BlockBuffer;
|
||||||
import com.moulberry.axiom.buffer.CompressedBlockEntity;
|
import com.moulberry.axiom.buffer.CompressedBlockEntity;
|
||||||
|
import com.moulberry.axiom.buffer.MojBuf;
|
||||||
import com.moulberry.axiom.event.AxiomModifyWorldEvent;
|
import com.moulberry.axiom.event.AxiomModifyWorldEvent;
|
||||||
import com.moulberry.axiom.integration.RegionProtection;
|
import com.moulberry.axiom.integration.RegionProtection;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
@ -13,7 +15,6 @@ import net.minecraft.core.Holder;
|
|||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraft.network.protocol.game.ClientboundChunksBiomesPacket;
|
import net.minecraft.network.protocol.game.ClientboundChunksBiomesPacket;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
@ -35,49 +36,31 @@ import net.minecraft.world.level.lighting.LightEngine;
|
|||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
|
import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import xyz.jpenilla.reflectionremapper.ReflectionRemapper;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class SetBlockBufferPacketListener implements AxiomPacketListener {
|
public class SetBlockBufferPacketListener implements AxiomPacketListener {
|
||||||
|
|
||||||
private final Method updateBlockEntityTicker;
|
private static final Reflection.Method<LevelChunk, Object> updateBlockEntityTicker = Reflection.getMethod(LevelChunk.class, BlockEntity.class);
|
||||||
|
|
||||||
public SetBlockBufferPacketListener() {
|
|
||||||
ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar();
|
|
||||||
String methodName = reflectionRemapper.remapMethodName(LevelChunk.class, "updateBlockEntityTicker", BlockEntity.class);
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.updateBlockEntityTicker = LevelChunk.class.getDeclaredMethod(methodName, BlockEntity.class);
|
|
||||||
this.updateBlockEntityTicker.setAccessible(true);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(Player player, ByteBuf buf) {
|
public void onMessage(Player player, ByteBuf buf) {
|
||||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
|
|
||||||
MinecraftServer server = ((CraftServer)player.getServer()).getServer();
|
MinecraftServer server = ((CraftServer)player.getServer()).getServer();
|
||||||
if (server == null) return;
|
if (server == null) return;
|
||||||
|
|
||||||
ResourceKey<Level> worldKey = friendlyByteBuf.readResourceKey(Registries.DIMENSION);
|
ResourceKey<Level> worldKey = buf.readResourceKey(Registries.DIMENSION);
|
||||||
friendlyByteBuf.readUUID(); // Discard, we don't need to associate buffers
|
MojBuf.readUUID(buf); // Discard, we don't need to associate buffers
|
||||||
boolean continuation = friendlyByteBuf.readBoolean();
|
|
||||||
|
|
||||||
if (!continuation) {
|
if (!buf.readBoolean()) {
|
||||||
friendlyByteBuf.readNbt(); // Discard sourceInfo
|
MojBuf.readNbt(buf); // Discard sourceInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
byte type = friendlyByteBuf.readByte();
|
byte type = buf.readByte();
|
||||||
if (type == 0) {
|
if (type == 0) {
|
||||||
BlockBuffer buffer = BlockBuffer.load(friendlyByteBuf);
|
BlockBuffer buffer = BlockBuffer.load(buf);
|
||||||
applyBlockBuffer(player, server, buffer, worldKey);
|
applyBlockBuffer(player, server, buffer, worldKey);
|
||||||
} else if (type == 1) {
|
} else if (type == 1) {
|
||||||
BiomeBuffer buffer = BiomeBuffer.load(friendlyByteBuf);
|
BiomeBuffer buffer = BiomeBuffer.load(buf);
|
||||||
applyBiomeBuffer(server, buffer, worldKey);
|
applyBiomeBuffer(server, buffer, worldKey);
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Unknown buffer type: " + type);
|
throw new RuntimeException("Unknown buffer type: " + type);
|
||||||
@ -186,11 +169,7 @@ public class SetBlockBufferPacketListener implements AxiomPacketListener {
|
|||||||
// Block entity is here and the type is correct
|
// Block entity is here and the type is correct
|
||||||
blockEntity.setBlockState(blockState);
|
blockEntity.setBlockState(blockState);
|
||||||
|
|
||||||
try {
|
updateBlockEntityTicker.invoke(chunk, blockEntity);
|
||||||
this.updateBlockEntityTicker.invoke(chunk, blockEntity);
|
|
||||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Block entity type isn't correct, we need to recreate it
|
// Block entity type isn't correct, we need to recreate it
|
||||||
chunk.removeBlockEntity(blockPos);
|
chunk.removeBlockEntity(blockPos);
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.Reflection;
|
||||||
import com.moulberry.axiom.event.AxiomModifyWorldEvent;
|
import com.moulberry.axiom.event.AxiomModifyWorldEvent;
|
||||||
import com.moulberry.axiom.integration.VersionTranslator;
|
import com.moulberry.axiom.integration.VersionTranslator;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
@ -20,28 +20,12 @@ import org.bukkit.Bukkit;
|
|||||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import xyz.jpenilla.reflectionremapper.ReflectionRemapper;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class SetBlockPacketListener implements AxiomPacketListener {
|
public class SetBlockPacketListener implements AxiomPacketListener {
|
||||||
|
|
||||||
private final Method updateBlockEntityTicker;
|
private static final Reflection.Method<LevelChunk, Object> updateBlockEntityTicker = Reflection.getMethod(LevelChunk.class, BlockEntity.class);
|
||||||
|
|
||||||
public SetBlockPacketListener() {
|
|
||||||
ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar();
|
|
||||||
String methodName = reflectionRemapper.remapMethodName(LevelChunk.class, "updateBlockEntityTicker", BlockEntity.class);
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.updateBlockEntityTicker = LevelChunk.class.getDeclaredMethod(methodName, BlockEntity.class);
|
|
||||||
this.updateBlockEntityTicker.setAccessible(true);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(@NotNull Player bukkitPlayer, @NotNull ByteBuf buf) {
|
public void onMessage(@NotNull Player bukkitPlayer, @NotNull ByteBuf buf) {
|
||||||
@ -51,11 +35,10 @@ public class SetBlockPacketListener implements AxiomPacketListener {
|
|||||||
if (modifyWorldEvent.isCancelled()) return;
|
if (modifyWorldEvent.isCancelled()) return;
|
||||||
|
|
||||||
// Read packet
|
// Read packet
|
||||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
|
BlockPos blockPos = buf.readBlockPos();
|
||||||
BlockPos blockPos = friendlyByteBuf.readBlockPos();
|
BlockState blockState = Block.BLOCK_STATE_REGISTRY.byId(VersionTranslator.impl.blockStateMapper(bukkitPlayer).apply(buf.readVarInt()));
|
||||||
BlockState blockState = Block.BLOCK_STATE_REGISTRY.byId(VersionTranslator.impl.blockStateMapper(bukkitPlayer).apply(friendlyByteBuf.readVarInt()));
|
boolean updateNeighbors = buf.readBoolean();
|
||||||
boolean updateNeighbors = friendlyByteBuf.readBoolean();
|
int sequenceId = buf.readInt();
|
||||||
int sequenceId = friendlyByteBuf.readInt();
|
|
||||||
|
|
||||||
ServerPlayer player = ((CraftPlayer)bukkitPlayer).getHandle();
|
ServerPlayer player = ((CraftPlayer)bukkitPlayer).getHandle();
|
||||||
|
|
||||||
@ -116,11 +99,7 @@ public class SetBlockPacketListener implements AxiomPacketListener {
|
|||||||
// Just update the state and ticker and move on
|
// Just update the state and ticker and move on
|
||||||
blockEntity.setBlockState(blockState);
|
blockEntity.setBlockState(blockState);
|
||||||
|
|
||||||
try {
|
updateBlockEntityTicker.invoke(chunk, blockEntity);
|
||||||
this.updateBlockEntityTicker.invoke(chunk, blockEntity);
|
|
||||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Block entity type isn't correct, we need to recreate it
|
// Block entity type isn't correct, we need to recreate it
|
||||||
chunk.removeBlockEntity(blockPos);
|
chunk.removeBlockEntity(blockPos);
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
import com.moulberry.axiom.AxiomConstants;
|
import com.moulberry.axiom.AxiomConstants;
|
||||||
|
import com.moulberry.axiom.buffer.MojBuf;
|
||||||
import com.moulberry.axiom.View;
|
import com.moulberry.axiom.View;
|
||||||
import com.moulberry.axiom.persistence.UUIDDataType;
|
import com.moulberry.axiom.persistence.UUIDDataType;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.persistence.PersistentDataContainer;
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
@ -17,9 +17,8 @@ public class SetEditorViewsPacketListener implements AxiomPacketListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(@NotNull Player player, @NotNull ByteBuf buf) {
|
public void onMessage(@NotNull Player player, @NotNull ByteBuf buf) {
|
||||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
|
UUID uuid = MojBuf.readUUID(buf);
|
||||||
UUID uuid = friendlyByteBuf.readUUID();
|
List<View> views = MojBuf.readList(buf, View::read);
|
||||||
List<View> views = friendlyByteBuf.readList(View::read);
|
|
||||||
|
|
||||||
PersistentDataContainer container = player.getPersistentDataContainer();
|
PersistentDataContainer container = player.getPersistentDataContainer();
|
||||||
container.set(AxiomConstants.ACTIVE_VIEW, UUIDDataType.INSTANCE, uuid);
|
container.set(AxiomConstants.ACTIVE_VIEW, UUIDDataType.INSTANCE, uuid);
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.AxiomPaper;
|
||||||
|
import com.moulberry.axiom.Reflection;
|
||||||
import com.moulberry.axiom.event.AxiomFlySpeedChangeEvent;
|
import com.moulberry.axiom.event.AxiomFlySpeedChangeEvent;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.player.Abilities;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class SetFlySpeedPacketListener implements AxiomPacketListener {
|
public class SetFlySpeedPacketListener implements AxiomPacketListener {
|
||||||
|
|
||||||
|
private static final Reflection.Method<ServerPlayer, Abilities> getAbilities = Reflection.getTypedMethod(ServerPlayer.class, Abilities.class);
|
||||||
|
private static final Reflection.Field<Abilities, Float> flyingSpeed = Reflection.getField(Abilities.class, float.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(@NotNull Player player, @NotNull ByteBuf buf) {
|
public void onMessage(@NotNull Player player, @NotNull ByteBuf buf) {
|
||||||
float flySpeed = buf.readFloat();
|
float flySpeed = buf.readFloat();
|
||||||
@ -19,7 +25,7 @@ public class SetFlySpeedPacketListener implements AxiomPacketListener {
|
|||||||
if (flySpeedChangeEvent.isCancelled()) return;
|
if (flySpeedChangeEvent.isCancelled()) return;
|
||||||
|
|
||||||
// Change flying speed
|
// Change flying speed
|
||||||
((CraftPlayer)player).getHandle().getAbilities().setFlyingSpeed(flySpeed);
|
flyingSpeed.set(getAbilities.invoke(AxiomPaper.convert(player)), flySpeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
import com.moulberry.axiom.AxiomConstants;
|
import com.moulberry.axiom.AxiomConstants;
|
||||||
|
import com.moulberry.axiom.buffer.MojBuf;
|
||||||
import com.moulberry.axiom.persistence.ItemStackDataType;
|
import com.moulberry.axiom.persistence.ItemStackDataType;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import org.bukkit.NamespacedKey;
|
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.persistence.PersistentDataContainer;
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -15,15 +14,14 @@ public class SetHotbarSlotPacketListener implements AxiomPacketListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(@NotNull Player player, @NotNull ByteBuf buf) {
|
public void onMessage(@NotNull Player player, @NotNull ByteBuf buf) {
|
||||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
|
int index = buf.readByte();
|
||||||
int index = friendlyByteBuf.readByte();
|
|
||||||
if (index < 0 || index >= 9*9) return;
|
if (index < 0 || index >= 9*9) return;
|
||||||
net.minecraft.world.item.ItemStack nmsStack = friendlyByteBuf.readItem();
|
ItemStack stack = MojBuf.readItem(buf);
|
||||||
|
|
||||||
PersistentDataContainer container = player.getPersistentDataContainer();
|
PersistentDataContainer container = player.getPersistentDataContainer();
|
||||||
PersistentDataContainer hotbarItems = container.get(AxiomConstants.HOTBAR_DATA, PersistentDataType.TAG_CONTAINER);
|
PersistentDataContainer hotbarItems = container.get(AxiomConstants.HOTBAR_DATA, PersistentDataType.TAG_CONTAINER);
|
||||||
if (hotbarItems == null) hotbarItems = container.getAdapterContext().newPersistentDataContainer();
|
if (hotbarItems == null) hotbarItems = container.getAdapterContext().newPersistentDataContainer();
|
||||||
hotbarItems.set(new NamespacedKey("axiom", "slot_"+index), ItemStackDataType.INSTANCE, CraftItemStack.asCraftMirror(nmsStack));
|
hotbarItems.set(AxiomConstants.axiomKey("slot_"+index), ItemStackDataType.INSTANCE, stack);
|
||||||
container.set(AxiomConstants.HOTBAR_DATA, PersistentDataType.TAG_CONTAINER, hotbarItems);
|
container.set(AxiomConstants.HOTBAR_DATA, PersistentDataType.TAG_CONTAINER, hotbarItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
import com.moulberry.axiom.AxiomConstants;
|
import com.moulberry.axiom.AxiomConstants;
|
||||||
|
import com.moulberry.axiom.buffer.MojBuf;
|
||||||
import com.moulberry.axiom.persistence.ItemStackDataType;
|
import com.moulberry.axiom.persistence.ItemStackDataType;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.NamespacedKey;
|
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.persistence.PersistentDataContainer;
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
@ -18,13 +16,12 @@ public class SwitchActiveHotbarPacketListener implements AxiomPacketListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(@NotNull Player player, @NotNull ByteBuf buf) {
|
public void onMessage(@NotNull Player player, @NotNull ByteBuf buf) {
|
||||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
|
int oldHotbarIndex = buf.readByte();
|
||||||
int oldHotbarIndex = friendlyByteBuf.readByte();
|
int activeHotbarIndex = buf.readByte();
|
||||||
int activeHotbarIndex = friendlyByteBuf.readByte();
|
|
||||||
|
|
||||||
ItemStack[] hotbarItems = new ItemStack[9];
|
ItemStack[] hotbarItems = new ItemStack[9];
|
||||||
for (int i=0; i<9; i++) {
|
for (int i=0; i<9; i++) {
|
||||||
hotbarItems[i] = CraftItemStack.asCraftMirror(friendlyByteBuf.readItem());
|
hotbarItems[i] = MojBuf.readItem(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
PersistentDataContainer container = player.getPersistentDataContainer();
|
PersistentDataContainer container = player.getPersistentDataContainer();
|
||||||
@ -40,10 +37,10 @@ public class SwitchActiveHotbarPacketListener implements AxiomPacketListener {
|
|||||||
} else {
|
} else {
|
||||||
stack = stack.clone();
|
stack = stack.clone();
|
||||||
}
|
}
|
||||||
containerHotbarItems.set(new NamespacedKey("axiom", "slot_"+index), ItemStackDataType.INSTANCE, stack);
|
containerHotbarItems.set(AxiomConstants.axiomKey("slot_"+index), ItemStackDataType.INSTANCE, stack);
|
||||||
}
|
}
|
||||||
int index = activeHotbarIndex*9 + i;
|
int index = activeHotbarIndex*9 + i;
|
||||||
containerHotbarItems.set(new NamespacedKey("axiom", "slot_"+index), ItemStackDataType.INSTANCE, hotbarItems[i].clone());
|
containerHotbarItems.set(AxiomConstants.axiomKey("slot_"+index), ItemStackDataType.INSTANCE, hotbarItems[i].clone());
|
||||||
if (player.getGameMode() == GameMode.CREATIVE) player.getInventory().setItem(i, hotbarItems[i]);
|
if (player.getGameMode() == GameMode.CREATIVE) player.getInventory().setItem(i, hotbarItems[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.buffer.MojBuf;
|
||||||
import com.moulberry.axiom.event.AxiomTeleportEvent;
|
import com.moulberry.axiom.event.AxiomTeleportEvent;
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import net.minecraft.core.registries.Registries;
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.NamespacedKey;
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -16,17 +12,14 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
public class TeleportPacketListener implements AxiomPacketListener {
|
public class TeleportPacketListener implements AxiomPacketListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(@NotNull Player player, @NotNull ByteBuf buf) {
|
public void onMessage(@NotNull Player player, @NotNull FriendlyByteBuf buf) {
|
||||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
|
World world = Bukkit.getWorld(MojBuf.readKey(buf));
|
||||||
ResourceKey<Level> resourceKey = friendlyByteBuf.readResourceKey(Registries.DIMENSION);
|
double x = buf.readDouble();
|
||||||
double x = friendlyByteBuf.readDouble();
|
double y = buf.readDouble();
|
||||||
double y = friendlyByteBuf.readDouble();
|
double z = buf.readDouble();
|
||||||
double z = friendlyByteBuf.readDouble();
|
float yRot = buf.readFloat();
|
||||||
float yRot = friendlyByteBuf.readFloat();
|
float xRot = buf.readFloat();
|
||||||
float xRot = friendlyByteBuf.readFloat();
|
|
||||||
|
|
||||||
NamespacedKey namespacedKey = new NamespacedKey(resourceKey.location().getNamespace(), resourceKey.location().getPath());
|
|
||||||
World world = Bukkit.getWorld(namespacedKey);
|
|
||||||
if (world == null) return;
|
if (world == null) return;
|
||||||
|
|
||||||
// Call event
|
// Call event
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package com.moulberry.axiom.persistence;
|
package com.moulberry.axiom.persistence;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.Reflection;
|
||||||
|
import com.moulberry.axiom.buffer.MojBuf;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.persistence.CraftPersistentDataContainer;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.persistence.PersistentDataAdapterContext;
|
import org.bukkit.persistence.PersistentDataAdapterContext;
|
||||||
import org.bukkit.persistence.PersistentDataContainer;
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
@ -10,9 +10,9 @@ import org.bukkit.persistence.PersistentDataType;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class ItemStackDataType implements PersistentDataType<PersistentDataContainer, ItemStack> {
|
public class ItemStackDataType implements PersistentDataType<PersistentDataContainer, ItemStack> {
|
||||||
public static ItemStackDataType INSTANCE = new ItemStackDataType();
|
private ItemStackDataType() {}
|
||||||
private ItemStackDataType() {
|
|
||||||
}
|
public static final ItemStackDataType INSTANCE = new ItemStackDataType();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Class<PersistentDataContainer> getPrimitiveType() {
|
public @NotNull Class<PersistentDataContainer> getPrimitiveType() {
|
||||||
@ -24,23 +24,23 @@ public class ItemStackDataType implements PersistentDataType<PersistentDataConta
|
|||||||
return ItemStack.class;
|
return ItemStack.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Class<PersistentDataContainer> CraftPersistentDataContainer = Reflection.getClass("org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer");
|
||||||
|
private static final Reflection.Method<PersistentDataContainer, Object> putAll = Reflection.getMethod(CraftPersistentDataContainer, "putAll", CompoundTag.class);
|
||||||
|
private static final Reflection.Method<PersistentDataContainer, CompoundTag> toTagCompound = Reflection.getTypedMethod(CraftPersistentDataContainer, "toTagCompound", CompoundTag.class);
|
||||||
|
|
||||||
|
private static final Reflection.Method<net.minecraft.world.item.ItemStack, CompoundTag> save = Reflection.getTypedMethod(net.minecraft.world.item.ItemStack.class, CompoundTag.class, CompoundTag.class);
|
||||||
@Override
|
@Override
|
||||||
public @NotNull PersistentDataContainer toPrimitive(@NotNull ItemStack complex, @NotNull PersistentDataAdapterContext context) {
|
public @NotNull PersistentDataContainer toPrimitive(@NotNull ItemStack stack, @NotNull PersistentDataAdapterContext context) {
|
||||||
net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(complex);
|
CompoundTag tag = save.invoke(MojBuf.toMojang(stack), new CompoundTag());
|
||||||
if (nmsStack == null) nmsStack = net.minecraft.world.item.ItemStack.EMPTY;
|
|
||||||
CompoundTag tag = new CompoundTag();
|
|
||||||
nmsStack.save(tag);
|
|
||||||
|
|
||||||
PersistentDataContainer container = context.newPersistentDataContainer();
|
PersistentDataContainer container = context.newPersistentDataContainer();
|
||||||
((CraftPersistentDataContainer)container).putAll(tag);
|
putAll.invoke(container, tag);
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Reflection.Method<net.minecraft.world.item.ItemStack, net.minecraft.world.item.ItemStack> of = Reflection.getTypedMethod(net.minecraft.world.item.ItemStack.class, net.minecraft.world.item.ItemStack.class, CompoundTag.class);
|
||||||
@Override
|
@Override
|
||||||
public @NotNull ItemStack fromPrimitive(@NotNull PersistentDataContainer primitive, @NotNull PersistentDataAdapterContext context) {
|
public @NotNull ItemStack fromPrimitive(@NotNull PersistentDataContainer primitive, @NotNull PersistentDataAdapterContext context) {
|
||||||
CompoundTag tag = ((CraftPersistentDataContainer)primitive).toTagCompound();
|
return MojBuf.toBukkit(of.invoke(null, toTagCompound.invoke(primitive)));
|
||||||
net.minecraft.world.item.ItemStack nmsStack = net.minecraft.world.item.ItemStack.of(tag);
|
|
||||||
|
|
||||||
return CraftItemStack.asCraftMirror(nmsStack);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,9 @@ import java.nio.ByteBuffer;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class UUIDDataType implements PersistentDataType<byte[], UUID> {
|
public class UUIDDataType implements PersistentDataType<byte[], UUID> {
|
||||||
public static UUIDDataType INSTANCE = new UUIDDataType();
|
private UUIDDataType() {}
|
||||||
private UUIDDataType() {
|
|
||||||
}
|
public static final UUIDDataType INSTANCE = new UUIDDataType();
|
||||||
|
|
||||||
public Class<byte[]> getPrimitiveType() {
|
public Class<byte[]> getPrimitiveType() {
|
||||||
return byte[].class;
|
return byte[].class;
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren