66import net .minecraft .core .registries .BuiltInRegistries ;
77import net .minecraft .world .item .ItemStack ;
88import net .minecraft .world .item .crafting .Ingredient ;
9+ import org .embeddedt .modernfix .forge .load .MinecraftServerReloadTracker ;
910import org .embeddedt .modernfix .forge .recipe .ExtendedIngredient ;
1011import org .embeddedt .modernfix .forge .recipe .IngredientItemStacksSoftReference ;
1112import org .jetbrains .annotations .Nullable ;
@@ -34,13 +35,32 @@ public abstract class IngredientMixin implements ExtendedIngredient {
3435
3536 private volatile IngredientItemStacksSoftReference mfix$cachedItemStacks ;
3637
38+ /**
39+ * Minecraft's server resource loading process has a design flaw in that tags are loaded, recipes are loaded,
40+ * then tags are bound to the server registries. This results in recipe modification mods like KubeJS/CraftTweaker
41+ * not being able to use Ingredient.test reliably as the TagValue will not find any contents for the given tag.
42+ * To work around this issue these mods track tag context themselves and then patch TagValue.getItems to use it
43+ * during the resource reload process. We often bypass Value.getItems, so we must disable that bypass
44+ * whenever a server reload is in progress.
45+ * <p>
46+ * An alternative fix would be to bind tags ourselves when the recipe manager reload begins, before control is
47+ * handed to these mods. However, it's unclear if there would be any negative side effects from binding tags early
48+ * like this. Moreover, this fix would only work if the mod-provided patches to getItems read exactly what the
49+ * registry would normally contain, rather than a modified version.
50+ * <p>
51+ * Note: this is a separate problem from the issue where clients may receive recipes before tags in 1.21.
52+ */
53+ private boolean mfix$areTagsAvailable () {
54+ return !MinecraftServerReloadTracker .isReloadActive ();
55+ }
56+
3757 /**
3858 * @author embeddedt
3959 * @reason tag ingredients can be tested without iterating over all items
4060 */
4161 @ 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 )
4262 private void modernfix$fasterTagIngredientTest (ItemStack stack , CallbackInfoReturnable <Boolean > cir ) {
43- if (this .isVanilla () && this .values .length == 1 && this .values [0 ] instanceof Ingredient .TagValue tagValue ) {
63+ if (this .isVanilla () && this .values .length == 1 && this .values [0 ] instanceof Ingredient .TagValue tagValue && mfix$areTagsAvailable () ) {
4464 cir .setReturnValue (stack .getItemHolder ().is (tagValue .tag ));
4565 }
4666 }
@@ -60,7 +80,7 @@ private boolean containsItems() {
6080 for (Ingredient .Value value : this .values ) {
6181 if (value instanceof Ingredient .ItemValue ) {
6282 return true ;
63- } else if (value instanceof Ingredient .TagValue tagValue ) {
83+ } else if (value instanceof Ingredient .TagValue tagValue && mfix$areTagsAvailable () ) {
6484 var holderSetOpt = BuiltInRegistries .ITEM .getTag (tagValue .tag );
6585 if (holderSetOpt .isPresent () && holderSetOpt .get ().size () > 0 ) {
6686 return true ;
@@ -84,7 +104,7 @@ private boolean containsItems() {
84104 */
85105 @ Inject (method = "getStackingIds" , at = @ At (value = "INVOKE" , target = "Lnet/minecraft/world/item/crafting/Ingredient;getItems()[Lnet/minecraft/world/item/ItemStack;" ), cancellable = true )
86106 private void modernfix$fasterTagIngredientStacking (CallbackInfoReturnable <IntList > cir ) {
87- if (this .isVanilla () && this .values .length == 1 && this .values [0 ] instanceof Ingredient .TagValue tagValue ) {
107+ if (this .isVanilla () && this .values .length == 1 && this .values [0 ] instanceof Ingredient .TagValue tagValue && mfix$areTagsAvailable () ) {
88108 var tag = BuiltInRegistries .ITEM .getTag (tagValue .tag );
89109 if (!tag .isPresent () || tag .get ().size () == 0 ) {
90110 return ;
@@ -124,7 +144,7 @@ private ItemStack[] computeItemsArray() {
124144 if (this .values .length == 1 ) {
125145 if (this .values [0 ] instanceof Ingredient .ItemValue itemValue ) {
126146 return new ItemStack [] { itemValue .item };
127- } else if (this .values [0 ] instanceof Ingredient .TagValue tagValue ) {
147+ } else if (this .values [0 ] instanceof Ingredient .TagValue tagValue && mfix$areTagsAvailable () ) {
128148 var tag = BuiltInRegistries .ITEM .getTag (tagValue .tag );
129149 if (tag .isPresent () && tag .get ().size () > 0 ) {
130150 var holderSet = tag .get ();
0 commit comments