diff --git a/src/main/java/li/cil/oc/api/event/GeolyzerEvent.java b/src/main/java/li/cil/oc/api/event/GeolyzerEvent.java index 52c9ab02a..2d7d0f4be 100644 --- a/src/main/java/li/cil/oc/api/event/GeolyzerEvent.java +++ b/src/main/java/li/cil/oc/api/event/GeolyzerEvent.java @@ -36,18 +36,42 @@ public abstract class GeolyzerEvent extends Event { * the geolyzer. By default this will yield a (noisy) listing of the * hardness of the blocks. *
- * Note: the y coordinate is computed as geolyzer.y - 32 + data.index. + * The bounds are guaranteed to not define a volume larger than 64. + * Resulting data should be written to the {@link #data} array such that + *index = x + z*w + y*w*d
, with w = maxX - minX
+ * and d = maxZ - minZ
(h meaning height, d
+ * meaning depth).
*/
public static class Scan extends GeolyzerEvent {
/**
- * The relative x coordinate of the column being scanned.
+ * The relative minimal x coordinate of the box being scanned (inclusive).
*/
- public final int scanX;
+ public final int minX;
/**
- * The relative z coordinate of the column being scanned.
+ * The relative minimal y coordinate of the box being scanned (inclusive).
*/
- public final int scanZ;
+ public final int minY;
+
+ /**
+ * The relative minimal z coordinate of the box being scanned (inclusive).
+ */
+ public final int minZ;
+
+ /**
+ * The relative maximal x coordinate of the box being scanned (inclusive).
+ */
+ public final int maxX;
+
+ /**
+ * The relative maximal y coordinate of the box being scanned (inclusive).
+ */
+ public final int maxY;
+
+ /**
+ * The relative maximal z coordinate of the box being scanned (inclusive).
+ */
+ public final int maxZ;
/**
* The data for the column of blocks being scanned, which is an
@@ -56,10 +80,14 @@ public abstract class GeolyzerEvent extends Event {
*/
public final float[] data = new float[64];
- public Scan(EnvironmentHost host, Map, ?> options, int scanX, int scanZ) {
+ public Scan(EnvironmentHost host, Map, ?> options, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
super(host, options);
- this.scanX = scanX;
- this.scanZ = scanZ;
+ this.minX = minX;
+ this.minY = minY;
+ this.minZ = minZ;
+ this.maxX = maxX;
+ this.maxY = maxY;
+ this.maxZ = maxZ;
}
}
diff --git a/src/main/scala/li/cil/oc/common/event/GeolyzerHandler.scala b/src/main/scala/li/cil/oc/common/event/GeolyzerHandler.scala
index 948afffc3..0505083e5 100644
--- a/src/main/scala/li/cil/oc/common/event/GeolyzerHandler.scala
+++ b/src/main/scala/li/cil/oc/common/event/GeolyzerHandler.scala
@@ -15,8 +15,6 @@ object GeolyzerHandler {
def onGeolyzerScan(e: GeolyzerEvent.Scan) {
val world = e.host.world
val blockPos = BlockPosition(e.host)
- val bx = blockPos.x + e.scanX
- val bz = blockPos.z + e.scanZ
val includeReplaceable = e.options.get("includeReplaceable") match {
case value: java.lang.Boolean => value.booleanValue()
case _ => true
@@ -27,16 +25,25 @@ object GeolyzerHandler {
// Map to [-1, 1). The additional /33f is for normalization below.
noise.map(_ / 128f / 33f).copyToArray(e.data)
- for (ry <- 0 until e.data.length) {
- val by = blockPos.y + ry - 32
- if (!world.isAirBlock(bx, by, bz)) {
- val block = world.getBlock(bx, by, bz)
+ val w = e.maxX - e.minX + 1
+ val d = e.maxZ - e.minZ + 1
+ for (ry <- e.minY to e.maxY; rz <- e.minZ to e.maxZ; rx <- e.minX to e.maxX) {
+ val x = blockPos.x + rx
+ val y = blockPos.y + ry
+ val z = blockPos.z + rz
+ val index = (rx - e.minX) + ((rz - e.minZ) + (ry - e.minY) * d) * w
+ if (world.blockExists(x, y, z) && !world.isAirBlock(x, y, z)) {
+ val block = world.getBlock(x, y, z)
if (block != null && (includeReplaceable || isFluid(block) || !block.isReplaceable(world, blockPos.x, blockPos.y, blockPos.z))) {
- e.data(ry) = e.data(ry) * (math.abs(ry - 32) + 1) * Settings.get.geolyzerNoise + block.getBlockHardness(world, bx, by, bz)
+ val dx = blockPos.x - x
+ val dy = blockPos.y - y
+ val dz = blockPos.z - z
+ val distance = math.sqrt(dx * dx + dy * dy + dz * dz).toFloat
+ e.data(index) = e.data(index) * distance * Settings.get.geolyzerNoise + block.getBlockHardness(world, x, y, z)
}
- else e.data(ry) = 0
+ else e.data(index) = 0
}
- else e.data(ry) = 0
+ else e.data(index) = 0
}
}
diff --git a/src/main/scala/li/cil/oc/server/component/Geolyzer.scala b/src/main/scala/li/cil/oc/server/component/Geolyzer.scala
index 4ea1e0a2c..38befe3fc 100644
--- a/src/main/scala/li/cil/oc/server/component/Geolyzer.scala
+++ b/src/main/scala/li/cil/oc/server/component/Geolyzer.scala
@@ -33,25 +33,48 @@ class Geolyzer(val host: EnvironmentHost) extends prefab.ManagedEnvironment {
withConnector().
create()
- @Callback(doc = """function(x:number, z:number[, ignoreReplaceable:boolean|options:table]):table -- Analyzes the density of the column at the specified relative coordinates.""")
+ @Callback(doc = """function(x:number, z:number[, y:number, w:number, d:number, h:number][, ignoreReplaceable:boolean|options:table]):table -- Analyzes the density of the column at the specified relative coordinates.""")
def scan(computer: Context, args: Arguments): Array[AnyRef] = {
- val rx = args.checkInteger(0)
- val rz = args.checkInteger(1)
- val options = if (args.isBoolean(2)) mapAsJavaMap(Map("includeReplaceable" -> !args.checkBoolean(2))) else args.optTable(2, Map.empty[AnyRef, AnyRef])
-
- if (math.abs(rx) > Settings.get.geolyzerRange || math.abs(rz) > Settings.get.geolyzerRange) {
+ val (minX, minY, minZ, maxX, maxY, maxZ, optIndex) = getScanArgs(args)
+ val volume = (maxX - minX + 1) * (maxZ - minZ + 1) * (maxY - minY + 1)
+ if (volume > 64) throw new IllegalArgumentException("volume too large (maximum is 64)")
+ val options = if (args.isBoolean(optIndex)) mapAsJavaMap(Map("includeReplaceable" -> !args.checkBoolean(optIndex))) else args.optTable(optIndex, Map.empty[AnyRef, AnyRef])
+ if (math.abs(minX) > Settings.get.geolyzerRange || math.abs(maxX) > Settings.get.geolyzerRange ||
+ math.abs(minY) > Settings.get.geolyzerRange || math.abs(maxY) > Settings.get.geolyzerRange ||
+ math.abs(minZ) > Settings.get.geolyzerRange || math.abs(maxZ) > Settings.get.geolyzerRange) {
throw new IllegalArgumentException("location out of bounds")
}
if (!node.tryChangeBuffer(-Settings.get.geolyzerScanCost))
return result(Unit, "not enough energy")
- val event = new GeolyzerEvent.Scan(host, options, rx, rz)
+ val event = new GeolyzerEvent.Scan(host, options, minX, minY, minZ, maxX, maxY, maxZ)
MinecraftForge.EVENT_BUS.post(event)
if (event.isCanceled) result(Unit, "scan was canceled")
else result(event.data)
}
+ private def getScanArgs(args: Arguments) = {
+ val minX = args.checkInteger(0)
+ val minZ = args.checkInteger(1)
+ if (args.isInteger(2) && args.isInteger(3) && args.isInteger(4) && args.isInteger(5)) {
+ val minY = args.checkInteger(2)
+ val w = args.checkInteger(3)
+ val d = args.checkInteger(4)
+ val h = args.checkInteger(5)
+ val maxX = minX + w - 1
+ val maxY = minY + h - 1
+ val maxZ = minZ + d - 1
+
+ (math.min(minX, maxX), math.min(minY, maxY), math.min(minZ, maxZ),
+ math.max(minX, maxX), math.max(minY, maxY), math.max(minZ, maxZ),
+ 6)
+ }
+ else {
+ (minX, -32, minZ, minX, 31, minZ, 2)
+ }
+ }
+
@Callback(doc = """function(side:number[,options:table]):table -- Get some information on a directly adjacent block.""")
def analyze(computer: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) {
val side = args.checkSideAny(0)