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
|
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 && monument.loaded_chunk == null:
monument.loaded_chunk = coords
|