Game Development Community

C-code and Dynamic Fields

by Jason Gossiaux · in Torque 2D Beginner · 04/16/2016 (10:35 pm) · 4 replies

Howdy everyone.

In an attempt to improve level loading times, I've been testing various methods of moving Torquescript code into the Engine. This has worked very well in all other parts of my game, but here I am struggling a bit and could use some ideas.

The levels consist of 10,000 logical tiles. These are directly represented by 10000 sprites on two compositesprites- one for the map and one above it for fog of war. To track map data I use several ScriptObjects and a dozen or so [50][50] arrays.

When a new level is loaded the game must iterate through all 10000 tiles and setup the sprites and populate the map data. This process is taking about 45 seconds on my iPad 3rd Gen when done completely in TS.

Now, because I am using dynamic fields on generic scriptobjects, accessing them in C-code is made more difficult. Two problems exist.

* I cannot access dynamic fields in C-code until they are first created in TS. The engine throws an error when it isn't found in the hash table otherwise.

* The code is gnarly and this limits the speed improvement. For example:

fieldName = "tileType" + stringLocation;
entry= StringTable->insert(fieldName.c_str());
frame = to_string(TILE_STONE);
tempChar = frame.c_str();
tileManagerObject->getFieldDictionary()->setFieldValue(entry, tempChar);


The performance hit of first creating all of the dynamic fields and zeroing them out in Torquescript is negating any speed improvement by doing the dynamic field assignment and compositesprite setup in C code.

Does a simpler way exist to create and set large arrays of dynamic fields? The for-loops are what is killing me.




The next idea I had, was using persistent fields and creating new object types in C code. However, I have not seen a good example of addfield with an array.

Does a method exist for defining persist field arrays on an object and then accessing them through TS using the same %someObject.someArray[%x,%y] = %somevariable; syntax?

I followed the examples here :https://www.garagegames.com/community/forums/viewthread/133395

But it didn't quite get me far enough along. Thank you for any help you can give me!

-Jason



#1
04/17/2016 (7:36 am)
Well, technically it doesn't have to be an "array" - you could use a whitespace-separated string (using "val" SPC "val2" or "val" TAB "val2") - since passing arrays across the console control boundary is ugly. Or you could look into MangoFusion's TS2 - he's added native TS array objects and there should be at least one example of using one as an object field.

Also, I don't understand this:
Quote:The performance hit of first creating all of the dynamic fields and zeroing them out in Torquescript....
You don't have to zero them out - just create them. They are automatically "" when created, and you can store them on the saved object as theField=""; or simply add them using %theObj.theField=""; - boom, field created and is "". Then you test for $= "" or simply false (though that can be misleading as 0, "", and false all equal false in TS).

If you're saving the data out then loading it back in, the objects should be able to save out their fields and values then read them back in fairly quickly - are you manually iterating over the objects? If you store the data on script objects, then do you really need to duplicate the data on the sprite/compositesprite objects too? Or am I misunderstanding the design?
#2
04/17/2016 (8:57 am)
Yes, I do have to zero them out. If a dynamic field is not first created and initialized in TS, then it doesn't exist and the engine code will crash while searching the hash table for it.

It is extremely reproduce-able. Perhaps these functions are not the correct way to access dynamic fields from C-code?


tileManagerObject->getFieldDictionary()->setFieldValue(entry, tempChar);

or

tileManagerObject->getFieldDictionary()->getFieldValue(entry);

Will crash on line 79 of SimFieldDictionary.cc

void SimFieldDictionary::setFieldValue(StringTableEntry slotName, const char *value)
{
U32 bucket = HashPointer(slotName) % HashTableSize;
Entry **walk = &mHashTable[bucket];
-->while(*walk && (*walk)->slotName != slotName)
walk = &((*walk)->next);

Entry *field = *walk;
if(!*value)
{
if(field)



I studied how the Console Method of getDynamicField works, and it ends up calling these functions. Any insight would be appreciated :)


#3
04/17/2016 (9:31 am)
Many thanks to the folks on IRC. With their help I found a getDynamicField console method and saw it was using object->get/setDataField. Those methods appear to do some checking and stack protection prior to calling into the Dictionary, and it resolved my crashing problem.

Not sure how I missed them before, but I'm now seeing a good speed improvement!
#4
04/17/2016 (11:56 am)
Quote:Yes, I do have to zero them out. If a dynamic field is not first created and initialized in TS, then it doesn't exist and the engine code will crash while searching the hash table for it.
Ah - sorry - misunderstood which side of the curtain you were working on. If you save a Sprite with its dynamic fields it should load with those values intact. My thought was that if you were generating them once and then saving them then the rest was purely academic anyway since the values should simply load.