diff --git a/BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/PlayerMovementWrapper15.java b/BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/PlayerMovementWrapper15.java
index b0ed19b3..12f80cdb 100644
--- a/BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/PlayerMovementWrapper15.java
+++ b/BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/PlayerMovementWrapper15.java
@@ -46,14 +46,9 @@ public class PlayerMovementWrapper15 implements PlayerMovementWrapper {
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
Object packet = Reflection.newInstance(teleportPacket);
teleportEntity.set(packet, player.getEntityId());
- teleportPosition.set(packet, packetPlayInFlying.a(0.0), packetPlayInFlying.b(0.0), packetPlayInFlying.c(0.0));
- if (Float.isNaN(packetPlayInFlying.a(Float.NaN))) {
- teleportYaw.set(packet, rotToByte(player.getLocation().getYaw()));
- teleportPitch.set(packet, rotToByte(player.getLocation().getPitch()));
- } else {
- teleportYaw.set(packet, rotToByte(packetPlayInFlying.a(0.0F)));
- teleportPitch.set(packet, rotToByte(packetPlayInFlying.b(0.0F)));
- }
+ teleportPosition.set(packet, packetPlayInFlying.a(0.0), packetPlayInFlying.b(0.0), packetPlayInFlying.c(0.0),
+ Float.isNaN(packetPlayInFlying.a(Float.NaN)) ? player.getLocation().getYaw() : packetPlayInFlying.a(0.0F),
+ Float.isNaN(packetPlayInFlying.b(Float.NaN)) ? player.getLocation().getPitch() : packetPlayInFlying.b(0.0F));
return packet;
}
}
diff --git a/BauSystem/BauSystem_18/src/de/steamwar/bausystem/utils/PlayerMovementWrapper18.java b/BauSystem/BauSystem_18/src/de/steamwar/bausystem/utils/PlayerMovementWrapper18.java
index 8762e418..d1e186d2 100644
--- a/BauSystem/BauSystem_18/src/de/steamwar/bausystem/utils/PlayerMovementWrapper18.java
+++ b/BauSystem/BauSystem_18/src/de/steamwar/bausystem/utils/PlayerMovementWrapper18.java
@@ -44,14 +44,9 @@ public class PlayerMovementWrapper18 implements PlayerMovementWrapper {
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
Object packet = Reflection.newInstance(teleportPacket);
teleportEntity.set(packet, player.getEntityId());
- teleportPosition.set(packet, packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c);
- if (packetPlayInFlying.h) {
- teleportYaw.set(packet, rotToByte(player.getLocation().getYaw()));
- teleportPitch.set(packet, rotToByte(player.getLocation().getPitch()));
- } else {
- teleportYaw.set(packet, rotToByte(packetPlayInFlying.d));
- teleportPitch.set(packet, rotToByte(packetPlayInFlying.e));
- }
+ teleportPosition.set(packet, packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c,
+ packetPlayInFlying.h ? player.getLocation().getYaw() : packetPlayInFlying.d,
+ packetPlayInFlying.h ? player.getLocation().getPitch() : packetPlayInFlying.e);
return packet;
}
}
diff --git a/BauSystem/BauSystem_19/src/de/steamwar/bausystem/utils/PlayerMovementWrapper19.java b/BauSystem/BauSystem_19/src/de/steamwar/bausystem/utils/PlayerMovementWrapper19.java
index 9262bfea..9815023c 100644
--- a/BauSystem/BauSystem_19/src/de/steamwar/bausystem/utils/PlayerMovementWrapper19.java
+++ b/BauSystem/BauSystem_19/src/de/steamwar/bausystem/utils/PlayerMovementWrapper19.java
@@ -48,14 +48,9 @@ public class PlayerMovementWrapper19 implements PlayerMovementWrapper {
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
Object packet = Reflection.newInstance(teleportPacket);
teleportEntity.set(packet, player.getEntityId());
- teleportPosition.set(packet, packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c);
- if (packetPlayInFlying.h) {
- teleportYaw.set(packet, rotToByte(player.getLocation().getYaw()));
- teleportPitch.set(packet, rotToByte(player.getLocation().getPitch()));
- } else {
- teleportYaw.set(packet, rotToByte(packetPlayInFlying.d));
- teleportPitch.set(packet, rotToByte(packetPlayInFlying.e));
- }
+ teleportPosition.set(packet, packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c,
+ packetPlayInFlying.h ? player.getLocation().getYaw() : packetPlayInFlying.d,
+ packetPlayInFlying.h ? player.getLocation().getPitch() : packetPlayInFlying.e);
return packet;
}
}
diff --git a/BauSystem/BauSystem_20/src/de/steamwar/bausystem/utils/PlayerMovementWrapper20.java b/BauSystem/BauSystem_20/src/de/steamwar/bausystem/utils/PlayerMovementWrapper20.java
index 958e4bb8..75701471 100644
--- a/BauSystem/BauSystem_20/src/de/steamwar/bausystem/utils/PlayerMovementWrapper20.java
+++ b/BauSystem/BauSystem_20/src/de/steamwar/bausystem/utils/PlayerMovementWrapper20.java
@@ -49,14 +49,9 @@ public class PlayerMovementWrapper20 implements PlayerMovementWrapper {
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
Object packet = Reflection.newInstance(teleportPacket);
teleportEntity.set(packet, player.getEntityId());
- teleportPosition.set(packet, packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c);
- if (packetPlayInFlying.h) {
- teleportYaw.set(packet, rotToByte(player.getLocation().getYaw()));
- teleportPitch.set(packet, rotToByte(player.getLocation().getPitch()));
- } else {
- teleportYaw.set(packet, rotToByte(packetPlayInFlying.d));
- teleportPitch.set(packet, rotToByte(packetPlayInFlying.e));
- }
+ teleportPosition.set(packet, packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c,
+ packetPlayInFlying.h ? player.getLocation().getYaw() : packetPlayInFlying.d,
+ packetPlayInFlying.h ? player.getLocation().getPitch() : packetPlayInFlying.e);
return packet;
}
}
diff --git a/BauSystem/BauSystem_21/build.gradle.kts b/BauSystem/BauSystem_21/build.gradle.kts
new file mode 100644
index 00000000..0c9e97d4
--- /dev/null
+++ b/BauSystem/BauSystem_21/build.gradle.kts
@@ -0,0 +1,17 @@
+plugins {
+ steamwar.java
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_21
+ targetCompatibility = JavaVersion.VERSION_21
+}
+
+dependencies {
+ compileOnly(project(":BauSystem:BauSystem_Main", "default"))
+ compileOnly(project(":SpigotCore", "default"))
+
+ compileOnly(libs.paperapi21)
+
+ compileOnly(libs.nms21)
+}
\ No newline at end of file
diff --git a/BauSystem/BauSystem_21/src/de/steamwar/bausystem/utils/NMSWrapper21.java b/BauSystem/BauSystem_21/src/de/steamwar/bausystem/utils/NMSWrapper21.java
new file mode 100644
index 00000000..1c3ce035
--- /dev/null
+++ b/BauSystem/BauSystem_21/src/de/steamwar/bausystem/utils/NMSWrapper21.java
@@ -0,0 +1,141 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.bausystem.utils;
+
+import com.comphenix.tinyprotocol.Reflection;
+import de.steamwar.bausystem.features.util.NoClipCommand;
+import net.minecraft.core.component.DataComponents;
+import net.minecraft.nbt.NBTBase;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.network.protocol.game.PacketPlayInSetCreativeSlot;
+import net.minecraft.network.protocol.game.PacketPlayOutExplosion;
+import net.minecraft.network.protocol.game.PacketPlayOutGameStateChange;
+import net.minecraft.server.level.EntityPlayer;
+import net.minecraft.server.level.PlayerInteractManager;
+import net.minecraft.world.entity.player.EntityHuman;
+import net.minecraft.world.entity.player.PlayerAbilities;
+import net.minecraft.world.item.component.CustomData;
+import net.minecraft.world.level.EnumGamemode;
+import org.bukkit.GameMode;
+import org.bukkit.Material;
+import org.bukkit.craftbukkit.v1_21_R2.entity.CraftPlayer;
+import org.bukkit.craftbukkit.v1_21_R2.inventory.CraftItemStack;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.Optional;
+
+public class NMSWrapper21 implements NMSWrapper {
+
+ private static final Reflection.FieldAccessor playerInteractManager = Reflection.getField(EntityPlayer.class, null, PlayerInteractManager.class);
+
+ @Override
+ public void setInternalGameMode(Player player, GameMode gameMode) {
+ playerInteractManager.get(((CraftPlayer) player).getHandle()).a(EnumGamemode.a(gameMode.getValue()));
+ }
+
+ @Override
+ public void setSlotToItemStack(Player player, Object o) {
+ PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) o;
+ int index = packetPlayInSetCreativeSlot.b();
+ if (index >= 36 && index <= 44) {
+ index -= 36;
+ } else if (index > 44) {
+ index -= 5;
+ } else if (index <= 8) {
+ index = index - 8 + 36;
+ }
+ player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.e()));
+ if (index < 9) player.getInventory().setHeldItemSlot(index);
+ player.updateInventory();
+ }
+
+ private static final Reflection.FieldAccessor gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, PacketPlayOutGameStateChange.a.class, 12);
+
+ @Override
+ public void setGameStateChangeReason(Object packet) {
+ gameStateChangeReason.set(packet, PacketPlayOutGameStateChange.d);
+ }
+
+ private static final Reflection.FieldAccessor playerAbilities = Reflection.getField(EntityHuman.class, null, PlayerAbilities.class);
+
+ @Override
+ public void setPlayerBuildAbilities(Player player) {
+ PlayerAbilities abilities = playerAbilities.get(((CraftPlayer) player).getHandle());
+ abilities.d = true;
+ abilities.e = true;
+ }
+
+ @Override
+ public Material pathMaterial() {
+ return Material.DIRT_PATH;
+ }
+
+ private static final int threshold = 2048;
+
+ @Override
+ public boolean checkItemStack(ItemStack item) {
+ net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item);
+ NBTTagCompound tag = nmsItem.a(DataComponents.b, CustomData.a).c();
+ if (tag.e("BlockEntityTag")) {
+ NBTTagCompound blockTag = tag.p("BlockEntityTag");
+ if (blockTag.e("Items")) {
+ return drillDown(blockTag.c("Items", 10), 0, 0) > threshold;
+ }
+ }
+
+ return false;
+ }
+
+ private int drillDown(NBTTagList items, int layer, int start) {
+ if (layer > 2) return start + threshold;
+ int invalid = start;
+ for (NBTBase nbtBase : items) {
+ if (!(nbtBase instanceof NBTTagCompound slot))
+ continue;
+ if (slot.e("tag")) {
+ invalid += slot.f("Count");
+ NBTTagCompound iTag = slot.p("tag");
+ if (iTag.e("BlockEntityTag")) {
+ NBTTagCompound blockTag = iTag.p("BlockEntityTag");
+ if (blockTag.e("Items")) {
+ invalid = drillDown(blockTag.c("Items", 10), layer + 1, invalid);
+ }
+ }
+ }
+ if (invalid > threshold)
+ break;
+ }
+ return invalid;
+ }
+
+ @Override
+ public Object resetExplosionKnockback(Object packet) {
+ PacketPlayOutExplosion explosion = (PacketPlayOutExplosion) packet;
+
+ return new PacketPlayOutExplosion(
+ explosion.b(),
+ Optional.empty(),
+ explosion.f(),
+ explosion.g()
+ );
+ }
+}
diff --git a/BauSystem/BauSystem_Main/build.gradle.kts b/BauSystem/BauSystem_Main/build.gradle.kts
index 63d6f026..9ae53822 100644
--- a/BauSystem/BauSystem_Main/build.gradle.kts
+++ b/BauSystem/BauSystem_Main/build.gradle.kts
@@ -35,12 +35,16 @@ dependencies {
annotationProcessor(libs.classindex)
compileOnly(project(":SpigotCore", "default"))
- compileOnly(libs.spigotapi)
+ compileOnly(libs.paperapi21) {
+ attributes {
+ // Very Hacky, but it works
+ attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21)
+ }
+ }
compileOnly(libs.axiom)
compileOnly(libs.authlib)
compileOnly(libs.viaapi)
- compileOnly(libs.nms20)
compileOnly(libs.fawe18)
implementation(libs.luaj)
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/gui/editor/BauGuiEditor.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/gui/editor/BauGuiEditor.java
index 733e7213..e40b01f3 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/gui/editor/BauGuiEditor.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/gui/editor/BauGuiEditor.java
@@ -22,6 +22,7 @@ package de.steamwar.bausystem.features.gui.editor;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.features.gui.BauGUI;
import de.steamwar.bausystem.linkage.specific.BauGuiItem;
+import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.inventory.SWItem;
import de.steamwar.inventory.SWListInv;
import de.steamwar.linkage.Linked;
@@ -72,7 +73,7 @@ public class BauGuiEditor implements Listener {
inv.setItem(mapping.getSize() + 5, new SWItem(Material.BARRIER, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_TRASH", p), Arrays.asList(BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_TRASH_LORE", p)), false, clickType -> {
}).getItemStack());
- inv.setItem(mapping.getSize() + 6, new SWItem(Material.SCUTE, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_MORE", p)).getItemStack());
+ inv.setItem(mapping.getSize() + 6, new SWItem(TrickyTrialsWrapper.impl.getTurtleScute(), BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_MORE", p)).getItemStack());
inv.setItem(mapping.getSize() + 8, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_CLOSE", p)).getItemStack());
p.openInventory(inv);
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loadtimer/LoadtimerListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loadtimer/LoadtimerListener.java
index ddbaed9a..c528b9ad 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loadtimer/LoadtimerListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loadtimer/LoadtimerListener.java
@@ -20,6 +20,7 @@
package de.steamwar.bausystem.features.loadtimer;
import de.steamwar.bausystem.region.Region;
+import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
@@ -57,7 +58,7 @@ public class LoadtimerListener implements Listener {
@EventHandler
public void onEntitySpawn(EntitySpawnEvent event) {
- if (!getTimers().isEmpty() && event.getEntityType() == EntityType.PRIMED_TNT) {
+ if (!getTimers().isEmpty() && event.getEntityType() == TrickyTrialsWrapper.impl.getTntEntityType()) {
Region r = Region.getRegion(event.getLocation());
if (hasTimer(r)) {
getTimer(r).onTntSpawn();
@@ -67,7 +68,7 @@ public class LoadtimerListener implements Listener {
@EventHandler
public void onEntityExplode(EntityExplodeEvent event) {
- if (!getTimers().isEmpty() && event.getEntityType() == EntityType.PRIMED_TNT) {
+ if (!getTimers().isEmpty() && event.getEntityType() == TrickyTrialsWrapper.impl.getTntEntityType()) {
Region r = Region.getRegion(event.getLocation());
if (hasTimer(r)) {
getTimer(r).onTntExplode(event);
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/FreezeListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/FreezeListener.java
index df73575c..a284cfa8 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/FreezeListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/FreezeListener.java
@@ -6,6 +6,7 @@ import de.steamwar.bausystem.region.flags.Flag;
import de.steamwar.bausystem.region.flags.flagvalues.FreezeMode;
import de.steamwar.bausystem.utils.ScoreboardElement;
import de.steamwar.core.Core;
+import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.linkage.Linked;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@@ -31,7 +32,7 @@ public class FreezeListener implements Listener, ScoreboardElement {
return;
}
e.setCancelled(true);
- if (e.getEntityType() == EntityType.PRIMED_TNT) {
+ if (e.getEntityType() == TrickyTrialsWrapper.impl.getTntEntityType()) {
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
e.getLocation().getBlock().setType(Material.TNT, false);
}, 1L);
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/event/EventListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/event/EventListener.java
index c32b0231..3eb099aa 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/event/EventListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/event/EventListener.java
@@ -28,6 +28,7 @@ import de.steamwar.bausystem.features.tpslimit.TPSUtils;
import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.region.utils.RegionExtensionType;
import de.steamwar.bausystem.region.utils.RegionType;
+import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.linkage.Linked;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@@ -146,7 +147,7 @@ public class EventListener implements Listener {
@EventHandler(priority = EventPriority.HIGH)
public void onEntitySpawn(EntitySpawnEvent event) {
- if (event.getEntityType() != EntityType.PRIMED_TNT) {
+ if (event.getEntityType() != TrickyTrialsWrapper.impl.getTntEntityType()) {
return;
}
Region tntRegion = Region.getRegion(event.getLocation());
@@ -161,7 +162,7 @@ public class EventListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public void onEntityExplode(EntityExplodeEvent event) {
- if (event.getEntityType() != EntityType.PRIMED_TNT) {
+ if (event.getEntityType() != TrickyTrialsWrapper.impl.getTntEntityType()) {
return;
}
Region tntRegion = Region.getRegion(event.getLocation());
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorBaseGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorBaseGui.java
index 41f95a88..9e81340b 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorBaseGui.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorBaseGui.java
@@ -22,6 +22,7 @@ package de.steamwar.bausystem.features.simulator.gui.base;
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
import de.steamwar.bausystem.features.simulator.data.Simulator;
import de.steamwar.core.Core;
+import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.inventory.SWInventory;
import de.steamwar.inventory.SWItem;
import org.bukkit.Bukkit;
@@ -46,7 +47,7 @@ public abstract class SimulatorBaseGui {
public final void open() {
String newTitle = title();
- String originalTitle = player.getOpenInventory().getTitle();
+ String originalTitle = TrickyTrialsWrapper.impl.getInventoryTitle(player.getOpenInventory());
if (inv != null && (Core.getVersion() > 19 || newTitle.equals(originalTitle))) {
// TODO: Flickering is better but not gone!
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/team/boundary/BoundaryViewer.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/team/boundary/BoundaryViewer.java
index 744ae0df..51bef65c 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/team/boundary/BoundaryViewer.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/team/boundary/BoundaryViewer.java
@@ -23,6 +23,8 @@ import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.region.Point;
import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.region.utils.RegionType;
+import de.steamwar.core.TrickyParticleWrapper;
+import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.linkage.Linked;
import org.bukkit.Bukkit;
import org.bukkit.Particle;
@@ -56,7 +58,7 @@ public class BoundaryViewer implements Listener {
}
private void showRegion(Region region, Player player) {
- drawCuboid(player, Particle.VILLAGER_HAPPY, region.getMinPoint(), region.getMaxPoint());
+ drawCuboid(player, TrickyParticleWrapper.impl.getVillagerHappy(), region.getMinPoint(), region.getMaxPoint());
if (region.hasType(RegionType.TESTBLOCK)) {
drawCuboid(player, Particle.END_ROD, region.getMinPointTestblockExtension(), region.getMaxPointTestblockExtension());
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/items/NightVisionBauGuiItem.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/items/NightVisionBauGuiItem.java
index d9cab51e..03ebb495 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/items/NightVisionBauGuiItem.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/items/NightVisionBauGuiItem.java
@@ -47,7 +47,6 @@ public class NightVisionBauGuiItem extends BauGuiItem {
PotionMeta meta = (PotionMeta) itemStack.getItemMeta();
meta.setColor(PotionEffectType.NIGHT_VISION.getColor());
meta.setDisplayName(BauSystem.MESSAGE.parse("NIGHT_VISION_ITEM_ON", player));
- meta.addItemFlags(ItemFlag.HIDE_POTION_EFFECTS);
meta.setCustomModelData(1);
itemStack.setItemMeta(meta);
return itemStack;
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/PlayerMovementWrapper.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/PlayerMovementWrapper.java
index b0748762..15aea7f0 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/PlayerMovementWrapper.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/PlayerMovementWrapper.java
@@ -24,21 +24,16 @@ import de.steamwar.bausystem.BauSystem;
import de.steamwar.core.BountifulWrapper;
import de.steamwar.core.Core;
import de.steamwar.core.VersionDependent;
+import de.steamwar.entity.REntity;
import org.bukkit.entity.Player;
public interface PlayerMovementWrapper {
- Class> teleportPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntityTeleport");
- Reflection.FieldAccessor teleportEntity = Reflection.getField(teleportPacket, Integer.TYPE, 0);
- BountifulWrapper.PositionSetter teleportPosition = BountifulWrapper.impl.getPositionSetter(teleportPacket, Core.getVersion() == 8 ? 1 : 0);
- Reflection.FieldAccessor teleportYaw = Reflection.getField(teleportPacket, Byte.TYPE, 0);
- Reflection.FieldAccessor teleportPitch = Reflection.getField(teleportPacket, Byte.TYPE, 1);
+ Class> teleportPacket = REntity.teleportPacket;
+ Reflection.FieldAccessor teleportEntity = REntity.teleportEntity;
+ BountifulWrapper.PositionSetter teleportPosition = REntity.teleportPosition;
PlayerMovementWrapper impl = VersionDependent.getVersionImpl(BauSystem.getInstance());
void setPosition(Player player, Object object);
Object convertToOut(Player player, Object object);
-
- default byte rotToByte(float rot) {
- return (byte)((int)(rot * 256.0F / 360.0F));
- }
}
diff --git a/BauSystem/build.gradle.kts b/BauSystem/build.gradle.kts
index 55df7b50..7a02ffa7 100644
--- a/BauSystem/build.gradle.kts
+++ b/BauSystem/build.gradle.kts
@@ -32,4 +32,5 @@ dependencies {
implementation(project(":BauSystem:BauSystem_18"))
implementation(project(":BauSystem:BauSystem_19"))
implementation(project(":BauSystem:BauSystem_20"))
+ implementation(project(":BauSystem:BauSystem_21"))
}
diff --git a/FightSystem/FightSystem_21/build.gradle.kts b/FightSystem/FightSystem_21/build.gradle.kts
new file mode 100644
index 00000000..a05590d1
--- /dev/null
+++ b/FightSystem/FightSystem_21/build.gradle.kts
@@ -0,0 +1,43 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+plugins {
+ steamwar.java
+}
+
+dependencies {
+ compileOnly(project(":FightSystem:FightSystem_Core", "default"))
+ compileOnly(project(":FightSystem:FightSystem_18", "default"))
+
+ compileOnly(libs.paperapi21) {
+ attributes {
+ // Very Hacky, but it works
+ attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21)
+ }
+ }
+
+ compileOnly(libs.nms21) {
+ attributes {
+ // Very Hacky, but it works
+ attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21)
+ }
+ }
+
+ compileOnly(libs.fastutil)
+}
diff --git a/FightSystem/FightSystem_21/src/de/steamwar/fightsystem/utils/CraftbukkitWrapper21.java b/FightSystem/FightSystem_21/src/de/steamwar/fightsystem/utils/CraftbukkitWrapper21.java
new file mode 100644
index 00000000..9e52bb36
--- /dev/null
+++ b/FightSystem/FightSystem_21/src/de/steamwar/fightsystem/utils/CraftbukkitWrapper21.java
@@ -0,0 +1,30 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.fightsystem.utils;
+
+import org.bukkit.entity.Entity;
+
+public class CraftbukkitWrapper21 extends CraftbukkitWrapper18 {
+
+ @Override
+ public float headRotation(Entity e) {
+ return getEntity(e).bS();
+ }
+}
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/event/HellsBells.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/event/HellsBells.java
index 7fe7e4b2..3cfa7a87 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/event/HellsBells.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/event/HellsBells.java
@@ -19,6 +19,7 @@
package de.steamwar.fightsystem.event;
+import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.countdown.Countdown;
@@ -97,13 +98,13 @@ public class HellsBells {
currentDropping = Bukkit.getScheduler().runTaskTimer(FightSystem.getPlugin(), () -> {
for (int w = 0; w < width; w++) {
if (direction.isNorthOrWest()) {
- Config.world.spawnEntity(redStart.addAndToLocation(Config.world, -1 * (direction.dx * length.get() + w * direction.other().dx), 0, -1 * (direction.dz * length.get() + w * direction.other().dz)), EntityType.PRIMED_TNT);
+ Config.world.spawnEntity(redStart.addAndToLocation(Config.world, -1 * (direction.dx * length.get() + w * direction.other().dx), 0, -1 * (direction.dz * length.get() + w * direction.other().dz)), TrickyTrialsWrapper.impl.getTntEntityType());
- Config.world.spawnEntity(blueStart.addAndToLocation(Config.world, direction.dx * length.get() + w * direction.other().dx, 0, direction.dz * length.get() + w * direction.other().dz), EntityType.PRIMED_TNT);
+ Config.world.spawnEntity(blueStart.addAndToLocation(Config.world, direction.dx * length.get() + w * direction.other().dx, 0, direction.dz * length.get() + w * direction.other().dz), TrickyTrialsWrapper.impl.getTntEntityType());
} else {
- Config.world.spawnEntity(redStart.addAndToLocation(Config.world, direction.dx * length.get() + w * direction.other().dx, 0, direction.dz * length.get() + w * direction.other().dz), EntityType.PRIMED_TNT);
+ Config.world.spawnEntity(redStart.addAndToLocation(Config.world, direction.dx * length.get() + w * direction.other().dx, 0, direction.dz * length.get() + w * direction.other().dz), TrickyTrialsWrapper.impl.getTntEntityType());
- Config.world.spawnEntity(blueStart.addAndToLocation(Config.world, -1 * (direction.dx * length.get() + w * direction.other().dx), 0, -1 * (direction.dz * length.get() + w * direction.other().dz)), EntityType.PRIMED_TNT);
+ Config.world.spawnEntity(blueStart.addAndToLocation(Config.world, -1 * (direction.dx * length.get() + w * direction.other().dx), 0, -1 * (direction.dz * length.get() + w * direction.other().dz)), TrickyTrialsWrapper.impl.getTntEntityType());
}
}
if (length.addAndGet(-2) <= 0) {
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Recording.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Recording.java
index 889c3c1c..b4040b74 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Recording.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/Recording.java
@@ -21,6 +21,7 @@ package de.steamwar.fightsystem.listener;
import com.comphenix.tinyprotocol.Reflection;
import com.comphenix.tinyprotocol.TinyProtocol;
+import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.events.TeamDeathEvent;
@@ -221,7 +222,7 @@ public class Recording implements Listener {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onTNTSpawn(EntitySpawnEvent e){
- if(e.getEntityType() != EntityType.PRIMED_TNT)
+ if(e.getEntityType() != TrickyTrialsWrapper.impl.getTntEntityType())
return;
GlobalRecorder.getInstance().tntSpawn(e.getEntity());
@@ -229,7 +230,7 @@ public class Recording implements Listener {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onExplosion(EntityExplodeEvent e){
- if(e.getEntityType() != EntityType.PRIMED_TNT)
+ if(e.getEntityType() != TrickyTrialsWrapper.impl.getTntEntityType())
return;
Location loc = e.getLocation();
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/WaterRemover.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/WaterRemover.java
index c89fcab0..847e647b 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/WaterRemover.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/WaterRemover.java
@@ -19,6 +19,7 @@
package de.steamwar.fightsystem.listener;
+import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.fight.Fight;
@@ -56,7 +57,7 @@ public class WaterRemover implements Listener {
@EventHandler
public void handleEntitySpawn(EntitySpawnEvent event) {
- if(event.getEntityType() != EntityType.PRIMED_TNT)
+ if(event.getEntityType() != TrickyTrialsWrapper.impl.getTntEntityType())
return;
Location location = event.getLocation();
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java
index 6296e374..ee0c1af1 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java
@@ -21,6 +21,7 @@ package de.steamwar.fightsystem.record;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import de.steamwar.core.Core;
+import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.entity.REntity;
import de.steamwar.entity.REntityServer;
import de.steamwar.entity.RPlayer;
@@ -298,7 +299,7 @@ public class PacketProcessor implements Listener {
private void tntSpawn() throws IOException {
int entityId = source.readInt();
- execSync(() -> addREntity(entityId, new REntity(entityServer, EntityType.PRIMED_TNT, Config.SpecSpawn)));
+ execSync(() -> addREntity(entityId, new REntity(entityServer, TrickyTrialsWrapper.impl.getTntEntityType(), Config.SpecSpawn)));
}
private void entityVelocity() throws IOException {
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionTimeTechKO.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionTimeTechKO.java
index 1659edbc..f1177afa 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionTimeTechKO.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionTimeTechKO.java
@@ -19,6 +19,7 @@
package de.steamwar.fightsystem.winconditions;
+import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.fightsystem.countdown.Countdown;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightTeam;
@@ -70,7 +71,7 @@ public class WinconditionTimeTechKO extends Wincondition implements Listener {
@EventHandler
public void onSpawn(EntitySpawnEvent e) {
- if(e.getEntityType() != EntityType.PRIMED_TNT)
+ if(e.getEntityType() != TrickyTrialsWrapper.impl.getTntEntityType())
return;
Location location = e.getLocation();
@@ -84,7 +85,7 @@ public class WinconditionTimeTechKO extends Wincondition implements Listener {
@EventHandler
public void onExplode(EntityExplodeEvent e) {
- if(e.getEntityType() != EntityType.PRIMED_TNT)
+ if(e.getEntityType() != TrickyTrialsWrapper.impl.getTntEntityType())
return;
FightTeam spawn = spawnLocations.remove(e.getEntity().getEntityId());
diff --git a/FightSystem/build.gradle.kts b/FightSystem/build.gradle.kts
index 3f367461..0cd412bc 100644
--- a/FightSystem/build.gradle.kts
+++ b/FightSystem/build.gradle.kts
@@ -37,4 +37,5 @@ dependencies {
implementation(project(":FightSystem:FightSystem_18"))
implementation(project(":FightSystem:FightSystem_19"))
implementation(project(":FightSystem:FightSystem_20"))
+ implementation(project(":FightSystem:FightSystem_21"))
}
diff --git a/SpigotCore/SpigotCore_14/src/de/steamwar/core/FlatteningWrapper14.java b/SpigotCore/SpigotCore_14/src/de/steamwar/core/FlatteningWrapper14.java
index f5626d03..b7a9bf7f 100644
--- a/SpigotCore/SpigotCore_14/src/de/steamwar/core/FlatteningWrapper14.java
+++ b/SpigotCore/SpigotCore_14/src/de/steamwar/core/FlatteningWrapper14.java
@@ -232,9 +232,9 @@ public class FlatteningWrapper14 implements FlatteningWrapper.IFlatteningWrapper
scoreboardName.set(packet, ChatWrapper.impl.stringToChatComponent(title));
}
- private static final Class> scoreActionEnum = Reflection.getClass("{nms.server}.ScoreboardServer$Action");
- private static final Reflection.FieldAccessor> scoreAction = Reflection.getField(FlatteningWrapper.scoreboardScore, scoreActionEnum, 0);
- private static final Object scoreActionChange = scoreActionEnum.getEnumConstants()[0];
+ private static final Class> scoreActionEnum = Core.getVersion() < 21 ? Reflection.getClass("{nms.server}.ScoreboardServer$Action") : null;
+ private static final Reflection.FieldAccessor> scoreAction = Core.getVersion() < 21 ? Reflection.getField(FlatteningWrapper.scoreboardScore, scoreActionEnum, 0) : null;
+ private static final Object scoreActionChange = Core.getVersion() < 21 ? scoreActionEnum.getEnumConstants()[0] : null;
@Override
public void setScoreAction(Object packet) {
diff --git a/SpigotCore/SpigotCore_14/src/de/steamwar/core/TrickyTrialsWrapper14.java b/SpigotCore/SpigotCore_14/src/de/steamwar/core/TrickyTrialsWrapper14.java
new file mode 100644
index 00000000..aa30ea37
--- /dev/null
+++ b/SpigotCore/SpigotCore_14/src/de/steamwar/core/TrickyTrialsWrapper14.java
@@ -0,0 +1,30 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.core;
+
+import org.bukkit.Material;
+
+public class TrickyTrialsWrapper14 extends TrickyTrialsWrapper8 {
+
+ @Override
+ public Material getTurtleScute() {
+ return Material.SCUTE;
+ }
+}
diff --git a/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java b/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java
index eae1c53e..cd116bac 100644
--- a/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java
+++ b/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java
@@ -57,52 +57,20 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class WorldEditWrapper14 implements WorldEditWrapper {
- private static final ClipboardFormat SCHEMATIC = ClipboardFormats.findByAlias("schematic");
- private static final ClipboardFormat SCHEM = ClipboardFormats.findByAlias("schem");
+ private static final ClipboardFormat SCHEMATIC = BuiltInClipboardFormat.MCEDIT_SCHEMATIC;
+ private static final ClipboardFormat SCHEM = BuiltInClipboardFormat.SPONGE_SCHEMATIC;
@Override
public InputStream getPlayerClipboard(Player player, boolean schemFormat) {
- ClipboardHolder clipboardHolder;
- try {
- clipboardHolder = WorldEditWrapper.getWorldEditPlugin().getSession(player).getClipboard();
- } catch (EmptyClipboardException e) {
- throw new NoClipboardException();
- }
-
- Clipboard clipboard = clipboardHolder.getClipboard();
- if(clipboard == null)
- throw new NoClipboardException();
-
- PipedOutputStream outputStream = new PipedOutputStream();
- PipedInputStream inputStream;
- try {
- inputStream = new PipedInputStream(outputStream, 4096);
- }catch(NullPointerException e){
- throw new RuntimeException(e.getMessage(), new IOException(e));
- } catch (IOException e) {
- throw new SecurityException("Could not init piped input stream", e);
- }
-
- new Thread(() -> {
- try{
- if(schemFormat){
- ClipboardWriter writer = SCHEM.getWriter(outputStream);
- writer.write(clipboard);
- writer.close();
- }else{
- SCHEMATIC.getWriter(outputStream).write(clipboard);
- }
- }catch(NullPointerException | IOException e) {
- Core.getInstance().getLogger().log(Level.SEVERE, "Could not write schematic", e);
+ return WorldEditWrapper.getPlayerClipboard(player, schemFormat, (outputStream, clipboard, clipboardHolder) -> {
+ if(schemFormat){
+ ClipboardWriter writer = SCHEM.getWriter(outputStream);
+ writer.write(clipboard);
+ writer.close();
+ }else{
+ SCHEMATIC.getWriter(outputStream).write(clipboard);
}
- try {
- outputStream.close();
- } catch (IOException e) {
- Core.getInstance().getLogger().log(Level.SEVERE, "Could not close schem writer", e);
- }
- }, "SchemWriter").start();
-
- return inputStream;
+ });
}
@Override
diff --git a/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java b/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java
index 4942b2a1..903113c4 100644
--- a/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java
+++ b/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java
@@ -21,8 +21,7 @@ package de.steamwar.core;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
-import com.sk89q.worldedit.extent.clipboard.io.MCEditSchematicReader;
-import com.sk89q.worldedit.extent.clipboard.io.SpongeSchematicReader;
+import com.sk89q.worldedit.extent.clipboard.io.*;
import de.steamwar.sql.NoClipboardException;
import java.io.IOException;
@@ -33,8 +32,8 @@ public class WorldEditWrapper18 extends WorldEditWrapper14 {
@Override
@SuppressWarnings("removal")
public Clipboard getClipboard(InputStream is, boolean schemFormat) throws IOException {
- //Use FAWE reader due to FAWE capability of reading corrupt FAWE schems
NBTInputStream nbtStream = new NBTInputStream(is);
+ //Use FAWE reader due to FAWE capability of reading corrupt FAWE schems
try {
return (schemFormat ? new SpongeSchematicReader(nbtStream) : new MCEditSchematicReader(nbtStream)).read();
} catch (NullPointerException e) {
diff --git a/SpigotCore/SpigotCore_21/build.gradle.kts b/SpigotCore/SpigotCore_21/build.gradle.kts
index b702534b..b9a7805e 100644
--- a/SpigotCore/SpigotCore_21/build.gradle.kts
+++ b/SpigotCore/SpigotCore_21/build.gradle.kts
@@ -23,6 +23,11 @@ plugins {
dependencies {
compileOnly(project(":SpigotCore:SpigotCore_Main", "default"))
+ compileOnly(project(":SpigotCore:SpigotCore_18", "default"))
+ compileOnly(project(":SpigotCore:SpigotCore_14", "default"))
+ compileOnly(project(":SpigotCore:SpigotCore_9", "default"))
+
+ compileOnly(libs.fawe21)
compileOnly(libs.paperapi21) {
attributes {
@@ -30,4 +35,10 @@ dependencies {
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21)
}
}
+ compileOnly(libs.nms21) {
+ attributes {
+ // Very Hacky, but it works
+ attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21)
+ }
+ }
}
diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/BountifulWrapper21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/BountifulWrapper21.java
new file mode 100644
index 00000000..d144c9b6
--- /dev/null
+++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/BountifulWrapper21.java
@@ -0,0 +1,42 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.core;
+
+import com.comphenix.tinyprotocol.Reflection;
+import net.minecraft.world.entity.PositionMoveRotation;
+import net.minecraft.world.phys.Vec3D;
+
+public class BountifulWrapper21 extends BountifulWrapper9 {
+
+ @Override
+ public BountifulWrapper.PositionSetter getPositionSetter(Class> packetClass, int fieldOffset) {
+ try {
+ Reflection.FieldAccessor field = Reflection.getField(packetClass, PositionMoveRotation.class, 0);
+
+ return (packet, x, y, z, pitch, yaw) -> {
+ PositionMoveRotation pos = field.get(packet);
+
+ field.set(packet, new PositionMoveRotation(new Vec3D(x, y, z), pos.b(), pitch, yaw));
+ };
+ } catch (IllegalArgumentException e) {
+ return super.getPositionSetter(packetClass, fieldOffset);
+ }
+ }
+}
diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/ChatWrapper21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/ChatWrapper21.java
new file mode 100644
index 00000000..760ba393
--- /dev/null
+++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/ChatWrapper21.java
@@ -0,0 +1,44 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.core;
+
+import net.minecraft.network.chat.IChatMutableComponent;
+import net.minecraft.network.chat.contents.LiteralContents;
+import net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata;
+import net.minecraft.network.syncher.DataWatcher;
+
+import java.util.ArrayList;
+
+public class ChatWrapper21 implements ChatWrapper {
+ @Override
+ public Object stringToChatComponent(String text) {
+ return IChatMutableComponent.a(LiteralContents.a(text));
+ }
+
+ @Override
+ public Object getDataWatcherPacket(int entityId, Object... dataWatcherKeyValues) {
+ ArrayList> nativeWatchers = new ArrayList<>(1);
+ for(int i = 0; i < dataWatcherKeyValues.length; i+=2) {
+ nativeWatchers.add(((DataWatcher.Item>) BountifulWrapper.impl.getDataWatcherItem(dataWatcherKeyValues[i], dataWatcherKeyValues[i+1])).e());
+ }
+
+ return new PacketPlayOutEntityMetadata(entityId, nativeWatchers);
+ }
+}
diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/CraftbukkitWrapper21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/CraftbukkitWrapper21.java
new file mode 100644
index 00000000..2309a2a6
--- /dev/null
+++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/CraftbukkitWrapper21.java
@@ -0,0 +1,41 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.core;
+
+import com.comphenix.tinyprotocol.Reflection;
+import com.comphenix.tinyprotocol.TinyProtocol;
+import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
+import net.minecraft.world.level.World;
+import net.minecraft.world.level.chunk.Chunk;
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+import net.minecraft.world.level.lighting.LevelLightEngine;
+import org.bukkit.entity.Player;
+
+public class CraftbukkitWrapper21 implements CraftbukkitWrapper.ICraftbukkitWrapper {
+
+ private static final Reflection.MethodInvoker getHandle = Reflection.getMethod("{obc}.CraftChunk", "getHandle", ChunkStatus.class);
+ private static final Reflection.MethodInvoker getLightEngine = Reflection.getTypedMethod(World.class, null, LevelLightEngine.class);
+
+ @Override
+ public void sendChunk(Player p, int chunkX, int chunkZ) {
+ Chunk chunk = (Chunk) getHandle.invoke(p.getWorld().getChunkAt(chunkX, chunkZ), ChunkStatus.n);
+ TinyProtocol.instance.sendPacket(p, new ClientboundLevelChunkWithLightPacket(chunk, (LevelLightEngine) getLightEngine.invoke(chunk.r), null, null, true));
+ }
+}
diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/TrickyParticleWrapper21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/TrickyParticleWrapper21.java
new file mode 100644
index 00000000..5575a45b
--- /dev/null
+++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/TrickyParticleWrapper21.java
@@ -0,0 +1,29 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.core;
+
+import org.bukkit.Particle;
+
+public class TrickyParticleWrapper21 implements TrickyParticleWrapper {
+ @Override
+ public Particle getVillagerHappy() {
+ return Particle.HAPPY_VILLAGER;
+ }
+}
diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/TrickyTrialsWrapper21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/TrickyTrialsWrapper21.java
new file mode 100644
index 00000000..1b10c742
--- /dev/null
+++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/TrickyTrialsWrapper21.java
@@ -0,0 +1,48 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.core;
+
+import org.bukkit.Material;
+import org.bukkit.Particle;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.EntityType;
+import org.bukkit.inventory.InventoryView;
+
+public class TrickyTrialsWrapper21 implements TrickyTrialsWrapper {
+ @Override
+ public EntityType getTntEntityType() {
+ return EntityType.TNT;
+ }
+
+ @Override
+ public Enchantment getUnbreakingEnchantment() {
+ return Enchantment.UNBREAKING;
+ }
+
+ @Override
+ public Material getTurtleScute() {
+ return Material.TURTLE_SCUTE;
+ }
+
+ @Override
+ public String getInventoryTitle(InventoryView view) {
+ return view.getTitle();
+ }
+}
diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java
new file mode 100644
index 00000000..087dc439
--- /dev/null
+++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java
@@ -0,0 +1,123 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.core;
+
+import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV2;
+import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV3;
+import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriterV3;
+import com.sk89q.jnbt.NBTInputStream;
+import com.sk89q.jnbt.NBTOutputStream;
+import com.sk89q.worldedit.extension.platform.Actor;
+import com.sk89q.worldedit.extent.clipboard.Clipboard;
+import com.sk89q.worldedit.extent.clipboard.io.MCEditSchematicReader;
+import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV1Reader;
+import com.sk89q.worldedit.math.Vector3;
+import com.sk89q.worldedit.math.transform.Transform;
+import com.sk89q.worldedit.regions.Region;
+import com.sk89q.worldedit.session.ClipboardHolder;
+import org.bukkit.entity.Player;
+import org.bukkit.util.Vector;
+import org.enginehub.linbus.stream.LinBinaryIO;
+import org.enginehub.linbus.stream.LinStream;
+import org.enginehub.linbus.tree.LinCompoundTag;
+import org.enginehub.linbus.tree.LinRootEntry;
+import org.enginehub.linbus.tree.LinTagType;
+
+import java.io.*;
+
+public class WorldEditWrapper21 implements WorldEditWrapper {
+
+ @Override
+ public InputStream getPlayerClipboard(Player player, boolean schemFormat) {
+ return WorldEditWrapper.getPlayerClipboard(player, schemFormat, (outputStream, clipboard, clipboardHolder) -> {
+ try {
+ new FastSchematicWriterV3(new NBTOutputStream(outputStream)).write(clipboard);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ }
+
+ @Override
+ public void setPlayerClipboard(Player player, InputStream is, boolean schemFormat) {
+ Clipboard clipboard = null;
+ try {
+ clipboard = getClipboard(is, schemFormat);
+ } catch (IOException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+
+ if (clipboard == null)
+ throw new SecurityException("Clipboard is null");
+
+ Actor actor = WorldEditWrapper.getWorldEditPlugin().wrapCommandSender(player);
+ WorldEditWrapper.getWorldEditPlugin().getWorldEdit().getSessionManager().get(actor).setClipboard(new ClipboardHolder(clipboard));
+ }
+
+ @Override
+ public Clipboard getClipboard(InputStream is, boolean schemFormat) throws IOException {
+ if (!schemFormat) {
+ return new MCEditSchematicReader(new NBTInputStream(is)).read();
+ } else {
+ BufferedInputStream bis = new BufferedInputStream(is);
+
+ bis.mark(Integer.MAX_VALUE);
+
+ LinStream linStream = LinBinaryIO.read(new DataInputStream(bis));
+
+ LinCompoundTag entry = LinRootEntry.readFrom(linStream).value();
+
+ bis.reset();
+
+ switch (entry.getTag("Version", LinTagType.intTag()).valueAsInt()) {
+ case 1:
+ return new SpongeSchematicV1Reader(entry.linStream()).read();
+ case 2:
+ return new FastSchematicReaderV2(new NBTInputStream(bis)).read();
+ case 3:
+ return new FastSchematicReaderV3(bis).read();
+ default:
+ throw new IOException("Unknown schematic version");
+ }
+ }
+ }
+
+ @Override
+ public org.bukkit.util.Vector getOrigin(Clipboard clipboard) {
+ return new org.bukkit.util.Vector(clipboard.getOrigin().x(), clipboard.getOrigin().y(), clipboard.getOrigin().z());
+ }
+
+ @Override
+ public Vector getMinimum(Region region) {
+ return new Vector(region.getMinimumPoint().x(), region.getMinimumPoint().y(), region.getMinimumPoint().z());
+ }
+
+ @Override
+ public Vector getMaximum(Region region) {
+ return new Vector(region.getMaximumPoint().x(), region.getMaximumPoint().y(), region.getMaximumPoint().z());
+ }
+
+ @Override
+ public Vector applyTransform(Vector vector, Transform transform) {
+ Vector3 v = Vector3.at(vector.getX(), vector.getY(), vector.getZ());
+ v = transform.apply(v);
+ return new org.bukkit.util.Vector(v.x(), v.y(), v.z());
+ }
+}
diff --git a/SpigotCore/SpigotCore_8/src/de/steamwar/core/BountifulWrapper8.java b/SpigotCore/SpigotCore_8/src/de/steamwar/core/BountifulWrapper8.java
index d901401c..54ea45b3 100644
--- a/SpigotCore/SpigotCore_8/src/de/steamwar/core/BountifulWrapper8.java
+++ b/SpigotCore/SpigotCore_8/src/de/steamwar/core/BountifulWrapper8.java
@@ -25,6 +25,7 @@ import net.md_5.bungee.api.chat.BaseComponent;
import net.minecraft.server.v1_8_R3.ChatComponentText;
import net.minecraft.server.v1_8_R3.MathHelper;
import net.minecraft.server.v1_8_R3.PacketPlayOutChat;
+import net.minecraft.server.v1_8_R3.PacketPlayOutEntityTeleport;
import org.bukkit.Sound;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;
@@ -70,11 +71,15 @@ public class BountifulWrapper8 implements BountifulWrapper.IBountifulWrapper {
Reflection.FieldAccessor posX = Reflection.getField(packetClass, int.class, fieldOffset);
Reflection.FieldAccessor posY = Reflection.getField(packetClass, int.class, fieldOffset +1);
Reflection.FieldAccessor posZ = Reflection.getField(packetClass, int.class, fieldOffset +2);
+ Reflection.FieldAccessor lookPitch = Reflection.getField(packetClass, byte.class, 0);
+ Reflection.FieldAccessor lookYaw = Reflection.getField(packetClass, byte.class, 1);
- return (packet, x, y, z) -> {
+ return (packet, x, y, z, pitch, yaw) -> {
posX.set(packet, MathHelper.floor(x * 32));
posY.set(packet, MathHelper.floor(y * 32));
posZ.set(packet, MathHelper.floor(z * 32));
+ lookPitch.set(packet, (byte)(pitch * 256 / 360));
+ lookYaw.set(packet, (byte)(yaw * 256 / 360));
};
}
@@ -83,11 +88,15 @@ public class BountifulWrapper8 implements BountifulWrapper.IBountifulWrapper {
Reflection.FieldAccessor> moveX = Reflection.getField(packetClass, "b", byte.class);
Reflection.FieldAccessor> moveY = Reflection.getField(packetClass, "c", byte.class);
Reflection.FieldAccessor> moveZ = Reflection.getField(packetClass, "d", byte.class);
+ Reflection.FieldAccessor lookYaw = Reflection.getField(packetClass, "e", byte.class);
+ Reflection.FieldAccessor lookPitch = Reflection.getField(packetClass, "f", byte.class);
- return (packet, x, y, z) -> {
+ return (packet, x, y, z, pitch, yaw) -> {
moveX.set(packet, (byte)(x*32));
moveY.set(packet, (byte)(y*32));
moveZ.set(packet, (byte)(z*32));
+ lookYaw.set(packet, (byte)(yaw*256/360));
+ lookPitch.set(packet, (byte)(pitch*256/360));
};
}
diff --git a/SpigotCore/SpigotCore_8/src/de/steamwar/core/FlatteningWrapper8.java b/SpigotCore/SpigotCore_8/src/de/steamwar/core/FlatteningWrapper8.java
index 535c5261..7d485286 100644
--- a/SpigotCore/SpigotCore_8/src/de/steamwar/core/FlatteningWrapper8.java
+++ b/SpigotCore/SpigotCore_8/src/de/steamwar/core/FlatteningWrapper8.java
@@ -96,7 +96,7 @@ public class FlatteningWrapper8 implements FlatteningWrapper.IFlatteningWrapper
private static final Reflection.FieldAccessor spawnLivingType = Reflection.getField(ProtocolWrapper.spawnLivingPacket, int.class, 1);
private static final Map types = new HashMap<>();
static {
- types.put(EntityType.PRIMED_TNT, 50);
+ types.put(TrickyTrialsWrapper.impl.getTntEntityType(), 50);
types.put(EntityType.ARMOR_STAND, 30);
types.put(EntityType.ARROW, 60);
types.put(EntityType.FIREBALL, 63);
diff --git a/SpigotCore/SpigotCore_8/src/de/steamwar/core/TrickyTrialsWrapper8.java b/SpigotCore/SpigotCore_8/src/de/steamwar/core/TrickyTrialsWrapper8.java
new file mode 100644
index 00000000..35b80c58
--- /dev/null
+++ b/SpigotCore/SpigotCore_8/src/de/steamwar/core/TrickyTrialsWrapper8.java
@@ -0,0 +1,47 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.core;
+
+import org.bukkit.Material;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.EntityType;
+import org.bukkit.inventory.InventoryView;
+
+public class TrickyTrialsWrapper8 implements TrickyTrialsWrapper {
+ @Override
+ public EntityType getTntEntityType() {
+ return EntityType.PRIMED_TNT;
+ }
+
+ @Override
+ public Enchantment getUnbreakingEnchantment() {
+ return Enchantment.DURABILITY;
+ }
+
+ @Override
+ public Material getTurtleScute() {
+ return Material.STONE;
+ }
+
+ @Override
+ public String getInventoryTitle(InventoryView view) {
+ return view.getTitle();
+ }
+}
diff --git a/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java b/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java
index 69ebb544..f3fc2800 100644
--- a/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java
+++ b/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java
@@ -37,57 +37,22 @@ import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.world.registry.WorldData;
-import de.steamwar.sql.NoClipboardException;
import org.bukkit.entity.Player;
import java.io.IOException;
import java.io.InputStream;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.logging.Level;
import java.util.stream.Collectors;
public class WorldEditWrapper8 implements WorldEditWrapper {
@Override
public InputStream getPlayerClipboard(Player player, boolean schemFormat) {
- ClipboardHolder clipboardHolder;
- try {
- clipboardHolder = WorldEditWrapper.getWorldEditPlugin().getSession(player).getClipboard();
- } catch (EmptyClipboardException e) {
- throw new NoClipboardException();
- }
-
- Clipboard clipboard = clipboardHolder.getClipboard();
- if(clipboard == null)
- throw new NoClipboardException();
-
- PipedOutputStream outputStream = new PipedOutputStream();
- PipedInputStream inputStream;
- try {
- inputStream = new PipedInputStream(outputStream, 4096);
- } catch (IOException e) {
- throw new SecurityException("Could not init piped input stream", e);
- }
-
- new Thread(() -> {
- try {
- ClipboardFormat.SCHEMATIC.getWriter(outputStream).write(clipboard, clipboardHolder.getWorldData());
- } catch (IOException e) {
- Core.getInstance().getLogger().log(Level.SEVERE, "Could not write schematic", e);
- }
- try {
- outputStream.close();
- } catch (IOException e) {
- Core.getInstance().getLogger().log(Level.SEVERE, "Could not close schem writer", e);
- }
- }, "SchemWriter").start();
-
- return inputStream;
+ return WorldEditWrapper.getPlayerClipboard(player, schemFormat, (outputStream, clipboard, clipboardHolder) ->
+ ClipboardFormat.SCHEMATIC.getWriter(outputStream).write(clipboard, clipboardHolder.getWorldData()));
}
@Override
diff --git a/SpigotCore/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java b/SpigotCore/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java
index 2832f2f4..b4ae9845 100644
--- a/SpigotCore/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java
+++ b/SpigotCore/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java
@@ -23,6 +23,7 @@ import com.comphenix.tinyprotocol.Reflection;
import com.viaversion.viaversion.api.Via;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.BaseComponent;
+import net.minecraft.server.v1_9_R2.PacketPlayOutEntity;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
@@ -64,11 +65,17 @@ public class BountifulWrapper9 implements BountifulWrapper.IBountifulWrapper {
Reflection.FieldAccessor posX = Reflection.getField(packetClass, double.class, fieldOffset);
Reflection.FieldAccessor posY = Reflection.getField(packetClass, double.class, fieldOffset+1);
Reflection.FieldAccessor posZ = Reflection.getField(packetClass, double.class, fieldOffset+2);
+ boolean isByteClass = packetClass.getSimpleName().contains("PacketPlayOutEntityTeleport");
+ Class> pitchYawType = isByteClass ? byte.class : int.class;
+ Reflection.FieldAccessor> lookPitch = Reflection.getField(packetClass, pitchYawType, isByteClass ? 0 : 1);
+ Reflection.FieldAccessor> lookYaw = Reflection.getField(packetClass, pitchYawType, isByteClass ? 1 : 2);
- return (packet, x, y, z) -> {
+ return (packet, x, y, z, pitch, yaw) -> {
posX.set(packet, x);
posY.set(packet, y);
posZ.set(packet, z);
+ lookPitch.set(packet, (int)(pitch*256/360));
+ lookYaw.set(packet, (int)(yaw*256/360));
};
}
@@ -78,11 +85,15 @@ public class BountifulWrapper9 implements BountifulWrapper.IBountifulWrapper {
Reflection.FieldAccessor> moveX = Reflection.getField(packetClass, "b", type);
Reflection.FieldAccessor> moveY = Reflection.getField(packetClass, "c", type);
Reflection.FieldAccessor> moveZ = Reflection.getField(packetClass, "d", type);
+ Reflection.FieldAccessor movePitch = Reflection.getField(packetClass, "e", byte.class);
+ Reflection.FieldAccessor moveYaw = Reflection.getField(packetClass, "f", byte.class);
- return (packet, x, y, z) -> {
+ return (packet, x, y, z, pitch, yaw) -> {
moveX.set(packet, (short)(x*4096));
moveY.set(packet, (short)(y*4096));
moveZ.set(packet, (short)(z*4096));
+ movePitch.set(packet, (byte)(pitch*256/360));
+ moveYaw.set(packet, (byte)(yaw*256/360));
};
}
diff --git a/SpigotCore/SpigotCore_9/src/de/steamwar/core/TrickyParticleWrapper9.java b/SpigotCore/SpigotCore_9/src/de/steamwar/core/TrickyParticleWrapper9.java
new file mode 100644
index 00000000..5c2c879b
--- /dev/null
+++ b/SpigotCore/SpigotCore_9/src/de/steamwar/core/TrickyParticleWrapper9.java
@@ -0,0 +1,29 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.core;
+
+import org.bukkit.Particle;
+
+public class TrickyParticleWrapper9 implements TrickyParticleWrapper {
+ @Override
+ public Particle getVillagerHappy() {
+ return Particle.VILLAGER_HAPPY;
+ }
+}
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/BountifulWrapper.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/BountifulWrapper.java
index 2e532908..f1c86afe 100644
--- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/BountifulWrapper.java
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/BountifulWrapper.java
@@ -44,7 +44,7 @@ public class BountifulWrapper {
}
public interface PositionSetter {
- void set(Object packet, double x, double y, double z);
+ void set(Object packet, double x, double y, double z, float pitch, float yaw);
}
public interface UUIDSetter {
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/TrickyParticleWrapper.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/TrickyParticleWrapper.java
new file mode 100644
index 00000000..ae781100
--- /dev/null
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/TrickyParticleWrapper.java
@@ -0,0 +1,28 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.core;
+
+import org.bukkit.Particle;
+
+public interface TrickyParticleWrapper {
+ public TrickyParticleWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
+
+ Particle getVillagerHappy();
+}
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/TrickyTrialsWrapper.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/TrickyTrialsWrapper.java
new file mode 100644
index 00000000..da8fc7cd
--- /dev/null
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/TrickyTrialsWrapper.java
@@ -0,0 +1,37 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.core;
+
+import org.bukkit.Material;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.EntityType;
+import org.bukkit.inventory.InventoryView;
+
+public interface TrickyTrialsWrapper {
+ TrickyTrialsWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
+
+ EntityType getTntEntityType();
+
+ Enchantment getUnbreakingEnchantment();
+
+ Material getTurtleScute();
+
+ String getInventoryTitle(InventoryView view);
+}
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java
index cd9a0d4e..377efe13 100644
--- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java
@@ -68,7 +68,7 @@ public class WorldEditRenderer {
Transform transform = session.getClipboard().getTransform();
Vector a = WorldEditWrapper.impl.applyTransform(WorldEditWrapper.impl.getMinimum(region).subtract(WorldEditWrapper.impl.getOrigin(clipboard)), transform).add(pos);
Vector b = WorldEditWrapper.impl.applyTransform(WorldEditWrapper.impl.getMaximum(region).subtract(WorldEditWrapper.impl.getOrigin(clipboard)), transform).add(pos);
- drawCuboid(Vector.getMinimum(a, b), Vector.getMaximum(a, b), Particle.VILLAGER_HAPPY, player);
+ drawCuboid(Vector.getMinimum(a, b), Vector.getMaximum(a, b), TrickyParticleWrapper.impl.getVillagerHappy(), player);
} catch (EmptyClipboardException e) {
//ignore
}
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java
index 1d9ef6cd..87906944 100644
--- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java
@@ -19,16 +19,19 @@
package de.steamwar.core;
+import com.sk89q.worldedit.EmptyClipboardException;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
+import com.sk89q.worldedit.session.ClipboardHolder;
+import de.steamwar.sql.NoClipboardException;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.Region;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
-import java.io.IOException;
-import java.io.InputStream;
+import java.io.*;
+import java.util.logging.Level;
public interface WorldEditWrapper {
WorldEditWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
@@ -45,4 +48,44 @@ public interface WorldEditWrapper {
static WorldEditPlugin getWorldEditPlugin() {
return (WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit");
}
+
+ public static InputStream getPlayerClipboard(Player player, boolean schemFormat, SchematicWriter consumer) {
+ ClipboardHolder clipboardHolder;
+ try {
+ clipboardHolder = WorldEditWrapper.getWorldEditPlugin().getSession(player).getClipboard();
+ } catch (EmptyClipboardException e) {
+ throw new NoClipboardException();
+ }
+
+ Clipboard clipboard = clipboardHolder.getClipboard();
+ if(clipboard == null)
+ throw new NoClipboardException();
+
+ PipedOutputStream outputStream = new PipedOutputStream();
+ PipedInputStream inputStream;
+ try {
+ inputStream = new PipedInputStream(outputStream, 4096);
+ } catch (IOException e) {
+ throw new SecurityException("Could not init piped input stream", e);
+ }
+
+ new Thread(() -> {
+ try {
+ consumer.write(outputStream, clipboard, clipboardHolder);
+ } catch (Exception e) {
+ Core.getInstance().getLogger().log(Level.SEVERE, "Could not write schematic", e);
+ }
+ try {
+ outputStream.close();
+ } catch (IOException e) {
+ Core.getInstance().getLogger().log(Level.SEVERE, "Could not close schem writer", e);
+ }
+ }, "SchemWriter").start();
+
+ return inputStream;
+ }
+
+ public static interface SchematicWriter {
+ void write(OutputStream outputStream, Clipboard clipboard, ClipboardHolder holder) throws IOException;
+ }
}
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/REntity.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/REntity.java
index 5f97b0df..6948dc68 100644
--- a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/REntity.java
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/REntity.java
@@ -393,25 +393,19 @@ public class REntity {
return ChatWrapper.impl.getDataWatcherPacket(entityId, dataWatcherKeyValues);
}
- private static final Class> teleportPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntityTeleport");
- private static final Reflection.FieldAccessor teleportEntity = Reflection.getField(teleportPacket, int.class, 0);
- private static final BountifulWrapper.PositionSetter teleportPosition = BountifulWrapper.impl.getPositionSetter(teleportPacket, Core.getVersion() == 8 ? 1 : 0);
- private static final Reflection.FieldAccessor teleportYaw = Reflection.getField(teleportPacket, byte.class, 0);
- private static final Reflection.FieldAccessor teleportPitch = Reflection.getField(teleportPacket, byte.class, 1);
+ public static final Class> teleportPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntityTeleport");
+ public static final Reflection.FieldAccessor teleportEntity = Reflection.getField(teleportPacket, int.class, 0);
+ public static final BountifulWrapper.PositionSetter teleportPosition = BountifulWrapper.impl.getPositionSetter(teleportPacket, Core.getVersion() == 8 ? 1 : 0);
private Object getTeleportPacket(){
Object packet = Reflection.newInstance(teleportPacket);
teleportEntity.set(packet, entityId);
- teleportPosition.set(packet, x, y, z);
- teleportYaw.set(packet, yaw);
- teleportPitch.set(packet, pitch);
+ teleportPosition.set(packet, x, y, z, pitch, yaw);
return packet;
}
private static final Class> entityPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntity");
private static final Reflection.FieldAccessor moveEntityId = Reflection.getField(entityPacket, int.class, 0);
private static final BountifulWrapper.PositionSetter movePosition = BountifulWrapper.impl.getRelMoveSetter(entityPacket);
- private static final Reflection.FieldAccessor lookYaw = Reflection.getField(entityPacket, "e", byte.class);
- private static final Reflection.FieldAccessor lookPitch = Reflection.getField(entityPacket, "f", byte.class);
private static final Class> lookPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntity$PacketPlayOutEntityLook");
private static final Class> movePacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntity$PacketPlayOutRelEntityMove");
private static final Class> moveLookPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntity$PacketPlayOutRelEntityMoveLook");
@@ -430,9 +424,7 @@ public class REntity {
Object packet = Reflection.newInstance(clazz);
moveEntityId.set(packet, entityId);
- movePosition.set(packet, diffX, diffY, diffZ);
- lookYaw.set(packet, yaw);
- lookPitch.set(packet, pitch);
+ movePosition.set(packet, diffX, diffY, diffZ, pitch, yaw);
return packet;
}
@@ -476,7 +468,7 @@ public class REntity {
return entity -> {
Object packet = Reflection.newInstance(spawnPacket);
entityId.set(packet, entity.entityId);
- position.set(packet, entity.x, entity.y, entity.z);
+ position.set(packet, entity.x, entity.y, entity.z, entity.pitch, entity.yaw);
return packet;
};
}
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWInventory.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWInventory.java
index 94a8cf3a..11fe1ec6 100644
--- a/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWInventory.java
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWInventory.java
@@ -20,6 +20,7 @@
package de.steamwar.inventory;
import de.steamwar.core.Core;
+import de.steamwar.core.TrickyTrialsWrapper;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
@@ -138,7 +139,7 @@ public class SWInventory implements Listener {
public void open() {
InventoryView view = player.openInventory(inventory);
- title = view.getTitle();
+ title = TrickyTrialsWrapper.impl.getInventoryTitle(view);
Core.getInstance().getLogger().info("[SWINV] Opened " + title + " for " + player.getName());
if(!open) {
Bukkit.getPluginManager().registerEvents(this, Core.getInstance());
@@ -153,7 +154,7 @@ public class SWInventory implements Listener {
if (callbacks.containsKey(e.getRawSlot()) && callbacks.get(e.getRawSlot()) != null) {
e.setCancelled(true);
- Core.getInstance().getLogger().info("[SWINV] " + e.getWhoClicked().getName() + " " + e.getClick().name() + " clicked " + e.getRawSlot() + " on " + (e.getCurrentItem() != null ? e.getCurrentItem().getItemMeta().getDisplayName() : "[EMPTY]") + " in " + e.getView().getTitle());
+ Core.getInstance().getLogger().info("[SWINV] " + e.getWhoClicked().getName() + " " + e.getClick().name() + " clicked " + e.getRawSlot() + " on " + (e.getCurrentItem() != null ? e.getCurrentItem().getItemMeta().getDisplayName() : "[EMPTY]") + " in " + TrickyTrialsWrapper.impl.getInventoryTitle(e.getView()));
callbacks.get(e.getRawSlot()).accept(e);
}
}
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWItem.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWItem.java
index d9f9c23a..bc401476 100644
--- a/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWItem.java
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWItem.java
@@ -21,7 +21,10 @@ package de.steamwar.inventory;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
+import de.steamwar.core.Core;
import de.steamwar.core.FlatteningWrapper;
+import de.steamwar.core.TrickyTrialsWrapper;
+import de.steamwar.core.VersionDependent;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.enchantments.Enchantment;
@@ -30,6 +33,8 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
import java.util.List;
public class SWItem {
@@ -107,7 +112,7 @@ public class SWItem {
itemMeta.setDisplayName(name);
if (lore != null && !lore.isEmpty()) itemMeta.setLore(lore);
- if (enchanted) itemMeta.addEnchant(Enchantment.DURABILITY , 10, true);
+ if (enchanted) itemMeta.addEnchant(TrickyTrialsWrapper.impl.getUnbreakingEnchantment(), 10, true);
itemStack.setItemMeta(itemMeta);
}
callback = c;
@@ -144,12 +149,9 @@ public class SWItem {
private void hideAttributes() {
if (itemMeta == null) return;
- itemMeta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
- itemMeta.addItemFlags(ItemFlag.HIDE_DESTROYS);
- itemMeta.addItemFlags(ItemFlag.HIDE_UNBREAKABLE);
- itemMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
- itemMeta.addItemFlags(ItemFlag.HIDE_PLACED_ON);
- itemMeta.addItemFlags(ItemFlag.HIDE_POTION_EFFECTS);
+ for (ItemFlag flag : EnumSet.allOf(ItemFlag.class)) {
+ itemMeta.addItemFlags(flag);
+ }
}
public ItemStack getItemStack() {
@@ -192,9 +194,9 @@ public class SWItem {
public void setEnchanted(boolean enchanted) {
if (enchanted){
- itemMeta.addEnchant(Enchantment.DURABILITY , 10, true);
+ itemMeta.addEnchant(TrickyTrialsWrapper.impl.getUnbreakingEnchantment() , 10, true);
} else {
- itemMeta.removeEnchant(Enchantment.DURABILITY);
+ itemMeta.removeEnchant(TrickyTrialsWrapper.impl.getUnbreakingEnchantment());
}
itemStack.setItemMeta(itemMeta);
}
diff --git a/Teamserver/src/de/steamwar/teamserver/listener/FreezeListener.java b/Teamserver/src/de/steamwar/teamserver/listener/FreezeListener.java
index 5bcb4fed..7d576d2f 100644
--- a/Teamserver/src/de/steamwar/teamserver/listener/FreezeListener.java
+++ b/Teamserver/src/de/steamwar/teamserver/listener/FreezeListener.java
@@ -20,6 +20,7 @@
package de.steamwar.teamserver.listener;
import de.steamwar.core.Core;
+import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.teamserver.Builder;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.BaseComponent;
@@ -55,7 +56,7 @@ public class FreezeListener implements Listener {
public void onEntitySpawn(EntitySpawnEvent e) {
if (!freeze) return;
e.setCancelled(true);
- if (e.getEntityType() == EntityType.PRIMED_TNT) {
+ if (e.getEntityType() == TrickyTrialsWrapper.impl.getTntEntityType()) {
Bukkit.getScheduler().runTaskLater(Builder.getInstance(), () -> {
e.getLocation().getBlock().setType(Material.TNT, false);
}, 1L);
diff --git a/settings.gradle.kts b/settings.gradle.kts
index d12d432f..69d5c67b 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -119,7 +119,7 @@ dependencyResolutionManagement {
library("datafixer", "com.mojang:datafixerupper:4.0.26")
library("brigadier", "com.mojang:brigadier:1.0.18")
library("viaapi", "com.viaversion:viaversion-api:4.3.1")
- library("anvilgui", "net.wesjd:anvilgui:1.7.0-SNAPSHOT")
+ library("anvilgui", "net.wesjd:anvilgui:1.10.3-SNAPSHOT")
library("nms8", "de.steamwar:spigot:1.8")
library("nms9", "de.steamwar:spigot:1.9")
@@ -130,11 +130,13 @@ dependencyResolutionManagement {
library("nms18", "de.steamwar:spigot:1.18")
library("nms19", "de.steamwar:spigot:1.19")
library("nms20", "de.steamwar:spigot:1.20")
+ library("nms21", "de.steamwar:spigot:1.21")
library("axiom", "de.steamwar:axiompaper:RELEASE")
library("worldedit12", "de.steamwar:worldedit:1.12")
library("worldedit15", "de.steamwar:worldedit:1.15")
library("fawe18", "de.steamwar:fastasyncworldedit:1.18")
+ library("fawe21", "de.steamwar:fastasyncworldedit:1.21")
library("velocity", "de.steamwar:velocity:RELEASE")
library("velocityapi", "com.velocitypowered:velocity-api:3.3.0-SNAPSHOT")
@@ -173,6 +175,7 @@ include(
"BauSystem:BauSystem_18",
"BauSystem:BauSystem_19",
"BauSystem:BauSystem_20",
+ "BauSystem:BauSystem_21",
"BauSystem:BauSystem_Main"
)
@@ -195,6 +198,7 @@ include(
"FightSystem:FightSystem_18",
"FightSystem:FightSystem_19",
"FightSystem:FightSystem_20",
+ "FightSystem:FightSystem_21",
"FightSystem:FightSystem_Core",
"FightSystem:FightSystem_Standalone"
)