Mirror von
https://github.com/Moulberry/AxiomPaperPlugin.git
synchronisiert 2024-11-17 05:40:06 +01:00
Support 4.2.0 changes
Dieser Commit ist enthalten in:
Ursprung
3ac78c2093
Commit
aadace89de
@ -4,7 +4,7 @@ bom-newest = "1.37"
|
|||||||
cloud-paper = "2.0.0-20240516.054251-69"
|
cloud-paper = "2.0.0-20240516.054251-69"
|
||||||
coreprotect = "22.4"
|
coreprotect = "22.4"
|
||||||
paper = "1.20.4-R0.1-SNAPSHOT"
|
paper = "1.20.4-R0.1-SNAPSHOT"
|
||||||
plotsquared = "7.3.9-20240513.192211-13"
|
plotsquared = "7.3.8"
|
||||||
reflection-remapper = "0.1.2-20240315.033304-2"
|
reflection-remapper = "0.1.2-20240315.033304-2"
|
||||||
viaversion-api = "5.0.1"
|
viaversion-api = "5.0.1"
|
||||||
worldguard-bukkit = "7.0.9-SNAPSHOT"
|
worldguard-bukkit = "7.0.9-SNAPSHOT"
|
||||||
|
@ -9,25 +9,7 @@ import com.moulberry.axiom.event.AxiomModifyWorldEvent;
|
|||||||
import com.moulberry.axiom.integration.coreprotect.CoreProtectIntegration;
|
import com.moulberry.axiom.integration.coreprotect.CoreProtectIntegration;
|
||||||
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
|
import com.moulberry.axiom.integration.plotsquared.PlotSquaredIntegration;
|
||||||
import com.moulberry.axiom.packet.*;
|
import com.moulberry.axiom.packet.*;
|
||||||
import com.moulberry.axiom.packet.impl.BlueprintRequestPacketListener;
|
import com.moulberry.axiom.packet.impl.*;
|
||||||
import com.moulberry.axiom.packet.impl.DeleteEntityPacketListener;
|
|
||||||
import com.moulberry.axiom.packet.impl.HelloPacketListener;
|
|
||||||
import com.moulberry.axiom.packet.impl.ManipulateEntityPacketListener;
|
|
||||||
import com.moulberry.axiom.packet.impl.MarkerNbtRequestPacketListener;
|
|
||||||
import com.moulberry.axiom.packet.impl.RequestChunkDataPacketListener;
|
|
||||||
import com.moulberry.axiom.packet.impl.SetBlockBufferPacketListener;
|
|
||||||
import com.moulberry.axiom.packet.impl.SetBlockPacketListener;
|
|
||||||
import com.moulberry.axiom.packet.impl.SetEditorViewsPacketListener;
|
|
||||||
import com.moulberry.axiom.packet.impl.SetFlySpeedPacketListener;
|
|
||||||
import com.moulberry.axiom.packet.impl.SetGamemodePacketListener;
|
|
||||||
import com.moulberry.axiom.packet.impl.SetHotbarSlotPacketListener;
|
|
||||||
import com.moulberry.axiom.packet.impl.SetTimePacketListener;
|
|
||||||
import com.moulberry.axiom.packet.impl.SetWorldPropertyListener;
|
|
||||||
import com.moulberry.axiom.packet.impl.SpawnEntityPacketListener;
|
|
||||||
import com.moulberry.axiom.packet.impl.SwitchActiveHotbarPacketListener;
|
|
||||||
import com.moulberry.axiom.packet.impl.TeleportPacketListener;
|
|
||||||
import com.moulberry.axiom.packet.impl.UpdateAnnotationPacketListener;
|
|
||||||
import com.moulberry.axiom.packet.impl.UploadBlueprintPacketListener;
|
|
||||||
import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry;
|
import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
@ -46,6 +28,7 @@ import net.minecraft.network.protocol.Packet;
|
|||||||
import net.minecraft.network.protocol.PacketFlow;
|
import net.minecraft.network.protocol.PacketFlow;
|
||||||
import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket;
|
import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
@ -68,6 +51,7 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.IntFunction;
|
||||||
|
|
||||||
public class AxiomPaper extends JavaPlugin implements Listener {
|
public class AxiomPaper extends JavaPlugin implements Listener {
|
||||||
|
|
||||||
@ -82,6 +66,9 @@ public class AxiomPaper extends JavaPlugin implements Listener {
|
|||||||
|
|
||||||
public IdMapper<BlockState> allowedBlockRegistry = null;
|
public IdMapper<BlockState> allowedBlockRegistry = null;
|
||||||
private boolean logLargeBlockBufferChanges = false;
|
private boolean logLargeBlockBufferChanges = false;
|
||||||
|
private int packetCollectionReadLimit = 1024;
|
||||||
|
private Set<EntityType<?>> whitelistedEntities = new HashSet<>();
|
||||||
|
private Set<EntityType<?>> blacklistedEntities = new HashSet<>();
|
||||||
|
|
||||||
public Path blueprintFolder = null;
|
public Path blueprintFolder = null;
|
||||||
public boolean allowAnnotations = false;
|
public boolean allowAnnotations = false;
|
||||||
@ -101,9 +88,21 @@ public class AxiomPaper extends JavaPlugin implements Listener {
|
|||||||
this.getLogger().warning("Invalid value for unsupported-axiom-version, expected 'kick', 'warn' or 'ignore'");
|
this.getLogger().warning("Invalid value for unsupported-axiom-version, expected 'kick', 'warn' or 'ignore'");
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean allowLargeChunkDataRequest = this.configuration.getBoolean("allow-large-chunk-data-request");
|
|
||||||
this.logLargeBlockBufferChanges = this.configuration.getBoolean("log-large-block-buffer-changes");
|
this.logLargeBlockBufferChanges = this.configuration.getBoolean("log-large-block-buffer-changes");
|
||||||
|
|
||||||
|
if (this.configuration.getBoolean("allow-large-payload-for-all-packets")) {
|
||||||
|
packetCollectionReadLimit = Short.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.whitelistedEntities.clear();
|
||||||
|
this.blacklistedEntities.clear();
|
||||||
|
for (String whitelistedEntity : this.configuration.getStringList("whitelist-entities")) {
|
||||||
|
EntityType.byString(whitelistedEntity).ifPresent(this.whitelistedEntities::add);
|
||||||
|
}
|
||||||
|
for (String blacklistedEntity : this.configuration.getStringList("blacklist-entities")) {
|
||||||
|
EntityType.byString(blacklistedEntity).ifPresent(this.blacklistedEntities::add);
|
||||||
|
}
|
||||||
|
|
||||||
List<String> disallowedBlocks = this.configuration.getStringList("disallowed-blocks");
|
List<String> disallowedBlocks = this.configuration.getStringList("disallowed-blocks");
|
||||||
this.allowedBlockRegistry = DisallowedBlocks.createAllowedBlockRegistry(disallowedBlocks);
|
this.allowedBlockRegistry = DisallowedBlocks.createAllowedBlockRegistry(disallowedBlocks);
|
||||||
|
|
||||||
@ -132,27 +131,29 @@ public class AxiomPaper extends JavaPlugin implements Listener {
|
|||||||
|
|
||||||
Map<String, PacketHandler> largePayloadHandlers = new HashMap<>();
|
Map<String, PacketHandler> largePayloadHandlers = new HashMap<>();
|
||||||
|
|
||||||
registerPacketHandler("hello", new HelloPacketListener(this), msg, largePayloadHandlers);
|
registerPacketHandler("hello", new HelloPacketListener(this), msg, LargePayloadBehaviour.FORCE_SMALL, largePayloadHandlers);
|
||||||
registerPacketHandler("set_gamemode", new SetGamemodePacketListener(this), msg, largePayloadHandlers);
|
registerPacketHandler("set_gamemode", new SetGamemodePacketListener(this), msg, LargePayloadBehaviour.DEFAULT, largePayloadHandlers);
|
||||||
registerPacketHandler("set_fly_speed", new SetFlySpeedPacketListener(this), msg, largePayloadHandlers);
|
registerPacketHandler("set_fly_speed", new SetFlySpeedPacketListener(this), msg, LargePayloadBehaviour.DEFAULT, largePayloadHandlers);
|
||||||
registerPacketHandler("set_world_time", new SetTimePacketListener(this), msg, largePayloadHandlers);
|
registerPacketHandler("set_world_time", new SetTimePacketListener(this), msg, LargePayloadBehaviour.DEFAULT, largePayloadHandlers);
|
||||||
registerPacketHandler("set_world_property", new SetWorldPropertyListener(this), msg, largePayloadHandlers);
|
registerPacketHandler("set_world_property", new SetWorldPropertyListener(this), msg, LargePayloadBehaviour.DEFAULT, largePayloadHandlers);
|
||||||
registerPacketHandler("set_block", new SetBlockPacketListener(this), msg, largePayloadHandlers); // set-single-block
|
registerPacketHandler("set_block", new SetBlockPacketListener(this), msg, LargePayloadBehaviour.DEFAULT, largePayloadHandlers); // set-single-block
|
||||||
registerPacketHandler("set_hotbar_slot", new SetHotbarSlotPacketListener(this), msg, largePayloadHandlers);
|
registerPacketHandler("set_hotbar_slot", new SetHotbarSlotPacketListener(this), msg, LargePayloadBehaviour.DEFAULT, largePayloadHandlers);
|
||||||
registerPacketHandler("switch_active_hotbar", new SwitchActiveHotbarPacketListener(this), msg, largePayloadHandlers);
|
registerPacketHandler("switch_active_hotbar", new SwitchActiveHotbarPacketListener(this), msg, LargePayloadBehaviour.DEFAULT, largePayloadHandlers);
|
||||||
registerPacketHandler("teleport", new TeleportPacketListener(this), msg, largePayloadHandlers);
|
registerPacketHandler("teleport", new TeleportPacketListener(this), msg, LargePayloadBehaviour.DEFAULT, largePayloadHandlers);
|
||||||
registerPacketHandler("set_editor_views", new SetEditorViewsPacketListener(this), msg, largePayloadHandlers);
|
registerPacketHandler("set_editor_views", new SetEditorViewsPacketListener(this), msg, LargePayloadBehaviour.DEFAULT, largePayloadHandlers);
|
||||||
registerPacketHandler("request_chunk_data", new RequestChunkDataPacketListener(this,
|
registerPacketHandler("request_chunk_data", new RequestChunkDataPacketListener(this, !configuration.getBoolean("packet-handlers.request-chunk-data")), msg,
|
||||||
!configuration.getBoolean("packet-handlers.request-chunk-data")), msg, largePayloadHandlers);
|
this.configuration.getBoolean("allow-large-chunk-data-request") ? LargePayloadBehaviour.FORCE_LARGE : LargePayloadBehaviour.DEFAULT, largePayloadHandlers);
|
||||||
registerPacketHandler("spawn_entity", new SpawnEntityPacketListener(this), msg, largePayloadHandlers);
|
registerPacketHandler("request_entity_data", new RequestEntityDataPacketListener(this, !configuration.getBoolean("packet-handlers.request-entity-data")), msg,
|
||||||
registerPacketHandler("manipulate_entity", new ManipulateEntityPacketListener(this), msg, largePayloadHandlers);
|
this.configuration.getBoolean("allow-large-chunk-data-request") ? LargePayloadBehaviour.FORCE_LARGE : LargePayloadBehaviour.DEFAULT, largePayloadHandlers);
|
||||||
registerPacketHandler("delete_entity", new DeleteEntityPacketListener(this), msg, largePayloadHandlers);
|
registerPacketHandler("spawn_entity", new SpawnEntityPacketListener(this), msg, LargePayloadBehaviour.DEFAULT, largePayloadHandlers);
|
||||||
registerPacketHandler("marker_nbt_request", new MarkerNbtRequestPacketListener(this), msg, largePayloadHandlers);
|
registerPacketHandler("manipulate_entity", new ManipulateEntityPacketListener(this), msg, LargePayloadBehaviour.DEFAULT, largePayloadHandlers);
|
||||||
registerPacketHandler("request_blueprint", new BlueprintRequestPacketListener(this), msg, largePayloadHandlers);
|
registerPacketHandler("delete_entity", new DeleteEntityPacketListener(this), msg, LargePayloadBehaviour.DEFAULT, largePayloadHandlers);
|
||||||
|
registerPacketHandler("marker_nbt_request", new MarkerNbtRequestPacketListener(this), msg, LargePayloadBehaviour.DEFAULT, largePayloadHandlers);
|
||||||
|
registerPacketHandler("request_blueprint", new BlueprintRequestPacketListener(this), msg, LargePayloadBehaviour.DEFAULT, largePayloadHandlers);
|
||||||
|
|
||||||
registerPacketHandler("set_buffer", new SetBlockBufferPacketListener(this), msg, largePayloadHandlers);
|
registerPacketHandler("set_buffer", new SetBlockBufferPacketListener(this), msg, LargePayloadBehaviour.FORCE_LARGE, largePayloadHandlers);
|
||||||
registerPacketHandler("upload_blueprint", new UploadBlueprintPacketListener(this), msg, largePayloadHandlers);
|
registerPacketHandler("upload_blueprint", new UploadBlueprintPacketListener(this), msg, LargePayloadBehaviour.FORCE_LARGE, largePayloadHandlers);
|
||||||
registerPacketHandler("annotation_update", new UpdateAnnotationPacketListener(this), msg, largePayloadHandlers);
|
registerPacketHandler("annotation_update", new UpdateAnnotationPacketListener(this), msg, LargePayloadBehaviour.FORCE_LARGE, largePayloadHandlers);
|
||||||
|
|
||||||
if (!largePayloadHandlers.isEmpty()) {
|
if (!largePayloadHandlers.isEmpty()) {
|
||||||
ChannelInitializeListenerHolder.addListener(Key.key("axiom:handle_big_payload"), new ChannelInitializeListener() {
|
ChannelInitializeListenerHolder.addListener(Key.key("axiom:handle_big_payload"), new ChannelInitializeListener() {
|
||||||
@ -302,25 +303,26 @@ public class AxiomPaper extends JavaPlugin implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerPacketHandler(String name, PacketHandler handler, Messenger messenger, Map<String, PacketHandler> largePayloadHandlers) {
|
private enum LargePayloadBehaviour {
|
||||||
|
DEFAULT,
|
||||||
|
FORCE_LARGE,
|
||||||
|
FORCE_SMALL
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerPacketHandler(String name, PacketHandler handler, Messenger messenger, LargePayloadBehaviour behaviour,
|
||||||
|
Map<String, PacketHandler> largePayloadHandlers) {
|
||||||
String configEntry = "packet-handlers." + name.replace("_", "-");
|
String configEntry = "packet-handlers." + name.replace("_", "-");
|
||||||
if (name.equals("set_block")) {
|
if (name.equals("set_block")) {
|
||||||
configEntry = "packet-handlers.set-single-block";
|
configEntry = "packet-handlers.set-single-block";
|
||||||
} else if (name.equals("request_blueprint")) {
|
} else if (name.equals("request_blueprint")) {
|
||||||
configEntry = "packet-handlers.blueprint-request";
|
configEntry = "packet-handlers.blueprint-request";
|
||||||
}
|
}
|
||||||
if (name.equals("request-chunk-data") || this.configuration.getBoolean(configEntry, true)) {
|
if (name.equals("request_chunk_data") || name.equals("request_entity_data") || this.configuration.getBoolean(configEntry, true)) {
|
||||||
boolean isLargePayload = false;
|
boolean isLargePayload = switch (behaviour) {
|
||||||
|
case DEFAULT -> this.configuration.getBoolean("allow-large-payload-for-all-packets");
|
||||||
if (name.equals("hello")) { // Hello must use normal system, as non-Axiom players can't send large payloads
|
case FORCE_LARGE -> true;
|
||||||
isLargePayload = false;
|
case FORCE_SMALL -> false;
|
||||||
} else if (this.configuration.getBoolean("allow-large-payload-for-all-packets")) {
|
};
|
||||||
isLargePayload = true;
|
|
||||||
} else if (name.equals("set_buffer") || name.equals("upload_blueprint") || name.equals("annotation_update")) {
|
|
||||||
isLargePayload = true;
|
|
||||||
} else if (name.equals("request_chunk_data") && this.configuration.getBoolean("allow-large-chunk-data-request")) {
|
|
||||||
isLargePayload = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLargePayload) {
|
if (isLargePayload) {
|
||||||
largePayloadHandlers.put("axiom:"+name, handler);
|
largePayloadHandlers.put("axiom:"+name, handler);
|
||||||
@ -350,6 +352,10 @@ public class AxiomPaper extends JavaPlugin implements Listener {
|
|||||||
return allowedCapabilities;
|
return allowedCapabilities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <T> IntFunction<T> limitCollection(IntFunction<T> applier) {
|
||||||
|
return FriendlyByteBuf.limitValue(applier, this.packetCollectionReadLimit);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean logLargeBlockBufferChanges() {
|
public boolean logLargeBlockBufferChanges() {
|
||||||
return this.logLargeBlockBufferChanges;
|
return this.logLargeBlockBufferChanges;
|
||||||
}
|
}
|
||||||
@ -379,6 +385,19 @@ public class AxiomPaper extends JavaPlugin implements Listener {
|
|||||||
return activeAxiomPlayers.contains(player.getUniqueId()) && hasAxiomPermission(player, permission, strict);
|
return activeAxiomPlayers.contains(player.getUniqueId()) && hasAxiomPermission(player, permission, strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canEntityBeManipulated(EntityType<?> entityType) {
|
||||||
|
if (entityType == EntityType.PLAYER) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!this.whitelistedEntities.isEmpty() && !this.whitelistedEntities.contains(entityType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.blacklistedEntities.contains(entityType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public @Nullable RateLimiter getBlockBufferRateLimiter(UUID uuid) {
|
public @Nullable RateLimiter getBlockBufferRateLimiter(UUID uuid) {
|
||||||
return this.playerBlockBufferRateLimiters.get(uuid);
|
return this.playerBlockBufferRateLimiters.get(uuid);
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,15 @@ public class NbtSanitization {
|
|||||||
"Glowing",
|
"Glowing",
|
||||||
"Tags",
|
"Tags",
|
||||||
"Passengers",
|
"Passengers",
|
||||||
|
// armor stand
|
||||||
|
"ArmorItems",
|
||||||
|
"HandItems",
|
||||||
|
"Small",
|
||||||
|
"ShowArms",
|
||||||
|
"DisabledSlots",
|
||||||
|
"NoBasePlate",
|
||||||
|
"Marker",
|
||||||
|
"Pose",
|
||||||
// marker
|
// marker
|
||||||
"data",
|
"data",
|
||||||
// display entity
|
// display entity
|
||||||
@ -50,6 +59,10 @@ public class NbtSanitization {
|
|||||||
);
|
);
|
||||||
|
|
||||||
public static void sanitizeEntity(CompoundTag entityRoot) {
|
public static void sanitizeEntity(CompoundTag entityRoot) {
|
||||||
|
if (AxiomPaper.PLUGIN.configuration.getBoolean("disable-entity-sanitization")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
entityRoot.getAllKeys().retainAll(ALLOWED_KEYS);
|
entityRoot.getAllKeys().retainAll(ALLOWED_KEYS);
|
||||||
|
|
||||||
if (entityRoot.contains("Passengers", Tag.TAG_LIST)) {
|
if (entityRoot.contains("Passengers", Tag.TAG_LIST)) {
|
||||||
|
@ -9,24 +9,25 @@ import net.minecraft.network.FriendlyByteBuf;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public record BlueprintHeader(String name, String author, List<String> tags, float thumbnailYaw, float thumbnailPitch, boolean lockedThumbnail, int blockCount) {
|
public record BlueprintHeader(String name, String author, List<String> tags, float thumbnailYaw, float thumbnailPitch, boolean lockedThumbnail, int blockCount, boolean containsAir) {
|
||||||
|
|
||||||
private static final int CURRENT_VERSION = 0;
|
private static final int CURRENT_VERSION = 1;
|
||||||
|
|
||||||
public void write(FriendlyByteBuf friendlyByteBuf) {
|
public void write(FriendlyByteBuf friendlyByteBuf) {
|
||||||
friendlyByteBuf.writeUtf(this.name);
|
friendlyByteBuf.writeUtf(this.name);
|
||||||
friendlyByteBuf.writeUtf(this.author);
|
friendlyByteBuf.writeUtf(this.author);
|
||||||
friendlyByteBuf.writeCollection(this.tags, FriendlyByteBuf::writeUtf);
|
friendlyByteBuf.writeCollection(this.tags, FriendlyByteBuf::writeUtf);
|
||||||
friendlyByteBuf.writeInt(this.blockCount);
|
friendlyByteBuf.writeInt(this.blockCount);
|
||||||
|
friendlyByteBuf.writeBoolean(this.containsAir);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlueprintHeader read(FriendlyByteBuf friendlyByteBuf) {
|
public static BlueprintHeader read(FriendlyByteBuf friendlyByteBuf) {
|
||||||
String name = friendlyByteBuf.readUtf();
|
String name = friendlyByteBuf.readUtf();
|
||||||
String author = friendlyByteBuf.readUtf();
|
String author = friendlyByteBuf.readUtf();
|
||||||
List<String> tags = friendlyByteBuf.readCollection(FriendlyByteBuf.limitValue(ArrayList::new, 1000),
|
List<String> tags = friendlyByteBuf.readList(FriendlyByteBuf::readUtf);
|
||||||
FriendlyByteBuf::readUtf);
|
|
||||||
int blockCount = friendlyByteBuf.readInt();
|
int blockCount = friendlyByteBuf.readInt();
|
||||||
return new BlueprintHeader(name, author, tags, 0, 0, true, blockCount);
|
boolean containsAir = friendlyByteBuf.readBoolean();
|
||||||
|
return new BlueprintHeader(name, author, tags, 0, 0, true, blockCount, containsAir);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlueprintHeader load(CompoundTag tag) {
|
public static BlueprintHeader load(CompoundTag tag) {
|
||||||
@ -37,13 +38,14 @@ public record BlueprintHeader(String name, String author, List<String> tags, flo
|
|||||||
float thumbnailPitch = tag.contains("ThumbnailPitch", Tag.TAG_FLOAT) ? tag.getFloat("ThumbnailPitch") : 30;
|
float thumbnailPitch = tag.contains("ThumbnailPitch", Tag.TAG_FLOAT) ? tag.getFloat("ThumbnailPitch") : 30;
|
||||||
boolean lockedThumbnail = tag.getBoolean("LockedThumbnail");
|
boolean lockedThumbnail = tag.getBoolean("LockedThumbnail");
|
||||||
int blockCount = tag.getInt("BlockCount");
|
int blockCount = tag.getInt("BlockCount");
|
||||||
|
boolean containsAir = tag.getBoolean("ContainsAir");
|
||||||
|
|
||||||
List<String> tags = new ArrayList<>();
|
List<String> tags = new ArrayList<>();
|
||||||
for (Tag string : tag.getList("Tags", Tag.TAG_STRING)) {
|
for (Tag string : tag.getList("Tags", Tag.TAG_STRING)) {
|
||||||
tags.add(string.getAsString());
|
tags.add(string.getAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BlueprintHeader(name, author, tags, thumbnailYaw, thumbnailPitch, lockedThumbnail, blockCount);
|
return new BlueprintHeader(name, author, tags, thumbnailYaw, thumbnailPitch, lockedThumbnail, blockCount, containsAir);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompoundTag save(CompoundTag tag) {
|
public CompoundTag save(CompoundTag tag) {
|
||||||
@ -60,6 +62,7 @@ public record BlueprintHeader(String name, String author, List<String> tags, flo
|
|||||||
tag.putFloat("ThumbnailPitch", this.thumbnailPitch);
|
tag.putFloat("ThumbnailPitch", this.thumbnailPitch);
|
||||||
tag.putBoolean("LockedThumbnail", this.lockedThumbnail);
|
tag.putBoolean("LockedThumbnail", this.lockedThumbnail);
|
||||||
tag.putInt("BlockCount", this.blockCount);
|
tag.putInt("BlockCount", this.blockCount);
|
||||||
|
tag.putBoolean("ContainsAir", this.containsAir);
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ import net.minecraft.world.level.chunk.PalettedContainer;
|
|||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class BlueprintIo {
|
public class BlueprintIo {
|
||||||
|
|
||||||
@ -111,7 +113,23 @@ public class BlueprintIo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RawBlueprint(header, thumbnailBytes, blockMap, blockEntities);
|
ListTag entitiesTag = blockDataTag.getList("Entities", Tag.TAG_COMPOUND);
|
||||||
|
List<CompoundTag> entities = new ArrayList<>();
|
||||||
|
for (Tag tag : entitiesTag) {
|
||||||
|
CompoundTag entityCompound = (CompoundTag) tag;
|
||||||
|
|
||||||
|
// Data Fix
|
||||||
|
if (blueprintDataVersion != currentDataVersion) {
|
||||||
|
Dynamic<Tag> dynamic = new Dynamic<>(NbtOps.INSTANCE, entityCompound);
|
||||||
|
Dynamic<Tag> output = DataFixers.getDataFixer().update(References.ENTITY, dynamic,
|
||||||
|
blueprintDataVersion, currentDataVersion);
|
||||||
|
entityCompound = (CompoundTag) output.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
entities.add(entityCompound);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RawBlueprint(header, thumbnailBytes, blockMap, blockEntities, entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC,
|
public static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC,
|
||||||
@ -137,41 +155,6 @@ public class BlueprintIo {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeHeader(Path inPath, Path outPath, BlueprintHeader newHeader) throws IOException {
|
|
||||||
byte[] thumbnailAndBlockBytes;
|
|
||||||
try (InputStream inputStream = new BufferedInputStream(Files.newInputStream(inPath))) {
|
|
||||||
if (inputStream.available() < 4) throw NOT_VALID_BLUEPRINT;
|
|
||||||
DataInputStream dataInputStream = new DataInputStream(inputStream);
|
|
||||||
|
|
||||||
int magic = dataInputStream.readInt();
|
|
||||||
if (magic != MAGIC) throw NOT_VALID_BLUEPRINT;
|
|
||||||
|
|
||||||
// Header
|
|
||||||
int headerLength = dataInputStream.readInt(); // Ignore header length
|
|
||||||
if (dataInputStream.skip(headerLength) < headerLength) throw NOT_VALID_BLUEPRINT;
|
|
||||||
|
|
||||||
thumbnailAndBlockBytes = dataInputStream.readAllBytes();
|
|
||||||
}
|
|
||||||
|
|
||||||
try (OutputStream outputStream = new BufferedOutputStream(Files.newOutputStream(outPath))) {
|
|
||||||
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
|
|
||||||
|
|
||||||
dataOutputStream.writeInt(MAGIC);
|
|
||||||
|
|
||||||
// Write header
|
|
||||||
CompoundTag headerTag = newHeader.save(new CompoundTag());
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
try (DataOutputStream os = new DataOutputStream(baos)) {
|
|
||||||
NbtIo.write(headerTag, os);
|
|
||||||
}
|
|
||||||
dataOutputStream.writeInt(baos.size());
|
|
||||||
baos.writeTo(dataOutputStream);
|
|
||||||
|
|
||||||
// Copy remaining bytes
|
|
||||||
dataOutputStream.write(thumbnailAndBlockBytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void writeRaw(OutputStream outputStream, RawBlueprint rawBlueprint) throws IOException {
|
public static void writeRaw(OutputStream outputStream, RawBlueprint rawBlueprint) throws IOException {
|
||||||
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
|
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
|
||||||
|
|
||||||
@ -241,6 +224,11 @@ public class BlueprintIo {
|
|||||||
});
|
});
|
||||||
compound.put("BlockEntities", blockEntitiesTag);
|
compound.put("BlockEntities", blockEntitiesTag);
|
||||||
|
|
||||||
|
// Write entities
|
||||||
|
ListTag entitiesTag = new ListTag();
|
||||||
|
entitiesTag.addAll(rawBlueprint.entities());
|
||||||
|
compound.put("Entities", entitiesTag);
|
||||||
|
|
||||||
baos.reset();
|
baos.reset();
|
||||||
NbtIo.writeCompressed(compound, baos);
|
NbtIo.writeCompressed(compound, baos);
|
||||||
dataOutputStream.writeInt(baos.size());
|
dataOutputStream.writeInt(baos.size());
|
||||||
|
@ -5,14 +5,18 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
|||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public record RawBlueprint(BlueprintHeader header, byte[] thumbnail, Long2ObjectMap<PalettedContainer<BlockState>> blocks,
|
public record RawBlueprint(BlueprintHeader header, byte[] thumbnail, Long2ObjectMap<PalettedContainer<BlockState>> blocks,
|
||||||
Long2ObjectMap<CompressedBlockEntity> blockEntities) {
|
Long2ObjectMap<CompressedBlockEntity> blockEntities, List<CompoundTag> entities) {
|
||||||
|
|
||||||
public static void writeHeader(FriendlyByteBuf friendlyByteBuf, RawBlueprint rawBlueprint) {
|
public static void writeHeader(FriendlyByteBuf friendlyByteBuf, RawBlueprint rawBlueprint) {
|
||||||
rawBlueprint.header.write(friendlyByteBuf);
|
rawBlueprint.header.write(friendlyByteBuf);
|
||||||
@ -23,7 +27,7 @@ public record RawBlueprint(BlueprintHeader header, byte[] thumbnail, Long2Object
|
|||||||
BlueprintHeader header = BlueprintHeader.read(friendlyByteBuf);
|
BlueprintHeader header = BlueprintHeader.read(friendlyByteBuf);
|
||||||
byte[] thumbnail = friendlyByteBuf.readByteArray();
|
byte[] thumbnail = friendlyByteBuf.readByteArray();
|
||||||
|
|
||||||
return new RawBlueprint(header, thumbnail, null, null);
|
return new RawBlueprint(header, thumbnail, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void write(FriendlyByteBuf friendlyByteBuf, RawBlueprint rawBlueprint) {
|
public static void write(FriendlyByteBuf friendlyByteBuf, RawBlueprint rawBlueprint) {
|
||||||
@ -49,6 +53,11 @@ public record RawBlueprint(BlueprintHeader header, byte[] thumbnail, Long2Object
|
|||||||
friendlyByteBuf.writeLong(pos);
|
friendlyByteBuf.writeLong(pos);
|
||||||
rawBlueprint.blockEntities.get(pos).write(friendlyByteBuf);
|
rawBlueprint.blockEntities.get(pos).write(friendlyByteBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
friendlyByteBuf.writeVarInt(rawBlueprint.entities.size());
|
||||||
|
for (CompoundTag entity : rawBlueprint.entities) {
|
||||||
|
friendlyByteBuf.writeNbt(entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RawBlueprint read(FriendlyByteBuf friendlyByteBuf) {
|
public static RawBlueprint read(FriendlyByteBuf friendlyByteBuf) {
|
||||||
@ -78,7 +87,14 @@ public record RawBlueprint(BlueprintHeader header, byte[] thumbnail, Long2Object
|
|||||||
blockEntities.put(pos, compressedBlockEntity);
|
blockEntities.put(pos, compressedBlockEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RawBlueprint(header, thumbnail, blocks, blockEntities);
|
List<CompoundTag> entities = new ArrayList<>();
|
||||||
|
|
||||||
|
int entityCount = friendlyByteBuf.readVarInt();
|
||||||
|
for (int i = 0; i < entityCount; i++) {
|
||||||
|
entities.add(friendlyByteBuf.readNbt());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RawBlueprint(header, thumbnail, blocks, blockEntities, entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,22 +35,17 @@ public class DeleteEntityPacketListener implements PacketHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<UUID> delete = friendlyByteBuf.readCollection(FriendlyByteBuf.limitValue(ArrayList::new, 1000),
|
List<UUID> delete = friendlyByteBuf.readCollection(this.plugin.limitCollection(ArrayList::new), FriendlyByteBuf::readUUID);
|
||||||
FriendlyByteBuf::readUUID);
|
|
||||||
|
|
||||||
ServerLevel serverLevel = ((CraftWorld)player.getWorld()).getHandle();
|
ServerLevel serverLevel = ((CraftWorld)player.getWorld()).getHandle();
|
||||||
|
|
||||||
List<String> whitelistedEntities = this.plugin.configuration.getStringList("whitelist-entities");
|
|
||||||
List<String> blacklistedEntities = this.plugin.configuration.getStringList("blacklist-entities");
|
|
||||||
|
|
||||||
for (UUID uuid : delete) {
|
for (UUID uuid : delete) {
|
||||||
Entity entity = serverLevel.getEntity(uuid);
|
Entity entity = serverLevel.getEntity(uuid);
|
||||||
if (entity == null || entity instanceof net.minecraft.world.entity.player.Player || entity.hasPassenger(e -> e instanceof net.minecraft.world.entity.player.Player)) continue;
|
if (entity == null || entity instanceof net.minecraft.world.entity.player.Player || entity.hasPassenger(e -> e instanceof net.minecraft.world.entity.player.Player)) continue;
|
||||||
|
|
||||||
String type = EntityType.getKey(entity.getType()).toString();
|
if (!this.plugin.canEntityBeManipulated(entity.getType())) {
|
||||||
|
continue;
|
||||||
if (!whitelistedEntities.isEmpty() && !whitelistedEntities.contains(type)) continue;
|
}
|
||||||
if (blacklistedEntities.contains(type)) continue;
|
|
||||||
|
|
||||||
if (!Integration.canBreakBlock(player,
|
if (!Integration.canBreakBlock(player,
|
||||||
player.getWorld().getBlockAt(entity.getBlockX(), entity.getBlockY(), entity.getBlockZ()))) {
|
player.getWorld().getBlockAt(entity.getBlockX(), entity.getBlockY(), entity.getBlockZ()))) {
|
||||||
|
@ -136,6 +136,9 @@ public class HelloPacketListener implements PacketHandler {
|
|||||||
buf.writeVarInt(5); // Maximum Reach
|
buf.writeVarInt(5); // Maximum Reach
|
||||||
buf.writeVarInt(16); // Max editor views
|
buf.writeVarInt(16); // Max editor views
|
||||||
buf.writeBoolean(true); // Editable Views
|
buf.writeBoolean(true); // Editable Views
|
||||||
|
buf.writeVarInt(0); // No custom data overrides
|
||||||
|
buf.writeVarInt(0); // No rotation overrides
|
||||||
|
buf.writeVarInt(1); // Blueprint version
|
||||||
|
|
||||||
byte[] enableBytes = new byte[buf.writerIndex()];
|
byte[] enableBytes = new byte[buf.writerIndex()];
|
||||||
buf.getBytes(0, enableBytes);
|
buf.getBytes(0, enableBytes);
|
||||||
|
@ -49,7 +49,7 @@ public class ManipulateEntityPacketListener implements PacketHandler {
|
|||||||
|
|
||||||
public record ManipulateEntry(UUID uuid, @Nullable Set<RelativeMovement> relativeMovementSet, @Nullable Vec3 position,
|
public record ManipulateEntry(UUID uuid, @Nullable Set<RelativeMovement> relativeMovementSet, @Nullable Vec3 position,
|
||||||
float yaw, float pitch, CompoundTag merge, PassengerManipulation passengerManipulation, List<UUID> passengers) {
|
float yaw, float pitch, CompoundTag merge, PassengerManipulation passengerManipulation, List<UUID> passengers) {
|
||||||
public static ManipulateEntry read(FriendlyByteBuf friendlyByteBuf, Player player) {
|
public static ManipulateEntry read(FriendlyByteBuf friendlyByteBuf, Player player, AxiomPaper plugin) {
|
||||||
UUID uuid = friendlyByteBuf.readUUID();
|
UUID uuid = friendlyByteBuf.readUUID();
|
||||||
|
|
||||||
int flags = friendlyByteBuf.readByte();
|
int flags = friendlyByteBuf.readByte();
|
||||||
@ -69,8 +69,7 @@ public class ManipulateEntityPacketListener implements PacketHandler {
|
|||||||
PassengerManipulation passengerManipulation = friendlyByteBuf.readEnum(PassengerManipulation.class);
|
PassengerManipulation passengerManipulation = friendlyByteBuf.readEnum(PassengerManipulation.class);
|
||||||
List<UUID> passengers = List.of();
|
List<UUID> passengers = List.of();
|
||||||
if (passengerManipulation == PassengerManipulation.ADD_LIST || passengerManipulation == PassengerManipulation.REMOVE_LIST) {
|
if (passengerManipulation == PassengerManipulation.ADD_LIST || passengerManipulation == PassengerManipulation.REMOVE_LIST) {
|
||||||
passengers = friendlyByteBuf.readCollection(FriendlyByteBuf.limitValue(ArrayList::new, 1000),
|
passengers = friendlyByteBuf.readCollection(plugin.limitCollection(ArrayList::new), FriendlyByteBuf::readUUID);
|
||||||
FriendlyByteBuf::readUUID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ManipulateEntry(uuid, relativeMovementSet, position, yaw, pitch, nbt,
|
return new ManipulateEntry(uuid, relativeMovementSet, position, yaw, pitch, nbt,
|
||||||
@ -90,22 +89,18 @@ public class ManipulateEntityPacketListener implements PacketHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ManipulateEntry> entries = friendlyByteBuf.readCollection(FriendlyByteBuf.limitValue(ArrayList::new, 1000),
|
List<ManipulateEntry> entries = friendlyByteBuf.readCollection(this.plugin.limitCollection(ArrayList::new),
|
||||||
buf -> ManipulateEntry.read(buf, player));
|
buf -> ManipulateEntry.read(buf, player, this.plugin));
|
||||||
|
|
||||||
ServerLevel serverLevel = ((CraftWorld)player.getWorld()).getHandle();
|
ServerLevel serverLevel = ((CraftWorld)player.getWorld()).getHandle();
|
||||||
|
|
||||||
List<String> whitelistedEntities = this.plugin.configuration.getStringList("whitelist-entities");
|
|
||||||
List<String> blacklistedEntities = this.plugin.configuration.getStringList("blacklist-entities");
|
|
||||||
|
|
||||||
for (ManipulateEntry entry : entries) {
|
for (ManipulateEntry entry : entries) {
|
||||||
Entity entity = serverLevel.getEntity(entry.uuid);
|
Entity entity = serverLevel.getEntity(entry.uuid);
|
||||||
if (entity == null || entity instanceof net.minecraft.world.entity.player.Player || entity.hasPassenger(ManipulateEntityPacketListener::isPlayer)) continue;
|
if (entity == null || entity instanceof net.minecraft.world.entity.player.Player || entity.hasPassenger(ManipulateEntityPacketListener::isPlayer)) continue;
|
||||||
|
|
||||||
String type = EntityType.getKey(entity.getType()).toString();
|
if (!this.plugin.canEntityBeManipulated(entity.getType())) {
|
||||||
|
continue;
|
||||||
if (!whitelistedEntities.isEmpty() && !whitelistedEntities.contains(type)) continue;
|
}
|
||||||
if (blacklistedEntities.contains(type)) continue;
|
|
||||||
|
|
||||||
Vec3 position = entity.position();
|
Vec3 position = entity.position();
|
||||||
BlockPos containing = BlockPos.containing(position.x, position.y, position.z);
|
BlockPos containing = BlockPos.containing(position.x, position.y, position.z);
|
||||||
@ -168,10 +163,9 @@ public class ManipulateEntityPacketListener implements PacketHandler {
|
|||||||
if (passenger == null || passenger.isPassenger() ||
|
if (passenger == null || passenger.isPassenger() ||
|
||||||
passenger instanceof net.minecraft.world.entity.player.Player || passenger.hasPassenger(ManipulateEntityPacketListener::isPlayer)) continue;
|
passenger instanceof net.minecraft.world.entity.player.Player || passenger.hasPassenger(ManipulateEntityPacketListener::isPlayer)) continue;
|
||||||
|
|
||||||
String passengerType = EntityType.getKey(passenger.getType()).toString();
|
if (!this.plugin.canEntityBeManipulated(passenger.getType())) {
|
||||||
|
continue;
|
||||||
if (!whitelistedEntities.isEmpty() && !whitelistedEntities.contains(passengerType)) continue;
|
}
|
||||||
if (blacklistedEntities.contains(passengerType)) continue;
|
|
||||||
|
|
||||||
// Prevent mounting loop
|
// Prevent mounting loop
|
||||||
if (passenger.getSelfAndPassengers().anyMatch(entity2 -> entity2 == entity)) {
|
if (passenger.getSelfAndPassengers().anyMatch(entity2 -> entity2 == entity)) {
|
||||||
@ -195,10 +189,9 @@ public class ManipulateEntityPacketListener implements PacketHandler {
|
|||||||
if (passenger == null || passenger == entity || passenger instanceof net.minecraft.world.entity.player.Player ||
|
if (passenger == null || passenger == entity || passenger instanceof net.minecraft.world.entity.player.Player ||
|
||||||
passenger.hasPassenger(ManipulateEntityPacketListener::isPlayer)) continue;
|
passenger.hasPassenger(ManipulateEntityPacketListener::isPlayer)) continue;
|
||||||
|
|
||||||
String passengerType = EntityType.getKey(passenger.getType()).toString();
|
if (!this.plugin.canEntityBeManipulated(passenger.getType())) {
|
||||||
|
continue;
|
||||||
if (!whitelistedEntities.isEmpty() && !whitelistedEntities.contains(passengerType)) continue;
|
}
|
||||||
if (blacklistedEntities.contains(passengerType)) continue;
|
|
||||||
|
|
||||||
Entity vehicle = passenger.getVehicle();
|
Entity vehicle = passenger.getVehicle();
|
||||||
if (vehicle == entity) {
|
if (vehicle == entity) {
|
||||||
|
@ -68,7 +68,7 @@ public class RequestChunkDataPacketListener implements PacketHandler {
|
|||||||
|
|
||||||
ResourceKey<Level> worldKey = friendlyByteBuf.readResourceKey(Registries.DIMENSION);
|
ResourceKey<Level> worldKey = friendlyByteBuf.readResourceKey(Registries.DIMENSION);
|
||||||
ServerLevel level = server.getLevel(worldKey);
|
ServerLevel level = server.getLevel(worldKey);
|
||||||
if (level == null) {
|
if (level == null || level != player.serverLevel()) {
|
||||||
sendEmptyResponse(player, id);
|
sendEmptyResponse(player, id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,108 @@
|
|||||||
|
package com.moulberry.axiom.packet.impl;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.AxiomPaper;
|
||||||
|
import com.moulberry.axiom.VersionHelper;
|
||||||
|
import com.moulberry.axiom.integration.Integration;
|
||||||
|
import com.moulberry.axiom.packet.PacketHandler;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class RequestEntityDataPacketListener implements PacketHandler {
|
||||||
|
|
||||||
|
public static final ResourceLocation RESPONSE_ID = VersionHelper.createResourceLocation("axiom:response_entity_data");
|
||||||
|
|
||||||
|
private final AxiomPaper plugin;
|
||||||
|
private final boolean forceFail;
|
||||||
|
public RequestEntityDataPacketListener(AxiomPaper plugin, boolean forceFail) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.forceFail = forceFail;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(org.bukkit.entity.Player bukkitPlayer, FriendlyByteBuf friendlyByteBuf) {
|
||||||
|
ServerPlayer player = ((CraftPlayer)bukkitPlayer).getHandle();
|
||||||
|
long id = friendlyByteBuf.readLong();
|
||||||
|
|
||||||
|
if (this.forceFail || !this.plugin.canUseAxiom(bukkitPlayer, "axiom.entity.request_data") || this.plugin.isMismatchedDataVersion(bukkitPlayer.getUniqueId())) {
|
||||||
|
// We always send an 'empty' response in order to make the client happy
|
||||||
|
sendResponse(player, id, true, Map.of());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.plugin.canModifyWorld(bukkitPlayer, bukkitPlayer.getWorld())) {
|
||||||
|
sendResponse(player, id, true, Map.of());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<UUID> request = friendlyByteBuf.readCollection(this.plugin.limitCollection(ArrayList::new), buf -> buf.readUUID());
|
||||||
|
ServerLevel serverLevel = player.serverLevel();
|
||||||
|
|
||||||
|
final int maxPacketSize = 0x100000;
|
||||||
|
int remainingBytes = maxPacketSize;
|
||||||
|
|
||||||
|
Map<UUID, CompoundTag> entityData = new HashMap<>();
|
||||||
|
|
||||||
|
Set<UUID> visitedEntities = new HashSet<>();
|
||||||
|
|
||||||
|
for (UUID uuid : request) {
|
||||||
|
if (!visitedEntities.add(uuid)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity entity = serverLevel.getEntity(uuid);
|
||||||
|
if (entity == null || entity instanceof Player) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.plugin.canEntityBeManipulated(entity.getType())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Integration.canPlaceBlock(bukkitPlayer, new Location(bukkitPlayer.getWorld(),
|
||||||
|
entity.getBlockX(), entity.getBlockY(), entity.getBlockZ()))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompoundTag entityTag = new CompoundTag();
|
||||||
|
if (entity.save(entityTag)) {
|
||||||
|
int size = entityTag.sizeInBytes();
|
||||||
|
if (size >= maxPacketSize) {
|
||||||
|
sendResponse(player, id, false, Map.of(uuid, entityTag));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send partial packet if we've run out of available bytes
|
||||||
|
if (remainingBytes - size < 0) {
|
||||||
|
sendResponse(player, id, false, entityData);
|
||||||
|
entityData.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
entityData.put(uuid, entityTag);
|
||||||
|
remainingBytes -= size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendResponse(player, id, true, entityData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void sendResponse(ServerPlayer player, long id, boolean finished, Map<UUID, CompoundTag> map) {
|
||||||
|
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer());
|
||||||
|
friendlyByteBuf.writeLong(id);
|
||||||
|
friendlyByteBuf.writeBoolean(finished);
|
||||||
|
friendlyByteBuf.writeMap(map, (buf, uuid) -> buf.writeUUID(uuid), (buf, nbt) -> buf.writeNbt(nbt));
|
||||||
|
|
||||||
|
player.connection.send(new ClientboundCustomPayloadPacket(RESPONSE_ID, friendlyByteBuf));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -92,7 +92,7 @@ public class SetBlockPacketListener implements PacketHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read packet
|
// Read packet
|
||||||
IntFunction<Map<BlockPos, BlockState>> mapFunction = FriendlyByteBuf.limitValue(Maps::newLinkedHashMapWithExpectedSize, 512);
|
IntFunction<Map<BlockPos, BlockState>> mapFunction = this.plugin.limitCollection(Maps::newLinkedHashMapWithExpectedSize);
|
||||||
IdMapper<BlockState> registry = this.plugin.getBlockRegistry(bukkitPlayer.getUniqueId());
|
IdMapper<BlockState> registry = this.plugin.getBlockRegistry(bukkitPlayer.getUniqueId());
|
||||||
Map<BlockPos, BlockState> blocks = friendlyByteBuf.readMap(mapFunction,
|
Map<BlockPos, BlockState> blocks = friendlyByteBuf.readMap(mapFunction,
|
||||||
FriendlyByteBuf::readBlockPos, buf -> buf.readById(registry));
|
FriendlyByteBuf::readBlockPos, buf -> buf.readById(registry));
|
||||||
|
@ -54,16 +54,13 @@ public class SpawnEntityPacketListener implements PacketHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<SpawnEntry> entries = friendlyByteBuf.readCollection(FriendlyByteBuf.limitValue(ArrayList::new, 1000),
|
List<SpawnEntry> entries = friendlyByteBuf.readCollection(this.plugin.limitCollection(ArrayList::new),
|
||||||
buf -> new SpawnEntry(buf.readUUID(), buf.readDouble(), buf.readDouble(),
|
buf -> new SpawnEntry(buf.readUUID(), buf.readDouble(), buf.readDouble(),
|
||||||
buf.readDouble(), buf.readFloat(), buf.readFloat(),
|
buf.readDouble(), buf.readFloat(), buf.readFloat(),
|
||||||
buf.readNullable(FriendlyByteBuf::readUUID), UnknownVersionHelper.readTagUnknown(buf, player)));
|
buf.readNullable(FriendlyByteBuf::readUUID), UnknownVersionHelper.readTagUnknown(buf, player)));
|
||||||
|
|
||||||
ServerLevel serverLevel = ((CraftWorld)player.getWorld()).getHandle();
|
ServerLevel serverLevel = ((CraftWorld)player.getWorld()).getHandle();
|
||||||
|
|
||||||
List<String> whitelistedEntities = this.plugin.configuration.getStringList("whitelist-entities");
|
|
||||||
List<String> blacklistedEntities = this.plugin.configuration.getStringList("blacklist-entities");
|
|
||||||
|
|
||||||
for (SpawnEntry entry : entries) {
|
for (SpawnEntry entry : entries) {
|
||||||
Vec3 position = new Vec3(entry.x, entry.y, entry.z);
|
Vec3 position = new Vec3(entry.x, entry.y, entry.z);
|
||||||
|
|
||||||
@ -99,9 +96,9 @@ public class SpawnEntityPacketListener implements PacketHandler {
|
|||||||
AtomicBoolean useNewUuid = new AtomicBoolean(true);
|
AtomicBoolean useNewUuid = new AtomicBoolean(true);
|
||||||
|
|
||||||
Entity spawned = EntityType.loadEntityRecursive(tag, serverLevel, entity -> {
|
Entity spawned = EntityType.loadEntityRecursive(tag, serverLevel, entity -> {
|
||||||
String type = EntityType.getKey(entity.getType()).toString();
|
if (!this.plugin.canEntityBeManipulated(entity.getType())) {
|
||||||
if (!whitelistedEntities.isEmpty() && !whitelistedEntities.contains(type)) return null;
|
return null;
|
||||||
if (blacklistedEntities.contains(type)) return null;
|
}
|
||||||
|
|
||||||
if (useNewUuid.getAndSet(false)) {
|
if (useNewUuid.getAndSet(false)) {
|
||||||
entity.setUUID(entry.newUuid);
|
entity.setUUID(entry.newUuid);
|
||||||
|
@ -14,7 +14,7 @@ allow-teleport-between-worlds: true
|
|||||||
# Whether to allow clients to save/load/share blueprints through the server
|
# Whether to allow clients to save/load/share blueprints through the server
|
||||||
blueprint-sharing: false
|
blueprint-sharing: false
|
||||||
|
|
||||||
# Allow large chunk data requests, not recommended for public servers
|
# Allow large chunk & entity data requests, not recommended for public servers
|
||||||
allow-large-chunk-data-request: false
|
allow-large-chunk-data-request: false
|
||||||
|
|
||||||
# Raise the size limit for *all* packets to 2mb instead of 32kb. NOT RECOMMENDED FOR PUBLIC SERVERS
|
# Raise the size limit for *all* packets to 2mb instead of 32kb. NOT RECOMMENDED FOR PUBLIC SERVERS
|
||||||
@ -57,6 +57,9 @@ whitelist-entities:
|
|||||||
blacklist-entities:
|
blacklist-entities:
|
||||||
# - "minecraft:ender_dragon"
|
# - "minecraft:ender_dragon"
|
||||||
|
|
||||||
|
# Disables entity data sanitization. NOT RECOMMENDED FOR PUBLIC SERVERS
|
||||||
|
disable-entity-sanitization: false
|
||||||
|
|
||||||
# True allows players to see/manipulate marker entities
|
# True allows players to see/manipulate marker entities
|
||||||
send-markers: false
|
send-markers: false
|
||||||
|
|
||||||
@ -95,6 +98,7 @@ packet-handlers:
|
|||||||
teleport: true
|
teleport: true
|
||||||
set-editor-views: true
|
set-editor-views: true
|
||||||
request-chunk-data: true
|
request-chunk-data: true
|
||||||
|
request-entity-data: true
|
||||||
set-buffer: true
|
set-buffer: true
|
||||||
spawn-entity: true
|
spawn-entity: true
|
||||||
manipulate-entity: true
|
manipulate-entity: true
|
||||||
|
@ -25,6 +25,7 @@ permissions:
|
|||||||
axiom.entity.spawn: true
|
axiom.entity.spawn: true
|
||||||
axiom.entity.manipulate: true
|
axiom.entity.manipulate: true
|
||||||
axiom.entity.delete: true
|
axiom.entity.delete: true
|
||||||
|
axiom.entity.request_data: true
|
||||||
axiom.blueprint.*:
|
axiom.blueprint.*:
|
||||||
description: Allows use of all blueprint-related features
|
description: Allows use of all blueprint-related features
|
||||||
default: op
|
default: op
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren