Jump to content
  • Advertisement
Sign in to follow this  
Kest

Allocating unknown data

This topic is 4831 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I want to do something that appears complex (to myself), but I'll try to explain it very simply. I want to add a routine to construct tables in my scripting engine. This is my first rough idea of how to initialize the scripting engine with structure data:
struct Ship
{
  INT Type;     // Type of ship
  INT Men;      // Max number of men on the ship
  FLOAT Weight; // Weight of the ship
  String Name;  // Name of the ship
};

...

// Possibly in a class somewhere
Array<Ship> MyData;

....

// Preparing to parse a scripting file
TablePtr = ScriptEngine.AddTable( "Ships", &MyData );

Ship temp;
TablePtr->StartEntries( &temp ); // Records base offset
TablePtr->AddEntry_Int( &temp.Type ); // Records offset to Type
TablePtr->AddEntry_Int( &temp.Men ); // Records offset to Men
TablePtr->AddEntry_Float( &temp.Weight ); // Gets offset to Weight
TablePtr->AddEntry_String( &temp.Name ); // Records offset to Name
Now within the script file, I could do this:
CreateTable Ships:
  TYPE_ROWBOAT, 3, 25.0, "Swisher",
  TYPE_SPEEDER, 2, 65.0, "Blazer",
  TYPE_DESTROYER, 150, 1500.0, "Miap";
Keep in mind that this is an example. My real data would be a huge number of entries, and have nothing to do with ships. This script code would allocate the ship array size to 3 and fill in those three entries with the provided values. Filling in the data is easy, but I can't think of any way to allocate the array. My scripting engine has no access to the types of structures that may be used. It seems my only alternative would be to let my game allocate the data before running the script. Which would actually limit the number of entries available. I can also provide a script callback-like function to allocate the data, but one of these would need to be provided for every table addition ; a huge hassle. The really messy way to do it - just to make it clear what I'm trying to do - would be to allocate an array of bytes the size of three ship structs, then format the values of that data, then hand it back and pretend it's an array of ships. This is bad for business, though. Even my own custom memory manager would yell at me for trying to delete bytes as ships. I doubt I'll get many answers, but I'm getting desperate :) If anyone has any suggestions, I'd love to hear them.

Share this post


Link to post
Share on other sites
Advertisement
Part of your problem is a parsing issue: reading the file and interpreting the text found there as data used to build Ship objects. It can get arbitrarily complicated (e.g. a C++ compiler needs to parse C++ programs). Carefully designing the input format may greatly simplify your task. Don't get cute! Keep it simple! Correctly dealing with quoted strings isn't as easy as it seems. Consider using a library. Boost provides tokenizers as well as a full parser framework (Spirit). Alternatively, you can use parser generators like flex (lexer generator) and bison (parser generator).

The other part of the problem involves creating the actual Ship objects. If you know your file only contains Ship data, it's just a matter of grabbing the data for one Ship, passing it to the constructor (with new) and doing something with the new object. If the file contains mixed objects, you need to tell your parser what kind of object comes next (Ship, Banana, PowerPill...) so that it selects the correct loader functions. This means using a Factory.

There have been numerous articles on these topics on Gamedev. Check the Feature Articles archives.

Share this post


Link to post
Share on other sites
Quote:
Original post by Fruny
Part of your problem is a parsing issue: reading the file and interpreting the text found there as data used to build Ship objects. It can get arbitrarily complicated (e.g. a C++ compiler needs to parse C++ programs).

I currently have a really decent system running. It emulates C/C++ syntax. It supports arrays, functions, scope, loops, declaring data, etc. Here's one of my working parser files, used to create a sword:

StartKit( KIT_EQUIPMENT );

Tags_Name = "Avalon";
Tags_Desc = "It feels slightly heavy for its size.";
Tags_Weight = 4.0;
Tags_Value = 425.0;

Icon = DF( "WEAP_ShortSword_Unique_IconsA.png" );
IconIndex = 0;
EQClass = FindEQClass( "Short Sword" );

FireType = FIRE_MELEE_RAYS;
HitPoints = MaxHitPoints = 200.0;
SpeedFactor = 0.95;
PropertyFlags = 0;

PROPERTY[KITPROP_LENGTH] = 27.5;
PROPERTY[KITPROP_DAMAGE] = 2.0;

{
AddMaterial( "Metal", LIGHT_SHINYFRONT, COLOR(255,255,255,255), DEF_AMBIENCE, 1.0, 0 );

SetPropertyCount = 3; // Number of strings in each "Set" below
Sets.insert( "WEAP_ShortSword_Avalon.mesh", "Metal", "WEAP_ShortSword_Avalon_Default.png" );

SetShape( DNASP_TRIPPLE, 0 );
SetSphereStart( 0, -2.0, 0.0, -1.081, 0.85f );
SetSphereStart( 1, 2.0, 0.0, -1.081, 0.85f );
SetSphereStart( 2, 0.0, 0.0, -27.5, 0.45f );

SetSphereVelFactors( 0, 2.5f, 1.0f, 0.4f );
SetSphereVelFactors( 1, 2.5f, 1.0f, 0.4f );
SetSphereVelFactors( 2, 3.5f, 1.0f, 0.6f );

SetSound( KITSOUND_EQUIP, "SND_EQ_ShortSword_Draw.wav" );
SetSound( KITSOUND_UNEQUIP, "SND_EQ_ShortSword_Stow.wav" );
}








