Hi I have been strugging with this simple issue for over a week and I can't get anywhere. Please could you help.
So to give some context: I am making a minecraft clone for learning. I have chunks of blocks that are in a hashmap. For a block, the light level needs to be calculated by looking at the neighbouring blocks, which may be in other chunks. I want to have a reference to the main chunk for speed, and then only look in the hashmap when the surrounding block falls off the current chunk.
**The problem is that I can't have access to the main chunk (that I'm writing to) at the same time as looking at surrounding chunks, because I'm accessing the same hashmap with two references to it **
You could just say, why don't you treat the middle chunk like the surrounding chunks and always look up the chunk from the dictionary to get to the block: But that is very slow.
pub fn calculate_chunk_light_level(mut chunks: &mut std::collections::HashMap<String, Box<Chunk>>, chunk_pos: IVec3, block_metadata: &HashMap<BlockType, BlockMetadata>) {
let mut air_blocks_in_darkness: Vec<[usize; 3]> = Vec::new();
let chunk_corner_world_pos = Chunk::get_chunk_pos_as_i_world_pos(chunk_pos);
let main_chunk: &mut Chunk = get_chunk_from_chunk_pos_mut(&mut chunks, chunk_pos);
// Go from top to bottom, and illuminate
for x in 0..CHUNK_WIDTH_X {
for z in 0..CHUNK_DEPTH_Z {
let mut in_darkness = false;
for inv_y in 0..CHUNK_HEIGHT_Y {
let y = CHUNK_HEIGHT_Y - inv_y - 1;
let block: &mut Block = &mut main_chunk.blocks[x][y][z];
if block_metadata[&block.block_type].is_see_through == false {
in_darkness = true;
}
if !in_darkness {
block.light_evaluated = true;
block.light_level = 1.0;
} else if block_metadata[&block.block_type].is_see_through { // In darkness and air then we can set it to be iterated
air_blocks_in_darkness.push([x, y, z]);
}
}
}
}
let mut next_light_levels: Vec<f32> = Vec::with_capacity(air_blocks_in_darkness.len());
// Cellular automata, for 30 iterations
for i in 0..30 {
for air_block in air_blocks_in_darkness.iter() {
let mut highest_surrounding_light_level: f32 = 0.0;
for dir in NEIGHBOUR_ITERATOR { // This just iterates through [(-1,-1), (-1, 0), (1, 0) etc... ]
let other_local_block_pos = IVec3::new(
air_block[0] as i32 + dir[0],
air_block[1] as i32 + dir[1],
air_block[2] as i32 + dir[2]);
if is_vec_on_chunk(other_local_block_pos){
let other_block: &Block = &main_chunk.blocks[other_local_block_pos.x as usize][other_local_block_pos.z as usize][other_local_block_pos.y as usize];
if block_metadata[&other_block.block_type].is_see_through {
if other_block.light_level > highest_surrounding_light_level {
highest_surrounding_light_level = other_block.light_level;
}
}
} else { // Not on chunk so must be from surrounding
// THE BELOW LINE IS THE PROBLEM, BECAUSE IM ACCESSING CHUNKS AGAIN
let other_block_option = get_block_from_world_pos(chunks, chunk_corner_world_pos + other_local_block_pos);
match other_block_option {
Some(other_block) =>{
if block_metadata[&other_block.block_type].is_see_through {
if other_block.light_level > highest_surrounding_light_level {
highest_surrounding_light_level = other_block.light_level;
}
}
},
None =>{ }
}
}
}
// Move in the direction
let next = highest_surrounding_light_level - 0.05;// TODO: The darker it gets the less it takes off
next_light_levels.push(next);
}
// transfer next to current
for (index, air_block) in air_blocks_in_darkness.iter().enumerate() {
main_chunk.blocks[air_block[0]][air_block[1]][air_block[2]].light_level = next_light_levels[index];
}
next_light_levels.clear();
}
}