Răsfoiți Sursa

Added basic support for setting and referencing variables in properties files via the syntax ${variable}.
Added two new methods on the Properties class, getVariable and setVariable.

sgrenier 12 ani în urmă
părinte
comite
45a9d03a4d
4 a modificat fișierele cu 146 adăugiri și 23 ștergeri
  1. 10 7
      gameplay/src/Bundle.cpp
  2. 1 1
      gameplay/src/Material.cpp
  3. 114 15
      gameplay/src/Properties.cpp
  4. 21 0
      gameplay/src/Properties.h

+ 10 - 7
gameplay/src/Bundle.cpp

@@ -1007,14 +1007,17 @@ Model* Bundle::readModel(const char* nodeId)
                 {
                     std::string materialName = readString(_stream);
                     std::string materialPath = getMaterialPath();
-                    materialPath.append("#");
-                    materialPath.append(materialName);
-                    Material* material = Material::create(materialPath.c_str());
-                    if (material)
+                    if (materialPath.length() > 0)
                     {
-                        int partIndex = model->getMesh()->getPartCount() > 0 ? i : -1;
-                        model->setMaterial(material, partIndex);
-                        SAFE_RELEASE(material);
+                        materialPath.append("#");
+                        materialPath.append(materialName);
+                        Material* material = Material::create(materialPath.c_str());
+                        if (material)
+                        {
+                            int partIndex = model->getMesh()->getPartCount() > 0 ? i : -1;
+                            model->setMaterial(material, partIndex);
+                            SAFE_RELEASE(material);
+                        }
                     }
                 }
             }

+ 1 - 1
gameplay/src/Material.cpp

@@ -36,7 +36,7 @@ Material* Material::create(const char* url, PassCallback callback, void* cookie)
     Properties* properties = Properties::create(url);
     if (properties == NULL)
     {
-        GP_WARN("Failed to create material from file.");
+        GP_WARN("Failed to create material from file: %s", url);
         return NULL;
     }
 

+ 114 - 15
gameplay/src/Properties.cpp

@@ -26,12 +26,12 @@ void calculateNamespacePath(const std::string& urlString, std::string& fileStrin
 Properties* getPropertiesFromNamespacePath(Properties* properties, const std::vector<std::string>& namespacePath);
 
 Properties::Properties()
-    : _dirPath(NULL), _parent(NULL)
+    : _variables(NULL), _dirPath(NULL), _parent(NULL)
 {
 }
 
 Properties::Properties(const Properties& copy)
-    : _namespace(copy._namespace), _id(copy._id), _parentID(copy._parentID), _properties(copy._properties), _dirPath(NULL), _parent(copy._parent)
+    : _namespace(copy._namespace), _id(copy._id), _parentID(copy._parentID), _properties(copy._properties), _variables(NULL), _dirPath(NULL), _parent(copy._parent)
 {
     setDirectoryPath(copy._dirPath);
     _namespaces = std::vector<Properties*>();
@@ -45,14 +45,14 @@ Properties::Properties(const Properties& copy)
 }
 
 Properties::Properties(Stream* stream)
-    : _dirPath(NULL), _parent(NULL)
+    : _variables(NULL), _dirPath(NULL), _parent(NULL)
 {
     readProperties(stream);
     rewind();
 }
 
 Properties::Properties(Stream* stream, const char* name, const char* id, const char* parentID, Properties* parent)
-    : _namespace(name), _dirPath(NULL), _parent(parent)
+    : _namespace(name), _variables(NULL), _dirPath(NULL), _parent(parent)
 {
     if (id)
     {
@@ -112,11 +112,28 @@ Properties* Properties::create(const char* url)
     return p;
 }
 
+static bool isVariable(const char* str, char* outName, size_t outSize)
+{
+    size_t len = strlen(str);
+    if (len > 3 && str[0] == '$' && str[1] == '{' && str[len - 1] == '}')
+    {
+        size_t size = len - 3;
+        if (size > (outSize - 1))
+            size = outSize - 1;
+        strncpy(outName, str + 2, len - 3);
+        outName[len - 3] = 0;
+        return true;
+    }
+
+    return false;
+}
+
 void Properties::readProperties(Stream* stream)
 {
     GP_ASSERT(stream);
 
     char line[2048];
+    char variable[256];
     int c;
     char* name;
     char* value;
@@ -169,9 +186,6 @@ void Properties::readProperties(Stream* stream)
             rc = strchr(line, '=');
             if (rc != NULL)
             {
-                // There could be a '}' at the end of the line, ending a namespace.
-                rc = strchr(line, '}');
-
                 // First token should be the property name.
                 name = strtok(line, "=");
                 if (name == NULL)
@@ -194,13 +208,15 @@ void Properties::readProperties(Stream* stream)
                 // Remove white-space from value.
                 value = trimWhiteSpace(value);
 
-                // Store name/value pair.
-                _properties.push_back(Property(name, value));
-
-                if (rc != NULL)
+                // Is this a variable assignment?
+                if (isVariable(name, variable, 256))
                 {
-                    // End of namespace.
-                    return;
+                    setVariable(variable, value);
+                }
+                else
+                {
+                    // Normal name/value pair
+                    _properties.push_back(Property(name, value));
                 }
             }
             else
@@ -369,6 +385,8 @@ Properties::~Properties()
     {
         SAFE_DELETE(_namespaces[i]);
     }
+
+    SAFE_DELETE(_variables);
 }
 
 void Properties::skipWhiteSpace(Stream* stream)
@@ -695,22 +713,44 @@ Properties::Type Properties::getType(const char* name) const
 
 const char* Properties::getString(const char* name, const char* defaultValue) const
 {
+    char variable[256];
+    const char* value = NULL;
+
     if (name)
     {
+        // If 'name' is a variable, return the variable value
+        if (isVariable(name, variable, 256))
+        {
+            return getVariable(variable, defaultValue);
+        }
+
         for (std::list<Property>::const_iterator itr = _properties.begin(); itr != _properties.end(); ++itr)
         {
             if (itr->name == name)
-                return itr->value.c_str();
+            {
+                value = itr->value.c_str();
+                break;
+            }
         }
     }
     else
     {
+        // No name provided - get the value at the current iterator position
         if (_propertiesItr != _properties.end())
         {
-            return _propertiesItr->value.c_str();
+            value = _propertiesItr->value.c_str();
         }
     }
 
+    if (value)
+    {
+        // If the value references a variable, return the variable value
+        if (isVariable(value, variable, 256))
+            return getVariable(variable, defaultValue);
+
+        return value;
+    }
+
     return defaultValue;
 }
 
@@ -904,6 +944,65 @@ bool Properties::getPath(const char* name, std::string* path) const
     return false;
 }
 
+const char* Properties::getVariable(const char* name, const char* defaultValue) const
+{
+    if (name == NULL)
+        return defaultValue;
+
+    // Search for variable in this Properties object
+    if (_variables)
+    {
+        for (size_t i = 0, count = _variables->size(); i < count; ++i)
+        {
+            Property& prop = (*_variables)[i];
+            if (prop.name == name)
+                return prop.value.c_str();
+        }
+    }
+
+    // Search for variable in parent Properties
+    return _parent ? _parent->getVariable(name, defaultValue) : defaultValue;
+}
+
+void Properties::setVariable(const char* name, const char* value)
+{
+    GP_ASSERT(name);
+
+    Property* prop = NULL;
+
+    // Search for variable in this Properties object and parents
+    Properties* current = const_cast<Properties*>(this);
+    while (current)
+    {
+        if (current->_variables)
+        {
+            for (size_t i = 0, count = current->_variables->size(); i < count; ++i)
+            {
+                Property* p = &(*current->_variables)[i];
+                if (p->name == name)
+                {
+                    prop = p;
+                    break;
+                }
+            }
+        }
+        current = current->_parent;
+    }
+
+    if (prop)
+    {
+        // Found an existing property, set it
+        prop->value = value ? value : "";
+    }
+    else
+    {
+        // Add a new variable with this name
+        if (!_variables)
+            _variables = new std::vector<Property>();
+        _variables->push_back(Property(name, value ? value : ""));
+    }
+}
+
 Properties* Properties::clone()
 {
     Properties* p = new Properties();

+ 21 - 0
gameplay/src/Properties.h

@@ -414,6 +414,26 @@ public:
      */
     bool getPath(const char* name, std::string* path) const;
 
+    /**
+     * Returns the value of a variable that is set in this Properties object.
+     *
+     * Variables take on the format ${name} and are inherited from parent Property objects.
+     *
+     * @param name Name of the variable to get.
+     * @param defaultValue Value to return if the variable is not found.
+     *
+     * @return The value of the specified variable, or defaultValue if not found.
+     */
+    const char* getVariable(const char* name, const char* defaultValue = NULL) const;
+
+    /**
+     * Sets the value of the specified variable.
+     *
+     * @param name Name of the variable to set.
+     * @param value The value to set.
+     */
+    void setVariable(const char* name, const char* value);
+
     /**
      * Attempts to parse the specified string as a Vector2 value.
      *
@@ -541,6 +561,7 @@ private:
     std::list<Property>::iterator _propertiesItr;
     std::vector<Properties*> _namespaces;
     std::vector<Properties*>::const_iterator _namespacesItr;
+    std::vector<Property>* _variables;
     std::string* _dirPath;
     Properties* _parent;
 };