public static void Scatter(OCMap map, OCColumnMap columnMap, int cx, int cz)
        {
            int x1 = cx * OCChunk.SIZE_X;
            int z1 = cz * OCChunk.SIZE_Z;

            int x2 = x1 + OCChunk.SIZE_X;
            int z2 = z1 + OCChunk.SIZE_Z;

            OCSunLightMap lightmap = map.GetSunLightmap();

            list.Clear();
            for (int x = x1; x < x2; x++)
            {
                for (int z = z1; z < z2; z++)
                {
                    int maxY = ComputeMaxY(lightmap, x, z) + 1;
                    for (int y = 0; y < maxY; y++)
                    {
                        if (lightmap.GetLight(x, y, z) > MIN_LIGHT)
                        {
                            list.Add(new Vector3i(x, y, z));
                        }
                    }
                }
            }
            Scatter(map, columnMap, list);
        }
        private static void Scatter(OCMap map, List <Vector3i> list)          // рассеивание
        {
            OCSunLightMap lightmap = map.GetSunLightmap();

            for (int i = 0; i < list.Count; i++)
            {
                Vector3i pos = list[i];
                if (pos.y < 0)
                {
                    continue;
                }

                OCBlockData block = map.GetBlock(pos);
                int         light = lightmap.GetLight(pos) - OCLightComputerUtils.GetLightStep(block);
                if (light <= MIN_LIGHT)
                {
                    continue;
                }

                foreach (Vector3i dir in Vector3i.directions)
                {
                    Vector3i nextPos = pos + dir;
                    block = map.GetBlock(nextPos);
                    if (block.IsAlpha() && lightmap.SetMaxLight((byte)light, nextPos))
                    {
                        list.Add(nextPos);
                    }
                    if (!block.IsEmpty())
                    {
                        OCLightComputerUtils.SetLightDirty(map, nextPos);
                    }
                }
            }
        }
		public static void RecomputeLightAtPosition(OCMap map, Vector3i pos) {
			OCSunLightMap lightmap = map.GetSunLightmap();
			int oldSunHeight = lightmap.GetSunHeight(pos.x, pos.z);
			ComputeRayAtPosition(map, pos.x, pos.z);
			int newSunHeight = lightmap.GetSunHeight(pos.x, pos.z);
			
			if(newSunHeight < oldSunHeight) { // свет опустился
				// добавляем свет
				list.Clear();
	            for (int ty = newSunHeight; ty <= oldSunHeight; ty++) {
					pos.y = ty;
	                lightmap.SetLight(MIN_LIGHT, pos);
	                list.Add( pos );
	            }
	            Scatter(map, list);
			}
			if(newSunHeight > oldSunHeight) { // свет поднялся
				// удаляем свет
				list.Clear();
	            for (int ty = oldSunHeight; ty <= newSunHeight; ty++) {
					pos.y = ty;
					list.Add( pos );
	            }
	            RemoveLight(map, list);
			}
			
			if(newSunHeight == oldSunHeight) {
				if( map.GetBlock(pos).IsAlpha() ) {
					UpdateLight(map, pos);
				} else {
					RemoveLight(map, pos);
				}
			}
		}
        private static void RemoveLight(OCMap map, List <Vector3i> list)
        {
            OCSunLightMap lightmap = map.GetSunLightmap();

            foreach (Vector3i pos in list)
            {
                lightmap.SetLight(MAX_LIGHT, pos);
            }

            List <Vector3i> lightPoints = new List <Vector3i>();

            for (int i = 0; i < list.Count; i++)
            {
                Vector3i pos = list[i];
                if (pos.y < 0)
                {
                    continue;
                }
                if (lightmap.IsSunLight(pos.x, pos.y, pos.z))
                {
                    lightPoints.Add(pos);
                    continue;
                }
                byte light = (byte)(lightmap.GetLight(pos) - STEP_LIGHT);
                lightmap.SetLight(MIN_LIGHT, pos);
                if (light <= MIN_LIGHT)
                {
                    continue;
                }

                foreach (Vector3i dir in Vector3i.directions)
                {
                    Vector3i    nextPos = pos + dir;
                    OCBlockData block   = map.GetBlock(nextPos);
                    if (block.IsAlpha())
                    {
                        if (lightmap.GetLight(nextPos) <= light)
                        {
                            list.Add(nextPos);
                        }
                        else
                        {
                            lightPoints.Add(nextPos);
                        }
                    }
                    if (!block.IsEmpty())
                    {
                        OCLightComputerUtils.SetLightDirty(map, nextPos);
                    }
                }
            }

            Scatter(map, lightPoints);
        }
        public static void RecomputeLightAtPosition(OCMap map, Vector3i pos)
        {
            OCSunLightMap lightmap     = map.GetSunLightmap();
            int           oldSunHeight = lightmap.GetSunHeight(pos.x, pos.z);

            ComputeRayAtPosition(map, pos.x, pos.z);
            int newSunHeight = lightmap.GetSunHeight(pos.x, pos.z);

            if (newSunHeight < oldSunHeight)              // свет опустился
            // добавляем свет
            {
                list.Clear();
                for (int ty = newSunHeight; ty <= oldSunHeight; ty++)
                {
                    pos.y = ty;
                    lightmap.SetLight(MIN_LIGHT, pos);
                    list.Add(pos);
                }
                Scatter(map, list);
            }
            if (newSunHeight > oldSunHeight)              // свет поднялся
            // удаляем свет
            {
                list.Clear();
                for (int ty = oldSunHeight; ty <= newSunHeight; ty++)
                {
                    pos.y = ty;
                    list.Add(pos);
                }
                RemoveLight(map, list);
            }

            if (newSunHeight == oldSunHeight)
            {
                if (map.GetBlock(pos).IsAlpha())
                {
                    UpdateLight(map, pos);
                }
                else
                {
                    RemoveLight(map, pos);
                }
            }
        }
		private static void Scatter(OCMap map, List<Vector3i> list) { // рассеивание
			OCSunLightMap lightmap = map.GetSunLightmap();
	        for(int i=0; i<list.Count; i++) {
	            Vector3i pos = list[i];
				if(pos.y<0) continue;
				
				OCBlockData block = map.GetBlock(pos);
				int light = lightmap.GetLight(pos) - OCLightComputerUtils.GetLightStep(block);
	            if(light <= MIN_LIGHT) continue;
				
	            foreach(Vector3i dir in Vector3i.directions) {
					Vector3i nextPos = pos + dir;
					block = map.GetBlock(nextPos);
	                if( block.IsAlpha() && lightmap.SetMaxLight((byte)light, nextPos) ) {
	                	list.Add( nextPos );
	                }
					if(!block.IsEmpty()) OCLightComputerUtils.SetLightDirty(map, nextPos);
	            }
	        }
	    }
        public static void ComputeRayAtPosition(OCMap map, int x, int z)
        {
            int maxY = map.GetMaxY(x, z);

            map.GetSunLightmap().SetSunHeight(maxY + 1, x, z);
        }
		private static void RemoveLight(OCMap map, List<Vector3i> list) {
			OCSunLightMap lightmap = map.GetSunLightmap();
			foreach(Vector3i pos in list) {
				lightmap.SetLight(MAX_LIGHT, pos);
			}
			
			List<Vector3i> lightPoints = new List<Vector3i>();
			for(int i=0; i<list.Count; i++) {
	            Vector3i pos = list[i];
				if(pos.y<0) continue;
				if(lightmap.IsSunLight(pos.x, pos.y, pos.z)) {
					lightPoints.Add( pos );
					continue;
				}
				byte light = (byte) (lightmap.GetLight(pos) - STEP_LIGHT);
				lightmap.SetLight(MIN_LIGHT, pos);
	            if (light <= MIN_LIGHT) continue;
				
				foreach(Vector3i dir in Vector3i.directions) {
					Vector3i nextPos = pos + dir;
					OCBlockData block = map.GetBlock(nextPos);
					if(block.IsAlpha()) {
						if(lightmap.GetLight(nextPos) <= light) {
							list.Add( nextPos );
						} else {
							lightPoints.Add( nextPos );
						}
					}
					if(!block.IsEmpty()) OCLightComputerUtils.SetLightDirty(map, nextPos);
				}	
			}
			
	        Scatter(map, lightPoints);
	    }
		public static void Scatter(OCMap map, OCColumnMap columnMap, int cx, int cz) {
			int x1 = cx*OCChunk.SIZE_X;
			int z1 = cz*OCChunk.SIZE_Z;
			
			int x2 = x1+OCChunk.SIZE_X;
			int z2 = z1+OCChunk.SIZE_Z;
			
			OCSunLightMap lightmap = map.GetSunLightmap();
			list.Clear();
			for(int x=x1; x<x2; x++) {
				for(int z=z1; z<z2; z++) {
					int maxY = ComputeMaxY(lightmap, x, z)+1;
					for(int y=0; y<maxY; y++) {
						if(lightmap.GetLight(x, y, z) > MIN_LIGHT) {
							list.Add( new Vector3i(x, y, z) );
						}
					}
				}
			}
			Scatter(map, columnMap, list);
		}
		public static void ComputeRayAtPosition(OCMap map, int x, int z) {
			int maxY = map.GetMaxY( x, z );
			
			map.GetSunLightmap().SetSunHeight(maxY+1, x, z);
		}