diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/BauSystem.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/BauSystem.java
index 0d5fa43c..8376f0f1 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/BauSystem.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/BauSystem.java
@@ -19,6 +19,7 @@
package de.steamwar.bausystem;
+import de.steamwar.core.WorldEditRendererCUIEditor;
import de.steamwar.bausystem.config.BauServer;
import de.steamwar.bausystem.configplayer.Config;
import de.steamwar.bausystem.configplayer.ConfigConverter;
@@ -206,6 +207,8 @@ public class BauSystem extends JavaPlugin {
TraceManager.instance.init();
TraceRecorder.instance.init();
+
+ new WorldEditRendererCUIEditor();
}
@Override
diff --git a/CommonCore/Network/src/de/steamwar/network/packets/server/ClientVersionPacket.java b/CommonCore/Network/src/de/steamwar/network/packets/server/ClientVersionPacket.java
new file mode 100644
index 00000000..c8f43446
--- /dev/null
+++ b/CommonCore/Network/src/de/steamwar/network/packets/server/ClientVersionPacket.java
@@ -0,0 +1,37 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2020 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.network.packets.server;
+
+import de.steamwar.network.packets.NetworkPacket;
+import lombok.*;
+
+import java.util.UUID;
+
+@EqualsAndHashCode(callSuper = true)
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@ToString
+public class ClientVersionPacket extends NetworkPacket {
+ private static final long serialVersionUID = 3686482311704273200L;
+
+ private UUID player;
+ private int version;
+}
diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java
index ce47ee34..9ebc4f0c 100644
--- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java
+++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java
@@ -20,6 +20,7 @@
package de.steamwar.fightsystem;
import com.comphenix.tinyprotocol.TinyProtocol;
+import de.steamwar.core.WorldEditRendererCUIEditor;
import de.steamwar.core.Core;
import de.steamwar.fightsystem.commands.*;
import de.steamwar.fightsystem.countdown.*;
@@ -28,8 +29,8 @@ import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.fight.FightWorld;
import de.steamwar.fightsystem.fight.HotbarKit;
-import de.steamwar.fightsystem.listener.Shutdown;
import de.steamwar.fightsystem.listener.*;
+import de.steamwar.fightsystem.listener.Shutdown;
import de.steamwar.fightsystem.record.FileRecorder;
import de.steamwar.fightsystem.record.FileSource;
import de.steamwar.fightsystem.record.GlobalRecorder;
@@ -106,6 +107,7 @@ public class FightSystem extends JavaPlugin {
new HotbarKit.HotbarKitListener();
new JoinRequestListener();
new OneShotStateDependent(ArenaMode.All, FightState.PreSchemSetup, () -> Fight.playSound(SWSound.BLOCK_NOTE_PLING.getSound(), 100.0f, 2.0f));
+ new OneShotStateDependent(ArenaMode.Test, FightState.All, WorldEditRendererCUIEditor::new);
new EnterHandler();
techHider = new TechHiderWrapper();
diff --git a/SpigotCore/SpigotCore_20/build.gradle.kts b/SpigotCore/SpigotCore_20/build.gradle.kts
index 3e894ccc..79f667e0 100644
--- a/SpigotCore/SpigotCore_20/build.gradle.kts
+++ b/SpigotCore/SpigotCore_20/build.gradle.kts
@@ -26,5 +26,6 @@ dependencies {
compileOnly(libs.spigotapi)
+ compileOnly(libs.fawe18)
compileOnly(libs.nms20)
}
diff --git a/SpigotCore/SpigotCore_20/src/de/steamwar/core/WorldEditRendererWrapper20.java b/SpigotCore/SpigotCore_20/src/de/steamwar/core/WorldEditRendererWrapper20.java
new file mode 100644
index 00000000..36ded8ef
--- /dev/null
+++ b/SpigotCore/SpigotCore_20/src/de/steamwar/core/WorldEditRendererWrapper20.java
@@ -0,0 +1,119 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2020 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 de.steamwar.entity.CWireframe;
+import de.steamwar.entity.REntityServer;
+import org.bukkit.Material;
+import org.bukkit.block.data.BlockData;
+import org.bukkit.entity.Player;
+import org.bukkit.util.Vector;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class WorldEditRendererWrapper20 implements WorldEditRendererWrapper {
+
+ private static final class BoxPair {
+ private CWireframe regionBox;
+ private CWireframe clipboardBox;
+
+ public CWireframe get(boolean clipboard) {
+ if (clipboard) {
+ return clipboardBox;
+ } else {
+ return regionBox;
+ }
+ }
+
+ public void set(boolean clipboard, CWireframe box) {
+ if (clipboard) {
+ this.clipboardBox = box;
+ } else {
+ this.regionBox = box;
+ }
+ }
+
+ public void die() {
+ if (clipboardBox != null) {
+ clipboardBox.die();
+ }
+ if (regionBox != null) {
+ regionBox.die();
+ }
+ }
+ }
+
+ private static final Map servers = new HashMap<>();
+ private static final Map boxes = new HashMap<>();
+
+ @Override
+ public void draw(Player player, boolean scheduled, boolean clipboard, Vector pos1, Vector pos2) {
+ REntityServer server = servers.computeIfAbsent(player, __ -> {
+ REntityServer entityServer = new REntityServer();
+ entityServer.addPlayer(player);
+ return entityServer;
+ });
+
+ WorldEditRendererCUIEditor.Type type = clipboard ? WorldEditRendererCUIEditor.Type.CLIPBOARD : WorldEditRendererCUIEditor.Type.SELECTION;
+ float width = type.getWidth(player).value;
+ Material material = type.getMaterial(player);
+ if (material == Material.BARRIER) {
+ hide(player, clipboard, true);
+ return;
+ }
+ BlockData block = material.createBlockData();
+
+ BoxPair boxPair = boxes.computeIfAbsent(player, __ -> new BoxPair());
+ CWireframe box = boxPair.get(clipboard);
+ if (box == null) {
+ box = new CWireframe(server);
+ boxPair.set(clipboard, box);
+ }
+ box.setPos1(null).setPos2(null);
+ box.setPos1(pos1.toLocation(player.getWorld()));
+ box.setPos2(pos2.toLocation(player.getWorld()));
+ box.setWidth(width);
+ box.setBlock(block);
+ }
+
+ @Override
+ public void tick(Player player) {
+ REntityServer server = servers.get(player);
+ if (server != null) server.tick();
+ }
+
+ @Override
+ public void hide(Player player, boolean clipboard, boolean hide) {
+ BoxPair boxPair = boxes.get(player);
+ if (boxPair == null) return;
+ CWireframe box = boxPair.get(clipboard);
+ if (box == null) return;
+ box.hide(hide);
+ }
+
+ @Override
+ public void remove(Player player) {
+ BoxPair boxPair = boxes.remove(player);
+ if (boxPair != null) boxPair.die();
+ REntityServer server = servers.remove(player);
+ if (server != null) server.close();
+ }
+}
diff --git a/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditRendererWrapper8.java b/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditRendererWrapper8.java
new file mode 100644
index 00000000..68f64c46
--- /dev/null
+++ b/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditRendererWrapper8.java
@@ -0,0 +1,42 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2020 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.entity.Player;
+import org.bukkit.util.Vector;
+
+public class WorldEditRendererWrapper8 implements WorldEditRendererWrapper {
+
+ @Override
+ public void draw(Player player, boolean scheduled, boolean clipboard, Vector pos1, Vector pos2) {
+ }
+
+ @Override
+ public void tick(Player player) {
+ }
+
+ @Override
+ public void hide(Player player, boolean clipboard, boolean hide) {
+ }
+
+ @Override
+ public void remove(Player player) {
+ }
+}
diff --git a/SpigotCore/SpigotCore_9/build.gradle.kts b/SpigotCore/SpigotCore_9/build.gradle.kts
index a888faf1..c149a3fd 100644
--- a/SpigotCore/SpigotCore_9/build.gradle.kts
+++ b/SpigotCore/SpigotCore_9/build.gradle.kts
@@ -26,4 +26,5 @@ dependencies {
compileOnly(project(":SpigotCore:SpigotCore_8", "default"))
compileOnly(libs.nms9)
+ compileOnly(libs.worldedit12)
}
diff --git a/SpigotCore/SpigotCore_9/src/de/steamwar/core/WorldEditRendererWrapper9.java b/SpigotCore/SpigotCore_9/src/de/steamwar/core/WorldEditRendererWrapper9.java
new file mode 100644
index 00000000..5da6104a
--- /dev/null
+++ b/SpigotCore/SpigotCore_9/src/de/steamwar/core/WorldEditRendererWrapper9.java
@@ -0,0 +1,92 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2020 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.Location;
+import org.bukkit.Particle;
+import org.bukkit.entity.Player;
+import org.bukkit.util.Vector;
+
+public class WorldEditRendererWrapper9 implements WorldEditRendererWrapper {
+
+ private static final int VIEW_DISTANCE = 64;
+ private static final int SQ_VIEW_DISTANCE = VIEW_DISTANCE * VIEW_DISTANCE;
+
+ private static final double STEP_SIZE = 0.5;
+ private static final Vector ONES = new Vector(1, 1, 1);
+ private static final Vector STEPS = new Vector(STEP_SIZE, STEP_SIZE, STEP_SIZE);
+
+ @Override
+ public void draw(Player player, boolean scheduled, boolean clipboard, Vector min, Vector max) {
+ if (!scheduled) return;
+
+ max = max.clone().add(ONES);
+ drawLine(player, clipboard, new Vector(min.getX(), min.getY(), min.getZ()), new Vector(max.getX(), min.getY(), min.getZ()));
+ drawLine(player, clipboard, new Vector(min.getX(), max.getY(), min.getZ()), new Vector(max.getX(), max.getY(), min.getZ()));
+ drawLine(player, clipboard, new Vector(min.getX(), min.getY(), max.getZ()), new Vector(max.getX(), min.getY(), max.getZ()));
+ drawLine(player, clipboard, new Vector(min.getX(), max.getY(), max.getZ()), new Vector(max.getX(), max.getY(), max.getZ()));
+
+ drawLine(player, clipboard, new Vector(min.getX(), min.getY(), min.getZ()), new Vector(min.getX(), max.getY(), min.getZ()));
+ drawLine(player, clipboard, new Vector(max.getX(), min.getY(), min.getZ()), new Vector(max.getX(), max.getY(), min.getZ()));
+ drawLine(player, clipboard, new Vector(min.getX(), min.getY(), max.getZ()), new Vector(min.getX(), max.getY(), max.getZ()));
+ drawLine(player, clipboard, new Vector(max.getX(), min.getY(), max.getZ()), new Vector(max.getX(), max.getY(), max.getZ()));
+
+ drawLine(player, clipboard, new Vector(min.getX(), min.getY(), min.getZ()), new Vector(min.getX(), min.getY(), max.getZ()));
+ drawLine(player, clipboard, new Vector(max.getX(), min.getY(), min.getZ()), new Vector(max.getX(), min.getY(), max.getZ()));
+ drawLine(player, clipboard, new Vector(min.getX(), max.getY(), min.getZ()), new Vector(min.getX(), max.getY(), max.getZ()));
+ drawLine(player, clipboard, new Vector(max.getX(), max.getY(), min.getZ()), new Vector(max.getX(), max.getY(), max.getZ()));
+ }
+
+ private void drawLine(Player player, boolean clipboard, Vector min, Vector max) {
+ Particle particle;
+ if (clipboard) {
+ particle = TrickyParticleWrapper.impl.getVillagerHappy();
+ } else {
+ particle = Particle.DRAGON_BREATH;
+ }
+
+ Vector stepSize = max.clone().subtract(min).normalize().multiply(STEPS);
+ while (min.getX() <= max.getX() && min.getY() <= max.getY() && min.getZ() <= max.getZ()) {
+ Location location = player.getLocation();
+ double dx = min.getX() - location.getX();
+ double dy = min.getY() - location.getY();
+ double dz = min.getZ() - location.getZ();
+ if (dx * dx + dy * dy + dz * dz > SQ_VIEW_DISTANCE) {
+ min.add(stepSize);
+ continue;
+ }
+
+ player.spawnParticle(particle, min.getX(), min.getY(), min.getZ(), 1, 0.0, 0.0, 0.0, 0.0);
+ min.add(stepSize);
+ }
+ }
+
+ @Override
+ public void tick(Player player) {
+ }
+
+ @Override
+ public void hide(Player player, boolean clipboard, boolean hide) {
+ }
+
+ @Override
+ public void remove(Player player) {
+ }
+}
diff --git a/SpigotCore/SpigotCore_Main/src/SpigotCore.properties b/SpigotCore/SpigotCore_Main/src/SpigotCore.properties
index 10c64603..94e57d6c 100644
--- a/SpigotCore/SpigotCore_Main/src/SpigotCore.properties
+++ b/SpigotCore/SpigotCore_Main/src/SpigotCore.properties
@@ -105,3 +105,22 @@ NOSCHEMSUBMITTING_PERMA=§7You are §epermanently§7 excluded from submitting §
NOSCHEMSUBMITTING_UNTIL=§7You are excluded from submitting §e§lschematics §euntil {0}§8: §e{1}
UNNOSCHEMSUBMITTING_ERROR=§cThe player is not excluded from submitting schematics.
UNNOSCHEMSUBMITTING=§e{0} §7may now submit §e§lschematics§7 again§8.
+
+WORLDEDIT_CUI_TITLE = WorldEdit CUI
+WORLDEDIT_CUI_TITLE_SUBMENU = WorldEdit CUI - {0}
+WORLDEDIT_CUI_SELECTION = Own Selection
+WORLDEDIT_CUI_CLIPBOARD = Own Clipboard
+WORLDEDIT_CUI_SELECTION_OTHER = Other Selection
+WORLDEDIT_CUI_CLIPBOARD_OTHER = Other Clipboard
+
+WORLDEDIT_CUI_MATERIAL_NAME = §eWorldEdit {0}
+WORLDEDIT_CUI_MATERIAL_CLICK = §7Click to edit
+
+WORLDEDIT_CUI_WIDTH_NAME = §eWidth {0}
+WORLDEDIT_CUI_WIDTH_LORE = §8> §7{0}
+WORLDEDIT_CUI_WIDTH_LORE_SELECTED = §8> §e{0}
+WORLDEDIT_CUI_WIDTH_CLICK = §7Click to change
+WORLDEDIT_CUI_WIDTH_HUGE = 1/ 8 Block
+WORLDEDIT_CUI_WIDTH_LARGE = 1/16 Block
+WORLDEDIT_CUI_WIDTH_MEDIUM = 1/32 Block
+WORLDEDIT_CUI_WIDTH_SLIM = 1/64 Block
\ No newline at end of file
diff --git a/SpigotCore/SpigotCore_Main/src/SpigotCore_de.properties b/SpigotCore/SpigotCore_Main/src/SpigotCore_de.properties
index 83fa39f5..1f573eff 100644
--- a/SpigotCore/SpigotCore_Main/src/SpigotCore_de.properties
+++ b/SpigotCore/SpigotCore_Main/src/SpigotCore_de.properties
@@ -99,4 +99,15 @@ NOSCHEMSUBMITTING_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lSchematic
NOSCHEMSUBMITTING_PERMA=§7Du bist §epermanent §7vom §e§lEinsenden von Schematics§7 ausgeschlossen§8: §e{0}
NOSCHEMSUBMITTING_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lEinsenden von Schematics§7 ausgeschlossen§8: §e{1}
UNNOSCHEMSUBMITTING_ERROR=§cDer Spieler ist nicht vom Einsenden von Schematics ausgeschlossen.
-UNNOSCHEMSUBMITTING=§e{0} §7darf nun wieder §e§lSchematis§7 einsenden§8.
\ No newline at end of file
+UNNOSCHEMSUBMITTING=§e{0} §7darf nun wieder §e§lSchematis§7 einsenden§8.
+
+WORLDEDIT_CUI_SELECTION = Eigene Auswahl
+WORLDEDIT_CUI_CLIPBOARD = Eigene Kopie
+WORLDEDIT_CUI_SELECTION_OTHER = Auswahl Anderer
+WORLDEDIT_CUI_CLIPBOARD_OTHER = Kopie Anderer
+
+WORLDEDIT_CUI_MATERIAL_NAME = §eWorldEdit {0}
+WORLDEDIT_CUI_MATERIAL_CLICK = §7Klicke zum Editieren
+
+WORLDEDIT_CUI_WIDTH_NAME = §eDicke - {0}
+WORLDEDIT_CUI_WIDTH_CLICK = §7Klicke zum ändern
\ No newline at end of file
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/Core.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/Core.java
index 4e7b7576..c2086b0b 100644
--- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/Core.java
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/Core.java
@@ -23,7 +23,10 @@ import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.Reflection;
import de.steamwar.command.*;
import de.steamwar.core.authlib.AuthlibInjector;
-import de.steamwar.core.events.*;
+import de.steamwar.core.events.AntiNocom;
+import de.steamwar.core.events.ChattingEvent;
+import de.steamwar.core.events.PlayerJoinedEvent;
+import de.steamwar.core.events.WorldLoadEvent;
import de.steamwar.message.Message;
import de.steamwar.network.NetworkReceiver;
import de.steamwar.network.handlers.ServerDataHandler;
@@ -41,7 +44,7 @@ import java.io.InputStreamReader;
import java.util.Collection;
import java.util.logging.Level;
-public class Core extends JavaPlugin{
+public class Core extends JavaPlugin {
public static final Message MESSAGE = new Message("SpigotCore", Core.class.getClassLoader());
@@ -67,6 +70,8 @@ public class Core extends JavaPlugin{
@Override
public void onEnable() {
+ new PlayerVersion();
+
errorHandler = new ErrorHandler();
crashDetector = new CrashDetector();
@@ -102,7 +107,7 @@ public class Core extends JavaPlugin{
if(Core.getVersion() >= 19)
new ServerDataHandler();
- if(Core.getVersion() > 8 && Bukkit.getPluginManager().getPlugin("WorldEdit") != null)
+ if(Bukkit.getPluginManager().getPlugin("WorldEdit") != null)
new WorldEditRenderer();
Bukkit.getScheduler().runTaskTimer(this, TabCompletionCache::invalidateOldEntries, 20, 20);
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/PlayerVersion.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/PlayerVersion.java
new file mode 100644
index 00000000..512df0d3
--- /dev/null
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/PlayerVersion.java
@@ -0,0 +1,61 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2020 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 de.steamwar.network.packets.PacketHandler;
+import de.steamwar.network.packets.server.ClientVersionPacket;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerQuitEvent;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class PlayerVersion extends PacketHandler implements Listener {
+
+ private static final Map playerVersions = new HashMap<>();
+
+ public static int getVersion(Player player) {
+ return playerVersions.getOrDefault(player.getUniqueId(), -1);
+ }
+
+ public static boolean isBedrock(Player player) {
+ return player.getName().startsWith(".");
+ }
+
+ public PlayerVersion() {
+ Bukkit.getPluginManager().registerEvents(this, Core.getInstance());
+ register();
+ }
+
+ @Handler
+ public void handlePacket(ClientVersionPacket clientVersionPacket) {
+ playerVersions.put(clientVersionPacket.getPlayer(), clientVersionPacket.getVersion());
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onPlayerQuit(PlayerQuitEvent event) {
+ playerVersions.remove(event.getPlayer().getUniqueId());
+ }
+}
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/VersionDependent.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/VersionDependent.java
index 5e8ec241..2fe94ce5 100644
--- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/VersionDependent.java
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/VersionDependent.java
@@ -31,8 +31,16 @@ public class VersionDependent {
}
public static T getVersionImpl(Plugin plugin, String className){
+ return getVersionImpl(plugin, Core.getVersion(), className);
+ }
+
+ public static T getVersionImpl(Plugin plugin, int fromVersion){
+ return getVersionImpl(plugin, fromVersion, (new Exception()).getStackTrace()[1].getClassName());
+ }
+
+ public static T getVersionImpl(Plugin plugin, int fromVersion, String className){
ClassLoader loader = plugin.getClass().getClassLoader();
- for(int version = Core.getVersion(); version >= 8; version--) {
+ for(int version = fromVersion; version >= 8; version--) {
try {
return ((Class extends T>) Class.forName(className + version, true, loader)).getDeclaredConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java
index 377efe13..5e359512 100644
--- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java
@@ -29,20 +29,15 @@ import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.world.World;
import org.bukkit.Bukkit;
-import org.bukkit.Location;
import org.bukkit.Material;
-import org.bukkit.Particle;
import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.event.player.*;
import org.bukkit.util.Vector;
-public class WorldEditRenderer {
-
- private static final int VIEW_DISTANCE = 64;
- private static final int SQ_VIEW_DISTANCE = VIEW_DISTANCE * VIEW_DISTANCE;
-
- private static final double STEP_SIZE = 0.5;
-
- private static final Vector ONES = new Vector(1, 1, 1);
+public class WorldEditRenderer implements Listener {
private static final Material WAND = FlatteningWrapper.impl.getMaterial("WOOD_AXE");
@@ -50,77 +45,116 @@ public class WorldEditRenderer {
public WorldEditRenderer() {
we = WorldEditWrapper.getWorldEditPlugin();
+ Bukkit.getPluginManager().registerEvents(this, Core.getInstance());
- Bukkit.getScheduler().runTaskTimer(Core.getInstance(), this::render, 20, 20);
+ Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> {
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ renderPlayer(player, true);
+ }
+ }, 20, 20);
}
- private void render() {
- for(Player player : Bukkit.getOnlinePlayers()) {
- //noinspection deprecation
- if(player.getItemInHand().getType() != WAND)
- continue;
+ private void renderPlayer(Player player, boolean scheduled) {
+ LocalSession session = we.getSession(player);
+ renderClipboard(player, session, scheduled);
+ renderRegion(player, session, scheduled);
+ }
- LocalSession session = we.getSession(player);
+ private void renderClipboard(Player player, LocalSession session, boolean scheduled) {
+ try {
+ Clipboard clipboard = session.getClipboard().getClipboard();
+ Vector pos = player.getLocation().toVector();
+ Region region = clipboard.getRegion();
+ 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);
+ a = new Vector(a.getBlockX(), a.getBlockY(), a.getBlockZ());
+ b = new Vector(b.getBlockX(), b.getBlockY(), b.getBlockZ());
+ drawCuboid(Vector.getMinimum(a, b), Vector.getMaximum(a, b), scheduled, true, player);
+ } catch (EmptyClipboardException e) {
+ WorldEditRendererWrapper.impl.hide(player, true, true);
+ }
+ }
+
+ private void renderRegion(Player player, LocalSession session, boolean scheduled) {
+ World world = session.getSelectionWorld();
+ if(world != null) {
+ RegionSelector regionSelector = session.getRegionSelector(world);
try {
- Clipboard clipboard = session.getClipboard().getClipboard();
- Vector pos = player.getLocation().toVector();
- Region region = clipboard.getRegion();
- 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), TrickyParticleWrapper.impl.getVillagerHappy(), player);
- } catch (EmptyClipboardException e) {
- //ignore
- }
-
- World world = session.getSelectionWorld();
- if(world != null) {
- RegionSelector regionSelector = session.getRegionSelector(world);
- try {
- Region region = regionSelector.getRegion();
- drawCuboid(WorldEditWrapper.impl.getMinimum(region), WorldEditWrapper.impl.getMaximum(region), Particle.DRAGON_BREATH, player);
- } catch (IncompleteRegionException e) {
- //ignore
- }
+ Region region = regionSelector.getRegion();
+ drawCuboid(WorldEditWrapper.impl.getMinimum(region), WorldEditWrapper.impl.getMaximum(region), scheduled, false, player);
+ } catch (IncompleteRegionException e) {
+ WorldEditRendererWrapper.impl.hide(player, false, true);
}
}
}
- private void drawCuboid(Vector min, Vector max, Particle particle, Player owner) {
- max.add(ONES);
-
- for(double x = min.getBlockX(); x <= max.getBlockX(); x += STEP_SIZE) {
- draw(x, min.getBlockY(), min.getBlockZ(), particle, owner);
- draw(x, min.getBlockY(), max.getBlockZ(), particle, owner);
- draw(x, max.getBlockY(), min.getBlockZ(), particle, owner);
- draw(x, max.getBlockY(), max.getBlockZ(), particle, owner);
- }
-
- for(double y = min.getBlockY() + STEP_SIZE; y <= max.getBlockY() - STEP_SIZE; y += STEP_SIZE) {
- draw(min.getBlockX(), y, min.getBlockZ(), particle, owner);
- draw(min.getBlockX(), y, max.getBlockZ(), particle, owner);
- draw(max.getBlockX(), y, min.getBlockZ(), particle, owner);
- draw(max.getBlockX(), y, max.getBlockZ(), particle, owner);
- }
-
- for(double z = min.getBlockZ() + STEP_SIZE; z <= max.getBlockZ() - STEP_SIZE; z += STEP_SIZE) {
- draw(min.getBlockX(), min.getBlockY(), z, particle, owner);
- draw(min.getBlockX(), max.getBlockY(), z, particle, owner);
- draw(max.getBlockX(), min.getBlockY(), z, particle, owner);
- draw(max.getBlockX(), max.getBlockY(), z, particle, owner);
+ private void drawCuboid(Vector min, Vector max, boolean scheduled, boolean clipboard, Player owner) {
+ //noinspection deprecation
+ if(owner.getItemInHand().getType() != WAND) {
+ WorldEditRendererWrapper.impl.hide(owner, true, true);
+ WorldEditRendererWrapper.impl.hide(owner, false, true);
+ } else {
+ WorldEditRendererWrapper.impl.hide(owner, true, false);
+ WorldEditRendererWrapper.impl.hide(owner, false, false);
+ WorldEditRendererWrapper.safeDraw(owner, scheduled, clipboard, min, max);
}
}
- private void draw(double x, double y, double z, Particle particle, Player owner) {
- for(Player player : Bukkit.getOnlinePlayers()) {
- Location location = player.getLocation();
- double dx = x - location.getX();
- double dy = y - location.getY();
- double dz = z - location.getZ();
- if(dx*dx + dy*dy + dz*dz > SQ_VIEW_DISTANCE)
- continue;
-
- player.spawnParticle(player == owner ? particle : Particle.TOWN_AURA, x, y, z, 1, 0.0, 0.0, 0.0, 0.0);
+ @EventHandler
+ public void onPlayerMove(PlayerMoveEvent event) {
+ if(event.getPlayer().getItemInHand().getType() == WAND) {
+ WorldEditRendererWrapper.impl.tick(event.getPlayer());
}
+ renderClipboard(event.getPlayer(), we.getSession(event.getPlayer()), false);
+ }
+
+ @EventHandler
+ public void onPlayerInteract(PlayerInteractEvent event) {
+ Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> {
+ renderRegion(event.getPlayer(), we.getSession(event.getPlayer()), false);
+ }, 0);
+ }
+
+ @EventHandler
+ public void onBlockBreak(BlockBreakEvent event) {
+ Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> {
+ renderRegion(event.getPlayer(), we.getSession(event.getPlayer()), false);
+ }, 0);
+ }
+
+ @EventHandler
+ public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
+ if (event.getMessage().startsWith("//")) {
+ Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> {
+ LocalSession session = we.getSession(event.getPlayer());
+ renderRegion(event.getPlayer(), session, false);
+ renderClipboard(event.getPlayer(), session, false);
+ }, 5);
+ }
+ }
+
+ @EventHandler
+ public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) {
+ Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> {
+ renderPlayer(event.getPlayer(), false);
+ }, 1);
+ }
+
+ @EventHandler
+ public void onPlayerDropItem(PlayerDropItemEvent event) {
+ renderPlayer(event.getPlayer(), false);
+ }
+
+ @EventHandler
+ public void onPlayerItemHeld(PlayerItemHeldEvent event) {
+ Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> {
+ renderPlayer(event.getPlayer(), false);
+ }, 1);
+ }
+
+ @EventHandler
+ public void onPlayerQuit(PlayerQuitEvent event) {
+ WorldEditRendererWrapper.impl.remove(event.getPlayer());
}
}
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererCUIEditor.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererCUIEditor.java
new file mode 100644
index 00000000..e50eac9d
--- /dev/null
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererCUIEditor.java
@@ -0,0 +1,155 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2020 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 de.steamwar.command.SWCommand;
+import de.steamwar.inventory.SWInventory;
+import de.steamwar.inventory.SWItem;
+import de.steamwar.sql.UserConfig;
+import lombok.AllArgsConstructor;
+import org.bukkit.Material;
+import org.bukkit.block.data.type.Light;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.meta.BlockDataMeta;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class WorldEditRendererCUIEditor {
+
+ @AllArgsConstructor
+ public enum Type {
+ SELECTION("cui_selection_material", "cui_selection_width", Material.PURPLE_CONCRETE, Width.MEDIUM),
+ CLIPBOARD("cui_clipboard_material", "cui_clipboard_width", Material.LIME_CONCRETE, Width.SLIM),
+ ;
+
+ private final String configMaterial;
+ private final String configWidth;
+ private final Material defaultMaterial;
+ private final Width defaultWidth;
+
+ public Material getMaterial(Player player) {
+ String material = UserConfig.getConfig(player.getUniqueId(), configMaterial);
+ if (material == null) {
+ return defaultMaterial;
+ } else {
+ return Material.valueOf(material);
+ }
+ }
+
+ public void setMaterial(Player player, Material material) {
+ UserConfig.updatePlayerConfig(player.getUniqueId(), configMaterial, material.name());
+ }
+
+ public Width getWidth(Player player) {
+ String width = UserConfig.getConfig(player.getUniqueId(), configWidth);
+ if (width == null) {
+ return defaultWidth;
+ } else {
+ return Width.valueOf(width);
+ }
+ }
+
+ public void setWidth(Player player, Width width) {
+ UserConfig.updatePlayerConfig(player.getUniqueId(), configWidth, width.name());
+ }
+ }
+
+ @AllArgsConstructor
+ public enum Width {
+ HUGE(15, "WORLDEDIT_CUI_WIDTH_HUGE", 2/16f),
+ LARGE(8, "WORLDEDIT_CUI_WIDTH_LARGE", 1/16f),
+ MEDIUM(4, "WORLDEDIT_CUI_WIDTH_MEDIUM", 1/32f),
+ SLIM(0, "WORLDEDIT_CUI_WIDTH_SLIM", 1/64f);
+
+ public final int lightLevel;
+ public final String name;
+ public final float value;
+ }
+
+ public WorldEditRendererCUIEditor() {
+ if (Core.getVersion() >= 20) {
+ new Command();
+ }
+ }
+
+ private static class Command extends SWCommand {
+
+ public Command() {
+ super("cui");
+ }
+
+ @Register
+ public void cuiEditor(Player player) {
+ SWInventory inv = new SWInventory(player, 9 * 2, Core.MESSAGE.parse("WORLDEDIT_CUI_TITLE", player));
+ setElement(inv, player, 3, "WORLDEDIT_CUI_SELECTION", Type.SELECTION);
+ setElement(inv, player, 5, "WORLDEDIT_CUI_CLIPBOARD", Type.CLIPBOARD);
+ inv.open();
+ }
+
+ private void setElement(SWInventory inv, Player player, int index, String uiName, Type type) {
+ Material material = type.getMaterial(player);
+ Width width = type.getWidth(player);
+
+ inv.setItem(index, new SWItem(material, Core.MESSAGE.parse("WORLDEDIT_CUI_MATERIAL_NAME", player, Core.MESSAGE.parse(uiName, player)), Arrays.asList(Core.MESSAGE.parse("WORLDEDIT_CUI_MATERIAL_CLICK", player)), false, click -> {
+ cuiMaterial(player, uiName, type, material);
+ }));
+
+ List lore = new ArrayList<>();
+ lore.add(Core.MESSAGE.parse("WORLDEDIT_CUI_WIDTH_CLICK", player));
+ lore.add("");
+ for (Width value : Width.values()) {
+ if (value == width) {
+ lore.add(Core.MESSAGE.parse("WORLDEDIT_CUI_WIDTH_LORE_SELECTED", player, Core.MESSAGE.parse(value.name, player)));
+ } else {
+ lore.add(Core.MESSAGE.parse("WORLDEDIT_CUI_WIDTH_LORE", player, Core.MESSAGE.parse(value.name, player)));
+ }
+ }
+ SWItem lightItem = new SWItem(Material.LIGHT, Core.MESSAGE.parse("WORLDEDIT_CUI_WIDTH_NAME", player, Core.MESSAGE.parse(uiName, player)), lore, false, click -> {
+ type.setWidth(player, Width.values()[(width.ordinal() + 1) % Width.values().length]);
+ setElement(inv, player, index, uiName, type);
+ });
+ ItemMeta itemMeta = lightItem.getItemMeta();
+ Light light = (Light) Material.LIGHT.createBlockData();
+ light.setLevel(width.lightLevel);
+ ((BlockDataMeta) itemMeta).setBlockData(light);
+ lightItem.setItemMeta(itemMeta);
+ inv.setItem(index + 9, lightItem);
+ }
+
+ private final Material[] materials = {Material.WHITE_CONCRETE, Material.LIGHT_GRAY_CONCRETE, Material.GRAY_CONCRETE, Material.BLACK_CONCRETE, Material.BROWN_CONCRETE, Material.RED_CONCRETE, Material.ORANGE_CONCRETE, Material.YELLOW_CONCRETE, Material.LIME_CONCRETE, Material.GREEN_CONCRETE, Material.CYAN_CONCRETE, Material.LIGHT_BLUE_CONCRETE, Material.BLUE_CONCRETE, Material.PURPLE_CONCRETE, Material.MAGENTA_CONCRETE, Material.PINK_CONCRETE, null, Material.BARRIER};
+
+ private void cuiMaterial(Player player, String subMenu, Type type, Material currentSelection) {
+ SWInventory inv = new SWInventory(player, 9 * 2, Core.MESSAGE.parse("WORLDEDIT_CUI_TITLE_SUBMENU", player, Core.MESSAGE.parse(subMenu, player)));
+ for (int i = 0; i < materials.length; i++) {
+ Material material = materials[i];
+ if (material == null) continue;
+ inv.setItem(i, new SWItem(material, "", Collections.emptyList(), material == currentSelection, click -> {
+ type.setMaterial(player, material);
+ cuiEditor(player);
+ }));
+ }
+ inv.open();
+ }
+ }
+}
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererWrapper.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererWrapper.java
new file mode 100644
index 00000000..2439d40d
--- /dev/null
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererWrapper.java
@@ -0,0 +1,44 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2020 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.entity.Player;
+import org.bukkit.util.Vector;
+
+public interface WorldEditRendererWrapper {
+ WorldEditRendererWrapper fallback = VersionDependent.getVersionImpl(Core.getInstance(), 9);
+ WorldEditRendererWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
+
+ static void safeDraw(Player player, boolean scheduled, boolean clipboard, Vector pos1, Vector pos2) {
+ if (PlayerVersion.isBedrock(player) || PlayerVersion.getVersion(player) < 20) {
+ fallback.draw(player, scheduled, clipboard, pos1, pos2);
+ } else {
+ impl.draw(player, scheduled, clipboard, pos1, pos2);
+ }
+ }
+
+ void draw(Player player, boolean scheduled, boolean clipboard, Vector pos1, Vector pos2);
+
+ void tick(Player player);
+
+ void hide(Player player, boolean clipboard, boolean hide);
+
+ void remove(Player player);
+}
diff --git a/Teamserver/src/de/steamwar/teamserver/Builder.java b/Teamserver/src/de/steamwar/teamserver/Builder.java
index 137906ad..55aeed2d 100644
--- a/Teamserver/src/de/steamwar/teamserver/Builder.java
+++ b/Teamserver/src/de/steamwar/teamserver/Builder.java
@@ -19,6 +19,7 @@
package de.steamwar.teamserver;
+import de.steamwar.core.WorldEditRendererCUIEditor;
import de.steamwar.message.Message;
import de.steamwar.teamserver.command.*;
import de.steamwar.teamserver.listener.AxiomHandshakeListener;
@@ -58,6 +59,7 @@ public final class Builder extends JavaPlugin {
Bukkit.getPluginManager().registerEvents(materialCommand, this);
Bukkit.getWorlds().get(0).setGameRule(GameRule.REDUCED_DEBUG_INFO, false);
+ new WorldEditRendererCUIEditor();
}
@Override
diff --git a/VelocityCore/src/de/steamwar/velocitycore/listeners/VersionAnnouncer.java b/VelocityCore/src/de/steamwar/velocitycore/listeners/VersionAnnouncer.java
index c28a8fee..cf39f843 100644
--- a/VelocityCore/src/de/steamwar/velocitycore/listeners/VersionAnnouncer.java
+++ b/VelocityCore/src/de/steamwar/velocitycore/listeners/VersionAnnouncer.java
@@ -27,19 +27,33 @@ import com.velocitypowered.api.proxy.server.ServerInfo;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.velocity.platform.VelocityViaConfig;
import de.steamwar.messages.Chatter;
+import de.steamwar.network.packets.server.ClientVersionPacket;
import de.steamwar.persistent.Subserver;
+import de.steamwar.velocitycore.VelocityCore;
+import de.steamwar.velocitycore.network.NetworkSender;
+
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
public class VersionAnnouncer extends BasicListener {
@Subscribe
public void postConnect(ServerConnectedEvent e) {
ServerInfo server = e.getServer().getServerInfo();
- if(!Subserver.isBuild(Subserver.getSubserver(server)))
- return;
-
Player player = e.getPlayer();
int serverVersion = ((VelocityViaConfig) Via.getConfig()).getVelocityServerProtocols().get(server.getName());
- if(Via.getAPI().getPlayerVersion(player) == serverVersion)
+
+ int playerVersion = Via.getAPI().getPlayerVersion(player);
+ String version = ProtocolVersion.getProtocolVersion(playerVersion).getVersionIntroducedIn();
+ // PluginChannel 'vv:proxy_details' from ViaVersion apparently does not work any longer!
+ VelocityCore.schedule(() -> {
+ NetworkSender.send(player, new ClientVersionPacket(player.getUniqueId(), Integer.parseInt(version.split("-")[0].split("\\.")[1])));
+ }).delay(Duration.of(100, ChronoUnit.MILLIS)).schedule();
+
+ if(playerVersion == serverVersion)
+ return;
+
+ if(!Subserver.isBuild(Subserver.getSubserver(server)))
return;
player.sendActionBar(Chatter.of(player).parse("SERVER_VERSION", ProtocolVersion.getProtocolVersion(serverVersion).getMostRecentSupportedVersion()));