Skip to content

Commit

Permalink
Minor optimizations for chunk retrieval
Browse files Browse the repository at this point in the history
  • Loading branch information
embeddedt committed Dec 29, 2023
1 parent 6128f9f commit 78cf313
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 0 deletions.
65 changes: 65 additions & 0 deletions src/main/java/org/embeddedt/vintagefix/chunk/VintageChunkMap.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.embeddedt.vintagefix.chunk;

import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.chunk.Chunk;

/**
* This class implements a small LRU cache on top of Long2ObjectOpenHashMap to enable
* faster chunk lookups if the same chunk is retrieved many times.
*/
public class VintageChunkMap extends Long2ObjectOpenHashMap<Chunk> {
private static final int CACHE_SIZE = 4;
private final long[] cachedChunkPositions = new long[CACHE_SIZE];
private final Chunk[] cachedChunks = new Chunk[CACHE_SIZE];

public VintageChunkMap() {
super(8192);
}

@Override
public Chunk get(long key) {
for (int i = 0; i < 4; ++i) {
// Consolidate the scan into one comparison, allowing the JVM to better optimize the function
// This is considerably faster than scanning two arrays side-by-side
if (key == cachedChunkPositions[i]) {
Chunk chunk = this.cachedChunks[i];

// If the chunk exists for the key, return the result
// We also check that the position matches, in case mods try to access
// chunks on the wrong thread
if (chunk != null && ChunkPos.asLong(chunk.x, chunk.z) == key) {
return chunk;
}
}
}

Chunk chunk = super.get(key);

if (chunk != null) {
this.addToCache(key, chunk);
}

return chunk;
}

@Override
public Chunk remove(long k) {
for (int i = 0; i < 4; ++i) {
if (k == cachedChunkPositions[i]) {
cachedChunks[i] = null;
}
}
return super.remove(k);
}

private void addToCache(long key, Chunk chunk) {
for (int i = CACHE_SIZE - 1; i > 0; --i) {
this.cachedChunkPositions[i] = this.cachedChunkPositions[i - 1];
this.cachedChunks[i] = this.cachedChunks[i - 1];
}

this.cachedChunkPositions[0] = key;
this.cachedChunks[0] = chunk;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.embeddedt.vintagefix.mixin.chunk_access;

import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;

@Mixin(Chunk.class)
public class ChunkMixin {
@Shadow
@Final
private ExtendedBlockStorage[] storageArrays;

@Shadow
@Final
public static ExtendedBlockStorage NULL_BLOCK_STORAGE;

private static final IBlockState DEFAULT_BLOCK_STATE = Blocks.AIR.getDefaultState();

/**
* @reason Reduce method size to help the JVM inline
* @author JellySquid
*/
@Overwrite
public IBlockState getBlockState(int x, int y, int z) {
if (y >= 0 && (y >> 4) < this.storageArrays.length) {
ExtendedBlockStorage section = this.storageArrays[y >> 4];

if (section != NULL_BLOCK_STORAGE) {
return section.get(x & 15, y & 15, z & 15);
}
}

return DEFAULT_BLOCK_STATE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.embeddedt.vintagefix.mixin.chunk_access;

import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import net.minecraft.client.multiplayer.ChunkProviderClient;
import net.minecraft.world.chunk.Chunk;
import org.embeddedt.vintagefix.chunk.VintageChunkMap;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

@Mixin(ChunkProviderClient.class)
public class ChunkProviderClientMixin {
@Shadow @Final private final Long2ObjectMap<Chunk> loadedChunks = new VintageChunkMap();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.embeddedt.vintagefix.mixin.chunk_access;

import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.gen.ChunkProviderServer;
import org.embeddedt.vintagefix.chunk.VintageChunkMap;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

@Mixin(ChunkProviderServer.class)
public class ChunkProviderServerMixin {
@Shadow
@Final
private final Long2ObjectMap<Chunk> loadedChunks = new VintageChunkMap();
}

0 comments on commit 78cf313

Please sign in to comment.