Dynamically Adding Entities to a geWorld

Programming Reality Factory and Genesis3D.
Post Reply
User avatar
QuestOfDreams
Site Admin
Posts: 1520
Joined: Sun Jul 03, 2005 11:12 pm
Location: Austria
Contact:

Dynamically Adding Entities to a geWorld

Post by QuestOfDreams » Sat Oct 20, 2007 7:41 pm

The following code allows to add an entity to a geWorld at runtime. The entity can be of any class that is available in the editor
(as all entity class definitions are stored in the bsp file even if there is actually no entity of a specific type). All you have to pass to
the function is the current world, the name of the entity class, a name for the entity to identify it and the user data for that entity.
On success the function returns a pointer to the created geEntity, otherwise it returns a NULL pointer. :D

in Genesis.h add

Code: Select all

GENESISAPI geEntity* geWorld_AddEntity(
		geWorld		*World,
		const char	*ClassName,
		const char	*EntityName,
		void		*UserData)
in World.c add

Code: Select all

//========================================================================================
//	geWorld_AddEntity
//========================================================================================
GENESISAPI geEntity* geWorld_AddEntity(
		geWorld		*World,
		const char	*ClassName,
		const char	*EntityName,
		void		*UserData)
{
	geWorld_EntClassSet	*WSets;
	int32				i;
	geEntity			*Entity;
	geEntity_Class		*Class;
	
	assert(World);

	// No classname, just return
	if(!ClassName || !EntityName ||!UserData)
	{
		return NULL;
	}

	WSets = World->EntClassSets;
	
	Entity = geEntity_Create();
	if(!Entity)
	{
		return NULL;
	}

	// Add it to the main set
	if(!geEntity_EntitySetAddEntity(WSets[0].Set, Entity))
	{
		geEntity_Destroy(Entity);
		return NULL;
	}

	// create Epair for name (every entity needs one - should be unique but we don't check for it here)
	{
		geEntity_Epair *EntityNameEpair = geEntity_EpairCreate();
		
		EntityNameEpair->Key = geRam_Allocate(strlen("%Name%")+1);
		strcpy(EntityNameEpair->Key, "%Name%");
		
		EntityNameEpair->Value = geRam_Allocate(strlen(EntityName)+1);
		strcpy(EntityNameEpair->Value, EntityName);
		
		geEntity_AddEpair(Entity, EntityNameEpair);
	}

	// remember type class
	Class = geEntity_EntitySetFindClassByName(WSets[0].Set, ClassName);
	if(!Class)
	{
		geEntity_Destroy(Entity);
		return NULL;
	}

	Entity->Class = Class;

	// allocate space for user data
	Entity->UserData = GE_RAM_ALLOCATE_ARRAY(char, Entity->Class->FieldSize);
	if(!Entity->UserData)
	{
		geEntity_Destroy(Entity);
		return NULL;
	}
	memcpy(Entity->UserData, UserData, Entity->Class->FieldSize);
	
	// check all fields and look if there are any strings in this entity class
	// if so, add a new Epair, copy the string to the Epair->Value and
	// set the char pointer in the UserData to point to Epair->Value
	{
		geEntity_Field	*Field;
		char			*UData = Entity->UserData;
		
		for(Field=Class->Fields; Field; Field=Field->Next)
		{
			if(Field->TypeClass->Type == TYPE_STRING)
			{
				if(*(char**)(UData + Field->Offset) != NULL)
				{
					geEntity_Epair *Epair = geEntity_EpairCreate();

					// get fieldname
					Epair->Key = geRam_Allocate(strlen(Field->Name)+1);
					strcpy(Epair->Key, Field->Name);
				
					// copy string
					Epair->Value = geRam_Allocate(strlen(*(char**)(UData + Field->Offset))+1);
					strcpy(Epair->Value, *(char**)(UData + Field->Offset));
					*(char**)(UData + Field->Offset) = Epair->Value;

					// add epair to entity
					geEntity_AddEpair(Entity, Epair);
				}
			}
		}
	}
	
	// insert entity in class list
	for(i=1; i<World->NumEntClassSets; i++)
	{
		assert(WSets[i].Set);

		if(!stricmp(WSets[i].ClassName, ClassName))
		{			
			geEntity_EntitySetAddEntity(WSets[i].Set, Entity);
			return Entity;
		}
	}

	if(i >= MAX_WORLD_ENT_CLASS_SETS)
	{
		geEntity_Destroy(Entity);
		return NULL;					// oh well...
	}

	// Create a new entity set
	WSets[i].Set = geEntity_EntitySetCreate();

	// Insert the entity into a new class set
	WSets[i].ClassName = Entity->Class->Name;
	geEntity_EntitySetAddEntity(WSets[i].Set, Entity);

	World->NumEntClassSets++;

	return Entity;
}

User avatar
zany_001
Posts: 1047
Joined: Fri Mar 02, 2007 8:36 am
Location: Aotearoa

Post by zany_001 » Mon Oct 22, 2007 10:50 pm

so you can create lights etc. in the middle of the game?cool.
Once I was sad, and I stopped being sad and was awesome instead.
True story.

User avatar
QuestOfDreams
Site Admin
Posts: 1520
Joined: Sun Jul 03, 2005 11:12 pm
Location: Austria
Contact:

Post by QuestOfDreams » Tue Oct 23, 2007 12:04 am

Yes, that's an example, although this special case would have been doable before. First feature I'm using it for is to spawn an Attribute entity when dropping a weapon so you can pick it up again later.

User avatar
Juutis
Posts: 1511
Joined: Thu Jan 12, 2006 12:46 pm
Location: Finland

Post by Juutis » Tue Oct 23, 2007 9:59 am

Sounds great! I can see plenty of new possibilities with this feature.

Thanks QoD. :)
Pain is only psychological.

User avatar
zany_001
Posts: 1047
Joined: Fri Mar 02, 2007 8:36 am
Location: Aotearoa

Post by zany_001 » Wed Oct 24, 2007 2:30 am

yah tnks a lot.
Once I was sad, and I stopped being sad and was awesome instead.
True story.

User avatar
federico
RF Dev Team
Posts: 443
Joined: Tue Jul 05, 2005 3:14 pm
Contact:

Post by federico » Wed Oct 24, 2007 9:48 am

hoping to join the Physics release with the official RF, I will add this command to my genesis3d source, including my new command to globally rotate bones...

User avatar
darksmaster923
Posts: 1857
Joined: Wed Jan 03, 2007 10:32 pm
Location: Huntington Beach, California, USA
Contact:

Post by darksmaster923 » Thu Oct 25, 2007 12:34 am

will this be in the neu rf release??
Herp derp.

User avatar
federico
RF Dev Team
Posts: 443
Joined: Tue Jul 05, 2005 3:14 pm
Contact:

Post by federico » Thu Oct 25, 2007 1:37 am

The question should be: what will contain the new version of RF?
Anyway I added this command to the genesis3d source I packed for the physics release.

Post Reply