geforkt von Mirrors/AxiomPaperPlugin
Dieser Commit ist enthalten in:
Ursprung
ef7886341e
Commit
b8fa0aa640
@ -22,6 +22,7 @@ repositories {
|
|||||||
maven("https://jitpack.io")
|
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")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -38,6 +39,9 @@ dependencies {
|
|||||||
implementation(platform("com.intellectualsites.bom:bom-newest:1.37"))
|
implementation(platform("com.intellectualsites.bom:bom-newest:1.37"))
|
||||||
compileOnly("com.intellectualsites.plotsquared:plotsquared-core")
|
compileOnly("com.intellectualsites.plotsquared:plotsquared-core")
|
||||||
compileOnly("com.intellectualsites.plotsquared:plotsquared-bukkit") { isTransitive = false }
|
compileOnly("com.intellectualsites.plotsquared:plotsquared-bukkit") { isTransitive = false }
|
||||||
|
|
||||||
|
// ViaVersion support
|
||||||
|
compileOnly("com.viaversion:viaversion-api:4.7.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
|
@ -1,16 +1,10 @@
|
|||||||
package com.moulberry.axiom;
|
package com.moulberry.axiom;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
|
|
||||||
public class AxiomConstants {
|
public class AxiomConstants {
|
||||||
|
|
||||||
public static final long MIN_POSITION_LONG = BlockPos.asLong(-33554432, -2048, -33554432);
|
public static final long MIN_POSITION_LONG = 0b1000000000000000000000000010000000000000000000000000100000000000L;
|
||||||
static {
|
|
||||||
if (MIN_POSITION_LONG != 0b1000000000000000000000000010000000000000000000000000100000000000L) {
|
|
||||||
throw new Error("BlockPos representation changed!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 ACTIVE_HOTBAR_INDEX = new NamespacedKey("axiom", "active_hotbar_index");
|
||||||
|
@ -1,105 +1,67 @@
|
|||||||
package com.moulberry.axiom;
|
package com.moulberry.axiom;
|
||||||
|
|
||||||
import com.moulberry.axiom.buffer.CompressedBlockEntity;
|
import com.moulberry.axiom.integration.PaperFailMoveListener;
|
||||||
import com.moulberry.axiom.packet.*;
|
import com.moulberry.axiom.packet.*;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.channel.Channel;
|
import org.bukkit.Bukkit;
|
||||||
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.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 org.bukkit.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.bukkit.plugin.messaging.Messenger;
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public class AxiomPaper extends JavaPlugin implements Listener {
|
public class AxiomPaper extends JavaPlugin implements Listener {
|
||||||
|
|
||||||
@Override
|
public static final String PERMISSION = "axiom.*";
|
||||||
public void onEnable() {
|
|
||||||
Bukkit.getPluginManager().registerEvents(this, this);
|
|
||||||
CompressedBlockEntity.initialize(this);
|
|
||||||
|
|
||||||
Messenger msg = Bukkit.getMessenger();
|
private static AxiomPaper instance;
|
||||||
|
public static Plugin getPlugin() {
|
||||||
msg.registerOutgoingPluginChannel(this, "axiom:enable");
|
return instance;
|
||||||
msg.registerOutgoingPluginChannel(this, "axiom:initialize_hotbars");
|
|
||||||
msg.registerOutgoingPluginChannel(this, "axiom:set_editor_views");
|
|
||||||
msg.registerOutgoingPluginChannel(this, "axiom:block_entities");
|
|
||||||
|
|
||||||
final Set<UUID> activeAxiomPlayers = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
ChannelInitializeListenerHolder.addListener(Key.key("axiom:handle_big_payload"), new ChannelInitializeListener() {
|
|
||||||
@Override
|
|
||||||
public void afterInitChannel(@NonNull Channel channel) {
|
|
||||||
var packets = ConnectionProtocol.PLAY.getPacketsByIds(PacketFlow.SERVERBOUND);
|
|
||||||
int payloadId = -1;
|
|
||||||
for (Map.Entry<Integer, Class<? extends Packet<?>>> entry : packets.entrySet()) {
|
|
||||||
if (entry.getValue() == ServerboundCustomPayloadPacket.class) {
|
|
||||||
payloadId = entry.getKey();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (payloadId < 0) {
|
|
||||||
throw new RuntimeException("Failed to find ServerboundCustomPayloadPacket id");
|
|
||||||
}
|
|
||||||
|
|
||||||
Connection connection = (Connection) channel.pipeline().get("packet_handler");
|
|
||||||
channel.pipeline().addBefore("decoder", "axiom-big-payload-handler",
|
|
||||||
new AxiomBigPayloadHandler(payloadId, connection, setBlockBufferPacketListener));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Bukkit.getScheduler().scheduleSyncRepeatingTask(this, () -> {
|
|
||||||
HashSet<UUID> newActiveAxiomPlayers = new HashSet<>();
|
|
||||||
|
|
||||||
for (Player player : Bukkit.getServer().getOnlinePlayers()) {
|
|
||||||
if (activeAxiomPlayers.contains(player.getUniqueId())) {
|
|
||||||
if (!player.hasPermission("axiom.*")) {
|
|
||||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
|
|
||||||
buf.writeBoolean(false);
|
|
||||||
player.sendPluginMessage(this, "axiom:enable", buf.accessByteBufWithCorrectSize());
|
|
||||||
} else {
|
|
||||||
newActiveAxiomPlayers.add(player.getUniqueId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
activeAxiomPlayers.clear();
|
|
||||||
activeAxiomPlayers.addAll(newActiveAxiomPlayers);
|
|
||||||
}, 20, 20);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
private static final Map<String, AxiomPacketListener> listeners = new ConcurrentHashMap<>();
|
||||||
public void onFailMove(PlayerFailMoveEvent event) {
|
|
||||||
if (event.getPlayer().hasPermission("axiom.*") &&
|
public static AxiomPacketListener getListener(String channel) {
|
||||||
event.getFailReason() == PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY) {
|
return listeners.get(channel);
|
||||||
event.setAllowed(true);
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
instance = this;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Bukkit.getPluginManager().registerEvents(new PaperFailMoveListener(), this);
|
||||||
|
} catch (NoClassDefFoundError e) {
|
||||||
|
getLogger().log(Level.WARNING, "Axiom players may move too quickly according to the server. Use a current Paper version or increase the 'moved-too-quickly-multiplier' in spigot.yml.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(OutChannel channel : OutChannel.values()) {
|
||||||
|
Bukkit.getMessenger().registerOutgoingPluginChannel(this, channel.getChannel());
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO multiversion (Except setGamemode)
|
||||||
|
registerInChannel("hello", new HelloPacketListener());
|
||||||
|
registerInChannel("set_gamemode", new SetGamemodePacketListener());
|
||||||
|
registerInChannel("set_fly_speed", new SetFlySpeedPacketListener());
|
||||||
|
registerInChannel("set_block", new SetBlockPacketListener());
|
||||||
|
registerInChannel("set_hotbar_slot", new SetHotbarSlotPacketListener());
|
||||||
|
registerInChannel("switch_active_hotbar", new SwitchActiveHotbarPacketListener());
|
||||||
|
registerInChannel("teleport", new TeleportPacketListener());
|
||||||
|
registerInChannel("set_editor_views", new SetEditorViewsPacketListener());
|
||||||
|
registerInChannel("request_block_entity", new RequestBlockEntityPacketListener());
|
||||||
|
registerInChannel("handle_big_payload", new SetBlockBufferPacketListener());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerInChannel(String channel, AxiomPacketListener handler) {
|
||||||
|
listeners.put(channel, handler);
|
||||||
|
Bukkit.getMessenger().registerIncomingPluginChannel(this, "axiom:" + channel, (ch, player, message) -> {
|
||||||
|
if (!player.hasPermission(PERMISSION))
|
||||||
|
return;
|
||||||
|
|
||||||
|
handler.onMessage(player, Unpooled.wrappedBuffer(message));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
32
src/main/java/com/moulberry/axiom/OutChannel.java
Normale Datei
32
src/main/java/com/moulberry/axiom/OutChannel.java
Normale Datei
@ -0,0 +1,32 @@
|
|||||||
|
package com.moulberry.axiom;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public enum OutChannel {
|
||||||
|
ENABLE,
|
||||||
|
INITIALIZE_HOTBARS,
|
||||||
|
SET_EDITOR_VIEWS,
|
||||||
|
BLOCK_ENTITIES;
|
||||||
|
|
||||||
|
private final String channel;
|
||||||
|
|
||||||
|
OutChannel() {
|
||||||
|
channel = "axiom:" + name();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getChannel() {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(Player player, ByteBuf buf) {
|
||||||
|
// trustin https://stackoverflow.com/a/19309312 CC BY-SA 3.0
|
||||||
|
byte[] array = new byte[buf.readableBytes()];
|
||||||
|
buf.getBytes(buf.readerIndex(), array);
|
||||||
|
send(player, array);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(Player player, byte[] array) {
|
||||||
|
player.sendPluginMessage(AxiomPaper.getPlugin(), channel, array);
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,6 @@ package com.moulberry.axiom;
|
|||||||
|
|
||||||
import com.moulberry.axiom.persistence.UUIDDataType;
|
import com.moulberry.axiom.persistence.UUIDDataType;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
|
||||||
import net.minecraft.nbt.Tag;
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
@ -3,7 +3,6 @@ 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.AxiomPaper;
|
|
||||||
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 net.minecraft.network.FriendlyByteBuf;
|
||||||
@ -13,16 +12,15 @@ import java.util.Objects;
|
|||||||
|
|
||||||
public record CompressedBlockEntity(int originalSize, byte compressionDict, byte[] compressed) {
|
public record CompressedBlockEntity(int originalSize, byte compressionDict, byte[] compressed) {
|
||||||
|
|
||||||
private static ZstdDictCompress zstdDictCompress = null;
|
private static final ZstdDictCompress zstdDictCompress;
|
||||||
private static ZstdDictDecompress zstdDictDecompress = null;
|
private static final ZstdDictDecompress zstdDictDecompress;
|
||||||
|
static {
|
||||||
public static void initialize(AxiomPaper plugin) {
|
try (InputStream is = Objects.requireNonNull(CompressedBlockEntity.class.getClassLoader().getResourceAsStream("zstd_dictionaries/block_entities_v1.dict"))) {
|
||||||
try (InputStream is = Objects.requireNonNull(plugin.getResource("zstd_dictionaries/block_entities_v1.dict"))) {
|
|
||||||
byte[] bytes = is.readAllBytes();
|
byte[] bytes = is.readAllBytes();
|
||||||
zstdDictCompress = new ZstdDictCompress(bytes, Zstd.defaultCompressionLevel());
|
zstdDictCompress = new ZstdDictCompress(bytes, Zstd.defaultCompressionLevel());
|
||||||
zstdDictDecompress = new ZstdDictDecompress(bytes);
|
zstdDictDecompress = new ZstdDictDecompress(bytes);
|
||||||
} catch (Exception e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package com.moulberry.axiom.buffer;
|
package com.moulberry.axiom.buffer;
|
||||||
|
|
||||||
import com.moulberry.axiom.AxiomConstants;
|
import com.moulberry.axiom.AxiomConstants;
|
||||||
import com.moulberry.axiom.AxiomPaper;
|
|
||||||
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;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.moulberry.axiom.event;
|
package com.moulberry.axiom.event;
|
||||||
|
|
||||||
import org.bukkit.GameMode;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.Cancellable;
|
import org.bukkit.event.Cancellable;
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package com.moulberry.axiom.event;
|
package com.moulberry.axiom.event;
|
||||||
|
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.Cancellable;
|
import org.bukkit.event.Cancellable;
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package com.moulberry.axiom.event;
|
package com.moulberry.axiom.event;
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.Cancellable;
|
import org.bukkit.event.Cancellable;
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.moulberry.axiom.integration;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.AxiomPaper;
|
||||||
|
import io.papermc.paper.event.player.PlayerFailMoveEvent;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
|
||||||
|
public class PaperFailMoveListener implements Listener {
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onFailMove(PlayerFailMoveEvent event) {
|
||||||
|
if (event.getPlayer().hasPermission(AxiomPaper.PERMISSION) &&
|
||||||
|
event.getFailReason() == PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY) {
|
||||||
|
event.setAllowed(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
22
src/main/java/com/moulberry/axiom/integration/VersionTranslator.java
Normale Datei
22
src/main/java/com/moulberry/axiom/integration/VersionTranslator.java
Normale Datei
@ -0,0 +1,22 @@
|
|||||||
|
package com.moulberry.axiom.integration;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.function.IntFunction;
|
||||||
|
|
||||||
|
public interface VersionTranslator {
|
||||||
|
|
||||||
|
VersionTranslator impl = Bukkit.getPluginManager().getPlugin("ViaVersion") != null ? new ViaVersionTranslator() : new Dummy();
|
||||||
|
|
||||||
|
IntFunction<Integer> blockStateMapper(Player player);
|
||||||
|
|
||||||
|
class Dummy implements VersionTranslator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntFunction<Integer> blockStateMapper(Player player) {
|
||||||
|
return id -> id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
14
src/main/java/com/moulberry/axiom/integration/ViaVersionDummy.java
Normale Datei
14
src/main/java/com/moulberry/axiom/integration/ViaVersionDummy.java
Normale Datei
@ -0,0 +1,14 @@
|
|||||||
|
package com.moulberry.axiom.integration;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.function.IntFunction;
|
||||||
|
|
||||||
|
public class ViaVersionDummy implements VersionTranslator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntFunction<Integer> blockStateMapper(Player player) {
|
||||||
|
return id -> id;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package com.moulberry.axiom.integration;
|
||||||
|
|
||||||
|
import com.viaversion.viaversion.api.Via;
|
||||||
|
import com.viaversion.viaversion.api.data.MappingData;
|
||||||
|
import com.viaversion.viaversion.api.protocol.ProtocolManager;
|
||||||
|
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
|
||||||
|
import com.viaversion.viaversion.api.protocol.version.ServerProtocolVersion;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.IntFunction;
|
||||||
|
|
||||||
|
public class ViaVersionTranslator implements VersionTranslator {
|
||||||
|
|
||||||
|
private final ProtocolManager protocolManager;
|
||||||
|
private final ServerProtocolVersion serverVersion;
|
||||||
|
|
||||||
|
public ViaVersionTranslator() {
|
||||||
|
protocolManager = Via.getManager().getProtocolManager();
|
||||||
|
serverVersion = Via.getAPI().getServerVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntFunction<Integer> blockStateMapper(Player player) {
|
||||||
|
List<ProtocolPathEntry> path = protocolManager.getProtocolPath(Via.getAPI().getPlayerVersion(player.getUniqueId()), serverVersion.highestSupportedVersion());
|
||||||
|
if(path == null)
|
||||||
|
return id -> id;
|
||||||
|
|
||||||
|
List<IntFunction<Integer>> mappers = new ArrayList<>(path.size());
|
||||||
|
for(ProtocolPathEntry entry : path) {
|
||||||
|
MappingData mappings = entry.protocol().getMappingData();
|
||||||
|
if(mappings != null)
|
||||||
|
mappers.add(mappings::getNewBlockStateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return id -> {
|
||||||
|
for(IntFunction<Integer> transformer : mappers)
|
||||||
|
id = transformer.apply(id);
|
||||||
|
return id;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,64 +1,63 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.AxiomPaper;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||||
import io.papermc.paper.network.ConnectionEvent;
|
import io.papermc.paper.network.ConnectionEvent;
|
||||||
import net.minecraft.network.Connection;
|
import net.minecraft.network.ConnectionProtocol;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.protocol.PacketFlow;
|
||||||
|
import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.List;
|
@ChannelHandler.Sharable
|
||||||
|
public class AxiomBigPayloadHandler extends ChannelInboundHandlerAdapter {
|
||||||
|
|
||||||
public class AxiomBigPayloadHandler extends ByteToMessageDecoder {
|
private static final int PLUGINMESSAGE_PACKETID = ConnectionProtocol.PLAY.getPacketId(PacketFlow.SERVERBOUND, new ServerboundCustomPayloadPacket(null, null));
|
||||||
|
|
||||||
private static final ResourceLocation SET_BUFFER = new ResourceLocation("axiom", "set_buffer");
|
private final Player player;
|
||||||
private final int payloadId;
|
|
||||||
private final Connection connection;
|
|
||||||
private final SetBlockBufferPacketListener listener;
|
|
||||||
|
|
||||||
public AxiomBigPayloadHandler(int payloadId, Connection connection, SetBlockBufferPacketListener listener) {
|
public AxiomBigPayloadHandler(Player player) {
|
||||||
this.payloadId = payloadId;
|
this.player = player;
|
||||||
this.connection = connection;
|
|
||||||
this.listener = listener;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
public void channelRead(@NotNull ChannelHandlerContext ctx, @NotNull Object msg) throws Exception {
|
||||||
try {
|
if(!(msg instanceof ByteBuf in)) {
|
||||||
int readerIndex = in.readerIndex();
|
ctx.fireChannelRead(msg);
|
||||||
int i = in.readableBytes();
|
return;
|
||||||
if (i != 0) {
|
|
||||||
FriendlyByteBuf buf = new FriendlyByteBuf(in);
|
|
||||||
int packetId = buf.readVarInt();
|
|
||||||
|
|
||||||
if (packetId == payloadId) {
|
|
||||||
ResourceLocation identifier = buf.readResourceLocation();
|
|
||||||
if (identifier.equals(SET_BUFFER)) {
|
|
||||||
ServerPlayer player = connection.getPlayer();
|
|
||||||
if (player != null && player.getBukkitEntity().hasPermission("axiom.*")) {
|
|
||||||
if (listener.onReceive(player, buf)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
in.readerIndex(readerIndex);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.fireChannelRead(in.retain());
|
int readerIndexBackup = in.readerIndex();
|
||||||
|
|
||||||
|
if(in.readableBytes() != 0) {
|
||||||
|
FriendlyByteBuf buf = new FriendlyByteBuf((ByteBuf) msg);
|
||||||
|
|
||||||
|
if (buf.readVarInt() == PLUGINMESSAGE_PACKETID) {
|
||||||
|
ResourceLocation identifier = buf.readResourceLocation();
|
||||||
|
if (identifier.getNamespace().equals("axiom") && player.hasPermission(AxiomPaper.PERMISSION)) {
|
||||||
|
AxiomPacketListener listener = AxiomPaper.getListener(identifier.getPath());
|
||||||
|
//TODO sync!
|
||||||
|
listener.onMessage(player, in);
|
||||||
|
in.release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
in.readerIndex(readerIndexBackup);
|
||||||
|
ctx.fireChannelRead(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||||
if (evt == ConnectionEvent.COMPRESSION_THRESHOLD_SET || evt == ConnectionEvent.COMPRESSION_DISABLED) {
|
if (evt == ConnectionEvent.COMPRESSION_THRESHOLD_SET || evt == ConnectionEvent.COMPRESSION_DISABLED) {
|
||||||
ctx.channel().pipeline().remove("axiom-big-payload-handler");
|
ctx.channel().pipeline().remove("axiom-big-payload-handler");
|
||||||
ctx.channel().pipeline().addBefore("decoder", "axiom-big-payload-handler",
|
ctx.channel().pipeline().addBefore("decoder", "axiom-big-payload-handler", this);
|
||||||
new AxiomBigPayloadHandler(payloadId, connection, listener));
|
|
||||||
}
|
}
|
||||||
super.userEventTriggered(ctx, evt);
|
super.userEventTriggered(ctx, evt);
|
||||||
}
|
}
|
||||||
|
10
src/main/java/com/moulberry/axiom/packet/AxiomPacketListener.java
Normale Datei
10
src/main/java/com/moulberry/axiom/packet/AxiomPacketListener.java
Normale Datei
@ -0,0 +1,10 @@
|
|||||||
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public interface AxiomPacketListener {
|
||||||
|
|
||||||
|
void onMessage(Player player, ByteBuf buf);
|
||||||
|
|
||||||
|
}
|
@ -2,49 +2,62 @@ package com.moulberry.axiom.packet;
|
|||||||
|
|
||||||
import com.moulberry.axiom.AxiomConstants;
|
import com.moulberry.axiom.AxiomConstants;
|
||||||
import com.moulberry.axiom.AxiomPaper;
|
import com.moulberry.axiom.AxiomPaper;
|
||||||
|
import com.moulberry.axiom.OutChannel;
|
||||||
import com.moulberry.axiom.View;
|
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.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.NamespacedKey;
|
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.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.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 org.bukkit.plugin.messaging.PluginMessageListener;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class HelloPacketListener implements PluginMessageListener {
|
public class HelloPacketListener implements AxiomPacketListener, Listener {
|
||||||
|
|
||||||
private final AxiomPaper plugin;
|
private final Set<Player> axiomPlayers = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||||
private final Set<UUID> activeAxiomPlayers;
|
|
||||||
|
|
||||||
public HelloPacketListener(AxiomPaper plugin, Set<UUID> activeAxiomPlayers) {
|
public HelloPacketListener() {
|
||||||
this.plugin = plugin;
|
//TODO cleanup (side effects of class)
|
||||||
this.activeAxiomPlayers = activeAxiomPlayers;
|
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;
|
||||||
|
}), 20, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
|
axiomPlayers.remove(event.getPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
|
public void onMessage(Player player, ByteBuf buf) {
|
||||||
if (!player.hasPermission("axiom.*")) {
|
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
|
||||||
int apiVersion = friendlyByteBuf.readVarInt();
|
int apiVersion = friendlyByteBuf.readVarInt();
|
||||||
friendlyByteBuf.readNbt(); // Discard
|
friendlyByteBuf.readNbt(); // Discard
|
||||||
|
|
||||||
if (apiVersion != AxiomConstants.API_VERSION) {
|
if (apiVersion != AxiomConstants.API_VERSION) {
|
||||||
player.kick(Component.text("Unsupported Axiom API Version. Server supports " + AxiomConstants.API_VERSION +
|
player.sendMessage(Component.text("Unsupported Axiom API Version. Server supports " + AxiomConstants.API_VERSION + ", while client is " + apiVersion));
|
||||||
", while client is " + apiVersion));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,52 +68,54 @@ public class HelloPacketListener implements PluginMessageListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
activeAxiomPlayers.add(player.getUniqueId());
|
axiomPlayers.add(player);
|
||||||
|
//TODO thread safety
|
||||||
|
((CraftPlayer)player).getHandle().connection.connection.channel.pipeline().addBefore("decoder", "axiom-big-payload-handler", new AxiomBigPayloadHandler(player));
|
||||||
|
|
||||||
// Enable
|
// Enable
|
||||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
|
FriendlyByteBuf out = new FriendlyByteBuf(Unpooled.buffer());
|
||||||
buf.writeBoolean(true);
|
out.writeBoolean(true);
|
||||||
buf.writeByte(0); // todo: world properties
|
out.writeByte(0); // todo: world properties
|
||||||
buf.writeInt(handshakeEvent.getMaxBufferSize()); // Max Buffer Size
|
out.writeInt(handshakeEvent.getMaxBufferSize()); // Max Buffer Size
|
||||||
buf.writeBoolean(false); // No source info
|
out.writeBoolean(false); // No source info
|
||||||
buf.writeBoolean(false); // No source settings
|
out.writeBoolean(false); // No source settings
|
||||||
buf.writeVarInt(5); // Maximum Reach
|
out.writeVarInt(5); // Maximum Reach
|
||||||
buf.writeVarInt(16); // Max editor views
|
out.writeVarInt(16); // Max editor views
|
||||||
buf.writeBoolean(true); // Editable Views
|
out.writeBoolean(true); // Editable Views
|
||||||
player.sendPluginMessage(this.plugin, "axiom:enable", buf.accessByteBufWithCorrectSize());
|
OutChannel.ENABLE.send(player, out);
|
||||||
|
|
||||||
// Initialize Hotbars
|
// Initialize Hotbars
|
||||||
PersistentDataContainer container = player.getPersistentDataContainer();
|
PersistentDataContainer container = player.getPersistentDataContainer();
|
||||||
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) {
|
||||||
buf = new FriendlyByteBuf(Unpooled.buffer());
|
out = new FriendlyByteBuf(Unpooled.buffer());
|
||||||
buf.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) {
|
||||||
buf.writeItem(net.minecraft.world.item.ItemStack.EMPTY);
|
out.writeItem(net.minecraft.world.item.ItemStack.EMPTY);
|
||||||
} else {
|
} else {
|
||||||
ItemStack stack = hotbarItems.get(new NamespacedKey("axiom", "slot_"+i), ItemStackDataType.INSTANCE);
|
ItemStack stack = hotbarItems.get(new NamespacedKey("axiom", "slot_"+i), ItemStackDataType.INSTANCE);
|
||||||
buf.writeItem(CraftItemStack.asNMSCopy(stack));
|
out.writeItem(CraftItemStack.asNMSCopy(stack));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
player.sendPluginMessage(this.plugin, "axiom:initialize_hotbars", buf.accessByteBufWithCorrectSize());
|
OutChannel.INITIALIZE_HOTBARS.send(player, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
||||||
buf = new FriendlyByteBuf(Unpooled.buffer());
|
out = new FriendlyByteBuf(Unpooled.buffer());
|
||||||
buf.writeUUID(activeView);
|
out.writeUUID(activeView);
|
||||||
|
|
||||||
PersistentDataContainer[] views = container.get(AxiomConstants.VIEWS, PersistentDataType.TAG_CONTAINER_ARRAY);
|
PersistentDataContainer[] views = container.get(AxiomConstants.VIEWS, PersistentDataType.TAG_CONTAINER_ARRAY);
|
||||||
buf.writeVarInt(views.length);
|
out.writeVarInt(views.length);
|
||||||
for (PersistentDataContainer view : views) {
|
for (PersistentDataContainer view : views) {
|
||||||
View.load(view).write(buf);
|
View.load(view).write(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
player.sendPluginMessage(this.plugin, "axiom:set_editor_views", buf.accessByteBufWithCorrectSize());
|
OutChannel.SET_EDITOR_VIEWS.send(player, out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
import com.moulberry.axiom.AxiomPaper;
|
import com.moulberry.axiom.OutChannel;
|
||||||
import com.moulberry.axiom.buffer.CompressedBlockEntity;
|
import com.moulberry.axiom.buffer.CompressedBlockEntity;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import it.unimi.dsi.fastutil.longs.*;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
|
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.core.registries.Registries;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
@ -16,27 +18,20 @@ 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.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
|
||||||
public class RequestBlockEntityPacketListener implements PluginMessageListener {
|
public class RequestBlockEntityPacketListener implements AxiomPacketListener {
|
||||||
|
|
||||||
private final AxiomPaper plugin;
|
|
||||||
|
|
||||||
public RequestBlockEntityPacketListener(AxiomPaper plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player bukkitPlayer, @NotNull byte[] message) {
|
public void onMessage(@NotNull Player bukkitPlayer, @NotNull ByteBuf buf) {
|
||||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
|
||||||
long id = friendlyByteBuf.readLong();
|
long id = friendlyByteBuf.readLong();
|
||||||
|
|
||||||
if (!bukkitPlayer.hasPermission("axiom.*")) {
|
if (!bukkitPlayer.hasPermission("axiom.*")) {
|
||||||
// We always send an 'empty' response in order to make the client happy
|
// We always send an 'empty' response in order to make the client happy
|
||||||
sendEmptyResponse(bukkitPlayer, id);
|
sendEmptyResponse(bukkitPlayer, id); //TODO
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,21 +65,21 @@ public class RequestBlockEntityPacketListener implements PluginMessageListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send response packet
|
// Send response packet
|
||||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer(16));
|
FriendlyByteBuf out = new FriendlyByteBuf(Unpooled.buffer(16));
|
||||||
buf.writeLong(id);
|
out.writeLong(id);
|
||||||
buf.writeVarInt(map.size());
|
out.writeVarInt(map.size());
|
||||||
for (Long2ObjectMap.Entry<CompressedBlockEntity> entry : map.long2ObjectEntrySet()) {
|
for (Long2ObjectMap.Entry<CompressedBlockEntity> entry : map.long2ObjectEntrySet()) {
|
||||||
buf.writeLong(entry.getLongKey());
|
out.writeLong(entry.getLongKey());
|
||||||
entry.getValue().write(buf);
|
entry.getValue().write(out);
|
||||||
}
|
}
|
||||||
bukkitPlayer.sendPluginMessage(this.plugin, "axiom:block_entities", buf.accessByteBufWithCorrectSize());
|
OutChannel.BLOCK_ENTITIES.send(bukkitPlayer, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendEmptyResponse(Player player, long id) {
|
private void sendEmptyResponse(Player player, long id) {
|
||||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer(16));
|
ByteBuf buf = Unpooled.buffer(16);
|
||||||
buf.writeLong(id);
|
buf.writeLong(id);
|
||||||
buf.writeByte(0); // no block entities
|
buf.writeByte(0); // no block entities
|
||||||
player.sendPluginMessage(this.plugin, "axiom:block_entities", buf.accessByteBufWithCorrectSize());
|
OutChannel.BLOCK_ENTITIES.send(player, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,11 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
import com.moulberry.axiom.AxiomPaper;
|
|
||||||
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.event.AxiomModifyWorldEvent;
|
import com.moulberry.axiom.event.AxiomModifyWorldEvent;
|
||||||
import com.moulberry.axiom.integration.RegionProtection;
|
import com.moulberry.axiom.integration.RegionProtection;
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import io.netty.buffer.ByteBuf;
|
||||||
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.longs.Long2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
|
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
@ -48,26 +33,19 @@ import net.minecraft.world.level.chunk.PalettedContainer;
|
|||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.Heightmap;
|
||||||
import net.minecraft.world.level.lighting.LightEngine;
|
import net.minecraft.world.level.lighting.LightEngine;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
|
||||||
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.entity.Player;
|
||||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import xyz.jpenilla.reflectionremapper.ReflectionRemapper;
|
import xyz.jpenilla.reflectionremapper.ReflectionRemapper;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class SetBlockBufferPacketListener {
|
public class SetBlockBufferPacketListener implements AxiomPacketListener {
|
||||||
|
|
||||||
private final AxiomPaper plugin;
|
|
||||||
private final Method updateBlockEntityTicker;
|
private final Method updateBlockEntityTicker;
|
||||||
|
|
||||||
public SetBlockBufferPacketListener(AxiomPaper plugin) {
|
public SetBlockBufferPacketListener() {
|
||||||
this.plugin = plugin;
|
|
||||||
|
|
||||||
ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar();
|
ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar();
|
||||||
String methodName = reflectionRemapper.remapMethodName(LevelChunk.class, "updateBlockEntityTicker", BlockEntity.class);
|
String methodName = reflectionRemapper.remapMethodName(LevelChunk.class, "updateBlockEntityTicker", BlockEntity.class);
|
||||||
|
|
||||||
@ -80,9 +58,11 @@ public class SetBlockBufferPacketListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onReceive(ServerPlayer player, FriendlyByteBuf friendlyByteBuf) {
|
@Override
|
||||||
MinecraftServer server = player.getServer();
|
public void onMessage(Player player, ByteBuf buf) {
|
||||||
if (server == null) return false;
|
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
|
||||||
|
MinecraftServer server = ((CraftServer)player.getServer()).getServer();
|
||||||
|
if (server == null) return;
|
||||||
|
|
||||||
ResourceKey<Level> worldKey = friendlyByteBuf.readResourceKey(Registries.DIMENSION);
|
ResourceKey<Level> worldKey = friendlyByteBuf.readResourceKey(Registries.DIMENSION);
|
||||||
friendlyByteBuf.readUUID(); // Discard, we don't need to associate buffers
|
friendlyByteBuf.readUUID(); // Discard, we don't need to associate buffers
|
||||||
@ -102,205 +82,199 @@ public class SetBlockBufferPacketListener {
|
|||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Unknown buffer type: " + type);
|
throw new RuntimeException("Unknown buffer type: " + type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyBlockBuffer(ServerPlayer player, MinecraftServer server, BlockBuffer buffer, ResourceKey<Level> worldKey) {
|
private void applyBlockBuffer(Player player, MinecraftServer server, BlockBuffer buffer, ResourceKey<Level> worldKey) {
|
||||||
server.execute(() -> {
|
ServerLevel world = server.getLevel(worldKey);
|
||||||
ServerLevel world = server.getLevel(worldKey);
|
if (world == null) return;
|
||||||
if (world == null) return;
|
|
||||||
|
|
||||||
// Call AxiomModifyWorldEvent event
|
// Call AxiomModifyWorldEvent event
|
||||||
AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(player.getBukkitEntity(), world.getWorld());
|
AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(player, world.getWorld());
|
||||||
Bukkit.getPluginManager().callEvent(modifyWorldEvent);
|
Bukkit.getPluginManager().callEvent(modifyWorldEvent);
|
||||||
if (modifyWorldEvent.isCancelled()) return;
|
if (modifyWorldEvent.isCancelled()) return;
|
||||||
|
|
||||||
RegionProtection regionProtection = new RegionProtection(player.getBukkitEntity(), world.getWorld());
|
RegionProtection regionProtection = new RegionProtection(player, world.getWorld());
|
||||||
|
|
||||||
// Allowed, apply buffer
|
// Allowed, apply buffer
|
||||||
BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos();
|
BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos();
|
||||||
|
|
||||||
var lightEngine = world.getChunkSource().getLightEngine();
|
var lightEngine = world.getChunkSource().getLightEngine();
|
||||||
|
|
||||||
BlockState emptyState = BlockBuffer.EMPTY_STATE;
|
BlockState emptyState = BlockBuffer.EMPTY_STATE;
|
||||||
|
|
||||||
for (Long2ObjectMap.Entry<PalettedContainer<BlockState>> entry : buffer.entrySet()) {
|
for (Long2ObjectMap.Entry<PalettedContainer<BlockState>> entry : buffer.entrySet()) {
|
||||||
int cx = BlockPos.getX(entry.getLongKey());
|
int cx = BlockPos.getX(entry.getLongKey());
|
||||||
int cy = BlockPos.getY(entry.getLongKey());
|
int cy = BlockPos.getY(entry.getLongKey());
|
||||||
int cz = BlockPos.getZ(entry.getLongKey());
|
int cz = BlockPos.getZ(entry.getLongKey());
|
||||||
PalettedContainer<BlockState> container = entry.getValue();
|
PalettedContainer<BlockState> container = entry.getValue();
|
||||||
|
|
||||||
if (cy < world.getMinSection() || cy >= world.getMaxSection()) {
|
if (cy < world.getMinSection() || cy >= world.getMaxSection()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!regionProtection.canBuildInSection(cx, cy, cz)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LevelChunk chunk = world.getChunk(cx, cz);
|
||||||
|
chunk.setUnsaved(true);
|
||||||
|
|
||||||
|
LevelChunkSection section = chunk.getSection(world.getSectionIndexFromSectionY(cy));
|
||||||
|
PalettedContainer<BlockState> sectionStates = section.getStates();
|
||||||
|
boolean hasOnlyAir = section.hasOnlyAir();
|
||||||
|
|
||||||
|
Heightmap worldSurface = null;
|
||||||
|
Heightmap oceanFloor = null;
|
||||||
|
Heightmap motionBlocking = null;
|
||||||
|
Heightmap motionBlockingNoLeaves = null;
|
||||||
|
for (Map.Entry<Heightmap.Types, Heightmap> heightmap : chunk.getHeightmaps()) {
|
||||||
|
switch (heightmap.getKey()) {
|
||||||
|
case WORLD_SURFACE -> worldSurface = heightmap.getValue();
|
||||||
|
case OCEAN_FLOOR -> oceanFloor = heightmap.getValue();
|
||||||
|
case MOTION_BLOCKING -> motionBlocking = heightmap.getValue();
|
||||||
|
case MOTION_BLOCKING_NO_LEAVES -> motionBlockingNoLeaves = heightmap.getValue();
|
||||||
|
default -> {}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!regionProtection.canBuildInSection(cx, cy, cz)) {
|
Short2ObjectMap<CompressedBlockEntity> blockEntityChunkMap = buffer.getBlockEntityChunkMap(entry.getLongKey());
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
LevelChunk chunk = world.getChunk(cx, cz);
|
sectionStates.acquire();
|
||||||
chunk.setUnsaved(true);
|
try {
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
for (int y = 0; y < 16; y++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
BlockState blockState = container.get(x, y, z);
|
||||||
|
if (blockState == emptyState) continue;
|
||||||
|
|
||||||
LevelChunkSection section = chunk.getSection(world.getSectionIndexFromSectionY(cy));
|
int bx = cx*16 + x;
|
||||||
PalettedContainer<BlockState> sectionStates = section.getStates();
|
int by = cy*16 + y;
|
||||||
boolean hasOnlyAir = section.hasOnlyAir();
|
int bz = cz*16 + z;
|
||||||
|
|
||||||
Heightmap worldSurface = null;
|
blockPos.set(bx, by, bz);
|
||||||
Heightmap oceanFloor = null;
|
|
||||||
Heightmap motionBlocking = null;
|
|
||||||
Heightmap motionBlockingNoLeaves = null;
|
|
||||||
for (Map.Entry<Heightmap.Types, Heightmap> heightmap : chunk.getHeightmaps()) {
|
|
||||||
switch (heightmap.getKey()) {
|
|
||||||
case WORLD_SURFACE -> worldSurface = heightmap.getValue();
|
|
||||||
case OCEAN_FLOOR -> oceanFloor = heightmap.getValue();
|
|
||||||
case MOTION_BLOCKING -> motionBlocking = heightmap.getValue();
|
|
||||||
case MOTION_BLOCKING_NO_LEAVES -> motionBlockingNoLeaves = heightmap.getValue();
|
|
||||||
default -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Short2ObjectMap<CompressedBlockEntity> blockEntityChunkMap = buffer.getBlockEntityChunkMap(entry.getLongKey());
|
if (hasOnlyAir && blockState.isAir()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
sectionStates.acquire();
|
BlockState old = section.setBlockState(x, y, z, blockState, false);
|
||||||
try {
|
if (blockState != old) {
|
||||||
for (int x = 0; x < 16; x++) {
|
Block block = blockState.getBlock();
|
||||||
for (int y = 0; y < 16; y++) {
|
motionBlocking.update(x, by, z, blockState);
|
||||||
for (int z = 0; z < 16; z++) {
|
motionBlockingNoLeaves.update(x, by, z, blockState);
|
||||||
BlockState blockState = container.get(x, y, z);
|
oceanFloor.update(x, by, z, blockState);
|
||||||
if (blockState == emptyState) continue;
|
worldSurface.update(x, by, z, blockState);
|
||||||
|
|
||||||
int bx = cx*16 + x;
|
if (false) { // Full update
|
||||||
int by = cy*16 + y;
|
old.onRemove(world, blockPos, blockState, false);
|
||||||
int bz = cz*16 + z;
|
|
||||||
|
|
||||||
blockPos.set(bx, by, bz);
|
if (sectionStates.get(x, y, z).is(block)) {
|
||||||
|
blockState.onPlace(world, blockPos, old, false);
|
||||||
if (hasOnlyAir && blockState.isAir()) {
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockState old = section.setBlockState(x, y, z, blockState, false);
|
if (blockState.hasBlockEntity()) {
|
||||||
if (blockState != old) {
|
BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK);
|
||||||
Block block = blockState.getBlock();
|
|
||||||
motionBlocking.update(x, by, z, blockState);
|
|
||||||
motionBlockingNoLeaves.update(x, by, z, blockState);
|
|
||||||
oceanFloor.update(x, by, z, blockState);
|
|
||||||
worldSurface.update(x, by, z, blockState);
|
|
||||||
|
|
||||||
if (false) { // Full update
|
if (blockEntity == null) {
|
||||||
old.onRemove(world, blockPos, blockState, false);
|
// There isn't a block entity here, create it!
|
||||||
|
blockEntity = ((EntityBlock)block).newBlockEntity(blockPos, blockState);
|
||||||
if (sectionStates.get(x, y, z).is(block)) {
|
if (blockEntity != null) {
|
||||||
blockState.onPlace(world, blockPos, old, false);
|
chunk.addAndRegisterBlockEntity(blockEntity);
|
||||||
}
|
}
|
||||||
}
|
} else if (blockEntity.getType().isValid(blockState)) {
|
||||||
|
// Block entity is here and the type is correct
|
||||||
|
blockEntity.setBlockState(blockState);
|
||||||
|
|
||||||
if (blockState.hasBlockEntity()) {
|
try {
|
||||||
BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK);
|
this.updateBlockEntityTicker.invoke(chunk, blockEntity);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
if (blockEntity == null) {
|
throw new RuntimeException(e);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (blockEntity != null && blockEntityChunkMap != null) {
|
} else {
|
||||||
int key = x | (y << 4) | (z << 8);
|
// Block entity type isn't correct, we need to recreate it
|
||||||
CompressedBlockEntity savedBlockEntity = blockEntityChunkMap.get((short) key);
|
|
||||||
if (savedBlockEntity != null) {
|
|
||||||
blockEntity.load(savedBlockEntity.decompress());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (old.hasBlockEntity()) {
|
|
||||||
chunk.removeBlockEntity(blockPos);
|
chunk.removeBlockEntity(blockPos);
|
||||||
}
|
|
||||||
|
|
||||||
world.getChunkSource().blockChanged(blockPos); // todo: maybe simply resend chunk instead of this?
|
blockEntity = ((EntityBlock)block).newBlockEntity(blockPos, blockState);
|
||||||
|
if (blockEntity != null) {
|
||||||
if (LightEngine.hasDifferentLightProperties(chunk, blockPos, old, blockState)) {
|
chunk.addAndRegisterBlockEntity(blockEntity);
|
||||||
lightEngine.checkBlock(blockPos);
|
}
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
world.getChunkSource().blockChanged(blockPos); // todo: maybe simply resend chunk instead of this?
|
||||||
|
|
||||||
|
if (LightEngine.hasDifferentLightProperties(chunk, blockPos, old, blockState)) {
|
||||||
|
lightEngine.checkBlock(blockPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
sectionStates.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean nowHasOnlyAir = section.hasOnlyAir();
|
|
||||||
if (hasOnlyAir != nowHasOnlyAir) {
|
|
||||||
world.getChunkSource().getLightEngine().updateSectionStatus(SectionPos.of(cx, cy, cz), nowHasOnlyAir);
|
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
sectionStates.release();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
boolean nowHasOnlyAir = section.hasOnlyAir();
|
||||||
|
if (hasOnlyAir != nowHasOnlyAir) {
|
||||||
|
world.getChunkSource().getLightEngine().updateSectionStatus(SectionPos.of(cx, cy, cz), nowHasOnlyAir);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void applyBiomeBuffer(MinecraftServer server, BiomeBuffer biomeBuffer, ResourceKey<Level> worldKey) {
|
private void applyBiomeBuffer(MinecraftServer server, BiomeBuffer biomeBuffer, ResourceKey<Level> worldKey) {
|
||||||
server.execute(() -> {
|
ServerLevel world = server.getLevel(worldKey);
|
||||||
ServerLevel world = server.getLevel(worldKey);
|
if (world == null) return;
|
||||||
if (world == null) return;
|
|
||||||
|
|
||||||
Set<LevelChunk> changedChunks = new HashSet<>();
|
Set<LevelChunk> changedChunks = new HashSet<>();
|
||||||
|
|
||||||
int minSection = world.getMinSection();
|
int minSection = world.getMinSection();
|
||||||
int maxSection = world.getMaxSection();
|
int maxSection = world.getMaxSection();
|
||||||
|
|
||||||
Optional<Registry<Biome>> registryOptional = world.registryAccess().registry(Registries.BIOME);
|
Optional<Registry<Biome>> registryOptional = world.registryAccess().registry(Registries.BIOME);
|
||||||
if (registryOptional.isEmpty()) return;
|
if (registryOptional.isEmpty()) return;
|
||||||
|
|
||||||
Registry<Biome> registry = registryOptional.get();
|
Registry<Biome> registry = registryOptional.get();
|
||||||
|
|
||||||
biomeBuffer.forEachEntry((x, y, z, biome) -> {
|
biomeBuffer.forEachEntry((x, y, z, biome) -> {
|
||||||
int cy = y >> 2;
|
int cy = y >> 2;
|
||||||
if (cy < minSection || cy >= maxSection) {
|
if (cy < minSection || cy >= maxSection) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var chunk = (LevelChunk) world.getChunk(x >> 2, z >> 2, ChunkStatus.FULL, false);
|
var chunk = (LevelChunk) world.getChunk(x >> 2, z >> 2, ChunkStatus.FULL, false);
|
||||||
if (chunk == null) return;
|
if (chunk == null) return;
|
||||||
|
|
||||||
var section = chunk.getSection(cy - minSection);
|
var section = chunk.getSection(cy - minSection);
|
||||||
PalettedContainer<Holder<Biome>> container = (PalettedContainer<Holder<Biome>>) section.getBiomes();
|
PalettedContainer<Holder<Biome>> container = (PalettedContainer<Holder<Biome>>) section.getBiomes();
|
||||||
|
|
||||||
var holder = registry.getHolder(biome);
|
var holder = registry.getHolder(biome);
|
||||||
if (holder.isPresent()) {
|
if (holder.isPresent()) {
|
||||||
container.set(x & 3, y & 3, z & 3, holder.get());
|
container.set(x & 3, y & 3, z & 3, holder.get());
|
||||||
changedChunks.add(chunk);
|
changedChunks.add(chunk);
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var chunkMap = world.getChunkSource().chunkMap;
|
|
||||||
HashMap<ServerPlayer, List<LevelChunk>> map = new HashMap<>();
|
|
||||||
for (LevelChunk chunk : changedChunks) {
|
|
||||||
chunk.setUnsaved(true);
|
|
||||||
ChunkPos chunkPos = chunk.getPos();
|
|
||||||
for (ServerPlayer serverPlayer2 : chunkMap.getPlayers(chunkPos, false)) {
|
|
||||||
map.computeIfAbsent(serverPlayer2, serverPlayer -> new ArrayList<>()).add(chunk);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
map.forEach((serverPlayer, list) -> serverPlayer.connection.send(ClientboundChunksBiomesPacket.forChunks(list)));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var chunkMap = world.getChunkSource().chunkMap;
|
||||||
|
HashMap<ServerPlayer, List<LevelChunk>> map = new HashMap<>();
|
||||||
|
for (LevelChunk chunk : changedChunks) {
|
||||||
|
chunk.setUnsaved(true);
|
||||||
|
ChunkPos chunkPos = chunk.getPos();
|
||||||
|
for (ServerPlayer serverPlayer2 : chunkMap.getPlayers(chunkPos, false)) {
|
||||||
|
map.computeIfAbsent(serverPlayer2, serverPlayer -> new ArrayList<>()).add(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
map.forEach((serverPlayer, list) -> serverPlayer.connection.send(ClientboundChunksBiomesPacket.forChunks(list)));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
import com.moulberry.axiom.AxiomPaper;
|
|
||||||
import com.moulberry.axiom.event.AxiomModifyWorldEvent;
|
import com.moulberry.axiom.event.AxiomModifyWorldEvent;
|
||||||
import io.netty.buffer.Unpooled;
|
import com.moulberry.axiom.integration.VersionTranslator;
|
||||||
|
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.network.FriendlyByteBuf;
|
||||||
@ -19,23 +19,18 @@ import net.minecraft.world.level.lighting.LightEngine;
|
|||||||
import org.bukkit.Bukkit;
|
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.bukkit.plugin.messaging.PluginMessageListener;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import xyz.jpenilla.reflectionremapper.ReflectionRemapper;
|
import xyz.jpenilla.reflectionremapper.ReflectionRemapper;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
public class SetBlockPacketListener implements PluginMessageListener {
|
public class SetBlockPacketListener implements AxiomPacketListener {
|
||||||
|
|
||||||
private final AxiomPaper plugin;
|
|
||||||
private final Method updateBlockEntityTicker;
|
private final Method updateBlockEntityTicker;
|
||||||
|
|
||||||
public SetBlockPacketListener(AxiomPaper plugin) {
|
public SetBlockPacketListener() {
|
||||||
this.plugin = plugin;
|
|
||||||
|
|
||||||
ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar();
|
ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar();
|
||||||
String methodName = reflectionRemapper.remapMethodName(LevelChunk.class, "updateBlockEntityTicker", BlockEntity.class);
|
String methodName = reflectionRemapper.remapMethodName(LevelChunk.class, "updateBlockEntityTicker", BlockEntity.class);
|
||||||
|
|
||||||
@ -49,20 +44,16 @@ public class SetBlockPacketListener implements PluginMessageListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player bukkitPlayer, @NotNull byte[] message) {
|
public void onMessage(@NotNull Player bukkitPlayer, @NotNull ByteBuf buf) {
|
||||||
if (!bukkitPlayer.hasPermission("axiom.*")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if player is allowed to modify this world
|
// Check if player is allowed to modify this world
|
||||||
AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(bukkitPlayer, bukkitPlayer.getWorld());
|
AxiomModifyWorldEvent modifyWorldEvent = new AxiomModifyWorldEvent(bukkitPlayer, bukkitPlayer.getWorld());
|
||||||
Bukkit.getPluginManager().callEvent(modifyWorldEvent);
|
Bukkit.getPluginManager().callEvent(modifyWorldEvent);
|
||||||
if (modifyWorldEvent.isCancelled()) return;
|
if (modifyWorldEvent.isCancelled()) return;
|
||||||
|
|
||||||
// Read packet
|
// Read packet
|
||||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
|
||||||
BlockPos blockPos = friendlyByteBuf.readBlockPos();
|
BlockPos blockPos = friendlyByteBuf.readBlockPos();
|
||||||
BlockState blockState = friendlyByteBuf.readById(Block.BLOCK_STATE_REGISTRY);
|
BlockState blockState = Block.BLOCK_STATE_REGISTRY.byId(VersionTranslator.impl.blockStateMapper(bukkitPlayer).apply(friendlyByteBuf.readVarInt()));
|
||||||
boolean updateNeighbors = friendlyByteBuf.readBoolean();
|
boolean updateNeighbors = friendlyByteBuf.readBoolean();
|
||||||
int sequenceId = friendlyByteBuf.readInt();
|
int sequenceId = friendlyByteBuf.readInt();
|
||||||
|
|
||||||
|
@ -3,26 +3,21 @@ package com.moulberry.axiom.packet;
|
|||||||
import com.moulberry.axiom.AxiomConstants;
|
import com.moulberry.axiom.AxiomConstants;
|
||||||
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.Unpooled;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
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;
|
||||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class SetEditorViewsPacketListener implements PluginMessageListener {
|
public class SetEditorViewsPacketListener implements AxiomPacketListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
|
public void onMessage(@NotNull Player player, @NotNull ByteBuf buf) {
|
||||||
if (!player.hasPermission("axiom.*")) {
|
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
|
||||||
UUID uuid = friendlyByteBuf.readUUID();
|
UUID uuid = friendlyByteBuf.readUUID();
|
||||||
List<View> views = friendlyByteBuf.readList(View::read);
|
List<View> views = friendlyByteBuf.readList(View::read);
|
||||||
|
|
||||||
|
@ -1,28 +1,17 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
import com.moulberry.axiom.event.AxiomFlySpeedChangeEvent;
|
import com.moulberry.axiom.event.AxiomFlySpeedChangeEvent;
|
||||||
import com.moulberry.axiom.event.AxiomGameModeChangeEvent;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraft.world.level.GameType;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.GameMode;
|
|
||||||
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.bukkit.plugin.messaging.PluginMessageListener;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class SetFlySpeedPacketListener implements PluginMessageListener {
|
public class SetFlySpeedPacketListener implements AxiomPacketListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
|
public void onMessage(@NotNull Player player, @NotNull ByteBuf buf) {
|
||||||
if (!player.hasPermission("axiom.*")) {
|
float flySpeed = buf.readFloat();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
|
||||||
float flySpeed = friendlyByteBuf.readFloat();
|
|
||||||
|
|
||||||
// Call event
|
// Call event
|
||||||
AxiomFlySpeedChangeEvent flySpeedChangeEvent = new AxiomFlySpeedChangeEvent(player, flySpeed);
|
AxiomFlySpeedChangeEvent flySpeedChangeEvent = new AxiomFlySpeedChangeEvent(player, flySpeed);
|
||||||
|
@ -1,34 +1,26 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
import com.moulberry.axiom.event.AxiomGameModeChangeEvent;
|
import com.moulberry.axiom.event.AxiomGameModeChangeEvent;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraft.world.level.GameType;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public class SetGamemodePacketListener implements PluginMessageListener {
|
public class SetGamemodePacketListener implements AxiomPacketListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
|
public void onMessage(Player player, ByteBuf buf) {
|
||||||
if (!player.hasPermission("axiom.*")) {
|
@SuppressWarnings("deprecation")
|
||||||
return;
|
GameMode gameMode = GameMode.getByValue(buf.readByte());
|
||||||
}
|
assert gameMode != null;
|
||||||
|
|
||||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
|
||||||
GameType gameType = GameType.byId(friendlyByteBuf.readByte());
|
|
||||||
|
|
||||||
// Call event
|
// Call event
|
||||||
AxiomGameModeChangeEvent gameModeChangeEvent = new AxiomGameModeChangeEvent(player, GameMode.getByValue(gameType.getId()));
|
AxiomGameModeChangeEvent gameModeChangeEvent = new AxiomGameModeChangeEvent(player, gameMode);
|
||||||
Bukkit.getPluginManager().callEvent(gameModeChangeEvent);
|
Bukkit.getPluginManager().callEvent(gameModeChangeEvent);
|
||||||
if (gameModeChangeEvent.isCancelled()) return;
|
if (gameModeChangeEvent.isCancelled()) return;
|
||||||
|
|
||||||
// Change gamemode
|
// Change gamemode
|
||||||
((CraftPlayer)player).getHandle().setGameMode(gameType);
|
player.setGameMode(gameMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,26 +2,20 @@ package com.moulberry.axiom.packet;
|
|||||||
|
|
||||||
import com.moulberry.axiom.AxiomConstants;
|
import com.moulberry.axiom.AxiomConstants;
|
||||||
import com.moulberry.axiom.persistence.ItemStackDataType;
|
import com.moulberry.axiom.persistence.ItemStackDataType;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import org.bukkit.NamespacedKey;
|
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.craftbukkit.v1_20_R1.inventory.CraftItemStack;
|
||||||
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;
|
||||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class SetHotbarSlotPacketListener implements PluginMessageListener {
|
public class SetHotbarSlotPacketListener implements AxiomPacketListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
|
public void onMessage(@NotNull Player player, @NotNull ByteBuf buf) {
|
||||||
if (!player.hasPermission("axiom.*")) {
|
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
|
||||||
int index = friendlyByteBuf.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();
|
net.minecraft.world.item.ItemStack nmsStack = friendlyByteBuf.readItem();
|
||||||
|
@ -2,7 +2,7 @@ package com.moulberry.axiom.packet;
|
|||||||
|
|
||||||
import com.moulberry.axiom.AxiomConstants;
|
import com.moulberry.axiom.AxiomConstants;
|
||||||
import com.moulberry.axiom.persistence.ItemStackDataType;
|
import com.moulberry.axiom.persistence.ItemStackDataType;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
@ -12,18 +12,13 @@ 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;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class SwitchActiveHotbarPacketListener implements PluginMessageListener {
|
public class SwitchActiveHotbarPacketListener implements AxiomPacketListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
|
public void onMessage(@NotNull Player player, @NotNull ByteBuf buf) {
|
||||||
if (!player.hasPermission("axiom.*")) {
|
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
|
||||||
int oldHotbarIndex = friendlyByteBuf.readByte();
|
int oldHotbarIndex = friendlyByteBuf.readByte();
|
||||||
int activeHotbarIndex = friendlyByteBuf.readByte();
|
int activeHotbarIndex = friendlyByteBuf.readByte();
|
||||||
|
|
||||||
|
@ -1,26 +1,23 @@
|
|||||||
package com.moulberry.axiom.packet;
|
package com.moulberry.axiom.packet;
|
||||||
|
|
||||||
import com.moulberry.axiom.event.AxiomGameModeChangeEvent;
|
|
||||||
import com.moulberry.axiom.event.AxiomTeleportEvent;
|
import com.moulberry.axiom.event.AxiomTeleportEvent;
|
||||||
import io.netty.buffer.Unpooled;
|
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;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import org.bukkit.*;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class TeleportPacketListener implements PluginMessageListener {
|
public class TeleportPacketListener implements AxiomPacketListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
|
public void onMessage(@NotNull Player player, @NotNull ByteBuf buf) {
|
||||||
if (!player.hasPermission("axiom.*")) {
|
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(buf);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
|
||||||
ResourceKey<Level> resourceKey = friendlyByteBuf.readResourceKey(Registries.DIMENSION);
|
ResourceKey<Level> resourceKey = friendlyByteBuf.readResourceKey(Registries.DIMENSION);
|
||||||
double x = friendlyByteBuf.readDouble();
|
double x = friendlyByteBuf.readDouble();
|
||||||
double y = friendlyByteBuf.readDouble();
|
double y = friendlyByteBuf.readDouble();
|
||||||
|
@ -2,8 +2,12 @@ name: $name
|
|||||||
version: $version
|
version: $version
|
||||||
main: com.moulberry.axiom.AxiomPaper
|
main: com.moulberry.axiom.AxiomPaper
|
||||||
description: $description
|
description: $description
|
||||||
|
softdepend:
|
||||||
|
- ViaVersion
|
||||||
|
- WorldGuard
|
||||||
authors:
|
authors:
|
||||||
- Moulberry
|
- Moulberry
|
||||||
|
- Lixfel
|
||||||
api-version: "$apiVersion"
|
api-version: "$apiVersion"
|
||||||
permissions:
|
permissions:
|
||||||
axiom.*:
|
axiom.*:
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren