diff --git a/deprecated/fabric-rendering-data-attachment-v1/build.gradle b/deprecated/fabric-rendering-data-attachment-v1/build.gradle
new file mode 100644
index 000000000..d13b85ea0
--- /dev/null
+++ b/deprecated/fabric-rendering-data-attachment-v1/build.gradle
@@ -0,0 +1,3 @@
+version = getSubprojectVersion(project)
+
+moduleDependencies(project, ['fabric-block-view-api-v2'])
diff --git a/deprecated/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/api/rendering/data/v1/RenderAttachedBlockView.java b/deprecated/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/api/rendering/data/v1/RenderAttachedBlockView.java
new file mode 100644
index 000000000..a5214e0f5
--- /dev/null
+++ b/deprecated/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/api/rendering/data/v1/RenderAttachedBlockView.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * 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.rendering.data.v1;
+
+import org.jetbrains.annotations.Nullable;
+
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.BlockRenderView;
+import net.minecraft.world.WorldView;
+
+import net.fabricmc.fabric.api.blockview.v2.FabricBlockView;
+
+/**
+ * This interface is guaranteed to be implemented on all {@link WorldView} instances.
+ * It is likely to be implemented on any given {@link BlockRenderView} instance, but
+ * this is not guaranteed.
+ *
+ * @deprecated Use {@link FabricBlockView} instead.
+ */
+@Deprecated
+public interface RenderAttachedBlockView extends BlockRenderView {
+ /**
+ * This method will call {@link FabricBlockView#getBlockEntityRenderData(BlockPos)} by default.
+ *
+ * @deprecated Use {@link FabricBlockView#getBlockEntityRenderData(BlockPos)} instead.
+ */
+ @Deprecated
+ @Nullable
+ default Object getBlockEntityRenderAttachment(BlockPos pos) {
+ return getBlockEntityRenderData(pos);
+ }
+}
diff --git a/deprecated/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/api/rendering/data/v1/RenderAttachmentBlockEntity.java b/deprecated/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/api/rendering/data/v1/RenderAttachmentBlockEntity.java
new file mode 100644
index 000000000..30b2b1c5c
--- /dev/null
+++ b/deprecated/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/api/rendering/data/v1/RenderAttachmentBlockEntity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * 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.rendering.data.v1;
+
+import org.jetbrains.annotations.Nullable;
+
+import net.minecraft.block.entity.BlockEntity;
+
+import net.fabricmc.fabric.api.blockview.v2.RenderDataBlockEntity;
+
+/**
+ * This interface is guaranteed to be implemented on all {@link BlockEntity} instances.
+ *
+ * @deprecated Use {@link RenderDataBlockEntity} instead.
+ */
+@Deprecated
+@FunctionalInterface
+public interface RenderAttachmentBlockEntity {
+ /**
+ * This method will be automatically called if {@link RenderDataBlockEntity#getRenderData()} is not overridden.
+ *
+ * @deprecated Use {@link RenderDataBlockEntity#getRenderData()} instead.
+ */
+ @Deprecated
+ @Nullable
+ Object getRenderAttachmentData();
+}
diff --git a/deprecated/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/mixin/rendering/data/BlockEntityMixin.java b/deprecated/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/mixin/rendering/data/BlockEntityMixin.java
new file mode 100644
index 000000000..c82fa3042
--- /dev/null
+++ b/deprecated/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/mixin/rendering/data/BlockEntityMixin.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * 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.rendering.data;
+
+import org.jetbrains.annotations.Nullable;
+import org.spongepowered.asm.mixin.Mixin;
+
+import net.minecraft.block.entity.BlockEntity;
+
+import net.fabricmc.fabric.api.blockview.v2.RenderDataBlockEntity;
+import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachmentBlockEntity;
+
+@Mixin(BlockEntity.class)
+public class BlockEntityMixin implements RenderAttachmentBlockEntity, RenderDataBlockEntity {
+ @Override
+ @Nullable
+ public Object getRenderAttachmentData() {
+ return null;
+ }
+
+ /**
+ * Instead of returning null by default in v2, proxy to v1 method instead.
+ */
+ @Override
+ @Nullable
+ public Object getRenderData() {
+ return getRenderAttachmentData();
+ }
+}
diff --git a/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/mixin/rendering/data/attachment/WorldViewMixin.java b/deprecated/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/mixin/rendering/data/WorldViewMixin.java
similarity index 82%
rename from fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/mixin/rendering/data/attachment/WorldViewMixin.java
rename to deprecated/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/mixin/rendering/data/WorldViewMixin.java
index 317cc7df8..bbd04fcfd 100644
--- a/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/mixin/rendering/data/attachment/WorldViewMixin.java
+++ b/deprecated/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/mixin/rendering/data/WorldViewMixin.java
@@ -14,15 +14,14 @@
* limitations under the License.
*/
-package net.fabricmc.fabric.mixin.rendering.data.attachment;
+package net.fabricmc.fabric.mixin.rendering.data;
import org.spongepowered.asm.mixin.Mixin;
-import net.minecraft.world.BlockRenderView;
import net.minecraft.world.WorldView;
import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView;
-/** Make {@link BlockRenderView} implement {@link RenderAttachedBlockView}. */
@Mixin(WorldView.class)
-public interface WorldViewMixin extends RenderAttachedBlockView { }
+public interface WorldViewMixin extends RenderAttachedBlockView {
+}
diff --git a/fabric-rendering-data-attachment-v1/src/main/resources/assets/fabric-rendering-data-attachment-v1/icon.png b/deprecated/fabric-rendering-data-attachment-v1/src/main/resources/assets/fabric-rendering-data-attachment-v1/icon.png
similarity index 100%
rename from fabric-rendering-data-attachment-v1/src/main/resources/assets/fabric-rendering-data-attachment-v1/icon.png
rename to deprecated/fabric-rendering-data-attachment-v1/src/main/resources/assets/fabric-rendering-data-attachment-v1/icon.png
diff --git a/fabric-rendering-data-attachment-v1/src/main/resources/fabric-rendering-data-attachment-v1.mixins.json b/deprecated/fabric-rendering-data-attachment-v1/src/main/resources/fabric-rendering-data-attachment-v1.mixins.json
similarity index 56%
rename from fabric-rendering-data-attachment-v1/src/main/resources/fabric-rendering-data-attachment-v1.mixins.json
rename to deprecated/fabric-rendering-data-attachment-v1/src/main/resources/fabric-rendering-data-attachment-v1.mixins.json
index 3e4c81bc9..9c09ede3c 100644
--- a/fabric-rendering-data-attachment-v1/src/main/resources/fabric-rendering-data-attachment-v1.mixins.json
+++ b/deprecated/fabric-rendering-data-attachment-v1/src/main/resources/fabric-rendering-data-attachment-v1.mixins.json
@@ -1,7 +1,7 @@
{
"required": true,
- "package": "net.fabricmc.fabric.mixin.rendering.data.attachment",
- "compatibilityLevel": "JAVA_16",
+ "package": "net.fabricmc.fabric.mixin.rendering.data",
+ "compatibilityLevel": "JAVA_17",
"mixins": [
"BlockEntityMixin",
"WorldViewMixin"
diff --git a/fabric-rendering-data-attachment-v1/src/main/resources/fabric.mod.json b/deprecated/fabric-rendering-data-attachment-v1/src/main/resources/fabric.mod.json
similarity index 68%
rename from fabric-rendering-data-attachment-v1/src/main/resources/fabric.mod.json
rename to deprecated/fabric-rendering-data-attachment-v1/src/main/resources/fabric.mod.json
index 03fcd4627..dd8fa3ad8 100644
--- a/fabric-rendering-data-attachment-v1/src/main/resources/fabric.mod.json
+++ b/deprecated/fabric-rendering-data-attachment-v1/src/main/resources/fabric.mod.json
@@ -17,18 +17,13 @@
],
"depends": {
"fabricloader": ">=0.4.0",
- "fabric-api-base": "*"
+ "fabric-block-view-api-v2": "*"
},
"description": "Thread-safe hooks for block entity data use during terrain rendering.",
"mixins": [
- "fabric-rendering-data-attachment-v1.mixins.json",
- {
- "config": "fabric-rendering-data-attachment-v1.client.mixins.json",
- "environment": "client"
- }
+ "fabric-rendering-data-attachment-v1.mixins.json"
],
"custom": {
- "fabric-api:module-lifecycle": "stable"
- },
- "accessWidener": "fabric-rendering-data-attachment-v1.accesswidener"
+ "fabric-api:module-lifecycle": "deprecated"
+ }
}
diff --git a/fabric-block-api-v1/src/main/java/net/fabricmc/fabric/api/block/v1/FabricBlock.java b/fabric-block-api-v1/src/main/java/net/fabricmc/fabric/api/block/v1/FabricBlock.java
index 5240b08f4..6304c434a 100644
--- a/fabric-block-api-v1/src/main/java/net/fabricmc/fabric/api/block/v1/FabricBlock.java
+++ b/fabric-block-api-v1/src/main/java/net/fabricmc/fabric/api/block/v1/FabricBlock.java
@@ -56,11 +56,12 @@ public interface FabricBlock {
*
This can be called on the server, where block entity data can be safely accessed,
* and on the client, possibly in a meshing thread, where block entity data is not safe to access!
* Here is an example of how data from a block entity can be handled safely.
- * The block entity needs to implement {@code RenderAttachmentBlockEntity} for this to work.
+ * The block entity should override {@code RenderDataBlockEntity#getBlockEntityRenderData} to return
+ * the necessary data. Refer to the documentation of {@code RenderDataBlockEntity} for more information.
*
{@code @Override
* public BlockState getAppearance(BlockState state, BlockRenderView renderView, BlockPos pos, Direction side, @Nullable BlockState sourceState, @Nullable BlockPos sourcePos) {
* if (renderView instanceof ServerWorld serverWorld) {
- * // Server side, ok to use block entity directly!
+ * // Server side; ok to use block entity directly!
* BlockEntity blockEntity = serverWorld.getBlockEntity(pos);
*
* if (blockEntity instanceof ...) {
@@ -68,9 +69,8 @@ public interface FabricBlock {
* return ...;
* }
* } else {
- * // Client side, need to use the render attachment!
- * RenderAttachedBlockView attachmentView = (RenderAttachedBlockView) renderView;
- * Object data = attachmentView.getBlockEntityRenderAttachment(pos);
+ * // Client side; need to use the block entity render data!
+ * Object data = renderView.getBlockEntityRenderData(pos);
*
* // Check if data is not null and of the correct type, and use that to determine the appearance
* if (data instanceof ...) {
diff --git a/fabric-block-view-api-v2/build.gradle b/fabric-block-view-api-v2/build.gradle
new file mode 100644
index 000000000..84bd602fa
--- /dev/null
+++ b/fabric-block-view-api-v2/build.gradle
@@ -0,0 +1,5 @@
+version = getSubprojectVersion(project)
+
+loom {
+ accessWidenerPath = file("src/main/resources/fabric-block-view-api-v2.accesswidener")
+}
diff --git a/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/impl/rendering/data/attachment/RenderDataObjectConsumer.java b/fabric-block-view-api-v2/src/client/java/net/fabricmc/fabric/impl/blockview/client/RenderDataMapConsumer.java
similarity index 71%
rename from fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/impl/rendering/data/attachment/RenderDataObjectConsumer.java
rename to fabric-block-view-api-v2/src/client/java/net/fabricmc/fabric/impl/blockview/client/RenderDataMapConsumer.java
index 32c50114a..b525be8ce 100644
--- a/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/impl/rendering/data/attachment/RenderDataObjectConsumer.java
+++ b/fabric-block-view-api-v2/src/client/java/net/fabricmc/fabric/impl/blockview/client/RenderDataMapConsumer.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package net.fabricmc.fabric.impl.rendering.data.attachment;
+package net.fabricmc.fabric.impl.blockview.client;
-import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
-public interface RenderDataObjectConsumer {
- void fabric_acceptRenderDataObjects(Long2ObjectOpenHashMap renderDataObjects);
+public interface RenderDataMapConsumer {
+ void fabric_acceptRenderDataMap(Long2ObjectMap renderDataMap);
}
diff --git a/fabric-rendering-data-attachment-v1/src/client/java/net/fabricmc/fabric/mixin/rendering/data/attachment/client/ChunkRendererRegionBuilderMixin.java b/fabric-block-view-api-v2/src/client/java/net/fabricmc/fabric/mixin/blockview/client/ChunkRendererRegionBuilderMixin.java
similarity index 62%
rename from fabric-rendering-data-attachment-v1/src/client/java/net/fabricmc/fabric/mixin/rendering/data/attachment/client/ChunkRendererRegionBuilderMixin.java
rename to fabric-block-view-api-v2/src/client/java/net/fabricmc/fabric/mixin/blockview/client/ChunkRendererRegionBuilderMixin.java
index eb759c789..039dfec9a 100644
--- a/fabric-rendering-data-attachment-v1/src/client/java/net/fabricmc/fabric/mixin/rendering/data/attachment/client/ChunkRendererRegionBuilderMixin.java
+++ b/fabric-block-view-api-v2/src/client/java/net/fabricmc/fabric/mixin/blockview/client/ChunkRendererRegionBuilderMixin.java
@@ -14,61 +14,67 @@
* limitations under the License.
*/
-package net.fabricmc.fabric.mixin.rendering.data.attachment.client;
+package net.fabricmc.fabric.mixin.blockview.client;
import java.util.ConcurrentModificationException;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
-import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
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 org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import net.minecraft.block.entity.BlockEntity;
-import net.minecraft.client.render.chunk.ChunkRendererRegionBuilder;
import net.minecraft.client.render.chunk.ChunkRendererRegion;
+import net.minecraft.client.render.chunk.ChunkRendererRegionBuilder;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.WorldChunk;
-import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachmentBlockEntity;
-import net.fabricmc.fabric.impl.rendering.data.attachment.RenderDataObjectConsumer;
+import net.fabricmc.fabric.impl.blockview.client.RenderDataMapConsumer;
@Mixin(ChunkRendererRegionBuilder.class)
public abstract class ChunkRendererRegionBuilderMixin {
private static final AtomicInteger ERROR_COUNTER = new AtomicInteger();
private static final Logger LOGGER = LoggerFactory.getLogger(ChunkRendererRegionBuilderMixin.class);
- @Inject(at = @At("RETURN"), method = "build", locals = LocalCapture.CAPTURE_FAILHARD)
- private void create(World world, BlockPos startPos, BlockPos endPos, int chunkRadius, CallbackInfoReturnable info, int i, int j, int k, int l, ChunkRendererRegionBuilder.ClientChunk[][] chunkData) {
+ @Inject(method = "build", at = @At("RETURN"), locals = LocalCapture.CAPTURE_FAILHARD)
+ private void createDataMap(World world, BlockPos startPos, BlockPos endPos, int offset, CallbackInfoReturnable cir, int startX, int startZ, int endX, int endZ, ChunkRendererRegionBuilder.ClientChunk[][] chunksXZ) {
+ ChunkRendererRegion rendererRegion = cir.getReturnValue();
+
+ if (rendererRegion == null) {
+ return;
+ }
+
// instantiated lazily - avoids allocation for chunks without any data objects - which is most of them!
Long2ObjectOpenHashMap map = null;
- for (ChunkRendererRegionBuilder.ClientChunk[] chunkDataOuter : chunkData) {
- for (ChunkRendererRegionBuilder.ClientChunk data : chunkDataOuter) {
+ for (ChunkRendererRegionBuilder.ClientChunk[] chunksZ : chunksXZ) {
+ for (ChunkRendererRegionBuilder.ClientChunk chunk : chunksZ) {
// Hash maps in chunks should generally not be modified outside of client thread
// but does happen in practice, due to mods or inconsistent vanilla behaviors, causing
- // CMEs when we iterate the map. (Vanilla does not iterate these maps when it builds
+ // CMEs when we iterate the map. (Vanilla does not iterate these maps when it builds
// the chunk cache and does not suffer from this problem.)
//
- // We handle this simply by retrying until it works. Ugly but effective.
- for (;;) {
+ // We handle this simply by retrying until it works. Ugly but effective.
+ while (true) {
try {
- map = mapChunk(data.getChunk(), startPos, endPos, map);
+ map = mapChunk(chunk.getChunk(), startPos, endPos, map);
break;
} catch (ConcurrentModificationException e) {
final int count = ERROR_COUNTER.incrementAndGet();
if (count <= 5) {
- LOGGER.warn("[Render Data Attachment] Encountered CME during render region build. A mod is accessing or changing chunk data outside the main thread. Retrying.", e);
+ LOGGER.warn("[Block Entity Render Data] Encountered CME during render region build. A mod is accessing or changing chunk data outside the main thread. Retrying.", e);
if (count == 5) {
- LOGGER.info("[Render Data Attachment] Subsequent exceptions will be suppressed.");
+ LOGGER.info("[Block Entity Render Data] Subsequent exceptions will be suppressed.");
}
}
}
@@ -76,35 +82,34 @@ public abstract class ChunkRendererRegionBuilderMixin {
}
}
- ChunkRendererRegion rendererRegion = info.getReturnValue();
-
- if (map != null && rendererRegion != null) {
- ((RenderDataObjectConsumer) rendererRegion).fabric_acceptRenderDataObjects(map);
+ if (map != null) {
+ ((RenderDataMapConsumer) rendererRegion).fabric_acceptRenderDataMap(map);
}
}
+ @Unique
private static Long2ObjectOpenHashMap mapChunk(WorldChunk chunk, BlockPos posFrom, BlockPos posTo, Long2ObjectOpenHashMap map) {
final int xMin = posFrom.getX();
final int xMax = posTo.getX();
- final int zMin = posFrom.getZ();
- final int zMax = posTo.getZ();
final int yMin = posFrom.getY();
final int yMax = posTo.getY();
+ final int zMin = posFrom.getZ();
+ final int zMax = posTo.getZ();
for (Map.Entry entry : chunk.getBlockEntities().entrySet()) {
- final BlockPos entPos = entry.getKey();
+ final BlockPos pos = entry.getKey();
- if (entPos.getX() >= xMin && entPos.getX() <= xMax
- && entPos.getY() >= yMin && entPos.getY() <= yMax
- && entPos.getZ() >= zMin && entPos.getZ() <= zMax) {
- final Object o = ((RenderAttachmentBlockEntity) entry.getValue()).getRenderAttachmentData();
+ if (pos.getX() >= xMin && pos.getX() <= xMax
+ && pos.getY() >= yMin && pos.getY() <= yMax
+ && pos.getZ() >= zMin && pos.getZ() <= zMax) {
+ final Object data = entry.getValue().getRenderData();
- if (o != null) {
+ if (data != null) {
if (map == null) {
map = new Long2ObjectOpenHashMap<>();
}
- map.put(entPos.asLong(), o);
+ map.put(pos.asLong(), data);
}
}
}
diff --git a/fabric-block-view-api-v2/src/client/java/net/fabricmc/fabric/mixin/blockview/client/ChunkRendererRegionMixin.java b/fabric-block-view-api-v2/src/client/java/net/fabricmc/fabric/mixin/blockview/client/ChunkRendererRegionMixin.java
new file mode 100644
index 000000000..71e771936
--- /dev/null
+++ b/fabric-block-view-api-v2/src/client/java/net/fabricmc/fabric/mixin/blockview/client/ChunkRendererRegionMixin.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * 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.blockview.client;
+
+import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
+import org.jetbrains.annotations.Nullable;
+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 net.minecraft.client.render.chunk.ChunkRendererRegion;
+import net.minecraft.registry.entry.RegistryEntry;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.BlockRenderView;
+import net.minecraft.world.World;
+import net.minecraft.world.biome.Biome;
+
+import net.fabricmc.fabric.impl.blockview.client.RenderDataMapConsumer;
+
+@Mixin(ChunkRendererRegion.class)
+public abstract class ChunkRendererRegionMixin implements BlockRenderView, RenderDataMapConsumer {
+ @Shadow
+ @Final
+ protected World world;
+
+ @Unique
+ @Nullable
+ private Long2ObjectMap fabric_renderDataMap;
+
+ @Override
+ public Object getBlockEntityRenderData(BlockPos pos) {
+ return fabric_renderDataMap == null ? null : fabric_renderDataMap.get(pos.asLong());
+ }
+
+ /**
+ * Called in {@link ChunkRendererRegionBuilderMixin}.
+ */
+ @Override
+ public void fabric_acceptRenderDataMap(Long2ObjectMap renderDataMap) {
+ this.fabric_renderDataMap = renderDataMap;
+ }
+
+ @Override
+ public boolean hasBiomes() {
+ return true;
+ }
+
+ @Override
+ public RegistryEntry getBiomeFabric(BlockPos pos) {
+ return world.getBiome(pos);
+ }
+}
diff --git a/fabric-rendering-data-attachment-v1/src/client/resources/fabric-rendering-data-attachment-v1.client.mixins.json b/fabric-block-view-api-v2/src/client/resources/fabric-block-view-api-v2.client.mixins.json
similarity index 58%
rename from fabric-rendering-data-attachment-v1/src/client/resources/fabric-rendering-data-attachment-v1.client.mixins.json
rename to fabric-block-view-api-v2/src/client/resources/fabric-block-view-api-v2.client.mixins.json
index 1acdfb76b..2aae97626 100644
--- a/fabric-rendering-data-attachment-v1/src/client/resources/fabric-rendering-data-attachment-v1.client.mixins.json
+++ b/fabric-block-view-api-v2/src/client/resources/fabric-block-view-api-v2.client.mixins.json
@@ -1,7 +1,7 @@
{
"required": true,
- "package": "net.fabricmc.fabric.mixin.rendering.data.attachment.client",
- "compatibilityLevel": "JAVA_16",
+ "package": "net.fabricmc.fabric.mixin.blockview.client",
+ "compatibilityLevel": "JAVA_17",
"client": [
"ChunkRendererRegionMixin",
"ChunkRendererRegionBuilderMixin"
diff --git a/fabric-block-view-api-v2/src/main/java/net/fabricmc/fabric/api/blockview/v2/FabricBlockView.java b/fabric-block-view-api-v2/src/main/java/net/fabricmc/fabric/api/blockview/v2/FabricBlockView.java
new file mode 100644
index 000000000..e310ca4ef
--- /dev/null
+++ b/fabric-block-view-api-v2/src/main/java/net/fabricmc/fabric/api/blockview/v2/FabricBlockView.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * 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.blockview.v2;
+
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.UnknownNullability;
+
+import net.minecraft.block.entity.BlockEntity;
+import net.minecraft.registry.entry.RegistryEntry;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.BlockView;
+import net.minecraft.world.WorldView;
+import net.minecraft.world.biome.Biome;
+
+/**
+ * General-purpose Fabric-provided extensions for {@link BlockView} subclasses.
+ *
+ * These extensions were designed primarily for use by methods invoked during chunk building, but
+ * they can also be used in other contexts.
+ *
+ *
Note: This interface is automatically implemented on all {@link BlockView} instances via Mixin and interface injection.
+ */
+public interface FabricBlockView {
+ /**
+ * Retrieves block entity render data for a given block position.
+ *
+ *
This method must be used instead of {@link BlockView#getBlockEntity(BlockPos)} in cases
+ * where the user knows that the current context may be multithreaded, such as chunk building, to
+ * ensure thread safety and data consistency. Using a {@link BlockEntity} directly may not be
+ * thread-safe since it may lead to non-atomic modification of the internal state of the
+ * {@link BlockEntity} (such as through lazy computation). Using a {@link BlockEntity} directly
+ * may not be consistent since the internal state of the {@link BlockEntity} may change on a
+ * different thread.
+ *
+ *
As previously stated, a common environment to use this method in is chunk building. Methods
+ * that are invoked during chunk building and that thus should use this method include, but are
+ * not limited to, {@code FabricBakedModel#emitBlockQuads} (block models),
+ * {@code BlockColorProvider#getColor} (block color providers), and
+ * {@code FabricBlock#getAppearance} (block appearance computation).
+ *
+ *
Users of this method are required to check the returned object before using it. Users must
+ * check if it is null and if it is of the correct type to avoid null pointer and class cast
+ * exceptions, as the returned data is not guaranteed to be what the user expects. A simple way
+ * to implement these checks is to use {@code instanceof}, since it always returns {@code false}
+ * if the object is null. If the {@code instanceof} returns {@code false}, a fallback path should
+ * be used.
+ *
+ * @param pos the position of the block entity
+ * @return the render data provided by the block entity, or null if there is no block entity at this position
+ *
+ * @see RenderDataBlockEntity
+ */
+ @Nullable
+ default Object getBlockEntityRenderData(BlockPos pos) {
+ BlockEntity blockEntity = ((BlockView) this).getBlockEntity(pos);
+ return blockEntity == null ? null : blockEntity.getRenderData();
+ }
+
+ /**
+ * Checks whether biome retrieval is supported. The returned value will not change between
+ * multiple calls of this method. See {@link #getBiomeFabric(BlockPos)} for more information.
+ *
+ * @return whether biome retrieval is supported
+ * @see #getBiomeFabric(BlockPos)
+ */
+ default boolean hasBiomes() {
+ return false;
+ }
+
+ /**
+ * Retrieves the biome at the given position if biome retrieval is supported. If
+ * {@link #hasBiomes()} returns {@code true}, this method will always return a non-null
+ * {@link RegistryEntry} whose {@link RegistryEntry#value() value} is non-null. If
+ * {@link #hasBiomes()} returns {@code false}, this method will always return {@code null}.
+ *
+ *
Prefer using {@link WorldView#getBiome(BlockPos)} instead of this method if this instance
+ * is known to implement {@link WorldView}.
+ *
+ * @implNote Implementations which do not return null are encouraged to use the plains biome as
+ * the default value, for example when the biome at the given position is unknown.
+ *
+ * @param pos the position for which to retrieve the biome
+ * @return the biome, or null if biome retrieval is not supported
+ * @see #hasBiomes()
+ */
+ @UnknownNullability
+ default RegistryEntry getBiomeFabric(BlockPos pos) {
+ return null;
+ }
+}
diff --git a/fabric-block-view-api-v2/src/main/java/net/fabricmc/fabric/api/blockview/v2/RenderDataBlockEntity.java b/fabric-block-view-api-v2/src/main/java/net/fabricmc/fabric/api/blockview/v2/RenderDataBlockEntity.java
new file mode 100644
index 000000000..487b6a017
--- /dev/null
+++ b/fabric-block-view-api-v2/src/main/java/net/fabricmc/fabric/api/blockview/v2/RenderDataBlockEntity.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * 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.blockview.v2;
+
+import org.jetbrains.annotations.Nullable;
+
+import net.minecraft.block.entity.BlockEntity;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.BlockView;
+
+/**
+ * Extensions that allow {@link BlockEntity} subclasses to provide render data.
+ *
+ * Block entity render data is arbitrary data that captures some useful state of the
+ * {@link BlockEntity} and is safe to use in a multithreaded environment. In these environments,
+ * accessing and using a {@link BlockEntity} directly via {@link BlockView#getBlockEntity(BlockPos)}
+ * may not be thread-safe since the {@link BlockEntity} may be modified on a different thread, and it
+ * may not be consistent since accessing the internal state of the {@link BlockEntity} could modify it
+ * in a non-atomic way (such as through lazy computation). Using render data avoids these issues.
+ *
+ *
Implementation Tips
+ *
+ * The simplest form of render data is a value or object that is immutable. If only one such value
+ * must serve as render data, then it can be returned directly. An example of this would be returning
+ * an {@code Integer} that represents some internal state of a block entity. If more than one value
+ * must be used as render data, it can be packaged into an object that cannot be modified externally,
+ * such as a record. It is also possible to make render data a mutable object, but it must be ensured
+ * that changes to the internal state of this object are atomic and safe.
+ *
+ *
Note: This interface is automatically implemented on all {@link BlockEntity} instances via Mixin and interface injection.
+ */
+public interface RenderDataBlockEntity {
+ /**
+ * Gets the render data provided by this block entity. The returned object must be safe to
+ * use in a multithreaded environment.
+ *
+ *
Note: This method should not be called directly ; use
+ * {@link FabricBlockView#getBlockEntityRenderData(BlockPos)} instead. Only call this
+ * method when the result is used to implement
+ * {@link FabricBlockView#getBlockEntityRenderData(BlockPos)}.
+ *
+ * @return the render data
+ * @see FabricBlockView#getBlockEntityRenderData(BlockPos)
+ */
+ @Nullable
+ default Object getRenderData() {
+ return null;
+ }
+}
diff --git a/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/mixin/rendering/data/attachment/BlockEntityMixin.java b/fabric-block-view-api-v2/src/main/java/net/fabricmc/fabric/mixin/blockview/BlockEntityMixin.java
similarity index 72%
rename from fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/mixin/rendering/data/attachment/BlockEntityMixin.java
rename to fabric-block-view-api-v2/src/main/java/net/fabricmc/fabric/mixin/blockview/BlockEntityMixin.java
index e1c8f7395..d55f59205 100644
--- a/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/mixin/rendering/data/attachment/BlockEntityMixin.java
+++ b/fabric-block-view-api-v2/src/main/java/net/fabricmc/fabric/mixin/blockview/BlockEntityMixin.java
@@ -14,18 +14,14 @@
* limitations under the License.
*/
-package net.fabricmc.fabric.mixin.rendering.data.attachment;
+package net.fabricmc.fabric.mixin.blockview;
import org.spongepowered.asm.mixin.Mixin;
import net.minecraft.block.entity.BlockEntity;
-import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachmentBlockEntity;
+import net.fabricmc.fabric.api.blockview.v2.RenderDataBlockEntity;
@Mixin(BlockEntity.class)
-public class BlockEntityMixin implements RenderAttachmentBlockEntity {
- @Override
- public Object getRenderAttachmentData() {
- return null;
- }
+public abstract class BlockEntityMixin implements RenderDataBlockEntity {
}
diff --git a/fabric-block-view-api-v2/src/main/java/net/fabricmc/fabric/mixin/blockview/BlockViewMixin.java b/fabric-block-view-api-v2/src/main/java/net/fabricmc/fabric/mixin/blockview/BlockViewMixin.java
new file mode 100644
index 000000000..e9e5730ce
--- /dev/null
+++ b/fabric-block-view-api-v2/src/main/java/net/fabricmc/fabric/mixin/blockview/BlockViewMixin.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * 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.blockview;
+
+import org.spongepowered.asm.mixin.Mixin;
+
+import net.minecraft.world.BlockView;
+
+import net.fabricmc.fabric.api.blockview.v2.FabricBlockView;
+
+@Mixin(BlockView.class)
+public interface BlockViewMixin extends FabricBlockView {
+}
diff --git a/fabric-block-view-api-v2/src/main/java/net/fabricmc/fabric/mixin/blockview/WorldViewMixin.java b/fabric-block-view-api-v2/src/main/java/net/fabricmc/fabric/mixin/blockview/WorldViewMixin.java
new file mode 100644
index 000000000..ea5852ab7
--- /dev/null
+++ b/fabric-block-view-api-v2/src/main/java/net/fabricmc/fabric/mixin/blockview/WorldViewMixin.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * 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.blockview;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+
+import net.minecraft.registry.entry.RegistryEntry;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.BlockRenderView;
+import net.minecraft.world.WorldView;
+import net.minecraft.world.biome.Biome;
+
+@Mixin(WorldView.class)
+public interface WorldViewMixin extends BlockRenderView {
+ @Shadow
+ RegistryEntry getBiome(BlockPos pos);
+
+ @Override
+ default boolean hasBiomes() {
+ return true;
+ }
+
+ @Override
+ default RegistryEntry getBiomeFabric(BlockPos pos) {
+ return getBiome(pos);
+ }
+}
diff --git a/fabric-block-view-api-v2/src/main/resources/assets/fabric-block-view-api-v2/icon.png b/fabric-block-view-api-v2/src/main/resources/assets/fabric-block-view-api-v2/icon.png
new file mode 100644
index 000000000..2931efbf6
Binary files /dev/null and b/fabric-block-view-api-v2/src/main/resources/assets/fabric-block-view-api-v2/icon.png differ
diff --git a/fabric-rendering-data-attachment-v1/src/main/resources/fabric-rendering-data-attachment-v1.accesswidener b/fabric-block-view-api-v2/src/main/resources/fabric-block-view-api-v2.accesswidener
similarity index 100%
rename from fabric-rendering-data-attachment-v1/src/main/resources/fabric-rendering-data-attachment-v1.accesswidener
rename to fabric-block-view-api-v2/src/main/resources/fabric-block-view-api-v2.accesswidener
diff --git a/fabric-block-view-api-v2/src/main/resources/fabric-block-view-api-v2.mixins.json b/fabric-block-view-api-v2/src/main/resources/fabric-block-view-api-v2.mixins.json
new file mode 100644
index 000000000..4fdfe605a
--- /dev/null
+++ b/fabric-block-view-api-v2/src/main/resources/fabric-block-view-api-v2.mixins.json
@@ -0,0 +1,12 @@
+{
+ "required": true,
+ "package": "net.fabricmc.fabric.mixin.blockview",
+ "compatibilityLevel": "JAVA_17",
+ "mixins": [
+ "BlockEntityMixin",
+ "BlockViewMixin"
+ ],
+ "injectors": {
+ "defaultRequire": 1
+ }
+}
diff --git a/fabric-block-view-api-v2/src/main/resources/fabric.mod.json b/fabric-block-view-api-v2/src/main/resources/fabric.mod.json
new file mode 100644
index 000000000..63d06cb7c
--- /dev/null
+++ b/fabric-block-view-api-v2/src/main/resources/fabric.mod.json
@@ -0,0 +1,37 @@
+{
+ "schemaVersion": 1,
+ "id": "fabric-block-view-api-v2",
+ "name": "Fabric BlockView API (v2)",
+ "version": "${version}",
+ "environment": "*",
+ "license": "Apache-2.0",
+ "icon": "assets/fabric-block-view-api-v2/icon.png",
+ "contact": {
+ "homepage": "https://fabricmc.net",
+ "irc": "irc://irc.esper.net:6667/fabric",
+ "issues": "https://github.com/FabricMC/fabric/issues",
+ "sources": "https://github.com/FabricMC/fabric"
+ },
+ "authors": [
+ "FabricMC"
+ ],
+ "depends": {
+ "fabricloader": ">=0.14.21"
+ },
+ "description": "Hooks for block views",
+ "mixins": [
+ "fabric-block-view-api-v2.mixins.json",
+ {
+ "config": "fabric-block-view-api-v2.client.mixins.json",
+ "environment": "client"
+ }
+ ],
+ "custom": {
+ "fabric-api:module-lifecycle": "stable",
+ "loom:injected_interfaces": {
+ "net/minecraft/class_1922": ["net/fabricmc/fabric/api/blockview/v2/FabricBlockView"],
+ "net/minecraft/class_2586": ["net/fabricmc/fabric/api/blockview/v2/RenderDataBlockEntity"]
+ }
+ },
+ "accessWidener": "fabric-block-view-api-v2.accesswidener"
+}
diff --git a/fabric-renderer-api-v1/build.gradle b/fabric-renderer-api-v1/build.gradle
index 1aa415cf4..4c5a4747f 100644
--- a/fabric-renderer-api-v1/build.gradle
+++ b/fabric-renderer-api-v1/build.gradle
@@ -4,10 +4,10 @@ moduleDependencies(project, ['fabric-api-base'])
testDependencies(project, [
':fabric-block-api-v1',
+ ':fabric-block-view-api-v2',
':fabric-blockrenderlayer-v1',
':fabric-model-loading-api-v1',
':fabric-object-builder-api-v1',
':fabric-renderer-indigo',
- ':fabric-rendering-data-attachment-v1',
':fabric-resource-loader-v0'
])
diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java
index 34cccae9e..080305ebf 100644
--- a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java
+++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java
@@ -34,7 +34,7 @@ import net.minecraft.world.BlockRenderView;
import net.minecraft.world.World;
import net.fabricmc.fabric.api.block.v1.FabricBlock;
-import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView;
+import net.fabricmc.fabric.api.blockview.v2.FabricBlockView;
// Need to implement FabricBlock manually because this is a testmod for another Fabric module, otherwise it would be injected.
public class FrameBlock extends Block implements BlockEntityProvider, FabricBlock {
@@ -101,8 +101,8 @@ public class FrameBlock extends Block implements BlockEntityProvider, FabricBloc
// but the goal here is just to test the behavior with the pillar's connected textures. ;-)
@Override
public BlockState getAppearance(BlockState state, BlockRenderView renderView, BlockPos pos, Direction side, @Nullable BlockState sourceState, @Nullable BlockPos sourcePos) {
- // For this specific block, the render attachment works on both the client and the server, so let's use that.
- if (((RenderAttachedBlockView) renderView).getBlockEntityRenderAttachment(pos) instanceof Block mimickedBlock) {
+ // For this specific block, the render data works on both the client and the server, so let's use that.
+ if (((FabricBlockView) renderView).getBlockEntityRenderData(pos) instanceof Block mimickedBlock) {
return mimickedBlock.getDefaultState();
}
diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlockEntity.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlockEntity.java
index a90ae8236..82587d29e 100644
--- a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlockEntity.java
+++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlockEntity.java
@@ -29,9 +29,9 @@ import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
-import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachmentBlockEntity;
+import net.fabricmc.fabric.api.blockview.v2.RenderDataBlockEntity;
-public class FrameBlockEntity extends BlockEntity implements RenderAttachmentBlockEntity {
+public class FrameBlockEntity extends BlockEntity implements RenderDataBlockEntity {
@Nullable
private Block block = null;
@@ -86,7 +86,7 @@ public class FrameBlockEntity extends BlockEntity implements RenderAttachmentBlo
@Nullable
@Override
- public Block getRenderAttachmentData() {
+ public Block getRenderData() {
return this.block;
}
diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java
index 7c72d3759..aca7347d6 100644
--- a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java
+++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java
@@ -33,6 +33,7 @@ public final class Registration {
public static final FrameBlock FRAME_VARIANT_BLOCK = register("frame_variant", new FrameBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque()));
public static final Block PILLAR_BLOCK = register("pillar", new Block(FabricBlockSettings.create()));
public static final Block OCTAGONAL_COLUMN_BLOCK = register("octagonal_column", new Block(FabricBlockSettings.create().nonOpaque().strength(1.8F)));
+ public static final Block RIVERSTONE_BLOCK = register("riverstone", new Block(FabricBlockSettings.copyOf(Blocks.STONE)));
public static final FrameBlock[] FRAME_BLOCKS = new FrameBlock[] {
FRAME_BLOCK,
@@ -45,6 +46,7 @@ public final class Registration {
public static final Item FRAME_VARIANT_ITEM = register("frame_variant", new BlockItem(FRAME_VARIANT_BLOCK, new Item.Settings()));
public static final Item PILLAR_ITEM = register("pillar", new BlockItem(PILLAR_BLOCK, new Item.Settings()));
public static final Item OCTAGONAL_COLUMN_ITEM = register("octagonal_column", new BlockItem(OCTAGONAL_COLUMN_BLOCK, new Item.Settings()));
+ public static final Item RIVERSTONE_ITEM = register("riverstone", new BlockItem(RIVERSTONE_BLOCK, new Item.Settings()));
public static final BlockEntityType FRAME_BLOCK_ENTITY_TYPE = register("frame", FabricBlockEntityTypeBuilder.create(FrameBlockEntity::new, FRAME_BLOCKS).build(null));
diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/RendererTest.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/RendererTest.java
index bdd6e22bb..cab675940 100644
--- a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/RendererTest.java
+++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/RendererTest.java
@@ -37,6 +37,9 @@ import net.fabricmc.api.ModInitializer;
* Octagonal columns have irregular faces to test enhanced AO and normal shade. The
* octagonal item column has glint force enabled on all faces except the top and bottom
* faces.
+ *
+ * Riverstone blocks look like stone normally, but turn to gold in river biomes
+ * (biomes tagged with #minecraft:is_river).
*
*/
public final class RendererTest implements ModInitializer {
diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameBakedModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameBakedModel.java
index 59a921037..5e9423f59 100644
--- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameBakedModel.java
+++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameBakedModel.java
@@ -37,6 +37,7 @@ import net.minecraft.util.math.Direction;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.BlockRenderView;
+import net.fabricmc.fabric.api.blockview.v2.FabricBlockView;
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder;
@@ -44,7 +45,6 @@ import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
-import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView;
public class FrameBakedModel implements BakedModel {
private final Mesh frameMesh;
@@ -72,17 +72,12 @@ public class FrameBakedModel implements BakedModel {
// Emit our frame mesh
this.frameMesh.outputTo(context.getEmitter());
- RenderAttachedBlockView renderAttachedBlockView = (RenderAttachedBlockView) blockView;
-
- // We cannot access the block entity from here. We should instead use the immutable render attachments provided by the block entity.
- @Nullable
- Block data = (Block) renderAttachedBlockView.getBlockEntityRenderAttachment(pos);
-
- if (data == null) {
- return; // No inner block to render
+ // We should not access the block entity from here. We should instead use the immutable render data provided by the block entity.
+ if (!(((FabricBlockView) blockView).getBlockEntityRenderData(pos) instanceof Block mimickedBlock)) {
+ return; // No inner block to render, or data of wrong type
}
- BlockState innerState = data.getDefaultState();
+ BlockState innerState = mimickedBlock.getDefaultState();
// Now, we emit a transparent scaled-down version of the inner model
// Try both emissive and non-emissive versions of the translucent material
diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/ModelResolverImpl.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/ModelResolverImpl.java
index 5440d5f3b..6cb8950f2 100644
--- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/ModelResolverImpl.java
+++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/ModelResolverImpl.java
@@ -44,6 +44,11 @@ public class ModelResolverImpl implements ModelResolver {
RendererTest.id("item/octagonal_column")
);
+ private static final Set RIVERSTONE_MODEL_LOCATIONS = Set.of(
+ RendererTest.id("block/riverstone"),
+ RendererTest.id("item/riverstone")
+ );
+
@Override
@Nullable
public UnbakedModel resolveModel(Context context) {
@@ -61,6 +66,10 @@ public class ModelResolverImpl implements ModelResolver {
return new OctagonalColumnUnbakedModel();
}
+ if (RIVERSTONE_MODEL_LOCATIONS.contains(id)) {
+ return new RiverstoneUnbakedModel();
+ }
+
return null;
}
}
diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/RiverstoneBakedModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/RiverstoneBakedModel.java
new file mode 100644
index 000000000..e414c793d
--- /dev/null
+++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/RiverstoneBakedModel.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * 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.renderer.client;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Supplier;
+
+import org.jetbrains.annotations.Nullable;
+
+import net.minecraft.block.BlockState;
+import net.minecraft.client.render.model.BakedModel;
+import net.minecraft.client.render.model.BakedQuad;
+import net.minecraft.client.render.model.json.ModelOverrideList;
+import net.minecraft.client.render.model.json.ModelTransformation;
+import net.minecraft.client.texture.Sprite;
+import net.minecraft.item.ItemStack;
+import net.minecraft.registry.tag.BiomeTags;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Direction;
+import net.minecraft.util.math.random.Random;
+import net.minecraft.world.BlockRenderView;
+
+import net.fabricmc.fabric.api.blockview.v2.FabricBlockView;
+import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
+import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
+
+public class RiverstoneBakedModel implements BakedModel {
+ private final BakedModel regularModel;
+ private final BakedModel riverModel;
+
+ public RiverstoneBakedModel(BakedModel regularModel, BakedModel riverModel) {
+ this.regularModel = regularModel;
+ this.riverModel = riverModel;
+ }
+
+ @Override
+ public boolean isVanillaAdapter() {
+ return false;
+ }
+
+ @Override
+ public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) {
+ if (((FabricBlockView) blockView).hasBiomes() && ((FabricBlockView) blockView).getBiomeFabric(pos).isIn(BiomeTags.IS_RIVER)) {
+ riverModel.emitBlockQuads(blockView, state, pos, randomSupplier, context);
+ } else {
+ regularModel.emitBlockQuads(blockView, state, pos, randomSupplier, context);
+ }
+ }
+
+ @Override
+ public void emitItemQuads(ItemStack stack, Supplier randomSupplier, RenderContext context) {
+ regularModel.emitItemQuads(stack, randomSupplier, context);
+ }
+
+ @Override
+ public List getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public boolean useAmbientOcclusion() {
+ return true;
+ }
+
+ @Override
+ public boolean hasDepth() {
+ return false;
+ }
+
+ @Override
+ public boolean isSideLit() {
+ return true;
+ }
+
+ @Override
+ public boolean isBuiltin() {
+ return false;
+ }
+
+ @Override
+ public Sprite getParticleSprite() {
+ return regularModel.getParticleSprite();
+ }
+
+ @Override
+ public ModelTransformation getTransformation() {
+ return ModelHelper.MODEL_TRANSFORM_BLOCK;
+ }
+
+ @Override
+ public ModelOverrideList getOverrides() {
+ return ModelOverrideList.EMPTY;
+ }
+}
diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/RiverstoneUnbakedModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/RiverstoneUnbakedModel.java
new file mode 100644
index 000000000..523cb2f10
--- /dev/null
+++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/RiverstoneUnbakedModel.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * 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.renderer.client;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.function.Function;
+
+import org.jetbrains.annotations.Nullable;
+
+import net.minecraft.client.render.model.BakedModel;
+import net.minecraft.client.render.model.Baker;
+import net.minecraft.client.render.model.ModelBakeSettings;
+import net.minecraft.client.render.model.UnbakedModel;
+import net.minecraft.client.texture.Sprite;
+import net.minecraft.client.util.SpriteIdentifier;
+import net.minecraft.util.Identifier;
+
+public class RiverstoneUnbakedModel implements UnbakedModel {
+ private static final Identifier STONE_MODEL_ID = new Identifier("block/stone");
+ private static final Identifier GOLD_BLOCK_MODEL_ID = new Identifier("block/gold_block");
+
+ @Override
+ public Collection getModelDependencies() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public void setParents(Function modelLoader) {
+ }
+
+ @Nullable
+ @Override
+ public BakedModel bake(Baker baker, Function textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
+ BakedModel stoneModel = baker.bake(STONE_MODEL_ID, rotationContainer);
+ BakedModel goldBlockModel = baker.bake(GOLD_BLOCK_MODEL_ID, rotationContainer);
+ return new RiverstoneBakedModel(stoneModel, goldBlockModel);
+ }
+}
diff --git a/fabric-renderer-api-v1/src/testmodClient/resources/assets/fabric-renderer-api-v1-testmod/blockstates/riverstone.json b/fabric-renderer-api-v1/src/testmodClient/resources/assets/fabric-renderer-api-v1-testmod/blockstates/riverstone.json
new file mode 100644
index 000000000..68aaeaaf8
--- /dev/null
+++ b/fabric-renderer-api-v1/src/testmodClient/resources/assets/fabric-renderer-api-v1-testmod/blockstates/riverstone.json
@@ -0,0 +1,5 @@
+{
+ "variants": {
+ "": { "model": "fabric-renderer-api-v1-testmod:block/riverstone" }
+ }
+}
diff --git a/fabric-rendering-data-attachment-v1/build.gradle b/fabric-rendering-data-attachment-v1/build.gradle
deleted file mode 100644
index 456672201..000000000
--- a/fabric-rendering-data-attachment-v1/build.gradle
+++ /dev/null
@@ -1,7 +0,0 @@
-version = getSubprojectVersion(project)
-
-moduleDependencies(project, ['fabric-api-base'])
-
-loom {
- accessWidenerPath = file("src/main/resources/fabric-rendering-data-attachment-v1.accesswidener")
-}
diff --git a/fabric-rendering-data-attachment-v1/src/client/java/net/fabricmc/fabric/mixin/rendering/data/attachment/client/ChunkRendererRegionMixin.java b/fabric-rendering-data-attachment-v1/src/client/java/net/fabricmc/fabric/mixin/rendering/data/attachment/client/ChunkRendererRegionMixin.java
deleted file mode 100644
index 71a1b4986..000000000
--- a/fabric-rendering-data-attachment-v1/src/client/java/net/fabricmc/fabric/mixin/rendering/data/attachment/client/ChunkRendererRegionMixin.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
- *
- * 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.rendering.data.attachment.client;
-
-import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
-import org.spongepowered.asm.mixin.Mixin;
-
-import net.minecraft.client.render.chunk.ChunkRendererRegion;
-import net.minecraft.util.math.BlockPos;
-
-import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView;
-import net.fabricmc.fabric.impl.rendering.data.attachment.RenderDataObjectConsumer;
-
-@Mixin(ChunkRendererRegion.class)
-public abstract class ChunkRendererRegionMixin implements RenderAttachedBlockView, RenderDataObjectConsumer {
- private Long2ObjectOpenHashMap fabric_renderDataObjects;
-
- @Override
- public Object getBlockEntityRenderAttachment(BlockPos pos) {
- return fabric_renderDataObjects == null ? null : fabric_renderDataObjects.get(pos.asLong());
- }
-
- // Called in MixinChunkRendererRegionBuilder
- @Override
- public void fabric_acceptRenderDataObjects(Long2ObjectOpenHashMap renderDataObjects) {
- this.fabric_renderDataObjects = renderDataObjects;
- }
-}
diff --git a/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/api/rendering/data/v1/RenderAttachedBlockView.java b/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/api/rendering/data/v1/RenderAttachedBlockView.java
deleted file mode 100644
index dbfd88d37..000000000
--- a/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/api/rendering/data/v1/RenderAttachedBlockView.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
- *
- * 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.rendering.data.v1;
-
-import org.jetbrains.annotations.Nullable;
-
-import net.minecraft.block.entity.BlockEntity;
-import net.minecraft.util.math.BlockPos;
-import net.minecraft.world.BlockRenderView;
-import net.minecraft.world.World;
-
-/**
- * {@link BlockRenderView}-extending interface to be used by {@code FabricBakedModel}
- * for dynamic model customization. It ensures thread safety and exploits data cached in render
- * chunks for performance and data consistency. This interface is guaranteed to be implemented on
- * every {@link BlockRenderView} subclass, and as such any {@link BlockRenderView}
- * can be safely cast to {@link RenderAttachedBlockView}.
- *
- * There are differences from regular {@link World} access that consumers must understand:
- *
- *
BlockEntity implementations that provide data for model customization should implement
- * {@link RenderAttachmentBlockEntity} which will be queried on the main thread when a render
- * chunk is enqueued for rebuild. The model should retrieve the results by casting the
- * {@link BlockRenderView} to this class and then calling {@link #getBlockEntityRenderAttachment(BlockPos)}.
- * While {@link #getBlockEntity(net.minecraft.util.math.BlockPos)} is not disabled, it
- * is not thread-safe for use on render threads. Models that violate this guidance are
- * responsible for any necessary synchronization or collision detection.
- *
- *
{@link #getBlockState(net.minecraft.util.math.BlockPos)} and {@link #getFluidState(net.minecraft.util.math.BlockPos)}
- * will always reflect the state cached with the render chunk. Block and fluid states
- * can thus be different from main-thread world state due to lag between block update
- * application from network packets and render chunk rebuilds. Use of {link #getCachedRenderData()}
- * will ensure consistency of model state with the rest of the chunk being rendered.
- *
- *
Models should avoid using {@link BlockRenderView#getBlockEntity(BlockPos)}
- * to ensure thread safety because this view may be accessed outside the main client thread.
- * Models that require Block Entity data should implement {@link RenderAttachmentBlockEntity}
- * on their block entity class, cast the {@link BlockRenderView} to {@link RenderAttachedBlockView}
- * and then use {@link #getBlockEntityRenderAttachment(BlockPos)} to retrieve the data. When called from the
- * main thread, that method will simply retrieve the data directly.
- */
-public interface RenderAttachedBlockView extends BlockRenderView {
- /**
- * For models associated with Block Entities that implement {@link RenderAttachmentBlockEntity}
- * this will be the most recent value provided by that implementation for the given block position.
- *
- *
Null in all other cases, or if the result from the implementation was null.
- *
- * @param pos Position of the block for the block model.
- */
- @Nullable
- default Object getBlockEntityRenderAttachment(BlockPos pos) {
- BlockEntity be = this.getBlockEntity(pos);
- return be == null ? null : ((RenderAttachmentBlockEntity) be).getRenderAttachmentData();
- }
-}
diff --git a/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/api/rendering/data/v1/RenderAttachmentBlockEntity.java b/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/api/rendering/data/v1/RenderAttachmentBlockEntity.java
deleted file mode 100644
index b96c0bfc9..000000000
--- a/fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/api/rendering/data/v1/RenderAttachmentBlockEntity.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
- *
- * 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.rendering.data.v1;
-
-import org.jetbrains.annotations.Nullable;
-
-import net.minecraft.block.entity.BlockEntity;
-import net.minecraft.world.BlockRenderView;
-
-/**
- * Interface for {@link BlockEntity}s which provide dynamic model state data.
- *
- *
Dynamic model state data is separate from BlockState, and will be
- * cached during render chunk building on the main thread (safely) and accessible
- * during chunk rendering on non-main threads.
- *
- *
To access the dynamic data, cast the {@link BlockRenderView} to {@link RenderAttachedBlockView},
- * and then call {@link #getRenderAttachmentData()} with the correct position.
- *
- *
Due to chunk meshing happening on non-main threads, please ensure that all accesses to the passed model data are
- * thread-safe. This can be achieved by, for example, passing a pre-generated
- * immutable object, or ensuring all gets performed on the passed object are atomic
- * and well-checked for unusual states.
- */
-@FunctionalInterface
-public interface RenderAttachmentBlockEntity {
- /**
- * @return The model state data provided by this block entity. Can be null.
- */
- @Nullable
- Object getRenderAttachmentData();
-}
diff --git a/gradle.properties b/gradle.properties
index dc9186f00..339bf9535 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -16,6 +16,7 @@ fabric-api-base-version=0.4.32
fabric-api-lookup-api-v1-version=1.6.38
fabric-biome-api-v1-version=13.0.11
fabric-block-api-v1-version=1.0.10
+fabric-block-view-api-v2-version=1.0.0
fabric-blockrenderlayer-v1-version=1.1.42
fabric-command-api-v1-version=1.2.35
fabric-command-api-v2-version=2.2.14
diff --git a/settings.gradle b/settings.gradle
index a5907a801..2db408cbe 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -16,9 +16,12 @@ include 'fabric-api-base'
include 'fabric-api-lookup-api-v1'
include 'fabric-biome-api-v1'
include 'fabric-block-api-v1'
+include 'fabric-block-view-api-v2'
include 'fabric-blockrenderlayer-v1'
+include 'fabric-client-tags-api-v1'
include 'fabric-command-api-v2'
include 'fabric-content-registries-v0'
+include 'fabric-convention-tags-v1'
include 'fabric-crash-report-info-v1'
include 'fabric-data-generation-api-v1'
include 'fabric-dimensions-v1'
@@ -41,26 +44,23 @@ include 'fabric-recipe-api-v1'
include 'fabric-registry-sync-v0'
include 'fabric-renderer-api-v1'
include 'fabric-renderer-indigo'
-
-include 'fabric-rendering-v1'
-include 'fabric-rendering-data-attachment-v1'
include 'fabric-rendering-fluids-v1'
+include 'fabric-rendering-v1'
include 'fabric-resource-conditions-api-v1'
include 'fabric-resource-loader-v0'
include 'fabric-screen-api-v1'
include 'fabric-screen-handler-api-v1'
include 'fabric-sound-api-v1'
include 'fabric-transfer-api-v1'
-include 'fabric-convention-tags-v1'
-include 'fabric-client-tags-api-v1'
include 'fabric-transitive-access-wideners-v1'
include 'deprecated'
-include 'deprecated:fabric-commands-v0'
include 'deprecated:fabric-command-api-v1'
+include 'deprecated:fabric-commands-v0'
include 'deprecated:fabric-containers-v0'
include 'deprecated:fabric-events-lifecycle-v0'
include 'deprecated:fabric-keybindings-v0'
include 'deprecated:fabric-models-v0'
include 'deprecated:fabric-renderer-registries-v1'
+include 'deprecated:fabric-rendering-data-attachment-v1'
include 'deprecated:fabric-rendering-v0'