Skip to content

Commit

Permalink
Added support to 1.20.2
Browse files Browse the repository at this point in the history
  • Loading branch information
OmerBenGera committed Sep 23, 2023
1 parent 5e7ef98 commit 5060e71
Show file tree
Hide file tree
Showing 12 changed files with 1,186 additions and 2 deletions.
36 changes: 36 additions & 0 deletions NMS/v1_20_2/build.gradle
@@ -0,0 +1,36 @@
plugins {
id("io.papermc.paperweight.userdev") version "1.3.8"
}

java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}

group 'NMS:v1_20_2'

dependencies {
paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.20.2-R0.1-SNAPSHOT")
compileOnly project(":API")
compileOnly rootProject
}

shadowJar {
archiveFileName = "${project.name}-exclude.jar"
}

assemble {
dependsOn(reobfJar)
}

tasks {
reobfJar {
File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar")
outputJar.set(layout.buildDirectory.file(outputFile.getPath()))
}
}

if (project.hasProperty('nms.compile_v1_20') && !Boolean.valueOf(project.findProperty("nms.compile_v1_20").toString())) {
project.tasks.all { task -> task.enabled = false }
}
@@ -0,0 +1,212 @@
package com.bgsoftware.wildchests.nms.v1_20_2;

import com.bgsoftware.wildchests.api.objects.ChestType;
import com.bgsoftware.wildchests.objects.inventory.InventoryHolder;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtIo;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.ChestBlockEntity;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R2.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack;
import org.bukkit.entity.HumanEntity;
import org.bukkit.inventory.Inventory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.math.BigInteger;
import java.util.Base64;

public final class NMSAdapter implements com.bgsoftware.wildchests.nms.NMSAdapter {

@Override
public String serialize(org.bukkit.inventory.ItemStack bukkitItem) {
ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);

if (itemStack.isEmpty())
return "";

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
DataOutput dataOutput = new DataOutputStream(outputStream);

CompoundTag compoundTag = new CompoundTag();

itemStack.setCount(1);
itemStack.save(compoundTag);

try {
NbtIo.write(compoundTag, dataOutput);
} catch (Exception ex) {
return null;
}

return "*" + new String(Base64.getEncoder().encode(outputStream.toByteArray()));
}

@Override
public String serialize(Inventory[] inventories) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
DataOutput dataOutput = new DataOutputStream(outputStream);

CompoundTag compoundTag = new CompoundTag();
compoundTag.putInt("Length", inventories.length);

for (int slot = 0; slot < inventories.length; slot++) {
CompoundTag inventoryCompound = new CompoundTag();
serialize(inventories[slot], inventoryCompound);
compoundTag.put(slot + "", inventoryCompound);
}

try {
NbtIo.write(compoundTag, dataOutput);
} catch (Exception ex) {
return null;
}

return "*" + new String(Base64.getEncoder().encode(outputStream.toByteArray()));
}

@Override
public InventoryHolder[] deserialze(String serialized) {
byte[] buff;

if (serialized.toCharArray()[0] == '*') {
buff = Base64.getDecoder().decode(serialized.substring(1));
} else {
buff = new BigInteger(serialized, 32).toByteArray();
}

ByteArrayInputStream inputStream = new ByteArrayInputStream(buff);
InventoryHolder[] inventories = new InventoryHolder[0];

try {
CompoundTag compoundTag = NbtIo.read(new DataInputStream(inputStream));
int length = compoundTag.getInt("Length");
inventories = new InventoryHolder[length];

for (int i = 0; i < length; i++) {
if (compoundTag.contains(i + "")) {
CompoundTag itemCompound = compoundTag.getCompound(i + "");
inventories[i] = deserialize(itemCompound);
}
}

} catch (Exception ex) {
ex.printStackTrace();
}

return inventories;
}

@Override
public org.bukkit.inventory.ItemStack deserialzeItem(String serialized) {
if (serialized.isEmpty())
return new org.bukkit.inventory.ItemStack(Material.AIR);

byte[] buff;

if (serialized.toCharArray()[0] == '*') {
buff = Base64.getDecoder().decode(serialized.substring(1));
} else {
buff = new BigInteger(serialized, 32).toByteArray();
}

ByteArrayInputStream inputStream = new ByteArrayInputStream(buff);

try {
CompoundTag compoundTag = NbtIo.read(new DataInputStream(inputStream));
ItemStack itemStack = ItemStack.of(compoundTag);
return CraftItemStack.asBukkitCopy(itemStack);
} catch (Exception ex) {
return null;
}
}

