From 81ae5bbb40481163c959287bbb56b0446be13eb5 Mon Sep 17 00:00:00 2001 From: gnembon Date: Mon, 7 Sep 2020 01:26:23 -0300 Subject: [PATCH] poi can query in square column as well. --- docs/scarpet/api/BlocksAndWorldAccess.md | 17 +++++--- .../java/carpet/script/CarpetExpression.java | 40 ++++++++++++------- 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/docs/scarpet/api/BlocksAndWorldAccess.md b/docs/scarpet/api/BlocksAndWorldAccess.md index 6675bf01..fbfc197f 100644 --- a/docs/scarpet/api/BlocksAndWorldAccess.md +++ b/docs/scarpet/api/BlocksAndWorldAccess.md @@ -261,15 +261,20 @@ used to match specific information from it, or use it to copy to another block
    block_data(x,y,z) => '{TransferCooldown:0,x:450,y:68, ... }'
 
-### `poi(pos), poi(pos, radius), poi(pos, radius, status)` +### `poi(pos), poi(pos, radius?, type?, status?, column?)` Queries a POI (Point of Interest) at a given position, returning `null` if none is found, or tuple of poi type and its -occupancy load. With optional `radius` and `status`, returns a list of POIs around `pos` within a given `radius`. -If `status` is specified (either 'available', or 'occupied') returns only POIs with that status. The return format is -again, poi type, occupancy load, and extra tripple of coordinates. +occupancy load. With optional `type`, `radius` and `status`, returns a list of POIs around `pos` within a +given `radius`. If the `type` is specified, returns only poi types of that types, or everything if omitted or `'any'`. +If `status` is specified (either `'any'`, `'available'`, or `'occupied'`) returns only POIs with that status. +With `column` set to `true`, it will return all POIs in a cuboid with `radius` blocks away on x and z, in the entire +block column from 0 to 255. Default (`false`) returns POIs within a spherical area centered on `pos` and with `radius` +radius. -Querying for POIs using the radius is intended use of POI mechanics and ability of accessing individual POIs -via `poi(pos)` in only provided for completness. +The return format of the results is a list of poi type, occupancy load, and extra triple of coordinates. + +Querying for POIs using the radius is the intended use of POI mechanics, and the ability of accessing individual POIs +via `poi(pos)` in only provided for completeness.
 poi(x,y,z) => null  // nothing set at position
diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java
index b481df3e..fb661ec9 100644
--- a/src/main/java/carpet/script/CarpetExpression.java
+++ b/src/main/java/carpet/script/CarpetExpression.java
@@ -164,6 +164,7 @@ import java.util.concurrent.CompletionException;
 import java.util.function.BiFunction;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import static carpet.script.utils.WorldTools.canHasChunk;
 import static java.lang.Math.abs;
@@ -401,7 +402,7 @@ public class CarpetExpression
             return (c_, t_) -> retval;
         });
 
-        // poi_get(pos, radius?, type?, occupation?)
+        // poi_get(pos, radius?, type?, occupation?, column_mode?)
         this.expr.addLazyFunction("poi", -1, (c, t, lv) ->
         {
             CarpetContext cc = (CarpetContext) c;
@@ -431,9 +432,11 @@ public class CarpetExpression
                 );
                 return (_c, _t) -> ret;
             }
-            long radius = NumericValue.asNumber(lv.get(locator.offset+0).evalValue(c)).getLong();
+            int radius = NumericValue.asNumber(lv.get(locator.offset+0).evalValue(c)).getInt();
             if (radius < 0) return ListValue.lazyEmpty();
             Predicate condition = PointOfInterestType.ALWAYS_TRUE;
+            PointOfInterestStorage.OccupationStatus status = PointOfInterestStorage.OccupationStatus.ANY;
+            boolean inColumn = false;
             if (locator.offset + 1 < lv.size())
             {
                 String poiType = lv.get(locator.offset+1).evalValue(c).getString().toLowerCase(Locale.ROOT);
@@ -443,20 +446,27 @@ public class CarpetExpression
                     if (type == PointOfInterestType.UNEMPLOYED && !"unemployed".equals(poiType)) return LazyValue.NULL;
                     condition = (tt) -> tt == type;
                 }
+                if (locator.offset + 2 < lv.size())
+                {
+                    String statusString = lv.get(locator.offset+2).evalValue(c).getString().toLowerCase(Locale.ROOT);
+                    if ("occupied".equals(statusString))
+                        status = PointOfInterestStorage.OccupationStatus.IS_OCCUPIED;
+                    else if ("available".equals(statusString))
+                        status = PointOfInterestStorage.OccupationStatus.HAS_SPACE;
+                    else if (!("any".equals(statusString)))
+                        throw new InternalExpressionException(
+                                "Incorrect POI occupation status "+status+ " use `any`, " + "`occupied` or `available`"
+                        );
+                    if (locator.offset + 3 < lv.size())
+                    {
+                        inColumn = lv.get(locator.offset+3).evalValue(c, Context.BOOLEAN).getBoolean();
+                    }
+                }
             }
-            PointOfInterestStorage.OccupationStatus status = PointOfInterestStorage.OccupationStatus.ANY;
-            if (locator.offset + 2 < lv.size())
-            {
-                String statusString = lv.get(locator.offset+2).evalValue(c).getString().toLowerCase(Locale.ROOT);
-                if ("occupied".equals(statusString))
-                    status = PointOfInterestStorage.OccupationStatus.IS_OCCUPIED;
-                else if ("available".equals(statusString))
-                    status = PointOfInterestStorage.OccupationStatus.HAS_SPACE;
-                else
-                    return LazyValue.NULL;
-            }
-
-            Value ret = ListValue.wrap(store.getInCircle(condition, pos, (int)radius, status).sorted(Comparator.comparingDouble(p -> p.getPos().getSquaredDistance(pos))).map(p ->
+            Stream pois = inColumn?
+                    store.getInSquare(condition, pos, radius, status):
+                    store.getInCircle(condition, pos, radius, status);
+            Value ret = ListValue.wrap(pois.sorted(Comparator.comparingDouble(p -> p.getPos().getSquaredDistance(pos))).map(p ->
                     ListValue.of(
                             new StringValue(p.getType().toString()),
                             new NumericValue(p.getType().getTicketCount() - ((PointOfInterest_scarpetMixin)p).getFreeTickets()),