User Tools

Site Tools


tutorial:1.15:jigsaw

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Last revisionBoth sides next revision
tutorial:jigsaw [2019/10/20 21:01] draylartutorial:1.15:jigsaw [2020/08/15 12:46] – [Jigsaws] emmanuelmess
Line 1: Line 1:
-Jigsaws!+====== Jigsaws ====== 
 +Jigsaws are good for advanced structures such as dungeons & villages, and allow you to spend more time on actually building content vs. messing with procedural generation code. 
  
-Starting: +A repository with finished code can be found [[https://github.com/Draylar/jigsaw-example-mod|here for 1.14]], [[https://github.com/Draylar/jigsaw-example-mod/tree/1.15|here for 1.15]], [[tutorial:jigsaw|here for 1.16]] 
- StructureFeatureclass +
- StructureStart class +
- Piece class+
  
-`Feature` is essentially wrapper for almost any world addition. Almost every generation detail is somehow related to features: +===== Creating StructureFeature =====
- - trees +
- - rocks +
- - dungeons +
- - underground ores+
  
-==== Creating a StructureFeature ==== +A ''StructureFeature'' is an advanced ''Feature'': it keeps track of its location and bounds, and also has the ability to generate itself from a structure file((While you can generate your StructureFeature from a ''.nbt'' file, most vanilla StructureFeatures simply override the ''generate'' method inside their given Piece class.)). If it helps, you can think of it as a ''Structure'' + ''Feature''. We'll need to create one for our jigsaw generated structure. To start, create a class that extends ''StructureFeature<DefaultFeatureConfig>''((AbstractTempleFeature is another option. It automatically spaces out the structures similar to the existing temples-- this logic is also used by villages.)). Feature naming convention is "structure name" + "Feature"; a few vanilla examples are ''EndCityFeature'', ''OceanRuinFeature'', and ''VillageFeature''.
-A ''StructureFeature'' is an advanced ''Feature'': it keeps track of its location and bounds, and also has the ability to generate itself from a structure file((While you can generate your StructureFeature from a ''.nbt'' file, most vanilla StructureFeatures simply override the `generatemethod inside their given Piece class.)). If it helps, you can think of it as a ''Structure'' + ''Feature''. We'll need to create one for our jigsaw generated structure. To start, create a class that extends `StructureFeature<DefaultFeatureConfig>`[2]. Feature naming convention is "structure name" + "Feature"; a few vanilla examples are ''EndCityFeature'', ''OceanRuinFeature'', and ''VillageFeature''.+
  
 //Note: while Feature is the proper name for something generated in the world, we'll refer to our addition as a Structure. This is to distinguish between a StructureFeature and a standard Feature.// //Note: while Feature is the proper name for something generated in the world, we'll refer to our addition as a Structure. This is to distinguish between a StructureFeature and a standard Feature.//
  
-We'll keep the constructor as-is. The `Function<Dynamic<?>>parameter is the structure config-- if you don't have any plans to mess with it, you can simply pass `DefaultFeatureConfig::deserializeinto super:+We'll keep the constructor as-is. The ''Function<Dynamic<?>>'' parameter is the structure config-- if you don't have any plans to mess with it, you can simply pass ''DefaultFeatureConfig::deserialize'' into super:
  
 <code java [enable_line_numbers="false"]> <code java [enable_line_numbers="false"]>
Line 125: Line 118:
  * turns into  * turns into
  
-[jigsaw_blank]+{{ https://i.imgur.com/owaJ0k2.png?nolink&600 |Blank Jigsaw}}
  
 When thinking about this as a puzzle, the target pool is the group of puzzle pieces you can search through. If you have a total of 10 pieces, one target pool may have 7 of the total pieces. This field is how a jigsaw specifies, "Hi, I'd like a piece from group B to connect to me!" In the case of a village, this may be a road saying, "Give me a house!" The target pools of 2 jigsaws do not have to match: the requestor gets to decide who they select from. It is **not** defining what type //the given// jigsaw block is, but rather what type should be on the //other side//. When thinking about this as a puzzle, the target pool is the group of puzzle pieces you can search through. If you have a total of 10 pieces, one target pool may have 7 of the total pieces. This field is how a jigsaw specifies, "Hi, I'd like a piece from group B to connect to me!" In the case of a village, this may be a road saying, "Give me a house!" The target pools of 2 jigsaws do not have to match: the requestor gets to decide who they select from. It is **not** defining what type //the given// jigsaw block is, but rather what type should be on the //other side//.
Line 135: Line 128:
 Here's an example implementation: the given jigsaw will draw from the //tutorial:my_pool// structure pool, looks for any jigsaws with the //tutorial:any// type, and turns into cobblestone when it's done. Here's an example implementation: the given jigsaw will draw from the //tutorial:my_pool// structure pool, looks for any jigsaws with the //tutorial:any// type, and turns into cobblestone when it's done.
  
-[jigsaw_finished]+{{ https://i.imgur.com/f9tP2sv.png?nolink&600 |Example Finished Jigsaw}}
  
 Our finalized structure will consist of multiple colored squares connecting to each other. It will have a white or a black square in the center, and orange, magenta, light blue, and lime squares branching off on the sides randomly. Here is the setup of our 2 initial squares: Our finalized structure will consist of multiple colored squares connecting to each other. It will have a white or a black square in the center, and orange, magenta, light blue, and lime squares branching off on the sides randomly. Here is the setup of our 2 initial squares:
-[pre]+ 
 +{{ https://i.imgur.com/dVFADy8.png?nolink&400 |Initial Squares}}
  
 This jigsaw will ask for any other jigsaw that: This jigsaw will ask for any other jigsaw that:
Line 146: Line 140:
  
 For demo purposes, we've made 2 starting platforms: one is white, and one is black. The only difference is what they turn into. We'll save these as structure files using structure blocks: For demo purposes, we've made 2 starting platforms: one is white, and one is black. The only difference is what they turn into. We'll save these as structure files using structure blocks:
-[bwpost]+ 
 +{{ https://i.imgur.com/31LAORw.png?nolink&400 |Finalized Initial Squares}}
  
 For our randomized edge platforms, we've made 4 extra squares of different colors. Again, despite being used for a different purpose, the jigsaw construction is //the same// aside from the "turns into" field. For our randomized edge platforms, we've made 4 extra squares of different colors. Again, despite being used for a different purpose, the jigsaw construction is //the same// aside from the "turns into" field.
-[post]+ 
 +{{ https://i.imgur.com/OngxweJ.png?nolink&400 |Colored Squares}}
  
 We now have 6 saved ''.nbt'' files. These can be found in our world save folder under ''generated'': We now have 6 saved ''.nbt'' files. These can be found in our world save folder under ''generated'':
-[location]+ 
 +{{ https://i.imgur.com/ZKIoZT9.png?nolink&400 |Saved NBT files}} 
 For usage, we'll move these to ''resources/data/tutorial/structures'', where "tutorial" is your modid: For usage, we'll move these to ''resources/data/tutorial/structures'', where "tutorial" is your modid:
-[destination]+ 
 +{{ https://i.imgur.com/kaiy84U.png?nolink&400 |Moved NBT files}}
  
 The setup is complete! We now have 6 total squares. Let's briefly recap the goal: The setup is complete! We now have 6 total squares. Let's briefly recap the goal:
Line 215: Line 214:
 public void initialize(ChunkGenerator<?> chunkGenerator, StructureManager structureManager, int x, int z, Biome biome) { public void initialize(ChunkGenerator<?> chunkGenerator, StructureManager structureManager, int x, int z, Biome biome) {
     StructurePoolBasedGenerator.addPieces(BASE_POOL, 7, ExamplePiece::new, chunkGenerator, structureManager, new BlockPos(x * 16, 150, z * 16), children, random);     StructurePoolBasedGenerator.addPieces(BASE_POOL, 7, ExamplePiece::new, chunkGenerator, structureManager, new BlockPos(x * 16, 150, z * 16), children, random);
 +    setBoundingBoxFromChildren();
 } }
 </code> </code>
-The Identifier is the starting pool to select from, the int is the size of the entire structure (exact size per 1 is not determined-- is most likely chunks wide), and the 3rd argument is a factory for the piece we'll register in a second.+The Identifier is the starting pool to select from, the int is the size of the entire structure (with 7 being "7 squares out"), and the 3rd argument is a factory for the piece we'll register in a second.
  
 ==== Creating a Piece ==== ==== Creating a Piece ====
Line 239: Line 239:
 We'll need to register our structure as both a feature //and// a structure feature, and also register our piece. Registering your structure as a StructureFeature is optional, and is used for saving it to the chunk. If the world is stopped half-way through your structure loading, having this registered will allow it to continue after the world is re-opened. If it is not registered to a structure feature and this happens, the structure will stop half-way through (which would mostly only occur in larger, multiple chunk wide structures). We'll need to register our structure as both a feature //and// a structure feature, and also register our piece. Registering your structure as a StructureFeature is optional, and is used for saving it to the chunk. If the world is stopped half-way through your structure loading, having this registered will allow it to continue after the world is re-opened. If it is not registered to a structure feature and this happens, the structure will stop half-way through (which would mostly only occur in larger, multiple chunk wide structures).
 <code java [enable_line_numbers="true"]> <code java [enable_line_numbers="true"]>
-public static final Feature<DefaultFeatureConfig> EXAMPLE_FEATURE = Registry.register(+public static final StructureFeature<DefaultFeatureConfig> EXAMPLE_FEATURE = Registry.register(
  Registry.FEATURE,  Registry.FEATURE,
  new Identifier("tutorial", "example_feature"),  new Identifier("tutorial", "example_feature"),
Line 248: Line 248:
  Registry.STRUCTURE_FEATURE,  Registry.STRUCTURE_FEATURE,
  new Identifier("tutorial", "example_structure_feature"),  new Identifier("tutorial", "example_structure_feature"),
- new ExampleFeature(DefaultFeatureConfig::deserialize)+ EXAMPLE_FEATURE
 ); );
  
Line 262: Line 262:
 <code java [enable_line_numbers="false"]> <code java [enable_line_numbers="false"]>
 Registry.BIOME.forEach(biome -> { Registry.BIOME.forEach(biome -> {
- biome.addFeature(GenerationStep.Feature.RAW_GENERATION, Biome.configureFeature(EXAMPLE_FEATURE, new DefaultFeatureConfig()Decorator.NOPEDecoratorConfig.DEFAULT)); + biome.addFeature(GenerationStep.Feature.RAW_GENERATION, EXAMPLE_FEATURE.configure(new DefaultFeatureConfig()).createDecoratedFeature(Decorator.NOPE.configure(DecoratorConfig.DEFAULT))); 
- biome.addStructureFeature(EXAMPLE_STRUCTURE_FEATURE, new DefaultFeatureConfig());+ biome.addStructureFeature(EXAMPLE_FEATURE.configure(new DefaultFeatureConfig()));
 }); });
 </code> </code>
 +
 +=== Finished! ===
 +As you can see, we have a single white square in the center, with boxes going off the edges. Note that the radius in this screenshot was increased to 14 instead of the 7 used in the tutorial.
 +
 +{{ https://i.imgur.com/qndZzZu.png?nolink&600 |Finalized}}
 +=== Jigsaw Tips ===
 +Ideally, you do not want structure pieces to be bigger than 32x32x32, so breaking them into chunk-sized pieces is the best option. 
 +You cannot generate other structure pieces of the same pool through jigsaws. So, if you have a piece in pool A and you try to generate another piece, you will have to have another pool. 
tutorial/1.15/jigsaw.txt · Last modified: 2021/12/28 19:44 by banana