X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;ds=sidebyside;f=src%2Fnodedef.cpp;h=57d4c008f4243eef34bf6cfffba7004fc1020b50;hb=0f74c7a977c412a81890926548e2a5c8dae5f6eb;hp=37332c3c60928488052817ad5464440484db3781;hpb=5cf6318117edcae6bf30d829d9e9dd9dbf1d4bf7;p=dragonfireclient.git diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 37332c3c6..57d4c008f 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -207,7 +207,7 @@ void TileDef::serialize(std::ostream &os, u16 protocol_version) const u8 version = 6; writeU8(os, version); - os << serializeString(name); + os << serializeString16(name); animation.serialize(os, version); bool has_scale = scale > 0; u16 flags = 0; @@ -241,7 +241,7 @@ void TileDef::deSerialize(std::istream &is, u8 contentfeatures_version, int version = readU8(is); if (version < 6) throw SerializationError("unsupported TileDef version"); - name = deSerializeString(is); + name = deSerializeString16(is); animation.deSerialize(is, version); u16 flags = readU16(is); backface_culling = flags & TILE_FLAG_BACKFACE_CULLING; @@ -266,9 +266,6 @@ void TextureSettings::readSettings() { connected_glass = g_settings->getBool("connected_glass"); opaque_water = g_settings->getBool("opaque_water"); - 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"); @@ -281,8 +278,6 @@ void TextureSettings::readSettings() if (smooth_lighting) enable_mesh_cache = false; - use_normal_texture = enable_shaders && - (enable_bumpmapping || enable_parallax_occlusion); if (leaves_style_str == "fancy") { leaves_style = LEAVES_FANCY; } else if (leaves_style_str == "simple") { @@ -317,6 +312,18 @@ ContentFeatures::ContentFeatures() reset(); } +ContentFeatures::~ContentFeatures() +{ +#ifndef SERVER + for (u16 j = 0; j < 6; j++) { + delete tiles[j].layers[0].frames; + delete tiles[j].layers[1].frames; + } + for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) + delete special_tiles[j].layers[0].frames; +#endif +} + void ContentFeatures::reset() { /* @@ -353,7 +360,7 @@ void ContentFeatures::reset() i = TileDef(); for (auto &j : tiledef_special) j = TileDef(); - alpha = 255; + alpha = ALPHAMODE_OPAQUE; post_effect_color = video::SColor(0, 0, 0, 0); param_type = CPT_NONE; param_type_2 = CPT2_NONE; @@ -368,9 +375,12 @@ void ContentFeatures::reset() floodable = false; rightclickable = true; leveled = 0; + leveled_max = LEVELED_MAX; liquid_type = LIQUID_NONE; liquid_alternative_flowing = ""; + liquid_alternative_flowing_id = CONTENT_IGNORE; liquid_alternative_source = ""; + liquid_alternative_source_id = CONTENT_IGNORE; liquid_viscosity = 0; liquid_renewable = true; liquid_range = LIQUID_LEVEL_MAX+1; @@ -395,16 +405,41 @@ void ContentFeatures::reset() node_dig_prediction = "air"; } +void ContentFeatures::setAlphaFromLegacy(u8 legacy_alpha) +{ + // No special handling for nodebox/mesh here as it doesn't make sense to + // throw warnings when the server is too old to support the "correct" way + switch (drawtype) { + case NDT_NORMAL: + alpha = legacy_alpha == 255 ? ALPHAMODE_OPAQUE : ALPHAMODE_CLIP; + break; + case NDT_LIQUID: + case NDT_FLOWINGLIQUID: + alpha = legacy_alpha == 255 ? ALPHAMODE_OPAQUE : ALPHAMODE_BLEND; + break; + default: + alpha = legacy_alpha == 255 ? ALPHAMODE_CLIP : ALPHAMODE_BLEND; + break; + } +} + +u8 ContentFeatures::getAlphaForLegacy() const +{ + // This is so simple only because 255 and 0 mean wildly different things + // depending on drawtype... + return alpha == ALPHAMODE_OPAQUE ? 255 : 0; +} + void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const { const u8 version = CONTENTFEATURES_VERSION; writeU8(os, version); // general - os << serializeString(name); + os << serializeString16(name); writeU16(os, groups.size()); for (const auto &group : groups) { - os << serializeString(group.first); + os << serializeString16(group.first); writeS16(os, group.second); } writeU8(os, param_type); @@ -412,7 +447,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const // visual writeU8(os, drawtype); - os << serializeString(mesh); + os << serializeString16(mesh); writeF32(os, visual_scale); writeU8(os, 6); for (const TileDef &td : tiledef) @@ -423,11 +458,11 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const for (const TileDef &td : tiledef_special) { td.serialize(os, protocol_version); } - writeU8(os, alpha); + writeU8(os, getAlphaForLegacy()); writeU8(os, color.getRed()); writeU8(os, color.getGreen()); writeU8(os, color.getBlue()); - os << serializeString(palette_name); + os << serializeString16(palette_name); writeU8(os, waving); writeU8(os, connect_sides); writeU16(os, connects_to_ids.size()); @@ -455,8 +490,8 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const // liquid writeU8(os, liquid_type); - os << serializeString(liquid_alternative_flowing); - os << serializeString(liquid_alternative_source); + os << serializeString16(liquid_alternative_flowing); + os << serializeString16(liquid_alternative_source); writeU8(os, liquid_viscosity); writeU8(os, liquid_renewable); writeU8(os, liquid_range); @@ -477,22 +512,9 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const writeU8(os, legacy_facedir_simple); writeU8(os, legacy_wallmounted); - os << serializeString(node_dig_prediction); -} - -void ContentFeatures::correctAlpha(TileDef *tiles, int length) -{ - // alpha == 0 means that the node is using texture alpha - if (alpha == 0 || alpha == 255) - return; - - for (int i = 0; i < length; i++) { - if (tiles[i].name.empty()) - continue; - std::stringstream s; - s << tiles[i].name << "^[noalpha^[opacity:" << ((int)alpha); - tiles[i].name = s.str(); - } + os << serializeString16(node_dig_prediction); + writeU8(os, leveled_max); + writeU8(os, alpha); } void ContentFeatures::deSerialize(std::istream &is) @@ -503,11 +525,11 @@ void ContentFeatures::deSerialize(std::istream &is) throw SerializationError("unsupported ContentFeatures version"); // general - name = deSerializeString(is); + name = deSerializeString16(is); groups.clear(); u32 groups_size = readU16(is); for (u32 i = 0; i < groups_size; i++) { - std::string name = deSerializeString(is); + std::string name = deSerializeString16(is); int value = readS16(is); groups[name] = value; } @@ -516,7 +538,7 @@ void ContentFeatures::deSerialize(std::istream &is) // visual drawtype = (enum NodeDrawType) readU8(is); - mesh = deSerializeString(is); + mesh = deSerializeString16(is); visual_scale = readF32(is); if (readU8(is) != 6) throw SerializationError("unsupported tile count"); @@ -528,11 +550,11 @@ void ContentFeatures::deSerialize(std::istream &is) throw SerializationError("unsupported CF_SPECIAL_COUNT"); for (TileDef &td : tiledef_special) td.deSerialize(is, version, drawtype); - alpha = readU8(is); + setAlphaFromLegacy(readU8(is)); color.setRed(readU8(is)); color.setGreen(readU8(is)); color.setBlue(readU8(is)); - palette_name = deSerializeString(is); + palette_name = deSerializeString16(is); waving = readU8(is); connect_sides = readU8(is); u16 connects_to_size = readU16(is); @@ -562,8 +584,8 @@ void ContentFeatures::deSerialize(std::istream &is) // liquid liquid_type = (enum LiquidType) readU8(is); - liquid_alternative_flowing = deSerializeString(is); - liquid_alternative_source = deSerializeString(is); + liquid_alternative_flowing = deSerializeString16(is); + liquid_alternative_source = deSerializeString16(is); liquid_viscosity = readU8(is); liquid_renewable = readU8(is); liquid_range = readU8(is); @@ -585,7 +607,17 @@ void ContentFeatures::deSerialize(std::istream &is) legacy_wallmounted = readU8(is); try { - node_dig_prediction = deSerializeString(is); + node_dig_prediction = deSerializeString16(is); + + u8 tmp = readU8(is); + if (is.eof()) /* readU8 doesn't throw exceptions so we have to do this */ + throw SerializationError(""); + leveled_max = tmp; + + tmp = readU8(is); + if (is.eof()) + throw SerializationError(""); + alpha = static_cast(tmp); } catch(SerializationError &e) {}; } @@ -600,8 +632,9 @@ static void fillTileAttribs(ITextureSource *tsrc, TileLayer *layer, layer->material_type = material_type; bool has_scale = tiledef.scale > 0; - if (((tsettings.autoscale_mode == AUTOSCALE_ENABLE) && !has_scale) || - (tsettings.autoscale_mode == AUTOSCALE_FORCE)) { + bool use_autoscale = tsettings.autoscale_mode == AUTOSCALE_FORCE || + (tsettings.autoscale_mode == AUTOSCALE_ENABLE && !has_scale); + if (use_autoscale) { auto texture_size = layer->texture->getOriginalSize(); float base_size = tsettings.node_texture_size; float size = std::fmin(texture_size.Width, texture_size.Height); @@ -614,10 +647,6 @@ static void fillTileAttribs(ITextureSource *tsrc, TileLayer *layer, if (!tile.world_aligned) layer->scale = 1; - // Normal texture and shader flags texture - if (tsettings.use_normal_texture) { - layer->normal_texture = tsrc->getNormalTexture(tiledef.name); - } layer->flags_texture = tsrc->getShaderFlagsTexture(layer->normal_texture ? true : false); // Material flags @@ -653,7 +682,7 @@ static void fillTileAttribs(ITextureSource *tsrc, TileLayer *layer, } else { std::ostringstream os(std::ios::binary); if (!layer->frames) { - layer->frames = std::make_shared>(); + layer->frames = new std::vector(); } layer->frames->resize(frame_count); @@ -674,9 +703,56 @@ static void fillTileAttribs(ITextureSource *tsrc, TileLayer *layer, } } } -#endif -#ifndef SERVER +bool ContentFeatures::textureAlphaCheck(ITextureSource *tsrc, const TileDef *tiles, int length) +{ + video::IVideoDriver *driver = RenderingEngine::get_video_driver(); + static thread_local bool long_warning_printed = false; + std::set seen; + + for (int i = 0; i < length; i++) { + if (seen.find(tiles[i].name) != seen.end()) + continue; + seen.insert(tiles[i].name); + + // Load the texture and see if there's any transparent pixels + video::ITexture *texture = tsrc->getTexture(tiles[i].name); + video::IImage *image = driver->createImage(texture, + core::position2d(0, 0), texture->getOriginalSize()); + if (!image) + continue; + core::dimension2d dim = image->getDimension(); + bool ok = true; + for (u16 x = 0; x < dim.Width; x++) { + for (u16 y = 0; y < dim.Height; y++) { + if (image->getPixel(x, y).getAlpha() < 255) { + ok = false; + goto break_loop; + } + } + } + +break_loop: + image->drop(); + if (ok) + continue; + warningstream << "Texture \"" << tiles[i].name << "\" of " + << name << " has transparency, assuming " + "use_texture_alpha = \"clip\"." << std::endl; + if (!long_warning_printed) { + warningstream << " This warning can be a false-positive if " + "unused pixels in the texture are transparent. However if " + "it is meant to be transparent, you *MUST* update the " + "nodedef and set use_texture_alpha = \"clip\"! This " + "compatibility code will be removed in a few releases." + << std::endl; + long_warning_printed = true; + } + return true; + } + return false; +} + bool isWorldAligned(AlignStyle style, WorldAlignMode mode, NodeDrawType drawtype) { if (style == ALIGN_STYLE_WORLD) @@ -717,31 +793,33 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc bool is_liquid = false; - u8 material_type = (alpha == 255) ? - TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA; + if (alpha == ALPHAMODE_LEGACY_COMPAT) { + // Before working with the alpha mode, resolve any legacy kludges + alpha = textureAlphaCheck(tsrc, tdef, 6) ? ALPHAMODE_CLIP : ALPHAMODE_OPAQUE; + } + + MaterialType material_type = alpha == ALPHAMODE_OPAQUE ? + TILE_MATERIAL_OPAQUE : (alpha == ALPHAMODE_CLIP ? TILE_MATERIAL_BASIC : + TILE_MATERIAL_ALPHA); switch (drawtype) { default: case NDT_NORMAL: - material_type = (alpha == 255) ? - TILE_MATERIAL_OPAQUE : TILE_MATERIAL_ALPHA; solidness = 2; break; case NDT_AIRLIKE: solidness = 0; break; case NDT_LIQUID: - assert(liquid_type == LIQUID_SOURCE); if (tsettings.opaque_water) - alpha = 255; + alpha = ALPHAMODE_OPAQUE; solidness = 1; is_liquid = true; break; case NDT_FLOWINGLIQUID: - assert(liquid_type == LIQUID_FLOWING); solidness = 0; if (tsettings.opaque_water) - alpha = 255; + alpha = ALPHAMODE_OPAQUE; is_liquid = true; break; case NDT_GLASSLIKE: @@ -794,12 +872,15 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc case NDT_MESH: case NDT_NODEBOX: solidness = 0; - if (waving == 1) + if (waving == 1) { material_type = TILE_MATERIAL_WAVING_PLANTS; - else if (waving == 2) + } else if (waving == 2) { material_type = TILE_MATERIAL_WAVING_LEAVES; - else if (waving == 3) - material_type = TILE_MATERIAL_WAVING_LIQUID_BASIC; + } else if (waving == 3) { + material_type = alpha == ALPHAMODE_OPAQUE ? + TILE_MATERIAL_WAVING_LIQUID_OPAQUE : (alpha == ALPHAMODE_CLIP ? + TILE_MATERIAL_WAVING_LIQUID_BASIC : TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT); + } break; case NDT_TORCHLIKE: case NDT_SIGNLIKE: @@ -813,23 +894,19 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc } if (is_liquid) { - // Vertex alpha is no longer supported, correct if necessary. - correctAlpha(tdef, 6); - correctAlpha(tdef_overlay, 6); - correctAlpha(tdef_spec, CF_SPECIAL_COUNT); - if (waving == 3) { - material_type = (alpha == 255) ? TILE_MATERIAL_WAVING_LIQUID_OPAQUE : - TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT; + material_type = alpha == ALPHAMODE_OPAQUE ? + TILE_MATERIAL_WAVING_LIQUID_OPAQUE : (alpha == ALPHAMODE_CLIP ? + TILE_MATERIAL_WAVING_LIQUID_BASIC : TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT); } else { - material_type = (alpha == 255) ? TILE_MATERIAL_LIQUID_OPAQUE : + material_type = alpha == ALPHAMODE_OPAQUE ? TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT; } } u32 tile_shader = shdsrc->getShader("nodes_shader", material_type, drawtype); - u8 overlay_material = material_type; + MaterialType overlay_material = material_type; if (overlay_material == TILE_MATERIAL_OPAQUE) overlay_material = TILE_MATERIAL_BASIC; else if (overlay_material == TILE_MATERIAL_LIQUID_OPAQUE) @@ -850,7 +927,7 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc tdef[j].backface_culling, tsettings); } - u8 special_material = material_type; + MaterialType special_material = material_type; if (drawtype == NDT_PLANTLIKE_ROOTED) { if (waving == 1) special_material = TILE_MATERIAL_WAVING_PLANTS; @@ -1316,6 +1393,7 @@ void NodeDefManager::applyTextureOverrides(const std::vector &o ContentFeatures &nodedef = m_content_features[id]; + // Override tiles if (texture_override.hasTarget(OverrideTarget::TOP)) nodedef.tiledef[0].name = texture_override.texture; @@ -1333,6 +1411,26 @@ void NodeDefManager::applyTextureOverrides(const std::vector &o if (texture_override.hasTarget(OverrideTarget::FRONT)) nodedef.tiledef[5].name = texture_override.texture; + + + // Override special tiles, if applicable + if (texture_override.hasTarget(OverrideTarget::SPECIAL_1)) + nodedef.tiledef_special[0].name = texture_override.texture; + + if (texture_override.hasTarget(OverrideTarget::SPECIAL_2)) + nodedef.tiledef_special[1].name = texture_override.texture; + + if (texture_override.hasTarget(OverrideTarget::SPECIAL_3)) + nodedef.tiledef_special[2].name = texture_override.texture; + + if (texture_override.hasTarget(OverrideTarget::SPECIAL_4)) + nodedef.tiledef_special[3].name = texture_override.texture; + + if (texture_override.hasTarget(OverrideTarget::SPECIAL_5)) + nodedef.tiledef_special[4].name = texture_override.texture; + + if (texture_override.hasTarget(OverrideTarget::SPECIAL_6)) + nodedef.tiledef_special[5].name = texture_override.texture; } } @@ -1379,7 +1477,7 @@ void NodeDefManager::serialize(std::ostream &os, u16 protocol_version) const // strict version incompatibilities std::ostringstream wrapper_os(std::ios::binary); f->serialize(wrapper_os, protocol_version); - os2< &list) +{ + std::sort(list.begin(), list.end()); + auto new_end = std::unique(list.begin(), list.end()); + list.erase(new_end, list.end()); +} + +void NodeDefManager::resolveCrossrefs() { for (ContentFeatures &f : m_content_features) { + if (f.liquid_type != LIQUID_NONE || f.drawtype == NDT_LIQUID || f.drawtype == NDT_FLOWINGLIQUID) { + f.liquid_alternative_flowing_id = getId(f.liquid_alternative_flowing); + f.liquid_alternative_source_id = getId(f.liquid_alternative_source); + continue; + } if (f.drawtype != NDT_NODEBOX || f.node_box.type != NODEBOX_CONNECTED) continue; for (const std::string &name : f.connects_to) { getIds(name, f.connects_to_ids); } + removeDupes(f.connects_to_ids); } } @@ -1572,6 +1687,18 @@ NodeResolver::~NodeResolver() } +void NodeResolver::cloneTo(NodeResolver *res) const +{ + FATAL_ERROR_IF(!m_resolve_done, "NodeResolver can only be cloned" + " after resolving has completed"); + /* We don't actually do anything significant. Since the node resolving has + * already completed, the class that called us will already have the + * resolved IDs in its data structures (which it copies on its own) */ + res->m_ndef = m_ndef; + res->m_resolve_done = true; +} + + void NodeResolver::nodeResolveInternal() { m_nodenames_idx = 0;