1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-06-27 16:36:03 +00:00

Add hardware node coloring. Includes:

- Increase ContentFeatures serialization version
- Color property and palettes for nodes
- paramtype2 = "color", "colored facedir" or "colored wallmounted"
This commit is contained in:
Dániel Juhász 2017-01-12 15:46:30 +01:00 committed by Ekdohibs
parent 43822de5c6
commit d04d8aba70
27 changed files with 1207 additions and 554 deletions

View file

@ -189,7 +189,9 @@ void NodeBox::deSerialize(std::istream &is)
void TileDef::serialize(std::ostream &os, u16 protocol_version) const
{
if (protocol_version >= 29)
if (protocol_version >= 30)
writeU8(os, 4);
else if (protocol_version >= 29)
writeU8(os, 3);
else if (protocol_version >= 26)
writeU8(os, 2);
@ -205,6 +207,14 @@ void TileDef::serialize(std::ostream &os, u16 protocol_version) const
writeU8(os, tileable_horizontal);
writeU8(os, tileable_vertical);
}
if (protocol_version >= 30) {
writeU8(os, has_color);
if (has_color) {
writeU8(os, color.getRed());
writeU8(os, color.getGreen());
writeU8(os, color.getBlue());
}
}
}
void TileDef::deSerialize(std::istream &is, const u8 contenfeatures_version, const NodeDrawType drawtype)
@ -218,6 +228,14 @@ void TileDef::deSerialize(std::istream &is, const u8 contenfeatures_version, con
tileable_horizontal = readU8(is);
tileable_vertical = readU8(is);
}
if (version >= 4) {
has_color = readU8(is);
if (has_color) {
color.setRed(readU8(is));
color.setGreen(readU8(is));
color.setBlue(readU8(is));
}
}
if ((contenfeatures_version < 8) &&
((drawtype == NDT_MESH) ||
@ -351,172 +369,222 @@ void ContentFeatures::reset()
connects_to.clear();
connects_to_ids.clear();
connect_sides = 0;
color = video::SColor(0xFFFFFFFF);
palette_name = "";
palette = NULL;
}
void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
{
if(protocol_version < 24){
if (protocol_version < 30) {
serializeOld(os, protocol_version);
return;
}
writeU8(os, protocol_version < 27 ? 7 : 8);
// version
writeU8(os, 9);
os<<serializeString(name);
// general
os << serializeString(name);
writeU16(os, groups.size());
for(ItemGroupList::const_iterator
i = groups.begin(); i != groups.end(); ++i){
os<<serializeString(i->first);
for (ItemGroupList::const_iterator i = groups.begin(); i != groups.end();
++i) {
os << serializeString(i->first);
writeS16(os, i->second);
}
writeU8(os, param_type);
writeU8(os, param_type_2);
// visual
writeU8(os, drawtype);
os << serializeString(mesh);
writeF1000(os, visual_scale);
writeU8(os, 6);
for(u32 i = 0; i < 6; i++)
for (u32 i = 0; i < 6; i++)
tiledef[i].serialize(os, protocol_version);
writeU8(os, CF_SPECIAL_COUNT);
for(u32 i = 0; i < CF_SPECIAL_COUNT; i++){
for (u32 i = 0; i < CF_SPECIAL_COUNT; i++) {
tiledef_special[i].serialize(os, protocol_version);
}
writeU8(os, alpha);
writeU8(os, color.getRed());
writeU8(os, color.getGreen());
writeU8(os, color.getBlue());
os << serializeString(palette_name);
writeU8(os, waving);
writeU8(os, connect_sides);
writeU16(os, connects_to_ids.size());
for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
i != connects_to_ids.end(); ++i)
writeU16(os, *i);
writeU8(os, post_effect_color.getAlpha());
writeU8(os, post_effect_color.getRed());
writeU8(os, post_effect_color.getGreen());
writeU8(os, post_effect_color.getBlue());
writeU8(os, param_type);
if ((protocol_version < 28) && (param_type_2 == CPT2_MESHOPTIONS))
writeU8(os, CPT2_NONE);
else
writeU8(os, param_type_2);
writeU8(os, is_ground_content);
writeU8(os, leveled);
// lighting
writeU8(os, light_propagates);
writeU8(os, sunlight_propagates);
writeU8(os, light_source);
// map generation
writeU8(os, is_ground_content);
// interaction
writeU8(os, walkable);
writeU8(os, pointable);
writeU8(os, diggable);
writeU8(os, climbable);
writeU8(os, buildable_to);
os<<serializeString(""); // legacy: used to be metadata_name
writeU8(os, rightclickable);
writeU32(os, damage_per_second);
// liquid
writeU8(os, liquid_type);
os<<serializeString(liquid_alternative_flowing);
os<<serializeString(liquid_alternative_source);
os << serializeString(liquid_alternative_flowing);
os << serializeString(liquid_alternative_source);
writeU8(os, liquid_viscosity);
writeU8(os, liquid_renewable);
writeU8(os, light_source);
writeU32(os, damage_per_second);
writeU8(os, liquid_range);
writeU8(os, drowning);
writeU8(os, floodable);
// node boxes
node_box.serialize(os, protocol_version);
selection_box.serialize(os, protocol_version);
writeU8(os, legacy_facedir_simple);
writeU8(os, legacy_wallmounted);
collision_box.serialize(os, protocol_version);
// sound
serializeSimpleSoundSpec(sound_footstep, os);
serializeSimpleSoundSpec(sound_dig, os);
serializeSimpleSoundSpec(sound_dug, os);
writeU8(os, rightclickable);
writeU8(os, drowning);
writeU8(os, leveled);
writeU8(os, liquid_range);
writeU8(os, waving);
// Stuff below should be moved to correct place in a version that otherwise changes
// the protocol version
os<<serializeString(mesh);
collision_box.serialize(os, protocol_version);
writeU8(os, floodable);
writeU16(os, connects_to_ids.size());
for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
i != connects_to_ids.end(); ++i)
writeU16(os, *i);
writeU8(os, connect_sides);
// legacy
writeU8(os, legacy_facedir_simple);
writeU8(os, legacy_wallmounted);
}
void ContentFeatures::correctAlpha()
{
if (alpha == 0 || alpha == 255)
return;
for (u32 i = 0; i < 6; i++) {
std::stringstream s;
s << tiledef[i].name << "^[noalpha^[opacity:" << ((int)alpha);
tiledef[i].name = s.str();
}
for (u32 i = 0; i < CF_SPECIAL_COUNT; i++) {
std::stringstream s;
s << tiledef_special[i].name << "^[noalpha^[opacity:" << ((int)alpha);
tiledef_special[i].name = s.str();
}
}
void ContentFeatures::deSerialize(std::istream &is)
{
// version detection
int version = readU8(is);
if (version < 7) {
if (version < 9) {
deSerializeOld(is, version);
return;
} else if (version > 8) {
} else if (version > 9) {
throw SerializationError("unsupported ContentFeatures version");
}
// general
name = deSerializeString(is);
groups.clear();
u32 groups_size = readU16(is);
for(u32 i = 0; i < groups_size; i++){
for (u32 i = 0; i < groups_size; i++) {
std::string name = deSerializeString(is);
int value = readS16(is);
groups[name] = value;
}
drawtype = (enum NodeDrawType)readU8(is);
param_type = (enum ContentParamType) readU8(is);
param_type_2 = (enum ContentParamType2) readU8(is);
// visual
drawtype = (enum NodeDrawType) readU8(is);
mesh = deSerializeString(is);
visual_scale = readF1000(is);
if(readU8(is) != 6)
if (readU8(is) != 6)
throw SerializationError("unsupported tile count");
for(u32 i = 0; i < 6; i++)
for (u32 i = 0; i < 6; i++)
tiledef[i].deSerialize(is, version, drawtype);
if(readU8(is) != CF_SPECIAL_COUNT)
if (readU8(is) != CF_SPECIAL_COUNT)
throw SerializationError("unsupported CF_SPECIAL_COUNT");
for(u32 i = 0; i < CF_SPECIAL_COUNT; i++)
for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
tiledef_special[i].deSerialize(is, version, drawtype);
alpha = readU8(is);
color.setRed(readU8(is));
color.setGreen(readU8(is));
color.setBlue(readU8(is));
palette_name = deSerializeString(is);
waving = readU8(is);
connect_sides = readU8(is);
u16 connects_to_size = readU16(is);
connects_to_ids.clear();
for (u16 i = 0; i < connects_to_size; i++)
connects_to_ids.insert(readU16(is));
post_effect_color.setAlpha(readU8(is));
post_effect_color.setRed(readU8(is));
post_effect_color.setGreen(readU8(is));
post_effect_color.setBlue(readU8(is));
param_type = (enum ContentParamType)readU8(is);
param_type_2 = (enum ContentParamType2)readU8(is);
is_ground_content = readU8(is);
leveled = readU8(is);
// lighting-related
light_propagates = readU8(is);
sunlight_propagates = readU8(is);
light_source = readU8(is);
light_source = MYMIN(light_source, LIGHT_MAX);
// map generation
is_ground_content = readU8(is);
// interaction
walkable = readU8(is);
pointable = readU8(is);
diggable = readU8(is);
climbable = readU8(is);
buildable_to = readU8(is);
deSerializeString(is); // legacy: used to be metadata_name
liquid_type = (enum LiquidType)readU8(is);
rightclickable = readU8(is);
damage_per_second = readU32(is);
// liquid
liquid_type = (enum LiquidType) readU8(is);
liquid_alternative_flowing = deSerializeString(is);
liquid_alternative_source = deSerializeString(is);
liquid_viscosity = readU8(is);
liquid_renewable = readU8(is);
light_source = readU8(is);
light_source = MYMIN(light_source, LIGHT_MAX);
damage_per_second = readU32(is);
liquid_range = readU8(is);
drowning = readU8(is);
floodable = readU8(is);
// node boxes
node_box.deSerialize(is);
selection_box.deSerialize(is);
legacy_facedir_simple = readU8(is);
legacy_wallmounted = readU8(is);
collision_box.deSerialize(is);
// sounds
deSerializeSimpleSoundSpec(sound_footstep, is);
deSerializeSimpleSoundSpec(sound_dig, is);
deSerializeSimpleSoundSpec(sound_dug, is);
rightclickable = readU8(is);
drowning = readU8(is);
leveled = readU8(is);
liquid_range = readU8(is);
waving = readU8(is);
// If you add anything here, insert it primarily inside the try-catch
// block to not need to increase the version.
try{
// Stuff below should be moved to correct place in a version that
// otherwise changes the protocol version
mesh = deSerializeString(is);
collision_box.deSerialize(is);
floodable = readU8(is);
u16 connects_to_size = readU16(is);
connects_to_ids.clear();
for (u16 i = 0; i < connects_to_size; i++)
connects_to_ids.insert(readU16(is));
connect_sides = readU8(is);
}catch(SerializationError &e) {};
// read legacy properties
legacy_facedir_simple = readU8(is);
legacy_wallmounted = readU8(is);
}
#ifndef SERVER
void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
TileDef *tiledef, u32 shader_id, bool use_normal_texture,
bool backface_culling, u8 alpha, u8 material_type)
bool backface_culling, u8 material_type)
{
tile->shader_id = shader_id;
tile->texture = tsrc->getTextureForMesh(tiledef->name, &tile->texture_id);
tile->alpha = alpha;
tile->material_type = material_type;
// Normal texture and shader flags texture
@ -536,6 +604,13 @@ void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
if (tiledef->tileable_vertical)
tile->material_flags |= MATERIAL_FLAG_TILEABLE_VERTICAL;
// Color
tile->has_color = tiledef->has_color;
if (tiledef->has_color)
tile->color = tiledef->color;
else
tile->color = color;
// Animation parameters
int frame_count = 1;
if (tile->material_flags & MATERIAL_FLAG_ANIMATION) {
@ -681,6 +756,9 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
is_water_surface = true;
}
// Vertex alpha is no longer supported, correct if necessary.
correctAlpha();
u32 tile_shader[6];
for (u16 j = 0; j < 6; j++) {
tile_shader[j] = shdsrc->getShader("nodes_shader",
@ -696,14 +774,14 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
for (u16 j = 0; j < 6; j++) {
fillTileAttribs(tsrc, &tiles[j], &tdef[j], tile_shader[j],
tsettings.use_normal_texture,
tiledef[j].backface_culling, alpha, material_type);
tiledef[j].backface_culling, material_type);
}
// Special tiles (fill in f->special_tiles[])
for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) {
fillTileAttribs(tsrc, &special_tiles[j], &tiledef_special[j],
tile_shader[j], tsettings.use_normal_texture,
tiledef_special[j].backface_culling, alpha, material_type);
tiledef_special[j].backface_culling, material_type);
}
if ((drawtype == NDT_MESH) && (mesh != "")) {
@ -731,15 +809,19 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
}
//Cache 6dfacedir and wallmounted rotated clones of meshes
if (tsettings.enable_mesh_cache && mesh_ptr[0] && (param_type_2 == CPT2_FACEDIR)) {
if (tsettings.enable_mesh_cache && mesh_ptr[0] &&
(param_type_2 == CPT2_FACEDIR
|| param_type_2 == CPT2_COLORED_FACEDIR)) {
for (u16 j = 1; j < 24; j++) {
mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
rotateMeshBy6dFacedir(mesh_ptr[j], j);
recalculateBoundingBox(mesh_ptr[j]);
meshmanip->recalculateNormals(mesh_ptr[j], true, false);
}
} else if (tsettings.enable_mesh_cache && mesh_ptr[0] && (param_type_2 == CPT2_WALLMOUNTED)) {
static const u8 wm_to_6d[6] = {20, 0, 16+1, 12+3, 8, 4+2};
} else if (tsettings.enable_mesh_cache && mesh_ptr[0]
&& (param_type_2 == CPT2_WALLMOUNTED ||
param_type_2 == CPT2_COLORED_WALLMOUNTED)) {
static const u8 wm_to_6d[6] = { 20, 0, 16 + 1, 12 + 3, 8, 4 + 2 };
for (u16 j = 1; j < 6; j++) {
mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
rotateMeshBy6dFacedir(mesh_ptr[j], wm_to_6d[j]);
@ -775,6 +857,9 @@ public:
virtual void removeNode(const std::string &name);
virtual void updateAliases(IItemDefManager *idef);
virtual void applyTextureOverrides(const std::string &override_filepath);
//! Returns a palette or NULL if not found. Only on client.
std::vector<video::SColor> *getPalette(const ContentFeatures &f,
const IGameDef *gamedef);
virtual void updateTextures(IGameDef *gamedef,
void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress),
void *progress_cbk_args);
@ -823,6 +908,9 @@ private:
// Next possibly free id
content_t m_next_id;
// Maps image file names to loaded palettes.
UNORDERED_MAP<std::string, std::vector<video::SColor> > m_palettes;
// NodeResolvers to callback once node registration has ended
std::vector<NodeResolver *> m_pending_resolve_callbacks;
@ -1062,7 +1150,8 @@ void getNodeBoxUnion(const NodeBox &nodebox, const ContentFeatures &features,
if (nodebox.type == NODEBOX_LEVELED) {
half_processed.MaxEdge.Y = +BS / 2;
}
if (features.param_type_2 == CPT2_FACEDIR) {
if (features.param_type_2 == CPT2_FACEDIR ||
features.param_type_2 == CPT2_COLORED_FACEDIR) {
// Get maximal coordinate
f32 coords[] = {
fabsf(half_processed.MinEdge.X),
@ -1309,6 +1398,78 @@ void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath
}
}
std::vector<video::SColor> *CNodeDefManager::getPalette(
const ContentFeatures &f, const IGameDef *gamedef)
{
#ifndef SERVER
// This works because colors always use the most significant bits
// of param2. If you add a new colored type which uses param2
// in a more advanced way, you should change this code, too.
u32 palette_pixels = 0;
switch (f.param_type_2) {
case CPT2_COLOR:
palette_pixels = 256;
break;
case CPT2_COLORED_FACEDIR:
palette_pixels = 8;
break;
case CPT2_COLORED_WALLMOUNTED:
palette_pixels = 32;
break;
default:
return NULL;
}
// This many param2 values will have the same color
u32 step = 256 / palette_pixels;
const std::string &name = f.palette_name;
if (name == "")
return NULL;
Client *client = (Client *) gamedef;
ITextureSource *tsrc = client->tsrc();
UNORDERED_MAP<std::string, std::vector<video::SColor> >::iterator it =
m_palettes.find(name);
if (it == m_palettes.end()) {
// Create palette
if (!tsrc->isKnownSourceImage(name)) {
warningstream << "CNodeDefManager::getPalette(): palette \"" << name
<< "\" could not be loaded." << std::endl;
return NULL;
}
video::IImage *img = tsrc->generateImage(name);
std::vector<video::SColor> new_palette;
u32 w = img->getDimension().Width;
u32 h = img->getDimension().Height;
// Real area of the image
u32 area = h * w;
if (area != palette_pixels)
warningstream << "CNodeDefManager::getPalette(): the "
<< "specified palette image \"" << name << "\" does not "
<< "contain exactly " << palette_pixels
<< " pixels." << std::endl;
if (area > palette_pixels)
area = palette_pixels;
// For each pixel in the image
for (u32 i = 0; i < area; i++) {
video::SColor c = img->getPixel(i % w, i / w);
// Fill in palette with 'step' colors
for (u32 j = 0; j < step; j++)
new_palette.push_back(c);
}
img->drop();
// Fill in remaining elements
while (new_palette.size() < 256)
new_palette.push_back(video::SColor(0xFFFFFFFF));
m_palettes[name] = new_palette;
it = m_palettes.find(name);
}
if (it != m_palettes.end())
return &((*it).second);
#endif
return NULL;
}
void CNodeDefManager::updateTextures(IGameDef *gamedef,
void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
void *progress_callback_args)
@ -1325,10 +1486,13 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef,
TextureSettings tsettings;
tsettings.readSettings();
m_palettes.clear();
u32 size = m_content_features.size();
for (u32 i = 0; i < size; i++) {
m_content_features[i].updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
ContentFeatures *f = &(m_content_features[i]);
f->palette = getPalette(*f, gamedef);
f->updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
progress_callback(progress_callback_args, i, size);
}
#endif
@ -1429,6 +1593,19 @@ IWritableNodeDefManager *createNodeDefManager()
//// Serialization of old ContentFeatures formats
void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
{
u8 compatible_param_type_2 = param_type_2;
if ((protocol_version < 28)
&& (compatible_param_type_2 == CPT2_MESHOPTIONS))
compatible_param_type_2 = CPT2_NONE;
else if (protocol_version < 30) {
if (compatible_param_type_2 == CPT2_COLOR)
compatible_param_type_2 = CPT2_NONE;
else if (compatible_param_type_2 == CPT2_COLORED_FACEDIR)
compatible_param_type_2 = CPT2_FACEDIR;
else if (compatible_param_type_2 == CPT2_COLORED_WALLMOUNTED)
compatible_param_type_2 = CPT2_WALLMOUNTED;
}
if (protocol_version == 13)
{
writeU8(os, 5); // version
@ -1454,7 +1631,7 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
writeU8(os, post_effect_color.getGreen());
writeU8(os, post_effect_color.getBlue());
writeU8(os, param_type);
writeU8(os, param_type_2);
writeU8(os, compatible_param_type_2);
writeU8(os, is_ground_content);
writeU8(os, light_propagates);
writeU8(os, sunlight_propagates);
@ -1483,9 +1660,9 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
os<<serializeString(name);
writeU16(os, groups.size());
for (ItemGroupList::const_iterator
i = groups.begin(); i != groups.end(); ++i) {
os<<serializeString(i->first);
writeS16(os, i->second);
i = groups.begin(); i != groups.end(); ++i) {
os<<serializeString(i->first);
writeS16(os, i->second);
}
writeU8(os, drawtype);
writeF1000(os, visual_scale);
@ -1502,7 +1679,7 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
writeU8(os, post_effect_color.getGreen());
writeU8(os, post_effect_color.getBlue());
writeU8(os, param_type);
writeU8(os, param_type_2);
writeU8(os, compatible_param_type_2);
writeU8(os, is_ground_content);
writeU8(os, light_propagates);
writeU8(os, sunlight_propagates);
@ -1530,6 +1707,68 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
writeU8(os, drowning);
writeU8(os, leveled);
writeU8(os, liquid_range);
}
else if(protocol_version >= 24 && protocol_version < 30) {
writeU8(os, protocol_version < 27 ? 7 : 8);
os << serializeString(name);
writeU16(os, groups.size());
for (ItemGroupList::const_iterator i = groups.begin();
i != groups.end(); ++i) {
os << serializeString(i->first);
writeS16(os, i->second);
}
writeU8(os, drawtype);
writeF1000(os, visual_scale);
writeU8(os, 6);
for (u32 i = 0; i < 6; i++)
tiledef[i].serialize(os, protocol_version);
writeU8(os, CF_SPECIAL_COUNT);
for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
tiledef_special[i].serialize(os, protocol_version);
writeU8(os, alpha);
writeU8(os, post_effect_color.getAlpha());
writeU8(os, post_effect_color.getRed());
writeU8(os, post_effect_color.getGreen());
writeU8(os, post_effect_color.getBlue());
writeU8(os, param_type);
writeU8(os, compatible_param_type_2);
writeU8(os, is_ground_content);
writeU8(os, light_propagates);
writeU8(os, sunlight_propagates);
writeU8(os, walkable);
writeU8(os, pointable);
writeU8(os, diggable);
writeU8(os, climbable);
writeU8(os, buildable_to);
os << serializeString(""); // legacy: used to be metadata_name
writeU8(os, liquid_type);
os << serializeString(liquid_alternative_flowing);
os << serializeString(liquid_alternative_source);
writeU8(os, liquid_viscosity);
writeU8(os, liquid_renewable);
writeU8(os, light_source);
writeU32(os, damage_per_second);
node_box.serialize(os, protocol_version);
selection_box.serialize(os, protocol_version);
writeU8(os, legacy_facedir_simple);
writeU8(os, legacy_wallmounted);
serializeSimpleSoundSpec(sound_footstep, os);
serializeSimpleSoundSpec(sound_dig, os);
serializeSimpleSoundSpec(sound_dug, os);
writeU8(os, rightclickable);
writeU8(os, drowning);
writeU8(os, leveled);
writeU8(os, liquid_range);
writeU8(os, waving);
os << serializeString(mesh);
collision_box.serialize(os, protocol_version);
writeU8(os, floodable);
writeU16(os, connects_to_ids.size());
for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
i != connects_to_ids.end(); ++i)
writeU16(os, *i);
writeU8(os, connect_sides);
} else
throw SerializationError("ContentFeatures::serialize(): "
"Unsupported version requested");
@ -1642,7 +1881,73 @@ void ContentFeatures::deSerializeOld(std::istream &is, int version)
drowning = readU8(is);
leveled = readU8(is);
liquid_range = readU8(is);
} else {
} else if (version == 7 || version == 8){
name = deSerializeString(is);
groups.clear();
u32 groups_size = readU16(is);
for (u32 i = 0; i < groups_size; i++) {
std::string name = deSerializeString(is);
int value = readS16(is);
groups[name] = value;
}
drawtype = (enum NodeDrawType) readU8(is);
visual_scale = readF1000(is);
if (readU8(is) != 6)
throw SerializationError("unsupported tile count");
for (u32 i = 0; i < 6; i++)
tiledef[i].deSerialize(is, version, drawtype);
if (readU8(is) != CF_SPECIAL_COUNT)
throw SerializationError("unsupported CF_SPECIAL_COUNT");
for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
tiledef_special[i].deSerialize(is, version, drawtype);
alpha = readU8(is);
post_effect_color.setAlpha(readU8(is));
post_effect_color.setRed(readU8(is));
post_effect_color.setGreen(readU8(is));
post_effect_color.setBlue(readU8(is));
param_type = (enum ContentParamType) readU8(is);
param_type_2 = (enum ContentParamType2) readU8(is);
is_ground_content = readU8(is);
light_propagates = readU8(is);
sunlight_propagates = readU8(is);
walkable = readU8(is);
pointable = readU8(is);
diggable = readU8(is);
climbable = readU8(is);
buildable_to = readU8(is);
deSerializeString(is); // legacy: used to be metadata_name
liquid_type = (enum LiquidType) readU8(is);
liquid_alternative_flowing = deSerializeString(is);
liquid_alternative_source = deSerializeString(is);
liquid_viscosity = readU8(is);
liquid_renewable = readU8(is);
light_source = readU8(is);
light_source = MYMIN(light_source, LIGHT_MAX);
damage_per_second = readU32(is);
node_box.deSerialize(is);
selection_box.deSerialize(is);
legacy_facedir_simple = readU8(is);
legacy_wallmounted = readU8(is);
deSerializeSimpleSoundSpec(sound_footstep, is);
deSerializeSimpleSoundSpec(sound_dig, is);
deSerializeSimpleSoundSpec(sound_dug, is);
rightclickable = readU8(is);
drowning = readU8(is);
leveled = readU8(is);
liquid_range = readU8(is);
waving = readU8(is);
try {
mesh = deSerializeString(is);
collision_box.deSerialize(is);
floodable = readU8(is);
u16 connects_to_size = readU16(is);
connects_to_ids.clear();
for (u16 i = 0; i < connects_to_size; i++)
connects_to_ids.insert(readU16(is));
connect_sides = readU8(is);
} catch (SerializationError &e) {};
}else{
throw SerializationError("unsupported ContentFeatures version");
}
}
@ -1736,19 +2041,23 @@ bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face)
// does to node declare usable faces?
if (f2.connect_sides > 0) {
if ((f2.param_type_2 == CPT2_FACEDIR) && (connect_face >= 4)) {
static const u8 rot[33 * 4] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 - back
8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 - right
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16, 8, 4, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - front
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
32, 16, 8, 4 // 32 - left
};
return (f2.connect_sides & rot[(connect_face * 4) + to.param2]);
if ((f2.param_type_2 == CPT2_FACEDIR ||
f2.param_type_2 == CPT2_COLORED_FACEDIR)
&& (connect_face >= 4)) {
static const u8 rot[33 * 4] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, // 4 - back
8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, // 8 - right
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 8, 4, 32, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, // 16 - front
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 32, 16, 8, 4 // 32 - left
};
return (f2.connect_sides
& rot[(connect_face * 4) + (to.param2 & 0x1F)]);
}
return (f2.connect_sides & connect_face);
}