Пример #1
0
 public LoadChunkDataFromFileJob(Chunk.ID chunkID, string levelName)
 {
     this.chunkID    = chunkID;
     this.levelName  = levelName;
     solidVoxelCount = new NativeArray <int>(1, Allocator.TempJob);
     outVoxels       = new NativeArray <byte>(Chunk.Diameter * Chunk.Diameter * Chunk.Diameter, Allocator.TempJob);
 }
Пример #2
0
 public SaveChunkDataToFileJob(Chunk.ID chunkID, string levelName, NativeArray <byte> inputVoxels, int solidVoxelCount)
 {
     this.chunkID         = chunkID;
     this.levelName       = levelName;
     this.solidVoxelCount = solidVoxelCount;
     saveVoxels           = inputVoxels;
 }
Пример #3
0
        /// <summary>
        /// Schedule the job for loading new data from file
        /// </summary>
        /// <param name="chunkID"></param>
        /// <returns></returns>
        public override ApertureJobHandle getJobFor(Chunk.ID chunkID, FocusAdjustmentType adjustmentType)
        {
            IJob job;

            if (adjustmentType == FocusAdjustmentType.InFocus)
            {
                if (LevelDAO.ChunkFileExists(chunkID, level))
                {
                    job = new LevelDAO.LoadChunkDataFromFileJob(chunkID, level.name);
                    // if there's no file, we need to generate the chunk data from scratch
                }
                else
                {
                    job = BiomeMap.GetTerrainGenerationJob(chunkID, level);
                }
                /// if it's out of focus, we want to save the chunk to file
            }
            else if (level.chunks.TryGetValue(chunkID, out Chunk chunkToSave))
            {
                job = new LevelDAO.SaveChunkDataToFileJob(chunkID, level.name, chunkToSave.getVoxels(), chunkToSave.solidVoxelCount);
            }
            else
            {
                throw new System.MissingMemberException(
                          $"VoxelDataAperture is trying to save chunk data for {chunkID} but could not find the chunk data in the level"
                          );
            }

            return(new ApertureJobHandle(job, this));
        }
Пример #4
0
        /// <summary>
        /// Get the voxeldata for a chunk location from file
        /// </summary>
        /// <returns>False if the chunk is empty</returns>
        static bool GetDataForChunkFromFile(Chunk.ID chunkId, string levelName, out ChunkSaveData chunkData)
        {
            chunkData = default;
            IFormatter formatter  = new BinaryFormatter();
            Stream     readStream = new FileStream(
                GetChunkDataFileName(chunkId, levelName),
                FileMode.Open,
                FileAccess.Read,
                FileShare.Read
                )
            {
                Position = 0
            };
            var fileData = formatter.Deserialize(readStream);

            if (fileData is ChunkSaveData)
            {
                chunkData = (ChunkSaveData)fileData;
                readStream.Close();
                return(true);
            }

            readStream.Close();
            return(false);
        }
 /// <summary>
 /// If the chunk is loaded but empty, we should just drop it from this queue
 /// </summary>
 /// <param name="chunkID"></param>
 /// <returns></returns>
 internal override bool validateChunk(Chunk.ID chunkID, out Chunk chunk)
 {
     // if this is valid for meshing
     // and if the chunk is meshed and isn't empty, or just isn't meshed, it's valid for the queue.
     return(level.getApetureByPriority(Level.AperturePriority.Meshed).validateChunk(chunkID, out chunk) &&
            !(chunk != null && chunk.meshIsGenerated && chunk.meshIsEmpty));
 }
 /// <summary>
 /// Make a mesh
 /// </summary>
 public VoxelMeshData(
     Chunk.ID forChunk,
     bool meshDataIsEmpty,
     NativeArray <Vector3> vertices,
     NativeArray <int> triangles,
     NativeArray <Color> colors
     )
 {
     chunkID = forChunk;
     if (meshDataIsEmpty)
     {
         this.vertices  = null;
         this.triangles = null;
         this.colors    = null;
     }
     else
     {
         this.vertices = new Vector3[vertices.Length];
         vertices.CopyTo(this.vertices);
         this.triangles = new int[triangles.Length];
         triangles.CopyTo(this.triangles);
         this.colors = new Color[colors.Length];
         colors.CopyTo(this.colors);
     }
 }
        /// <summary>
        /// Validate the chunk for this aperture.
        /// Should it be being managed still?
        /// </summary>
        /// <param name="chunkID">The id of the chunk to validate</param>
        /// <param name="chunk">The chunk grabbed for validation, used to speed up chains/callbacks</param>
        /// <returns></returns>
        internal virtual bool validateChunk(Chunk.ID chunkID, out Chunk chunk)
        {
            if (!level.chunks.TryGetValue(chunkID, out chunk))
            {
                chunk = null;
            }

            return(true);
        }
