diff --git a/fabric-dimensions-v1/src/main/java/net/fabricmc/fabric/impl/dimension/FabricDimensionInternals.java b/fabric-dimensions-v1/src/main/java/net/fabricmc/fabric/impl/dimension/FabricDimensionInternals.java index 72a2316508..16407652fe 100644 --- a/fabric-dimensions-v1/src/main/java/net/fabricmc/fabric/impl/dimension/FabricDimensionInternals.java +++ b/fabric-dimensions-v1/src/main/java/net/fabricmc/fabric/impl/dimension/FabricDimensionInternals.java @@ -20,6 +20,7 @@ import com.google.common.base.Preconditions; import net.minecraft.entity.Entity; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.world.TeleportTarget; @@ -49,6 +50,21 @@ public static E changeDimension(E teleported, ServerWorld dim try { currentTarget = target; + + // Fast path for teleporting within the same dimension. + if (teleported.getWorld() == dimension) { + if (teleported instanceof ServerPlayerEntity serverPlayerEntity) { + serverPlayerEntity.networkHandler.requestTeleport(target.position.x, target.position.y, target.position.z, target.yaw, teleported.getPitch()); + } else { + teleported.refreshPositionAndAngles(target.position.x, target.position.y, target.position.z, target.yaw, teleported.getPitch()); + } + + teleported.setVelocity(target.velocity); + teleported.setHeadYaw(target.yaw); + + return teleported; + } + return (E) teleported.moveToWorld(dimension); } finally { currentTarget = null; diff --git a/fabric-dimensions-v1/src/main/java/net/fabricmc/fabric/mixin/dimension/LevelStorageBugfixMixin.java b/fabric-dimensions-v1/src/main/java/net/fabricmc/fabric/mixin/dimension/LevelStorageBugfixMixin.java new file mode 100644 index 0000000000..6b8a257a1f --- /dev/null +++ b/fabric-dimensions-v1/src/main/java/net/fabricmc/fabric/mixin/dimension/LevelStorageBugfixMixin.java @@ -0,0 +1,84 @@ +/* + * Copyright 2016, 2017, 2018, 2019 FabricMC + * Copyright 2022 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.dimension; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import com.mojang.datafixers.DataFixer; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.Lifecycle; + +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.world.gen.GeneratorOptions; +import net.minecraft.world.level.storage.LevelStorage; + +/** + * After removing a dimension mod or a dimension datapack, Minecraft may fail to enter + * the world, because it fails to deserialize the chunk generator of the custom dimensions in file {@code level.dat} + * This mixin will remove the custom dimensions from the nbt tag, so the deserializer and DFU cannot see custom + * dimensions and won't cause errors. + * The custom dimensions will be re-added later. + * + *

This Mixin changes a vanilla behavior that is deemed as a bug (MC-197860). In vanilla, the custom dimension + * is not removed after uninstalling the dimension datapack. + * This makes custom dimensions non-removable. Most players don't want this behavior. + * With this Mixin, custom dimensions will be removed when its datapack is removed. + */ +@Mixin(LevelStorage.class) +public class LevelStorageBugfixMixin { + @SuppressWarnings("unchecked") + @Inject(method = "readGeneratorProperties", at = @At("HEAD")) + private static void onReadGeneratorProperties( + Dynamic nbt, DataFixer dataFixer, int version, + CallbackInfoReturnable> cir + ) { + NbtElement nbtTag = ((Dynamic) nbt).getValue(); + + NbtCompound worldGenSettings = ((NbtCompound) nbtTag).getCompound("WorldGenSettings"); + + removeNonVanillaDimensionsFromWorldGenSettingsTag(worldGenSettings); + } + + /** + * Removes all non-vanilla dimensions from the tag. The custom dimensions will be re-added later from the datapacks. + */ + @Unique + private static void removeNonVanillaDimensionsFromWorldGenSettingsTag(NbtCompound worldGenSettings) { + String[] vanillaDimensionIds = + new String[]{"minecraft:overworld", "minecraft:the_nether", "minecraft:the_end"}; + + NbtCompound dimensions = worldGenSettings.getCompound("dimensions"); + + if (dimensions.getSize() > vanillaDimensionIds.length) { + NbtCompound newDimensions = new NbtCompound(); + + for (String dimId : vanillaDimensionIds) { + if (dimensions.contains(dimId)) { + newDimensions.put(dimId, dimensions.getCompound(dimId)); + } + } + + worldGenSettings.put("dimensions", newDimensions); + } + } +} diff --git a/fabric-dimensions-v1/src/main/resources/quilted_fabric_dimensions_v1.mixins.json b/fabric-dimensions-v1/src/main/resources/quilted_fabric_dimensions_v1.mixins.json index ee87d1a79b..66d3ddda18 100644 --- a/fabric-dimensions-v1/src/main/resources/quilted_fabric_dimensions_v1.mixins.json +++ b/fabric-dimensions-v1/src/main/resources/quilted_fabric_dimensions_v1.mixins.json @@ -4,8 +4,9 @@ "compatibilityLevel": "JAVA_17", "mixins": [ "EntityMixin", - "ServerPlayerEntityMixin", - "ServerBugfixMixin" + "LevelStorageBugfixMixin", + "ServerBugfixMixin", + "ServerPlayerEntityMixin" ], "injectors": { "defaultRequire": 1 diff --git a/fabric-dimensions-v1/src/testmod/java/net/fabricmc/fabric/test/dimension/FabricDimensionTest.java b/fabric-dimensions-v1/src/testmod/java/net/fabricmc/fabric/test/dimension/FabricDimensionTest.java index 19be274d17..2d9ed94d34 100644 --- a/fabric-dimensions-v1/src/testmod/java/net/fabricmc/fabric/test/dimension/FabricDimensionTest.java +++ b/fabric-dimensions-v1/src/testmod/java/net/fabricmc/fabric/test/dimension/FabricDimensionTest.java @@ -103,6 +103,14 @@ public void onInitialize() { CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> dispatcher.register(literal("fabric_dimension_test").executes(FabricDimensionTest.this::swapTargeted)) ); + + // Used to test https://github.com/FabricMC/fabric/issues/2239 + CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> dispatcher.register(literal("fabric_dimension_test_desync") + .executes(FabricDimensionTest.this::testDesync))); + + // Used to test https://github.com/FabricMC/fabric/issues/2238 + CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> dispatcher.register(literal("fabric_dimension_test_entity") + .executes(FabricDimensionTest.this::testEntityTeleport))); } private int swapTargeted(CommandContext context) throws CommandSyntaxException { @@ -129,6 +137,50 @@ private int swapTargeted(CommandContext context) throws Com return 1; } + private int testDesync(CommandContext context) throws CommandSyntaxException { + ServerPlayerEntity player = context.getSource().getPlayer(); + + if (player == null) { + context.getSource().sendFeedback(new LiteralText("You must be a player to execute this command."), false); + return 1; + } + + if (!context.getSource().getServer().isDedicated()) { + context.getSource().sendFeedback(new LiteralText("This command can only be executed on dedicated servers."), false); + return 1; + } + + TeleportTarget target = new TeleportTarget(player.getPos().add(5, 0, 0), player.getVelocity(), player.getYaw(), player.getPitch()); + FabricDimensions.teleport(player, (ServerWorld) player.world, target); + + return 1; + } + + private int testEntityTeleport(CommandContext context) throws CommandSyntaxException { + ServerPlayerEntity player = context.getSource().getPlayer(); + + if (player == null) { + context.getSource().sendFeedback(new LiteralText("You must be a player to execute this command."), false); + return 1; + } + + Entity entity = player.world + .getOtherEntities(player, player.getBoundingBox().expand(100, 100, 100)) + .stream() + .findFirst() + .orElse(null); + + if (entity == null) { + context.getSource().sendFeedback(new LiteralText("No entities found."), false); + return 1; + } + + TeleportTarget target = new TeleportTarget(player.getPos(), player.getVelocity(), player.getYaw(), player.getPitch()); + FabricDimensions.teleport(entity, (ServerWorld) entity.world, target); + + return 1; + } + private ServerWorld getModWorld(CommandContext context) { return getWorld(context, WORLD_KEY); } diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/ModifyItemAttributeModifiersCallback.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/ModifyItemAttributeModifiersCallback.java new file mode 100644 index 0000000000..8e842f0119 --- /dev/null +++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/ModifyItemAttributeModifiersCallback.java @@ -0,0 +1,60 @@ +/* + * Copyright 2016, 2017, 2018, 2019 FabricMC + * Copyright 2022 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.item.v1; + +import com.google.common.collect.Multimap; + +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.attribute.EntityAttribute; +import net.minecraft.entity.attribute.EntityAttributeModifier; +import net.minecraft.item.ItemStack; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; + +/** + * Stack-aware attribute modifier callback for foreign items. + * Instead of using Mixin to change attribute modifiers in items not in your mod, + * you can use this event instead, either checking the Item itself or using a tag. + * This event provides you with a guaranteed mutable map you can put attribute modifiers in. + * Do not use for your own Item classes; see {@link FabricItem#getAttributeModifiers} instead. + * For example, the following code modifies a Diamond Helmet to give you five extra hearts when wearing. + * + *

+ * {@code
+ * ModifyItemAttributeModifiersCallback.EVENT.register((stack, slot, attributeModifiers) -> {
+ * 	if (stack.isOf(Items.DIAMOND_HELMET) && slot.getEntitySlotId() == HEAD_SLOT_ID) {
+ * 		attributeModifiers.put(EntityAttributes.GENERIC_MAX_HEALTH, MODIFIER);
+ * 	}
+ * });
+ * }
+ * 
+ */ +@FunctionalInterface +public interface ModifyItemAttributeModifiersCallback { + void modifyAttributeModifiers(ItemStack stack, EquipmentSlot slot, Multimap attributeModifiers); + + Event EVENT = EventFactory.createArrayBacked( + ModifyItemAttributeModifiersCallback.class, + callbacks -> (stack, slot, attributeModifiers) -> { + for (ModifyItemAttributeModifiersCallback callback : callbacks) { + callback.modifyAttributeModifiers(stack, slot, attributeModifiers); + } + } + ); +} diff --git a/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/ModifyItemAttributeModifiersCallbackTest.java b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/ModifyItemAttributeModifiersCallbackTest.java new file mode 100644 index 0000000000..e8f9626258 --- /dev/null +++ b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/ModifyItemAttributeModifiersCallbackTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2016, 2017, 2018, 2019 FabricMC + * Copyright 2022 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.item; + +import org.quiltmc.loader.api.ModContainer; +import org.quiltmc.qsl.base.api.entrypoint.ModInitializer; + +import net.minecraft.entity.attribute.EntityAttributeModifier; +import net.minecraft.entity.attribute.EntityAttributes; +import net.minecraft.item.Items; + +import net.fabricmc.fabric.api.item.v1.ModifyItemAttributeModifiersCallback; + +public class ModifyItemAttributeModifiersCallbackTest implements ModInitializer { + public static final int HEAD_SLOT_ID = 3; + public static final EntityAttributeModifier MODIFIER = new EntityAttributeModifier("generic_max_health_modifier", 5.0, EntityAttributeModifier.Operation.ADDITION); + + @Override + public void onInitialize(ModContainer mod) { + ModifyItemAttributeModifiersCallback.EVENT.register((stack, slot, attributeModifiers) -> { + if (stack.isOf(Items.DIAMOND_HELMET) && slot.getEntitySlotId() == HEAD_SLOT_ID) { + attributeModifiers.put(EntityAttributes.GENERIC_MAX_HEALTH, MODIFIER); + } + }); + } +} diff --git a/fabric-item-api-v1/src/testmod/resources/fabric.mod.json b/fabric-item-api-v1/src/testmod/resources/fabric.mod.json index 1fbf80d7b3..e581fec1c2 100644 --- a/fabric-item-api-v1/src/testmod/resources/fabric.mod.json +++ b/fabric-item-api-v1/src/testmod/resources/fabric.mod.json @@ -12,7 +12,8 @@ "init": [ "net.fabricmc.fabric.test.item.CustomDamageTest", "net.fabricmc.fabric.test.item.FabricItemSettingsTests", - "net.fabricmc.fabric.test.item.ItemUpdateAnimationTest" + "net.fabricmc.fabric.test.item.ItemUpdateAnimationTest", + "net.fabricmc.fabric.test.item.ModifyItemAttributeModifiersCallbackTest" ], "client_init": [ "net.fabricmc.fabric.test.item.client.TooltipTests" diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/client/ClientChunkManagerMixin.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/client/ClientChunkManagerMixin.java index e590290976..14d5b5c422 100644 --- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/client/ClientChunkManagerMixin.java +++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/client/ClientChunkManagerMixin.java @@ -34,6 +34,7 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.network.PacketByteBuf; import net.minecraft.world.chunk.WorldChunk; +import net.minecraft.util.math.ChunkPos; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -51,6 +52,13 @@ private void onChunkLoad(int x, int z, PacketByteBuf packetByteBuf, NbtCompound ClientChunkEvents.CHUNK_LOAD.invoker().onChunkLoad(this.world, info.getReturnValue()); } + @Inject(method = "loadChunkFromPacket", at = @At(value = "NEW", target = "net/minecraft/world/chunk/WorldChunk", shift = At.Shift.BEFORE), locals = LocalCapture.CAPTURE_FAILHARD) + private void onChunkUnload(int x, int z, PacketByteBuf buf, NbtCompound tag, Consumer consumer, CallbackInfoReturnable info, int index, WorldChunk worldChunk, ChunkPos chunkPos) { + if (worldChunk != null) { + ClientChunkEvents.CHUNK_UNLOAD.invoker().onChunkUnload(this.world, worldChunk); + } + } + @Inject(method = "unload", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientChunkManager$ClientChunkMap;compareAndSet(ILnet/minecraft/world/chunk/WorldChunk;Lnet/minecraft/world/chunk/WorldChunk;)Lnet/minecraft/world/chunk/WorldChunk;", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILEXCEPTION) private void onChunkUnload(int chunkX, int chunkZ, CallbackInfo ci, int i, WorldChunk chunk) { ClientChunkEvents.CHUNK_UNLOAD.invoker().onChunkUnload(this.world, chunk); diff --git a/fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/api/object/builder/v1/block/FabricBlockSettings.java b/fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/api/object/builder/v1/block/FabricBlockSettings.java index 8427905ae9..54e0806ceb 100644 --- a/fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/api/object/builder/v1/block/FabricBlockSettings.java +++ b/fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/api/object/builder/v1/block/FabricBlockSettings.java @@ -37,6 +37,9 @@ * Fabric's version of Block.Settings. Adds additional methods and hooks * not found in the original class. * + *

Make note that this behaves slightly different from the + * vanilla counterpart, copying some settings that vanilla does not. + * *

To use it, simply replace Block.Settings.of() with * FabricBlockSettings.of(). */ diff --git a/fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/mixin/object/builder/AbstractBlockSettingsAccessor.java b/fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/mixin/object/builder/AbstractBlockSettingsAccessor.java index 9f17c7649e..fe0df3a3d1 100644 --- a/fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/mixin/object/builder/AbstractBlockSettingsAccessor.java +++ b/fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/mixin/object/builder/AbstractBlockSettingsAccessor.java @@ -29,6 +29,7 @@ import net.minecraft.block.BlockState; import net.minecraft.block.MapColor; import net.minecraft.block.Material; +import net.minecraft.entity.EntityType; import net.minecraft.sound.BlockSoundGroup; import net.minecraft.util.Identifier; @@ -75,6 +76,10 @@ public interface AbstractBlockSettingsAccessor { @Accessor float getVelocityMultiplier(); + @Deprecated + @Accessor + float getJumpVelocityMultiplier(); + @Deprecated @Accessor boolean getDynamicBounds(); @@ -91,6 +96,30 @@ public interface AbstractBlockSettingsAccessor { @Accessor boolean isToolRequired(); + @Deprecated + @Accessor + AbstractBlock.TypedContextPredicate> getAllowsSpawningPredicate(); + + @Deprecated + @Accessor + AbstractBlock.ContextPredicate getSolidBlockPredicate(); + + @Deprecated + @Accessor + AbstractBlock.ContextPredicate getSuffocationPredicate(); + + @Deprecated + @Accessor + AbstractBlock.ContextPredicate getBlockVisionPredicate(); + + @Deprecated + @Accessor + AbstractBlock.ContextPredicate getPostProcessPredicate(); + + @Deprecated + @Accessor + AbstractBlock.ContextPredicate getEmissiveLightingPredicate(); + /* SETTERS */ @Deprecated @Accessor diff --git a/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/api/resource/ResourceManagerHelper.java b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/api/resource/ResourceManagerHelper.java index 2f85693d07..74fa81cdfa 100644 --- a/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/api/resource/ResourceManagerHelper.java +++ b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/api/resource/ResourceManagerHelper.java @@ -23,6 +23,7 @@ import net.minecraft.resource.ResourceManager; import net.minecraft.resource.ResourceType; +import net.minecraft.text.Text; import net.minecraft.util.Identifier; import net.fabricmc.fabric.impl.resource.loader.ResourceManagerHelperImpl; @@ -82,6 +83,28 @@ static boolean registerBuiltinResourcePack(Identifier id, ModContainer container return ResourceLoader.registerBuiltinResourcePack(id, quiltyContainer, activationType.getQuiltEquivalent()); } + /** + * Registers a built-in resource pack. + * + *

A built-in resource pack is an extra resource pack provided by your mod which is not always active, it's similar to the "Programmer Art" resource pack. + * + *

Why and when to use it? A built-in resource pack should be used to provide extra assets/data that should be optional with your mod but still directly provided by it. + * For example it could provide textures of your mod in another resolution, or could allow to provide different styles of your assets. + * + *

The path in which the resource pack is located is in the mod JAR file under the {@code "resourcepacks/"} directory. {@code id path} being the path specified + * in the identifier of this built-in resource pack. + * + * @param id the identifier of the resource pack + * @param container the mod container + * @param displayName the display name of the resource pack, should include mod name for clarity + * @param activationType the activation type of the resource pack + * @return {@code true} if successfully registered the resource pack, else {@code false} + */ + static boolean registerBuiltinResourcePack(Identifier id, ModContainer container, String displayName, ResourcePackActivationType activationType) { + org.quiltmc.loader.api.ModContainer quiltyContainer = QuiltLoader.getModContainer(container.getMetadata().getId()).get(); + return org.quiltmc.qsl.resource.loader.api.ResourceLoader.registerBuiltinResourcePack(id, quiltyContainer, activationType.getQuiltEquivalent(), Text.of(displayName)); + } + /** * Registers a built-in resource pack. * diff --git a/fabric-resource-loader-v0/src/main/resources/assets/quilted_fabric_resource_loader_v0/lang/en_us.json b/fabric-resource-loader-v0/src/main/resources/assets/quilted_fabric_resource_loader_v0/lang/en_us.json index 3965e20c7a..2d624999e4 100644 --- a/fabric-resource-loader-v0/src/main/resources/assets/quilted_fabric_resource_loader_v0/lang/en_us.json +++ b/fabric-resource-loader-v0/src/main/resources/assets/quilted_fabric_resource_loader_v0/lang/en_us.json @@ -1,3 +1,4 @@ { - "pack.source.fabricmod": "Fabric mod" -} \ No newline at end of file + "pack.source.fabricmod": "Fabric mod", + "pack.source.builtinMod": "built-in: %s" +} diff --git a/fabric-resource-loader-v0/src/main/resources/assets/quilted_fabric_resource_loader_v0/lang/fr_ca.json b/fabric-resource-loader-v0/src/main/resources/assets/quilted_fabric_resource_loader_v0/lang/fr_ca.json new file mode 100644 index 0000000000..fa9cf19566 --- /dev/null +++ b/fabric-resource-loader-v0/src/main/resources/assets/quilted_fabric_resource_loader_v0/lang/fr_ca.json @@ -0,0 +1,3 @@ +{ + "pack.source.builtinMod": "intégré: %s" +} diff --git a/fabric-resource-loader-v0/src/main/resources/assets/quilted_fabric_resource_loader_v0/lang/fr_fr.json b/fabric-resource-loader-v0/src/main/resources/assets/quilted_fabric_resource_loader_v0/lang/fr_fr.json new file mode 100644 index 0000000000..fa9cf19566 --- /dev/null +++ b/fabric-resource-loader-v0/src/main/resources/assets/quilted_fabric_resource_loader_v0/lang/fr_fr.json @@ -0,0 +1,3 @@ +{ + "pack.source.builtinMod": "intégré: %s" +} diff --git a/fabric-resource-loader-v0/src/testmod/java/net/fabricmc/fabric/test/resource/loader/BuiltinResourcePackTestMod.java b/fabric-resource-loader-v0/src/testmod/java/net/fabricmc/fabric/test/resource/loader/BuiltinResourcePackTestMod.java index f92d22873d..15097c992f 100644 --- a/fabric-resource-loader-v0/src/testmod/java/net/fabricmc/fabric/test/resource/loader/BuiltinResourcePackTestMod.java +++ b/fabric-resource-loader-v0/src/testmod/java/net/fabricmc/fabric/test/resource/loader/BuiltinResourcePackTestMod.java @@ -37,6 +37,10 @@ public void onInitialize() { // Should always be present as it's **this** mod. FabricLoader.getInstance().getModContainer(MODID) .map(container -> ResourceManagerHelper.registerBuiltinResourcePack(new Identifier(MODID, "test"), + container, "Fabric Resource Loader Test Pack", ResourcePackActivationType.NORMAL)) + .filter(success -> !success).ifPresent(success -> LOGGER.warn("Could not register built-in resource pack with custom name.")); + FabricLoader.getInstance().getModContainer(MODID) + .map(container -> ResourceManagerHelper.registerBuiltinResourcePack(new Identifier(MODID, "test2"), container, ResourcePackActivationType.NORMAL)) .filter(success -> !success).ifPresent(success -> LOGGER.warn("Could not register built-in resource pack.")); } diff --git a/fabric-resource-loader-v0/src/testmod/resources/resourcepacks/test/pack.mcmeta b/fabric-resource-loader-v0/src/testmod/resources/resourcepacks/test/pack.mcmeta index ce1669837b..0c7c189d3e 100644 --- a/fabric-resource-loader-v0/src/testmod/resources/resourcepacks/test/pack.mcmeta +++ b/fabric-resource-loader-v0/src/testmod/resources/resourcepacks/test/pack.mcmeta @@ -1,6 +1,6 @@ { "pack": { - "pack_format": 7, + "pack_format": 8, "description": "Fabric Resource Loader Test Builtin Pack." } } diff --git a/fabric-resource-loader-v0/src/testmod/resources/resourcepacks/test/data/minecraft/tags/blocks/climbable.json b/fabric-resource-loader-v0/src/testmod/resources/resourcepacks/test2/data/minecraft/tags/blocks/climbable.json similarity index 100% rename from fabric-resource-loader-v0/src/testmod/resources/resourcepacks/test/data/minecraft/tags/blocks/climbable.json rename to fabric-resource-loader-v0/src/testmod/resources/resourcepacks/test2/data/minecraft/tags/blocks/climbable.json diff --git a/fabric-resource-loader-v0/src/testmod/resources/resourcepacks/test2/pack.mcmeta b/fabric-resource-loader-v0/src/testmod/resources/resourcepacks/test2/pack.mcmeta new file mode 100644 index 0000000000..6d1f6996f9 --- /dev/null +++ b/fabric-resource-loader-v0/src/testmod/resources/resourcepacks/test2/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "pack_format": 9, + "description": "Fabric Resource Loader Test Builtin Pack." + } +} diff --git a/fabric-resource-loader-v0/src/testmod/resources/resourcepacks/test2/pack.png b/fabric-resource-loader-v0/src/testmod/resources/resourcepacks/test2/pack.png new file mode 100644 index 0000000000..2931efbf61 Binary files /dev/null and b/fabric-resource-loader-v0/src/testmod/resources/resourcepacks/test2/pack.png differ diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/item/base/SingleStackStorage.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/item/base/SingleStackStorage.java index fae7d85b32..9354854a81 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/item/base/SingleStackStorage.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/item/base/SingleStackStorage.java @@ -86,7 +86,7 @@ protected int getCapacity(ItemVariant itemVariant) { @Override public boolean isResourceBlank() { - return getResource().isBlank(); + return getStack().isEmpty(); } @Override @@ -124,9 +124,9 @@ public long insert(ItemVariant insertedVariant, long maxAmount, TransactionConte } setStack(currentStack); - } - return insertedAmount; + return insertedAmount; + } } return 0; @@ -146,9 +146,9 @@ public long extract(ItemVariant variant, long maxAmount, TransactionContext tran currentStack = getStack(); currentStack.decrement(extracted); setStack(currentStack); - } - return extracted; + return extracted; + } } return 0; diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/storage/base/SingleVariantStorage.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/storage/base/SingleVariantStorage.java index a5edbe1757..a821abd06d 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/storage/base/SingleVariantStorage.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/api/transfer/v1/storage/base/SingleVariantStorage.java @@ -82,9 +82,9 @@ public long insert(T insertedVariant, long maxAmount, TransactionContext transac } else { amount += insertedAmount; } - } - return insertedAmount; + return insertedAmount; + } } return 0; @@ -104,9 +104,9 @@ public long extract(T extractedVariant, long maxAmount, TransactionContext trans if (amount == 0) { variant = getBlankVariant(); } - } - return extractedAmount; + return extractedAmount; + } } return 0; diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/TransferApiImpl.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/TransferApiImpl.java index 7332c4352f..6cc6f5756c 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/TransferApiImpl.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/TransferApiImpl.java @@ -63,9 +63,4 @@ public long getVersion() { return 0; } }; - - /** - * Not null when writing to an inventory in a transaction, null otherwise. - */ - public static final ThreadLocal SUPPRESS_SPECIAL_LOGIC = new ThreadLocal<>(); } diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/item/InventorySlotWrapper.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/item/InventorySlotWrapper.java index 396edf9a22..67f88d1bdc 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/item/InventorySlotWrapper.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/item/InventorySlotWrapper.java @@ -22,7 +22,6 @@ import net.fabricmc.fabric.api.transfer.v1.item.base.SingleStackStorage; import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant; import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext; -import net.fabricmc.fabric.impl.transfer.TransferApiImpl; /** * A wrapper around a single slot of an inventory. @@ -36,11 +35,13 @@ class InventorySlotWrapper extends SingleStackStorage { */ private final InventoryStorageImpl storage; final int slot; + private final SpecialLogicInventory specialInv; private ItemStack lastReleasedSnapshot = null; InventorySlotWrapper(InventoryStorageImpl storage, int slot) { this.storage = storage; this.slot = slot; + this.specialInv = storage.inventory instanceof SpecialLogicInventory specialInv ? specialInv : null; } @Override @@ -50,18 +51,26 @@ protected ItemStack getStack() { @Override protected void setStack(ItemStack stack) { - TransferApiImpl.SUPPRESS_SPECIAL_LOGIC.set(Boolean.TRUE); - - try { + if (specialInv == null) { storage.inventory.setStack(slot, stack); - } finally { - TransferApiImpl.SUPPRESS_SPECIAL_LOGIC.remove(); + } else { + specialInv.fabric_setSuppress(true); + + try { + storage.inventory.setStack(slot, stack); + } finally { + specialInv.fabric_setSuppress(false); + } } } @Override - protected boolean canInsert(ItemVariant itemVariant) { - return storage.inventory.isValid(slot, itemVariant.toStack()); + public long insert(ItemVariant insertedVariant, long maxAmount, TransactionContext transaction) { + if (!storage.inventory.isValid(slot, ((ItemVariantImpl) insertedVariant).getCachedStack())) { + return 0; + } else { + return super.insert(insertedVariant, maxAmount, transaction); + } } @Override diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/item/ItemVariantImpl.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/item/ItemVariantImpl.java index 5009770b17..47b13e000e 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/item/ItemVariantImpl.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/item/ItemVariantImpl.java @@ -24,6 +24,7 @@ import org.jetbrains.annotations.Nullable; import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.nbt.NbtCompound; import net.minecraft.network.PacketByteBuf; @@ -49,6 +50,10 @@ public static ItemVariant of(Item item, @Nullable NbtCompound tag) { private final Item item; private final @Nullable NbtCompound nbt; private final int hashCode; + /** + * Lazily computed, equivalent to calling toStack(1). MAKE SURE IT IS NEVER MODIFIED! + */ + private volatile @Nullable ItemStack cachedStack = null; public ItemVariantImpl(Item item, NbtCompound nbt) { this.item = item; @@ -136,4 +141,15 @@ public boolean equals(Object o) { public int hashCode() { return hashCode; } + + public ItemStack getCachedStack() { + ItemStack ret = cachedStack; + + if (ret == null) { + // multiple stacks could be created at the same time by different threads, but that is not an issue + cachedStack = ret = toStack(); + } + + return ret; + } } diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/item/SidedInventorySlotWrapper.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/item/SidedInventorySlotWrapper.java index cc1ce6dd6f..7a93819fab 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/item/SidedInventorySlotWrapper.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/item/SidedInventorySlotWrapper.java @@ -41,7 +41,7 @@ class SidedInventorySlotWrapper implements SingleSlotStorage { @Override public long insert(ItemVariant resource, long maxAmount, TransactionContext transaction) { - if (!sidedInventory.canInsert(slotWrapper.slot, resource.toStack(), direction)) { + if (!sidedInventory.canInsert(slotWrapper.slot, ((ItemVariantImpl) resource).getCachedStack(), direction)) { return 0; } else { return slotWrapper.insert(resource, maxAmount, transaction); @@ -50,7 +50,7 @@ public long insert(ItemVariant resource, long maxAmount, TransactionContext tran @Override public long extract(ItemVariant resource, long maxAmount, TransactionContext transaction) { - if (!sidedInventory.canExtract(slotWrapper.slot, resource.toStack(), direction)) { + if (!sidedInventory.canExtract(slotWrapper.slot, ((ItemVariantImpl) resource).getCachedStack(), direction)) { return 0; } else { return slotWrapper.extract(resource, maxAmount, transaction); diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/item/SpecialLogicInventory.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/item/SpecialLogicInventory.java index acf4db7645..3aa3f4c38f 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/item/SpecialLogicInventory.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/impl/transfer/item/SpecialLogicInventory.java @@ -23,9 +23,13 @@ /** * Internal class that allows inventory instances to defer special logic until {@link InventorySlotWrapper#onFinalCommit()} is called. - * Special logic should be suppressed when {@link net.fabricmc.fabric.impl.transfer.TransferApiImpl#SUPPRESS_SPECIAL_LOGIC} is true. */ @ApiStatus.Internal public interface SpecialLogicInventory { + /** + * Decide whether special logic should now be suppressed. If true, must remain suppressed until the next call. + */ + void fabric_setSuppress(boolean suppress); + void fabric_onFinalCommit(int slot, ItemStack oldStack, ItemStack newStack); } diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/AbstractFurnaceBlockEntityMixin.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/AbstractFurnaceBlockEntityMixin.java index 7090d66da5..725749572d 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/AbstractFurnaceBlockEntityMixin.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/AbstractFurnaceBlockEntityMixin.java @@ -20,6 +20,7 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -36,7 +37,6 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -import net.fabricmc.fabric.impl.transfer.TransferApiImpl; import net.fabricmc.fabric.impl.transfer.item.SpecialLogicInventory; /** @@ -53,6 +53,8 @@ public abstract class AbstractFurnaceBlockEntityMixin extends LockableContainerB @Final @Shadow private RecipeType recipeType; + @Unique + private boolean fabric_suppressSpecialLogic = false; protected AbstractFurnaceBlockEntityMixin(BlockEntityType blockEntityType, BlockPos blockPos, BlockState blockState) { super(blockEntityType, blockPos, blockState); @@ -61,12 +63,17 @@ protected AbstractFurnaceBlockEntityMixin(BlockEntityType blockEntityType, Bl @Inject(at = @At("HEAD"), method = "setStack", cancellable = true) public void setStackSuppressUpdate(int slot, ItemStack stack, CallbackInfo ci) { - if (TransferApiImpl.SUPPRESS_SPECIAL_LOGIC.get() != null) { + if (fabric_suppressSpecialLogic) { inventory.set(slot, stack); ci.cancel(); } } + @Override + public void fabric_setSuppress(boolean suppress) { + fabric_suppressSpecialLogic = suppress; + } + @Override public void fabric_onFinalCommit(int slot, ItemStack oldStack, ItemStack newStack) { if (slot == 0) { diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/LootableContainerBlockEntityMixin.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/LootableContainerBlockEntityMixin.java index 7fac5665af..e8eccee497 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/LootableContainerBlockEntityMixin.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/LootableContainerBlockEntityMixin.java @@ -18,25 +18,39 @@ package net.fabricmc.fabric.mixin.transfer; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; import net.minecraft.block.entity.LootableContainerBlockEntity; +import net.minecraft.item.ItemStack; -import net.fabricmc.fabric.impl.transfer.TransferApiImpl; +import net.fabricmc.fabric.impl.transfer.item.SpecialLogicInventory; /** * Defer markDirty until the outer transaction close callback when setStack is called from an inventory wrapper. */ @Mixin(LootableContainerBlockEntity.class) -public class LootableContainerBlockEntityMixin { +public class LootableContainerBlockEntityMixin implements SpecialLogicInventory { + @Unique + private boolean fabric_suppressSpecialLogic = false; + @Redirect( at = @At(value = "INVOKE", target = "Lnet/minecraft/block/entity/LootableContainerBlockEntity;markDirty()V"), method = "setStack(ILnet/minecraft/item/ItemStack;)V" ) public void fabric_redirectMarkDirty(LootableContainerBlockEntity self) { - if (TransferApiImpl.SUPPRESS_SPECIAL_LOGIC.get() == null) { + if (!fabric_suppressSpecialLogic) { self.markDirty(); } } + + @Override + public void fabric_setSuppress(boolean suppress) { + fabric_suppressSpecialLogic = suppress; + } + + @Override + public void fabric_onFinalCommit(int slot, ItemStack oldStack, ItemStack newStack) { + } } diff --git a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/SimpleInventoryMixin.java b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/SimpleInventoryMixin.java index 842944532f..8429fcf5dd 100644 --- a/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/SimpleInventoryMixin.java +++ b/fabric-transfer-api-v1/src/main/java/net/fabricmc/fabric/mixin/transfer/SimpleInventoryMixin.java @@ -18,25 +18,39 @@ package net.fabricmc.fabric.mixin.transfer; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; import net.minecraft.inventory.SimpleInventory; +import net.minecraft.item.ItemStack; -import net.fabricmc.fabric.impl.transfer.TransferApiImpl; +import net.fabricmc.fabric.impl.transfer.item.SpecialLogicInventory; /** * Defer markDirty until the outer transaction close callback when setStack is called from an inventory wrapper. */ @Mixin(SimpleInventory.class) -public class SimpleInventoryMixin { +public class SimpleInventoryMixin implements SpecialLogicInventory { + @Unique + private boolean fabric_suppressSpecialLogic = false; + @Redirect( at = @At(value = "INVOKE", target = "Lnet/minecraft/inventory/SimpleInventory;markDirty()V"), method = "setStack(ILnet/minecraft/item/ItemStack;)V" ) public void fabric_redirectMarkDirty(SimpleInventory self) { - if (TransferApiImpl.SUPPRESS_SPECIAL_LOGIC.get() == null) { + if (!fabric_suppressSpecialLogic) { self.markDirty(); } } + + @Override + public void fabric_setSuppress(boolean suppress) { + fabric_suppressSpecialLogic = suppress; + } + + @Override + public void fabric_onFinalCommit(int slot, ItemStack oldStack, ItemStack newStack) { + } } diff --git a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/unittests/ItemTests.java b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/unittests/ItemTests.java index ce1d832c28..0f5a374365 100644 --- a/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/unittests/ItemTests.java +++ b/fabric-transfer-api-v1/src/testmod/java/net/fabricmc/fabric/test/transfer/unittests/ItemTests.java @@ -17,6 +17,8 @@ package net.fabricmc.fabric.test.transfer.unittests; +import static net.fabricmc.fabric.test.transfer.unittests.TestUtil.assertEquals; + import java.util.stream.IntStream; import org.jetbrains.annotations.Nullable; @@ -128,6 +130,16 @@ private static void testInventoryWrappers() { if (!testInventory.getStack(1).isOf(Items.BUCKET) || testInventory.getStack(1).getCount() != 1) throw new AssertionError("Slot 1 should have been a bucket."); checkComparatorOutput(testInventory, null); + + // Check that we return sensible results if amount stored > capacity + ItemStack oversizedStack = new ItemStack(Items.DIAMOND_PICKAXE, 2); + SimpleInventory simpleInventory = new SimpleInventory(oversizedStack); + InventoryStorage wrapper = InventoryStorage.of(simpleInventory, null); + + try (Transaction transaction = Transaction.openOuter()) { + assertEquals(0L, wrapper.insert(ItemVariant.of(oversizedStack), 10, transaction)); + transaction.commit(); + } } private static boolean stackEquals(ItemStack stack, Item item, int count) { diff --git a/gradle.properties b/gradle.properties index 2786206807..69278a1ed2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,8 +2,8 @@ org.gradle.jvmargs=-Xmx2560M org.gradle.parallel=true archivesBaseName=quilted-fabric-api -version=1.0.0-beta.14 -upstream_version=0.51.1 +version=1.0.0-beta.15 +upstream_version=0.53.4 minecraft_version=1.18.2 yarn_version=+build.1 loader_version=0.16.1 @@ -13,32 +13,32 @@ prerelease=true # The upstream version list. Each quilted module should aim to be compatible with them fabric-api-base-version=0.4.4 -fabric-api-lookup-api-v1-version=1.6.0 +fabric-api-lookup-api-v1-version=1.6.1 fabric-biome-api-v1-version=8.0.4 fabric-blockrenderlayer-v1-version=1.1.12 fabric-command-api-v1-version=1.1.9 fabric-commands-v0-version=0.2.8 fabric-containers-v0-version=0.1.21 -fabric-content-registries-v0-version=3.0.3 -fabric-crash-report-info-v1-version=0.1.11 +fabric-content-registries-v0-version=3.0.5 +fabric-crash-report-info-v1-version=0.2.1 fabric-data-generation-api-v1-version=2.0.9 -fabric-dimensions-v1-version=2.1.17 +fabric-dimensions-v1-version=2.1.19 fabric-entity-events-v1-version=1.4.8 fabric-events-interaction-v0-version=0.4.19 -fabric-events-lifecycle-v0-version=0.2.14 +fabric-events-lifecycle-v0-version=0.2.16 fabric-game-rule-api-v1-version=1.0.13 -fabric-gametest-api-v1-version=1.0.16 -fabric-item-api-v1-version=1.4.0 -fabric-item-groups-v0-version=0.3.11 +fabric-gametest-api-v1-version=1.0.17 +fabric-item-api-v1-version=1.5.0 +fabric-item-groups-v0-version=0.3.12 fabric-key-binding-api-v1-version=1.0.12 fabric-keybindings-v0-version=0.2.10 -fabric-lifecycle-events-v1-version=2.0.3 +fabric-lifecycle-events-v1-version=2.0.4 fabric-loot-tables-v1-version=1.0.11 -fabric-mining-level-api-v1-version=2.1.0 +fabric-mining-level-api-v1-version=2.1.1 fabric-models-v0-version=0.3.6 fabric-networking-api-v1-version=1.0.21 fabric-networking-v0-version=0.3.8 -fabric-object-builder-api-v1-version=2.1.0 +fabric-object-builder-api-v1-version=2.1.1 fabric-particles-v1-version=0.2.12 fabric-registry-sync-v0-version=0.9.8 fabric-renderer-api-v1-version=0.4.13 @@ -49,10 +49,10 @@ fabric-rendering-fluids-v1-version=2.0.2 fabric-rendering-v0-version=1.1.13 fabric-rendering-v1-version=1.10.7 fabric-resource-conditions-api-v1-version=2.0.3 -fabric-resource-loader-v0-version=0.4.18 +fabric-resource-loader-v0-version=0.5.0 fabric-screen-api-v1-version=1.0.10 fabric-screen-handler-api-v1-version=1.2.0 fabric-textures-v0-version=1.0.12 -fabric-transfer-api-v1-version=1.6.0 +fabric-transfer-api-v1-version=1.6.2 fabric-transitive-access-wideners-v1-version=1.0.0 fabric-convention-tags-v1-version=1.0.1