BlockTintCache.java

net.minecraft.client.color.block.BlockTintCache

信息

  • 全限定名:net.minecraft.client.color.block.BlockTintCache
  • 类型:public class
  • 包:net.minecraft.client.color.block
  • 源码路径:src/main/java/net/minecraft/client/color/block/BlockTintCache.java
  • 起始行号:L17
  • 职责:

    TODO

字段/常量

  • MAX_CACHE_ENTRIES

    • 类型: int
    • 修饰符: private static final
    • 源码定位: L18
    • 说明:

      TODO

  • latestChunkOnThread

    • 类型: ThreadLocal<BlockTintCache.LatestCacheInfo>
    • 修饰符: private final
    • 源码定位: L19
    • 说明:

      TODO

  • cache

    • 类型: Long2ObjectLinkedOpenHashMap<BlockTintCache.CacheData>
    • 修饰符: private final
    • 源码定位: L20
    • 说明:

      TODO

  • lock

    • 类型: ReentrantReadWriteLock
    • 修饰符: private final
    • 源码定位: L21
    • 说明:

      TODO

  • source

    • 类型: ToIntFunction<BlockPos>
    • 修饰符: private final
    • 源码定位: L22
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.color.block.BlockTintCache.CacheData

    • 类型: class
    • 修饰符: private static
    • 源码定位: L120
    • 说明:

      TODO

  • net.minecraft.client.color.block.BlockTintCache.LatestCacheInfo

    • 类型: class
    • 修饰符: private static
    • 源码定位: L166
    • 说明:

      TODO

构造器

public BlockTintCache(ToIntFunction<BlockPos> source) @ L24

  • 构造器名:BlockTintCache
  • 源码定位:L24
  • 修饰符:public

参数:

  • source: ToIntFunction

说明:

TODO

方法

下面的方法块按源码顺序生成。

public int getColor(BlockPos pos) @ L28

  • 方法名:getColor
  • 源码定位:L28
  • 返回类型:int
  • 修饰符:public

参数:

  • pos: BlockPos

说明:

TODO

public void invalidateForChunk(int chunkX, int chunkZ) @ L52

  • 方法名:invalidateForChunk
  • 源码定位:L52
  • 返回类型:void
  • 修饰符:public

参数:

  • chunkX: int
  • chunkZ: int

说明:

TODO

public void invalidateAll() @ L70

  • 方法名:invalidateAll
  • 源码定位:L70
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

private BlockTintCache.CacheData findOrCreateChunkCache(int x, int z) @ L80

  • 方法名:findOrCreateChunkCache
  • 源码定位:L80
  • 返回类型:BlockTintCache.CacheData
  • 修饰符:private

