瀏覽代碼

Added Simple String Multitag System

removed old implementation, no optimisation, scene caches tagged nodes
svifylabs 10 年之前
父節點
當前提交
4297cdedd2

+ 12 - 7
Source/Urho3D/AngelScript/APITemplates.h

@@ -581,13 +581,18 @@ static CScriptArray* NodeGetChildrenWithComponent(const String& typeName, bool r
     return VectorToHandleArray<Node>(nodes, "Array<Node@>");
 }
 
-static CScriptArray* NodeGetChildrenWithTag(const StringHash& typeName, bool recursive, Node* ptr)
+static CScriptArray* NodeGetChildrenWithTag(const String& typeName, bool recursive, Node* ptr)
 {
 	PODVector<Node*> nodes;
 	ptr->GetChildrenWithTag(nodes, typeName, recursive);
 	return VectorToHandleArray<Node>(nodes, "Array<Node@>");
 }
 
+static CScriptArray* NodeGetTags(Node* ptr)
+{
+	return VectorToArray<String>(ptr->GetTags(), "Array<String>");
+}
+
 static unsigned NodeGetNumChildrenNonRecursive(Node* ptr)
 {
     return ptr->GetNumChildren(false);
@@ -698,7 +703,7 @@ template <class T> void RegisterNode(asIScriptEngine* engine, const char* classN
     engine->RegisterObjectMethod(className, "void RemoveAllComponents()", asMETHOD(T, RemoveAllComponents), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildren(bool recursive = false) const", asFUNCTION(NodeGetChildren), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildrenWithComponent(const String&in, bool recursive = false) const", asFUNCTION(NodeGetChildrenWithComponent), asCALL_CDECL_OBJLAST);
-	engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildrenWithTag(const StringHash&in, bool recursive = false) const", asFUNCTION(NodeGetChildrenWithTag), asCALL_CDECL_OBJLAST);
+	engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildrenWithTag(const String&in, bool recursive = false) const", asFUNCTION(NodeGetChildrenWithTag), asCALL_CDECL_OBJLAST);
 	engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildrenWithScript(bool recursive = false) const", asFUNCTION(NodeGetChildrenWithScript), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildrenWithScript(const String&in, bool recursive = false) const", asFUNCTION(NodeGetChildrenWithClassName), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "Node@+ GetChild(const String&in, bool recursive = false) const", asMETHODPR(T, GetChild, (const String&, bool) const, Node*), asCALL_THISCALL);
@@ -758,11 +763,11 @@ template <class T> void RegisterNode(asIScriptEngine* engine, const char* classN
     engine->RegisterObjectMethod(className, "void set_parent(Node@+)", asMETHOD(T, SetParent), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "Node@+ get_parent() const", asMETHOD(T, GetParent), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "VariantMap& get_vars()", asFUNCTION(NodeGetVars), asCALL_CDECL_OBJLAST);
-	engine->RegisterObjectMethod(className, "bool HasTag(const StringHash&in)", asMETHOD(T, HasTag), asCALL_THISCALL);
-	engine->RegisterObjectMethod(className, "StringHash get_tag()", asMETHOD(T, GetTag), asCALL_THISCALL);
-	engine->RegisterObjectMethod(className, "void set_tag(const StringHash&in)", asMETHOD(T, SetTag), asCALL_THISCALL);
-	engine->RegisterObjectMethod(className, "const String& get_tagString()", asMETHOD(T, GetTagString), asCALL_THISCALL);
-	engine->RegisterObjectMethod(className, "void set_tagName(const String&in)", asMETHOD(T, SetTagString), asCALL_THISCALL);
+	engine->RegisterObjectMethod(className, "bool HasTag(const String&in)", asMETHOD(T, HasTag), asCALL_THISCALL);
+	engine->RegisterObjectMethod(className, "Array<String>@ get_tags()", asFUNCTION(NodeGetTags), asCALL_CDECL_OBJLAST);
+	engine->RegisterObjectMethod(className, "void AddTag(const String&in)", asMETHOD(T, AddTag), asCALL_THISCALL);
+	engine->RegisterObjectMethod(className, "void RemoveTag(const String&in)", asMETHOD(T, RemoveTag), asCALL_THISCALL);
+	engine->RegisterObjectMethod(className, "void RemoveAllTags()", asMETHOD(T, RemoveAllTags), asCALL_THISCALL);
 }
 
 static bool ResourceLoad(File* file, XMLFile* ptr)

+ 4 - 7
Source/Urho3D/AngelScript/SceneAPI.cpp

@@ -165,10 +165,10 @@ static bool SceneLoadXMLVectorBuffer(VectorBuffer& buffer, Scene* ptr)
     return ptr->LoadXML(buffer);
 }
 
