summaryrefslogtreecommitdiffstats
path: root/world/chunk/ChunkLoader.gd
blob: 0ea422a0264df957bfb3a9bd7073e93888fd29a8 (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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
extends Node

var world = null

var Chunk = preload("res://world/chunk/Chunk.tscn")
var loaded_chunks = {}
var freed_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
var chunk_to_dummy

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 v3_coords(coords:Vector2):
    return Vector3(coords.x,0.0,coords.y)

func free_chunk(coords:Vector2):
    var monument = ChunkGen.get_monument_at_chunk(coords)
    if monument != null && monument.loaded_chunk != null && monument.loaded_chunk == coords:
        return
    if !loaded_chunks.has(coords):
        return
    freed_chunks[coords] = loaded_chunks[coords]
    loaded_chunks.erase(coords)

func clean_chunks():
    var cleaned = {}
    for chunk in freed_chunks.keys():
        var c = freed_chunks[chunk].get_ref()
        if c == null:
            cleaned[chunk] = c
            continue
        c.queue_free()
    for chunk in cleaned.keys():
        freed_chunks.erase(chunk)

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)
            var coords_len = gen_coords.length()
            if coords_len > gen_radius:
                continue
            var coords = chunk_coords(gen_coords + gen_center)
            chunks[coords] = coords_len
    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:
        var dummy = false
        var monument = ChunkGen.get_monument_at_chunk(closest_unloaded_chunk)
        if monument != null && monument.loaded_chunk != null:
            dummy = true
        mtx.lock()
        if chunk_to_load == null:
            chunk_to_load = closest_unloaded_chunk
            chunk_to_len = closest_len
            chunk_to_dummy = dummy
            sgnl.post()
        mtx.unlock()
    for monument in ChunkGen.monuments:
        if monument.loaded_chunk != null:
            var loaded = false
            for chunk in chunks.keys():
                if monument.chunks.has(chunk):
                    loaded = true
                    break
            if !loaded:
                monument.loaded_chunk = null
    for chunk in loaded_chunks.keys():
        if !chunks.has(chunk):
            free_chunk(chunk)
    clean_chunks()

func chunk_loader():
    while true:
        sgnl.wait()
        mtx.lock()
        var x = exit
        var coords = chunk_to_load
        var lod = chunk_to_len
        var dummy = chunk_to_dummy
        mtx.unlock()
        if x:
            break
        var chunk = Chunk.instance()
        chunk.transform.origin = Vector3(coords.x,0.0,coords.y)
        lod -= world.chunk_size
        var tmp = world.get_node("Chunk")
        chunk.lod = tmp.LOD.CLOSE if lod <= world.lod_close else tmp.LOD.MID if lod <= world.lod_mid else tmp.LOD.DISTANCE
        ChunkGen.gen_chunk(chunk,dummy)
        self.call_deferred("finish_chunk", chunk)

func finish_chunk(chunk):
    mtx.lock()
    chunk_to_load = null
    mtx.unlock()
    world.get_node("Chunks").add_child(chunk)
    var coords = v2_coords(chunk.transform.origin)
    loaded_chunks[coords] = weakref(chunk)
    var monument = ChunkGen.get_monument_at_chunk(coords)
    if monument != null:
        if monument.loaded_chunk == null:
            monument.loaded_chunk = coords