示例#1
0
        public bool DiscreteUpdate(VoxelChunk chunk)
        {
            Vector3 gridCoord = new Vector3(0, 0, 0);

            bool updateOccurred = false;

            List <int> updateList = new List <int>();
            WaterCell  cellBelow  = new WaterCell();

            int maxSize = chunk.SizeX * chunk.SizeY * chunk.SizeZ;

            for (int i = 0; i < maxSize; i++)
            {
                WaterCell cell = chunk.Data.Water[i];
                // Don't check empty cells or cells we've already modified.
                if (cell.WaterLevel < 1 || chunk.Data.Types[i] != 0)
                {
                    continue;
                }
                updateList.Add(i);
            }

            if (updateList.Count == 0)
            {
                return(false);
            }
            Voxel voxBelow = chunk.MakeVoxel(0, 0, 0);

            List <int> indices = Datastructures.RandomIndices(updateList.Count);

            // Loop through each cell.
            foreach (int t in indices)
            {
                int idx = updateList[indices[t]];


                // Don't check empty cells or cells we've already modified.
                if (chunk.Data.Water[idx].Type == LiquidType.None || chunk.Data.Types[idx] != 0)
                {
                    continue;
                }

                gridCoord = chunk.Data.CoordsAt(idx);
                int     x        = (int)gridCoord.X;
                int     y        = (int)gridCoord.Y;
                int     z        = (int)gridCoord.Z;
                Vector3 worldPos = gridCoord + chunk.Origin;

                if (chunk.Data.Water[idx].WaterLevel <= EvaporationLevel && MathFunctions.RandEvent(0.01f))
                {
                    if (chunk.Data.Water[idx].WaterLevel > 1)
                    {
                        chunk.Data.Water[idx].WaterLevel--;
                    }
                    else
                    {
                        chunk.Data.Water[idx].WaterLevel = 0;

                        if (chunk.Data.Water[idx].Type == LiquidType.Lava)
                        {
                            chunk.Data.Types[idx]           = (byte)VoxelLibrary.GetVoxelType("Stone").ID;
                            chunk.Data.Health[idx]          = (byte)VoxelLibrary.GetVoxelType("Stone").StartingHealth;
                            chunk.ShouldRebuild             = true;
                            chunk.ShouldRecalculateLighting = true;
                        }
                        chunk.Data.Water[idx].Type = LiquidType.None;
                    }
                    updateOccurred = true;
                }



                bool shouldFall = false;


                // Now check the cell immediately below this one.
                // There are two cases, either we are at the bottom of the chunk,
                // in which case we must find the water from the chunk manager.
                // Otherwise, we just get the cell immediately beneath us.
                if (y > 0)
                {
                    voxBelow.GridPosition = new Vector3(x, y - 1, z);
                    if (voxBelow.IsEmpty)
                    {
                        cellBelow  = voxBelow.Water;
                        shouldFall = true;
                    }
                }

                /*
                 * else
                 * {
                 * if(chunk.Manager.ChunkData.DoesWaterCellExist(worldPos))
                 * {
                 *  Voxel voxelsBelow = chunk.Manager.ChunkData.GetVoxel(chunk, worldPos + new Vector3(0, -1, 0));
                 *
                 *  if(voxelsBelow != null && voxelsBelow.IsEmpty)
                 *  {
                 *      cellBelow = chunk.Manager.ChunkData.GetWaterCellAtLocation(worldPos + new Vector3(0, -1, 0));
                 *      shouldFall = true;
                 *      cellBelow.IsFalling = true;
                 *  }
                 * }
                 * }
                 */

                // Cases where the fluid can fall down.
                if (shouldFall)
                {
                    // If the cell immediately below us is empty,
                    // swap the contents and move on.
                    if (cellBelow.WaterLevel < 1)
                    {
                        CreateSplash(worldPos, chunk.Data.Water[idx].Type);
                        cellBelow.WaterLevel = chunk.Data.Water[idx].WaterLevel;
                        if (cellBelow.Type == LiquidType.None)
                        {
                            cellBelow.Type = chunk.Data.Water[idx].Type;
                        }
                        chunk.Data.Water[idx].WaterLevel = 0;
                        chunk.Data.Water[idx].Type       = LiquidType.None;
                        voxBelow.Water = cellBelow;
                        CreateTransfer(worldPos, chunk.Data.Water[idx], cellBelow, cellBelow.WaterLevel);
                        updateOccurred = true;

                        continue;
                    }
                    // Otherwise, fill as much of the space as we can.
                    else
                    {
                        byte spaceLeft = (byte)(8 - cellBelow.WaterLevel);


                        // Special case where we can flow completely into the next cell.
                        if (spaceLeft >= chunk.Data.Water[idx].WaterLevel)
                        {
                            byte transfer = chunk.Data.Water[idx].WaterLevel;
                            cellBelow.WaterLevel += transfer;
                            if (cellBelow.Type == LiquidType.None)
                            {
                                cellBelow.Type = chunk.Data.Water[idx].Type;
                            }
                            chunk.Data.Water[idx].WaterLevel = 0;
                            chunk.Data.Water[idx].Type       = LiquidType.None;

                            CreateTransfer(worldPos - Vector3.UnitY, chunk.Data.Water[idx], cellBelow, transfer);
                            voxBelow.Water = cellBelow;
                            updateOccurred = true;
                            continue;
                        }
                        // Otherwise, only flow a little bit, and spread later.
                        else
                        {
                            chunk.Data.Water[idx].WaterLevel -= spaceLeft;
                            cellBelow.WaterLevel             += spaceLeft;
                            if (cellBelow.Type == LiquidType.None)
                            {
                                cellBelow.Type = chunk.Data.Water[idx].Type;
                            }
                            CreateTransfer(worldPos - Vector3.UnitY, chunk.Data.Water[idx], cellBelow, spaceLeft);
                            voxBelow.Water = cellBelow;
                        }
                    }
                }

                // Now the only fluid left can spread.
                // We spread to the manhattan neighbors
                //Array.Sort(m_spreadNeighbors, (a, b) => CompareFlowVectors(a, b, chunk.Data.Water[idx].FluidFlow));
                m_spreadNeighbors.Shuffle();
                Voxel neighbor = new Voxel();
                foreach (Vector3 spread in m_spreadNeighbors)
                {
                    bool success = chunk.Manager.ChunkData.GetVoxel(chunk, worldPos + spread, ref neighbor);

                    if (!success)
                    {
                        continue;
                    }

                    if (!neighbor.IsEmpty)
                    {
                        continue;
                    }

                    WaterCell neighborWater = neighbor.Water;

                    if (neighborWater.WaterLevel >= chunk.Data.Water[idx].WaterLevel)
                    {
                        continue;
                    }

                    byte amountToMove = (byte)(Math.Min(8.0f - (float)neighborWater.WaterLevel, chunk.Data.Water[idx].WaterLevel) * GetSpreadRate(chunk.Data.Water[idx].Type));

                    if (amountToMove == 0)
                    {
                        continue;
                    }


                    if (neighborWater.WaterLevel < 2)
                    {
                        updateOccurred = true;
                    }

                    CreateTransfer(worldPos + spread, chunk.Data.Water[idx], neighborWater, amountToMove);

                    chunk.Data.Water[idx].WaterLevel -= amountToMove;
                    neighborWater.WaterLevel         += amountToMove;

                    if (neighborWater.Type == LiquidType.None)
                    {
                        neighborWater.Type = chunk.Data.Water[idx].Type;
                    }

                    neighbor.Water = neighborWater;

                    if (chunk.Data.Water[idx].WaterLevel >= 1)
                    {
                        continue;
                    }

                    chunk.Data.Water[idx].WaterLevel = 0;
                    chunk.Data.Water[idx].Type       = LiquidType.None;
                    break;
                }
            }

            return(updateOccurred);
        }