From 603297cc352cab685dd01dcd645999624ad17c0b Mon Sep 17 00:00:00 2001
From: rubenwardy <rubenwardy@gmail.com>
Date: Mon, 30 Mar 2015 11:55:29 +0100
Subject: [PATCH] Add texture overriding

---
 doc/texture_overrides.txt | 35 +++++++++++++++++++++
 src/client.cpp            |  3 ++
 src/nodedef.cpp           | 65 +++++++++++++++++++++++++++++++++++++--
 src/nodedef.h             |  6 +++-
 src/server.cpp            |  7 +++--
 5 files changed, 111 insertions(+), 5 deletions(-)
 create mode 100644 doc/texture_overrides.txt

diff --git a/doc/texture_overrides.txt b/doc/texture_overrides.txt
new file mode 100644
index 000000000..559591184
--- /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 780b07872..1d0245c45 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 ac432d196..6c2e96c4f 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 <fstream> // Used in applyTextureOverrides()
 
 /*
 	NodeBox
@@ -397,6 +398,7 @@ class CNodeDefManager: public IWritableNodeDefManager {
 	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<std::string> 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 68f6c8c37..3a5e5228d 100644
--- a/src/nodedef.h
+++ b/src/nodedef.h
@@ -335,6 +335,11 @@ class IWritableNodeDefManager : public INodeDefManager {
 	*/
 	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 @@ class NodeResolver {
 };
 
 #endif
-
diff --git a/src/server.cpp b/src/server.cpp
index 22b7d38f2..2a34c8675 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)
 		}
 	}
 }
-
-
-- 
GitLab