Selaa lähdekoodia

DynamicCast to UIElement when creating layouts, because the returned object could theoretically be a Component or Resource as well.
Changed object typename & attribute infos to store std::strings instead of C strings.
Improved error reporting in attribute access.

Lasse Öörni 14 vuotta sitten
vanhempi
sitoutus
9dd15c95e2

+ 2 - 2
Engine/Audio/SoundSource.cpp

@@ -88,13 +88,13 @@
 
 #define GET_IP_SAMPLE_RIGHT() (((((int)pos[3] - (int)pos[1]) * fractPos) / 65536) + (int)pos[1])
 
-static const char* typeNames[] = 
+static const std::string typeNames[] = 
 {
     "master",
     "effect",
     "music",
     "voice",
-    0
+    ""
 };
 
 // Compressed audio decode buffer length in milliseconds

+ 3 - 16
Engine/Core/Attribute.h

@@ -51,25 +51,12 @@ struct AttributeInfo
     /// Construct empty
     AttributeInfo() :
         type_(VAR_NONE),
-        name_(0),
         offset_(0),
         enumNames_(0),
         mode_(AM_BOTH)
     {
     }
     
-    /// Copy-construct from another AttributeInfo
-    AttributeInfo(const AttributeInfo& rhs) :
-        type_(rhs.type_),
-        name_(rhs.name_),
-        offset_(rhs.offset_),
-        accessor_(rhs.accessor_),
-        enumNames_(rhs.enumNames_),
-        defaultValue_(rhs.defaultValue_),
-        mode_(rhs.mode_)
-    {
-    }
-    
     /// Construct offset attribute
     AttributeInfo(VariantType type, const char* name, unsigned offset, const Variant& defaultValue, unsigned mode) :
         type_(type),
@@ -82,7 +69,7 @@ struct AttributeInfo
     }
     
    /// Construct offset enum attribute
-    AttributeInfo(VariantType type, const char* name, unsigned offset, const char** enumNames, const Variant& defaultValue, unsigned mode) :
+    AttributeInfo(VariantType type, const char* name, unsigned offset, const std::string* enumNames, const Variant& defaultValue, unsigned mode) :
         type_(type),
         name_(name),
         offset_(offset),
@@ -107,11 +94,11 @@ struct AttributeInfo
     /// Attribute type
     VariantType type_;
     /// Name
-    const char* name_;
+    std::string name_;
     /// Byte offset from start of object
     unsigned offset_;
     /// Enum string names
-    const char** enumNames_;
+    const std::string* enumNames_;
     /// Helper object for accessor mode
     SharedPtr<AttributeAccessor> accessor_;
     /// Default value for network replication

+ 4 - 6
Engine/Core/Context.cpp

@@ -25,8 +25,6 @@
 #include "Context.h"
 #include "StringUtils.h"
 
-#include <cstring>
-
 #include "DebugNew.h"
 
 static std::string noType;
@@ -79,12 +77,12 @@ void Context::RegisterAttribute(ShortStringHash objectType, const AttributeInfo&
     attributes_[objectType].push_back(attr);
 }
 
