diff --git a/Cargo.lock b/Cargo.lock index 65f5c8fe67..b8e5e4307c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6143,6 +6143,7 @@ dependencies = [ "arr_macro", "bincode", "bitvec", + "clap", "criterion", "csv", "deflate 0.9.1", diff --git a/common/net/src/msg/compression.rs b/common/net/src/msg/compression.rs index 0fd0f89276..98136476ec 100644 --- a/common/net/src/msg/compression.rs +++ b/common/net/src/msg/compression.rs @@ -127,8 +127,9 @@ pub trait VoxelImageEncoding: Copy { type Workspace; type Output; fn create(width: u32, height: u32) -> Self::Workspace; - fn put_solid(ws: &mut Self::Workspace, x: u32, y: u32, kind: BlockKind, rgb: Rgb); + fn put_solid(&self, ws: &mut Self::Workspace, x: u32, y: u32, kind: BlockKind, rgb: Rgb); fn put_sprite( + &self, ws: &mut Self::Workspace, x: u32, y: u32, @@ -176,13 +177,14 @@ impl VoxelImageEncoding for QuadPngEncoding { } #[inline(always)] - fn put_solid(ws: &mut Self::Workspace, x: u32, y: u32, kind: BlockKind, rgb: Rgb) { + fn put_solid(&self, ws: &mut Self::Workspace, x: u32, y: u32, kind: BlockKind, rgb: Rgb) { ws.0.put_pixel(x, y, image::Luma([kind as u8])); ws.3.put_pixel(x / N, y / N, image::Rgb([rgb.r, rgb.g, rgb.b])); } #[inline(always)] fn put_sprite( + &self, ws: &mut Self::Workspace, x: u32, y: u32, @@ -451,7 +453,7 @@ impl VoxelImageEncoding for TriPngEncoding) { + fn put_solid(&self, ws: &mut Self::Workspace, x: u32, y: u32, kind: BlockKind, rgb: Rgb) { ws.0.put_pixel(x, y, image::Luma([kind as u8])); ws.1.put_pixel(x, y, image::Luma([0])); ws.2.put_pixel(x, y, image::Luma([0])); @@ -461,6 +463,7 @@ impl VoxelImageEncoding for TriPngEncoding( - _: VIE, + vie: VIE, packing: P, vol: &V, lo: Vec3, @@ -697,10 +700,10 @@ pub fn image_terrain< .unwrap_or(&Block::empty()); match (block.get_color(), block.get_sprite()) { (Some(rgb), None) => { - VIE::put_solid(&mut image, i, j, *block, rgb); + VIE::put_solid(&vie, &mut image, i, j, *block, rgb); }, (None, Some(sprite)) => { - VIE::put_sprite(&mut image, i, j, *block, sprite, block.get_ori()); + VIE::put_sprite(&vie, &mut image, i, j, *block, sprite, block.get_ori()); }, _ => panic!( "attr being used for color vs sprite is mutually exclusive (and that's \ diff --git a/world/Cargo.toml b/world/Cargo.toml index 56ff2134b6..b6d4ef4666 100644 --- a/world/Cargo.toml +++ b/world/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [features] simd = ["vek/platform_intrinsics"] -bin_compression = ["lz-fear", "deflate", "flate2", "image/jpeg", "num-traits", "fallible-iterator", "kiddo"] +bin_compression = ["lz-fear", "deflate", "flate2", "image/jpeg", "num-traits", "fallible-iterator", "kiddo", "clap"] default = ["simd"] @@ -43,6 +43,7 @@ flate2 = { version = "1.0.20", optional = true } num-traits = { version = "0.2", optional = true } fallible-iterator = { version = "0.2.0", optional = true } kiddo = { version = "0.1.4", optional = true } +clap = { version = "2.33.3", optional = true } [dev-dependencies] diff --git a/world/examples/chunk_compression_benchmarks.rs b/world/examples/chunk_compression_benchmarks.rs index 9ac934b953..538612618e 100644 --- a/world/examples/chunk_compression_benchmarks.rs +++ b/world/examples/chunk_compression_benchmarks.rs @@ -173,11 +173,12 @@ impl VoxelImageEncoding for PngEncoding { ImageBuffer::, Vec>::new(width, height) } - fn put_solid(ws: &mut Self::Workspace, x: u32, y: u32, kind: BlockKind, rgb: Rgb) { + fn put_solid(&self, ws: &mut Self::Workspace, x: u32, y: u32, kind: BlockKind, rgb: Rgb) { ws.put_pixel(x, y, image::Rgba([rgb.r, rgb.g, rgb.b, 255 - kind as u8])); } fn put_sprite( + &self, ws: &mut Self::Workspace, x: u32, y: u32, @@ -223,11 +224,12 @@ impl VoxelImageEncoding for JpegEncoding { ImageBuffer::, Vec>::new(width, height) } - fn put_solid(ws: &mut Self::Workspace, x: u32, y: u32, kind: BlockKind, rgb: Rgb) { + fn put_solid(&self, ws: &mut Self::Workspace, x: u32, y: u32, kind: BlockKind, rgb: Rgb) { ws.put_pixel(x, y, image::Rgba([rgb.r, rgb.g, rgb.b, 255 - kind as u8])); } fn put_sprite( + &self, ws: &mut Self::Workspace, x: u32, y: u32, @@ -268,7 +270,7 @@ impl VoxelImageEncoding for MixedEncoding { ) } - fn put_solid(ws: &mut Self::Workspace, x: u32, y: u32, kind: BlockKind, rgb: Rgb) { + fn put_solid(&self, ws: &mut Self::Workspace, x: u32, y: u32, kind: BlockKind, rgb: Rgb) { ws.0.put_pixel(x, y, image::Luma([kind as u8])); ws.1.put_pixel(x, y, image::Luma([0])); ws.2.put_pixel(x, y, image::Luma([0])); @@ -276,6 +278,7 @@ impl VoxelImageEncoding for MixedEncoding { } fn put_sprite( + &self, ws: &mut Self::Workspace, x: u32, y: u32, @@ -378,12 +381,13 @@ impl VoxelImageEncoding for MixedEncodingSparseSprites { ) } - fn put_solid(ws: &mut Self::Workspace, x: u32, y: u32, kind: BlockKind, rgb: Rgb) { + fn put_solid(&self, ws: &mut Self::Workspace, x: u32, y: u32, kind: BlockKind, rgb: Rgb) { ws.0.put_pixel(x, y, image::Luma([kind as u8])); ws.1.put_pixel(x, y, image::Rgb([rgb.r, rgb.g, rgb.b])); } fn put_sprite( + &self, ws: &mut Self::Workspace, x: u32, y: u32, @@ -439,12 +443,13 @@ impl VoxelImageEncoding for MixedEncodingDenseSprites { ) } - fn put_solid(ws: &mut Self::Workspace, x: u32, y: u32, kind: BlockKind, rgb: Rgb) { + fn put_solid(&self, ws: &mut Self::Workspace, x: u32, y: u32, kind: BlockKind, rgb: Rgb) { ws.0.put_pixel(x, y, image::Luma([kind as u8])); ws.3.put_pixel(x, y, image::Rgb([rgb.r, rgb.g, rgb.b])); } fn put_sprite( + &self, ws: &mut Self::Workspace, x: u32, y: u32, @@ -488,6 +493,100 @@ impl VoxelImageEncoding for MixedEncodingDenseSprites { } } +use kiddo::KdTree; + +lazy_static::lazy_static! { + pub static ref PALETTE: HashMap> = { + let ron_bytes = include_bytes!("palettes.ron"); + let palettes: HashMap>> = + ron::de::from_bytes(&*ron_bytes).expect("palette should parse"); + palettes + .into_iter() + .map(|(k, v)| { + let mut tree = KdTree::new(); + for (i, rgb) in v.into_iter().enumerate() { + tree.add(&[rgb.r as f32, rgb.g as f32, rgb.b as f32], i as u8) + .expect("kdtree insert should succeed"); + } + (k, tree) + }) + .collect() + }; +} + +#[derive(Debug, Clone, Copy)] +pub struct PaletteEncoding<'a, const N: u32>(&'a HashMap>); + +impl<'a, const N: u32> VoxelImageEncoding for PaletteEncoding<'a, N> { + #[allow(clippy::type_complexity)] + type Output = CompressedData<(Vec, [usize; 4])>; + #[allow(clippy::type_complexity)] + type Workspace = ( + ImageBuffer, Vec>, + ImageBuffer, Vec>, + ImageBuffer, Vec>, + ImageBuffer, Vec>, + ); + + fn create(width: u32, height: u32) -> Self::Workspace { + ( + ImageBuffer::new(width, height), + ImageBuffer::new(width, height), + ImageBuffer::new(width, height), + ImageBuffer::new(width / N, height / N), + ) + } + + fn put_solid(&self, ws: &mut Self::Workspace, x: u32, y: u32, kind: BlockKind, rgb: Rgb) { + ws.0.put_pixel(x, y, image::Luma([kind as u8])); + let i = self.0[&kind] + .nearest_one( + &[rgb.r as f32, rgb.g as f32, rgb.b as f32], + &kiddo::distance::squared_euclidean, + ) + .map(|(_, i)| *i) + .unwrap_or(0); + ws.3.put_pixel(x / N, y / N, image::Luma([i])); + } + + fn put_sprite( + &self, + ws: &mut Self::Workspace, + x: u32, + y: u32, + kind: BlockKind, + sprite: SpriteKind, + ori: Option, + ) { + ws.0.put_pixel(x, y, image::Luma([kind as u8])); + ws.1.put_pixel(x, y, image::Luma([sprite as u8])); + ws.2.put_pixel(x, y, image::Luma([ori.unwrap_or(0)])); + } + + fn finish(ws: &Self::Workspace) -> Option { + let mut buf = Vec::new(); + use image::codecs::png::{CompressionType, FilterType}; + let mut indices = [0; 4]; + let mut f = |x: &ImageBuffer<_, Vec>, i| { + let png = image::codecs::png::PngEncoder::new_with_quality( + &mut buf, + CompressionType::Rle, + FilterType::Up, + ); + png.encode(&*x.as_raw(), x.width(), x.height(), image::ColorType::L8) + .ok()?; + indices[i] = buf.len(); + Some(()) + }; + f(&ws.0, 0)?; + f(&ws.1, 1)?; + f(&ws.2, 2)?; + f(&ws.3, 3)?; + + Some(CompressedData::compress(&(buf, indices), 1)) + } +} + #[allow(clippy::many_single_char_names)] fn histogram_to_dictionary(histogram: &HashMap, usize>, dictionary: &mut Vec) { let mut tmp: Vec<(Vec, usize)> = histogram.iter().map(|(k, v)| (k.clone(), *v)).collect(); @@ -898,6 +997,15 @@ fn main() { .unwrap(); let tripngconst_post = Instant::now(); + let palettepng_pre = Instant::now(); + let palettepng = image_terrain_chonk( + PaletteEncoding::<4>(&PALETTE), + WidePacking::(), + &chunk, + ) + .unwrap(); + let palettepng_post = Instant::now(); + #[rustfmt::skip] sizes.extend_from_slice(&[ ("quadpngfull", quadpngfull.data.len() as f32 / n as f32), @@ -906,6 +1014,7 @@ fn main() { ("quadpngquartwide", quadpngquartwide.data.len() as f32 / n as f32), ("tripngaverage", tripngaverage.data.len() as f32 / n as f32), ("tripngconst", tripngconst.data.len() as f32 / n as f32), + ("palettepng", palettepng.data.len() as f32 / n as f32), ]); let best_idx = sizes .iter() @@ -926,6 +1035,7 @@ fn main() { ("quadpngquartwide", (quadpngquartwide_post - quadpngquartwide_pre).subsec_nanos()), ("tripngaverage", (tripngaverage_post - tripngaverage_pre).subsec_nanos()), ("tripngconst", (tripngconst_post - tripngconst_pre).subsec_nanos()), + ("palettepng", (palettepng_post - palettepng_pre).subsec_nanos()), ]); if false { let bucket = z_buckets @@ -965,6 +1075,15 @@ fn main() { bucket.0 += 1; bucket.1 += (tripngconst_post - tripngconst_pre).subsec_nanos() as f32; } + if true { + let bucket = z_buckets + .entry("palettepng") + .or_default() + .entry(chunk.get_max_z() - chunk.get_min_z()) + .or_insert((0, 0.0)); + bucket.0 += 1; + bucket.1 += (palettepng_post - palettepng_pre).subsec_nanos() as f32; + } trace!( "{} {}: uncompressed: {}, {:?} {} {:?}", spiralpos.x, diff --git a/world/examples/palettes.ron b/world/examples/palettes.ron new file mode 100644 index 0000000000..efea1bc695 --- /dev/null +++ b/world/examples/palettes.ron @@ -0,0 +1,1838 @@ +{ + Leaves: [ + (r:9,g:66,b:37), + (r:67,g:122,b:11), + (r:35,g:97,b:27), + (r:57,g:74,b:34), + (r:34,g:130,b:60), + (r:90,g:140,b:0), + (r:15,g:80,b:10), + (r:57,g:140,b:34), + (r:19,g:115,b:42), + (r:31,g:100,b:0), + (r:89,g:109,b:19), + (r:33,g:61,b:45), + (r:53,g:103,b:7), + (r:15,g:88,b:35), + (r:62,g:54,b:43), + (r:32,g:77,b:32), + (r:54,g:95,b:22), + (r:31,g:94,b:29), + (r:17,g:98,b:27), + (r:0,g:60,b:50), + (r:71,g:106,b:13), + (r:18,g:72,b:24), + (r:49,g:63,b:44), + (r:20,g:75,b:44), + (r:47,g:107,b:21), + (r:78,g:131,b:5), + (r:46,g:84,b:30), + (r:16,g:91,b:20), + (r:29,g:79,b:11), + (r:65,g:83,b:27), + (r:34,g:96,b:27), + (r:33,g:81,b:35), + (r:25,g:55,b:50), + (r:57,g:114,b:16), + (r:43,g:74,b:38), + (r:11,g:77,b:33), + (r:1,g:71,b:44), + (r:42,g:102,b:4), + (r:32,g:69,b:40), + (r:26,g:86,b:35), + (r:63,g:64,b:39), + (r:18,g:107,b:35), + (r:21,g:83,b:25), + (r:34,g:73,b:42), + (r:37,g:86,b:27), + (r:23,g:63,b:45), + (r:21,g:71,b:33), + (r:20,g:92,b:29), + (r:24,g:95,b:30), + (r:29,g:73,b:29), + (r:31,g:84,b:28), + (r:62,g:105,b:10), + (r:80,g:108,b:16), + (r:38,g:89,b:36), + (r:47,g:55,b:48), + (r:24,g:76,b:18), + (r:37,g:77,b:28), + (r:32,g:91,b:30), + (r:20,g:79,b:36), + (r:25,g:97,b:30), + (r:41,g:102,b:24), + (r:4,g:63,b:43), + (r:7,g:76,b:41), + (r:17,g:74,b:42), + (r:11,g:74,b:33), + (r:30,g:76,b:40), + (r:54,g:104,b:8), + (r:13,g:84,b:42), + (r:55,g:66,b:39), + (r:61,g:76,b:31), + (r:42,g:77,b:37), + (r:25,g:74,b:40), + (r:49,g:77,b:33), + (r:42,g:92,b:25), + (r:43,g:66,b:38), + (r:53,g:111,b:18), + (r:84,g:135,b:2), + (r:73,g:126,b:8), + (r:52,g:102,b:18), + (r:63,g:71,b:31), + (r:7,g:83,b:33), + (r:15,g:86,b:15), + (r:21,g:86,b:30), + (r:35,g:75,b:38), + (r:32,g:84,b:32), + (r:25,g:87,b:29), + (r:18,g:94,b:33), + (r:62,g:118,b:13), + (r:39,g:82,b:32), + (r:15,g:68,b:35), + (r:6,g:74,b:41), + (r:25,g:76,b:33), + (r:17,g:96,b:24), + (r:26,g:93,b:25), + (r:16,g:82,b:31), + (r:18,g:78,b:43), + (r:19,g:78,b:36), + (r:20,g:89,b:36), + (r:19,g:84,b:39), + (r:24,g:82,b:40), + (r:13,g:75,b:39), + (r:21,g:76,b:28), + (r:16,g:83,b:29), + (r:34,g:67,b:40), + (r:15,g:70,b:29), + (r:49,g:73,b:37), + (r:14,g:81,b:37), + (r:31,g:81,b:37), + (r:28,g:71,b:36), + (r:34,g:91,b:30), + (r:26,g:67,b:42), + (r:17,g:103,b:31), + (r:25,g:82,b:30), + (r:26,g:90,b:31), + (r:36,g:101,b:2), + (r:18,g:76,b:31), + (r:20,g:75,b:31), + (r:65,g:59,b:40), + (r:33,g:86,b:32), + (r:25,g:76,b:42), + (r:31,g:86,b:33), + (r:36,g:73,b:37), + (r:37,g:75,b:33), + (r:49,g:87,b:27), + (r:46,g:79,b:33), + (r:22,g:84,b:35), + (r:14,g:69,b:30), + (r:22,g:71,b:43), + (r:42,g:97,b:23), + (r:16,g:71,b:35), + (r:22,g:81,b:29), + (r:15,g:74,b:40), + (r:21,g:66,b:41), + (r:18,g:111,b:39), + (r:48,g:103,b:6), + (r:25,g:97,b:27), + (r:32,g:89,b:28), + (r:20,g:92,b:31), + (r:8,g:80,b:37), + (r:25,g:74,b:32), + (r:33,g:83,b:28), + (r:16,g:89,b:29), + (r:38,g:130,b:57), + (r:24,g:95,b:29), + (r:22,g:85,b:38), + (r:41,g:88,b:29), + (r:27,g:84,b:34), + (r:21,g:74,b:21), + (r:29,g:94,b:32), + (r:26,g:77,b:14), + (r:75,g:107,b:15), + (r:66,g:106,b:12), + (r:51,g:68,b:38), + (r:22,g:75,b:37), + (r:84,g:109,b:18), + (r:45,g:70,b:39), + (r:48,g:74,b:35), + (r:20,g:80,b:41), + (r:19,g:86,b:34), + (r:50,g:93,b:22), + (r:33,g:97,b:23), + (r:20,g:84,b:39), + (r:34,g:92,b:25), + (r:35,g:85,b:33), + (r:21,g:73,b:37), + (r:19,g:91,b:30), + (r:39,g:72,b:40), + (r:22,g:79,b:32), + (r:32,g:82,b:36), + (r:27,g:80,b:36), + (r:29,g:76,b:35), + (r:42,g:63,b:41), + (r:19,g:91,b:36), + (r:16,g:85,b:38), + (r:8,g:87,b:34), + (r:12,g:80,b:30), + (r:27,g:83,b:37), + (r:20,g:86,b:28), + (r:20,g:85,b:34), + (r:15,g:83,b:12), + (r:37,g:80,b:36), + (r:21,g:83,b:31), + (r:25,g:85,b:31), + (r:40,g:103,b:20), + (r:41,g:96,b:24), + (r:27,g:92,b:29), + (r:18,g:82,b:35), + (r:24,g:79,b:37), + (r:44,g:104,b:22), + (r:7,g:64,b:40), + (r:38,g:99,b:25), + (r:23,g:88,b:33), + (r:2,g:61,b:46), + (r:34,g:97,b:27), + (r:58,g:104,b:9), + (r:71,g:125,b:9), + (r:38,g:90,b:27), + (r:42,g:85,b:30), + (r:11,g:83,b:35), + (r:17,g:76,b:39), + (r:37,g:84,b:28), + (r:42,g:80,b:34), + (r:12,g:74,b:37), + (r:15,g:89,b:31), + (r:54,g:72,b:36), + (r:29,g:81,b:32), + (r:29,g:73,b:40), + (r:17,g:74,b:38), + (r:46,g:75,b:33), + (r:26,g:90,b:35), + (r:54,g:112,b:17), + (r:11,g:67,b:34), + (r:50,g:109,b:19), + (r:81,g:133,b:4), + (r:11,g:79,b:39), + (r:75,g:129,b:7), + (r:87,g:138,b:1), + (r:37,g:95,b:25), + (r:19,g:80,b:39), + (r:59,g:71,b:35), + (r:14,g:79,b:35), + (r:29,g:85,b:30), + (r:20,g:97,b:29), + (r:29,g:87,b:29), + (r:23,g:89,b:29), + (r:17,g:85,b:31), + (r:29,g:91,b:26), + (r:31,g:87,b:25), + (r:17,g:91,b:26), + (r:17,g:101,b:29), + (r:16,g:88,b:18), + (r:36,g:88,b:30), + (r:19,g:87,b:38), + (r:23,g:84,b:37), + (r:32,g:76,b:37), + (r:15,g:84,b:35), + (r:33,g:78,b:38), + (r:15,g:94,b:35), + (r:38,g:77,b:38), + (r:34,g:89,b:27), + (r:33,g:81,b:31), + (r:27,g:80,b:39), + (r:24,g:78,b:36), + (r:28,g:84,b:30), + (r:49,g:80,b:31), + (r:20,g:78,b:38), + (r:16,g:76,b:35), + (r:15,g:71,b:33), + (r:60,g:116,b:15), + (r:28,g:88,b:33), + (r:38,g:101,b:22), + (r:19,g:72,b:40), + (r:24,g:92,b:33), + (r:25,g:86,b:36), + (r:41,g:83,b:33), + (r:19,g:83,b:32), + ], + Lava: [ + (r:186,g:41,b:2), + (r:177,g:32,b:0), + (r:189,g:44,b:5), + (r:178,g:33,b:0), + (r:188,g:43,b:4), + (r:184,g:39,b:0), + (r:179,g:34,b:0), + (r:180,g:35,b:0), + (r:190,g:45,b:6), + (r:176,g:31,b:0), + (r:183,g:38,b:0), + (r:191,g:46,b:7), + (r:181,g:36,b:0), + (r:187,g:42,b:3), + (r:185,g:40,b:1), + (r:182,g:37,b:0), + ], + Misc: [ + (r:73,g:42,b:36), + (r:255,g:255,b:255), + (r:65,g:65,b:65), + (r:114,g:68,b:57), + (r:158,g:93,b:79), + (r:32,g:32,b:32), + (r:65,g:30,b:0), + (r:227,g:198,b:172), + (r:97,g:44,b:0), + (r:207,g:179,b:149), + (r:244,g:202,b:144), + (r:114,g:105,b:100), + (r:204,g:86,b:62), + (r:0,g:52,b:58), + (r:87,g:39,b:67), + (r:184,g:151,b:134), + (r:223,g:212,b:202), + (r:61,g:93,b:94), + (r:141,g:71,b:37), + (r:177,g:173,b:157), + (r:128,g:85,b:74), + (r:237,g:237,b:237), + (r:180,g:94,b:47), + (r:166,g:133,b:148), + (r:98,g:53,b:40), + (r:127,g:84,b:73), + (r:52,g:52,b:47), + (r:177,g:142,b:111), + (r:232,g:178,b:152), + (r:191,g:187,b:171), + (r:247,g:208,b:150), + (r:221,g:167,b:141), + (r:194,g:174,b:144), + (r:180,g:147,b:162), + (r:77,g:45,b:13), + (r:54,g:30,b:26), + (r:74,g:106,b:107), + (r:12,g:65,b:71), + (r:63,g:63,b:63), + (r:57,g:22,b:0), + (r:103,g:76,b:74), + (r:24,g:19,b:17), + (r:244,g:210,b:174), + (r:90,g:58,b:59), + (r:77,g:77,b:77), + (r:97,g:72,b:47), + (r:88,g:56,b:24), + (r:125,g:116,b:111), + (r:80,g:49,b:55), + (r:114,g:72,b:53), + (r:220,g:190,b:157), + (r:77,g:29,b:57), + (r:64,g:96,b:97), + (r:108,g:55,b:7), + (r:79,g:70,b:57), + (r:107,g:82,b:57), + (r:235,g:193,b:135), + (r:41,g:41,b:41), + (r:137,g:94,b:83), + (r:160,g:101,b:91), + (r:95,g:60,b:55), + (r:109,g:62,b:42), + (r:100,g:70,b:60), + (r:55,g:39,b:40), + (r:186,g:151,b:120), + (r:196,g:78,b:54), + (r:145,g:86,b:76), + (r:86,g:42,b:22), + (r:43,g:35,b:22), + (r:86,g:47,b:44), + (r:105,g:80,b:55), + (r:184,g:180,b:164), + (r:211,g:93,b:69), + (r:64,g:36,b:31), + (r:196,g:176,b:146), + (r:213,g:175,b:144), + (r:97,g:64,b:37), + (r:116,g:100,b:90), + (r:207,g:187,b:157), + (r:72,g:37,b:7), + (r:89,g:57,b:46), + (r:71,g:71,b:71), + (r:6,g:59,b:65), + (r:226,g:172,b:146), + (r:172,g:139,b:154), + (r:192,g:157,b:126), + (r:117,g:77,b:59), + (r:239,g:209,b:183), + (r:104,g:65,b:54), + (r:45,g:29,b:30), + (r:203,g:175,b:145), + (r:220,g:195,b:177), + (r:82,g:50,b:18), + (r:50,g:34,b:35), + (r:103,g:50,b:2), + (r:60,g:44,b:45), + (r:120,g:111,b:106), + (r:82,g:34,b:62), + (r:69,g:101,b:102), + (r:92,g:44,b:72), + (r:122,g:79,b:68), + (r:150,g:91,b:81), + (r:63,g:28,b:0), + (r:50,g:52,b:55), + (r:155,g:96,b:86), + (r:97,g:62,b:58), + (r:87,g:51,b:51), + (r:110,g:73,b:59), + (r:97,g:57,b:48), + (r:93,g:66,b:44), + (r:108,g:72,b:60), + (r:54,g:46,b:38), + (r:220,g:186,b:163), + (r:84,g:54,b:59), + (r:214,g:186,b:156), + (r:105,g:67,b:56), + (r:92,g:51,b:44), + (r:73,g:73,b:73), + (r:101,g:76,b:51), + (r:239,g:197,b:139), + (r:133,g:90,b:79), + (r:200,g:82,b:58), + (r:217,g:163,b:137), + (r:110,g:101,b:96), + (r:182,g:147,b:116), + (r:176,g:143,b:158), + (r:200,g:180,b:150), + (r:225,g:171,b:145), + (r:89,g:54,b:52), + (r:113,g:68,b:48), + (r:92,g:65,b:50), + (r:103,g:71,b:65), + (r:109,g:69,b:54), + (r:101,g:57,b:43), + (r:246,g:204,b:146), + (r:93,g:40,b:0), + (r:119,g:69,b:59), + (r:94,g:71,b:42), + (r:104,g:63,b:49), + (r:68,g:68,b:68), + (r:85,g:53,b:21), + (r:187,g:183,b:167), + (r:211,g:183,b:153), + (r:208,g:90,b:66), + (r:69,g:34,b:4), + (r:91,g:43,b:71), + (r:229,g:175,b:149), + (r:169,g:136,b:151), + (r:204,g:176,b:146), + (r:189,g:154,b:123), + (r:9,g:62,b:68), + (r:117,g:108,b:103), + (r:181,g:177,b:161), + (r:203,g:183,b:153), + (r:92,g:59,b:58), + (r:94,g:63,b:62), + (r:89,g:51,b:48), + (r:93,g:54,b:48), + (r:111,g:72,b:56), + (r:100,g:70,b:44), + (r:2,g:55,b:61), + (r:96,g:54,b:44), + (r:111,g:102,b:101), + (r:98,g:65,b:61), + (r:51,g:51,b:51), + (r:100,g:47,b:0), + (r:60,g:25,b:0), + (r:88,g:50,b:47), + (r:114,g:77,b:62), + (r:93,g:57,b:53), + (r:115,g:74,b:57), + (r:91,g:55,b:43), + (r:99,g:54,b:41), + (r:217,g:189,b:159), + (r:101,g:62,b:51), + (r:89,g:56,b:56), + (r:102,g:66,b:58), + (r:86,g:53,b:54), + (r:105,g:70,b:62), + (r:89,g:49,b:44), + (r:99,g:57,b:46), + (r:111,g:75,b:62), + (r:84,g:47,b:47), + (r:75,g:75,b:75), + (r:90,g:58,b:26), + (r:79,g:47,b:15), + (r:48,g:32,b:33), + (r:106,g:53,b:5), + (r:75,g:43,b:11), + (r:103,g:78,b:53), + (r:99,g:74,b:49), + (r:52,g:36,b:37), + (r:57,g:41,b:42), + (r:153,g:94,b:84), + (r:123,g:114,b:109), + (r:198,g:80,b:56), + (r:206,g:88,b:64), + (r:158,g:99,b:89), + (r:179,g:175,b:159), + (r:89,g:41,b:69), + (r:237,g:195,b:137), + (r:202,g:84,b:60), + (r:148,g:89,b:79), + (r:184,g:149,b:118), + (r:198,g:178,b:148), + (r:192,g:172,b:142), + (r:179,g:144,b:113), + (r:84,g:36,b:64), + (r:80,g:32,b:60), + (r:242,g:200,b:142), + (r:189,g:185,b:169), + (r:66,g:98,b:99), + (r:130,g:87,b:76), + (r:63,g:95,b:96), + (r:223,g:169,b:143), + (r:71,g:103,b:104), + (r:67,g:32,b:2), + (r:125,g:82,b:71), + (r:209,g:181,b:151), + (r:59,g:91,b:92), + (r:219,g:165,b:139), + (r:135,g:92,b:81), + (r:95,g:70,b:45), + (r:112,g:103,b:98), + (r:95,g:52,b:41), + (r:112,g:73,b:56), + (r:98,g:57,b:45), + (r:92,g:50,b:41), + (r:103,g:68,b:60), + (r:94,g:56,b:50), + (r:111,g:71,b:55), + (r:92,g:52,b:46), + (r:95,g:55,b:46), + (r:95,g:67,b:42), + (r:98,g:65,b:58), + (r:95,g:42,b:0), + (r:247,g:206,b:148), + (r:91,g:54,b:50), + (r:107,g:69,b:56), + (r:111,g:69,b:52), + (r:92,g:67,b:42), + (r:99,g:63,b:57), + (r:94,g:53,b:45), + (r:96,g:51,b:39), + (r:106,g:72,b:62), + (r:87,g:49,b:45), + (r:90,g:51,b:45), + (r:89,g:50,b:46), + (r:110,g:72,b:58), + (r:112,g:69,b:50), + (r:112,g:74,b:58), + (r:91,g:49,b:43), + (r:117,g:76,b:57), + (r:91,g:53,b:48), + (r:91,g:55,b:52), + (r:94,g:52,b:43), + ], + Wood: [ + (r:60,g:30,b:0), + ], + Snow: [ + (r:210,g:210,b:255), + (r:129,g:163,b:255), + (r:164,g:186,b:255), + (r:90,g:110,b:150), + (r:97,g:142,b:233), + (r:82,g:132,b:198), + (r:59,g:117,b:144), + (r:46,g:108,b:116), + (r:131,g:131,b:255), + (r:111,g:118,b:208), + (r:81,g:98,b:114), + (r:107,g:101,b:179), + (r:35,g:101,b:85), + (r:72,g:84,b:79), + (r:19,g:89,b:58), + (r:64,g:73,b:47), + (r:43,g:51,b:73), + (r:67,g:122,b:165), + (r:86,g:100,b:151), + (r:52,g:65,b:101), + (r:65,g:73,b:130), + (r:77,g:103,b:188), + (r:87,g:72,b:102), + (r:94,g:84,b:136), + (r:103,g:160,b:212), + (r:94,g:128,b:173), + (r:47,g:86,b:65), + (r:123,g:135,b:227), + (r:107,g:119,b:242), + (r:155,g:159,b:255), + (r:56,g:92,b:98), + (r:186,g:200,b:255), + (r:109,g:147,b:255), + (r:71,g:95,b:141), + (r:73,g:60,b:66), + (r:58,g:90,b:104), + (r:84,g:69,b:95), + (r:86,g:97,b:98), + (r:50,g:68,b:97), + (r:139,g:176,b:255), + (r:8,g:82,b:39), + (r:111,g:161,b:237), + (r:34,g:99,b:99), + (r:68,g:87,b:153), + (r:101,g:138,b:209), + (r:100,g:118,b:199), + (r:80,g:130,b:203), + (r:89,g:110,b:203), + (r:139,g:144,b:255), + (r:66,g:109,b:125), + (r:97,g:147,b:202), + (r:101,g:114,b:157), + (r:95,g:105,b:130), + (r:94,g:123,b:222), + (r:88,g:95,b:171), + (r:55,g:113,b:151), + (r:84,g:125,b:154), + (r:50,g:78,b:33), + (r:55,g:69,b:73), + (r:80,g:79,b:119), + (r:71,g:124,b:184), + (r:54,g:90,b:123), + (r:103,g:94,b:157), + (r:76,g:87,b:99), + (r:83,g:113,b:169), + (r:67,g:77,b:96), + (r:91,g:144,b:185), + (r:100,g:116,b:193), + (r:74,g:116,b:153), + (r:109,g:118,b:178), + (r:39,g:83,b:49), + (r:117,g:134,b:244), + (r:114,g:109,b:202), + (r:66,g:83,b:62), + (r:43,g:88,b:68), + (r:44,g:74,b:82), + (r:47,g:94,b:82), + (r:115,g:127,b:202), + (r:65,g:75,b:110), + (r:65,g:113,b:143), + (r:63,g:108,b:122), + (r:65,g:91,b:124), + (r:63,g:74,b:119), + (r:64,g:93,b:138), + (r:87,g:117,b:186), + (r:138,g:148,b:255), + (r:65,g:99,b:107), + (r:114,g:120,b:226), + (r:99,g:116,b:175), + (r:46,g:103,b:98), + (r:85,g:92,b:150), + (r:59,g:117,b:151), + (r:127,g:122,b:237), + (r:108,g:149,b:255), + (r:102,g:121,b:206), + (r:108,g:132,b:225), + (r:109,g:119,b:247), + (r:24,g:93,b:75), + (r:49,g:109,b:133), + (r:109,g:144,b:224), + (r:84,g:115,b:198), + (r:105,g:135,b:246), + (r:82,g:117,b:170), + (r:69,g:102,b:160), + (r:73,g:68,b:83), + (r:93,g:101,b:187), + (r:79,g:108,b:136), + (r:82,g:92,b:129), + (r:67,g:107,b:124), + (r:65,g:92,b:126), + (r:139,g:160,b:255), + (r:56,g:80,b:85), + (r:99,g:131,b:190), + (r:49,g:103,b:101), + (r:107,g:115,b:224), + (r:72,g:93,b:93), + (r:90,g:138,b:220), + (r:110,g:131,b:216), + (r:105,g:147,b:221), + (r:154,g:174,b:255), + (r:89,g:107,b:123), + (r:62,g:76,b:101), + (r:76,g:120,b:150), + (r:110,g:146,b:239), + (r:124,g:144,b:255), + (r:87,g:114,b:183), + (r:83,g:103,b:152), + (r:85,g:111,b:166), + (r:83,g:98,b:173), + (r:84,g:88,b:151), + (r:85,g:115,b:152), + (r:86,g:115,b:201), + (r:46,g:92,b:82), + (r:76,g:105,b:150), + (r:82,g:116,b:183), + (r:56,g:63,b:60), + (r:61,g:81,b:67), + (r:47,g:87,b:67), + (r:68,g:81,b:142), + (r:81,g:83,b:98), + (r:96,g:104,b:214), + (r:109,g:132,b:232), + (r:99,g:90,b:150), + (r:89,g:89,b:123), + (r:52,g:81,b:53), + (r:134,g:176,b:255), + (r:124,g:148,b:255), + (r:110,g:146,b:255), + (r:138,g:145,b:255), + (r:109,g:148,b:232), + (r:64,g:101,b:110), + (r:96,g:117,b:165), + (r:64,g:107,b:136), + (r:61,g:65,b:89), + (r:98,g:105,b:201), + (r:97,g:104,b:166), + (r:32,g:98,b:98), + (r:49,g:81,b:109), + (r:108,g:150,b:234), + (r:83,g:132,b:166), + (r:178,g:189,b:255), + (r:49,g:59,b:66), + (r:66,g:89,b:83), + (r:66,g:83,b:96), + (r:67,g:72,b:71), + (r:47,g:102,b:97), + (r:71,g:88,b:112), + (r:116,g:164,b:249), + (r:93,g:99,b:142), + (r:110,g:121,b:191), + (r:88,g:127,b:196), + (r:85,g:124,b:187), + (r:87,g:121,b:152), + (r:69,g:84,b:66), + (r:99,g:150,b:204), + (r:86,g:135,b:207), + (r:108,g:128,b:226), + (r:93,g:131,b:211), + (r:107,g:131,b:248), + (r:116,g:148,b:244), + (r:72,g:117,b:154), + (r:110,g:133,b:255), + (r:108,g:130,b:213), + (r:32,g:87,b:59), + (r:107,g:159,b:225), + (r:109,g:105,b:191), + (r:86,g:87,b:110), + (r:73,g:83,b:130), + (r:81,g:100,b:126), + (r:72,g:97,b:135), + (r:90,g:96,b:139), + (r:80,g:93,b:162), + (r:87,g:81,b:126), + (r:61,g:65,b:38), + (r:64,g:88,b:116), + (r:100,g:135,b:202), + (r:58,g:117,b:131), + (r:64,g:91,b:117), + (r:62,g:95,b:99), + (r:99,g:119,b:185), + (r:60,g:90,b:134), + (r:52,g:94,b:113), + (r:56,g:97,b:125), + (r:54,g:80,b:98), + (r:66,g:70,b:68), + (r:66,g:80,b:99), + (r:74,g:128,b:173), + (r:87,g:118,b:173), + (r:91,g:119,b:211), + (r:57,g:90,b:74), + (r:77,g:90,b:124), + (r:90,g:76,b:113), + (r:108,g:116,b:183), + (r:97,g:108,b:178), + (r:86,g:101,b:177), + (r:104,g:100,b:175), + (r:62,g:72,b:65), + (r:90,g:107,b:176), + (r:93,g:90,b:152), + (r:103,g:129,b:237), + (r:83,g:86,b:140), + (r:88,g:130,b:183), + (r:65,g:77,b:78), + (r:16,g:86,b:47), + (r:81,g:97,b:143), + (r:119,g:113,b:215), + (r:108,g:138,b:235), + (r:66,g:97,b:125), + (r:38,g:102,b:110), + (r:102,g:146,b:244), + (r:86,g:130,b:177), + (r:36,g:94,b:75), + (r:115,g:123,b:238), + (r:109,g:133,b:230), + (r:122,g:136,b:233), + (r:77,g:107,b:177), + (r:67,g:100,b:145), + (r:85,g:96,b:103), + (r:65,g:80,b:121), + (r:72,g:90,b:105), + (r:88,g:95,b:123), + (r:74,g:88,b:124), + (r:77,g:79,b:108), + (r:72,g:114,b:164), + (r:109,g:128,b:203), + (r:104,g:112,b:213), + (r:84,g:115,b:158), + (r:89,g:117,b:201), + (r:107,g:120,b:176), + (r:165,g:172,b:255), + (r:65,g:122,b:150), + (r:78,g:102,b:124), + (r:96,g:104,b:154), + (r:130,g:139,b:247), + (r:52,g:91,b:102), + (r:88,g:133,b:165), + ], + Air: [ + (r:0,g:0,b:0), + ], + Earth: [ + (r:90,g:110,b:150), + (r:71,g:31,b:11), + (r:48,g:68,b:18), + (r:128,g:102,b:73), + (r:68,g:88,b:38), + (r:115,g:107,b:103), + (r:87,g:75,b:92), + (r:57,g:103,b:110), + (r:85,g:50,b:35), + (r:35,g:101,b:85), + (r:95,g:64,b:63), + (r:68,g:46,b:65), + (r:117,g:61,b:30), + (r:90,g:93,b:120), + (r:154,g:124,b:81), + (r:60,g:76,b:74), + (r:38,g:56,b:49), + (r:28,g:96,b:73), + (r:63,g:54,b:85), + (r:152,g:122,b:80), + (r:94,g:96,b:62), + (r:40,g:27,b:66), + (r:60,g:68,b:114), + (r:133,g:84,b:47), + (r:81,g:124,b:178), + (r:44,g:24,b:34), + (r:14,g:72,b:31), + (r:81,g:58,b:36), + (r:91,g:79,b:20), + (r:171,g:152,b:101), + (r:59,g:115,b:141), + (r:101,g:141,b:155), + (r:95,g:136,b:218), + (r:38,g:34,b:81), + (r:93,g:154,b:184), + (r:15,g:10,b:43), + (r:145,g:74,b:18), + (r:111,g:128,b:127), + (r:64,g:91,b:151), + (r:87,g:130,b:149), + (r:86,g:108,b:89), + (r:82,g:98,b:77), + (r:37,g:70,b:90), + (r:32,g:96,b:24), + (r:62,g:88,b:81), + (r:63,g:83,b:140), + (r:104,g:82,b:83), + (r:102,g:122,b:121), + (r:40,g:54,b:79), + (r:133,g:131,b:107), + (r:14,g:41,b:62), + (r:153,g:105,b:56), + (r:109,g:97,b:37), + (r:63,g:120,b:152), + (r:43,g:84,b:52), + (r:82,g:47,b:32), + (r:81,g:57,b:68), + (r:49,g:53,b:42), + (r:43,g:53,b:80), + (r:83,g:39,b:9), + (r:132,g:106,b:81), + (r:86,g:102,b:146), + (r:118,g:87,b:13), + (r:78,g:99,b:15), + (r:51,g:16,b:1), + (r:22,g:71,b:65), + (r:109,g:83,b:80), + (r:114,g:143,b:149), + (r:83,g:79,b:45), + (r:83,g:81,b:80), + (r:19,g:92,b:47), + (r:188,g:169,b:110), + (r:82,g:81,b:58), + (r:19,g:18,b:77), + (r:62,g:65,b:51), + (r:43,g:63,b:13), + (r:48,g:54,b:80), + (r:48,g:98,b:77), + (r:46,g:79,b:80), + (r:77,g:116,b:124), + (r:22,g:26,b:23), + (r:24,g:53,b:43), + (r:50,g:93,b:22), + (r:102,g:91,b:81), + (r:82,g:83,b:95), + (r:62,g:80,b:88), + (r:44,g:82,b:100), + (r:69,g:81,b:139), + (r:43,g:49,b:101), + (r:48,g:88,b:52), + (r:61,g:51,b:21), + (r:72,g:74,b:19), + (r:69,g:82,b:117), + (r:110,g:76,b:49), + (r:106,g:80,b:77), + (r:84,g:81,b:43), + (r:83,g:87,b:20), + (r:132,g:77,b:40), + (r:122,g:80,b:16), + (r:142,g:83,b:18), + (r:111,g:81,b:55), + (r:83,g:75,b:80), + (r:79,g:100,b:168), + (r:15,g:54,b:46), + (r:79,g:81,b:114), + (r:47,g:79,b:29), + (r:103,g:107,b:123), + (r:88,g:119,b:199), + (r:102,g:105,b:105), + (r:173,g:139,b:83), + (r:153,g:137,b:99), + (r:82,g:76,b:80), + (r:99,g:52,b:18), + (r:63,g:36,b:37), + (r:80,g:133,b:157), + (r:110,g:103,b:82), + (r:51,g:54,b:36), + (r:100,g:142,b:238), + (r:37,g:47,b:60), + (r:80,g:100,b:50), + (r:48,g:77,b:45), + (r:67,g:69,b:47), + (r:83,g:103,b:78), + (r:98,g:67,b:35), + (r:82,g:62,b:48), + (r:82,g:53,b:52), + (r:50,g:31,b:44), + (r:31,g:39,b:40), + (r:77,g:100,b:106), + (r:61,g:105,b:116), + (r:67,g:82,b:112), + (r:21,g:11,b:37), + (r:49,g:52,b:39), + (r:103,g:81,b:26), + (r:128,g:139,b:125), + (r:121,g:103,b:54), + (r:83,g:50,b:55), + (r:31,g:21,b:48), + (r:48,g:54,b:60), + (r:47,g:67,b:63), + (r:73,g:97,b:130), + (r:49,g:81,b:103), + (r:9,g:91,b:28), + (r:28,g:73,b:45), + (r:47,g:100,b:76), + (r:102,g:81,b:81), + (r:71,g:66,b:98), + (r:43,g:54,b:81), + (r:92,g:89,b:111), + (r:66,g:44,b:43), + (r:103,g:91,b:100), + (r:95,g:138,b:173), + (r:43,g:84,b:81), + (r:88,g:116,b:112), + (r:37,g:101,b:104), + (r:122,g:82,b:31), + (r:118,g:83,b:59), + (r:117,g:101,b:79), + (r:105,g:94,b:12), + (r:117,g:99,b:57), + (r:98,g:107,b:132), + (r:168,g:132,b:78), + (r:138,g:122,b:91), + (r:136,g:97,b:29), + (r:38,g:62,b:31), + (r:47,g:54,b:46), + (r:27,g:75,b:47), + (r:18,g:56,b:50), + (r:12,g:85,b:46), + (r:66,g:59,b:79), + (r:66,g:84,b:49), + (r:42,g:85,b:46), + (r:64,g:55,b:23), + (r:27,g:40,b:75), + (r:110,g:80,b:30), + (r:82,g:76,b:39), + (r:62,g:94,b:66), + (r:79,g:63,b:81), + (r:52,g:40,b:71), + (r:53,g:102,b:88), + (r:43,g:105,b:116), + (r:61,g:53,b:80), + (r:56,g:27,b:20), + (r:148,g:93,b:43), + (r:101,g:128,b:138), + (r:104,g:129,b:144), + (r:155,g:126,b:82), + (r:104,g:123,b:131), + (r:111,g:122,b:114), + (r:126,g:125,b:104), + (r:53,g:64,b:98), + (r:48,g:72,b:60), + (r:87,g:80,b:63), + (r:102,g:60,b:47), + (r:84,g:80,b:42), + (r:129,g:78,b:45), + (r:67,g:53,b:40), + (r:59,g:73,b:31), + (r:138,g:96,b:59), + (r:33,g:38,b:41), + (r:46,g:51,b:44), + (r:102,g:105,b:115), + (r:144,g:109,b:71), + (r:79,g:94,b:81), + (r:27,g:68,b:18), + (r:48,g:53,b:60), + (r:118,g:80,b:64), + (r:77,g:117,b:143), + (r:118,g:88,b:76), + (r:78,g:116,b:161), + (r:63,g:92,b:98), + (r:69,g:83,b:107), + (r:115,g:71,b:44), + (r:67,g:117,b:112), + (r:117,g:82,b:16), + (r:84,g:82,b:62), + (r:100,g:99,b:78), + (r:52,g:83,b:119), + (r:30,g:54,b:64), + (r:117,g:82,b:36), + (r:43,g:36,b:80), + (r:51,g:69,b:81), + (r:47,g:30,b:45), + (r:97,g:125,b:151), + (r:29,g:80,b:30), + (r:65,g:54,b:63), + (r:66,g:81,b:76), + (r:76,g:72,b:63), + (r:58,g:77,b:62), + (r:48,g:78,b:80), + (r:82,g:78,b:79), + (r:101,g:87,b:97), + (r:162,g:120,b:67), + (r:83,g:67,b:28), + (r:82,g:43,b:16), + (r:131,g:67,b:23), + (r:36,g:80,b:67), + (r:51,g:87,b:114), + (r:33,g:96,b:57), + (r:92,g:95,b:40), + (r:92,g:84,b:47), + (r:102,g:82,b:44), + (r:59,g:35,b:57), + (r:77,g:102,b:115), + (r:72,g:106,b:128), + (r:77,g:83,b:118), + (r:71,g:103,b:144), + (r:86,g:63,b:45), + (r:31,g:57,b:46), + (r:61,g:94,b:128), + (r:76,g:102,b:152), + (r:66,g:90,b:22), + (r:83,g:64,b:44), + (r:80,g:60,b:20), + (r:69,g:82,b:85), + (r:56,g:80,b:124), + ], + GlowingRock: [ + (r:96,g:0,b:128), + ], + Water: [ + (r:0,g:0,b:0), + ], + Grass: [ + (r:90,g:110,b:150), + (r:128,g:102,b:73), + (r:167,g:132,b:79), + (r:47,g:71,b:39), + (r:94,g:80,b:53), + (r:182,g:156,b:99), + (r:110,g:100,b:100), + (r:12,g:70,b:30), + (r:50,g:84,b:76), + (r:84,g:76,b:85), + (r:62,g:47,b:54), + (r:103,g:54,b:36), + (r:43,g:106,b:99), + (r:32,g:96,b:24), + (r:70,g:86,b:19), + (r:24,g:89,b:56), + (r:28,g:47,b:56), + (r:98,g:108,b:132), + (r:106,g:81,b:58), + (r:94,g:50,b:40), + (r:69,g:89,b:114), + (r:48,g:41,b:85), + (r:156,g:109,b:58), + (r:130,g:66,b:23), + (r:196,g:180,b:119), + (r:82,g:111,b:185), + (r:97,g:82,b:19), + (r:69,g:82,b:146), + (r:45,g:107,b:102), + (r:45,g:61,b:103), + (r:120,g:103,b:39), + (r:151,g:138,b:107), + (r:96,g:115,b:57), + (r:98,g:113,b:67), + (r:66,g:99,b:48), + (r:124,g:134,b:74), + (r:26,g:20,b:73), + (r:59,g:66,b:100), + (r:29,g:67,b:32), + (r:80,g:66,b:74), + (r:61,g:67,b:30), + (r:94,g:105,b:88), + (r:61,g:110,b:136), + (r:59,g:68,b:101), + (r:93,g:105,b:12), + (r:96,g:73,b:24), + (r:124,g:125,b:107), + (r:44,g:67,b:70), + (r:68,g:68,b:60), + (r:95,g:99,b:124), + (r:143,g:119,b:88), + (r:105,g:118,b:130), + (r:102,g:120,b:63), + (r:97,g:81,b:86), + (r:152,g:117,b:63), + (r:60,g:67,b:126), + (r:8,g:101,b:33), + (r:93,g:81,b:57), + (r:69,g:70,b:55), + (r:31,g:79,b:58), + (r:93,g:106,b:43), + (r:30,g:102,b:72), + (r:76,g:99,b:67), + (r:8,g:56,b:42), + (r:131,g:115,b:95), + (r:77,g:67,b:49), + (r:65,g:92,b:99), + (r:120,g:88,b:12), + (r:46,g:30,b:63), + (r:136,g:90,b:52), + (r:70,g:68,b:102), + (r:76,g:96,b:167), + (r:97,g:96,b:41), + (r:56,g:104,b:14), + (r:47,g:87,b:56), + (r:75,g:68,b:33), + (r:45,g:61,b:48), + (r:113,g:79,b:35), + (r:146,g:116,b:78), + (r:125,g:98,b:71), + (r:99,g:105,b:73), + (r:92,g:87,b:105), + (r:50,g:84,b:103), + (r:115,g:115,b:116), + (r:119,g:116,b:59), + (r:25,g:68,b:48), + (r:44,g:84,b:101), + (r:115,g:118,b:86), + (r:95,g:86,b:101), + (r:86,g:67,b:29), + (r:52,g:91,b:32), + (r:52,g:69,b:31), + (r:51,g:84,b:22), + (r:52,g:84,b:56), + (r:137,g:116,b:71), + (r:61,g:57,b:79), + (r:84,g:88,b:36), + (r:40,g:65,b:91), + (r:55,g:67,b:51), + (r:96,g:62,b:57), + (r:53,g:39,b:71), + (r:58,g:86,b:57), + (r:112,g:89,b:74), + (r:39,g:70,b:87), + (r:63,g:69,b:81), + (r:61,g:68,b:67), + (r:70,g:69,b:101), + (r:62,g:91,b:91), + (r:25,g:67,b:52), + (r:132,g:85,b:31), + (r:32,g:75,b:26), + (r:30,g:47,b:78), + (r:70,g:111,b:155), + (r:167,g:143,b:96), + (r:77,g:95,b:133), + (r:53,g:100,b:119), + (r:179,g:166,b:116), + (r:98,g:63,b:53), + (r:96,g:97,b:70), + (r:133,g:117,b:70), + (r:48,g:105,b:17), + (r:49,g:67,b:30), + (r:21,g:87,b:37), + (r:63,g:85,b:69), + (r:83,g:116,b:56), + (r:141,g:138,b:89), + (r:49,g:49,b:66), + (r:81,g:49,b:54), + (r:103,g:95,b:71), + (r:117,g:86,b:53), + (r:97,g:85,b:19), + (r:113,g:87,b:31), + (r:117,g:84,b:15), + (r:42,g:68,b:68), + (r:45,g:98,b:37), + (r:66,g:82,b:41), + (r:74,g:107,b:12), + (r:88,g:88,b:17), + (r:78,g:90,b:54), + (r:88,g:92,b:54), + (r:52,g:92,b:33), + (r:80,g:93,b:37), + (r:68,g:92,b:21), + (r:112,g:64,b:23), + (r:100,g:100,b:115), + (r:117,g:111,b:84), + (r:41,g:69,b:56), + (r:84,g:68,b:68), + (r:75,g:66,b:91), + (r:69,g:54,b:39), + (r:93,g:92,b:24), + (r:99,g:85,b:57), + (r:37,g:96,b:57), + (r:38,g:95,b:86), + (r:108,g:101,b:54), + (r:67,g:62,b:63), + (r:61,g:73,b:84), + (r:52,g:68,b:49), + (r:51,g:55,b:39), + (r:81,g:93,b:87), + (r:31,g:82,b:75), + (r:98,g:70,b:32), + (r:139,g:107,b:56), + (r:128,g:99,b:70), + (r:129,g:106,b:36), + (r:168,g:153,b:110), + (r:59,g:92,b:133), + (r:94,g:109,b:141), + (r:45,g:44,b:50), + (r:145,g:129,b:73), + (r:151,g:122,b:81), + (r:9,g:86,b:25), + (r:90,g:69,b:41), + (r:69,g:83,b:143), + (r:97,g:83,b:44), + (r:51,g:67,b:70), + (r:54,g:33,b:59), + (r:74,g:51,b:67), + (r:63,g:102,b:57), + (r:35,g:81,b:45), + (r:151,g:136,b:90), + (r:84,g:85,b:71), + (r:75,g:86,b:57), + (r:64,g:89,b:100), + (r:55,g:82,b:119), + (r:95,g:91,b:82), + (r:18,g:89,b:57), + (r:69,g:85,b:85), + (r:74,g:98,b:146), + (r:19,g:102,b:45), + (r:79,g:112,b:169), + (r:96,g:126,b:69), + (r:79,g:83,b:99), + (r:52,g:48,b:89), + (r:81,g:115,b:63), + (r:24,g:54,b:42), + (r:121,g:84,b:53), + (r:13,g:67,b:31), + (r:61,g:96,b:102), + (r:87,g:93,b:57), + (r:147,g:133,b:103), + (r:97,g:82,b:71), + (r:99,g:103,b:89), + (r:66,g:67,b:65), + (r:119,g:121,b:64), + (r:50,g:56,b:80), + (r:33,g:59,b:61), + (r:39,g:33,b:60), + (r:28,g:39,b:63), + (r:115,g:115,b:99), + (r:49,g:97,b:67), + (r:42,g:97,b:86), + (r:42,g:85,b:57), + (r:46,g:73,b:89), + (r:113,g:108,b:71), + (r:149,g:97,b:47), + (r:49,g:69,b:19), + (r:29,g:70,b:30), + (r:24,g:98,b:25), + (r:31,g:95,b:55), + (r:26,g:83,b:22), + (r:36,g:68,b:71), + (r:94,g:66,b:42), + (r:85,g:68,b:56), + (r:51,g:60,b:64), + (r:55,g:83,b:19), + (r:58,g:60,b:111), + (r:71,g:91,b:110), + (r:70,g:81,b:124), + (r:68,g:77,b:102), + (r:71,g:105,b:143), + (r:129,g:118,b:94), + (r:94,g:66,b:68), + (r:58,g:52,b:65), + (r:9,g:75,b:44), + (r:115,g:86,b:68), + (r:82,g:64,b:63), + (r:153,g:116,b:71), + (r:123,g:102,b:54), + (r:99,g:76,b:72), + (r:99,g:110,b:46), + (r:30,g:68,b:39), + (r:190,g:167,b:106), + (r:126,g:81,b:28), + (r:50,g:54,b:60), + (r:113,g:64,b:40), + (r:96,g:92,b:40), + (r:68,g:79,b:129), + (r:82,g:95,b:14), + (r:130,g:116,b:80), + (r:79,g:78,b:46), + (r:73,g:68,b:33), + (r:74,g:88,b:22), + (r:51,g:71,b:57), + (r:72,g:90,b:52), + (r:50,g:85,b:42), + ], + WeakRock: [ + (r:90,g:110,b:150), + (r:190,g:185,b:207), + (r:39,g:22,b:80), + (r:71,g:50,b:17), + (r:88,g:69,b:110), + (r:229,g:147,b:46), + (r:209,g:127,b:26), + (r:76,g:93,b:128), + (r:49,g:46,b:89), + (r:75,g:95,b:150), + (r:95,g:102,b:127), + (r:202,g:197,b:219), + (r:75,g:110,b:137), + (r:61,g:40,b:7), + (r:219,g:137,b:36), + (r:90,g:95,b:142), + (r:30,g:13,b:71), + (r:96,g:77,b:118), + (r:40,g:37,b:80), + (r:76,g:112,b:154), + (r:237,g:155,b:54), + (r:89,g:110,b:136), + (r:71,g:97,b:139), + (r:82,g:103,b:145), + (r:86,g:97,b:131), + (r:196,g:191,b:213), + (r:45,g:28,b:86), + (r:82,g:63,b:104), + (r:34,g:31,b:74), + (r:81,g:95,b:139), + (r:90,g:100,b:150), + (r:82,g:104,b:135), + (r:81,g:113,b:143), + (r:98,g:108,b:133), + (r:73,g:102,b:132), + (r:66,g:45,b:12), + (r:76,g:55,b:22), + (r:91,g:72,b:113), + (r:214,g:132,b:31), + (r:224,g:142,b:41), + (r:75,g:104,b:150), + (r:87,g:104,b:142), + (r:84,g:95,b:149), + (r:79,g:96,b:131), + (r:84,g:103,b:153), + (r:91,g:102,b:135), + (r:94,g:110,b:143), + (r:83,g:110,b:150), + (r:75,g:104,b:142), + (r:85,g:95,b:148), + (r:75,g:110,b:146), + (r:85,g:98,b:138), + (r:34,g:17,b:75), + (r:45,g:42,b:85), + (r:233,g:151,b:50), + (r:85,g:106,b:148), + (r:77,g:97,b:144), + (r:84,g:105,b:142), + (r:82,g:110,b:138), + (r:75,g:104,b:143), + (r:85,g:105,b:135), + (r:74,g:100,b:155), + (r:85,g:110,b:141), + (r:77,g:101,b:137), + (r:84,g:95,b:143), + (r:90,g:95,b:135), + (r:84,g:99,b:142), + (r:76,g:95,b:136), + (r:76,g:95,b:142), + (r:79,g:100,b:149), + (r:92,g:106,b:139), + (r:85,g:95,b:139), + (r:84,g:108,b:143), + (r:78,g:109,b:142), + (r:84,g:99,b:136), + (r:87,g:105,b:153), + (r:86,g:99,b:144), + (r:89,g:100,b:139), + (r:89,g:108,b:145), + (r:187,g:182,b:204), + (r:193,g:188,b:210), + (r:199,g:194,b:216), + (r:37,g:34,b:77), + (r:42,g:25,b:83), + (r:85,g:66,b:107), + (r:206,g:124,b:23), + (r:79,g:107,b:149), + (r:79,g:100,b:142), + (r:90,g:95,b:149), + (r:82,g:114,b:153), + (r:76,g:106,b:143), + (r:84,g:105,b:148), + (r:95,g:108,b:137), + (r:90,g:103,b:146), + (r:71,g:104,b:139), + (r:78,g:105,b:138), + (r:73,g:106,b:132), + (r:85,g:100,b:150), + (r:90,g:102,b:145), + (r:82,g:102,b:139), + (r:75,g:103,b:135), + (r:84,g:100,b:148), + (r:90,g:98,b:129), + (r:81,g:99,b:143), + (r:85,g:109,b:138), + (r:75,g:105,b:148), + (r:80,g:105,b:145), + (r:90,g:106,b:138), + (r:90,g:110,b:140), + (r:82,g:100,b:132), + (r:75,g:102,b:142), + (r:80,g:95,b:147), + (r:84,g:110,b:142), + (r:85,g:110,b:150), + (r:75,g:100,b:147), + (r:80,g:110,b:146), + (r:94,g:105,b:134), + (r:81,g:104,b:150), + (r:85,g:102,b:141), + (r:79,g:108,b:135), + (r:78,g:104,b:147), + (r:90,g:98,b:138), + (r:80,g:97,b:135), + (r:90,g:105,b:150), + (r:85,g:95,b:135), + (r:85,g:109,b:145), + (r:87,g:100,b:135), + (r:92,g:101,b:131), + (r:90,g:103,b:135), + (r:82,g:103,b:139), + (r:75,g:109,b:150), + (r:84,g:108,b:135), + (r:85,g:106,b:139), + (r:90,g:98,b:146), + (r:86,g:95,b:143), + (r:84,g:95,b:136), + (r:84,g:95,b:142), + (r:80,g:105,b:142), + (r:76,g:99,b:140), + (r:87,g:103,b:149), + (r:79,g:101,b:135), + (r:78,g:96,b:142), + (r:78,g:98,b:138), + (r:86,g:102,b:147), + (r:79,g:104,b:143), + (r:75,g:96,b:147), + (r:84,g:96,b:148), + (r:83,g:100,b:150), + (r:79,g:95,b:150), + (r:80,g:101,b:148), + (r:75,g:99,b:149), + (r:84,g:104,b:148), + (r:75,g:100,b:143), + (r:80,g:113,b:150), + (r:85,g:103,b:145), + (r:89,g:104,b:139), + (r:75,g:108,b:140), + (r:84,g:98,b:145), + (r:89,g:107,b:146), + (r:90,g:106,b:142), + (r:77,g:110,b:143), + (r:90,g:103,b:145), + (r:75,g:107,b:135), + (r:84,g:106,b:138), + (r:88,g:95,b:138), + (r:78,g:98,b:148), + (r:79,g:101,b:145), + (r:77,g:105,b:139), + (r:85,g:109,b:146), + (r:88,g:95,b:146), + (r:84,g:97,b:139), + (r:78,g:110,b:138), + (r:78,g:103,b:135), + (r:85,g:99,b:139), + (r:87,g:104,b:138), + (r:89,g:102,b:138), + (r:84,g:110,b:146), + (r:32,g:15,b:73), + (r:36,g:19,b:77), + (r:68,g:47,b:14), + (r:73,g:52,b:19), + (r:64,g:43,b:10), + (r:47,g:44,b:87), + (r:93,g:74,b:115), + (r:42,g:39,b:82), + (r:90,g:71,b:112), + (r:77,g:110,b:142), + (r:221,g:139,b:38), + (r:226,g:144,b:43), + (r:217,g:135,b:34), + (r:231,g:149,b:48), + (r:212,g:130,b:29), + (r:75,g:99,b:135), + (r:85,g:102,b:137), + (r:235,g:153,b:52), + (r:87,g:97,b:150), + (r:77,g:96,b:139), + (r:77,g:107,b:146), + (r:82,g:105,b:149), + (r:80,g:107,b:148), + (r:83,g:102,b:135), + (r:89,g:96,b:139), + (r:90,g:100,b:144), + (r:87,g:99,b:145), + (r:84,g:103,b:149), + (r:88,g:107,b:135), + (r:78,g:102,b:138), + (r:80,g:96,b:143), + (r:76,g:106,b:149), + (r:81,g:98,b:140), + (r:81,g:106,b:139), + (r:80,g:110,b:149), + (r:86,g:103,b:146), + (r:81,g:109,b:143), + (r:86,g:106,b:145), + (r:81,g:98,b:146), + (r:78,g:95,b:147), + (r:90,g:99,b:135), + (r:78,g:104,b:149), + (r:75,g:103,b:148), + (r:84,g:100,b:137), + (r:78,g:95,b:137), + (r:83,g:105,b:143), + (r:85,g:110,b:135), + (r:74,g:97,b:138), + (r:81,g:110,b:141), + (r:85,g:107,b:142), + (r:87,g:102,b:144), + (r:82,g:103,b:132), + (r:75,g:102,b:139), + (r:75,g:95,b:143), + (r:90,g:103,b:138), + (r:90,g:98,b:141), + (r:77,g:107,b:142), + (r:87,g:97,b:136), + (r:78,g:95,b:136), + (r:89,g:102,b:148), + (r:87,g:108,b:140), + (r:85,g:103,b:139), + (r:85,g:95,b:138), + (r:78,g:103,b:141), + (r:75,g:103,b:138), + (r:81,g:104,b:148), + (r:83,g:108,b:148), + (r:78,g:101,b:148), + (r:81,g:98,b:137), + (r:89,g:97,b:144), + (r:79,g:95,b:143), + (r:85,g:95,b:145), + (r:75,g:102,b:135), + (r:82,g:97,b:150), + (r:77,g:105,b:136), + (r:84,g:101,b:144), + (r:87,g:98,b:141), + (r:90,g:102,b:141), + (r:73,g:96,b:141), + ], + Rock: [ + (r:90,g:110,b:150), + (r:63,g:77,b:105), + (r:90,g:94,b:122), + (r:95,g:81,b:93), + (r:115,g:112,b:112), + (r:59,g:107,b:116), + (r:150,g:150,b:175), + (r:55,g:53,b:74), + (r:85,g:59,b:58), + (r:91,g:122,b:181), + (r:40,g:98,b:87), + (r:119,g:89,b:76), + (r:69,g:90,b:79), + (r:77,g:64,b:84), + (r:66,g:86,b:130), + (r:40,g:74,b:78), + (r:68,g:112,b:139), + (r:90,g:92,b:118), + (r:108,g:111,b:122), + (r:101,g:72,b:70), + (r:56,g:105,b:120), + (r:83,g:131,b:157), + (r:54,g:55,b:97), + (r:77,g:95,b:100), + (r:89,g:114,b:119), + (r:112,g:95,b:96), + (r:79,g:84,b:119), + (r:80,g:70,b:78), + (r:70,g:63,b:60), + (r:90,g:101,b:99), + (r:80,g:78,b:107), + (r:56,g:95,b:99), + (r:59,g:73,b:85), + (r:78,g:95,b:145), + (r:93,g:119,b:132), + (r:75,g:108,b:122), + (r:86,g:109,b:168), + (r:77,g:104,b:117), + (r:44,g:108,b:102), + (r:61,g:72,b:120), + (r:79,g:77,b:97), + (r:43,g:67,b:62), + (r:49,g:77,b:90), + (r:66,g:67,b:90), + (r:99,g:129,b:150), + (r:60,g:87,b:119), + (r:55,g:90,b:89), + (r:103,g:100,b:110), + (r:56,g:64,b:113), + (r:79,g:81,b:89), + (r:62,g:55,b:89), + (r:67,g:86,b:90), + (r:91,g:102,b:136), + (r:75,g:115,b:158), + (r:102,g:107,b:125), + (r:71,g:53,b:73), + (r:78,g:84,b:120), + (r:90,g:116,b:153), + (r:84,g:101,b:154), + (r:81,g:123,b:147), + (r:93,g:134,b:171), + (r:106,g:82,b:82), + (r:80,g:82,b:89), + (r:68,g:70,b:73), + (r:80,g:93,b:107), + (r:43,g:98,b:91), + (r:78,g:96,b:130), + (r:43,g:51,b:66), + (r:126,g:120,b:107), + (r:95,g:89,b:105), + (r:86,g:88,b:116), + (r:99,g:90,b:100), + (r:116,g:90,b:83), + (r:66,g:96,b:109), + (r:54,g:68,b:72), + (r:67,g:96,b:120), + (r:48,g:53,b:86), + (r:93,g:73,b:82), + (r:67,g:75,b:118), + (r:79,g:80,b:111), + (r:51,g:82,b:95), + (r:72,g:83,b:107), + (r:67,g:81,b:91), + (r:106,g:89,b:94), + (r:78,g:52,b:61), + (r:47,g:77,b:88), + (r:62,g:77,b:87), + (r:58,g:79,b:72), + (r:79,g:82,b:95), + (r:81,g:103,b:119), + (r:81,g:111,b:135), + (r:87,g:101,b:123), + (r:79,g:101,b:145), + (r:88,g:70,b:67), + (r:101,g:120,b:118), + (r:105,g:118,b:133), + (r:90,g:100,b:134), + (r:82,g:89,b:100), + (r:117,g:107,b:100), + (r:81,g:59,b:71), + (r:80,g:69,b:91), + (r:48,g:66,b:85), + (r:57,g:83,b:107), + (r:82,g:121,b:171), + (r:76,g:75,b:78), + (r:66,g:99,b:133), + (r:63,g:64,b:102), + (r:79,g:65,b:69), + (r:90,g:90,b:91), + (r:71,g:101,b:134), + (r:40,g:75,b:78), + (r:105,g:108,b:119), + (r:75,g:112,b:149), + (r:95,g:125,b:192), + (r:93,g:120,b:144), + (r:100,g:100,b:120), + (r:71,g:74,b:86), + (r:92,g:103,b:113), + (r:61,g:56,b:63), + (r:60,g:68,b:87), + (r:60,g:58,b:76), + (r:59,g:61,b:86), + (r:45,g:59,b:76), + (r:58,g:56,b:63), + (r:77,g:93,b:112), + (r:97,g:125,b:151), + (r:117,g:118,b:120), + (r:51,g:102,b:109), + (r:98,g:111,b:139), + (r:55,g:112,b:129), + (r:78,g:120,b:141), + (r:78,g:102,b:143), + (r:79,g:68,b:90), + (r:55,g:71,b:98), + (r:91,g:124,b:161), + (r:89,g:112,b:124), + (r:73,g:72,b:105), + (r:67,g:96,b:95), + (r:65,g:104,b:119), + (r:61,g:86,b:101), + (r:68,g:86,b:117), + (r:60,g:95,b:111), + (r:78,g:73,b:77), + (r:81,g:100,b:120), + (r:79,g:101,b:131), + (r:65,g:108,b:127), + (r:86,g:77,b:98), + (r:83,g:81,b:86), + (r:89,g:74,b:87), + (r:56,g:63,b:90), + (r:91,g:94,b:107), + (r:102,g:98,b:108), + (r:102,g:104,b:119), + (r:103,g:90,b:99), + (r:110,g:121,b:116), + (r:68,g:80,b:121), + (r:80,g:112,b:147), + (r:78,g:109,b:135), + (r:60,g:86,b:91), + (r:54,g:81,b:101), + (r:113,g:89,b:85), + (r:80,g:90,b:119), + (r:76,g:93,b:90), + (r:93,g:83,b:86), + (r:67,g:101,b:120), + (r:100,g:100,b:98), + (r:67,g:64,b:81), + (r:46,g:49,b:77), + (r:89,g:89,b:92), + (r:106,g:114,b:108), + (r:59,g:51,b:86), + (r:75,g:90,b:87), + (r:107,g:90,b:89), + (r:50,g:111,b:113), + (r:102,g:118,b:128), + (r:36,g:67,b:69), + (r:59,g:75,b:90), + (r:103,g:83,b:87), + (r:81,g:110,b:152), + (r:46,g:87,b:87), + (r:61,g:83,b:111), + (r:71,g:96,b:119), + (r:64,g:87,b:87), + (r:65,g:69,b:110), + (r:65,g:79,b:108), + (r:64,g:74,b:99), + (r:64,g:63,b:99), + (r:62,g:71,b:116), + (r:63,g:81,b:115), + (r:49,g:90,b:90), + (r:84,g:116,b:161), + (r:60,g:71,b:78), + (r:86,g:100,b:146), + (r:111,g:105,b:107), + (r:72,g:81,b:102), + (r:85,g:70,b:86), + (r:65,g:77,b:78), + (r:67,g:61,b:70), + (r:54,g:48,b:66), + (r:54,g:82,b:80), + (r:70,g:88,b:99), + (r:85,g:90,b:99), + (r:67,g:47,b:67), + (r:97,g:101,b:120), + (r:88,g:83,b:106), + (r:86,g:107,b:142), + (r:94,g:105,b:134), + (r:80,g:101,b:135), + (r:74,g:81,b:119), + (r:71,g:76,b:89), + (r:86,g:110,b:134), + (r:60,g:54,b:90), + (r:50,g:88,b:102), + (r:89,g:117,b:136), + (r:90,g:116,b:174), + (r:100,g:122,b:135), + (r:101,g:111,b:134), + (r:80,g:88,b:109), + (r:78,g:101,b:128), + (r:98,g:96,b:116), + (r:50,g:74,b:89), + (r:72,g:67,b:97), + (r:61,g:96,b:117), + (r:78,g:86,b:104), + (r:61,g:98,b:103), + (r:75,g:87,b:129), + (r:49,g:101,b:99), + (r:79,g:62,b:59), + (r:60,g:56,b:73), + (r:74,g:65,b:74), + (r:73,g:56,b:75), + (r:58,g:61,b:77), + (r:53,g:72,b:77), + (r:44,g:69,b:73), + (r:43,g:60,b:72), + (r:70,g:61,b:89), + (r:45,g:49,b:75), + (r:55,g:47,b:77), + (r:82,g:99,b:138), + (r:62,g:81,b:96), + (r:52,g:62,b:102), + (r:79,g:88,b:105), + (r:66,g:51,b:77), + (r:82,g:91,b:124), + (r:107,g:99,b:102), + (r:61,g:90,b:105), + (r:118,g:118,b:118), + (r:62,g:65,b:64), + (r:92,g:75,b:73), + (r:70,g:93,b:138), + (r:76,g:97,b:121), + (r:81,g:99,b:129), + (r:103,g:110,b:129), + (r:77,g:100,b:138), + (r:87,g:65,b:74), + (r:72,g:74,b:90), + ], +} \ No newline at end of file diff --git a/world/examples/world_block_statistics.rs b/world/examples/world_block_statistics.rs index dbd4d2948c..a6c0138e8b 100644 --- a/world/examples/world_block_statistics.rs +++ b/world/examples/world_block_statistics.rs @@ -1,5 +1,6 @@ +use clap::{App, Arg, SubCommand}; use common::{ - terrain::TerrainChunkSize, + terrain::{BlockKind, TerrainChunkSize}, vol::{IntoVolIterator, RectVolSize}, }; use fallible_iterator::FallibleIterator; @@ -12,6 +13,9 @@ use rusqlite::{Connection, ToSql, Transaction, TransactionBehavior, NO_PARAMS}; use std::{ collections::{HashMap, HashSet}, error::Error, + fs::File, + io::Write, + str::FromStr, sync::mpsc, time::{SystemTime, UNIX_EPOCH}, }; @@ -21,8 +25,8 @@ use veloren_world::{ World, }; -fn block_statistics_db() -> Result> { - let conn = Connection::open("block_statistics.sqlite")?; +fn block_statistics_db(db_path: &str) -> Result> { + let conn = Connection::open(db_path)?; #[rustfmt::skip] conn.execute_batch(" CREATE TABLE IF NOT EXISTS chunk ( @@ -54,7 +58,7 @@ fn block_statistics_db() -> Result> { Ok(conn) } -fn main() -> Result<(), Box> { +fn generate(db_path: &str, ymin: Option, ymax: Option) -> Result<(), Box> { common_frontend::init_stdout(None); println!("Loading world"); let pool = ThreadPoolBuilder::new().build().unwrap(); @@ -68,7 +72,7 @@ fn main() -> Result<(), Box> { ); println!("Loaded world"); - let conn = block_statistics_db()?; + let conn = block_statistics_db(db_path)?; let existing_chunks: HashSet<(i32, i32)> = conn .prepare("SELECT xcoord, ycoord FROM chunk")? @@ -79,13 +83,13 @@ fn main() -> Result<(), Box> { let sz = world.sim().get_size(); let (tx, rx) = mpsc::channel(); rayon::spawn(move || { - let coords: Vec<_> = (1..sz.y) + let coords: Vec<_> = (ymin.unwrap_or(1)..ymax.unwrap_or(sz.y as i32)) .into_iter() .flat_map(move |y| { let tx = tx.clone(); - (1..sz.x) + (1..sz.x as i32) .into_iter() - .map(move |x| (tx.clone(), x as i32, y as i32)) + .map(move |x| (tx.clone(), x, y)) }) .collect(); coords.into_par_iter().for_each(|(tx, x, y)| { @@ -107,7 +111,7 @@ fn main() -> Result<(), Box> { let hi = TerrainChunkSize::RECT_SIZE.as_().with_z(chunk.get_max_z()); let height = chunk.get_max_z() - chunk.get_min_z(); for (_, block) in chunk.vol_iter(lo, hi) { - let mut rgb = block.get_color().unwrap_or(Rgb::new(0, 0, 0)); + let mut rgb = block.get_color().unwrap_or_else(|| Rgb::new(0, 0, 0)); let color: [f32; 3] = [rgb.r as _, rgb.g as _, rgb.b as _]; if let Ok((dist, nearest)) = block_colors.nearest_one(&color, &squared_euclidean) @@ -152,7 +156,7 @@ fn main() -> Result<(), Box> { REPLACE INTO chunk (xcoord, ycoord, height, start_time, end_time) VALUES (?1, ?2, ?3, ?4, ?5) ")?; - println!("Inserting results for chunk at ({}, {})", x, y); + println!("Inserting results for chunk at ({}, {}): {}", x, y, i); for ((kind, color), count) in block_counts.iter() { insert_block.execute(&[ &x as &dyn ToSql, @@ -182,3 +186,99 @@ fn main() -> Result<(), Box> { } Ok(()) } + +fn palette(conn: Connection) -> Result<(), Box> { + let mut stmt = + conn.prepare("SELECT kind, r, g, b, SUM(quantity) FROM block GROUP BY kind, r, g, b")?; + let mut block_colors: HashMap, i64)>> = HashMap::new(); + + let mut rows = stmt.query(NO_PARAMS)?; + while let Some(row) = rows.next()? { + let kind = BlockKind::from_str(&row.get::<_, String>(0)?)?; + let rgb: Rgb = Rgb::new(row.get(1)?, row.get(2)?, row.get(3)?); + let count: i64 = row.get(4)?; + block_colors + .entry(kind) + .or_insert_with(Vec::new) + .push((rgb, count)); + } + for (_, v) in block_colors.iter_mut() { + v.sort_by(|a, b| b.1.cmp(&a.1)); + } + + let mut palettes: HashMap>> = HashMap::new(); + for (kind, colors) in block_colors.iter() { + let palette = palettes.entry(*kind).or_insert_with(Vec::new); + if colors.len() <= 256 { + for (color, _) in colors { + palette.push(*color); + } + println!("{:?}: {:?}", kind, palette); + continue; + } + let mut radius = 1024.0; + let mut tree = KdTree::, 3>::new(); + while palette.len() < 256 { + if let Some((color, _)) = colors.iter().find(|(color, _)| { + tree.nearest_one( + &[color.r as f32, color.g as f32, color.b as f32], + &squared_euclidean, + ) + .map(|(dist, _)| dist > radius) + .unwrap_or(true) + }) { + palette.push(*color); + tree.add(&[color.r as f32, color.g as f32, color.b as f32], *color)?; + println!("{:?}, {:?}: {:?}", kind, radius, *color); + } else { + radius -= 1.0; + } + } + } + let mut f = File::create("palettes.ron")?; + let pretty = ron::ser::PrettyConfig::default().with_depth_limit(2); + write!(f, "{}", ron::ser::to_string_pretty(&palettes, pretty)?)?; + Ok(()) +} + +fn main() -> Result<(), Box> { + let mut app = App::new("world_block_statistics") + .version(common::util::DISPLAY_VERSION_LONG.as_str()) + .author("The veloren devs ") + .about("Compute and process block statistics on generated chunks") + .subcommand( + SubCommand::with_name("generate") + .about("Generate block statistics") + .args(&[ + Arg::with_name("database") + .required(true) + .help("File to generate/resume generation"), + Arg::with_name("ymin").long("ymin").takes_value(true), + Arg::with_name("ymax").long("ymax").takes_value(true), + ]), + ) + .subcommand( + SubCommand::with_name("palette") + .about("Compute a palette from previously gathered statistics") + .args(&[Arg::with_name("database").required(true)]), + ); + + let matches = app.clone().get_matches(); + match matches.subcommand() { + ("generate", Some(matches)) => { + let db_path = matches.value_of("database").expect("database is required"); + let ymin = matches.value_of("ymin").and_then(|x| i32::from_str(x).ok()); + let ymax = matches.value_of("ymax").and_then(|x| i32::from_str(x).ok()); + generate(db_path, ymin, ymax)?; + }, + ("palette", Some(matches)) => { + let conn = + Connection::open(&matches.value_of("database").expect("database is required"))?; + palette(conn)?; + }, + _ => { + app.print_help()?; + }, + } + Ok(()) +}