Skip to content

Instantly share code, notes, and snippets.

@Runemoro
Created April 28, 2019 09:37
Show Gist options
  • Save Runemoro/02bf2f7e273b415dd0bdb4aaec2a75c4 to your computer and use it in GitHub Desktop.
Save Runemoro/02bf2f7e273b415dd0bdb4aaec2a75c4 to your computer and use it in GitHub Desktop.
import it.unimi.dsi.fastutil.longs.Long2ByteLinkedOpenHashMap;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.util.BooleanBiFunction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
@Mixin(value = Block.class, priority = 500)
public class BlockMixin {
private static final ThreadLocal<Long2ByteLinkedOpenHashMap> FACE_CULL_MAP_ = ThreadLocal.withInitial(() -> {
Long2ByteLinkedOpenHashMap map = new Long2ByteLinkedOpenHashMap(1000) {
@Override
protected void rehash(int newN) {}
}
map.defaultReturnValue((byte) 127);
return map;
});
/**
* Don't use NeighborGroups, calculating its hashCode is slow. Instead, calculate a long cache key based
* on the state, neighbor state and side.
*/
@Overwrite
@Environment(EnvType.CLIENT)
public static boolean shouldDrawSide(BlockState state, BlockView world, BlockPos pos, Direction side) {
BlockPos neighbor = pos.offset(side);
BlockState neighborState = world.getBlockState(neighbor);
if (state.skipRenderingSide(neighborState, side)) {
return false;
}
if (!neighborState.isFullBoundsCubeForCulling()) {
return true;
}
Long2ByteLinkedOpenHashMap cullMap = FACE_CULL_MAP_.get();
// hashCode is unique, see AbstractPropertyContainerMixin
long cacheKey = ((long) state.hashCode() << 32 + 3) + ((long) neighborState.hashCode() << 3) + side.ordinal();
byte cached = cullMap.getAndMoveToFirst(cacheKey);
if (cached != 127) {
return cached != 0;
}
VoxelShape shape = state.getCullShape(world, pos, side);
VoxelShape neighborShape = neighborState.getCullShape(world, neighbor, side.getOpposite());
boolean shouldDraw = VoxelShapes.matchesAnywhere(shape, neighborShape, BooleanBiFunction.ONLY_FIRST);
if (cullMap.size() == 1000) {
cullMap.removeLastByte();
}
cullMap.putAndMoveToFirst(cacheKey, (byte) (shouldDraw ? 1 : 0));
return shouldDraw;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment