Add CArea, RInteractionCallback
Add DynamicRegionEditor, DynamicRegionVisualizer
This commit is contained in:
@@ -36,15 +36,15 @@ public class DynamicRegionCommand extends SWCommand {
|
||||
|
||||
@Register({"dynamic"})
|
||||
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 if (Permission.SUPERVISOR.hasPermission(player)) {
|
||||
swPlayer.setComponent(new DynamicRegionVisualizer());
|
||||
swPlayer.removeComponent(DynamicRegionEditor.class);
|
||||
} else {
|
||||
// TODO: Add Message
|
||||
swPlayer.setComponent(DynamicRegionVisualizer.INSTANCE);
|
||||
if (Permission.SUPERVISOR.hasPermission(player)) {
|
||||
swPlayer.setComponent(new DynamicRegionEditor(player.getPlayer()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.region;
|
||||
|
||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||
import de.steamwar.Reflection;
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.Permission;
|
||||
import de.steamwar.bausystem.region.dynamic.DynamicRegion;
|
||||
import de.steamwar.bausystem.region.dynamic.DynamicRegionRepository;
|
||||
import de.steamwar.bausystem.region.dynamic.RegionConstructorData;
|
||||
import de.steamwar.bausystem.region.dynamic.Tile;
|
||||
import de.steamwar.bausystem.utils.PasteBuilder;
|
||||
import de.steamwar.core.SWPlayer;
|
||||
import de.steamwar.entity.CArea;
|
||||
import de.steamwar.entity.REntityServer;
|
||||
import de.steamwar.entity.RInteraction;
|
||||
import de.steamwar.inventory.SWInventory;
|
||||
import de.steamwar.inventory.SWItem;
|
||||
import de.steamwar.inventory.SWListInv;
|
||||
import lombok.NonNull;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
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.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerSwapHandItemsEvent;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.joml.RayAabIntersection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class DynamicRegionEditor implements SWPlayer.Component, Listener {
|
||||
|
||||
private static final Class<?> position = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Pos");
|
||||
private static final Class<?> look = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Rot");
|
||||
private static final Class<?> positionLook = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$PosRot");
|
||||
|
||||
static {
|
||||
BiFunction<Player, Object, Object> function = (player, object) -> {
|
||||
SWPlayer.of(player).getComponent(DynamicRegionEditor.class).ifPresent(DynamicRegionEditor::calcCursor);
|
||||
return object;
|
||||
};
|
||||
TinyProtocol.instance.addFilter(position, function);
|
||||
TinyProtocol.instance.addFilter(look, function);
|
||||
TinyProtocol.instance.addFilter(positionLook, function);
|
||||
}
|
||||
|
||||
private final REntityServer entityServer = new REntityServer();
|
||||
private final CArea area = new CArea(entityServer);
|
||||
|
||||
private static final BlockData DELETE = Material.RED_CONCRETE.createBlockData();
|
||||
private static final BlockData INVALID = Material.YELLOW_CONCRETE.createBlockData();
|
||||
private static final BlockData PLACE = Material.LIME_CONCRETE.createBlockData();
|
||||
|
||||
{
|
||||
area.hide(true);
|
||||
}
|
||||
|
||||
private final Player player;
|
||||
|
||||
private final BukkitTask task;
|
||||
private Type type = new Delete();
|
||||
|
||||
public DynamicRegionEditor(Player player) {
|
||||
this.player = player;
|
||||
entityServer.addPlayer(player);
|
||||
|
||||
Bukkit.getPluginManager().registerEvents(this, BauSystem.getInstance());
|
||||
|
||||
for (int i = 0; i < 121; i++) {
|
||||
new RInteraction(entityServer, player.getLocation());
|
||||
}
|
||||
moveInteractionEntities(Point.fromLocation(player.getLocation()));
|
||||
|
||||
CArea area = new CArea(entityServer);
|
||||
area.setPos1And2(new Location(null, -Tile.maxTile, 1, -Tile.maxTile), new Location(null, Tile.maxTile, 1, Tile.maxTile));
|
||||
area.setBlock(Material.BEDROCK.createBlockData());
|
||||
|
||||
task = Bukkit.getScheduler().runTaskTimer(BauSystem.getInstance(), this::showHotbar, 0, 20);
|
||||
}
|
||||
|
||||
private void showHotbar() {
|
||||
entityServer.tick();
|
||||
|
||||
StringBuilder st = new StringBuilder();
|
||||
st.append(type.title());
|
||||
st.append(" §8(§7Change with §eSwap Hands§8)");
|
||||
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(st.toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnmount(SWPlayer player) {
|
||||
entityServer.close();
|
||||
task.cancel();
|
||||
PlayerMoveEvent.getHandlerList().unregister(this);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
if (event.getPlayer() != player) return;
|
||||
if (!Permission.SUPERVISOR.hasPermission(player)) {
|
||||
SWPlayer.of(player).removeComponent(DynamicRegionEditor.class);
|
||||
return;
|
||||
}
|
||||
if (event.getTo() == null) return;
|
||||
if (event.getFrom().getBlockX() == event.getTo().getBlockX() && event.getFrom().getBlockZ() == event.getTo().getBlockZ()) {
|
||||
return;
|
||||
}
|
||||
moveInteractionEntities(Point.fromLocation(event.getTo()));
|
||||
}
|
||||
|
||||
private void moveInteractionEntities(Point position) {
|
||||
List<RInteraction> interactionList = entityServer.getEntitiesByType(RInteraction.class);
|
||||
for (int x = -5; x <= 5; x++) {
|
||||
for (int z = -5; z <= 5; z++) {
|
||||
interactionList.removeFirst().move(position.getX() + x + 0.5, 0, position.getZ() + z + 0.5, 0, 0, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) {
|
||||
event.setCancelled(true);
|
||||
|
||||
List<SWListInv.SWListEntry<Type>> list = new ArrayList<>();
|
||||
list.add(new SWListInv.SWListEntry<>(new SWItem(Material.BARRIER, "§cDelete"), new Delete()));
|
||||
|
||||
DynamicRegionSystem.constructorDataMap.values()
|
||||
.stream()
|
||||
.sorted(Comparator.comparing(RegionConstructorData::name))
|
||||
.forEach(data -> {
|
||||
list.add(new SWListInv.SWListEntry<>(new SWItem(data.material(), "§f" + data.name()), new Place(data)));
|
||||
});
|
||||
|
||||
SWListInv<Type> inventory = new SWListInv<>(player, "Select Region to place", list, (click, type) -> {
|
||||
this.type = type;
|
||||
player.closeInventory();
|
||||
showHotbar();
|
||||
});
|
||||
inventory.open();
|
||||
}
|
||||
|
||||
private void calcCursor() {
|
||||
Location startPos = player.getLocation().clone().add(0.0, player.getEyeHeight(), 0.0);
|
||||
Vector direction = player.getLocation().getDirection();
|
||||
|
||||
RayAabIntersection intersection = new RayAabIntersection((float) startPos.getX(), (float) startPos.getY(), (float) startPos.getZ(), (float) direction.getX(), (float) direction.getY(), (float) direction.getZ());
|
||||
boolean hide = true;
|
||||
for (RInteraction interaction : entityServer.getEntitiesByType(RInteraction.class)) {
|
||||
float x = (float) (interaction.getX() - 0.5);
|
||||
float z = (float) (interaction.getZ() - 0.5);
|
||||
if (intersection.test(x, (float) 0.95, z, x + 1, (float) 1.05, z + 1)) {
|
||||
int tileX = (int) x;
|
||||
int tileZ = (int) z;
|
||||
if (type.visualize(area, tileX, tileZ)) {
|
||||
hide = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
area.hide(hide);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||
Location startPos = player.getLocation().clone().add(0.0, player.getEyeHeight(), 0.0);
|
||||
Vector direction = player.getLocation().getDirection();
|
||||
if (direction.getY() > 0) return;
|
||||
|
||||
RayAabIntersection intersection = new RayAabIntersection((float) startPos.getX(), (float) startPos.getY(), (float) startPos.getZ(), (float) direction.getX(), (float) direction.getY(), (float) direction.getZ());
|
||||
for (RInteraction interaction : entityServer.getEntitiesByType(RInteraction.class)) {
|
||||
float x = (float) (interaction.getX() - 0.5);
|
||||
float z = (float) (interaction.getZ() - 0.5);
|
||||
if (intersection.test(x, (float) 0.95, z, x + 1, (float) 1.05, z + 1)) {
|
||||
int tileX = (int) x;
|
||||
int tileZ = (int) z;
|
||||
type.run(event.getPlayer(), tileX, tileZ);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private interface Type {
|
||||
|
||||
String title();
|
||||
|
||||
boolean visualize(CArea area, int tileX, int tileZ);
|
||||
|
||||
void run(Player player, int tileX, int tileZ);
|
||||
}
|
||||
|
||||
private static class Delete implements Type {
|
||||
|
||||
private boolean valid = false;
|
||||
|
||||
private Delete() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String title() {
|
||||
return "§cDelete";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visualize(CArea area, int tileX, int tileZ) {
|
||||
Tile tile = Tile.fromTile(tileX, tileZ).orElse(null);
|
||||
if (tile == null) {
|
||||
valid = false;
|
||||
return false;
|
||||
}
|
||||
Region region = DynamicRegionSystem.INSTANCE.get(tile);
|
||||
if (region.getType().isGlobal()) {
|
||||
valid = false;
|
||||
return false;
|
||||
}
|
||||
Tile minTile = Tile.fromPoint(region.getArea().getMinPoint(false)).orElse(null);
|
||||
Tile maxTile = Tile.fromPoint(region.getArea().getMaxPoint(false)).orElse(null);
|
||||
if (minTile == null || maxTile == null) {
|
||||
valid = false;
|
||||
return false;
|
||||
}
|
||||
Location minLoc = new Location(null, minTile.getTileX(), 1, minTile.getTileZ());
|
||||
Location maxLoc = new Location(null, maxTile.getTileX(), 1, maxTile.getTileZ());
|
||||
area.setBlock(DELETE);
|
||||
area.setPos1And2(minLoc, maxLoc);
|
||||
valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Player player, int tileX, int tileZ) {
|
||||
if (!valid) return;
|
||||
Tile tile = Tile.fromTile(tileX, tileZ).orElse(null);
|
||||
if (tile == null) return;
|
||||
Region region = DynamicRegionSystem.INSTANCE.get(tile);
|
||||
if (region.getType().isGlobal()) return;
|
||||
|
||||
if (region.getType().isPath()) {
|
||||
region.delete();
|
||||
return;
|
||||
}
|
||||
|
||||
RegionConstructorData data = DynamicRegionSystem.constructorDataMap.get(region.getClass());
|
||||
SWInventory inventory = new SWInventory(player, 9, "Confirm delete: " + data.name());
|
||||
inventory.setItem(0, new SWItem(Material.GRAY_CONCRETE, "§7Cancel", click -> {
|
||||
player.closeInventory();
|
||||
}));
|
||||
inventory.setItem(8, new SWItem(Material.RED_CONCRETE, "§cDelete: " + data.name(), click -> {
|
||||
Region checkRegion = DynamicRegionSystem.INSTANCE.get(tile);
|
||||
if (region == checkRegion) region.delete();
|
||||
player.closeInventory();
|
||||
}));
|
||||
inventory.open();
|
||||
}
|
||||
}
|
||||
|
||||
private static class Place implements Type {
|
||||
|
||||
private final RegionConstructorData data;
|
||||
private final int widthX;
|
||||
private final int widthZ;
|
||||
|
||||
private boolean valid = false;
|
||||
|
||||
private Place(@NonNull RegionConstructorData data) {
|
||||
this.data = data;
|
||||
this.widthX = data.widthX() - 1;
|
||||
this.widthZ = data.widthZ() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String title() {
|
||||
return "§ePlace§8: §a" + data.name();
|
||||
}
|
||||
|
||||
private boolean validPlacement(int tileX, int tileZ) {
|
||||
for (int x = 0; x <= widthX; x++) {
|
||||
for (int z = 0; z <= widthZ; z++) {
|
||||
Tile tile = Tile.fromTile(tileX + x, tileZ + z).orElse(null);
|
||||
if (tile == null) return false;
|
||||
Region region = DynamicRegionSystem.INSTANCE.get(tile);
|
||||
if (!region.getType().isGlobal()) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visualize(CArea area, int tileX, int tileZ) {
|
||||
Tile tile = Tile.fromTile(tileX, tileZ).orElse(null);
|
||||
if (tile == null) {
|
||||
valid = false;
|
||||
return false;
|
||||
}
|
||||
// Center Tile placement!
|
||||
tileX -= widthX / 2;
|
||||
tileZ -= widthZ / 2;
|
||||
// Validate placements!
|
||||
if (validPlacement(tileX, tileZ)) {
|
||||
area.setBlock(PLACE);
|
||||
valid = true;
|
||||
} else {
|
||||
area.setBlock(INVALID);
|
||||
valid = false;
|
||||
}
|
||||
area.setPos1And2(new Location(null, tileX, 1, tileZ), new Location(null, tileX + widthX, 1, tileZ + widthZ));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Player player, int tileX, int tileZ) {
|
||||
if (!valid) return;
|
||||
// Center Tile placement!
|
||||
tileX -= widthX / 2;
|
||||
tileZ -= widthZ / 2;
|
||||
if (!validPlacement(tileX, tileZ)) return;
|
||||
Tile tile = Tile.fromTile(tileX, tileZ).orElse(null);
|
||||
if (tile == null) return;
|
||||
DynamicRegion region = DynamicRegionRepository.constructRegion(DynamicRegionSystem.identifierDataMap.get(data.identifier()), tile);
|
||||
if (region == null) return;
|
||||
region.getArea().place(new PasteBuilder(), false);
|
||||
region.updateNeighbours();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,12 +56,14 @@ public class DynamicRegionSystem implements RegionSystem {
|
||||
regionCache.clear();
|
||||
regionMap.put(region.getID(), region);
|
||||
regionTypeMap.computeIfAbsent(region.getType(), __ -> new HashSet<>()).add(region);
|
||||
DynamicRegionVisualizer.INSTANCE.addRegion(region);
|
||||
}
|
||||
|
||||
public void remove(DynamicRegion region) {
|
||||
regionCache.clear();
|
||||
regionMap.remove(region.getID());
|
||||
regionTypeMap.getOrDefault(region.getType(), Collections.emptySet()).remove(region);
|
||||
DynamicRegionVisualizer.INSTANCE.removeRegion(region);
|
||||
}
|
||||
|
||||
public static Map<Class<? extends DynamicRegion>, RegionConstructorData> constructorDataMap = new HashMap<>();
|
||||
@@ -197,31 +199,37 @@ public class DynamicRegionSystem implements RegionSystem {
|
||||
Set<Neighbour<Region>> neighbours = new HashSet<>();
|
||||
|
||||
if (!noCorners) {
|
||||
neighbours.add(new Neighbour<>(get(minTile.add(-1, -1).orElseThrow(), fastCache, regions), minTile, NeighbourDirection.NorthWest));
|
||||
neighbours.add(new Neighbour<>(get(minTile.add(-1, -1).orElse(null), fastCache, regions), minTile, NeighbourDirection.NorthWest));
|
||||
|
||||
Tile cornerMinMaxSelf = Tile.fromTile(minTile.getTileX(), maxTile.getTileZ()).orElseThrow();
|
||||
neighbours.add(new Neighbour<>(get(cornerMinMaxSelf.add(-1, 1).orElseThrow(), fastCache, regions), cornerMinMaxSelf, NeighbourDirection.SouthWest));
|
||||
Tile.fromTile(minTile.getTileX(), maxTile.getTileZ()).ifPresent(cornerMinMaxSelf -> {
|
||||
neighbours.add(new Neighbour<>(get(cornerMinMaxSelf.add(-1, 1).orElse(null), fastCache, regions), cornerMinMaxSelf, NeighbourDirection.SouthWest));
|
||||
});
|
||||
|
||||
Tile cornerMaxMinSelf = Tile.fromTile(maxTile.getTileX(), minTile.getTileZ()).orElseThrow();
|
||||
neighbours.add(new Neighbour<>(get(cornerMaxMinSelf.add(1, -1).orElseThrow(), fastCache, regions), cornerMaxMinSelf, NeighbourDirection.NorthEast));
|
||||
Tile.fromTile(maxTile.getTileX(), minTile.getTileZ()).ifPresent(cornerMaxMinSelf -> {
|
||||
neighbours.add(new Neighbour<>(get(cornerMaxMinSelf.add(1, -1).orElse(null), fastCache, regions), cornerMaxMinSelf, NeighbourDirection.NorthEast));
|
||||
});
|
||||
|
||||
neighbours.add(new Neighbour<>(get(maxTile.add(1, 1).orElseThrow(), fastCache, regions), maxTile, NeighbourDirection.SouthEast));
|
||||
neighbours.add(new Neighbour<>(get(maxTile.add(1, 1).orElse(null), fastCache, regions), maxTile, NeighbourDirection.SouthEast));
|
||||
}
|
||||
|
||||
for (int x = minTile.getTileX(); x <= maxTile.getTileX(); x++) {
|
||||
Tile tileMinZSelf = Tile.fromTile(x, minTile.getTileZ()).orElseThrow();
|
||||
neighbours.add(new Neighbour<>(get(tileMinZSelf.add(0, -1).orElseThrow(), fastCache, regions), tileMinZSelf, NeighbourDirection.North));
|
||||
Tile.fromTile(x, minTile.getTileZ()).ifPresent(tileMinZSelf -> {
|
||||
neighbours.add(new Neighbour<>(get(tileMinZSelf.add(0, -1).orElse(null), fastCache, regions), tileMinZSelf, NeighbourDirection.North));
|
||||
});
|
||||
|
||||
Tile tileMaxZSelf = Tile.fromTile(x, maxTile.getTileZ()).orElseThrow();
|
||||
neighbours.add(new Neighbour<>(get(tileMaxZSelf.add(0, 1).orElseThrow(), fastCache, regions), tileMaxZSelf, NeighbourDirection.South));
|
||||
Tile.fromTile(x, maxTile.getTileZ()).ifPresent(tileMaxZSelf -> {
|
||||
neighbours.add(new Neighbour<>(get(tileMaxZSelf.add(0, 1).orElse(null), fastCache, regions), tileMaxZSelf, NeighbourDirection.South));
|
||||
});
|
||||
}
|
||||
|
||||
for (int z = minTile.getTileZ(); z <= maxTile.getTileZ(); z++) {
|
||||
Tile tileMinXSelf = Tile.fromTile(minTile.getTileX(), z).orElseThrow();
|
||||
neighbours.add(new Neighbour<>(get(tileMinXSelf.add(-1, 0).orElseThrow(), fastCache, regions), tileMinXSelf, NeighbourDirection.West));
|
||||
Tile.fromTile(minTile.getTileX(), z).ifPresent(tileMinXSelf -> {
|
||||
neighbours.add(new Neighbour<>(get(tileMinXSelf.add(-1, 0).orElse(null), fastCache, regions), tileMinXSelf, NeighbourDirection.West));
|
||||
});
|
||||
|
||||
Tile tileMaxXSelf = Tile.fromTile(maxTile.getTileX(), z).orElseThrow();
|
||||
neighbours.add(new Neighbour<>(get(tileMaxXSelf.add(1, 0).orElseThrow(), fastCache, regions), tileMaxXSelf, NeighbourDirection.East));
|
||||
Tile.fromTile(maxTile.getTileX(), z).ifPresent(tileMaxXSelf -> {
|
||||
neighbours.add(new Neighbour<>(get(tileMaxXSelf.add(1, 0).orElse(null), fastCache, regions), tileMaxXSelf, NeighbourDirection.East));
|
||||
});
|
||||
}
|
||||
|
||||
neighbours.removeIf(neighbour -> neighbour.region.getType().isGlobal());
|
||||
|
||||
@@ -19,313 +19,96 @@
|
||||
|
||||
package de.steamwar.bausystem.region;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.region.dynamic.DynamicRegion;
|
||||
import de.steamwar.bausystem.region.dynamic.DynamicRegionRepository;
|
||||
import de.steamwar.bausystem.region.dynamic.RegionConstructorData;
|
||||
import de.steamwar.bausystem.region.dynamic.Tile;
|
||||
import de.steamwar.bausystem.utils.PasteBuilder;
|
||||
import de.steamwar.core.SWPlayer;
|
||||
import de.steamwar.entity.*;
|
||||
import de.steamwar.inventory.SWInventory;
|
||||
import de.steamwar.inventory.SWItem;
|
||||
import de.steamwar.inventory.SWListInv;
|
||||
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.player.PlayerMoveEvent;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Display;
|
||||
import org.bukkit.util.Transformation;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
public class DynamicRegionVisualizer implements SWPlayer.Component {
|
||||
|
||||
public class DynamicRegionVisualizer implements SWPlayer.Component, Listener {
|
||||
public static final DynamicRegionVisualizer INSTANCE = new DynamicRegionVisualizer();
|
||||
|
||||
private final REntityServer entityServer;
|
||||
private Player player;
|
||||
private Location sourceLocation;
|
||||
private Tile sourceTile;
|
||||
private final REntityServer entityServer = new REntityServer();
|
||||
|
||||
private Placement placement = null;
|
||||
private DynamicRegionVisualizer() {
|
||||
RTextDisplay text = new RTextDisplay(entityServer, new Location(null, 0.5, 1.1, 0.5));
|
||||
text.setText("Spawn");
|
||||
text.setBillboard(Display.Billboard.VERTICAL);
|
||||
text.setBackgroundColor(0);
|
||||
text.setShadowed(false);
|
||||
text.setTransform(new Transformation(new Vector3f(0, 0, 0), new Quaternionf().rotationX((float) Math.toRadians(270)), new Vector3f(1, 1, 1), new Quaternionf()));
|
||||
}
|
||||
|
||||
public DynamicRegionVisualizer() {
|
||||
this.entityServer = new REntityServer();
|
||||
public void addRegion(DynamicRegion region) {
|
||||
new CRegion(entityServer, region);
|
||||
}
|
||||
|
||||
public void removeRegion(DynamicRegion region) {
|
||||
entityServer.getEntitiesByType(CRegion.class)
|
||||
.stream()
|
||||
.filter(cRegion -> cRegion.region == region)
|
||||
.forEach(CRegion::die);
|
||||
}
|
||||
|
||||
@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();
|
||||
entityServer.removePlayer(player.getPlayer());
|
||||
}
|
||||
|
||||
@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 static final Vector3f VEC_ZERO = new Vector3f(0, 0, 0);
|
||||
private static final Quaternionf QUT_ZERO = new Quaternionf(0, 0, 0, 1);
|
||||
|
||||
public static Point toVisualization(Location worldLocation) {
|
||||
Tile tile = Tile.fromLocation(worldLocation).orElseThrow();
|
||||
return new Point(tile.getTileX(), 0, tile.getTileZ());
|
||||
}
|
||||
|
||||
private void renderTiles(int dx, int dz) {
|
||||
Set<Tile> tileSet = entityServer.getEntitiesByType(CTile.class)
|
||||
.stream()
|
||||
.filter(cTile -> {
|
||||
if (Math.abs(cTile.tile.getTileX() - dx) > 40 || Math.abs(cTile.tile.getTileZ() - dz) > 40) {
|
||||
cTile.die();
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.map(cTile -> cTile.tile)
|
||||
.collect(Collectors.toSet());
|
||||
private static class CRegion extends CEntity {
|
||||
|
||||
for (int x = dx - 20; x <= dx + 20; x++) {
|
||||
for (int z = dz - 20; z <= dz + 20; z++) {
|
||||
Tile tile = sourceTile.add(x, z).orElse(null);
|
||||
if (tile == null || tileSet.contains(tile)) continue;
|
||||
new CTile(entityServer, tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
private final DynamicRegion region;
|
||||
|
||||
private void resetTiles(Set<Tile> tiles) {
|
||||
entityServer.getEntitiesByType(CTile.class)
|
||||
.stream()
|
||||
.filter(cTile -> tiles.contains(cTile.tile))
|
||||
.peek(CTile::die)
|
||||
.map(cTile -> cTile.tile)
|
||||
.forEach(tile -> {
|
||||
new CTile(entityServer, tile);
|
||||
});
|
||||
|
||||
if (placement != null) {
|
||||
placement.check();
|
||||
}
|
||||
}
|
||||
|
||||
private class CTile extends CEntity {
|
||||
|
||||
private final Tile tile;
|
||||
|
||||
public CTile(REntityServer server, Tile tile) {
|
||||
private CRegion(REntityServer server, DynamicRegion region) {
|
||||
super(server);
|
||||
this.tile = tile;
|
||||
this.region = region;
|
||||
|
||||
RegionType regionType = DynamicRegionSystem.INSTANCE.get(tile).getType();
|
||||
Material material = switch (regionType) {
|
||||
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 origin = new CCubedTextDisplay(entityServer, location);
|
||||
origin.setText("§eORIGIN");
|
||||
origin.setBackgroundColor(0);
|
||||
origin.setShadowed(false);
|
||||
entities.add(origin);
|
||||
RegionConstructorData data = DynamicRegionSystem.constructorDataMap.get(region.getClass());
|
||||
int widthX = data.widthX();
|
||||
int widthZ = data.widthZ();
|
||||
|
||||
Point point = toVisualization(region.getArea().getMinPoint(false).toLocation((World) null));
|
||||
|
||||
if (widthX != 1 || widthZ != 1) {
|
||||
CArea area = new CArea(server);
|
||||
area.setBlock(Material.WHITE_CONCRETE.createBlockData());
|
||||
area.setPos1And2(point.toLocation((World) null).add(0, 1 - CArea.DEFAULT_WIDTH, 0), point.toLocation((World) null).add(widthX - 1, 1 - CArea.DEFAULT_WIDTH, widthZ - 1));
|
||||
entities.add(area);
|
||||
|
||||
RTextDisplay text = new RTextDisplay(server, point.toLocation((World) null).add(widthX / 2.0, 1.1, widthZ / 2.0));
|
||||
text.setText(data.name());
|
||||
text.setBillboard(Display.Billboard.VERTICAL);
|
||||
text.setBackgroundColor(0);
|
||||
text.setShadowed(false);
|
||||
text.setTransform(new Transformation(new Vector3f(0, 0, 0), new Quaternionf().rotationX((float) Math.toRadians(270)), new Vector3f(1, 1, 1), new Quaternionf()));
|
||||
entities.add(text);
|
||||
}
|
||||
|
||||
RBlockDisplay blockDisplay = new RBlockDisplay(entityServer, location);
|
||||
blockDisplay.setBlock(material.createBlockData());
|
||||
entities.add(blockDisplay);
|
||||
|
||||
RInteraction interaction = new RInteraction(entityServer, location.clone().add(0.5, 0, 0.5));
|
||||
interaction.setInteraction((player, entityAction) -> {
|
||||
if (placement != null) {
|
||||
placement.click(tile, regionType.isGlobal());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!regionType.isGlobal()) {
|
||||
SWInventory inv = new SWInventory(player, 9, "Delete Region: " + tile.display());
|
||||
inv.setItem(0, new SWItem(SWItem.getDye(10), "§8Cancel", click -> {
|
||||
player.closeInventory();
|
||||
}));
|
||||
inv.setItem(8, new SWItem(SWItem.getDye(1), "§cDelete", click -> {
|
||||
player.closeInventory();
|
||||
Region region = DynamicRegionSystem.INSTANCE.get(tile);
|
||||
Set<Tile> tiles = DynamicRegionSystem.INSTANCE.getTilesOfRegion(region);
|
||||
region.delete();
|
||||
|
||||
SWPlayer.allWithSingleComponent(DynamicRegionVisualizer.class)
|
||||
.forEach(pair -> {
|
||||
pair.getComponent().resetTiles(tiles);
|
||||
});
|
||||
}));
|
||||
inv.open();
|
||||
} else {
|
||||
List<SWListInv.SWListEntry<Map.Entry<Class<? extends DynamicRegion>, RegionConstructorData>>> entries = new ArrayList<>();
|
||||
DynamicRegionSystem.constructorDataMap.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> entry.getValue().placeable())
|
||||
.sorted(Comparator.comparing(entry -> entry.getValue().name()))
|
||||
.forEach(entry -> {
|
||||
entries.add(new SWListInv.SWListEntry<>(new SWItem(entry.getValue().material(), entry.getValue().name()), entry));
|
||||
});
|
||||
|
||||
SWListInv<Map.Entry<Class<? extends DynamicRegion>, RegionConstructorData>> listInv = new SWListInv<>(player, "Select Region for: " + tile.display(), entries, (click, entry) -> {
|
||||
new Placement(entry.getKey(), entry.getValue(), tile);
|
||||
player.closeInventory();
|
||||
});
|
||||
listInv.open();
|
||||
}
|
||||
});
|
||||
entities.add(interaction);
|
||||
}
|
||||
}
|
||||
|
||||
private class Placement {
|
||||
private final Class<? extends DynamicRegion> regionType;
|
||||
private final RegionConstructorData constructorData;
|
||||
|
||||
private CWireframe wireframe;
|
||||
private Tile sourceTile;
|
||||
private int dx;
|
||||
private int dz;
|
||||
private boolean valid = false;
|
||||
|
||||
private Location getMinLocation() {
|
||||
Tile tile = sourceTile.add(-DynamicRegionVisualizer.this.sourceTile.getTileX(), -DynamicRegionVisualizer.this.sourceTile.getTileZ()).orElse(null);
|
||||
if (tile == null) tile = Tile.ZERO;
|
||||
return sourceLocation.clone().add(tile.getTileX(), 0, tile.getTileZ());
|
||||
}
|
||||
|
||||
private Location getMaxLocation() {
|
||||
Tile tile = sourceTile.add(-DynamicRegionVisualizer.this.sourceTile.getTileX(), -DynamicRegionVisualizer.this.sourceTile.getTileZ()).orElse(null);
|
||||
if (tile == null) tile = Tile.ZERO;
|
||||
return sourceLocation.clone().add(tile.getTileX(), 0, tile.getTileZ()).add(dx, 0, dz);
|
||||
}
|
||||
|
||||
public Placement(Class<? extends DynamicRegion> regionType, RegionConstructorData constructorData, Tile sourceTile) {
|
||||
this.regionType = regionType;
|
||||
this.constructorData = constructorData;
|
||||
this.sourceTile = sourceTile;
|
||||
dx = constructorData.widthX() / Tile.tileSize - 1;
|
||||
dz = constructorData.widthZ() / Tile.tileSize - 1;
|
||||
if (dx == 0 && dz == 0) {
|
||||
place();
|
||||
return;
|
||||
}
|
||||
|
||||
placement = this;
|
||||
wireframe = new CWireframe(entityServer);
|
||||
check();
|
||||
}
|
||||
|
||||
private void check() {
|
||||
wireframe.setPos1And2(getMinLocation(), getMaxLocation());
|
||||
for (int x = 0; x <= dx; x++) {
|
||||
for (int z = 0; z <= dz; z++) {
|
||||
Tile tile = sourceTile.add(x, z).orElse(null);
|
||||
if (tile == null || !DynamicRegionSystem.INSTANCE.get(tile).getType().isGlobal()) {
|
||||
wireframe.setBlock(Material.RED_CONCRETE.createBlockData());
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
wireframe.setBlock(Material.LIME_CONCRETE.createBlockData());
|
||||
valid = true;
|
||||
}
|
||||
|
||||
public void click(Tile tile, boolean global) {
|
||||
if (tile.getTileX() >= sourceTile.getTileX() && tile.getTileX() <= sourceTile.getTileX() + dx && tile.getTileZ() >= sourceTile.getTileZ() && tile.getTileZ() <= sourceTile.getTileZ() + dz) {
|
||||
SWInventory inv = new SWInventory(player, 9, "Place Region: " + constructorData.name());
|
||||
inv.setItem(0, new SWItem(SWItem.getDye(1), "§cDeselect", click -> {
|
||||
placement = null;
|
||||
wireframe.die();
|
||||
player.closeInventory();
|
||||
}));
|
||||
if (valid) {
|
||||
inv.setItem(8, new SWItem(SWItem.getDye(10), "§aPlace", click -> {
|
||||
player.closeInventory();
|
||||
place();
|
||||
}));
|
||||
} else {
|
||||
inv.setItem(8, new SWItem(SWItem.getDye(8), "§8Place", click -> {
|
||||
}));
|
||||
}
|
||||
inv.open();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!global) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<Tile> tiles = new HashSet<>();
|
||||
for (int x = 0; x <= dx; x++) {
|
||||
for (int z = 0; z <= dz; z++) {
|
||||
tiles.add(Tile.fromTile(x + sourceTile.getTileX(), z + sourceTile.getTileZ()).orElse(null));
|
||||
}
|
||||
}
|
||||
tiles.remove(null);
|
||||
Tile selected = tiles.stream().min(Comparator.comparing(current -> {
|
||||
int dx = current.getTileX() - tile.getTileX();
|
||||
int dz = current.getTileZ() - tile.getTileZ();
|
||||
return dx * dx + dz * dz;
|
||||
}))
|
||||
.orElse(null);
|
||||
if (selected == null) return;
|
||||
|
||||
int dx = tile.getTileX() - selected.getTileX();
|
||||
int dz = tile.getTileZ() - selected.getTileZ();
|
||||
Tile newSourceTile = sourceTile.add(dx, dz).orElse(null);
|
||||
if (newSourceTile == null) return;
|
||||
sourceTile = newSourceTile;
|
||||
check();
|
||||
}
|
||||
|
||||
private void place() {
|
||||
DynamicRegion dynamicRegion = DynamicRegionRepository.constructRegion(regionType, sourceTile);
|
||||
if (dynamicRegion == null) {
|
||||
// TODO: Give error to user
|
||||
return;
|
||||
}
|
||||
|
||||
dynamicRegion.getArea().place(new PasteBuilder(), false);
|
||||
dynamicRegion.updateNeighbours();
|
||||
|
||||
placement = null;
|
||||
if (wireframe != null) wireframe.die();
|
||||
Set<Tile> tiles = new HashSet<>();
|
||||
for (int x = 0; x <= dx; x++) {
|
||||
for (int z = 0; z <= dz; z++) {
|
||||
tiles.add(Tile.fromTile(x + sourceTile.getTileX(), z + sourceTile.getTileZ()).orElse(null));
|
||||
}
|
||||
}
|
||||
tiles.remove(null);
|
||||
SWPlayer.allWithSingleComponent(DynamicRegionVisualizer.class)
|
||||
.forEach(pair -> pair.getComponent().resetTiles(tiles));
|
||||
RBlockDisplay display = new RBlockDisplay(server, point.toLocation((World) null));
|
||||
display.setTransform(new Transformation(VEC_ZERO, QUT_ZERO, new Vector3f(widthX, 1, widthZ), QUT_ZERO));
|
||||
display.setBlock(data.material().createBlockData());
|
||||
entities.add(display);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,11 +33,9 @@ import java.util.stream.Stream;
|
||||
@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 = 255;
|
||||
public static final int maxTile = 127;
|
||||
public static final int minTile = -maxTile;
|
||||
public static final int tilesPerAxis = maxTile * 2 + 1;
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import de.steamwar.bausystem.utils.PasteBuilder;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
import org.bukkit.Location;
|
||||
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class AreaBlock implements Region.Area {
|
||||
|
||||
@@ -40,9 +40,9 @@ import java.util.UUID;
|
||||
@RegionConstructorData(
|
||||
identifier = "microwargear_display_7",
|
||||
name = "MicroWarGearDisplay",
|
||||
material = Material.STONE_BUTTON,
|
||||
widthX = MiWG7DisplayRegion.TILE_X * Tile.tileSize,
|
||||
widthZ = MiWG7DisplayRegion.TILE_Z * Tile.tileSize
|
||||
material = Material.GRAY_CONCRETE,
|
||||
widthX = MiWG7DisplayRegion.TILE_X,
|
||||
widthZ = MiWG7DisplayRegion.TILE_Z
|
||||
)
|
||||
public class MiWG7DisplayRegion extends DynamicRegion {
|
||||
|
||||
|
||||
@@ -41,9 +41,9 @@ import java.util.UUID;
|
||||
@RegionConstructorData(
|
||||
identifier = "microwargear_plot_7",
|
||||
name = "MicroWarGearPlot",
|
||||
material = Material.STONE_BUTTON,
|
||||
widthX = Tile.tileSize * MiWG7PlotRegion.TILE_X,
|
||||
widthZ = Tile.tileSize * MiWG7PlotRegion.TILE_Z
|
||||
material = Material.GRAY_CONCRETE,
|
||||
widthX = MiWG7PlotRegion.TILE_X,
|
||||
widthZ = MiWG7PlotRegion.TILE_Z
|
||||
)
|
||||
public class MiWG7PlotRegion extends DynamicRegion {
|
||||
|
||||
|
||||
@@ -40,9 +40,9 @@ import java.util.UUID;
|
||||
@RegionConstructorData(
|
||||
identifier = "miniwargear_display",
|
||||
name = "MiniWarGearDisplay",
|
||||
material = Material.END_STONE_BRICK_SLAB,
|
||||
widthX = MWGDisplayRegion.TILE_X * Tile.tileSize,
|
||||
widthZ = MWGDisplayRegion.TILE_Z * Tile.tileSize
|
||||
material = Material.YELLOW_CONCRETE,
|
||||
widthX = MWGDisplayRegion.TILE_X,
|
||||
widthZ = MWGDisplayRegion.TILE_Z
|
||||
)
|
||||
public class MWGDisplayRegion extends DynamicRegion {
|
||||
|
||||
|
||||
@@ -41,9 +41,9 @@ import java.util.UUID;
|
||||
@RegionConstructorData(
|
||||
identifier = "miniwargear_plot",
|
||||
name = "MiniWarGearPlot",
|
||||
material = Material.END_STONE_BRICK_SLAB,
|
||||
widthX = Tile.tileSize * MWGPlotRegion.TILE_X,
|
||||
widthZ = Tile.tileSize * MWGPlotRegion.TILE_Z
|
||||
material = Material.YELLOW_CONCRETE,
|
||||
widthX = MWGPlotRegion.TILE_X,
|
||||
widthZ = MWGPlotRegion.TILE_Z
|
||||
)
|
||||
public class MWGPlotRegion extends DynamicRegion {
|
||||
|
||||
|
||||
@@ -40,9 +40,9 @@ import java.util.UUID;
|
||||
@RegionConstructorData(
|
||||
identifier = "wargear_display_45",
|
||||
name = "WarGearDisplay 45",
|
||||
material = Material.END_STONE_BRICKS,
|
||||
widthX = WG45DisplayRegion.TILE_X * Tile.tileSize,
|
||||
widthZ = WG45DisplayRegion.TILE_Z * Tile.tileSize
|
||||
material = Material.YELLOW_CONCRETE,
|
||||
widthX = WG45DisplayRegion.TILE_X,
|
||||
widthZ = WG45DisplayRegion.TILE_Z
|
||||
)
|
||||
public class WG45DisplayRegion extends DynamicRegion {
|
||||
|
||||
|
||||
@@ -41,9 +41,9 @@ import java.util.UUID;
|
||||
@RegionConstructorData(
|
||||
identifier = "wargear_plot_45",
|
||||
name = "WarGearPlot 45",
|
||||
material = Material.END_STONE_BRICKS,
|
||||
widthX = Tile.tileSize * WG45PlotRegion.TILE_X,
|
||||
widthZ = Tile.tileSize * WG45PlotRegion.TILE_Z
|
||||
material = Material.YELLOW_CONCRETE,
|
||||
widthX = WG45PlotRegion.TILE_X,
|
||||
widthZ = WG45PlotRegion.TILE_Z
|
||||
)
|
||||
public class WG45PlotRegion extends DynamicRegion {
|
||||
|
||||
|
||||
@@ -40,9 +40,9 @@ import java.util.UUID;
|
||||
@RegionConstructorData(
|
||||
identifier = "warship_display_175",
|
||||
name = "WarShipDisplay 175",
|
||||
material = Material.BIRCH_BOAT,
|
||||
widthX = WS175DisplayRegion.TILE_X * Tile.tileSize,
|
||||
widthZ = WS175DisplayRegion.TILE_Z * Tile.tileSize
|
||||
material = Material.BLUE_CONCRETE,
|
||||
widthX = WS175DisplayRegion.TILE_X,
|
||||
widthZ = WS175DisplayRegion.TILE_Z
|
||||
)
|
||||
public class WS175DisplayRegion extends DynamicRegion {
|
||||
|
||||
|
||||
@@ -41,9 +41,9 @@ import java.util.UUID;
|
||||
@RegionConstructorData(
|
||||
identifier = "warship_plot_175",
|
||||
name = "WarShipPlot 175",
|
||||
material = Material.BIRCH_BOAT,
|
||||
widthX = Tile.tileSize * WS175PlotRegion.TILE_X,
|
||||
widthZ = Tile.tileSize * WS175PlotRegion.TILE_Z
|
||||
material = Material.BLUE_CONCRETE,
|
||||
widthX = WS175PlotRegion.TILE_X,
|
||||
widthZ = WS175PlotRegion.TILE_Z
|
||||
)
|
||||
public class WS175PlotRegion extends DynamicRegion {
|
||||
|
||||
|
||||
@@ -40,9 +40,9 @@ import java.util.UUID;
|
||||
@RegionConstructorData(
|
||||
identifier = "warship_display_230",
|
||||
name = "WarShipDisplay 230",
|
||||
material = Material.BIRCH_BOAT,
|
||||
widthX = WS230DisplayRegion.TILE_X * Tile.tileSize,
|
||||
widthZ = WS230DisplayRegion.TILE_Z * Tile.tileSize
|
||||
material = Material.BLUE_CONCRETE,
|
||||
widthX = WS230DisplayRegion.TILE_X,
|
||||
widthZ = WS230DisplayRegion.TILE_Z
|
||||
)
|
||||
public class WS230DisplayRegion extends DynamicRegion {
|
||||
|
||||
|
||||
@@ -41,9 +41,9 @@ import java.util.UUID;
|
||||
@RegionConstructorData(
|
||||
identifier = "warship_plot_230",
|
||||
name = "WarShipPlot 230",
|
||||
material = Material.BIRCH_BOAT,
|
||||
widthX = Tile.tileSize * WS230PlotRegion.TILE_X,
|
||||
widthZ = Tile.tileSize * WS230PlotRegion.TILE_Z
|
||||
material = Material.BLUE_CONCRETE,
|
||||
widthX = WS230PlotRegion.TILE_X,
|
||||
widthZ = WS230PlotRegion.TILE_Z
|
||||
)
|
||||
public class WS230PlotRegion extends DynamicRegion {
|
||||
|
||||
|
||||
@@ -37,11 +37,14 @@ import java.util.stream.Collectors;
|
||||
identifier = "path",
|
||||
name = "Path",
|
||||
material = Material.DIRT_PATH,
|
||||
widthX = Tile.tileSize,
|
||||
widthZ = Tile.tileSize
|
||||
widthX = PathRegion.TILE_X,
|
||||
widthZ = PathRegion.TILE_Z
|
||||
)
|
||||
public class PathRegion extends DynamicRegion {
|
||||
|
||||
protected static final int TILE_X = 1;
|
||||
protected static final int TILE_Z = 1;
|
||||
|
||||
private final PathArea area;
|
||||
@Getter
|
||||
private final Tile tile;
|
||||
|
||||
@@ -31,12 +31,9 @@ import de.steamwar.bausystem.utils.PasteBuilder;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class SpecialArea implements Region.Area {
|
||||
|
||||
@@ -26,8 +26,6 @@ import de.steamwar.bausystem.region.RegionData;
|
||||
import de.steamwar.bausystem.region.RegionHistory;
|
||||
import de.steamwar.bausystem.region.RegionType;
|
||||
import de.steamwar.bausystem.region.dynamic.*;
|
||||
import de.steamwar.bausystem.region.dynamic.modes.AreaTile;
|
||||
import de.steamwar.bausystem.region.dynamic.modes.DisplayRegionData;
|
||||
import de.steamwar.bausystem.region.dynamic.special.SpecialArea;
|
||||
import de.steamwar.bausystem.region.dynamic.special.SpecialRegionData;
|
||||
import de.steamwar.sql.GameModeConfig;
|
||||
@@ -43,12 +41,15 @@ import static de.steamwar.bausystem.region.dynamic.special.SpecialArea.SPECIAL_P
|
||||
@RegionConstructorData(
|
||||
identifier = "special_dry",
|
||||
name = "Dry",
|
||||
material = Material.SAND,
|
||||
widthX = Tile.tileSize,
|
||||
widthZ = Tile.tileSize
|
||||
material = Material.IRON_BLOCK,
|
||||
widthX = DryRegion.TILE_X,
|
||||
widthZ = DryRegion.TILE_Z
|
||||
)
|
||||
public class DryRegion extends DynamicRegion {
|
||||
|
||||
protected static final int TILE_X = 1;
|
||||
protected static final int TILE_Z = 1;
|
||||
|
||||
private static final VariantSelector DRY = VariantSelector.Get(new File(SPECIAL_PATH_DIR, "dry"));
|
||||
|
||||
private final SpecialArea area;
|
||||
|
||||
@@ -27,7 +27,6 @@ import de.steamwar.bausystem.region.RegionHistory;
|
||||
import de.steamwar.bausystem.region.RegionType;
|
||||
import de.steamwar.bausystem.region.dynamic.*;
|
||||
import de.steamwar.bausystem.region.dynamic.special.SpecialArea;
|
||||
import de.steamwar.bausystem.region.dynamic.special.SpecialRegionData;
|
||||
import de.steamwar.sql.GameModeConfig;
|
||||
import lombok.NonNull;
|
||||
import org.bukkit.Material;
|
||||
@@ -41,12 +40,15 @@ import static de.steamwar.bausystem.region.dynamic.special.SpecialArea.SPECIAL_P
|
||||
@RegionConstructorData(
|
||||
identifier = "special_wet",
|
||||
name = "Wet",
|
||||
material = Material.LIGHT_BLUE_CONCRETE_POWDER,
|
||||
widthX = Tile.tileSize,
|
||||
widthZ = Tile.tileSize
|
||||
material = Material.LAPIS_BLOCK,
|
||||
widthX = WetRegion.TILE_X,
|
||||
widthZ = WetRegion.TILE_Z
|
||||
)
|
||||
public class WetRegion extends DynamicRegion {
|
||||
|
||||
protected static final int TILE_X = 1;
|
||||
protected static final int TILE_Z = 1;
|
||||
|
||||
private static final VariantSelector WET = VariantSelector.Get(new File(SPECIAL_PATH_DIR, "wet"));
|
||||
|
||||
private final SpecialArea area;
|
||||
|
||||
83
SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CArea.java
Normal file
83
SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CArea.java
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.entity;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CArea extends CEntity {
|
||||
|
||||
public static final float DEFAULT_WIDTH = 1 / 16f;
|
||||
|
||||
private Location pos1;
|
||||
private Location pos2;
|
||||
private float width = DEFAULT_WIDTH;
|
||||
|
||||
public CArea(REntityServer server) {
|
||||
super(server);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
entities.add(new CLine(server));
|
||||
}
|
||||
}
|
||||
|
||||
public CArea setPos1And2(Location pos1, Location pos2) {
|
||||
if (pos1.getY() != pos2.getY()) return this;
|
||||
this.pos1 = pos1;
|
||||
this.pos2 = pos2;
|
||||
updateAndSpawnLines();
|
||||
return this;
|
||||
}
|
||||
|
||||
public CArea setWidth(float width) {
|
||||
this.width = width;
|
||||
updateAndSpawnLines();
|
||||
getEntitiesByType(CLine.class).forEach(haaLine -> {
|
||||
haaLine.setWidth(width);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public CArea setBlock(BlockData blockData) {
|
||||
getEntitiesByType(CLine.class).forEach(haaLine -> {
|
||||
haaLine.setBlock(blockData);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
private void updateAndSpawnLines() {
|
||||
List<CLine> lines = getEntitiesByType(CLine.class);
|
||||
if (pos1 == null || pos2 == null) {
|
||||
lines.forEach(line -> line.setFromAndTo(null, null));
|
||||
return;
|
||||
}
|
||||
|
||||
Vector min = Vector.getMinimum(pos1.toVector(), pos2.toVector());
|
||||
Vector max = Vector.getMaximum(pos1.toVector(), pos2.toVector())
|
||||
.add(new Vector(1 - width, 0, 1 - width));
|
||||
|
||||
lines.get(0).setFromAndTo(new Location(null, min.getX(), min.getY(), min.getZ()), new Location(null, max.getX() + width, min.getY(), min.getZ()));
|
||||
lines.get(1).setFromAndTo(new Location(null, min.getX(), min.getY(), max.getZ()), new Location(null, max.getX() + width, min.getY(), max.getZ()));
|
||||
lines.get(2).setFromAndTo(new Location(null, min.getX(), min.getY(), min.getZ()), new Location(null, min.getX(), min.getY(), max.getZ() + width));
|
||||
lines.get(3).setFromAndTo(new Location(null, max.getX(), min.getY(), min.getZ()), new Location(null, max.getX(), min.getY(), max.getZ() + width));
|
||||
}
|
||||
}
|
||||
@@ -72,9 +72,6 @@ public class REntityServer implements Listener {
|
||||
private EntityActionListener callback = null;
|
||||
private final Set<Player> playersThatClicked = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
private static final String DE_STEAMWAR_ENTITY_RINTERACTION = "de.steamwar.entity.RInteraction";
|
||||
private Reflection.Field<BiConsumer> interactionField = Reflection.getField(DE_STEAMWAR_ENTITY_RINTERACTION, "interaction", BiConsumer.class);
|
||||
|
||||
private final BiFunction<Player, Object, Object> filter = (player, packet) -> {
|
||||
REntity entity = entityMap.get(useEntityTarget.get(packet));
|
||||
if (entity == null)
|
||||
@@ -87,8 +84,11 @@ public class REntityServer implements Listener {
|
||||
EntityAction action = getEntityAction.apply(useEntityAction.get(packet)) == 1 ? EntityAction.ATTACK : EntityAction.INTERACT;
|
||||
Bukkit.getScheduler().runTask(Core.getInstance(), () -> {
|
||||
playersThatClicked.remove(player);
|
||||
if (entity.getClass().getTypeName().equals(DE_STEAMWAR_ENTITY_RINTERACTION)) {
|
||||
interactionField.get(entity).accept(player, action);
|
||||
if (Core.getVersion() >= 20 && entity instanceof de.steamwar.entity.RInteraction) {
|
||||
de.steamwar.entity.RInteraction interaction = (de.steamwar.entity.RInteraction) entity;
|
||||
if (interaction.callback != null) {
|
||||
interaction.callback.call(player, interaction, action);
|
||||
}
|
||||
}
|
||||
callback.onAction(player, entity, action);
|
||||
});
|
||||
@@ -135,7 +135,7 @@ public class REntityServer implements Listener {
|
||||
}
|
||||
|
||||
void addEntity(REntity entity) {
|
||||
if (callback == null && entity.getClass().getTypeName().equals(DE_STEAMWAR_ENTITY_RINTERACTION)) {
|
||||
if (callback == null && Core.getVersion() >= 20 && entity instanceof de.steamwar.entity.RInteraction) {
|
||||
setCallback((player, entity1, action) -> {});
|
||||
}
|
||||
entityMap.put(entity.entityId, entity);
|
||||
|
||||
@@ -22,7 +22,6 @@ package de.steamwar.entity;
|
||||
import de.steamwar.core.BountifulWrapper;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -40,9 +39,8 @@ public class RInteraction extends REntity {
|
||||
|
||||
protected final Consumer<Object> updatePacketSink = o -> server.updateEntity(this, o);
|
||||
|
||||
@Setter
|
||||
@Getter(AccessLevel.PRIVATE)
|
||||
protected BiConsumer<Player, REntityServer.EntityAction> interaction;
|
||||
protected RInteractionCallback callback;
|
||||
|
||||
private float interactionWidth = 1.0f;
|
||||
private float interactionHeight = 1.0f;
|
||||
@@ -116,4 +114,12 @@ public class RInteraction extends REntity {
|
||||
dataSink.accept(responsiveWatcher, responsive);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCallback(RInteractionCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public void setCallback(BiConsumer<Player, REntityServer.EntityAction> callback) {
|
||||
this.callback = (player, interaction, entityAction) -> callback.accept(player, entityAction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.entity;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public interface RInteractionCallback {
|
||||
void call(Player player, RInteraction interaction, REntityServer.EntityAction entityAction);
|
||||
}
|
||||
Reference in New Issue
Block a user