block inventories (backend)
This commit is contained in:
@@ -200,3 +200,11 @@ std::string ByteReader::getString() {
|
|||||||
bool ByteReader::hasNext() const {
|
bool ByteReader::hasNext() const {
|
||||||
return pos < size;
|
return pos < size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ubyte* ByteReader::pointer() const {
|
||||||
|
return data + pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByteReader::skip(size_t n) {
|
||||||
|
pos += n;
|
||||||
|
}
|
||||||
@@ -71,6 +71,9 @@ public:
|
|||||||
const char* getCString();
|
const char* getCString();
|
||||||
std::string getString();
|
std::string getString();
|
||||||
bool hasNext() const;
|
bool hasNext() const;
|
||||||
|
|
||||||
|
const ubyte* pointer() const;
|
||||||
|
void skip(size_t n);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CODERS_BYTE_UTILS_H_
|
#endif // CODERS_BYTE_UTILS_H_
|
||||||
|
|||||||
+35
-12
@@ -29,6 +29,8 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
const size_t BUFFER_SIZE_UNKNOWN = -1;
|
||||||
|
|
||||||
regfile::regfile(fs::path filename) : file(filename) {
|
regfile::regfile(fs::path filename) : file(filename) {
|
||||||
if (file.length() < REGION_HEADER_SIZE)
|
if (file.length() < REGION_HEADER_SIZE)
|
||||||
throw std::runtime_error("incomplete region file header");
|
throw std::runtime_error("incomplete region file header");
|
||||||
@@ -217,7 +219,7 @@ void WorldFiles::put(Chunk* chunk){
|
|||||||
for (auto& entry : inventories) {
|
for (auto& entry : inventories) {
|
||||||
builder.putInt32(entry.first);
|
builder.putInt32(entry.first);
|
||||||
auto map = entry.second->serialize();
|
auto map = entry.second->serialize();
|
||||||
auto bytes = json::to_binary(map.get(), true);
|
auto bytes = json::to_binary(map.get(), false);
|
||||||
builder.putInt32(bytes.size());
|
builder.putInt32(bytes.size());
|
||||||
builder.put(bytes.data(), bytes.size());
|
builder.put(bytes.data(), bytes.size());
|
||||||
}
|
}
|
||||||
@@ -226,8 +228,8 @@ void WorldFiles::put(Chunk* chunk){
|
|||||||
|
|
||||||
auto datavec = builder.data();
|
auto datavec = builder.data();
|
||||||
uint datasize = builder.size();
|
uint datasize = builder.size();
|
||||||
auto data = std::make_unique<ubyte[]>(builder.size());
|
auto data = std::make_unique<ubyte[]>(datasize);
|
||||||
for (uint i = 0; i < builder.size(); i++) {
|
for (uint i = 0; i < datasize; i++) {
|
||||||
data[i] = datavec[i];
|
data[i] = datavec[i];
|
||||||
}
|
}
|
||||||
region->put(localX, localZ, data.release(), datasize);
|
region->put(localX, localZ, data.release(), datasize);
|
||||||
@@ -289,20 +291,39 @@ fs::path WorldFiles::getPacksFile() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ubyte* WorldFiles::getChunk(int x, int z){
|
ubyte* WorldFiles::getChunk(int x, int z){
|
||||||
return getData(regions, getRegionsFolder(), x, z, REGION_LAYER_VOXELS);
|
return getData(regions, getRegionsFolder(), x, z, REGION_LAYER_VOXELS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get cached lights for chunk at x,z
|
/* Get cached lights for chunk at x,z
|
||||||
* @return lights data or nullptr */
|
* @return lights data or nullptr */
|
||||||
light_t* WorldFiles::getLights(int x, int z) {
|
light_t* WorldFiles::getLights(int x, int z) {
|
||||||
std::unique_ptr<ubyte> data (getData(lights, getLightsFolder(), x, z, REGION_LAYER_LIGHTS));
|
std::unique_ptr<ubyte[]> data (getData(lights, getLightsFolder(), x, z, REGION_LAYER_LIGHTS, true));
|
||||||
if (data == nullptr)
|
if (data == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return Lightmap::decode(data.get());
|
return Lightmap::decode(data.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chunk_inventories_map WorldFiles::fetchInventories(int x, int z) {
|
||||||
|
chunk_inventories_map inventories;
|
||||||
|
const ubyte* data = getData(storages, getInventoriesFolder(), x, z, REGION_LAYER_INVENTORIES, false);
|
||||||
|
if (data == nullptr)
|
||||||
|
return inventories;
|
||||||
|
ByteReader reader(data, BUFFER_SIZE_UNKNOWN);
|
||||||
|
int count = reader.getInt32();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
uint index = reader.getInt32();
|
||||||
|
uint size = reader.getInt32();
|
||||||
|
auto map = json::from_binary(reader.pointer(), size);
|
||||||
|
reader.skip(size);
|
||||||
|
auto inv = std::make_shared<Inventory>(0, 0);
|
||||||
|
inv->deserialize(map.get());
|
||||||
|
inventories[index] = inv;
|
||||||
|
}
|
||||||
|
return inventories;
|
||||||
|
}
|
||||||
|
|
||||||
ubyte* WorldFiles::getData(regionsmap& regions, const fs::path& folder,
|
ubyte* WorldFiles::getData(regionsmap& regions, const fs::path& folder,
|
||||||
int x, int z, int layer) {
|
int x, int z, int layer, bool compression) {
|
||||||
int regionX = floordiv(x, REGION_SIZE);
|
int regionX = floordiv(x, REGION_SIZE);
|
||||||
int regionZ = floordiv(z, REGION_SIZE);
|
int regionZ = floordiv(z, REGION_SIZE);
|
||||||
|
|
||||||
@@ -320,7 +341,10 @@ ubyte* WorldFiles::getData(regionsmap& regions, const fs::path& folder,
|
|||||||
}
|
}
|
||||||
if (data != nullptr) {
|
if (data != nullptr) {
|
||||||
size_t size = region->getChunkDataSize(localX, localZ);
|
size_t size = region->getChunkDataSize(localX, localZ);
|
||||||
return decompress(data, size, CHUNK_DATA_LEN);
|
if (compression) {
|
||||||
|
return decompress(data, size, CHUNK_DATA_LEN);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -372,17 +396,16 @@ ubyte* WorldFiles::readChunkData(int x,
|
|||||||
file.seekg(table_offset + chunkIndex * 4);
|
file.seekg(table_offset + chunkIndex * 4);
|
||||||
file.read((char*)(&offset), 4);
|
file.read((char*)(&offset), 4);
|
||||||
offset = dataio::read_int32_big((const ubyte*)(&offset), 0);
|
offset = dataio::read_int32_big((const ubyte*)(&offset), 0);
|
||||||
|
|
||||||
if (offset == 0){
|
if (offset == 0){
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.seekg(offset);
|
file.seekg(offset);
|
||||||
file.read((char*)(&offset), 4);
|
file.read((char*)(&offset), 4);
|
||||||
length = dataio::read_int32_big((const ubyte*)(&offset), 0);
|
length = dataio::read_int32_big((const ubyte*)(&offset), 0);
|
||||||
ubyte* data = new ubyte[length];
|
ubyte* data = new ubyte[length]{};
|
||||||
file.read((char*)data, length);
|
file.read((char*)data, length);
|
||||||
if (data == nullptr) {
|
|
||||||
std::cerr << "ERROR: failed to read data of chunk x("<< x <<"), z("<< z <<")" << std::endl;
|
|
||||||
}
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,7 +505,7 @@ void WorldFiles::write(const World* world, const Content* content) {
|
|||||||
writeIndices(content->getIndices());
|
writeIndices(content->getIndices());
|
||||||
writeRegions(regions, regionsFolder, REGION_LAYER_VOXELS);
|
writeRegions(regions, regionsFolder, REGION_LAYER_VOXELS);
|
||||||
writeRegions(lights, lightsFolder, REGION_LAYER_LIGHTS);
|
writeRegions(lights, lightsFolder, REGION_LAYER_LIGHTS);
|
||||||
writeRegions(storages, inventoriesFolder, REGION_LAYER_STORAGES);
|
writeRegions(storages, inventoriesFolder, REGION_LAYER_INVENTORIES);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldFiles::writePacks(const World* world) {
|
void WorldFiles::writePacks(const World* world) {
|
||||||
|
|||||||
@@ -15,11 +15,13 @@
|
|||||||
#include "../typedefs.h"
|
#include "../typedefs.h"
|
||||||
#include "../settings.h"
|
#include "../settings.h"
|
||||||
|
|
||||||
|
#include "../voxels/Chunk.h"
|
||||||
|
|
||||||
const uint REGION_HEADER_SIZE = 10;
|
const uint REGION_HEADER_SIZE = 10;
|
||||||
|
|
||||||
const uint REGION_LAYER_VOXELS = 0;
|
const uint REGION_LAYER_VOXELS = 0;
|
||||||
const uint REGION_LAYER_LIGHTS = 1;
|
const uint REGION_LAYER_LIGHTS = 1;
|
||||||
const uint REGION_LAYER_STORAGES = 2;
|
const uint REGION_LAYER_INVENTORIES = 2;
|
||||||
|
|
||||||
const uint REGION_SIZE_BIT = 5;
|
const uint REGION_SIZE_BIT = 5;
|
||||||
const uint REGION_SIZE = (1 << (REGION_SIZE_BIT));
|
const uint REGION_SIZE = (1 << (REGION_SIZE_BIT));
|
||||||
@@ -32,7 +34,6 @@ const uint MAX_OPEN_REGION_FILES = 16;
|
|||||||
#define WORLD_FORMAT_MAGIC ".VOXWLD"
|
#define WORLD_FORMAT_MAGIC ".VOXWLD"
|
||||||
|
|
||||||
class Player;
|
class Player;
|
||||||
class Chunk;
|
|
||||||
class Content;
|
class Content;
|
||||||
class ContentIndices;
|
class ContentIndices;
|
||||||
class World;
|
class World;
|
||||||
@@ -109,7 +110,7 @@ class WorldFiles {
|
|||||||
|
|
||||||
ubyte* getData(regionsmap& regions,
|
ubyte* getData(regionsmap& regions,
|
||||||
const fs::path& folder,
|
const fs::path& folder,
|
||||||
int x, int z, int layer);
|
int x, int z, int layer, bool compression);
|
||||||
|
|
||||||
regfile* getRegFile(glm::ivec3 coord, const fs::path& folder);
|
regfile* getRegFile(glm::ivec3 coord, const fs::path& folder);
|
||||||
|
|
||||||
@@ -139,6 +140,7 @@ public:
|
|||||||
|
|
||||||
ubyte* getChunk(int x, int z);
|
ubyte* getChunk(int x, int z);
|
||||||
light_t* getLights(int x, int z);
|
light_t* getLights(int x, int z);
|
||||||
|
chunk_inventories_map fetchInventories(int x, int z);
|
||||||
|
|
||||||
bool readWorldInfo(World* world);
|
bool readWorldInfo(World* world);
|
||||||
bool readPlayer(Player* player);
|
bool readPlayer(Player* player);
|
||||||
|
|||||||
@@ -47,7 +47,10 @@ void Inventory::move(
|
|||||||
void Inventory::deserialize(dynamic::Map* src) {
|
void Inventory::deserialize(dynamic::Map* src) {
|
||||||
id = src->getNum("id", 1);
|
id = src->getNum("id", 1);
|
||||||
auto slotsarr = src->list("slots");
|
auto slotsarr = src->list("slots");
|
||||||
size_t slotscount = std::min(slotsarr->size(), slots.size());
|
size_t slotscount = slotsarr->size();
|
||||||
|
while (slots.size() < slotscount) {
|
||||||
|
slots.push_back(ItemStack());
|
||||||
|
}
|
||||||
for (size_t i = 0; i < slotscount; i++) {
|
for (size_t i = 0; i < slotscount; i++) {
|
||||||
auto item = slotsarr->map(i);
|
auto item = slotsarr->map(i);
|
||||||
itemid_t id = item->getInt("id", ITEM_EMPTY);
|
itemid_t id = item->getInt("id", ITEM_EMPTY);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "../util/timeutil.h"
|
#include "../util/timeutil.h"
|
||||||
#include "../maths/fastmaths.h"
|
#include "../maths/fastmaths.h"
|
||||||
#include "../items/Inventory.h"
|
#include "../items/Inventory.h"
|
||||||
|
#include "../items/Inventories.h"
|
||||||
|
|
||||||
#include "scripting/scripting.h"
|
#include "scripting/scripting.h"
|
||||||
|
|
||||||
@@ -147,3 +148,24 @@ void BlocksController::randomTick(int tickid, int parts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t BlocksController::createBlockInventory(int x, int y, int z) {
|
||||||
|
auto chunk = chunks->getChunkByVoxel(x, y, z);
|
||||||
|
if (chunk == nullptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int lx = x - chunk->x * CHUNK_W;
|
||||||
|
int lz = z - chunk->z * CHUNK_D;
|
||||||
|
auto inv = chunk->getBlockInventory(lx, y, lz);
|
||||||
|
if (inv == nullptr) {
|
||||||
|
auto indices = level->content->getIndices();
|
||||||
|
auto def = indices->getBlockDef(chunk->voxels[vox_index(lx, y, lz)].id);
|
||||||
|
int invsize = def->inventorySize;
|
||||||
|
if (invsize == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
inv = level->inventories->create(invsize);
|
||||||
|
chunk->addBlockInventory(inv, lx, y, lz);
|
||||||
|
}
|
||||||
|
return inv->getId();
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public:
|
|||||||
void update(float delta);
|
void update(float delta);
|
||||||
void randomTick(int tickid, int parts);
|
void randomTick(int tickid, int parts);
|
||||||
void onBlocksTick(int tickid, int parts);
|
void onBlocksTick(int tickid, int parts);
|
||||||
uint createBlockInventory(int x, int y, int z);
|
int64_t createBlockInventory(int x, int y, int z);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LOGIC_BLOCKS_CONTROLLER_H_
|
#endif // LOGIC_BLOCKS_CONTROLLER_H_
|
||||||
|
|||||||
@@ -299,11 +299,21 @@ static int l_inventory_add(lua_State* L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int l_inventory_get_block(lua_State* L) {
|
||||||
|
lua::luaint x = lua_tointeger(L, 1);
|
||||||
|
lua::luaint y = lua_tointeger(L, 2);
|
||||||
|
lua::luaint z = lua_tointeger(L, 3);
|
||||||
|
int64_t id = scripting::blocks->createBlockInventory(x, y, z);
|
||||||
|
lua_pushinteger(L, id);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static const luaL_Reg inventorylib [] = {
|
static const luaL_Reg inventorylib [] = {
|
||||||
{"get", l_inventory_get},
|
{"get", l_inventory_get},
|
||||||
{"set", l_inventory_set},
|
{"set", l_inventory_set},
|
||||||
{"size", l_inventory_size},
|
{"size", l_inventory_size},
|
||||||
{"add", l_inventory_add},
|
{"add", l_inventory_add},
|
||||||
|
{"get_block", l_inventory_get_block},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,16 @@ void Chunk::addBlockInventory(std::shared_ptr<Inventory> inventory,
|
|||||||
setUnsaved(true);
|
setUnsaved(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Chunk::removeBlockInventory(uint x, uint y, uint z) {
|
||||||
|
if (inventories.erase(vox_index(x, y, z))) {
|
||||||
|
setUnsaved(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Chunk::setBlockInventories(chunk_inventories_map map) {
|
||||||
|
inventories = map;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<Inventory> Chunk::getBlockInventory(uint x, uint y, uint z) const {
|
std::shared_ptr<Inventory> Chunk::getBlockInventory(uint x, uint y, uint z) const {
|
||||||
if (x >= CHUNK_W || y >= CHUNK_H || z >= CHUNK_D)
|
if (x >= CHUNK_W || y >= CHUNK_H || z >= CHUNK_D)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|||||||
+5
-1
@@ -23,6 +23,8 @@ class Lightmap;
|
|||||||
class ContentLUT;
|
class ContentLUT;
|
||||||
class Inventory;
|
class Inventory;
|
||||||
|
|
||||||
|
using chunk_inventories_map = std::unordered_map<uint, std::shared_ptr<Inventory>>;
|
||||||
|
|
||||||
class Chunk {
|
class Chunk {
|
||||||
public:
|
public:
|
||||||
int x, z;
|
int x, z;
|
||||||
@@ -32,7 +34,7 @@ public:
|
|||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
|
||||||
/* Block inventories map where key is index of block in voxels array */
|
/* Block inventories map where key is index of block in voxels array */
|
||||||
std::unordered_map<uint, std::shared_ptr<Inventory>> inventories;
|
chunk_inventories_map inventories;
|
||||||
|
|
||||||
Chunk(int x, int z);
|
Chunk(int x, int z);
|
||||||
|
|
||||||
@@ -55,6 +57,8 @@ public:
|
|||||||
@return inventory id or 0 if block does not exists */
|
@return inventory id or 0 if block does not exists */
|
||||||
void addBlockInventory(std::shared_ptr<Inventory> inventory,
|
void addBlockInventory(std::shared_ptr<Inventory> inventory,
|
||||||
uint x, uint y, uint z);
|
uint x, uint y, uint z);
|
||||||
|
void removeBlockInventory(uint x, uint y, uint z);
|
||||||
|
void setBlockInventories(chunk_inventories_map map);
|
||||||
|
|
||||||
/* @return inventory bound to the given block or nullptr */
|
/* @return inventory bound to the given block or nullptr */
|
||||||
std::shared_ptr<Inventory> getBlockInventory(uint x, uint y, uint z) const;
|
std::shared_ptr<Inventory> getBlockInventory(uint x, uint y, uint z) const;
|
||||||
|
|||||||
@@ -162,6 +162,9 @@ void Chunks::set(int x, int y, int z, int id, uint8_t states){
|
|||||||
int lz = z - cz * CHUNK_D;
|
int lz = z - cz * CHUNK_D;
|
||||||
|
|
||||||
voxel& vox = chunk->voxels[(y * CHUNK_D + lz) * CHUNK_W + lx];
|
voxel& vox = chunk->voxels[(y * CHUNK_D + lz) * CHUNK_W + lx];
|
||||||
|
auto def = contentIds->getBlockDef(vox.id);
|
||||||
|
if (def->inventorySize == 0)
|
||||||
|
chunk->removeBlockInventory(lx, y, lz);
|
||||||
vox.id = id;
|
vox.id = id;
|
||||||
vox.states = states;
|
vox.states = states;
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ std::shared_ptr<Chunk> ChunksStorage::create(int x, int z) {
|
|||||||
std::unique_ptr<ubyte[]> data(wfile->getChunk(chunk->x, chunk->z));
|
std::unique_ptr<ubyte[]> data(wfile->getChunk(chunk->x, chunk->z));
|
||||||
if (data) {
|
if (data) {
|
||||||
chunk->decode(data.get());
|
chunk->decode(data.get());
|
||||||
|
auto invs = wfile->fetchInventories(chunk->x, chunk->z);
|
||||||
|
chunk->setBlockInventories(std::move(invs));
|
||||||
chunk->setLoaded(true);
|
chunk->setLoaded(true);
|
||||||
verifyLoadedChunk(level->content->getIndices(), chunk.get());
|
verifyLoadedChunk(level->content->getIndices(), chunk.get());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user