예제 #1
0
        public void FillDataFromChunk(VoxelChunk chunk)
        {
            VoxelChunk.VoxelData data = chunk.Data;
            for (int x = 0; x < Size.X; x++)
            {
                for (int y = 0; y < Size.Y; y++)
                {
                    for (int z = 0; z < Size.Z; z++)
                    {
                        int       index = data.IndexAt(x, y, z);
                        WaterCell water = data.Water[index];
                        Types[x, y, z]    = data.Types[index];
                        Explored[x, y, z] = data.IsExplored[index];

                        if (water.WaterLevel > 0)
                        {
                            Liquid[x, y, z]      = water.WaterLevel;
                            LiquidTypes[x, y, z] = (byte)water.Type;
                        }
                        else
                        {
                            Liquid[x, y, z]      = 0;
                            LiquidTypes[x, y, z] = 0;
                        }
                    }
                }
            }
        }
예제 #2
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;

            VoxelChunk.VoxelData data = chunk.Data;
            for (int i = 0; i < maxSize; i++)
            {
                WaterCell cell = data.Water[i];
                // Don't check empty cells or cells we've already modified.
                if (cell.WaterLevel < 1 || 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 (data.Water[idx].Type == LiquidType.None || data.Types[idx] != 0)
                {
                    continue;
                }

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

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

                        if (data.Water[idx].Type == LiquidType.Lava)
                        {
                            data.Types[idx]                 = (byte)VoxelLibrary.GetVoxelType("Stone").ID;
                            data.Health[idx]                = (byte)VoxelLibrary.GetVoxelType("Stone").StartingHealth;
                            chunk.ShouldRebuild             = true;
                            chunk.ShouldRecalculateLighting = true;
                        }
                        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;
                    }
                }

                /*  This is commented out as Chunks take up the full vertical space.  This needs to be added/fixed if the chunks take up less space.
                 * 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, data.Water[idx].Type);
                        cellBelow.WaterLevel = data.Water[idx].WaterLevel;
                        if (cellBelow.Type == LiquidType.None)
                        {
                            cellBelow.Type = data.Water[idx].Type;
                        }
                        data.Water[idx].WaterLevel = 0;
                        data.Water[idx].Type       = LiquidType.None;
                        voxBelow.Water             = cellBelow;
                        CreateTransfer(worldPos, data.Water[idx], cellBelow, cellBelow.WaterLevel);
                        updateOccurred = true;

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

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

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

                    byte amountToMove = (byte)(Math.Min(maxWaterLevel - neighborWater.WaterLevel, data.Water[idx].WaterLevel) * GetSpreadRate(data.Water[idx].Type));

                    if (amountToMove == 0)
                    {
                        continue;
                    }


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

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

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

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

                    neighbor.Water = neighborWater;

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

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

            return(updateOccurred);
        }