Add HullHider
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful

Dieser Commit ist enthalten in:
yoyosource 2023-12-16 12:37:04 +01:00
Ursprung 27627c3b41
Commit 408cb21db0
4 geänderte Dateien mit 880 neuen und 0 gelöschten Zeilen

Datei anzeigen

@ -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);
}
}
}
}
}

Datei anzeigen

@ -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);
}
}
}

Datei anzeigen

@ -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;
};
}
}

Datei anzeigen

@ -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();
}
}
}