-static CScriptArray* SceneGetNodesWithTag(const StringHash& typeName, Scene* ptr)
+static CScriptArray* SceneGetNodesWithTag(const String& tag, Scene* ptr)
 {
 	PODVector<Node*> nodes;
-	ptr->GetNodesWithTag(nodes, typeName);
+	ptr->GetNodesWithTag(nodes, tag);
 	return VectorToHandleArray<Node>(nodes, "Array<Node@>");
 }
 
@@ -360,15 +360,12 @@ static void RegisterScene(asIScriptEngine* engine)
 	engine->RegisterObjectMethod("Scene", "void RegisterVar(const String&in)", asMETHOD(Scene, RegisterVar), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void UnregisterVar(const String&in)", asMETHOD(Scene, UnregisterVar), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void UnregisterAllVars(const String&in)", asMETHOD(Scene, UnregisterAllVars), asCALL_THISCALL);
-	
-	engine->RegisterObjectMethod("Scene", "void RegisterTag(const String&in)", asMETHOD(Scene, RegisterTag), asCALL_THISCALL);
-	engine->RegisterObjectMethod("Scene", "void UnregisterTag(const String&in)", asMETHOD(Scene, UnregisterTag), asCALL_THISCALL);
-	engine->RegisterObjectMethod("Scene", "void UnregisterAllTags(const String&in)", asMETHOD(Scene, UnregisterAllTags), asCALL_THISCALL);
+
+	engine->RegisterObjectMethod("Scene", "Array<Node@>@ GetNodesWithTag(const String&in) const", asFUNCTION(SceneGetNodesWithTag), asCALL_CDECL_OBJLAST);
 
 	engine->RegisterObjectMethod("Scene", "Component@+ GetComponent(uint) const", asMETHODPR(Scene, GetComponent, (unsigned) const, Component*), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "Node@+ GetNode(uint) const", asMETHOD(Scene, GetNode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "const String& GetVarName(StringHash) const", asMETHOD(Scene, GetVarName), asCALL_THISCALL);
-	engine->RegisterObjectMethod("Scene", "const String& GetTagName(StringHash) const", asMETHOD(Scene, GetTagName), asCALL_THISCALL);
 	engine->RegisterObjectMethod("Scene", "void Update(float)", asMETHOD(Scene, Update), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void set_updateEnabled(bool)", asMETHOD(Scene, SetUpdateEnabled), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "bool get_updateEnabled() const", asMETHOD(Scene, IsUpdateEnabled), asCALL_THISCALL);

+ 17 - 0
Source/Urho3D/LuaScript/pkgs/Scene/Node.pkg

@@ -192,6 +192,15 @@ class Node : public Animatable
     Node* CreateChild(unsigned id, CreateMode mode);
     void AddComponent(Component* component, unsigned id, CreateMode mode);
 
+	void AddTag(const String& tag);
+    void RemoveTag(const String& tag);
+	void RemoveAllTags();
+    bool HasTag(const String& tag) const;
+    const StringVector& GetTags() const;
+
+	// void GetChildrenWithTag(PODVector<Node*>& dest, const String& tag, bool recursive = false) const;
+    tolua_outside const PODVector<Node*>& NodeGetChildrenWithTag @ GetChildrenWithTag(const String& tag, bool recursive = false) const; 
+
     tolua_readonly tolua_property__get_set unsigned ID;
     tolua_property__get_set String name;
     tolua_readonly tolua_property__get_set StringHash nameHash;
@@ -432,4 +441,12 @@ static const PODVector<Node*>& NodeGetChildrenWithComponent(Node* node, String t
     node->GetChildrenWithComponent(result, type, recursive);
     return result;
 }
+
+static const PODVector<Node*>& NodeGetChildrenWithTag(const Node* node, const String& tag, bool recursive)
+{
+    static PODVector<Node*> result;
+    result.Clear();
+    node->GetChildrenWithTag(result, tag, recursive);
+    return result;
+}
 $}

+ 11 - 0
Source/Urho3D/LuaScript/pkgs/Scene/Scene.pkg

@@ -82,6 +82,9 @@ class Scene : public Node
     void MarkNetworkUpdate(Component* component);
     void MarkReplicationDirty(Node* node);
     
+	// bool GetNodesWithTag(PODVector<Node*>& dest, const String& tag) const;
+    tolua_outside const PODVector<Node*>&  SceneGetNodesWithTag @ GetNodesWithTag( const String& tag) const; 
+
     tolua_property__is_set bool updateEnabled;
     tolua_readonly tolua_property__is_set bool asyncLoading;
     tolua_readonly tolua_property__get_set float asyncProgress;
@@ -148,6 +151,14 @@ static bool SceneLoadXML(Scene* scene, const String& fileName)
     return file.IsOpen() && scene->LoadXML(file);
 }
 
+static const PODVector<Node*>& SceneGetNodesWithTag(const Scene* scene, const String& tag)
+{
+    static PODVector<Node*> result;
+    result.Clear();
+    scene->GetNodesWithTag(result, tag);
+    return result;
+}
+
 static bool SceneSaveXML(const Scene* scene, const String& fileName, const String& indentation)
 {
     File file(scene->GetContext(), fileName, FILE_WRITE);

+ 114 - 36
Source/Urho3D/Scene/Node.cpp

@@ -79,8 +79,8 @@ void Node::RegisterObject(Context* context)
 
     URHO3D_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Name", GetName, SetName, String, String::EMPTY, AM_DEFAULT);
-	URHO3D_ACCESSOR_ATTRIBUTE("Tag", GetTag, SetTag, StringHash, StringHash::ZERO, AM_DEFAULT | AM_NOEDIT);
-	URHO3D_ACCESSOR_ATTRIBUTE("TagString", GetTagString, SetTagString, String, String::EMPTY, AM_FILE | AM_EDIT);
+	URHO3D_ATTRIBUTE("Tags", StringVector, tags_, Variant::emptyStringVector, AM_DEFAULT);
+	URHO3D_ACCESSOR_ATTRIBUTE("Tags", GetTags, SetTags, StringVector, Variant::emptyStringVector, AM_DEFAULT );
 	URHO3D_ACCESSOR_ATTRIBUTE("Position", GetPosition, SetPosition, Vector3, Vector3::ZERO, AM_FILE);
     URHO3D_ACCESSOR_ATTRIBUTE("Rotation", GetRotation, SetRotation, Quaternion, Quaternion::IDENTITY, AM_FILE);
     URHO3D_ACCESSOR_ATTRIBUTE("Scale", GetScale, SetScale, Vector3, Vector3::ONE, AM_DEFAULT);
@@ -342,38 +342,128 @@ void Node::SetName(const String& name)
     }
 }
 
