mirror of
https://github.com/FabricMC/fabric.git
synced 2025-07-28 15:09:35 -04:00
1.18-rc1
This commit is contained in:
parent
6f8dfbb3f7
commit
d154e2c6fb
10 changed files with 162 additions and 92 deletions
fabric-containers-v0/src/main/java/net/fabricmc/fabric
fabric-rendering-data-attachment-v1
build.gradle
gradle.propertiessrc/main
java/net/fabricmc/fabric
impl/rendering/data/attachment
mixin/rendering/data/attachment/client
resources
|
@ -100,7 +100,7 @@ public class ContainerProviderImpl implements ContainerProviderRegistry {
|
|||
}
|
||||
|
||||
player.currentScreenHandler = screenHandler;
|
||||
((ServerPlayerEntityAccessor) player).callOnSpawn(screenHandler);
|
||||
((ServerPlayerEntityAccessor) player).callOnScreenHandlerOpened(screenHandler);
|
||||
}
|
||||
|
||||
public <C extends ScreenHandler> C createContainer(int syncId, Identifier identifier, PlayerEntity player, PacketByteBuf buf) {
|
||||
|
|
|
@ -31,5 +31,5 @@ public interface ServerPlayerEntityAccessor {
|
|||
void setScreenHandlerSyncId(int syncId);
|
||||
|
||||
@Invoker()
|
||||
void callOnSpawn(ScreenHandler screenHandler);
|
||||
void callOnScreenHandlerOpened(ScreenHandler screenHandler);
|
||||
}
|
||||
|
|
|
@ -4,3 +4,7 @@ version = getSubprojectVersion(project)
|
|||
moduleDependencies(project, [
|
||||
'fabric-api-base'
|
||||
])
|
||||
|
||||
loom {
|
||||
accessWidenerPath = file("src/main/resources/fabric-rendering-data-attachment-v1.accesswidener")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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.impl.rendering.data.attachment;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public interface RenderDataObjectConsumer {
|
||||
void fabric_acceptRenderDataObjects(Long2ObjectOpenHashMap<Object> renderDataObjects);
|
||||
}
|
|
@ -16,105 +16,27 @@
|
|||
|
||||
package net.fabricmc.fabric.mixin.rendering.data.attachment.client;
|
||||
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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.ChunkRendererRegion;
|
||||
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.RenderAttachedBlockView;
|
||||
import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachmentBlockEntity;
|
||||
import net.fabricmc.fabric.impl.rendering.data.attachment.RenderDataObjectConsumer;
|
||||
|
||||
@Mixin(ChunkRendererRegion.class)
|
||||
public abstract class MixinChunkRendererRegion implements RenderAttachedBlockView {
|
||||
public abstract class MixinChunkRendererRegion implements RenderAttachedBlockView, RenderDataObjectConsumer {
|
||||
private Long2ObjectOpenHashMap<Object> fabric_renderDataObjects;
|
||||
|
||||
private static final AtomicInteger ERROR_COUNTER = new AtomicInteger();
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "create", locals = LocalCapture.CAPTURE_FAILHARD)
|
||||
private static void init(World world, BlockPos startPos, BlockPos endPos, int chunkRadius, CallbackInfoReturnable<ChunkRendererRegion> info, int i, int j, int k, int l, WorldChunk[][] chunks) {
|
||||
// instantiated lazily - avoids allocation for chunks without any data objects - which is most of them!
|
||||
Long2ObjectOpenHashMap<Object> map = null;
|
||||
|
||||
for (WorldChunk[] chunkOuter : chunks) {
|
||||
for (WorldChunk chunk : chunkOuter) {
|
||||
// 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
|
||||
// the chunk cache and does not suffer from this problem.)
|
||||
//
|
||||
// We handle this simply by retrying until it works. Ugly but effective.
|
||||
for (;;) {
|
||||
try {
|
||||
map = mapChunk(chunk, 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);
|
||||
|
||||
if (count == 5) {
|
||||
LOGGER.info("[Render Data Attachment] Subsequent exceptions will be suppressed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ChunkRendererRegion rendererRegion = info.getReturnValue();
|
||||
|
||||
if (map != null && rendererRegion != null) {
|
||||
((MixinChunkRendererRegion) (Object) rendererRegion).fabric_renderDataObjects = map;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
for (Map.Entry<BlockPos, BlockEntity> entry : chunk.getBlockEntities().entrySet()) {
|
||||
final BlockPos entPos = 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 (o != null) {
|
||||
if (map == null) {
|
||||
map = new Long2ObjectOpenHashMap<>();
|
||||
}
|
||||
|
||||
map.put(entPos.asLong(), o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* 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 java.util.ConcurrentModificationException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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.class_6850;
|
||||
import net.minecraft.client.render.chunk.ChunkRendererRegion;
|
||||
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;
|
||||
|
||||
@Mixin(class_6850.class)
|
||||
public abstract class MixinChunkRendererRegionBuilder {
|
||||
private static final AtomicInteger ERROR_COUNTER = new AtomicInteger();
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "method_39969", 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, class_6850.class_6851[][] chunkData) {
|
||||
// instantiated lazily - avoids allocation for chunks without any data objects - which is most of them!
|
||||
Long2ObjectOpenHashMap<Object> map = null;
|
||||
|
||||
for (class_6850.class_6851[] chunkDataOuter : chunkData) {
|
||||
for (class_6850.class_6851 data : chunkDataOuter) {
|
||||
// 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
|
||||
// the chunk cache and does not suffer from this problem.)
|
||||
//
|
||||
// We handle this simply by retrying until it works. Ugly but effective.
|
||||
for (;;) {
|
||||
try {
|
||||
map = mapChunk(data.method_39971(), 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);
|
||||
|
||||
if (count == 5) {
|
||||
LOGGER.info("[Render Data Attachment] Subsequent exceptions will be suppressed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ChunkRendererRegion rendererRegion = info.getReturnValue();
|
||||
|
||||
if (map != null && rendererRegion != null) {
|
||||
((RenderDataObjectConsumer) rendererRegion).fabric_acceptRenderDataObjects(map);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
for (Map.Entry<BlockPos, BlockEntity> entry : chunk.getBlockEntities().entrySet()) {
|
||||
final BlockPos entPos = 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 (o != null) {
|
||||
if (map == null) {
|
||||
map = new Long2ObjectOpenHashMap<>();
|
||||
}
|
||||
|
||||
map.put(entPos.asLong(), o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
accessWidener v2 named
|
||||
|
||||
accessible class net/minecraft/class_6850$class_6851
|
|
@ -7,7 +7,8 @@
|
|||
"MixinViewableWorld"
|
||||
],
|
||||
"client": [
|
||||
"client.MixinChunkRendererRegion"
|
||||
"client.MixinChunkRendererRegion",
|
||||
"client.MixinChunkRendererRegionBuilder"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
|
|
@ -25,5 +25,6 @@
|
|||
],
|
||||
"custom": {
|
||||
"fabric-api:module-lifecycle": "stable"
|
||||
}
|
||||
},
|
||||
"accessWidener": "fabric-rendering-data-attachment-v1.accesswidener"
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
org.gradle.jvmargs=-Xmx2560M
|
||||
|
||||
version=0.43.0
|
||||
minecraft_version=1.18-pre7
|
||||
yarn_version=+build.2
|
||||
minecraft_version=1.18-rc1
|
||||
yarn_version=+build.1
|
||||
loader_version=0.12.5
|
||||
|
||||
prerelease=true
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue