Example #1
0
            /// <summary>
            /// remove empty chunks that have loaded from the mesh gen queue
            /// </summary>
            /// <param name="chunkLocation"></param>
            /// <returns></returns>
            protected override bool isAValidQueueItem(Coordinate chunkLocation)
            {
                IVoxelChunk chunk = level.getChunk(chunkLocation);

                // the chunk can't be loaded and empty, and it doesn't already have a loaded mesh.
                return(!(chunk.isLoaded && chunk.isEmpty));
            }
        /// <summary>
        /// Get the chunk at the given location (if it's loaded)
        /// </summary>
        /// <param name="chunkLocation">the location of the chunk to grab</param>
        /// <param name="withMeshes">get the chunk with it's mesh</param>
        /// <param name="withNeighbors">get the chunk with neighbors linked</param>
        /// <returns>the chunk data or null if there's none loaded</returns>
        public IVoxelChunk getChunk(Coordinate chunkLocation, bool withMeshes = false, bool withNeighbors = false, bool withNeighborsNeighbors = false, bool fullNeighborEncasement = false)
        {
            // just get an empty chunk for this one if this is out of bounds
            if (!chunkLocation.isWithin(Coordinate.Zero, chunkBounds))
            {
                return(Chunk.GetEmptyChunk(chunkLocation, withNeighbors));
            }

            IVoxelStorage voxels = chunkDataStorage.getChunkVoxelData(chunkLocation);

            IVoxelChunk[] neighbors = null;

            if (withNeighbors)
            {
                neighbors = new IVoxelChunk[Directions.All.Length];
                foreach (Directions.Direction direction in Directions.All)
                {
                    Coordinate neighborLocation = chunkLocation + direction.Offset;
                    neighbors[direction.Value] = getChunk(neighborLocation, withMeshes, withNeighborsNeighbors, fullNeighborEncasement);
                }
            }

            return(new Chunk(
                       chunkLocation,
                       voxels,
                       neighbors,
                       withMeshes ? chunkDataStorage.getChunkMesh(chunkLocation) : null
                       ));
        }
Example #3
0
            /// <summary>
            /// remove empty chunks that have loaded from the mesh gen queue
            /// </summary>
            /// <param name="chunkLocation"></param>
            /// <returns></returns>
            protected override bool isAValidQueueItem(Coordinate chunkLocation)
            {
                if (!chunkManager.isWithinManagedBounds(chunkLocation))
                {
                    return(false);
                }

                IVoxelChunk chunk = chunkManager.level.getChunk(chunkLocation, true);

                // the chunk can't be loaded and empty, or meshed with an empty mesh.
                if ((chunk.isLoaded && chunk.isEmpty) || (chunk.isMeshed && chunk.mesh.isEmpty))
                {
                    return(false);
                }

                /// in this case, we want to make sure the mesh job didn't drop or loose our chunk
                // @TODO: cull this better, instead of isfull, maybe use a system to determine if it's visible to a player or not,
                // this notification should only be sent if a chunk needs to be rendered badly because it's missing.
                if (chunk.isLoaded && !chunk.isMeshed && !chunk.isEmpty && !chunk.isFull)
                {
                    new Thread(() => {
                        World.EventSystem.notifyChannelOf(
                            new ChunkWaitingForActiveMissingMeshEvent(chunkLocation),
                            Evix.EventSystems.WorldEventSystem.Channels.ChunkActivationUpdates
                            );
                    })
                    {
                        Name = "Missing Mesh Messenger"
                    }.Start();
                }

                return(true);
            }
                /// <summary>
                /// Threaded function, loads all the voxel data for this chunk
                /// </summary>
                protected override void doWork(Coordinate chunkLocation)
                {
                    IVoxelChunk chunk = jobManager.chunkManager.level.getChunk(chunkLocation);

                    if (chunk.isEmpty && !chunk.isLoaded)
                    {
                        VoxelStorageType voxelData = jobManager.chunkManager.getVoxelDataForChunkFromFile(chunkLocation);
                        jobManager.chunkManager.level.chunkDataStorage.setChunkVoxelData(chunkLocation, voxelData);
                    }
                }
        /// <summary>
        /// Generate the mesh for the voxeldata at the given chunk location
        /// </summary>
        /// <param name="chunkLocation"></param>
        /// <returns></returns>
        internal IMesh generateMeshDataForChunk(Coordinate chunkLocation)
        {
            IVoxelChunk chunk = level.getChunk(chunkLocation, false, true, true, true);

            if (!chunk.isEmpty)
            {
                return(level.meshGenerator.generateMesh(chunk));
            }

            return(new Mesh());
        }
                /// <summary>
                /// Threaded function, loads all the voxel data for this chunk
                /// </summary>
                protected override void doWork(Coordinate chunkLocation)
                {
                    // if the chunk is empty, lets try to fill it.
                    IVoxelChunk chunk = jobManager.chunkManager.level.getChunk(chunkLocation);

                    if (chunk.isEmpty && !chunk.isLoaded)
                    {
                        IVoxelStorage voxelData = jobManager.chunkManager.generateVoxelDataForChunk(chunkLocation);
                        jobManager.chunkManager.level.chunkDataStorage.setChunkVoxelData(chunkLocation, voxelData);
                    }
                }
        /// <summary>
        /// deactivate and free up this object for use again by the level controller
        /// </summary>
        public void deactivateAndClear()
        {
            gameObject.SetActive(false);
            currentChunkMesh = new UnityEngine.Mesh();
            currentChunkMesh.Clear();

            currentChunk         = null;
            chunkLocation        = default;
            colliderBakerHandler = default;
            isMeshed             = false;
            isActive             = false;
        }
Example #8
0
                /// <summary>
                /// generate the chunk mesh if the level doesn't have it yet.
                /// </summary>
                protected override void doWork(Coordinate chunkLocation)
                {
                    IVoxelChunk chunk = jobManager.chunkManager.level.getChunk(chunkLocation, true);

                    if (chunk.isMeshed && !chunk.mesh.isEmpty)
                    {
                        World.EventSystem.notifyChannelOf(
                            new SetChunkObjectActiveEvent(chunkLocation),
                            Evix.EventSystems.WorldEventSystem.Channels.ChunkActivationUpdates
                            );
                    }
                }
        /// <summary>
        /// Only to be used by jobs
        /// Save a chunk to file
        /// </summary>
        /// <param name="chunkLocation"></param>
        internal void saveChunkDataToFile(Coordinate chunkLocation)
        {
            IVoxelChunk chunkData = level.getChunk(chunkLocation);

            if (!chunkData.isEmpty)
            {
                IFormatter formatter = new BinaryFormatter();
                checkForSaveDirectory();
                Stream stream = new FileStream(getChunkFileName(chunkLocation), FileMode.Create, FileAccess.Write, FileShare.None);
                formatter.Serialize(stream, chunkData.voxels);
                stream.Close();
            }
        }
Example #10
0
        /// <summary>
        /// Set the chunk to render. Returns true if the data was set up
        /// </summary>
        /// <param name="chunk"></param>
        /// <param name="chunkLevelLocation"></param>
        public bool setChunkToRender(IVoxelChunk chunk, Vector3 chunkLevelLocation)
        {
            if (chunk.isLoaded && chunk.mesh != null && !chunk.isEmpty)
            {
                currentChunk = chunk;
                if (chunkLevelLocation.Equals(new Vector3(42, 1, 55)))
                {
                    Debug.Log("test");
                }
                chunkLocation = chunkLevelLocation;
                isMeshed      = false;

                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Get notifications from other observers, EX:
        ///   block breaking and placing
        ///   player chunk location changes
        /// </summary>
        /// <param name="event">The event to notify this observer of</param>
        /// <param name="origin">(optional) the source of the event</param>
        public void notifyOf(IEvent @event, IObserver origin = null)
        {
            // ignore events if we have no level to control
            if (!isLoaded || level == null)
            {
                return;
            }

            switch (@event)
            {
            // when a player spawns in the level
            case Player.SpawnEvent pse:
                level.initializeAround(pse.spawnLocation.toChunkLocation());
                break;

            // When the player moves to a new chunk, adjust the loaded level focus
            case Player.ChangeChunkLocationEvent pccle:
                level.adjustFocusTo(pccle.newChunkLocation);
                break;

            // when the level finishes loading a chunk's mesh. Render it in world
            case Level <VoxelDictionary> .ChunkMeshGenerationFinishedEvent lcmgfe:
                UnityChunkController unusedChunkController = getUnusedChunkController();
                if (unusedChunkController == null)
                {
                    Debug.LogError($"No free chunk controller found for {lcmgfe.chunkLocation.ToString()}");
                }
                else
                {
                    IVoxelChunk chunk = level.getChunk(lcmgfe.chunkLocation, true);
                    if (unusedChunkController.setChunkToRender(chunk, lcmgfe.chunkLocation.vec3))
                    {
                        chunkControllerActivationQueue.Enqueue(unusedChunkController);
                    }
                }
                break;

            case Level <VoxelDictionary> .ChunkDataLoadingFinishedEvent lcdlfe:
                loadedChunkLocations.Add(lcdlfe.chunkLocation.vec3);
                break;

            // ignore other events
            default:
                return;
            }
        }
            /// <summary>
            /// remove empty chunks that have loaded from the mesh gen queue
            /// </summary>
            /// <param name="chunkLocation"></param>
            /// <returns></returns>
            protected override bool isAValidQueueItem(Coordinate chunkLocation)
            {
                if (!chunkManager.isWithinManagedBounds(chunkLocation))
                {
                    //World.Debugger.log($"{threadName} dropped {chunkLocation} due to it being out of bounds");
                    return(false);
                }

                IVoxelChunk chunk = chunkManager.level.getChunk(chunkLocation);

                // the chunk can't be loaded and empty, we'll generate nothing.
                if (chunk.isLoaded && chunk.isEmpty)
                {
                    //World.Debugger.log($"{threadName} dropped {chunkLocation} due to it being loaded and empty");
                    return(false);
                }

                return(true);
            }
Example #13
0
        /// <summary>
        /// Get notifications from other observers, EX:
        ///   block breaking and placing
        ///   player chunk location changes
        /// </summary>
        /// <param name="event">The event to notify this observer of</param>
        /// <param name="origin">(optional) the source of the event</param>
        public void notifyOf(IEvent @event, IObserver origin = null)
        {
            // ignore events if we have no level to control
            if (!isLoaded || level == null)
            {
                return;
            }

            switch (@event)
            {
            // when a chunk mesh comes into focus, or loads, set the mesh to a chunkManager
            case LoadedChunkMeshDataResolutionAperture.ChunkMeshLoadingFinishedEvent cmfle:
                IVoxelChunk chunk = level.getChunk(cmfle.chunkLocation, true);
                if (!tryToAssignNewlyMeshedChunkToController(chunk))
                {
                    chunksWaitingForAFreeController.Add(chunk);
                    newChunkCount++;
                }
                break;

            // when the level finishes loading a chunk's mesh. Render it in world
            case ActivateGameobjectResolutionAperture.SetChunkObjectActiveEvent scoae:
                newlyActivatedChunks.Add(scoae.chunkLocation);
                newlyActivatedChunksCount++;
                break;

            case ActivateGameobjectResolutionAperture.SetChunkObjectInactiveEvent scoie:
                newlyDeactivatedChunks.Add(scoie.chunkLocation);
                newlyDeactivatedChunksCount++;
                break;

            case LoadedChunkMeshDataResolutionAperture.ChunkMeshMovedOutOfFocusEvent smmoof:
                if (tryToGetAssignedChunkController(smmoof.chunkLocation, out ChunkController assignedChunkController))
                {
                    chunksWithOutOfFocusMeshes.Add(assignedChunkController);
                    outOfFocusMeshesCount++;
                }
                break;

            default:
                return;
            }
        }
Example #14
0
        ///// SUB FUNCTIONS

        /// <summary>
        /// Try to assign a chunk to an unused controller.
        /// </summary>
        /// <param name="chunkLocation"></param>
        /// <returns>A bool for being used in Removeall, if the chunk should be removed from the wait queue.</returns>
        bool tryToAssignNewlyMeshedChunkToController(IVoxelChunk chunk)
        {
            if (chunk.isLoaded && chunk.isMeshed && !chunk.isEmpty && !chunk.mesh.isEmpty)
            {
                // try to find an unused chunk controller and add it to the queue if it's valid
                if (getUnusedChunkController(chunk.location.vec3, out ChunkController unusedChunkController))
                {
                    unusedChunkController.setChunkToRender(chunk);
                    chunksWithNewlyGeneratedMeshes.Add(unusedChunkController);
                    newlyGeneratedMeshesCount++;
                    return(true);
                    // don't drop it yet, we didn't find a chunk controller.
                }
                else
                {
                    return(false);
                }
                // if the chunk isn't meshable, just drop it from the queue
            }
            else
            {
                return(true);
            }
        }
        ///// PUBLIC FUNCTIONS

        /// <summary>
        /// Set the chunk to render. Returns true if the data was set up
        /// </summary>
        /// <param name="chunk"></param>
        /// <param name="chunkLevelLocation"></param>
        public void setChunkToRender(IVoxelChunk chunk)
        {
            currentChunk  = chunk;
            chunkLocation = chunk.location.vec3;
            isMeshed      = false;
        }
Example #16
0
            /// <summary>
            /// Don't activate the chunk until a mesh is loaded for the loaded chunk
            /// </summary>
            /// <param name="queueItem"></param>
            /// <returns></returns>
            protected override bool itemIsReady(Coordinate chunkLocation)
            {
                IVoxelChunk chunk = chunkManager.level.getChunk(chunkLocation, true);

                return(chunk.isLoaded && chunk.isMeshed && !chunk.mesh.isEmpty);
            }
            /// <summary>
            /// If the chunk never finished loading, we should not save it
            /// </summary>
            /// <param name="chunkLocation"></param>
            /// <returns></returns>
            protected override bool isAValidQueueItem(Coordinate chunkLocation)
            {
                IVoxelChunk chunk = chunkManager.level.getChunk(chunkLocation);

                return(chunk.isLoaded);
            }
            /// <summary>
            /// Don't generate a mesh until a chunk's data is loaded
            /// </summary>
            /// <param name="queueItem"></param>
            /// <returns></returns>
            protected override bool itemIsReady(Coordinate chunkLocation)
            {
                IVoxelChunk chunk = chunkManager.level.getChunk(chunkLocation, false, true, true, true);

                return(chunk.isLoaded && chunk.neighborsNeighborsAreLoaded);
            }