Mirror von
https://github.com/Moulberry/AxiomPaperPlugin.git
synchronisiert 2024-11-13 19:50:09 +01:00
Support spawn, manipulate and delete packets
Dieser Commit ist enthalten in:
Ursprung
f81bf5c8c5
Commit
9e9798de6c
@ -124,6 +124,15 @@ public class AxiomPaper extends JavaPlugin implements Listener {
|
||||
if (configuration.getBoolean("packet-handlers.request-chunk-data")) {
|
||||
msg.registerIncomingPluginChannel(this, "axiom:request_chunk_data", new RequestChunkDataPacketListener(this));
|
||||
}
|
||||
if (configuration.getBoolean("packet-handlers.spawn-entity")) {
|
||||
msg.registerIncomingPluginChannel(this, "axiom:spawn_entity", new SpawnEntityPacketListener(this));
|
||||
}
|
||||
if (configuration.getBoolean("packet-handlers.manipulate-entity")) {
|
||||
msg.registerIncomingPluginChannel(this, "axiom:manipulate_entity", new ManipulateEntityPacketListener(this));
|
||||
}
|
||||
if (configuration.getBoolean("packet-handlers.delete-entity")) {
|
||||
msg.registerIncomingPluginChannel(this, "axiom:delete_entity", new DeleteEntityPacketListener(this));
|
||||
}
|
||||
|
||||
if (configuration.getBoolean("packet-handlers.set-buffer")) {
|
||||
SetBlockBufferPacketListener setBlockBufferPacketListener = new SetBlockBufferPacketListener(this);
|
||||
|
@ -0,0 +1,68 @@
|
||||
package com.moulberry.axiom.packet;
|
||||
|
||||
import com.moulberry.axiom.AxiomPaper;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.decoration.HangingEntity;
|
||||
import net.minecraft.world.entity.decoration.ItemFrame;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class DeleteEntityPacketListener implements PluginMessageListener {
|
||||
|
||||
private final AxiomPaper plugin;
|
||||
public DeleteEntityPacketListener(AxiomPaper plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
|
||||
if (!this.plugin.canUseAxiom(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.hasPermission("axiom.entity.*") && !player.hasPermission("axiom.entity.delete")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.plugin.canModifyWorld(player, player.getWorld())) {
|
||||
return;
|
||||
}
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
List<UUID> delete = friendlyByteBuf.readList(FriendlyByteBuf::readUUID);
|
||||
|
||||
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) {
|
||||
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;
|
||||
|
||||
String type = EntityType.getKey(entity.getType()).toString();
|
||||
|
||||
if (!whitelistedEntities.isEmpty() && !whitelistedEntities.contains(type)) continue;
|
||||
if (blacklistedEntities.contains(type)) continue;
|
||||
|
||||
entity.remove(Entity.RemovalReason.DISCARDED);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,201 @@
|
||||
package com.moulberry.axiom.packet;
|
||||
|
||||
import com.moulberry.axiom.AxiomPaper;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.RelativeMovement;
|
||||
import net.minecraft.world.entity.decoration.HangingEntity;
|
||||
import net.minecraft.world.entity.decoration.ItemFrame;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ManipulateEntityPacketListener implements PluginMessageListener {
|
||||
|
||||
private final AxiomPaper plugin;
|
||||
public ManipulateEntityPacketListener(AxiomPaper plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public enum PassengerManipulation {
|
||||
NONE,
|
||||
REMOVE_ALL,
|
||||
ADD_LIST,
|
||||
REMOVE_LIST
|
||||
}
|
||||
|
||||
public record ManipulateEntry(UUID uuid, @Nullable Set<RelativeMovement> relativeMovementSet, @Nullable Vec3 position,
|
||||
float yaw, float pitch, CompoundTag merge, PassengerManipulation passengerManipulation, List<UUID> passengers) {
|
||||
public static ManipulateEntry read(FriendlyByteBuf friendlyByteBuf) {
|
||||
UUID uuid = friendlyByteBuf.readUUID();
|
||||
|
||||
int flags = friendlyByteBuf.readByte();
|
||||
Set<RelativeMovement> relativeMovementSet = null;
|
||||
Vec3 position = null;
|
||||
float yaw = 0;
|
||||
float pitch = 0;
|
||||
if (flags >= 0) {
|
||||
relativeMovementSet = RelativeMovement.unpack(flags);
|
||||
position = new Vec3(friendlyByteBuf.readDouble(), friendlyByteBuf.readDouble(), friendlyByteBuf.readDouble());
|
||||
yaw = friendlyByteBuf.readFloat();
|
||||
pitch = friendlyByteBuf.readFloat();
|
||||
}
|
||||
|
||||
CompoundTag nbt = friendlyByteBuf.readNbt();
|
||||
|
||||
PassengerManipulation passengerManipulation = friendlyByteBuf.readEnum(PassengerManipulation.class);
|
||||
List<UUID> passengers = List.of();
|
||||
if (passengerManipulation == PassengerManipulation.ADD_LIST || passengerManipulation == PassengerManipulation.REMOVE_LIST) {
|
||||
passengers = friendlyByteBuf.readList(FriendlyByteBuf::readUUID);
|
||||
}
|
||||
|
||||
return new ManipulateEntry(uuid, relativeMovementSet, position, yaw, pitch, nbt,
|
||||
passengerManipulation, passengers);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Rotation[] ROTATION_VALUES = Rotation.values();
|
||||
|
||||
@Override
|
||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
|
||||
if (!this.plugin.canUseAxiom(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.hasPermission("axiom.entity.*") && !player.hasPermission("axiom.entity.manipulate")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.plugin.canModifyWorld(player, player.getWorld())) {
|
||||
return;
|
||||
}
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
List<ManipulateEntry> entries = friendlyByteBuf.readList(ManipulateEntry::read);
|
||||
|
||||
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) {
|
||||
Entity entity = serverLevel.getEntity(entry.uuid);
|
||||
if (entity == null || entity instanceof net.minecraft.world.entity.player.Player || entity.hasPassenger(ManipulateEntityPacketListener::isPlayer)) continue;
|
||||
|
||||
String type = EntityType.getKey(entity.getType()).toString();
|
||||
|
||||
if (!whitelistedEntities.isEmpty() && !whitelistedEntities.contains(type)) continue;
|
||||
if (blacklistedEntities.contains(type)) continue;
|
||||
|
||||
if (entry.merge != null && !entry.merge.isEmpty()) {
|
||||
CompoundTag compoundTag = entity.saveWithoutId(new CompoundTag());
|
||||
compoundTag = merge(compoundTag, entry.merge);
|
||||
entity.load(compoundTag);
|
||||
}
|
||||
|
||||
Vec3 entryPos = entry.position();
|
||||
if (entryPos != null && entry.relativeMovementSet != null) {
|
||||
double newX = entry.relativeMovementSet.contains(RelativeMovement.X) ? entity.position().x + entryPos.x : entryPos.x;
|
||||
double newY = entry.relativeMovementSet.contains(RelativeMovement.Y) ? entity.position().y + entryPos.y : entryPos.y;
|
||||
double newZ = entry.relativeMovementSet.contains(RelativeMovement.Z) ? entity.position().z + entryPos.z : entryPos.z;
|
||||
float newYaw = entry.relativeMovementSet.contains(RelativeMovement.Y_ROT) ? entity.getYRot() + entry.yaw : entry.yaw;
|
||||
float newPitch = entry.relativeMovementSet.contains(RelativeMovement.X_ROT) ? entity.getXRot() + entry.pitch : entry.pitch;
|
||||
|
||||
if (entity instanceof HangingEntity hangingEntity) {
|
||||
float changedYaw = newYaw - entity.getYRot();
|
||||
int rotations = Math.round(changedYaw / 90);
|
||||
hangingEntity.rotate(ROTATION_VALUES[rotations & 3]);
|
||||
|
||||
if (entity instanceof ItemFrame itemFrame && itemFrame.getDirection().getAxis() == Direction.Axis.Y) {
|
||||
itemFrame.setRotation(itemFrame.getRotation() - Math.round(changedYaw / 45));
|
||||
}
|
||||
}
|
||||
|
||||
entity.teleportTo(serverLevel, newX, newY, newZ, Set.of(), newYaw, newPitch);
|
||||
entity.setYHeadRot(newYaw);
|
||||
}
|
||||
|
||||
switch (entry.passengerManipulation) {
|
||||
case NONE -> {}
|
||||
case REMOVE_ALL -> entity.ejectPassengers();
|
||||
case ADD_LIST -> {
|
||||
for (UUID passengerUuid : entry.passengers) {
|
||||
Entity passenger = serverLevel.getEntity(passengerUuid);
|
||||
|
||||
if (passenger == null || passenger.isPassenger() ||
|
||||
passenger instanceof net.minecraft.world.entity.player.Player || passenger.hasPassenger(ManipulateEntityPacketListener::isPlayer)) continue;
|
||||
|
||||
String passengerType = EntityType.getKey(passenger.getType()).toString();
|
||||
|
||||
if (!whitelistedEntities.isEmpty() && !whitelistedEntities.contains(passengerType)) continue;
|
||||
if (blacklistedEntities.contains(passengerType)) continue;
|
||||
|
||||
// Prevent mounting loop
|
||||
if (passenger.getSelfAndPassengers().anyMatch(entity2 -> entity2 == entity)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
passenger.startRiding(entity, true);
|
||||
}
|
||||
}
|
||||
case REMOVE_LIST -> {
|
||||
for (UUID passengerUuid : entry.passengers) {
|
||||
Entity passenger = serverLevel.getEntity(passengerUuid);
|
||||
if (passenger == null || passenger == entity || passenger instanceof net.minecraft.world.entity.player.Player ||
|
||||
passenger.hasPassenger(ManipulateEntityPacketListener::isPlayer)) continue;
|
||||
|
||||
String passengerType = EntityType.getKey(passenger.getType()).toString();
|
||||
|
||||
if (!whitelistedEntities.isEmpty() && !whitelistedEntities.contains(passengerType)) continue;
|
||||
if (blacklistedEntities.contains(passengerType)) continue;
|
||||
|
||||
Entity vehicle = passenger.getVehicle();
|
||||
if (vehicle == entity) {
|
||||
passenger.stopRiding();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static CompoundTag merge(CompoundTag left, CompoundTag right) {
|
||||
for (String key : right.getAllKeys()) {
|
||||
Tag tag = right.get(key);
|
||||
if (tag instanceof CompoundTag compound) {
|
||||
if (compound.isEmpty()) {
|
||||
left.remove(key);
|
||||
} else if (left.contains(key, Tag.TAG_COMPOUND)) {
|
||||
CompoundTag child = left.getCompound(key);
|
||||
merge(child, compound);
|
||||
} else {
|
||||
left.put(key, tag.copy());
|
||||
}
|
||||
} else {
|
||||
left.put(key, tag.copy());
|
||||
}
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
private static boolean isPlayer(Entity entity) {
|
||||
return entity instanceof net.minecraft.world.entity.player.Player;
|
||||
}
|
||||
|
||||
}
|
130
src/main/java/com/moulberry/axiom/packet/SpawnEntityPacketListener.java
Normale Datei
130
src/main/java/com/moulberry/axiom/packet/SpawnEntityPacketListener.java
Normale Datei
@ -0,0 +1,130 @@
|
||||
package com.moulberry.axiom.packet;
|
||||
|
||||
import com.moulberry.axiom.AxiomPaper;
|
||||
import com.moulberry.axiom.event.AxiomTeleportEvent;
|
||||
import com.moulberry.axiom.event.AxiomUnknownTeleportEvent;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.decoration.HangingEntity;
|
||||
import net.minecraft.world.entity.decoration.ItemFrame;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class SpawnEntityPacketListener implements PluginMessageListener {
|
||||
|
||||
private final AxiomPaper plugin;
|
||||
public SpawnEntityPacketListener(AxiomPaper plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
private record SpawnEntry(UUID newUuid, double x, double y, double z, float yaw, float pitch,
|
||||
@Nullable UUID copyFrom, CompoundTag tag) {
|
||||
public SpawnEntry(FriendlyByteBuf friendlyByteBuf) {
|
||||
this(friendlyByteBuf.readUUID(), friendlyByteBuf.readDouble(), friendlyByteBuf.readDouble(),
|
||||
friendlyByteBuf.readDouble(), friendlyByteBuf.readFloat(), friendlyByteBuf.readFloat(),
|
||||
friendlyByteBuf.readNullable(FriendlyByteBuf::readUUID), friendlyByteBuf.readNbt());
|
||||
}
|
||||
}
|
||||
|
||||
private static final Rotation[] ROTATION_VALUES = Rotation.values();
|
||||
|
||||
@Override
|
||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
|
||||
if (!this.plugin.canUseAxiom(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.hasPermission("axiom.entity.*") && !player.hasPermission("axiom.entity.spawn")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.plugin.canModifyWorld(player, player.getWorld())) {
|
||||
return;
|
||||
}
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
List<SpawnEntry> entries = friendlyByteBuf.readList(SpawnEntry::new);
|
||||
|
||||
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) {
|
||||
Vec3 position = new Vec3(entry.x, entry.y, entry.z);
|
||||
|
||||
BlockPos blockPos = BlockPos.containing(position);
|
||||
if (!Level.isInSpawnableBounds(blockPos)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CompoundTag tag = entry.tag == null ? new CompoundTag() : entry.tag;
|
||||
|
||||
if (serverLevel.getEntity(entry.newUuid) != null) continue;
|
||||
|
||||
if (entry.copyFrom != null) {
|
||||
Entity entityCopyFrom = serverLevel.getEntity(entry.copyFrom);
|
||||
if (entityCopyFrom != null) {
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
if (entityCopyFrom.saveAsPassenger(compoundTag)) {
|
||||
compoundTag.remove("Dimension");
|
||||
tag = tag.merge(compoundTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!tag.contains("id")) continue;
|
||||
|
||||
Entity spawned = EntityType.loadEntityRecursive(tag, serverLevel, entity -> {
|
||||
String type = EntityType.getKey(entity.getType()).toString();
|
||||
if (!whitelistedEntities.isEmpty() && !whitelistedEntities.contains(type)) return null;
|
||||
if (blacklistedEntities.contains(type)) return null;
|
||||
|
||||
entity.setUUID(entry.newUuid);
|
||||
|
||||
if (entity instanceof HangingEntity hangingEntity) {
|
||||
float changedYaw = entry.yaw - entity.getYRot();
|
||||
int rotations = Math.round(changedYaw / 90);
|
||||
hangingEntity.rotate(ROTATION_VALUES[rotations & 3]);
|
||||
|
||||
if (entity instanceof ItemFrame itemFrame && itemFrame.getDirection().getAxis() == Direction.Axis.Y) {
|
||||
itemFrame.setRotation(itemFrame.getRotation() - Math.round(changedYaw / 45));
|
||||
}
|
||||
}
|
||||
|
||||
entity.moveTo(position.x, position.y, position.z, entry.yaw, entry.pitch);
|
||||
entity.setYHeadRot(entity.getYRot());
|
||||
|
||||
return entity;
|
||||
});
|
||||
|
||||
if (spawned != null) {
|
||||
serverLevel.tryAddFreshEntityWithPassengers(spawned);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -34,6 +34,20 @@ block-buffer-rate-limit: 0
|
||||
# Log large block buffer changes
|
||||
log-large-block-buffer-changes: false
|
||||
|
||||
# Whitelist entities that can be spawned/manipulated/deleted by the client
|
||||
whitelist-entities:
|
||||
- "minecraft:item_display"
|
||||
- "minecraft:block_display"
|
||||
- "minecraft:text_display"
|
||||
- "minecraft:painting"
|
||||
- "minecraft:armor_stand"
|
||||
- "minecraft:item_frame"
|
||||
- "minecraft:glow_item_frame"
|
||||
|
||||
# Blacklist entities that can be spawned/manipulated/deleted by the client
|
||||
blacklist-entities:
|
||||
# - "minecraft:ender_dragon"
|
||||
|
||||
# Disallowed blocks
|
||||
disallowed-blocks:
|
||||
# - "minecraft:wheat"
|
||||
@ -53,3 +67,6 @@ packet-handlers:
|
||||
set-editor-views: true
|
||||
request-chunk-data: true
|
||||
set-buffer: true
|
||||
spawn-entity: true
|
||||
manipulate-entity: true
|
||||
delete-entity: true
|
||||
|
@ -7,6 +7,15 @@ authors:
|
||||
api-version: "$apiVersion"
|
||||
permissions:
|
||||
axiom.*:
|
||||
description: Allows use of all Axiom features
|
||||
description: Allows use of all default Axiom features
|
||||
default: op
|
||||
|
||||
axiom.entity.*:
|
||||
description: Allows use of all entity-related features (spawning, manipulating, deleting)
|
||||
default: op
|
||||
axiom.entity.spawn:
|
||||
description: Allows entity spawning
|
||||
axiom.entity.manipulate:
|
||||
description: Allows entity manipulation
|
||||
axiom.entity.delete:
|
||||
description: Allows entity deletion
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren