Jeff Hutchinson 4 lat temu
rodzic
commit
93500b6ac4

+ 1 - 1
Engine/source/console/console.cpp

@@ -1657,7 +1657,7 @@ static ConsoleValue _internalExecute(SimObject *object, S32 argc, ConsoleValue a
 
       if(ent == NULL)
       {
-         warnf(ConsoleLogEntry::Script, "%s: undefined for object '%s' - id %d", funcName, object->getName(), object->getId());
+         //warnf(ConsoleLogEntry::Script, "%s: undefined for object '%s' - id %d", funcName, object->getName(), object->getId());
 
          STR.clearFunctionOffset();
          return std::move(ConsoleValue());

+ 88 - 12
Engine/source/console/consoleInternal.cpp

@@ -183,13 +183,13 @@ void Dictionary::exportVariables(const char *varString, const char *fileName, bo
 
    for (s = sortList.begin(); s != sortList.end(); s++)
    {
-      switch ((*s)->value.getType())
+      switch ((*s)->type)
       {
-         case ConsoleValueType::cvInteger:
-            dSprintf(buffer, sizeof(buffer), "%s = %d;%s", (*s)->name, (*s)->value.getInt(), cat);
+         case Entry::TypeInternalInt:
+            dSprintf(buffer, sizeof(buffer), "%s = %d;%s", (*s)->name, (*s)->ival, cat);
             break;
-         case ConsoleValueType::cvFloat:
-            dSprintf(buffer, sizeof(buffer), "%s = %g;%s", (*s)->name, (*s)->value.getFloat(), cat);
+         case Entry::TypeInternalFloat:
+            dSprintf(buffer, sizeof(buffer), "%s = %g;%s", (*s)->name, (*s)->fval, cat);
             break;
          default:
             expandEscape(expandBuffer, (*s)->getStringValue());
@@ -243,11 +243,11 @@ void Dictionary::exportVariables(const char *varString, Vector<String> *names, V
 
       if (values)
       {
-         switch ((*s)->value.getType())
+         switch ((*s)->type)
          {
             case ConsoleValueType::cvInteger:
             case ConsoleValueType::cvFloat:
-               values->push_back(String((*s)->value.getString()));
+               values->push_back(String((*s)->getStringValue()));
                break;
             default:
                expandEscape(expandBuffer, (*s)->getStringValue());
@@ -473,17 +473,88 @@ Dictionary::Entry::Entry(StringTableEntry in_name)
    mUsage = NULL;
    mIsConstant = false;
    mNext = NULL;
-   // NOTE: This is data inside a nameless
-   // union, so we don't need to init the rest.
-   value.init();
+
+   ival = 0;
+   fval = 0;
+   sval = typeValueEmpty;
+   bufferLen = 0;
 }
 
 Dictionary::Entry::~Entry()
 {
+   reset();
+}
+
+void Dictionary::Entry::reset()
+{
+   name = NULL;
+   if (type <= TypeInternalString && sval != typeValueEmpty)
+      dFree(sval);
    if (notify)
       delete notify;
 }
 
+void Dictionary::Entry::setStringValue(const char* value)
+{
+   if (mIsConstant)
+   {
+      Con::errorf("Cannot assign value to constant '%s'.", name);
+      return;
+   }
+
+   if (type <= TypeInternalString)
+   {
+      // Let's not remove empty-string-valued global vars from the dict.
+      // If we remove them, then they won't be exported, and sometimes
+      // it could be necessary to export such a global.  There are very
+      // few empty-string global vars so there's no performance-related
+      // need to remove them from the dict.
+      /*
+       if(!value[0] && name[0] == '$')
+       {
+       gEvalState.globalVars.remove(this);
+       return;
+       }
+       */
+
+      U32 stringLen = dStrlen(value);
+
+      // If it's longer than 256 bytes, it's certainly not a number.
+      //
+      // (This decision may come back to haunt you. Shame on you if it
+      // does.)
+      if (stringLen < 256)
+      {
+         fval = dAtof(value);
+         ival = dAtoi(value);
+      }
+      else
+      {
+         fval = 0.f;
+         ival = 0;
+      }
+
+      type = TypeInternalString;
+
+      // may as well pad to the next cache line
+      U32 newLen = ((stringLen + 1) + 15) & ~15;
+
+      if (sval == typeValueEmpty)
+         sval = (char*)dMalloc(newLen);
+      else if (newLen > bufferLen)
+         sval = (char*)dRealloc(sval, newLen);
+
+      bufferLen = newLen;
+      dStrcpy(sval, value, newLen);
+   }
+   else
+      Con::setData(type, dataPtr, 0, 1, &value, enumTable);
+
+   // Fire off the notification if we have one.
+   if (notify)
+      notify->trigger();
+}
+
 const char *Dictionary::getVariable(StringTableEntry name, bool *entValid)
 {
    Entry *ent = lookup(name);
@@ -558,13 +629,18 @@ Dictionary::Entry* Dictionary::addVariable(const char *name,
    }
 
    Entry *ent = add(StringTable->insert(name));
+
+   if (ent->type <= Entry::TypeInternalString && ent->sval != typeValueEmpty)
+      dFree(ent->sval);
+
    ent->mUsage = usage;
+   ent->type = type;
+   ent->dataPtr = dataPtr;
 
    // Fetch enum table, if any.
-
    ConsoleBaseType* conType = ConsoleBaseType::getType(type);
    AssertFatal(conType, "Dictionary::addVariable - invalid console type");
-   ent->value.setConsoleData(type, dataPtr, conType->getEnumTable());
+   ent->enumTable = conType->getEnumTable();
 
    return ent;
 }

+ 94 - 25
Engine/source/console/consoleInternal.h

@@ -280,9 +280,18 @@ public:
 
    struct Entry
    {
+      friend class Dictionary;
+
+      enum
+      {
+         TypeInternalInt = -3,
+         TypeInternalFloat = -2,
+         TypeInternalString = -1,
+      };
+
       StringTableEntry name;
-      ConsoleValue value;
       Entry *nextEntry;
+      S32 type;
 
       typedef Signal<void()> NotifySignal;
 
@@ -296,6 +305,41 @@ public:
       /// Whether this is a constant that cannot be assigned to.
       bool mIsConstant;
 
+   protected:
+
+      // NOTE: This is protected to ensure no one outside
+      // of this structure is messing with it.
+
+#pragma warning( push )
+#pragma warning( disable : 4201 ) // warning C4201: nonstandard extension used : nameless struct/union
+
+      // An variable is either a real dynamic type or
+      // its one exposed from C++ using a data pointer.
+      //
+      // We use this nameless union and struct setup
+      // to optimize the memory usage.
+      union
+      {
+         struct
+         {
+            char* sval;
+            U32 ival;  // doubles as strlen when type is TypeInternalString
+            F32 fval;
+            U32 bufferLen;
+         };
+
+         struct
+         {
+            /// The real data pointer.
+            void* dataPtr;
+
+            /// The enum lookup table for enumerated types.
+            const EnumTable* enumTable;
+         };
+      };
+
+#pragma warning( pop ) // C4201
+
    public:
 
       Entry() {
@@ -312,26 +356,34 @@ public:
 
       Entry *mNext;
 
-      void reset() {
-         name = NULL;
-         value.reset();
-         if (notify)
-            delete notify;
-      }
+      void reset();
 
       inline U32 getIntValue()
       {
-         return value.getInt();
+         if (type <= TypeInternalString)
+            return ival;
+         else
+            return dAtoi(Con::getData(type, dataPtr, 0, enumTable));
       }
 
       inline F32 getFloatValue()
       {
-         return value.getFloat();
+         if (type <= TypeInternalString)
+            return fval;
+         else
+            return dAtof(Con::getData(type, dataPtr, 0, enumTable));
       }
 
       inline const char *getStringValue()
       {
-         return value.getString();
+         if (type == TypeInternalString)
+            return sval;
+         if (type == TypeInternalFloat)
+            return Con::getData(TypeF32, &fval, 0);
+         else if (type == TypeInternalInt)
+            return Con::getData(TypeS32, &ival, 0);
+         else
+            return Con::getData(type, dataPtr, 0, enumTable);
       }
 
       void setIntValue(U32 val)
@@ -342,7 +394,22 @@ public:
             return;
          }
 
-         value.setInt(val);
+         if (type <= TypeInternalString)
+         {
+            fval = (F32)val;
+            ival = val;
+            if (sval != typeValueEmpty)
+            {
+               dFree(sval);
+               sval = typeValueEmpty;
+            }
+            type = TypeInternalInt;
+         }
+         else
+         {
+            const char* dptr = Con::getData(TypeS32, &val, 0);
+            Con::setData(type, dataPtr, 0, 1, &dptr, enumTable);
+         }
 
          // Fire off the notification if we have one.
          if (notify)
@@ -357,27 +424,29 @@ public:
             return;
          }
 
-         value.setFloat(val);
-
-         // Fire off the notification if we have one.
-         if (notify)
-            notify->trigger();
-      }
-
-      void setStringValue(const char *newValue)
-      {
-         if (mIsConstant)
+         if (type <= TypeInternalString)
          {
-            Con::errorf("Cannot assign value to constant '%s'.", name);
-            return;
+            fval = val;
+            ival = static_cast<U32>(val);
+            if (sval != typeValueEmpty)
+            {
+               dFree(sval);
+               sval = typeValueEmpty;
+            }
+            type = TypeInternalFloat;
+         }
+         else
+         {
+            const char* dptr = Con::getData(TypeF32, &val, 0);
+            Con::setData(type, dataPtr, 0, 1, &dptr, enumTable);
          }
-
-         value.setString(newValue);
 
          // Fire off the notification if we have one.
          if (notify)
             notify->trigger();
       }
+
+      void setStringValue(const char* value);
    };
 
    struct HashTableData

+ 2 - 2
Engine/source/console/engineDoc.cpp

@@ -114,7 +114,7 @@ static void dumpVariable(  Stream& stream,
 {
    // Skip variables defined in script.
    
-   if( !entry->value.isConsoleType() )
+   if( entry->type <= Dictionary::Entry::TypeInternalString )
       return;
          
    // Skip internals... don't export them.
@@ -149,7 +149,7 @@ static void dumpVariable(  Stream& stream,
             
    // Skip variables for which we can't decipher their type.
 
-   ConsoleBaseType* type = ConsoleBaseType::getType( entry->value.getType() );
+   ConsoleBaseType* type = ConsoleBaseType::getType( entry->type );
    if( !type )
    {
       Con::errorf( "Can't find type for variable '%s'", entry->name );