X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fnodedef.cpp;h=2745a45e8cb1644f9eee09f7f93998ba1743f68b;hb=e70e15134c95d37241bb6f6124105c0f1c08ab8a;hp=b7d023897ad58e1bb1cec6c63c65ed7828befd9e;hpb=8e7449e09253e138716d8dbad6a2ab5c6e089e28;p=oweals%2Fminetest.git diff --git a/src/nodedef.cpp b/src/nodedef.cpp index b7d023897..2745a45e8 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -61,11 +61,10 @@ void NodeBox::reset() void NodeBox::serialize(std::ostream &os, u16 protocol_version) const { - int version = 1; + // Protocol >= 21 + int version = 2; if (protocol_version >= 27) version = 3; - else if (protocol_version >= 21) - version = 2; writeU8(os, version); switch (type) { @@ -189,22 +188,30 @@ 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); - else if (protocol_version >= 17) - writeU8(os, 1); else - writeU8(os, 0); - os<= 17) - writeU8(os, backface_culling); + writeU8(os, backface_culling); if (protocol_version >= 26) { 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 +225,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) || @@ -251,10 +266,15 @@ void TextureSettings::readSettings() bool enable_shaders = g_settings->getBool("enable_shaders"); bool enable_bumpmapping = g_settings->getBool("enable_bumpmapping"); bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion"); + bool smooth_lighting = g_settings->getBool("smooth_lighting"); enable_mesh_cache = g_settings->getBool("enable_mesh_cache"); enable_minimap = g_settings->getBool("enable_minimap"); std::string leaves_style_str = g_settings->get("leaves_style"); + // Mesh cache is not supported in combination with smooth lighting + if (smooth_lighting) + enable_mesh_cache = false; + use_normal_texture = enable_shaders && (enable_bumpmapping || enable_parallax_occlusion); if (leaves_style_str == "fancy") { @@ -351,172 +371,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<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::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<::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,12 +606,19 @@ 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) { int frame_length_ms; tiledef->animation.determineParams(tile->texture->getOriginalSize(), - &frame_count, &frame_length_ms); + &frame_count, &frame_length_ms, NULL); tile->animation_frame_count = frame_count; tile->animation_frame_length_ms = frame_length_ms; } @@ -681,6 +758,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 +776,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 +811,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 +859,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 *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 +910,9 @@ private: // Next possibly free id content_t m_next_id; + // Maps image file names to loaded palettes. + UNORDERED_MAP > m_palettes; + // NodeResolvers to callback once node registration has ended std::vector m_pending_resolve_callbacks; @@ -1062,7 +1152,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), @@ -1241,12 +1332,13 @@ void CNodeDefManager::removeNode(const std::string &name) void CNodeDefManager::updateAliases(IItemDefManager *idef) { - std::set all = idef->getAll(); + std::set all; + idef->getAll(all); m_name_id_mapping_with_aliases.clear(); - for (std::set::iterator + for (std::set::const_iterator i = all.begin(); i != all.end(); ++i) { - std::string name = *i; - std::string convert_to = idef->getAlias(name); + const std::string &name = *i; + const std::string &convert_to = idef->getAlias(name); content_t id; if (m_name_id_mapping.getId(convert_to, id)) { m_name_id_mapping_with_aliases.insert( @@ -1309,6 +1401,78 @@ void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath } } +std::vector *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 >::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 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 +1489,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,72 +1596,41 @@ IWritableNodeDefManager *createNodeDefManager() //// Serialization of old ContentFeatures formats void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const { - if (protocol_version == 13) - { - writeU8(os, 5); // version - os<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); - //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24 - writeU8(os, 2); - for (u32 i = 0; i < 2; 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, 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< 13 && protocol_version < 24) { - writeU8(os, 6); // version - os<= 24 + if (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<first); - writeS16(os, i->second); + 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); + writeF1000(os, compatible_visual_scale); writeU8(os, 6); for (u32 i = 0; i < 6; i++) tiledef[i].serialize(os, protocol_version); - //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24 - writeU8(os, 2); - for (u32 i = 0; i < 2; i++) + 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()); @@ -1502,7 +1638,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); @@ -1511,10 +1647,10 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const writeU8(os, diggable); writeU8(os, climbable); writeU8(os, buildable_to); - os<::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"); + } } void ContentFeatures::deSerializeOld(std::istream &is, int version) @@ -1642,7 +1788,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 +1948,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); }