diff --git a/doc/texture_overrides.txt b/doc/texture_overrides.txt new file mode 100644 index 00000000..55959118 --- /dev/null +++ b/doc/texture_overrides.txt @@ -0,0 +1,35 @@ +Texture Overrides +================= + +You can override the textures of a node from a texture pack using +texture overrides. To do this, create a file in a texture pack +called override.txt + +Basic Format +------------ + +Each line in an override.txt file is a rule. It consists of + + nodename face-selector texture + +For example, + + default:dirt_with_grass sides default_stone.png + +You can use ^ operators as usual: + + default:dirt_with_grass sides default_stone.png^[brighten + +Face Selectors +-------------- + +| face-selector | behavior | +|---------------|---------------------------------------------------| +| left | x- | +| right | x+ | +| front | z- | +| back | z+ | +| top | z+ | +| bottom | z- | +| sides | x-, x+, z-, z+ | +| all | All faces. You can also use '*' instead of 'all'. | diff --git a/src/client.cpp b/src/client.cpp index 780b0787..1d0245c4 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1741,6 +1741,9 @@ void Client::afterContentReceived(IrrlichtDevice *device) text = wgettext("Initializing nodes..."); draw_load_screen(text, device, guienv, 0, 72); m_nodedef->updateAliases(m_itemdef); + std::string texture_path = g_settings->get("texture_path"); + if (texture_path != "" && fs::IsDir(texture_path)) + m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt"); m_nodedef->setNodeRegistrationStatus(true); m_nodedef->runNodeResolveCallbacks(); delete[] text; diff --git a/src/nodedef.cpp b/src/nodedef.cpp index ac432d19..6c2e96c4 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "exceptions.h" #include "debug.h" #include "gamedef.h" +#include // Used in applyTextureOverrides() /* NodeBox @@ -397,6 +398,7 @@ public: virtual content_t set(const std::string &name, const ContentFeatures &def); virtual content_t allocateDummy(const std::string &name); virtual void updateAliases(IItemDefManager *idef); + virtual void applyTextureOverrides(const std::string &override_filepath); virtual void updateTextures(IGameDef *gamedef, void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress), void *progress_cbk_args); @@ -670,7 +672,7 @@ content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &d j = m_group_to_items.find(group_name); if (j == m_group_to_items.end()) { m_group_to_items[group_name].push_back( - std::make_pair(id, i->second)); + std::make_pair(id, i->second)); } else { GroupItems &items = j->second; items.push_back(std::make_pair(id, i->second)); @@ -700,7 +702,66 @@ void CNodeDefManager::updateAliases(IItemDefManager *idef) content_t id; if (m_name_id_mapping.getId(convert_to, id)) { m_name_id_mapping_with_aliases.insert( - std::make_pair(name, id)); + std::make_pair(name, id)); + } + } +} + +void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath) +{ + infostream << "CNodeDefManager::applyTextureOverrides(): Applying " + "overrides to textures from " << override_filepath << std::endl; + + std::ifstream infile(override_filepath.c_str()); + std::string line; + int line_c = 0; + while (std::getline(infile, line)) { + line_c++; + if (trim(line) == "") + continue; + std::vector splitted = str_split(line, ' '); + if (splitted.size() != 3) { + errorstream << override_filepath + << ":" << line_c << " Could not apply texture override \"" + << line << "\": Syntax error" << std::endl; + continue; + } + + content_t id; + if (!getId(splitted[0], id)) { + errorstream << override_filepath + << ":" << line_c << " Could not apply texture override \"" + << line << "\": Unknown node \"" + << splitted[0] << "\"" << std::endl; + continue; + } + + ContentFeatures &nodedef = m_content_features[id]; + + if (splitted[1] == "top") + nodedef.tiledef[0].name = splitted[2]; + else if (splitted[1] == "bottom") + nodedef.tiledef[1].name = splitted[2]; + else if (splitted[1] == "right") + nodedef.tiledef[2].name = splitted[2]; + else if (splitted[1] == "left") + nodedef.tiledef[3].name = splitted[2]; + else if (splitted[1] == "back") + nodedef.tiledef[4].name = splitted[2]; + else if (splitted[1] == "front") + nodedef.tiledef[5].name = splitted[2]; + else if (splitted[1] == "all" || splitted[1] == "*") + for (int i = 0; i < 6; i++) + nodedef.tiledef[i].name = splitted[2]; + else if (splitted[1] == "sides") + for (int i = 2; i < 6; i++) + nodedef.tiledef[i].name = splitted[2]; + else { + errorstream << override_filepath + << ":" << line_c << " Could not apply texture override \"" + << line << "\": Unknown node side \"" + << splitted[1] << "\"" << std::endl; + continue; } } } diff --git a/src/nodedef.h b/src/nodedef.h index 68f6c8c3..3a5e5228 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -335,6 +335,11 @@ public: */ virtual void updateAliases(IItemDefManager *idef)=0; + /* + Override textures from servers with ones specified in texturepack/override.txt + */ + virtual void applyTextureOverrides(const std::string &override_filepath)=0; + /* Update tile textures to latest return values of TextueSource. */ @@ -378,4 +383,3 @@ public: }; #endif - diff --git a/src/server.cpp b/src/server.cpp index 22b7d38f..2a34c867 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -335,6 +335,11 @@ Server::Server( // Apply item aliases in the node definition manager m_nodedef->updateAliases(m_itemdef); + // Apply texture overrides from texturepack/override.txt + std::string texture_path = g_settings->get("texture_path"); + if (texture_path != "" && fs::IsDir(texture_path)) + m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt"); + m_nodedef->setNodeRegistrationStatus(true); // Perform pending node name resolutions @@ -3397,5 +3402,3 @@ void dedicated_server_loop(Server &server, bool &kill) } } } - -