Untitled

Published February 15, 2006
Advertisement
I'm slightly disappointed that my last entry didn't seem to peak anyone's interest. Here's a few examples of the pseudo definition and query syntax that would be used by the entity DB.

Object Definition
// Build a prototype objectobject obj("Prototype1");obj.define_attribute( "intAttribute", AT_INT );obj.define_attribute( "stringAttribute", AT_STRING );db.add_prototype( obj );


It would be possible to define a default value for the attributes and to pre-assign tags by adding them to the prototype. Because a protoype is an object it means that objects can be used to define other objects via cloning. In the following example the saved prototype is used to build another object:

// create other objects from the prototypeobject inst = db.create_object_from_prototype( "Prototype1" );inst.set_attribute( "intAttribute", 50 );inst.set_attribute( "stringAttribute", "test" );inst.add_tag( "test" );inst.add_tag( "another_test" );


In this case, I've added values and tags after the object has been built. I can then use this object how I need to, even to build other objects. If you've ever used SpiderMonkey (Mozilla's JS implementation) you will know what I mean.

Now that we have an object set up in the database we can run queries to retreive it.

Querying tagged objects

If you read my journal yesterday you will remember me talking about tags; these are a way of categorising an object for querying. With the pseudo-query select from global where tagged( "test", "another_test" ) broken into API functions you will see how we can retreive objects that are tagged with the categories "test" and "another_test".

query qry = db.create_query( QT_GET );query_condition cond1( COND_TAGGED, "test" );query_condition cond2( COND_TAGGED, "another_test" );query_condition cond( cond1, OP_AND, cond2 );qry.with_test( cond1 );object_set res = qry.execute();


You may also wish to retreive objects that are not tagged with a specific tag:

query qry = db.create_query( QT_GET );query_condition cond( COND_UNTAGGED, "test" );qry.with_test( cond );object_set res = qry.execute();



Querying object attributes

You will also need to be able to query the attributes of an object to build your result set. Imagine the pseudoquery select from global where intAttribute = 50 broken down:

query qry = db.create_query( QT_GET );query_condition cond( "intAttribute", OP_EQ, 50 );qry.with_test( cond );object_set res = qry.execute();


And with multiple tests (select from global where stringAttribute = "test" and intAttribute = 50)

query qry = db.create_query( QT_GET );query_condition cond1( "intAttribute", OP_EQ, 50 );query_condition cond2( "stringAttribute", OP_EQ, "test" );query_condition cond( cond1, OP_AND, cond2 );qry.with_test( cond );object_set res = qry.execute();



Querying with tags and attributes

You can then combine these to build object queries that test for both tags and attribute conditions. Imagine the pseudoquery select from global where stringAttribute != "test" and tagged( "myTag" ):

query qry = db.create_query( QT_GET );query_condition cond1( "stringAttribute", OP_NOTEQ, "test" );query_condition cond2( COND_TAGGED, "myTest" );query_condition cond( cond1, OP_AND, cond2 );qry.with_test( cond );object_set res = qry.execute();



Storing Queries

One powerful aspect of RDBMS databases is their ability to store values in a table or a 'view' (stored query). Because this isn't a traditional DB system we don't have the concept of 'table', but we can implement the concept of a view, or predefined query. This would add a huge amount of power to the system, letting users create their own recordsets to query.

The pseudoqueries you saw before all retreived from 'global', which is an implicit 'everything' recordset. This global recordset can be replaced with your stored query name(s), eg: select from MyQuery where dead = 0

// Storing a query in the DBdb.store_query( qry, "myStoredQuery" );// Using stored queries as datasourcesquery qry = db.create_query( QT_GET );qry.from_source( db.get_query( "myStoredQuery" ) );query_condition cond( "dead", OP_EQ, 0 );qry.with_test( cond );object_set res = qry.execute();


I have not yet considered the possibility of joins and such combinations outside of multiple query sources.

I am hoping that you can now see what I'm talking about.
Previous Entry Game Entity DB
Next Entry Untitled
0 likes 4 comments

Comments

Nit
Aside from the cool factor of rolling your own db system, how does this compare/differ from current available databases, i.e. SQLite, MySQL? Is it lightweight/fast? What you have shown here looks good.

I plan on using a database for my own project, but I still have to read up on cost/benefits of one implementation over the next.
February 15, 2006 08:47 AM
ApochPiQ
The last time I read your journal, I was far too brain-dead to have any clue what you were on about; now that I've re-read it with the benefit of consciousness, it sounds like a very interesting concept.

One slight philosophical tweak I would make, personally: let tags associate data with themselves. A bare object has no tags and is basically just a nameless, formless glob (or gormless fob, whichever you prefer). A tag consists of a nominative component and optional descriptive components; any object can have as many tags applied to it as is necessary.

To build off the initial example you provided, a purely nominative tag might be "Belongs to squad 1." However, I'd suggest a slightly different approach: the nominative portion is "Belongs to Squad" and a data component describes the actual squad number. This can then be generalized to many other things: team, unit type, properties (health, attack power, etc.), current orders, current AI routines... etc.


Slap on some judicious use of the Interpreter pattern, and you could get some interesting stuff: Find all objects tagged as 'Infantry Units' and tagged as 'Team A' and having tagged value 'Vitals.HP' < 20 percent of tagged value 'Vitals.MaxHP' That sort of structured language should be pretty easy to define a grammar and parse/execute engine for, especially combined with a generic object-tag system.


Just some thoughts.
February 15, 2006 01:32 PM
evolutional
RE: Nit

The question about using existing database systems is a very good one and is something I've put some thought into already. The system I'm describing here is atypical of the normal RDBMS model in that an entity isn't static in terms of properties. In a normal SQL database entities of the same type must all share the same properties; they cannot have additional attributes that others of the same 'type' have. You could acheive this in a small way by defining bolt-on tables that are linked via foreign keys to your master entity table but again these must all share the same attributes and it's impossible to modify them at runtime.

The main goal for this 'project' is to provide a database style system for games that doesn't force you into static models; it's designed to be dynamic so that you can assign additional data to entities whilst the game is running. Another primary goal is to be as 'independent' of any scripting or storage models as possible. This doesn't mean the system will not use technology, quite the opposite - it means that I'd like to have a system that could be accessed via the standard API that you see and have storage and other things implemented in whatever best suits the game it's being used in. This would mean that you could invoke method calls on objects scripted in Lua, GameMonkey, Python or whatever using the same API - it also means that data could be stored in a SQL database, in memory or in flat files such as XML.

It's interesting that you mention using SQL databases as the first prototype version I'm creating with this is actually based on the SQLite database. Although it fascinates me greatly to create my own database system, the amount of work spent to get just a simple prototype up will be prohibitive - I'll have to do reasearch into indexing, atomic transactions and all the stuff that makes up a database. So yeah, I have a simple table schema worked out for this system and will have to perform a bit of behind the scenes magic to make the query concepts mix (you can't query the entity db using SQL, for example).

One major piece of work with the project that I see right now is the caching side of it all; if objects are stored in a database we still need to maintain an in-memory cache of the 'active' objects - things that fall out of activity will be swapped out to the database and likewise for things becoming live.
February 15, 2006 02:57 PM
evolutional
Re: ApochPiQ

That's an interesting addition to the concept. I think I agree with the idea; it would allow you to start querying "all units attached to a squad", "all units attached to squad 2", "all units in a squad except squad 2", etc. It's definitely something I can see being used. The original philosophy would quickly get clunky without this in place, effectively meaning we'd be forced to assigning too many tags to objects to get what we wanted.

Thanks for this input, both of you =)
February 15, 2006 03:03 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement