public void TryRemoveComponents(WorldApi worldApi, List <FluidComponent> components, bool rebuildEnabled)
        {
            UnityEngine.Profiling.Profiler.BeginSample("TryRemoveComponents");

            for (int i = 0; i < components.Count; i++)
            {
                FluidComponent component = components[i];

                component.UpdateLifetime(RealtimeSinceStartup);

                // cleanup components marked for rebuild
                if (rebuildEnabled && component.ToRebuild)
                {
                    component.Unsettle(component.Count * component.Viscosity);
                    component.Cleanup(worldApi);
                }

                // remove small and old components
                if (component.ToRemove)
                {
                    component.Cleanup(worldApi);
                    component.UpdateJob.ToRemove = true;
                    components.RemoveAtViaEndSwap(i--);
                }
            }

            UnityEngine.Profiling.Profiler.EndSample();
        }
        /// <summary>
        /// Initializes array of blocks and the neighbour references in blocks and chunks.
        /// </summary>
        public void Initialize()
        {
            _worldApi = GetComponent <WorldApi>();

            // initialize arrays
            _blocks = new Block[_worldApi.SizeX * _worldApi.SizeY * _worldApi.SizeZ];

            _worldApi.Initialize(_blocks);

            for (int blockX = 0; blockX < _worldApi.SizeX; blockX++)
            {
                for (int blockY = 0; blockY < _worldApi.SizeY; blockY++)
                {
                    for (int blockZ = 0; blockZ < _worldApi.SizeZ; blockZ++)
                    {
                        int blockId = blockX * _worldApi.SizeZ * _worldApi.SizeY + blockY * _worldApi.SizeZ + blockZ;

                        VectorI3 coords = new VectorI3(blockX, blockY, blockZ);

                        Block block = new GameObject($"Block ({blockX}, {blockY}, {blockZ})").AddComponent <Block>();
                        _blocks[blockId] = block;

                        block.Initialize(blockId, transform, _worldApi, coords);
                    }
                }
            }

            InitializeBlockReferences();

            for (int blockId = 0; blockId < _blocks.Length; blockId++)
            {
                _blocks[blockId].InitializeChunkReferences();
            }
        }
示例#3
0
        /// <summary>
        /// Traverses the 2 top rows of component and validates them.
        /// Removes/shortens segments containing invalid voxels and adds eligible voxels to outlets.
        /// </summary>
        private void UpdateSegments(WorldApi worldApi, Dictionary <Vector2, List <FluidSegment> > allSegments, HashSet <VectorI3> outlets, ref int componentCount, ref float componentWaterLevel)
        {
            UnityEngine.Profiling.Profiler.BeginSample("UpdateSegments");

            foreach (var segments in allSegments)
            {
                Vector2 row = segments.Key;

                // skip deep y segments
                if (row.y < componentWaterLevel - 2 * WorldGridInfo.kVoxelSize)
                {
                    continue;
                }

                bool allValid = ValidateSegmentRow(worldApi, in row, segments.Value, outlets, ref componentCount);

                // grow water level to the highest valid segment row if there are no outlets
                if (componentWaterLevel < row.y && allValid && outlets?.Count == 0)
                {
                    componentWaterLevel = row.y;
                }

                if (segments.Value.Count == 0)
                {
                    _helperDictKeysList.Add(row);
                }
            }

            allSegments.RemoveRange(in _helperDictKeysList);
            _helperDictKeysList.Clear();

            UnityEngine.Profiling.Profiler.EndSample();
        }
        public void CreateData(FluidComponentManager manager, WorldApi worldApi)
        {
            _helperIndicesList = new NativeList <VectorI3>(Unity.Collections.Allocator.Persistent);

            _worldApiPointer = GCHandle.Alloc(worldApi, GCHandleType.Pinned);
            _managerPointer  = GCHandle.Alloc(manager, GCHandleType.Pinned);
        }
        public void Execute()
        {
            WorldApi worldApi             = (WorldApi)_worldApiPointer.Target;
            FluidComponentManager manager = (FluidComponentManager)_managerPointer.Target;

            TryCreateComponents(worldApi, manager);
            TryRemoveComponents(worldApi, manager.Components, manager.RebuildEnabled);
        }
        public FluidComponentManager(WorldApi worldApi)
        {
            _worldApi = worldApi;

            MaintenanceJob.CreateData(this, _worldApi);

            Components                 = new List <FluidComponent>();
            VoxelsToProcess            = new HashSet <VectorI3>();
            _componentsWithJobsRunning = new List <FluidComponent>();
        }
示例#7
0
        public void Initialize(int id, Transform parent, WorldApi worldApi, Block block)
        {
            Id = id;
            transform.parent = parent;
            Block            = block;

            worldApi.GetChunkWorldPos(block.Id, Id, out Vector3 worldPos);
            WorldPos = worldPos;

            RenderData = new ChunkRenderData(this);
        }
