mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-05-19 16:10:42 +00:00
Whoops
This commit is contained in:
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package art.arcane.iris.core.commands;
|
||||||
|
|
||||||
|
import art.arcane.iris.Iris;
|
||||||
|
import art.arcane.iris.core.service.ObjectStudioSaveService;
|
||||||
|
import art.arcane.iris.engine.framework.Engine;
|
||||||
|
import art.arcane.iris.engine.object.IrisBiome;
|
||||||
|
import art.arcane.iris.engine.object.IrisRegion;
|
||||||
|
import art.arcane.iris.util.common.director.DirectorExecutor;
|
||||||
|
import art.arcane.iris.util.common.director.specialhandlers.ObjectHandler;
|
||||||
|
import art.arcane.iris.util.common.format.C;
|
||||||
|
import art.arcane.volmlib.util.director.DirectorOrigin;
|
||||||
|
import art.arcane.volmlib.util.director.annotations.Director;
|
||||||
|
import art.arcane.volmlib.util.director.annotations.Param;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
@Director(name = "find", origin = DirectorOrigin.PLAYER, description = "Iris Find commands", aliases = "goto")
|
||||||
|
public class CommandFind implements DirectorExecutor {
|
||||||
|
@Director(description = "Find a biome")
|
||||||
|
public void biome(
|
||||||
|
@Param(description = "The biome to look for")
|
||||||
|
IrisBiome biome,
|
||||||
|
@Param(description = "Should you be teleported", defaultValue = "true")
|
||||||
|
boolean teleport
|
||||||
|
) {
|
||||||
|
Engine e = engine();
|
||||||
|
|
||||||
|
if (e == null) {
|
||||||
|
sender().sendMessage(C.GOLD + "Not in an Iris World!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.gotoBiome(biome, player(), teleport);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Director(description = "Find a region")
|
||||||
|
public void region(
|
||||||
|
@Param(description = "The region to look for")
|
||||||
|
IrisRegion region,
|
||||||
|
@Param(description = "Should you be teleported", defaultValue = "true")
|
||||||
|
boolean teleport
|
||||||
|
) {
|
||||||
|
Engine e = engine();
|
||||||
|
|
||||||
|
if (e == null) {
|
||||||
|
sender().sendMessage(C.GOLD + "Not in an Iris World!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.gotoRegion(region, player(), teleport);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Director(description = "Find a point of interest.")
|
||||||
|
public void poi(
|
||||||
|
@Param(description = "The type of PoI to look for.")
|
||||||
|
String type,
|
||||||
|
@Param(description = "Should you be teleported", defaultValue = "true")
|
||||||
|
boolean teleport
|
||||||
|
) {
|
||||||
|
Engine e = engine();
|
||||||
|
if (e == null) {
|
||||||
|
sender().sendMessage(C.GOLD + "Not in an Iris World!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.gotoPOI(type, player(), teleport);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Director(description = "Find an object")
|
||||||
|
public void object(
|
||||||
|
@Param(description = "The object to look for", customHandler = ObjectHandler.class)
|
||||||
|
String object,
|
||||||
|
@Param(description = "Should you be teleported", defaultValue = "true")
|
||||||
|
boolean teleport
|
||||||
|
) {
|
||||||
|
Engine e = engine();
|
||||||
|
|
||||||
|
if (e == null) {
|
||||||
|
sender().sendMessage(C.GOLD + "Not in an Iris World!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player studioPlayer = player();
|
||||||
|
if (studioPlayer != null) {
|
||||||
|
try {
|
||||||
|
if (ObjectStudioSaveService.get().teleportTo(studioPlayer, object)) {
|
||||||
|
sender().sendMessage(C.GREEN + "Object Studio: teleporting to " + object);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (Throwable t) {
|
||||||
|
Iris.reportError(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.hasObjectPlacement(object)) {
|
||||||
|
e.gotoObject(object, player(), teleport);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sender().sendMessage(C.RED + object + " is not configured in any region/biome object placements.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -101,6 +101,7 @@ public class CommandIris implements DirectorExecutor {
|
|||||||
private CommandEdit edit;
|
private CommandEdit edit;
|
||||||
private CommandDeveloper developer;
|
private CommandDeveloper developer;
|
||||||
private CommandPack pack;
|
private CommandPack pack;
|
||||||
|
private CommandFind find;
|
||||||
public static boolean worldCreation = false;
|
public static boolean worldCreation = false;
|
||||||
private static final AtomicReference<Thread> mainWorld = new AtomicReference<>();
|
private static final AtomicReference<Thread> mainWorld = new AtomicReference<>();
|
||||||
String WorldEngine;
|
String WorldEngine;
|
||||||
|
|||||||
+43
-19
@@ -33,6 +33,7 @@ public class IslandObjectPlacer implements IObjectPlacer {
|
|||||||
|
|
||||||
private final MantleWriter wrapped;
|
private final MantleWriter wrapped;
|
||||||
private final FloatingIslandSample[] samples;
|
private final FloatingIslandSample[] samples;
|
||||||
|
private final boolean[] overhangAllowed;
|
||||||
private final int minX;
|
private final int minX;
|
||||||
private final int minZ;
|
private final int minZ;
|
||||||
private final int chunkMaxIslandTopY;
|
private final int chunkMaxIslandTopY;
|
||||||
@@ -57,6 +58,38 @@ public class IslandObjectPlacer implements IObjectPlacer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.chunkMaxIslandTopY = maxY;
|
this.chunkMaxIslandTopY = maxY;
|
||||||
|
this.overhangAllowed = buildOverhangMask(samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean[] buildOverhangMask(FloatingIslandSample[] samples) {
|
||||||
|
boolean[] mask = new boolean[256];
|
||||||
|
for (int zf = 0; zf < 16; zf++) {
|
||||||
|
for (int xf = 0; xf < 16; xf++) {
|
||||||
|
int idx = (zf << 4) | xf;
|
||||||
|
if (samples[idx] != null) {
|
||||||
|
mask[idx] = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
boolean touchedEdge = false;
|
||||||
|
boolean found = false;
|
||||||
|
for (int dz = -OVERHANG_RADIUS; dz <= OVERHANG_RADIUS && !found; dz++) {
|
||||||
|
int nzf = zf + dz;
|
||||||
|
for (int dx = -OVERHANG_RADIUS; dx <= OVERHANG_RADIUS; dx++) {
|
||||||
|
int nxf = xf + dx;
|
||||||
|
if (nxf < 0 || nxf >= 16 || nzf < 0 || nzf >= 16) {
|
||||||
|
touchedEdge = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (samples[(nzf << 4) | nxf] != null) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mask[idx] = found || touchedEdge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getWritesAttempted() {
|
public int getWritesAttempted() {
|
||||||
@@ -73,38 +106,29 @@ public class IslandObjectPlacer implements IObjectPlacer {
|
|||||||
|
|
||||||
private boolean shouldSkipAirColumn(int x, int y, int z) {
|
private boolean shouldSkipAirColumn(int x, int y, int z) {
|
||||||
writesAttempted++;
|
writesAttempted++;
|
||||||
if (sampleAt(x, z) != null) {
|
int xf = x - minX;
|
||||||
|
int zf = z - minZ;
|
||||||
|
if (xf >= 0 && xf < 16 && zf >= 0 && zf < 16) {
|
||||||
|
int idx = (zf << 4) | xf;
|
||||||
|
if (samples[idx] != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (y <= anchorTopY) {
|
if (y <= anchorTopY) {
|
||||||
writesDroppedBelow++;
|
writesDroppedBelow++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!hasIslandNeighborWithin(x, z, OVERHANG_RADIUS)) {
|
if (!overhangAllowed[idx]) {
|
||||||
writesDroppedOverhang++;
|
writesDroppedOverhang++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (y <= anchorTopY) {
|
||||||
private boolean hasIslandNeighborWithin(int x, int z, int radius) {
|
writesDroppedBelow++;
|
||||||
int xf = x - minX;
|
|
||||||
int zf = z - minZ;
|
|
||||||
boolean touchedChunkEdge = false;
|
|
||||||
for (int dx = -radius; dx <= radius; dx++) {
|
|
||||||
int nxf = xf + dx;
|
|
||||||
for (int dz = -radius; dz <= radius; dz++) {
|
|
||||||
int nzf = zf + dz;
|
|
||||||
if (nxf < 0 || nxf >= 16 || nzf < 0 || nzf >= 16) {
|
|
||||||
touchedChunkEdge = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (samples[(nzf << 4) | nxf] != null) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
writesDroppedOverhang++;
|
||||||
}
|
return true;
|
||||||
return touchedChunkEdge;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable FloatingIslandSample sampleAt(int x, int z) {
|
private @Nullable FloatingIslandSample sampleAt(int x, int z) {
|
||||||
|
|||||||
+25
-28
@@ -62,6 +62,7 @@ public class MantleFloatingObjectComponent extends IrisMantleComponent {
|
|||||||
private static final int HEAVY_CLIP_WARNING_CAP = 30;
|
private static final int HEAVY_CLIP_WARNING_CAP = 30;
|
||||||
private static final double HEAVY_CLIP_RATIO = 0.5;
|
private static final double HEAVY_CLIP_RATIO = 0.5;
|
||||||
private static final int MIN_FOOTPRINT_CELLS_CHECKED = 3;
|
private static final int MIN_FOOTPRINT_CELLS_CHECKED = 3;
|
||||||
|
private static final IrisObjectRotation ROTATION_NONE = IrisObjectRotation.of(0, 0, 0);
|
||||||
public static final java.util.concurrent.ConcurrentHashMap<String, AtomicLong> anchorYHisto = new java.util.concurrent.ConcurrentHashMap<>();
|
public static final java.util.concurrent.ConcurrentHashMap<String, AtomicLong> anchorYHisto = new java.util.concurrent.ConcurrentHashMap<>();
|
||||||
|
|
||||||
public MantleFloatingObjectComponent(EngineMantle engineMantle) {
|
public MantleFloatingObjectComponent(EngineMantle engineMantle) {
|
||||||
@@ -106,23 +107,15 @@ public class MantleFloatingObjectComponent extends IrisMantleComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void verifyTerrainBelowObject(MantleWriter writer, IrisObject obj, int wx, int wz, int pickTopY, FloatingIslandSample sample) {
|
private static void verifyTerrainBelowObject(IrisObject obj, int wx, int wz, int pickTopY, FloatingIslandSample sample) {
|
||||||
long warned = terrainMismatchWarnings.get();
|
if (terrainMismatchWarnings.get() >= TERRAIN_MISMATCH_WARNING_CAP) {
|
||||||
if (warned >= TERRAIN_MISMATCH_WARNING_CAP) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boolean mantleSolid;
|
if (sample != null
|
||||||
try {
|
|
||||||
mantleSolid = writer.isSolid(wx, pickTopY, wz);
|
|
||||||
} catch (Throwable t) {
|
|
||||||
mantleSolid = false;
|
|
||||||
}
|
|
||||||
boolean sampleSolid = sample != null
|
|
||||||
&& sample.solidMask != null
|
&& sample.solidMask != null
|
||||||
&& sample.topIdx >= 0
|
&& sample.topIdx >= 0
|
||||||
&& sample.topIdx < sample.solidMask.length
|
&& sample.topIdx < sample.solidMask.length
|
||||||
&& sample.solidMask[sample.topIdx];
|
&& sample.solidMask[sample.topIdx]) {
|
||||||
if (mantleSolid && sampleSolid) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (terrainMismatchWarnings.incrementAndGet() > TERRAIN_MISMATCH_WARNING_CAP) {
|
if (terrainMismatchWarnings.incrementAndGet() > TERRAIN_MISMATCH_WARNING_CAP) {
|
||||||
@@ -135,9 +128,7 @@ public class MantleFloatingObjectComponent extends IrisMantleComponent {
|
|||||||
String sampleMaskLen = sample == null || sample.solidMask == null ? "null" : String.valueOf(sample.solidMask.length);
|
String sampleMaskLen = sample == null || sample.solidMask == null ? "null" : String.valueOf(sample.solidMask.length);
|
||||||
Iris.warn("[FloatingTerrainCheck] object=" + objKey
|
Iris.warn("[FloatingTerrainCheck] object=" + objKey
|
||||||
+ " at=(" + wx + "," + (pickTopY + 1) + "," + wz + ")"
|
+ " at=(" + wx + "," + (pickTopY + 1) + "," + wz + ")"
|
||||||
+ " expected solid below at y=" + pickTopY
|
+ " sample reports non-solid trunk column"
|
||||||
+ " mantleSolid=" + mantleSolid
|
|
||||||
+ " sampleSolid=" + sampleSolid
|
|
||||||
+ " sampleTopY=" + sampleTop
|
+ " sampleTopY=" + sampleTop
|
||||||
+ " sampleBaseY=" + sampleBase
|
+ " sampleBaseY=" + sampleBase
|
||||||
+ " sampleTopIdx=" + sampleTopIdx
|
+ " sampleTopIdx=" + sampleTopIdx
|
||||||
@@ -198,16 +189,21 @@ public class MantleFloatingObjectComponent extends IrisMantleComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.isInheritObjects() && target != null) {
|
KList<IrisObjectPlacement> surface = entry.isInheritObjects() && target != null ? target.getSurfaceObjects() : null;
|
||||||
for (IrisObjectPlacement placement : target.getSurfaceObjects()) {
|
|
||||||
tryPlaceAnchoredChunk(writer, complex, chunkRng, data, placement, samples, columns, minX, minZ, entry, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
KList<IrisObjectPlacement> extras = entry.getExtraObjects();
|
KList<IrisObjectPlacement> extras = entry.getExtraObjects();
|
||||||
if (extras != null && !extras.isEmpty()) {
|
boolean hasSurface = surface != null && !surface.isEmpty();
|
||||||
|
boolean hasExtras = extras != null && !extras.isEmpty();
|
||||||
|
if (hasSurface || hasExtras) {
|
||||||
|
KList<Integer> interior = interiorColumns(samples, columns);
|
||||||
|
if (hasSurface) {
|
||||||
|
for (IrisObjectPlacement placement : surface) {
|
||||||
|
tryPlaceAnchoredChunk(writer, complex, chunkRng, data, placement, samples, columns, interior, minX, minZ, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasExtras) {
|
||||||
for (IrisObjectPlacement placement : extras) {
|
for (IrisObjectPlacement placement : extras) {
|
||||||
tryPlaceAnchoredChunk(writer, complex, chunkRng, data, placement, samples, columns, minX, minZ, entry, target);
|
tryPlaceAnchoredChunk(writer, complex, chunkRng, data, placement, samples, columns, interior, minX, minZ, entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,13 +261,12 @@ public class MantleFloatingObjectComponent extends IrisMantleComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ChunkCoordinates
|
@ChunkCoordinates
|
||||||
private void tryPlaceAnchoredChunk(MantleWriter writer, IrisComplex complex, RNG rng, IrisData data, IrisObjectPlacement placement, FloatingIslandSample[] samples, KList<Integer> columns, int minX, int minZ, IrisFloatingChildBiomes entry, IrisBiome target) {
|
private void tryPlaceAnchoredChunk(MantleWriter writer, IrisComplex complex, RNG rng, IrisData data, IrisObjectPlacement placement, FloatingIslandSample[] samples, KList<Integer> columns, KList<Integer> interior, int minX, int minZ, IrisFloatingChildBiomes entry) {
|
||||||
if (placement == null || columns.isEmpty()) {
|
if (placement == null || columns.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int density = placement.getDensity(rng, minX, minZ, data);
|
int density = placement.getDensity(rng, minX, minZ, data);
|
||||||
double perAttempt = placement.getChance();
|
double perAttempt = placement.getChance();
|
||||||
KList<Integer> interior = interiorColumns(samples, columns);
|
|
||||||
|
|
||||||
for (int i = 0; i < density; i++) {
|
for (int i = 0; i < density; i++) {
|
||||||
objectsAttempted.incrementAndGet();
|
objectsAttempted.incrementAndGet();
|
||||||
@@ -329,7 +324,7 @@ public class MantleFloatingObjectComponent extends IrisMantleComponent {
|
|||||||
IrisObjectPlacement anchored = placement.toPlacement(obj.getLoadKey());
|
IrisObjectPlacement anchored = placement.toPlacement(obj.getLoadKey());
|
||||||
anchored.setMode(translateStiltModeForFloating(anchored.getMode()));
|
anchored.setMode(translateStiltModeForFloating(anchored.getMode()));
|
||||||
anchored.setTranslate(new IrisObjectTranslate());
|
anchored.setTranslate(new IrisObjectTranslate());
|
||||||
anchored.setRotation(IrisObjectRotation.of(0, 0, 0));
|
anchored.setRotation(ROTATION_NONE);
|
||||||
anchored.setForcePlace(true);
|
anchored.setForcePlace(true);
|
||||||
anchored.setBottom(false);
|
anchored.setBottom(false);
|
||||||
|
|
||||||
@@ -349,7 +344,7 @@ public class MantleFloatingObjectComponent extends IrisMantleComponent {
|
|||||||
recordAnchorYHisto(pickTopY);
|
recordAnchorYHisto(pickTopY);
|
||||||
int trunkWx = minX + pickedXf;
|
int trunkWx = minX + pickedXf;
|
||||||
int trunkWz = minZ + pickedZf;
|
int trunkWz = minZ + pickedZf;
|
||||||
verifyTerrainBelowObject(writer, obj, trunkWx, trunkWz, pickTopY, pickedSample);
|
verifyTerrainBelowObject(obj, trunkWx, trunkWz, pickTopY, pickedSample);
|
||||||
recordWriteStats(obj, trunkWx, trunkWz, pickTopY, islandPlacer);
|
recordWriteStats(obj, trunkWx, trunkWz, pickTopY, islandPlacer);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
@@ -362,7 +357,9 @@ public class MantleFloatingObjectComponent extends IrisMantleComponent {
|
|||||||
int tallestKz = fp.getTallestKz();
|
int tallestKz = fp.getTallestKz();
|
||||||
int checked = 0;
|
int checked = 0;
|
||||||
boolean touchedChunkEdge = false;
|
boolean touchedChunkEdge = false;
|
||||||
for (long encoded : fp.footprintXZ()) {
|
long[] cells = fp.footprintXZ();
|
||||||
|
for (int i = 0, n = cells.length; i < n; i++) {
|
||||||
|
long encoded = cells[i];
|
||||||
int kx = (int) (encoded >> 32);
|
int kx = (int) (encoded >> 32);
|
||||||
int kz = (int) (encoded & 0xFFFFFFFFL);
|
int kz = (int) (encoded & 0xFFFFFFFFL);
|
||||||
int colXf = pickedXf + (kx - tallestKx);
|
int colXf = pickedXf + (kx - tallestKx);
|
||||||
|
|||||||
@@ -24,13 +24,9 @@ import org.bukkit.block.data.BlockData;
|
|||||||
import org.bukkit.util.BlockVector;
|
import org.bukkit.util.BlockVector;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@@ -44,16 +40,16 @@ public class FloatingObjectFootprint {
|
|||||||
private final int centerZ;
|
private final int centerZ;
|
||||||
private final int tallestKx;
|
private final int tallestKx;
|
||||||
private final int tallestKz;
|
private final int tallestKz;
|
||||||
private final Set<Long> footprintXZ;
|
private final long[] footprintXZ;
|
||||||
|
|
||||||
private FloatingObjectFootprint(int lowestSolidKeyY, int centerX, int centerY, int centerZ, int tallestKx, int tallestKz, Set<Long> footprintXZ) {
|
private FloatingObjectFootprint(int lowestSolidKeyY, int centerX, int centerY, int centerZ, int tallestKx, int tallestKz, long[] footprintXZ) {
|
||||||
this.lowestSolidKeyY = lowestSolidKeyY;
|
this.lowestSolidKeyY = lowestSolidKeyY;
|
||||||
this.centerX = centerX;
|
this.centerX = centerX;
|
||||||
this.centerY = centerY;
|
this.centerY = centerY;
|
||||||
this.centerZ = centerZ;
|
this.centerZ = centerZ;
|
||||||
this.tallestKx = tallestKx;
|
this.tallestKx = tallestKx;
|
||||||
this.tallestKz = tallestKz;
|
this.tallestKz = tallestKz;
|
||||||
this.footprintXZ = Collections.unmodifiableSet(footprintXZ);
|
this.footprintXZ = footprintXZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FloatingObjectFootprint compute(IrisObject obj) {
|
public static FloatingObjectFootprint compute(IrisObject obj) {
|
||||||
@@ -65,7 +61,6 @@ public class FloatingObjectFootprint {
|
|||||||
int cx = obj.getCenter().getBlockX();
|
int cx = obj.getCenter().getBlockX();
|
||||||
int cy = obj.getCenter().getBlockY();
|
int cy = obj.getCenter().getBlockY();
|
||||||
int cz = obj.getCenter().getBlockZ();
|
int cz = obj.getCenter().getBlockZ();
|
||||||
Set<Long> xzSet = new HashSet<>();
|
|
||||||
Map<Long, int[]> columnStats = new HashMap<>();
|
Map<Long, int[]> columnStats = new HashMap<>();
|
||||||
|
|
||||||
obj.getBlocks().forEach((BlockVector key, BlockData bd) -> {
|
obj.getBlocks().forEach((BlockVector key, BlockData bd) -> {
|
||||||
@@ -76,7 +71,6 @@ public class FloatingObjectFootprint {
|
|||||||
int ky = key.getBlockY();
|
int ky = key.getBlockY();
|
||||||
int kz = key.getBlockZ();
|
int kz = key.getBlockZ();
|
||||||
long packed = ((long) kx << 32) | (kz & 0xFFFFFFFFL);
|
long packed = ((long) kx << 32) | (kz & 0xFFFFFFFFL);
|
||||||
xzSet.add(packed);
|
|
||||||
int[] stats = columnStats.get(packed);
|
int[] stats = columnStats.get(packed);
|
||||||
if (stats == null) {
|
if (stats == null) {
|
||||||
stats = new int[]{ky, 1};
|
stats = new int[]{ky, 1};
|
||||||
@@ -89,6 +83,12 @@ public class FloatingObjectFootprint {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
long[] footprintArray = new long[columnStats.size()];
|
||||||
|
int idx = 0;
|
||||||
|
for (Long packed : columnStats.keySet()) {
|
||||||
|
footprintArray[idx++] = packed;
|
||||||
|
}
|
||||||
|
|
||||||
long tallestPacked = resolveTallestColumn(columnStats);
|
long tallestPacked = resolveTallestColumn(columnStats);
|
||||||
int lowestSolidKeyY = columnStats.isEmpty()
|
int lowestSolidKeyY = columnStats.isEmpty()
|
||||||
? cy
|
? cy
|
||||||
@@ -98,7 +98,7 @@ public class FloatingObjectFootprint {
|
|||||||
if (DIAGNOSTIC_LOG) {
|
if (DIAGNOSTIC_LOG) {
|
||||||
logFootprintDiagnostic(cacheKey, obj, cx, cy, cz, lowestSolidKeyY, tallestKx, tallestKz, columnStats);
|
logFootprintDiagnostic(cacheKey, obj, cx, cy, cz, lowestSolidKeyY, tallestKx, tallestKz, columnStats);
|
||||||
}
|
}
|
||||||
return new FloatingObjectFootprint(lowestSolidKeyY, cx, cy, cz, tallestKx, tallestKz, xzSet);
|
return new FloatingObjectFootprint(lowestSolidKeyY, cx, cy, cz, tallestKx, tallestKz, footprintArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void logFootprintDiagnostic(String cacheKey, IrisObject obj, int cx, int cy, int cz, int anchorY, int tallestKx, int tallestKz, Map<Long, int[]> columnStats) {
|
private static void logFootprintDiagnostic(String cacheKey, IrisObject obj, int cx, int cy, int cz, int anchorY, int tallestKx, int tallestKz, Map<Long, int[]> columnStats) {
|
||||||
@@ -204,10 +204,6 @@ public class FloatingObjectFootprint {
|
|||||||
return bestPacked;
|
return bestPacked;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean columnInFootprint(int objKeyX, int objKeyZ) {
|
|
||||||
return footprintXZ.contains(((long) objKeyX << 32) | (objKeyZ & 0xFFFFFFFFL));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int lowestSolidRelCenterY() {
|
public int lowestSolidRelCenterY() {
|
||||||
return lowestSolidKeyY - centerY;
|
return lowestSolidKeyY - centerY;
|
||||||
}
|
}
|
||||||
@@ -236,7 +232,7 @@ public class FloatingObjectFootprint {
|
|||||||
return tallestKz;
|
return tallestKz;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<Long> footprintXZ() {
|
public long[] footprintXZ() {
|
||||||
return footprintXZ;
|
return footprintXZ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user