From 8addbc9655f60e0a2673e8df83ebb0d78e2a6aec Mon Sep 17 00:00:00 2001
From: Perttu Ahola <celeron55@gmail.com>
Date: Sun, 4 Dec 2011 00:22:34 +0200
Subject: [PATCH] Tool aliases

---
 data/mods/default/init.lua |  2 ++
 data/mods/legacy/init.lua  | 14 ++++++++++
 src/scriptapi.cpp          | 19 +++++++++++++
 src/tooldef.cpp            | 57 ++++++++++++++++++++++++++++++++------
 src/tooldef.h              |  5 ++++
 5 files changed, 89 insertions(+), 8 deletions(-)

diff --git a/data/mods/default/init.lua b/data/mods/default/init.lua
index c69d26454..003a02323 100644
--- a/data/mods/default/init.lua
+++ b/data/mods/default/init.lua
@@ -92,6 +92,8 @@
 -- minetest.register_craftitem(name, craftitem definition)
 -- minetest.register_craft(recipe)
 -- minetest.register_abm(abm definition)
+-- minetest.alias_node(name, convert_to)
+-- minetest.alias_tool(name, convert_to)
 -- minetest.register_globalstep(func(dtime))
 -- minetest.register_on_placenode(func(pos, newnode, placer))
 -- minetest.register_on_dignode(func(pos, oldnode, digger))
diff --git a/data/mods/legacy/init.lua b/data/mods/legacy/init.lua
index a51931e41..6bd5526e5 100644
--- a/data/mods/legacy/init.lua
+++ b/data/mods/legacy/init.lua
@@ -40,6 +40,20 @@ minetest.alias_node("nyancat_rainbow", "default:nyancat_rainbow")
 minetest.alias_node("sapling", "default:sapling")
 minetest.alias_node("apple", "default:apple")
 
+minetest.alias_tool("WPick", "default:pick_wood")
+minetest.alias_tool("STPick", "default:pick_stone")
+minetest.alias_tool("SteelPick", "default:pick_steel")
+minetest.alias_tool("MesePick", "default:pick_mese")
+minetest.alias_tool("WShovel", "default:shovel_wood")
+minetest.alias_tool("STShovel", "default:shovel_stone")
+minetest.alias_tool("SteelShovel", "default:shovel_steel")
+minetest.alias_tool("WAxe", "default:axe_wood")
+minetest.alias_tool("STAxe", "default:axe_stone")
+minetest.alias_tool("SteelAxe", "default:axe_steel")
+minetest.alias_tool("WSword", "default:sword_wood")
+minetest.alias_tool("STSword", "default:sword_stone")
+minetest.alias_tool("SteelSword", "default:sword_steel")
+
 --[[
 WATER_ALPHA = 160
 WATER_VISC = 1
diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp
index c5574dd8e..ab9f89212 100644
--- a/src/scriptapi.cpp
+++ b/src/scriptapi.cpp
@@ -1140,6 +1140,24 @@ static int l_alias_node(lua_State *L)
 	return 0; /* number of results */
 }
 
+// alias_tool(name, convert_to_name)
+static int l_alias_tool(lua_State *L)
+{
+	std::string name = luaL_checkstring(L, 1);
+	std::string convert_to = luaL_checkstring(L, 2);
+
+	// Get server from registry
+	lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
+	Server *server = (Server*)lua_touserdata(L, -1);
+	// And get the writable tool definition manager from the server
+	IWritableToolDefManager *tooldef =
+			server->getWritableToolDefManager();
+	
+	tooldef->setAlias(name, convert_to);
+
+	return 0; /* number of results */
+}
+
 // register_craft({output=item, recipe={{item00,item10},{item01,item11}})
 static int l_register_craft(lua_State *L)
 {
@@ -1293,6 +1311,7 @@ static const struct luaL_Reg minetest_f [] = {
 	{"register_craft", l_register_craft},
 	{"register_abm", l_register_abm},
 	{"alias_node", l_alias_node},
+	{"alias_tool", l_alias_tool},
 	{"setting_get", l_setting_get},
 	{"setting_getbool", l_setting_getbool},
 	{"chat_send_all", l_chat_send_all},
diff --git a/src/tooldef.cpp b/src/tooldef.cpp
index 45193f46b..6733dfff0 100644
--- a/src/tooldef.cpp
+++ b/src/tooldef.cpp
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "log.h"
 #include <sstream>
 #include "utility.h"
+#include <map>
 
 ToolDiggingProperties::ToolDiggingProperties(float full_punch_interval_,
 		float a, float b, float c, float d, float e,
@@ -92,8 +93,16 @@ public:
 	{
 		clear();
 	}
-	virtual const ToolDefinition* getToolDefinition(const std::string &toolname) const
+	virtual const ToolDefinition* getToolDefinition(const std::string &toolname_) const
 	{
+		// Convert name according to possible alias
+		std::string toolname = toolname_;
+		std::map<std::string, std::string>::const_iterator i;
+		i = m_aliases.find(toolname);
+		if(i != m_aliases.end()){
+			toolname = i->second;
+		}
+		// Get the definition
 		core::map<std::string, ToolDefinition*>::Node *n;
 		n = m_tool_definitions.find(toolname);
 		if(n == NULL)
@@ -124,14 +133,14 @@ public:
 	virtual bool registerTool(std::string toolname, const ToolDefinition &def)
 	{
 		infostream<<"registerTool: registering tool \""<<toolname<<"\""<<std::endl;
-		/*core::map<std::string, ToolDefinition*>::Node *n;
-		n = m_tool_definitions.find(toolname);
-		if(n != NULL){
-			errorstream<<"registerTool: registering tool \""<<toolname
-					<<"\" failed: name is already registered"<<std::endl;
-			return false;
-		}*/
 		m_tool_definitions[toolname] = new ToolDefinition(def);
+
+		// Remove conflicting alias if it exists
+		bool alias_removed = (m_aliases.erase(toolname) != 0);
+		if(alias_removed)
+			infostream<<"tdef: erased alias "<<toolname
+					<<" because node was defined"<<std::endl;
+		
 		return true;
 	}
 	virtual void clear()
@@ -142,6 +151,19 @@ public:
 			delete i.getNode()->getValue();
 		}
 		m_tool_definitions.clear();
+		m_aliases.clear();
+	}
+	virtual void setAlias(const std::string &name,
+			const std::string &convert_to)
+	{
+		if(getToolDefinition(name) != NULL){
+			infostream<<"tdef: not setting alias "<<name<<" -> "<<convert_to
+					<<": "<<name<<" is already defined"<<std::endl;
+			return;
+		}
+		infostream<<"tdef: setting alias "<<name<<" -> "<<convert_to
+				<<std::endl;
+		m_aliases[name] = convert_to;
 	}
 	virtual void serialize(std::ostream &os)
 	{
@@ -160,6 +182,14 @@ public:
 			def->serialize(tmp_os);
 			os<<serializeString(tmp_os.str());
 		}
+
+		writeU16(os, m_aliases.size());
+		for(std::map<std::string, std::string>::const_iterator
+				i = m_aliases.begin(); i != m_aliases.end(); i++)
+		{
+			os<<serializeString(i->first);
+			os<<serializeString(i->second);
+		}
 	}
 	virtual void deSerialize(std::istream &is)
 	{
@@ -180,10 +210,21 @@ public:
 			// Register
 			registerTool(name, def);
 		}
+
+		u16 num_aliases = readU16(is);
+		if(!is.eof()){
+			for(u16 i=0; i<num_aliases; i++){
+				std::string name = deSerializeString(is);
+				std::string convert_to = deSerializeString(is);
+				m_aliases[name] = convert_to;
+			}
+		}
 	}
 private:
 	// Key is name
 	core::map<std::string, ToolDefinition*> m_tool_definitions;
+	// Aliases for loading legacy crap
+	std::map<std::string, std::string> m_aliases;
 };
 
 IWritableToolDefManager* createToolDefManager()
diff --git a/src/tooldef.h b/src/tooldef.h
index aa4cb6931..e28935e43 100644
--- a/src/tooldef.h
+++ b/src/tooldef.h
@@ -85,6 +85,11 @@ public:
 			
 	virtual bool registerTool(std::string toolname, const ToolDefinition &def)=0;
 	virtual void clear()=0;
+	// Set an alias so that entries named <name> will load as <convert_to>.
+	// Alias is not set if <name> has already been defined.
+	// Alias will be removed if <name> is defined at a later point of time.
+	virtual void setAlias(const std::string &name,
+			const std::string &convert_to)=0;
 
 	virtual void serialize(std::ostream &os)=0;
 	virtual void deSerialize(std::istream &is)=0;
-- 
2.25.1