-
-
Save TelepathicGrunt/c02333993a1c35dea26fdb98fead5074 to your computer and use it in GitHub Desktop.
// Note: Lithostitch mod allows you to add to processor lists easily! No code needed. | |
// https://github.com/Apollounknowndev/lithostitched/wiki/Worldgen-Modifier-Types#add_processor_list_processors | |
// This gist code is public domain. Take it! Steal it! AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!!!!!!!!!!!! | |
// 1.18.2+ | |
public ExampleMod() { | |
MinecraftForge.EVENT_BUS.addListener(this::addNewVillageCrop); | |
} | |
public void addNewVillageCrop(final ServerAboutToStartEvent event) { | |
// Dynamic registry of processor lists. We will edit the processor lists from here as this is what the world will actually use. | |
Registry<StructureProcessorList> processorListRegistry = event.getServer().registryAccess().registry(Registry.PROCESSOR_LIST_REGISTRY).orElseThrow(); | |
// Create a new processor to add to the processor lists | |
StructureProcessor newCropProcessor = new RuleProcessor(List.of(new ProcessorRule( | |
// We replace the vanilla Wheat block with Sweet Berry Bush 50% of the time. | |
// Note, Potatoes and Beetroot will also be avaliable to be replaced too by our processor. | |
new RandomBlockMatchTest(Blocks.WHEAT, 0.5F), | |
// Location predicate. Keep this as always true for most use-cases. | |
AlwaysTrueTest.INSTANCE, | |
// The modded block to use. | |
Blocks.SWEET_BERRY_BUSH.defaultBlockState() | |
))); | |
// Now add new rule processor to vanilla crop processors | |
addNewRuleToProcessorList(new ResourceLocation("minecraft:farm_plains"), newCropProcessor, processorListRegistry); | |
addNewRuleToProcessorList(new ResourceLocation("minecraft:farm_savanna"), newCropProcessor, processorListRegistry); | |
addNewRuleToProcessorList(new ResourceLocation("minecraft:farm_snowy"), newCropProcessor, processorListRegistry); | |
addNewRuleToProcessorList(new ResourceLocation("minecraft:farm_taiga"), newCropProcessor, processorListRegistry); | |
addNewRuleToProcessorList(new ResourceLocation("minecraft:farm_desert"), newCropProcessor, processorListRegistry); | |
// Can target other mod's processor lists | |
addNewRuleToProcessorList(new ResourceLocation("repurposed_structures:villages/badlands/crop_replacement"), newCropProcessor, processorListRegistry); | |
addNewRuleToProcessorList(new ResourceLocation("repurposed_structures:villages/birch/crop_randomizer"), newCropProcessor, processorListRegistry); | |
addNewRuleToProcessorList(new ResourceLocation("repurposed_structures:villages/dark_forest/crop_randomizer"), newCropProcessor, processorListRegistry); | |
addNewRuleToProcessorList(new ResourceLocation("repurposed_structures:villages/giant_taiga/crop_randomizer"), newCropProcessor, processorListRegistry); | |
addNewRuleToProcessorList(new ResourceLocation("repurposed_structures:villages/jungle/crop_randomizer"), newCropProcessor, processorListRegistry); | |
addNewRuleToProcessorList(new ResourceLocation("repurposed_structures:villages/mountains/crop_randomizer"), newCropProcessor, processorListRegistry); | |
addNewRuleToProcessorList(new ResourceLocation("repurposed_structures:villages/oak/crop_randomizer"), newCropProcessor, processorListRegistry); | |
addNewRuleToProcessorList(new ResourceLocation("repurposed_structures:villages/swamp/crop_randomizer"), newCropProcessor, processorListRegistry); | |
} | |
private static void addNewRuleToProcessorList(ResourceLocation targetProcessorList, StructureProcessor processorToAdd, Registry<StructureProcessorList> processorListRegistry) { | |
processorListRegistry.getOptional(targetProcessorList) | |
.ifPresent(processorList -> { | |
// The list of processor is an immutable list. | |
// So we will create a new list, add to it, and set the field to that new list. | |
List<StructureProcessor> newSafeList = new ArrayList<>(processorList.list()); | |
newSafeList.add(processorToAdd); | |
processorList.list = newSafeList; // Use an Access Transformer or Accessor Mixin to set the private list field. | |
}); | |
} | |
//////////////////////////////////////////////////////// | |
// 1.16.5 - (this old way is outdated and probably entirely unnecessary. Try the method done above instead and see if that works in 1.16.5) | |
public ExampleMod() { | |
MinecraftForge.EVENT_BUS.addListener(this::addNewVillageCrop); | |
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::createProcessors); | |
} | |
// We will create the processor in FMLCommonSetupEvent as we know our | |
// block will be created and registered by the time this event fires. | |
public static RuleStructureProcessor MODDED_CROP_PROCESSOR; | |
public void createProcessors(final FMLCommonSetupEvent event) { | |
MODDED_CROP_PROCESSOR = new RuleStructureProcessor(ImmutableList.of( | |
new RuleEntry( | |
// We replace the vanilla Wheat block with Sweet Berry Bush 50% of the time. | |
// Note, Potatoes and Beetroot will also be avaliable to be replaced too by our processor. | |
new RandomBlockMatchRuleTest(Blocks.WHEAT, 0.5F), | |
// Location predicate. Keep this as always true for most use-cases. | |
AlwaysTrueRuleTest.INSTANCE, | |
// The modded block to use. | |
Blocks.SWEET_BERRY_BUSH.defaultBlockState() | |
) | |
)); | |
} | |
/** | |
* Appends the given processor to the end of the targeted pieces in the targeted pools. | |
* We will call this in addNewVillageCrop method further down to add to every village farm pool entry. | |
* | |
* Note: This is an additive operation which means multiple mods can do this and they stack with each other safely. | |
*/ | |
private static void addCropToPoolElement(MutableRegistry<JigsawPattern> templatePoolRegistry, ResourceLocation poolRL, List<ResourceLocation> nbtPieceRLList) { | |
JigsawPattern pool = templatePoolRegistry.get(poolRL); | |
if (pool == null) return; | |
// AccessTransformer to make JigsawPattern's templates field public for us to see. | |
// public net.minecraft.world.gen.feature.jigsaw.JigsawPattern field_214953_e #templates | |
pool.templates.forEach(entry -> { | |
if (entry instanceof SingleJigsawPiece) { | |
SingleJigsawPiece jigsawPiece = (SingleJigsawPiece) entry; | |
// AccessTransformer to make SingleJigsawPiece's template field public for us to see. | |
// public net.minecraft.world.gen.feature.jigsaw.SingleJigsawPiece field_236839_c_ #template | |
if (jigsawPiece.template.left().isPresent()) { | |
// Found the piece entry we want to modify. | |
ResourceLocation currentNBTPiece = jigsawPiece.template.left().get(); | |
if (nbtPieceRLList.stream().anyMatch(currentNBTPiece::equals)) { | |
// AccessTransformer to make SingleJigsawPiece's processors field public and non-final for us to see and swap out. | |
// public-f net.minecraft.world.gen.feature.jigsaw.SingleJigsawPiece field_214862_b #processors | |
StructureProcessorList originalStructureProcessorList = jigsawPiece.processors.get(); | |
// Make a mutable list as this is an immutable list originally | |
List<StructureProcessor> mutableProcessorList = new ArrayList<>(originalStructureProcessorList.list()); | |
// Add our processor to the end so it runs after everything else | |
mutableProcessorList.add(MODDED_CROP_PROCESSOR); | |
StructureProcessorList newStructureProcessorList = new StructureProcessorList(mutableProcessorList); | |
// Override the original field with our new instance. This is an additive operation and safe to stack with other mods | |
jigsawPiece.processors = () -> newStructureProcessorList; | |
} | |
} | |
} | |
}); | |
} | |
/** | |
* We use FMLServerAboutToStartEvent as the dynamic registry exists now and all JSON worldgen files were parsed. | |
* Mod compat is best done here. | |
*/ | |
public void addNewVillageCrop(final FMLServerAboutToStartEvent event) { | |
MutableRegistry<JigsawPattern> templatePoolRegistry = event.getServer().registryAccess().registry(Registry.TEMPLATE_POOL_REGISTRY).get(); | |
// Adds the crop processor to all vanilla farm village pieces | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("minecraft:village/plains/houses"), ImmutableList.of( | |
new ResourceLocation("minecraft:village/plains/houses/plains_large_farm_1"), | |
new ResourceLocation("minecraft:village/plains/houses/plains_small_farm_1") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("minecraft:village/plains/zombie/houses"), ImmutableList.of( | |
new ResourceLocation("minecraft:village/plains/houses/plains_large_farm_1"), | |
new ResourceLocation("minecraft:village/plains/houses/plains_small_farm_1") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("minecraft:village/snowy/houses"), ImmutableList.of( | |
new ResourceLocation("minecraft:village/snowy/houses/snowy_farm_1"), | |
new ResourceLocation("minecraft:village/snowy/houses/snowy_farm_2") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("minecraft:village/snowy/zombie/houses"), ImmutableList.of( | |
new ResourceLocation("minecraft:village/snowy/houses/snowy_farm_1"), | |
new ResourceLocation("minecraft:village/snowy/houses/snowy_farm_2") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("minecraft:village/savanna/houses"), ImmutableList.of( | |
new ResourceLocation("minecraft:village/savanna/houses/savanna_large_farm_1"), | |
new ResourceLocation("minecraft:village/savanna/houses/savanna_large_farm_2"), | |
new ResourceLocation("minecraft:village/savanna/houses/savanna_small_farm") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("minecraft:village/savanna/zombie/houses"), ImmutableList.of( | |
new ResourceLocation("minecraft:village/savanna/houses/savanna_large_farm_1"), | |
new ResourceLocation("minecraft:village/savanna/zombie/houses/savanna_large_farm_2"), | |
new ResourceLocation("minecraft:village/savanna/houses/savanna_small_farm") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("minecraft:village/taiga/houses"), ImmutableList.of( | |
new ResourceLocation("minecraft:village/taiga/houses/taiga_large_farm_1"), | |
new ResourceLocation("minecraft:village/taiga/houses/taiga_large_farm_2"), | |
new ResourceLocation("minecraft:village/taiga/houses/taiga_small_farm_1") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("minecraft:village/taiga/zombie/houses"), ImmutableList.of( | |
new ResourceLocation("minecraft:village/taiga/houses/taiga_large_farm_1"), | |
new ResourceLocation("minecraft:village/taiga/zombie/houses/taiga_large_farm_2"), | |
new ResourceLocation("minecraft:village/taiga/houses/taiga_small_farm_1") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("minecraft:village/desert/houses"), ImmutableList.of( | |
new ResourceLocation("minecraft:village/desert/houses/desert_large_farm_1"), | |
new ResourceLocation("minecraft:village/desert/houses/desert_farm_1"), | |
new ResourceLocation("minecraft:village/desert/houses/desert_farm_2") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("minecraft:village/desert/zombie/houses"), ImmutableList.of( | |
new ResourceLocation("minecraft:village/desert/houses/desert_large_farm_1"), | |
new ResourceLocation("minecraft:village/desert/houses/desert_farm_1"), | |
new ResourceLocation("minecraft:village/desert/houses/desert_farm_2") | |
)); | |
// Since we only use Resourcelocations to target where to add our processor, 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")) { | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("repurposed_structures:villages/badlands/houses"), ImmutableList.of( | |
new ResourceLocation("repurposed_structures:villages/badlands/houses/farm_1"), | |
new ResourceLocation("repurposed_structures:villages/badlands/houses/farm_2") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("repurposed_structures:villages/badlands/zombie/houses"), ImmutableList.of( | |
new ResourceLocation("repurposed_structures:villages/badlands/houses/farm_1"), | |
new ResourceLocation("repurposed_structures:villages/badlands/houses/farm_2") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("repurposed_structures:villages/birch/houses"), ImmutableList.of( | |
new ResourceLocation("repurposed_structures:villages/birch/houses/large_farm_1"), | |
new ResourceLocation("repurposed_structures:villages/birch/houses/small_farm_1") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("repurposed_structures:villages/birch/zombie/houses"), ImmutableList.of( | |
new ResourceLocation("repurposed_structures:villages/birch/houses/large_farm_1"), | |
new ResourceLocation("repurposed_structures:villages/birch/houses/small_farm_1") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("repurposed_structures:villages/dark_forest/houses"), ImmutableList.of( | |
new ResourceLocation("repurposed_structures:villages/dark_forest/houses/large_farm_1"), | |
new ResourceLocation("repurposed_structures:villages/dark_forest/houses/small_farm_1") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("repurposed_structures:villages/dark_forest/zombie/houses"), ImmutableList.of( | |
new ResourceLocation("repurposed_structures:villages/dark_forest/houses/large_farm_1"), | |
new ResourceLocation("repurposed_structures:villages/dark_forest/houses/small_farm_1") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("repurposed_structures:villages/giant_tree_taiga/houses"), ImmutableList.of( | |
new ResourceLocation("repurposed_structures:villages/giant_taiga/houses/farm_1"), | |
new ResourceLocation("repurposed_structures:villages/giant_taiga/houses/farm_2") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("repurposed_structures:villages/giant_tree_taiga/zombie/houses"), ImmutableList.of( | |
new ResourceLocation("repurposed_structures:villages/giant_taiga/houses/farm_1"), | |
new ResourceLocation("repurposed_structures:villages/giant_taiga/houses/farm_2") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("repurposed_structures:villages/jungle/houses"), ImmutableList.of( | |
new ResourceLocation("repurposed_structures:villages/jungle/houses/large_farm_1"), | |
new ResourceLocation("repurposed_structures:villages/jungle/houses/large_farm_2"), | |
new ResourceLocation("repurposed_structures:villages/jungle/houses/small_farm") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("repurposed_structures:villages/jungle/zombie/houses"), ImmutableList.of( | |
new ResourceLocation("repurposed_structures:villages/jungle/houses/large_farm_1"), | |
new ResourceLocation("repurposed_structures:villages/jungle/zombie/houses/large_farm_2"), | |
new ResourceLocation("repurposed_structures:villages/jungle/houses/small_farm") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("repurposed_structures:villages/mountains/houses"), ImmutableList.of( | |
new ResourceLocation("repurposed_structures:villages/mountains/houses/large_farm_1"), | |
new ResourceLocation("repurposed_structures:villages/mountains/houses/large_farm_2"), | |
new ResourceLocation("repurposed_structures:villages/mountains/houses/small_farm_1") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("repurposed_structures:villages/mountains/zombie/houses"), ImmutableList.of( | |
new ResourceLocation("repurposed_structures:villages/mountains/houses/large_farm_1"), | |
new ResourceLocation("repurposed_structures:villages/mountains/zombie/houses/large_farm_2"), | |
new ResourceLocation("repurposed_structures:villages/mountains/houses/small_farm_1") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("repurposed_structures:villages/mushroom/houses"), ImmutableList.of( | |
new ResourceLocation("repurposed_structures:villages/mushroom/houses/large_farm_1"), | |
new ResourceLocation("repurposed_structures:villages/mushroom/houses/small_farm_1") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("repurposed_structures:villages/oak/houses"), ImmutableList.of( | |
new ResourceLocation("repurposed_structures:villages/oak/houses/large_farm_1"), | |
new ResourceLocation("repurposed_structures:villages/oak/houses/small_farm_1") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("repurposed_structures:villages/oak/zombie/houses"), ImmutableList.of( | |
new ResourceLocation("repurposed_structures:villages/oak/houses/large_farm_1"), | |
new ResourceLocation("repurposed_structures:villages/oak/houses/small_farm_1") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("repurposed_structures:village/swamp/houses"), ImmutableList.of( | |
new ResourceLocation("repurposed_structures:villages/swamp/houses/farm_1"), | |
new ResourceLocation("repurposed_structures:villages/swamp/houses/farm_2") | |
)); | |
addCropToPoolElement(templatePoolRegistry, new ResourceLocation("repurposed_structures:villages/swamp/zombie/houses"), ImmutableList.of( | |
new ResourceLocation("repurposed_structures:villages/swamp/houses/farm_1"), | |
new ResourceLocation("repurposed_structures:villages/swamp/houses/farm_2") | |
)); | |
} | |
} |
Fixed. Thanks!
One last thing, "public static final RuleStructureProcessor MODDED_CROP_PROCESSOR;" cannot be final. It would have to be created immediately outside of any method, because it has to be declared on class declaration, because it is static and final. And you cannot define it outside of the method it is in because it would trigger an exception because defaultBlockState would not be defined yet, especially for custom crops.
It is a little sad I did not end up using this code though, it is well documented and straight forward. What I did was I added my own structure to the game. Which I then looked at your addNewBuildingsVillages code, which is also well documented, and it taught me how to get a NBT file to actually load into the game.
But sadly again I ended up not using that code again, and instead made my structure a surface structure that was required to spawn within 5 chunks of a village. (It is the reverse of a Pillager Outpost that has to be further away than 10 chunks from a village) Which let me have one structure have a chance of spawning on the outskirts of an village regardless of the type of village. Which had the added benefit of making my outdoor theater structure spawn in the open areas next to the villages, rather than in the middle of the villages with no audience space.
In summary, there is one small fix needed, and I wanted to give you credit for the useful code you have posted that greatly helped me solve the issues I was having with the code I was writing. Keep up the good work, and continue to share useful code.
Fixed again and thanks! I’m guessing you looked at my StructureTutorialMod for creating a new structure. But yeah, doing a reverse pillager outpost placing is smart for having a nearby building to villages without actually being connected. I’m imagining a village barn and stuff lol. Good luck with your mod!
I just checked, and yep I got inspiration from the StructureTutorialMod, I did not even realize that was also yours.
Edit: I added the second closing parentheses in my code snippet.