<commit_before>package com.voxelwind.server.game.level.manager;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.spotify.futures.CompletableFutures;
import com.voxelwind.api.game.entities.Entity;
import com.voxelwind.api.game.level.Chunk;
import com.voxelwind.server.VoxelwindServer;
import com.voxelwind.server.game.level.VoxelwindLevel;
import com.voxelwind.server.game.level.chunk.SectionedChunk;
import com.voxelwind.server.game.level.chunk.generator.ChunkGenerator;
import com.voxelwind.server.game.level.chunk.provider.ChunkProvider;
import com.voxelwind.server.network.session.PlayerSession;
import gnu.trove.TCollections;
import gnu.trove.map.TLongLongMap;
import gnu.trove.map.TLongObjectMap;
import gnu.trove.map.hash.TLongLongHashMap;
import gnu.trove.map.hash.TLongObjectHashMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.annotation.Nonnull;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Handles chunk management, including loading and unloading chunks.
 *
 * This class keeps all loaded chunks in memory and cleans chunks that are no longer required to be loaded. Chunks are
 * loaded asynchronously and only one attempt to load the same chunk is made, even with concurrent callers.
 */
public class LevelChunkManager {
    private static final Logger LOGGER = LogManager.getLogger(LevelChunkManager.class);

    private final TLongObjectMap<Chunk> chunksLoaded = TCollections.synchronizedMap(new TLongObjectHashMap<Chunk>());
    private final TLongObjectMap<LoadingTask> chunksToLoad = TCollections.synchronizedMap(new TLongObjectHashMap<LoadingTask>());
    private final TLongLongMap loadedTimes = TCollections.synchronizedMap(new TLongLongHashMap());
    private final TLongLongMap lastAccessTimes = TCollections.synchronizedMap(new TLongLongHashMap());
    private final ExecutorService loadService;

    private final VoxelwindLevel level;
    private final ChunkProvider backingChunkProvider;
    private final ChunkGenerator backingChunkGenerator;
    private final VoxelwindServer server;

    public LevelChunkManager(@Nonnull VoxelwindServer server, @Nonnull VoxelwindLevel level, @Nonnull ChunkProvider backingChunkProvider, @Nonnull ChunkGenerator backingChunkGenerator) {
        this.server = server;
        this.level = level;
        this.backingChunkProvider = backingChunkProvider;
        this.backingChunkGenerator = backingChunkGenerator;
        this.loadService = Executors.newFixedThreadPool(server.getConfiguration().getFineTuning().getChunkLoadThreads(), new ThreadFactoryBuilder()
                .setNameFormat("Voxelwind Chunk Load Handler for " + level.getName() + " - #%d")
                .setDaemon(true)
                .build());
    }

    public CompletableFuture<Chunk> getChunk(int x, int z) {
        Optional<Chunk> alreadyLoaded = getChunkIfLoaded(x, z);
        if (alreadyLoaded.isPresent()) {
            return CompletableFuture.completedFuture(alreadyLoaded.get());
        }

        // Not already loaded, so we need to ask the chunk provider.
        long chunkKey = toLong(x, z);
        LoadingTask loadingTask = chunksToLoad.get(chunkKey);<commit_msg>Safety valve<commit_after>package com.voxelwind.server.game.level.manager;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.spotify.futures.CompletableFutures;
import com.voxelwind.api.game.entities.Entity;
import com.voxelwind.api.game.level.Chunk;
import com.voxelwind.server.VoxelwindServer;
import com.voxelwind.server.game.level.VoxelwindLevel;
import com.voxelwind.server.game.level.chunk.SectionedChunk;
import com.voxelwind.server.game.level.chunk.generator.ChunkGenerator;
import com.voxelwind.server.game.level.chunk.provider.ChunkProvider;
import com.voxelwind.server.network.session.PlayerSession;
import gnu.trove.TCollections;
import gnu.trove.map.TLongLongMap;
import gnu.trove.map.TLongObjectMap;
import gnu.trove.map.hash.TLongLongHashMap;
import gnu.trove.map.hash.TLongObjectHashMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.annotation.Nonnull;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Handles chunk management, including loading and unloading chunks.
 *
 * This class keeps all loaded chunks in memory and cleans chunks that are no longer required to be loaded. Chunks are
 * loaded asynchronously and only one attempt to load the same chunk is made, even with concurrent callers.
 */
public class LevelChunkManager {
    private static final Logger LOGGER = LogManager.getLogger(LevelChunkManager.class);

    private final TLongObjectMap<Chunk> chunksLoaded = TCollections.synchronizedMap(new TLongObjectHashMap<Chunk>());
    private final TLongObjectMap<LoadingTask> chunksToLoad = TCollections.synchronizedMap(new TLongObjectHashMap<LoadingTask>());
    private final TLongLongMap loadedTimes = TCollections.synchronizedMap(new TLongLongHashMap());
    private final TLongLongMap lastAccessTimes = TCollections.synchronizedMap(new TLongLongHashMap());
    private final ExecutorService loadService;

    private final VoxelwindLevel level;
    private final ChunkProvider backingChunkProvider;
    private final ChunkGenerator backingChunkGenerator;
    private final VoxelwindServer server;

    public LevelChunkManager(@Nonnull VoxelwindServer server, @Nonnull VoxelwindLevel level, @Nonnull ChunkProvider backingChunkProvider, @Nonnull ChunkGenerator backingChunkGenerator) {
        this.server = server;
        this.level = level;
        this.backingChunkProvider = backingChunkProvider;
        this.backingChunkGenerator = backingChunkGenerator;
        this.loadService = Executors.newFixedThreadPool(Math.max(1, server.getConfiguration().getFineTuning().getChunkLoadThreads()),
                new ThreadFactoryBuilder()
                        .setNameFormat("Voxelwind Chunk Load Handler for " + level.getName() + " - #%d")
                        .setDaemon(true)
                        .build());
    }

    public CompletableFuture<Chunk> getChunk(int x, int z) {
        Optional<Chunk> alreadyLoaded = getChunkIfLoaded(x, z);
        if (alreadyLoaded.isPresent()) {
            return CompletableFuture.completedFuture(alreadyLoaded.get());
        }

        // Not already loaded, so we need to ask the chunk provider.
        long chunkKey = toLong(x, z);
        LoadingTask loadingTask = chunksToLoad.get(chunkKey);
{'fraction_non_alphanumeric': 0.08661887694145759, 'fraction_numerical': 0.0007467144563918758, 'mean_word_length': 4.534710743801653, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '833885', 'n_tokens_mistral': 1910, 'n_tokens_neox': 1876, 'n_words': 427}