-void Node::SetTag(const StringHash& tag)
+void Node::SetTags(const StringVector& tags)
 {
-	if (tag_ != tag)
-	{
-		StringHash oldTag = tag_;
-		tag_ = tag;
+	RemoveAllTags();
+	AddTags(tags);
+	// sync
+	// MarkNetworkUpdate(); already called in RemoveAllTags() / AddTags()
+}
 
+void Node::AddTag(const String& tag)
+{
+	// check if tag already added. 
+	StringVector::Iterator it = tags_.Find(tag);
+	if (it != tags_.End())
+		return;
+	
+		// add tag 
+		tags_.Push(tag);
 
-		MarkNetworkUpdate();
+		// cache 
+		scene_->NodeTagAdded(this, tag);
 
-		// Send change event
-		if (scene_)
-		{
-			scene_->NodeTagChanged(this, oldTag);
+		// send event
+		using namespace NodeTagAdded;
+		VariantMap& eventData = GetEventDataMap();
+		eventData[P_SCENE] = scene_;
+		eventData[P_NODE] = this;
+		eventData[P_TAG] = tag;
+		scene_->SendEvent(E_NODETAGADDED, eventData);
+		
+	// sync
+	MarkNetworkUpdate();
+}
 
-			using namespace NodeTagChanged;
+void Node::AddTags(const String& tags, char s /*= ','*/)
+{
+	if (tags.Empty())
+		return;
+	StringVector tags_temp = tags.Split(s);
+	AddTags(tags_temp);
+}
+
+void Node::AddTags(const StringVector& tags)
+{
+	bool added = false;
 
+	for (unsigned i = 0; i < tags.Size(); ++i)
+	{
+		// check if tag already added. 
+		StringVector::Iterator it = tags_.Find(tags[i]);
+		if (it != tags_.End())
+		{
+			// add tag 
+			tags_.Push(tags[i]);
+
+			// cache 
+			scene_->NodeTagAdded(this, tags[i]);
+			// send event
+			using namespace NodeTagAdded;
 			VariantMap& eventData = GetEventDataMap();
 			eventData[P_SCENE] = scene_;
 			eventData[P_NODE] = this;
-			eventData[P_TAG] = tag_;
-			eventData[P_OLDTAG] = oldTag;
-			scene_->SendEvent(E_NODETAGCHANGED, eventData);
+			eventData[P_TAG] = tags[i];
+			scene_->SendEvent(E_NODETAGADDED, eventData);
+			added = true;
 		}
 	}
+
+	// sync
+	if (added)
+		MarkNetworkUpdate();
 }
 
-void Node::SetTagString(const String & tag)
+void Node::RemoveTag(const String& tag)
 {
-	StringHash id(tag);
-	tagString_ = tag;
-	SetTag(id);
+	// early out
+	if (tags_.Empty())
+		return;
+	bool removed = tags_.Remove(tag);
+
+	// nothing to do
+	if (!removed)
+		return;
+	
+	// scene cache update
+	if (scene_)
+	{
+		scene_->NodeTagRemoved(this, tag);
+		// send event
+		using namespace NodeTagRemoved;
+		VariantMap& eventData = GetEventDataMap();
+		eventData[P_SCENE] = scene_;
+		eventData[P_NODE] = this;
+		eventData[P_TAG] = tag;
+		scene_->SendEvent(E_NODETAGREMOVED, eventData);
+	}
+	// sync
+	MarkNetworkUpdate();
+}
+
+void Node::RemoveAllTags()
+{
+	// clear old scene cache
+	if (scene_)
+	{
+		for (unsigned i = 0; i < tags_.Size(); ++i)
+		{
+			scene_->NodeTagRemoved(this, tags_[i]);
+
+			// send event
+			using namespace NodeTagRemoved;
+			VariantMap& eventData = GetEventDataMap();
+			eventData[P_SCENE] = scene_;
+			eventData[P_NODE] = this;
+			eventData[P_TAG] = tags_[i];
+			scene_->SendEvent(E_NODETAGREMOVED, eventData);
+		}
+	}
+
+	tags_.Clear();
+
+	// sync
+	MarkNetworkUpdate();
 }
 
 void Node::SetPosition(const Vector3& position)
@@ -1148,7 +1238,7 @@ void Node::GetChildrenWithComponent(PODVector<Node*>& dest, StringHash type, boo
         GetChildrenWithComponentRecursive(dest, type);
 }
 
-void Node::GetChildrenWithTag(PODVector<Node*>& dest, StringHash tag, bool recursive /*= true*/) const
+void Node::GetChildrenWithTag(PODVector<Node*>& dest, const String& tag, bool recursive /*= true*/) const
 {
 	dest.Clear();
 
@@ -1235,21 +1325,9 @@ bool Node::HasComponent(StringHash type) const
     return false;
 }
 
-bool Node::HasTag(StringHash tag) const
-{
-	return tag_ == tag;
-}
-
-const StringHash& Node::GetTag() const
-{
-	return tag_;
-}
-
-const String & Node::GetTagString() const
+bool Node::HasTag(const String& tag) const
 {
-	if (tagString_.Empty() && scene_)
-		return scene_->GetTagName(tag_);
-	return tagString_;
+	return tags_.Empty() ? false : tags_.Contains(tag);
 }
 
 const Variant& Node::GetVar(StringHash key) const
@@ -2022,7 +2100,7 @@ void Node::GetComponentsRecursive(PODVector<Component*>& dest, StringHash type)
         (*i)->GetComponentsRecursive(dest, type);
 }
 
-void Node::GetChildrenWithTagRecursive(PODVector<Node*>& dest, StringHash tag) const
+void Node::GetChildrenWithTagRecursive(PODVector<Node*>& dest, const String& tag) const
 {
 	for (Vector<SharedPtr<Node> >::ConstIterator i = children_.Begin(); i != children_.End(); ++i)
 	{

+ 20 - 14
Source/Urho3D/Scene/Node.h

@@ -95,10 +95,20 @@ public:
     bool SaveJSON(Serializer& dest, const String& indentation = "\t") const;
     /// Set name of the scene node. Names are not required to be unique.
     void SetName(const String& name);
-	/// Set tag for the scene node. 
-	void SetTag(const StringHash& tag);
-	/// Set tag string for the scene node. 
-	void SetTagString(const String& tag);
+
+	/// Set Tags, overrites old tags.
+	void SetTags(const StringVector& tags);
+	/// Add tag. 
+	void AddTag(const String& tag);
+	/// Add tags. 
+	void AddTags(const String& tags, char s = ',');
+	/// Add tags.
+	void AddTags(const StringVector& tags);
+	/// Remove Tag.
+	void RemoveTag(const String& tag);
+	/// Remove all Tags.
+	void RemoveAllTags();
+
 	/// Set position in parent space. If the scene node is on the root level (is child of the scene itself), this is same as world space.
     void SetPosition(const Vector3& position);
 
@@ -309,10 +319,8 @@ public:
     /// Return name hash.
     StringHash GetNameHash() const { return nameHash_; }
 
-	/// Return the tag.
-	const StringHash& GetTag() const;
-	/// Return the tag as a string.
-	const String& GetTagString() const;
+	/// Return the tags.
+	const StringVector& GetTags() const { return tags_; }
     /// Return parent scene node.
     Node* GetParent() const { return parent_; }
 
@@ -468,7 +476,7 @@ public:
     /// Return child scene nodes with a specific component.
     void GetChildrenWithComponent(PODVector<Node*>& dest, StringHash type, bool recursive = false) const;
 	/// Return child scene nodes with a specific tag.
-	void GetChildrenWithTag(PODVector<Node*>& dest, StringHash tag, bool recursive = false) const;
+	void GetChildrenWithTag(PODVector<Node*>& dest, const String& tag, bool recursive = false) const;
 
 	/// Return child scene node by index.
     Node* GetChild(unsigned index) const;
@@ -497,7 +505,7 @@ public:
     /// Return whether has a specific component.
     bool HasComponent(StringHash type) const;
 	/// Return whether has a specific tag.
-	bool HasTag(StringHash tag) const;
+	bool HasTag(const String& tag) const;
     /// Return listener components.
     const Vector<WeakPtr<Component> > GetListeners() const { return listeners_; }
 
@@ -608,7 +616,7 @@ private:
     /// Return child nodes with a specific component recursively.
     void GetChildrenWithComponentRecursive(PODVector<Node*>& dest, StringHash type) const;
 	/// Return child nodes with a specific tag recursively.
-	void GetChildrenWithTagRecursive(PODVector<Node*>& dest, StringHash tag) const;
+	void GetChildrenWithTagRecursive(PODVector<Node*>& dest, const String& tag) const;
 	/// Return specific components recursively.
     void GetComponentsRecursive(PODVector<Component*>& dest, StringHash type) const;
     /// Clone node recursively.
@@ -652,10 +660,8 @@ private:
     Connection* owner_;
     /// Name.
     String name_;
-	/// Tag.
-	StringHash tag_;
 	/// Tag String.
-	String tagString_;
+	StringVector tags_;
     /// Name hash.
     StringHash nameHash_;
     /// Attribute buffer for network updates.

+ 27 - 59
Source/Urho3D/Scene/Scene.cpp

@@ -109,7 +109,6 @@ void Scene::RegisterObject(Context* context)
     URHO3D_ATTRIBUTE("Next Local Component ID", unsigned, localComponentID_, FIRST_LOCAL_ID, AM_FILE | AM_NOEDIT);
     URHO3D_ATTRIBUTE("Variables", VariantMap, vars_, Variant::emptyVariantMap, AM_FILE); // Network replication of vars uses custom data
     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Variable Names", GetVarNamesAttr, SetVarNamesAttr, String, String::EMPTY, AM_FILE | AM_NOEDIT);
-	URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Tag Names", GetTagNamesAttr, SetTagNamesAttr, String, String::EMPTY, AM_FILE | AM_NOEDIT);
 }
 
 bool Scene::Load(Deserializer& source, bool setInstanceDefault)
@@ -704,21 +703,6 @@ void Scene::UnregisterAllVars()
     varNames_.Clear();
 }
 
-void Scene::RegisterTag(const String& name)
-{
-	tagNames_[name] = name;
-}
-
-void Scene::UnregisterTag(const String& name)
-{
-	tagNames_.Erase(name);
-}
-
-void Scene::UnregisterAllTags()
-{
-	tagNames_.Clear();
-}
-
 Node* Scene::GetNode(unsigned id) const
 {
     if (id < FIRST_LOCAL_ID)
@@ -733,7 +717,7 @@ Node* Scene::GetNode(unsigned id) const
     }
 }
 
