diff --git a/.github/actions/setup_project_workspace/action.yml b/.github/actions/setup_project_workspace/action.yml index baedbb77..5df0e19d 100644 --- a/.github/actions/setup_project_workspace/action.yml +++ b/.github/actions/setup_project_workspace/action.yml @@ -56,7 +56,7 @@ runs: - uses: SpraxDev/Action-SpigotMC@v5 with: - versions: 1.20.6 + versions: 1.20.6, 1.21 remapped: true sftpCacheHost: ${{ inputs.spigot_buildtools_sftp_host }} sftpCachePort: ${{ inputs.spigot_buildtools_sftp_port }} diff --git a/Compatibility/src/main/java/com/craftaro/core/compatibility/ServerVersion.java b/Compatibility/src/main/java/com/craftaro/core/compatibility/ServerVersion.java index 8ff39406..bdd4883e 100644 --- a/Compatibility/src/main/java/com/craftaro/core/compatibility/ServerVersion.java +++ b/Compatibility/src/main/java/com/craftaro/core/compatibility/ServerVersion.java @@ -26,6 +26,7 @@ public enum ServerVersion { VERSION_TO_REVISION.put("1.20.4", "v1_20_R3"); VERSION_TO_REVISION.put("1.20.5", "v1_20_R4"); VERSION_TO_REVISION.put("1.20.6", "v1_20_R4"); + VERSION_TO_REVISION.put("1.21", "v1_21_R1"); if (Bukkit.getServer() != null) { String srvPackage = Bukkit.getServer().getClass().getPackage().getName(); diff --git a/NMS/NMS-v1_21_R1/pom.xml b/NMS/NMS-v1_21_R1/pom.xml new file mode 100644 index 00000000..8c4bbcd0 --- /dev/null +++ b/NMS/NMS-v1_21_R1/pom.xml @@ -0,0 +1,89 @@ + + + 4.0.0 + + + com.craftaro + CraftaroCore-Modules + 3.0.8-SNAPSHOT + ../../pom.xml + + CraftaroCore-NMS-v1_21_R1 + + + 21 + 21 + + 1.21-R0.1-SNAPSHOT + + + + + + net.md-5 + specialsource-maven-plugin + 2.0.3 + + + + remap-obf + package + + remap + + + + org.spigotmc:minecraft-server:${nms.ver}:txt:maps-mojang + true + org.spigotmc:spigot:${nms.ver}:jar:remapped-mojang + true + remapped-obf + + + + + remap-spigot + package + + remap + + + + ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar + org.spigotmc:minecraft-server:${nms.ver}:csrg:maps-spigot + org.spigotmc:spigot:${nms.ver}:jar:remapped-obf + + + + + + + + + + + org.spigotmc + spigot + ${nms.ver} + remapped-mojang + provided + + + + + ${project.groupId} + CraftaroCore-NMS-API + ${project.version} + provided + + + + ${project.groupId} + CraftaroCore-Compatibility + ${project.version} + provided + + + diff --git a/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/NmsImplementationsImpl.java b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/NmsImplementationsImpl.java new file mode 100644 index 00000000..f0f72375 --- /dev/null +++ b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/NmsImplementationsImpl.java @@ -0,0 +1,63 @@ +package com.craftaro.core.nms.v1_21_R1; + +import com.craftaro.core.nms.NmsImplementations; +import com.craftaro.core.nms.entity.NMSPlayer; +import com.craftaro.core.nms.entity.NmsEntity; +import com.craftaro.core.nms.nbt.NBTCore; +import com.craftaro.core.nms.v1_21_R1.anvil.AnvilCore; +import com.craftaro.core.nms.v1_21_R1.entity.NMSPlayerImpl; +import com.craftaro.core.nms.v1_21_R1.entity.NmsEntityImpl; +import com.craftaro.core.nms.v1_21_R1.nbt.NBTCoreImpl; +import com.craftaro.core.nms.v1_21_R1.world.NmsWorldBorderImpl; +import com.craftaro.core.nms.v1_21_R1.world.WorldCoreImpl; +import com.craftaro.core.nms.world.NmsWorldBorder; +import com.craftaro.core.nms.world.WorldCore; +import org.jetbrains.annotations.NotNull; + +public class NmsImplementationsImpl implements NmsImplementations { + private final NmsEntity entity; + private final NMSPlayer player; + private final WorldCore world; + private final NmsWorldBorder worldBorder; + private final com.craftaro.core.nms.anvil.AnvilCore anvil; + private final NBTCore nbt; + + public NmsImplementationsImpl() { + this.entity = new NmsEntityImpl(); + this.player = new NMSPlayerImpl(); + this.world = new WorldCoreImpl(); + this.worldBorder = new NmsWorldBorderImpl(); + this.anvil = new AnvilCore(); + this.nbt = new NBTCoreImpl(); + } + + @Override + public @NotNull NmsEntity getEntity() { + return this.entity; + } + + @Override + public @NotNull NMSPlayer getPlayer() { + return this.player; + } + + @Override + public @NotNull WorldCore getWorld() { + return this.world; + } + + @Override + public @NotNull NmsWorldBorder getWorldBorder() { + return this.worldBorder; + } + + @Override + public @NotNull com.craftaro.core.nms.anvil.AnvilCore getAnvil() { + return this.anvil; + } + + @Override + public @NotNull NBTCore getNbt() { + return this.nbt; + } +} diff --git a/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/anvil/AnvilCore.java b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/anvil/AnvilCore.java new file mode 100644 index 00000000..eb2d7b26 --- /dev/null +++ b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/anvil/AnvilCore.java @@ -0,0 +1,21 @@ +package com.craftaro.core.nms.v1_21_R1.anvil; + +import com.craftaro.core.nms.anvil.CustomAnvil; +import net.minecraft.server.level.ServerPlayer; +import org.bukkit.craftbukkit.v1_21_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; + +public class AnvilCore implements com.craftaro.core.nms.anvil.AnvilCore { + @Override + public CustomAnvil createAnvil(Player player) { + ServerPlayer p = ((CraftPlayer) player).getHandle(); + return new AnvilView(p.nextContainerCounter(), p, null); + } + + @Override + public CustomAnvil createAnvil(Player player, InventoryHolder holder) { + ServerPlayer p = ((CraftPlayer) player).getHandle(); + return new AnvilView(p.nextContainerCounter(), p, holder); + } +} diff --git a/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/anvil/AnvilInventoryCustom.java b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/anvil/AnvilInventoryCustom.java new file mode 100644 index 00000000..15d1cb18 --- /dev/null +++ b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/anvil/AnvilInventoryCustom.java @@ -0,0 +1,22 @@ +package com.craftaro.core.nms.v1_21_R1.anvil; + +import net.minecraft.world.Container; +import net.minecraft.world.inventory.AnvilMenu; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftInventoryAnvil; +import org.bukkit.inventory.InventoryHolder; + +public class AnvilInventoryCustom extends CraftInventoryAnvil { + final InventoryHolder holder; + + public AnvilInventoryCustom(InventoryHolder holder, Location location, Container inventory, Container resultInventory, AnvilMenu container) { + super(location, inventory, resultInventory, container); + + this.holder = holder; + } + + @Override + public InventoryHolder getHolder() { + return this.holder; + } +} diff --git a/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/anvil/AnvilView.java b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/anvil/AnvilView.java new file mode 100644 index 00000000..c7512a21 --- /dev/null +++ b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/anvil/AnvilView.java @@ -0,0 +1,197 @@ +package com.craftaro.core.nms.v1_21_R1.anvil; + +import com.craftaro.core.nms.anvil.CustomAnvil; +import com.craftaro.core.nms.anvil.methods.AnvilTextChange; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.contents.TranslatableContents; +import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.AnvilMenu; +import net.minecraft.world.inventory.ContainerLevelAccess; +import net.minecraft.world.inventory.MenuType; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftInventoryView; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; + +import java.lang.reflect.Field; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class AnvilView extends AnvilMenu implements CustomAnvil { + private final ServerPlayer entity; + private final Inventory inventory; + private String customTitle = "Repairing"; + private int cost = -1; + private boolean canUse = true; + private AnvilTextChange textChange; + + static Field mc_Container_title; + static Field mc_ContainerAnvil_bukkitEntity; + + static { + try { + mc_Container_title = AbstractContainerMenu.class.getDeclaredField("title"); + mc_Container_title.setAccessible(true); + + mc_ContainerAnvil_bukkitEntity = AnvilMenu.class.getDeclaredField("bukkitEntity"); + mc_ContainerAnvil_bukkitEntity.setAccessible(true); + } catch (Exception ex) { + Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Setup Error", ex); + } + } + + public AnvilView(int id, ServerPlayer entity, InventoryHolder holder) { + super(entity.nextContainerCounter(), entity.getInventory(), ContainerLevelAccess.create(entity.level(), new BlockPos(0, 0, 0))); + + this.setTitle(MutableComponent.create(new TranslatableContents(this.customTitle != null ? this.customTitle : "", this.customTitle != null ? this.customTitle : "", new Object[0]))); + this.checkReachable = false; + this.entity = entity; + + if (holder != null) { + this.inventory = getBukkitView(entity, holder).getTopInventory(); + } else { + this.inventory = getBukkitView().getTopInventory(); + } + } + + public CraftInventoryView getBukkitView(Player player, InventoryHolder holder) { + try { + AnvilInventoryCustom craftInventory = new AnvilInventoryCustom(holder, + new Location(this.entity.level().getWorld(), 0, 0, 0), + this.inputSlots, + this.resultSlots, + this); + CraftInventoryView view = new CraftInventoryView(player.getBukkitEntity(), craftInventory, this); + mc_ContainerAnvil_bukkitEntity.set(this, view); + + return view; + } catch (Exception ex) { + Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Setup Error", ex); + } + + return getBukkitView(); + } + + @Override + public boolean stillValid(Player entityhuman) { + return this.canUse; + } + + @Override + public void broadcastFullState() { + super.broadcastFullState(); + + if (this.cost >= 0) { + this.setLevelCost(this.cost); + } + + this.textChange.onChange(); + } + + @Override + public void update() { + broadcastFullState(); + } + + @Override + public String getRenameText() { + return this.itemName; + } + + @Override + public void setRenameText(String text) { + this.setItemName(text); + } + + @Override + public void setOnChange(AnvilTextChange handler) { + this.textChange = handler; + } + + @Override + public String getCustomTitle() { + return this.customTitle; + } + + @Override + public void setCustomTitle(String title) { + this.customTitle = title; + + try { + mc_Container_title.set(this, MutableComponent.create(new TranslatableContents(this.customTitle != null ? this.customTitle : "", this.customTitle != null ? this.customTitle : "", new Object[0]))); + } catch (Exception ex) { + Logger.getLogger(AnvilView.class.getName()).log(Level.SEVERE, "Anvil Error", ex); + } + } + + @Override + public void setLevelCost(int cost) { + this.cost = cost; + } + + @Override + public int getLevelCost() { + if (this.cost >= 0) { + return this.cost; + } + + return this.getLevelCost(); + } + + @Override + public void setCanUse(boolean bool) { + this.canUse = bool; + } + + @Override + public ItemStack getLeftInput() { + return this.inventory.getItem(0); + } + + @Override + public ItemStack getRightInput() { + return this.inventory.getItem(1); + } + + @Override + public ItemStack getOutput() { + return this.inventory.getItem(2); + } + + @Override + public void setLeftInput(ItemStack item) { + this.inventory.setItem(0, item); + } + + @Override + public void setRightInput(ItemStack item) { + this.inventory.setItem(1, item); + } + + @Override + public void setOutput(ItemStack item) { + this.inventory.setItem(2, item); + } + + @Override + public Inventory getInventory() { + return this.inventory; + } + + @Override + public void open() { + // Send the packet + this.entity.connection.send(new ClientboundOpenScreenPacket(super.containerId, MenuType.ANVIL, MutableComponent.create(new TranslatableContents(this.customTitle != null ? this.customTitle : "", this.customTitle != null ? this.customTitle : "", new Object[0])))); + + // Set their active container to this anvil + this.entity.containerMenu = this; + + // Add the slot listener + this.entity.initMenu(this.entity.containerMenu); + } +} diff --git a/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/entity/NMSPlayerImpl.java b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/entity/NMSPlayerImpl.java new file mode 100644 index 00000000..29280549 --- /dev/null +++ b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/entity/NMSPlayerImpl.java @@ -0,0 +1,13 @@ +package com.craftaro.core.nms.v1_21_R1.entity; + +import com.craftaro.core.nms.entity.NMSPlayer; +import net.minecraft.network.protocol.Packet; +import org.bukkit.craftbukkit.v1_21_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; + +public class NMSPlayerImpl implements NMSPlayer { + @Override + public void sendPacket(Player p, Object packet) { + ((CraftPlayer) p).getHandle().connection.send((Packet) packet); + } +} diff --git a/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/entity/NmsEntityImpl.java b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/entity/NmsEntityImpl.java new file mode 100644 index 00000000..2ff0078a --- /dev/null +++ b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/entity/NmsEntityImpl.java @@ -0,0 +1,33 @@ +package com.craftaro.core.nms.v1_21_R1.entity; + +import com.craftaro.core.nms.entity.NmsEntity; +import net.minecraft.world.entity.Mob; +import org.bukkit.craftbukkit.v1_21_R1.entity.CraftEntity; +import org.bukkit.entity.Entity; + +public class NmsEntityImpl implements NmsEntity { + @Override + public boolean isMob(Entity entity) { + return ((CraftEntity) entity).getHandle() instanceof Mob; + } + + @Override + public void setMobAware(Entity entity, boolean aware) { + if (!isMob(entity)) { + throw new IllegalArgumentException("Entity is not a mob and cannot be set aware"); + } + + var nmsEntity = ((CraftEntity) entity).getHandle(); + ((Mob) nmsEntity).aware = aware; + } + + @Override + public boolean isAware(Entity entity) { + var nmsEntity = ((CraftEntity) entity).getHandle(); + if (nmsEntity instanceof Mob nmsMob) { + return nmsMob.aware; + } + + return false; + } +} diff --git a/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/nbt/NBTCompoundImpl.java b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/nbt/NBTCompoundImpl.java new file mode 100644 index 00000000..92bc607b --- /dev/null +++ b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/nbt/NBTCompoundImpl.java @@ -0,0 +1,209 @@ +package com.craftaro.core.nms.v1_21_R1.nbt; + +import com.craftaro.core.nms.nbt.NBTCompound; +import com.craftaro.core.nms.nbt.NBTObject; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtAccounter; +import net.minecraft.nbt.NbtIo; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Set; +import java.util.UUID; + +public class NBTCompoundImpl implements NBTCompound { + protected CompoundTag compound; + + protected NBTCompoundImpl(CompoundTag compound) { + this.compound = compound; + } + + public NBTCompoundImpl() { + this.compound = new CompoundTag(); + } + + @Override + public NBTCompound set(String tag, String s) { + this.compound.putString(tag, s); + return this; + } + + @Override + public NBTCompound set(String tag, boolean b) { + this.compound.putBoolean(tag, b); + return this; + } + + @Override + public NBTCompound set(String tag, int i) { + this.compound.putInt(tag, i); + return this; + } + + @Override + public NBTCompound set(String tag, double i) { + this.compound.putDouble(tag, i); + return this; + } + + @Override + public NBTCompound set(String tag, long l) { + this.compound.putLong(tag, l); + return this; + } + + @Override + public NBTCompound set(String tag, short s) { + this.compound.putShort(tag, s); + return this; + } + + @Override + public NBTCompound set(String tag, byte b) { + this.compound.putByte(tag, b); + return this; + } + + @Override + public NBTCompound set(String tag, int[] i) { + this.compound.putIntArray(tag, i); + return this; + } + + @Override + public NBTCompound set(String tag, byte[] b) { + this.compound.putByteArray(tag, b); + return this; + } + + @Override + public NBTCompound set(String tag, UUID u) { + this.compound.putUUID(tag, u); + return this; + } + + @Override + public NBTCompound remove(String tag) { + this.compound.remove(tag); + return this; + } + + @Override + public boolean has(String tag) { + return this.compound.contains(tag); + } + + @Override + public NBTObject getNBTObject(String tag) { + return new NBTObjectImpl(this.compound, tag); + } + + @Override + public String getString(String tag) { + return getNBTObject(tag).asString(); + } + + @Override + public boolean getBoolean(String tag) { + return getNBTObject(tag).asBoolean(); + } + + @Override + public int getInt(String tag) { + return getNBTObject(tag).asInt(); + } + + @Override + public double getDouble(String tag) { + return getNBTObject(tag).asDouble(); + } + + @Override + public long getLong(String tag) { + return getNBTObject(tag).asLong(); + } + + @Override + public short getShort(String tag) { + return getNBTObject(tag).asShort(); + } + + @Override + public byte getByte(String tag) { + return getNBTObject(tag).asByte(); + } + + @Override + public int[] getIntArray(String tag) { + return getNBTObject(tag).asIntArray(); + } + + @Override + public byte[] getByteArray(String tag) { + return getNBTObject(tag).asByteArray(); + } + + @Override + public NBTCompound getCompound(String tag) { + if (has(tag)) { + return getNBTObject(tag).asCompound(); + } + + CompoundTag newCompound = new CompoundTag(); + this.compound.put(tag, newCompound); + return new NBTCompoundImpl(newCompound); + } + + @Override + public Set getKeys() { + return this.compound.getAllKeys(); + } + + @Override + public Set getKeys(String tag) { + return this.compound.getCompound(tag).getAllKeys(); + } + + @Override + public byte[] serialize(String... exclusions) { + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ObjectOutputStream dataOutput = new ObjectOutputStream(outputStream)) { + addExtras(); + CompoundTag compound = this.compound.copy(); + + for (String exclusion : exclusions) { + compound.remove(exclusion); + } + + NbtIo.writeCompressed(compound, dataOutput); + + return outputStream.toByteArray(); + } catch (Exception ex) { + ex.printStackTrace(); + } + + return null; + } + + @Override + public void deSerialize(byte[] serialized) { + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(serialized); + ObjectInputStream dataInput = new ObjectInputStream(inputStream)) { + this.compound = NbtIo.readCompressed(dataInput, NbtAccounter.unlimitedHeap()); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + @Override + public void addExtras() { + // None + } + + @Override + public String toString() { + return this.compound.toString(); + } +} diff --git a/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/nbt/NBTCoreImpl.java b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/nbt/NBTCoreImpl.java new file mode 100644 index 00000000..4e2b442c --- /dev/null +++ b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/nbt/NBTCoreImpl.java @@ -0,0 +1,38 @@ +package com.craftaro.core.nms.v1_21_R1.nbt; + +import com.craftaro.core.nms.nbt.NBTCore; +import com.craftaro.core.nms.nbt.NBTEntity; +import com.craftaro.core.nms.nbt.NBTItem; +import net.minecraft.nbt.CompoundTag; +import org.bukkit.craftbukkit.v1_21_R1.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftItemStack; +import org.bukkit.entity.Entity; +import org.bukkit.inventory.ItemStack; + +public class NBTCoreImpl implements NBTCore { + @Deprecated + @Override + public NBTItem of(ItemStack item) { + return new NBTItemImpl(CraftItemStack.asNMSCopy(item)); + } + + @Deprecated + @Override + public NBTItem newItem() { + return new NBTItemImpl(null); + } + + @Override + public NBTEntity of(Entity entity) { + net.minecraft.world.entity.Entity nmsEntity = ((CraftEntity) entity).getHandle(); + CompoundTag nbt = new CompoundTag(); + nmsEntity.saveWithoutId(nbt); + + return new NBTEntityImpl(nbt, nmsEntity); + } + + @Override + public NBTEntity newEntity() { + return new NBTEntityImpl(new CompoundTag(), null); + } +} diff --git a/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/nbt/NBTEntityImpl.java b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/nbt/NBTEntityImpl.java new file mode 100644 index 00000000..44b517d1 --- /dev/null +++ b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/nbt/NBTEntityImpl.java @@ -0,0 +1,65 @@ +package com.craftaro.core.nms.v1_21_R1.nbt; + +import com.craftaro.core.nms.nbt.NBTEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobSpawnType; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_21_R1.CraftWorld; + +import java.util.Optional; + +public class NBTEntityImpl extends NBTCompoundImpl implements NBTEntity { + private Entity nmsEntity; + + public NBTEntityImpl(CompoundTag entityNBT, Entity nmsEntity) { + super(entityNBT); + + this.nmsEntity = nmsEntity; + } + + @Override + public org.bukkit.entity.Entity spawn(Location location) { + String entityType = getNBTObject("entity_type").asString(); + getKeys().remove("UUID"); + + Optional> optionalEntity = EntityType.byString(entityType); + if (optionalEntity.isPresent()) { + assert location.getWorld() != null; + + Entity spawned = optionalEntity.get().spawn( + ((CraftWorld) location.getWorld()).getHandle(), + null, + new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), + MobSpawnType.COMMAND, + true, + false + ); + + if (spawned != null) { + spawned.load(this.compound); + org.bukkit.entity.Entity entity = spawned.getBukkitEntity(); + entity.teleport(location); + this.nmsEntity = spawned; + + return entity; + } + } + + return null; + } + + @Override + public org.bukkit.entity.Entity reSpawn(Location location) { + this.nmsEntity.discard(); + return spawn(location); + } + + @Override + public void addExtras() { + this.compound.putString("entity_type", BuiltInRegistries.ENTITY_TYPE.getKey(this.nmsEntity.getType()).toString()); + } +} diff --git a/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/nbt/NBTItemImpl.java b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/nbt/NBTItemImpl.java new file mode 100644 index 00000000..ef713174 --- /dev/null +++ b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/nbt/NBTItemImpl.java @@ -0,0 +1,16 @@ +package com.craftaro.core.nms.v1_21_R1.nbt; + +import com.craftaro.core.nms.nbt.NBTItem; +import net.minecraft.world.item.ItemStack; + +public class NBTItemImpl extends NBTCompoundImpl implements NBTItem { + private final ItemStack nmsItem; + + public NBTItemImpl(ItemStack nmsItem) { + throw new UnsupportedOperationException("This constructor is not supported in this version of Minecraft."); + } + + public org.bukkit.inventory.ItemStack finish() { + throw new UnsupportedOperationException("This method is not supported in this version of Minecraft."); + } +} diff --git a/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/nbt/NBTObjectImpl.java b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/nbt/NBTObjectImpl.java new file mode 100644 index 00000000..7e60473f --- /dev/null +++ b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/nbt/NBTObjectImpl.java @@ -0,0 +1,72 @@ +package com.craftaro.core.nms.v1_21_R1.nbt; + +import com.craftaro.core.nms.nbt.NBTCompound; +import com.craftaro.core.nms.nbt.NBTObject; +import net.minecraft.nbt.CompoundTag; + +import java.util.Set; + +public class NBTObjectImpl implements NBTObject { + private final CompoundTag compound; + private final String tag; + + public NBTObjectImpl(CompoundTag compound, String tag) { + this.compound = compound; + this.tag = tag; + } + + @Override + public String asString() { + return this.compound.getString(this.tag); + } + + @Override + public boolean asBoolean() { + return this.compound.getBoolean(this.tag); + } + + @Override + public int asInt() { + return this.compound.getInt(this.tag); + } + + @Override + public double asDouble() { + return this.compound.getDouble(this.tag); + } + + @Override + public long asLong() { + return this.compound.getLong(this.tag); + } + + @Override + public short asShort() { + return this.compound.getShort(this.tag); + } + + @Override + public byte asByte() { + return this.compound.getByte(this.tag); + } + + @Override + public int[] asIntArray() { + return this.compound.getIntArray(this.tag); + } + + @Override + public byte[] asByteArray() { + return this.compound.getByteArray(this.tag); + } + + @Override + public NBTCompound asCompound() { + return new NBTCompoundImpl(this.compound.getCompound(this.tag)); + } + + @Override + public Set getKeys() { + return this.compound.getAllKeys(); + } +} diff --git a/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/NmsWorldBorderImpl.java b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/NmsWorldBorderImpl.java new file mode 100644 index 00000000..477b140e --- /dev/null +++ b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/NmsWorldBorderImpl.java @@ -0,0 +1,34 @@ +package com.craftaro.core.nms.v1_21_R1.world; + +import com.craftaro.core.nms.world.NmsWorldBorder; +import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; +import net.minecraft.world.level.border.WorldBorder; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_21_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Objects; + +public class NmsWorldBorderImpl implements NmsWorldBorder { + @Override + public void send(Player player, BorderColor color, double size, Location center) { + Objects.requireNonNull(center.getWorld()); + + WorldBorder worldBorder = new WorldBorder(); + worldBorder.world = ((CraftWorld) center.getWorld()).getHandle(); + + worldBorder.setCenter(center.getX(), center.getZ()); + worldBorder.setSize(size); + worldBorder.setWarningTime(0); + worldBorder.setWarningBlocks(0); + + if (color == BorderColor.GREEN) { + worldBorder.lerpSizeBetween(size - 0.1D, size, Long.MAX_VALUE); + } else if (color == BorderColor.RED) { + worldBorder.lerpSizeBetween(size, size - 1.0D, Long.MAX_VALUE); + } + + ((CraftPlayer) player).getHandle().connection.send(new ClientboundInitializeBorderPacket(worldBorder)); + } +} diff --git a/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/SItemStackImpl.java b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/SItemStackImpl.java new file mode 100644 index 00000000..0ec7f8dc --- /dev/null +++ b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/SItemStackImpl.java @@ -0,0 +1,39 @@ +package com.craftaro.core.nms.v1_21_R1.world; + +import com.craftaro.core.nms.world.SItemStack; +import net.minecraft.core.particles.ItemParticleOption; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.phys.Vec3; +import org.bukkit.craftbukkit.v1_21_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +public class SItemStackImpl implements SItemStack { + private final ItemStack item; + + public SItemStackImpl(ItemStack item) { + this.item = item; + } + + @Override + public void breakItem(Player player, int amount) { + ServerPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + + for (int i = 0; i < amount; ++i) { + Vec3 vec3d = new Vec3(((double) random.nextFloat() - 0.5D) * 0.1D, Math.random() * 0.1D + 0.1D, 0.0D); + vec3d = vec3d.xRot(-entityPlayer.getXRot() * 0.017453292F); + vec3d = vec3d.yRot(-entityPlayer.getYRot() * 0.017453292F); + + double d0 = (double) (-random.nextFloat()) * 0.6D - 0.3D; + + Vec3 vec3d1 = new Vec3(((double) random.nextFloat() - 0.5D) * 0.3D, d0, 0.6D); + vec3d1 = vec3d1.xRot(-entityPlayer.getXRot() * 0.017453292F); + vec3d1 = vec3d1.yRot(-entityPlayer.getYRot() * 0.017453292F); + vec3d1 = vec3d1.add(entityPlayer.getX(), entityPlayer.getEyeY(), entityPlayer.getZ()); + + entityPlayer.level().addParticle(new ItemParticleOption(ParticleTypes.ITEM, CraftItemStack.asNMSCopy(this.item)), vec3d1.x, vec3d1.y, vec3d1.z, vec3d.x, vec3d.y + 0.05D, vec3d.z); + } + } +} diff --git a/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/SSpawnerImpl.java b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/SSpawnerImpl.java new file mode 100644 index 00000000..9d5c70a0 --- /dev/null +++ b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/SSpawnerImpl.java @@ -0,0 +1,136 @@ +package com.craftaro.core.nms.v1_21_R1.world; + +import com.craftaro.core.compatibility.CompatibleMaterial; +import com.craftaro.core.compatibility.CompatibleParticleHandler; +import com.craftaro.core.nms.world.SSpawner; +import com.craftaro.core.nms.world.SpawnedEntity; +import com.cryptomorin.xseries.XMaterial; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.MobSpawnType; +import net.minecraft.world.level.SpawnData; +import org.bukkit.Location; +import org.bukkit.block.BlockFace; +import org.bukkit.craftbukkit.v1_21_R1.CraftWorld; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.util.Optional; +import java.util.Set; + +public class SSpawnerImpl implements SSpawner { + private final Location spawnerLocation; + + public SSpawnerImpl(Location location) { + this.spawnerLocation = location; + } + + @Override + public LivingEntity spawnEntity(EntityType type, Location spawnerLocation) { + return spawnEntity(type, "EXPLOSION_NORMAL", null, null); + } + + @Override + public LivingEntity spawnEntity(EntityType type, String particleType, SpawnedEntity spawned, Set canSpawnOn) { + SpawnData data = new SpawnData(); + CompoundTag compound = data.getEntityToSpawn(); + + String name = type + .name() + .toLowerCase() + .replace("snowman", "snow_golem") + .replace("mushroom_cow", "mooshroom"); + compound.putString("id", "minecraft:" + name); + + short spawnRange = 4; + for (int i = 0; i < 50; ++i) { + assert this.spawnerLocation.getWorld() != null; + ServerLevel world = ((CraftWorld) this.spawnerLocation.getWorld()).getHandle(); + + RandomSource random = world.getRandom(); + double x = this.spawnerLocation.getX() + (random.nextDouble() - random.nextDouble()) * (double) spawnRange + 0.5D; + double y = this.spawnerLocation.getY() + random.nextInt(3) - 1; + double z = this.spawnerLocation.getZ() + (random.nextDouble() - random.nextDouble()) * (double) spawnRange + 0.5D; + + Optional optionalEntity = net.minecraft.world.entity.EntityType.create(compound, world); + if (optionalEntity.isEmpty()) continue; + + Entity entity = optionalEntity.get(); + entity.setPos(x, y, z); + + BlockPos position = entity.blockPosition(); + DifficultyInstance damageScaler = world.getCurrentDifficultyAt(position); + + if (!(entity instanceof Mob entityInsentient)) { + continue; + } + + Location spot = new Location(this.spawnerLocation.getWorld(), x, y, z); + + if (!canSpawn(world, entityInsentient, spot, canSpawnOn)) { + continue; + } + + entityInsentient.finalizeSpawn(world, damageScaler, MobSpawnType.SPAWNER, null); + + LivingEntity craftEntity = (LivingEntity) entity.getBukkitEntity(); + + if (spawned != null && !spawned.onSpawn(craftEntity)) { + return null; + } + + if (particleType != null) { + float xx = (float) (0 + (Math.random() * 1)); + float yy = (float) (0 + (Math.random() * 2)); + float zz = (float) (0 + (Math.random() * 1)); + + CompatibleParticleHandler.spawnParticles(CompatibleParticleHandler.ParticleType.getParticle(particleType), spot, 5, xx, yy, zz, 0); + } + + world.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.SPAWNER); + + spot.setYaw(random.nextFloat() * 360.0F); + craftEntity.teleport(spot); + + return craftEntity; + } + + return null; + } + + private boolean canSpawn(ServerLevel world, Mob entityInsentient, Location location, Set canSpawnOn) { + if (!world.noCollision(entityInsentient, entityInsentient.getBoundingBox())) { + return false; + } + + Optional spawnedIn = CompatibleMaterial.getMaterial(location.getBlock().getType()); + Optional spawnedOn = CompatibleMaterial.getMaterial(location.getBlock().getRelative(BlockFace.DOWN).getType()); + + if (spawnedIn.isEmpty() || spawnedOn.isEmpty()) { + return false; + } + + if (!CompatibleMaterial.isAir(spawnedIn.get()) && + spawnedIn.get() != XMaterial.WATER && + !spawnedIn.get().name().contains("PRESSURE") && + !spawnedIn.get().name().contains("SLAB")) { + return false; + } + + for (XMaterial material : canSpawnOn) { + if (material == null) continue; + + if (spawnedOn.get() == material || CompatibleMaterial.isAir(material)) { + return true; + } + } + + return false; + } +} diff --git a/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/SWorldImpl.java b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/SWorldImpl.java new file mode 100644 index 00000000..fc5f1e9a --- /dev/null +++ b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/SWorldImpl.java @@ -0,0 +1,52 @@ +package com.craftaro.core.nms.v1_21_R1.world; + +import com.craftaro.core.nms.world.SWorld; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.entity.LevelEntityGetter; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_21_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R1.block.data.CraftBlockData; +import org.bukkit.entity.LivingEntity; + +import java.util.ArrayList; +import java.util.List; + +public class SWorldImpl implements SWorld { + private final World world; + + public SWorldImpl(World world) { + this.world = world; + } + + @Override + public List getLivingEntities() { + List result = new ArrayList<>(); + + ServerLevel worldServer = ((CraftWorld) this.world).getHandle(); + LevelEntityGetter entities = worldServer.getEntities(); + + entities.getAll().forEach((mcEnt) -> { + org.bukkit.entity.Entity bukkitEntity = mcEnt.getBukkitEntity(); + + if (bukkitEntity instanceof LivingEntity && bukkitEntity.isValid()) { + result.add((LivingEntity) bukkitEntity); + } + }); + + return result; + } + + @Override + public void setBlockFast(int x, int y, int z, Material material) { + ServerLevel serverLevel = ((CraftWorld) this.world).getHandle(); + LevelChunk levelChunk = serverLevel.getChunk(x >> 4, z >> 4); + BlockState blockState = ((CraftBlockData) material.createBlockData()).getState(); + + levelChunk.setBlockState(new BlockPos(x & 0xF, y, z & 0xF), blockState, true); + } +} diff --git a/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/WorldCoreImpl.java b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/WorldCoreImpl.java new file mode 100644 index 00000000..6e86e3f2 --- /dev/null +++ b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/WorldCoreImpl.java @@ -0,0 +1,110 @@ +package com.craftaro.core.nms.v1_21_R1.world; + +import com.craftaro.core.nms.ReflectionUtils; +import com.craftaro.core.nms.v1_21_R1.world.spawner.BBaseSpawnerImpl; +import com.craftaro.core.nms.world.BBaseSpawner; +import com.craftaro.core.nms.world.SItemStack; +import com.craftaro.core.nms.world.SSpawner; +import com.craftaro.core.nms.world.SWorld; +import com.craftaro.core.nms.world.WorldCore; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.profiling.ProfilerFiller; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.entity.SpawnerBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.material.FluidState; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_21_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_21_R1.block.CraftBlock; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +public class WorldCoreImpl implements WorldCore { + @Override + public SSpawner getSpawner(CreatureSpawner spawner) { + return new SSpawnerImpl(spawner.getLocation()); + } + + @Override + public SSpawner getSpawner(Location location) { + return new SSpawnerImpl(location); + } + + @Override + public SItemStack getItemStack(ItemStack item) { + return new SItemStackImpl(item); + } + + @Override + public SWorld getWorld(World world) { + return new SWorldImpl(world); + } + + @Override + public BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return new BBaseSpawnerImpl(spawner, ((SpawnerBlockEntity) cTileEntity).getSpawner()); + } + + /** + * Method is based on {@link ServerLevel#tickChunk(LevelChunk, int)}. + */ + @Override + public void randomTickChunk(org.bukkit.Chunk bukkitChunk, int tickAmount) { + LevelChunk chunk = (LevelChunk) ((CraftChunk) bukkitChunk).getHandle(ChunkStatus.FULL); + ServerLevel world = chunk.r; + ProfilerFiller gameProfilerFiller = world.getProfiler(); + + ChunkPos chunkcoordintpair = chunk.getPos(); + int j = chunkcoordintpair.getMinBlockX(); + int k = chunkcoordintpair.getMinBlockZ(); + + gameProfilerFiller.push("tickBlocks"); + if (tickAmount > 0) { + LevelChunkSection[] achunksection = chunk.getSections(); + + for (int i1 = 0; i1 < achunksection.length; ++i1) { + LevelChunkSection chunksection = achunksection[i1]; + if (chunksection.isRandomlyTicking()) { + int j1 = chunk.getSectionYFromSectionIndex(i1); + int k1 = SectionPos.sectionToBlockCoord(j1); + + for (int l1 = 0; l1 < tickAmount; ++l1) { + BlockPos blockposition1 = world.getBlockRandomPos(j, k1, k, 15); + gameProfilerFiller.push("randomTick"); + BlockState iblockdata = chunksection.getBlockState(blockposition1.getX() - j, blockposition1.getY() - k1, blockposition1.getZ() - k); + if (iblockdata.isRandomlyTicking()) { + iblockdata.randomTick(world, blockposition1, world.random); + } + + FluidState fluid = iblockdata.getFluidState(); + if (fluid.isRandomlyTicking()) { + fluid.randomTick(world, blockposition1, world.random); + } + + gameProfilerFiller.pop(); + } + } + } + } + + gameProfilerFiller.pop(); + } + + @Override + public void updateAdjacentComparators(@NotNull Block bukkitBlock) { + CraftBlock craftBlock = (CraftBlock) bukkitBlock; + ServerLevel serverLevel = craftBlock.getCraftWorld().getHandle(); + + serverLevel.updateNeighbourForOutputSignal(craftBlock.getPosition(), craftBlock.getNMS().getBlock()); + } +} diff --git a/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/spawner/BBaseSpawnerImpl.java b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/spawner/BBaseSpawnerImpl.java new file mode 100644 index 00000000..5fd76ca1 --- /dev/null +++ b/NMS/NMS-v1_21_R1/src/main/java/com/craftaro/core/nms/v1_21_R1/world/spawner/BBaseSpawnerImpl.java @@ -0,0 +1,208 @@ +package com.craftaro.core.nms.v1_21_R1.world.spawner; + +import com.craftaro.core.nms.world.BBaseSpawner; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.util.random.WeightedEntry; +import net.minecraft.world.Difficulty; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntitySelector; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.EquipmentTable; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.MobSpawnType; +import net.minecraft.world.entity.SpawnPlacements; +import net.minecraft.world.level.BaseSpawner; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.SpawnData; +import net.minecraft.world.level.entity.EntityTypeTest; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.phys.AABB; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_21_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R1.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.v1_21_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.lang.reflect.InvocationTargetException; +import java.util.Objects; +import java.util.Optional; + +public class BBaseSpawnerImpl implements BBaseSpawner { + private final CreatureSpawner bukkitSpawner; + private final BaseSpawner spawner; + + public BBaseSpawnerImpl(CreatureSpawner bukkitSpawner, BaseSpawner spawner) { + this.bukkitSpawner = bukkitSpawner; + this.spawner = spawner; + } + + /** + * This method is based on {@link BaseSpawner#isNearPlayer(Level, BlockPos)}. + */ + @SuppressWarnings("JavadocReference") + @Override + public boolean isNearPlayer() { + BlockPos bPos = getBlockPosition(); + return getWorld().hasNearbyAlivePlayer( + (double) bPos.getX() + 0.5, + (double) bPos.getY() + 0.5, + (double) bPos.getZ() + 0.5, + this.spawner.requiredPlayerRange + ); + } + + /** + * This method is based on {@link BaseSpawner#serverTick(ServerLevel, BlockPos)}. + */ + @Override + public void tick() throws InvocationTargetException, IllegalAccessException { + ServerLevel worldServer = getWorld(); + BlockPos blockposition = getBlockPosition(); + + if (this.spawner.spawnDelay == -1) { + delay(worldServer, blockposition); + } + + if (this.spawner.spawnDelay > 0) { + --this.spawner.spawnDelay; + } else { + boolean flag = false; + RandomSource randomsource = worldServer.getRandom(); + SpawnData mobspawnerdata = getOrCreateNextSpawnData(randomsource); + int i = 0; + + while (true) { + if (i >= this.spawner.spawnCount) { + if (flag) { + delay(worldServer, blockposition); + } + break; + } + + CompoundTag nbttagcompound = mobspawnerdata.getEntityToSpawn(); + Optional> optional = EntityType.by(nbttagcompound); + if (optional.isEmpty()) { + delay(worldServer, blockposition); + return; + } + + ListTag nbttaglist = nbttagcompound.getList("Pos", 6); + int j = nbttaglist.size(); + double d0 = j >= 1 ? nbttaglist.getDouble(0) : (double) blockposition.getX() + (randomsource.nextDouble() - randomsource.nextDouble()) * (double) this.spawner.spawnRange + 0.5; + double d1 = j >= 2 ? nbttaglist.getDouble(1) : (double) (blockposition.getY() + randomsource.nextInt(3) - 1); + double d2 = j >= 3 ? nbttaglist.getDouble(2) : (double) blockposition.getZ() + (randomsource.nextDouble() - randomsource.nextDouble()) * (double) this.spawner.spawnRange + 0.5; + if (worldServer.noCollision(optional.get().getSpawnAABB(d0, d1, d2))) { + label119: + { + BlockPos blockposition1 = BlockPos.containing(d0, d1, d2); + if (mobspawnerdata.getCustomSpawnRules().isPresent()) { + if (!optional.get().getCategory().isFriendly() && worldServer.getDifficulty() == Difficulty.PEACEFUL) { + break label119; + } + + SpawnData.CustomSpawnRules mobspawnerdata_a = mobspawnerdata.getCustomSpawnRules().get(); + if (!mobspawnerdata_a.isValidPosition(blockposition1, worldServer)) { + break label119; + } + } else if (!SpawnPlacements.checkSpawnRules((EntityType) optional.get(), worldServer, MobSpawnType.SPAWNER, blockposition1, worldServer.getRandom())) { + break label119; + } + + Entity entity = EntityType.loadEntityRecursive(nbttagcompound, worldServer, (entity1) -> { + entity1.moveTo(d0, d1, d2, entity1.getYRot(), entity1.getXRot()); + return entity1; + }); + if (entity == null) { + delay(worldServer, blockposition); + return; + } + + int k = worldServer.getEntities(EntityTypeTest.forExactClass(entity.getClass()), (new AABB(blockposition.getX(), blockposition.getY(), blockposition.getZ(), blockposition.getX() + 1, blockposition.getY() + 1, blockposition.getZ() + 1)).inflate((double) this.spawner.spawnRange), EntitySelector.NO_SPECTATORS).size(); + if (k >= this.spawner.maxNearbyEntities) { + delay(worldServer, blockposition); + return; + } + + entity.moveTo(entity.getX(), entity.getY(), entity.getZ(), randomsource.nextFloat() * 360.0F, 0.0F); + if (entity instanceof Mob entityinsentient) { + if (mobspawnerdata.getCustomSpawnRules().isEmpty() && !entityinsentient.checkSpawnRules(worldServer, MobSpawnType.SPAWNER) || !entityinsentient.checkSpawnObstruction(worldServer)) { + break label119; + } + + boolean flag1 = mobspawnerdata.getEntityToSpawn().size() == 1 && mobspawnerdata.getEntityToSpawn().contains("id", 8); + if (flag1) { + ((Mob) entity).finalizeSpawn(worldServer, worldServer.getCurrentDifficultyAt(entity.blockPosition()), MobSpawnType.SPAWNER, null); + } + + Optional optional1 = mobspawnerdata.getEquipment(); + Objects.requireNonNull(entityinsentient); + Objects.requireNonNull(entityinsentient); + optional1.ifPresent(entityinsentient::equip); + if (entityinsentient.level().spigotConfig.nerfSpawnerMobs) { + entityinsentient.aware = false; + } + } + + if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + if (!worldServer.tryAddFreshEntityWithPassengers(entity, CreatureSpawnEvent.SpawnReason.SPAWNER)) { + delay(worldServer, blockposition); + return; + } + + worldServer.levelEvent(2004, blockposition, 0); + worldServer.gameEvent(entity, GameEvent.ENTITY_PLACE, blockposition1); + if (entity instanceof Mob) { + ((Mob) entity).spawnAnim(); + } + + flag = true; + } + } + } + + ++i; + } + } + } + + /** + * This method is based on {@link BaseSpawner#delay(Level, BlockPos)}. + */ + @SuppressWarnings("JavadocReference") + private void delay(ServerLevel world, BlockPos bPos) { + RandomSource randomsource = world.random; + if (this.spawner.maxSpawnDelay <= this.spawner.minSpawnDelay) { + this.spawner.spawnDelay = this.spawner.minSpawnDelay; + } else { + this.spawner.spawnDelay = this.spawner.minSpawnDelay + randomsource.nextInt(this.spawner.maxSpawnDelay - this.spawner.minSpawnDelay); + } + + this.spawner.spawnPotentials.getRandom(randomsource).ifPresent((entry) -> this.spawner.nextSpawnData = entry.data()); + this.spawner.broadcastEvent(world, bPos, 1); + } + + /** + * This method is based on {@link BaseSpawner#getOrCreateNextSpawnData(Level, RandomSource, BlockPos)}. + */ + @SuppressWarnings("JavadocReference") + private SpawnData getOrCreateNextSpawnData(RandomSource randomsource) { + if (this.spawner.nextSpawnData != null) { + return this.spawner.nextSpawnData; + } + + this.spawner.nextSpawnData = this.spawner.spawnPotentials.getRandom(randomsource).map(WeightedEntry.Wrapper::data).orElseGet(SpawnData::new); + return this.spawner.nextSpawnData; + } + + private ServerLevel getWorld() { + return ((CraftWorld) this.bukkitSpawner.getWorld()).getHandle(); + } + + private BlockPos getBlockPosition() { + return ((CraftCreatureSpawner) this.bukkitSpawner).getPosition(); + } +} diff --git a/NMS/NMS/pom.xml b/NMS/NMS/pom.xml index 6838a6fa..c2393213 100644 --- a/NMS/NMS/pom.xml +++ b/NMS/NMS/pom.xml @@ -22,6 +22,12 @@ + + ${project.version} + CraftaroCore-NMS-v1_21_R1 + ${project.groupId} + compile + ${project.version} CraftaroCore-NMS-v1_20_R4 diff --git a/pom.xml b/pom.xml index 46a0207f..f8b6032e 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,7 @@ NMS/NMS NMS/NMS-API + NMS/NMS-v1_21_R1 NMS/NMS-v1_20_R4 NMS/NMS-v1_20_R3 NMS/NMS-v1_20_R2