forked from townforge/townforge
game: fix loading schematic models with blocks larger than 8 bits
This commit is contained in:
parent
25cc1bf99a
commit
e9955db73e
@ -5237,11 +5237,26 @@ bool CryptoCityUrho3D::LoadModelData(const std::shared_ptr<Flag> &flag, const st
|
||||
}
|
||||
else if (!mm.front().imported_palette.empty())
|
||||
{
|
||||
// remove unused palette entries in case the imported model is heavy
|
||||
bool used[256];
|
||||
memset(used, 0, sizeof(used));
|
||||
const auto *tiles = flag->get_raw_tiles();
|
||||
const size_t n_tiles = (flag->x1 - flag->x0 + 1) * (flag->y1 - flag->y0 + 1);
|
||||
for (size_t i = 0; i < n_tiles; ++i, ++tiles)
|
||||
{
|
||||
const uint32_t height = tiles->get_height();
|
||||
for (uint32_t h = 0; h < height; ++h)
|
||||
used[tiles->get_type(h)] = true;
|
||||
}
|
||||
for (size_t i = flag->palette.size() - 1; i > 0; --i)
|
||||
if (!used[i])
|
||||
flag->palette.erase(flag->palette.begin() + i);
|
||||
|
||||
std::map<uint8_t, uint8_t> remap;
|
||||
for (auto &e: mm.front().imported_palette)
|
||||
{
|
||||
// the empty block
|
||||
if (e.second == "minecraft:air")
|
||||
if (e.second == "minecraft:air" || e.second == "minecraft::structure_void")
|
||||
{
|
||||
remap[e.first] = 0;
|
||||
continue;
|
||||
|
@ -295,9 +295,10 @@ bool load_schematic_data(std::list<VoxelModel> &sm, const std::string &compresse
|
||||
m.depth = 0;
|
||||
m.height = 0;
|
||||
|
||||
std::map<int32_t, uint16_t> palette_map;
|
||||
int32_t palette_index = -1;
|
||||
if (!load_schematic_data(compressed_data, [&m, &palette_index, &palette_map](uint8_t type, const char *name, const void *data, size_t bytes) {
|
||||
std::map<uint32_t, std::string> imported_palette;
|
||||
|
||||
bool in_palette = false;
|
||||
if (!load_schematic_data(compressed_data, [&m, &in_palette, &imported_palette](uint8_t type, const char *name, const void *data, size_t bytes) {
|
||||
if (type == tag_short && !strcmp(name, "Width"))
|
||||
m.width = *(const uint16_t*)data;
|
||||
else if (type == tag_short && !strcmp(name, "Height"))
|
||||
@ -307,11 +308,11 @@ bool load_schematic_data(std::list<VoxelModel> &sm, const std::string &compresse
|
||||
else if (type == tag_byte_array && !strcmp(name, "BlockData"))
|
||||
m.data.assign((const uint8_t*)data, (const uint8_t*)data + bytes);
|
||||
else if (type == tag_compound && !strcmp(name, "Palette"))
|
||||
palette_index = 0;
|
||||
in_palette = true;
|
||||
else if (type == tag_end)
|
||||
palette_index = -1;
|
||||
else if (type == tag_int && palette_index >= 0)
|
||||
m.imported_palette[*(const int32_t*)data] = name;
|
||||
in_palette = false;
|
||||
else if (type == tag_int && in_palette)
|
||||
imported_palette[*(const int32_t*)data] = name;
|
||||
}))
|
||||
return false;
|
||||
|
||||
@ -336,6 +337,67 @@ bool load_schematic_data(std::list<VoxelModel> &sm, const std::string &compresse
|
||||
return false;
|
||||
}
|
||||
|
||||
// these files have a 32 bit palette, we have a 8 bit palette,
|
||||
// but they have a lot of variations on a smaller number of basic
|
||||
// materials, so we can merge all the variations and hopefully
|
||||
// fit in 8 bits
|
||||
std::map<uint32_t, uint8_t> reduced_palette_map;
|
||||
std::map<uint8_t, std::string> reduced_imported_palette;
|
||||
if (imported_palette.size() > 256 || (!imported_palette.empty() && imported_palette.rbegin()->first >= 256))
|
||||
{
|
||||
std::map<std::string, uint8_t> material_map;
|
||||
size_t palette_entries = 1; // reserve empty/0
|
||||
material_map["minecraft:air"] = 0;
|
||||
material_map["minecraft:structure_void"] = 0; // some test model has that, wiki says empty
|
||||
for (const auto &e: imported_palette)
|
||||
{
|
||||
std::string material = e.second;
|
||||
const char *ptr = strchr(material.c_str(), '[');
|
||||
if (ptr)
|
||||
material.resize(ptr - material.c_str());
|
||||
const auto i = material_map.find(material);
|
||||
if (i == material_map.end())
|
||||
{
|
||||
if (palette_entries == 256)
|
||||
{
|
||||
MERROR("Too many materials to fit in palette");
|
||||
return false;
|
||||
}
|
||||
material_map[material] = palette_entries;
|
||||
reduced_palette_map[e.first] = palette_entries;
|
||||
reduced_imported_palette[palette_entries] = material;
|
||||
++palette_entries;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto &e: imported_palette)
|
||||
m.imported_palette[e.first] = std::move(e.second);
|
||||
}
|
||||
|
||||
const size_t n_blocks = m.width * m.height * (size_t)m.depth;
|
||||
std::vector<uint8_t> blocks;
|
||||
blocks.resize(n_blocks);
|
||||
const uint8_t *begin = m.data.data();
|
||||
const uint8_t *end = m.data.data() + m.data.size();
|
||||
for (size_t i = 0; i < n_blocks; ++i)
|
||||
{
|
||||
uint32_t v;
|
||||
const int read = tools::read_varint(begin, end, v);
|
||||
if (read <= 0)
|
||||
{
|
||||
MERROR("Failed to decode block data");
|
||||
return false;
|
||||
}
|
||||
if (!reduced_palette_map.empty())
|
||||
v = reduced_palette_map[v];
|
||||
blocks[i] = v;
|
||||
}
|
||||
std::swap(m.data, blocks);
|
||||
if (!reduced_imported_palette.empty())
|
||||
std::swap(m.imported_palette, reduced_imported_palette);
|
||||
|
||||
sm.push_back(std::move(m));
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user