Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Structure Tutorial Mod
**How to register and generate structures in 1.15 Minecraft using nbt files!**
**How to register and generate structures in 1.16 Minecraft using nbt files!**

This very small Forge mod is full of comments that will help you understand what a lot of the methods do and what needs to be done to get your structure to generate. In all, this mod is really just 4 files plus 2 structure nbt files.
This very small Forge mod is full of comments that will help you understand what a lot of the methods do and what needs to be done to get your structure to generate. In all, this mod is really just 5 files plus 2 structure nbt files.

If you don't know how to make an nbt file for structures, it's actually fairly simple and you can do it all inside minecraft itself! Here is a video on how to make and save a structure to nbt using structure blocks:
>https://www.youtube.com/watch?v=ylGFb4F4xVk&t=1s
Expand All @@ -11,11 +11,13 @@ Once saved, the structure nbt file is stored in that world's save folder within

Now you're ready to begin adding the structure to your mod! Take a look at StructureTutorialMain, start reading the comments, and follow the methods/classes. Don't just copy the code quickly or else you will get confuse. Take your time and try to understand how it all works before attempting to register and generate your structure in your own mod.

When making your own mod, make sure to include the accesstransformer file and to include it in your build.gradle. Your IDE may still say that the methods listed in the access transformer are private and indicate so as an error, but if the access transformer is set up properly it won't actually throw any errors when run.

Good luck and I hope this helps!

------------------

