mirror of https://github.com/basinserver/basin/
230 lines
9.9 KiB
C
230 lines
9.9 KiB
C
#include <basin/chunk.h>
|
|
#include <basin/tileentity.h>
|
|
#include <avuna/list.h>
|
|
#include <avuna/hash.h>
|
|
#include <avuna/string.h>
|
|
#include <math.h>
|
|
|
|
|
|
uint64_t chunk_get_key(struct chunk* ch) {
|
|
return (uint64_t)(((int64_t) ch->x) << 32) | (((int64_t) ch->z) & 0xFFFFFFFF);
|
|
}
|
|
|
|
uint64_t chunk_get_key_direct(int32_t cx, int32_t cz) {
|
|
return (uint64_t)(((int64_t) cx) << 32) | (((int64_t) cz) & 0xFFFFFFFF);
|
|
}
|
|
|
|
|
|
struct tile_entity* chunk_get_tile(struct chunk* chunk, uint8_t x, uint8_t y, uint8_t z) {
|
|
if (y > 255 || y < 0 || chunk->tileEntities == NULL || x > 15 | z > 15) return NULL;
|
|
return hashmap_getint(chunk->tileEntities, (uint64_t) x << 16 | (uint64_t) y << 8 | (uint64_t) z);
|
|
}
|
|
|
|
|
|
void chunk_set_tile(struct chunk* chunk, struct tile_entity* tile, uint8_t x, uint8_t y, uint8_t z) {
|
|
pchild(chunk->pool, tile->pool);
|
|
if (y > 255 || y < 0 || chunk->tileEntities == NULL || x > 15 | z > 15) return;
|
|
uint64_t key = (uint64_t) x << 16 | (uint64_t) y << 8 | (uint64_t) z;
|
|
struct tile_entity* current_tile = hashmap_getint(chunk->tileEntities, key);
|
|
if (current_tile != NULL) {
|
|
if (current_tile->tick) {
|
|
hashmap_putint(chunk->tileEntitiesTickable, key, tile);
|
|
}
|
|
pfree(current_tile->pool);
|
|
}
|
|
hashmap_putint(chunk->tileEntities, key, tile);
|
|
}
|
|
|
|
block chunk_get_block(struct chunk* chunk, uint8_t x, uint8_t y, uint8_t z) {
|
|
if (x > 15 || z > 15 || y > 255 || x < 0 || z < 0 || y < 0) return 0;
|
|
struct chunk_section* section = chunk->sections[y >> 4];
|
|
if (section == NULL) return 0;
|
|
uint32_t block_index = ((y & 0x0fu) << 8u) | (z << 4u) | x;
|
|
uint32_t bit_index = section->bits_per_block * block_index;
|
|
uint32_t byte_index = *((uint32_t*) (§ion->blocks[bit_index / 8]));
|
|
uint32_t remainder_bits = bit_index % 8;
|
|
block b = (block) ((byte_index >> remainder_bits) & section->block_mask);
|
|
if (section->palette != NULL && b < section->palette_count) b = section->palette[b];
|
|
return b;
|
|
}
|
|
|
|
uint8_t chunk_get_light(struct chunk* chunk, uint8_t x, uint8_t y, uint8_t z, uint8_t subtract) {
|
|
if (x > 15 || z > 15 || y > 255 || x < 0 || z < 0 || y < 0) return 0;
|
|
struct chunk_section* section = chunk->sections[y >> 4];
|
|
if (section == NULL) return 0;
|
|
uint32_t block_index = ((y & 0x0fu) << 8u) | (z << 4u) | x;
|
|
uint32_t bit_index = 4 * block_index;
|
|
uint8_t skylight = 0;
|
|
if (section->skyLight != NULL) {
|
|
uint8_t this_skylight = section->skyLight[bit_index / 8];
|
|
if (block_index % 2 == 1) {
|
|
this_skylight &= 0xf0;
|
|
this_skylight >>= 4;
|
|
} else this_skylight &= 0x0f;
|
|
skylight = this_skylight;
|
|
}
|
|
skylight -= subtract;
|
|
uint8_t blocklight = section->blockLight[bit_index / 8];
|
|
if (block_index % 2 == 1) {
|
|
blocklight &= 0xf0;
|
|
blocklight >>= 4;
|
|
} else blocklight &= 0x0f;
|
|
if (blocklight > skylight) skylight = blocklight;
|
|
if (skylight < 0) skylight = 0;
|
|
return skylight;
|
|
}
|
|
|
|
uint8_t chunk_get_raw_light(struct chunk* chunk, uint8_t x, uint8_t y, uint8_t z, uint8_t blocklight) {
|
|
if (x > 15 || z > 15 || y > 255 || x < 0 || z < 0 || y < 0) return 0;
|
|
struct chunk_section* section = chunk->sections[y >> 4];
|
|
if (section == NULL) return 0;
|
|
uint32_t block_index = ((y & 0x0fu) << 8u) | (z << 4u) | x;
|
|
uint32_t bit_index = 4 * block_index;
|
|
uint8_t* target = blocklight ? section->blockLight : section->skyLight;
|
|
if (target == NULL) {
|
|
return 0;
|
|
}
|
|
uint8_t light = target[bit_index / 8];
|
|
if (block_index % 2 == 1) {
|
|
light &= 0xf0;
|
|
light >>= 4;
|
|
} else light &= 0x0f;
|
|
return light;
|
|
}
|
|
|
|
void chunk_set_light(struct chunk* chunk, uint8_t light, uint8_t x, uint8_t y, uint8_t z, uint8_t blocklight, uint8_t skylight) { // skylight is only for making new chunk sections, not related to set!
|
|
if (x > 15 || z > 15 || y > 255 || x < 0 || z < 0 || y < 0) return;
|
|
struct chunk_section* section = chunk->sections[y >> 4];
|
|
if (section == NULL) {
|
|
section = chunk_new_section(chunk, y >> 4, skylight);
|
|
}
|
|
uint32_t block_index = ((y & 0x0fu) << 8u) | (z << 4u) | x;
|
|
uint32_t bit_index = 4 * block_index;
|
|
uint8_t* target = blocklight ? section->blockLight : section->skyLight;
|
|
uint8_t current_light = target[bit_index / 8];
|
|
if (block_index % 2 == 1) {
|
|
current_light &= 0x0f;
|
|
current_light |= (light & 0x0f) << 4;
|
|
} else {
|
|
current_light &= 0xf0;
|
|
current_light |= light & 0x0f;
|
|
}
|
|
target[bit_index / 8] = current_light;
|
|
}
|
|
|
|
|
|
|
|
struct chunk* chunk_new(struct mempool* pool, int16_t x, int16_t z) {
|
|
struct chunk* chunk = pcalloc(pool, sizeof(struct chunk));
|
|
chunk->pool = pool;
|
|
chunk->x = x;
|
|
chunk->z = z;
|
|
chunk->playersLoaded = 0;
|
|
chunk->tileEntities = hashmap_thread_new(16, 0);
|
|
chunk->tileEntitiesTickable = hashmap_thread_new(8, 0);
|
|
chunk->defunct = 0;
|
|
chunk->xp = NULL;
|
|
chunk->xn = NULL;
|
|
chunk->zp = NULL;
|
|
chunk->zn = NULL;
|
|
return chunk;
|
|
}
|
|
|
|
struct chunk_section* chunk_new_section(struct chunk* chunk, int ymj, int skylight) {
|
|
chunk->sections[ymj] = pcalloc(chunk->pool, sizeof(struct chunk_section));
|
|
struct chunk_section* cs = chunk->sections[ymj];
|
|
cs->bits_per_block = 4;
|
|
cs->block_size = 512 * 4;
|
|
cs->blocks = pcalloc(chunk->pool, 512 * 4 + 4);
|
|
cs->palette_count = 1;
|
|
cs->palette = pmalloc(chunk->pool, sizeof(block));
|
|
cs->palette[0] = BLK_AIR;
|
|
cs->block_mask = 0xf;
|
|
if (skylight) {
|
|
cs->skyLight = pmalloc(chunk->pool, 2048);
|
|
memset(cs->skyLight, 0xFF, 2048);
|
|
}
|
|
return cs;
|
|
}
|
|
|
|
void chunk_set_block(struct chunk* chunk, block blk, uint8_t x, uint8_t y, uint8_t z, int skylight) {
|
|
if (x > 15 || z > 15 || y > 255 || x < 0 || z < 0 || y < 0) return;
|
|
struct chunk_section* section = chunk->sections[y >> 4];
|
|
if (section == NULL && blk != 0) {
|
|
section = chunk_new_section(chunk, y >> 4, skylight);
|
|
} else if (section == NULL) return;
|
|
if (skylight) {
|
|
struct block_info* info = getBlockInfo(blk);
|
|
if (info != NULL) {
|
|
if (info->lightOpacity >= 1) {
|
|
if (chunk->heightMap[z][x] <= y) chunk->heightMap[z][x] = (uint16_t) (y + 1);
|
|
else {
|
|
for (int ny = chunk->heightMap[z][x] - 1; ny >= 0; ny--) {
|
|
struct block_info* new_info = getBlockInfo(chunk_get_block(chunk, x, y, z));
|
|
if (new_info != NULL && new_info->lightOpacity >= 1) {
|
|
chunk->heightMap[z][x] = (uint16_t) (ny + 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else if (chunk->heightMap[z][x] > y) {
|
|
for (int ny = chunk->heightMap[z][x] - 1; ny >= 0; ny--) {
|
|
struct block_info* new_info = getBlockInfo(chunk_get_block(chunk, x, y, z));
|
|
if (new_info != NULL && new_info->lightOpacity >= 1) {
|
|
chunk->heightMap[z][x] = (uint16_t) (ny + 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
block wanted_block = blk;
|
|
if (section->bits_per_block < 9) {
|
|
for (int i = 0; i < section->palette_count; i++) {
|
|
if (section->palette[i] == blk) {
|
|
wanted_block = (block) i;
|
|
goto post_palette;
|
|
}
|
|
}
|
|
uint32_t room = (uint32_t) (pow(2, section->bits_per_block) - section->palette_count);
|
|
if (room < 1) {
|
|
uint8_t modified_bits_per_block = (uint8_t) (section->bits_per_block + 1);
|
|
if (modified_bits_per_block >= 9) modified_bits_per_block = 13;
|
|
uint8_t* new_blocks = pcalloc(chunk->pool, (size_t) (modified_bits_per_block * 512 + 4));
|
|
uint32_t encoded_bit_length = 0;
|
|
uint32_t encoded_bit_length_modified = 0;
|
|
int32_t nmvs = section->block_mask | (1 << (modified_bits_per_block - 1));
|
|
if (modified_bits_per_block == 13) nmvs = 0x1FFF;
|
|
for (int i = 0; i < 4096; i++) {
|
|
int32_t received_bytes = *((int32_t*) (§ion->blocks[encoded_bit_length / 8]));
|
|
int32_t bit_index = encoded_bit_length % 8;
|
|
int32_t bits = (received_bytes >> bit_index) & section->block_mask;
|
|
if (modified_bits_per_block == 13) bits = section->palette[bits];
|
|
int32_t new_current_bytes = *((int32_t*) (&new_blocks[encoded_bit_length_modified / 8]));
|
|
int32_t new_bit_index = encoded_bit_length_modified % 8;
|
|
new_current_bytes = (new_current_bytes & ~(nmvs << new_bit_index)) | (bits << new_bit_index);
|
|
*((int32_t*) &new_blocks[encoded_bit_length_modified / 8]) = new_current_bytes;
|
|
encoded_bit_length += section->bits_per_block;
|
|
encoded_bit_length_modified += modified_bits_per_block;
|
|
}
|
|
uint8_t* old_blocks = section->blocks;
|
|
section->blocks = new_blocks;
|
|
section->block_size = (size_t) (modified_bits_per_block * 512);
|
|
pprefree(chunk->pool, old_blocks);
|
|
section->block_mask = nmvs;
|
|
section->bits_per_block = modified_bits_per_block;
|
|
}
|
|
wanted_block = (block) section->palette_count;
|
|
section->palette = prealloc(chunk->pool, section->palette, sizeof(block) * (section->palette_count + 1));
|
|
section->palette[section->palette_count++] = blk;
|
|
post_palette: ;
|
|
}
|
|
uint32_t i = ((y & 0x0fu) << 8u) | (z << 4u) | x;
|
|
uint32_t final_bit_index = section->bits_per_block * i;
|
|
int32_t final_bits = ((int32_t) wanted_block) & section->block_mask;
|
|
int32_t final_selected_bits = *((int32_t*) (§ion->blocks[final_bit_index / 8]));
|
|
int32_t selected_bits_index = final_bit_index % 8;
|
|
final_selected_bits = (final_selected_bits & ~(section->block_mask << selected_bits_index)) | (final_bits << selected_bits_index);
|
|
*((int32_t*) §ion->blocks[final_bit_index / 8]) = final_selected_bits;
|
|
}
|