My parsing engine doesn't support structures of any kind, though, which is part of my problem. It means to allow filling lists with varying variable types, I have to provide code functions, such as SetSound() above.

The best feature about tables, though, if I get it working, is that you could allocate a solid array all at once by simply counting the number of entries before processing the text. The "Sets" variable above is an array, which can do the same thing - it can store any number of entries for each parsed object, but it can hold only one type at a time.

Quote:
Carefully designing the input format may greatly simplify your task. Don't get cute! Keep it simple!

Do you mean input as in the method in which my game engine sends data to the parser object? Or the parsed text itself?

Quote:
The other part of the problem involves creating the actual Ship objects. If you know your file only contains Ship data, it's just a matter of grabbing the data for one Ship, passing it to the constructor (with new) and doing something with the new object.

This is what I'm trying to do. Each table will only allow entries for one array of structures - ships. But I'm not sure how to allocate an array of ships inside of the parser engine without the outside-game-code providing some type of callback. I keep wanting to think <templates>, but I'm not sure they're going to help me.

My parser can currently only allocate basic types - it simply records what the type is for each variable. I just can't come up with a decent way to allocate unknown types. I would appreciate any help on this exact issue that you could give me.

Quote:
There have been numerous articles on these topics on Gamedev. Check the Feature Articles archives.

I'll take a look at those, thanks :)

[Edited by - Kest on August 29, 2005 4:09:56 AM]

Share this post


Link to post
Share on other sites
Another solution you probably dont like because you may want do it yourself is use an existent scripting language.

Widely used languages are

AngelScript (so simple to use that is ready to go)(C++ style!)
Lua (simple and widely used)
Python (powerful but difficult to embed)(it will be used in Civilazion4 next release)
CInt

Note that these language scripts are robust, tested and cross platform.

Share this post


Link to post
Share on other sites
Quote:
Original post by blizzard999
Another solution you probably dont like because you may want do it yourself is use an existent scripting language.

It's not that I want to do it myself, it's that its already done :)
I'm just looking into making a certain task flow more smoothly. Mainly defining large lists of structures.

Quote:
Note that these language scripts are robust, tested and cross platform.

Do they support a table-like method such as the one I'm proposing? I'm basically wanting an initializer-list like operation, such as the C/C++ code..
struct MyStruct { INT A; String B; };
MyStruct data[3] = {
{ 1, "Help" },
{ 5, "String" },
{ 3, "Nice" }
};

Same concept, except the data doesn't need declared when it's used. My parser can handle everything above except allocating 3 MyStruct's.

Share this post


Link to post
Share on other sites
Okay, I have an idea. This is a little crazy. I'm not even sure it will work:


// All of this can be defined in the parser engine:

typedef VOID* (FuncPtr_ParserTableAlloc)(INT array_count);

template <class Type>
VOID* ParserAllocator(INT array_count)
{
return new Type[ array_count ];
}

...

struct ParserTable
{
FuncPtr_ParserTableAlloc *Allocator;
VOID *Data;
SIZE_T SizeOfObject;
INT ArrayCount;
};

...

template <class Type>
ParserTable* Parser::AddTable(const CHAR *name, Type **array_ptr, INT *array_count)
{
ParserTable *table = new ParserTable;
table->Allocator = ParserAllocator<Type>;
table->SizeOfObject = sizeof( Type );
...
return table;
}

...

VOID ParserTable::SetArraySize(INT count)
{
Data = Allocator( count );
ArrayCount = count;
}




The game has no idea what happened. Of course this would create a new allocator function for every type of table, as before. But I wouldn't have to write them all by hand. Would this work? Seems nutso? I kinda like it :P

Share this post


Link to post
Share on other sites
Instead of trying to figure out ahead of time how many items you need to allocate, consider making use of std::vector.

As for determining what sort of thing to allocate, look at the Abstract Factory pattern.

Share this post


Link to post
Share on other sites
Judging from the data you've given for the original problem, my suggestion would be to use a linked list instead of an array. Is there any particular reason you're not doing this?

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Instead of trying to figure out ahead of time how many items you need to allocate, consider making use of std::vector.

Well, that's not so much the problem. When parsing, counting the number of items to allocate is as easy as counting through commas to end-block operators. So arrays are ideal for parser data.

Quote:
Original post by the_dannobot
Judging from the data you've given for the original problem, my suggestion would be to use a linked list instead of an array. Is there any particular reason you're not doing this?

Because it doesn't help anything? I still have to allocate the structures. I'm not following how a linked list fits the situation.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kest
Quote:
Original post by the_dannobot
Judging from the data you've given for the original problem, my suggestion would be to use a linked list instead of an array. Is there any particular reason you're not doing this?

Because it doesn't help anything? I still have to allocate the structures. I'm not following how a linked list fits the situation.

Maybe I misunderstood the problem. You don't know how many structures the user will allocate, so you can't know how big of an array to allocate. Instead of allocating all your memory at once in an array and reading into it, you could create a linked list and add a node to the end for every entry you read in until you reach the end of the "CreateTable".

Yes/No?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!