diff --git a/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/api/event/registry/DynamicRegistrySetupCallback.java b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/api/event/registry/DynamicRegistrySetupCallback.java new file mode 100644 index 000000000..d16aea52e --- /dev/null +++ b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/api/event/registry/DynamicRegistrySetupCallback.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.event.registry; + +import net.minecraft.util.registry.DynamicRegistryManager; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; + +/** + * This event gets triggered when a new {@link DynamicRegistryManager} gets created, but before it gets filled. + * Therefore, this is the ideal place to register callbacks to dynamic registries. + * For example, the following code is used to register a callback that gets triggered for any registered Biome, both JSON and code defined. + * + *
+ * {@code
+ * DynamicRegistrySetupCallback.EVENT.register(registryManager -> {
+ *     Registry biomes = registryManager.get(Registry.BIOME_KEY);
+ *     RegistryEntryAddedCallback.event(biomes).register((rawId, id, object) -> {
+ *         // Do something
+ *     });
+ * });
+ * }
+ * 
+ */ +@FunctionalInterface +public interface DynamicRegistrySetupCallback { + void onRegistrySetup(DynamicRegistryManager registryManager); + + Event EVENT = EventFactory.createArrayBacked( + DynamicRegistrySetupCallback.class, + callbacks -> registryManager -> { + for (DynamicRegistrySetupCallback callback : callbacks) { + callback.onRegistrySetup(registryManager); + } + } + ); +} diff --git a/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/mixin/registry/sync/DynamicRegistryManagerMixin.java b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/mixin/registry/sync/DynamicRegistryManagerMixin.java new file mode 100644 index 000000000..58df768d5 --- /dev/null +++ b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/mixin/registry/sync/DynamicRegistryManagerMixin.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.registry.sync; + +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 org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import net.minecraft.util.registry.DynamicRegistryManager; + +import net.fabricmc.fabric.api.event.registry.DynamicRegistrySetupCallback; + +@Mixin(DynamicRegistryManager.class) +public class DynamicRegistryManagerMixin { + @Inject(method = "create", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/dynamic/RegistryOps$class_5506$class_5507;()V"), locals = LocalCapture.CAPTURE_FAILHARD) + private static void onCreateImpl(CallbackInfoReturnable cir, DynamicRegistryManager.Impl registryManager) { + DynamicRegistrySetupCallback.EVENT.invoker().onRegistrySetup(registryManager); + } +} diff --git a/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/mixin/registry/sync/MixinIdRegistry.java b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/mixin/registry/sync/MixinIdRegistry.java index 441504b32..a39365139 100644 --- a/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/mixin/registry/sync/MixinIdRegistry.java +++ b/fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/mixin/registry/sync/MixinIdRegistry.java @@ -45,8 +45,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import net.minecraft.util.Identifier; import net.minecraft.util.registry.Registry; -import net.minecraft.util.registry.SimpleRegistry; import net.minecraft.util.registry.RegistryKey; +import net.minecraft.util.registry.SimpleRegistry; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; @@ -132,8 +132,8 @@ public abstract class MixinIdRegistry extends Registry implements Remappab @Unique private boolean fabric_isObjectNew = false; - @Inject(method = "set", at = @At("HEAD")) - public void setPre(int id, RegistryKey registryId, T object, Lifecycle lifecycle, CallbackInfoReturnable info) { + @Inject(method = "set(ILnet/minecraft/util/registry/RegistryKey;Ljava/lang/Object;Lcom/mojang/serialization/Lifecycle;Z)Ljava/lang/Object;", at = @At("HEAD")) + public void setPre(int id, RegistryKey registryId, T object, Lifecycle lifecycle, boolean checkDuplicateKeys, CallbackInfoReturnable info) { int indexedEntriesId = entryToRawId.getInt(object); if (indexedEntriesId >= 0) { @@ -148,7 +148,7 @@ public abstract class MixinIdRegistry extends Registry implements Remappab if (oldObject != null && oldObject != object) { int oldId = entryToRawId.getInt(oldObject); - if (oldId != id) { + if (oldId != id && checkDuplicateKeys) { throw new RuntimeException("Attempted to register ID " + registryId + " at different raw IDs (" + oldId + ", " + id + ")! If you're trying to override an item, use .set(), not .register()!"); } @@ -160,8 +160,8 @@ public abstract class MixinIdRegistry extends Registry implements Remappab } } - @Inject(method = "set", at = @At("RETURN")) - public void setPost(int id, RegistryKey registryId, T object, Lifecycle lifecycle, CallbackInfoReturnable info) { + @Inject(method = "set(ILnet/minecraft/util/registry/RegistryKey;Ljava/lang/Object;Lcom/mojang/serialization/Lifecycle;Z)Ljava/lang/Object;", at = @At("RETURN")) + public void setPost(int id, RegistryKey registryId, T object, Lifecycle lifecycle, boolean checkDuplicateKeys, CallbackInfoReturnable info) { if (fabric_isObjectNew) { fabric_addObjectEvent.invoker().onEntryAdded(id, registryId.getValue(), object); } diff --git a/fabric-registry-sync-v0/src/main/resources/fabric-registry-sync-v0.mixins.json b/fabric-registry-sync-v0/src/main/resources/fabric-registry-sync-v0.mixins.json index 435ba89ee..ce24616b0 100644 --- a/fabric-registry-sync-v0/src/main/resources/fabric-registry-sync-v0.mixins.json +++ b/fabric-registry-sync-v0/src/main/resources/fabric-registry-sync-v0.mixins.json @@ -11,7 +11,8 @@ "MixinPlayerManager", "MixinLevelStorageSession", "MixinRegistry", - "MixinSimpleRegistry" + "MixinSimpleRegistry", + "DynamicRegistryManagerMixin" ], "client": [ "client.MixinBlockColorMap", diff --git a/fabric-registry-sync-v0/src/main/resources/fabric.mod.json b/fabric-registry-sync-v0/src/main/resources/fabric.mod.json index 6fa2597a5..cb03233b2 100644 --- a/fabric-registry-sync-v0/src/main/resources/fabric.mod.json +++ b/fabric-registry-sync-v0/src/main/resources/fabric.mod.json @@ -16,7 +16,7 @@ "FabricMC" ], "depends": { - "fabricloader": ">=0.4.0", + "fabricloader": ">=0.9.2", "fabric-api-base": "*", "fabric-networking-v0": "*" }, diff --git a/fabric-registry-sync-v0/src/testmod/java/net/fabricmc/fabric/test/registry/sync/RegistrySyncTest.java b/fabric-registry-sync-v0/src/testmod/java/net/fabricmc/fabric/test/registry/sync/RegistrySyncTest.java index 6a687784c..b85bc1731 100644 --- a/fabric-registry-sync-v0/src/testmod/java/net/fabricmc/fabric/test/registry/sync/RegistrySyncTest.java +++ b/fabric-registry-sync-v0/src/testmod/java/net/fabricmc/fabric/test/registry/sync/RegistrySyncTest.java @@ -34,9 +34,11 @@ import net.minecraft.world.gen.feature.DefaultFeatureConfig; import net.minecraft.world.gen.feature.Feature; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.event.registry.DynamicRegistrySetupCallback; import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder; import net.fabricmc.fabric.api.event.registry.RegistryAttribute; import net.fabricmc.fabric.api.event.registry.RegistryAttributeHolder; +import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback; public class RegistrySyncTest implements ModInitializer { /** @@ -73,9 +75,17 @@ public class RegistrySyncTest implements ModInitializer { Registry.register(fabricRegistry, new Identifier("registry_sync", "test"), "test"); + Validate.isTrue(Registry.REGISTRIES.getIds().contains(new Identifier("registry_sync", "fabric_registry"))); + Validate.isTrue(RegistryAttributeHolder.get(fabricRegistry).hasAttribute(RegistryAttribute.MODDED)); Validate.isTrue(RegistryAttributeHolder.get(fabricRegistry).hasAttribute(RegistryAttribute.SYNCED)); Validate.isTrue(!RegistryAttributeHolder.get(fabricRegistry).hasAttribute(RegistryAttribute.PERSISTED)); + + DynamicRegistrySetupCallback.EVENT.register(registryManager -> { + RegistryEntryAddedCallback.event(registryManager.get(Registry.BIOME_KEY)).register((rawId, id, object) -> { + System.out.println(id); + }); + }); } /**