-void Context::RemoveAttribute(ShortStringHash objectType, const char* name)
+void Context::RemoveAttribute(ShortStringHash objectType, const std::string& name)
 {
     std::vector<AttributeInfo>& attributes = attributes_[objectType];
     for (std::vector<AttributeInfo>::iterator i = attributes.begin(); i != attributes.end(); ++i)
     {
-        if (!strcmp(i->name_, name))
+        if (i->name_ == name)
         {
             attributes.erase(i);
             return;
@@ -203,9 +201,9 @@ Object* Context::GetSender() const
         return 0;
 }
 
-const char* Context::GetTypeName(ShortStringHash type) const
+const std::string& Context::GetTypeName(ShortStringHash type) const
 {
     // Search factories to find the hash-to-name mapping
     std::map<ShortStringHash, SharedPtr<ObjectFactory> >::const_iterator i = factories_.find(type);
-    return (i != factories_.end()) ? i->second->GetTypeName() : noType.c_str();
+    return (i != factories_.end()) ? i->second->GetTypeName() : noType;
 }

+ 3 - 3
Engine/Core/Context.h

@@ -48,7 +48,7 @@ public:
     /// Register object attribute
     void RegisterAttribute(ShortStringHash objectType, const AttributeInfo& attr);
     /// Remove object attribute
-    void RemoveAttribute(ShortStringHash objectType, const char* name);
+    void RemoveAttribute(ShortStringHash objectType, const std::string& name);
     /// Copy base class attributes to derived class
     void CopyBaseAttributes(ShortStringHash baseType, ShortStringHash derivedType);
     /// Add event receiver
@@ -138,8 +138,8 @@ public:
     Object* GetSender() const;
     /// Return active event handler. Set by Object. Null outside event handling
     EventHandler* GetHandler() const { return handler_; }
-    /// Return object type name from hash, or null if unknown
-    const char* GetTypeName(ShortStringHash type) const;
+    /// Return object type name from hash, or empty if unknown
+    const std::string& GetTypeName(ShortStringHash type) const;
     /// Template version of returning a subsystem
     template <class T> T* GetSubsystem() const;
     

+ 0 - 2
Engine/Core/Object.cpp

@@ -25,8 +25,6 @@
 #include "Context.h"
 #include "StringUtils.h"
 
-#include <cstring>
-
 #include "DebugNew.h"
 
 static VariantMap noEventData;

+ 7 - 11
Engine/Core/Object.h

@@ -41,7 +41,7 @@ public:
     /// Return type
     virtual ShortStringHash GetType() const = 0;
     /// Return type name
-    virtual const char* GetTypeName() const = 0;
+    virtual const std::string& GetTypeName() const = 0;
     /// Handle event
     virtual void OnEvent(Object* sender, bool broadcast, StringHash eventType, VariantMap& eventData);
     
@@ -70,8 +70,6 @@ public:
     /// Template version of creating an object
     template <class T> SharedPtr<T> CreateObject();
     
-    /// Return typename as std::string
-    std::string GetTypeNameStr() const { return std::string(GetTypeName()); }
     /// Return execution context
     Context* GetContext() const { return context_; }
     /// Return subsystem by type
@@ -125,9 +123,7 @@ public:
     /// Return type
     ShortStringHash GetType() const { return type_; }
     /// Return typename
-    const char* GetTypeName() const { return typeName_; }
-    /// Return typename as std::string
-    std::string GetTypeNameStr() const { return std::string(typeName_); }
+    const std::string& GetTypeName() const { return typeName_; }
     
 protected:
     /// Execution context
@@ -135,7 +131,7 @@ protected:
     /// Object type
     ShortStringHash type_;
     /// Object typename
-    const char* typeName_;
+    std::string typeName_;
 };
 
 /// Template implementation of the object factory
@@ -228,22 +224,22 @@ private:
 #define OBJECT(typeName) \
     private: \
         static const ShortStringHash typeStatic; \
-        static const char* typeNameStatic; \
+        static const std::string typeNameStatic; \
     public: \
         virtual ShortStringHash GetType() const { return GetTypeStatic(); } \
-        virtual const char* GetTypeName() const { return GetTypeNameStatic(); } \
+        virtual const std::string& GetTypeName() const { return GetTypeNameStatic(); } \
         static ShortStringHash GetTypeStatic() \
         { \
             return typeStatic; \
         } \
-        static const char* GetTypeNameStatic() \
+        static const std::string& GetTypeNameStatic() \
         { \
             return typeNameStatic; \
         } \
 
 #define OBJECTTYPESTATIC(typeName) \
     const ShortStringHash typeName::typeStatic(#typeName); \
-    const char* typeName::typeNameStatic = #typeName; \
+    const std::string typeName::typeNameStatic(#typeName); \
 
 #define EVENT(eventID, eventName) static const StringHash eventID(#eventName); namespace eventName
 #define PARAM(paraid_, paraname_) static const ShortStringHash paraid_(#paraname_)

+ 0 - 21
Engine/Core/StringUtils.cpp

@@ -25,7 +25,6 @@
 #include "StringUtils.h"
 
 #include <cstdio>
-#include <cstring>
 #include <ctype.h>
 
 #include "DebugNew.h"
@@ -410,23 +409,3 @@ unsigned GetStringListIndex(const std::string& value, const std::string* strings
     
     return defaultIndex;
 }
-
-unsigned GetStringListIndex(const char* value, const char** strings, unsigned count, unsigned defaultIndex,
-    bool caseSensitive)
-{
-    for (unsigned i = 0; i < count; ++i)
-    {
-        if (caseSensitive)
-        {
-            if (!strcmp(value, strings[i]))
-                return i;
-        }
-        else
-        {
-            if (!_stricmp(value, strings[i]))
-                return i;
-        }
-    }
-    
-    return defaultIndex;
-}

+ 0 - 3
Engine/Core/StringUtils.h

@@ -109,6 +109,3 @@ std::string ToStringHex(unsigned value);
 /// Return an index to a string list corresponding to the given string, or a default value if not found
 unsigned GetStringListIndex(const std::string& value, const std::string* strings, unsigned count, unsigned defaultIndex,
     bool caseSensitive = false);
-/// Return an index to a string list (C string version)
-unsigned GetStringListIndex(const char* value, const char** strings, unsigned count, unsigned defaultIndex,
-    bool caseSensitive = false);

+ 5 - 0
Engine/Core/Variant.cpp

@@ -479,3 +479,8 @@ template<> std::vector<unsigned char> Variant::Get<std::vector<unsigned char> >(
 {
     return GetBuffer();
 }
+
+const std::string& Variant::GetTypeName(VariantType type)
+{
+    return typeNames[type];
+}

+ 3 - 0
Engine/Core/Variant.h

@@ -847,6 +847,9 @@ public:
     /// Convert value to string. Pointers are returned as null, and VariantBuffer or VariantMap are not supported and return empty
     std::string ToString() const;
     
+    /// Return type name for enum value
+    static const std::string& GetTypeName(VariantType type);
+    
     /// Empty variant
     static const Variant EMPTY;
     

+ 7 - 8
Engine/Engine/APITemplates.h

@@ -241,7 +241,7 @@ template <class T> void RegisterObject(asIScriptEngine* engine, const char* clas
     engine->RegisterObjectBehaviour(className, asBEHAVE_ADDREF, "void f()", asMETHODPR(T, AddRef, (), void), asCALL_THISCALL);
     engine->RegisterObjectBehaviour(className, asBEHAVE_RELEASE, "void f()", asMETHODPR(T, ReleaseRef, (), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "ShortStringHash get_type() const", asMETHODPR(T, GetType, () const, ShortStringHash), asCALL_THISCALL);
-    engine->RegisterObjectMethod(className, "String get_typeName() const", asMETHODPR(T, GetTypeNameStr, () const, std::string), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "const String& get_typeName() const", asMETHODPR(T, GetTypeName, () const, const std::string&), asCALL_THISCALL);
     RegisterSubclass<Object, T>(engine, "Object", className);
 }
 
@@ -277,7 +277,10 @@ static const AttributeInfo& SerializableGetAttributeInfo(unsigned index, Seriali
 {
     const std::vector<AttributeInfo>* attributes = ptr->GetAttributes();
     if ((!attributes) || (index >= attributes->size()))
+    {
+        asGetActiveContext()->SetException("Index out of bounds");
         return noAttributeInfo;
+    }
     else
         return attributes->at(index);
 }
@@ -306,8 +309,10 @@ template <class T> void RegisterSerializable(asIScriptEngine* engine, const char
     engine->RegisterObjectMethod(className, "bool Save(File@+)", asFUNCTION(SerializableSave), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "bool LoadXML(const XMLElement&)", asMETHODPR(T, LoadXML, (const XMLElement&), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool SaveXML(XMLElement&)", asMETHODPR(T, SaveXML, (XMLElement&), bool), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "bool SetAttribute(const String&in, const Variant&in)", asMETHODPR(T, SetAttribute, (const std::string&, const Variant&), bool), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "Variant GetAttribute(const String&in)", asMETHODPR(T, GetAttribute, (const std::string&), Variant), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "uint get_numAttributes() const", asMETHODPR(T, GetNumAttributes, () const, unsigned), asCALL_THISCALL);
-    engine->RegisterObjectMethod(className, "void set_attributes(uint, const Variant&in) const", asMETHODPR(T, SetAttribute, (unsigned, const Variant&), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "void set_attributes(uint, const Variant&in) const", asMETHODPR(T, SetAttribute, (unsigned, const Variant&), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "Variant get_attributes(uint) const", asMETHODPR(T, GetAttribute, (unsigned), Variant), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "const AttributeInfo& get_attributeInfos(uint) const", asFUNCTION(SerializableGetAttributeInfo), asCALL_CDECL_OBJLAST);
     RegisterSubclass<Object, T>(engine, "Serializable", className);
@@ -324,11 +329,6 @@ template <class T> void RegisterComponent(asIScriptEngine* engine, const char* c
         engine->RegisterObjectMethod(className, "Node@+ get_node() const", asMETHODPR(T, GetNode, () const, Node*), asCALL_THISCALL);
 }
 
-static Node* NodeCreateChild(Node* ptr)
-{
-    return ptr->CreateChild();
-}
-
 static Component* NodeCreateComponent(const std::string& typeName, Node* ptr)
 {
     return ptr->CreateComponent(ShortStringHash(typeName));
@@ -453,7 +453,6 @@ template <class T> void RegisterNode(asIScriptEngine* engine, const char* classN
     engine->RegisterObjectMethod(className, "void Scale(float)", asMETHODPR(T, Scale, (float), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void Scale(const Vector3&in)", asMETHODPR(T, Scale, (const Vector3&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "Node@+ CreateChild(const String&in name = \"\")", asMETHODPR(T, CreateChild, (const std::string&), Node*), asCALL_THISCALL);
-    //engine->RegisterObjectMethod(className, "Node@+ CreateChild()", asFUNCTION(NodeCreateChild), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "void AddChild(Node@+)", asMETHOD(T, AddChild), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void RemoveChild(Node@+)", asMETHODPR(T, RemoveChild, (Node*), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void RemoveAllChildren()", asMETHOD(T, RemoveAllChildren), asCALL_THISCALL);

+ 5 - 10
Engine/Engine/CoreAPI.cpp

@@ -420,7 +420,7 @@ static void RegisterVariant(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Variant", "void FromString(const String&in, const String&in)", asMETHOD(Variant, FromString), asCALL_THISCALL);
     engine->RegisterObjectMethod("Variant", "String ToString() const", asMETHOD(Variant, ToString), asCALL_THISCALL);
     engine->RegisterObjectMethod("Variant", "VariantType get_type() const", asMETHOD(Variant, GetType), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Variant", "const String &get_typeName() const", asMETHOD(Variant, GetTypeName), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Variant", "const String &get_typeName() const", asMETHODPR(Variant, GetTypeName, () const, const std::string&), asCALL_THISCALL);
     
     engine->RegisterObjectBehaviour("VariantMap", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructVariantMap), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("VariantMap", asBEHAVE_CONSTRUCT, "void f(const VariantMap&in)", asFUNCTION(ConstructVariantMapCopy), asCALL_CDECL_OBJLAST);
@@ -525,18 +525,13 @@ static void DestructAttributeInfo(AttributeInfo* ptr)
     ptr->~AttributeInfo();
 }
 
-static std::string AttributeInfoGetName(AttributeInfo* ptr)
-{
-    return ptr->name_ ? std::string(ptr->name_) : std::string();
-}
-
 static CScriptArray* AttributeInfoGetEnumNames(AttributeInfo* ptr)
 {
     std::vector<std::string> enumNames;
-    const char** enumNamePtrs = ptr->enumNames_;
-    while ((enumNamePtrs) && (*enumNamePtrs))
+    const std::string* enumNamePtrs = ptr->enumNames_;
+    while ((enumNamePtrs) && (enumNamePtrs->length()))
     {
-        enumNames.push_back(std::string(*enumNamePtrs));
+        enumNames.push_back(*enumNamePtrs);
         ++enumNamePtrs;
     }
     return VectorToArray<std::string>(enumNames, "Array<String>");
@@ -610,9 +605,9 @@ void RegisterObject(asIScriptEngine* engine)
     engine->RegisterObjectBehaviour("AttributeInfo", asBEHAVE_CONSTRUCT, "void f(const AttributeInfo&in)", asFUNCTION(ConstructAttributeInfoCopy), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("AttributeInfo", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructAttributeInfo), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("AttributeInfo", "AttributeInfo& opAssign(const AttributeInfo&in)", asMETHODPR(AttributeInfo, operator =, (const AttributeInfo&), AttributeInfo&), asCALL_THISCALL);
-    engine->RegisterObjectMethod("AttributeInfo", "String get_name()", asFUNCTION(AttributeInfoGetName), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("AttributeInfo", "Array<String>@ get_enumNames()", asFUNCTION(AttributeInfoGetEnumNames), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectProperty("AttributeInfo", "VariantType type", offsetof(AttributeInfo, type_));
+    engine->RegisterObjectProperty("AttributeInfo", "const String name", offsetof(AttributeInfo, name_));
     engine->RegisterObjectProperty("AttributeInfo", "Variant defaultValue", offsetof(AttributeInfo, defaultValue_));
     engine->RegisterObjectProperty("AttributeInfo", "uint mode", offsetof(AttributeInfo, mode_));
     

+ 1 - 1
Engine/Engine/Engine.cpp

@@ -334,7 +334,7 @@ void Engine::DumpResources()
         
         if (num)
         {
-            LOGRAW("Resource type " + i->second.resources_.begin()->second->GetTypeNameStr() +
+            LOGRAW("Resource type " + i->second.resources_.begin()->second->GetTypeName() +
                 ": count " + ToString(num) + " memory use " + ToString(memoryUse) + "\n");
         }
     }

+ 1 - 1
Engine/Graphics/AnimatedModel.cpp

@@ -85,7 +85,7 @@ void AnimatedModel::RegisterObject(Context* context)
     ATTRIBUTE(AnimatedModel, VAR_RESOURCEREFLIST, "Materials", materials_, ResourceRefList(Material::GetTypeStatic()));
     ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Animation LOD Bias", animationLodBias_, 1.0f);
     ATTRIBUTE(AnimatedModel, VAR_INT, "Raycast/Occlusion LOD Level", softwareLodLevel_, M_MAX_UNSIGNED);
-    ATTRIBUTE(AnimatedModel, VAR_BUFFER, "Bones Animated", skeleton_, std::vector<unsigned char>());
+    ATTRIBUTE(AnimatedModel, VAR_BUFFER, "Bone Animation Enabled", skeleton_, std::vector<unsigned char>());
     ATTRIBUTE(AnimatedModel, VAR_BUFFER, "Animation States", animationStates_, std::vector<unsigned char>());
 }
 

+ 1 - 1
Engine/Graphics/Geometry.cpp

@@ -74,7 +74,7 @@ bool Geometry::SetVertexBuffer(unsigned index, VertexBuffer* buffer, unsigned el
 {
     if (index >= vertexBuffer_.size())
     {
-        LOGERROR("Illegal stream index");
+        LOGERROR("Stream index out of bounds");
         return false;
     }
     

+ 0 - 2
Engine/Graphics/Graphics.cpp

@@ -50,8 +50,6 @@
 #include "VertexShader.h"
 #include "Zone.h"
 
-#include <cstring>
-
 #include "DebugNew.h"
 
 #ifdef _MSC_VER

+ 2 - 2
Engine/Graphics/Light.cpp

@@ -44,13 +44,13 @@ static const float DEFAULT_SHADOWQUANTIZE = 0.5f;
 static const float DEFAULT_SHADOWMINVIEW = 3.0f;
 static const float DEFAULT_SHADOWNEARFARRATIO = 0.002f;
 
-static const char* typeNames[] =
+static const std::string typeNames[] =
 {
     "directional",
     "spot",
     "point",
     "splitpoint",
-    0
+    ""
 };
 
 void BiasParameters::Validate()

+ 11 - 11
Engine/Graphics/Model.cpp

@@ -37,7 +37,7 @@
 
 #include "DebugNew.h"
 
-unsigned storeOrLookupVertexBuffer(VertexBuffer* buffer, std::vector<VertexBuffer*>& dest)
+unsigned StoreOrLookupVertexBuffer(VertexBuffer* buffer, std::vector<VertexBuffer*>& dest)
 {
     for (unsigned i = 0; i < dest.size(); ++i)
     {
@@ -48,7 +48,7 @@ unsigned storeOrLookupVertexBuffer(VertexBuffer* buffer, std::vector<VertexBuffe
     return dest.size() - 1;
 }
 
-unsigned storeOrLookupIndexBuffer(IndexBuffer* buffer, std::vector<IndexBuffer*>& dest)
+unsigned StoreOrLookupIndexBuffer(IndexBuffer* buffer, std::vector<IndexBuffer*>& dest)
 {
     for (unsigned i = 0; i < dest.size(); ++i)
     {
@@ -165,12 +165,12 @@ bool Model::Load(Deserializer& source)
             
             if (vertexBufferRef >= vertexBuffer_.size())
             {
-                LOGERROR("Illegal vertex buffer index");
+                LOGERROR("Vertex buffer index out of bounds");
                 return false;
             }
             if (indexBufferRef >= indexBuffers_.size())
             {
-                LOGERROR("Illegal index buffer index");
+                LOGERROR("Index buffer index out of bounds");
                 return false;
             }
             
@@ -244,8 +244,8 @@ bool Model::Save(Serializer& dest)
     {
         for (unsigned j = 0; j < geometries_[i].size(); ++j)
         {
-            storeOrLookupVertexBuffer(geometries_[i][j]->GetVertexBuffer(0), vertexBuffers);
-            storeOrLookupIndexBuffer(geometries_[i][j]->GetIndexBuffer(), indexBuffers);
+            StoreOrLookupVertexBuffer(geometries_[i][j]->GetVertexBuffer(0), vertexBuffers);
+            StoreOrLookupIndexBuffer(geometries_[i][j]->GetIndexBuffer(), indexBuffers);
         }
     }
     
@@ -297,8 +297,8 @@ bool Model::Save(Serializer& dest)
             Geometry* geometry = geometries_[i][j];
             dest.WriteFloat(geometry->GetLodDistance());
             dest.WriteUInt(geometry->GetPrimitiveType());
-            dest.WriteUInt(storeOrLookupVertexBuffer(geometry->GetVertexBuffer(0), vertexBuffers));
-            dest.WriteUInt(storeOrLookupIndexBuffer(geometry->GetIndexBuffer(), indexBuffers));
+            dest.WriteUInt(StoreOrLookupVertexBuffer(geometry->GetVertexBuffer(0), vertexBuffers));
+            dest.WriteUInt(StoreOrLookupIndexBuffer(geometry->GetIndexBuffer(), indexBuffers));
             dest.WriteUInt(geometry->GetIndexStart());
             dest.WriteUInt(geometry->GetIndexCount());
         }
@@ -357,7 +357,7 @@ bool Model::SetNumGeometryLodLevels(unsigned index, unsigned num)
 {
     if (index >= geometries_.size())
     {
-        LOGERROR("Illegal geometry index");
+        LOGERROR("Geometry index out of bounds");
         return false;
     }
     if (!num)
@@ -374,12 +374,12 @@ bool Model::SetGeometry(unsigned index, unsigned lodLevel, Geometry* geometry)
 {
     if (index >= geometries_.size())
     {
-        LOGERROR("Illegal geometry index");
+        LOGERROR("Geometry index out of bounds");
         return false;
     }
     if (lodLevel >= geometries_[index].size())
     {
-        LOGERROR("Illegal LOD level index");
+        LOGERROR("LOD level index out of bounds");
         return false;
     }
     

+ 1 - 1
Engine/Graphics/Renderer.cpp

@@ -307,7 +307,7 @@ void Renderer::SetViewport(unsigned index, const Viewport& viewport)
 {
     if (index >= viewports_.size())
     {
-        LOGERROR("Illegal viewport index");
+        LOGERROR("Viewport index out of bounds");
         return;
     }
     

+ 1 - 1
Engine/Graphics/StaticModel.cpp

@@ -284,7 +284,7 @@ bool StaticModel::SetMaterial(unsigned index, Material* material)
 {
     if (index >= materials_.size())
     {
-        LOGERROR("Illegal material index");
+        LOGERROR("Material index out of bounds");
         return false;
     }
     

+ 2 - 2
Engine/Physics/CollisionShape.cpp

@@ -43,7 +43,7 @@
 
 #include "DebugNew.h"
 
-static const char* typeNames[] = 
+static const std::string typeNames[] = 
 {
     "none",
     "box",
@@ -53,7 +53,7 @@ static const char* typeNames[] =
     "trianglemesh",
     "heightfield",
     "convexhull",
-    0
+    ""
 };
 
 static const float DEFAULT_FRICTION = 0.5f;

+ 2 - 2
Engine/Physics/Joint.cpp

@@ -34,12 +34,12 @@
 
 #include "DebugNew.h"
 
-static const char* typeNames[] =
+static const std::string typeNames[] =
 {
     "none",
     "ball",
     "hinge",
-    0
+    ""
 };
 
 OBJECTTYPESTATIC(Joint);

+ 1 - 1
Engine/Resource/Image.cpp

@@ -350,7 +350,7 @@ CompressedLevel Image::GetCompressedLevel(unsigned index) const
     }
     if (index >= numCompressedLevels_)
     {
-        LOGERROR("Illegal compressed image mip level");
+        LOGERROR("Compressed image mip level out of bounds");
         return level;
     }
     

+ 1 - 1
Engine/Resource/Resource.cpp

@@ -40,7 +40,7 @@ bool Resource::Load(Deserializer& src)
 
 bool Resource::Save(Serializer& dest)
 {
-    LOGERROR("Save not supported for " + GetTypeNameStr());
+    LOGERROR("Save not supported for " + GetTypeName());
     return false;
 }
 

+ 1 - 1
Engine/Resource/ResourceCache.cpp

@@ -577,7 +577,7 @@ void ResourceCache::UpdateResourceGroup(ShortStringHash type)
         if ((i->second.memoryBudget_) && (i->second.memoryUse_ > i->second.memoryBudget_) &&
             (oldestResource != i->second.resources_.end()))
         {
-            LOGDEBUG("Resource group " + oldestResource->second->GetTypeNameStr() + " over memory budget, releasing resource " +
+            LOGDEBUG("Resource group " + oldestResource->second->GetTypeName() + " over memory budget, releasing resource " +
                 oldestResource->second->GetName());
             i->second.resources_.erase(oldestResource);
         }

+ 1 - 1
Engine/Scene/Node.cpp

@@ -225,7 +225,7 @@ bool Node::SaveXML(XMLElement& dest)
         Component* component = components_[i];
         XMLElement compElem = dest.CreateChildElement("component");
         
-        compElem.SetString("type", component->GetTypeNameStr());
+        compElem.SetString("type", component->GetTypeName());
         compElem.SetInt("id", component->GetID());
         if (!component->SaveXML(compElem))
             return false;

+ 52 - 19
Engine/Scene/Serializable.cpp

@@ -30,8 +30,6 @@
 #include "StringUtils.h"
 #include "XMLElement.h"
 
-#include <cstring>
-
 #include "DebugNew.h"
 
 OBJECTTYPESTATIC(Serializable);
@@ -201,7 +199,7 @@ bool Serializable::Load(Deserializer& source)
         
         if (source.IsEof())
         {
-            LOGERROR("Could not load " + ToLower(GetTypeNameStr()) + ", stream not open or at end");
+            LOGERROR("Could not load " + ToLower(GetTypeName()) + ", stream not open or at end");
             inSerialization_  = false;
             return false;
         }
@@ -229,7 +227,7 @@ bool Serializable::Save(Serializer& dest)
         
         if (!dest.WriteVariantData(GetAttribute(i)))
         {
-            LOGERROR("Could not save " + ToLower(GetTypeNameStr()) + ", writing to stream failed");
+            LOGERROR("Could not save " + ToLower(GetTypeName()) + ", writing to stream failed");
             inSerialization_ = false;
             return false;
         }
@@ -243,7 +241,7 @@ bool Serializable::LoadXML(const XMLElement& source)
 {
     if (source.IsNull())
     {
-        LOGERROR("Could not load " + ToLower(GetTypeNameStr()) + ", null source element");
+        LOGERROR("Could not load " + ToLower(GetTypeName()) + ", null source element");
         return false;
     }
     
@@ -264,18 +262,18 @@ bool Serializable::LoadXML(const XMLElement& source)
         bool found = false;
         while (attrElem)
         {
-            if (!strcmp(attrElem.GetString("name").c_str(), attr.name_))
+            if (attrElem.GetString("name") == attr.name_)
             {
                 // If enums specified, do enum lookup and int assignment. Otherwise assign the variant directly
                 if (attr.enumNames_)
                 {
                     std::string value = attrElem.GetString("value");
-                    const char** enumPtr = attr.enumNames_;
+                    const std::string* enumPtr = attr.enumNames_;
                     int enumValue = 0;
                     bool enumFound = false;
-                    while (*enumPtr)
+                    while (enumPtr->length())
                     {
-                        if (!strcmp(value.c_str(), *enumPtr))
+                        if (*enumPtr == value)
                         {
                             enumFound = true;
                             break;
@@ -310,7 +308,7 @@ bool Serializable::SaveXML(XMLElement& dest)
 {
     if (dest.IsNull())
     {
-        LOGERROR("Could not save " + ToLower(GetTypeNameStr()) + ", null destination element");
+        LOGERROR("Could not save " + ToLower(GetTypeName()) + ", null destination element");
         return false;
     }
     
@@ -343,35 +341,66 @@ bool Serializable::SaveXML(XMLElement& dest)
     return true;
 }
 
-void Serializable::SetAttribute(unsigned index, const Variant& value)
+bool Serializable::SetAttribute(unsigned index, const Variant& value)
 {
     const std::vector<AttributeInfo>* attributes = context_->GetAttributes(GetType());
-    if ((!attributes) || (index >= attributes->size()))
-        return;
+    if (!attributes)
+    {
+        LOGERROR(GetTypeName() + " has no attributes");
+        return false;
+    }
+    if (index >= attributes->size())
+    {
+        LOGERROR("Attribute index out of bounds");
+        return false;
+    }
     
     const AttributeInfo& attr = attributes->at(index);
     
     // Check that the new value's type matches the attribute type
     if (value.GetType() == attr.type_)
+    {
         OnSetAttribute(attr, value);
+        return true;
+    }
+    else
+    {
+        LOGERROR("Could not set attribute " + std::string(attr.name_) + ": expected type " + Variant::GetTypeName(attr.type_) +
+            " but got " + value.GetTypeName());
+        return false;
+    }
 }
 
-void Serializable::SetAttribute(const char* name, const Variant& value)
+bool Serializable::SetAttribute(const std::string& name, const Variant& value)
 {
     const std::vector<AttributeInfo>* attributes = context_->GetAttributes(GetType());
     if (!attributes)
-        return;
+    {
+        LOGERROR(GetTypeName() + " has no attributes");
+        return false;
+    }
     
     for (std::vector<AttributeInfo>::const_iterator i = attributes->begin(); i != attributes->end(); ++i)
     {
-        if (!strcmp(i->name_, name))
+        if (i->name_ == name)
         {
             // Check that the new value's type matches the attribute type
             if (value.GetType() == i->type_)
+            {
                 OnSetAttribute(*i, value);
-            return;
+                return true;
+            }
+            else
+            {
+                LOGERROR("Could not set attribute " + std::string(i->name_) + ": expected type " + Variant::GetTypeName(i->type_)
+                    + " but got " + value.GetTypeName());
+                return false;
+            }
         }
     }
+    
+    LOGERROR("Could not find attribute " + std::string(name) + " in " + GetTypeName());
+    return false;
 }
 
 Variant Serializable::GetAttribute(unsigned index)
@@ -383,18 +412,22 @@ Variant Serializable::GetAttribute(unsigned index)
     return OnGetAttribute(attributes->at(index));
 }
 
-Variant Serializable::GetAttribute(const char* name)
+Variant Serializable::GetAttribute(const std::string& name)
 {
     const std::vector<AttributeInfo>* attributes = context_->GetAttributes(GetType());
     if (!attributes)
+    {
+        LOGERROR(GetTypeName() + " has no attributes");
         return Variant();
+    }
     
     for (std::vector<AttributeInfo>::const_iterator i = attributes->begin(); i != attributes->end(); ++i)
     {
-        if (!strcmp(i->name_, name))
+        if (i->name_ == name)
             return OnGetAttribute(*i);
     }
     
+    LOGERROR("Could not find attribute " + std::string(name) + " in " + GetTypeName());
     return Variant();
 }
 

+ 5 - 5
Engine/Scene/Serializable.h

@@ -56,15 +56,15 @@ public:
     /// Perform post-load after the whole scene has been loaded
     virtual void PostLoad() {}
     
-    /// Set attribute by index
-    void SetAttribute(unsigned index, const Variant& value);
-    /// Set attribute by name
-    void SetAttribute(const char* name, const Variant& value);
+    /// Set attribute by index. Return true if successfully set
+    bool SetAttribute(unsigned index, const Variant& value);
+    /// Set attribute by name. Return true if successfully set
+    bool SetAttribute(const std::string& name, const Variant& value);
     
     /// Return attribute value by index. Return empty if illegal index
     Variant GetAttribute(unsigned index);
     /// Return attribute value by name. Return empty if not found
-    Variant GetAttribute(const char* name);
+    Variant GetAttribute(const std::string& name);
     /// Return number of attributes
     unsigned GetNumAttributes() const;
     /// Return attribute descriptions, or null if none defined

+ 2 - 2
Engine/UI/UI.cpp

@@ -304,7 +304,7 @@ SharedPtr<UIElement> UI::LoadLayout(XMLFile* file, XMLFile* styleFile)
     }
     
     std::string type = rootElem.GetString("type");
-    root = StaticCast<UIElement>(context_->CreateObject(ShortStringHash(type)));
+    root = DynamicCast<UIElement>(context_->CreateObject(ShortStringHash(type)));
     if (!root)
     {
         LOGERROR("Could not create UI element " + type);
@@ -508,7 +508,7 @@ void UI::LoadLayout(UIElement* current, const XMLElement& elem, XMLFile* styleFi
     {
         // Create element
         std::string type = childElem.GetString("type");
-        SharedPtr<UIElement> child = StaticCast<UIElement>(context_->CreateObject(ShortStringHash(type)));
+        SharedPtr<UIElement> child = DynamicCast<UIElement>(context_->CreateObject(ShortStringHash(type)));
         if (!child)
         {
             LOGERROR("Could not create UI element " + type);