mirror of
https://github.com/FabricMC/fabric.git
synced 2024-11-14 19:25:23 -05:00
BlockView API v2 (#3268)
* Fabric BlockView API v2 * Fix dependency on nonexistent module * Add test for biome getter * Improve getBiomeFabric documentation * Simplify javadoc
This commit is contained in:
parent
195226a756
commit
92a0d36746
39 changed files with 749 additions and 251 deletions
|
@ -0,0 +1,4 @@
|
|||
archivesBaseName = "fabric-rendering-data-attachment-v1"
|
||||
version = getSubprojectVersion(project)
|
||||
|
||||
moduleDependencies(project, ['fabric-block-view-api-v2'])
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
}
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -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"
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -56,11 +56,12 @@ public interface FabricBlock {
|
|||
* <p>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.
|
||||
* <pre>{@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 ...) {
|
||||
|
|
6
fabric-block-view-api-v2/build.gradle
Normal file
6
fabric-block-view-api-v2/build.gradle
Normal file
|
@ -0,0 +1,6 @@
|
|||
archivesBaseName = "fabric-block-view-api-v2"
|
||||
version = getSubprojectVersion(project)
|
||||
|
||||
loom {
|
||||
accessWidenerPath = file("src/main/resources/fabric-block-view-api-v2.accesswidener")
|
||||
}
|
|
@ -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<Object> renderDataObjects);
|
||||
public interface RenderDataMapConsumer {
|
||||
void fabric_acceptRenderDataMap(Long2ObjectMap<Object> renderDataMap);
|
||||
}
|
|
@ -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<ChunkRendererRegion> 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<ChunkRendererRegion> 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<Object> 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<Object> mapChunk(WorldChunk chunk, BlockPos posFrom, BlockPos posTo, Long2ObjectOpenHashMap<Object> 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<BlockPos, BlockEntity> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<Object> 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<Object> renderDataMap) {
|
||||
this.fabric_renderDataMap = renderDataMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBiomes() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegistryEntry<Biome> getBiomeFabric(BlockPos pos) {
|
||||
return world.getBiome(pos);
|
||||
}
|
||||
}
|
|
@ -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"
|
|
@ -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.
|
||||
*
|
||||
* <p>These extensions were designed primarily for use by methods invoked during chunk building, but
|
||||
* they can also be used in other contexts.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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).
|
||||
*
|
||||
* <p>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}.
|
||||
*
|
||||
* <p>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<Biome> getBiomeFabric(BlockPos pos) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <h3>Implementation Tips</h3>
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>Note: <b>This method should not be called directly</b>; 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;
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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<Biome> getBiome(BlockPos pos);
|
||||
|
||||
@Override
|
||||
default boolean hasBiomes() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
default RegistryEntry<Biome> getBiomeFabric(BlockPos pos) {
|
||||
return getBiome(pos);
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "net.fabricmc.fabric.mixin.blockview",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"mixins": [
|
||||
"BlockEntityMixin",
|
||||
"BlockViewMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
37
fabric-block-view-api-v2/src/main/resources/fabric.mod.json
Normal file
37
fabric-block-view-api-v2/src/main/resources/fabric.mod.json
Normal file
|
@ -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"
|
||||
}
|
|
@ -5,10 +5,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'
|
||||
])
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<FrameBlockEntity> FRAME_BLOCK_ENTITY_TYPE = register("frame", FabricBlockEntityTypeBuilder.create(FrameBlockEntity::new, FRAME_BLOCKS).build(null));
|
||||
|
||||
|
|
|
@ -37,6 +37,9 @@ import net.fabricmc.api.ModInitializer;
|
|||
* <li>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.
|
||||
*
|
||||
* <li>Riverstone blocks look like stone normally, but turn to gold in river biomes
|
||||
* (biomes tagged with #minecraft:is_river).
|
||||
* </ul>
|
||||
*/
|
||||
public final class RendererTest implements ModInitializer {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -44,6 +44,11 @@ public class ModelResolverImpl implements ModelResolver {
|
|||
RendererTest.id("item/octagonal_column")
|
||||
);
|
||||
|
||||
private static final Set<Identifier> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Random> 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<Random> randomSupplier, RenderContext context) {
|
||||
regularModel.emitItemQuads(stack, randomSupplier, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> 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;
|
||||
}
|
||||
}
|
|
@ -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<Identifier> getModelDependencies() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParents(Function<Identifier, UnbakedModel> modelLoader) {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BakedModel bake(Baker baker, Function<SpriteIdentifier, Sprite> 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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"variants": {
|
||||
"": { "model": "fabric-renderer-api-v1-testmod:block/riverstone" }
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
archivesBaseName = "fabric-rendering-data-attachment-v1"
|
||||
version = getSubprojectVersion(project)
|
||||
|
||||
moduleDependencies(project, ['fabric-api-base'])
|
||||
|
||||
loom {
|
||||
accessWidenerPath = file("src/main/resources/fabric-rendering-data-attachment-v1.accesswidener")
|
||||
}
|
|
@ -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<Object> 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<Object> renderDataObjects) {
|
||||
this.fabric_renderDataObjects = renderDataObjects;
|
||||
}
|
||||
}
|
|
@ -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}.
|
||||
*
|
||||
* <p>There are differences from regular {@link World} access that consumers must understand:
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>{@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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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();
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>To access the dynamic data, cast the {@link BlockRenderView} to {@link RenderAttachedBlockView},
|
||||
* and then call {@link #getRenderAttachmentData()} with the correct position.
|
||||
*
|
||||
* <p>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();
|
||||
}
|
|
@ -15,6 +15,7 @@ fabric-api-base-version=0.4.30
|
|||
fabric-api-lookup-api-v1-version=1.6.35
|
||||
fabric-biome-api-v1-version=13.0.10
|
||||
fabric-block-api-v1-version=1.0.9
|
||||
fabric-block-view-api-v2-version=1.0.0
|
||||
fabric-blockrenderlayer-v1-version=1.1.40
|
||||
fabric-command-api-v1-version=1.2.33
|
||||
fabric-command-api-v2-version=2.2.12
|
||||
|
|
|
@ -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,28 +44,25 @@ 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-loot-tables-v1'
|
||||
include 'deprecated:fabric-models-v0'
|
||||
include 'deprecated:fabric-networking-v0'
|
||||
include 'deprecated:fabric-renderer-registries-v1'
|
||||
include 'deprecated:fabric-rendering-data-attachment-v1'
|
||||
include 'deprecated:fabric-rendering-v0'
|
||||
include 'deprecated:fabric-loot-tables-v1'
|
||||
|
|
Loading…
Reference in a new issue