forked from StanislavPetrovV/Minecraft
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathvoxel_handler.py
More file actions
185 lines (150 loc) · 6.23 KB
/
voxel_handler.py
File metadata and controls
185 lines (150 loc) · 6.23 KB
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
from settings import *
from meshes.chunk_mesh_builder import get_chunk_index
import csv
class VoxelHandler:
def __init__(self, world):
self.app = world.app
self.chunks = world.chunks
# ray casting result
self.chunk = None
self.voxel_id = None
self.voxel_index = None
self.voxel_local_pos = None
self.voxel_world_pos = None
self.voxel_normal = None
self.interaction_mode = 0 # 0: remove voxel 1: add voxel
self.new_voxel_id = DIRT
self.voxel_dict = dict()
raw = list(csv.reader(open('assets/minecraft_textures_atlas_blocks.png.txt', 'r'), delimiter='\t'))
clean = list()
for item in raw:
if 'minecraft:block/' in item[0]:
item[0] = item[0][16::]
clean.append(item)
for i, v in enumerate(clean):
self.voxel_dict[v[0]] = i
# print(self.voxel_dict)
def add_voxel(self, x, y, z, kind):
# if self.voxel_id:
# # check voxel id along normal
# result = self.get_voxel_id(self.voxel_world_pos + self.voxel_normal)
#
# # is the new place empty?
# if not result[0]:
# _, voxel_index, _, chunk = result
# chunk.voxels[voxel_index] = self.new_voxel_id
# chunk.mesh.rebuild()
#
# # was it an empty chunk
# if chunk.is_empty:
# chunk.is_empty = False
# check voxel id along normal
result = self.get_voxel_id(glm.ivec3(x, y, z))
# is the new place empty?
if not result[0]:
_, voxel_index, _, chunk = result
try:
match kind:
case 'grass_block':
kind = 'grass_block_top'
chunk.voxels[voxel_index] = self.voxel_dict[kind]
# print('type', kind, self.voxel_dict[kind])
chunk.mesh.rebuild()
# was it an empty chunk
if chunk.is_empty:
chunk.is_empty = False
except KeyError:
pass
def rebuild_adj_chunk(self, adj_voxel_pos):
index = get_chunk_index(adj_voxel_pos)
if index != -1:
self.chunks[index].mesh.rebuild()
def rebuild_adjacent_chunks(self):
lx, ly, lz = self.voxel_local_pos
wx, wy, wz = self.voxel_world_pos
if lx == 0:
self.rebuild_adj_chunk((wx - 1, wy, wz))
elif lx == CHUNK_SIZE - 1:
self.rebuild_adj_chunk((wx + 1, wy, wz))
if ly == 0:
self.rebuild_adj_chunk((wx, wy - 1, wz))
elif ly == CHUNK_SIZE - 1:
self.rebuild_adj_chunk((wx, wy + 1, wz))
if lz == 0:
self.rebuild_adj_chunk((wx, wy, wz - 1))
elif lz == CHUNK_SIZE - 1:
self.rebuild_adj_chunk((wx, wy, wz + 1))
def remove_voxel(self):
if self.voxel_id:
self.chunk.voxels[self.voxel_index] = 0
self.chunk.mesh.rebuild()
self.rebuild_adjacent_chunks()
def set_voxel(self):
if self.interaction_mode:
self.add_voxel()
else:
self.remove_voxel()
def switch_mode(self):
self.interaction_mode = not self.interaction_mode
def update(self):
self.ray_cast()
def ray_cast(self):
if not self.app.player.follow_mode:
# start point
x1, y1, z1 = self.app.player.position
# end point
x2, y2, z2 = self.app.player.position + self.app.player.forward * MAX_RAY_DIST
current_voxel_pos = glm.ivec3(x1, y1, z1)
self.voxel_id = 0
self.voxel_normal = glm.ivec3(0)
step_dir = -1
dx = glm.sign(x2 - x1)
delta_x = min(dx / (x2 - x1), 10000000.0) if dx != 0 else 10000000.0
max_x = delta_x * (1.0 - glm.fract(x1)) if dx > 0 else delta_x * glm.fract(x1)
dy = glm.sign(y2 - y1)
delta_y = min(dy / (y2 - y1), 10000000.0) if dy != 0 else 10000000.0
max_y = delta_y * (1.0 - glm.fract(y1)) if dy > 0 else delta_y * glm.fract(y1)
dz = glm.sign(z2 - z1)
delta_z = min(dz / (z2 - z1), 10000000.0) if dz != 0 else 10000000.0
max_z = delta_z * (1.0 - glm.fract(z1)) if dz > 0 else delta_z * glm.fract(z1)
while not (max_x > 1.0 and max_y > 1.0 and max_z > 1.0):
result = self.get_voxel_id(voxel_world_pos=current_voxel_pos)
if result[0]:
self.voxel_id, self.voxel_index, self.voxel_local_pos, self.chunk = result
self.voxel_world_pos = current_voxel_pos
if step_dir == 0:
self.voxel_normal.x = -dx
elif step_dir == 1:
self.voxel_normal.y = -dy
else:
self.voxel_normal.z = -dz
return True
if max_x < max_y:
if max_x < max_z:
current_voxel_pos.x += dx
max_x += delta_x
step_dir = 0
else:
current_voxel_pos.z += dz
max_z += delta_z
step_dir = 2
else:
if max_y < max_z:
current_voxel_pos.y += dy
max_y += delta_y
step_dir = 1
else:
current_voxel_pos.z += dz
max_z += delta_z
step_dir = 2
return False
def get_voxel_id(self, voxel_world_pos):
cx, cy, cz = chunk_pos = voxel_world_pos / CHUNK_SIZE
if 0 <= cx < WORLD_W and 0 <= cy < WORLD_H and 0 <= cz < WORLD_D:
chunk_index = cx + WORLD_W * cz + WORLD_AREA * cy
chunk = self.chunks[chunk_index]
lx, ly, lz = voxel_local_pos = voxel_world_pos - chunk_pos * CHUNK_SIZE
voxel_index = lx + CHUNK_SIZE * lz + CHUNK_AREA * ly
voxel_id = chunk.voxels[voxel_index]
return voxel_id, voxel_index, voxel_local_pos, chunk
return 0, 0, 0, 0