Do not bypass Ingredient.TagValue#getItems during server resource reload
This breaks KubeJS/CraftTweaker's workarounds for tags not being available during RecipeManager#apply (even though they become available right after) Related: #555
This commit is contained in:
parent
c3086e5249
commit
5048e74c79
|
|
@ -0,0 +1,9 @@
|
|||
package org.embeddedt.modernfix.forge.load;
|
||||
|
||||
public class MinecraftServerReloadTracker {
|
||||
public static int ACTIVE_RELOADS = 0;
|
||||
|
||||
public static boolean isReloadActive() {
|
||||
return ACTIVE_RELOADS > 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package org.embeddedt.modernfix.forge.mixin.core;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.embeddedt.modernfix.forge.load.MinecraftServerReloadTracker;
|
||||
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 java.util.Collection;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Mixin(MinecraftServer.class)
|
||||
public class MinecraftServerMixin {
|
||||
@Inject(method = "reloadResources", at = @At("HEAD"))
|
||||
private void startReloadTrack(Collection<String> selectedIds, CallbackInfoReturnable<CompletableFuture<Void>> cir) {
|
||||
MinecraftServerReloadTracker.ACTIVE_RELOADS++;
|
||||
}
|
||||
|
||||
@ModifyExpressionValue(method = "reloadResources", at = @At(value = "INVOKE", target = "Ljava/util/concurrent/CompletableFuture;thenAcceptAsync(Ljava/util/function/Consumer;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;", ordinal = 0))
|
||||
private CompletableFuture<Void> mfix$endReloadTrack(CompletableFuture<Void> original) {
|
||||
return original.thenAcceptAsync(val -> {
|
||||
MinecraftServerReloadTracker.ACTIVE_RELOADS--;
|
||||
}, (Executor)this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package org.embeddedt.modernfix.forge.mixin.core;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.server.WorldLoader;
|
||||
import org.embeddedt.modernfix.forge.load.MinecraftServerReloadTracker;
|
||||
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 java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Mixin(WorldLoader.class)
|
||||
public class WorldLoaderMixin {
|
||||
@Inject(method = "load", at = @At("HEAD"))
|
||||
private static void trackStartReload(CallbackInfoReturnable<CompletableFuture<?>> cir) {
|
||||
MinecraftServerReloadTracker.ACTIVE_RELOADS++;
|
||||
}
|
||||
|
||||
@ModifyReturnValue(method = "load", at = @At("RETURN"))
|
||||
private static <V> CompletableFuture<V> trackEndReload(CompletableFuture<V> original, @Local(ordinal = 1, argsOnly = true) Executor syncExecutor) {
|
||||
return original.thenApplyAsync(val -> {
|
||||
MinecraftServerReloadTracker.ACTIVE_RELOADS--;
|
||||
return val;
|
||||
}, syncExecutor);
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import it.unimi.dsi.fastutil.ints.IntList;
|
|||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import org.embeddedt.modernfix.forge.load.MinecraftServerReloadTracker;
|
||||
import org.embeddedt.modernfix.forge.recipe.ExtendedIngredient;
|
||||
import org.embeddedt.modernfix.forge.recipe.IngredientItemStacksSoftReference;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
|
@ -34,13 +35,32 @@ public abstract class IngredientMixin implements ExtendedIngredient {
|
|||
|
||||
private volatile IngredientItemStacksSoftReference mfix$cachedItemStacks;
|
||||
|
||||
/**
|
||||
* Minecraft's server resource loading process has a design flaw in that tags are loaded, recipes are loaded,
|
||||
* then tags are bound to the server registries. This results in recipe modification mods like KubeJS/CraftTweaker
|
||||
* not being able to use Ingredient.test reliably as the TagValue will not find any contents for the given tag.
|
||||
* To work around this issue these mods track tag context themselves and then patch TagValue.getItems to use it
|
||||
* during the resource reload process. We often bypass Value.getItems, so we must disable that bypass
|
||||
* whenever a server reload is in progress.
|
||||
* <p>
|
||||
* An alternative fix would be to bind tags ourselves when the recipe manager reload begins, before control is
|
||||
* handed to these mods. However, it's unclear if there would be any negative side effects from binding tags early
|
||||
* like this. Moreover, this fix would only work if the mod-provided patches to getItems read exactly what the
|
||||
* registry would normally contain, rather than a modified version.
|
||||
* <p>
|
||||
* Note: this is a separate problem from the issue where clients may receive recipes before tags in 1.21.
|
||||
*/
|
||||
private boolean mfix$areTagsAvailable() {
|
||||
return !MinecraftServerReloadTracker.isReloadActive();
|
||||
}
|
||||
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason tag ingredients can be tested without iterating over all items
|
||||
*/
|
||||
@Inject(method = "test(Lnet/minecraft/world/item/ItemStack;)Z", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/crafting/Ingredient;getItems()[Lnet/minecraft/world/item/ItemStack;"), cancellable = true)
|
||||
private void modernfix$fasterTagIngredientTest(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (this.isVanilla() && this.values.length == 1 && this.values[0] instanceof Ingredient.TagValue tagValue) {
|
||||
if (this.isVanilla() && this.values.length == 1 && this.values[0] instanceof Ingredient.TagValue tagValue && mfix$areTagsAvailable()) {
|
||||
cir.setReturnValue(stack.getItemHolder().is(tagValue.tag));
|
||||
}
|
||||
}
|
||||
|
|
@ -60,7 +80,7 @@ public abstract class IngredientMixin implements ExtendedIngredient {
|
|||
for (Ingredient.Value value : this.values) {
|
||||
if (value instanceof Ingredient.ItemValue) {
|
||||
return true;
|
||||
} else if (value instanceof Ingredient.TagValue tagValue) {
|
||||
} else if (value instanceof Ingredient.TagValue tagValue && mfix$areTagsAvailable()) {
|
||||
var holderSetOpt = BuiltInRegistries.ITEM.getTag(tagValue.tag);
|
||||
if (holderSetOpt.isPresent() && holderSetOpt.get().size() > 0) {
|
||||
return true;
|
||||
|
|
@ -84,7 +104,7 @@ public abstract class IngredientMixin implements ExtendedIngredient {
|
|||
*/
|
||||
@Inject(method = "getStackingIds", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/crafting/Ingredient;getItems()[Lnet/minecraft/world/item/ItemStack;"), cancellable = true)
|
||||
private void modernfix$fasterTagIngredientStacking(CallbackInfoReturnable<IntList> cir) {
|
||||
if (this.isVanilla() && this.values.length == 1 && this.values[0] instanceof Ingredient.TagValue tagValue) {
|
||||
if (this.isVanilla() && this.values.length == 1 && this.values[0] instanceof Ingredient.TagValue tagValue && mfix$areTagsAvailable()) {
|
||||
var tag = BuiltInRegistries.ITEM.getTag(tagValue.tag);
|
||||
if (!tag.isPresent() || tag.get().size() == 0) {
|
||||
return;
|
||||
|
|
@ -124,7 +144,7 @@ public abstract class IngredientMixin implements ExtendedIngredient {
|
|||
if (this.values.length == 1) {
|
||||
if (this.values[0] instanceof Ingredient.ItemValue itemValue) {
|
||||
return new ItemStack[] { itemValue.item };
|
||||
} else if (this.values[0] instanceof Ingredient.TagValue tagValue) {
|
||||
} else if (this.values[0] instanceof Ingredient.TagValue tagValue && mfix$areTagsAvailable()) {
|
||||
var tag = BuiltInRegistries.ITEM.getTag(tagValue.tag);
|
||||
if (tag.isPresent() && tag.get().size() > 0) {
|
||||
var holderSet = tag.get();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user