-bool Scene::GetNodesWithTag(PODVector<Node*>& dest, StringHash tag) const
+bool Scene::GetNodesWithTag(PODVector<Node*>& dest, const String& tag) const
 {
 	dest.Clear();
 	HashMap<StringHash, PODVector<Node*> >::ConstIterator it = tagedNodes_.Find(tag);
@@ -773,12 +757,6 @@ const String& Scene::GetVarName(StringHash hash) const
     return i != varNames_.End() ? i->second_ : String::EMPTY;
 }
 
-const String& Scene::GetTagName(StringHash tag) const
-{
-	HashMap<StringHash, String>::ConstIterator i = tagNames_.Find(tag);
-	return i != tagNames_.End() ? i->second_ : String::EMPTY;
-}
-
 void Scene::Update(float timeStep)
 {
     if (asyncLoading_)
@@ -971,9 +949,15 @@ void Scene::NodeAdded(Node* node)
         localNodes_[id] = node;
     }
 
-	// cache tag if already taged.
-	if (node->GetTag() != StringHash::ZERO)
-		tagedNodes_[node->GetTag()].Push(node);
+	// cache tag if already tagged.
+	if (!node->GetTags().Empty())
+	{
+		const StringVector& tags = node->GetTags();
+		for (unsigned i = 0; i < tags.Size(); ++i)
+		{
+			tagedNodes_[tags[i]].Push(node);
+		}
+	}
 
     // Add already created components and child nodes now
     const Vector<SharedPtr<Component> >& components = node->GetComponents();
