Skip to content

Commit

Permalink
Support for 1.20.3/1.20.4
Browse files Browse the repository at this point in the history
  • Loading branch information
ds58 committed Dec 13, 2023
1 parent 26a74b9 commit 4683ed8
Show file tree
Hide file tree
Showing 11 changed files with 511 additions and 6 deletions.
9 changes: 5 additions & 4 deletions bukkit/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ dependencies {
implementation project(':panilla-craftbukkit-v1_17_R1')
implementation project(':panilla-craftbukkit-v1_18_R1')
implementation project(':panilla-craftbukkit-v1_18_R2')
implementation project(':panilla-craftbukkit-v1_19_R1')
implementation project(':panilla-craftbukkit-v1_19_R2')
implementation project(':panilla-craftbukkit-v1_19_R3')
implementation project(':panilla-craftbukkit-v1_20_R1')
implementation project(':panilla-craftbukkit-v1_19_R1')
implementation project(':panilla-craftbukkit-v1_19_R2')
implementation project(':panilla-craftbukkit-v1_19_R3')
implementation project(':panilla-craftbukkit-v1_20_R1')
implementation project(':panilla-craftbukkit-v1_20_R2')
implementation project(':panilla-craftbukkit-v1_20_R3')
compileOnly 'org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT' // use 1.13 Bukkit API
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,18 @@ public int maxBookPages() {
packetInspector = new com.ruinscraft.panilla.craftbukkit.v1_20_R2.io.PacketInspector(this);
containerCleaner = new com.ruinscraft.panilla.craftbukkit.v1_20_R2.InventoryCleaner(this);
break imp;
case "v1_20_R3":
packetSerializerClass = com.ruinscraft.panilla.craftbukkit.v1_20_R3.io.dplx.PacketSerializer.class;
protocolConstants = new IProtocolConstants() {
@Override
public int maxBookPages() {
return 100;
}
};
playerInjector = new com.ruinscraft.panilla.craftbukkit.v1_20_R3.io.PlayerInjector();
packetInspector = new com.ruinscraft.panilla.craftbukkit.v1_20_R3.io.PacketInspector(this);
containerCleaner = new com.ruinscraft.panilla.craftbukkit.v1_20_R3.InventoryCleaner(this);
break imp;
}
default:
getLogger().warning("Unknown server implementation. " + Bukkit.getVersion() + " may not be supported by Panilla.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public void checkPacketPlayOutSpawnEntity(Object _packet) throws EntityNbtNotPer
if (entity instanceof EntityItem) {
EntityItem item = (EntityItem) entity;

if (item.v() == null) {
if (item.q() == null) {
return;
}

Expand Down Expand Up @@ -207,7 +207,7 @@ public void stripNbtFromItemEntity(UUID entityId) {

if (entity instanceof EntityItem) {
EntityItem item = (EntityItem) entity;
if (item.v() == null) return;
if (item.q() == null) return;
if (!item.q().u()) return;
item.q().c((NBTTagCompound) null);
}
Expand Down
4 changes: 4 additions & 0 deletions craftbukkit-v1_20_R3/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dependencies {
compileOnly project(':panilla-api')
compileOnly 'org.spigotmc:spigot:1.20.4-R0.1-SNAPSHOT'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.ruinscraft.panilla.craftbukkit.v1_20_R3;

import com.ruinscraft.panilla.api.IInventoryCleaner;
import com.ruinscraft.panilla.api.IPanilla;
import com.ruinscraft.panilla.api.IPanillaPlayer;
import com.ruinscraft.panilla.api.exception.FailedNbt;
import com.ruinscraft.panilla.api.nbt.INbtTagCompound;
import com.ruinscraft.panilla.api.nbt.checks.NbtChecks;
import com.ruinscraft.panilla.craftbukkit.v1_20_R3.nbt.NbtTagCompound;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.inventory.Container;
import net.minecraft.world.item.ItemStack;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;

public class InventoryCleaner implements IInventoryCleaner {

private final IPanilla panilla;

public InventoryCleaner(IPanilla panilla) {
this.panilla = panilla;
}

@Override
public void clean(IPanillaPlayer player) {
CraftPlayer craftPlayer = (CraftPlayer) player.getHandle();
Container container = craftPlayer.getHandle().bR;

for (int slot = 0; slot < container.i.size(); slot++) {
ItemStack itemStack = container.b(slot).g();

if (itemStack == null || !itemStack.u()) {
continue;
}

NBTTagCompound nmsTag = itemStack.w();
INbtTagCompound tag = new NbtTagCompound(nmsTag);
String itemName = itemStack.d().a();

if (nmsTag == null || itemName == null) {
continue;
}

FailedNbt failedNbt = NbtChecks.checkAll(tag, itemName, panilla);

if (FailedNbt.failsThreshold(failedNbt)) {
container.b(slot).g().c((NBTTagCompound) null);
} else if (FailedNbt.fails(failedNbt)) {
nmsTag.r(failedNbt.key);
container.b(slot).g().c(nmsTag);
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
package com.ruinscraft.panilla.craftbukkit.v1_20_R3.io;

import com.ruinscraft.panilla.api.IPanilla;
import com.ruinscraft.panilla.api.IPanillaPlayer;
import com.ruinscraft.panilla.api.exception.EntityNbtNotPermittedException;
import com.ruinscraft.panilla.api.exception.FailedNbt;
import com.ruinscraft.panilla.api.exception.NbtNotPermittedException;
import com.ruinscraft.panilla.api.io.IPacketInspector;
import com.ruinscraft.panilla.api.nbt.INbtTagCompound;
import com.ruinscraft.panilla.api.nbt.checks.NbtChecks;
import com.ruinscraft.panilla.craftbukkit.v1_20_R3.nbt.NbtTagCompound;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.chat.IChatBaseComponent;
import net.minecraft.network.protocol.game.PacketPlayInSetCreativeSlot;
import net.minecraft.network.protocol.game.PacketPlayOutSetSlot;
import net.minecraft.network.protocol.game.PacketPlayOutSpawnEntity;
import net.minecraft.network.protocol.game.PacketPlayOutWindowItems;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.EntityPlayer;
import net.minecraft.server.level.WorldServer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.EntityItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.World;
import net.minecraft.world.level.block.Blocks;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
import java.util.List;
import java.util.UUID;

public class PacketInspector implements IPacketInspector {

private static boolean paperChunkSystem = false;
private static MethodHandle getEntityLookupMethodHandle = null;
private static MethodHandle getEntityMethodHandle = null;

static {
try {
Class<?> entityLookupClass = Class.forName("io.papermc.paper.chunk.system.entity.EntityLookup");
getEntityLookupMethodHandle = MethodHandles.lookup().findVirtual(WorldServer.class, "getEntityLookup", MethodType.methodType(entityLookupClass));
getEntityMethodHandle = MethodHandles.lookup().findVirtual(entityLookupClass, "get", MethodType.methodType(Entity.class, UUID.class));
paperChunkSystem = true;
} catch (ClassNotFoundException ignored) {
} catch (NoSuchMethodException | IllegalAccessException e) {
e.printStackTrace();
}
}

private Entity getChunkSystemEntity(WorldServer worldServer, UUID entityId) {
try {
Object entityLookup = getEntityLookupMethodHandle.invoke(worldServer);
return (Entity) getEntityMethodHandle.invoke(entityLookup, entityId);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}

private final IPanilla panilla;

public PacketInspector(IPanilla panilla) {
this.panilla = panilla;
}

@Override
public void checkPacketPlayInSetCreativeSlot(Object _packet) throws NbtNotPermittedException {
if (_packet instanceof PacketPlayInSetCreativeSlot) {
PacketPlayInSetCreativeSlot packet = (PacketPlayInSetCreativeSlot) _packet;

int slot = packet.a();
ItemStack itemStack = packet.d();

if (itemStack == null || !itemStack.u()) return;

NbtTagCompound tag = new NbtTagCompound(itemStack.w());
String itemClass = itemStack.q();
String packetClass = "PacketPlayInSetCreativeSlot";

NbtChecks.checkPacketPlayIn(slot, tag, itemClass, packetClass, panilla);
}
}

@Override
public void checkPacketPlayOutSetSlot(Object _packet) throws NbtNotPermittedException {
if (_packet instanceof PacketPlayOutSetSlot) {
PacketPlayOutSetSlot packet = (PacketPlayOutSetSlot) _packet;

int windowId = packet.a();

// check if window is not player inventory and we are ignoring non-player inventories
if (windowId != 0 && panilla.getPConfig().ignoreNonPlayerInventories) {
return;
}

int slot = packet.a();

ItemStack itemStack = packet.e();

if (itemStack == null || !itemStack.u()) {
return;
}

NbtTagCompound tag = new NbtTagCompound(itemStack.w());
String itemClass = itemStack.getClass().getSimpleName();
String packetClass = packet.getClass().getSimpleName();

NbtChecks.checkPacketPlayOut(slot, tag, itemClass, packetClass, panilla);
}
}

@Override
public void checkPacketPlayOutWindowItems(Object _packet) throws NbtNotPermittedException {
if (_packet instanceof PacketPlayOutWindowItems) {
PacketPlayOutWindowItems packet = (PacketPlayOutWindowItems) _packet;

int windowId = packet.a();

// check if window is not player inventory
if (windowId != 0) {
return;
}

List<ItemStack> itemStacks = packet.d();

for (ItemStack itemStack : itemStacks) {
if (itemStack == null || !itemStack.u()) {
continue;
}

NbtTagCompound tag = new NbtTagCompound(itemStack.w());
String itemClass = itemStack.getClass().getSimpleName();
String packetClass = packet.getClass().getSimpleName();

NbtChecks.checkPacketPlayOut(0, tag, itemClass, packetClass, panilla); // TODO: set slot?
}
}
}

@Override
public void checkPacketPlayOutSpawnEntity(Object _packet) throws EntityNbtNotPermittedException {
if (_packet instanceof PacketPlayOutSpawnEntity) {
PacketPlayOutSpawnEntity packet = (PacketPlayOutSpawnEntity) _packet;

UUID entityId = packet.d();
Entity entity = null;

for (WorldServer worldServer : MinecraftServer.getServer().H()) {
entity = paperChunkSystem ? getChunkSystemEntity(worldServer, entityId) : worldServer.M.d().a(entityId);
if (entity != null) break;
}

if (entity != null) {
if (entity instanceof EntityItem) {
EntityItem item = (EntityItem) entity;

if (item.q() == null) {
return;
}

if (!item.q().u()) {
return;
}

INbtTagCompound tag = new NbtTagCompound(item.q().w());
String itemName = item.q().d().a();
FailedNbt failedNbt = NbtChecks.checkAll(tag, itemName, panilla);

if (FailedNbt.fails(failedNbt)) {
String worldName = "";

try {
Field worldField = Entity.class.getDeclaredField("t");
worldField.setAccessible(true);
World world = (World) worldField.get(entity);
worldName = world.getWorld().getName();
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}

throw new EntityNbtNotPermittedException(packet.getClass().getSimpleName(), false, failedNbt, entityId, worldName);
}
}
}
}
}

@Override
public void sendPacketPlayOutSetSlotAir(IPanillaPlayer player, int slot) {
CraftPlayer craftPlayer = (CraftPlayer) player.getHandle();
EntityPlayer entityPlayer = craftPlayer.getHandle();
PacketPlayOutSetSlot packet = new PacketPlayOutSetSlot(entityPlayer.bR.j, entityPlayer.bR.k(), slot, new ItemStack(Blocks.a));
entityPlayer.c.b(packet);
}

@Override
public void stripNbtFromItemEntity(UUID entityId) {
Entity entity = null;

for (WorldServer worldServer : MinecraftServer.getServer().H()) {
entity = paperChunkSystem ? getChunkSystemEntity(worldServer, entityId) : worldServer.M.d().a(entityId);
if (entity != null) break;
}

if (entity instanceof EntityItem) {
EntityItem item = (EntityItem) entity;
if (item.q() == null) return;
if (!item.q().u()) return;
item.q().c((NBTTagCompound) null);
}
}

@Override
public void stripNbtFromItemEntityLegacy(int entityId) {
throw new RuntimeException("cannot use #stripNbtFromItemEntityLegacy on 1.20.2");
}

@Override
public void validateBaseComponentParse(String string) throws Exception {
IChatBaseComponent.ChatSerializer.a(string);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.ruinscraft.panilla.craftbukkit.v1_20_R3.io;

import com.ruinscraft.panilla.api.IPanillaPlayer;
import com.ruinscraft.panilla.api.io.IPlayerInjector;
import io.netty.channel.Channel;
import io.netty.handler.codec.ByteToMessageDecoder;
import net.minecraft.network.NetworkManager;
import net.minecraft.server.level.EntityPlayer;
import net.minecraft.server.network.PlayerConnection;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer;

import java.lang.reflect.Field;

public class PlayerInjector implements IPlayerInjector {

@Override
public Channel getPlayerChannel(IPanillaPlayer player) throws IllegalArgumentException {
CraftPlayer craftPlayer = (CraftPlayer) player.getHandle();
EntityPlayer entityPlayer = craftPlayer.getHandle();
PlayerConnection playerConnection = entityPlayer.c;

try {
Field networkManagerField = PlayerConnection.class.getSuperclass().getDeclaredField("c");
networkManagerField.setAccessible(true);
NetworkManager networkManager = (NetworkManager) networkManagerField.get(playerConnection);
return networkManager.n;
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}

@Override
public int getCompressionLevel() {
return 256;
}

@Override
public ByteToMessageDecoder getDecompressor() {
return null;
}

@Override
public ByteToMessageDecoder getDecoder() {
throw new RuntimeException("Not implemented");
}

}
Loading

0 comments on commit 4683ed8

Please sign in to comment.