|
| 1 | +use crate::error::Result; |
| 2 | +use rand::*; |
| 3 | +use std::fmt::Write; |
| 4 | +use std::rc::Rc; |
| 5 | + |
| 6 | +byond_fn! { worley_generate(region_size, threshold, node_per_region_chance, width, height) { |
| 7 | + worley_noise(region_size, threshold, node_per_region_chance, width, height).ok() |
| 8 | +} } |
| 9 | + |
| 10 | +// This is a quite complex algorithm basically what it does is it creates 2 maps, one filled with cells and the other with 'regions' that map onto these cells. |
| 11 | +// Each region can spawn 1 node, the cell then determines wether it is true or false depending on the distance from it to the nearest node in the region minus the second closest node. |
| 12 | +// If this distance is greater than the threshold then the cell is true, otherwise it is false. |
| 13 | +fn worley_noise( |
| 14 | + str_reg_size: &str, |
| 15 | + str_positive_threshold: &str, |
| 16 | + str_node_per_region_chance: &str, |
| 17 | + str_width: &str, |
| 18 | + str_height: &str, |
| 19 | +) -> Result<String> { |
| 20 | + let region_size = str_reg_size.parse::<i32>()?; |
| 21 | + let positive_threshold = str_positive_threshold.parse::<f32>()?; |
| 22 | + let width = str_width.parse::<i32>()?; |
| 23 | + let height = str_height.parse::<i32>()?; |
| 24 | + let node_per_region_chance = str_node_per_region_chance.parse::<f32>()?; |
| 25 | + |
| 26 | + //i fucking mixed up width and height again. it really doesnt matter but here is a comment just warning you. |
| 27 | + let mut map = Map::new(region_size, height, width, node_per_region_chance); |
| 28 | + |
| 29 | + map.generate_noise(positive_threshold as f32); |
| 30 | + |
| 31 | + let mut output = String::new(); |
| 32 | + |
| 33 | + for row in map.cell_map { |
| 34 | + for cell in row { |
| 35 | + if cell.value { |
| 36 | + let _ = write!(output, "1"); |
| 37 | + } else { |
| 38 | + let _ = write!(output, "0"); |
| 39 | + } |
| 40 | + } |
| 41 | + } |
| 42 | + Ok(output) |
| 43 | +} |
| 44 | + |
| 45 | +struct Map { |
| 46 | + region_size: i32, |
| 47 | + region_map: Vec<Vec<Rc<Region>>>, |
| 48 | + cell_map: Vec<Vec<Cell>>, |
| 49 | + cell_map_width: i32, |
| 50 | + cell_map_height: i32, |
| 51 | + node_chance: f32, |
| 52 | +} |
| 53 | + |
| 54 | +impl Map { |
| 55 | + fn new(region_size: i32, cell_map_width: i32, cell_map_height: i32, node_chance: f32) -> Map { |
| 56 | + let mut map = Map { |
| 57 | + region_size: region_size, |
| 58 | + region_map: Vec::new(), |
| 59 | + cell_map: Vec::new(), |
| 60 | + cell_map_width: cell_map_width, |
| 61 | + cell_map_height: cell_map_height, |
| 62 | + node_chance: node_chance, |
| 63 | + }; |
| 64 | + |
| 65 | + map.init_regions(); |
| 66 | + |
| 67 | + for x in 0..cell_map_width { |
| 68 | + map.cell_map.push(Vec::new()); |
| 69 | + for y in 0..cell_map_height { |
| 70 | + let cell = Cell::new( |
| 71 | + x, |
| 72 | + y, |
| 73 | + map.region_map[(x / region_size) as usize][(y / region_size) as usize].clone(), |
| 74 | + ); |
| 75 | + map.cell_map[(x) as usize].push(cell); |
| 76 | + } |
| 77 | + } |
| 78 | + map |
| 79 | + } |
| 80 | + fn init_regions(&mut self) { |
| 81 | + let mut rng = rand::thread_rng(); |
| 82 | + |
| 83 | + let regions_x = self.cell_map_width / self.region_size; |
| 84 | + let regions_y = self.cell_map_height / self.region_size; |
| 85 | + //those two variables ensure that we dont EVER panic due to not having enough nodes spawned for the distance algorithm to function. |
| 86 | + let mut node_count = 0; |
| 87 | + let mut distance_in_regions_since_last_node = 0; |
| 88 | + |
| 89 | + for i in 0..regions_x { |
| 90 | + distance_in_regions_since_last_node += 1; |
| 91 | + self.region_map.push(Vec::new()); |
| 92 | + for j in 0..regions_y { |
| 93 | + distance_in_regions_since_last_node += 1; |
| 94 | + let mut region = Region::new(i, j); |
| 95 | + if rng.gen_range(0..100) as f32 <= self.node_chance || node_count < 2 { |
| 96 | + let xcord = rng.gen_range(0..self.region_size); |
| 97 | + let ycord = rng.gen_range(0..self.region_size); |
| 98 | + let node = |
| 99 | + Node::new(xcord + i * self.region_size, ycord + j * self.region_size); |
| 100 | + region.node = Some(node); |
| 101 | + node_count += 1; |
| 102 | + distance_in_regions_since_last_node = 0; |
| 103 | + } |
| 104 | + |
| 105 | + if distance_in_regions_since_last_node > 3 { |
| 106 | + node_count = 0; |
| 107 | + } |
| 108 | + |
| 109 | + let rcregion = Rc::new(region); |
| 110 | + |
| 111 | + self.region_map[i as usize].push(rcregion); |
| 112 | + } |
| 113 | + } |
| 114 | + } |
| 115 | + |
| 116 | + fn get_regions_in_bound(&self, x: i32, y: i32, radius: i32) -> Vec<&Region> { |
| 117 | + let mut regions = Vec::new(); |
| 118 | + let x_min = x - radius; |
| 119 | + let x_max = x + radius; |
| 120 | + let y_min = y - radius; |
| 121 | + let y_max = y + radius; |
| 122 | + for i in x_min..x_max { |
| 123 | + for j in y_min..y_max { |
| 124 | + let region_x = i; |
| 125 | + let region_y = j; |
| 126 | + if region_x >= 0 |
| 127 | + && region_x < self.region_map.len() as i32 |
| 128 | + && region_y >= 0 |
| 129 | + && region_y < self.region_map[region_x as usize].len() as i32 |
| 130 | + { |
| 131 | + let region = &self.region_map[region_x as usize][region_y as usize]; |
| 132 | + regions.push(region.as_ref()); |
| 133 | + } |
| 134 | + } |
| 135 | + } |
| 136 | + regions |
| 137 | + } |
| 138 | + |
| 139 | + fn generate_noise(&mut self, threshold: f32) { |
| 140 | + for i in 0..self.cell_map.len() { |
| 141 | + for j in 0..self.cell_map[i as usize].len() { |
| 142 | + let cell = &self.cell_map[i as usize][j as usize]; |
| 143 | + let region = &self.region_map[cell.region.as_ref().reg_x as usize] |
| 144 | + [cell.region.as_ref().reg_y as usize]; |
| 145 | + let neighbours = self.get_regions_in_bound(region.reg_x, region.reg_y, 3); |
| 146 | + |
| 147 | + let mut node_vec = Vec::new(); |
| 148 | + for neighbour in neighbours { |
| 149 | + if neighbour.node.is_some() { |
| 150 | + let node = neighbour.node.as_ref().unwrap(); |
| 151 | + node_vec.push(node); |
| 152 | + } |
| 153 | + } |
| 154 | + |
| 155 | + dmsort::sort_by(&mut node_vec, |a, b| { |
| 156 | + quick_distance_from_to(cell.x, cell.y, a.x, a.y) |
| 157 | + .partial_cmp(&quick_distance_from_to(cell.x, cell.y, b.x, b.y)) |
| 158 | + .unwrap() |
| 159 | + }); |
| 160 | + let dist = distance_from_to(cell.x, cell.y, node_vec[0].x, node_vec[0].y) |
| 161 | + - distance_from_to(cell.x, cell.y, node_vec[1].x, node_vec[1].y); |
| 162 | + // |
| 163 | + let mutable_cell = &mut self.cell_map[i as usize][j as usize]; |
| 164 | + if dist.abs() > threshold { |
| 165 | + mutable_cell.value = true; |
| 166 | + } |
| 167 | + } |
| 168 | + } |
| 169 | + } |
| 170 | +} |
| 171 | + |
| 172 | +fn distance_from_to(x1: i32, y1: i32, x2: i32, y2: i32) -> f32 { |
| 173 | + let x_diff = x1 - x2; |
| 174 | + let y_diff = y1 - y2; |
| 175 | + let distance = (((x_diff * x_diff) + (y_diff * y_diff)) as f32).sqrt(); |
| 176 | + distance |
| 177 | +} |
| 178 | + |
| 179 | +fn quick_distance_from_to(x1: i32, y1: i32, x2: i32, y2: i32) -> f32 { |
| 180 | + let x_diff = x1 - x2; |
| 181 | + let y_diff = y1 - y2; |
| 182 | + let distance = (x_diff.abs() + y_diff.abs()) as f32; |
| 183 | + distance |
| 184 | +} |
| 185 | + |
| 186 | +struct Cell { |
| 187 | + x: i32, |
| 188 | + y: i32, |
| 189 | + value: bool, |
| 190 | + region: Rc<Region>, |
| 191 | +} |
| 192 | + |
| 193 | +impl Cell { |
| 194 | + fn new(x: i32, y: i32, region: Rc<Region>) -> Cell { |
| 195 | + Cell { |
| 196 | + x: x, |
| 197 | + y: y, |
| 198 | + value: false, |
| 199 | + region: region, |
| 200 | + } |
| 201 | + } |
| 202 | +} |
| 203 | + |
| 204 | +struct Region { |
| 205 | + reg_x: i32, |
| 206 | + reg_y: i32, |
| 207 | + node: Option<Node>, |
| 208 | +} |
| 209 | + |
| 210 | +impl Region { |
| 211 | + fn new(reg_x: i32, reg_y: i32) -> Region { |
| 212 | + Region { |
| 213 | + reg_x: reg_x, |
| 214 | + reg_y: reg_y, |
| 215 | + node: None, |
| 216 | + } |
| 217 | + } |
| 218 | +} |
| 219 | + |
| 220 | +struct Node { |
| 221 | + x: i32, |
| 222 | + y: i32, |
| 223 | +} |
| 224 | + |
| 225 | +impl Node { |
| 226 | + fn new(x: i32, y: i32) -> Node { |
| 227 | + Node { x: x, y: y } |
| 228 | + } |
| 229 | +} |
0 commit comments