@@ -984,12 +968,14 @@ void Scene::NodeAdded(Node* node)
         NodeAdded(*i);
 }
 
-void Scene::NodeTagChanged(Node* node, StringHash oldTag)
+void Scene::NodeTagAdded(Node* node, const String& tag)
+{
+	tagedNodes_[tag].Push(node);
+}
+
+void Scene::NodeTagRemoved(Node* node, const String& tag)
 {
-	if (oldTag != StringHash::ZERO)
-		tagedNodes_[oldTag].Remove(node);
-	if (node->GetTag() != StringHash::ZERO)
-		tagedNodes_[node->GetTag()].Push(node);
+	tagedNodes_[tag].Remove(node);
 }
 
 void Scene::NodeRemoved(Node* node)
@@ -1008,10 +994,16 @@ void Scene::NodeRemoved(Node* node)
 
     node->ResetScene();
 
-	// Remove cached taged node 
-	if(node->GetTag() != StringHash::ZERO)
-		tagedNodes_[node->GetTag()].Remove(node);
-
+	// Remove node from tag cache 
+	if (!node->GetTags().Empty())
+	{
+		const StringVector& tags = node->GetTags();
+		for (unsigned i = 0; i < tags.Size(); ++i)
+		{
+			tagedNodes_[tags[i]].Remove(node);
+		}
+	}
+		
     // Remove components and child nodes as well
     const Vector<SharedPtr<Component> >& components = node->GetComponents();
     for (Vector<SharedPtr<Component> >::ConstIterator i = components.Begin(); i != components.End(); ++i)
@@ -1540,30 +1532,6 @@ void Scene::PreloadResourcesJSON(const JSONValue& value)
 #endif
 }
 
