public bool SetLight(int2 worldTilePosition, int value, LightType type)
    {
        if (!TileUtil.BoundaryCheck(worldTilePosition, mapSize))
        {
            return(false);
        }

        int index = TileUtil.To1DIndex(worldTilePosition, mapSize);

        if (lights[index].GetLight(type) == value)
        {
            return(false);
        }

        int2 chunkPosition = TileUtil.WorldTileToChunk(worldTilePosition, chunkSize);

        if (chunks.TryGetValue(chunkPosition, out TileChunk chunk))
        {
            chunk.SetLightDirty();
        }
        else
        {
            TileChunk newChunk = GenerateChunk(chunkPosition);
            newChunk.SetLightDirty();
        }

        lights[index].SetLight(value, type);

        return(true);
    }
    public int GetLight(int2 worldTilePosition, LightType type)
    {
        if (!TileUtil.BoundaryCheck(worldTilePosition, mapSize))
        {
            return(0);
        }

        return(lights[TileUtil.To1DIndex(worldTilePosition, mapSize)].GetLight(type));
    }
    public void TorchLightPropagation(ref Queue <int2> propagationQueue, ref Queue <Tuple <int2, int> > removalQueue, LightType lightType)
    {
        while (removalQueue.Count != 0)
        {
            (int2 lightPosition, int torchLight) = removalQueue.Dequeue();

            foreach (int2 direction in TileUtil.Direction4)
            {
                int2 neighborPosition = lightPosition + direction;

                if (!TileUtil.BoundaryCheck(neighborPosition, mapSize))
                {
                    continue;
                }

                int neighborTorchLight = GetLight(neighborPosition, lightType);

                if (neighborTorchLight != 0 && neighborTorchLight < torchLight)
                {
                    SetLight(neighborPosition, 0, lightType);
                    removalQueue.Enqueue(new Tuple <int2, int>(neighborPosition, neighborTorchLight));
                }
                else if (neighborTorchLight >= torchLight)
                {
                    propagationQueue.Enqueue(neighborPosition);
                }
            }
        }

        while (propagationQueue.Count != 0)
        {
            int2 lightPosition = propagationQueue.Dequeue();
            int  torchLight    = GetLight(lightPosition, lightType);

            if (torchLight <= 0)
            {
                continue;
            }

            foreach (int2 direction in TileUtil.Direction4)
            {
                int2 neighborPosition = lightPosition + direction;

                if (!TileUtil.BoundaryCheck(neighborPosition, mapSize))
                {
                    continue;
                }

                int neighborTorchLight = GetLight(neighborPosition, lightType);

                int resultTorchLight = torchLight - TileLight.SunLightAttenuation;

                int neighborTile = GetTile(neighborPosition);

                bool isOpacity = neighborTile != -1 && neighborTile != 0;

                if (isOpacity)
                {
                    resultTorchLight -= tileInformations[neighborTile].attenuation;
                }

                if (neighborTorchLight >= resultTorchLight)
                {
                    continue;
                }

                SetLight(neighborPosition, resultTorchLight, lightType);
                propagationQueue.Enqueue(neighborPosition);
            }
        }
    }
    void CheckTileToUpdateLight(int2 worldTilePosition, int id, LightEmission beforeEmission)
    {
        if (id == 0)
        {
            foreach (int2 direction in TileUtil.Direction4)
            {
                int2 neighborPosition = worldTilePosition + direction;

                if (!TileUtil.BoundaryCheck(neighborPosition, mapSize))
                {
                    continue;
                }

                for (int i = 0; i < 4; i++)
                {
                    LightType lightType     = (LightType)i;
                    int       neighborLight = GetLight(neighborPosition, lightType);

                    if (neighborLight <= 0)
                    {
                        continue;
                    }

                    switch (lightType)
                    {
                    case LightType.S:
                        sunLightPropagationQueue.Enqueue(neighborPosition);
                        break;

                    case LightType.R:
                        torchRedLightPropagationQueue.Enqueue(neighborPosition);
                        break;

                    case LightType.G:
                        torchGreenLightPropagationQueue.Enqueue(neighborPosition);
                        break;

                    case LightType.B:
                        torchBlueLightPropagationQueue.Enqueue(neighborPosition);
                        break;
                    }
                }
            }
        }
        else
        {
            int sunLight = GetLight(worldTilePosition, LightType.S);
            SetLight(worldTilePosition, 0, LightType.S);
            sunLightRemovalQueue.Enqueue(new Tuple <int2, int>(worldTilePosition, sunLight));

            foreach (int2 direction in TileUtil.Direction4)
            {
                int2 neighborPosition = worldTilePosition + direction;

                if (!TileUtil.BoundaryCheck(neighborPosition, mapSize))
                {
                    continue;
                }

                for (int i = 1; i < 4; i++)
                {
                    LightType lightType     = (LightType)i;
                    int       neighborLight = GetLight(neighborPosition, lightType);

                    if (neighborLight <= 0)
                    {
                        continue;
                    }

                    switch (lightType)
                    {
                    case LightType.R:
                        torchRedLightRemovalQueue.Enqueue(new Tuple <int2, int>(worldTilePosition, neighborLight));
                        break;

                    case LightType.G:
                        torchGreenLightRemovalQueue.Enqueue(new Tuple <int2, int>(worldTilePosition, neighborLight));
                        break;

                    case LightType.B:
                        torchBlueLightRemovalQueue.Enqueue(new Tuple <int2, int>(worldTilePosition, neighborLight));
                        break;
                    }
                }
            }
        }

        if (tileInformations[id].emission.r > 0)
        {
            torchRedLightPropagationQueue.Enqueue(worldTilePosition);
        }

        if (tileInformations[id].emission.g > 0)
        {
            torchGreenLightPropagationQueue.Enqueue(worldTilePosition);
        }

        if (tileInformations[id].emission.b > 0)
        {
            torchBlueLightPropagationQueue.Enqueue(worldTilePosition);
        }

        if (beforeEmission.r > 0)
        {
            torchRedLightRemovalQueue.Enqueue(new Tuple <int2, int>(worldTilePosition, beforeEmission.r));
        }

        if (beforeEmission.g > 0)
        {
            torchGreenLightRemovalQueue.Enqueue(new Tuple <int2, int>(worldTilePosition, beforeEmission.g));
        }

        if (beforeEmission.b > 0)
        {
            torchBlueLightRemovalQueue.Enqueue(new Tuple <int2, int>(worldTilePosition, beforeEmission.b));
        }
    }