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 CommandDeveloper developer;
|
||||
private CommandPack pack;
|
||||
private CommandFind find;
|
||||
public static boolean worldCreation = false;
|
||||
private static final AtomicReference<Thread> mainWorld = new AtomicReference<>();
|
||||
String WorldEngine;
|
||||
|
||||
+43
-19
@@ -33,6 +33,7 @@ public class IslandObjectPlacer implements IObjectPlacer {
|
||||
|
||||
private final MantleWriter wrapped;
|
||||
private final FloatingIslandSample[] samples;
|
||||
private final boolean[] overhangAllowed;
|
||||
private final int minX;
|
||||
private final int minZ;
|
||||
private final int chunkMaxIslandTopY;
|
||||
@@ -57,6 +58,38 @@ public class IslandObjectPlacer implements IObjectPlacer {
|
||||
}
|
||||
}
|
||||
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() {
|
||||
@@ -73,38 +106,29 @@ public class IslandObjectPlacer implements IObjectPlacer {
|
||||
|
||||
private boolean shouldSkipAirColumn(int x, int y, int z) {
|
||||
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;
|
||||
}
|
||||
if (y <= anchorTopY) {
|
||||
writesDroppedBelow++;
|
||||
return true;
|
||||
}
|
||||
if (!hasIslandNeighborWithin(x, z, OVERHANG_RADIUS)) {
|
||||
if (!overhangAllowed[idx]) {
|
||||
writesDroppedOverhang++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasIslandNeighborWithin(int x, int z, int radius) {
|
||||
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) {
|
||||
if (y <= anchorTopY) {
|
||||
writesDroppedBelow++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return touchedChunkEdge;
|
||||
writesDroppedOverhang++;
|
||||
return true;
|
||||
}
|
||||
|
||||
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 double HEAVY_CLIP_RATIO = 0.5;
|
||||
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 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) {
|
||||
long warned = terrainMismatchWarnings.get();
|
||||
if (warned >= TERRAIN_MISMATCH_WARNING_CAP) {
|
||||
private static void verifyTerrainBelowObject(IrisObject obj, int wx, int wz, int pickTopY, FloatingIslandSample sample) {
|
||||
if (terrainMismatchWarnings.get() >= TERRAIN_MISMATCH_WARNING_CAP) {
|
||||
return;
|
||||
}
|
||||
boolean mantleSolid;
|
||||
try {
|
||||
mantleSolid = writer.isSolid(wx, pickTopY, wz);
|
||||
} catch (Throwable t) {
|
||||
mantleSolid = false;
|
||||
}
|
||||
boolean sampleSolid = sample != null
|
||||
if (sample != null
|
||||
&& sample.solidMask != null
|
||||
&& sample.topIdx >= 0
|
||||
&& sample.topIdx < sample.solidMask.length
|
||||
&& sample.solidMask[sample.topIdx];
|
||||
if (mantleSolid && sampleSolid) {
|
||||
&& sample.solidMask[sample.topIdx]) {
|
||||
return;
|
||||
}
|
||||
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);
|
||||
Iris.warn("[FloatingTerrainCheck] object=" + objKey
|
||||
+ " at=(" + wx + "," + (pickTopY + 1) + "," + wz + ")"
|
||||
+ " expected solid below at y=" + pickTopY
|
||||
+ " mantleSolid=" + mantleSolid
|
||||
+ " sampleSolid=" + sampleSolid
|
||||
+ " sample reports non-solid trunk column"
|
||||
+ " sampleTopY=" + sampleTop
|
||||
+ " sampleBaseY=" + sampleBase
|
||||
+ " sampleTopIdx=" + sampleTopIdx
|
||||
@@ -198,16 +189,21 @@ public class MantleFloatingObjectComponent extends IrisMantleComponent {
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.isInheritObjects() && target != null) {
|
||||
for (IrisObjectPlacement placement : target.getSurfaceObjects()) {
|
||||
tryPlaceAnchoredChunk(writer, complex, chunkRng, data, placement, samples, columns, minX, minZ, entry, target);
|
||||
}
|
||||
}
|
||||
|
||||
KList<IrisObjectPlacement> surface = entry.isInheritObjects() && target != null ? target.getSurfaceObjects() : null;
|
||||
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) {
|
||||
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
|
||||
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()) {
|
||||
return;
|
||||
}
|
||||
int density = placement.getDensity(rng, minX, minZ, data);
|
||||
double perAttempt = placement.getChance();
|
||||
KList<Integer> interior = interiorColumns(samples, columns);
|
||||
|
||||
for (int i = 0; i < density; i++) {
|
||||
objectsAttempted.incrementAndGet();
|
||||
@@ -329,7 +324,7 @@ public class MantleFloatingObjectComponent extends IrisMantleComponent {
|
||||
IrisObjectPlacement anchored = placement.toPlacement(obj.getLoadKey());
|
||||
anchored.setMode(translateStiltModeForFloating(anchored.getMode()));
|
||||
anchored.setTranslate(new IrisObjectTranslate());
|
||||
anchored.setRotation(IrisObjectRotation.of(0, 0, 0));
|
||||
anchored.setRotation(ROTATION_NONE);
|
||||
anchored.setForcePlace(true);
|
||||
anchored.setBottom(false);
|
||||
|
||||
@@ -349,7 +344,7 @@ public class MantleFloatingObjectComponent extends IrisMantleComponent {
|
||||
recordAnchorYHisto(pickTopY);
|
||||
int trunkWx = minX + pickedXf;
|
||||
int trunkWz = minZ + pickedZf;
|
||||
verifyTerrainBelowObject(writer, obj, trunkWx, trunkWz, pickTopY, pickedSample);
|
||||
verifyTerrainBelowObject(obj, trunkWx, trunkWz, pickTopY, pickedSample);
|
||||
recordWriteStats(obj, trunkWx, trunkWz, pickTopY, islandPlacer);
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
@@ -362,7 +357,9 @@ public class MantleFloatingObjectComponent extends IrisMantleComponent {
|
||||
int tallestKz = fp.getTallestKz();
|
||||
int checked = 0;
|
||||
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 kz = (int) (encoded & 0xFFFFFFFFL);
|
||||
int colXf = pickedXf + (kx - tallestKx);
|
||||
|
||||
@@ -24,13 +24,9 @@ import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.util.BlockVector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -44,16 +40,16 @@ public class FloatingObjectFootprint {
|
||||
private final int centerZ;
|
||||
private final int tallestKx;
|
||||
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.centerX = centerX;
|
||||
this.centerY = centerY;
|
||||
this.centerZ = centerZ;
|
||||
this.tallestKx = tallestKx;
|
||||
this.tallestKz = tallestKz;
|
||||
this.footprintXZ = Collections.unmodifiableSet(footprintXZ);
|
||||
this.footprintXZ = footprintXZ;
|
||||
}
|
||||
|
||||
public static FloatingObjectFootprint compute(IrisObject obj) {
|
||||
@@ -65,7 +61,6 @@ public class FloatingObjectFootprint {
|
||||
int cx = obj.getCenter().getBlockX();
|
||||
int cy = obj.getCenter().getBlockY();
|
||||
int cz = obj.getCenter().getBlockZ();
|
||||
Set<Long> xzSet = new HashSet<>();
|
||||
Map<Long, int[]> columnStats = new HashMap<>();
|
||||
|
||||
obj.getBlocks().forEach((BlockVector key, BlockData bd) -> {
|
||||
@@ -76,7 +71,6 @@ public class FloatingObjectFootprint {
|
||||
int ky = key.getBlockY();
|
||||
int kz = key.getBlockZ();
|
||||
long packed = ((long) kx << 32) | (kz & 0xFFFFFFFFL);
|
||||
xzSet.add(packed);
|
||||
int[] stats = columnStats.get(packed);
|
||||
if (stats == null) {
|
||||
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);
|
||||
int lowestSolidKeyY = columnStats.isEmpty()
|
||||
? cy
|
||||
@@ -98,7 +98,7 @@ public class FloatingObjectFootprint {
|
||||
if (DIAGNOSTIC_LOG) {
|
||||
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) {
|
||||
@@ -204,10 +204,6 @@ public class FloatingObjectFootprint {
|
||||
return bestPacked;
|
||||
}
|
||||
|
||||
public boolean columnInFootprint(int objKeyX, int objKeyZ) {
|
||||
return footprintXZ.contains(((long) objKeyX << 32) | (objKeyZ & 0xFFFFFFFFL));
|
||||
}
|
||||
|
||||
public int lowestSolidRelCenterY() {
|
||||
return lowestSolidKeyY - centerY;
|
||||
}
|
||||
@@ -236,7 +232,7 @@ public class FloatingObjectFootprint {
|
||||
return tallestKz;
|
||||
}
|
||||
|
||||
public Set<Long> footprintXZ() {
|
||||
public long[] footprintXZ() {
|
||||
return footprintXZ;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user