geforkt von Mirrors/AxiomPaperPlugin
Update #1
@ -7,8 +7,8 @@ plugins {
|
||||
id("com.github.johnrengelman.shadow") version "8.1.1"
|
||||
}
|
||||
|
||||
group = "com.moulberry.com.moulberry.axiom"
|
||||
version = "1.0.0-SNAPSHOT"
|
||||
group = "com.moulberry.axiom"
|
||||
version = "1.2.1"
|
||||
description = "Serverside component for Axiom on Paper"
|
||||
|
||||
java {
|
||||
@ -17,13 +17,27 @@ java {
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||
maven("https://jitpack.io")
|
||||
maven("https://maven.enginehub.org/repo/")
|
||||
maven("https://repo.papermc.io/repository/maven-public/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
paperweight.paperDevBundle("1.20.1-R0.1-SNAPSHOT")
|
||||
implementation("xyz.jpenilla:reflection-remapper:0.1.0-SNAPSHOT")
|
||||
|
||||
// Zstd Compression Library
|
||||
implementation("com.github.luben:zstd-jni:1.5.5-4")
|
||||
|
||||
// WorldGuard support
|
||||
compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.1.0-SNAPSHOT")
|
||||
|
||||
// PlotSquared support
|
||||
implementation(platform("com.intellectualsites.bom:bom-newest:1.37"))
|
||||
compileOnly("com.intellectualsites.plotsquared:plotsquared-core")
|
||||
compileOnly("com.intellectualsites.plotsquared:plotsquared-bukkit") { isTransitive = false }
|
||||
}
|
||||
|
||||
tasks {
|
||||
|
22
src/main/java/com/moulberry/axiom/AxiomConstants.java
Normale Datei
22
src/main/java/com/moulberry/axiom/AxiomConstants.java
Normale Datei
@ -0,0 +1,22 @@
|
||||
package com.moulberry.axiom;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import org.bukkit.NamespacedKey;
|
||||
|
||||
public class AxiomConstants {
|
||||
|
||||
public static final long MIN_POSITION_LONG = BlockPos.asLong(-33554432, -2048, -33554432);
|
||||
static {
|
||||
if (MIN_POSITION_LONG != 0b1000000000000000000000000010000000000000000000000000100000000000L) {
|
||||
throw new Error("BlockPos representation changed!");
|
||||
}
|
||||
}
|
||||
|
||||
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 NamespacedKey VIEWS = new NamespacedKey("axiom", "views");
|
||||
|
||||
}
|
@ -1,245 +1,55 @@
|
||||
package com.moulberry.axiom;
|
||||
|
||||
import com.moulberry.axiom.packet.AxiomBigPayloadHandler;
|
||||
import com.moulberry.axiom.packet.SetBlockBufferPacketListener;
|
||||
import com.moulberry.axiom.packet.SetBlockPacketListener;
|
||||
import com.moulberry.axiom.persistence.ItemStackDataType;
|
||||
import com.moulberry.axiom.persistence.UUIDDataType;
|
||||
import com.moulberry.axiom.buffer.CompressedBlockEntity;
|
||||
import com.moulberry.axiom.packet.*;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.papermc.paper.event.player.PlayerFailMoveEvent;
|
||||
import io.papermc.paper.network.ChannelInitializeListener;
|
||||
import io.papermc.paper.network.ChannelInitializeListenerHolder;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.network.ConnectionProtocol;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.PacketFlow;
|
||||
import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.GameType;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.bukkit.*;
|
||||
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.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.plugin.messaging.Messenger;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class AxiomPaper extends JavaPlugin implements Listener {
|
||||
|
||||
public static final long MIN_POSITION_LONG = BlockPos.asLong(-33554432, -2048, -33554432);
|
||||
static {
|
||||
if (MIN_POSITION_LONG != 0b1000000000000000000000000010000000000000000000000000100000000000L) {
|
||||
throw new Error("BlockPos representation changed!");
|
||||
}
|
||||
}
|
||||
|
||||
private static final int API_VERSION = 4;
|
||||
private static final NamespacedKey ACTIVE_HOTBAR_INDEX = new NamespacedKey("axiom", "active_hotbar_index");
|
||||
private static final NamespacedKey HOTBAR_DATA = new NamespacedKey("axiom", "hotbar_data");
|
||||
|
||||
private static final NamespacedKey ACTIVE_VIEW = new NamespacedKey("axiom", "active_view");
|
||||
private static final NamespacedKey VIEWS = new NamespacedKey("axiom", "views");
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
Bukkit.getPluginManager().registerEvents(this, this);
|
||||
CompressedBlockEntity.initialize(this);
|
||||
|
||||
Bukkit.getMessenger().registerOutgoingPluginChannel(this, "axiom:enable");
|
||||
Bukkit.getMessenger().registerOutgoingPluginChannel(this, "axiom:initialize_hotbars");
|
||||
Bukkit.getMessenger().registerOutgoingPluginChannel(this, "axiom:set_editor_views");
|
||||
Messenger msg = Bukkit.getMessenger();
|
||||
|
||||
HashSet<UUID> activeAxiomPlayers = new HashSet<>();
|
||||
msg.registerOutgoingPluginChannel(this, "axiom:enable");
|
||||
msg.registerOutgoingPluginChannel(this, "axiom:initialize_hotbars");
|
||||
msg.registerOutgoingPluginChannel(this, "axiom:set_editor_views");
|
||||
msg.registerOutgoingPluginChannel(this, "axiom:block_entities");
|
||||
|
||||
Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:hello", (channel, player, message) -> {
|
||||
if (!player.hasPermission("axiom.*")) {
|
||||
return;
|
||||
}
|
||||
final Set<UUID> activeAxiomPlayers = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
int apiVersion = friendlyByteBuf.readVarInt();
|
||||
friendlyByteBuf.readNbt(); // Discard
|
||||
|
||||
if (apiVersion != API_VERSION) {
|
||||
player.kick(Component.text("Unsupported Axiom API Version. Server supports " + API_VERSION +
|
||||
", while client is " + apiVersion));
|
||||
return;
|
||||
}
|
||||
|
||||
activeAxiomPlayers.add(player.getUniqueId());
|
||||
|
||||
// Enable
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
buf.writeBoolean(true);
|
||||
buf.writeByte(0); // todo: world properties
|
||||
buf.writeInt(0x100000); // Max Buffer Size
|
||||
buf.writeBoolean(false); // No source info
|
||||
buf.writeBoolean(false); // No source settings
|
||||
buf.writeVarInt(5); // Maximum Reach
|
||||
buf.writeVarInt(16); // Max editor views
|
||||
buf.writeBoolean(true); // Editable Views
|
||||
player.sendPluginMessage(this, "axiom:enable", buf.accessByteBufWithCorrectSize());
|
||||
|
||||
// Initialize Hotbars
|
||||
PersistentDataContainer container = player.getPersistentDataContainer();
|
||||
int activeHotbarIndex = container.getOrDefault(ACTIVE_HOTBAR_INDEX, PersistentDataType.BYTE, (byte) 0);
|
||||
PersistentDataContainer hotbarItems = container.get(HOTBAR_DATA, PersistentDataType.TAG_CONTAINER);
|
||||
if (hotbarItems != null) {
|
||||
buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
buf.writeByte((byte) activeHotbarIndex);
|
||||
for (int i=0; i<9*9; i++) {
|
||||
// Ignore selected hotbar
|
||||
if (i / 9 == activeHotbarIndex) {
|
||||
buf.writeItem(net.minecraft.world.item.ItemStack.EMPTY);
|
||||
} else {
|
||||
ItemStack stack = hotbarItems.get(new NamespacedKey("axiom", "slot_"+i), ItemStackDataType.INSTANCE);
|
||||
buf.writeItem(CraftItemStack.asNMSCopy(stack));
|
||||
}
|
||||
}
|
||||
player.sendPluginMessage(this, "axiom:initialize_hotbars", buf.accessByteBufWithCorrectSize());
|
||||
}
|
||||
|
||||
// Initialize Views
|
||||
UUID activeView = container.get(ACTIVE_VIEW, UUIDDataType.INSTANCE);
|
||||
if (activeView != null) {
|
||||
buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
buf.writeUUID(activeView);
|
||||
|
||||
PersistentDataContainer[] views = container.get(VIEWS, PersistentDataType.TAG_CONTAINER_ARRAY);
|
||||
buf.writeVarInt(views.length);
|
||||
for (PersistentDataContainer view : views) {
|
||||
View.load(view).write(buf);
|
||||
}
|
||||
|
||||
player.sendPluginMessage(this, "axiom:set_editor_views", buf.accessByteBufWithCorrectSize());
|
||||
}
|
||||
});
|
||||
Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:set_gamemode", (channel, player, message) -> {
|
||||
if (!player.hasPermission("axiom.*")) {
|
||||
return;
|
||||
}
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
GameType gameType = GameType.byId(friendlyByteBuf.readByte());
|
||||
((CraftPlayer)player).getHandle().setGameMode(gameType);
|
||||
});
|
||||
Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:set_fly_speed", (channel, player, message) -> {
|
||||
if (!player.hasPermission("axiom.*")) {
|
||||
return;
|
||||
}
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
float flySpeed = friendlyByteBuf.readFloat();
|
||||
((CraftPlayer)player).getHandle().getAbilities().setFlyingSpeed(flySpeed);
|
||||
});
|
||||
Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:set_block", new SetBlockPacketListener(this));
|
||||
Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:set_hotbar_slot", (channel, player, message) -> {
|
||||
if (!player.hasPermission("axiom.*")) {
|
||||
return;
|
||||
}
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
int index = friendlyByteBuf.readByte();
|
||||
if (index < 0 || index >= 9*9) return;
|
||||
net.minecraft.world.item.ItemStack nmsStack = friendlyByteBuf.readItem();
|
||||
|
||||
PersistentDataContainer container = player.getPersistentDataContainer();
|
||||
PersistentDataContainer hotbarItems = container.get(HOTBAR_DATA, PersistentDataType.TAG_CONTAINER);
|
||||
if (hotbarItems == null) hotbarItems = container.getAdapterContext().newPersistentDataContainer();
|
||||
hotbarItems.set(new NamespacedKey("axiom", "slot_"+index), ItemStackDataType.INSTANCE, CraftItemStack.asCraftMirror(nmsStack));
|
||||
container.set(HOTBAR_DATA, PersistentDataType.TAG_CONTAINER, hotbarItems);
|
||||
});
|
||||
Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:switch_active_hotbar", (channel, player, message) -> {
|
||||
if (!player.hasPermission("axiom.*")) {
|
||||
return;
|
||||
}
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
int oldHotbarIndex = friendlyByteBuf.readByte();
|
||||
int activeHotbarIndex = friendlyByteBuf.readByte();
|
||||
|
||||
ItemStack[] hotbarItems = new ItemStack[9];
|
||||
for (int i=0; i<9; i++) {
|
||||
hotbarItems[i] = CraftItemStack.asCraftMirror(friendlyByteBuf.readItem());
|
||||
}
|
||||
|
||||
PersistentDataContainer container = player.getPersistentDataContainer();
|
||||
PersistentDataContainer containerHotbarItems = container.get(HOTBAR_DATA, PersistentDataType.TAG_CONTAINER);
|
||||
if (containerHotbarItems == null) containerHotbarItems = container.getAdapterContext().newPersistentDataContainer();
|
||||
|
||||
for (int i=0; i<9; i++) {
|
||||
if (oldHotbarIndex != activeHotbarIndex) {
|
||||
int index = oldHotbarIndex*9 + i;
|
||||
ItemStack stack = player.getInventory().getItem(i);
|
||||
if (stack == null) {
|
||||
stack = new ItemStack(Material.AIR);
|
||||
} else {
|
||||
stack = stack.clone();
|
||||
}
|
||||
containerHotbarItems.set(new NamespacedKey("axiom", "slot_"+index), ItemStackDataType.INSTANCE, stack);
|
||||
}
|
||||
int index = activeHotbarIndex*9 + i;
|
||||
containerHotbarItems.set(new NamespacedKey("axiom", "slot_"+index), ItemStackDataType.INSTANCE, hotbarItems[i].clone());
|
||||
if (player.getGameMode() == GameMode.CREATIVE) player.getInventory().setItem(i, hotbarItems[i]);
|
||||
}
|
||||
|
||||
container.set(HOTBAR_DATA, PersistentDataType.TAG_CONTAINER, containerHotbarItems);
|
||||
container.set(ACTIVE_HOTBAR_INDEX, PersistentDataType.BYTE, (byte) activeHotbarIndex);
|
||||
});
|
||||
Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:teleport", (channel, player, message) -> {
|
||||
if (!player.hasPermission("axiom.*")) {
|
||||
return;
|
||||
}
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
ResourceKey<Level> resourceKey = friendlyByteBuf.readResourceKey(Registries.DIMENSION);
|
||||
double x = friendlyByteBuf.readDouble();
|
||||
double y = friendlyByteBuf.readDouble();
|
||||
double z = friendlyByteBuf.readDouble();
|
||||
float yRot = friendlyByteBuf.readFloat();
|
||||
float xRot = friendlyByteBuf.readFloat();
|
||||
|
||||
NamespacedKey namespacedKey = new NamespacedKey(resourceKey.location().getNamespace(), resourceKey.location().getPath());
|
||||
World world = Bukkit.getWorld(namespacedKey);
|
||||
if (world != null) {
|
||||
player.teleport(new Location(world, x, y, z, yRot, xRot));
|
||||
}
|
||||
});
|
||||
Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:set_editor_views", (channel, player, message) -> {
|
||||
if (!player.hasPermission("axiom.*")) {
|
||||
return;
|
||||
}
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
UUID uuid = friendlyByteBuf.readUUID();
|
||||
List<View> views = friendlyByteBuf.readList(View::read);
|
||||
|
||||
PersistentDataContainer container = player.getPersistentDataContainer();
|
||||
container.set(ACTIVE_VIEW, UUIDDataType.INSTANCE, uuid);
|
||||
|
||||
PersistentDataContainer[] containerArray = new PersistentDataContainer[views.size()];
|
||||
for (int i = 0; i < views.size(); i++) {
|
||||
PersistentDataContainer viewContainer = container.getAdapterContext().newPersistentDataContainer();
|
||||
views.get(i).save(viewContainer);
|
||||
containerArray[i] = viewContainer;
|
||||
}
|
||||
container.set(VIEWS, PersistentDataType.TAG_CONTAINER_ARRAY, containerArray);
|
||||
});
|
||||
msg.registerIncomingPluginChannel(this, "axiom:hello", new HelloPacketListener(this, activeAxiomPlayers));
|
||||
msg.registerIncomingPluginChannel(this, "axiom:set_gamemode", new SetGamemodePacketListener());
|
||||
msg.registerIncomingPluginChannel(this, "axiom:set_fly_speed", new SetFlySpeedPacketListener());
|
||||
msg.registerIncomingPluginChannel(this, "axiom:set_block", new SetBlockPacketListener(this));
|
||||
msg.registerIncomingPluginChannel(this, "axiom:set_hotbar_slot", new SetHotbarSlotPacketListener());
|
||||
msg.registerIncomingPluginChannel(this, "axiom:switch_active_hotbar", new SwitchActiveHotbarPacketListener());
|
||||
msg.registerIncomingPluginChannel(this, "axiom:teleport", new TeleportPacketListener());
|
||||
msg.registerIncomingPluginChannel(this, "axiom:set_editor_views", new SetEditorViewsPacketListener());
|
||||
msg.registerIncomingPluginChannel(this, "axiom:request_block_entity", new RequestBlockEntityPacketListener(this));
|
||||
|
||||
SetBlockBufferPacketListener setBlockBufferPacketListener = new SetBlockBufferPacketListener(this);
|
||||
|
||||
|
@ -1,15 +1,19 @@
|
||||
package com.moulberry.axiom.buffer;
|
||||
|
||||
import com.moulberry.axiom.AxiomConstants;
|
||||
import com.moulberry.axiom.AxiomPaper;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
||||
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class BlockBuffer {
|
||||
|
||||
@ -18,8 +22,8 @@ public class BlockBuffer {
|
||||
private final Long2ObjectMap<PalettedContainer<BlockState>> values;
|
||||
|
||||
private PalettedContainer<BlockState> last = null;
|
||||
private long lastId = AxiomPaper.MIN_POSITION_LONG;
|
||||
private int count;
|
||||
private long lastId = AxiomConstants.MIN_POSITION_LONG;
|
||||
private final Long2ObjectMap<Short2ObjectMap<CompressedBlockEntity>> blockEntities = new Long2ObjectOpenHashMap<>();
|
||||
|
||||
public BlockBuffer() {
|
||||
this.values = new Long2ObjectOpenHashMap<>();
|
||||
@ -29,17 +33,24 @@ public class BlockBuffer {
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return this.count;
|
||||
}
|
||||
|
||||
public void save(FriendlyByteBuf friendlyByteBuf) {
|
||||
for (Long2ObjectMap.Entry<PalettedContainer<BlockState>> entry : this.entrySet()) {
|
||||
friendlyByteBuf.writeLong(entry.getLongKey());
|
||||
entry.getValue().write(friendlyByteBuf);
|
||||
|
||||
Short2ObjectMap<CompressedBlockEntity> blockEntities = this.blockEntities.get(entry.getLongKey());
|
||||
if (blockEntities != null) {
|
||||
friendlyByteBuf.writeVarInt(blockEntities.size());
|
||||
for (Short2ObjectMap.Entry<CompressedBlockEntity> entry2 : blockEntities.short2ObjectEntrySet()) {
|
||||
friendlyByteBuf.writeShort(entry2.getShortKey());
|
||||
entry2.getValue().write(friendlyByteBuf);
|
||||
}
|
||||
} else {
|
||||
friendlyByteBuf.writeVarInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
friendlyByteBuf.writeLong(AxiomPaper.MIN_POSITION_LONG);
|
||||
friendlyByteBuf.writeLong(AxiomConstants.MIN_POSITION_LONG);
|
||||
}
|
||||
|
||||
public static BlockBuffer load(FriendlyByteBuf friendlyByteBuf) {
|
||||
@ -47,10 +58,21 @@ public class BlockBuffer {
|
||||
|
||||
while (true) {
|
||||
long index = friendlyByteBuf.readLong();
|
||||
if (index == AxiomPaper.MIN_POSITION_LONG) break;
|
||||
if (index == AxiomConstants.MIN_POSITION_LONG) break;
|
||||
|
||||
PalettedContainer<BlockState> palettedContainer = buffer.getOrCreateSection(index);
|
||||
palettedContainer.read(friendlyByteBuf);
|
||||
|
||||
int blockEntitySize = Math.min(4096, friendlyByteBuf.readVarInt());
|
||||
if (blockEntitySize > 0) {
|
||||
Short2ObjectMap<CompressedBlockEntity> map = new Short2ObjectOpenHashMap<>(blockEntitySize);
|
||||
for (int i = 0; i < blockEntitySize; i++) {
|
||||
short offset = friendlyByteBuf.readShort();
|
||||
CompressedBlockEntity blockEntity = CompressedBlockEntity.read(friendlyByteBuf);
|
||||
map.put(offset, blockEntity);
|
||||
}
|
||||
buffer.blockEntities.put(index, map);
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
@ -58,10 +80,34 @@ public class BlockBuffer {
|
||||
|
||||
public void clear() {
|
||||
this.last = null;
|
||||
this.lastId = AxiomPaper.MIN_POSITION_LONG;
|
||||
this.lastId = AxiomConstants.MIN_POSITION_LONG;
|
||||
this.values.clear();
|
||||
}
|
||||
|
||||
public void putBlockEntity(int x, int y, int z, CompressedBlockEntity blockEntity) {
|
||||
long cpos = BlockPos.asLong(x >> 4, y >> 4, z >> 4);
|
||||
Short2ObjectMap<CompressedBlockEntity> chunkMap = this.blockEntities.computeIfAbsent(cpos, k -> new Short2ObjectOpenHashMap<>());
|
||||
|
||||
int key = (x & 0xF) | ((y & 0xF) << 4) | ((z & 0xF) << 8);
|
||||
chunkMap.put((short)key, blockEntity);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public CompressedBlockEntity getBlockEntity(int x, int y, int z) {
|
||||
long cpos = BlockPos.asLong(x >> 4, y >> 4, z >> 4);
|
||||
Short2ObjectMap<CompressedBlockEntity> chunkMap = this.blockEntities.get(cpos);
|
||||
|
||||
if (chunkMap == null) return null;
|
||||
|
||||
int key = (x & 0xF) | ((y & 0xF) << 4) | ((z & 0xF) << 8);
|
||||
return chunkMap.get((short)key);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Short2ObjectMap<CompressedBlockEntity> getBlockEntityChunkMap(long cpos) {
|
||||
return this.blockEntities.get(cpos);
|
||||
}
|
||||
|
||||
public BlockState get(int x, int y, int z) {
|
||||
var container = this.getSectionForCoord(x, y, z);
|
||||
if (container == null) {
|
||||
@ -79,23 +125,11 @@ public class BlockBuffer {
|
||||
public void set(int x, int y, int z, BlockState state) {
|
||||
var container = this.getOrCreateSectionForCoord(x, y, z);
|
||||
var old = container.getAndSet(x & 0xF, y & 0xF, z & 0xF, state);
|
||||
|
||||
if (old == EMPTY_STATE) {
|
||||
if (state != EMPTY_STATE) this.count += 1;
|
||||
} else if (state == EMPTY_STATE) {
|
||||
this.count -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void set(int cx, int cy, int cz, int lx, int ly, int lz, BlockState state) {
|
||||
var container = this.getOrCreateSection(BlockPos.asLong(cx, cy, cz));
|
||||
var old = container.getAndSet(lx, ly, lz, state);
|
||||
|
||||
if (old == EMPTY_STATE) {
|
||||
if (state != EMPTY_STATE) this.count += 1;
|
||||
} else if (state == EMPTY_STATE) {
|
||||
this.count -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
public BlockState remove(int x, int y, int z) {
|
||||
|
66
src/main/java/com/moulberry/axiom/buffer/CompressedBlockEntity.java
Normale Datei
66
src/main/java/com/moulberry/axiom/buffer/CompressedBlockEntity.java
Normale Datei
@ -0,0 +1,66 @@
|
||||
package com.moulberry.axiom.buffer;
|
||||
|
||||
import com.github.luben.zstd.Zstd;
|
||||
import com.github.luben.zstd.ZstdDictCompress;
|
||||
import com.github.luben.zstd.ZstdDictDecompress;
|
||||
import com.moulberry.axiom.AxiomPaper;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Objects;
|
||||
|
||||
public record CompressedBlockEntity(int originalSize, byte compressionDict, byte[] compressed) {
|
||||
|
||||
private static ZstdDictCompress zstdDictCompress = null;
|
||||
private static ZstdDictDecompress zstdDictDecompress = null;
|
||||
|
||||
public static void initialize(AxiomPaper plugin) {
|
||||
try (InputStream is = Objects.requireNonNull(plugin.getResource("zstd_dictionaries/block_entities_v1.dict"))) {
|
||||
byte[] bytes = is.readAllBytes();
|
||||
zstdDictCompress = new ZstdDictCompress(bytes, Zstd.defaultCompressionLevel());
|
||||
zstdDictDecompress = new ZstdDictDecompress(bytes);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static CompressedBlockEntity compress(CompoundTag tag, ByteArrayOutputStream baos) {
|
||||
try {
|
||||
baos.reset();
|
||||
DataOutputStream dos = new DataOutputStream(baos);
|
||||
NbtIo.write(tag, dos);
|
||||
byte[] uncompressed = baos.toByteArray();
|
||||
byte[] compressed = Zstd.compress(uncompressed, zstdDictCompress);
|
||||
return new CompressedBlockEntity(uncompressed.length, (byte) 0, compressed);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public CompoundTag decompress() {
|
||||
if (this.compressionDict != 0) throw new UnsupportedOperationException("Unknown compression dict: " + this.compressionDict);
|
||||
|
||||
try {
|
||||
byte[] nbt = Zstd.decompress(this.compressed, zstdDictDecompress, this.originalSize);
|
||||
return NbtIo.read(new DataInputStream(new ByteArrayInputStream(nbt)));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static CompressedBlockEntity read(FriendlyByteBuf friendlyByteBuf) {
|
||||
int originalSize = friendlyByteBuf.readVarInt();
|
||||
byte compressionDict = friendlyByteBuf.readByte();
|
||||
byte[] compressed = friendlyByteBuf.readByteArray();
|
||||
return new CompressedBlockEntity(originalSize, compressionDict, compressed);
|
||||
}
|
||||
|
||||
public void write(FriendlyByteBuf friendlyByteBuf) {
|
||||
friendlyByteBuf.writeVarInt(this.originalSize);
|
||||
friendlyByteBuf.writeByte(this.compressionDict);
|
||||
friendlyByteBuf.writeByteArray(this.compressed);
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.moulberry.axiom.buffer;
|
||||
|
||||
import com.moulberry.axiom.AxiomConstants;
|
||||
import com.moulberry.axiom.AxiomPaper;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
@ -20,7 +21,7 @@ public class Position2ByteMap {
|
||||
private final LongFunction<byte[]> defaultFunction;
|
||||
private final Long2ObjectMap<byte[]> map = new Long2ObjectOpenHashMap<>();
|
||||
|
||||
private long lastChunkPos = AxiomPaper.MIN_POSITION_LONG;
|
||||
private long lastChunkPos = AxiomConstants.MIN_POSITION_LONG;
|
||||
private byte[] lastChunk = null;
|
||||
|
||||
public Position2ByteMap() {
|
||||
@ -47,7 +48,7 @@ public class Position2ByteMap {
|
||||
friendlyByteBuf.writeLong(entry.getLongKey());
|
||||
friendlyByteBuf.writeBytes(entry.getValue());
|
||||
}
|
||||
friendlyByteBuf.writeLong(AxiomPaper.MIN_POSITION_LONG);
|
||||
friendlyByteBuf.writeLong(AxiomConstants.MIN_POSITION_LONG);
|
||||
}
|
||||
|
||||
public static Position2ByteMap load(FriendlyByteBuf friendlyByteBuf) {
|
||||
@ -55,7 +56,7 @@ public class Position2ByteMap {
|
||||
|
||||
while (true) {
|
||||
long pos = friendlyByteBuf.readLong();
|
||||
if (pos == AxiomPaper.MIN_POSITION_LONG) break;
|
||||
if (pos == AxiomConstants.MIN_POSITION_LONG) break;
|
||||
|
||||
byte[] bytes = new byte[16*16*16];
|
||||
friendlyByteBuf.readBytes(bytes);
|
||||
@ -67,7 +68,7 @@ public class Position2ByteMap {
|
||||
|
||||
public void clear() {
|
||||
this.map.clear();
|
||||
this.lastChunkPos = AxiomPaper.MIN_POSITION_LONG;
|
||||
this.lastChunkPos = AxiomConstants.MIN_POSITION_LONG;
|
||||
this.lastChunk = null;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,50 @@
|
||||
package com.moulberry.axiom.event;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AxiomFlySpeedChangeEvent extends Event implements Cancellable {
|
||||
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
|
||||
private final Player player;
|
||||
private final float flySpeed;
|
||||
private boolean cancelled = false;
|
||||
|
||||
public AxiomFlySpeedChangeEvent(Player player, float flySpeed) {
|
||||
this.player = player;
|
||||
this.flySpeed = flySpeed;
|
||||
}
|
||||
|
||||
public float getFlySpeed() {
|
||||
return flySpeed;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.cancelled = cancel;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.moulberry.axiom.event;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AxiomGameModeChangeEvent extends Event implements Cancellable {
|
||||
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
|
||||
private final Player player;
|
||||
private final GameMode gameMode;
|
||||
private boolean cancelled = false;
|
||||
|
||||
public AxiomGameModeChangeEvent(Player player, GameMode gameMode) {
|
||||
this.player = player;
|
||||
this.gameMode = gameMode;
|
||||
}
|
||||
|
||||
public GameMode getGameMode() {
|
||||
return gameMode;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.cancelled = cancel;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
}
|
52
src/main/java/com/moulberry/axiom/event/AxiomHandshakeEvent.java
Normale Datei
52
src/main/java/com/moulberry/axiom/event/AxiomHandshakeEvent.java
Normale Datei
@ -0,0 +1,52 @@
|
||||
package com.moulberry.axiom.event;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AxiomHandshakeEvent extends Event implements Cancellable {
|
||||
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
|
||||
private final Player player;
|
||||
private boolean cancelled = false;
|
||||
private int maxBufferSize = 0x100000;
|
||||
|
||||
public AxiomHandshakeEvent(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
public int getMaxBufferSize() {
|
||||
return this.maxBufferSize;
|
||||
}
|
||||
|
||||
public void setMaxBufferSize(int maxBufferSize) {
|
||||
this.maxBufferSize = maxBufferSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.cancelled = cancel;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
}
|
54
src/main/java/com/moulberry/axiom/event/AxiomModifyWorldEvent.java
Normale Datei
54
src/main/java/com/moulberry/axiom/event/AxiomModifyWorldEvent.java
Normale Datei
@ -0,0 +1,54 @@
|
||||
package com.moulberry.axiom.event;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AxiomModifyWorldEvent extends Event implements Cancellable {
|
||||
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
|
||||
private final Player player;
|
||||
private final World world;
|
||||
private boolean cancelled;
|
||||
|
||||
public AxiomModifyWorldEvent(Player player, World world) {
|
||||
this.player = player;
|
||||
this.world = world;
|
||||
|
||||
// By default, changes are only allowed if the player is in the same world
|
||||
// This behaviour can be changed by doing setCancelled(false)
|
||||
this.cancelled = player.getWorld() != world;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.cancelled = cancel;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
}
|
51
src/main/java/com/moulberry/axiom/event/AxiomTeleportEvent.java
Normale Datei
51
src/main/java/com/moulberry/axiom/event/AxiomTeleportEvent.java
Normale Datei
@ -0,0 +1,51 @@
|
||||
package com.moulberry.axiom.event;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AxiomTeleportEvent extends Event implements Cancellable {
|
||||
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
|
||||
private final Player player;
|
||||
private final Location location;
|
||||
private boolean cancelled = false;
|
||||
|
||||
public AxiomTeleportEvent(Player player, Location location) {
|
||||
this.player = player;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return this.location.clone();
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.cancelled = cancel;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
}
|
27
src/main/java/com/moulberry/axiom/integration/RegionProtection.java
Normale Datei
27
src/main/java/com/moulberry/axiom/integration/RegionProtection.java
Normale Datei
@ -0,0 +1,27 @@
|
||||
package com.moulberry.axiom.integration;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class RegionProtection {
|
||||
|
||||
private final RegionProtectionWorldGuard worldGuard;
|
||||
|
||||
public RegionProtection(Player player, World world) {
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("WorldGuard")) {
|
||||
this.worldGuard = RegionProtectionWorldGuard.tryCreate(player, world);
|
||||
} else {
|
||||
this.worldGuard = null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canBuildInSection(int cx, int cy, int cz) {
|
||||
if (this.worldGuard != null && !this.worldGuard.canBuildInSection(cx, cy, cz)) return false;
|
||||
// todo: PlotSquared
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.moulberry.axiom.integration;
|
||||
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldguard.LocalPlayer;
|
||||
import com.sk89q.worldguard.WorldGuard;
|
||||
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
||||
import com.sk89q.worldguard.internal.platform.WorldGuardPlatform;
|
||||
import com.sk89q.worldguard.protection.ApplicableRegionSet;
|
||||
import com.sk89q.worldguard.protection.flags.Flags;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import com.sk89q.worldguard.protection.regions.RegionContainer;
|
||||
import com.sk89q.worldguard.protection.regions.RegionQuery;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class RegionProtectionWorldGuard {
|
||||
|
||||
private final LocalPlayer player;
|
||||
private final RegionManager regionManager;
|
||||
|
||||
public RegionProtectionWorldGuard(LocalPlayer player, RegionManager regionManager) {
|
||||
this.player = player;
|
||||
this.regionManager = regionManager;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static RegionProtectionWorldGuard tryCreate(Player player, World world) {
|
||||
WorldGuardPlatform platform = WorldGuard.getInstance().getPlatform();
|
||||
|
||||
RegionContainer regionContainer = platform.getRegionContainer();
|
||||
com.sk89q.worldedit.world.World worldEditWorld = BukkitAdapter.adapt(world);
|
||||
LocalPlayer worldGuardPlayer = WorldGuardPlugin.inst().wrapPlayer(player);
|
||||
|
||||
// Don't do any protection if player has bypass
|
||||
if (platform.getSessionManager().hasBypass(worldGuardPlayer, worldEditWorld)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
RegionManager regionManager = regionContainer.get(worldEditWorld);
|
||||
if (regionManager == null) return null;
|
||||
|
||||
return new RegionProtectionWorldGuard(worldGuardPlayer, regionManager);
|
||||
}
|
||||
|
||||
public boolean canBuildInSection(int cx, int cy, int cz) {
|
||||
BlockVector3 min = BlockVector3.at(cx*16, cy*16, cz*16);
|
||||
BlockVector3 max = BlockVector3.at(cx*16+15, cy*16+15, cz*16+15);
|
||||
ProtectedRegion test = new ProtectedCuboidRegion("dummy", min, max);
|
||||
ApplicableRegionSet regions = this.regionManager.getApplicableRegions(test, RegionQuery.QueryOption.COMPUTE_PARENTS);
|
||||
return regions.testState(this.player, Flags.BUILD);
|
||||
}
|
||||
|
||||
}
|
@ -27,9 +27,9 @@ public class AxiomBigPayloadHandler extends ByteToMessageDecoder {
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||
try {
|
||||
int readerIndex = in.readerIndex();
|
||||
int i = in.readableBytes();
|
||||
if (i != 0) {
|
||||
int readerIndex = in.readerIndex();
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(in);
|
||||
int packetId = buf.readVarInt();
|
||||
|
||||
@ -38,13 +38,14 @@ public class AxiomBigPayloadHandler extends ByteToMessageDecoder {
|
||||
if (identifier.equals(SET_BUFFER)) {
|
||||
ServerPlayer player = connection.getPlayer();
|
||||
if (player != null && player.getBukkitEntity().hasPermission("axiom.*")) {
|
||||
listener.onReceive(player, buf);
|
||||
return;
|
||||
if (listener.onReceive(player, buf)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
in.readerIndex(readerIndex);
|
||||
}
|
||||
in.readerIndex(readerIndex);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
107
src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java
Normale Datei
107
src/main/java/com/moulberry/axiom/packet/HelloPacketListener.java
Normale Datei
@ -0,0 +1,107 @@
|
||||
package com.moulberry.axiom.packet;
|
||||
|
||||
import com.moulberry.axiom.AxiomConstants;
|
||||
import com.moulberry.axiom.AxiomPaper;
|
||||
import com.moulberry.axiom.View;
|
||||
import com.moulberry.axiom.event.AxiomHandshakeEvent;
|
||||
import com.moulberry.axiom.persistence.ItemStackDataType;
|
||||
import com.moulberry.axiom.persistence.UUIDDataType;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class HelloPacketListener implements PluginMessageListener {
|
||||
|
||||
private final AxiomPaper plugin;
|
||||
private final Set<UUID> activeAxiomPlayers;
|
||||
|
||||
public HelloPacketListener(AxiomPaper plugin, Set<UUID> activeAxiomPlayers) {
|
||||
this.plugin = plugin;
|
||||
this.activeAxiomPlayers = activeAxiomPlayers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
|
||||
if (!player.hasPermission("axiom.*")) {
|
||||
return;
|
||||
}
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
int apiVersion = friendlyByteBuf.readVarInt();
|
||||
friendlyByteBuf.readNbt(); // Discard
|
||||
|
||||
if (apiVersion != AxiomConstants.API_VERSION) {
|
||||
player.kick(Component.text("Unsupported Axiom API Version. Server supports " + AxiomConstants.API_VERSION +
|
||||
", while client is " + apiVersion));
|
||||
return;
|
||||
}
|
||||
|
||||
// Call handshake event
|
||||
AxiomHandshakeEvent handshakeEvent = new AxiomHandshakeEvent(player);
|
||||
Bukkit.getPluginManager().callEvent(handshakeEvent);
|
||||
if (handshakeEvent.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
activeAxiomPlayers.add(player.getUniqueId());
|
||||
|
||||
// Enable
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
buf.writeBoolean(true);
|
||||
buf.writeByte(0); // todo: world properties
|
||||
buf.writeInt(handshakeEvent.getMaxBufferSize()); // Max Buffer Size
|
||||
buf.writeBoolean(false); // No source info
|
||||
buf.writeBoolean(false); // No source settings
|
||||
buf.writeVarInt(5); // Maximum Reach
|
||||
buf.writeVarInt(16); // Max editor views
|
||||
buf.writeBoolean(true); // Editable Views
|
||||
player.sendPluginMessage(this.plugin, "axiom:enable", buf.accessByteBufWithCorrectSize());
|
||||
|
||||
// Initialize Hotbars
|
||||
PersistentDataContainer container = player.getPersistentDataContainer();
|
||||
int activeHotbarIndex = container.getOrDefault(AxiomConstants.ACTIVE_HOTBAR_INDEX, PersistentDataType.BYTE, (byte) 0);
|
||||
PersistentDataContainer hotbarItems = container.get(AxiomConstants.HOTBAR_DATA, PersistentDataType.TAG_CONTAINER);
|
||||
if (hotbarItems != null) {
|
||||
buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
buf.writeByte((byte) activeHotbarIndex);
|
||||
for (int i=0; i<9*9; i++) {
|
||||
// Ignore selected hotbar
|
||||
if (i / 9 == activeHotbarIndex) {
|
||||
buf.writeItem(net.minecraft.world.item.ItemStack.EMPTY);
|
||||
} else {
|
||||
ItemStack stack = hotbarItems.get(new NamespacedKey("axiom", "slot_"+i), ItemStackDataType.INSTANCE);
|
||||
buf.writeItem(CraftItemStack.asNMSCopy(stack));
|
||||
}
|
||||
}
|
||||
player.sendPluginMessage(this.plugin, "axiom:initialize_hotbars", buf.accessByteBufWithCorrectSize());
|
||||
}
|
||||
|
||||
// Initialize Views
|
||||
UUID activeView = container.get(AxiomConstants.ACTIVE_VIEW, UUIDDataType.INSTANCE);
|
||||
if (activeView != null) {
|
||||
buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
buf.writeUUID(activeView);
|
||||
|
||||
PersistentDataContainer[] views = container.get(AxiomConstants.VIEWS, PersistentDataType.TAG_CONTAINER_ARRAY);
|
||||
buf.writeVarInt(views.length);
|
||||
for (PersistentDataContainer view : views) {
|
||||
View.load(view).write(buf);
|
||||
}
|
||||
|
||||
player.sendPluginMessage(this.plugin, "axiom:set_editor_views", buf.accessByteBufWithCorrectSize());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package com.moulberry.axiom.packet;
|
||||
|
||||
import com.moulberry.axiom.AxiomPaper;
|
||||
import com.moulberry.axiom.buffer.CompressedBlockEntity;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import it.unimi.dsi.fastutil.longs.*;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
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.ServerPlayer;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
public class RequestBlockEntityPacketListener implements PluginMessageListener {
|
||||
|
||||
private final AxiomPaper plugin;
|
||||
|
||||
public RequestBlockEntityPacketListener(AxiomPaper plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player bukkitPlayer, @NotNull byte[] message) {
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
long id = friendlyByteBuf.readLong();
|
||||
|
||||
if (!bukkitPlayer.hasPermission("axiom.*")) {
|
||||
// We always send an 'empty' response in order to make the client happy
|
||||
sendEmptyResponse(bukkitPlayer, id);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
Long2ObjectMap<CompressedBlockEntity> map = new Long2ObjectOpenHashMap<>();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
||||
|
||||
// Save and compress block entities
|
||||
int count = friendlyByteBuf.readVarInt();
|
||||
for (int i = 0; i < count; i++) {
|
||||
long pos = friendlyByteBuf.readLong();
|
||||
BlockEntity blockEntity = level.getBlockEntity(mutableBlockPos.set(pos));
|
||||
if (blockEntity != null) {
|
||||
CompoundTag tag = blockEntity.saveWithoutMetadata();
|
||||
map.put(pos, CompressedBlockEntity.compress(tag, baos));
|
||||
}
|
||||
}
|
||||
|
||||
// Send response packet
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer(16));
|
||||
buf.writeLong(id);
|
||||
buf.writeVarInt(map.size());
|
||||
for (Long2ObjectMap.Entry<CompressedBlockEntity> entry : map.long2ObjectEntrySet()) {
|
||||
buf.writeLong(entry.getLongKey());
|
||||
entry.getValue().write(buf);
|
||||
}
|
||||
bukkitPlayer.sendPluginMessage(this.plugin, "axiom:block_entities", buf.accessByteBufWithCorrectSize());
|
||||
}
|
||||
|
||||
private void sendEmptyResponse(Player player, long id) {
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer(16));
|
||||
buf.writeLong(id);
|
||||
buf.writeByte(0); // no block entities
|
||||
player.sendPluginMessage(this.plugin, "axiom:block_entities", buf.accessByteBufWithCorrectSize());
|
||||
}
|
||||
|
||||
}
|
@ -3,8 +3,26 @@ package com.moulberry.axiom.packet;
|
||||
import com.moulberry.axiom.AxiomPaper;
|
||||
import com.moulberry.axiom.buffer.BiomeBuffer;
|
||||
import com.moulberry.axiom.buffer.BlockBuffer;
|
||||
import com.moulberry.axiom.buffer.CompressedBlockEntity;
|
||||
import com.moulberry.axiom.event.AxiomModifyWorldEvent;
|
||||
import com.moulberry.axiom.integration.RegionProtection;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldguard.LocalPlayer;
|
||||
import com.sk89q.worldguard.WorldGuard;
|
||||
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
||||
import com.sk89q.worldguard.protection.ApplicableRegionSet;
|
||||
import com.sk89q.worldguard.protection.flags.Flags;
|
||||
import com.sk89q.worldguard.protection.flags.StateFlag;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import com.sk89q.worldguard.protection.regions.RegionContainer;
|
||||
import com.sk89q.worldguard.protection.regions.RegionQuery;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.Registry;
|
||||
@ -29,6 +47,9 @@ import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.lighting.LightEngine;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
@ -59,9 +80,9 @@ public class SetBlockBufferPacketListener {
|
||||
}
|
||||
}
|
||||
|
||||
public void onReceive(ServerPlayer player, FriendlyByteBuf friendlyByteBuf) {
|
||||
public boolean onReceive(ServerPlayer player, FriendlyByteBuf friendlyByteBuf) {
|
||||
MinecraftServer server = player.getServer();
|
||||
if (server == null) return;
|
||||
if (server == null) return false;
|
||||
|
||||
ResourceKey<Level> worldKey = friendlyByteBuf.readResourceKey(Registries.DIMENSION);
|
||||
friendlyByteBuf.readUUID(); // Discard, we don't need to associate buffers
|
||||
@ -74,20 +95,30 @@ public class SetBlockBufferPacketListener {
|
||||
byte type = friendlyByteBuf.readByte();
|
||||
if (type == 0) {
|
||||
BlockBuffer buffer = BlockBuffer.load(friendlyByteBuf);
|
||||
applyBlockBuffer(server, buffer, worldKey);
|
||||
applyBlockBuffer(player, server, buffer, worldKey);
|
||||
} else if (type == 1) {
|
||||
BiomeBuffer buffer = BiomeBuffer.load(friendlyByteBuf);
|
||||
applyBiomeBuffer(server, buffer, worldKey);
|
||||
} else {
|
||||
throw new RuntimeException("Unknown buffer type: " + type);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void applyBlockBuffer(MinecraftServer server, BlockBuffer buffer, ResourceKey<Level> worldKey) {
|
||||
private void applyBlockBuffer(ServerPlayer player, MinecraftServer server, BlockBuffer buffer, ResourceKey<Level> worldKey) {
|
||||
server.execute(() -> {
|
||||
ServerLevel world = server.getLevel(worldKey);
|
||||
if (world == null) return;
|
||||
|
||||
// Call AxiomModifyWorldEvent event
|
||||
AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(player.getBukkitEntity(), world.getWorld());
|
||||
Bukkit.getPluginManager().callEvent(modifyWorldEvent);
|
||||
if (modifyWorldEvent.isCancelled()) return;
|
||||
|
||||
RegionProtection regionProtection = new RegionProtection(player.getBukkitEntity(), world.getWorld());
|
||||
|
||||
// Allowed, apply buffer
|
||||
BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos();
|
||||
|
||||
var lightEngine = world.getChunkSource().getLightEngine();
|
||||
@ -104,6 +135,10 @@ public class SetBlockBufferPacketListener {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!regionProtection.canBuildInSection(cx, cy, cz)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LevelChunk chunk = world.getChunk(cx, cz);
|
||||
chunk.setUnsaved(true);
|
||||
|
||||
@ -125,6 +160,8 @@ public class SetBlockBufferPacketListener {
|
||||
}
|
||||
}
|
||||
|
||||
Short2ObjectMap<CompressedBlockEntity> blockEntityChunkMap = buffer.getBlockEntityChunkMap(entry.getLongKey());
|
||||
|
||||
sectionStates.acquire();
|
||||
try {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
@ -159,26 +196,41 @@ public class SetBlockBufferPacketListener {
|
||||
}
|
||||
}
|
||||
|
||||
boolean oldHasBlockEntity = old.hasBlockEntity();
|
||||
if (old.is(block)) {
|
||||
if (blockState.hasBlockEntity()) {
|
||||
BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK);
|
||||
if (blockEntity == null) {
|
||||
blockEntity = ((EntityBlock)block).newBlockEntity(blockPos, blockState);
|
||||
if (blockEntity != null) {
|
||||
chunk.addAndRegisterBlockEntity(blockEntity);
|
||||
}
|
||||
} else {
|
||||
blockEntity.setBlockState(blockState);
|
||||
if (blockState.hasBlockEntity()) {
|
||||
BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK);
|
||||
|
||||
try {
|
||||
this.updateBlockEntityTicker.invoke(chunk, blockEntity);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (blockEntity == null) {
|
||||
// There isn't a block entity here, create it!
|
||||
blockEntity = ((EntityBlock)block).newBlockEntity(blockPos, blockState);
|
||||
if (blockEntity != null) {
|
||||
chunk.addAndRegisterBlockEntity(blockEntity);
|
||||
}
|
||||
} else if (blockEntity.getType().isValid(blockState)) {
|
||||
// Block entity is here and the type is correct
|
||||
blockEntity.setBlockState(blockState);
|
||||
|
||||
try {
|
||||
this.updateBlockEntityTicker.invoke(chunk, blockEntity);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
// Block entity type isn't correct, we need to recreate it
|
||||
chunk.removeBlockEntity(blockPos);
|
||||
|
||||
blockEntity = ((EntityBlock)block).newBlockEntity(blockPos, blockState);
|
||||
if (blockEntity != null) {
|
||||
chunk.addAndRegisterBlockEntity(blockEntity);
|
||||
}
|
||||
}
|
||||
} else if (oldHasBlockEntity) {
|
||||
if (blockEntity != null && blockEntityChunkMap != null) {
|
||||
int key = x | (y << 4) | (z << 8);
|
||||
CompressedBlockEntity savedBlockEntity = blockEntityChunkMap.get((short) key);
|
||||
if (savedBlockEntity != null) {
|
||||
blockEntity.load(savedBlockEntity.decompress());
|
||||
}
|
||||
}
|
||||
} else if (old.hasBlockEntity()) {
|
||||
chunk.removeBlockEntity(blockPos);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.moulberry.axiom.packet;
|
||||
|
||||
import com.moulberry.axiom.AxiomPaper;
|
||||
import com.moulberry.axiom.event.AxiomModifyWorldEvent;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.SectionPos;
|
||||
@ -15,6 +16,7 @@ import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.lighting.LightEngine;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
@ -52,6 +54,12 @@ public class SetBlockPacketListener implements PluginMessageListener {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if player is allowed to modify this world
|
||||
AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(bukkitPlayer, bukkitPlayer.getWorld());
|
||||
Bukkit.getPluginManager().callEvent(modifyWorldEvent);
|
||||
if (modifyWorldEvent.isCancelled()) return;
|
||||
|
||||
// Read packet
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
BlockPos blockPos = friendlyByteBuf.readBlockPos();
|
||||
BlockState blockState = friendlyByteBuf.readById(Block.BLOCK_STATE_REGISTRY);
|
||||
@ -60,6 +68,7 @@ public class SetBlockPacketListener implements PluginMessageListener {
|
||||
|
||||
ServerPlayer player = ((CraftPlayer)bukkitPlayer).getHandle();
|
||||
|
||||
// Update blocks
|
||||
if (updateNeighbors) {
|
||||
player.level().setBlock(blockPos, blockState, 3);
|
||||
} else {
|
||||
@ -111,25 +120,23 @@ public class SetBlockPacketListener implements PluginMessageListener {
|
||||
if (blockEntity != null) {
|
||||
chunk.addAndRegisterBlockEntity(blockEntity);
|
||||
}
|
||||
} else if (blockEntity.getType().isValid(blockState)) {
|
||||
// Block entity is here and the type is correct
|
||||
// Just update the state and ticker and move on
|
||||
blockEntity.setBlockState(blockState);
|
||||
|
||||
try {
|
||||
this.updateBlockEntityTicker.invoke(chunk, blockEntity);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
if (blockEntity.getType().isValid(blockState)) {
|
||||
// Block entity is here and the type is correct
|
||||
// Just update the state and ticker and move on
|
||||
blockEntity.setBlockState(blockState);
|
||||
// Block entity type isn't correct, we need to recreate it
|
||||
chunk.removeBlockEntity(blockPos);
|
||||
|
||||
try {
|
||||
this.updateBlockEntityTicker.invoke(chunk, blockEntity);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
// Block entity type isn't correct, we need to recreate it
|
||||
chunk.removeBlockEntity(blockPos);
|
||||
|
||||
blockEntity = ((EntityBlock)block).newBlockEntity(blockPos, blockState);
|
||||
if (blockEntity != null) {
|
||||
chunk.addAndRegisterBlockEntity(blockEntity);
|
||||
}
|
||||
blockEntity = ((EntityBlock)block).newBlockEntity(blockPos, blockState);
|
||||
if (blockEntity != null) {
|
||||
chunk.addAndRegisterBlockEntity(blockEntity);
|
||||
}
|
||||
}
|
||||
} else if (old.hasBlockEntity()) {
|
||||
|
@ -0,0 +1,41 @@
|
||||
package com.moulberry.axiom.packet;
|
||||
|
||||
import com.moulberry.axiom.AxiomConstants;
|
||||
import com.moulberry.axiom.View;
|
||||
import com.moulberry.axiom.persistence.UUIDDataType;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class SetEditorViewsPacketListener implements PluginMessageListener {
|
||||
|
||||
@Override
|
||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
|
||||
if (!player.hasPermission("axiom.*")) {
|
||||
return;
|
||||
}
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
UUID uuid = friendlyByteBuf.readUUID();
|
||||
List<View> views = friendlyByteBuf.readList(View::read);
|
||||
|
||||
PersistentDataContainer container = player.getPersistentDataContainer();
|
||||
container.set(AxiomConstants.ACTIVE_VIEW, UUIDDataType.INSTANCE, uuid);
|
||||
|
||||
PersistentDataContainer[] containerArray = new PersistentDataContainer[views.size()];
|
||||
for (int i = 0; i < views.size(); i++) {
|
||||
PersistentDataContainer viewContainer = container.getAdapterContext().newPersistentDataContainer();
|
||||
views.get(i).save(viewContainer);
|
||||
containerArray[i] = viewContainer;
|
||||
}
|
||||
container.set(AxiomConstants.VIEWS, PersistentDataType.TAG_CONTAINER_ARRAY, containerArray);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.moulberry.axiom.packet;
|
||||
|
||||
import com.moulberry.axiom.event.AxiomFlySpeedChangeEvent;
|
||||
import com.moulberry.axiom.event.AxiomGameModeChangeEvent;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.level.GameType;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class SetFlySpeedPacketListener implements PluginMessageListener {
|
||||
|
||||
@Override
|
||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
|
||||
if (!player.hasPermission("axiom.*")) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
float flySpeed = friendlyByteBuf.readFloat();
|
||||
|
||||
// Call event
|
||||
AxiomFlySpeedChangeEvent flySpeedChangeEvent = new AxiomFlySpeedChangeEvent(player, flySpeed);
|
||||
Bukkit.getPluginManager().callEvent(flySpeedChangeEvent);
|
||||
if (flySpeedChangeEvent.isCancelled()) return;
|
||||
|
||||
// Change flying speed
|
||||
((CraftPlayer)player).getHandle().getAbilities().setFlyingSpeed(flySpeed);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.moulberry.axiom.packet;
|
||||
|
||||
import com.moulberry.axiom.event.AxiomGameModeChangeEvent;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.level.GameType;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class SetGamemodePacketListener implements PluginMessageListener {
|
||||
|
||||
@Override
|
||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
|
||||
if (!player.hasPermission("axiom.*")) {
|
||||
return;
|
||||
}
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
GameType gameType = GameType.byId(friendlyByteBuf.readByte());
|
||||
|
||||
// Call event
|
||||
AxiomGameModeChangeEvent gameModeChangeEvent = new AxiomGameModeChangeEvent(player, GameMode.getByValue(gameType.getId()));
|
||||
Bukkit.getPluginManager().callEvent(gameModeChangeEvent);
|
||||
if (gameModeChangeEvent.isCancelled()) return;
|
||||
|
||||
// Change gamemode
|
||||
((CraftPlayer)player).getHandle().setGameMode(gameType);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.moulberry.axiom.packet;
|
||||
|
||||
import com.moulberry.axiom.AxiomConstants;
|
||||
import com.moulberry.axiom.persistence.ItemStackDataType;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import org.bukkit.NamespacedKey;
|
||||
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.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class SetHotbarSlotPacketListener implements PluginMessageListener {
|
||||
|
||||
@Override
|
||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
|
||||
if (!player.hasPermission("axiom.*")) {
|
||||
return;
|
||||
}
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
int index = friendlyByteBuf.readByte();
|
||||
if (index < 0 || index >= 9*9) return;
|
||||
net.minecraft.world.item.ItemStack nmsStack = friendlyByteBuf.readItem();
|
||||
|
||||
PersistentDataContainer container = player.getPersistentDataContainer();
|
||||
PersistentDataContainer hotbarItems = container.get(AxiomConstants.HOTBAR_DATA, PersistentDataType.TAG_CONTAINER);
|
||||
if (hotbarItems == null) hotbarItems = container.getAdapterContext().newPersistentDataContainer();
|
||||
hotbarItems.set(new NamespacedKey("axiom", "slot_"+index), ItemStackDataType.INSTANCE, CraftItemStack.asCraftMirror(nmsStack));
|
||||
container.set(AxiomConstants.HOTBAR_DATA, PersistentDataType.TAG_CONTAINER, hotbarItems);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package com.moulberry.axiom.packet;
|
||||
|
||||
import com.moulberry.axiom.AxiomConstants;
|
||||
import com.moulberry.axiom.persistence.ItemStackDataType;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import org.bukkit.GameMode;
|
||||
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.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class SwitchActiveHotbarPacketListener implements PluginMessageListener {
|
||||
|
||||
@Override
|
||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
|
||||
if (!player.hasPermission("axiom.*")) {
|
||||
return;
|
||||
}
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
int oldHotbarIndex = friendlyByteBuf.readByte();
|
||||
int activeHotbarIndex = friendlyByteBuf.readByte();
|
||||
|
||||
ItemStack[] hotbarItems = new ItemStack[9];
|
||||
for (int i=0; i<9; i++) {
|
||||
hotbarItems[i] = CraftItemStack.asCraftMirror(friendlyByteBuf.readItem());
|
||||
}
|
||||
|
||||
PersistentDataContainer container = player.getPersistentDataContainer();
|
||||
PersistentDataContainer containerHotbarItems = container.get(AxiomConstants.HOTBAR_DATA, PersistentDataType.TAG_CONTAINER);
|
||||
if (containerHotbarItems == null) containerHotbarItems = container.getAdapterContext().newPersistentDataContainer();
|
||||
|
||||
for (int i=0; i<9; i++) {
|
||||
if (oldHotbarIndex != activeHotbarIndex) {
|
||||
int index = oldHotbarIndex*9 + i;
|
||||
ItemStack stack = player.getInventory().getItem(i);
|
||||
if (stack == null) {
|
||||
stack = new ItemStack(Material.AIR);
|
||||
} else {
|
||||
stack = stack.clone();
|
||||
}
|
||||
containerHotbarItems.set(new NamespacedKey("axiom", "slot_"+index), ItemStackDataType.INSTANCE, stack);
|
||||
}
|
||||
int index = activeHotbarIndex*9 + i;
|
||||
containerHotbarItems.set(new NamespacedKey("axiom", "slot_"+index), ItemStackDataType.INSTANCE, hotbarItems[i].clone());
|
||||
if (player.getGameMode() == GameMode.CREATIVE) player.getInventory().setItem(i, hotbarItems[i]);
|
||||
}
|
||||
|
||||
container.set(AxiomConstants.HOTBAR_DATA, PersistentDataType.TAG_CONTAINER, containerHotbarItems);
|
||||
container.set(AxiomConstants.ACTIVE_HOTBAR_INDEX, PersistentDataType.BYTE, (byte) activeHotbarIndex);
|
||||
}
|
||||
|
||||
}
|
44
src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java
Normale Datei
44
src/main/java/com/moulberry/axiom/packet/TeleportPacketListener.java
Normale Datei
@ -0,0 +1,44 @@
|
||||
package com.moulberry.axiom.packet;
|
||||
|
||||
import com.moulberry.axiom.event.AxiomGameModeChangeEvent;
|
||||
import com.moulberry.axiom.event.AxiomTeleportEvent;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class TeleportPacketListener implements PluginMessageListener {
|
||||
|
||||
@Override
|
||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
|
||||
if (!player.hasPermission("axiom.*")) {
|
||||
return;
|
||||
}
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
ResourceKey<Level> resourceKey = friendlyByteBuf.readResourceKey(Registries.DIMENSION);
|
||||
double x = friendlyByteBuf.readDouble();
|
||||
double y = friendlyByteBuf.readDouble();
|
||||
double z = friendlyByteBuf.readDouble();
|
||||
float yRot = friendlyByteBuf.readFloat();
|
||||
float xRot = friendlyByteBuf.readFloat();
|
||||
|
||||
NamespacedKey namespacedKey = new NamespacedKey(resourceKey.location().getNamespace(), resourceKey.location().getPath());
|
||||
World world = Bukkit.getWorld(namespacedKey);
|
||||
if (world == null) return;
|
||||
|
||||
// Call event
|
||||
AxiomTeleportEvent teleportEvent = new AxiomTeleportEvent(player, new Location(world, x, y, z, yRot, xRot));
|
||||
Bukkit.getPluginManager().callEvent(teleportEvent);
|
||||
if (teleportEvent.isCancelled()) return;
|
||||
|
||||
// Do teleport
|
||||
player.teleport(new Location(world, x, y, z, yRot, xRot));
|
||||
}
|
||||
|
||||
}
|
BIN
src/main/resources/zstd_dictionaries/block_entities_v1.dict
Normale Datei
BIN
src/main/resources/zstd_dictionaries/block_entities_v1.dict
Normale Datei
Binäre Datei nicht angezeigt.
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren