Переглянути джерело

Improvements to enum handling, CSComponentAssembly type info now available at runtime (+1 squashed commits)

Squashed commits:

[84ae432] Work to serialize script enums via string instead of integer value, making them more robust for any changes to the associated enum.  Also, updates for editor scripts to edit enum attributes by value instead of index (which may not be accurate for some enums with duplicated entries, etc)
Josh Engebretson 8 роки тому
батько
коміт
5d8991f715

+ 11 - 5
Script/AtomicEditor/ui/frames/inspector/AttributeInfoEdit.ts

@@ -339,13 +339,19 @@ class IntAttributeEdit extends AttributeInfoEdit {
         if (uniform) {
             var object = this.editType.getFirstObject();
             if (object) {
-                var value = object.getAttribute(this.attrInfo.name, this.arrayIndex);
 
+                var value = object.getAttribute(this.attrInfo.name, this.arrayIndex);
                 var widget = this.editWidget;
                 var attrInfo = this.attrInfo;
 
                 if (attrInfo.enumNames.length) {
-                    widget.text = attrInfo.enumNames[value];
+
+                    if (attrInfo.enumValues.indexOf(value) != -1) {
+                        widget.text = attrInfo.enumNames[attrInfo.enumValues.indexOf(value)];
+                    } else {
+                        widget.text = attrInfo.enumNames[value];
+                    }
+                
                 }
                 else {
                     widget.text = value.toString();
@@ -381,10 +387,10 @@ class IntAttributeEdit extends AttributeInfoEdit {
             var id = this.attrInfo.name + " enum popup";
 
             if (ev.target.id == id) {
-
-                this.editType.onAttributeInfoEdited(this.attrInfo, Number(ev.refid) - 1, -1, true, this.arrayIndex);
+                let eindex =  Number(ev.refid) - 1;
+                let value = this.attrInfo.enumValues[eindex];
+                this.editType.onAttributeInfoEdited(this.attrInfo, value, -1, true, this.arrayIndex);
                 this.refresh();
-
             }
 
             else if (this.editWidget == ev.target && this.attrInfo.enumNames.length) {

+ 2 - 0
Script/AtomicNET/AtomicNET/Application/Application.cs

@@ -43,6 +43,8 @@ namespace AtomicEngine
             renderer.ShadowQuality = ShadowQuality.SHADOWQUALITY_SIMPLE_16BIT;
 #endif
 
+            CSComponentAssembly.PreloadClassAssemblies();
+
             appDelegate = (AppDelegate)Activator.CreateInstance(appDelegateType);
 
             try

+ 1 - 1
Script/AtomicNET/AtomicNET/Core/AtomicNET.cs

@@ -126,7 +126,7 @@ namespace AtomicEngine
             context = core.Context;            
 
             NativeCore.Initialize();
-            CSComponentCore.Initialize();
+            CSComponentCore.Initialize();            
 
 #if ATOMIC_DESKTOP
             string[] arguments = Environment.GetCommandLineArgs();

+ 1 - 0
Script/TypeScript/AtomicWork.d.ts

@@ -143,6 +143,7 @@ declare module Atomic {
         mode: number; // AM_*
         defaultValue: string;
         enumNames: string[];
+        enumValues: number[];
         resourceTypeName: string;
         dynamic: boolean;
         tooltip: string;

+ 4 - 4
Source/Atomic/Math/StringHash.cpp

@@ -78,18 +78,18 @@ String StringHash::ToString() const
 // ATOMIC BEGIN
 
 // Lookup for significant strings, not a member of StringHash so don't need to drag hashmap into header
-static HashMap<unsigned, String> gSignificantLookup;
+static HashMap<StringHash, String> gSignificantLookup;
 
 StringHash StringHash::RegisterSignificantString(const char* str)
 {
-    unsigned hash = Calculate(str);
+    StringHash hash(str);
 
     if (gSignificantLookup.Contains(hash))
         return StringHash(hash);
 
     gSignificantLookup[hash] = String(str);
 
-    return StringHash(hash);
+    return hash;
 
 }
 
@@ -98,7 +98,7 @@ StringHash StringHash::RegisterSignificantString(const String& str)
     return RegisterSignificantString(str.CString());
 }
 
-bool StringHash::GetSignificantString(unsigned hash, String& strOut)
+bool StringHash::GetSignificantString(StringHash hash, String& strOut)
 {
     if (!gSignificantLookup.TryGetValue(hash, strOut))
     {

+ 1 - 1
Source/Atomic/Math/StringHash.h

@@ -115,7 +115,7 @@ public:
     static StringHash RegisterSignificantString(const String& str);
 
     /// Get a significant string from a case insensitive hash value
-    static bool GetSignificantString(unsigned hash, String& strOut);
+    static bool GetSignificantString(StringHash hash, String& strOut);
 
     // ATOMIC END
 

+ 64 - 47
Source/Atomic/Resource/ResourceMapRouter.cpp

@@ -29,70 +29,87 @@
 namespace Atomic
 {
 
-ResourceMapRouter::ResourceMapRouter(Context* context, const String& mapFile) : ResourceRouter(context)
-{
-    if (mapFile.Length())
+    ResourceMapRouter::ResourceMapRouter(Context* context, const String& mapFile) : ResourceRouter(context)
     {
-        ResourceCache* cache = GetSubsystem<ResourceCache>();
-
-        if (!cache)
-            return;
-
-        SharedPtr<JSONFile> jsonFile = cache->GetTempResource<JSONFile>(mapFile);
-
-        if (jsonFile.NotNull())
+        if (mapFile.Length())
         {
-            if (Load(jsonFile->GetRoot()))
-                cache->AddResourceRouter(this);
-        }
+            ResourceCache* cache = GetSubsystem<ResourceCache>();
+
+            if (!cache)
+            {
+                ATOMIC_LOGERROR("ResourceMapRouter::ResourceMapRouter - ResourceCache subsystem not found");
+                return;
+            }
+
+            SharedPtr<JSONFile> jsonFile = cache->GetTempResource<JSONFile>(mapFile);
+
+            context_->RegisterSubsystem(this);
+
+            if (jsonFile.NotNull())
+            {
+                if (Load(jsonFile->GetRoot()))
+                {
+                    cache->AddResourceRouter(this);
+                }
+                else
+                {
+                    ATOMIC_LOGERROR("ResourceMapRouter::ResourceMapRouter - Unable to load resource map json");
+                }
+            }
+            else
+            {
+                ATOMIC_LOGERROR("ResourceMapRouter::ResourceMapRouter - Unable to parse resource map json");
+            }
 
+        }
     }
-}
 
-bool ResourceMapRouter::Load(const JSONValue& json)
-{
-    const JSONValue& assetMap = json.Get("assetMap");
-
-    if (!assetMap.IsObject())
-        return false;
-
-    ConstJSONObjectIterator itr = assetMap.Begin();
-    while (itr != assetMap.End())
+    bool ResourceMapRouter::Load(const JSONValue& json)
     {
-        StringVector tags = itr->first_.Split(';');
+        const JSONValue& assetMap = json.Get("assetMap");
+
+        if (!assetMap.IsObject())
+            return false;
 
-        if (tags.Size() == 2)
+        ConstJSONObjectIterator itr = assetMap.Begin();
+        while (itr != assetMap.End())
         {
-           resourceMap_[tags[0]][tags[1]] = itr->second_.GetString();
+            StringVector tags = itr->first_.Split(';');
+
+            if (tags.Size() == 2)
+            {
+                StringHash::RegisterSignificantString(tags[0]);
+                StringHash::RegisterSignificantString(tags[1]);
+                resourceMap_[tags[0]][tags[1]] = itr->second_.GetString();
+            }
+
+            itr++;
         }
 
-        itr++;
+        return true;
     }
 
-    return true;
-}
-
-void ResourceMapRouter::Route(String& name, StringHash type, ResourceRequest requestType)
-{
+    void ResourceMapRouter::Route(String& name, StringHash type, ResourceRequest requestType)
+    {
 
-    if (type == StringHash::ZERO)
-        return;
+        if (type == StringHash::ZERO)
+            return;
 
-    HashMap<StringHash, HashMap<StringHash, String>>::ConstIterator itr = resourceMap_.Find(type);
-    if (itr == resourceMap_.End())
-    {
-        return;
-    }
+        HashMap<StringHash, HashMap<StringHash, String>>::ConstIterator itr = resourceMap_.Find(type);
+        if (itr == resourceMap_.End())
+        {
+            return;
+        }
 
-    HashMap<StringHash, String>::ConstIterator mitr = itr->second_.Find(name);
-    if (mitr == itr->second_.End())
-    {
-        return;
-    }
+        HashMap<StringHash, String>::ConstIterator mitr = itr->second_.Find(name);
+        if (mitr == itr->second_.End())
+        {
+            return;
+        }
 
 
-    name = mitr->second_;
+        name = mitr->second_;
 
-}
+    }
 
 }

+ 2 - 0
Source/Atomic/Resource/ResourceMapRouter.h

@@ -40,6 +40,8 @@ public:
 
     void Route(String& name, StringHash type, ResourceRequest requestType);
 
+    const HashMap<StringHash, String>* GetTypeCacheMap(StringHash hash) const { return resourceMap_[hash]; }
+
 private:
 
     bool Load(const JSONValue& json);

+ 1 - 1
Source/Atomic/Resource/XMLElement.cpp

@@ -499,7 +499,7 @@ bool XMLElement::SetVariantMap(const VariantMap& value)
 // ATOMIC BEGIN
         // Check for significant string, to make variant map XML more friendly than using a hash
         String sigString;
-        if (StringHash::GetSignificantString(i->first_.Value(), sigString))
+        if (StringHash::GetSignificantString(i->first_, sigString))
         {
             variantElem.SetString("name", sigString);
         }

+ 174 - 2
Source/Atomic/Script/ScriptComponent.cpp

@@ -22,6 +22,8 @@
 
 
 #include "../Core/Context.h"
+#include "../IO/Log.h"
+
 #include "ScriptComponentFile.h"
 #include "ScriptComponent.h"
 
@@ -29,6 +31,7 @@ namespace Atomic
 {
 
 ScriptComponent::ScriptComponent(Context* context) : Component(context),
+    saving_(false),
     loading_(false)
 
 {
@@ -38,9 +41,7 @@ ScriptComponent::ScriptComponent(Context* context) : Component(context),
 void ScriptComponent::RegisterObject(Context* context)
 {
     ATOMIC_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
-
     ATOMIC_ACCESSOR_ATTRIBUTE("FieldValues", GetFieldValuesAttr, SetFieldValuesAttr, VariantMap, Variant::emptyVariantMap, AM_FILE);
-
 }
 
 ScriptComponent::~ScriptComponent()
@@ -66,14 +67,185 @@ bool ScriptComponent::LoadXML(const XMLElement& source, bool setInstanceDefault)
     return success;
 }
 
+bool ScriptComponent::Save(Serializer& dest) const
+{
+    saving_ = true;    
+    bool success = Component::Save(dest);    
+    saving_ = false;
+    
+    return success;
+}
+
+bool ScriptComponent::SaveXML(XMLElement& dest) const
+{
+    saving_ = true;
+    bool success = Component::SaveXML(dest);
+    saving_ = false;
+
+    return success;
+}
+
 const VariantMap& ScriptComponent::GetFieldValuesAttr() const
 {
+    ScriptComponentFile* componentFile = GetComponentFile();
+    const String& classname = GetComponentClassName();
+
+    if (saving_ && componentFile && classname.Length())
+    {
+        // When serializing enumerations, enum integer values are converted to enum strings
+        // This makes them independent of enum values/order changing
+
+        fieldValuesAttr_ = fieldValues_;
+
+        const EnumMap& enums = componentFile->GetEnums(classname);
+        VariantMap::ConstIterator itr = fieldValues_.Begin();
+        String fieldName;
+
+        while (itr != fieldValues_.End())
+        {
+            const StringHash& nameHash = itr->first_;
+            const Variant& v = itr->second_;
+            const FieldInfo* fieldInfo = 0;
+
+            bool skip = false;
+
+            // If we're not a numeric field, can skip
+            if (v.GetType() != VAR_INT &&
+                v.GetType() != VAR_FLOAT &&
+                v.GetType() != VAR_DOUBLE)
+            {
+                skip = true;
+            }
+            else if (!StringHash::GetSignificantString(nameHash, fieldName))
+            {
+                ATOMIC_LOGWARNING("ScriptComponent::GetFieldValuesAttr - unable to retrieve field name");
+                skip = true;
+            }
+            else if (!(fieldInfo = componentFile->GetFields(classname)[fieldName]) || !fieldInfo->isEnum_)
+            {
+                skip = true;
+            }
+
+            if (skip)
+            {
+                itr++;
+                continue;
+            }
+           
+            int intValue = v.GetInt();
+
+            EnumMap::ConstIterator eitr = enums.Begin();
+
+            // find corresponding enum, and convert to enum name representation
+            while (eitr != enums.End())
+            {
+                if (!eitr->first_.Compare(fieldName, false))
+                {
+                    const Vector<EnumInfo>& infos = eitr->second_;
+
+                    for (unsigned i = 0; i < infos.Size(); i++)
+                    {
+                        if (intValue == infos[i].value_)
+                        {
+                            // use enum name string instead of numeric value
+                            fieldValuesAttr_[nameHash] = infos[i].name_;
+                            break;
+                        }
+                    }
+
+                    break;
+                }
+
+                eitr++;
+            }
+
+            itr++;
+        }
+
+        return fieldValuesAttr_;
+    }
+
     return fieldValues_;
 }
 
 void ScriptComponent::SetFieldValuesAttr(const VariantMap& value)
 {
     fieldValues_ = value;
+
+    ScriptComponentFile* componentFile = GetComponentFile();
+    const String& classname = GetComponentClassName();
+
+    if (loading_ && componentFile && classname.Length())
+    {
+        // When serializing enumerations, enum integer values are converted to enum strings
+        // This makes them independent of enum values/order changing
+
+        const EnumMap& enums = componentFile->GetEnums(classname);
+        VariantMap::ConstIterator itr = value.Begin();
+        String fieldName;
+
+        // run through field values looking for enum name strings
+        // which need to be converted from string to numeric representation
+        while (itr != value.End())
+        {
+            const StringHash& nameHash = itr->first_;
+            const FieldInfo* fieldInfo = 0;
+
+            bool skip = false;
+
+            if (itr->second_.GetType() != VAR_STRING)
+            {
+                skip = true;
+            }
+            else if (!StringHash::GetSignificantString(nameHash, fieldName))
+            {
+                ATOMIC_LOGWARNING("ScriptComponent::SetFieldValuesAttr - unable to retrieve field name");
+                skip = true;
+            }
+            else if (!(fieldInfo = componentFile->GetFields(classname)[fieldName]) || !fieldInfo->isEnum_)
+            {
+                skip = true;
+            }
+
+            if (skip)
+            {
+                itr++;
+                continue;
+            }            
+
+            EnumMap::ConstIterator eitr = enums.Begin();
+            const String& svalue = itr->second_.GetString();
+
+            // find the corresponding enum if any
+            while (eitr != enums.End())
+            {
+                if (!eitr->first_.Compare(fieldName, false))
+                {
+                    const Vector<EnumInfo>& infos = eitr->second_;
+
+                    // default
+                    fieldValues_[nameHash] = infos.Size() > 0 ? infos[0].value_ : 0;
+
+                    for (unsigned i = 0; i < infos.Size(); i++)
+                    {
+                        if (!svalue.Compare(infos[i].name_, false))
+                        {
+                            fieldValues_[nameHash] = infos[i].value_;
+                            break;
+                        }
+                    }
+
+                    break;
+                }
+
+                eitr++;
+            }
+
+            itr++;
+        }
+
+    }
+
 }
 
 }

+ 11 - 2
Source/Atomic/Script/ScriptComponent.h

@@ -44,21 +44,30 @@ public:
     static void RegisterObject(Context* context);
 
     virtual const String& GetComponentClassName() const = 0;
+    virtual ScriptComponentFile* GetComponentFile() const = 0;
 
-    virtual ScriptComponentFile* GetComponentFile() = 0;
-
+    /// Get script field value map
     VariantMap& GetFieldValues() { return fieldValues_; }
 
+    /// Load from binary data. Return true if successful.
     bool Load(Deserializer& source, bool setInstanceDefault);
+    /// Load from XML data. Return true if successful.
     bool LoadXML(const XMLElement& source, bool setInstanceDefault);
 
+    /// Save as binary data. Return true if successful.
+    virtual bool Save(Serializer& dest) const;
+    /// Save as XML data. Return true if successful.
+    virtual bool SaveXML(XMLElement& dest) const;
+
 protected:
 
     const VariantMap& GetFieldValuesAttr() const;
     void SetFieldValuesAttr(const VariantMap& value);
 
     VariantMap fieldValues_;
+    mutable VariantMap fieldValuesAttr_;
 
+    mutable bool saving_;
     bool loading_;
 
 

+ 3 - 3
Source/Atomic/Script/ScriptComponentFile.cpp

@@ -43,7 +43,7 @@ ScriptComponentFile::~ScriptComponentFile()
 
 void ScriptComponentFile::RegisterObject(Context* context)
 {
-    //context->RegisterFactory<ScriptComponentFile>();
+    
 }
 
 void ScriptComponentFile::AddEnum(const String& enumName, const EnumInfo& enumInfo, const String& classname)
@@ -53,10 +53,10 @@ void ScriptComponentFile::AddEnum(const String& enumName, const EnumInfo& enumIn
     enumValues.Push(enumInfo);
 }
 
-void ScriptComponentFile::AddField(const String& fieldName, VariantType variantType, const String& resourceTypeName, bool isArray, unsigned fixedArraySize, const String &classname, const String& tooltip)
+void ScriptComponentFile::AddField(const String& fieldName, VariantType variantType, const String& resourceTypeName, bool isArray, bool isEnum, unsigned fixedArraySize, const String &classname, const String& tooltip)
 {
     FieldMap& fields = classFields_[classname];
-    FieldInfo finfo(fieldName, variantType, resourceTypeName, isArray, fixedArraySize);
+    FieldInfo finfo(fieldName, variantType, resourceTypeName, isArray, isEnum, fixedArraySize);
     fields[fieldName] = finfo;
 
     if (tooltip.Length())

+ 8 - 5
Source/Atomic/Script/ScriptComponentFile.h

@@ -37,15 +37,17 @@ struct FieldInfo
         name_ = "UNINITIALIZED_FIELDINFO";
         variantType_ = VAR_NONE;
         isArray_ = false;
+        isEnum_ = false;
         fixedArraySize_ = 0;
     }
 
-    FieldInfo(const String& name, VariantType variantType, const String& resourceTypeName = String::EMPTY, bool isArray = false, unsigned fixedArraySize = 0)
+    FieldInfo(const String& name, VariantType variantType, const String& resourceTypeName = String::EMPTY, bool isArray = false, bool isEnum = false, unsigned fixedArraySize = 0)
     {
         name_ = name;
         variantType_ = variantType;
         resourceTypeName_ = resourceTypeName;
         isArray_ = isArray;
+        isEnum_ = isEnum;
         fixedArraySize_ = fixedArraySize;
 
         // register field name as significant, for serialization
@@ -57,19 +59,20 @@ struct FieldInfo
     // for resource ref variants
     String resourceTypeName_;
     bool isArray_;
+    bool isEnum_;
     unsigned fixedArraySize_;
 };
 
 struct EnumInfo
 {
-    EnumInfo(const String& name = String::EMPTY, const Variant& v = Variant::EMPTY)
+    EnumInfo(const String& name = String::EMPTY, int value = 0)
     {
         name_ = name;
-        value_ = v;
+        value_ = value;
     }
 
     String name_;
-    Variant value_;
+    int value_;
 };
 
 // TODO: these should be broken out into some class info structs, getting unwieldy
@@ -111,7 +114,7 @@ protected:
     void Clear();
 
     void AddEnum(const String& enumName, const EnumInfo& enumInfo, const String& classname = String::EMPTY);
-    void AddField(const String& fieldName, VariantType variantType, const String& resourceTypeName = String::EMPTY, bool isArray = false, unsigned fixedArraySize = 0, const String& classname = String::EMPTY, const String& tooltip = String::EMPTY);
+    void AddField(const String& fieldName, VariantType variantType, const String& resourceTypeName = String::EMPTY, bool isArray = false, bool isEnum = false, unsigned fixedArraySize = 0, const String& classname = String::EMPTY, const String& tooltip = String::EMPTY);
     void AddDefaultValue(const String& fieldName, const Variant& value, const String& classname = String::EMPTY);
 
     // only valid in editor

+ 1 - 1
Source/AtomicJS/Javascript/JSComponent.h

@@ -79,7 +79,7 @@ public:
 
     /// Get script attribute
     ResourceRef GetComponentFileAttr() const;
-    ScriptComponentFile* GetComponentFile() { return componentFile_; }
+    ScriptComponentFile* GetComponentFile() const { return componentFile_; }
 
     /// Set script attribute.
     void SetComponentFile(JSComponentFile* cfile) { componentFile_ = cfile; }

+ 1 - 1
Source/AtomicJS/Javascript/JSComponentFile.cpp

@@ -377,7 +377,7 @@ bool JSComponentFile::BeginLoad(Deserializer& source)
                                         {
                                             duk_get_prop_index(ctx, -1, i);
                                             String enumName = duk_require_string(ctx, -1);
-                                            AddEnum(name, EnumInfo(enumName, Variant(float(i))));
+                                            AddEnum(name, EnumInfo(enumName, int(i)));
                                             duk_pop(ctx);
                                         }
 

+ 21 - 2
Source/AtomicJS/Javascript/JSSceneSerializable.cpp

@@ -512,6 +512,9 @@ namespace Atomic
                     duk_put_prop_string(ctx, -2, "tooltip");
                 }
 
+                // enum names
+                duk_push_array(ctx);
+                // enum values
                 duk_push_array(ctx);
 
                 if (enums.Contains(itr->first_))
@@ -522,13 +525,19 @@ namespace Atomic
 
                     while (eitr != infos->End())
                     {
+                        // enum value
+                        duk_push_number(ctx, eitr->value_);
+                        duk_put_prop_index(ctx, -2, enumCount);
+
+                        // enum name
                         duk_push_string(ctx, eitr->name_.CString());
-                        duk_put_prop_index(ctx, -2, enumCount++);
+                        duk_put_prop_index(ctx, -3, enumCount++);
                         eitr++;
                     }
 
                 }
 
+                duk_put_prop_string(ctx, -3, "enumValues");
                 duk_put_prop_string(ctx, -2, "enumNames");
 
                 // store attr object
@@ -623,6 +632,9 @@ namespace Atomic
                 duk_push_boolean(ctx, 0);
                 duk_put_prop_string(ctx, -2, "dynamic");
 
+                // Enum Names
+                duk_push_array(ctx);
+                // Enum Values
                 duk_push_array(ctx);
 
                 const char** enumPtr = attr->enumNames_;
@@ -632,12 +644,19 @@ namespace Atomic
                 {
                     while (*enumPtr)
                     {
+                        // set value
+                        duk_push_number(ctx, enumCount);
+                        duk_put_prop_index(ctx, -2, enumCount);
+
+                        // set name
                         duk_push_string(ctx, *enumPtr);
-                        duk_put_prop_index(ctx, -2, enumCount++);
+                        duk_put_prop_index(ctx, -3, enumCount++);
+
                         enumPtr++;
                     }
                 }
 
+                duk_put_prop_string(ctx, -3, "enumValues");
                 duk_put_prop_string(ctx, -2, "enumNames");
 
                 // store attr object

+ 3 - 3
Source/AtomicNET/NETScript/CSComponent.cpp

@@ -120,7 +120,7 @@ void CSComponent::SendLoadEvent()
 
 bool CSComponent::Load(Deserializer& source, bool setInstanceDefault)
 {
-    bool success = Component::Load(source, setInstanceDefault);
+    bool success = ScriptComponent::Load(source, setInstanceDefault);
 
     if (success)
         SendLoadEvent();
@@ -130,7 +130,7 @@ bool CSComponent::Load(Deserializer& source, bool setInstanceDefault)
 
 bool CSComponent::LoadXML(const XMLElement& source, bool setInstanceDefault)
 {
-    bool success = Component::LoadXML(source, setInstanceDefault);
+    bool success = ScriptComponent::LoadXML(source, setInstanceDefault);
 
     if (success)
         SendLoadEvent();
@@ -138,7 +138,7 @@ bool CSComponent::LoadXML(const XMLElement& source, bool setInstanceDefault)
     return success;
 }
 
-ScriptComponentFile* CSComponent::GetComponentFile()
+ScriptComponentFile* CSComponent::GetComponentFile() const
 {
     if (!componentClassName_.Length())
         return 0;

+ 1 - 1
Source/AtomicNET/NETScript/CSComponent.h

@@ -60,7 +60,7 @@ public:
     void SetComponentClassName(const String& name);
     const String& GetComponentClassName() const { return componentClassName_; }
 
-    virtual ScriptComponentFile* GetComponentFile();
+    virtual ScriptComponentFile* GetComponentFile() const;
 
 protected:
 

+ 45 - 28
Source/AtomicNET/NETScript/CSComponentAssembly.cpp

@@ -21,12 +21,14 @@
 //
 
 #include <Atomic/Core/Context.h>
+#include <Atomic/Core/Profiler.h>
 #include <Atomic/IO/Deserializer.h>
+#include <Atomic/IO/Serializer.h>
 #include <Atomic/IO/Log.h>
 #include <Atomic/IO/FileSystem.h>
-#include <Atomic/Core/Profiler.h>
 #include <Atomic/Resource/ResourceCache.h>
-#include <Atomic/IO/Serializer.h>
+#include <Atomic/Resource/JSONFile.h>
+#include <Atomic/Resource/ResourceMapRouter.h>
 #include <Atomic/Script/ScriptSystem.h>
 
 #include "NETScriptEvents.h"
@@ -194,7 +196,7 @@ namespace Atomic
                     }
                 }
 
-                AddField(fieldName, varType, resourceTypeName, isArray, fixedArraySize, className, tooltip);
+                AddField(fieldName, varType, resourceTypeName, isArray, isEnum, fixedArraySize, className, tooltip);
 
             }
 
@@ -260,6 +262,21 @@ namespace Atomic
 
         fullAssemblyPath_ = sourceFile->GetFullPath();
 
+        String text = sourceFile->ReadText();
+        JSONValue root;
+
+        if (!JSONFile::ParseJSON(text, root, false))        
+        {
+            ATOMIC_LOGERRORF("Failed to load assembly json for %s ", fullAssemblyPath_.CString());
+            return false;
+        }
+
+        if (!ParseAssemblyJSON(root))
+        {
+            ATOMIC_LOGERRORF("Failed to parse assembly json for %s ", fullAssemblyPath_.CString());
+            return false;
+        }
+
         VariantMap eventData;
 
         using namespace CSComponentAssemblyReference;
@@ -323,45 +340,45 @@ namespace Atomic
 
     bool CSComponentAssembly::PreloadClassAssemblies()
     {
-        // TEMPORARY SOLUTION, Desktop only
-
         ATOMIC_LOGINFO("Preloading Class Assemblies");
 
         Context* context = ScriptSystem::GetContext();
-        assert(context);
+        
+        if (!context)
+            return false;
 
-        ResourceCache* cache = context->GetSubsystem<ResourceCache>();
-        FileSystem* fileSystem = context->GetSubsystem<FileSystem>();
-
-        const StringVector& resourceDirs = cache->GetResourceDirs();
+        ResourceMapRouter* resourceMap = context->GetSubsystem<ResourceMapRouter>();
 
-        for (unsigned i = 0; i < resourceDirs.Size(); i++)
+        if (!resourceMap)
         {
-            const String& resourceDir = resourceDirs[i];
-
-            ATOMIC_LOGINFOF("Scanning: %s", resourceDir.CString());
+            ATOMIC_LOGERROR("CSComponentAssembly::PreloadClassAssemblies - ResourceMapRouter subsystem unavailable");
+            return false;
+        }
 
-            StringVector results;
-            fileSystem->ScanDir(results, resourceDir, "*.dll", SCAN_FILES, true);
+        ResourceCache* cache = context->GetSubsystem<ResourceCache>();
 
-            for (unsigned j = 0; j < results.Size(); j++)
-            {
-                // FIXME: This filtering is necessary as we're loading setting project root folder as a resource dir
-                // https://github.com/AtomicGameEngine/AtomicGameEngine/issues/1037
+        if (!cache)
+        {
+            ATOMIC_LOGERROR("CSComponentAssembly::PreloadClassAssemblies - ResourceCache subsystem unavailable");
+            return false;
+        }
 
-                String filter = results[j].ToLower();
+        const HashMap<StringHash, String>* assemblies = resourceMap->GetTypeCacheMap("CSComponentAssembly");
 
-                if (filter.StartsWith("atomicnet/") || filter.StartsWith("resources/"))
-                {
-                    ATOMIC_LOGINFOF("Skipping Assembly: %s (https://github.com/AtomicGameEngine/AtomicGameEngine/issues/1037)", results[j].CString());
-                    continue;
-                }
+        if (!assemblies)
+            return true;
 
-                ATOMIC_LOGINFOF("Loading Assembly: %s", results[j].CString());
+        HashMap<StringHash, String>::ConstIterator itr = assemblies->Begin();
 
-                cache->GetResource<CSComponentAssembly>(results[j]);
+        while (itr != assemblies->End())
+        {
+            if (!cache->GetResource<CSComponentAssembly>(itr->second_, false))
+            {
+                ATOMIC_LOGERRORF("CSComponentAssembly::PreloadClassAssemblies - Error getting resource %s", itr->second_.CString());
+                return false;
             }
 
+            itr++;
         }
 
         return true;

+ 3 - 3
Source/AtomicNET/NETScript/CSComponentAssembly.h

@@ -45,9 +45,7 @@ namespace Atomic
         /// Construct.
         CSComponentAssembly(Context* context);
         /// Destruct.
-        virtual ~CSComponentAssembly();
-
-        bool ParseAssemblyJSON(const JSONValue& json);
+        virtual ~CSComponentAssembly();        
 
         CSComponent* CreateCSComponent(const String& classname);
 
@@ -72,6 +70,8 @@ namespace Atomic
 
     private:
 
+        bool ParseAssemblyJSON(const JSONValue& json);
+
         static void InitTypeMap();
 
         bool ParseComponentClassJSON(const JSONValue& json);

+ 65 - 29
Source/ToolCore/Assets/NETAssemblyImporter.cpp

@@ -41,6 +41,7 @@ namespace ToolCore
 
     NETAssemblyImporter::NETAssemblyImporter(Context* context, Asset *asset) : AssetImporter(context, asset)
     {
+        requiresCacheFile_ = true;
         resultHandler_ = new NETAssemblyImporterResultHandler(context, this);
     }
 
@@ -73,31 +74,22 @@ namespace ToolCore
             }
             else
             {
-                ResourceCache* cache = GetSubsystem<ResourceCache>();
-                CSComponentAssembly* assemblyFile = cache->GetResource<CSComponentAssembly>(asset_->GetPath());
-                if (assemblyFile)
+
+                if (!SaveAssemblyCacheFile())
                 {
-                    if (!assemblyFile->ParseAssemblyJSON(assemblyJSON_))
-                    {
-                        ATOMIC_LOGERRORF("NETAssemblyImporter::HandleResult - Unable to parse assembly %s", asset_->GetPath().CString());
-                    }
-                    else
-                    {
-                        asset_->Save();
-
-                        using namespace CSComponentAssemblyChanged;
-                        VariantMap assemblyChangedEventData;
-                        assemblyChangedEventData[P_RESOURCE] = asset_->GetResource();
-                        assemblyChangedEventData[P_ASSEMBLYPATH] = asset_->GetPath();        
-                        SendEvent(E_CSCOMPONENTASSEMBLYCHANGED, assemblyChangedEventData);
-                    }
+                    return;
                 }
-                else
-                {
-
-                    ATOMIC_LOGERRORF("NETAssemblyImporter::HandleResult - Unable to get CSComponentAssembly resource for %s", asset_->GetPath().CString());
 
+                if (!assemblyJSON_.IsObject())
+                {
+                    ATOMIC_LOGERRORF("NETAssemblyImporter::HandleResult - Unable to parse assembly json for %s", asset_->GetPath().CString());
                 }
+
+                using namespace CSComponentAssemblyChanged;
+                VariantMap assemblyChangedEventData;
+                assemblyChangedEventData[P_RESOURCE] = asset_->GetResource();
+                assemblyChangedEventData[P_ASSEMBLYPATH] = asset_->GetPath();        
+                SendEvent(E_CSCOMPONENTASSEMBLYCHANGED, assemblyChangedEventData);
                     
             }
             
@@ -105,14 +97,50 @@ namespace ToolCore
 
     }
 
+    bool NETAssemblyImporter::SaveAssemblyCacheFile()
+    {
+        if (!assemblyJSON_.IsObject())
+            return false;
+
+        SharedPtr<JSONFile> jsonFile(new JSONFile(context_));
+        JSONValue& root = jsonFile->GetRoot();
+        root = assemblyJSON_;
+        jsonFile->SaveFile(asset_->GetCachePath());
+
+        ResourceCache* cache = GetSubsystem<ResourceCache>();
+        CSComponentAssembly* assemblyFile = cache->GetResource<CSComponentAssembly>(asset_->GetCachePath());
+
+        if (!assemblyFile)
+        {
+            ATOMIC_LOGERRORF("NETAssemblyImporter::Import - invalid cached assembly json importing %s", asset_->GetPath().CString());
+            return false;
+        }
+
+        asset_->Save();
+
+        return true;
+    }
+
     bool NETAssemblyImporter::Import()
     {
         AtomicNETService* service = GetSubsystem<AtomicNETService>();
 
         if (!service)
         {
-            ATOMIC_LOGERRORF("NETAssemblyImporter::Import - Unable to get AtomicNETService subsystem importing %s", asset_->GetPath().CString());
-            return false;
+            if (assemblyJSON_.IsObject())
+            {
+                if (!SaveAssemblyCacheFile())
+                    return false;
+
+                ATOMIC_LOGINFOF("NETAssemblyImporter::Import - AtomicNETService process unavailable, using cached assembly JSON for %s", asset_->GetPath().CString());
+
+                return true;
+            }
+            else
+            {
+                ATOMIC_LOGERRORF("NETAssemblyImporter::Import - Unable to get AtomicNETService subsystem and no cached assembly json importing %s", asset_->GetPath().CString());
+                return false;
+            }
         }
 
 
@@ -142,11 +170,8 @@ namespace ToolCore
         if (ajson.IsObject())
         {
             assemblyJSON_ = ajson.GetObject();
-
             ResourceCache* cache = GetSubsystem<ResourceCache>();
-            CSComponentAssembly* assemblyFile = cache->GetResource<CSComponentAssembly>(asset_->GetPath());
-            if (assemblyFile)
-                assemblyFile->ParseAssemblyJSON(assemblyJSON_);
+            cache->GetResource<CSComponentAssembly>(asset_->GetCachePath());
         }
 
         return true;
@@ -168,10 +193,21 @@ namespace ToolCore
     Resource* NETAssemblyImporter::GetResource(const String& typeName)
     {
         ResourceCache* cache = GetSubsystem<ResourceCache>();
+        CSComponentAssembly* assemblyFile = cache->GetResource<CSComponentAssembly>(asset_->GetCachePath());
+        return assemblyFile;
+    }
 
-        CSComponentAssembly* assemblyFile = cache->GetResource<CSComponentAssembly>(asset_->GetPath());
+    void NETAssemblyImporter::GetAssetCacheMap(HashMap<String, String>& assetMap)
+    {
+        if (asset_.Null())
+            return;
 
-        return assemblyFile;
+        String assetPath = asset_->GetRelativePath().ToLower();
+
+        String cachePath = asset_->GetGUID().ToLower();
+
+        // Default is load node xml
+        assetMap["CSComponentAssembly;" + assetPath] = cachePath;
 
     }
 

+ 4 - 0
Source/ToolCore/Assets/NETAssemblyImporter.h

@@ -72,10 +72,14 @@ namespace ToolCore
         virtual bool LoadSettingsInternal(JSONValue& jsonRoot);
         virtual bool SaveSettingsInternal(JSONValue& jsonRoot);
 
+        void GetAssetCacheMap(HashMap<String, String>& assetMap);
+
     private:
 
         virtual void HandleResult(unsigned cmdID, const VariantMap& cmdResult);
 
+        bool SaveAssemblyCacheFile();
+
         JSONValue assemblyJSON_;
 
         SharedPtr<NETAssemblyImporterResultHandler> resultHandler_;