Skip to content

Instantly share code, notes, and snippets.

@TelepathicGrunt
Last active June 23, 2024 04:37
Show Gist options
  • Save TelepathicGrunt/4fdbc445ebcbcbeb43ac748f4b18f342 to your computer and use it in GitHub Desktop.
Save TelepathicGrunt/4fdbc445ebcbcbeb43ac748f4b18f342 to your computer and use it in GitHub Desktop.
How to add new buildings to villages and other jigsaw structures
// This gist code is public domain. Take it! Steal it! AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!!!!!!!!!!!!
public ExampleMod() {
MinecraftForge.EVENT_BUS.addListener(this::addNewVillageBuilding);
}
/**
* Adds the building to the targeted pool.
* We will call this in addNewVillageBuilding method further down to add to every village.
*
* Note: This is an additive operation which means multiple mods can do this and they stack with each other safely.
*/
private static void addBuildingToPool(MutableRegistry<JigsawPattern> templatePoolRegistry, ResourceLocation poolRL, String nbtPieceRL, int weight) {
// Grab the pool we want to add to
JigsawPattern pool = templatePoolRegistry.get(poolRL);
if (pool == null) return;
// Grabs the nbt piece and creates a SingleJigsawPiece of it that we can add to a structure's pool.
SingleJigsawPiece piece = SingleJigsawPiece.single(nbtPieceRL).apply(JigsawPattern.PlacementBehaviour.RIGID);
// AccessTransformer to make JigsawPattern's templates field public for us to see.
// public net.minecraft.world.gen.feature.jigsaw.JigsawPattern field_214953_e #templates
// Weight is handled by how many times the entry appears in this list.
// We do not need to worry about immutability as this field is created using Lists.newArrayList(); which makes a mutable list.
for (int i = 0; i < weight; i++) {
pool.templates.add(piece);
}
// AccessTransformer to make JigsawPattern's rawTemplates field public for us to see.
// net.minecraft.world.gen.feature.jigsaw.JigsawPattern field_214952_d #rawTemplates
// This list of pairs of pieces and weights is not used by vanilla by default but another mod may need it for efficiency.
// So lets add to this list for completeness. We need to make a copy of the array as it can be an immutable list.
List<Pair<JigsawPiece, Integer>> listOfPieceEntries = new ArrayList<>(pool.rawTemplates);
listOfPieceEntries.add(new Pair<>(piece, weight));
pool.rawTemplates = listOfPieceEntries;
}
/**
* We use FMLServerAboutToStartEvent as the dynamic registry exists now and all JSON worldgen files were parsed.
* Mod compat is best done here.
*/
public void addNewVillageBuilding(final FMLServerAboutToStartEvent event) {
MutableRegistry<JigsawPattern> templatePoolRegistry = event.getServer().registryAccess().registry(Registry.TEMPLATE_POOL_REGISTRY).get();
// Adds our piece to all village houses pool
// Note, the resourcelocation is getting the pool files from the data folder. Not assets folder.
addBuildingToPool(templatePoolRegistry, new ResourceLocation("minecraft:village/plains/houses"),
"modid:structure_nbt_resourcelocation", 5);
addBuildingToPool(templatePoolRegistry, new ResourceLocation("minecraft:village/snowy/houses"),
"modid:structure_nbt_resourcelocation", 5);
addBuildingToPool(templatePoolRegistry, new ResourceLocation("minecraft:village/savanna/houses"),
"modid:structure_nbt_resourcelocation", 5);
addBuildingToPool(templatePoolRegistry, new ResourceLocation("minecraft:village/taiga/houses"),
"modid:structure_nbt_resourcelocation", 5);
addBuildingToPool(templatePoolRegistry, new ResourceLocation("minecraft:village/desert/houses"),
"modid:structure_nbt_resourcelocation", 5);
// Since we only use Resourcelocations to target where to add our building pieces, there's no hard dependency with other mod's code.
// A simple check to see if the targeted mod exists is sufficient before actaully attempting to add.
if (ModList.get().isLoaded("repurposed_structures")) {
// Repurposed Structures slightly changed their village path in 1.17.0 to be "villages" instead of "village"
// So this rough check should get the right path for both 1.16 and 1.17.
String rsVillagePath = MinecraftVersion.tryDetectVersion().getName().contains("1.16.") ?
"repurposed_structures:village" : "repurposed_structures:villages";
addBuildingToPool(templatePoolRegistry, new ResourceLocation(rsVillagePath + "/badlands/houses"),
"modid:structure_nbt_resourcelocation", 5);
addBuildingToPool(templatePoolRegistry, new ResourceLocation(rsVillagePath + "/birch/houses"),
"modid:structure_nbt_resourcelocation", 5);
addBuildingToPool(templatePoolRegistry, new ResourceLocation(rsVillagePath + "/dark_forest/houses"),
"modid:structure_nbt_resourcelocation", 5);
addBuildingToPool(templatePoolRegistry, new ResourceLocation(rsVillagePath + "/giant_tree_taiga/houses"),
"modid:structure_nbt_resourcelocation", 5);
addBuildingToPool(templatePoolRegistry, new ResourceLocation(rsVillagePath + "/jungle/houses"),
"modid:structure_nbt_resourcelocation", 5);
addBuildingToPool(templatePoolRegistry, new ResourceLocation(rsVillagePath + "/mountains/houses"),
"modid:structure_nbt_resourcelocation", 5);
addBuildingToPool(templatePoolRegistry, new ResourceLocation(rsVillagePath + "/oak/houses"),
"modid:structure_nbt_resourcelocation", 5);
addBuildingToPool(templatePoolRegistry, new ResourceLocation(rsVillagePath + "/swamp/houses"),
"modid:structure_nbt_resourcelocation", 5);
}
}
@FlamingoeZpZ
Copy link

For any confused chaps like me in 1.19 having problems related to private variables:

  1. Join this discord https://discord.gg/forge // it's the official forge discord
  2. in bot commands type !moj varName // for example: !moj rawTemplates
  3. Copy the value that says AT: ... // like public net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool f_210559_ # rawTemplates
  4. if the variable is final, add -f after the world public
  5. in build.gradle uncomment this line accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
  6. Follow that path and add and open the accesstransformer.cfg file
  7. Paste any copied values
  8. Rebuild gradle // It's the little refresh button on the right side in the gradle tab

Happy modding!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment