summaryrefslogtreecommitdiff
path: root/src/nodedef.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/nodedef.cpp')
-rw-r--r--src/nodedef.cpp746
1 files changed, 518 insertions, 228 deletions
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index ccbb42c66..98b34ea9e 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef SERVER
#include "client/tile.h"
#include "mesh.h"
+#include "client.h"
#include <IMeshManipulator.h>
#endif
#include "log.h"
@@ -60,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) {
@@ -188,39 +188,51 @@ void NodeBox::deSerialize(std::istream &is)
void TileDef::serialize(std::ostream &os, u16 protocol_version) const
{
- if (protocol_version >= 26)
+ 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<<serializeString(name);
- writeU8(os, animation.type);
- writeU16(os, animation.aspect_w);
- writeU16(os, animation.aspect_h);
- writeF1000(os, animation.length);
- if (protocol_version >= 17)
- writeU8(os, backface_culling);
+ writeU8(os, 1);
+
+ os << serializeString(name);
+ animation.serialize(os, protocol_version);
+ 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)
{
int version = readU8(is);
name = deSerializeString(is);
- animation.type = (TileAnimationType)readU8(is);
- animation.aspect_w = readU16(is);
- animation.aspect_h = readU16(is);
- animation.length = readF1000(is);
+ animation.deSerialize(is, version >= 3 ? 29 : 26);
if (version >= 1)
backface_culling = readU8(is);
if (version >= 2) {
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) ||
@@ -254,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") {
@@ -354,172 +371,224 @@ 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 < 31) {
serializeOld(os, protocol_version);
return;
}
- writeU8(os, protocol_version < 27 ? 7 : 8);
+ // version
+ writeU8(os, 10);
- 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);
+ for (u32 i = 0; i < 6; i++)
+ tiledef_overlay[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(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 == "")
+ continue;
+ std::stringstream s;
+ s << tiles[i].name << "^[noalpha^[opacity:" << ((int)alpha);
+ tiles[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 > 10) {
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 (version >= 10)
+ for (u32 i = 0; i < 6; i++)
+ tiledef_overlay[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++)
+ 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,
+void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileLayer *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
@@ -532,29 +601,32 @@ void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
tile->material_flags = 0;
if (backface_culling)
tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
- if (tiledef->animation.type == TAT_VERTICAL_FRAMES)
- tile->material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
+ if (tiledef->animation.type != TAT_NONE)
+ tile->material_flags |= MATERIAL_FLAG_ANIMATION;
if (tiledef->tileable_horizontal)
tile->material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL;
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_VERTICAL_FRAMES) {
- // Get texture size to determine frame count by aspect ratio
- v2u32 size = tile->texture->getOriginalSize();
- int frame_height = (float)size.X /
- (float)tiledef->animation.aspect_w *
- (float)tiledef->animation.aspect_h;
- frame_count = size.Y / frame_height;
- int frame_length_ms = 1000.0 * tiledef->animation.length / frame_count;
+ if (tile->material_flags & MATERIAL_FLAG_ANIMATION) {
+ int frame_length_ms;
+ tiledef->animation.determineParams(tile->texture->getOriginalSize(),
+ &frame_count, &frame_length_ms, NULL);
tile->animation_frame_count = frame_count;
tile->animation_frame_length_ms = frame_length_ms;
}
if (frame_count == 1) {
- tile->material_flags &= ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
+ tile->material_flags &= ~MATERIAL_FLAG_ANIMATION;
} else {
std::ostringstream os(std::ios::binary);
tile->frames.resize(frame_count);
@@ -564,8 +636,9 @@ void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
FrameSpec frame;
os.str("");
- os << tiledef->name << "^[verticalframe:"
- << frame_count << ":" << i;
+ os << tiledef->name;
+ tiledef->animation.getTextureModifer(os,
+ tile->texture->getOriginalSize(), i);
frame.texture = tsrc->getTextureForMesh(os.str(), &frame.texture_id);
if (tile->normal_texture)
@@ -579,8 +652,7 @@ void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
#ifndef SERVER
void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc,
- scene::ISceneManager *smgr, scene::IMeshManipulator *meshmanip,
- IGameDef *gamedef, const TextureSettings &tsettings)
+ scene::IMeshManipulator *meshmanip, Client *client, const TextureSettings &tsettings)
{
// minimap pixel color - the average color of a texture
if (tsettings.enable_minimap && tiledef[0].name != "")
@@ -593,9 +665,16 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
if (tdef[j].name == "")
tdef[j].name = "unknown_node.png";
}
+ // also the overlay tiles
+ TileDef tdef_overlay[6];
+ for (u32 j = 0; j < 6; j++)
+ tdef_overlay[j] = tiledef_overlay[j];
+ // also the special tiles
+ TileDef tdef_spec[6];
+ for (u32 j = 0; j < CF_SPECIAL_COUNT; j++)
+ tdef_spec[j] = tiledef_special[j];
bool is_liquid = false;
- bool is_water_surface = false;
u8 material_type = (alpha == 255) ?
TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
@@ -646,8 +725,8 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
visual_solidness = 1;
} else if (tsettings.leaves_style == LEAVES_SIMPLE) {
for (u32 j = 0; j < 6; j++) {
- if (tiledef_special[j].name != "")
- tdef[j].name = tiledef_special[j].name;
+ if (tdef_spec[j].name != "")
+ tdef[j].name = tdef_spec[j].name;
}
drawtype = NDT_GLASSLIKE;
solidness = 0;
@@ -658,34 +737,40 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
for (u32 i = 0; i < 6; i++)
tdef[i].name += std::string("^[noalpha");
}
- if (waving == 1)
+ if (waving >= 1)
material_type = TILE_MATERIAL_WAVING_LEAVES;
break;
case NDT_PLANTLIKE:
solidness = 0;
- if (waving == 1)
+ if (waving >= 1)
material_type = TILE_MATERIAL_WAVING_PLANTS;
break;
case NDT_FIRELIKE:
solidness = 0;
break;
case NDT_MESH:
+ case NDT_NODEBOX:
solidness = 0;
+ if (waving == 1)
+ material_type = TILE_MATERIAL_WAVING_PLANTS;
+ else if (waving == 2)
+ material_type = TILE_MATERIAL_WAVING_LEAVES;
break;
case NDT_TORCHLIKE:
case NDT_SIGNLIKE:
case NDT_FENCELIKE:
case NDT_RAILLIKE:
- case NDT_NODEBOX:
solidness = 0;
break;
}
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);
material_type = (alpha == 255) ?
TILE_MATERIAL_LIQUID_OPAQUE : TILE_MATERIAL_LIQUID_TRANSPARENT;
- if (name == "default:water_source")
- is_water_surface = true;
}
u32 tile_shader[6];
@@ -694,29 +779,33 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
material_type, drawtype);
}
- if (is_water_surface) {
- tile_shader[0] = shdsrc->getShader("water_surface_shader",
- material_type, drawtype);
- }
-
// Tiles (fill in f->tiles[])
for (u16 j = 0; j < 6; j++) {
- fillTileAttribs(tsrc, &tiles[j], &tdef[j], tile_shader[j],
+ fillTileAttribs(tsrc, &tiles[j].layers[0], &tdef[j], tile_shader[j],
tsettings.use_normal_texture,
- tiledef[j].backface_culling, alpha, material_type);
+ tdef[j].backface_culling, material_type);
+ if (tdef_overlay[j].name != "")
+ fillTileAttribs(tsrc, &tiles[j].layers[1], &tdef_overlay[j],
+ tile_shader[j], tsettings.use_normal_texture,
+ tdef[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],
+ fillTileAttribs(tsrc, &special_tiles[j].layers[0], &tdef_spec[j],
tile_shader[j], tsettings.use_normal_texture,
- tiledef_special[j].backface_culling, alpha, material_type);
+ tdef_spec[j].backface_culling, material_type);
}
+ if (param_type_2 == CPT2_COLOR ||
+ param_type_2 == CPT2_COLORED_FACEDIR ||
+ param_type_2 == CPT2_COLORED_WALLMOUNTED)
+ palette = tsrc->getPalette(palette_name);
+
if ((drawtype == NDT_MESH) && (mesh != "")) {
// Meshnode drawtype
// Read the mesh and apply scale
- mesh_ptr[0] = gamedef->getMesh(mesh);
+ mesh_ptr[0] = client->getMesh(mesh);
if (mesh_ptr[0]){
v3f scale = v3f(1.0, 1.0, 1.0) * BS * visual_scale;
scaleMesh(mesh_ptr[0], scale);
@@ -738,15 +827,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]);
@@ -788,7 +881,6 @@ public:
void serialize(std::ostream &os, u16 protocol_version) const;
void deSerialize(std::istream &is);
- inline virtual bool getNodeRegistrationStatus() const;
inline virtual void setNodeRegistrationStatus(bool completed);
virtual void pendNodeResolve(NodeResolver *nr);
@@ -797,9 +889,18 @@ public:
virtual void resetNodeResolveState();
virtual void mapNodeboxConnections();
virtual bool nodeboxConnects(MapNode from, MapNode to, u8 connect_face);
+ virtual core::aabbox3d<s16> getSelectionBoxIntUnion() const
+ {
+ return m_selection_box_int_union;
+ }
private:
void addNameIdMapping(content_t i, std::string name);
+ /*!
+ * Recalculates m_selection_box_int_union based on
+ * m_selection_box_union.
+ */
+ void fixSelectionBoxIntUnion();
// Features indexed by id
std::vector<ContentFeatures> m_content_features;
@@ -826,6 +927,14 @@ private:
// True when all nodes have been registered
bool m_node_registration_complete;
+
+ //! The union of all nodes' selection boxes.
+ aabb3f m_selection_box_union;
+ /*!
+ * The smallest box in node coordinates that
+ * contains all nodes' selection boxes.
+ */
+ core::aabbox3d<s16> m_selection_box_int_union;
};
@@ -856,6 +965,8 @@ void CNodeDefManager::clear()
m_name_id_mapping_with_aliases.clear();
m_group_to_items.clear();
m_next_id = 0;
+ m_selection_box_union.reset(0,0,0);
+ m_selection_box_int_union.reset(0,0,0);
resetNodeResolveState();
@@ -1014,6 +1125,124 @@ content_t CNodeDefManager::allocateId()
}
+/*!
+ * Returns the smallest box that contains all boxes
+ * in the vector. Box_union is expanded.
+ * @param[in] boxes the vector containing the boxes
+ * @param[in, out] box_union the union of the arguments
+ */
+void boxVectorUnion(const std::vector<aabb3f> &boxes, aabb3f *box_union)
+{
+ for (std::vector<aabb3f>::const_iterator it = boxes.begin();
+ it != boxes.end(); ++it) {
+ box_union->addInternalBox(*it);
+ }
+}
+
+
+/*!
+ * Returns a box that contains the nodebox in every case.
+ * The argument node_union is expanded.
+ * @param[in] nodebox the nodebox to be measured
+ * @param[in] features used to decide whether the nodebox
+ * can be rotated
+ * @param[in, out] box_union the union of the arguments
+ */
+void getNodeBoxUnion(const NodeBox &nodebox, const ContentFeatures &features,
+ aabb3f *box_union)
+{
+ switch(nodebox.type) {
+ case NODEBOX_FIXED:
+ case NODEBOX_LEVELED: {
+ // Raw union
+ aabb3f half_processed(0, 0, 0, 0, 0, 0);
+ boxVectorUnion(nodebox.fixed, &half_processed);
+ // Set leveled boxes to maximal
+ if (nodebox.type == NODEBOX_LEVELED) {
+ half_processed.MaxEdge.Y = +BS / 2;
+ }
+ if (features.param_type_2 == CPT2_FACEDIR ||
+ features.param_type_2 == CPT2_COLORED_FACEDIR) {
+ // Get maximal coordinate
+ f32 coords[] = {
+ fabsf(half_processed.MinEdge.X),
+ fabsf(half_processed.MinEdge.Y),
+ fabsf(half_processed.MinEdge.Z),
+ fabsf(half_processed.MaxEdge.X),
+ fabsf(half_processed.MaxEdge.Y),
+ fabsf(half_processed.MaxEdge.Z) };
+ f32 max = 0;
+ for (int i = 0; i < 6; i++) {
+ if (max < coords[i]) {
+ max = coords[i];
+ }
+ }
+ // Add the union of all possible rotated boxes
+ box_union->addInternalPoint(-max, -max, -max);
+ box_union->addInternalPoint(+max, +max, +max);
+ } else {
+ box_union->addInternalBox(half_processed);
+ }
+ break;
+ }
+ case NODEBOX_WALLMOUNTED: {
+ // Add fix boxes
+ box_union->addInternalBox(nodebox.wall_top);
+ box_union->addInternalBox(nodebox.wall_bottom);
+ // Find maximal coordinate in the X-Z plane
+ f32 coords[] = {
+ fabsf(nodebox.wall_side.MinEdge.X),
+ fabsf(nodebox.wall_side.MinEdge.Z),
+ fabsf(nodebox.wall_side.MaxEdge.X),
+ fabsf(nodebox.wall_side.MaxEdge.Z) };
+ f32 max = 0;
+ for (int i = 0; i < 4; i++) {
+ if (max < coords[i]) {
+ max = coords[i];
+ }
+ }
+ // Add the union of all possible rotated boxes
+ box_union->addInternalPoint(-max, nodebox.wall_side.MinEdge.Y, -max);
+ box_union->addInternalPoint(max, nodebox.wall_side.MaxEdge.Y, max);
+ break;
+ }
+ case NODEBOX_CONNECTED: {
+ // Add all possible connected boxes
+ boxVectorUnion(nodebox.fixed, box_union);
+ boxVectorUnion(nodebox.connect_top, box_union);
+ boxVectorUnion(nodebox.connect_bottom, box_union);
+ boxVectorUnion(nodebox.connect_front, box_union);
+ boxVectorUnion(nodebox.connect_left, box_union);
+ boxVectorUnion(nodebox.connect_back, box_union);
+ boxVectorUnion(nodebox.connect_right, box_union);
+ break;
+ }
+ default: {
+ // NODEBOX_REGULAR
+ box_union->addInternalPoint(-BS / 2, -BS / 2, -BS / 2);
+ box_union->addInternalPoint(+BS / 2, +BS / 2, +BS / 2);
+ }
+ }
+}
+
+
+inline void CNodeDefManager::fixSelectionBoxIntUnion()
+{
+ m_selection_box_int_union.MinEdge.X = floorf(
+ m_selection_box_union.MinEdge.X / BS + 0.5f);
+ m_selection_box_int_union.MinEdge.Y = floorf(
+ m_selection_box_union.MinEdge.Y / BS + 0.5f);
+ m_selection_box_int_union.MinEdge.Z = floorf(
+ m_selection_box_union.MinEdge.Z / BS + 0.5f);
+ m_selection_box_int_union.MaxEdge.X = ceilf(
+ m_selection_box_union.MaxEdge.X / BS - 0.5f);
+ m_selection_box_int_union.MaxEdge.Y = ceilf(
+ m_selection_box_union.MaxEdge.Y / BS - 0.5f);
+ m_selection_box_int_union.MaxEdge.Z = ceilf(
+ m_selection_box_union.MaxEdge.Z / BS - 0.5f);
+}
+
+
// IWritableNodeDefManager
content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def)
{
@@ -1044,6 +1273,8 @@ content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &d
verbosestream << "NodeDefManager: registering content id \"" << id
<< "\": name=\"" << def.name << "\""<<std::endl;
+ getNodeBoxUnion(def.selection_box, def, &m_selection_box_union);
+ fixSelectionBoxIntUnion();
// Add this content to the list of all groups it belongs to
// FIXME: This should remove a node from groups it no longer
// belongs to when a node is re-registered
@@ -1088,34 +1319,34 @@ void CNodeDefManager::removeNode(const std::string &name)
// Erase node content from all groups it belongs to
for (UNORDERED_MAP<std::string, GroupItems>::iterator iter_groups =
- m_group_to_items.begin();
- iter_groups != m_group_to_items.end();) {
+ m_group_to_items.begin(); iter_groups != m_group_to_items.end();) {
GroupItems &items = iter_groups->second;
for (GroupItems::iterator iter_groupitems = items.begin();
iter_groupitems != items.end();) {
if (iter_groupitems->first == id)
items.erase(iter_groupitems++);
else
- iter_groupitems++;
+ ++iter_groupitems;
}
// Check if group is empty
if (items.size() == 0)
m_group_to_items.erase(iter_groups++);
else
- iter_groups++;
+ ++iter_groups;
}
}
void CNodeDefManager::updateAliases(IItemDefManager *idef)
{
- std::set<std::string> all = idef->getAll();
+ std::set<std::string> all;
+ idef->getAll(all);
m_name_id_mapping_with_aliases.clear();
- for (std::set<std::string>::iterator
+ for (std::set<std::string>::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(
@@ -1185,9 +1416,11 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef,
#ifndef SERVER
infostream << "CNodeDefManager::updateTextures(): Updating "
"textures in node definitions" << std::endl;
- ITextureSource *tsrc = gamedef->tsrc();
- IShaderSource *shdsrc = gamedef->getShaderSource();
- scene::ISceneManager* smgr = gamedef->getSceneManager();
+
+ Client *client = (Client *)gamedef;
+ ITextureSource *tsrc = client->tsrc();
+ IShaderSource *shdsrc = client->getShaderSource();
+ scene::ISceneManager* smgr = client->getSceneManager();
scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
TextureSettings tsettings;
tsettings.readSettings();
@@ -1195,7 +1428,8 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef,
u32 size = m_content_features.size();
for (u32 i = 0; i < size; i++) {
- m_content_features[i].updateTextures(tsrc, shdsrc, smgr, meshmanip, gamedef, tsettings);
+ ContentFeatures *f = &(m_content_features[i]);
+ f->updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
progress_callback(progress_callback_args, i, size);
}
#endif
@@ -1273,6 +1507,9 @@ void CNodeDefManager::deSerialize(std::istream &is)
m_content_features[i] = f;
addNameIdMapping(i, f.name);
verbosestream << "deserialized " << f.name << std::endl;
+
+ getNodeBoxUnion(f.selection_box, f, &m_selection_box_union);
+ fixSelectionBoxIntUnion();
}
}
@@ -1293,72 +1530,52 @@ 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<<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);
+ 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;
+ }
+
+ float compatible_visual_scale = visual_scale;
+ if (protocol_version < 30 && drawtype == NDT_PLANTLIKE)
+ compatible_visual_scale = sqrt(visual_scale);
+
+ TileDef compatible_tiles[6];
+ for (u8 i = 0; i < 6; i++) {
+ compatible_tiles[i] = tiledef[i];
+ if (tiledef_overlay[i].name != "") {
+ std::stringstream s;
+ s << "(" << tiledef[i].name << ")^(" << tiledef_overlay[i].name
+ << ")";
+ compatible_tiles[i].name = s.str();
}
- 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<<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, 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);
}
- else if (protocol_version > 13 && protocol_version < 24) {
- writeU8(os, 6); // version
- os<<serializeString(name);
+
+ // Protocol >= 24
+ if (protocol_version < 31) {
+ 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);
+ 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++)
+ compatible_tiles[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());
@@ -1366,7 +1583,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);
@@ -1375,10 +1592,10 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
writeU8(os, diggable);
writeU8(os, climbable);
writeU8(os, buildable_to);
- os<<serializeString(""); // legacy: used to be metadata_name
+ os << serializeString(""); // legacy: used to be metadata_name
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);
@@ -1394,9 +1611,19 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
writeU8(os, drowning);
writeU8(os, leveled);
writeU8(os, liquid_range);
- } else
+ 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");
+ }
}
void ContentFeatures::deSerializeOld(std::istream &is, int version)
@@ -1506,18 +1733,77 @@ 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");
}
}
-
-inline bool CNodeDefManager::getNodeRegistrationStatus() const
-{
- return m_node_registration_complete;
-}
-
-
inline void CNodeDefManager::setNodeRegistrationStatus(bool completed)
{
m_node_registration_complete = completed;
@@ -1600,19 +1886,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);
}