-void Scene::SetTagNamesAttr(const String& value)
-{
-	Vector<String> tagNames = value.Split(';');
-
-	tagNames_.Clear();
-	for (Vector<String>::ConstIterator i = tagNames.Begin(); i != tagNames.End(); ++i)
-		tagNames_[*i] = *i;
-}
-
-Urho3D::String Scene::GetTagNamesAttr() const
-{
-	String ret;
-
-	if (!tagNames_.Empty())
-	{
-		for (HashMap<StringHash, String>::ConstIterator i = tagNames_.Begin(); i != tagNames_.End(); ++i)
-			ret += i->second_ + ';';
-
-		ret.Resize(ret.Length() - 1);
-	}
-
-	return ret;
-}
-
 void RegisterSceneLibrary(Context* context)
 {
     ValueAnimation::RegisterObject(context);

+ 6 - 16
Source/Urho3D/Scene/Scene.h

@@ -165,19 +165,13 @@ public:
     void UnregisterVar(const String& name);
     /// Clear all registered node user variable hash reverse mappings.
     void UnregisterAllVars();
-	/// Register a node Tag.
-	void RegisterTag(const String& name);
-	/// Unregister a node Tag and if set remove Tag from nodes.
-	void UnregisterTag(const String& name);
-	/// Clear all registered node Tag.
-	void UnregisterAllTags();
 
     /// Return node from the whole scene by ID, or null if not found.
     Node* GetNode(unsigned id) const;
     /// Return component from the whole scene by ID, or null if not found.
     Component* GetComponent(unsigned id) const;
 	/// Get nodes with specific tag from the whole scene, return false if empty.
-	bool GetNodesWithTag(PODVector<Node*>& dest, StringHash tag)  const;
+	bool GetNodesWithTag(PODVector<Node*>& dest, const String& tag)  const;
 	
 	/// Return whether updates are enabled.
 	bool IsUpdateEnabled() const { return updateEnabled_; }
@@ -217,8 +211,6 @@ public:
 
 	/// Return a node user variable name, or empty if not registered.
 	const String& GetVarName(StringHash hash) const;
-	/// Return a node tag name, or empty if not registered.
-	const String& GetTagName(StringHash tag) const;
 
     /// Update scene. Called by HandleUpdate.
     void Update(float timeStep);
@@ -236,8 +228,12 @@ public:
     unsigned GetFreeNodeID(CreateMode mode);
     /// Get free component ID, either non-local or local.
     unsigned GetFreeComponentID(CreateMode mode);
+
+	/// Cache node by tag if tag not zero, no checking if already added. Used internaly in Node::AddTag.
+	void NodeTagAdded(Node* node, const String& tag);
 	/// Cache node by tag if tag not zero.
-	void NodeTagChanged(Node* node, StringHash oldTag);
+	void NodeTagRemoved(Node* node, const String& tag);
+
     /// Node added. Assign scene pointer and add to ID map.
     void NodeAdded(Node* node);
     /// Node removed. Remove from ID map.
@@ -250,10 +246,6 @@ public:
     void SetVarNamesAttr(const String& value);
     /// Return node user variable reverse mappings.
     String GetVarNamesAttr() const;
-	/// Set node tag reverse mappings.
-	void SetTagNamesAttr(const String& value);
-	/// Return node tag reverse mappings.
-	String GetTagNamesAttr() const;
     /// Prepare network update by comparing attributes and marking replication states dirty as necessary.
     void PrepareNetworkUpdate();
     /// Clean up all references to a network connection that is about to be removed.
@@ -305,8 +297,6 @@ private:
     Vector<SharedPtr<PackageFile> > requiredPackageFiles_;
     /// Registered node user variable reverse mappings.
     HashMap<StringHash, String> varNames_;
-	/// Registered node tag reverse mappings.
-	HashMap<StringHash, String> tagNames_;
     /// Nodes to check for attribute changes on the next network update.
     HashSet<unsigned> networkUpdateNodes_;
     /// Components to check for attribute changes on the next network update.

+ 11 - 4
Source/Urho3D/Scene/SceneEvents.h

@@ -156,13 +156,20 @@ URHO3D_EVENT(E_NODEENABLEDCHANGED, NodeEnabledChanged)
     URHO3D_PARAM(P_NODE, Node);                    // Node pointer
 }
 
-/// A node's tag has changed.
-URHO3D_EVENT(E_NODETAGCHANGED, NodeTagChanged)
+/// A node's tag has been added.
+URHO3D_EVENT(E_NODETAGADDED, NodeTagAdded)
 {
 	URHO3D_PARAM(P_SCENE, Scene);					// Scene pointer
 	URHO3D_PARAM(P_NODE, Node);						// Node pointer
-	URHO3D_PARAM(P_TAG, Tag);						// StringHash tag
-	URHO3D_PARAM(P_OLDTAG, Tag);					// StringHash tag
+	URHO3D_PARAM(P_TAG, Tag);						// String tag
+}
+
+/// A node's tag has been removed.
+URHO3D_EVENT(E_NODETAGREMOVED, NodeTagRemoved)
+{
+	URHO3D_PARAM(P_SCENE, Scene);					// Scene pointer
+	URHO3D_PARAM(P_NODE, Node);						// Node pointer
+	URHO3D_PARAM(P_TAG, Tag);						// String tag
 }
 
 /// A component's enabled state has changed.