Browse Source

Working on prefabs

Josh Engebretson 10 years ago
parent
commit
f4b0ca5ac5

+ 3 - 0
Script/AtomicEditor/ui/HierarchyFrame.ts

@@ -33,6 +33,9 @@ class HierarchyFrame extends Atomic.UIWidget {
 
     recursiveAddNode(parentID: number, node: Atomic.Node) {
 
+        //if (node.isTemporary())
+        //  return;
+
         var name = node.name;
 
         if (!name.length)

+ 73 - 7
Script/AtomicEditor/ui/inspector/NodeInspector.ts

@@ -20,10 +20,10 @@ class NodeInspector extends ScriptWidget {
         if (data.key == 27) {
 
             if (this.nodeLayout) {
-            this.sendEvent("EditorActiveNodeChange", { node: null });
-            this.nodeLayout.deleteAllChildren();
-            this.nodeLayout = null;
-          }
+                this.sendEvent("EditorActiveNodeChange", { node: null });
+                this.nodeLayout.deleteAllChildren();
+                this.nodeLayout = null;
+            }
         }
 
         if (data.key == 92) {
@@ -36,7 +36,7 @@ class NodeInspector extends ScriptWidget {
                 this.nodeLayout = null;
                 this.node.removeComponents(true, true);
                 if (this.node.parent)
-                  this.node.parent.removeChild(this.node);
+                    this.node.parent.removeChild(this.node);
                 this.node = null;
                 this.sendEvent("EditorActiveNodeChange", { node: null });
                 this.sendEvent("EditorUpdateHierarchy", {});
@@ -66,11 +66,37 @@ class NodeInspector extends ScriptWidget {
 
     }
 
+    getPrefabComponent(node: Atomic.Node):Atomic.PrefabComponent {
+
+      if (node.parent && node.parent.getComponent("PrefabComponent"))
+        return <Atomic.PrefabComponent> node.parent.getComponent("PrefabComponent");
+
+      if (node.parent)
+          return this.getPrefabComponent(node.parent);
+
+        return null;
+
+    }
+
+    detectPrefab(node: Atomic.Node): boolean {
+
+      if (node.parent && node.parent.getComponent("PrefabComponent"))
+        return true;
+
+      if (node.parent)
+          return this.detectPrefab(node.parent);
+
+        return false;
+
+    }
+
 
     inspect(node: Atomic.Node) {
 
         this.node = node;
 
+        this.isPrefab = this.detectPrefab(node);
+
         var fd = new Atomic.UIFontDescription();
         fd.id = "Vera";
         fd.size = 11;
@@ -91,8 +117,6 @@ class NodeInspector extends ScriptWidget {
         var nodeSection = new Atomic.UISection();
         nodeSection.text = "Node";
         nodeSection.value = 1;
-        //nodeSection.textAlign = Atomic.UI_TEXT_ALIGN_LEFT;
-        //nodeSection.skinBg = "InspectorTextLabel";
         nodeLayout.addChild(nodeSection);
 
         var attrsVerticalLayout = new Atomic.UILayout(Atomic.UI_AXIS_Y);
@@ -150,6 +174,47 @@ class NodeInspector extends ScriptWidget {
 
         }
 
+        // PREFAB
+
+        if (this.isPrefab) {
+
+          var name = new Atomic.UITextField();
+          name.textAlign = Atomic.UI_TEXT_ALIGN_LEFT;
+          name.skinBg = "InspectorTextAttrName";
+          name.text = "Prefab"
+          name.fontDescription = fd;
+
+          var prefabLayout = new Atomic.UILayout();
+          prefabLayout.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION_GRAVITY;
+
+          var saveButton = new Atomic.UIButton();
+          saveButton.text = "Save";
+          saveButton.fontDescription = fd;
+
+          saveButton.onClick = function() {
+
+            var prefabComponent = this.getPrefabComponent(this.node);
+
+            if (prefabComponent) {
+              prefabComponent.savePrefab();
+            }
+
+          }.bind(this);
+
+          var undoButton = new Atomic.UIButton();
+          undoButton.text = "Undo";
+          undoButton.fontDescription = fd;
+
+          prefabLayout.addChild(name);
+          prefabLayout.addChild(saveButton);
+          prefabLayout.addChild(undoButton);
+
+          attrsVerticalLayout.addChild(prefabLayout);
+
+        }
+
+        // COMPONENTS
+
         var components = node.getComponents();
 
         for (var i in components) {
@@ -175,6 +240,7 @@ class NodeInspector extends ScriptWidget {
 
     }
 
+    isPrefab:boolean;
     node: Atomic.Node;
     nodeLayout: Atomic.UILayout;
     bindings: Array<DataBinding> = new Array();

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

@@ -1807,6 +1807,21 @@ declare module Atomic {
 
    }
 
+   export class PrefabComponent extends Component {
+
+      prefabGUID: string;
+      prefabNode: Node;
+
+      // Construct.
+      constructor();
+
+      setPrefabGUID(guid: string): void;
+      getPrefabGUID(): string;
+      savePrefab(): boolean;
+      getPrefabNode(): Node;
+
+   }
+
    export class Scene extends Node {
 
       updateEnabled: boolean;

+ 86 - 0
Source/Atomic/Scene/PrefabComponent.cpp

@@ -0,0 +1,86 @@
+
+#include <Atomic/Core/Context.h>
+#include <Atomic/Scene/Node.h>
+#include <Atomic/Resource/XMLFile.h>
+#include <Atomic/Resource/ResourceCache.h>
+#include <Atomic/Resource/ResourceEvents.h>
+
+#include "PrefabEvents.h"
+#include "PrefabComponent.h"
+
+
+namespace Atomic
+{
+
+PrefabComponent::PrefabComponent(Context* context) :
+    Component(context)
+{
+
+}
+
+PrefabComponent::~PrefabComponent()
+{
+
+}
+
+bool PrefabComponent::SavePrefab()
+{    
+    using namespace PrefabSave;
+    VariantMap eventData;
+    eventData[P_PREFABCOMPONENT] = this;
+    SendEvent(E_PREFABSAVE, eventData);
+    return true;
+}
+
+void PrefabComponent::RegisterObject(Context* context)
+{
+    context->RegisterFactory<PrefabComponent>();
+
+    ACCESSOR_ATTRIBUTE("PrefabGUID", GetPrefabGUID, SetPrefabGUID, String, String::EMPTY, AM_FILE | AM_NOEDIT);
+}
+
+void PrefabComponent::HandleReloadFinished(StringHash eventType, VariantMap& eventData)
+{
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+    XMLFile* xmlfile = cache->GetResource<XMLFile>(prefabGUID_);
+
+    prefabNode_->LoadXML(xmlfile->GetRoot());
+    prefabNode_->SetTemporary(true);
+
+}
+
+void PrefabComponent::SetPrefabGUID(const String& guid)
+{
+    assert(prefabNode_.Null());
+
+    // ensure to use node_->CreateChild() so in scene, this may be fixed
+    // with update on https://github.com/urho3d/Urho3D/issues/748
+    assert(node_);
+
+    prefabGUID_ = guid;
+    prefabNode_ = node_->CreateChild();
+
+    if (prefabGUID_.Length())
+    {
+        ResourceCache* cache = GetSubsystem<ResourceCache>();
+        XMLFile* xmlfile = cache->GetResource<XMLFile>(prefabGUID_);
+
+        SubscribeToEvent(xmlfile, E_RELOADFINISHED, HANDLER(PrefabComponent, HandleReloadFinished));
+
+        if (xmlfile)
+        {
+            prefabNode_->LoadXML(xmlfile->GetRoot());
+        }
+    }
+
+    prefabNode_->SetName(prefabNode_->GetName() + "_Prefab");
+    prefabNode_->SetTemporary(true);
+
+}
+
+void PrefabComponent::OnNodeSet(Node* node)
+{
+    Component::OnNodeSet(node);
+}
+
+}

+ 47 - 0
Source/Atomic/Scene/PrefabComponent.h

@@ -0,0 +1,47 @@
+
+
+#pragma once
+
+#include "../Scene/Component.h"
+
+namespace Atomic
+{
+
+/// Helper base class for user-defined game logic components that hooks up to update events and forwards them to virtual functions similar to ScriptInstance class.
+class PrefabComponent : public Component
+{
+    OBJECT(PrefabComponent);
+
+public:
+
+    /// Construct.
+    PrefabComponent(Context* context);
+    /// Destruct.
+    virtual ~PrefabComponent();
+
+    /// Register object factory.
+    static void RegisterObject(Context* context);
+
+    void SetPrefabGUID(const String& guid);
+    const String& GetPrefabGUID() const { return prefabGUID_; }
+
+    bool SavePrefab();
+
+    Node* GetPrefabNode() { return prefabNode_; }
+
+protected:
+
+    /// Handle scene node being assigned at creation.
+    virtual void OnNodeSet(Node* node);
+
+
+private:
+
+    void HandleReloadFinished(StringHash eventType, VariantMap& eventData);
+
+    SharedPtr<Node> prefabNode_;
+    String prefabGUID_;
+
+};
+
+}

+ 19 - 0
Source/Atomic/Scene/PrefabEvents.h

@@ -0,0 +1,19 @@
+
+
+#include "../Core/Object.h"
+
+namespace Atomic
+{
+
+EVENT(E_PREFABSAVE, PrefabSave)
+{
+    PARAM(P_PREFABCOMPONENT, PrefabComponent); // PrefabComponent Pointer
+}
+
+EVENT(E_PREFABCHANGED, PrefabChanged)
+{
+    PARAM(P_PREFABCOMPONENT, PrefabComponent); // PrefabComponent Pointer
+    PARAM(P_NODE, Node); // Node Pointer
+}
+
+}

+ 3 - 0
Source/Atomic/Scene/Scene.cpp

@@ -41,6 +41,8 @@
 #include "../Core/WorkQueue.h"
 #include "../Resource/XMLFile.h"
 
+#include "../Scene/PrefabComponent.h"
+
 #include "../DebugNew.h"
 
 namespace Atomic
@@ -1233,6 +1235,7 @@ void RegisterSceneLibrary(Context* context)
     SmoothedTransform::RegisterObject(context);
     UnknownComponent::RegisterObject(context);
     SplinePath::RegisterObject(context);
+    PrefabComponent::RegisterObject(context);
 }
 
 }

+ 23 - 0
Source/Atomic/UI/UIWidget.cpp

@@ -568,6 +568,29 @@ bool UIWidget::OnEvent(const tb::TBWidgetEvent &ev)
         }
 
     }
+    else if (ev.type == EVENT_TYPE_POINTER_DOWN)
+    {
+        /*
+        if (ev.target)
+        {
+            TBWidget* tbwidget = ev.target;
+
+            while (tbwidget && !ui->IsWidgetWrapped(tbwidget))
+                tbwidget = tbwidget->GetParent();
+
+            if (tbwidget)
+            {
+                VariantMap eventData;
+                ConvertEvent(this, ui->WrapWidget(tbwidget), ev, eventData);
+                SendEvent(E_WIDGETEVENT, eventData);
+
+                if (eventData[WidgetEvent::P_HANDLED].GetBool())
+                    return true;
+
+            }
+        }
+        */
+    }
     else if (ev.type == EVENT_TYPE_TAB_CHANGED)
     {
         if (!ev.target || ui->IsWidgetWrapped(ev.target))

+ 4 - 13
Source/AtomicEditorWork/Editors/SceneEditor3D/SceneView3D.cpp

@@ -8,6 +8,7 @@
 #include <Atomic/IO/Log.h>
 #include <Atomic/Core/CoreEvents.h>
 #include <Atomic/Scene/Scene.h>
+#include <Atomic/Scene/PrefabComponent.h>
 #include <Atomic/Graphics/Camera.h>
 
 #include <Atomic/Graphics/Graphics.h>
@@ -447,9 +448,6 @@ void SceneView3D::HandleDragEnterWidget(StringHash eventType, VariantMap& eventD
     if (object->GetType() == Asset::GetTypeStatic())
     {
         Asset* asset = (Asset*) object;
-
-        AssetDatabase* db = GetSubsystem<AssetDatabase>();
-
         AssetImporter* importer = asset->GetImporter();
 
         if (!importer)
@@ -460,15 +458,8 @@ void SceneView3D::HandleDragEnterWidget(StringHash eventType, VariantMap& eventD
         if (importerType == PrefabImporter::GetTypeStatic())
         {
             dragNode_ = scene_->CreateChild(asset->GetName());
-
-            SharedPtr<File> file(new File(context_, asset->GetPath()));
-            SharedPtr<XMLFile> xml(new XMLFile(context_));
-
-            if (!xml->Load(*file))
-                return;
-
-            dragNode_->LoadXML(xml->GetRoot());
-
+            PrefabComponent* pc = dragNode_->CreateComponent<PrefabComponent>();
+            pc->SetPrefabGUID(asset->GetGUID());
             dragNode_->SetName(asset->GetName());
 
         }
@@ -486,7 +477,7 @@ void SceneView3D::HandleDragEnterWidget(StringHash eventType, VariantMap& eventD
             dragNode_->SetName(asset->GetName());
 
             /*
-            dragNode_ = scene_->CreateChild(asset->GetName());            
+            dragNode_ = scene_->CreateChild(asset->GetName());
             preloadResourceScene_ = new Scene(context_);
 
             SharedPtr<File> file(new File(context_, asset->GetCachePath()));

+ 1 - 1
Source/AtomicJS/Packages/Atomic/Scene.json

@@ -4,7 +4,7 @@
 	"includes" : ["<Atomic/Scene/LogicComponent.h>", "<Atomic/Network/Connection.h>"],
 	"classes" : ["Animatable", "Node", "Scene", "Component", "Serializable",
 				 "ObjectAnimation", "SmoothedTransform", "SplinePath",
-				 "ValueAnimation", "ValueAnimationInfo"],
+				 "ValueAnimation", "ValueAnimationInfo", "PrefabComponent"],
 	"overloads" : {
 		"Node" : {
 			"CreateChild" : ["String", "CreateMode", "unsigned"],

+ 27 - 7
Source/ToolCore/Assets/PrefabImporter.cpp

@@ -1,8 +1,10 @@
 
 #include <Atomic/Resource/ResourceCache.h>
 #include <Atomic/Resource/Image.h>
-
 #include <Atomic/Scene/Scene.h>
+#include <Atomic/Scene/PrefabEvents.h>
+#include <Atomic/Scene/PrefabComponent.h>
+#include <Atomic/IO/FileSystem.h>
 
 #include "Asset.h"
 #include "AssetDatabase.h"
@@ -13,7 +15,7 @@ namespace ToolCore
 
 PrefabImporter::PrefabImporter(Context* context, Asset* asset) : AssetImporter(context, asset)
 {
-    requiresCacheFile_ = false;
+    SubscribeToEvent(E_PREFABSAVE, HANDLER(PrefabImporter, HandlePrefabSave));
 }
 
 PrefabImporter::~PrefabImporter()
@@ -32,19 +34,37 @@ bool PrefabImporter::Preload()
         return false;
 
     preloadResourceScene_ = new Scene(context_);
-    SharedPtr<File> file(new File(context_, asset_->GetPath()));
+    SharedPtr<File> file(new File(context_, asset_->GetCachePath()));
     preloadResourceScene_->LoadAsyncXML(file, LOAD_RESOURCES_ONLY);
 
     return true;
 }
 
+void PrefabImporter::HandlePrefabSave(StringHash eventType, VariantMap& eventData)
+{
+    using namespace PrefabSave;
+
+    PrefabComponent* component = static_cast<PrefabComponent*>(eventData[P_PREFABCOMPONENT].GetPtr());
+
+    if (component->GetPrefabGUID() != asset_->GetGUID())
+        return;
+
+    Node* node = component->GetPrefabNode();
+
+    SharedPtr<File> file(new File(context_, asset_->GetPath(), FILE_WRITE));
+    node->SaveXML(*file);
+    file->Close();
+
+    FileSystem* fs = GetSubsystem<FileSystem>();
+    fs->Copy(asset_->GetPath(), asset_->GetCachePath());
+
+}
+
 bool PrefabImporter::Import(const String& guid)
 {
-    AssetDatabase* db = GetSubsystem<AssetDatabase>();
-    Asset* asset = db->GetAssetByGUID(guid);
+    FileSystem* fs = GetSubsystem<FileSystem>();
 
-    if (!asset)
-        return false;
+    fs->Copy(asset_->GetPath(), asset_->GetCachePath());
 
     return true;
 }

+ 2 - 0
Source/ToolCore/Assets/PrefabImporter.h

@@ -32,6 +32,8 @@ protected:
 
 private:
 
+    void HandlePrefabSave(StringHash eventType, VariantMap& eventData);
+
    SharedPtr<Atomic::Scene> preloadResourceScene_;
 
 };