diff --git a/api/build.gradle b/api/build.gradle index 6c428a7d2..b0eeca7df 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -2,6 +2,10 @@ import net.fabricmc.loom.task.RemapJarTask archivesBaseName = rootProject.name + "-" + project.name +loom { + accessWidenerPath = gradle.rootProject.project("fabric").file("src/main/resources/roughlyenoughitems.accessWidener") +} + dependencies { modCompileOnly("net.fabricmc:fabric-loader:${project.fabricloader_version}") modApi("me.shedaniel.cloth:cloth-config:${cloth_config_version}") diff --git a/api/src/main/java/me/shedaniel/rei/api/common/display/basic/BasicDisplay.java b/api/src/main/java/me/shedaniel/rei/api/common/display/basic/BasicDisplay.java index 4acd1c530..f09f2fe4c 100644 --- a/api/src/main/java/me/shedaniel/rei/api/common/display/basic/BasicDisplay.java +++ b/api/src/main/java/me/shedaniel/rei/api/common/display/basic/BasicDisplay.java @@ -23,12 +23,11 @@ package me.shedaniel.rei.api.common.display.basic; -import dev.architectury.utils.EnvExecutor; -import dev.architectury.utils.GameInstance; import me.shedaniel.rei.api.common.display.Display; import me.shedaniel.rei.api.common.display.SimpleDisplaySerializer; import me.shedaniel.rei.api.common.entry.EntryIngredient; import me.shedaniel.rei.api.common.util.EntryIngredients; +import me.shedaniel.rei.impl.common.InternalRegistryAccess; import net.minecraft.core.RegistryAccess; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; @@ -38,16 +37,12 @@ import java.util.List; import java.util.Optional; -import java.util.function.Supplier; /** * A basic implementation of a display, consisting of a list of inputs, a list of outputs * and a possible display location. */ public abstract class BasicDisplay implements Display { - protected static final Supplier REGISTRY_ACCESS = - EnvExecutor.getEnvSpecific(() -> () -> () -> GameInstance.getClient().player.level().registryAccess(), - () -> () -> () -> GameInstance.getServer().registryAccess()); protected List inputs; protected List outputs; protected Optional location; @@ -64,7 +59,7 @@ public BasicDisplay(List inputs, List outputs, @ApiStatus.Experimental public static RegistryAccess registryAccess() { - return REGISTRY_ACCESS.get(); + return InternalRegistryAccess.getInstance().get(); } /** diff --git a/api/src/main/java/me/shedaniel/rei/impl/common/InternalRegistryAccess.java b/api/src/main/java/me/shedaniel/rei/impl/common/InternalRegistryAccess.java new file mode 100644 index 000000000..2f1354c4a --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/impl/common/InternalRegistryAccess.java @@ -0,0 +1,86 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 shedaniel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.shedaniel.rei.impl.common; + +import dev.architectury.platform.Platform; +import dev.architectury.utils.Env; +import dev.architectury.utils.GameInstance; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.Minecraft; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.BuiltInRegistries; +import org.jetbrains.annotations.ApiStatus; + +import java.lang.ref.WeakReference; +import java.util.function.Supplier; + +@ApiStatus.Internal +public final class InternalRegistryAccess implements Supplier { + private static final InternalRegistryAccess INSTANCE = new InternalRegistryAccess(); + private WeakReference registryAccess; + private boolean warned; + + public static InternalRegistryAccess getInstance() { + return INSTANCE; + } + + @Override + public RegistryAccess get() { + RegistryAccess access = this.registryAccess == null ? null : this.registryAccess.get(); + if (access != null) { + return access; + } + + if (Platform.getEnvironment() == Env.CLIENT) { + access = getFromClient(); + } else if (GameInstance.getServer() != null) { + access = GameInstance.getServer().registryAccess(); + } + + if (access == null && !this.warned) { + this.warned = true; + + new NullPointerException("Cannot get registry access!").printStackTrace(); + InternalLogger.getInstance().warn("Cannot get registry access!"); + return RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY); + } + + return access; + } + + @Environment(EnvType.CLIENT) + private static RegistryAccess getFromClient() { + if (Minecraft.getInstance().level != null) { + return Minecraft.getInstance().level.registryAccess(); + } else if (Minecraft.getInstance().getConnection() != null) { + return Minecraft.getInstance().getConnection().registryAccess(); + } else if (Minecraft.getInstance().gameMode != null) { + // Sometimes the packet is sent way too fast and is between the connection and the level, better safe than sorry + return Minecraft.getInstance().gameMode.connection.registryAccess(); + } + + return null; + } +} diff --git a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/DefaultPlugin.java b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/DefaultPlugin.java index 0cb016597..a98ee1563 100644 --- a/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/DefaultPlugin.java +++ b/default-plugin/src/main/java/me/shedaniel/rei/plugin/common/DefaultPlugin.java @@ -64,11 +64,8 @@ public class DefaultPlugin implements BuiltinPlugin, REIServerPlugin { @Override public void registerItemComparators(ItemComparatorRegistry registry) { Function enchantmentTag = stack -> { - if (!stack.has(DataComponents.ENCHANTMENTS)) { - if (stack.has(DataComponents.STORED_ENCHANTMENTS)) { - return stack.get(DataComponents.STORED_ENCHANTMENTS); - } - return null; + if (stack.has(DataComponents.STORED_ENCHANTMENTS)) { + return stack.get(DataComponents.STORED_ENCHANTMENTS); } return stack.get(DataComponents.ENCHANTMENTS); }; diff --git a/fabric/src/main/java/me/shedaniel/rei/impl/client/fabric/CreativeModeTabCollectorImpl.java b/fabric/src/main/java/me/shedaniel/rei/impl/client/fabric/CreativeModeTabCollectorImpl.java index a24a34f42..660ebefaa 100644 --- a/fabric/src/main/java/me/shedaniel/rei/impl/client/fabric/CreativeModeTabCollectorImpl.java +++ b/fabric/src/main/java/me/shedaniel/rei/impl/client/fabric/CreativeModeTabCollectorImpl.java @@ -27,7 +27,6 @@ import me.shedaniel.rei.impl.common.InternalLogger; import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroupEntries; import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents; -import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceKey; import net.minecraft.world.flag.FeatureFlagSet; @@ -42,7 +41,7 @@ public class CreativeModeTabCollectorImpl { public static Map> collectTabs() { Map> map = new LinkedHashMap<>(); FeatureFlagSet featureFlags = FeatureFlags.REGISTRY.allFlags(); - CreativeModeTab.ItemDisplayParameters parameters = new CreativeModeTab.ItemDisplayParameters(featureFlags, true, Objects.requireNonNullElseGet(BasicDisplay.registryAccess(), () -> RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY))); + CreativeModeTab.ItemDisplayParameters parameters = new CreativeModeTab.ItemDisplayParameters(featureFlags, true, BasicDisplay.registryAccess()); for (CreativeModeTab tab : CreativeModeTabs.allTabs()) { if (tab.getType() != CreativeModeTab.Type.HOTBAR && tab.getType() != CreativeModeTab.Type.INVENTORY) { diff --git a/fabric/src/main/java/me/shedaniel/rei/mixin/fabric/MixinClientPacketListener.java b/fabric/src/main/java/me/shedaniel/rei/mixin/fabric/MixinClientPacketListener.java index 4b4f394e7..4cff54d51 100644 --- a/fabric/src/main/java/me/shedaniel/rei/mixin/fabric/MixinClientPacketListener.java +++ b/fabric/src/main/java/me/shedaniel/rei/mixin/fabric/MixinClientPacketListener.java @@ -25,6 +25,7 @@ import me.shedaniel.rei.RoughlyEnoughItemsCoreClient; import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.core.RegistryAccess; import net.minecraft.network.protocol.common.ClientboundUpdateTagsPacket; import net.minecraft.network.protocol.game.ClientboundUpdateRecipesPacket; import net.minecraft.world.item.crafting.RecipeManager; @@ -36,12 +37,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ClientPacketListener.class) -public class MixinClientPacketListener { +public abstract class MixinClientPacketListener { @Shadow @Final private RecipeManager recipeManager; + @Shadow public abstract RegistryAccess.Frozen registryAccess(); + @Inject(method = "handleUpdateRecipes", at = @At("HEAD")) private void handleUpdateRecipes(ClientboundUpdateRecipesPacket clientboundUpdateRecipesPacket, CallbackInfo ci) { - RoughlyEnoughItemsCoreClient.PRE_UPDATE_RECIPES.invoker().update(recipeManager); + RoughlyEnoughItemsCoreClient.PRE_UPDATE_RECIPES.invoker().accept(recipeManager, registryAccess()); } @Inject(method = "handleUpdateTags", at = @At("HEAD")) diff --git a/fabric/src/main/resources/roughlyenoughitems.accessWidener b/fabric/src/main/resources/roughlyenoughitems.accessWidener index 2430ce5b4..461372b01 100644 --- a/fabric/src/main/resources/roughlyenoughitems.accessWidener +++ b/fabric/src/main/resources/roughlyenoughitems.accessWidener @@ -39,3 +39,4 @@ accessible field net/minecraft/world/item/crafting/SmithingTrimRecipe base Lnet/ accessible field net/minecraft/world/item/crafting/SmithingTrimRecipe addition Lnet/minecraft/world/item/crafting/Ingredient; accessible field net/minecraft/world/item/CreativeModeTab displayItemsGenerator Lnet/minecraft/world/item/CreativeModeTab$DisplayItemsGenerator; accessible class net/minecraft/world/item/CreativeModeTab$ItemDisplayBuilder +accessible field net/minecraft/client/multiplayer/MultiPlayerGameMode connection Lnet/minecraft/client/multiplayer/ClientPacketListener; \ No newline at end of file diff --git a/neoforge/src/main/java/me/shedaniel/rei/forge/AnnotationUtils.java b/neoforge/src/main/java/me/shedaniel/rei/forge/AnnotationUtils.java index 9a13e0cdc..6486f0aba 100644 --- a/neoforge/src/main/java/me/shedaniel/rei/forge/AnnotationUtils.java +++ b/neoforge/src/main/java/me/shedaniel/rei/forge/AnnotationUtils.java @@ -28,7 +28,7 @@ import net.neoforged.api.distmarker.Dist; import net.neoforged.fml.ModList; import net.neoforged.fml.loading.FMLEnvironment; -import net.neoforged.fml.loading.moddiscovery.ModAnnotation; +import net.neoforged.fml.loading.modscan.ModAnnotation; import net.neoforged.neoforgespi.language.IModInfo; import net.neoforged.neoforgespi.language.ModFileScanData; import org.apache.commons.lang3.tuple.ImmutableTriple; @@ -68,13 +68,13 @@ public static void scanAnnotation(Type annotationType, Predicate> p if (value instanceof Dist[]) { enabled = Arrays.asList((Dist[]) value).contains(FMLEnvironment.dist); } else if (value instanceof ModAnnotation.EnumHolder) { - enabled = Objects.equals(((ModAnnotation.EnumHolder) value).getValue(), FMLEnvironment.dist.name()); + enabled = Objects.equals(((ModAnnotation.EnumHolder) value).value(), FMLEnvironment.dist.name()); } else if (value instanceof List) { List holders = ((List) value).stream().filter(o -> o instanceof ModAnnotation.EnumHolder) .map(o -> (ModAnnotation.EnumHolder) o).toList(); if (!holders.isEmpty()) { enabled = holders.stream() - .anyMatch(o -> Objects.equals(o.getValue(), FMLEnvironment.dist.name())); + .anyMatch(o -> Objects.equals(o.value(), FMLEnvironment.dist.name())); } else { enabled = true; } diff --git a/neoforge/src/main/java/me/shedaniel/rei/impl/client/forge/CreativeModeTabCollectorImpl.java b/neoforge/src/main/java/me/shedaniel/rei/impl/client/forge/CreativeModeTabCollectorImpl.java index 1f01634e4..57b097ec6 100644 --- a/neoforge/src/main/java/me/shedaniel/rei/impl/client/forge/CreativeModeTabCollectorImpl.java +++ b/neoforge/src/main/java/me/shedaniel/rei/impl/client/forge/CreativeModeTabCollectorImpl.java @@ -25,7 +25,6 @@ import me.shedaniel.rei.api.common.display.basic.BasicDisplay; import me.shedaniel.rei.impl.common.InternalLogger; -import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceKey; import net.minecraft.world.flag.FeatureFlagSet; @@ -38,13 +37,12 @@ import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Objects; public class CreativeModeTabCollectorImpl { public static Map> collectTabs() { Map> map = new LinkedHashMap<>(); FeatureFlagSet featureFlags = FeatureFlags.REGISTRY.allFlags(); - CreativeModeTab.ItemDisplayParameters parameters = new CreativeModeTab.ItemDisplayParameters(featureFlags, true, Objects.requireNonNullElseGet(BasicDisplay.registryAccess(), () -> RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY))); + CreativeModeTab.ItemDisplayParameters parameters = new CreativeModeTab.ItemDisplayParameters(featureFlags, true, BasicDisplay.registryAccess()); for (CreativeModeTab tab : CreativeModeTabs.allTabs()) { if (tab.getType() != CreativeModeTab.Type.HOTBAR && tab.getType() != CreativeModeTab.Type.INVENTORY) { diff --git a/neoforge/src/main/java/me/shedaniel/rei/mixin/forge/MixinClientPacketListener.java b/neoforge/src/main/java/me/shedaniel/rei/mixin/forge/MixinClientPacketListener.java index 333f8fdbc..7b059f109 100644 --- a/neoforge/src/main/java/me/shedaniel/rei/mixin/forge/MixinClientPacketListener.java +++ b/neoforge/src/main/java/me/shedaniel/rei/mixin/forge/MixinClientPacketListener.java @@ -25,6 +25,7 @@ import me.shedaniel.rei.RoughlyEnoughItemsCoreClient; import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.core.RegistryAccess; import net.minecraft.network.protocol.common.ClientboundUpdateTagsPacket; import net.minecraft.network.protocol.game.ClientboundUpdateRecipesPacket; import net.minecraft.world.item.crafting.RecipeManager; @@ -36,12 +37,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ClientPacketListener.class) -public class MixinClientPacketListener { +public abstract class MixinClientPacketListener { @Shadow @Final private RecipeManager recipeManager; + @Shadow public abstract RegistryAccess.Frozen registryAccess(); + @Inject(method = "handleUpdateRecipes", at = @At("HEAD")) private void handleUpdateRecipes(ClientboundUpdateRecipesPacket clientboundUpdateRecipesPacket, CallbackInfo ci) { - RoughlyEnoughItemsCoreClient.PRE_UPDATE_RECIPES.invoker().update(recipeManager); + RoughlyEnoughItemsCoreClient.PRE_UPDATE_RECIPES.invoker().accept(recipeManager, registryAccess()); } @Inject(method = "handleUpdateTags", at = @At("HEAD")) diff --git a/neoforge/src/main/resources/META-INF/accesstransformer.cfg b/neoforge/src/main/resources/META-INF/accesstransformer.cfg index d1b35d717..2d87bddf1 100644 --- a/neoforge/src/main/resources/META-INF/accesstransformer.cfg +++ b/neoforge/src/main/resources/META-INF/accesstransformer.cfg @@ -48,3 +48,4 @@ public-f net.minecraft.client.gui.font.CodepointMap blockMap # blockMap public-f net.minecraft.client.gui.font.CodepointMap blockConstructor # blockConstructor public net.minecraft.world.item.CreativeModeTab displayItemsGenerator # displayItemsGenerator public net.minecraft.world.item.CreativeModeTab$ItemDisplayBuilder +public net.minecraft.client.multiplayer.MultiPlayerGameMode connection # connection diff --git a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java index 8d748f704..7756fb24c 100644 --- a/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java +++ b/runtime/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCoreClient.java @@ -100,6 +100,7 @@ import net.minecraft.client.gui.screens.recipebook.GhostRecipe; import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent; import net.minecraft.client.resources.language.I18n; +import net.minecraft.core.RegistryAccess; import net.minecraft.data.models.blockstates.PropertyDispatch; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; @@ -112,6 +113,7 @@ import net.minecraft.world.item.Items; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeManager; import org.apache.commons.lang3.mutable.MutableLong; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -120,15 +122,12 @@ import java.util.ConcurrentModificationException; import java.util.List; import java.util.concurrent.*; -import java.util.function.BiFunction; -import java.util.function.BooleanSupplier; -import java.util.function.Function; -import java.util.function.Supplier; +import java.util.function.*; import java.util.stream.Stream; @Environment(EnvType.CLIENT) public class RoughlyEnoughItemsCoreClient { - public static final Event PRE_UPDATE_RECIPES = EventFactory.createLoop(); + public static final Event> PRE_UPDATE_RECIPES = EventFactory.createLoop(); public static final Event POST_UPDATE_TAGS = EventFactory.createLoop(); public static boolean isLeftMousePressed = false; private static final ExecutorService RELOAD_PLUGINS = Executors.newSingleThreadScheduledExecutor(task -> { @@ -317,9 +316,9 @@ private void registerEvents() { final ResourceLocation recipeButtonTex = new ResourceLocation("textures/gui/recipe_button.png"); MutableLong startReload = new MutableLong(-1); MutableLong endReload = new MutableLong(-1); - PRE_UPDATE_RECIPES.register(recipeManager -> { + PRE_UPDATE_RECIPES.register((recipeManager, registryAccess) -> { RoughlyEnoughItemsCore.PERFORMANCE_LOGGER.clear(); - reloadPlugins(startReload, ReloadStage.START); + reloadPlugins(startReload, ReloadStage.START, registryAccess); }); ClientRecipeUpdateEvent.EVENT.register(recipeManager -> { reloadPlugins(endReload, ReloadStage.END); @@ -469,6 +468,11 @@ public static boolean resetFocused(Screen screen) { @ApiStatus.Internal public static void reloadPlugins(MutableLong lastReload, @Nullable ReloadStage start) { + reloadPlugins(lastReload, start, null); + } + + @ApiStatus.Internal + public static void reloadPlugins(MutableLong lastReload, @Nullable ReloadStage start, @Nullable RegistryAccess registryAccess) { if (Minecraft.getInstance().level == null) return; if (lastReload != null) { if (lastReload.getValue() > 0 && System.currentTimeMillis() - lastReload.getValue() <= 5000) {