@Override
public void playChestAction(Location location, boolean open) {
World bukkitWorld = location.getWorld();

if (bukkitWorld == null)
return;

ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();
BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ());
BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos);
if (blockEntity instanceof ChestBlockEntity)
serverLevel.blockEvent(blockPos, blockEntity.getBlockState().getBlock(), 1, open ? 1 : 0);
}

@Override
public org.bukkit.inventory.ItemStack setChestType(org.bukkit.inventory.ItemStack itemStack, ChestType chestType) {
return setItemTag(itemStack, "chest-type", chestType.name());
}

@Override
public org.bukkit.inventory.ItemStack setChestName(org.bukkit.inventory.ItemStack itemStack, String chestName) {
return setItemTag(itemStack, "chest-name", chestName);
}

@Override
public String getChestName(org.bukkit.inventory.ItemStack bukkitItem) {
ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);
CompoundTag compoundTag = itemStack.getTag();
return compoundTag == null || !compoundTag.contains("chest-name") ? null :
compoundTag.getString("chest-name");
}

@Override
public void dropItemAsPlayer(HumanEntity humanEntity, org.bukkit.inventory.ItemStack bukkitItem) {
Player player = ((CraftHumanEntity) humanEntity).getHandle();
ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);
player.drop(itemStack, false);
}

private org.bukkit.inventory.ItemStack setItemTag(org.bukkit.inventory.ItemStack bukkitItem, String key, String value) {
ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem);
CompoundTag compoundTag = itemStack.getOrCreateTag();
compoundTag.putString(key, value);
return CraftItemStack.asCraftMirror(itemStack);
}

private static void serialize(Inventory inventory, CompoundTag compoundTag) {
ListTag itemsList = new ListTag();
org.bukkit.inventory.ItemStack[] items = inventory.getContents();

for (int i = 0; i < items.length; ++i) {
if (items[i] != null) {
ItemStack itemStack = CraftItemStack.asNMSCopy(items[i]);
CompoundTag itemTag = new CompoundTag();
itemTag.putByte("Slot", (byte) i);
itemStack.save(itemTag);
itemsList.add(itemTag);
}
}

compoundTag.putInt("Size", inventory.getSize());
compoundTag.put("Items", itemsList);
}

private static InventoryHolder deserialize(CompoundTag compoundTag) {
InventoryHolder inventory = new InventoryHolder(compoundTag.getInt("Size"), "Chest");
ListTag itemsList = compoundTag.getList("Items", 10);

for (int i = 0; i < itemsList.size(); i++) {
CompoundTag itemTag = itemsList.getCompound(i);
inventory.setItem(itemTag.getByte("Slot"), CraftItemStack.asBukkitCopy(ItemStack.of(itemTag)));
}

return inventory;
}

}
@@ -0,0 +1,137 @@
package com.bgsoftware.wildchests.nms.v1_20_2;

import com.bgsoftware.common.reflection.ReflectMethod;
import com.bgsoftware.wildchests.api.objects.chests.Chest;
import com.bgsoftware.wildchests.api.objects.chests.StorageChest;
import com.bgsoftware.wildchests.nms.v1_20_2.inventory.CraftWildInventoryImpl;
import com.bgsoftware.wildchests.nms.v1_20_2.inventory.WildChestBlockEntity;
import com.bgsoftware.wildchests.nms.v1_20_2.inventory.WildChestMenu;
import com.bgsoftware.wildchests.nms.v1_20_2.inventory.WildContainer;
import com.bgsoftware.wildchests.nms.v1_20_2.inventory.WildContainerItemImpl;
import com.bgsoftware.wildchests.nms.v1_20_2.inventory.WildHopperMenu;
import com.bgsoftware.wildchests.objects.chests.WChest;
import com.bgsoftware.wildchests.objects.inventory.CraftWildInventory;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.ByteTag;
import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.TickingBlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_20_R2.util.CraftChatMessage;
import org.bukkit.entity.Player;

