tutorial:structures_old
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| tutorial:structures_old [2024/08/25 13:35] – removed - external edit (Unknown date) 127.0.0.1 | tutorial:structures_old [2024/08/25 13:52] (current) – ↷ Links adapted because of a move operation 52.167.144.180 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== Adding Structure Features [1.16.3] ====== | ||
| + | :!: //**For versions 1.18 and beyond, the Fabric Structure API no longer exists and structures can be done entirely in datapacks. See [[https:// | ||
| + | |||
| + | We’re going to look at registering and placing structures in your world. | ||
| + | |||
| + | To view examples of vanilla structures in action, '' | ||
| + | |||
| + | You are going to need a feature and generator for the most basic structure. | ||
| + | The feature handles the process of registering the structure and loading it in when the world is generating. | ||
| + | The generator handles the placement of blocks or loading in a structure file if you choose to do so. | ||
| + | |||
| + | Note that this tutorial depends on [[https:// | ||
| + | If the API doesn' | ||
| + | |||
| + | ===== Creating a Feature ===== | ||
| + | To create a basic feature, we recommend creating a class that extends '' | ||
| + | Various vanilla structures, such as shipwrecks, igloos, and temples, use '' | ||
| + | |||
| + | You will have to override '' | ||
| + | For '' | ||
| + | |||
| + | <code java> | ||
| + | public class MyFeature extends StructureFeature< | ||
| + | public MyFeature(Codec< | ||
| + | super(codec); | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | public StructureFeature.StructureStartFactory< | ||
| + | return Start::new; | ||
| + | } | ||
| + | |||
| + | public static class Start extends StructureStart< | ||
| + | public Start(StructureFeature< | ||
| + | long seed) { | ||
| + | super(feature, | ||
| + | } | ||
| + | |||
| + | // Called when the world attempts to spawn in a new structure, and is the gap between your feature and generator. | ||
| + | public void init(DynamicRegistryManager registryManager, | ||
| + | int chunkZ, Biome biome, DefaultFeatureConfig config) { | ||
| + | int x = chunkX * 16; | ||
| + | int z = chunkZ * 16; | ||
| + | int y = chunkGenerator.getHeight(x, | ||
| + | BlockPos pos = new BlockPos(x, y, z); | ||
| + | BlockRotation rotation = BlockRotation.random(this.random); | ||
| + | MyGenerator.addPieces(manager, | ||
| + | this.setBoundingBoxFromChildren(); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Creating a Generator ===== | ||
| + | As you have probably noticed, we need to create a generator. | ||
| + | |||
| + | This is where structure files and generating straight from a '' | ||
| + | |||
| + | * If you want, you can simply override '' | ||
| + | * Use structure files. These are rather powerful at this point and are highly recommended. | ||
| + | |||
| + | In this tutorial, we'll use a structure file. | ||
| + | It doesn' | ||
| + | * An identifier that points to your structure file; use ''" | ||
| + | * Some sort of setup method - '' | ||
| + | |||
| + | <code java> | ||
| + | public class MyGenerator { | ||
| + | private static final Identifier IGLOO_TOP = new Identifier(" | ||
| + | |||
| + | public static void addPieces(StructureManager manager, BlockPos pos, BlockRotation rotation, List< | ||
| + | pieces.add(new MyPiece(manager, | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | In your '' | ||
| + | |||
| + | We're now going to create the piece we just referenced; make a class called '' | ||
| + | |||
| + | Override required methods, and add a constructor that takes in a '' | ||
| + | **toNbt isn't required but is available if you need it**. | ||
| + | We're also implementing '' | ||
| + | We also have 2 constructors: | ||
| + | A basic template would be: | ||
| + | |||
| + | <code java> | ||
| + | public static class MyPiece extends SimpleStructurePiece { | ||
| + | private final BlockRotation rotation; | ||
| + | private final Identifier template; | ||
| + | |||
| + | public MyPiece(StructureManager structureManager, | ||
| + | super(ExampleMod.MY_PIECE, | ||
| + | this.template = new Identifier(compoundTag.getString(" | ||
| + | this.rotation = BlockRotation.valueOf(compoundTag.getString(" | ||
| + | this.initializeStructureData(structureManager); | ||
| + | } | ||
| + | |||
| + | public MyPiece(StructureManager structureManager, | ||
| + | super(ExampleMod.MY_PIECE, | ||
| + | this.pos = pos; | ||
| + | this.rotation = rotation; | ||
| + | this.template = template; | ||
| + | |||
| + | this.initializeStructureData(structureManager); | ||
| + | } | ||
| + | |||
| + | private void initializeStructureData(StructureManager structureManager) { | ||
| + | Structure structure = structureManager.getStructureOrBlank(this.template); | ||
| + | StructurePlacementData placementData = (new StructurePlacementData()) | ||
| + | .setRotation(this.rotation) | ||
| + | .setMirror(BlockMirror.NONE) | ||
| + | .addProcessor(BlockIgnoreStructureProcessor.IGNORE_STRUCTURE_BLOCKS); | ||
| + | this.setStructureData(structure, | ||
| + | } | ||
| + | |||
| + | protected void toNbt(CompoundTag tag) { | ||
| + | super.toNbt(tag); | ||
| + | tag.putString(" | ||
| + | tag.putString(" | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | protected void handleMetadata(String metadata, BlockPos pos, ServerWorldAccess serverWorldAccess, | ||
| + | BlockBox boundingBox) { | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | | ||
| + | '' | ||
| + | This can be good for dynamic stuff such as placing certain mobs based on what mod is on and so on. | ||
| + | |||
| + | In vanilla structures, data blocks are placed above chests so they can be filled with loot in this method. | ||
| + | HOWEVER, you do not need to use datablocks to place chests with loot. Instead, use this command to set a north facing chest with a loottable. | ||
| + | Save this chest into your structure' | ||
| + | < | ||
| + | |||
| + | We set the '' | ||
| + | |||
| + | ===== Registering Structures ===== | ||
| + | The last step is to register our structures. We're going to need to register: | ||
| + | |||
| + | * structure | ||
| + | * piece | ||
| + | * configured structure | ||
| + | |||
| + | <code java> | ||
| + | public class ExampleMod implements ModInitializer { | ||
| + | public static final StructurePieceType MY_PIECE = MyGenerator.MyPiece:: | ||
| + | private static final StructureFeature< | ||
| + | private static final ConfiguredStructureFeature<?, | ||
| + | |||
| + | @Override | ||
| + | public void onInitialize() { | ||
| + | Registry.register(Registry.STRUCTURE_PIECE, | ||
| + | FabricStructureBuilder.create(new Identifier(" | ||
| + | .step(GenerationStep.Feature.SURFACE_STRUCTURES) | ||
| + | .defaultConfig(32, | ||
| + | .adjustsSurface() | ||
| + | .register(); | ||
| + | |||
| + | RegistryKey< | ||
| + | new Identifier(" | ||
| + | BuiltinRegistries.add(BuiltinRegistries.CONFIGURED_STRUCTURE_FEATURE, | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Adding a configured feature to biomes ===== | ||
| + | In this tutorial, we add our structure to all biomes. | ||
| + | |||
| + | <code java> | ||
| + | public class ExampleMod implements ModInitializer { | ||
| + | [...] | ||
| + | |||
| + | @Override | ||
| + | public void onInitialize() { | ||
| + | [...] | ||
| + | |||
| + | BiomeModifications.addStructure(BiomeSelectors.all(), | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Result ===== | ||
| + | You should be met with igloos. | ||
| + | You can use below command to find your structure in the world. | ||
| + | |||
| + | < | ||
| + | /locate tutorial: | ||
| + | </ | ||
| + | |||
| + | {{tutorial: | ||