Remove BlockEntry

This commit is contained in:
TheMode 2021-07-10 18:42:02 +02:00
parent fc52b502dd
commit a8a9f59715
3 changed files with 40 additions and 65 deletions

View File

@ -1,8 +1,6 @@
package net.minestom.server.instance;
import com.extollit.gaming.ai.path.model.ColumnarOcclusionFieldList;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.pathfinding.PFBlock;
@ -11,15 +9,14 @@ import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.server.world.biomes.Biome;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.lang.ref.SoftReference;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
/**
* Represents a {@link Chunk} which store each individual block in memory.
@ -31,8 +28,8 @@ public class DynamicChunk extends Chunk {
protected final TreeMap<Integer, Section> sectionMap = new TreeMap<>();
// Key = ChunkUtils#getBlockIndex
protected final Int2ObjectOpenHashMap<BlockEntry> entries = new Int2ObjectOpenHashMap<>();
protected final Int2ObjectOpenHashMap<BlockHandler> tickableMap = new Int2ObjectOpenHashMap<>();
protected final Int2ObjectOpenHashMap<Block> entries = new Int2ObjectOpenHashMap<>();
protected final Int2ObjectOpenHashMap<Block> tickableMap = new Int2ObjectOpenHashMap<>();
private long lastChangeTime;
@ -60,13 +57,13 @@ public class DynamicChunk extends Chunk {
final BlockHandler handler = block.handler();
final NBTCompound nbt = block.nbt();
if (handler != null || nbt != null) {
this.entries.put(index, new BlockEntry(handler, nbt));
this.entries.put(index, block);
} else {
this.entries.remove(index);
}
// Tickable
if (handler != null && handler.isTickable()) {
this.tickableMap.put(index, handler);
this.tickableMap.put(index, block);
} else {
this.tickableMap.remove(index);
}
@ -88,41 +85,33 @@ public class DynamicChunk extends Chunk {
return;
for (var entry : tickableMap.int2ObjectEntrySet()) {
final int index = entry.getIntKey();
final int x = ChunkUtils.blockIndexToChunkPositionX(index);
final int y = ChunkUtils.blockIndexToChunkPositionY(index);
final int z = ChunkUtils.blockIndexToChunkPositionZ(index);
final Vec blockPosition = new Vec(x, y, z);
final Block block = getBlock(blockPosition);
entry.getValue().tick(new BlockHandler.Tick(block, instance, blockPosition));
final Block block = entry.getValue();
final var handler = block.handler();
if (handler != null) {
final int x = ChunkUtils.blockIndexToChunkPositionX(index);
final int y = ChunkUtils.blockIndexToChunkPositionY(index);
final int z = ChunkUtils.blockIndexToChunkPositionZ(index);
final Vec blockPosition = new Vec(x, y, z);
handler.tick(new BlockHandler.Tick(block, instance, blockPosition));
}
}
}
@Override
public @NotNull Block getBlock(int x, int y, int z) {
// Verify if the block object is present
final int index = ChunkUtils.getBlockIndex(x, y, z);
final var entry = entries.get(index);
if (entry != null) {
return entry;
}
// Retrieve the block from state id
final Section section = retrieveSection(y);
final short blockStateId = section.getBlockAt(x, y, z);
if (blockStateId == -1) {
return Block.AIR;
}
Block block = Block.fromStateId(blockStateId);
if (block == null) {
return Block.AIR;
}
final int index = ChunkUtils.getBlockIndex(x, y, z);
final var entry = entries.get(index);
if (entry != null) {
final BlockHandler handler = entry.handler;
final NBTCompound nbt = entry.nbtCompound;
if (handler != null) {
block = block.withHandler(handler);
}
if (nbt != null) {
block = block.withNbt(nbt);
}
}
return block;
return Objects.requireNonNullElse(Block.fromStateId(blockStateId), Block.AIR);
}
@Override
@ -170,28 +159,4 @@ public class DynamicChunk extends Chunk {
final int sectionIndex = ChunkUtils.getSectionAt(y);
return getSection(sectionIndex);
}
@ApiStatus.Internal
public static class BlockEntry {
private static final Cache<NBTCompound, NBTCompound> NBT_CACHE = Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.weakValues()
.build();
private final BlockHandler handler;
private final NBTCompound nbtCompound;
public BlockEntry(BlockHandler handler, NBTCompound nbtCompound) {
this.handler = handler;
this.nbtCompound = nbtCompound != null ? NBT_CACHE.get(nbtCompound, compound -> nbtCompound) : null;
}
public BlockHandler handler() {
return handler;
}
public NBTCompound nbtCompound() {
return nbtCompound;
}
}
}

View File

@ -1,5 +1,7 @@
package net.minestom.server.instance.block;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import net.minestom.server.registry.Registry;
import net.minestom.server.tag.Tag;
import org.jetbrains.annotations.NotNull;
@ -10,8 +12,14 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
class BlockImpl implements Block {
private static final Cache<NBTCompound, NBTCompound> NBT_CACHE = Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.weakValues()
.build();
private final Registry.BlockEntry registry;
private final Map<String, String> properties;
private final NBTCompound nbt;
@ -48,7 +56,7 @@ class BlockImpl implements Block {
public @NotNull <T> Block withTag(@NotNull Tag<T> tag, @Nullable T value) {
var compound = Objects.requireNonNullElseGet(nbt(), NBTCompound::new);
tag.write(compound, value);
return new BlockImpl(registry, properties, compound, handler);
return new BlockImpl(registry, properties, NBT_CACHE.get(compound, c -> compound), handler);
}
@Override

View File

@ -7,6 +7,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minestom.server.MinecraftServer;
import net.minestom.server.instance.DynamicChunk;
import net.minestom.server.instance.Section;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -35,7 +36,7 @@ public class ChunkDataPacket implements ServerPacket, CacheablePacket {
public int chunkX, chunkZ;
public Map<Integer, Section> sections = new HashMap<>();
public Map<Integer, DynamicChunk.BlockEntry> entries = new HashMap<>();
public Map<Integer, Block> entries = new HashMap<>();
private static final byte CHUNK_SECTION_COUNT = 16;
private static final int MAX_BITS_PER_ENTRY = 16;
@ -130,14 +131,15 @@ public class ChunkDataPacket implements ServerPacket, CacheablePacket {
List<NBTCompound> compounds = new ArrayList<>();
for (var entry : entries.entrySet()) {
final int index = entry.getKey();
final var blockEntry = entry.getValue();
final BlockHandler handler = blockEntry.handler();
final var blockEntityTags = handler.getBlockEntityTags();
if (blockEntityTags.isEmpty())
final var block = entry.getValue();
final BlockHandler handler = block.handler();
if(handler == null)
continue;
final var blockNbt = Objects.requireNonNullElseGet(blockEntry.nbtCompound(), NBTCompound::new);
final var blockEntityTags = handler.getBlockEntityTags();
if (blockEntityTags.isEmpty()) // Verify if the block should be sent as block entity to client
continue;
final var blockNbt = Objects.requireNonNullElseGet(block.nbt(), NBTCompound::new);
final var resultNbt = new NBTCompound();
for (Tag<?> tag : blockEntityTags) {
final var value = tag.read(blockNbt);
if (value != null) {