Пример #8
0
        /// <summary>
        /// Only to be used by jobs
        /// Save a chunk to file
        /// </summary>
        /// <param name="chunkLocation"></param>
        static public void SaveChunkDataToFile(Chunk.ID chunkId, string levelName, NativeArray <byte> voxelsToSave, int solidVoxelCount)
        {
            IFormatter formatter = new BinaryFormatter();

            CheckForSaveDirectory(levelName);
            Stream stream = new FileStream(GetChunkDataFileName(chunkId, levelName), FileMode.Create, FileAccess.Write, FileShare.None);

            formatter.Serialize(stream, new ChunkSaveData(voxelsToSave, solidVoxelCount));
            stream.Close();
        }
Пример #9
0
        /// <summary>
        /// Get the distance from this chunk to the closest level focus
        /// </summary>
        /// <param name="chunkID"></param>
        /// <returns></returns>
        float getDistanceToClosestFocus(Chunk.ID chunkID, float yWeightMultiplier = 5.0f)
        {
            float closestFocusDistance = float.MaxValue;

            level.forEachFocus(focus => {
                float focusDistance  = focus.currentChunk.Coordinate.distanceYFlattened(chunkID.Coordinate, yWeightMultiplier);
                closestFocusDistance = focusDistance < closestFocusDistance ? focusDistance : closestFocusDistance;
            });

            return(closestFocusDistance);
        }
Пример #10
0
        /// <summary>
        /// if the queue item is ready to go, or should be put back in the queue
        /// </summary>
        /// <returns></returns>
        bool itemIsReady(Chunk.ID chunkID, ChunkResolutionAperture aperture)
        {
            bool isReady = aperture.chunkIsReady(chunkID);

            if (isReady)
            {
                aperture.prepareChunkJobData(chunkID);
            }

            return(isReady);
        }
Пример #11
0
 /// <summary>
 /// Get the priority object for a given chunk being loaded by the given apeture
 /// </summary>
 /// <param name="chunkID"></param>
 /// <param name="aperture"></param>
 /// <returns></returns>
 ApertureWorkQueuePriority getCurrentPriorityForChunk(
     Chunk.ID chunkID,
     ChunkResolutionAperture aperture,
     ChunkResolutionAperture.FocusAdjustmentType adjustmentType = ChunkResolutionAperture.FocusAdjustmentType.InFocus
     )
 {
     return(new ApertureWorkQueuePriority(
                aperture.priority,
                (int)getDistanceToClosestFocus(chunkID, aperture.yWeightMultiplier),
                adjustmentType
                ));
 }
        /// <summary>
        /// Schedule the activate chunk job
        /// </summary>
        /// <param name="chunkID"></param>
        /// <returns></returns>
        public override ApertureJobHandle getJobFor(Chunk.ID chunkID, FocusAdjustmentType adjustmentType)
        {
            IJob job;

            if (adjustmentType == FocusAdjustmentType.InFocus)
            {
                job = new ActivateChunkObjectJob(chunkID);
            }
            else
            {
                job = new DeactivateChunkObjectJob(chunkID);
            }


            return(new ApertureJobHandle(job, this));
        }
