diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionCommand.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionCommand.java
index 73eb44c9..74ab6bc1 100644
--- a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionCommand.java
+++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionCommand.java
@@ -29,6 +29,7 @@ import de.steamwar.command.AbstractSWCommand;
import de.steamwar.command.PreviousArguments;
import de.steamwar.command.SWCommand;
import de.steamwar.command.TypeMapper;
+import de.steamwar.core.SWPlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -44,6 +45,18 @@ public class DynamicRegionCommand extends SWCommand {
super("");
}
+ @Register({"dynamic", "visualize"})
+ public void visualizeRegions(Player player) {
+ Tile tile = Tile.fromLocation(player.getLocation()).orElse(null);
+ if (tile == null) return;
+ SWPlayer swPlayer = SWPlayer.of(player);
+ if (swPlayer.hasComponent(DynamicRegionVisualizer.class)) {
+ swPlayer.removeComponent(DynamicRegionVisualizer.class);
+ } else {
+ swPlayer.setComponent(new DynamicRegionVisualizer());
+ }
+ }
+
@Register({"dynamic", "place"})
public void placeRegion(Player player, @Mapper("regionType") String regionType) {
Region region = DynamicRegionSystem.INSTANCE.get(player.getLocation());
diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionVisualizer.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionVisualizer.java
new file mode 100644
index 00000000..27d6a68a
--- /dev/null
+++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionVisualizer.java
@@ -0,0 +1,146 @@
+/*
+ * 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.region;
+
+import de.steamwar.bausystem.BauSystem;
+import de.steamwar.bausystem.region.dynamic.Tile;
+import de.steamwar.core.SWPlayer;
+import de.steamwar.entity.*;
+import de.steamwar.inventory.SWInventory;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryType;
+import org.bukkit.event.player.PlayerMoveEvent;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class DynamicRegionVisualizer implements SWPlayer.Component, Listener {
+
+ private final REntityServer entityServer;
+ private Player player;
+ private Location sourceLocation;
+ private Tile sourceTile;
+
+ public DynamicRegionVisualizer() {
+ this.entityServer = new REntityServer();
+ }
+
+ @Override
+ public void onMount(SWPlayer player) {
+ this.player = player.getPlayer();
+ sourceTile = Tile.fromLocation(player.getLocation()).orElse(null);
+ if (sourceTile == null) {
+ player.removeComponent(DynamicRegionVisualizer.class);
+ return;
+ }
+ sourceLocation = player.getLocation().add(0, -5, 0).getBlock().getLocation();
+ entityServer.addPlayer(player.getPlayer());
+
+ Bukkit.getPluginManager().registerEvents(this, BauSystem.getInstance());
+
+ renderTiles(0, 0);
+ }
+
+ @Override
+ public void onUnmount(SWPlayer player) {
+ Bukkit.getPluginManager().registerEvents(this, BauSystem.getInstance());
+ entityServer.close();
+ }
+
+ @EventHandler
+ public void onPlayerMove(PlayerMoveEvent event) {
+ if (event.getPlayer() != player) return;
+ Location position = event.getTo().getBlock().getLocation();
+ int dx = position.getBlockX() - sourceLocation.getBlockX();
+ int dz = position.getBlockZ() - sourceLocation.getBlockZ();
+ renderTiles(dx, dz);
+ }
+
+ private void renderTiles(int dx, int dz) {
+ Set tileSet = entityServer.getEntitiesByType(CTile.class)
+ .stream()
+ .filter(cTile -> {
+ if (Math.abs(cTile.tile.getTileX() - dx) > 20 || Math.abs(cTile.tile.getTileZ() - dz) > 20) {
+ cTile.die();
+ return false;
+ } else {
+ return true;
+ }
+ })
+ .map(cTile -> cTile.tile)
+ .collect(Collectors.toSet());
+
+ for (int x = dx - 10; x <= dx + 10; x++) {
+ for (int z = dz - 10; z <= dz + 10; z++) {
+ Tile tile = sourceTile.add(x, z).orElse(null);
+ if (tile == null || tileSet.contains(tile)) continue;
+ new CTile(entityServer, tile);
+ }
+ }
+ }
+
+ private class CTile extends CEntity {
+
+ private final Tile tile;
+
+ public CTile(REntityServer server, Tile tile) {
+ super(server);
+ this.tile = tile;
+
+ Material material = switch (DynamicRegionSystem.INSTANCE.get(tile).getType()) {
+ case SPAWN, SPAWN_EXTENSION -> Material.LODESTONE;
+ case SPAWN_PATH, PATH -> Material.DIRT_PATH;
+ case DRY, DRY_SPECIAL -> Material.IRON_BLOCK;
+ case WET, WET_SPECIAL -> Material.LAPIS_BLOCK;
+ default -> Material.WHITE_CARPET;
+ };
+ Location location = sourceLocation.clone().add(tile.getTileX() - sourceTile.getTileX(), 0, tile.getTileZ() - sourceTile.getTileZ());
+ if (tile.equals(Tile.ZERO)) {
+ CCubedTextDisplay spawn = new CCubedTextDisplay(entityServer, location);
+ spawn.setText("§eSPAWN");
+ spawn.setBackgroundColor(0);
+ spawn.setShadowed(false);
+ entities.add(spawn);
+ } else if (tile.equals(sourceTile)) {
+ CCubedTextDisplay spawn = new CCubedTextDisplay(entityServer, location);
+ spawn.setText("§eORIGIN");
+ spawn.setBackgroundColor(0);
+ spawn.setShadowed(false);
+ entities.add(spawn);
+ }
+
+ RBlockDisplay entity = new RBlockDisplay(entityServer, location);
+ entity.setBlock(material.createBlockData());
+ entities.add(entity);
+
+ RInteraction interaction = new RInteraction(entityServer, location.clone().add(0.5, 0, 0.5));
+ interaction.setInteraction((player, entityAction) -> {
+ SWInventory swInv = new SWInventory(player, () -> Bukkit.createInventory(null, InventoryType.DROPPER, tile.toString()));
+ swInv.open();
+ });
+ entities.add(entity);
+ }
+ }
+}
diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/Tile.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/Tile.java
index 68f77a35..3f327d97 100644
--- a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/Tile.java
+++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/Tile.java
@@ -20,14 +20,18 @@
package de.steamwar.bausystem.region.dynamic;
import de.steamwar.bausystem.region.Point;
+import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.bukkit.Location;
import java.util.Optional;
@Getter
+@EqualsAndHashCode
public class Tile {
+ public static final Tile ZERO = new Tile(0, 0);
+
public static final int tileSize = 21;
public static final int tileOffset = tileSize / 2;
public static final int maxTile = 1023;
@@ -122,12 +126,12 @@ public class Tile {
return fromTile(tileX + offsetX, tileZ + offsetZ);
}
- public static long getID(int tileX, int tileZ) {
+ public static long getId(int tileX, int tileZ) {
return (tileX + maxTile) * tilesPerAxis + tileZ + maxTile;
}
public long getId() {
- return getID(tileX, tileZ);
+ return getId(tileX, tileZ);
}
@Override
diff --git a/BauSystem/build.gradle.kts b/BauSystem/build.gradle.kts
index 5a8b572d..1034e4eb 100644
--- a/BauSystem/build.gradle.kts
+++ b/BauSystem/build.gradle.kts
@@ -44,6 +44,7 @@ tasks.register("DevBau21") {
tasks.register("DevBau21Dynamic") {
group = "run"
description = "Run a 1.21 Dynamic Dev Bau"
+ dependsOn(":SpigotCore:shadowJar")
dependsOn(":BauSystem:shadowJar")
dependsOn(":SchematicSystem:shadowJar")
template = "Bau21-Dynamic"