forked from xen-42/Minecraft-Clone
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ProcWorld.gd
134 lines (116 loc) · 4.21 KB
/
ProcWorld.gd
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
132
133
134
extends Spatial
var height_noise = OpenSimplexNoise.new()
onready var Chunk = load("res://Chunk.gd")
# Thread variables No reason to declare these on startup just do it up here
var thread = Thread.new()
var mutex = Mutex.new()
var semaphore = Semaphore.new()
var bKill_thread = false
#Use this when adding/removing from the chunk array/dict
var chunk_mutex = Mutex.new()
var _new_chunk_pos = Vector2()
var _chunk_pos = null
var _loaded_chunks = {}
var _last_chunk = Vector2()
var _kill_thread = false
const load_radius = 5
var current_load_radius = 0
func _ready():
thread.start(self, "_thread_gen")
height_noise.period = 100
func _thread_gen(userdata):
var i = 0
# Center map generation on the player
while(!bKill_thread):
# Check if player in new chunk
var player_pos_updated = false
player_pos_updated = _new_chunk_pos != _chunk_pos
# Make sure we aren't making a shallow copy
_chunk_pos = Vector2(_new_chunk_pos.x, _new_chunk_pos.y)
var current_chunk_pos = Vector2(_new_chunk_pos.x, _new_chunk_pos.y)
i = i + 1
if player_pos_updated:
# If new chunk unload unneeded chunks (changed to be entirely done off main thread if I understand correctly, fixling some stuttering I was feeling
enforce_render_distance(current_chunk_pos)
# Make sure player chunk is loaded
_last_chunk = _load_chunk(current_chunk_pos.x, current_chunk_pos.y)
current_load_radius = 1
else:
# Load next chunk based on the position of the last one
var delta_pos = _last_chunk - current_chunk_pos
# Only have player chunk
if delta_pos == Vector2():
# Move down one
_last_chunk = _load_chunk(_last_chunk.x, _last_chunk.y + 1)
elif delta_pos.x < delta_pos.y:
# Either go right or up
# Prioritize going right
if delta_pos.y == current_load_radius and -delta_pos.x != current_load_radius:
# Go right
_last_chunk = _load_chunk(_last_chunk.x - 1, _last_chunk.y)
# Either moving in constant x or we just reached bottom right
elif -delta_pos.x == current_load_radius or -delta_pos.x == delta_pos.y:
# Go up
_last_chunk = _load_chunk(_last_chunk.x, _last_chunk.y - 1)
else:
# We increment here idk why
if current_load_radius < load_radius:
current_load_radius += 1
else:
# Either go left or down
# Prioritize going left
if -delta_pos.y == current_load_radius and delta_pos.x != current_load_radius:
# Go left
_last_chunk = _load_chunk(_last_chunk.x + 1, _last_chunk.y)
elif delta_pos.x == current_load_radius or delta_pos.x == -delta_pos.y:
# Go down
# Stop the last one where we'd go over the limit
if delta_pos.y < load_radius:
_last_chunk = _load_chunk(_last_chunk.x, _last_chunk.y + 1)
func update_player_pos(new_pos):
_new_chunk_pos = new_pos
func change_block(cx, cz, bx, by, bz, t):
var c = _loaded_chunks[Vector2(cx, cz)]
if c._block_data[bx][by][bz].type != t:
print("Changed block at %d %d %d in chunk %d, %d" % [bx, by, bz, cx, cz])
c._block_data[bx][by][bz].create(t)
_update_chunk(cx, cz)
func _load_chunk(cx, cz):
var c_pos = Vector2(cx, cz)
if not _loaded_chunks.has(c_pos):
var c = Chunk.new()
c.generate(self, cx, cz)
c.update()
add_child(c)
chunk_mutex.lock()
_loaded_chunks[c_pos] = c
chunk_mutex.unlock()
return c_pos
func _update_chunk(cx, cz):
var c_pos = Vector2(cx, cz)
if _loaded_chunks.has(c_pos):
var c = _loaded_chunks[c_pos]
c.update()
return c_pos
# Detects and removes chunks all in one go without consulting the main thread.
func enforce_render_distance(current_chunk_pos):
#Checks and deletes the offending chunks all in one go
for v in _loaded_chunks.keys():
# Anywhere you directly interface with chunks outside of unloading
if abs(v.x - current_chunk_pos.x) > load_radius or abs(v.y - current_chunk_pos.y) > load_radius:
chunk_mutex.lock()
_loaded_chunks[v].free()
_loaded_chunks.erase(v)
chunk_mutex.unlock()
func _unload_chunk(cx, cz):
var c_pos = Vector2(cx, cz)
if _loaded_chunks.has(c_pos):
chunk_mutex.lock()
_loaded_chunks[c_pos].free()
_loaded_chunks.erase(c_pos)
chunk_mutex.unlock()
# Leaving this here because it is funny as hell
# Force it to just fucking chill after holy shit
# OS.delay_msec(50)
func kill_thread():
bKill_thread = true