_[This is using MCP mapping version of: '20200521-1.15.1' but try to use the latest_
_[This is using MCP mapping version of: '20200514-1.16' but try to use the latest_
_mappings from http://export.mcpbot.bspk.rs/. Don't download any files but just_
_get the number like this '20200521-1.15.1' of the latest mapping release._
_Put that number into your mapping channel in build.gradle and rebuild your project_
Expand Down
8 changes: 6 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ minecraft {
// stable_# Stables are built at the discretion of the MCP team.
// Use non-default mappings at your own risk. they may not always work.
// Simply re-run your setup task after changing the mappings to update your workspace.
mappings channel: 'snapshot', version: '20200521-1.15.1'
mappings channel: 'snapshot', version: '20200514-1.16'

// Structures in 1.16.1 require you to place them in some vanilla maps which are private variables
// The access transformer allows us to make them public so we can place our structures in them
accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')


runs {
Expand Down Expand Up @@ -67,7 +71,7 @@ dependencies {
// Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed
// that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied.
// The userdev artifact is a special name and will get all sorts of transformations applied to it.
minecraft 'net.minecraftforge:forge:1.15.2-31.2.0'
minecraft 'net.minecraftforge:forge:1.16.1-32.0.106'

}

Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,8 @@

import net.minecraft.util.ResourceLocation;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.GenerationStage;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.IFeatureConfig;
import net.minecraft.world.gen.placement.IPlacementConfig;
import net.minecraft.world.gen.placement.Placement;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
Expand All @@ -22,100 +19,79 @@
import net.minecraftforge.registries.IForgeRegistry;
import net.minecraftforge.registries.IForgeRegistryEntry;


// The value here should match an entry in the META-INF/mods.toml file
@Mod(StructureTutorialMain.MODID)
public class StructureTutorialMain
{
// Directly reference a log4j logger.
public static final Logger LOGGER = LogManager.getLogger();
//mod ID to reference to from anywhere in mod
public static final String MODID = "structure_tutorial";
public class StructureTutorialMain {
// Directly reference a log4j logger.
public static final Logger LOGGER = LogManager.getLogger();
// mod ID to reference to from anywhere in mod
public static final String MODID = "structure_tutorial";

public StructureTutorialMain() {
// Register the setup method for modloading
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);

public StructureTutorialMain()
{
// Register the setup method for modloading
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
// Notice how we aren't using any proxies. If you find another tutorial that uses proxies
// or askes you to use them, ignore that. Proxies are nearly entirely useless and only end up
// making your code look a bit worse. Instead, do all your setup in the FMLCommonSetupEvent,
// FMLClientSetupEvent, and FMLDedicatedServerSetupEvent.
//
// But mainly FMLCommonSetupEvent will be used as doing stuff strictly client side or server
// side depends on specific cases. For example, purely graphical stuff will be under client
// setup because servers won't have any graphics stuff.
}

//Notice how we aren't using any proxies. If you find another tutorial that uses proxies
//or askes you to use them, ignore that. Proxies are nearly entirely useless and only end up
//making your code look a bit worse. Instead, do all your setup in the FMLCommonSetupEvent,
//FMLClientSetupEvent, and FMLDedicatedServerSetupEvent.
//
//But mainly FMLCommonSetupEvent will be used as doing stuff strictly client side or server
//side depends on specific cases. For example, purely graphical stuff will be under client
//setup because servers won't have any graphics stuff.
}
/*
* This is where you do all the manipulation and startup things you need to do for your mod. What is actually done here will be different for every mod
* depending on what the mod is doing.
*
* Here, we will use this to add our structure to all biomes.
*/
public void setup(final FMLCommonSetupEvent event) {
// Add our structure to all biomes including other modded biomes
//
// You can filter to certain biomes based on stuff like temperature, scale, precipitation, mod id,
// and if you use the BiomeDictionary, you can even check if the biome has certain tags like swamp or snowy.
for (Biome biome : ForgeRegistries.BIOMES) {
// All structures needs to be added to biomes by func_235063_a_ which replaces .addStructure and .addFeature from 1.15.2
// The function does not have a mapping at time of writing, but the most likely name for it is .addStructureFeature
//
// This function determines which biomes your structure will be able to spawn in

biome.func_235063_a_(FeatureInit.RUN_DOWN_HOUSE.func_236391_a_(IFeatureConfig.NO_FEATURE_CONFIG));
}

/*
* This is where you do all the manipulation and startup things you need to do for your mod. What is actually done here
* will be different for every mod depending on what the mod is doing.
*
* Here, we will use this to add our structure to all biomes.
*/
public void setup(final FMLCommonSetupEvent event)
{
//Add our structure to all biomes including other modded biomes
//
//You can filter to certain biomes based on stuff like temperature, scale, precipitation, mod id,
//and if you use the BiomeDictionary, you can even check if the biome has certain tags like swamp or snowy.
for (Biome biome : ForgeRegistries.BIOMES)
{
// All structures needs to be added by .addStructure AND .addFeature in order to spawn.
//
// .addStructure tells Minecraft that this biome can start the generation of the structure.
// .addFeature tells Minecraft that the pieces of the structure can be made in this biome.
//
// Thus it is best practice to do .addFeature for all biomes and do .addStructure as well for
// the biome you want the structure to spawn in. That way, the structure will only spawn in the
// biomes you want but will not get cut off when generating if part of it goes into a non-valid biome.
//
//Note: If your mappings are out of data,
// Biome.addStructure will be Biome.func_225566_b_ ,
// Feature.withConfiguration will be Feature.func_225566_b_ ,
// ConfiguredFeature.withPlacement will be ConfiguredFeature.func_227228_a_ ,
// Placement.configure will be Placement.func_227446_a_
biome.addStructure(FeatureInit.RUN_DOWN_HOUSE.withConfiguration(IFeatureConfig.NO_FEATURE_CONFIG));
biome.addFeature(GenerationStage.Decoration.SURFACE_STRUCTURES, FeatureInit.RUN_DOWN_HOUSE.withConfiguration(IFeatureConfig.NO_FEATURE_CONFIG)
.withPlacement(Placement.NOPE.configure(IPlacementConfig.NO_PLACEMENT_CONFIG)));
}
}

}
// You can use EventBusSubscriber to automatically subscribe events on the contained class
// (this is subscribing to the MOD Event bus for receiving Registry Events)

// You can use EventBusSubscriber to automatically subscribe events on the contained class
// (this is subscribing to the MOD Event bus for receiving Registry Events)
/*
* You will use this to register anything for your mod. The most common things you will register are blocks, items, biomes, entities, features, and
* dimensions.
*/
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
public static class RegistryEvents {

/*
* You will use this to register anything for your mod. The most common things you will register are blocks, items,
* biomes, entities, features, and dimensions.
*/
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
public static class RegistryEvents
{
/**
* This method will be called by Forge when it is time for the mod to register features.
*/
@SubscribeEvent
public static void onRegisterFeatures(final RegistryEvent.Register<Feature<?>> event) {
// registers the structures/features.
// If you don't do this, you'll crash.
FeatureInit.registerFeatures(event);

/**
* This method will be called by Forge when it is time for the mod to register features.
*/
@SubscribeEvent
public static void onRegisterFeatures(final RegistryEvent.Register<Feature<?>> event)
{
//registers the structures/features.
//If you don't do this, you'll crash.
FeatureInit.registerFeatures(event);
LOGGER.log(Level.INFO, "features/structures registered.");
}
}

LOGGER.log(Level.INFO, "features/structures registered.");
}
}

/*
* Helper method to quickly register features, blocks, items, structures, biomes, anything that can be registered.
*/
public static <T extends IForgeRegistryEntry<T>> T register(IForgeRegistry<T> registry, T entry, String registryKey)
{
entry.setRegistryName(new ResourceLocation(StructureTutorialMain.MODID, registryKey));
registry.register(entry);
return entry;
}
/*
* Helper method to quickly register features, blocks, items, structures, biomes, anything that can be registered.
*/
public static <T extends IForgeRegistryEntry<T>> T register(IForgeRegistry<T> registry, T entry, String registryKey) {
entry.setRegistryName(new ResourceLocation(StructureTutorialMain.MODID, registryKey));
registry.register(entry);
return entry;
}
}
Loading