diff --git a/BauSystem_Main/build.gradle b/BauSystem_Main/build.gradle
index 744e575c..62d604cf 100644
--- a/BauSystem_Main/build.gradle
+++ b/BauSystem_Main/build.gradle
@@ -54,12 +54,11 @@ dependencies {
implementation project(":BauSystem_Linkage")
annotationProcessor project(":BauSystem_Linkage")
- compileOnly 'org.spigotmc:spigot-api:1.19-R0.1-SNAPSHOT'
+ compileOnly 'org.spigotmc:spigot-api:1.20-R0.1-SNAPSHOT'
compileOnly 'com.mojang:authlib:1.5.25'
compileOnly 'io.netty:netty-all:4.1.68.Final'
- compileOnly swdep('Spigot-1.19')
- // compileOnly swdep('WorldEdit-1.15')
+ compileOnly swdep('Spigot-1.20')
compileOnly swdep('SpigotCore')
annotationProcessor swdep('SpigotCore')
diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/world/SignEditFrom20.java b/BauSystem_Main/src/de/steamwar/bausystem/features/world/SignEditFrom20.java
new file mode 100644
index 00000000..4f7ad67a
--- /dev/null
+++ b/BauSystem_Main/src/de/steamwar/bausystem/features/world/SignEditFrom20.java
@@ -0,0 +1,123 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2023 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.features.world;
+
+import com.comphenix.tinyprotocol.Reflection;
+import com.comphenix.tinyprotocol.TinyProtocol;
+import de.steamwar.bausystem.BauSystem;
+import de.steamwar.linkage.Linked;
+import de.steamwar.linkage.MinVersion;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.block.Sign;
+import org.bukkit.block.data.BlockData;
+import org.bukkit.block.data.Rotatable;
+import org.bukkit.block.sign.Side;
+import org.bukkit.block.sign.SignSide;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.util.Vector;
+
+@Linked
+@MinVersion(20)
+public class SignEditFrom20 implements Listener {
+
+ private static final Class> blockPosition = Reflection.getClass("{nms.core}.BlockPosition");
+ private static final Class> craftBlock = Reflection.getClass("{obc}.block.CraftBlock");
+ private static final Class> craftWorld = Reflection.getClass("{obc}.CraftWorld");
+ private static final Class> generatorAccess = Reflection.getClass("{nms.world.level}.GeneratorAccess");
+ private static final Reflection.MethodInvoker getPosition = Reflection.getTypedMethod(craftBlock, "getPosition", blockPosition);
+ private static final Reflection.MethodInvoker getWorldHandle = Reflection.getTypedMethod(craftWorld, "getHandle", null);
+ private static final Reflection.MethodInvoker at = Reflection.getTypedMethod(craftBlock, "at", craftBlock, generatorAccess, blockPosition);
+
+ private static final Class> openSign = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutOpenSignEditor");
+ private static final Reflection.FieldAccessor> blockPositionFieldAccessor = Reflection.getField(openSign, blockPosition, 0);
+ private static final Reflection.FieldAccessor> sideFieldAccessor = Reflection.getField(openSign, boolean.class, 0);
+
+ private static final Class> updateSign = Reflection.getClass("{nms.network.protocol.game}.PacketPlayInUpdateSign");
+ private static final Reflection.FieldAccessor> getBlockPositionFieldAccessor = Reflection.getField(updateSign, blockPosition, 0);
+ private static final Reflection.FieldAccessor stringFieldAccessor = Reflection.getField(updateSign, String[].class, 0);
+
+ @EventHandler
+ public void editSign(PlayerInteractEvent event) {
+ if (event.getClickedBlock() == null || !event.getClickedBlock().getType().name().contains("SIGN")) return;
+ if (event.getAction() == Action.RIGHT_CLICK_BLOCK) event.setCancelled(true);
+ if (!event.getPlayer().isSneaking()) return;
+ event.setCancelled(true);
+
+ if (event.getAction() == Action.RIGHT_CLICK_BLOCK && (event.getItem() == null || event.getItem().getType() == Material.AIR) || event.getAction() == Action.LEFT_CLICK_BLOCK) {
+ Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
+ edit(event.getPlayer(), event.getClickedBlock());
+ }, 1);
+ }
+ }
+
+ private void edit(Player player, Block block) {
+ Sign sign = (Sign) block.getState();
+ Side side = signSide(player, block);
+ SignSide signSide = sign.getSide(side);
+ String[] lines = signSide.getLines();
+ for (int i = 0; i < lines.length; i++) {
+ signSide.setLine(i, lines[i].replace('ยง', '&'));
+ }
+ sign.update(true);
+
+ Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
+ Object openSignObject = Reflection.newInstance(openSign);
+ blockPositionFieldAccessor.set(openSignObject, getPosition.invoke(block));
+ sideFieldAccessor.set(openSignObject, side == Side.FRONT);
+ TinyProtocol.instance.sendPacket(player, openSignObject);
+ }, 1);
+
+ }
+
+ private Side signSide(Player entity, Block sign) {
+ Vector vector = entity.getEyeLocation().toVector().subtract(sign.getLocation().add(0.5, 0.5, 0.5).toVector());
+ BlockFace blockFace = ((org.bukkit.block.data.type.Sign) sign.getBlockData()).getRotation();
+ Vector signDirection = new Vector(blockFace.getModX(), blockFace.getModY(), blockFace.getModZ());
+ return vector.dot(signDirection) > 0 ? Side.FRONT : Side.BACK;
+ }
+
+ {
+ TinyProtocol.instance.addFilter(updateSign, (player, o) -> {
+ Bukkit.getScheduler().runTask(BauSystem.getInstance(), () -> {
+ String[] lines = stringFieldAccessor.get(o);
+
+ Block signLoc = (Block) at.invoke(null, getWorldHandle.invoke(player.getWorld()), getBlockPositionFieldAccessor.get(o));
+ if (!signLoc.getType().name().contains("SIGN"))
+ return;
+
+ Sign sign = ((Sign) signLoc.getState());
+ SignSide signSide = sign.getSide(signSide(player, signLoc));
+ for (int i = 0; i < lines.length; i++) {
+ signSide.setLine(i, ChatColor.translateAlternateColorCodes('&', lines[i]));
+ }
+ sign.update(true);
+ });
+ return o;
+ });
+ }
+}
diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/world/SignEdit.java b/BauSystem_Main/src/de/steamwar/bausystem/features/world/SignEditUntil19.java
similarity index 97%
rename from BauSystem_Main/src/de/steamwar/bausystem/features/world/SignEdit.java
rename to BauSystem_Main/src/de/steamwar/bausystem/features/world/SignEditUntil19.java
index 2f8e154e..19184032 100644
--- a/BauSystem_Main/src/de/steamwar/bausystem/features/world/SignEdit.java
+++ b/BauSystem_Main/src/de/steamwar/bausystem/features/world/SignEditUntil19.java
@@ -23,6 +23,7 @@ import com.comphenix.tinyprotocol.Reflection;
import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.linkage.Linked;
+import de.steamwar.linkage.MaxVersion;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
@@ -35,7 +36,8 @@ import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
@Linked
-public class SignEdit implements Listener {
+@MaxVersion(19)
+public class SignEditUntil19 implements Listener {
private static final Class> blockPosition = Reflection.getClass("{nms.core}.BlockPosition");
private static final Class> craftBlock = Reflection.getClass("{obc}.block.CraftBlock");