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'