Node* Node::CloneRecursive(Node* parent, SceneResolver& resolver, CreateMode mode) { // Create clone node Node* cloneNode = parent->CreateChild(0, (mode == REPLICATED && id_ < FIRST_LOCAL_ID) ? REPLICATED : LOCAL); resolver.AddNode(id_, cloneNode); // Copy attributes const Vector<AttributeInfo>* attributes = GetAttributes(); for (unsigned j = 0; j < attributes->Size(); ++j) { const AttributeInfo& attr = attributes->At(j); // Do not copy network-only attributes, as they may have unintended side effects if (attr.mode_ & AM_FILE) cloneNode->SetAttribute(j, GetAttribute(j)); } // Clone components for (Vector<SharedPtr<Component> >::ConstIterator i = components_.Begin(); i != components_.End(); ++i) { Component* component = *i; Component* cloneComponent = cloneNode->SafeCreateComponent(component->GetTypeName(), component->GetType(), (mode == REPLICATED && component->GetID() < FIRST_LOCAL_ID) ? REPLICATED : LOCAL, 0); if (!cloneComponent) { LOGERROR("Could not clone component " + component->GetTypeName()); continue; } resolver.AddComponent(component->GetID(), cloneComponent); const Vector<AttributeInfo>* compAttributes = component->GetAttributes(); if (compAttributes) { for (unsigned j = 0; j < compAttributes->Size(); ++j) { const AttributeInfo& attr = compAttributes->At(j); if (attr.mode_ & AM_FILE) cloneComponent->SetAttribute(j, component->GetAttribute(j)); } } } // Clone child nodes recursively for (Vector<SharedPtr<Node> >::ConstIterator i = children_.Begin(); i != children_.End(); ++i) { Node* node = *i; node->CloneRecursive(cloneNode, resolver, mode); } return cloneNode; }
Component* Node::CloneComponent(Component* component, CreateMode mode, unsigned id) { if (!component) { LOGERROR("Null source component given for CloneComponent"); return 0; } Component* cloneComponent = SafeCreateComponent(component->GetTypeName(), component->GetType(), mode, 0); if (!cloneComponent) { LOGERROR("Could not clone component " + component->GetTypeName()); return 0; } const Vector<AttributeInfo>* compAttributes = component->GetAttributes(); const Vector<AttributeInfo>* cloneAttributes = cloneComponent->GetAttributes(); if (compAttributes) { for (unsigned i = 0; i < compAttributes->Size() && i < cloneAttributes->Size(); ++i) { const AttributeInfo& attr = compAttributes->At(i); const AttributeInfo& cloneAttr = cloneAttributes->At(i); if (attr.mode_ & AM_FILE) { Variant value; component->OnGetAttribute(attr, value); // Note: when eg. a ScriptInstance component is cloned, its script object attributes are unique and therefore we // can not simply refer to the source component's AttributeInfo cloneComponent->OnSetAttribute(cloneAttr, value); } } cloneComponent->ApplyAttributes(); } return cloneComponent; }
void SceneResolver::Resolve() { // Nodes do not have component or node ID attributes, so only have to go through components ea::hash_set<StringHash> noIDAttributes; for (auto i = components_.begin(); i != components_.end(); ++i) { Component* component = i->second; if (!component || noIDAttributes.contains(component->GetType())) continue; bool hasIDAttributes = false; const ea::vector<AttributeInfo>* attributes = component->GetAttributes(); if (!attributes) { noIDAttributes.insert(component->GetType()); continue; } for (unsigned j = 0; j < attributes->size(); ++j) { const AttributeInfo& info = attributes->at(j); if (info.mode_ & AM_NODEID) { hasIDAttributes = true; unsigned oldNodeID = component->GetAttribute(j).GetUInt(); if (oldNodeID) { auto k = nodes_.find(oldNodeID); if (k != nodes_.end() && k->second) { unsigned newNodeID = k->second->GetID(); component->SetAttribute(j, Variant(newNodeID)); } else URHO3D_LOGWARNING("Could not resolve node ID " + ea::to_string(oldNodeID)); } } else if (info.mode_ & AM_COMPONENTID) { hasIDAttributes = true; unsigned oldComponentID = component->GetAttribute(j).GetUInt(); if (oldComponentID) { auto k = components_.find( oldComponentID); if (k != components_.end() && k->second) { unsigned newComponentID = k->second->GetID(); component->SetAttribute(j, Variant(newComponentID)); } else URHO3D_LOGWARNING("Could not resolve component ID " + ea::to_string(oldComponentID)); } } else if (info.mode_ & AM_NODEIDVECTOR) { hasIDAttributes = true; Variant attrValue = component->GetAttribute(j); const VariantVector& oldNodeIDs = attrValue.GetVariantVector(); if (oldNodeIDs.size()) { // The first index stores the number of IDs redundantly. This is for editing unsigned numIDs = oldNodeIDs[0].GetUInt(); VariantVector newIDs; newIDs.push_back(numIDs); for (unsigned k = 1; k < oldNodeIDs.size(); ++k) { unsigned oldNodeID = oldNodeIDs[k].GetUInt(); auto l = nodes_.find(oldNodeID); if (l != nodes_.end() && l->second) newIDs.push_back(l->second->GetID()); else { // If node was not found, retain number of elements, just store ID 0 newIDs.push_back(0); URHO3D_LOGWARNING("Could not resolve node ID " + ea::to_string(oldNodeID)); } } component->SetAttribute(j, newIDs); } } } // If component type had no ID attributes, cache this fact for optimization if (!hasIDAttributes) noIDAttributes.insert(component->GetType()); } // Attributes have been resolved, so no need to remember the nodes after this Reset(); }
void SceneResolver::Resolve() { // Nodes do not have component or node ID attributes, so only have to go through components HashSet<StringHash> noIDAttributes; for (HashMap<unsigned, WeakPtr<Component> >::ConstIterator i = components_.Begin(); i != components_.End(); ++i) { Component* component = i->second_; if (!component || noIDAttributes.Contains(component->GetType())) continue; bool hasIDAttributes = false; const Vector<AttributeInfo>* attributes = component->GetAttributes(); if (!attributes) { noIDAttributes.Insert(component->GetType()); continue; } for (unsigned j = 0; j < attributes->Size(); ++j) { const AttributeInfo& info = attributes->At(j); if (info.mode_ & AM_NODEID) { hasIDAttributes = true; unsigned oldNodeID = component->GetAttribute(j).GetUInt(); if (oldNodeID) { HashMap<unsigned, WeakPtr<Node> >::ConstIterator k = nodes_.Find(oldNodeID); if (k != nodes_.End() && k->second_) { unsigned newNodeID = k->second_->GetID(); component->SetAttribute(j, Variant(newNodeID)); } else URHO3D_LOGWARNING("Could not resolve node ID " + String(oldNodeID)); } } else if (info.mode_ & AM_COMPONENTID) { hasIDAttributes = true; unsigned oldComponentID = component->GetAttribute(j).GetUInt(); if (oldComponentID) { HashMap<unsigned, WeakPtr<Component> >::ConstIterator k = components_.Find(oldComponentID); if (k != components_.End() && k->second_) { unsigned newComponentID = k->second_->GetID(); component->SetAttribute(j, Variant(newComponentID)); } else URHO3D_LOGWARNING("Could not resolve component ID " + String(oldComponentID)); } } else if (info.mode_ & AM_NODEIDVECTOR) { hasIDAttributes = true; const VariantVector& oldNodeIDs = component->GetAttribute(j).GetVariantVector(); if (oldNodeIDs.Size()) { // The first index stores the number of IDs redundantly. This is for editing unsigned numIDs = oldNodeIDs[0].GetUInt(); VariantVector newIDs; newIDs.Push(numIDs); for (unsigned k = 1; k < oldNodeIDs.Size(); ++k) { unsigned oldNodeID = oldNodeIDs[k].GetUInt(); HashMap<unsigned, WeakPtr<Node> >::ConstIterator l = nodes_.Find(oldNodeID); if (l != nodes_.End() && l->second_) newIDs.Push(l->second_->GetID()); else { // If node was not found, retain number of elements, just store ID 0 newIDs.Push(0); URHO3D_LOGWARNING("Could not resolve node ID " + String(oldNodeID)); } } component->SetAttribute(j, newIDs); } } } // If component type had no ID attributes, cache this fact for optimization if (!hasIDAttributes) noIDAttributes.Insert(component->GetType()); } // Attributes have been resolved, so no need to remember the nodes after this Reset(); }