diff --git a/src/main/java/carpet/fakes/StructureFeatureInterface.java b/src/main/java/carpet/fakes/StructureFeatureInterface.java
index 07906a04..f97b7eee 100644
--- a/src/main/java/carpet/fakes/StructureFeatureInterface.java
+++ b/src/main/java/carpet/fakes/StructureFeatureInterface.java
@@ -8,5 +8,6 @@ import net.minecraft.world.gen.chunk.ChunkGeneratorConfig;
public interface StructureFeatureInterface
{
boolean plopAnywhere(ServerWorld world, BlockPos pos);
- boolean plopAnywhere(ServerWorld world, BlockPos pos, ChunkGenerator extends ChunkGeneratorConfig> generator);
+ boolean gridAnywhere(ServerWorld world, BlockPos pos);
+ boolean plopAnywhere(ServerWorld world, BlockPos pos, ChunkGenerator extends ChunkGeneratorConfig> generator, boolean wireOnly);
}
diff --git a/src/main/java/carpet/helpers/FeatureGenerator.java b/src/main/java/carpet/helpers/FeatureGenerator.java
index 21d9898e..63cbcb93 100644
--- a/src/main/java/carpet/helpers/FeatureGenerator.java
+++ b/src/main/java/carpet/helpers/FeatureGenerator.java
@@ -37,7 +37,10 @@ import net.minecraft.world.gen.feature.VillageFeatureConfig;
import net.minecraft.world.gen.foliage.BlobFoliagePlacer;
import net.minecraft.world.gen.stateprovider.SimpleStateProvider;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -79,6 +82,14 @@ public class FeatureGenerator
private static Thing spawnCustomStructure(StructureFeature structure, FeatureConfig conf, Biome biome)
{
+ return setupCustomStructure(structure, conf, biome, false);
+ }
+ private static Thing gridCustomStructure(StructureFeature structure, FeatureConfig conf, Biome biome)
+ {
+ return setupCustomStructure(structure, conf, biome, true);
+ }
+ private static Thing setupCustomStructure(StructureFeature structure, FeatureConfig conf, Biome biome, boolean wireOnly)
+ {
//if (1+2==3)
// throw new RuntimeException("rebuild me");
return (w, p) -> {
@@ -111,7 +122,7 @@ public class FeatureGenerator
};
- return ((StructureFeatureInterface)structure).plopAnywhere(w, p, chunkgen);
+ return ((StructureFeatureInterface)structure).plopAnywhere(w, p, chunkgen, wireOnly);
};
}
@@ -123,6 +134,78 @@ public class FeatureGenerator
}
public static void noop() {System.out.println("boo");}
+ public static Boolean gridStructure(String name, World world, BlockPos pos)
+ {
+ if (gridMap.containsKey(name))
+ return gridMap.get(name).plop(world, pos);
+ return null;
+ }
+
+
+ public static final Map> structureToBuilding = new HashMap<>();
+ public static final Map buildingToStructure = new HashMap<>();
+ static
+ {
+ structureToBuilding.put("Monument", Collections.singletonList("monument"));
+ structureToBuilding.put("EndCity", Collections.singletonList("end_city"));
+ structureToBuilding.put("Ocean_Ruin", Arrays.asList("oceanruin", "oceanruin_warm", "oceanruin_small", "oceanruin_warm_small", "oceanruin_tall", "oceanruin_warm_tall"));
+ structureToBuilding.put("Village", Arrays.asList("village", "village_desert", "village_savanna", "village_taiga", "village_snowy"));
+ structureToBuilding.put("Mansion", Collections.singletonList("mansion"));
+ structureToBuilding.put("Buried_Treasure", Collections.singletonList("treasure"));
+ structureToBuilding.put("Swamp_Hut", Collections.singletonList("witchhut"));
+ structureToBuilding.put("Stronghold", Collections.singletonList("stronghold"));
+ structureToBuilding.put("Desert_Pyramid", Collections.singletonList("desert_temple"));
+ structureToBuilding.put("Jungle_Pyramid", Collections.singletonList("jungle_temple"));
+ structureToBuilding.put("Shipwreck", Arrays.asList("shipwreck", "shipwreck2"));
+ structureToBuilding.put("Pillager_Outpost", Collections.singletonList("pillager_outpost"));
+ structureToBuilding.put("Mineshaft", Arrays.asList("mineshaft", "mineshaft_mesa"));
+ structureToBuilding.put("Igloo", Collections.singletonList("igloo"));
+
+ structureToBuilding.forEach((key, value) -> value.forEach(el -> buildingToStructure.put(el, key)));
+ }
+
+
+ private static final Map gridMap = new HashMap() {{
+ put("monument", ((StructureFeatureInterface)Feature.OCEAN_MONUMENT)::gridAnywhere);
+ put("fortress", ((StructureFeatureInterface)Feature.NETHER_BRIDGE)::gridAnywhere);
+ put("mansion", ((StructureFeatureInterface)Feature.WOODLAND_MANSION)::gridAnywhere);
+ put("jungle_temple", ((StructureFeatureInterface)Feature.JUNGLE_TEMPLE)::gridAnywhere);
+ put("desert_temple", ((StructureFeatureInterface)Feature.DESERT_PYRAMID)::gridAnywhere);
+ put("end_city", ((StructureFeatureInterface)Feature.END_CITY)::gridAnywhere);
+ put("igloo", ((StructureFeatureInterface)Feature.IGLOO)::gridAnywhere);
+ put("shipwreck", gridCustomStructure(Feature.SHIPWRECK, new ShipwreckFeatureConfig(true), Biomes.PLAINS));
+ put("shipwreck2", gridCustomStructure(Feature.SHIPWRECK, new ShipwreckFeatureConfig(false), Biomes.PLAINS));
+ put("witchhut", ((StructureFeatureInterface)Feature.SWAMP_HUT)::gridAnywhere);
+ put("stronghold", ((StructureFeatureInterface)Feature.STRONGHOLD)::gridAnywhere);
+
+ put("oceanruin_small", gridCustomStructure(Feature.OCEAN_RUIN,
+ new OceanRuinFeatureConfig(OceanRuinFeature.BiomeType.COLD, 0.0F, 0.5F), Biomes.PLAINS));
+ put("oceanruin_warm_small", gridCustomStructure(Feature.OCEAN_RUIN,
+ new OceanRuinFeatureConfig(OceanRuinFeature.BiomeType.WARM, 0.0F, 0.5F), Biomes.PLAINS));
+ put("oceanruin_tall", gridCustomStructure(Feature.OCEAN_RUIN,
+ new OceanRuinFeatureConfig(OceanRuinFeature.BiomeType.COLD, 1.0F, 0.0F), Biomes.PLAINS));
+ put("oceanruin_warm_tall", gridCustomStructure(Feature.OCEAN_RUIN,
+ new OceanRuinFeatureConfig(OceanRuinFeature.BiomeType.WARM, 1.0F, 0.0F), Biomes.PLAINS));
+ put("oceanruin", gridCustomStructure(Feature.OCEAN_RUIN,
+ new OceanRuinFeatureConfig(OceanRuinFeature.BiomeType.COLD, 1.0F, 1.0F), Biomes.PLAINS));
+ put("oceanruin_warm", gridCustomStructure(Feature.OCEAN_RUIN,
+ new OceanRuinFeatureConfig(OceanRuinFeature.BiomeType.WARM, 1.0F, 1.0F), Biomes.PLAINS));
+ put("treasure", ((StructureFeatureInterface)Feature.BURIED_TREASURE)::gridAnywhere);
+
+ put("pillager_outpost", ((StructureFeatureInterface)Feature.PILLAGER_OUTPOST)::gridAnywhere);
+
+
+ put("mineshaft", gridCustomStructure(Feature.MINESHAFT, new MineshaftFeatureConfig(0.0, MineshaftFeature.Type.NORMAL), Biomes.PLAINS));
+ put("mineshaft_mesa", gridCustomStructure(Feature.MINESHAFT, new MineshaftFeatureConfig(0.0, MineshaftFeature.Type.MESA), Biomes.PLAINS));
+
+ put("village", gridCustomStructure(Feature.VILLAGE, new VillageFeatureConfig("village/plains/town_centers",6), Biomes.PLAINS));
+ put("village_desert", gridCustomStructure(Feature.VILLAGE, new VillageFeatureConfig("village/desert/town_centers", 6), Biomes.PLAINS));
+ put("village_savanna", gridCustomStructure(Feature.VILLAGE, new VillageFeatureConfig("village/savanna/town_centers", 6), Biomes.PLAINS));
+ put("village_taiga", gridCustomStructure(Feature.VILLAGE, new VillageFeatureConfig("village/taiga/town_centers", 6), Biomes.PLAINS));
+ put("village_snowy", gridCustomStructure(Feature.VILLAGE, new VillageFeatureConfig("village/snowy/town_centers", 6), Biomes.PLAINS));
+
+ }};
+
private static final Map featureMap = new HashMap() {{
diff --git a/src/main/java/carpet/mixins/StructureFeatureMixin.java b/src/main/java/carpet/mixins/StructureFeatureMixin.java
index 52c78523..deb70aa7 100644
--- a/src/main/java/carpet/mixins/StructureFeatureMixin.java
+++ b/src/main/java/carpet/mixins/StructureFeatureMixin.java
@@ -35,10 +35,17 @@ public abstract class StructureFeatureMixin implements StructureFeatureInterface
@Override
public boolean plopAnywhere(ServerWorld world, BlockPos pos)
{
- return plopAnywhere(world, pos, world.getChunkManager().getChunkGenerator());
+ return plopAnywhere(world, pos, world.getChunkManager().getChunkGenerator(), false);
}
@Override
public boolean plopAnywhere(ServerWorld world, BlockPos pos, ChunkGenerator extends ChunkGeneratorConfig> generator)
+ @Override
+ public boolean gridAnywhere(ServerWorld world, BlockPos pos)
+ {
+ return plopAnywhere(world, pos, world.getChunkManager().getChunkGenerator(), true);
+ }
+
+ public boolean plopAnywhere(IWorld world, BlockPos pos, ChunkGenerator extends ChunkGeneratorConfig> generator, boolean wireOnly)
{
if (world.isClient())
return false;
@@ -50,7 +57,7 @@ public abstract class StructureFeatureMixin implements StructureFeatureInterface
int k = pos.getZ() >> 4;
long chId = ChunkPos.toLong(j, k);
StructureStart structurestart = forceStructureStart(world, generator, rand, chId);
- if (structurestart == null || structurestart == StructureStart.DEFAULT)
+ if (structurestart == StructureStart.DEFAULT)
{
return false;
}
@@ -59,17 +66,20 @@ public abstract class StructureFeatureMixin implements StructureFeatureInterface
world.getChunk(j, k).addStructureReference(this.getName(), chId); //, ChunkStatus.STRUCTURE_STARTS
BlockBox box = structurestart.getBoundingBox();
- structurestart.generateStructure(
- world,
- generator,
+ if (!wireOnly)
+ {
+ structurestart.generateStructure(
+ world,
+ generator,
rand,
new BlockBox(
- pos.getX() - this.getRadius()*16,
- pos.getZ() - this.getRadius()*16,
- pos.getX() + (this.getRadius()+1)*16,
- pos.getZ() + (1+this.getRadius())*16),
- new ChunkPos(j, k)
- );
+ pos.getX() - this.getRadius() * 16,
+ pos.getZ() - this.getRadius() * 16,
+ pos.getX() + (this.getRadius() + 1) * 16,
+ pos.getZ() + (1 + this.getRadius()) * 16),
+ new ChunkPos(j, k)
+ );
+ }
//structurestart.notifyPostProcessAt(new ChunkPos(j, k));
int i = getRadius();
diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java
index 159175bd..c4824920 100644
--- a/src/main/java/carpet/script/CarpetExpression.java
+++ b/src/main/java/carpet/script/CarpetExpression.java
@@ -647,7 +647,7 @@ public class CarpetExpression
* and structure_starts. Returns null if the chunk is not in memory unless called with optional
* true.
* structures(pos), structures(pos, structure_name)
- * Returns structure information for a given block position. Note that strucuture information is the same for
+ *
Returns structure information for a given block position. Note that structure information is the same for
* all the 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
@@ -659,6 +659,11 @@ public class CarpetExpression
* a structure name. In the first case it returns a list of structure names that give chunk belongs to. When
* called with an extra structure name, returns list of positions pointing to the lowest block position in chunks that
* hold structure starts for these structures. You can query that chunk structures then to get its bounding boxes.
+ * structure_set(pos, structure_name), structure_set(pos, structure_name, null)
+ * Creates or removes structure information of a structure associated with a chunk of pos.
+ * Unlike plop, blocks are not placed in the world, only structure information is set. For the game this is a fully
+ * functional structure even if blocks are not set.. To remove structure a given point is in,
+ * use structure_references to find where current structure starts.
* suffocates(pos)
* Boolean function, true if the block causes suffocation.
@@ -900,7 +905,11 @@ public class CarpetExpression
PointOfInterestStorage store = cc.s.getWorld().getPointOfInterestStorage();
if (poi == Value.NULL)
{ // clear poi information
- if (store.getType(pos).isPresent()) store.remove(pos);
+ if (store.getType(pos).isPresent())
+ {
+ store.remove(pos);
+ return LazyValue.TRUE;
+ }
return LazyValue.NULL;
}
String poiTypeString = poi.getString().toLowerCase(Locale.ROOT);
@@ -927,7 +936,7 @@ public class CarpetExpression
for (int i=0; i < finalO; i++) ((PointOfInterest_scarpetMixin)p).callReserveTicket();
});
}
- return LazyValue.NULL;
+ return LazyValue.TRUE;
});
@@ -1398,10 +1407,11 @@ public class CarpetExpression
{
List referenceList = references.entrySet().stream().
filter(e -> e.getValue()!= null && !e.getValue().isEmpty()).
- map(e -> new StringValue(e.getKey())).collect(Collectors.toList());
+ map(e -> new StringValue(FeatureGenerator.structureToBuilding.get(e.getKey()).get(0))).collect(Collectors.toList());
return (_c, _t ) -> ListValue.wrap(referenceList);
}
- String structureName = lv.get(locator.offset).evalValue(c).getString();
+ String simpleStructureName = lv.get(locator.offset).evalValue(c).getString().toLowerCase(Locale.ROOT);
+ String structureName = FeatureGenerator.buildingToStructure.get(simpleStructureName);
LongSet structureReferences = references.get(structureName);
if (structureReferences == null || structureReferences.isEmpty())
{
@@ -1424,7 +1434,7 @@ public class CarpetExpression
Map structures = world.getChunk(pos).getStructureStarts();
if (lv.size() == locator.offset)
{
- Map strucutureList = new HashMap<>();
+ Map structureList = new HashMap<>();
for (Map.Entry entry : structures.entrySet())
{
StructureStart start = entry.getValue();
@@ -1433,13 +1443,13 @@ public class CarpetExpression
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));
- strucutureList.put(new StringValue(entry.getKey()), ListValue.of(coord1, coord2));
+ structureList.put(new StringValue(FeatureGenerator.structureToBuilding.get(entry.getKey()).get(0)), ListValue.of(coord1, coord2));
}
- Value ret = MapValue.wrap(strucutureList);
+ Value ret = MapValue.wrap(structureList);
return (_c, _t) -> ret;
}
- String structureName = lv.get(locator.offset).evalValue(c).getString();
- StructureStart start = structures.get(structureName);
+ String structureName = lv.get(locator.offset).evalValue(c).getString().toLowerCase(Locale.ROOT);
+ StructureStart start = structures.get(FeatureGenerator.buildingToStructure.get(structureName));
if (start == null || start == StructureStart.DEFAULT)
return (_c, _t) -> Value.NULL;
List pieces = new ArrayList<>();
@@ -1456,8 +1466,61 @@ public class CarpetExpression
Value ret = ListValue.wrap(pieces);
return (_c, _t) -> ret;
});
- // need get_biome
+ this.expr.addLazyFunction("structure_set", -1, (c, t, lv) ->
+ {
+ CarpetContext cc = (CarpetContext)c;
+ BlockValue.LocatorResult locator = BlockValue.fromParams(cc, lv, 0);
+
+ ServerWorld world = cc.s.getWorld();
+ BlockPos pos = locator.block.getPos();
+
+ if (lv.size() == locator.offset)
+ throw new InternalExpressionException("'structure_set requires at least position and a structure name");
+ String simpleStructureName = lv.get(locator.offset).evalValue(c).getString().toLowerCase(Locale.ROOT);
+ String structureName = FeatureGenerator.buildingToStructure.get(simpleStructureName);
+
+ Value[] result = new Value[]{Value.NULL};
+ ((CarpetContext) c).s.getMinecraftServer().executeSync(() ->
+ {
+ Map structures = world.getChunk(pos).getStructureStarts();
+ if (lv.size() == locator.offset + 1)
+ {
+ //if (newValue.getString().equalsIgnoreCase("default"))
+ // spawn default structure for location
+ Boolean res = FeatureGenerator.gridStructure(simpleStructureName, ((CarpetContext) c).s.getWorld(), locator.block.getPos());
+ if (res == null) return;
+ result[0] = res?Value.TRUE:Value.FALSE;
+ return;
+ }
+ Value newValue = lv.get(locator.offset+1).evalValue(c);
+ if (newValue instanceof NullValue) // remove structure
+ {
+ if (!structures.containsKey(structureName))
+ {
+ return;
+ }
+ StructureStart start = structures.get(structureName);
+ ChunkPos structureChunkPos = new ChunkPos(start.getChunkX(), start.getChunkZ());
+ MutableIntBoundingBox box = start.getBoundingBox();
+ for (int chx = box.minX / 16; chx <= box.maxX / 16; chx++)
+ {
+ for (int chz = box.minZ / 16; chz <= box.maxZ / 16; chz++)
+ {
+ ChunkPos chpos = new ChunkPos(chx, chz);
+ // getting a chunk will convert it to full, allowing to modify references
+ Map references = world.getChunk(chpos.getCenterBlockPos()).getStructureReferences();
+ if (references.containsKey(structureName) && references.get(structureName) != null)
+ references.get(structureName).remove(structureChunkPos.toLong());
+ }
+ }
+ structures.remove(structureName);
+ result[0] = Value.TRUE;
+ }
+ });
+ Value ret = result[0]; // preventing from lazy evaluating of the result in case a future completes later
+ return (_c, _t) -> ret;
+ });
}
/**