示例#8
0
        public void CreateData(WorldApi worldApi, FluidComponentManager manager, FluidComponent component)
        {
            IsRunning = true;
            ToRemove  = false;

            _helperIndicesList  = new NativeList <VectorI3>(Unity.Collections.Allocator.Persistent);
            _helperDictKeysList = new NativeList <Vector2>(Unity.Collections.Allocator.Persistent);

            _componentPointer = GCHandle.Alloc(component, GCHandleType.Pinned);
            _worldApiPointer  = GCHandle.Alloc(worldApi, GCHandleType.Pinned);
            _managerPointer   = GCHandle.Alloc(manager, GCHandleType.Pinned);
        }
        /// <summary>
        /// Initialize array of voxels and chunks.
        /// </summary>
        public void Initialize(int id, Transform parent, WorldApi worldApi, VectorI3 coords)
        {
            Id = id;
            transform.parent = parent;
            Coords           = coords;

            worldApi.GetBlockWorldPos(id, out Vector3 worldPos);
            WorldPos = worldPos;

            Chunks  = new Chunk[WorldGridInfo.kTotalChunksInBlock];
            _voxels = new NativeArray <Voxel>(WorldGridInfo.kTotalVoxelsInBlock, Unity.Collections.Allocator.Persistent);

            SimData            = new FluidBlockSimData(this);
            SimData.ReadVoxels = _voxels;

            for (int chunkX = 0; chunkX < WorldGridInfo.kChunksPerBlock; chunkX++)
            {
                for (int chunkY = 0; chunkY < WorldGridInfo.kChunksPerBlock; chunkY++)
                {
                    for (int chunkZ = 0; chunkZ < WorldGridInfo.kChunksPerBlock; chunkZ++)
                    {
                        int chunkId = chunkX * WorldGridInfo.kChunksPerBlock * WorldGridInfo.kChunksPerBlock + chunkY * WorldGridInfo.kChunksPerBlock + chunkZ;

                        Chunk chunk = new GameObject($"Chunk ({chunkX}, {chunkY}, {chunkZ})").AddComponent <Chunk>();
                        Chunks[chunkId] = chunk;

                        chunk.Initialize(chunkId, transform, worldApi, this);

                        for (int voxelX = 0; voxelX < WorldGridInfo.kVoxelsPerChunk; voxelX++)
                        {
                            for (int voxelY = 0; voxelY < WorldGridInfo.kVoxelsPerChunk; voxelY++)
                            {
                                for (int voxelZ = 0; voxelZ < WorldGridInfo.kVoxelsPerChunk; voxelZ++)
                                {
                                    int voxelId = voxelX * WorldGridInfo.kVoxelsPerChunk * WorldGridInfo.kVoxelsPerChunk + voxelY * WorldGridInfo.kVoxelsPerChunk + voxelZ;

                                    _voxels.GetWritable(chunkId, voxelId).Valid = true;
                                }
                            }
                        }
                    }
                }
            }
        }
        public void TryCreateComponents(WorldApi worldApi, FluidComponentManager manager)
        {
            UnityEngine.Profiling.Profiler.BeginSample("TryCreateComponents");

            // first try to add voxel to a nearby existing component because creating a new one is expensive
            int processed = 0;

            foreach (VectorI3 indices in manager.VoxelsToProcess)
            {
                if (TryAddToExistingComponent(worldApi, manager, in indices))
                {
                    _helperIndicesList.Add(indices);
                }

                if (processed++ > FluidComponentManager.kMaxVoxelsProcessedPerIteration)
                {
                    break;
                }
            }

            manager.VoxelsToProcess.RemoveRange(_helperIndicesList);
            _helperIndicesList.Clear();

            // no nearby existing component found
            if (manager.VoxelsToProcess.Count > FluidComponentManager.kMinComponentSize)
            {
                // try to create a single new component
                foreach (VectorI3 indices in manager.VoxelsToProcess)
                {
                    if (TryCreateNewComponent(worldApi, manager, in indices))
                    {
                        manager.VoxelsToProcess.Remove(indices);
                    }

                    break;
                }
            }

            UnityEngine.Profiling.Profiler.EndSample();
        }
示例#11
0
        // TODO speedup
        /// <summary>
        /// Validates the existing segments and updates / equalizes the outlets of this component.
        /// </summary>
        public void Execute()
        {
            UnityEngine.Profiling.Profiler.BeginSample("Update");

            FluidComponent        component = (FluidComponent)_componentPointer.Target;
            WorldApi              worldApi  = (WorldApi)_worldApiPointer.Target;
            FluidComponentManager manager   = (FluidComponentManager)_managerPointer.Target;

            int diff = component.Count;

            if (component.Viscosity > FluidComponentManager.kMaxViscosityNotEqualize && component.Outlets == null)
            {
                component.Outlets = new HashSet <VectorI3>();
            }

            UpdateSegments(worldApi, component.AllSegments, component.Outlets, ref component.Count, ref component.WaterLevel);

            diff -= component.Count;

            if (diff != 0)
            {
                component.Unsettle(diff * component.Viscosity);
            }
            else
            {
                component.DecreaseSettle();
            }

            if (component.Viscosity > FluidComponentManager.kMaxViscosityNotEqualize && component.Outlets.Count > 0)
            {
                UpdateOutlets(worldApi, component.Outlets, component.Rebuilding, component.Lifetime, ref component.WaterLevel);

                EqualizeOutlets(true, worldApi, component.Outlets, component.Viscosity);
                EqualizeOutlets(false, worldApi, component.Outlets, component.Viscosity);
            }

            UnityEngine.Profiling.Profiler.EndSample();
        }
 /// <summary>
 /// Try to create a new component out of given voxel indices.
 /// </summary>
 private bool TryCreateNewComponent(WorldApi worldApi, FluidComponentManager manager, in VectorI3 indices)
示例#13
0
 /// <summary>
 /// Traverses each segment in the row voxel by voxel and adds outlets from valid ones or removes the invalid ones.
 /// </summary>
 private bool ValidateSegmentRow(WorldApi worldApi, in Vector2 row, List <FluidSegment> segments, HashSet <VectorI3> outlets, ref int componentCount)