Skip to content

Instantly share code, notes, and snippets.

@Commoble
Last active May 1, 2021 01:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Commoble/6e297bf461a4fbb8f84685fe009aec28 to your computer and use it in GitHub Desktop.
Save Commoble/6e297bf461a4fbb8f84685fe009aec28 to your computer and use it in GitHub Desktop.
Experimental DynamicRegistriesLoaded hook for minecraft forge
package commoble.dynamicregistrycheeser.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeGenerationSettings;
@Mixin(Biome.class)
public interface BiomeAccessor
{
// TODO replace with AT
@Accessor
void setGenerationSettings(BiomeGenerationSettings generationSettings);
}
package commoble.dynamicregistrycheeser;
import javax.annotation.Nonnull;
import commoble.dynamicregistrycheeser.mixin.BiomeAccessor;
import net.minecraft.util.RegistryKey;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.registry.DynamicRegistries;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.gen.GenerationStage.Decoration;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.world.BiomeGenerationSettingsBuilder;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.common.Mod;
@Mod(DynamicRegistryCheeser.MODID)
public class DynamicRegistryCheeser
{
public static final String MODID = "dynamicregistrycheeser";
public static final RegistryKey<ConfiguredFeature<?,?>> TEST_FEATURE = RegistryKey.create(Registry.CONFIGURED_FEATURE_REGISTRY,
new ResourceLocation("dynamicregistrycheeser:test_pile"));
public DynamicRegistryCheeser()
{
IEventBus forgeBus = MinecraftForge.EVENT_BUS;
forgeBus.addListener(this::onDynamicRegistriesLoaded);
}
// event is fired at the end of WorldSettingsImport::create (the overload that takes a resource manager, not an IResourceAccess)
// the IResourceAccess one is a bit more generic and is also used when loading up the builtin vanilla stuff before datapacks are added.
// the resource manager one is called to add datapack stuff, firing the event at the end of the method results in the event
// firing after datapacks are loaded into the dynamic registries.
void onDynamicRegistriesLoaded(DynamicRegistriesLoadedEvent event)
{
DynamicRegistries.Impl registries = event.getRegistries();
registries.registry(Registry.BIOME_REGISTRY)
.ifPresent(biomeRegistry -> registries.registry(Registry.CONFIGURED_FEATURE_REGISTRY)
.ifPresent(featureRegistry ->
{
// let's add a datapack feature to each biome
ConfiguredFeature<?,?> testFeature = featureRegistry.get(TEST_FEATURE);
biomeRegistry.forEach(biome ->
{
// using the settings builder here is a bit chunky since it copies everything into a new list of lists
// the biome's final feature list is an immutable list, could that be improved?
// we could also theoretically just move the biome load event here and give it access to the dynamicregistries,
// which would handle most use cases (adding datapack stuff to biomes)
BiomeGenerationSettingsBuilder settingsBuilder = new BiomeGenerationSettingsBuilder(biome.getGenerationSettings());
// add the feature to the biome
settingsBuilder.addFeature(Decoration.VEGETAL_DECORATION, testFeature);
((BiomeAccessor)(Object)biome).setGenerationSettings(settingsBuilder.build());
});
}));
}
public static class DynamicRegistriesLoadedEvent extends Event
{
private final @Nonnull DynamicRegistries.Impl registries;
public DynamicRegistriesLoadedEvent(final @Nonnull DynamicRegistries.Impl registries)
{
this.registries = registries;
}
public @Nonnull DynamicRegistries.Impl getRegistries()
{
return this.registries;
}
}
}
{
"config":
{
"feature":
{
"config":
{
"feature":
{
"config":
{
"state_provider":
{
"state":
{
"Name": "minecraft:gold_block"
},
"type": "minecraft:simple_state_provider"
}
},
"type": "minecraft:block_pile"
},
"decorator":
{
"config":
{
"outer":
{
"config":
{
},
"type": "minecraft:square"
},
"inner":
{
"config":
{
},
"type": "minecraft:heightmap"
}
},
"type": "minecraft:decorated"
}
},
"type": "minecraft:decorated"
},
"decorator":
{
"config":
{
"count":
{
"base": 10,
"spread": 20
}
},
"type": "minecraft:count"
}
},
"type": "minecraft:decorated"
}
package commoble.dynamicregistrycheeser.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.mojang.serialization.DynamicOps;
import commoble.dynamicregistrycheeser.DynamicRegistryCheeser.DynamicRegistriesLoadedEvent;
import net.minecraft.resources.IResourceManager;
import net.minecraft.util.registry.DynamicRegistries;
import net.minecraft.util.registry.WorldSettingsImport;
import net.minecraftforge.common.MinecraftForge;
@Mixin(WorldSettingsImport.class)
public class WorldSettingsImportMixin
{
@SuppressWarnings("rawtypes")
@Inject(method="create", at=@At("TAIL"))
private static void onCreateFromResourceManager(DynamicOps ops, IResourceManager manager, DynamicRegistries.Impl registries, CallbackInfoReturnable<WorldSettingsImport> ci)
{
MinecraftForge.EVENT_BUS.post(new DynamicRegistriesLoadedEvent(registries));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment