class_name Chunk extends Node3D var grid_position := Vector3i.ZERO var mesh: ArrayMesh = ArrayMesh.new() @export var noise: FastNoiseLite @export var blocks: Array = [] func generate_block_data(row: int, column: int, depth: int, empty: bool = false): Global.mutex.lock() grid_position = Vector3i(row, column, depth) blocks = [] for x in Global.CHUNK_SIZE.x: blocks.append([]) for y in Global.CHUNK_SIZE.y: blocks[x].append([]) for z in Global.CHUNK_SIZE.z: var block_position = Vector3i( grid_position.x * Global.CHUNK_SIZE.x + x, grid_position.y * Global.CHUNK_SIZE.y + y, grid_position.z * Global.CHUNK_SIZE.z + z )# * 2 var value = noise.get_noise_3d(block_position.x, block_position.y, block_position.z) * 100 var type = Block.Type.AIR if value > 4: type = Block.Type.GRASS if value < -4: type = Block.Type.STONE #if value < -16: #type = Block.Type.DIRT if value < -17 and value > -20: type = Block.Type.SAND if abs(value) > 21 and abs(value) < 21.25: type = [Block.Type.STONE, Block.Type.YELLOW_STONE, Block.Type.BLUE_STONE, Block.Type.RED_STONE, Block.Type.BLACK_STONE].pick_random() #print(value) var block = Block.new() block.position = block_position block.type = type if empty: block.type = Block.Type.AIR blocks[x][y].append(block) Global.mutex.unlock() func generate_mesh(): Global.mutex.lock() var material := preload("res://new_shader_material.tres") var st = SurfaceTool.new() st.begin(Mesh.PRIMITIVE_TRIANGLES) st.set_material(material) for x in blocks.size(): for y in blocks[x].size(): for z in blocks[x][y].size(): var block: Block = blocks[x][y][z] if block.type == Block.Type.AIR: continue var block_front: Block if block_exists(x, y, z + 1): block_front = blocks[x][y][z + 1] elif is_chunk_border(x, y, z) and chunk_exists(grid_position + Vector3i(0, 0, 1)): var chunk_front := Global.chunks[grid_position + Vector3i(0, 0, 1)] block_front = chunk_front.blocks[x][y][0] var block_back: Block if block_exists(x, y, z - 1): block_back = blocks[x][y][z - 1] elif is_chunk_border(x, y, z) and chunk_exists(grid_position + Vector3i(0, 0, -1)): var chunk_back := Global.chunks[grid_position + Vector3i(0, 0, -1)] block_back = chunk_back.blocks[x][y][Global.CHUNK_SIZE.z - 1] var block_right: Block if block_exists(x + 1, y, z): block_right = blocks[x + 1][y][z] elif is_chunk_border(x, y, z) and chunk_exists(grid_position + Vector3i(1, 0, 0)): var chunk_right := Global.chunks[grid_position + Vector3i(1, 0, 0)] block_right = chunk_right.blocks[0][y][z] var block_left: Block if block_exists(x - 1, y, z): block_left = blocks[x - 1][y][z] elif is_chunk_border(x, y, z) and chunk_exists(grid_position + Vector3i(-1, 0, 0)): var chunk_left := Global.chunks[grid_position + Vector3i(-1, 0, 0)] block_left = chunk_left.blocks[Global.CHUNK_SIZE.x - 1][y][z] var block_top: Block if block_exists(x, y + 1, z): block_top = blocks[x][y + 1][z] elif is_chunk_border(x, y, z) and chunk_exists(grid_position + Vector3i(0, 1, 0)): var chunk_top := Global.chunks[grid_position + Vector3i(0, 1, 0)] #if chunk_top.is_inside_tree(): block_top = chunk_top.blocks[x][0][z] var block_bottom: Block if block_exists(x, y - 1, z): block_bottom = blocks[x][y - 1][z] elif is_chunk_border(x, y, z) and chunk_exists(grid_position + Vector3i(0, -1, 0)): var chunk_bottom := Global.chunks[grid_position + Vector3i(0, -1, 0)] #if chunk_bottom.is_inside_tree(): block_bottom = chunk_bottom.blocks[x][Global.CHUNK_SIZE.y - 1][z] if not block.type == Block.Type.AIR: if block.type == Block.Type.GRASS: if block_top and block_top.type != Block.Type.AIR: block.type = Block.Type.DIRT var rng = RandomNumberGenerator.new() rng.seed = randi() st.set_color(Color(rng.randf(), rng.randf(), rng.randf())) st.set_uv(Vector2(0, 0)) if not block_front or block_front.type == Block.Type.AIR: block.add_face(st, Block.Face.FRONT) if not block_back or block_back.type == Block.Type.AIR: block.add_face(st, Block.Face.BACK) if not block_right or block_right.type == Block.Type.AIR: block.add_face(st, Block.Face.RIGHT) if not block_left or block_left.type == Block.Type.AIR: block.add_face(st, Block.Face.LEFT) if not block_top or block_top.type == Block.Type.AIR: block.add_face(st, Block.Face.TOP) if not block_bottom or block_bottom.type == Block.Type.AIR: block.add_face(st, Block.Face.BOTTOM) #st.generate_normals() mesh = st.commit() Global.mutex.unlock() func update_mesh() -> void: $MeshInstance3D.mesh = mesh var shape := ConcavePolygonShape3D.new() var faces := mesh.get_faces() if faces.size() > 0: shape.set_faces(mesh.get_faces()) $StaticBody3D/CollisionShape3D.shape = shape func add_to(node: Node) -> void: node.add_child(self) update_mesh() func generate_chunk(row: int, column: int, depth: int): if blocks.is_empty(): generate_block_data(row, column, depth) generate_mesh() func add_block(block_position: Vector3, block_type: Block.Type = Block.Type.GRASS) -> void: var block = Block.new() block.position = Vector3i( grid_position.x * Global.CHUNK_SIZE.x + int(block_position.x), grid_position.y * Global.CHUNK_SIZE.y + int(block_position.y), grid_position.z * Global.CHUNK_SIZE.z + int(block_position.z) ) block.type = block_type blocks[block_position.x][block_position.y][block_position.z] = block #generate_mesh.call_deferred() func remove_block(block_position: Vector3) -> void: blocks[block_position.x][block_position.y][block_position.z].type = Block.Type.AIR static func chunk_exists(chunk_position: Vector3i): return Global.chunks.has(chunk_position) #return x >= 0 and chunks.size() - 1 >= x and y >= 0 and chunks[x].size() - 1 >= y and z >= 0 and chunks[x][y].size() - 1 >= z func block_exists(x: int, y: int, z: int): return x >= 0 and blocks.size() - 1 >= x and y >= 0 and blocks[x].size() - 1 >= y and z >= 0 and blocks[x][y].size() - 1 >= z func is_chunk_border(x: int, y: int, z: int): return x == 0 or x == Global.CHUNK_SIZE.x - 1 or y == 0 or y == Global.CHUNK_SIZE.y - 1 or z == 0 or z == Global.CHUNK_SIZE.z - 1 func get_bordering_chunks(block_position: Vector3i) -> Array[Vector3i]: var bordering_chunks := [] as Array[Vector3i] if not is_chunk_border(block_position.x, block_position.y, block_position.z): return bordering_chunks if block_position.z == 0: bordering_chunks.append(grid_position + Vector3i(0, 0, -1)) elif block_position.z == Global.CHUNK_SIZE.z - 1: bordering_chunks.append(grid_position + Vector3i(0, 0, 1)) if block_position.x == 0: bordering_chunks.append(grid_position + Vector3i(-1, 0, 0)) elif block_position.x == Global.CHUNK_SIZE.x - 1: bordering_chunks.append(grid_position + Vector3i(1, 0, 0)) if block_position.y == 0: bordering_chunks.append(grid_position + Vector3i(0, -1, 0)) elif block_position.y == Global.CHUNK_SIZE.y - 1: bordering_chunks.append(grid_position + Vector3i(0, 1, 0)) return bordering_chunks func get_neighboring_blocks(_block_position: Vector3i) -> Array[Vector3i]: return [] @warning_ignore("shadowed_variable_base_class") static func global_to_chunk(global_position: Vector3, normal: Vector3) -> Vector3i: return floor((global_position - normal * (Block.BLOCK_SIZE * 0.5)) / Vector3(Global.CHUNK_SIZE)) @warning_ignore("shadowed_variable_base_class") static func global_to_chunk_block(global_position: Vector3, normal: Vector3) -> Vector3i: return global_to_block(global_position, normal) - Global.CHUNK_SIZE * global_to_chunk(global_position, normal) @warning_ignore("shadowed_variable_base_class") static func global_to_block(global_position: Vector3, normal: Vector3) -> Vector3i: return floor(global_position - normal * (Block.BLOCK_SIZE * 0.5))