Browse Source

Support source XMLElement being passed to Object factory for custom behaviors, update JSComponent

Josh Engebretson 10 years ago
parent
commit
e7ebcef16f

+ 0 - 2
Script/TypeScript/Atomic.d.ts

@@ -1408,8 +1408,6 @@ declare module Atomic {
       // Construct.
       constructor();
 
-      // Create an object by type hash. Return pointer to it or null if no factory found.
-      createObject(objectType: string): AObject;
       // Register a subsystem.
       registerSubsystem(subsystem: AObject): void;
       // Remove a subsystem.

+ 2 - 2
Source/Atomic/Core/Context.cpp

@@ -84,11 +84,11 @@ Context::~Context()
     eventDataMaps_.Clear();
 }
 
-SharedPtr<Object> Context::CreateObject(StringHash objectType)
+SharedPtr<Object> Context::CreateObject(StringHash objectType, const XMLElement& source)
 {
     HashMap<StringHash, SharedPtr<ObjectFactory> >::ConstIterator i = factories_.Find(objectType);
     if (i != factories_.End())
-        return i->second_->CreateObject();
+        return i->second_->CreateObject(source);
     else
         return SharedPtr<Object>();
 }

+ 2 - 12
Source/Atomic/Core/Context.h

@@ -25,6 +25,7 @@
 #include "../Core/Attribute.h"
 #include "../Core/Object.h"
 #include "../Container/HashSet.h"
+#include "../Resource/XMLElement.h"
 
 namespace Atomic
 {
@@ -41,7 +42,7 @@ public:
     ~Context();
 
     /// Create an object by type hash. Return pointer to it or null if no factory found.
-    SharedPtr<Object> CreateObject(StringHash objectType);
+    SharedPtr<Object> CreateObject(StringHash objectType, const XMLElement &source = XMLElement::EMPTY);
     /// Register a factory for an object type.
     void RegisterFactory(ObjectFactory* factory);
     /// Register a factory for an object type and specify the object category.
@@ -145,17 +146,6 @@ public:
     // ATOMIC BEGIN
     /// Get whether an Editor Context
     void SetEditorContent(bool editor) { editorContext_ = editor; }
-
-    /// Return a user variable.
-    Variant& GetVar(StringHash key) { return vars_[key]; }
-    /// Return all user variables.
-    VariantMap& GetVars() { return vars_; }
-
-protected:
-
-    /// User variables.
-    VariantMap vars_;
-
     // ATOMIC END
 
 private:

+ 3 - 2
Source/Atomic/Core/Object.h

@@ -24,6 +24,7 @@
 
 #include "../Container/LinkedList.h"
 #include "../Core/Variant.h"
+#include "../Resource/XMLElement.h"
 
 namespace Atomic
 {
@@ -144,7 +145,7 @@ public:
     }
 
     /// Create an object. Implemented in templated subclasses.
-    virtual SharedPtr<Object> CreateObject() = 0;
+    virtual SharedPtr<Object> CreateObject(const XMLElement& source = XMLElement::EMPTY) = 0;
 
     /// Return execution context.
     Context* GetContext() const { return context_; }
@@ -183,7 +184,7 @@ public:
     }
 
     /// Create an object of the specific type.
-    virtual SharedPtr<Object> CreateObject() { return SharedPtr<Object>(new T(context_)); }
+    virtual SharedPtr<Object> CreateObject(const XMLElement& source = XMLElement::EMPTY) { return SharedPtr<Object>(new T(context_)); }
 };
 
 /// Internal helper class for invoking event handler functions.

+ 9 - 42
Source/Atomic/Scene/Node.cpp

@@ -685,6 +685,11 @@ void Node::RemoveChildren(bool removeReplicated, bool removeLocal, bool recursiv
 }
 
 Component* Node::CreateComponent(StringHash type, CreateMode mode, unsigned id)
