SteamWar/BauSystem2.0
Archiviert
12
0

Add Pos and OptimizedAxisMovementLimiter
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful

Signed-off-by: yoyosource <yoyosource@nidido.de>
Dieser Commit ist enthalten in:
yoyosource 2023-08-30 21:19:17 +02:00
Ursprung 8f54fa1ef0
Commit a83b538b04
6 geänderte Dateien mit 409 neuen und 46 gelöschten Zeilen

Datei anzeigen

@ -21,7 +21,6 @@ package de.steamwar.bausystem.features.simulator;
import org.bukkit.Axis; import org.bukkit.Axis;
import org.bukkit.util.BoundingBox; import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
import org.bukkit.util.VoxelShape; import org.bukkit.util.VoxelShape;
import java.util.ArrayList; import java.util.ArrayList;
@ -78,7 +77,7 @@ public class AxisMovementLimiter {
} }
} }
private List<Vector> possibleCollisions() { private List<Pos> possibleCollisions() {
int minX = TNT.floor(this.minX); int minX = TNT.floor(this.minX);
int maxX = TNT.floor(this.maxX); int maxX = TNT.floor(this.maxX);
int minY = TNT.floor(this.minY) - 1; int minY = TNT.floor(this.minY) - 1;
@ -86,26 +85,27 @@ public class AxisMovementLimiter {
int minZ = TNT.floor(this.minZ); int minZ = TNT.floor(this.minZ);
int maxZ = TNT.floor(this.maxZ); int maxZ = TNT.floor(this.maxZ);
List<Vector> vectors = new ArrayList<>(); List<Pos> poss = new ArrayList<>();
for (int x = minX; x <= maxX; x++) { for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) { for (int y = minY; y <= maxY; y++) {
for (int z = minZ; z <= maxZ; z++) { for (int z = minZ; z <= maxZ; z++) {
vectors.add(new Vector(x, y, z)); poss.add(new Pos(x, y, z));
} }
} }
} }
return vectors; return poss;
} }
// TODO: This can be optimized by optimizing the x,y,z loop layout
public double run() { public double run() {
BoundingBox movementBoundingBox = new BoundingBox(minX, minY, minZ, maxX, maxY, maxZ); BoundingBox movementBoundingBox = new BoundingBox(minX, minY, minZ, maxX, maxY, maxZ);
List<Vector> vectors = possibleCollisions(); List<Pos> poss = possibleCollisions();
Double collision = null; Double collision = null;
for (Vector vector : vectors) { for (Pos pos : poss) {
VoxelShape voxelShape = Simulator19.getVoxelShape(vector); VoxelShape voxelShape = Simulator19.getVoxelShape(pos);
for (BoundingBox boundingBox : voxelShape.getBoundingBoxes()) { for (BoundingBox boundingBox : voxelShape.getBoundingBoxes()) {
boundingBox = boundingBox.clone().shift(vector); boundingBox = boundingBox.clone().shift(pos.x, pos.y, pos.z);
boolean collides = boundingBox.overlaps(movementBoundingBox); boolean collides = boundingBox.overlaps(movementBoundingBox);
if (!collides) continue; if (!collides) continue;

Datei anzeigen

@ -49,6 +49,16 @@ public class Explosion {
} }
} }
private static final Set<Material> WATER_LOGABLE = new HashSet<>();
static {
for (Material material : Material.values()) {
if (Waterlogged.class.isAssignableFrom(material.data)) {
WATER_LOGABLE.add(material);
}
}
}
private static final Random RANDOM = new Random(); private static final Random RANDOM = new Random();
private static final float POWER = 4.0F; private static final float POWER = 4.0F;
@ -68,7 +78,7 @@ public class Explosion {
} }
public void calculate() { public void calculate() {
Set<Vector> affectedBlocks = new HashSet<>(); Set<Pos> affectedBlocks = new HashSet<>();
for (int i = 0; i < FACE_BLOCKS.length; i += 3) { for (int i = 0; i < FACE_BLOCKS.length; i += 3) {
double d = FACE_BLOCKS[i + 0]; double d = FACE_BLOCKS[i + 0];
double e = FACE_BLOCKS[i + 1]; double e = FACE_BLOCKS[i + 1];
@ -84,19 +94,17 @@ public class Explosion {
int y = TNT.floor(n); int y = TNT.floor(n);
int z = TNT.floor(o); int z = TNT.floor(o);
BlockData blockData = Simulator19.getBlockData(x, y, z); Material material = Simulator19.getBlockType(x, y, z);
if (blockData != null) { h -= (material.getBlastResistance() + 0.3F) * 0.3F;
h -= (blockData.getMaterial().getBlastResistance() + 0.3F) * 0.3F; if (WATER_LOGABLE.contains(material)) {
} Waterlogged waterlogged = (Waterlogged) Simulator19.getBlockData(x, y, z);
if (blockData instanceof Waterlogged) {
Waterlogged waterlogged = (Waterlogged) blockData;
if (waterlogged.isWaterlogged()) { if (waterlogged.isWaterlogged()) {
h = 0.0F; h = 0.0F;
} }
} }
if (h > 0.0F) { if (h > 0.0F) {
affectedBlocks.add(new Vector(x, y, z)); affectedBlocks.add(new Pos(x, y, z));
} }
m += d * 0.30000001192092896; m += d * 0.30000001192092896;
@ -104,7 +112,7 @@ public class Explosion {
o += f * 0.30000001192092896; o += f * 0.30000001192092896;
} }
} }
affectedBlocks.forEach(Simulator19::clearBlock); Simulator19.clearBlocks(affectedBlocks);
float q = POWER * 2.0F; float q = POWER * 2.0F;
int k = floor(x - q - 1.0D); int k = floor(x - q - 1.0D);

Datei anzeigen

@ -0,0 +1,299 @@
/*
* 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.simulator;
import org.bukkit.Axis;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.VoxelShape;
public class OptimizedAxisMovementLimiter {
private Axis axis;
private double movement;
private double minX;
private double maxX;
private double minY;
private double maxY;
private double minZ;
private double maxZ;
private int minIX;
private int maxIX;
private int minIY;
private int maxIY;
private int minIZ;
private int maxIZ;
private BoundingBox movementBoundingBox;
public OptimizedAxisMovementLimiter(double x, double y, double z, Axis axis, double movement) {
this.axis = axis;
this.movement = movement;
// Calculate the min and max values for the movement
minX = x;
maxX = x + 0.98;
minY = y;
maxY = y + 0.98;
minZ = z;
maxZ = z + 0.98;
switch (axis) {
case X:
if (movement < 0) {
minX += movement;
} else if (movement > 0) {
maxX += movement;
}
break;
case Y:
if (movement < 0) {
minY += movement;
} else if (movement > 0) {
maxY += movement;
}
break;
case Z:
if (movement < 0) {
minZ += movement;
} else if (movement > 0) {
maxZ += movement;
}
break;
}
minIX = TNT.floor(minX);
maxIX = TNT.floor(maxX);
minIY = TNT.floor(minY) - 1;
maxIY = TNT.floor(maxY);
minIZ = TNT.floor(minZ);
maxIZ = TNT.floor(maxZ);
movementBoundingBox = new BoundingBox(minX, minY, minZ, maxX, maxY, maxZ);
}
public double run() {
if (movement == 0.0) return 0.0;
switch (axis) {
case X:
if (movement < 0.0) {
return runNX();
} else {
return runPX();
}
case Y:
if (movement < 0.0) {
return runNY();
} else {
return runPY();
}
case Z:
default:
if (movement < 0.0) {
return runNZ();
} else {
return runPZ();
}
}
}
private double runNX() {
Double collision = null;
for (int x = maxIX - 1; x >= minIX; x--) {
for (int y = minIY; y < maxIY; y++) {
for (int z = minIZ; z < maxIZ; z++) {
Pos pos = new Pos(x, y, z);
VoxelShape voxelShape = Simulator19.getVoxelShape(pos);
for (BoundingBox boundingBox : voxelShape.getBoundingBoxes()) {
boundingBox = boundingBox.clone().shift(x, y, z);
if (!boundingBox.overlaps(movementBoundingBox)) continue;
double value = boundingBox.getMaxX();
if (collision == null) {
collision = value;
} else {
collision = Math.max(value, collision);
}
}
}
}
if (collision != null) {
break;
}
}
if (collision == null) {
return movement;
}
return movement + (collision - minX);
}
private double runPX() {
Double collision = null;
for (int x = minIX; x < maxIX; x++) {
for (int y = minIY; y < maxIY; y++) {
for (int z = minIZ; z < maxIZ; z++) {
Pos pos = new Pos(x, y, z);
VoxelShape voxelShape = Simulator19.getVoxelShape(pos);
for (BoundingBox boundingBox : voxelShape.getBoundingBoxes()) {
boundingBox = boundingBox.clone().shift(x, y, z);
if (!boundingBox.overlaps(movementBoundingBox)) continue;
double value = boundingBox.getMinX() - 0.98;
if (collision == null) {
collision = value;
} else {
collision = Math.min(value, collision);
}
}
}
}
if (collision != null) {
break;
}
}
if (collision == null) {
return movement;
}
return movement + (collision - minX);
}
private double runNY() {
Double collision = null;
for (int y = maxIY - 1; y >= minIY; y--) {
for (int x = minIX; x < maxIX; x++) {
for (int z = minIZ; z < maxIZ; z++) {
Pos pos = new Pos(x, y, z);
VoxelShape voxelShape = Simulator19.getVoxelShape(pos);
for (BoundingBox boundingBox : voxelShape.getBoundingBoxes()) {
boundingBox = boundingBox.clone().shift(x, y, z);
if (!boundingBox.overlaps(movementBoundingBox)) continue;
double value = boundingBox.getMaxY();
if (collision == null) {
collision = value;
} else {
collision = Math.max(value, collision);
}
}
}
}
if (collision != null) {
break;
}
}
if (collision == null) {
return movement;
}
return movement + (collision - minY);
}
private double runPY() {
Double collision = null;
for (int y = minIY; y < maxIY; y++) {
for (int x = minIX; x < maxIX; x++) {
for (int z = minIZ; z < maxIZ; z++) {
Pos pos = new Pos(x, y, z);
VoxelShape voxelShape = Simulator19.getVoxelShape(pos);
for (BoundingBox boundingBox : voxelShape.getBoundingBoxes()) {
boundingBox = boundingBox.clone().shift(x, y, z);
if (!boundingBox.overlaps(movementBoundingBox)) continue;
double value = boundingBox.getMinY() - 0.98;
if (collision == null) {
collision = value;
} else {
collision = Math.min(value, collision);
}
}
}
}
if (collision != null) {
break;
}
}
if (collision == null) {
return movement;
}
return movement + (collision - minY);
}
private double runNZ() {
Double collision = null;
for (int z = maxIZ - 1; z >= minIZ; z--) {
for (int x = minIX; x < maxIX; x++) {
for (int y = minIY; y < maxIY; y++) {
Pos pos = new Pos(x, y, z);
VoxelShape voxelShape = Simulator19.getVoxelShape(pos);
for (BoundingBox boundingBox : voxelShape.getBoundingBoxes()) {
boundingBox = boundingBox.clone().shift(x, y, z);
if (!boundingBox.overlaps(movementBoundingBox)) continue;
double value = boundingBox.getMaxZ();
if (collision == null) {
collision = value;
} else {
collision = Math.max(value, collision);
}
}
}
}
if (collision != null) {
break;
}
}
if (collision == null) {
return movement;
}
return movement + (collision - minZ);
}
private double runPZ() {
Double collision = null;
for (int z = minIZ; z < maxIZ; z++) {
for (int x = minIX; x < maxIX; x++) {
for (int y = minIY; y < maxIY; y++) {
Pos pos = new Pos(x, y, z);
VoxelShape voxelShape = Simulator19.getVoxelShape(pos);
for (BoundingBox boundingBox : voxelShape.getBoundingBoxes()) {
boundingBox = boundingBox.clone().shift(x, y, z);
if (!boundingBox.overlaps(movementBoundingBox)) continue;
double value = boundingBox.getMinZ() - 0.98;
if (collision == null) {
collision = value;
} else {
collision = Math.min(value, collision);
}
}
}
}
if (collision != null) {
break;
}
}
if (collision == null) {
return movement;
}
return movement + (collision - minZ);
}
}

Datei anzeigen

@ -0,0 +1,29 @@
/*
* 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.simulator;
import lombok.Data;
@Data
public class Pos {
public final int x;
public final int y;
public final int z;
}

Datei anzeigen

@ -46,9 +46,13 @@ public class Simulator19 implements Simulator {
} }
}; };
private static final Map<Vector, Material> BLOCK_TYPES_MAP = new HashMap<>(); private static long accessed = 0;
private static final Map<Vector, BlockData> BLOCK_DATA_MAP = new HashMap<>(); private static long cacheMisses = 0;
private static final Map<Vector, VoxelShape> COLLISION_DATA_MAP = new HashMap<>(); private static long aired = 0;
private static final Set<Pos> AIR_BLOCKS = new HashSet<>();
private static final Map<Pos, Material> BLOCK_TYPES_MAP = new HashMap<>();
private static final Map<Pos, BlockData> BLOCK_DATA_MAP = new HashMap<>();
private static final Map<Pos, VoxelShape> COLLISION_DATA_MAP = new HashMap<>();
@Override @Override
public synchronized void run() { public synchronized void run() {
@ -66,30 +70,55 @@ public class Simulator19 implements Simulator {
} }
tntList.removeAll(remove); tntList.removeAll(remove);
} }
System.out.println("Time: " + (System.currentTimeMillis() - time) + "ms"); System.out.println("Time: " + (System.currentTimeMillis() - time) + "ms " + cacheMisses + "/" + accessed + "/" + aired);
AIR_BLOCKS.clear();
BLOCK_TYPES_MAP.clear(); BLOCK_TYPES_MAP.clear();
BLOCK_DATA_MAP.clear(); BLOCK_DATA_MAP.clear();
COLLISION_DATA_MAP.clear(); COLLISION_DATA_MAP.clear();
accessed = 0;
cacheMisses = 0;
aired = 0;
} }
public static Material getBlockType(int x, int y, int z) { public static Material getBlockType(int x, int y, int z) { // Get BlockType of Chunk Data array?
Vector vector = new Vector(x, y, z); accessed++;
return BLOCK_TYPES_MAP.computeIfAbsent(vector, v -> WORLD.getBlockAt(v.getBlockX(), v.getBlockY(), v.getBlockZ()).getType()); Pos pos = new Pos(x, y, z);
if (AIR_BLOCKS.contains(pos)) {
return Material.AIR;
}
return BLOCK_TYPES_MAP.computeIfAbsent(pos, v -> {
cacheMisses++;
return WORLD.getBlockAt(x, y, z).getType();
});
} }
public static BlockData getBlockData(int x, int y, int z) { public static BlockData getBlockData(int x, int y, int z) {
Vector vector = new Vector(x, y, z); accessed++;
return BLOCK_DATA_MAP.computeIfAbsent(vector, v -> WORLD.getBlockAt(v.getBlockX(), v.getBlockY(), v.getBlockZ()).getBlockData()); return BLOCK_DATA_MAP.computeIfAbsent(new Pos(x, y, z), v -> {
cacheMisses++;
return WORLD.getBlockAt(x, y, z).getBlockData();
});
} }
public static VoxelShape getVoxelShape(Vector vector) { public static VoxelShape getVoxelShape(Pos pos) {
return COLLISION_DATA_MAP.computeIfAbsent(vector, v -> WORLD.getBlockAt(v.getBlockX(), v.getBlockY(), v.getBlockZ()).getCollisionShape()); accessed++;
if (AIR_BLOCKS.contains(pos)) {
return AIR_VOXEL_SHAPE;
}
return COLLISION_DATA_MAP.computeIfAbsent(pos, v -> {
cacheMisses++;
return WORLD.getBlockAt(pos.x, pos.y, pos.z).getCollisionShape();
});
} }
public static void clearBlock(Vector vector) { public static void clearBlock(Pos pos) {
BLOCK_TYPES_MAP.put(vector, Material.AIR); aired++;
BLOCK_DATA_MAP.put(vector, AIR_BLOCK_DATA); AIR_BLOCKS.add(pos);
COLLISION_DATA_MAP.put(vector, AIR_VOXEL_SHAPE); BLOCK_DATA_MAP.put(pos, AIR_BLOCK_DATA);
}
public static void clearBlocks(Set<Pos> pos) {
} }
} }

Datei anzeigen

@ -145,8 +145,7 @@ public class TNT {
} }
} }
if (onGround) { if (onGround && material == Material.SLIME_BLOCK) {
if (material == Material.SLIME_BLOCK) {
double cy = Math.abs(this.vy); double cy = Math.abs(this.vy);
if (cy < 0.1) { if (cy < 0.1) {
double cy2 = 0.4 + cy * 0.2; double cy2 = 0.4 + cy * 0.2;
@ -154,7 +153,6 @@ public class TNT {
this.vz = vz * cy2; this.vz = vz * cy2;
} }
} }
}
checkBlockCollision(); checkBlockCollision();
float j = this.getVelocityMultiplier(); float j = this.getVelocityMultiplier();
@ -167,16 +165,16 @@ public class TNT {
return movement; return movement;
} }
double mY = new AxisMovementLimiter(x, y, z, Axis.Y, movement.getY()).run(); double mY = new OptimizedAxisMovementLimiter(x, y, z, Axis.Y, movement.getY()).run();
boolean bl = Math.abs(movement.getX()) < Math.abs(movement.getZ()); boolean bl = Math.abs(movement.getX()) < Math.abs(movement.getZ());
if (bl) { if (bl) {
double mZ = new AxisMovementLimiter(x, y + mY, z, Axis.Z, movement.getZ()).run(); double mZ = new OptimizedAxisMovementLimiter(x, y + mY, z, Axis.Z, movement.getZ()).run();
double mX = new AxisMovementLimiter(x, y + mY, z + mZ, Axis.X, movement.getX()).run(); double mX = new OptimizedAxisMovementLimiter(x, y + mY, z + mZ, Axis.X, movement.getX()).run();
return new Vector(mX, mY, mZ); return new Vector(mX, mY, mZ);
} else { } else {
double mX = new AxisMovementLimiter(x, y + mY, z, Axis.X, movement.getX()).run(); double mX = new OptimizedAxisMovementLimiter(x, y + mY, z, Axis.X, movement.getX()).run();
double mZ = new AxisMovementLimiter(x + mX, y + mY, z, Axis.Z, movement.getZ()).run(); double mZ = new OptimizedAxisMovementLimiter(x + mX, y + mY, z, Axis.Z, movement.getZ()).run();
return new Vector(mX, mY, mZ); return new Vector(mX, mY, mZ);
} }
} }