diff --git a/common/src/main/java/dev/architectury/hooks/item/tool/HoeItemHooks.java b/common/src/main/java/dev/architectury/hooks/item/tool/HoeItemHooks.java index 4f2c716f..78617c36 100644 --- a/common/src/main/java/dev/architectury/hooks/item/tool/HoeItemHooks.java +++ b/common/src/main/java/dev/architectury/hooks/item/tool/HoeItemHooks.java @@ -21,12 +21,16 @@ package dev.architectury.hooks.item.tool; import com.google.common.collect.ImmutableMap; import com.mojang.datafixers.util.Pair; +import dev.architectury.injectables.annotations.ExpectPlatform; import net.minecraft.world.item.HoeItem; import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.ApiStatus; import java.util.HashMap; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; public final class HoeItemHooks { @@ -48,10 +52,25 @@ public final class HoeItemHooks { * @param predicate context predicate * @param action action to run */ + @Deprecated(forRemoval = true) + @ApiStatus.ScheduledForRemoval public static void addTillable(Block input, Predicate predicate, Consumer action) { if (HoeItem.TILLABLES instanceof ImmutableMap) { HoeItem.TILLABLES = new HashMap<>(HoeItem.TILLABLES); } HoeItem.TILLABLES.put(input, new Pair<>(predicate, action)); } + + /** + * Adds a new tilling action. + * + * @param input input block + * @param predicate context predicate + * @param action action to run + * @param newState the new block state + */ + @ExpectPlatform + public static void addTillable(Block input, Predicate predicate, Consumer action, Function newState) { + throw new AssertionError(); + } } diff --git a/fabric/src/main/java/dev/architectury/hooks/item/tool/fabric/HoeItemHooksImpl.java b/fabric/src/main/java/dev/architectury/hooks/item/tool/fabric/HoeItemHooksImpl.java new file mode 100644 index 00000000..b1562249 --- /dev/null +++ b/fabric/src/main/java/dev/architectury/hooks/item/tool/fabric/HoeItemHooksImpl.java @@ -0,0 +1,26 @@ +package dev.architectury.hooks.item.tool.fabric; + +import com.google.common.collect.ImmutableMap; +import com.mojang.datafixers.util.Pair; +import net.minecraft.world.item.HoeItem; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.HashMap; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; + +public class HoeItemHooksImpl { + public static void addTillable(Block input, Predicate predicate, Consumer action, Function newState) { + if (HoeItem.TILLABLES instanceof ImmutableMap) { + HoeItem.TILLABLES = new HashMap<>(HoeItem.TILLABLES); + } + HoeItem.TILLABLES.put(input, new Pair<>(predicate, useOnContext -> { + action.accept(useOnContext); + BlockState state = newState.apply(useOnContext); + useOnContext.getLevel().setBlock(useOnContext.getClickedPos(), state, 11); + })); + } +} diff --git a/fabric/src/main/java/dev/architectury/registry/registries/fabric/RegistriesImpl.java b/fabric/src/main/java/dev/architectury/registry/registries/fabric/RegistriesImpl.java index 0f4e9d6f..2110ee75 100644 --- a/fabric/src/main/java/dev/architectury/registry/registries/fabric/RegistriesImpl.java +++ b/fabric/src/main/java/dev/architectury/registry/registries/fabric/RegistriesImpl.java @@ -19,6 +19,7 @@ package dev.architectury.registry.registries.fabric; +import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import com.google.common.base.Suppliers; import com.google.common.collect.HashMultimap; @@ -34,6 +35,7 @@ import net.fabricmc.fabric.api.event.registry.RegistryAttribute; import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback; import net.minecraft.core.MappedRegistry; import net.minecraft.core.Registry; +import net.minecraft.data.BuiltinRegistries; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.Nullable; @@ -48,7 +50,8 @@ public class RegistriesImpl { private static void listen(ResourceKey resourceKey, ResourceLocation id, Consumer listener) { if (LISTENED_REGISTRIES.add(resourceKey)) { - RegistryEntryAddedCallback.event(Registry.REGISTRY.get(resourceKey.location())).register((rawId, entryId, object) -> { + Registry registry = MoreObjects.firstNonNull(Registry.REGISTRY.get(resourceKey.location()), BuiltinRegistries.REGISTRY.get(resourceKey.location())); + RegistryEntryAddedCallback.event(registry).register((rawId, entryId, object) -> { RegistryEntryId registryEntryId = new RegistryEntryId<>(resourceKey, entryId); for (Consumer consumer : LISTENERS.get(registryEntryId)) { ((Consumer) consumer).accept(object); @@ -67,7 +70,7 @@ public class RegistriesImpl { public static ResourceLocation getId(T object, ResourceKey> fallback) { if (fallback == null) return null; - return getId(object, (Registry) Registry.REGISTRY.get(fallback.location())); + return getId(object, (Registry) MoreObjects.firstNonNull(Registry.REGISTRY.get(fallback.location()), BuiltinRegistries.REGISTRY.get(fallback.location()))); } public static ResourceLocation getId(T object, Registry fallback) { @@ -85,7 +88,7 @@ public class RegistriesImpl { @Override public Registrar get(ResourceKey> key) { - return new RegistrarImpl<>(modId, (Registry) Registry.REGISTRY.get(key.location())); + return new RegistrarImpl<>(modId, (Registry) MoreObjects.firstNonNull(Registry.REGISTRY.get(key.location()), BuiltinRegistries.REGISTRY.get(key.location()))); } @Override diff --git a/forge/src/main/java/dev/architectury/hooks/item/tool/forge/HoeItemHooksImpl.java b/forge/src/main/java/dev/architectury/hooks/item/tool/forge/HoeItemHooksImpl.java new file mode 100644 index 00000000..7b25ca60 --- /dev/null +++ b/forge/src/main/java/dev/architectury/hooks/item/tool/forge/HoeItemHooksImpl.java @@ -0,0 +1,28 @@ +package dev.architectury.hooks.item.tool.forge; + +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.ToolActions; +import net.minecraftforge.event.world.BlockEvent; + +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; + +public class HoeItemHooksImpl { + public static void addTillable(Block input, Predicate predicate, Consumer action, Function function) { + MinecraftForge.EVENT_BUS.addListener(event -> { + UseOnContext context = event.getContext(); + if (ToolActions.HOE_TILL == event.getToolAction() && context.getItemInHand().canPerformAction(ToolActions.HOE_TILL) + && event.getState().is(input) && predicate.test(context)) { + if (!event.isSimulated()) { + action.accept(context); + } + + event.setFinalState(function.apply(context)); + } + }); + } +} diff --git a/forge/src/main/java/dev/architectury/registry/registries/forge/RegistriesImpl.java b/forge/src/main/java/dev/architectury/registry/registries/forge/RegistriesImpl.java index ec72c755..77daf25a 100644 --- a/forge/src/main/java/dev/architectury/registry/registries/forge/RegistriesImpl.java +++ b/forge/src/main/java/dev/architectury/registry/registries/forge/RegistriesImpl.java @@ -31,6 +31,7 @@ import dev.architectury.registry.registries.RegistrySupplier; import dev.architectury.registry.registries.options.RegistrarOption; import dev.architectury.registry.registries.options.StandardRegistrarOption; import net.minecraft.core.Registry; +import net.minecraft.data.BuiltinRegistries; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; @@ -42,8 +43,9 @@ import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.registries.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.*; import java.util.function.Consumer; import java.util.function.Supplier; @@ -139,6 +141,12 @@ public class RegistriesImpl { private final Map>, Data> registry = new HashMap<>(); private final Multimap>, Consumer>> listeners = HashMultimap.create(); + record RegistryBuilderEntry(RegistryBuilder builder, Consumer> forgeRegistry) { + } + + @Nullable + private List builders = new ArrayList<>(); + public RegistryProviderImpl(String modId) { this.modId = modId; this.eventBus = Suppliers.memoize(() -> { @@ -161,6 +169,7 @@ public class RegistriesImpl { ForgeRegistry registry = RegistryManager.ACTIVE.getRegistry(registryKey.location()); if (registry == null) { Registry ts = (Registry) Registry.REGISTRY.get(registryKey.location()); + if (ts == null) ts = (Registry) BuiltinRegistries.REGISTRY.get(registryKey.location()); if (ts == null) { throw new IllegalArgumentException("Registry " + registryKey + " does not exist!"); } else { @@ -191,7 +200,7 @@ public class RegistriesImpl { public RegistrarBuilder builder(Class type, ResourceLocation registryId) { return new RegistryBuilderWrapper<>(this, new net.minecraftforge.registries.RegistryBuilder<>() .setName(registryId) - .setType((Class) type)); + .setType((Class) type), registryId); } public class EventListener { @@ -325,25 +334,47 @@ public class RegistriesImpl { LISTENERS.removeAll(id); } } + + @SubscribeEvent + public void handleEvent(NewRegistryEvent event) { + if (builders != null) { + for (RegistryBuilderEntry builder : builders) { + event.create((RegistryBuilder) builder.builder(), (Consumer) builder.forgeRegistry()); + } + builders = null; + } + } } } public static class RegistryBuilderWrapper implements RegistrarBuilder { private final RegistryProviderImpl provider; private final net.minecraftforge.registries.RegistryBuilder builder; + private final ResourceLocation registryId; private boolean saveToDisk = false; private boolean syncToClients = false; - public RegistryBuilderWrapper(RegistryProviderImpl provider, net.minecraftforge.registries.RegistryBuilder builder) { + public RegistryBuilderWrapper(RegistryProviderImpl provider, RegistryBuilder builder, ResourceLocation registryId) { this.provider = provider; this.builder = builder; + this.registryId = registryId; } @Override public Registrar build() { if (!syncToClients) builder.disableSync(); if (!saveToDisk) builder.disableSaving(); - return provider.get(builder.create()); + if (provider.builders == null) { + throw new IllegalStateException("Cannot create registries when registries are already aggregated!"); + } + final var registrarRef = new Registrar[1]; + var registrar = new DelegatedRegistrar(provider.modId, () -> java.util.Objects.requireNonNull(registrarRef[0], "Registry not yet initialized!"), registryId); + var entry = new RegistryProviderImpl.RegistryBuilderEntry(builder, forgeRegistry -> { + registrarRef[0] = provider.get(forgeRegistry); + registrar.onRegister(); + }); + provider.builders.add(entry); + return registrar; } @Override @@ -565,7 +596,7 @@ public class RegistriesImpl { @Override public RegistrySupplier register(ResourceLocation id, Supplier supplier) { - RegistryObject registryObject = RegistryObject.of(id, delegate); + RegistryObject registryObject = RegistryObject.create(id, delegate); registry.computeIfAbsent(key(), type -> new Data()) .register(delegate, registryObject, () -> supplier.get().setRegistryName(id)); Registrar registrar = this; @@ -686,4 +717,141 @@ public class RegistriesImpl { } } } + + public static class DelegatedRegistrar implements Registrar { + private final String modId; + private final Supplier> delegate; + private final ResourceLocation registryId; + private List onRegister = new ArrayList<>(); + + public DelegatedRegistrar(String modId, Supplier> delegate, ResourceLocation registryId) { + this.modId = modId; + this.delegate = delegate; + this.registryId = registryId; + } + + public void onRegister() { + if (onRegister != null) { + for (Runnable runnable : onRegister) { + runnable.run(); + } + } + onRegister = null; + } + + public boolean isReady() { + return onRegister == null; + } + + @Override + public RegistrySupplier delegate(ResourceLocation id) { + if (isReady()) return delegate.get().delegate(id); + return new RegistrySupplier() { + @Override + public Registries getRegistries() { + return Registries.get(modId); + } + + @Override + public Registrar getRegistrar() { + return DelegatedRegistrar.this; + } + + @Override + public ResourceLocation getRegistryId() { + return DelegatedRegistrar.this.key().location(); + } + + @Override + public ResourceLocation getId() { + return id; + } + + @Override + public boolean isPresent() { + return isReady() && delegate.get().contains(id); + } + + @Override + public T get() { + return isReady() ? delegate.get().get(id) : null; + } + }; + } + + @Override + public RegistrySupplier register(ResourceLocation id, Supplier supplier) { + if (isReady()) return delegate.get().register(id, supplier); + onRegister.add(() -> delegate.get().register(id, supplier)); + return (RegistrySupplier) delegate(id); + } + + @Override + @Nullable + public ResourceLocation getId(T obj) { + return !isReady() ? null : delegate.get().getId(obj); + } + + @Override + public int getRawId(T obj) { + return !isReady() ? -1 : delegate.get().getRawId(obj); + } + + @Override + public Optional> getKey(T obj) { + return !isReady() ? Optional.empty() : delegate.get().getKey(obj); + } + + @Override + @Nullable + public T get(ResourceLocation id) { + return !isReady() ? null : delegate.get().get(id); + } + + @Override + @Nullable + public T byRawId(int rawId) { + return !isReady() ? null : delegate.get().byRawId(rawId); + } + + @Override + public boolean contains(ResourceLocation id) { + return isReady() && delegate.get().contains(id); + } + + @Override + public boolean containsValue(T obj) { + return isReady() && delegate.get().containsValue(obj); + } + + @Override + public Set getIds() { + return isReady() ? delegate.get().getIds() : Collections.emptySet(); + } + + @Override + public Set, T>> entrySet() { + return isReady() ? delegate.get().entrySet() : Collections.emptySet(); + } + + @Override + public ResourceKey> key() { + return isReady() ? delegate.get().key() : ResourceKey.createRegistryKey(registryId); + } + + @Override + public void listen(ResourceLocation id, Consumer callback) { + if (isReady()) { + delegate.get().listen(id, callback); + } else { + onRegister.add(() -> delegate.get().listen(id, callback)); + } + } + + @NotNull + @Override + public Iterator iterator() { + return isReady() ? delegate.get().iterator() : Collections.emptyIterator(); + } + } } diff --git a/gradle.properties b/gradle.properties index 4b052aed..3a28a646 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,4 +17,4 @@ fabric_loader_version=0.13.3 fabric_api_version=0.50.0+1.18.2 mod_menu_version=3.0.0 -forge_version=40.0.1 +forge_version=40.1.14 diff --git a/testmod-common/src/main/java/dev/architectury/test/item/TestBlockInteractions.java b/testmod-common/src/main/java/dev/architectury/test/item/TestBlockInteractions.java index 09862ccd..5572bc9b 100644 --- a/testmod-common/src/main/java/dev/architectury/test/item/TestBlockInteractions.java +++ b/testmod-common/src/main/java/dev/architectury/test/item/TestBlockInteractions.java @@ -31,28 +31,21 @@ import net.minecraft.world.level.block.Blocks; public final class TestBlockInteractions { private TestBlockInteractions() { } - + public static void init() { AxeItemHooks.addStrippable(Blocks.QUARTZ_PILLAR, Blocks.OAK_LOG); ShovelItemHooks.addFlattenable(Blocks.IRON_ORE, Blocks.DIAMOND_BLOCK.defaultBlockState()); HoeItemHooks.addTillable(Blocks.COAL_BLOCK, ctx -> { - if (!ctx.getLevel().isNight()) { - if (!ctx.getLevel().isClientSide) { - Player player = ctx.getPlayer(); - if (player != null) - player.sendMessage(new TextComponent("These dark arts can only be done at night!"), Util.NIL_UUID); - } - return false; - } - return true; + return ctx.getLevel().isNight(); }, ctx -> { BlockPos pos = ctx.getClickedPos(); - ctx.getLevel().setBlock(pos, Blocks.DIAMOND_BLOCK.defaultBlockState(), 3); if (!ctx.getLevel().isClientSide) { Player player = ctx.getPlayer(); if (player != null) player.sendMessage(new TextComponent("Thou has successfully committed the dark arts of alchemy!!"), Util.NIL_UUID); } + }, ctx -> { + return Blocks.DIAMOND_BLOCK.defaultBlockState(); }); } } diff --git a/testmod-common/src/main/java/dev/architectury/test/registry/TestRegistries.java b/testmod-common/src/main/java/dev/architectury/test/registry/TestRegistries.java index d1418a8d..3eeeb002 100644 --- a/testmod-common/src/main/java/dev/architectury/test/registry/TestRegistries.java +++ b/testmod-common/src/main/java/dev/architectury/test/registry/TestRegistries.java @@ -19,12 +19,15 @@ package dev.architectury.test.registry; +import dev.architectury.core.RegistryEntry; import dev.architectury.core.item.ArchitecturySpawnEggItem; import dev.architectury.hooks.item.food.FoodPropertiesHooks; import dev.architectury.hooks.level.entity.EntityHooks; import dev.architectury.registry.block.BlockProperties; import dev.architectury.registry.level.entity.EntityAttributeRegistry; import dev.architectury.registry.registries.DeferredRegister; +import dev.architectury.registry.registries.Registrar; +import dev.architectury.registry.registries.Registries; import dev.architectury.registry.registries.RegistrySupplier; import dev.architectury.test.TestMod; import dev.architectury.test.entity.TestEntity; @@ -33,6 +36,7 @@ import dev.architectury.test.registry.objects.EquippableTickingItem; import dev.architectury.test.tab.TestCreativeTabs; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectCategory; import net.minecraft.world.effect.MobEffectInstance; @@ -53,6 +57,17 @@ import net.minecraft.world.phys.shapes.VoxelShape; import static dev.architectury.test.TestMod.SINK; public class TestRegistries { + public static final class TestInt extends RegistryEntry { + public final int value; + + public TestInt(int value) { + this.value = value; + } + } + + public static final Registrar INTS = Registries.get(TestMod.MOD_ID).builder(new ResourceLocation(TestMod.MOD_ID, "ints")) + .syncToClients() + .build(); public static final DeferredRegister ITEMS = DeferredRegister.create(TestMod.MOD_ID, Registry.ITEM_REGISTRY); public static final DeferredRegister BLOCKS = DeferredRegister.create(TestMod.MOD_ID, Registry.BLOCK_REGISTRY); public static final DeferredRegister> ENTITY_TYPES = DeferredRegister.create(TestMod.MOD_ID, Registry.ENTITY_TYPE_REGISTRY); @@ -60,6 +75,8 @@ public class TestRegistries { public static final DeferredRegister> RECIPE_SERIALIZERS = DeferredRegister.create(TestMod.MOD_ID, Registry.RECIPE_SERIALIZER_REGISTRY); public static final DeferredRegister> RECIPE_TYPES = DeferredRegister.create(TestMod.MOD_ID, Registry.RECIPE_TYPE_REGISTRY); + public static final RegistrySupplier TEST_INT = INTS.register(new ResourceLocation(TestMod.MOD_ID, "test_int"), () -> new TestInt(1)); + public static final RegistrySupplier TEST_INT_2 = INTS.register(new ResourceLocation(TestMod.MOD_ID, "test_int_2"), () -> new TestInt(2)); public static final RegistrySupplier TEST_EFFECT = MOB_EFFECTS.register("test_effect", () -> new MobEffect(MobEffectCategory.NEUTRAL, 0x123456) { });