Loading External .Ent Files

Post tutorials on how to do certain tasks within game or engine code here.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Loading External .Ent Files

Post by Baker »

External entity files are files like start.ent that you throw in quake\id1\maps folder that are just a text file of the entities and these get used instead of the entities in the map (like start.bsp).

Particularly useful for Frikbot waypoints, CTF or altering the entities in a single player map for whatever reason.

Every engine should support this, there is a bit of naming differences among the engines as to the cvar name to turn the feature on or off (it is always defaulted on by every engine) ...

DarkPlaces uses: sv_entpatch
FTEQW, ezQuake use: sv_loadentfiles
Oldy QIPQuake uses: external_ents

Anyway ...

1. Open sv_main.c and go to the function SV_SpawnServer.
2. Locate this code:

Code: Select all

	ED_LoadFromFile (sv.worldmodel->entities);
3. Replace with ...

Code: Select all

	{
#define SUPPORTS_EXTERNAL_ENTS 1
#if SUPPORTS_EXTERNAL_ENTS
		char *entitystring = NULL;
		if ((entitystring = (char *)COM_LoadHunkFile (va ("maps/%s.ent", sv.name))))
		{
			Con_DPrintf ("Using entfile maps/%s.ent\n", sv.name);
			// To do: Maybe set some cvar to the .ent file name
			ED_LoadFromFile (entitystring);
			// Ideally we should free the entitystring here, except we put it on the hunk
			// which gets cleared on a new map.  But we are wasting some memory here
			// .ent files can occasionally be rather big (1 MB or 2 MB) but usually aren't.
		}
		else // Either we aren't using external ent files or we didn't have one, load the old fashioned way
#endif
			ED_LoadFromFile (sv.worldmodel->entities); // Baker: This isn't loading from "file" but from memory
	}
The End.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

I always wanted to add this feature but I'm paranoid about how to properly handle brush models.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
metlslime
Posts: 316
Joined: Tue Feb 05, 2008 11:03 pm

Post by metlslime »

should work the same way -- the entity lump in a bsp is just text, and the references to the brushmodels are just strings like "*12" so that same string could be stored in an external ent file.
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

It's not so much that (which does work) - it's the fact that someone could try to add extra brush model entities to the replacement lump but which don't exist in the original BSP. Easy to test though, I guess.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Post by Spike »

the respective setmodel call can catch it and 'safely' crash if that makes you any happier. if it doesn't match then it doesn't match.
the good thing about stuff like quakeworld or auto downloads and stuff is that there's generally only one 'true' version of the bsp, other versions are renamed. alphas are bad, but they don't linger long when you have servers accusing people of cheating when they have them installed. :)
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

mh wrote:It's not so much that (which does work) - it's the fact that someone could try to add extra brush model entities to the replacement lump but which don't exist in the original BSP. Easy to test though, I guess.
They could foobar a bsp -doents (-doentsonly? what it is) and royally mess up .bsp if they wanted to.

Most people doing stuff like this have mapping or modding experience and don't really need that kind of supervision. And those that are going to mess up will mess up and learn anyways.

/One thought on the topic
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

Baker wrote:They could foobar a bsp -doents (-doentsonly? what it is) and royally mess up .bsp if they wanted to.
That's a fair point and a valid counter-argument.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

If you want to be really nice, you can make it so mappers can copy the entities string (whether or not you loaded external entities) to the clipboard.

Many times someone new will want or need to do this for some reason. And then you have to explain how you open a text editor, find the entities, copy them and without external ent support then you have to download a qbsp save the text file as .ent and run qbsp with such and such params.

This isn't user-friendly.

Code: Select all

#ifdef SUPPORTS_CLIPBOARD
/*
================
Con_Copy_f -- Baker -- adapted from Con_Dump
================
*/
void Con_Copy_f (void)
{
	char	outstring[CON_TEXTSIZE]="";
	int		l, x;
	char	*line;
	char	buffer[1024];

	if (Cmd_Argc() > 1) // More than just the command
	{
		if (strcmp(Cmd_Argv(1), "ents")==0)  // If argument "ents" passed and we have an entitystring
		{
			extern char *entitystring;
			if (!sv.active)		{ Con_Printf ("copy ents: Not running a server"); return; }
			if (!entitystring)  { Con_Printf ("copy ents: No entities to copy");   return; }  // How would this happen, btw? 
			
			Sys_CopyToClipboard (entitystring);

			Con_Printf ("Entities copied to the clipboard (%i bytes)\n", strlen(entitystring));
			return;
		}
		else // Invalid args
		{
			Con_Printf ("Usage: copy [ents]\n");
			return;
		}

	}
.
.
.

}
#endif
The above works because I make some changes in my engine so that entitystring points to sv.worldmodel->entities if external entities weren't loaded.

Code: Select all

	entitystring = NULL; // Baker: Kill the reference
#define SUPPORTS_EXTERNAL_ENTS 1
#if SUPPORTS_EXTERNAL_ENTS
	if (sv_loadentfiles.value && (entitystring = (char *)COM_LoadHunkFile (va ("maps/%s.ent", sv.name))))
	{
		Con_DPrintf ("Using entfile maps/%s.ent\n", sv.name);
		// To do: Maybe set some cvar to the .ent file name
	}
	else // Either we aren't using external ent files or we didn't have one, load the old fashioned way
#endif
		entitystring = sv.worldmodel->entities; // Point it to the standard entities string
	
	ED_LoadFromFile (entitystring); // Baker: This isn't loading from "file" but from memory
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

A cool feature would be the ability to specify a .ent file to be loaded from the console and have it load the next time a map loads. Obviously not going to compatible with save games so that will need to be worked over, but I could see it speeding up processes such as monster placement a good bit.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

