summaryrefslogtreecommitdiffstats
path: root/world/chunk/ChunkLoader.gd
blob: 42e40bb81d3d69cba2b5b9b19d6f37367eac304a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
extends Node

var world = null

var Chunk = preload("res://world/chunk/Chunk.tscn")
var loaded_chunks = {}
var chunk_thread = Thread.new()
var mtx = Mutex.new()
var sgnl = Semaphore.new()
var exit = false
var chunk_to_load = null
var chunk_to_len

func _ready():
    chunk_thread.start(self, "chunk_loader")
    
func _exit_tree():
    mtx.lock()
    exit = true
    sgnl.post()
    mtx.unlock()
    chunk_thread.wait_to_finish()

func v2_coords(coords:Vector3):
    return Vector2(coords.x,coords.z)

func chunk_coords(coords:Vector2):
    return coords.snapped(Vector2(world.chunk_size,world.chunk_size))

func free_chunk(coords:Vector2):
    if !loaded_chunks.has(coords):
        return
    var c = loaded_chunks[coords].get_ref()
    if c != null:
        c.queue_free()
    loaded_chunks.erase(coords)

func chunk_update():
    var chunks = {}
    var gen_center = -v2_coords(world.get_node("Chunks").transform.origin)
    var gen_radius = world.lod_distance
    var gen_radius_rounded = stepify(gen_radius, world.chunk_size)
    for x in range(-gen_radius_rounded, gen_radius_rounded+world.chunk_size, world.chunk_size):
        for y in range(-gen_radius_rounded, gen_radius_rounded+world.chunk_size, world.chunk_size):
            var gen_coords = Vector2(x,y)
            if gen_coords.length() > gen_radius:
                continue
            var coords = chunk_coords(gen_coords + gen_center)
            chunks[coords] = coords.length()
    var closest_unloaded_chunk = null
    var closest_len = 0.0
    for chunk in chunks.keys():
        if !loaded_chunks.has(chunk):
            var chunk_len = chunks[chunk]
            if closest_unloaded_chunk == null || closest_len > chunk_len:
                closest_unloaded_chunk = chunk
                closest_len = chunk_len
    if closest_unloaded_chunk != null:
        mtx.lock()
        if chunk_to_load == null:
            chunk_to_load = closest_unloaded_chunk
            chunk_to_len = closest_len
            sgnl.post()
        mtx.unlock()
    for chunk in loaded_chunks.keys():
        if !chunks.has(chunk):
            free_chunk(chunk)

func chunk_loader():
    while true:
        sgnl.wait()
        mtx.lock()
        var x = exit
        var coords = chunk_to_load
        var owo = chunk_to_len
        chunk_to_load = null
        mtx.unlock()
        if x:
            break
        var chunk = Chunk.instance()
        chunk.transform.origin = Vector3(coords.x,0.0,coords.y)
        owo -= world.chunk_size
        chunk.lod = 2 if owo <= world.lod_close else 1 if owo <= world.lod_mid else 0
        ChunkGen.gen_chunk(chunk)
        self.call_deferred("finish_chunk", chunk)

func finish_chunk(chunk):
    world.get_node("Chunks").add_child(chunk)
    loaded_chunks[v2_coords(chunk.transform.origin)] = weakref(chunk)