<commit_before>﻿using DFHack;
using RemoteFortressReader;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;

// Two implementations: single and multithreaded.
// All of the actual meshing code is exactly the same;
// the only difference is in how it's called.

abstract class BlockMesher {
    // If n = 0, single threaded; else multithreaded.
    public static BlockMesher GetMesher (int nThreads) {
        if (nThreads < 0) {
            throw new System.InvalidOperationException(nThreads + " threads? What??");
        } else if (nThreads == 0) {
            return new SingleThreadedMesher();
        } else {
            return new MultiThreadedMesher(nThreads);
        }
    }

    public struct Result {
        public DFCoord location;
        public CPUMesh tiles;
        public CPUMesh stencilTiles;
        public CPUMesh transparentTiles;
        public CPUMesh topTiles;
        public CPUMesh topStencilTiles;
        public CPUMesh topTransparentTiles;
        public CPUMesh water;
        public CPUMesh magma;
        public CPUMesh collisionMesh;
    }

    protected struct Request {
        public bool tiles;
        public bool liquids;
        public MapDataStore data;
    }

    // There is REALLY NO REASON FOR THIS TO EXIST.
    // If unity was SENSIBLE we could use thread-local storage,
    // but unity is insensible, so we have to thread one of these through every method
    // that uses temporary buffers instead.
    protected struct TempBuffers {
        public void Init() {
            meshBuffer =
                new MeshCombineUtility.MeshInstance[GameMap.blockSize * GameMap.blockSize * (int)MeshLayer.StaticCutout];
            stencilMeshBuffer =
                new MeshCombineUtility.MeshInstance[GameMap.blockSize * GameMap.blockSize * ((int)MeshLayer.StaticTransparent - (int)MeshLayer.StaticCutout)];
            transparentMeshBuffer =
                new MeshCombineUtility.MeshInstance[GameMap.blockSize * GameMap.blockSize * ((int)MeshLayer.Collision - (int)MeshLayer.StaticTransparent)];
            collisionMeshBuffer =
                new MeshCombineUtility.MeshInstance[GameMap.blockSize * GameMap.blockSize * ((int)MeshLayer.Count - (int)MeshLayer.Collision)];
            heights = new float[2, 2];
        }

        public MeshCombineUtility.MeshInstance[] meshBuffer { get; private set; }
        public MeshCombineUtility.MeshInstance[] stencilMeshBuffer { get; private set; }
        public MeshCombineUtility.MeshInstance[] transparentMeshBuffer { get; private set; }
        public MeshCombineUtility.MeshInstance[] collisionMeshBuffer { get; private set; }
        public float[,] heights { get; private set; }
    }

    // Stuff for runtime configuration.
    // These will be accessed from multiple threads, but DON'T need to be
    // locked, since they don't change after being loaded.
    protected readonly Dictionary<MatPairStruct, RemoteFortressReader.MaterialDefinition> materials;

    // Some queues.
    // All of these need to be locked before access.
    // In general, NEVER LOCK MORE THAN ONE at the same time - 
    // That road leads to deadlock.
    protected readonly Util.UniqueQueue<DFCoord, Request> requestQueue; 
    protected readonly Queue<Result> resultQueue;
    protected readonly Stack<MapDataStore> recycledBlocks; // Object pool!

    protected BlockMesher() {
        // Make queues
        requestQueue = new Util.UniqueQueue<DFCoord, Request>();
        recycledBlocks = new Stack<MapDataStore>();
        resultQueue = new Queue<Result>();

        // Load materials
        materials = new Dictionary<MatPairStruct, RemoteFortressReader.MaterialDefinition>();
        foreach (RemoteFortressReader.MaterialDefinition material in DFConnection.Instance.NetMaterialList.material_list)
        {
            materials[material.mat_pair] = material;
        }
        System.GC.Collect(); //force a garbage collect after initial load.
    }