public final class NMSInventory implements com.bgsoftware.wildchests.nms.NMSInventory {

private static final ReflectMethod<TickingBlockEntity> CREATE_TICKING_BLOCK = new ReflectMethod<>(
LevelChunk.class, "a", BlockEntity.class, BlockEntityTicker.class);

@Override
public void updateTileEntity(Chest chest) {
Location location = chest.getLocation();
World bukkitWorld = location.getWorld();

if (bukkitWorld == null)
throw new IllegalArgumentException("Cannot update tile entity of chests in null world.");

ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();
BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ());
BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos);

if (blockEntity instanceof WildChestBlockEntity wildChestBlockEntity) {
((WChest) chest).setTileEntityContainer(wildChestBlockEntity);
} else {
WildChestBlockEntity wildChestBlockEntity = new WildChestBlockEntity(chest, serverLevel, blockPos);
serverLevel.removeBlockEntity(blockPos);
serverLevel.setBlockEntity(wildChestBlockEntity);
LevelChunk levelChunk = serverLevel.getChunkAt(blockPos);
serverLevel.addBlockEntityTicker(CREATE_TICKING_BLOCK.invoke(levelChunk, wildChestBlockEntity, wildChestBlockEntity));
}
}

@Override
public void removeTileEntity(Chest chest) {
Location location = chest.getLocation();
World bukkitWorld = location.getWorld();

if (bukkitWorld == null)
throw new IllegalArgumentException("Cannot update tile entity of chests in null world.");

ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle();
BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ());
BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos);
if (blockEntity instanceof WildChestBlockEntity)
serverLevel.removeBlockEntity(blockPos);
}

@Override
public WildContainerItemImpl createItemStack(org.bukkit.inventory.ItemStack bukkitItem) {
return new WildContainerItemImpl(CraftItemStack.asNMSCopy(bukkitItem));
}

@Override
public CraftWildInventory createInventory(Chest chest, int size, String title, int index) {
WildContainer wildContainer = new WildContainer(size, title, chest, index);

if (chest instanceof StorageChest)
wildContainer.setItemFunction = (slot, itemStack) -> chest.setItem(slot, CraftItemStack.asCraftMirror(itemStack));

return new CraftWildInventoryImpl(wildContainer);
}

@Override
public void openPage(Player player, CraftWildInventory inventory) {
ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
String title = inventory.getTitle();

AbstractContainerMenu containerMenu = createMenu(serverPlayer.nextContainerCounter(), serverPlayer.getInventory(), inventory);
containerMenu.setTitle(CraftChatMessage.fromStringOrNull(title));

// Cursor item is not updated, so we need to update it manually
org.bukkit.inventory.ItemStack cursorItem = player.getItemOnCursor();

ClientboundOpenScreenPacket openScreenPacket = new ClientboundOpenScreenPacket(containerMenu.containerId,
containerMenu.getType(), containerMenu.getTitle());

serverPlayer.connection.send(openScreenPacket);
serverPlayer.containerMenu = containerMenu;
serverPlayer.initMenu(containerMenu);

player.setItemOnCursor(cursorItem);
}

@Override
public void createDesignItem(CraftWildInventory craftWildInventory,
org.bukkit.inventory.ItemStack itemStack) {
ItemStack designItem = CraftItemStack.asNMSCopy(itemStack == null || itemStack.getType() == Material.AIR ?
new org.bukkit.inventory.ItemStack(Material.BLACK_STAINED_GLASS_PANE) : itemStack.clone());

designItem.setCount(1);
designItem.addTagElement("DesignItem", ByteTag.valueOf(true));

WildContainer container = ((CraftWildInventoryImpl) craftWildInventory).getInventory();
container.setItem(0, designItem, false);
container.setItem(1, designItem, false);
container.setItem(3, designItem, false);
container.setItem(4, designItem, false);
}

public static AbstractContainerMenu createMenu(int id, Inventory playerInventory,
CraftWildInventory craftWildInventory) {
WildContainer container = ((CraftWildInventoryImpl) craftWildInventory).getInventory();
return container.getContainerSize() == 5 ? WildHopperMenu.of(id, playerInventory, container) :
WildChestMenu.of(id, playerInventory, container);
}

}

0 comments on commit 5060e71

Please sign in to comment.