Fix some broken features and random crashes (#253)

[ci skip]
This commit is contained in:
shedaniel
2022-05-06 19:40:02 +08:00
committed by GitHub
parent 5318686674
commit 3532d24577
8 changed files with 274 additions and 20 deletions

View File

@@ -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<UseOnContext> predicate, Consumer<UseOnContext> 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<UseOnContext> predicate, Consumer<UseOnContext> action, Function<UseOnContext, BlockState> newState) {
throw new AssertionError();
}
}

View File

@@ -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<UseOnContext> predicate, Consumer<UseOnContext> action, Function<UseOnContext, BlockState> 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);
}));
}
}

View File

@@ -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<Object>) consumer).accept(object);
@@ -67,7 +70,7 @@ public class RegistriesImpl {
public static <T> ResourceLocation getId(T object, ResourceKey<Registry<T>> fallback) {
if (fallback == null)
return null;
return getId(object, (Registry<T>) Registry.REGISTRY.get(fallback.location()));
return getId(object, (Registry<T>) MoreObjects.firstNonNull(Registry.REGISTRY.get(fallback.location()), BuiltinRegistries.REGISTRY.get(fallback.location())));
}
public static <T> ResourceLocation getId(T object, Registry<T> fallback) {
@@ -85,7 +88,7 @@ public class RegistriesImpl {
@Override
public <T> Registrar<T> get(ResourceKey<Registry<T>> key) {
return new RegistrarImpl<>(modId, (Registry<T>) Registry.REGISTRY.get(key.location()));
return new RegistrarImpl<>(modId, (Registry<T>) MoreObjects.firstNonNull(Registry.REGISTRY.get(key.location()), BuiltinRegistries.REGISTRY.get(key.location())));
}
@Override

View File

@@ -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<UseOnContext> predicate, Consumer<UseOnContext> action, Function<UseOnContext, BlockState> function) {
MinecraftForge.EVENT_BUS.<BlockEvent.BlockToolModificationEvent>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));
}
});
}
}

View File

@@ -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<ResourceKey<? extends Registry<?>>, Data> registry = new HashMap<>();
private final Multimap<ResourceKey<Registry<?>>, Consumer<Registrar<?>>> listeners = HashMultimap.create();
record RegistryBuilderEntry(RegistryBuilder<?> builder, Consumer<IForgeRegistry<?>> forgeRegistry) {
}
@Nullable
private List<RegistryBuilderEntry> 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<T> ts = (Registry<T>) Registry.REGISTRY.get(registryKey.location());
if (ts == null) ts = (Registry<T>) 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 <T> RegistrarBuilder<T> builder(Class<T> 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<T> implements RegistrarBuilder<T> {
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<T> 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 <E extends T> RegistrySupplier<E> register(ResourceLocation id, Supplier<E> 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<T> registrar = this;
@@ -686,4 +717,141 @@ public class RegistriesImpl {
}
}
}
public static class DelegatedRegistrar<T> implements Registrar<T> {
private final String modId;
private final Supplier<Registrar<T>> delegate;
private final ResourceLocation registryId;
private List<Runnable> onRegister = new ArrayList<>();
public DelegatedRegistrar(String modId, Supplier<Registrar<T>> 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<T> delegate(ResourceLocation id) {
if (isReady()) return delegate.get().delegate(id);
return new RegistrySupplier<T>() {
@Override
public Registries getRegistries() {
return Registries.get(modId);
}
@Override
public Registrar<T> 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 <E extends T> RegistrySupplier<E> register(ResourceLocation id, Supplier<E> supplier) {
if (isReady()) return delegate.get().register(id, supplier);
onRegister.add(() -> delegate.get().register(id, supplier));
return (RegistrySupplier<E>) 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<ResourceKey<T>> 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<ResourceLocation> getIds() {
return isReady() ? delegate.get().getIds() : Collections.emptySet();
}
@Override
public Set<Map.Entry<ResourceKey<T>, T>> entrySet() {
return isReady() ? delegate.get().entrySet() : Collections.emptySet();
}
@Override
public ResourceKey<? extends Registry<T>> key() {
return isReady() ? delegate.get().key() : ResourceKey.createRegistryKey(registryId);
}
@Override
public void listen(ResourceLocation id, Consumer<T> callback) {
if (isReady()) {
delegate.get().listen(id, callback);
} else {
onRegister.add(() -> delegate.get().listen(id, callback));
}
}
@NotNull
@Override
public Iterator<T> iterator() {
return isReady() ? delegate.get().iterator() : Collections.emptyIterator();
}
}
}

View File

@@ -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

View File

@@ -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();
});
}
}

View File

@@ -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<TestInt> {
public final int value;
public TestInt(int value) {
this.value = value;
}
}
public static final Registrar<TestInt> INTS = Registries.get(TestMod.MOD_ID).<TestInt>builder(new ResourceLocation(TestMod.MOD_ID, "ints"))
.syncToClients()
.build();
public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(TestMod.MOD_ID, Registry.ITEM_REGISTRY);
public static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(TestMod.MOD_ID, Registry.BLOCK_REGISTRY);
public static final DeferredRegister<EntityType<?>> ENTITY_TYPES = DeferredRegister.create(TestMod.MOD_ID, Registry.ENTITY_TYPE_REGISTRY);
@@ -60,6 +75,8 @@ public class TestRegistries {
public static final DeferredRegister<RecipeSerializer<?>> RECIPE_SERIALIZERS = DeferredRegister.create(TestMod.MOD_ID, Registry.RECIPE_SERIALIZER_REGISTRY);
public static final DeferredRegister<RecipeType<?>> RECIPE_TYPES = DeferredRegister.create(TestMod.MOD_ID, Registry.RECIPE_TYPE_REGISTRY);
public static final RegistrySupplier<TestInt> TEST_INT = INTS.register(new ResourceLocation(TestMod.MOD_ID, "test_int"), () -> new TestInt(1));
public static final RegistrySupplier<TestInt> TEST_INT_2 = INTS.register(new ResourceLocation(TestMod.MOD_ID, "test_int_2"), () -> new TestInt(2));
public static final RegistrySupplier<MobEffect> TEST_EFFECT = MOB_EFFECTS.register("test_effect", () ->
new MobEffect(MobEffectCategory.NEUTRAL, 0x123456) {
});