IEnumerator UpdateFluid()
    {
        while (fluidQueue.Count != 0)
        {
            (int index, float density) = fluidQueue.Dequeue();

            if (TileUtil.BoundaryCheck(index, mapSize))
            {
                waterDensities[index] = density;
            }
        }

        nativeIndices.Clear();
        nativeTiles.CopyFrom(tiles);
        nativeWaterDensities.CopyFrom(waterDensities);

        for (int i = 0; i < nativeIsSolid.Length; i++)
        {
            nativeIsSolid[i] = tileInformations[i].isSolid;
        }

        InitDiffJob initJob = new InitDiffJob
        {
            waterDiff = nativeWaterDiff
        };

        initJob.Schedule(nativeWaterDiff.Length, 32).Complete();

        InitDirtyJob dirtyJob = new InitDirtyJob
        {
            waterChunkDirty = nativeWaterChunkDirty
        };

        dirtyJob.Schedule(nativeWaterChunkDirty.Length, 32).Complete();
        yield return(null);

        CalculateFluidJob fluidJob = new CalculateFluidJob
        {
            mapSize         = mapSize,
            chunkSize       = chunkSize,
            numChunks       = numChunks,
            maxFlow         = maxFlow,
            minFlow         = minFlow,
            minDensity      = minDensity,
            maxDensity      = maxDensity,
            maxCompress     = maxCompress,
            flowSpeed       = currentFlowSpeed,
            tiles           = nativeTiles,
            waterDensities  = nativeWaterDensities,
            waterDiff       = nativeWaterDiff,
            isSolid         = nativeIsSolid,
            waterChunkDirty = nativeWaterChunkDirty
        };

        fluidJob.Schedule(tiles.Length, 32).Complete();
        yield return(null);

        ApplyFluidJob applyFluidJob = new ApplyFluidJob
        {
            minDensity     = minDensity,
            waterDensities = nativeWaterDensities,
            waterDiff      = nativeWaterDiff
        };

        applyFluidJob.Schedule(waterDensities.Length, 32).Complete();

        nativeWaterDensities.CopyTo(waterDensities);
        yield return(null);

        FilterRemoveFluidJob filterRemoveFluidJob = new FilterRemoveFluidJob
        {
            tiles          = nativeTiles,
            isSolid        = nativeIsSolid,
            minDensity     = minDensity,
            waterDensities = nativeWaterDensities
        };

        filterRemoveFluidJob.ScheduleAppend(nativeIndices, tiles.Length, 32).Complete();
        yield return(null);

        foreach (int fluidIndex in nativeIndices)
        {
            waterDensities[fluidIndex] = 0.0f;
            SetTile(TileUtil.To2DIndex(fluidIndex, mapSize), tileInformations[0].id);
        }

        nativeIndices.Clear();
        FilterCreateFluidJob filterCreateFluidJob = new FilterCreateFluidJob
        {
            tiles          = nativeTiles,
            isSolid        = nativeIsSolid,
            minDensity     = minDensity,
            waterDensities = nativeWaterDensities
        };

        filterCreateFluidJob.ScheduleAppend(nativeIndices, tiles.Length, 32).Complete();
        yield return(null);

        foreach (int fluidIndex in nativeIndices)
        {
            SetTile(TileUtil.To2DIndex(fluidIndex, mapSize), waterID);
        }

        for (int i = 0; i < nativeWaterChunkDirty.Length; i++)
        {
            if (!nativeWaterChunkDirty[i])
            {
                continue;
            }

            if (chunks.TryGetValue(TileUtil.To2DIndex(i, numChunks), out TileChunk chunk))
            {
                chunk.SetMeshDirty();
            }
        }

        fluidUpdator = null;
    }
        public void Execute(int tileIndex)
        {
            int2 tilePosition = TileUtil.To2DIndex(tileIndex, mapSize);

            if (tiles[tileIndex] != waterID)
            {
                if (isSolid[tiles[tileIndex]])
                {
                    waterDensities[tileIndex] = 0.0f;
                }

                return;
            }

            if (waterDensities[tileIndex] < minDensity)
            {
                waterDensities[tileIndex] = 0;
                return;
            }

            float remainingDensity = waterDensities[tileIndex];

            if (remainingDensity <= 0)
            {
                return;
            }

            waterChunkDirty[TileUtil.To1DIndex(TileUtil.WorldTileToChunk(tilePosition, chunkSize), numChunks)] = true;

            int2 downPosition = tilePosition + TileUtil.Down;
            int  downIndex    = TileUtil.To1DIndex(downPosition, mapSize);

            if (TileUtil.BoundaryCheck(downPosition, mapSize) && !isSolid[tiles[downIndex]])
            {
                float flow = CalculateStableDensity(remainingDensity + waterDensities[downIndex]) - waterDensities[downIndex];
                if (flow > minFlow)
                {
                    flow *= flowSpeed;
                }

                flow = Mathf.Clamp(flow, 0, Mathf.Min(maxFlow, remainingDensity));
                waterDiff[tileIndex] -= flow;
                waterDiff[downIndex] += flow;
                remainingDensity     -= flow;
            }

            if (remainingDensity < minDensity)
            {
                waterDiff[tileIndex] -= remainingDensity;
                return;
            }

            int2 leftPosition = tilePosition + TileUtil.Left;
            int  leftIndex    = TileUtil.To1DIndex(leftPosition, mapSize);

            if (TileUtil.BoundaryCheck(leftIndex, mapSize) && !isSolid[tiles[leftIndex]])
            {
                float flow = (remainingDensity - waterDensities[leftIndex]) / 4.0f;
                if (flow > minFlow)
                {
                    flow *= flowSpeed;
                }

                flow = Mathf.Clamp(flow, 0, Mathf.Min(maxFlow, remainingDensity));
                waterDiff[tileIndex] -= flow;
                waterDiff[leftIndex] += flow;
                remainingDensity     -= flow;
            }

            if (remainingDensity < minDensity)
            {
                waterDiff[tileIndex] -= remainingDensity;
                return;
            }

            int2 rightPosition = tilePosition + TileUtil.Right;
            int  rightIndex    = TileUtil.To1DIndex(rightPosition, mapSize);

            if (TileUtil.BoundaryCheck(rightIndex, mapSize) && !isSolid[tiles[rightIndex]])
            {
                float flow = (remainingDensity - waterDensities[rightIndex]) / 3.0f;
                if (flow > minFlow)
                {
                    flow *= flowSpeed;
                }

                flow = Mathf.Clamp(flow, 0, Mathf.Min(maxFlow, remainingDensity));
                waterDiff[tileIndex]  -= flow;
                waterDiff[rightIndex] += flow;
                remainingDensity      -= flow;
            }

            if (remainingDensity < minDensity)
            {
                waterDiff[tileIndex] -= remainingDensity;
                return;
            }

            int2 upPosition = tilePosition + TileUtil.Up;
            int  upIndex    = TileUtil.To1DIndex(upPosition, mapSize);

            if (TileUtil.BoundaryCheck(upIndex, mapSize) && !isSolid[tiles[upIndex]])
            {
                float flow = remainingDensity - CalculateStableDensity(remainingDensity + waterDensities[upIndex]);
                if (flow > minFlow)
                {
                    flow *= flowSpeed;
                }

                flow = Mathf.Clamp(flow, 0, Mathf.Min(maxFlow, remainingDensity));
                waterDiff[tileIndex] -= flow;
                waterDiff[upIndex]   += flow;
                remainingDensity     -= flow;
            }

            if (remainingDensity < minDensity)
            {
                waterDiff[tileIndex] -= remainingDensity;
            }
        }