Commits vergleichen
1 Commits
Autor | SHA1 | Datum | |
---|---|---|---|
|
408cb21db0 |
@ -0,0 +1,310 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.hullhider;
|
||||
|
||||
import de.steamwar.bausystem.region.Point;
|
||||
import de.steamwar.bausystem.region.Region;
|
||||
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;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.type.Slab;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class HullCalc {
|
||||
|
||||
|
||||
|
||||
private static final World WORLD = Bukkit.getWorlds().get(0);
|
||||
|
||||
private static final int[] c1 = new int[]{1, -1, 0, 0};
|
||||
private static final int[] c2 = new int[]{0, 0, 1, -1};
|
||||
|
||||
private int minX, minY, minZ, maxX, maxY, maxZ;
|
||||
private REntityServer entityServer = new REntityServer();
|
||||
|
||||
private Set<Point> nonTechHideBlock = new HashSet<>();
|
||||
private Set<Point> hullBlocks = new HashSet<>();
|
||||
|
||||
public HullCalc(Region region) {
|
||||
this.minX = region.getMinPointBuild().getX();
|
||||
this.minY = region.getMinPointBuild().getY();
|
||||
this.minZ = region.getMinPointBuild().getZ();
|
||||
this.maxX = region.getMaxPointBuild().getX();
|
||||
this.maxY = region.getMaxPointBuild().getY();
|
||||
this.maxZ = region.getMaxPointBuild().getZ();
|
||||
}
|
||||
|
||||
public void calc() {
|
||||
entityServer.getEntities().forEach(REntity::die);
|
||||
long time = System.currentTimeMillis();
|
||||
hullBlocks.clear();
|
||||
|
||||
calc(minX, minY, minZ, maxX, maxY, minZ, 0, 0, 1, maxZ - minZ);
|
||||
calc(minX, minY, maxZ, maxX, maxY, maxZ, 0, 0, -1, maxZ - minZ);
|
||||
calc(minX, minY, minZ, minX, maxY, maxZ, 1, 0, 0, maxX - minX);
|
||||
calc(maxX, minY, minZ, maxX, maxY, maxZ, -1, 0, 0, maxX - minX);
|
||||
calc(minX, minY, minZ, maxX, minY, maxZ, 0, 1, 0, maxY - minY);
|
||||
calc(minX, maxY, minZ, maxX, maxY, maxZ, 0, -1, 0, maxY - minY);
|
||||
|
||||
hullBlocks.removeIf(point -> {
|
||||
return point.getX() < minX || point.getX() > maxX || point.getY() < minY || point.getY() > maxY || point.getZ() < minZ || point.getZ() > maxZ;
|
||||
});
|
||||
nonTechHideBlock.addAll(hullBlocks);
|
||||
|
||||
System.out.println(System.currentTimeMillis() - time + "ms " + hullBlocks.size());
|
||||
|
||||
hullBlocks.forEach(point -> {
|
||||
RFallingBlockEntity rFallingBlockEntity = new RFallingBlockEntity(entityServer, point.toLocation(WORLD).add(0.5, 0, 0.5), Material.WHITE_STAINED_GLASS);
|
||||
rFallingBlockEntity.setNoGravity(true);
|
||||
});
|
||||
}
|
||||
|
||||
private void calc(int minX, int minY, int minZ, int maxX, int maxY, int maxZ, int dirX, int dirY, int dirZ, int steps) {
|
||||
boolean sideWays = dirY == 0;
|
||||
Set<Point> points = new HashSet<>();
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
points.add(new Point(dirX == 0 ? x : minX - dirX, dirY == 0 ? y : minY - dirY, dirZ == 0 ? z : minZ - dirZ));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i <= steps; i++) {
|
||||
Set<Point> nextLayer = new HashSet<>();
|
||||
|
||||
for (Point point : points) {
|
||||
Point next = point.add(dirX, dirY, dirZ);
|
||||
if (!empty(next, sideWays)) {
|
||||
hullBlocks.add(next);
|
||||
|
||||
if (dirX != 0) {
|
||||
for (int c = 0; c < 4; c++) {
|
||||
if (empty(point.add(0, c1[c], c2[c]), sideWays) && empty(point.add(dirX, c1[c], c2[c]), sideWays)) {
|
||||
nextLayer.add(point.add(dirX, c1[c], c2[c]));
|
||||
}
|
||||
}
|
||||
} else if (dirY != 0) {
|
||||
for (int c = 0; c < 4; c++) {
|
||||
if (empty(point.add(c1[c], 0, c2[c]), sideWays) && empty(point.add(c1[c], dirY, c2[c]), sideWays)) {
|
||||
nextLayer.add(point.add(c1[c], dirY, c2[c]));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int c = 0; c < 4; c++) {
|
||||
if (empty(point.add(c1[c], c2[c], 0), sideWays) && empty(point.add(c1[c], c2[c], dirZ), sideWays)) {
|
||||
nextLayer.add(point.add(c1[c], c2[c], dirZ));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nextLayer.add(next);
|
||||
nonTechHideBlock.add(next);
|
||||
|
||||
if (dirX != 0) {
|
||||
for (int c = 0; c < 4; c++) {
|
||||
if (!empty(point.add(0, c1[c], c2[c]), sideWays)) {
|
||||
hullBlocks.add(point.add(0, c1[c], c2[c]));
|
||||
}
|
||||
if (empty(point.add(dirX, c1[c], c2[c]), sideWays)) {
|
||||
nextLayer.add(point.add(dirX, c1[c], c2[c]));
|
||||
} else {
|
||||
hullBlocks.add(point.add(dirX, c1[c], c2[c]));
|
||||
}
|
||||
}
|
||||
} else if (dirY != 0) {
|
||||
for (int c = 0; c < 4; c++) {
|
||||
if (!empty(point.add(c1[c], 0, c2[c]), sideWays)) {
|
||||
hullBlocks.add(point.add(c1[c], 0, c2[c]));
|
||||
}
|
||||
if (empty(point.add(c1[c], dirY, c2[c]), sideWays)) {
|
||||
nextLayer.add(point.add(c1[c], dirY, c2[c]));
|
||||
} else {
|
||||
hullBlocks.add(point.add(c1[c], dirY, c2[c]));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int c = 0; c < 4; c++) {
|
||||
if (!empty(point.add(c1[c], c2[c], 0), sideWays)) {
|
||||
hullBlocks.add(point.add(c1[c], c2[c], 0));
|
||||
}
|
||||
if (empty(point.add(c1[c], c2[c], dirZ), sideWays)) {
|
||||
nextLayer.add(point.add(c1[c], c2[c], dirZ));
|
||||
} else {
|
||||
hullBlocks.add(point.add(c1[c], c2[c], dirZ));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
points.clear();
|
||||
for (Point point : nextLayer) {
|
||||
if (point.getX() < this.minX || point.getX() > this.maxX) {
|
||||
continue;
|
||||
}
|
||||
if (point.getY() < this.minY || point.getY() > this.maxY) {
|
||||
continue;
|
||||
}
|
||||
if (point.getZ() < this.minZ || point.getZ() > this.maxZ) {
|
||||
continue;
|
||||
}
|
||||
points.add(point);
|
||||
}
|
||||
if (points.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean empty(Point point, boolean side) {
|
||||
Block block = point.toLocation(WORLD).getBlock();
|
||||
if (block.getBlockData() instanceof Slab slab && slab.getType() == Slab.Type.DOUBLE) {
|
||||
return false;
|
||||
}
|
||||
Material material = block.getType();
|
||||
if (material.isAir()) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.WATER) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.SCAFFOLDING) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.LADDER) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.COBWEB) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.IRON_BARS) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.PLAYER_HEAD || material == Material.PLAYER_WALL_HEAD) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.END_ROD) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.CHAIN) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.LANTERN) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.LIGHTNING_ROD) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.SOUL_LANTERN) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.VINE) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.SCULK_VEIN) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.LEVER) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.END_STONE_BRICK_WALL) {
|
||||
return false;
|
||||
}
|
||||
if (material == Material.END_STONE_BRICK_SLAB) {
|
||||
return false;
|
||||
}
|
||||
if (material == Material.END_STONE_BRICK_STAIRS) {
|
||||
return false;
|
||||
}
|
||||
String name = material.name();
|
||||
if (name.contains("GLASS")) {
|
||||
return true;
|
||||
}
|
||||
if (name.contains("BANNER")) {
|
||||
return true;
|
||||
}
|
||||
if (side && name.contains("CARPET")) {
|
||||
return true;
|
||||
}
|
||||
if (name.contains("DOOR")) {
|
||||
return true;
|
||||
}
|
||||
if (name.contains("SIGN")) {
|
||||
return true;
|
||||
}
|
||||
if (name.contains("FENCE_GATE")) {
|
||||
return true;
|
||||
}
|
||||
if (name.endsWith("_FENCE")) {
|
||||
return true;
|
||||
}
|
||||
if (name.endsWith("_SKULL")) {
|
||||
return true;
|
||||
}
|
||||
if (name.endsWith("_WALL")) {
|
||||
return true;
|
||||
}
|
||||
if (side && name.endsWith("_SLAB")) {
|
||||
return true;
|
||||
}
|
||||
if (name.endsWith("_STAIRS")) {
|
||||
return true;
|
||||
}
|
||||
if (name.endsWith("_CANDLE")) {
|
||||
return true;
|
||||
}
|
||||
if (name.endsWith("_BUTTON")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void show(Player player) {
|
||||
entityServer.addPlayer(player);
|
||||
}
|
||||
|
||||
public void set() {
|
||||
hullBlocks.forEach(point -> {
|
||||
point.toLocation(WORLD).getBlock().setType(Material.END_STONE);
|
||||
});
|
||||
entityServer.getPlayers().forEach(player -> {
|
||||
entityServer.removePlayer(player);
|
||||
});
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
if (nonTechHideBlock.contains(new Point(x, y, z))) {
|
||||
continue;
|
||||
}
|
||||
WORLD.getBlockAt(x, y, z).setType(Material.END_STONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.hullhider;
|
||||
|
||||
import de.steamwar.bausystem.region.Region;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.linkage.Linked;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Linked
|
||||
public class HullCommand extends SWCommand {
|
||||
|
||||
private Map<Region, Hullhider> hullhiderMap = new HashMap<>();
|
||||
|
||||
public HullCommand() {
|
||||
super("hullhider");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void toggle(Player p) {
|
||||
Region region = Region.getRegion(p.getLocation());
|
||||
if (hullhiderMap.containsKey(region)) {
|
||||
Hullhider hullhider = hullhiderMap.get(region);
|
||||
if (hullhider.togglePlayer(p)) {
|
||||
hullhider.close();
|
||||
hullhiderMap.remove(region);
|
||||
}
|
||||
} else {
|
||||
Hullhider hullhider = new Hullhider(region.getMinPointTestblock().getX(), region.getMaxPointTestblock().getX(),
|
||||
region.getMinPointTestblock().getY(), region.getMaxPointTestblock().getY(),
|
||||
region.getMinPointTestblock().getZ(), region.getMaxPointTestblock().getZ());
|
||||
hullhider.init(region.getFloorLevel() == 0);
|
||||
hullhider.togglePlayer(p);
|
||||
hullhiderMap.put(region, hullhider);
|
||||
}
|
||||
}
|
||||
|
||||
@Register("recalc")
|
||||
public void recalc(Player p) {
|
||||
Region region = Region.getRegion(p.getLocation());
|
||||
if (hullhiderMap.containsKey(region)) {
|
||||
Hullhider hullhider = hullhiderMap.get(region);
|
||||
hullhider.close();
|
||||
hullhider.init(region.getFloorLevel() == 0);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.hullhider;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum HullDir {
|
||||
UP(0, 1, 0, false),
|
||||
DOWN(0, -1, 0, false),
|
||||
NORTH(0, 0, -1, true),
|
||||
SOUTH(0, 0, 1, true),
|
||||
EAST(1, 0, 0, true),
|
||||
WEST(-1, 0, 0, true);
|
||||
|
||||
private final int dx;
|
||||
private final int dy;
|
||||
private final int dz;
|
||||
private final boolean sideWays;
|
||||
|
||||
private static final HullDir[] Y = new HullDir[]{NORTH, SOUTH, EAST, WEST};
|
||||
private static final HullDir[] Z = new HullDir[]{UP, DOWN, EAST, WEST};
|
||||
private static final HullDir[] X = new HullDir[]{UP, DOWN, NORTH, SOUTH};
|
||||
|
||||
public HullDir[] getSurrounding() {
|
||||
return switch (this) {
|
||||
case UP, DOWN -> Y;
|
||||
case NORTH, SOUTH -> Z;
|
||||
case EAST, WEST -> X;
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,452 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bausystem.features.hullhider;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.region.Point;
|
||||
import de.steamwar.bausystem.utils.TickEndEvent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Slab;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Hullhider implements Listener {
|
||||
|
||||
// TODO:
|
||||
// - Slab y calc diagonal
|
||||
// - Carpet y calc diagonal upwards only!
|
||||
|
||||
private static final World WORLD = Bukkit.getWorlds().get(0);
|
||||
|
||||
private final int minX;
|
||||
private final int maxX;
|
||||
private final int minY;
|
||||
private final int maxY;
|
||||
private final int minZ;
|
||||
private final int maxZ;
|
||||
|
||||
private final int width;
|
||||
private final int height;
|
||||
private final int depth;
|
||||
|
||||
private final Set<Player> players = new HashSet<>();
|
||||
|
||||
private final BitSet airBlocks;
|
||||
private final BitSet hullDirections;
|
||||
private final BitSet invisible;
|
||||
|
||||
public Hullhider(int minX, int maxX, int minY, int maxY, int minZ, int maxZ) {
|
||||
this.minX = minX;
|
||||
this.maxX = maxX;
|
||||
this.minY = minY;
|
||||
this.maxY = maxY;
|
||||
this.minZ = minZ;
|
||||
this.maxZ = maxZ;
|
||||
|
||||
this.width = maxX - minX + 1;
|
||||
this.height = maxY - minY + 1;
|
||||
this.depth = maxZ - minZ + 1;
|
||||
|
||||
this.airBlocks = new BitSet(width * height * depth);
|
||||
this.invisible = new BitSet(width * height * depth);
|
||||
this.hullDirections = new BitSet(width * height * depth * 6);
|
||||
}
|
||||
|
||||
private int toIndex(int x, int y, int z) {
|
||||
return (x - minX) * height * depth + (y - minY) * depth + (z - minZ);
|
||||
}
|
||||
|
||||
private int toIndex(Point point) {
|
||||
return toIndex(point.getX(), point.getY(), point.getZ());
|
||||
}
|
||||
|
||||
public void init(boolean noFloor) {
|
||||
Bukkit.getPluginManager().registerEvents(this, BauSystem.getInstance());
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
Point p = new Point(x, y, z);
|
||||
invisible.set(toIndex(p));
|
||||
Block block = p.toLocation(WORLD).getBlock();
|
||||
if (block.isEmpty()) {
|
||||
airBlocks.set(toIndex(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long time = System.currentTimeMillis();
|
||||
init(minX, minY, minZ, maxX, maxY, minZ, HullDir.SOUTH);
|
||||
init(minX, minY, maxZ, maxX, maxY, maxZ, HullDir.NORTH);
|
||||
init(minX, minY, minZ, minX, maxY, maxZ, HullDir.EAST);
|
||||
init(maxX, minY, minZ, maxX, maxY, maxZ, HullDir.WEST);
|
||||
if (noFloor) {
|
||||
init(minX, minY, minZ, maxX, minY, maxZ, HullDir.UP);
|
||||
}
|
||||
init(minX, maxY, minZ, maxX, maxY, maxZ, HullDir.DOWN);
|
||||
long timeDiff = System.currentTimeMillis() - time;
|
||||
Bukkit.getOnlinePlayers().forEach(player -> {
|
||||
player.sendMessage("Init took: " + timeDiff + "ms");
|
||||
});
|
||||
|
||||
BlockData endStone = Material.END_STONE.createBlockData();
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
if (invisible.get(toIndex(x, y, z))) {
|
||||
for (Player player : players) {
|
||||
player.sendBlockChange(new Location(WORLD, x, y, z), endStone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void init(int minX, int minY, int minZ, int maxX, int maxY, int maxZ, HullDir dir) {
|
||||
Set<Point> points = new HashSet<>();
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
points.add(new Point(dir.getDx() == 0 ? x : minX - dir.getDx(), dir.getDy() == 0 ? y : minY - dir.getDy(), dir.getDz() == 0 ? z : minZ - dir.getDz()));
|
||||
}
|
||||
}
|
||||
}
|
||||
calc(points, dir);
|
||||
}
|
||||
|
||||
private void calc(Set<Point> points, HullDir dir) {
|
||||
while (true) {
|
||||
Set<Point> nextLayer = new HashSet<>();
|
||||
|
||||
for (Point point : points) {
|
||||
Point next = point.add(dir.getDx(), dir.getDy(), dir.getDz());
|
||||
|
||||
if (next.getX() >= minX && next.getX() <= maxX && next.getY() >= minY && next.getY() <= maxY && next.getZ() >= minZ && next.getZ() <= maxZ) {
|
||||
invisible.clear(toIndex(next));
|
||||
}
|
||||
if (!empty(next, dir)) {
|
||||
if (next.getX() >= minX && next.getX() <= maxX && next.getY() >= minY && next.getY() <= maxY && next.getZ() >= minZ && next.getZ() <= maxZ) {
|
||||
hullDirections.set(toIndex(next) * 6 + dir.ordinal());
|
||||
}
|
||||
|
||||
for (HullDir hullDir : dir.getSurrounding()) {
|
||||
Point p1 = point.add(hullDir.getDx(), hullDir.getDy(), hullDir.getDz());
|
||||
Point p2 = p1.add(dir.getDx(), dir.getDy(), dir.getDz());
|
||||
if (empty(p1, hullDir) && empty(p2, dir)) {
|
||||
nextLayer.add(p2);
|
||||
}
|
||||
if (p1.getX() >= minX && p1.getX() <= maxX && p1.getY() >= minY && p1.getY() <= maxY && p1.getZ() >= minZ && p1.getZ() <= maxZ) {
|
||||
invisible.clear(toIndex(p1));
|
||||
}
|
||||
if (p2.getX() >= minX && p2.getX() <= maxX && p2.getY() >= minY && p2.getY() <= maxY && p2.getZ() >= minZ && p2.getZ() <= maxZ) {
|
||||
invisible.clear(toIndex(p2));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nextLayer.add(next);
|
||||
|
||||
for (HullDir hullDir : dir.getSurrounding()) {
|
||||
Point p1 = point.add(hullDir.getDx(), hullDir.getDy(), hullDir.getDz());
|
||||
Point p2 = p1.add(dir.getDx(), dir.getDy(), dir.getDz());
|
||||
if (empty(p2, dir)) {
|
||||
nextLayer.add(p2);
|
||||
}
|
||||
if (p1.getX() >= minX && p1.getX() <= maxX && p1.getY() >= minY && p1.getY() <= maxY && p1.getZ() >= minZ && p1.getZ() <= maxZ) {
|
||||
invisible.clear(toIndex(p1));
|
||||
}
|
||||
if (p2.getX() >= minX && p2.getX() <= maxX && p2.getY() >= minY && p2.getY() <= maxY && p2.getZ() >= minZ && p2.getZ() <= maxZ) {
|
||||
invisible.clear(toIndex(p2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
points.clear();
|
||||
for (Point point : nextLayer) {
|
||||
if (point.getX() < minX || point.getX() > maxX) {
|
||||
continue;
|
||||
}
|
||||
if (point.getY() < minY || point.getY() > maxY) {
|
||||
continue;
|
||||
}
|
||||
if (point.getZ() < minZ || point.getZ() > maxZ) {
|
||||
continue;
|
||||
}
|
||||
points.add(point);
|
||||
}
|
||||
if (points.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean empty(Point point, HullDir dir) {
|
||||
if (point.getX() >= minX && point.getX() <= maxX && point.getY() >= minY && point.getY() <= maxY && point.getZ() >= minZ && point.getZ() <= maxZ && airBlocks.get(toIndex(point))) {
|
||||
return true;
|
||||
}
|
||||
Block block = point.toLocation(WORLD).getBlock();
|
||||
if (block.getBlockData() instanceof Slab slab && slab.getType() == Slab.Type.DOUBLE) {
|
||||
return false;
|
||||
}
|
||||
Material material = block.getType();
|
||||
if (material.isAir()) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.WATER) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.SCAFFOLDING) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.LADDER) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.COBWEB) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.IRON_BARS) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.PLAYER_HEAD || material == Material.PLAYER_WALL_HEAD) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.END_ROD) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.CHAIN) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.LANTERN) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.LIGHTNING_ROD) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.SOUL_LANTERN) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.VINE) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.SCULK_VEIN) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.LEVER) {
|
||||
return true;
|
||||
}
|
||||
if (material == Material.END_STONE_BRICK_WALL) {
|
||||
return false;
|
||||
}
|
||||
if (material == Material.END_STONE_BRICK_SLAB) {
|
||||
return false;
|
||||
}
|
||||
if (material == Material.END_STONE_BRICK_STAIRS) {
|
||||
return false;
|
||||
}
|
||||
String name = material.name();
|
||||
if (name.contains("GLASS")) {
|
||||
return true;
|
||||
}
|
||||
if (name.contains("BANNER")) {
|
||||
return true;
|
||||
}
|
||||
if (dir.isSideWays() && name.contains("CARPET")) {
|
||||
return true;
|
||||
}
|
||||
if (name.contains("DOOR")) {
|
||||
return true;
|
||||
}
|
||||
if (name.contains("SIGN")) {
|
||||
return true;
|
||||
}
|
||||
if (name.contains("FENCE_GATE")) {
|
||||
return true;
|
||||
}
|
||||
if (name.endsWith("_FENCE")) {
|
||||
return true;
|
||||
}
|
||||
if (name.endsWith("_SKULL")) {
|
||||
return true;
|
||||
}
|
||||
if (name.endsWith("_WALL")) {
|
||||
return true;
|
||||
}
|
||||
if (dir.isSideWays() && name.endsWith("_SLAB")) {
|
||||
return true;
|
||||
}
|
||||
if (name.endsWith("_STAIRS")) {
|
||||
return true;
|
||||
}
|
||||
if (name.endsWith("_CANDLE")) {
|
||||
return true;
|
||||
}
|
||||
if (name.endsWith("_BUTTON")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
HandlerList.unregisterAll(this);
|
||||
airBlocks.clear();
|
||||
invisible.clear();
|
||||
hullDirections.clear();
|
||||
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
Block block = WORLD.getBlockAt(x, y, z);
|
||||
players.forEach(player -> {
|
||||
player.sendBlockChange(block.getLocation(), block.getBlockData());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean togglePlayer(Player player) {
|
||||
if (players.contains(player)) {
|
||||
players.remove(player);
|
||||
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
Block block = WORLD.getBlockAt(x, y, z);
|
||||
player.sendBlockChange(block.getLocation(), block.getBlockData());
|
||||
}
|
||||
}
|
||||
}
|
||||
return players.isEmpty();
|
||||
} else {
|
||||
players.add(player);
|
||||
|
||||
BlockData endStone = Material.END_STONE.createBlockData();
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
if (invisible.get(toIndex(x, y, z))) {
|
||||
player.sendBlockChange(new Location(WORLD, x, y, z), endStone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Set<Point> pointsToReshow = new HashSet<>();
|
||||
private Map<HullDir, Set<Point>> changedInTick = new HashMap<>();
|
||||
|
||||
@EventHandler
|
||||
public void onBlockBreak(BlockBreakEvent event) {
|
||||
Point point = new Point(event.getBlock().getX(), event.getBlock().getY(), event.getBlock().getZ());
|
||||
airBlocks.set(toIndex(point));
|
||||
Set<HullDir> hullDirs = new HashSet<>();
|
||||
for (HullDir hullDir : HullDir.values()) {
|
||||
if (hullDirections.get(toIndex(point) * 6 + hullDir.ordinal())) {
|
||||
hullDirs.add(hullDir);
|
||||
}
|
||||
}
|
||||
|
||||
pointsToReshow.add(point);
|
||||
hullDirs.forEach(dir -> {
|
||||
changedInTick.computeIfAbsent(dir, __ -> new HashSet<>()).add(point);
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onEntityExplode(EntityExplodeEvent event) {
|
||||
for (Block block : event.blockList()) {
|
||||
Point point = new Point(block.getX(), block.getY(), block.getZ());
|
||||
airBlocks.set(toIndex(point));
|
||||
pointsToReshow.add(point);
|
||||
Set<HullDir> hullDirs = new HashSet<>();
|
||||
for (HullDir hullDir : HullDir.values()) {
|
||||
if (hullDirections.get(toIndex(point) * 6 + hullDir.ordinal())) {
|
||||
hullDirs.add(hullDir);
|
||||
}
|
||||
}
|
||||
hullDirs.forEach(dir -> {
|
||||
changedInTick.computeIfAbsent(dir, __ -> new HashSet<>()).add(point);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onTickEnd(TickEndEvent event) {
|
||||
if (!changedInTick.isEmpty()) {
|
||||
BitSet oldInvisible = BitSet.valueOf(invisible.toLongArray());
|
||||
long time = System.currentTimeMillis();
|
||||
changedInTick.forEach((dir, points) -> {
|
||||
calc(points, dir);
|
||||
});
|
||||
long timeDiff = System.currentTimeMillis() - time;
|
||||
players.forEach(player -> {
|
||||
player.sendMessage("Calculated in " + timeDiff + "ms");
|
||||
});
|
||||
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
if (invisible.get(toIndex(x, y, z))) continue;
|
||||
if (!oldInvisible.get(toIndex(x, y, z))) continue;
|
||||
Location location = new Location(WORLD, x, y, z);
|
||||
BlockData blockData = location.getBlock().getBlockData();
|
||||
players.forEach(player -> {
|
||||
player.sendBlockChange(location, blockData);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
changedInTick.clear();
|
||||
}
|
||||
|
||||
if (!pointsToReshow.isEmpty()) {
|
||||
BlockData endStone = Material.END_STONE.createBlockData();
|
||||
pointsToReshow.forEach(point -> {
|
||||
for (int x = point.getX() - 1; x <= point.getX() + 1; x++) {
|
||||
for (int y = point.getY() - 1; y <= point.getY() + 1; y++) {
|
||||
for (int z = point.getZ() - 1; z <= point.getZ() + 1; z++) {
|
||||
Location location = point.toLocation(WORLD);
|
||||
if (x >= minX && x <= maxX && y >= minY && y <= maxY && z >= minZ && z <= maxZ && invisible.get(toIndex(x, y, z))) {
|
||||
players.forEach(player -> {
|
||||
player.sendBlockChange(location, endStone);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
pointsToReshow.clear();
|
||||
}
|
||||
}
|
||||
}
|
In neuem Issue referenzieren
Einen Benutzer sperren