mh wrote:A cool feature would be the ability to specify a .ent file to be loaded from the console and have it load the next time a map loads. Obviously not going to compatible with save games so that will need to be worked over, but I could see it speeding up processes such as monster placement a good bit.
I'm not talking CSQC here, but you could have "client side" entity placement.

Basically, this is an array of "models" and their positions that is entirely client side that gets added to the model drawing list but isn't part of the set of entities.

In CTF it is common to have to take a non-CTF level and go around and look for places to put flags. You'd have to walk around the level and figure out the "right" place a for a flag and type "viewpos" to get the map position you were at.

During maybe Quake Expo 2006 (?) or 2008, some mapper made a tool that was supposed to help with entity placement. Of course, he wasn't able to make a way to actually save the data within QuakeC. I can't remember the name of this (and I bet the tool is super-buried in the Func forums), but the need for these kind of things do exist and people have to use very primitive and silly ways to do them currently.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Lardarse
Posts: 266
Joined: Sat Nov 05, 2005 1:58 pm
Location: Bristol, UK

Post by Lardarse »

I also remember that tool. QExpo 2008, I believe. Sadly, I do not remember who it was either.

Exporting in .ent/.map format using FRIK_FILE would seem to be the way to go, if anyone ever finds it, finds the source, and feels like working on it.
Roaming status: Testing and documentation
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

Lardarse wrote:I also remember that tool. QExpo 2008, I believe. Sadly, I do not remember who it was either.

Exporting in .ent/.map format using FRIK_FILE would seem to be the way to go, if anyone ever finds it, finds the source, and feels like working on it.
http://qexpo.tastyspleen.net/booth.php?id=203
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
szo
Posts: 132
Joined: Mon Dec 06, 2010 4:42 pm

Post by szo »

Noticed this one late. Baker: Is the following suits your needs? (Modified Mod_LoadEntities() for quakespasm-0.85.4 or svn version.)

Code: Select all

void Mod_LoadEntities (lump_t *l)
{
	char	entfilename[MAX_QPATH];
	char		*ents;
	int		mark;
	unsigned int	path_id;

	strcpy(entfilename, loadmodel->name);
	COM_StripExtension(entfilename, entfilename);
	strcat(entfilename, ".ent");
	Con_DPrintf("trying to load %s\n", entfilename);
	mark = Hunk_LowMark();
	ents = (char *) COM_LoadHunkFile (entfilename, &path_id);
	if (ents)
	{
		// use ent file only from the same gamedir as the map
		// itself or from a searchpath with higher priority.
		if (path_id < loadmodel->path_id)
		{
			Hunk_FreeToLowMark(mark);
			Con_Printf("ignored %s from a gamedir with lower priority\n", entfilename);
		}
		else
		{
			loadmodel->entities = ents;
			Con_DPrintf("Loaded external entity file %s\n", entfilename);
			return;
		}
	}

	if (!l->filelen)
	{
		loadmodel->entities = NULL;
		return;
	}
	loadmodel->entities = (char *) Hunk_AllocName ( l->filelen, loadname);
	memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
}
I can add this to our svn...
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

Comments ...

1) I'd make sure there is a cvar to control it (sv_loadentfiles is probably the best name). This is a feature that someone doing testing or working on a mod will occasionally want to turn off and reload the map.
szo wrote: ents = (char *) COM_LoadHunkFile (entfilename, &path_id);
if (ents)
{
// use ent file only from the same gamedir as the map
// itself or from a searchpath with higher priority.
2) Question: If I have gamedir frikbot and frikbot\maps\start.ent is for id1\maps\start.bsp ... is it going to load start.ent like it should? It does, right ... it just wouldn't load id1\maps\start.ent for quoth\map\start.bsp. Neat. (This is the solution to protect against loading wrong .lit files, isn't it).

3) Your code above is going to load entities for health boxes and ammo boxes from .ent files. The server is going to do anything with those, but I wanted you to be aware of that. There really isn't a need for loading external entities for anything except the server worldmodel (sv.name).
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
szo
Posts: 132
Joined: Mon Dec 06, 2010 4:42 pm

Post by szo »

Baker wrote:Comments ...

1) I'd make sure there is a cvar to control it (sv_loadentfiles is probably the best name). This is a feature that someone doing testing or working on a mod will occasionally want to turn off and reload the map.
Sounds reasonable. I'd prefer external_ents from QIP, though, because it is the first implementation (AFAIK)
Baker wrote:
szo wrote: ents = (char *) COM_LoadHunkFile (entfilename, &path_id);
if (ents)
{
// use ent file only from the same gamedir as the map
// itself or from a searchpath with higher priority.
2) Question: If I have gamedir frikbot and frikbot\maps\start.ent is for id1\maps\start.bsp ... is it going to load start.ent like it should? It does, right
Yes. Since frikbot is above id1 in the searchpath priority, it will load frikbot\maps\start.ent
Baker wrote:... it just wouldn't load id1\maps\start.ent for quoth\map\start.bsp. Neat.
Thanks. The idea was loosely from QIP, however this path_id implementation is shorter and much cleaner IMO.
Baker wrote:(This is the solution to protect against loading wrong .lit files, isn't it).
Yes. I use the same mechanism for the lit files, too.
Baker wrote:3) Your code above is going to load entities for health boxes and ammo boxes from .ent files. The server is going to do anything with those, but I wanted you to be aware of that. There really isn't a need for loading external entities for anything except the server worldmodel (sv.name).
Hmm, haven't thought of that one. (apparently QIP hadn't thought of that, either.) However that seems harmless and I don't think anyone would place individual *.ent files for ammo boxes, etc, either.
Post Reply