参数:

  • x: int
  • z: int

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class BlockTintCache {
    private static final int MAX_CACHE_ENTRIES = 256;
    private final ThreadLocal<BlockTintCache.LatestCacheInfo> latestChunkOnThread = ThreadLocal.withInitial(BlockTintCache.LatestCacheInfo::new);
    private final Long2ObjectLinkedOpenHashMap<BlockTintCache.CacheData> cache = new Long2ObjectLinkedOpenHashMap<>(256, 0.25F);
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private final ToIntFunction<BlockPos> source;
 
    public BlockTintCache(ToIntFunction<BlockPos> source) {
        this.source = source;
    }
 
    public int getColor(BlockPos pos) {
        int chunkX = SectionPos.blockToSectionCoord(pos.getX());
        int chunkZ = SectionPos.blockToSectionCoord(pos.getZ());
        BlockTintCache.LatestCacheInfo chunkInfo = this.latestChunkOnThread.get();
        if (chunkInfo.x != chunkX || chunkInfo.z != chunkZ || chunkInfo.cache == null || chunkInfo.cache.isInvalidated()) {
            chunkInfo.x = chunkX;
            chunkInfo.z = chunkZ;
            chunkInfo.cache = this.findOrCreateChunkCache(chunkX, chunkZ);
        }
 
        int[] layer = chunkInfo.cache.getLayer(pos.getY());
        int x = pos.getX() & 15;
        int z = pos.getZ() & 15;
        int index = z << 4 | x;
        int cached = layer[index];
        if (cached != -1) {
            return cached;
        } else {
            int calculated = this.source.applyAsInt(pos);
            layer[index] = calculated;
            return calculated;
        }
    }
 
    public void invalidateForChunk(int chunkX, int chunkZ) {
        try {
            this.lock.writeLock().lock();
 
            for (int offsetX = -1; offsetX <= 1; offsetX++) {
                for (int offsetZ = -1; offsetZ <= 1; offsetZ++) {
                    long key = ChunkPos.pack(chunkX + offsetX, chunkZ + offsetZ);
                    BlockTintCache.CacheData removed = this.cache.remove(key);
                    if (removed != null) {
                        removed.invalidate();
                    }
                }
            }
        } finally {
            this.lock.writeLock().unlock();
        }
    }
 
    public void invalidateAll() {
        try {
            this.lock.writeLock().lock();
            this.cache.values().forEach(BlockTintCache.CacheData::invalidate);
            this.cache.clear();
        } finally {
            this.lock.writeLock().unlock();
        }
    }
 
    private BlockTintCache.CacheData findOrCreateChunkCache(int x, int z) {
        long key = ChunkPos.pack(x, z);
        this.lock.readLock().lock();
 
        try {
            BlockTintCache.CacheData existing = this.cache.get(key);
            if (existing != null) {
                return existing;
            }
        } finally {
            this.lock.readLock().unlock();
        }
 
        this.lock.writeLock().lock();
 
        BlockTintCache.CacheData newCache;
        try {
            BlockTintCache.CacheData existingNow = this.cache.get(key);
            if (existingNow == null) {
                newCache = new BlockTintCache.CacheData();
                if (this.cache.size() >= 256) {
                    BlockTintCache.CacheData cacheData = this.cache.removeFirst();
                    if (cacheData != null) {
                        cacheData.invalidate();
                    }
                }
 
                this.cache.put(key, newCache);
                return newCache;
            }
 
            newCache = existingNow;
        } finally {
            this.lock.writeLock().unlock();
        }
 
        return newCache;
    }
 
    @OnlyIn(Dist.CLIENT)
    private static class CacheData {
        private final Int2ObjectArrayMap<int[]> cache = new Int2ObjectArrayMap<>(16);
        private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
        private static final int BLOCKS_PER_LAYER = Mth.square(16);
        private volatile boolean invalidated;
 
        public int[] getLayer(int y) {
            this.lock.readLock().lock();
 
            try {
                int[] existing = this.cache.get(y);
                if (existing != null) {
                    return existing;
                }
            } finally {
                this.lock.readLock().unlock();
            }
 
            this.lock.writeLock().lock();
 
            int[] var12;
            try {
                var12 = this.cache.computeIfAbsent(y, n -> this.allocateLayer());
            } finally {
                this.lock.writeLock().unlock();
            }
 
            return var12;
        }
 
        private int[] allocateLayer() {
            int[] newCache = new int[BLOCKS_PER_LAYER];
            Arrays.fill(newCache, -1);
            return newCache;
        }
 
        public boolean isInvalidated() {
            return this.invalidated;
        }
 
        public void invalidate() {
            this.invalidated = true;
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    private static class LatestCacheInfo {
        public int x = Integer.MIN_VALUE;
        public int z = Integer.MIN_VALUE;
        BlockTintCache.@Nullable CacheData cache;
    }
}

引用的其他类

  • BlockPos

    • 引用位置: 参数/字段
  • SectionPos

    • 引用位置: 方法调用
    • 关联成员: SectionPos.blockToSectionCoord()
  • Mth

    • 引用位置: 方法调用
    • 关联成员: Mth.square()
  • ChunkPos

    • 引用位置: 方法调用
    • 关联成员: ChunkPos.pack()