1 /************************************************************************
3 * voxelands - 3d voxel world sandbox game
4 * Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>
18 ************************************************************************/
24 #include "content_block.h"
37 {NULL
,NULL
,NULL
,NULL
,NULL
,NULL
,NULL
,NULL
},
38 {NULL
,NULL
,NULL
,NULL
,NULL
,NULL
,NULL
,NULL
}
45 static void mapoct_delete(mapoct_t
*m
)
51 static int mapoct_index(mapoct_t
*m
, pos_t
*p
)
55 if (p
->x
< m
->pos
.x
) {
56 if (p
->y
< m
->pos
.y
) {
57 if (p
->z
< m
->pos
.z
) {
60 i
= MAPOCT_MINUS_XY_PLUS_Z
;
62 }else if (p
->z
< m
->pos
.z
) {
63 i
= MAPOCT_MINUS_XZ_PLUS_Y
;
65 i
= MAPOCT_MINUS_X_PLUS_YZ
;
67 }else if (p
->y
< m
->pos
.y
) {
68 if (p
->z
< m
->pos
.z
) {
69 i
= MAPOCT_MINUS_YZ_PLUS_X
;
71 i
= MAPOCT_MINUS_Y_PLUS_XZ
;
73 }else if (p
->z
< m
->pos
.z
) {
74 i
= MAPOCT_MINUS_Z_PLUS_XY
;
82 static mapoct_t
*mapoct_walk(mapoct_t
*m
, pos_t
*p
, uint8_t create
);
83 static mapoct_t
*mapoct_walk(mapoct_t
*m
, pos_t
*p
, uint8_t create
)
87 if (m
->size
== (CHUNKSIZE
*2))
90 i
= mapoct_index(m
,p
);
92 if (!m
->children
[i
]) {
98 mm
= malloc(sizeof(mapoct_t
));
103 mm
->parent_index
= i
;
104 mm
->size
= m
->size
/2;
108 if (p
->x
< m
->pos
.x
) {
109 mm
->pos
.x
= m
->pos
.x
-k
;
111 mm
->pos
.x
= m
->pos
.x
+k
;
113 if (p
->y
< m
->pos
.y
) {
114 mm
->pos
.y
= m
->pos
.y
-k
;
116 mm
->pos
.y
= m
->pos
.y
+k
;
118 if (p
->z
< m
->pos
.z
) {
119 mm
->pos
.z
= m
->pos
.z
-k
;
121 mm
->pos
.z
= m
->pos
.z
+k
;
124 for (k
=0; k
<8; k
++) {
125 mm
->children
[k
] = NULL
;
126 mm
->chunks
[k
] = NULL
;
132 if (m
->children
[i
]->size
== (CHUNKSIZE
*2))
133 return m
->children
[i
];
135 return mapoct_walk(m
->children
[i
],p
,create
);
138 static chunk_t
*mapoct_walk_chunk(mapoct_t
*m
, pos_t
*p
)
142 m
= mapoct_walk(m
,p
,0);
145 if (m
->size
!= (CHUNKSIZE
*2))
148 i
= mapoct_index(m
,p
);
153 /* intialise the map data */
157 map_data
.mut
= mutex_create();
159 return mapgen_init();
162 /* delete and free the current map */
165 while (map_data
.chunks
) {
166 map_delete_chunk(map_data
.chunks
);
170 /* deinitialise the map */
175 map_data
.last
= NULL
;
178 /* add a new chunk to the map */
179 void map_add_chunk(chunk_t
*ch
)
184 mutex_lock(map_data
.mut
);
186 m
= mapoct_walk(&map_data
.map
,&ch
->pos
,1);
191 i
= mapoct_index(m
,&ch
->pos
);
195 ch
->mapoct_index
= i
;
197 map_data
.chunks
= list_append(&map_data
.chunks
,ch
);
199 mutex_unlock(map_data
.mut
);
201 map_trigger(MAP_TRIGGER_LOADED
,ch
,&ch
->pos
);
204 /* delete a chunk from the map */
205 void map_delete_chunk(chunk_t
*ch
)
210 mutex_lock(map_data
.mut
);
212 map_data
.chunks
= list_remove(&map_data
.chunks
,ch
);
215 m
->chunks
[ch
->mapoct_index
] = NULL
;
217 map_trigger(MAP_TRIGGER_UNLOAD
,ch
,&ch
->pos
);
221 for (i
=0; i
<8; i
++) {
223 mutex_unlock(map_data
.mut
);
230 mutex_unlock(map_data
.mut
);
233 /* get the map chunk containing a position */
234 chunk_t
*map_get_chunk_containing(pos_t
*p
)
241 p
->x
>= ch
->pos
.x
&& p
->x
< ch
->pos
.x
+16
242 && p
->y
>= ch
->pos
.y
&& p
->y
< ch
->pos
.y
+16
243 && p
->z
>= ch
->pos
.z
&& p
->z
< ch
->pos
.z
+16
248 mutex_lock(map_data
.mut
);
250 ch
= mapoct_walk_chunk(&map_data
.map
,p
);
252 mutex_unlock(map_data
.mut
);
259 /* TODO: load from disk, possibly asyncronously */
266 /* get the map block at a position */
267 block_t
*map_get_block(pos_t
*p
)
274 ch
= map_get_chunk_containing(p
);
289 return &ch
->blocks
[x
][y
][z
];
292 /* add/update a block */
293 void map_set_block(pos_t
*p
, block_t
*b
)
301 ch
= map_get_chunk_containing(p
);
316 cb
= &ch
->blocks
[x
][y
][z
];
319 cb
->content
= b
->content
;
320 cb
->param1
= b
->param1
;
321 cb
->param2
= b
->param2
;
322 cb
->param3
= b
->param3
;
323 cb
->envticks
= b
->envticks
;
326 cb
->content
= CONTENT_AIR
;
333 map_trigger(MAP_TRIGGER_UPDATE
,ch
,&ch
->pos
);