+{
+    return CreateComponentInternal(type, mode, id);
+}
+
+Component* Node::CreateComponentInternal(StringHash type, CreateMode mode, unsigned id, const XMLElement& source)
 {
     // Do not attempt to create replicated components to local nodes, as that may lead to component ID overwrite
     // as replicated components are synced over
@@ -692,7 +697,7 @@ Component* Node::CreateComponent(StringHash type, CreateMode mode, unsigned id)
         mode = LOCAL;
 
     // Check that creation succeeds and that the object in fact is a component
-    SharedPtr<Component> newComponent = DynamicCast<Component>(context_->CreateObject(type));
+    SharedPtr<Component> newComponent = DynamicCast<Component>(context_->CreateObject(type, source));
     if (!newComponent)
     {
         LOGERROR("Could not create unknown component type " + type.ToString());
@@ -1239,46 +1244,8 @@ bool Node::LoadXML(const XMLElement& source, SceneResolver& resolver, bool readC
         String typeName = compElem.GetAttribute("type");
         unsigned compID = compElem.GetInt("id");
 
-        // ATOMIC BEGIN
-        // At runtime, a XML JSComponent may refer to a "scriptClass"
-        // component which is new'd in JS and creates the component itself
-        // we peek ahead here to see if we have a JSComponentFile and store
-        // it off in the Context vars, for the specialized JSComponent object factory to use
-        // when creating the component
-        if (!context_->GetEditorContext())
-        {
-            // at runtime peek ahead to see if we have a ComponentFile attr
-            if (typeName == "JSComponent")
-            {
-                XMLElement attrElem = compElem.GetChild("attribute");
-
-                while (attrElem)
-                {
-                    if (attrElem.GetAttribute("name") == "ComponentFile")
-                    {
-                        String componentFile = attrElem.GetAttribute("value");
-
-                        if (componentFile.Length())
-                        {
-                            // store in context vars
-                            context_->GetVars()["__JSComponent_ComponentFile"] = componentFile;
-                            break;
-                        }
-                    }
-
-                    attrElem = attrElem.GetNext("attribute");
-                }
-            }
-        }
-        // ATOMIC END
-
         Component* newComponent = SafeCreateComponent(typeName, StringHash(typeName),
-            (mode == REPLICATED && compID < FIRST_LOCAL_ID) ? REPLICATED : LOCAL, rewriteIDs ? 0 : compID);
-
-        // ATOMIC BEGIN
-        // ensure component file, if any, is cleared
-        context_->GetVars()["__JSComponent_ComponentFile"] = Variant::EMPTY;
-        // ATOMIC END
+            (mode == REPLICATED && compID < FIRST_LOCAL_ID) ? REPLICATED : LOCAL, rewriteIDs ? 0 : compID, compElem);
 
         if (newComponent)
         {
@@ -1681,7 +1648,7 @@ void Node::SetEnabled(bool enable, bool recursive, bool storeSelf)
     }
 }
 
-Component* Node::SafeCreateComponent(const String& typeName, StringHash type, CreateMode mode, unsigned id)
+Component* Node::SafeCreateComponent(const String& typeName, StringHash type, CreateMode mode, unsigned id, const Atomic::XMLElement &source)
 {
     // Do not attempt to create replicated components to local nodes, as that may lead to component ID overwrite
     // as replicated components are synced over
@@ -1690,7 +1657,7 @@ Component* Node::SafeCreateComponent(const String& typeName, StringHash type, Cr
 
     // First check if factory for type exists
     if (!context_->GetTypeName(type).Empty())
-        return CreateComponent(type, mode, id);
+        return CreateComponentInternal(type, mode, id, source);
     else
     {
         LOGWARNING("Component type " + type.ToString() + " not known, creating UnknownComponent as placeholder");

+ 4 - 1
Source/Atomic/Scene/Node.h

@@ -25,6 +25,7 @@
 #include "../IO/VectorBuffer.h"
 #include "../Math/Matrix3x4.h"
 #include "../Scene/Animatable.h"
+#include "../Resource/XMLElement.h"
 
 namespace Atomic
 {
@@ -576,8 +577,10 @@ protected:
 private:
     /// Set enabled/disabled state with optional recursion. Optionally affect the remembered enable state.
     void SetEnabled(bool enable, bool recursive, bool storeSelf);
+    /// Internal call for creating component
+    Component* CreateComponentInternal(StringHash type, CreateMode mode = REPLICATED, unsigned id = 0, const XMLElement& source = XMLElement::EMPTY);
     /// Create component, allowing UnknownComponent if actual type is not supported. Leave typeName empty if not known.
-    Component* SafeCreateComponent(const String& typeName, StringHash type, CreateMode mode, unsigned id);
+    Component* SafeCreateComponent(const String& typeName, StringHash type, CreateMode mode, unsigned id, const XMLElement& source = XMLElement::EMPTY);
     /// Recalculate the world transform.
     void UpdateWorldTransform() const;
     /// Remove child node by iterator.

+ 0 - 3
Source/AtomicEditorWork/Editors/SceneEditor3D/SceneView3D.cpp

@@ -520,9 +520,6 @@ void SceneView3D::HandleDragExitWidget(StringHash eventType, VariantMap& eventDa
 
     if (dragNode_.NotNull())
     {
-        // BUG! https://github.com/urho3d/Urho3D/issues/748
-        dragNode_->RemoveAllComponents();
-
         scene_->RemoveChild(dragNode_);
         VariantMap neventData;
         neventData[EditorActiveNodeChange::P_NODE] = (RefCounted*) 0;

+ 47 - 25
Source/AtomicJS/Javascript/JSComponent.cpp

@@ -58,34 +58,48 @@ public:
     }
 
     /// Create an object of the specific type.
-    SharedPtr<Object> CreateObject()
+    SharedPtr<Object> CreateObject(const XMLElement& source = XMLElement::EMPTY)
     {
-        SharedPtr<Object> ptr;
 
-        Variant& v = context_->GetVar("__JSComponent_ComponentFile");
+        // if in editor, just create the JSComponent
+        if (context_->GetEditorContext())
+        {
+            return SharedPtr<Object>(new JSComponent(context_));
+        }
+
+        // At runtime, a XML JSComponent may refer to a "scriptClass"
+        // component which is new'd in JS and creates the component itself
+        // we peek ahead here to see if we have a JSComponentFile and if it is a script class
+
+        String componentRef;
 
-        // __JSComponent_ComponentFile will only be set when coming from XML
-        // in player builds, not in editor
-        if (v.GetType() == VAR_STRING)
+        if (source != XMLElement::EMPTY)
         {
-            String componentRef = v.GetString();
+            XMLElement attrElem = source.GetChild("attribute");
 
-            // clear it, in case we end up recursively creating components
-            context_->GetVars()["__JSComponent_ComponentFile"] = Variant::EMPTY;
+            while (attrElem)
+            {
+                if (attrElem.GetAttribute("name") == "ComponentFile")
+                {
+                    componentRef = attrElem.GetAttribute("value");
+                    break;
+                }
 
+                attrElem = attrElem.GetNext("attribute");
+            }
+        }
+
+        SharedPtr<Object> ptr;
+
+        if (componentRef.Length())
+        {
             Vector<String> split = componentRef.Split(';');
 
             if (split.Size() == 2)
             {
                 ResourceCache* cache = context_->GetSubsystem<ResourceCache>();
-
                 JSComponentFile* componentFile = cache->GetResource<JSComponentFile>(split[1]);
-
-                if (componentFile)
-                {
-                    ptr = componentFile->CreateJSComponent();
-                }
-
+                ptr = componentFile->CreateJSComponent();
             }
 
         }
@@ -367,8 +381,7 @@ void JSComponent::OnNodeSet(Node* node)
 {
     if (node)
     {
-        // We have been attached to a node. Set initial update event subscription state
-        UpdateEventSubscription();
+
     }
     else
     {
@@ -378,18 +391,27 @@ void JSComponent::OnNodeSet(Node* node)
     }
 }
 
-void JSComponent::UpdateEventSubscription()
+void JSComponent::OnSceneSet(Scene* scene)
 {
-    // If scene node is not assigned yet, no need to update subscription
-    if (!node_)
-        return;
+    if (scene)
+        UpdateEventSubscription();
+    else
+    {
+        UnsubscribeFromEvent(E_SCENEUPDATE);
+        UnsubscribeFromEvent(E_SCENEPOSTUPDATE);
+#ifdef ATOMIC_PHYSICS
+        UnsubscribeFromEvent(E_PHYSICSPRESTEP);
+        UnsubscribeFromEvent(E_PHYSICSPOSTSTEP);
+#endif
+        currentEventMask_ = 0;
+    }
+}
 
+void JSComponent::UpdateEventSubscription()
+{
     Scene* scene = GetScene();
     if (!scene)
-    {
-        LOGWARNING("Node is detached from scene, can not subscribe to update events");
         return;
-    }
 
     bool enabled = IsEnabledEffective();
 

+ 2 - 0
Source/AtomicJS/Javascript/JSComponent.h

@@ -92,6 +92,8 @@ public:
 protected:
     /// Handle scene node being assigned at creation.
     virtual void OnNodeSet(Node* node);
+    /// Handle scene being assigned.
+    virtual void OnSceneSet(Scene* scene);
 
 private:
     /// Subscribe/unsubscribe to update events based on current enabled state and update event mask.