Voxel changed from 16 bit to 32 bit + new lua functions

This commit is contained in:
MihailRis 2024-01-04 15:27:07 +03:00
parent 460b08a006
commit 06f66ffd71
10 changed files with 229 additions and 36 deletions

View File

@ -11,6 +11,9 @@ const int CHUNK_W = 16;
const int CHUNK_H = 256;
const int CHUNK_D = 16;
const uint VOXEL_USER_BITS = 8;
constexpr uint VOXEL_USER_BITS_OFFSET = sizeof(blockstate_t)*8-VOXEL_USER_BITS;
/* Chunk volume (count of voxels per Chunk) */
constexpr int CHUNK_VOL = (CHUNK_W * CHUNK_H * CHUNK_D);

View File

@ -8,18 +8,15 @@
#include "../content/ContentLUT.h"
namespace fs = std::filesystem;
using std::string;
using std::unique_ptr;
using fs::path;
WorldConverter::WorldConverter(path folder,
WorldConverter::WorldConverter(fs::path folder,
const Content* content,
const ContentLUT* lut)
: lut(lut), content(content) {
DebugSettings settings;
wfile = new WorldFiles(folder, settings);
path regionsFolder = wfile->getRegionsFolder();
fs::path regionsFolder = wfile->getRegionsFolder();
if (!fs::is_directory(regionsFolder)) {
std::cerr << "nothing to convert" << std::endl;
return;
@ -41,13 +38,13 @@ void WorldConverter::convertNext() {
if (!hasNext()) {
throw std::runtime_error("no more regions to convert");
}
path regfile = regions.front();
fs::path regfile = regions.front();
regions.pop();
if (!fs::is_regular_file(regfile))
return;
int x, y;
string name = regfile.stem().string();
if (!WorldFiles::parseRegionFilename(name, x, y)) {
int x, z;
std::string name = regfile.stem().string();
if (!WorldFiles::parseRegionFilename(name, x, z)) {
std::cerr << "could not parse name " << name << std::endl;
return;
}
@ -55,11 +52,16 @@ void WorldConverter::convertNext() {
for (uint cz = 0; cz < REGION_SIZE; cz++) {
for (uint cx = 0; cx < REGION_SIZE; cx++) {
int gx = cx + x * REGION_SIZE;
int gz = cz + y * REGION_SIZE;
unique_ptr<ubyte[]> data (wfile->getChunk(gx, gz));
int gz = cz + z * REGION_SIZE;
std::unique_ptr<ubyte[]> data (wfile->getChunk(gx, gz));
if (data == nullptr)
continue;
Chunk::convert(data.get(), lut);
if (wfile->getVoxelRegionVersion(x, z) != REGION_FORMAT_VERSION) {
Chunk::fromOld(data.get());
}
if (lut) {
Chunk::convert(data.get(), lut);
}
wfile->put(gx, gz, data.get());
}
}

View File

@ -38,8 +38,8 @@ regfile::regfile(fs::path filename) : file(filename) {
throw std::runtime_error("invalid region file magic number");
}
version = header[8];
if (version > 2) {
throw std::runtime_error(
if (version > REGION_FORMAT_VERSION) {
throw illegal_region_format(
"region format "+std::to_string(version)+" is not supported");
}
}
@ -130,6 +130,31 @@ ubyte* WorldFiles::decompress(const ubyte* src, size_t srclen, size_t dstlen) {
return decompressed;
}
int WorldFiles::getVoxelRegionVersion(int x, int z) {
regfile* rf = getRegFile(glm::ivec3(x, z, REGION_LAYER_VOXELS), getRegionsFolder());
if (rf == nullptr) {
return 0;
}
return rf->version;
}
int WorldFiles::getVoxelRegionsVersion() {
fs::path regionsFolder = getRegionsFolder();
if (!fs::is_directory(regionsFolder)) {
return REGION_FORMAT_VERSION;
}
for (auto file : fs::directory_iterator(regionsFolder)) {
int x;
int z;
if (!parseRegionFilename(file.path().stem().string(), x, z)) {
continue;
}
regfile* rf = getRegFile(glm::ivec3(x, z, REGION_LAYER_VOXELS), regionsFolder);
return rf->version;
}
return REGION_FORMAT_VERSION;
}
/*
* Compress and store chunk voxels data in region
* @param x chunk.x
@ -190,8 +215,7 @@ fs::path WorldFiles::getLightsFolder() const {
}
fs::path WorldFiles::getRegionFilename(int x, int z) const {
std::string filename = std::to_string(x) + "_" + std::to_string(z) + ".bin";
return fs::path(filename);
return fs::path(std::to_string(x) + "_" + std::to_string(z) + ".bin");
}
/*
@ -254,7 +278,6 @@ ubyte* WorldFiles::getData(regionsmap& regions, const fs::path& folder,
int localZ = z - (regionZ * REGION_SIZE);
WorldRegion* region = getOrCreateRegion(regions, regionX, regionZ);
ubyte* data = region->getChunkData(localX, localZ);
if (data == nullptr) {
uint32_t size;

View File

@ -34,6 +34,12 @@ class Content;
class ContentIndices;
class World;
class illegal_region_format : public std::runtime_error {
public:
illegal_region_format(const std::string& message)
: std::runtime_error(message) {}
};
class WorldRegion {
ubyte** chunksData;
uint32_t* sizes;
@ -125,6 +131,9 @@ public:
void put(Chunk* chunk);
void put(int x, int z, const ubyte* voxelData);
int getVoxelRegionVersion(int x, int z);
int getVoxelRegionsVersion();
ubyte* getChunk(int x, int z);
light_t* getLights(int x, int z);

View File

@ -14,7 +14,9 @@
#include "../util/stringutil.h"
#include "../files/engine_paths.h"
#include "../files/WorldConverter.h"
#include "../files/WorldFiles.h"
#include "../world/World.h"
#include "../world/Level.h"
#include "../window/Events.h"
#include "../window/Window.h"
#include "../engine.h"
@ -175,8 +177,18 @@ void open_world(std::string name, Engine* engine) {
show_convert_request(engine, content, lut, folder);
}
} else {
Level* level = World::load(folder, settings, content, packs);
engine->setScreen(std::make_shared<LevelScreen>(engine, level));
// TODO: remove in 0.18
int version;
{
WorldFiles wfile(folder, settings.debug);
version = wfile.getVoxelRegionsVersion();
}
if (version != REGION_FORMAT_VERSION) {
show_convert_request(engine, content, lut, folder);
} else {
Level* level = World::load(folder, settings, content, packs);
engine->setScreen(std::make_shared<LevelScreen>(engine, level));
}
}
}

View File

@ -59,6 +59,64 @@ int l_get_block(lua_State* L) {
return 1;
}
inline int lua_pushivec3(lua_State* L, int x, int y, int z) {
lua_pushinteger(L, x);
lua_pushinteger(L, y);
lua_pushinteger(L, z);
return 3;
}
int l_get_block_x(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return lua_pushivec3(L, 1, 0, 0);
}
const Block* def = scripting::level->content->indices->getBlockDef(vox->id);
if (!def->rotatable) {
return lua_pushivec3(L, 1, 0, 0);
} else {
const CoordSystem& rot = def->rotations.variants[vox->rotation()];
return lua_pushivec3(L, rot.axisX.x, rot.axisX.y, rot.axisX.z);
}
}
int l_get_block_y(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return lua_pushivec3(L, 0, 1, 0);
}
const Block* def = scripting::level->content->indices->getBlockDef(vox->id);
if (!def->rotatable) {
return lua_pushivec3(L, 0, 1, 0);
} else {
const CoordSystem& rot = def->rotations.variants[vox->rotation()];
return lua_pushivec3(L, rot.axisY.x, rot.axisY.y, rot.axisY.z);
}
}
int l_get_block_z(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return lua_pushivec3(L, 0, 0, 1);
}
const Block* def = scripting::level->content->indices->getBlockDef(vox->id);
if (!def->rotatable) {
return lua_pushivec3(L, 0, 0, 1);
} else {
const CoordSystem& rot = def->rotations.variants[vox->rotation()];
return lua_pushivec3(L, rot.axisZ.x, rot.axisZ.y, rot.axisZ.z);
}
}
int l_get_player_pos(lua_State* L) {
glm::vec3 pos = scripting::level->player->hitbox->position;
lua_pushnumber(L, pos.x);
@ -101,6 +159,42 @@ int l_get_block_states(lua_State* L) {
return 1;
}
int l_get_block_script_states(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
int offset = lua_tointeger(L, 4) + VOXEL_USER_BITS_OFFSET;
int bits = lua_tointeger(L, 5);
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
lua_pushinteger(L, 0);
return 1;
}
uint mask = ((1 << bits) - 1) << offset;
uint data = (vox->states & mask) >> offset;
lua_pushinteger(L, data);
return 1;
}
int l_set_block_script_states(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
int z = lua_tointeger(L, 3);
int offset = lua_tointeger(L, 4) + VOXEL_USER_BITS_OFFSET;
int bits = lua_tointeger(L, 5);
uint mask = (1 << bits) - 1;
int value = lua_tointeger(L, 6) & mask;
voxel* vox = scripting::level->chunks->get(x, y, z);
if (vox == nullptr) {
return 0;
}
vox->states = (vox->states & (~mask)) | (value << offset);
return 0;
}
int l_is_replaceable_at(lua_State* L) {
int x = lua_tointeger(L, 1);
int y = lua_tointeger(L, 2);
@ -121,9 +215,14 @@ void apilua::create_funcs(lua_State* L) {
lua_addfunc(L, l_is_replaceable_at, "is_replaceable_at");
lua_addfunc(L, l_set_block, "set_block");
lua_addfunc(L, l_get_block, "get_block");
lua_addfunc(L, l_get_block_x, "get_block_X");
lua_addfunc(L, l_get_block_y, "get_block_Y");
lua_addfunc(L, l_get_block_z, "get_block_Z");
lua_addfunc(L, l_get_player_pos, "get_player_pos");
lua_addfunc(L, l_set_player_pos, "set_player_pos");
lua_addfunc(L, l_get_player_rot, "get_player_rot");
lua_addfunc(L, l_set_player_rot, "set_player_rot");
lua_addfunc(L, l_get_block_states, "get_block_states");
lua_addfunc(L, l_get_block_script_states, "get_block_script_states");
lua_addfunc(L, l_set_block_script_states, "set_block_script_states");
}

View File

@ -53,8 +53,14 @@ void scripting::initialize(EnginePaths* paths) {
if (L == nullptr) {
throw std::runtime_error("could not to initialize Lua");
}
// Allowed standard libraries
luaopen_base(L);
luaopen_math(L);
luaopen_string(L);
luaopen_table(L);
// io-manipulations will be implemented via api functions
std::cout << LUA_VERSION << std::endl;
# ifdef LUAJIT_VERSION

View File

@ -9,8 +9,8 @@ typedef unsigned int uint;
// use for bytes arrays
typedef uint8_t ubyte;
typedef uint8_t blockid_t;
typedef uint8_t blockstate_t;
typedef uint16_t blockid_t;
typedef uint16_t blockstate_t;
typedef uint16_t light_t;
#endif

View File

@ -1,4 +1,7 @@
#include "Chunk.h"
#include <memory>
#include "voxel.h"
#include "../content/ContentLUT.h"
#include "../lighting/Lightmap.h"
@ -22,7 +25,7 @@ Chunk::~Chunk(){
bool Chunk::isEmpty(){
int id = -1;
for (int i = 0; i < CHUNK_VOL; i++){
for (size_t i = 0; i < CHUNK_VOL; i++){
if (voxels[i].id != id){
if (id != -1)
return false;
@ -34,14 +37,14 @@ bool Chunk::isEmpty(){
}
void Chunk::updateHeights() {
for (int i = 0; i < CHUNK_VOL; i++) {
for (size_t i = 0; i < CHUNK_VOL; i++) {
if (voxels[i].id != 0) {
bottom = i / (CHUNK_D * CHUNK_W);
break;
}
}
for (int i = CHUNK_VOL - 1; i > -1; i--) {
for (int i = CHUNK_VOL - 1; i >= 0; i--) {
if (voxels[i].id != 0) {
top = i / (CHUNK_D * CHUNK_W) + 1;
break;
@ -51,7 +54,7 @@ void Chunk::updateHeights() {
Chunk* Chunk::clone() const {
Chunk* other = new Chunk(x,z);
for (int i = 0; i < CHUNK_VOL; i++)
for (size_t i = 0; i < CHUNK_VOL; i++)
other->voxels[i] = voxels[i];
other->lightmap->set(lightmap);
return other;
@ -59,32 +62,67 @@ Chunk* Chunk::clone() const {
/**
Current chunk format:
[voxel_ids...][voxel_states...];
- byte-order: big-endian
- [don't panic!] first and second bytes are separated for RLE efficiency
```cpp
uint8_t voxel_id_first_byte[CHUNK_VOL];
uint8_t voxel_id_second_byte[CHUNK_VOL];
uint8_t voxel_states_first_byte[CHUNK_VOL];
uint8_t voxel_states_second_byte[CHUNK_VOL];
```
Total size: (CHUNK_VOL * 4) bytes
*/
ubyte* Chunk::encode() const {
ubyte* buffer = new ubyte[CHUNK_DATA_LEN];
for (size_t i = 0; i < CHUNK_VOL; i++) {
buffer[i] = voxels[i].id;
buffer[CHUNK_VOL + i] = voxels[i].states;
buffer[i] = voxels[i].id >> 8;
buffer[CHUNK_VOL+i] = voxels[i].id & 0xFF;
buffer[CHUNK_VOL*2 + i] = voxels[i].states >> 8;
buffer[CHUNK_VOL*3 + i] = voxels[i].states & 0xFF;
}
return buffer;
}
/**
@return true if all is fine
*/
* @return true if all is fine
**/
bool Chunk::decode(ubyte* data) {
for (size_t i = 0; i < CHUNK_VOL; i++) {
voxel& vox = voxels[i];
vox.id = data[i];
vox.states = data[CHUNK_VOL + i];
ubyte bid1 = data[i];
ubyte bid2 = data[CHUNK_VOL + i];
ubyte bst1 = data[CHUNK_VOL*2 + i];
ubyte bst2 = data[CHUNK_VOL*3 + i];
vox.id = (blockid_t(bid1) << 8) | (blockid_t(bid2));
vox.states = (blockstate_t(bst1) << 8) | (blockstate_t(bst2));
}
return true;
}
void Chunk::convert(ubyte* data, const ContentLUT* lut) {
/*
* Convert chunk voxels data from 16 bit to 32 bit
*/
void Chunk::fromOld(ubyte* data) {
for (size_t i = 0; i < CHUNK_VOL; i++) {
blockid_t id = data[i];
data[i] = lut->getBlockId(id);
data[i + CHUNK_VOL*3] = data[i + CHUNK_VOL];
data[i + CHUNK_VOL] = data[i];
data[i + CHUNK_VOL*2] = 0;
data[i] = 0;
}
}
void Chunk::convert(ubyte* data, const ContentLUT* lut) {
for (size_t i = 0; i < CHUNK_VOL; i++) {
// see encode method to understand what the hell is going on here
blockid_t id = ((blockid_t(data[i]) << 8) |
blockid_t(data[CHUNK_VOL+i]));
blockid_t replacement = lut->getBlockId(id);
data[i] = replacement >> 8;
data[CHUNK_VOL+i] = replacement & 0xFF;
}
}

View File

@ -12,7 +12,7 @@ struct ChunkFlag{
static const int UNSAVED = 0x10;
static const int LOADED_LIGHTS = 0x20;
};
#define CHUNK_DATA_LEN (CHUNK_VOL*2)
#define CHUNK_DATA_LEN (CHUNK_VOL*4)
struct voxel;
class Lightmap;
@ -78,6 +78,7 @@ public:
ubyte* encode() const;
bool decode(ubyte* data);
static void fromOld(ubyte* data);
static void convert(ubyte* data, const ContentLUT* lut);
};