diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md index ad406637..4e0ea027 100644 --- a/docs/scarpet/Full.md +++ b/docs/scarpet/Full.md @@ -689,15 +689,22 @@ number('3bar') => null number('2')+number('2') => 4 -### `str(expr, params? ... ), str(expr, param_list)` +### `str(expr)`,`str(expr, params? ... )`, `str(expr, param_list)` -Returns a formatted string representing expression. Accepts formatting style accepted by `String.format`. -Supported types (with `"%?"` syntax): +If called with one argument, returns string representation of such value. + +Otherwise, returns a formatted string representing the expression. Arguments for formatting can either be provided as + each consecutive parameter, or as a list which then would be the only extra parameter. To format one list argument + , you can use `str(list)`, or `str('foo %s', l(list))`. + +Accepts formatting style accepted by `String.format`. +Supported types (with `"%>"` syntax): * `d`, `o`, `x`: integers, octal, hex * `a`, `e`, `f`, `g`: floats * `b`: booleans * `s`: strings +* `%%`: '%' character
str(null) => null
@@ -2069,13 +2076,17 @@ Returns spawn potential at a location (1.16+ only)
Checks wordgen eligibility for a structure in a given chunk. If no structure is given, or `null`, then it will check
for all structures. If bounding box of the structures is also requested, it will compute size of potential
structures. This function, unlike other in the `structure*` category is not using world data nor accesses chunks
- making it preferred for scoping ungenerated terrain.
+ making it preferred for scoping ungenerated terrain, but it takes some compute money to calculate the structure.
+
+ Unlike `'structure'` this will return a tentative structure location. Random factors in world generation may prevent
+ actual structure from forming.
If structure is specified, it will return `null` if a chunk is not eligible, `true` if the structure should appear, or
-a pair of coordinates indicating bounding box of the structure.
+a map with two values: `'box'` for a pair of coordinates indicating bounding box of the structure, and `'pieces'` for
+list of elements of the structure (as a tuple), with its name, direction, and box coordinates of the piece.
If structure is not specified, it will return a set of structure names that are eligible, or a map with structures
-as keys, and pair of bounding box coordinates as values. An empty set or an empty map would indicate that nothing
+as keys, and same type of map values as with a single structure call. An empty set or an empty map would indicate that nothing
should be generated there.
@@ -2085,7 +2096,8 @@ Returns structure information for a given block position. Note that structure in
blocks from the same chunk. `structures` function can be called with a block, or a block and a structure name. In
the first case it returns a map of structures at a given position, keyed by structure name, with values indicating
the bounding box of the structure - a pair of two 3-value coords (see examples). When called with an extra structure
-name, returns list of components for that structure, with their name, direction and two sets of coordinates
+name, returns a map with two values, `'box'` for bounding box of the structure, and `'pieces'` for a list of
+components for that structure, with their name, direction and two sets of coordinates
indicating the bounding box of the structure piece.
### `structure_references(pos), structure_references(pos, structure_name)`
diff --git a/docs/scarpet/api/BlocksAndWorldAccess.md b/docs/scarpet/api/BlocksAndWorldAccess.md
index 17145b86..e6ae9e39 100644
--- a/docs/scarpet/api/BlocksAndWorldAccess.md
+++ b/docs/scarpet/api/BlocksAndWorldAccess.md
@@ -532,13 +532,17 @@ Returns spawn potential at a location (1.16+ only)
Checks wordgen eligibility for a structure in a given chunk. If no structure is given, or `null`, then it will check
for all structures. If bounding box of the structures is also requested, it will compute size of potential
structures. This function, unlike other in the `structure*` category is not using world data nor accesses chunks
- making it preferred for scoping ungenerated terrain.
+ making it preferred for scoping ungenerated terrain, but it takes some compute money to calculate the structure.
+
+ Unlike `'structure'` this will return a tentative structure location. Random factors in world generation may prevent
+ actual structure from forming.
If structure is specified, it will return `null` if a chunk is not eligible, `true` if the structure should appear, or
-a pair of coordinates indicating bounding box of the structure.
+a map with two values: `'box'` for a pair of coordinates indicating bounding box of the structure, and `'pieces'` for
+list of elements of the structure (as a tuple), with its name, direction, and box coordinates of the piece.
If structure is not specified, it will return a set of structure names that are eligible, or a map with structures
-as keys, and pair of bounding box coordinates as values. An empty set or an empty map would indicate that nothing
+as keys, and same type of map values as with a single structure call. An empty set or an empty map would indicate that nothing
should be generated there.
@@ -548,7 +552,8 @@ Returns structure information for a given block position. Note that structure in
blocks from the same chunk. `structures` function can be called with a block, or a block and a structure name. In
the first case it returns a map of structures at a given position, keyed by structure name, with values indicating
the bounding box of the structure - a pair of two 3-value coords (see examples). When called with an extra structure
-name, returns list of components for that structure, with their name, direction and two sets of coordinates
+name, returns a map with two values, `'box'` for bounding box of the structure, and `'pieces'` for a list of
+components for that structure, with their name, direction and two sets of coordinates
indicating the bounding box of the structure piece.
### `structure_references(pos), structure_references(pos, structure_name)`
diff --git a/src/main/java/carpet/helpers/FeatureGenerator.java b/src/main/java/carpet/helpers/FeatureGenerator.java
index 98f47007..4efc2b76 100644
--- a/src/main/java/carpet/helpers/FeatureGenerator.java
+++ b/src/main/java/carpet/helpers/FeatureGenerator.java
@@ -154,10 +154,9 @@ public class FeatureGenerator
return null;
}
- public static BlockBox DEFAULT_BOX = new BlockBox(0,0,0,1,1,1);
- public static BlockBox shouldStructureStartAt(ServerWorld world, BlockPos pos, StructureFeature> structure, boolean computeBox)
+ public static StructureStart shouldStructureStartAt(ServerWorld world, BlockPos pos, StructureFeature> structure, boolean computeBox)
{
- ChunkGenerator generator = world.getChunkManager().getChunkGenerator();
+ ChunkGenerator> generator = world.getChunkManager().getChunkGenerator();
if (!generator.getBiomeSource().hasStructureFeature(structure))
return null;
BiomeAccess biomeAccess = world.getBiomeAccess().withSource(generator.getBiomeSource());
@@ -166,12 +165,12 @@ public class FeatureGenerator
Biome biome = biomeAccess.getBiome(new BlockPos(chunkPos.getStartX() + 9, 0, chunkPos.getStartZ() + 9));
if (structure.method_27217(biomeAccess, generator, chunkRandom, chunkPos.x, chunkPos.z, biome)) // should start at
{
- if (!computeBox) return DEFAULT_BOX;
+ if (!computeBox) return StructureStart.DEFAULT;
StructureManager manager = world.getStructureManager();
StructureStart structureStart3 = structure.getStructureStartFactory().create(structure, chunkPos.x, chunkPos.z, BlockBox.empty(), 0, generator.getSeed());
structureStart3.init(generator, manager, chunkPos.x, chunkPos.z, biome);
if (!structureStart3.hasChildren()) return null;
- return structureStart3.getBoundingBox();
+ return structureStart3;
}
return null;
}
diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java
index 989cc0f5..0a8cf83b 100644
--- a/src/main/java/carpet/script/CarpetExpression.java
+++ b/src/main/java/carpet/script/CarpetExpression.java
@@ -398,6 +398,32 @@ public class CarpetExpression
}
}
+
+
+ private static Value structureToValue(StructureStart structure)
+ {
+ if (structure == null || structure == StructureStart.DEFAULT) return Value.NULL;
+ List pieces = new ArrayList<>();
+ for (StructurePiece piece : structure.getChildren())
+ {
+ BlockBox box = piece.getBoundingBox();
+ pieces.add(ListValue.of(
+ new StringValue( NBTSerializableValue.nameFromRegistryId(Registry.STRUCTURE_PIECE.getId(piece.getType()))),
+ (piece.getFacing()== null)?Value.NULL: new StringValue(piece.getFacing().getName()),
+ ListValue.fromTriple(box.minX, box.minY, box.minZ),
+ ListValue.fromTriple(box.maxX, box.maxY, box.maxZ)
+ ));
+ };
+ BlockBox boundingBox = structure.getBoundingBox();
+ Map ret = new HashMap<>();
+ ret.put(new StringValue("box"), ListValue.of(
+ ListValue.fromTriple(boundingBox.minX, boundingBox.minY, boundingBox.minZ),
+ ListValue.fromTriple(boundingBox.maxX, boundingBox.maxY, boundingBox.maxZ)
+ ));
+ ret.put(new StringValue("pieces"), ListValue.wrap(pieces));
+ return MapValue.wrap(ret);
+ }
+
private void API_BlockManipulation()
{
this.expr.addLazyFunction("block", -1, (c, t, lv) ->
@@ -1148,25 +1174,20 @@ public class CarpetExpression
}
if (structure != null)
{
- BlockBox box = FeatureGenerator.shouldStructureStartAt(world, pos, structure, needSize);
- if (box == null) return LazyValue.NULL;
+ StructureStart start = FeatureGenerator.shouldStructureStartAt(world, pos, structure, needSize);
+ if (start == null) return LazyValue.NULL;
if (!needSize) return LazyValue.TRUE;
- Value ret = ListValue.of(
- ListValue.of(new NumericValue(box.minX), new NumericValue(box.minY), new NumericValue(box.minZ)),
- ListValue.of(new NumericValue(box.maxX), new NumericValue(box.maxY), new NumericValue(box.maxZ))
- );
+ Value ret = structureToValue(start);
return (_c, _t) -> ret;
}
Map ret = new HashMap<>();
for(StructureFeature> str : Feature.STRUCTURES.values())
{
- BlockBox box = FeatureGenerator.shouldStructureStartAt(world, pos, str, needSize);
- if (box == null) continue;
+ StructureStart start = FeatureGenerator.shouldStructureStartAt(world, pos, str, needSize);
+ if (start == null) continue;
+
Value key = new StringValue(FeatureGenerator.structureToFeature.get(str.getName()).get(0));
- ret.put(key, (!needSize)?Value.NULL:ListValue.of(
- ListValue.of(new NumericValue(box.minX), new NumericValue(box.minY), new NumericValue(box.minZ)),
- ListValue.of(new NumericValue(box.maxX), new NumericValue(box.maxY), new NumericValue(box.maxZ))
- ));
+ ret.put(key, (!needSize)?Value.NULL:structureToValue(start));
}
Value retMap = MapValue.wrap(ret);
return (_c, _t) -> retMap;
@@ -1188,28 +1209,17 @@ public class CarpetExpression
if (start == StructureStart.DEFAULT)
continue;
BlockBox box = start.getBoundingBox();
- ListValue coord1 = ListValue.of(new NumericValue(box.minX), new NumericValue(box.minY), new NumericValue(box.minZ));
- ListValue coord2 = ListValue.of(new NumericValue(box.maxX), new NumericValue(box.maxY), new NumericValue(box.maxZ));
- structureList.put(new StringValue(FeatureGenerator.structureToFeature.get(entry.getKey()).get(0)), ListValue.of(coord1, coord2));
+ structureList.put(
+ new StringValue(FeatureGenerator.structureToFeature.get(entry.getKey()).get(0)),
+ ListValue.of(ListValue.fromTriple(box.minX, box.minY, box.minZ), ListValue.fromTriple(box.maxX, box.maxY, box.maxZ))
+ );
}
Value ret = MapValue.wrap(structureList);
return (_c, _t) -> ret;
}
String structureName = lv.get(locator.offset).evalValue(c).getString().toLowerCase(Locale.ROOT);
StructureStart start = structures.get(FeatureGenerator.featureToStructure.get(structureName));
- if (start == null || start == StructureStart.DEFAULT) return LazyValue.NULL;
- List pieces = new ArrayList<>();
- for (StructurePiece piece : start.getChildren())
- {
- BlockBox box = piece.getBoundingBox();
- pieces.add(ListValue.of(
- new StringValue( NBTSerializableValue.nameFromRegistryId(Registry.STRUCTURE_PIECE.getId(piece.getType()))),
- (piece.getFacing()== null)?Value.NULL: new StringValue(piece.getFacing().getName()),
- ListValue.of(new NumericValue(box.minX), new NumericValue(box.minY), new NumericValue(box.minZ)),
- ListValue.of(new NumericValue(box.maxX), new NumericValue(box.maxY), new NumericValue(box.maxZ))
- ));
- }
- Value ret = ListValue.wrap(pieces);
+ Value ret = structureToValue(start);
return (_c, _t) -> ret;
});
diff --git a/src/main/java/carpet/script/value/ListValue.java b/src/main/java/carpet/script/value/ListValue.java
index 2d1ac5dc..e20d32b3 100644
--- a/src/main/java/carpet/script/value/ListValue.java
+++ b/src/main/java/carpet/script/value/ListValue.java
@@ -75,6 +75,18 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
);
}
+ public static Value fromTriple(double a, double b, double c)
+ {
+ return ListValue.of(new NumericValue(a), new NumericValue(b), new NumericValue(c));
+ }
+
+ public static Value fromTriple(int a, int b, int c)
+ {
+ return fromTriple((double) a, b, c);
+ }
+
+
+
public static ListValue wrap(List list)
{
diff --git a/src/main/resources/assets/carpet/scripts/overlay.sc b/src/main/resources/assets/carpet/scripts/overlay.sc
index 6868fb91..0b501051 100644
--- a/src/main/resources/assets/carpet/scripts/overlay.sc
+++ b/src/main/resources/assets/carpet/scripts/overlay.sc
@@ -93,7 +93,7 @@ __structure_renderer(player_name) ->
for (starts, l(position, name) = _;
structure_data = structures(position):name;
if (!structure_data, continue()); // messed up references - shouldn't happen
- structure_pieces = structures(position, name);
+ structure_pieces = structures(position, name):'pieces';
if (!structure_pieces, continue()); // messed up references - shouldn't happen
l(from, to) = structure_data;
total_size = _euclidean(from, to);