    // Needs to be run frequently.
    // Handles either talking to threads (multi) or doing meshing (single)<commit_msg>clean up BlockMesher a little.<commit_after>﻿using DFHack;
using RemoteFortressReader;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;

// Two implementations: single and multithreaded.
// All of the actual meshing code is exactly the same;
// the only difference is in how it's called.

abstract class BlockMesher {
    // If n = 0, single threaded; else multithreaded.
    public static BlockMesher GetMesher (int nThreads) {
        if (nThreads < 0) {
            throw new System.InvalidOperationException(nThreads + " threads? What??");
        } else if (nThreads == 0) {
            return new SingleThreadedMesher();
        } else {
            return new MultiThreadedMesher(nThreads);
        }
    }

    public struct Result {
        public DFCoord location;
        public CPUMesh tiles;
        public CPUMesh stencilTiles;
        public CPUMesh transparentTiles;
        public CPUMesh topTiles;
        public CPUMesh topStencilTiles;
        public CPUMesh topTransparentTiles;
        public CPUMesh water;
        public CPUMesh magma;
        public CPUMesh collisionMesh;
    }

    protected struct Request {
        public bool tiles;
        public bool liquids;
        public MapDataStore data;
    }

    // There is REALLY NO REASON FOR THIS TO EXIST.
    // If unity was SENSIBLE we could use thread-local storage,
    // but unity is insensible, so we have to thread one of these through every method
    // that uses temporary buffers instead.
    protected struct TempBuffers {
        public void Init() {
            meshBuffer =
                new MeshCombineUtility.MeshInstance[GameMap.blockSize * GameMap.blockSize * (int)MeshLayer.StaticCutout];
            stencilMeshBuffer =
                new MeshCombineUtility.MeshInstance[GameMap.blockSize * GameMap.blockSize * ((int)MeshLayer.StaticTransparent - (int)MeshLayer.StaticCutout)];
            transparentMeshBuffer =
                new MeshCombineUtility.MeshInstance[GameMap.blockSize * GameMap.blockSize * ((int)MeshLayer.Collision - (int)MeshLayer.StaticTransparent)];
            collisionMeshBuffer =
                new MeshCombineUtility.MeshInstance[GameMap.blockSize * GameMap.blockSize * ((int)MeshLayer.Count - (int)MeshLayer.Collision)];
            heights = new float[2, 2];
        }

        public MeshCombineUtility.MeshInstance[] meshBuffer { get; private set; }
        public MeshCombineUtility.MeshInstance[] stencilMeshBuffer { get; private set; }
        public MeshCombineUtility.MeshInstance[] transparentMeshBuffer { get; private set; }
        public MeshCombineUtility.MeshInstance[] collisionMeshBuffer { get; private set; }
        public float[,] heights { get; private set; }
    }

    // Stuff for runtime configuration.
    // These will be accessed from multiple threads, but DON'T need to be
    // locked, since they don't change after being loaded.
    protected readonly Dictionary<MatPairStruct, RemoteFortressReader.MaterialDefinition> materials;

    // Some queues.
    // All of these need to be locked before access.
    // In general, NEVER LOCK MORE THAN ONE at the same time - 
    // That road leads to deadlock.
    protected readonly Util.UniqueQueue<DFCoord, Request> requestQueue; 
    protected readonly Queue<Result> resultQueue;
    protected readonly Stack<MapDataStore> recycledBlocks; // Object pool!

    protected BlockMesher() {
        // Make queues
        requestQueue = new Util.UniqueQueue<DFCoord, Request>();
        recycledBlocks = new Stack<MapDataStore>();
        resultQueue = new Queue<Result>();

        // Load materials
        materials = new Dictionary<MatPairStruct, MaterialDefinition>();
        foreach (MaterialDefinition material in DFConnection.Instance.NetMaterialList.material_list)
        {
            materials[material.mat_pair] = material;
        }
        System.GC.Collect(); //force a garbage collect after initial load.
    }

    // Needs to be run frequently.
    // Handles either talking to threads (multi) or doing meshing (single)
{'fraction_non_alphanumeric': 0.07701726460144484, 'fraction_numerical': 0.0012244398187829068, 'mean_word_length': 2.7814814814814817, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 19, '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': '6522458', 'n_tokens_mistral': 2194, 'n_tokens_neox': 2134, 'n_words': 673}