results = new ArrayList<>();
+
+ try (ZipFile zip = new ZipFile(jarPath.toFile())) {
+ Enumeration extends ZipEntry> entries = zip.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ if (entry.isDirectory() || !entry.getName().endsWith(".accesswidener")) continue;
+
+ try (InputStream in = zip.getInputStream(entry)) {
+ results.addAll(AccessWidenerParser.parse(in));
+ } catch (IOException e) {
+ LOG.warning("[AccessWidener] Failed to parse " + entry.getName()
+ + " in " + jarPath.getFileName() + ": " + e.getMessage());
+ }
+ }
+ }
+
+ return results;
+ }
+}
diff --git a/AccessWidener/src/main/java/de/steamwar/WideningTransformer.java b/AccessWidener/src/main/java/de/steamwar/WideningTransformer.java
new file mode 100644
index 00000000..8fcd33e2
--- /dev/null
+++ b/AccessWidener/src/main/java/de/steamwar/WideningTransformer.java
@@ -0,0 +1,44 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2026 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;
+
+import java.lang.instrument.ClassFileTransformer;
+import java.security.ProtectionDomain;
+import java.util.List;
+
+/**
+ * Transforms class bytecode to apply access widening rules.
+ *
+ * Also monitors for new plugin ClassLoaders appearing (when plugins load after
+ * the agent attaches) and automatically picks up their .accesswidener files.
+ */
+public class WideningTransformer implements ClassFileTransformer {
+
+ private final ClassPatcher patcher;
+
+ public WideningTransformer(List entries) {
+ patcher = new ClassPatcher(entries);
+ }
+
+ @Override
+ public byte[] transform(ClassLoader loader, String className, Class> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
+ return patcher.patch(className, classfileBuffer);
+ }
+}
diff --git a/BauSystem/BauSystem_Main/build.gradle.kts b/BauSystem/BauSystem_Main/build.gradle.kts
index f51b33cd..c6316f7d 100644
--- a/BauSystem/BauSystem_Main/build.gradle.kts
+++ b/BauSystem/BauSystem_Main/build.gradle.kts
@@ -19,6 +19,7 @@
plugins {
steamwar.java
+ widener
}
tasks.compileJava {
@@ -34,6 +35,7 @@ dependencies {
compileOnly(libs.classindex)
annotationProcessor(libs.classindex)
compileOnly(project(":SpigotCore", "default"))
+ compileOnly(project(":KotlinCore", "default"))
compileOnly(libs.axiom)
compileOnly(libs.authlib)
@@ -47,3 +49,7 @@ dependencies {
implementation(libs.luaj)
implementation(files("$projectDir/../libs/YAPION-SNAPSHOT.jar"))
}
+
+widener {
+ fromCatalog(libs.nms)
+}
diff --git a/BauSystem/BauSystem_Main/src/BauSystem.properties b/BauSystem/BauSystem_Main/src/BauSystem.properties
index a045edf4..c5adfb70 100644
--- a/BauSystem/BauSystem_Main/src/BauSystem.properties
+++ b/BauSystem/BauSystem_Main/src/BauSystem.properties
@@ -834,6 +834,10 @@ SKIN_NO_REGION = §7You are not in a region with a changealbe skin
SKIN_ALREADY_EXISTS = §cThis skin already exists like this
SKIN_MESSAGE = §7Skin created
SKIN_MESSAGE_HOVER = §eClick to copy for YoyoNow and send
+# Blast Resistance
+BLASTRESISTANCE_HELP = §8/§eblastresistance §8-§7 Calculate min/max and average blast resistance of current clipboard
+BLASTRESISTANCE_NO_CLIPBOARD = §cYou currently do not have a clipboard to be used.
+BLASTRESISTANCE_RESULT = §7BlastResistance §8>>§7 Min§8: §e{0}§7 Max§8: §e{1}§7 Avg§8: §e{2}
# Panzern
PANZERN_HELP = §8/§epanzern §8[§7Block§8] §8[§7Slab§8] §8- §7Armor your WorldEdit selection
PANZERN_PREPARE1 = §71. Check, if barrels reach until border of armor.
diff --git a/BauSystem/BauSystem_Main/src/BauSystem_de.properties b/BauSystem/BauSystem_Main/src/BauSystem_de.properties
index dedc0599..9bee037c 100644
--- a/BauSystem/BauSystem_Main/src/BauSystem_de.properties
+++ b/BauSystem/BauSystem_Main/src/BauSystem_de.properties
@@ -772,6 +772,10 @@ SKIN_NO_REGION = §7Du steht in keiner Region, welche mit einem Skin versehen we
SKIN_ALREADY_EXISTS = §cDieser Skin existiert in der Form bereits
SKIN_MESSAGE = §7Skin erstellt
SKIN_MESSAGE_HOVER = §eKlicken zum kopieren für YoyoNow und an diesen senden
+# Blast Resistance
+BLASTRESISTANCE_HELP = §8/§eblastresistance §8-§7 Minimal-, Maximal- und durchschnittliche Sprengfestigkeit des aktuellen Inhalts der Zwischenablage berechnen
+BLASTRESISTANCE_NO_CLIPBOARD = §cDerzeit steht Ihnen keine Zwischenablage zur Verfügung.
+BLASTRESISTANCE_RESULT = §7BlastResistance §8>>§7 Min§8: §e{0}§7 Max§8: §e{1}§7 Avg§8: §e{2}
# Panzern
PANZERN_HELP = §8/§epanzern §8[§7Block§8] §8[§7Slab§8] §8- §7Panzer deine WorldEdit Auswahl
PANZERN_PREPARE1 = §71. Gucke nochmal nach, ob Läufe auch bis zur Panzergrenze führen.
diff --git a/BauSystem/BauSystem_Main/src/bausystem.accesswidener b/BauSystem/BauSystem_Main/src/bausystem.accesswidener
new file mode 100644
index 00000000..5dd89fdf
--- /dev/null
+++ b/BauSystem/BauSystem_Main/src/bausystem.accesswidener
@@ -0,0 +1,13 @@
+accessWidener v2 named
+
+# For NoClipCommand
+accessible field net/minecraft/server/level/ServerPlayerGameMode gameModeForPlayer Lnet/minecraft/world/level/GameType;
+
+# For PlaceItemUtils
+accessible field org/bukkit/craftbukkit/block/CraftBlockState position Lnet/minecraft/core/BlockPos;
+mutable field org/bukkit/craftbukkit/block/CraftBlockState position Lnet/minecraft/core/BlockPos;
+accessible field org/bukkit/craftbukkit/block/CraftBlockState world Lorg/bukkit/craftbukkit/CraftWorld;
+mutable field org/bukkit/craftbukkit/block/CraftBlockState world Lorg/bukkit/craftbukkit/CraftWorld;
+
+# For TickManager
+accessible field net/minecraft/server/ServerTickRateManager remainingSprintTicks J
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/design/endstone/DesignEndStone.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/design/endstone/DesignEndStone.java
index ad4afc56..70270bac 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/design/endstone/DesignEndStone.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/design/endstone/DesignEndStone.java
@@ -21,9 +21,7 @@ package de.steamwar.bausystem.features.design.endstone;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.region.Region;
-import de.steamwar.entity.REntity;
-import de.steamwar.entity.REntityServer;
-import de.steamwar.entity.RFallingBlockEntity;
+import de.steamwar.entity.*;
import net.md_5.bungee.api.ChatMessageType;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -59,15 +57,15 @@ public class DesignEndStone {
.filter(material -> material.getBlastResistance() > region.getGameModeConfig().Schematic.MaxDesignBlastResistance)
.collect(Collectors.toSet());
calculateFromBottom = region.getGameModeConfig().Arena.NoFloor;
+ }
- entityServer.setCallback((player, rEntity, entityAction) -> {
- if (entityAction != REntityServer.EntityAction.ATTACK) return;
- Location location = new Location(WORLD, rEntity.getX(), rEntity.getY(), rEntity.getZ());
- Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
- location.getBlock().breakNaturally();
- calc();
- }, 1);
- });
+ private void interact(Player player, RInteraction entity, REntityAction action) {
+ if (action != REntityAction.ATTACK) return;
+ Location location = new Location(WORLD, entity.getX(), entity.getY(), entity.getZ());
+ Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
+ location.getBlock().breakNaturally();
+ calc();
+ }, 1);
}
public void calc() {
@@ -110,12 +108,15 @@ public class DesignEndStone {
Material material = WORLD.getBlockAt(cx, cy, cz).getType();
if (material != Material.WATER && material != Material.LAVA && limited.contains(material)) {
- Location location = new Location(WORLD, cx + 0.5, cy, cz + 0.5);
+ Location location = new Location(WORLD, cx, cy, cz);
if (!locations.add(location)) break;
- RFallingBlockEntity entity = new RFallingBlockEntity(entityServer, location, Material.RED_STAINED_GLASS);
- entity.setNoGravity(true);
+ RBlockDisplay entity = new RBlockDisplay(entityServer, location);
+ entity.setBlock(Material.RED_STAINED_GLASS.createBlockData());
entity.setGlowing(true);
entities.add(entity);
+ RInteraction interaction = new RInteraction(entityServer, location);
+ interaction.setCallback(this::interact);
+ entities.add(interaction);
break;
} else if (!material.isAir() && material != Material.WATER && material != Material.LAVA) {
break;
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/detonator/Detonator.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/detonator/Detonator.java
index 51d5e4e5..86932f2e 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/detonator/Detonator.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/detonator/Detonator.java
@@ -26,8 +26,9 @@ import de.steamwar.bausystem.features.autostart.AutostartListener;
import de.steamwar.bausystem.features.detonator.storage.DetonatorStorage;
import de.steamwar.bausystem.features.detonator.storage.ItemStorage;
import de.steamwar.core.SWPlayer;
+import de.steamwar.entity.RBlockDisplay;
import de.steamwar.entity.REntityServer;
-import de.steamwar.entity.RFallingBlockEntity;
+import de.steamwar.entity.RInteraction;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.UtilityClass;
@@ -58,10 +59,6 @@ public class Detonator {
@Override
public void onMount(SWPlayer player) {
entities.addPlayer(player.getPlayer());
- entities.setCallback((player1, entity, action) -> {
- Vector vector = new Vector(entity.getX(), entity.getY(), entity.getZ());
- DetonatorListener.addLocationToDetonator(vector.toLocation(player.getWorld()).getBlock().getLocation(), player1);
- });
}
@Override
@@ -70,8 +67,6 @@ public class Detonator {
}
}
- private static final Vector HALF = new Vector(0.5, 0, 0.5);
-
public static boolean isDetonator(ItemStack itemStack) {
return ItemStorage.isDetonator(itemStack);
}
@@ -79,8 +74,14 @@ public class Detonator {
public static void showDetonator(Player p, List locs) {
DetonatorComponent detonatorComponent = SWPlayer.of(p).getComponentOrDefault(DetonatorComponent.class, DetonatorComponent::new);
locs.forEach(location -> {
- RFallingBlockEntity entity = new RFallingBlockEntity(detonatorComponent.entities, location.clone().add(HALF), Material.RED_STAINED_GLASS);
- entity.setNoGravity(true);
+ RBlockDisplay blockDisplay = new RBlockDisplay(detonatorComponent.entities, location);
+ blockDisplay.setBlock(Material.RED_STAINED_GLASS.createBlockData());
+
+ RInteraction interaction = new RInteraction(detonatorComponent.entities, location);
+ interaction.setCallback((player, entity, action) -> {
+ Vector vector = new Vector(entity.getX(), entity.getY(), entity.getZ());
+ DetonatorListener.addLocationToDetonator(vector.toLocation(player.getWorld()).getBlock().getLocation(), player);
+ });
});
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/experimental/ExperimentalCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/experimental/ExperimentalCommand.java
new file mode 100644
index 00000000..a765a351
--- /dev/null
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/experimental/ExperimentalCommand.java
@@ -0,0 +1,31 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2026 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.experimental;
+
+import de.steamwar.command.SWCommand;
+import de.steamwar.linkage.Linked;
+
+@Linked
+public class ExperimentalCommand extends SWCommand {
+
+ public ExperimentalCommand() {
+ super("experimental", "experiment");
+ }
+}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/experimental/redstone_engine/RedstoneEngine.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/experimental/redstone_engine/RedstoneEngine.java
new file mode 100644
index 00000000..1247b667
--- /dev/null
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/experimental/redstone_engine/RedstoneEngine.java
@@ -0,0 +1,135 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2026 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.experimental.redstone_engine;
+
+import de.steamwar.bausystem.features.experimental.ExperimentalCommand;
+import de.steamwar.bausystem.region.Region;
+import de.steamwar.bausystem.utils.ScoreboardElement;
+import de.steamwar.command.AbstractSWCommand;
+import de.steamwar.command.SWCommand;
+import de.steamwar.linkage.Linked;
+import io.papermc.paper.configuration.WorldConfiguration;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.title.TitlePart;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+
+import java.util.Collection;
+import java.util.List;
+
+@AbstractSWCommand.PartOf(ExperimentalCommand.class)
+@Linked
+public class RedstoneEngine extends SWCommand implements Listener, ScoreboardElement {
+
+ public RedstoneEngine() {
+ super("");
+ }
+
+ private WorldConfiguration.Misc getConfig() {
+ return ((CraftWorld) Bukkit.getWorlds().get(0)).getHandle().paperConfig().misc;
+ }
+
+ @Register("redstone")
+ @Register("redstoneengine")
+ public void setRedstoneEngine(Player player, @StaticValue("alternate_current") String __, WorldConfiguration.Misc.AlternateCurrentUpdateOrder updateOrder) {
+ WorldConfiguration.Misc misc = getConfig();
+ misc.redstoneImplementation = WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT;
+ misc.alternateCurrentUpdateOrder = updateOrder;
+ broadcastTitle(Bukkit.getOnlinePlayers());
+ }
+
+ @Register("redstone")
+ @Register("redstoneengine")
+ public void setRedstoneEngine(Player player, WorldConfiguration.Misc.RedstoneImplementation implementation) {
+ getConfig().redstoneImplementation = implementation;
+ broadcastTitle(Bukkit.getOnlinePlayers());
+ }
+
+ @EventHandler
+ public void onPlayerJoin(PlayerJoinEvent event) {
+ WorldConfiguration.Misc misc = getConfig();
+ if (misc.redstoneImplementation != WorldConfiguration.Misc.RedstoneImplementation.EIGENCRAFT) {
+ broadcastTitle(List.of(event.getPlayer()));
+ }
+ }
+
+ private void broadcastTitle(Collection extends Player> players) {
+ WorldConfiguration.Misc misc = getConfig();
+ Component title = switch (misc.redstoneImplementation) {
+ case VANILLA -> Component.text("⚠").color(NamedTextColor.RED).append(Component.text(" Redstone: Vanilla ").color(NamedTextColor.WHITE)).append(Component.text("⚠").color(NamedTextColor.RED));
+ case EIGENCRAFT -> Component.text("Redstone: Eigencraft");
+ case ALTERNATE_CURRENT -> Component.text("⚠").color(NamedTextColor.RED).append(Component.text(" Redstone: AC ").color(NamedTextColor.WHITE)).append(Component.text("⚠").color(NamedTextColor.RED));
+ };
+ Component subtitle;
+ if (misc.redstoneImplementation != WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
+ subtitle = Component.text().build();
+ } else {
+ subtitle = switch (misc.alternateCurrentUpdateOrder) {
+ case VERTICAL_FIRST_INWARD -> Component.text("Y first inwards"); // Y before XZ
+ case VERTICAL_FIRST_OUTWARD -> Component.text("Y first outwards"); // XZ before Y
+ case HORIZONTAL_FIRST_INWARD -> Component.text("XZ first inwards"); // Y before XZ
+ case HORIZONTAL_FIRST_OUTWARD -> Component.text("XZ first outwards"); // XZ before Y
+ };
+ }
+ players.forEach(player -> {
+ player.sendTitlePart(TitlePart.TITLE, title);
+ player.sendTitlePart(TitlePart.SUBTITLE, subtitle);
+ });
+ }
+
+ @Override
+ public ScoreboardGroup getGroup() {
+ return ScoreboardGroup.FOOTER;
+ }
+
+ @Override
+ public int order() {
+ return Integer.MAX_VALUE;
+ }
+
+ @Override
+ public String get(Region region, Player p) {
+ WorldConfiguration.Misc misc = getConfig();
+ switch (misc.redstoneImplementation) {
+ case ALTERNATE_CURRENT:
+ switch (misc.alternateCurrentUpdateOrder) {
+ case VERTICAL_FIRST_INWARD:
+ return "§eRedstone§8: §cAC §8(§7Y in§8)";
+ case VERTICAL_FIRST_OUTWARD:
+ return "§eRedstone§8: §cAC §8(§7Y out§8)";
+ case HORIZONTAL_FIRST_INWARD:
+ return "§eRedstone§8: §cAC §8(§7XZ in§8)";
+ case HORIZONTAL_FIRST_OUTWARD:
+ return "§eRedstone§8: §cAC §8(§7XZ out§8)";
+ }
+ return "§eRedstone§8: §cAC";
+ case EIGENCRAFT:
+ return null;
+ case VANILLA:
+ default:
+ return "§eRedstone§8: §cVanilla";
+ }
+ }
+}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/killchecker/KillcheckerVisualizer.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/killchecker/KillcheckerVisualizer.java
index 9efd6dc2..c0e3a032 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/killchecker/KillcheckerVisualizer.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/killchecker/KillcheckerVisualizer.java
@@ -24,9 +24,9 @@ import de.steamwar.bausystem.region.Point;
import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
import de.steamwar.bausystem.utils.bossbar.BossBarService;
+import de.steamwar.entity.RBlockDisplay;
import de.steamwar.entity.REntity;
import de.steamwar.entity.REntityServer;
-import de.steamwar.entity.RFallingBlockEntity;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
@@ -290,8 +290,8 @@ public class KillcheckerVisualizer {
}
rEntities.get(point).die();
}
- RFallingBlockEntity entity = new RFallingBlockEntity(outlinePoints.contains(point) ? outline : inner, point.toLocation(WORLD, 0.5, 0, 0.5), MATERIALS[Math.min(count - 1, MATERIALS.length) - 1]);
- entity.setNoGravity(true);
+ RBlockDisplay entity = new RBlockDisplay(outlinePoints.contains(point) ? outline : inner, point.toLocation(WORLD, 0, 0, 0));
+ entity.setBlock(MATERIALS[Math.min(count - 1, MATERIALS.length) - 1].createBlockData());
rEntities.put(point, entity);
if (outlinePoints.contains(point)) outlinePointsCache.add(point);
killCount.put(point, count);
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/TestblockCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/TestblockCommand.java
index 1644aaea..bce22006 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/TestblockCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/region/TestblockCommand.java
@@ -185,17 +185,16 @@ public class TestblockCommand extends SWCommand {
return new TypeMapper() {
@Override
public List tabCompletes(CommandSender commandSender, PreviousArguments previousArguments, String s) {
- List stringList = new ArrayList<>(SchematicNode.getNodeTabcomplete(SteamwarUser.get(((Player) commandSender).getUniqueId()), s));
+ List stringList = new ArrayList<>();
stringList.addAll(SchematicNode.getNodeTabcomplete(SteamwarUser.byId(0), s));
+ stringList.addAll(SchematicNode.getNodeTabcomplete(SteamwarUser.get(((Player) commandSender).getUniqueId()), s));
return stringList;
}
@Override
public SchematicNode map(CommandSender commandSender, PreviousArguments previousArguments, String s) {
- SchematicNode node = SchematicNode.getNodeFromPath(SteamwarUser.get(((Player) commandSender).getUniqueId()), s);
- if (node == null) {
- node = SchematicNode.getNodeFromPath(SteamwarUser.byId(0), s);
- }
+ SchematicNode node = SchematicNode.getNodeFromPath(SteamwarUser.byId(0), s);
+ if (node == null) node = SchematicNode.getNodeFromPath(SteamwarUser.get(((Player) commandSender).getUniqueId()), s);
return node;
}
};
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java
index c557f95f..6f674a71 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java
@@ -19,7 +19,7 @@
package de.steamwar.bausystem.features.simulator;
-import com.comphenix.tinyprotocol.TinyProtocol;
+import com.destroystokyo.paper.event.server.ServerTickEndEvent;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.Permission;
import de.steamwar.bausystem.SWUtils;
@@ -38,77 +38,88 @@ import de.steamwar.bausystem.features.simulator.gui.SimulatorGui;
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
import de.steamwar.bausystem.utils.BauMemberUpdateEvent;
import de.steamwar.bausystem.utils.ItemUtils;
-import de.steamwar.bausystem.utils.RayTraceUtils;
+import de.steamwar.core.SWPlayer;
+import de.steamwar.cursor.Cursor;
import de.steamwar.entity.REntity;
import de.steamwar.entity.REntityServer;
-import de.steamwar.entity.RFallingBlockEntity;
import de.steamwar.inventory.SWAnvilInv;
import de.steamwar.linkage.Linked;
import lombok.AllArgsConstructor;
import lombok.Getter;
-import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
-import org.bukkit.World;
-import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.player.*;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import java.util.*;
-import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
@Linked
public class SimulatorCursor implements Listener {
- private static final World WORLD = Bukkit.getWorlds().get(0);
-
- private static Map cursorType = Collections.synchronizedMap(new HashMap<>());
- private static Map cursors = Collections.synchronizedMap(new HashMap<>());
- private static final Set calculating = new HashSet<>();
+ private static final Map cursorType = Collections.synchronizedMap(new HashMap<>());
+ private static final Map emptyTargetServers = Collections.synchronizedMap(new HashMap<>());
public static boolean isSimulatorItem(ItemStack itemStack) {
return ItemUtils.isItem(itemStack, "simulator");
}
- public SimulatorCursor() {
- BiFunction function = (player, object) -> {
- calcCursor(player);
- return object;
- };
- TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.Pos.class, function);
- TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.Rot.class, function);
- TinyProtocol.instance.addFilter(ServerboundMovePlayerPacket.PosRot.class, function);
+ private static boolean hasSimulatorItem(Player player) {
+ return isSimulatorItem(player.getInventory().getItemInMainHand()) || isSimulatorItem(player.getInventory().getItemInOffHand());
+ }
+
+ private static Set scheduledUpdates = new HashSet<>();
+
+ private static void scheduleCursorUpdate(Player player) {
+ scheduledUpdates.add(player);
+ }
+
+ @EventHandler
+ public void onServerTickEnd(ServerTickEndEvent event) {
+ scheduledUpdates.forEach(SimulatorCursor::calcCursor);
+ scheduledUpdates.clear();
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
- Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
- calcCursor(event.getPlayer());
- }, 0);
+ scheduleCursorUpdate(event.getPlayer());
}
@EventHandler
public void onPlayerDropItem(PlayerDropItemEvent event) {
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
- calcCursor(event.getPlayer());
+ scheduleCursorUpdate(event.getPlayer());
}
@EventHandler
public void onPlayerItemHeld(PlayerItemHeldEvent event) {
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
- Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
- calcCursor(event.getPlayer());
- }, 1);
+ scheduleCursorUpdate(event.getPlayer());
+ }
+
+ @EventHandler
+ public void onInventoryClick(InventoryClickEvent event) {
+ if (!(event.getWhoClicked() instanceof Player player)) return;
+ if (!Permission.BUILD.hasPermission(player)) return;
+ scheduleCursorUpdate(player);
+ }
+
+ @EventHandler
+ public void onInventoryDrag(InventoryDragEvent event) {
+ if (!(event.getWhoClicked() instanceof Player player)) return;
+ if (!Permission.BUILD.hasPermission(player)) return;
+ scheduleCursorUpdate(player);
}
@EventHandler
@@ -119,10 +130,8 @@ public class SimulatorCursor implements Listener {
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
cursorType.remove(event.getPlayer());
- cursors.remove(event.getPlayer());
- synchronized (calculating) {
- calculating.remove(event.getPlayer());
- }
+ removeCursor(event.getPlayer());
+ scheduledUpdates.remove(event.getPlayer());
}
private static final Map LAST_SNEAKS = new HashMap<>();
@@ -138,7 +147,7 @@ public class SimulatorCursor implements Listener {
public void onPlayerToggleSneak(PlayerToggleSneakEvent event) {
if (!event.isSneaking()) return;
Player player = event.getPlayer();
- if (!isSimulatorItem(player.getInventory().getItemInMainHand()) && !isSimulatorItem(player.getInventory().getItemInOffHand())) {
+ if (!hasSimulatorItem(player)) {
return;
}
if (LAST_SNEAKS.containsKey(player)) {
@@ -164,17 +173,10 @@ public class SimulatorCursor implements Listener {
}
public static void calcCursor(Player player) {
- synchronized (calculating) {
- if (calculating.contains(player)) return;
- calculating.add(player);
- }
- if (!Permission.BUILD.hasPermission(player) || (!isSimulatorItem(player.getInventory().getItemInMainHand()) && !isSimulatorItem(player.getInventory().getItemInOffHand()))) {
- if (removeCursor(player) || SimulatorWatcher.show(null, player)) {
+ if (!Permission.BUILD.hasPermission(player) || !hasSimulatorItem(player)) {
+ if (removeCursor(player) | SimulatorWatcher.show(null, player)) {
SWUtils.sendToActionbar(player, "");
}
- synchronized (calculating) {
- calculating.remove(player);
- }
return;
}
@@ -183,203 +185,98 @@ public class SimulatorCursor implements Listener {
removeCursor(player);
SimulatorWatcher.show(null, player);
SWUtils.sendToActionbar(player, "§cGenerating Stab");
- synchronized (calculating) {
- calculating.remove(player);
- }
return;
}
SimulatorWatcher.show(simulator, player);
- List entities = SimulatorWatcher.getEntitiesOfSimulator(simulator);
- RayTraceUtils.RRayTraceResult rayTraceResult = RayTraceUtils.traceREntity(player, player.getLocation(), entities);
- if (rayTraceResult == null) {
- removeCursor(player);
- if (simulator == null) {
- SWUtils.sendToActionbar(player, "§eSelect Simulator");
- } else {
- SWUtils.sendToActionbar(player, "§eOpen Simulator");
- }
- synchronized (calculating) {
- calculating.remove(player);
- }
- return;
+ Cursor cursor = getOrCreateCursor(player, simulator, cursorType.getOrDefault(player, CursorType.TNT));
+ cursor.renderDeduplicated();
+ }
+
+ private static Cursor getOrCreateCursor(Player player, Simulator simulator, CursorType type) {
+ REntityServer targetServer = simulator == null ? emptyTargetServers.computeIfAbsent(player, __ -> new REntityServer()) : SimulatorWatcher.getEntityServerOfSimulator(simulator);
+ SWPlayer swPlayer = SWPlayer.of(player);
+ Optional activeCursor = swPlayer.getComponent(Cursor.class);
+
+ Cursor cursor = activeCursor.orElse(null);
+ if (cursor == null || cursor.getTargetServer() != targetServer) {
+ swPlayer.removeComponent(Cursor.class);
+ cursor = new Cursor(
+ targetServer,
+ player,
+ Material.GLASS,
+ type.material,
+ type.cursorModes,
+ (location, hitEntity, action) -> handlePlayerClick(player, location, hitEntity, action),
+ (location, hitEntity) -> sendCursorActionbar(player, SimulatorStorage.getSimulator(player), location != null, hitEntity.isPresent())
+ );
+ } else {
+ cursor.setCursorMaterial(type.material);
+ cursor.setAllowedCursorModes(type.cursorModes);
}
- showCursor(player, rayTraceResult, simulator != null);
- synchronized (calculating) {
- calculating.remove(player);
- }
+ return cursor;
}
private static synchronized boolean removeCursor(Player player) {
- REntityServer entityServer = cursors.get(player);
- boolean hadCursor = entityServer != null && !entityServer.getEntities().isEmpty();
- if (entityServer != null) {
- entityServer.getEntities().forEach(REntity::die);
+ Optional cursor = SWPlayer.of(player).getComponent(Cursor.class);
+ cursor.ifPresent(__ -> SWPlayer.of(player).removeComponent(Cursor.class));
+ REntityServer emptyTargetServer = emptyTargetServers.remove(player);
+ if (emptyTargetServer != null) {
+ emptyTargetServer.close();
}
- return hadCursor;
+ return cursor.isPresent();
}
- private static synchronized void showCursor(Player player, RayTraceUtils.RRayTraceResult rayTraceResult, boolean hasSimulatorSelected) {
- REntityServer entityServer = cursors.computeIfAbsent(player, __ -> {
- REntityServer rEntityServer = new REntityServer();
- rEntityServer.addPlayer(player);
- return rEntityServer;
- });
-
- CursorType type = cursorType.getOrDefault(player, CursorType.TNT);
- REntity hitEntity = rayTraceResult.getHitEntity();
- Location location = hitEntity != null ? new Vector(hitEntity.getX(), hitEntity.getY(), hitEntity.getZ()).toLocation(WORLD) :
- type.position.apply(player, rayTraceResult).toLocation(WORLD);
-
- Material material = hitEntity != null ? Material.GLASS : type.getMaterial();
- List entities = entityServer.getEntitiesByType(RFallingBlockEntity.class);
- entities.removeIf(rFallingBlockEntity -> {
- if (rFallingBlockEntity.getMaterial() != material) {
- rFallingBlockEntity.die();
- return true;
- }
- rFallingBlockEntity.move(location);
- return false;
- });
- if (entities.isEmpty()) {
- RFallingBlockEntity rFallingBlockEntity = new RFallingBlockEntity(entityServer, location, material);
- rFallingBlockEntity.setNoGravity(true);
- if (material == Material.GLASS) {
- rFallingBlockEntity.setGlowing(true);
- }
- }
-
- if (hasSimulatorSelected) {
- if (hitEntity != null) {
- SWUtils.sendToActionbar(player, "§eEdit Position");
- } else {
- SWUtils.sendToActionbar(player, "§eAdd new " + type.name);
- }
- } else {
+ private static void sendCursorActionbar(Player player, Simulator simulator, boolean hasCursorLocation, boolean hasHitEntity) {
+ if (!hasCursorLocation) {
+ SWUtils.sendToActionbar(player, simulator == null ? "§eSelect Simulator" : "§eOpen Simulator");
+ } else if (simulator == null) {
SWUtils.sendToActionbar(player, "§eCreate new Simulator");
- }
- }
-
- public static Vector getPosFree(Player player, RayTraceUtils.RRayTraceResult result) {
- Vector pos = result.getHitPosition();
-
- BlockFace face = result.getHitBlockFace();
- if (face != null) {
- switch (face) {
- case DOWN:
- pos.setY(pos.getY() - 0.98);
- break;
- case EAST:
- pos.setX(pos.getX() + 0.49);
- break;
- case WEST:
- pos.setX(pos.getX() - 0.49);
- break;
- case NORTH:
- pos.setZ(pos.getZ() - 0.49);
- break;
- case SOUTH:
- pos.setZ(pos.getZ() + 0.49);
- break;
- default:
- break;
- }
-
- if (face.getModY() == 0 && player.isSneaking()) {
- pos.setY(pos.getY() - 0.49);
- }
- }
-
- if (!player.isSneaking()) {
- pos.setX(pos.getBlockX() + 0.5);
- if (face == null || face.getModY() == 0) {
- pos.setY(pos.getBlockY() + 0.0);
- }
- pos.setZ(pos.getBlockZ() + 0.5);
- }
-
- return pos;
- }
-
- private static Vector getPosBlockAligned(Player player, RayTraceUtils.RRayTraceResult result) {
- Vector pos = result.getHitPosition();
-
- BlockFace face = result.getHitBlockFace();
- if (face != null) {
- switch (face) {
- case DOWN:
- pos.setY(pos.getY() - 0.98);
- break;
- case EAST:
- pos.setX(pos.getX() + 0.49);
- break;
- case WEST:
- pos.setX(pos.getX() - 0.49);
- break;
- case NORTH:
- pos.setZ(pos.getZ() - 0.49);
- break;
- case SOUTH:
- pos.setZ(pos.getZ() + 0.49);
- break;
- default:
- break;
- }
- }
-
- pos.setX(pos.getBlockX() + 0.5);
- if (pos.getY() - pos.getBlockY() != 0 && face == BlockFace.UP) {
- pos.setY(pos.getBlockY() + 1.0);
+ } else if (hasHitEntity) {
+ SWUtils.sendToActionbar(player, "§eEdit Position");
} else {
- pos.setY(pos.getBlockY());
+ SWUtils.sendToActionbar(player, "§eAdd new " + cursorType.getOrDefault(player, CursorType.TNT).name);
}
- pos.setZ(pos.getBlockZ() + 0.5);
- return pos;
}
@Getter
@AllArgsConstructor
public enum CursorType {
- TNT(Material.TNT, Material.GUNPOWDER, SimulatorCursor::getPosFree, "TNT", vector -> new TNTElement(vector).add(new TNTPhase())),
- REDSTONE_BLOCK(Material.REDSTONE_BLOCK, Material.REDSTONE, SimulatorCursor::getPosBlockAligned, "Redstone Block", vector -> new RedstoneElement(vector).add(new RedstonePhase())),
- OBSERVER(Material.OBSERVER, Material.QUARTZ, SimulatorCursor::getPosBlockAligned, "Observer", vector -> new ObserverElement(vector).add(new ObserverPhase())),
+ TNT(Material.TNT, Material.GUNPOWDER, List.of(Cursor.CursorMode.FREE, Cursor.CursorMode.SURFACE_ALIGNED), "TNT", vector -> new TNTElement(vector).add(new TNTPhase())),
+ REDSTONE_BLOCK(Material.REDSTONE_BLOCK, Material.REDSTONE, List.of(Cursor.CursorMode.BLOCK_ALIGNED), "Redstone Block", vector -> new RedstoneElement(vector).add(new RedstonePhase())),
+ OBSERVER(Material.OBSERVER, Material.QUARTZ, List.of(Cursor.CursorMode.BLOCK_ALIGNED), "Observer", vector -> new ObserverElement(vector).add(new ObserverPhase())),
;
public final Material material;
public final Material nonSelectedMaterial;
- public final BiFunction position;
+ public final List cursorModes;
public final String name;
public final Function> elementFunction;
}
- @EventHandler
- public void onPlayerInteract(PlayerInteractEvent event) {
- if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
- if (!ItemUtils.isItem(event.getItem(), "simulator")) {
+ private static void handlePlayerClick(Player player, Location cursorLocation, Optional hitEntity, Action action) {
+ if (!Permission.BUILD.hasPermission(player)) return;
+ if (!hasSimulatorItem(player)) {
return;
}
- event.setCancelled(true);
- Player player = event.getPlayer();
Simulator simulator = SimulatorStorage.getSimulator(player);
- if (event.getAction() == Action.LEFT_CLICK_BLOCK || event.getAction() == Action.LEFT_CLICK_AIR) {
+ if (action == Action.LEFT_CLICK_BLOCK || action == Action.LEFT_CLICK_AIR) {
if (simulator == null) {
return;
}
- SimulatorExecutor.run(event.getPlayer(), simulator, null);
+ SimulatorExecutor.run(player, simulator, null);
return;
}
- if (event.getAction() != Action.RIGHT_CLICK_BLOCK && event.getAction() != Action.RIGHT_CLICK_AIR) {
+ if (action != Action.RIGHT_CLICK_BLOCK && action != Action.RIGHT_CLICK_AIR) {
return;
}
-
- RayTraceUtils.RRayTraceResult rayTraceResult = RayTraceUtils.traceREntity(player, player.getLocation(), SimulatorWatcher.getEntitiesOfSimulator(simulator));
if (simulator == null) {
- if (rayTraceResult == null) {
+ if (cursorLocation == null) {
SimulatorStorage.openSimulatorSelector(player);
} else {
SWAnvilInv anvilInv = new SWAnvilInv(player, "Name");
@@ -395,7 +292,7 @@ public class SimulatorCursor implements Listener {
}
sim = new Simulator(s);
SimulatorStorage.addSimulator(s, sim);
- createElement(player, rayTraceResult, sim);
+ createElement(player, cursorLocation, sim);
SimulatorStorage.setSimulator(player, sim);
});
anvilInv.open();
@@ -403,57 +300,56 @@ public class SimulatorCursor implements Listener {
return;
}
- if (rayTraceResult == null) {
+ if (cursorLocation == null) {
new SimulatorGui(player, simulator).open();
return;
}
- if (rayTraceResult.getHitEntity() != null) {
- REntity hitEntity = rayTraceResult.getHitEntity();
- Vector vector = new Vector(hitEntity.getX(), hitEntity.getY(), hitEntity.getZ());
- List> elements = simulator.getGroups().stream().map(SimulatorGroup::getElements).flatMap(List::stream).filter(element -> {
- return element.getWorldPos().distanceSquared(vector) < (1 / 16.0) * (1 / 16.0);
- }).collect(Collectors.toList());
-
- switch (elements.size()) {
- case 0:
- return;
- case 1:
- // Open single element present in Simulator
- SimulatorElement> element = elements.get(0);
- SimulatorGroup group1 = element.getGroup(simulator);
- SimulatorBaseGui back = new SimulatorGui(player, simulator);
- if (group1.getElements().size() > 1) {
- back = new SimulatorGroupGui(player, simulator, group1, back);
- }
- element.open(player, simulator, group1, back);
- break;
- default:
- List parents = elements.stream().map(e -> e.getGroup(simulator)).distinct().collect(Collectors.toList());
- if (parents.size() == 1) {
- // Open multi element present in Simulator in existing group
- SimulatorGui simulatorGui = new SimulatorGui(player, simulator);
- new SimulatorGroupGui(player, simulator, parents.get(0), simulatorGui).open();
- } else {
- // Open multi element present in Simulator in implicit group
- SimulatorGroup group2 = new SimulatorGroup();
- group2.setMaterial(null);
- group2.getElements().addAll(elements);
- SimulatorGui simulatorGui = new SimulatorGui(player, simulator);
- new SimulatorGroupGui(player, simulator, group2, simulatorGui).open();
- }
- break;
- }
+ if (hitEntity.isPresent()) {
+ openElement(player, simulator, hitEntity.get());
return;
}
- // Add new Element to current simulator
- createElement(player, rayTraceResult, simulator);
+ createElement(player, cursorLocation, simulator);
}
- private void createElement(Player player, RayTraceUtils.RRayTraceResult rayTraceResult, Simulator simulator) {
+ private static void openElement(Player player, Simulator simulator, REntity hitEntity) {
+ Vector vector = new Vector(hitEntity.getX(), hitEntity.getY(), hitEntity.getZ());
+ List> elements = simulator.getGroups().stream().map(SimulatorGroup::getElements).flatMap(List::stream).filter(element -> {
+ return element.getWorldPos().distanceSquared(vector) < (1 / 16.0) * (1 / 16.0);
+ }).collect(Collectors.toList());
+
+ switch (elements.size()) {
+ case 0:
+ return;
+ case 1:
+ SimulatorElement> element = elements.get(0);
+ SimulatorGroup group1 = element.getGroup(simulator);
+ SimulatorBaseGui back = new SimulatorGui(player, simulator);
+ if (group1.getElements().size() > 1) {
+ back = new SimulatorGroupGui(player, simulator, group1, back);
+ }
+ element.open(player, simulator, group1, back);
+ break;
+ default:
+ List parents = elements.stream().map(e -> e.getGroup(simulator)).distinct().collect(Collectors.toList());
+ if (parents.size() == 1) {
+ SimulatorGui simulatorGui = new SimulatorGui(player, simulator);
+ new SimulatorGroupGui(player, simulator, parents.get(0), simulatorGui).open();
+ } else {
+ SimulatorGroup group2 = new SimulatorGroup();
+ group2.setMaterial(null);
+ group2.getElements().addAll(elements);
+ SimulatorGui simulatorGui = new SimulatorGui(player, simulator);
+ new SimulatorGroupGui(player, simulator, group2, simulatorGui).open();
+ }
+ break;
+ }
+ }
+
+ private static void createElement(Player player, Location cursorLocation, Simulator simulator) {
CursorType type = cursorType.getOrDefault(player, CursorType.TNT);
- Vector vector = type.position.apply(player, rayTraceResult);
+ Vector vector = cursorLocation.toVector();
if (type == CursorType.REDSTONE_BLOCK) {
vector.subtract(new Vector(0.5, 0, 0.5));
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorWatcher.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorWatcher.java
index 3c8ff96f..800c0c73 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorWatcher.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorWatcher.java
@@ -124,4 +124,11 @@ public class SimulatorWatcher {
}
return entityServer.getEntities();
}
+
+ synchronized REntityServer getEntityServerOfSimulator(Simulator simulator) {
+ if (simulator == null) {
+ return null;
+ }
+ return entityServers.computeIfAbsent(simulator, __ -> createSim(new REntityServer(), simulator));
+ }
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/slaves/blastresistance/BlastResistanceCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/slaves/blastresistance/BlastResistanceCommand.java
new file mode 100644
index 00000000..7afb0e5f
--- /dev/null
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/slaves/blastresistance/BlastResistanceCommand.java
@@ -0,0 +1,72 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2026 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.slaves.blastresistance;
+
+import com.google.common.util.concurrent.AtomicDouble;
+import com.sk89q.worldedit.LocalSession;
+import com.sk89q.worldedit.WorldEdit;
+import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.bukkit.BukkitAdapter;
+import com.sk89q.worldedit.extent.clipboard.Clipboard;
+import com.sk89q.worldedit.world.block.BlockState;
+import de.steamwar.bausystem.BauSystem;
+import de.steamwar.command.SWCommand;
+import de.steamwar.linkage.Linked;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+@Linked
+public class BlastResistanceCommand extends SWCommand {
+
+ public BlastResistanceCommand() {
+ super("blastresistance");
+ }
+
+ @Register(description = "BLASTRESISTANCE_HELP")
+ public void command(@Validator Player player) {
+ LocalSession localSession = WorldEdit.getInstance().getSessionManager().get(BukkitAdapter.adapt(player));
+ Clipboard clipboard;
+ try {
+ clipboard = localSession.getClipboard().getClipboards().getFirst();
+ } catch (WorldEditException e) {
+ BauSystem.MESSAGE.send("BLASTRESISTANCE_NO_CLIPBOARD", player);
+ return;
+ }
+
+ AtomicDouble min = new AtomicDouble(0);
+ AtomicDouble max = new AtomicDouble(0);
+ AtomicDouble sum = new AtomicDouble(0);
+ AtomicInteger count = new AtomicInteger(0);
+ clipboard.forEach(blockVector3 -> {
+ BlockState blockState = clipboard.getBlock(blockVector3);
+ Material material = BukkitAdapter.adapt(blockState).getMaterial();
+ if (material == Material.WATER || material == Material.LAVA) return;
+ double blastResistance = BukkitAdapter.adapt(blockState).getMaterial().getBlastResistance();
+ min.set(Math.min(min.get(), blastResistance));
+ max.set(Math.max(max.get(), blastResistance));
+ sum.addAndGet(blastResistance);
+ count.getAndIncrement();
+ });
+
+ BauSystem.MESSAGE.send("BLASTRESISTANCE_RESULT", player, min.get(), max.get(), sum.get() / count.get());
+ }
+}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/TechHiderCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/TechHiderCommand.java
index 4744e41d..2f401a59 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/TechHiderCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/techhider/TechHiderCommand.java
@@ -31,6 +31,7 @@ import de.steamwar.command.TypeMapper;
import de.steamwar.core.CraftbukkitWrapper;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.LinkedInstance;
+import de.steamwar.techhider.legacy.TechHider;
import net.md_5.bungee.api.ChatMessageType;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
@@ -38,7 +39,6 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
-import de.steamwar.techhider.legacy.TechHider;
import java.util.*;
import java.util.stream.Collectors;
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSSystem.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSSystem.java
index 3e1c2772..2789c4bf 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSSystem.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSSystem.java
@@ -165,6 +165,7 @@ public class TPSSystem implements Listener {
}
@Register(value = "default", description = "TPSLIMIT_DEFAULT_HELP")
+ @Register(value = "rate")
public void reset(@Validator Player player) {
TickManager.impl.setTickRate(20.0F);
sendTickRateChange();
@@ -187,15 +188,18 @@ public class TPSSystem implements Listener {
}
@Register(value = {"rate", "0"}, description = "TICK_FREEZE_HELP")
- @Register(value = "freeze", description = "TICK_FREEZE_HELP_2")
- public void freeze(@Validator Player player) {
+ public void rate(@Validator Player player) {
TickManager.impl.setFreeze(true);
sendTickRateChange();
}
- @Register(value = "unfreeze", description = "TICK_UNFREEZE_HELP")
- public void unfreeze(@Validator Player player) {
- TickManager.impl.setTickRate(20.0F);
+ @Register(value = "freeze", description = "TICK_FREEZE_HELP_2")
+ public void freezeToggle(@Validator Player player) {
+ if (TickManager.impl.isFrozen()) {
+ TickManager.impl.setTickRate(20.0F);
+ } else {
+ TickManager.impl.setFreeze(true);
+ }
sendTickRateChange();
}
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java
index c55c5135..8eb49d79 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java
@@ -143,14 +143,6 @@ public class Trace {
} else {
entityServer = new REntityServer();
entityServer.addPlayer(player);
- entityServer.setCallback((p, rEntity, entityAction) -> {
- if (entityAction != REntityServer.EntityAction.INTERACT) {
- return;
- }
- if (rEntity instanceof TraceEntity) {
- ((TraceEntity) rEntity).printIntoChat(p);
- }
- });
entityServerMap.put(player, entityServer);
}
render(getRecords(), entityServer, playerTraceShowData);
@@ -167,14 +159,6 @@ public class Trace {
REntityServer entityServer = entityServerMap.computeIfAbsent(player, k -> {
REntityServer newEntityServer = new REntityServer();
newEntityServer.addPlayer(k);
- newEntityServer.setCallback((p, rEntity, entityAction) -> {
- if (entityAction != REntityServer.EntityAction.INTERACT) {
- return;
- }
- if (rEntity instanceof TraceEntity) {
- ((TraceEntity) rEntity).printIntoChat(p);
- }
- });
return newEntityServer;
});
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceCommand.java
index cfe50f55..a40a4a62 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceCommand.java
@@ -153,7 +153,11 @@ public class TraceCommand extends SWCommand {
@Register(value = "isolate", description = "TRACE_COMMAND_HELP_ISOLATE")
public void isolate(@Validator Player player, Trace trace, @ErrorMessage("TRACE_RECORD_ID_INVALID") TNTPoint... records) {
- TraceManager.instance.isolate(player, records);
+ if (records.length == 0) {
+ TraceManager.instance.isolate(player, trace, trace.getRecords().toArray(TNTPoint[]::new));
+ } else {
+ TraceManager.instance.isolate(player, trace, records);
+ }
BauSystem.MESSAGE.send("TRACE_MESSAGE_ISOLATE", player);
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceManager.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceManager.java
index 38409347..af2e0d37 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceManager.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceManager.java
@@ -347,9 +347,10 @@ public class TraceManager implements Listener {
* Toggles the isolated render for the given records and player
*
* @param player the player the trace is shown to
- * @param records the record for which isolation is toggled
+ * @param ptrace the trace for whitch isolation is toggled
+ * @param records the records of the trace for which isolation is toggled
*/
- public void isolate(Player player, TNTPoint... records) {
+ public void isolate(Player player, Trace ptrace, TNTPoint... records) {
unfollow(player);
Region region = Region.getRegion(player.getLocation());
@@ -374,12 +375,20 @@ public class TraceManager implements Listener {
isolateFlag.toggleId(record.getTntId());
}
+ if (isolateFlag.isEmpty() && playerTraceShowData.hasViewFlagOnly(IsolateFlag.class) && records.length != 0) {
+ playerTraceShowData.removeViewFlag(IsolateFlag.class);
+ }
+
PlayerTraceShowData finalPlayerTraceShowData = playerTraceShowData;
tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> {
- trace.render(player, finalPlayerTraceShowData);
- followerMap.getOrDefault(player, Collections.emptySet()).forEach(follower -> {
- trace.render(follower, finalPlayerTraceShowData);
- });
+ if (trace.getUuid() == ptrace.getUuid() || finalPlayerTraceShowData.hasNoViewFlags()) {
+ trace.render(player, finalPlayerTraceShowData);
+ followerMap.getOrDefault(player, Collections.emptySet()).forEach(follower -> {
+ trace.render(follower, finalPlayerTraceShowData);
+ });
+ } else {
+ trace.hide(player);
+ }
});
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecorder.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecorder.java
index c976fa14..0c2936ec 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecorder.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecorder.java
@@ -135,6 +135,13 @@ public class TraceRecorder implements Listener {
Iterator iter = trackedTNT.getOrDefault(region, Collections.emptyList()).iterator();
while (iter.hasNext()) {
TNTPrimed tnt = iter.next();
+ if (tnt.isDead()) {
+ iter.remove();
+ tntSpawnRegion.remove(tnt);
+ historyMap.remove(tnt);
+ tntSpawnRegion.remove(tnt);
+ continue;
+ }
if (tnt.getFuseTicks() == 80) continue;
TNTPoint record = record(tnt, wrappedTrace, Collections.emptyList());
if (record == null) {
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/PlayerTraceShowData.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/PlayerTraceShowData.java
index 40bbb238..ca34da43 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/PlayerTraceShowData.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/PlayerTraceShowData.java
@@ -95,4 +95,8 @@ public class PlayerTraceShowData {
public void addViewFlag(ViewFlag viewFlag) {
viewFlags.put(viewFlag.getClass(), viewFlag);
}
+
+ public void removeViewFlag(Class clazz) {
+ viewFlags.remove(clazz);
+ }
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/TraceEntity.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/TraceEntity.java
index ff3cbcea..160e4d58 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/TraceEntity.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/TraceEntity.java
@@ -25,7 +25,9 @@ import de.steamwar.bausystem.features.tracer.TNTPoint;
import de.steamwar.bausystem.features.tracer.Trace;
import de.steamwar.bausystem.features.tracer.TraceManager;
import de.steamwar.entity.RBlockDisplay;
+import de.steamwar.entity.REntityAction;
import de.steamwar.entity.REntityServer;
+import de.steamwar.entity.RInteraction;
import lombok.Getter;
import net.md_5.bungee.api.chat.ClickEvent;
import org.bukkit.Location;
@@ -46,9 +48,9 @@ import static de.steamwar.bausystem.features.util.TNTClickListener.TNT_CLICK_DET
*/
public class TraceEntity extends RBlockDisplay {
- private static final float TNT_VISUAL_SCALE = 0.98F;
- private static final float TNT_VISUAL_OFFSET = -TNT_VISUAL_SCALE / 2.0F;
- private static final Transformation TNT_VISUAL_TRANSFORM = new Transformation(
+ public static final float TNT_VISUAL_SCALE = 0.98F;
+ public static final float TNT_VISUAL_OFFSET = -TNT_VISUAL_SCALE / 2.0F;
+ public static final Transformation TNT_VISUAL_TRANSFORM = new Transformation(
new Vector3f(TNT_VISUAL_OFFSET, 0.0F, TNT_VISUAL_OFFSET),
new Quaternionf(0, 0, 0, 1),
new Vector3f(TNT_VISUAL_SCALE, TNT_VISUAL_SCALE, TNT_VISUAL_SCALE),
@@ -67,6 +69,7 @@ public class TraceEntity extends RBlockDisplay {
private final String uniqueTntIdsString;
private final Trace trace;
+ private final RInteraction hitbox;
public TraceEntity(REntityServer server, Location location, boolean isExplosion, List records, Trace trace) {
super(server, location);
@@ -74,8 +77,23 @@ public class TraceEntity extends RBlockDisplay {
this.records = records;
this.trace = trace;
uniqueTntIdsString = records.stream().map(TNTPoint::getTntId).distinct().map(Object::toString).collect(Collectors.joining(" "));
+ hitbox = new RInteraction(server, location);
+ hitbox.setInteractionHeight(TNT_VISUAL_SCALE);
+ hitbox.setInteractionWidth(TNT_VISUAL_SCALE);
+ hitbox.setCallback((player, action) -> {
+ if (action == REntityAction.INTERACT) {
+ printIntoChat(player);
+ }
+ });
setTransform(TNT_VISUAL_TRANSFORM);
setBlock(material.createBlockData());
+
+ }
+
+ @Override
+ public void die() {
+ hitbox.die();
+ super.die();
}
/**
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/ViewFlag.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/ViewFlag.java
index c061bfe5..da08fecd 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/ViewFlag.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/ViewFlag.java
@@ -20,8 +20,8 @@
package de.steamwar.bausystem.features.tracer.rendering;
import de.steamwar.bausystem.features.tracer.TNTPoint;
+import de.steamwar.entity.RBlockDisplay;
import de.steamwar.entity.REntityServer;
-import de.steamwar.entity.RFallingBlockEntity;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.util.Vector;
@@ -129,8 +129,9 @@ public abstract class ViewFlag {
Location yLocation = previous.getLocation().clone().add(0, delta.getY(), 0);
if (yLocation.distanceSquared(representative.getLocation()) >= 1.0 / 256.0 && yLocation.distanceSquared(previous.getLocation()) >= 1.0 / 256.0) {
- RFallingBlockEntity y = new RFallingBlockEntity(server, yLocation, Material.WHITE_STAINED_GLASS);
- y.setNoGravity(true);
+ RBlockDisplay y = new RBlockDisplay(server, yLocation);
+ y.setBlock(Material.WHITE_STAINED_GLASS.createBlockData());
+ y.setTransform(TraceEntity.TNT_VISUAL_TRANSFORM);
}
Location secoundLocation;
@@ -141,8 +142,9 @@ public abstract class ViewFlag {
}
if (secoundLocation.distanceSquared(representative.getLocation()) >= 1.0 / 256.0 && secoundLocation.distanceSquared(previous.getLocation()) >= 1.0 / 256.0) {
- RFallingBlockEntity second = new RFallingBlockEntity(server, secoundLocation, Material.WHITE_STAINED_GLASS);
- second.setNoGravity(true);
+ RBlockDisplay second = new RBlockDisplay(server, secoundLocation);
+ second.setBlock(Material.WHITE_STAINED_GLASS.createBlockData());
+ second.setTransform(TraceEntity.TNT_VISUAL_TRANSFORM);
}
}
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/dynamicflags/IsolateFlag.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/dynamicflags/IsolateFlag.java
index 8c86fcaf..303e4a32 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/dynamicflags/IsolateFlag.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/rendering/dynamicflags/IsolateFlag.java
@@ -51,6 +51,10 @@ public class IsolateFlag extends ViewFlag {
}
}
+ public boolean isEmpty() {
+ return tntToIsolate.isEmpty();
+ }
+
@Override
public Stream filter(Stream records) {
if (tntToIsolate.isEmpty()) return records;
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/BindCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/BindCommand.java
index bde7967e..5db75a81 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/BindCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/BindCommand.java
@@ -38,6 +38,7 @@ import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.command.CommandMap;
import org.bukkit.command.CommandSender;
+import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@@ -47,7 +48,6 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;
-import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@@ -73,19 +73,7 @@ public class BindCommand extends SWCommand implements Listener {
}
}
- private static final CommandMap commandMap;
-
- static {
- Field knownCommandsField;
- try {
- knownCommandsField = Bukkit.getServer().getClass().getDeclaredField("commandMap");
- knownCommandsField.setAccessible(true);
- commandMap = (CommandMap) knownCommandsField.get(Bukkit.getServer());
- } catch (IllegalAccessException | NoSuchFieldException var2) {
- Bukkit.shutdown();
- throw new SecurityException("Oh shit. Commands cannot be registered.", var2);
- }
- }
+ private static final CommandMap commandMap = ((CraftServer) Bukkit.getServer()).getCommandMap();
private static final NamespacedKey KEY = SWUtils.getNamespaceKey("command");
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/NoClipCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/NoClipCommand.java
index 0b10e163..dd143f0a 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/NoClipCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/NoClipCommand.java
@@ -21,7 +21,6 @@ package de.steamwar.bausystem.features.util;
import com.comphenix.tinyprotocol.TinyProtocol;
import com.mojang.authlib.GameProfile;
-import de.steamwar.Reflection;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.features.tpslimit.TPSUtils;
import de.steamwar.bausystem.utils.BauMemberUpdateEvent;
@@ -30,7 +29,6 @@ import de.steamwar.core.ProtocolWrapper;
import de.steamwar.core.SWPlayer;
import de.steamwar.linkage.Linked;
import net.minecraft.network.protocol.game.*;
-import net.minecraft.server.level.ServerPlayerGameMode;
import net.minecraft.world.entity.player.Abilities;
import net.minecraft.world.level.GameType;
import org.bukkit.Bukkit;
@@ -103,10 +101,8 @@ public class NoClipCommand extends SWCommand implements Listener {
TinyProtocol.instance.addFilter(ServerboundSetCreativeModeSlotPacket.class, third);
}
- private static final Reflection.Field playerGameMode = Reflection.getField(ServerPlayerGameMode.class, GameType.class, 0);
-
private void setInternalGameMode(Player player, GameMode gameMode) {
- playerGameMode.set(((CraftPlayer) player).getHandle().gameMode, GameType.byId(gameMode.getValue()));
+ ((CraftPlayer) player).getHandle().gameMode.gameModeForPlayer = GameType.byId(gameMode.getValue());
}
@Register(help = true)
@@ -143,6 +139,7 @@ public class NoClipCommand extends SWCommand implements Listener {
@EventHandler(ignoreCancelled = true)
public void onBlock(BlockCanBuildEvent event) {
+ if (event.getPlayer() == null) return;
if (SWPlayer.of(event.getPlayer()).hasComponent(NoClipData.class)) {
event.setBuildable(true);
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/BauMemberUpdate.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/BauMemberUpdate.java
index ed5b068b..d3416e08 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/BauMemberUpdate.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/BauMemberUpdate.java
@@ -36,8 +36,6 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
-import org.bukkit.event.inventory.ClickType;
-import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerItemConsumeEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/SpectatorListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/SpectatorListener.java
index 92a5c59e..645600cd 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/SpectatorListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/SpectatorListener.java
@@ -25,6 +25,7 @@ import de.steamwar.bausystem.config.BauServer;
import de.steamwar.bausystem.utils.BauMemberUpdateEvent;
import de.steamwar.linkage.Linked;
import de.steamwar.sql.BauweltMember;
+import de.steamwar.techhider.legacy.TechHider;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
@@ -39,7 +40,6 @@ import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityPickupItemEvent;
import org.bukkit.event.player.*;
import org.bukkit.util.Vector;
-import de.steamwar.techhider.legacy.TechHider;
import java.util.HashSet;
import java.util.Set;
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/WorldEditListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/WorldEditListener.java
index 26943331..b0373595 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/WorldEditListener.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/WorldEditListener.java
@@ -57,7 +57,7 @@ public class WorldEditListener implements Listener {
private static final Set commands = new HashSet<>();
private static final Set commandExclusions = new HashSet<>();
- private static final String[] shortcutCommands = {"//1", "//2", "//90", "//-90", "//180", "//p", "//c", "//flopy", "//floppy", "//flopyp", "//floppyp", "//u", "//r"};
+ private static final String[] shortcutCommands = {"//1", "//2", "//90", "//-90", "//180", "//p", "//c", "//flopy", "//floppy", "//flopyp", "//floppyp", "//u", "//r", "//download", "/download"};
public static boolean isWorldEditCommand(String command) {
for (String shortcut : shortcutCommands) {
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/xray/XrayCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/xray/XrayCommand.java
index 55bcbeeb..aa90081c 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/xray/XrayCommand.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/xray/XrayCommand.java
@@ -28,6 +28,7 @@ import de.steamwar.command.SWCommand;
import de.steamwar.core.CraftbukkitWrapper;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.LinkedInstance;
+import de.steamwar.techhider.legacy.TechHider;
import net.md_5.bungee.api.ChatMessageType;
import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket;
import net.minecraft.server.level.ServerPlayer;
@@ -40,7 +41,6 @@ import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerQuitEvent;
-import de.steamwar.techhider.legacy.TechHider;
import java.util.*;
import java.util.function.BiFunction;
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/PlaceItemUtils.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/PlaceItemUtils.java
index c4ab9a54..71f42cbb 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/PlaceItemUtils.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/PlaceItemUtils.java
@@ -19,7 +19,6 @@
package de.steamwar.bausystem.utils;
-import de.steamwar.Reflection;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.experimental.UtilityClass;
@@ -86,9 +85,6 @@ public class PlaceItemUtils {
.collect(Collectors.toSet());
}
- private static final Reflection.Field> positionAccessor = Reflection.getField(CraftBlockState.class, BlockPos.class, 0);
- private static final Reflection.Field> worldAccessor = Reflection.getField(CraftBlockState.class, CraftWorld.class, 0);
-
/**
* Attempt to place an {@link ItemStack} the {@link Player} is holding against a {@link Block} inside the World.
* This can be easily used inside the {@link org.bukkit.event.player.PlayerInteractEvent} to mimik placing a
@@ -288,8 +284,9 @@ public class PlaceItemUtils {
} else {
// If a BlockState is present set the Position and World to the Block you want to place
Location blockLocation = block.getLocation();
- positionAccessor.set(blockState, new BlockPos(blockLocation.getBlockX(), blockLocation.getBlockY(), blockLocation.getBlockZ()));
- worldAccessor.set(blockState, blockLocation.getWorld());
+ CraftBlockState craftBlockState = (CraftBlockState) blockState;
+ craftBlockState.position = new BlockPos(blockLocation.getBlockX(), blockLocation.getBlockY(), blockLocation.getBlockZ());
+ craftBlockState.world = (CraftWorld) blockLocation.getWorld();
}
if (blockData.getMaterial().isSolid()) {
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/TickManager.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/TickManager.java
index 59d12df2..613b3ea4 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/TickManager.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/TickManager.java
@@ -20,7 +20,6 @@
package de.steamwar.bausystem.utils;
import com.comphenix.tinyprotocol.TinyProtocol;
-import de.steamwar.Reflection;
import de.steamwar.bausystem.BauSystem;
import net.minecraft.network.protocol.game.ClientboundTickingStatePacket;
import net.minecraft.server.MinecraftServer;
@@ -33,7 +32,6 @@ public class TickManager implements Listener {
public static final TickManager impl = new TickManager();
private static final ServerTickRateManager manager = MinecraftServer.getServer().tickRateManager();
- private static final Reflection.Field remainingSprintTicks = Reflection.getField(ServerTickRateManager.class, long.class, 0);
private boolean blockTpsPacket = true;
private int totalSteps;
@@ -121,7 +119,7 @@ public class TickManager implements Listener {
public long getRemainingTicks() {
if (isSprinting()) {
- return remainingSprintTicks.get(manager);
+ return manager.remainingSprintTicks;
} else {
return manager.frozenTicksToRun();
}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/WorldEditUtils.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/WorldEditUtils.java
index 0bab1548..8c493707 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/WorldEditUtils.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/WorldEditUtils.java
@@ -19,6 +19,7 @@
package de.steamwar.bausystem.utils;
+import com.fastasyncworldedit.core.regions.selector.PolyhedralRegionSelector;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
@@ -32,16 +33,19 @@ import com.sk89q.worldedit.internal.registry.InputParser;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionSelector;
+import com.sk89q.worldedit.regions.selector.*;
import com.sk89q.worldedit.regions.selector.limit.SelectorLimits;
-import de.steamwar.Reflection;
+import com.sk89q.worldedit.world.World;
import de.steamwar.bausystem.shared.Pair;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import org.bukkit.Location;
-import org.bukkit.World;
import org.bukkit.entity.Player;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
import java.util.stream.Collectors;
@UtilityClass
@@ -91,17 +95,36 @@ public class WorldEditUtils {
.getRegionSelector(BukkitAdapter.adapt(player.getWorld()));
return new Pair<>(regionSelector.getClass(), regionSelector.getVertices()
.stream()
- .map(blockVector3 -> blockVector3 == null ? null : adapt(player.getWorld(), blockVector3))
+ .map(blockVector3 -> {
+ if (blockVector3 == null) {
+ return null;
+ } else {
+ return BukkitAdapter.adapt(player.getWorld(), blockVector3);
+ }
+ })
.collect(Collectors.toList()));
}
+ private static final Map, Function> constructors = new HashMap<>();
+ static {
+ constructors.put(CuboidRegionSelector.class, CuboidRegionSelector::new);
+ constructors.put(ExtendingCuboidRegionSelector.class, ExtendingCuboidRegionSelector::new);
+ constructors.put(Polygonal2DRegionSelector.class, Polygonal2DRegionSelector::new);
+ constructors.put(EllipsoidRegionSelector.class, EllipsoidRegionSelector::new);
+ constructors.put(SphereRegionSelector.class, SphereRegionSelector::new);
+ constructors.put(CylinderRegionSelector.class, CylinderRegionSelector::new);
+ constructors.put(ConvexPolyhedralRegionSelector.class, ConvexPolyhedralRegionSelector::new);
+ constructors.put(PolyhedralRegionSelector.class, PolyhedralRegionSelector::new);
+ }
+
public void setVertices(Player player, Class extends RegionSelector> clazz, List vertices) {
LocalSession localSession = WorldEdit.getInstance()
.getSessionManager()
.get(BukkitAdapter.adapt(player));
- Reflection.Constructor constructorInvoker = Reflection.getConstructor(clazz, com.sk89q.worldedit.world.World.class);
- RegionSelector regionSelector = (RegionSelector) constructorInvoker.invoke(BukkitAdapter.adapt(player.getWorld()));
+ Function constructor = constructors.get(clazz);
+ if (constructor == null) return;
+ RegionSelector regionSelector = constructor.apply(BukkitAdapter.adapt(player.getWorld()));
localSession.setRegionSelector(BukkitAdapter.adapt(player.getWorld()), regionSelector);
if (vertices.isEmpty()) return;
@@ -127,13 +150,9 @@ public class WorldEditUtils {
try {
BlockVector3 min = regionSelector.getRegion().getMinimumPoint();
BlockVector3 max = regionSelector.getRegion().getMaximumPoint();
- return new Pair<>(adapt(player.getWorld(), min), adapt(player.getWorld(), max));
+ return new Pair<>(BukkitAdapter.adapt(player.getWorld(), min), BukkitAdapter.adapt(player.getWorld(), max));
} catch (IncompleteRegionException e) {
return null;
}
}
-
- private Location adapt(World world, BlockVector3 blockVector3) {
- return new Location(world, blockVector3.getBlockX(), blockVector3.getBlockY(), blockVector3.getBlockZ());
- }
}
diff --git a/BauSystem/BauSystem_Main/src/plugin.yml b/BauSystem/BauSystem_Main/src/plugin.yml
index 71b08d95..bbc550bc 100644
--- a/BauSystem/BauSystem_Main/src/plugin.yml
+++ b/BauSystem/BauSystem_Main/src/plugin.yml
@@ -4,7 +4,7 @@ version: "2.0"
depend: [ WorldEdit, SpigotCore ]
load: POSTWORLD
main: de.steamwar.bausystem.BauSystem
-api-version: "1.13"
+api-version: "1.21"
website: "https://steamwar.de"
description: "So unseriös wie wir sind: BauSystem nur besser."
diff --git a/BauSystem/build.gradle.kts b/BauSystem/build.gradle.kts
index de9fe1b8..6a6bfac5 100644
--- a/BauSystem/build.gradle.kts
+++ b/BauSystem/build.gradle.kts
@@ -37,5 +37,6 @@ tasks.register("DevBau21") {
dependsOn(":SpigotCore:shadowJar")
dependsOn(":BauSystem:shadowJar")
dependsOn(":SchematicSystem:shadowJar")
+ dependsOn(":KotlinCore:shadowJar")
template = "Bau21"
}
diff --git a/CLI/build.gradle.kts b/CLI/build.gradle.kts
index f27d16b8..9629fc04 100644
--- a/CLI/build.gradle.kts
+++ b/CLI/build.gradle.kts
@@ -18,6 +18,7 @@ dependencies {
implementation("com.github.ajalt.clikt:clikt:5.0.3")
implementation("com.github.ajalt.mordant:mordant:3.0.2")
implementation(libs.logback)
+ implementation("org.yaml:snakeyaml:2.2")
implementation("org.mariadb.jdbc:mariadb-java-client:3.3.1")
implementation(libs.exposedCore)
diff --git a/CLI/src/commands/database/ResetCommand.kt b/CLI/src/commands/database/ResetCommand.kt
index 07413ddf..89fdae5f 100644
--- a/CLI/src/commands/database/ResetCommand.kt
+++ b/CLI/src/commands/database/ResetCommand.kt
@@ -7,6 +7,7 @@ import com.github.ajalt.mordant.rendering.TextColors
import com.github.ajalt.mordant.rendering.TextStyles
import de.steamwar.db.Database
import de.steamwar.db.execute
+import de.steamwar.db.executeScript
import de.steamwar.db.useDb
import java.io.File
@@ -22,13 +23,25 @@ class ResetCommand : CliktCommand() {
val schema = schemaFile.readText()
- val tables = execute("SHOW TABLES;") { it.getString(1) }
- for (table in tables) {
- execute("DROP TABLE IF EXISTS $table;") { }
+ execute("SET FOREIGN_KEY_CHECKS=0;") { }
+
+ val databaseObjects = execute("SHOW FULL TABLES;") { it.getString(1) to it.getString(2) }
+ for (view in databaseObjects.filter { it.second == "VIEW" }.map { it.first }) {
+ execute("DROP VIEW IF EXISTS `${view.replace("`", "``")}`;") { }
+ }
+ for (table in databaseObjects.filter { it.second == "BASE TABLE" }.map { it.first }) {
+ execute("DROP TABLE IF EXISTS `${table.replace("`", "``")}`;") { }
}
- execute(schema) { }
+ executeScript(schema)
+
+ val seed = javaClass.getResource("/db/reset-seed.sql")
+ ?: throw CliktError("Reset seed file not found!")
+
+ executeScript(seed.readText())
+
+ execute("SET FOREIGN_KEY_CHECKS=1;") { }
echo(TextColors.brightGreen(TextStyles.bold("Database reset!")))
}
-}
\ No newline at end of file
+}
diff --git a/CLI/src/commands/dev/DevCommand.kt b/CLI/src/commands/dev/DevCommand.kt
index 03b1ed2f..075c5211 100644
--- a/CLI/src/commands/dev/DevCommand.kt
+++ b/CLI/src/commands/dev/DevCommand.kt
@@ -14,9 +14,11 @@ import com.github.ajalt.clikt.parameters.types.file
import com.github.ajalt.clikt.parameters.types.long
import com.github.ajalt.clikt.parameters.types.path
import com.sun.security.auth.module.UnixSystem
+import org.yaml.snakeyaml.Yaml
import java.io.File
import kotlin.io.path.absolute
import kotlin.io.path.absolutePathString
+import kotlin.random.Random
const val LOG4J_CONFIG = """
@@ -69,35 +71,47 @@ class DevCommand : CliktCommand("dev") {
override fun run() {
val args = mutableListOf()
- val serverDirectory = File(workingDir, server)
- val serverDir =
- if (serverDirectory.exists() && serverDirectory.isDirectory) serverDirectory else File(workingDir, server)
+ var serverDir = resolveServerDirectory(server)
if (isVelocity(server)) {
runServer(
args, jvmArgs, listOf(
jar?.absolutePath
- ?: File("/jar/Velocity.jar").absolutePath
+ ?: File("/jars/Velocity.jar").absolutePath
), serverDir
)
} else {
setLogConfig(args)
val version = findVersion(server)
?: throw CliktError("Unknown Server Version")
+ val gameModeTemplate = if (serverDir.isDirectory) null else loadGameModeTemplate(server)
+ if (gameModeTemplate != null) {
+ serverDir = gameModeTemplate.serverDir
+ args += "-Dconfig=$server.yml"
+ }
val worldFile = world?.absolute()?.toFile()
- ?: File(serverDir, "devtempworld")
- val jarFile = jar?.absolutePath
+ ?: File(workingDir, "devtempworld")
+ var jarFile = jar?.absolutePath
?: additionalVersions[server]?.let { supportedVersionJars[it] }
?: supportedVersionJars[version]
?: throw CliktError("Unknown Server Version")
+ if (gameModeTemplate != null) {
+ jarFile = if (gameModeTemplate.spigot) {
+ jarFile.replace("paper", "spigot")
+ } else {
+ jarFile.replace("spigot", "paper")
+ }
+ }
if (!worldFile.exists()) {
- val templateFile = File(serverDir, "Bauwelt")
+ val templateFile = gameModeTemplate?.worldTemplate ?: File(serverDir, "Bauwelt")
if (!templateFile.exists()) {
- throw CliktError("World Template not found!")
+ throw CliktError("Could not find world template: ${templateFile.absolutePath}")
}
+ worldFile.parentFile?.mkdirs()
templateFile.copyRecursively(worldFile)
}
+ val worldDir = worldFile.parentFile ?: workingDir
val devFile = File("/configs/DevServer/${System.getProperty("user.name")}.$port.$version")
if (System.getProperty("user.name") != "minecraft") {
@@ -108,10 +122,11 @@ class DevCommand : CliktCommand("dev") {
args, jvmArgs, listOf(
jarFile,
*(if (forceUpgrade) arrayOf("-forceUpgrade") else arrayOf()),
+ "--log-strip-color",
"--port", port.toString(),
"--level-name", worldFile.name,
- "--world-dir", workingDir.absolutePath,
- "--nogui",
+ "--world-dir", worldDir.absolutePath,
+ "nogui",
*(if (plugins != null) arrayOf("--plugins", plugins!!.absolutePathString()) else arrayOf())
), serverDir
)
@@ -123,6 +138,12 @@ class DevCommand : CliktCommand("dev") {
}
}
+ data class GameModeTemplate(
+ val serverDir: File,
+ val worldTemplate: File,
+ val spigot: Boolean
+ )
+
val jvmDefaultParams = arrayOf(
"-Xmx1G",
"-Xgc:excessiveGCratio=80",
@@ -138,6 +159,16 @@ class DevCommand : CliktCommand("dev") {
val jvmArgOverrides = arrayOf("--add-opens", "java.base/jdk.internal.misc=ALL-UNNAMED")
+ val jvmNonJava8Params = arrayOf(
+ *jvmArgOverrides,
+ "-XX:-CRIUSecProvider"
+ )
+
+ val extendedStartupParams = arrayOf(
+ "-Dpaper.disablePluginRemapping=true",
+ "-javaagent:/jars/AccessWidener.jar=start"
+ )
+
val supportedVersionJars = mapOf(
8 to "/jars/paper-1.8.8.jar",
9 to "/jars/spigot-1.9.4.jar",
@@ -152,8 +183,7 @@ class DevCommand : CliktCommand("dev") {
)
val additionalVersions = mapOf(
- "Tutorial" to 15,
- "Lobby" to 20
+ "Lobby" to 21
)
fun findVersion(server: String): Int? =
@@ -166,6 +196,41 @@ class DevCommand : CliktCommand("dev") {
fun isVelocity(server: String): Boolean =
server.endsWith("Velocity")
+ fun resolveServerDirectory(server: String): File {
+ val localServer = File(workingDir, server)
+ if (localServer.isDirectory) {
+ return localServer
+ }
+ return File("/servers", server)
+ }
+
+ fun loadGameModeTemplate(server: String): GameModeTemplate? {
+ val configFile = File("/configs/GameModes/$server.yml")
+ if (!configFile.exists()) {
+ throw CliktError("Server/GameMode not found")
+ }
+
+ val document = configFile.reader().use { reader ->
+ Yaml().load