Пример #13
0
        /// <summary>
        /// Do things for different jobs
        /// </summary>
        /// <param name="chunkID"></param>
        /// <param name="finishedJobHandle"></param>
        protected override void handleFinishedJob(Chunk.ID chunkID, ref ApertureJobHandle finishedJobHandle)
        {
            Chunk newlyLoadedChunk = new Chunk();

            switch (finishedJobHandle.job)
            {
            /// same for both, but they're structs so can't inherit.
            case LevelDAO.LoadChunkDataFromFileJob lcdffj:
                // if we didn't generate an empty chunk, copy the voxels over.
                if (lcdffj.solidVoxelCount[0] > 0)
                {
                    newlyLoadedChunk.setVoxels(
                        lcdffj.outVoxels,
                        lcdffj.solidVoxelCount[0]
                        );
                }
                // also dispose of the native array
                lcdffj.outVoxels.Dispose(finishedJobHandle.jobHandle);
                lcdffj.solidVoxelCount.Dispose(finishedJobHandle.jobHandle);
                break;

            case BiomeMap.GenerateChunkDataFromSourceJob gcdfsj:
                if (gcdfsj.solidVoxelCount[0] > 0)
                {
                    newlyLoadedChunk.setVoxels(
                        gcdfsj.outVoxels,
                        gcdfsj.solidVoxelCount[0]
                        );
                }
                gcdfsj.outVoxels.Dispose(finishedJobHandle.jobHandle);
                gcdfsj.solidVoxelCount.Dispose(finishedJobHandle.jobHandle);
                break;

            /// once the chunk data is saved, remove it from the level
            case LevelDAO.SaveChunkDataToFileJob scdtfj:
                level.chunks.Remove(scdtfj.chunkID);
                break;

            default:
                return;
            }

            // add chunk to the level
            newlyLoadedChunk.isLoaded = true;
            level.chunks.Add(chunkID, newlyLoadedChunk);
        }
Пример #14
0
    /// <summary>
    /// Generate all the voxels for the given chunk id using the provided biome
    /// </summary>
    /// <param name="biome"></param>
    /// <param name="chunkID"></param>
    /// <param name="generatedVoxels"></param>
    /// <returns>the number of solid voxels generated</returns>
    static int GenerateTerrainDataForChunk(VoxelSource biome, Chunk.ID chunkID, out byte[] generatedVoxels) {
      int solidVoxelCount = 0;
      generatedVoxels = null;
      byte[] voxels = new byte[Chunk.Diameter * Chunk.Diameter * Chunk.Diameter];
      Coordinate chunkWorldLocation = chunkID.toWorldLocation();

      chunkWorldLocation.until(chunkWorldLocation + Chunk.Diameter, currentWorldLocation => {
        byte voxelValue = biome.getVoxelValueAt(currentWorldLocation);
        if (voxelValue != Voxel.Types.Empty.Id) {
          solidVoxelCount++;
          Coordinate localChunkVoxelLocation = currentWorldLocation - chunkWorldLocation;
          voxels[localChunkVoxelLocation.flatten(Chunk.Diameter)] = voxelValue;
        }
      });

      generatedVoxels = voxels;
      return solidVoxelCount;
    }
Пример #15
0
 /// <summary>
 /// Get the biome for the given level seed and chunk id
 /// </summary>
 /// <param name="chunkID"></param>
 /// <param name="levelSeed"></param>
 /// <returns></returns>
 static VoxelSource GetBiomeForChunk(Chunk.ID chunkID, int levelSeed) {
   return new PerlinSource(levelSeed);
 }
Пример #16
0
 /// <summary>
 /// Get the file name a chunk is saved to based on it's location
 /// </summary>
 /// <param name="chunkLocation">the location of the chunk</param>
 /// <returns></returns>
 static string GetChunkDataFileName(Chunk.ID chunk, string levelName)
 {
     return($"{GetChunkDataFolder(levelName)}{chunk.Coordinate}.evxch");
 }
Пример #17
0
 /// <summary>
 /// Get a chunk terrain generation job from the biome map
 /// </summary>
 /// <param name="chunkID"></param>
 /// <param name="level"></param>
 /// <returns></returns>
 public static GenerateChunkDataFromSourceJob GetTerrainGenerationJob(Chunk.ID chunkID, Level level) {
   return new GenerateChunkDataFromSourceJob(chunkID, level.seed);
 }
        ///// PUBLIC FUNCTIONS

        /// <summary>
        /// Create and schedule the child job for this chunk using a unity IJob
        /// </summary>
        /// <param name="chunkID"></param>
        public abstract ApertureJobHandle getJobFor(Chunk.ID chunkID, FocusAdjustmentType adjustmentType);
 public SetChunkInactiveEvent(Chunk.ID chunkID)
 {
     this.chunkID = chunkID;
     name         = $"Setting chunk active: {chunkID.Coordinate}";
 }
