block inventories (backend)
This commit is contained in:
parent
fe57c38edf
commit
87f50f79c9
@ -200,3 +200,11 @@ std::string ByteReader::getString() {
|
||||
bool ByteReader::hasNext() const {
|
||||
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();
|
||||
std::string getString();
|
||||
bool hasNext() const;
|
||||
|
||||
const ubyte* pointer() const;
|
||||
void skip(size_t n);
|
||||
};
|
||||
|
||||
#endif // CODERS_BYTE_UTILS_H_
|
||||
|
||||
@ -29,6 +29,8 @@
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
|
||||
const size_t BUFFER_SIZE_UNKNOWN = -1;
|
||||
|
||||
regfile::regfile(fs::path filename) : file(filename) {
|
||||
if (file.length() < REGION_HEADER_SIZE)
|
||||
throw std::runtime_error("incomplete region file header");
|
||||
@ -217,7 +219,7 @@ void WorldFiles::put(Chunk* chunk){
|
||||
for (auto& entry : inventories) {
|
||||
builder.putInt32(entry.first);
|
||||
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.put(bytes.data(), bytes.size());
|
||||
}
|
||||
@ -226,8 +228,8 @@ void WorldFiles::put(Chunk* chunk){
|
||||
|
||||
auto datavec = builder.data();
|
||||
uint datasize = builder.size();
|
||||
auto data = std::make_unique<ubyte[]>(builder.size());
|
||||
for (uint i = 0; i < builder.size(); i++) {
|
||||
auto data = std::make_unique<ubyte[]>(datasize);
|
||||
for (uint i = 0; i < datasize; i++) {
|
||||
data[i] = datavec[i];
|
||||
}
|
||||
region->put(localX, localZ, data.release(), datasize);
|
||||
@ -289,20 +291,39 @@ fs::path WorldFiles::getPacksFile() const {
|
||||
}
|
||||
|
||||
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
|
||||
* @return lights data or nullptr */
|
||||
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)
|
||||
return nullptr;
|
||||
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,
|
||||
int x, int z, int layer) {
|
||||
int x, int z, int layer, bool compression) {
|
||||
int regionX = floordiv(x, REGION_SIZE);
|
||||
int regionZ = floordiv(z, REGION_SIZE);
|
||||
|
||||
@ -320,7 +341,10 @@ ubyte* WorldFiles::getData(regionsmap& regions, const fs::path& folder,
|
||||
}
|
||||
if (data != nullptr) {
|
||||
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;
|
||||
}
|
||||
@ -372,17 +396,16 @@ ubyte* WorldFiles::readChunkData(int x,
|
||||
file.seekg(table_offset + chunkIndex * 4);
|
||||
file.read((char*)(&offset), 4);
|
||||
offset = dataio::read_int32_big((const ubyte*)(&offset), 0);
|
||||
|
||||
if (offset == 0){
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
file.seekg(offset);
|
||||
file.read((char*)(&offset), 4);
|
||||
length = dataio::read_int32_big((const ubyte*)(&offset), 0);
|
||||
ubyte* data = new ubyte[length];
|
||||
ubyte* data = new ubyte[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;
|
||||
}
|
||||
|
||||
@ -482,7 +505,7 @@ void WorldFiles::write(const World* world, const Content* content) {
|
||||
writeIndices(content->getIndices());
|
||||
writeRegions(regions, regionsFolder, REGION_LAYER_VOXELS);
|
||||
writeRegions(lights, lightsFolder, REGION_LAYER_LIGHTS);
|
||||
writeRegions(storages, inventoriesFolder, REGION_LAYER_STORAGES);
|
||||
writeRegions(storages, inventoriesFolder, REGION_LAYER_INVENTORIES);
|
||||
}
|
||||
|
||||
void WorldFiles::writePacks(const World* world) {
|
||||
|
||||
@ -15,11 +15,13 @@
|
||||
#include "../typedefs.h"
|
||||
#include "../settings.h"
|
||||
|
||||
#include "../voxels/Chunk.h"
|
||||
|
||||
const uint REGION_HEADER_SIZE = 10;
|
||||
|
||||
const uint REGION_LAYER_VOXELS = 0;
|
||||
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 = (1 << (REGION_SIZE_BIT));
|
||||
@ -32,7 +34,6 @@ const uint MAX_OPEN_REGION_FILES = 16;
|
||||
#define WORLD_FORMAT_MAGIC ".VOXWLD"
|
||||
|
||||
class Player;
|
||||
class Chunk;
|
||||
class Content;
|
||||
class ContentIndices;
|
||||
class World;
|
||||
@ -109,7 +110,7 @@ class WorldFiles {
|
||||
|
||||
ubyte* getData(regionsmap& regions,
|
||||
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);
|
||||
|
||||
@ -139,6 +140,7 @@ public:
|
||||
|
||||
ubyte* getChunk(int x, int z);
|
||||
light_t* getLights(int x, int z);
|
||||
chunk_inventories_map fetchInventories(int x, int z);
|
||||
|
||||
bool readWorldInfo(World* world);
|
||||
bool readPlayer(Player* player);
|
||||
|
||||
@ -47,7 +47,10 @@ void Inventory::move(
|
||||
void Inventory::deserialize(dynamic::Map* src) {
|
||||
id = src->getNum("id", 1);
|
||||
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++) {
|
||||
auto item = slotsarr->map(i);
|
||||
itemid_t id = item->getInt("id", ITEM_EMPTY);
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "../util/timeutil.h"
|
||||
#include "../maths/fastmaths.h"
|
||||
#include "../items/Inventory.h"
|
||||
#include "../items/Inventories.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 randomTick(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_
|
||||
|
||||
@ -299,11 +299,21 @@ static int l_inventory_add(lua_State* L) {
|
||||
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 [] = {
|
||||
{"get", l_inventory_get},
|
||||
{"set", l_inventory_set},
|
||||
{"size", l_inventory_size},
|
||||
{"add", l_inventory_add},
|
||||
{"get_block", l_inventory_get_block},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
@ -49,6 +49,16 @@ void Chunk::addBlockInventory(std::shared_ptr<Inventory> inventory,
|
||||
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 {
|
||||
if (x >= CHUNK_W || y >= CHUNK_H || z >= CHUNK_D)
|
||||
return nullptr;
|
||||
|
||||
@ -23,6 +23,8 @@ class Lightmap;
|
||||
class ContentLUT;
|
||||
class Inventory;
|
||||
|
||||
using chunk_inventories_map = std::unordered_map<uint, std::shared_ptr<Inventory>>;
|
||||
|
||||
class Chunk {
|
||||
public:
|
||||
int x, z;
|
||||
@ -32,7 +34,7 @@ public:
|
||||
int flags = 0;
|
||||
|
||||
/* 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);
|
||||
|
||||
@ -55,6 +57,8 @@ public:
|
||||
@return inventory id or 0 if block does not exists */
|
||||
void addBlockInventory(std::shared_ptr<Inventory> inventory,
|
||||
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 */
|
||||
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;
|
||||
|
||||
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.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));
|
||||
if (data) {
|
||||
chunk->decode(data.get());
|
||||
auto invs = wfile->fetchInventories(chunk->x, chunk->z);
|
||||
chunk->setBlockInventories(std::move(invs));
|
||||
chunk->setLoaded(true);
|
||||
verifyLoadedChunk(level->content->getIndices(), chunk.get());
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user