Пример #20
0
 /// <summary>
 /// Get a file load job
 /// </summary>
 /// <param name="chunkID"></param>
 /// <param name="level"></param>
 /// <returns></returns>
 public static LoadChunkDataFromFileJob GetFileLoadJob(Chunk.ID chunkID, Level level)
 {
     return(new LoadChunkDataFromFileJob(chunkID, level.name));
 }
Пример #21
0
 /// <summary>
 /// Check if the chunk save file exists
 /// </summary>
 /// <param name=""></param>
 /// <param name="level"></param>
 /// <returns></returns>
 public static bool ChunkFileExists(Chunk.ID chunkID, Level level)
 {
     return(File.Exists(GetChunkDataFileName(chunkID, level.name)));
 }
 /// <summary>
 /// The chunk is ready to mesh when the mesh is generated but not empty
 /// </summary>
 /// <param name="chunkID"></param>
 /// <returns></returns>
 public override bool chunkIsReady(Chunk.ID chunkID)
 {
     return(level.chunks.TryGetValue(chunkID, out Chunk chunk) &&
            chunk.meshIsGenerated &&
            !chunk.meshIsEmpty);
 }
Пример #23
0
 public GenerateChunkDataFromSourceJob(Chunk.ID chunkID, int levelSeed) {
   this.chunkID = chunkID;
   this.levelSeed = levelSeed;
   solidVoxelCount = new NativeArray<int>(1, Allocator.Persistent);
   outVoxels = new NativeArray<byte>(Chunk.Diameter * Chunk.Diameter * Chunk.Diameter, Allocator.Persistent);
 }
 /// <summary>
 /// Make a new adjustment
 /// </summary>
 /// <param name="chunkID"></param>
 /// <param name="adjustmentType"></param>
 public ApetureChunkAdjustment(Chunk.ID chunkID, FocusAdjustmentType adjustmentType = FocusAdjustmentType.InFocus)
 {
     this.chunkID = chunkID;
     type         = adjustmentType;
 }
Пример #25
0
 /// <summary>
 /// Set the previous to the current chunk the level thinks we're in, to keep it up to date
 /// </summary>
 public void onFocusUpdatedForLevel(Chunk.ID toNewChunk)
 {
     previousChunk = toNewChunk;
 }
 /// <summary>
 /// Schedule a mesh job. Can only be called from the main thread!
 /// </summary>
 /// <param name="chunkID"></param>
 /// <returns></returns>
 public override ApertureJobHandle getJobFor(Chunk.ID chunkID, FocusAdjustmentType adjustmentType) {
   IJob job;
   /// if it's an in focus job
   if (adjustmentType == FocusAdjustmentType.InFocus) {
     // get the prep'd data and send it to the job
     if (preparedVoxelData.TryGetValue(chunkID, out byte[] marchVoxelData)) {
 /// <summary>
 /// Do nothing on job complete
 /// </summary>
 /// <param name="chunkID"></param>
 /// <param name="finishedJob"></param>
 protected override void handleFinishedJob(Chunk.ID chunkID, ref ApertureJobHandle finishedJob)
 {
 }
Пример #28
0
 /// <summary>
 /// If the chunk is already loaded, we don't need to load it again
 /// </summary>
 /// <param name="chunkID"></param>
 /// <param name="chunk"></param>
 /// <returns></returns>
 internal override bool validateChunk(Chunk.ID chunkID, out Chunk chunk)
 {
     return(base.validateChunk(chunkID, out chunk) && (chunk == null || !chunk.isLoaded));
 }
Пример #29
0
 /// <summary>
 /// Set the world position of the focus. Also sets the chunk position.
 /// </summary>
 public void setPosition(Coordinate worldPosition)
 {
     transform.position = worldLocation = previousWorldLocation = worldPosition.vec3;
     currentChunk       = previousChunk = worldLocation / Chunk.Diameter;
 }
 public ActivateChunkObjectJob(Chunk.ID chunkID)
 {
     this.chunkID = chunkID;
 }