mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-05-31 00:30:57 +00:00
progs now internally uses plists for entity/global initialization, with support for direct conversion from id's format. This means that the entity string in a map (or the external ent file) can be a plist.
This commit is contained in:
parent
ab1102bcd0
commit
2a79f42eb5
3 changed files with 149 additions and 179 deletions
|
@ -229,12 +229,14 @@ void ED_PrintNum (progs_t *pr, int ent);
|
||||||
|
|
||||||
// pr_parse.c
|
// pr_parse.c
|
||||||
struct script_s;
|
struct script_s;
|
||||||
|
struct plitem_s;
|
||||||
qboolean ED_ParseEpair (progs_t *pr, pr_type_t *base, ddef_t *key,
|
qboolean ED_ParseEpair (progs_t *pr, pr_type_t *base, ddef_t *key,
|
||||||
const char *s);
|
const char *s);
|
||||||
void ED_Write (progs_t *pr, QFile *f, edict_t *ed);
|
void ED_Write (progs_t *pr, QFile *f, edict_t *ed);
|
||||||
void ED_WriteGlobals (progs_t *pr, QFile *f);
|
void ED_WriteGlobals (progs_t *pr, QFile *f);
|
||||||
void ED_ParseEdict (progs_t *pr, struct script_s *script, edict_t *ent);
|
void ED_InitGlobals (progs_t *pr, struct plitem_s *globals);
|
||||||
void ED_ParseGlobals (progs_t *pr, struct script_s *script);
|
void ED_InitEntity (progs_t *pr, struct plitem_s *entity, edict_t *ent);
|
||||||
|
struct plitem_s *ED_ConvertToPlist (progs_t *pr, struct script_s *script);
|
||||||
void ED_LoadFromFile (progs_t *pr, const char *data);
|
void ED_LoadFromFile (progs_t *pr, const char *data);
|
||||||
void ED_EntityParseFunction (progs_t *pr);
|
void ED_EntityParseFunction (progs_t *pr);
|
||||||
|
|
||||||
|
|
|
@ -281,136 +281,6 @@ ED_ParseEpair (progs_t *pr, pr_type_t *base, ddef_t *key, const char *s)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
ED_ParseEdict
|
|
||||||
|
|
||||||
Parses an edict out of the given string, returning the new position
|
|
||||||
ent should be a properly initialized empty edict.
|
|
||||||
Used for initial level load and for savegames.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
ED_ParseEdict (progs_t *pr, script_t *script, edict_t *ent)
|
|
||||||
{
|
|
||||||
ddef_t *key;
|
|
||||||
qboolean anglehack;
|
|
||||||
qboolean init = false;
|
|
||||||
dstring_t *keyname = dstring_new ();
|
|
||||||
const char *token;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
// clear it
|
|
||||||
if (ent != *(pr)->edicts) // hack
|
|
||||||
memset (&ent->v, 0, pr->progs->entityfields * 4);
|
|
||||||
|
|
||||||
// go through all the dictionary pairs
|
|
||||||
while (1) {
|
|
||||||
if (!Script_GetToken (script, 1))
|
|
||||||
PR_Error (pr, "ED_ParseEntity: EOF without closing brace");
|
|
||||||
// parse key
|
|
||||||
if (script->token->str[0] == '}')
|
|
||||||
break;
|
|
||||||
|
|
||||||
token = script->token->str;
|
|
||||||
// anglehack is to allow QuakeEd to write single scalar angles
|
|
||||||
// and allow them to be turned into vectors.
|
|
||||||
if (!strcmp (token, "angle")) {
|
|
||||||
token = "angles";
|
|
||||||
anglehack = true;
|
|
||||||
} else
|
|
||||||
anglehack = false;
|
|
||||||
|
|
||||||
if (!strcmp (token, "light"))
|
|
||||||
token = "light_lev"; // hack for single light def
|
|
||||||
|
|
||||||
dstring_copystr (keyname, token);
|
|
||||||
|
|
||||||
// another hack to fix heynames with trailing spaces
|
|
||||||
n = strlen (keyname->str);
|
|
||||||
while (n && keyname->str[n - 1] == ' ') {
|
|
||||||
keyname->str[n - 1] = 0;
|
|
||||||
n--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse value
|
|
||||||
//FIXME shouldn't cross line
|
|
||||||
if (!Script_GetToken (script, 1))
|
|
||||||
PR_Error (pr, "ED_ParseEntity: EOF without closing brace");
|
|
||||||
token = script->token->str;
|
|
||||||
|
|
||||||
if (token[0] == '}')
|
|
||||||
PR_Error (pr, "ED_ParseEntity: closing brace without data");
|
|
||||||
|
|
||||||
init = true;
|
|
||||||
|
|
||||||
// keynames with a leading underscore are used for utility comments,
|
|
||||||
// and are immediately discarded by quake
|
|
||||||
if (keyname->str[0] == '_')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
key = PR_FindField (pr, keyname->str);
|
|
||||||
if (!key) {
|
|
||||||
if (!pr->parse_field
|
|
||||||
|| !pr->parse_field (pr, keyname->str, token)) {
|
|
||||||
Sys_Printf ("'%s' is not a field\n", keyname->str);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (anglehack) {
|
|
||||||
ret = ED_ParseEpair (pr, ent->v, key, va ("0 %s 0", token));
|
|
||||||
} else {
|
|
||||||
ret = ED_ParseEpair (pr, ent->v, key, token);
|
|
||||||
}
|
|
||||||
if (!ret)
|
|
||||||
PR_Error (pr, "ED_ParseEdict: parse error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!init)
|
|
||||||
ent->free = true;
|
|
||||||
|
|
||||||
dstring_delete (keyname);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ED_ParseGlobals (progs_t *pr, script_t *script)
|
|
||||||
{
|
|
||||||
dstring_t *keyname = dstring_new ();
|
|
||||||
ddef_t *key;
|
|
||||||
const char *token;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
// parse key
|
|
||||||
if (!Script_GetToken (script, 1))
|
|
||||||
PR_Error (pr, "ED_ParseEntity: EOF without closing brace");
|
|
||||||
token = script->token->str;
|
|
||||||
if (token[0] == '}')
|
|
||||||
break;
|
|
||||||
|
|
||||||
dstring_copystr (keyname, script->token->str);
|
|
||||||
|
|
||||||
// parse value
|
|
||||||
//FIXME shouldn't cross line
|
|
||||||
if (!Script_GetToken (script, 1))
|
|
||||||
PR_Error (pr, "ED_ParseEntity: EOF without closing brace");
|
|
||||||
token = script->token->str;
|
|
||||||
|
|
||||||
if (token[0] == '}')
|
|
||||||
PR_Error (pr, "ED_ParseEntity: closing brace without data");
|
|
||||||
|
|
||||||
key = PR_FindGlobal (pr, keyname->str);
|
|
||||||
if (!key) {
|
|
||||||
Sys_Printf ("'%s' is not a global\n", keyname->str);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ED_ParseEpair (pr, pr->pr_globals, key, token))
|
|
||||||
PR_Error (pr, "ED_ParseGlobals: parse error");
|
|
||||||
}
|
|
||||||
dstring_delete (keyname);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ED_ParseOld
|
ED_ParseOld
|
||||||
|
|
||||||
|
@ -424,26 +294,135 @@ ED_ParseGlobals (progs_t *pr, script_t *script)
|
||||||
Used for both fresh maps and savegame loads. A fresh map would also need
|
Used for both fresh maps and savegame loads. A fresh map would also need
|
||||||
to call ED_CallSpawnFunctions () to let the objects initialize themselves.
|
to call ED_CallSpawnFunctions () to let the objects initialize themselves.
|
||||||
*/
|
*/
|
||||||
static void
|
|
||||||
ED_ParseOld (progs_t *pr, script_t *script)
|
plitem_t *
|
||||||
|
ED_ConvertToPlist (progs_t *pr, script_t *script)
|
||||||
{
|
{
|
||||||
edict_t *ent = NULL;
|
plitem_t *plist = PL_NewArray ();
|
||||||
int inhibit = 0;
|
plitem_t *ent;
|
||||||
dfunction_t *func;
|
plitem_t *key;
|
||||||
pr_type_t *classname;
|
plitem_t *value;
|
||||||
ddef_t *def;
|
const char *token;
|
||||||
|
int anglehack;
|
||||||
|
|
||||||
while (Script_GetToken (script, 1)) { // parse ents
|
while (Script_GetToken (script, 1)) {
|
||||||
// parse the opening brace
|
token = script->token->str;
|
||||||
if (script->token->str[0] != '{')
|
if (!strequal (token, "{"))
|
||||||
PR_Error (pr, "ED_LoadFromFile: found %s when expecting {",
|
PR_Error (pr, "ED_ParseEntity: EOF without closing brace");
|
||||||
script->token->str);
|
ent = PL_NewDictionary ();
|
||||||
|
while (1) {
|
||||||
|
if (!Script_GetToken (script, 1))
|
||||||
|
PR_Error (pr, "ED_ParseEntity: EOF without closing brace");
|
||||||
|
token = script->token->str;
|
||||||
|
if (strequal (token, "}"))
|
||||||
|
break;
|
||||||
|
anglehack = 0;
|
||||||
|
if (strequal (token, "angle")) {
|
||||||
|
key = PL_NewString ("angles");
|
||||||
|
anglehack = 1;
|
||||||
|
} else if (strequal (token, "light")) {
|
||||||
|
key = PL_NewString ("light_lev");
|
||||||
|
} else {
|
||||||
|
key = PL_NewString (token);
|
||||||
|
}
|
||||||
|
if (!Script_TokenAvailable (script, 0))
|
||||||
|
PR_Error (pr, "ED_ParseEntity: EOL without value");
|
||||||
|
Script_GetToken (script, 0);
|
||||||
|
token = script->token->str;
|
||||||
|
if (strequal (token, "}"))
|
||||||
|
PR_Error (pr, "ED_ParseEntity: closing brace without data");
|
||||||
|
if (anglehack)
|
||||||
|
value = PL_NewString (va ("0 %s 0", token));
|
||||||
|
else
|
||||||
|
value = PL_NewString (token);
|
||||||
|
PL_D_AddObject (ent, key, value);
|
||||||
|
}
|
||||||
|
PL_A_AddObject (plist, ent);
|
||||||
|
}
|
||||||
|
return plist;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ent)
|
|
||||||
|
void
|
||||||
|
ED_InitGlobals (progs_t *pr, plitem_t *globals)
|
||||||
|
{
|
||||||
|
ddef_t *global;
|
||||||
|
plitem_t *keys;
|
||||||
|
int count;
|
||||||
|
const char *global_name;
|
||||||
|
const char *value;
|
||||||
|
|
||||||
|
keys = PL_D_AllKeys (globals);
|
||||||
|
count = PL_A_NumObjects (keys);
|
||||||
|
while (count--) {
|
||||||
|
global_name = PL_String (PL_ObjectAtIndex (keys, count));
|
||||||
|
value = PL_String (PL_ObjectForKey (globals, global_name));
|
||||||
|
global = PR_FindField (pr, global_name);
|
||||||
|
if (!global) {
|
||||||
|
Sys_Printf ("'%s' is not a global\n", global_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!ED_ParseEpair (pr, pr->pr_globals, global, value))
|
||||||
|
PR_Error (pr, "ED_ParseGlobals: parse error");
|
||||||
|
}
|
||||||
|
PL_Free (keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ED_InitEntity (progs_t *pr, plitem_t *entity, edict_t *ent)
|
||||||
|
{
|
||||||
|
ddef_t *field;
|
||||||
|
plitem_t *keys;
|
||||||
|
const char *field_name;
|
||||||
|
const char *value;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
keys = PL_D_AllKeys (entity);
|
||||||
|
count = PL_A_NumObjects (keys);
|
||||||
|
while (count--) {
|
||||||
|
field_name = PL_String (PL_ObjectAtIndex (keys, count));
|
||||||
|
value = PL_String (PL_ObjectForKey (entity, field_name));
|
||||||
|
field = PR_FindField (pr, field_name);
|
||||||
|
if (!field) {
|
||||||
|
if (!pr->parse_field
|
||||||
|
|| !pr->parse_field (pr, field_name, value)) {
|
||||||
|
Sys_Printf ("'%s' is not a field\n", field_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!ED_ParseEpair (pr, ent->v, field, value))
|
||||||
|
PR_Error (pr, "ED_InitEntity: parse error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PL_Free (keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ED_SpawnEntities (progs_t *pr, plitem_t *entity_list)
|
||||||
|
{
|
||||||
|
edict_t *ent;
|
||||||
|
int inhibit;
|
||||||
|
plitem_t *entity;
|
||||||
|
plitem_t *item;
|
||||||
|
int i;
|
||||||
|
int count;
|
||||||
|
const char *classname;
|
||||||
|
dfunction_t *func;
|
||||||
|
|
||||||
|
count = PL_A_NumObjects (entity_list);
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
entity = PL_ObjectAtIndex (entity_list, i);
|
||||||
|
|
||||||
|
item = PL_ObjectForKey (entity, "classname");
|
||||||
|
if (!item)
|
||||||
|
PR_Error (pr, "no classname for entity %d", i);
|
||||||
|
classname = PL_String (item);
|
||||||
|
if (strequal (classname, "worldspawn"))
|
||||||
ent = EDICT_NUM (pr, 0);
|
ent = EDICT_NUM (pr, 0);
|
||||||
else
|
else
|
||||||
ent = ED_Alloc (pr);
|
ent = ED_Alloc (pr);
|
||||||
ED_ParseEdict (pr, script, ent);
|
|
||||||
|
ED_InitEntity (pr, entity, ent);
|
||||||
|
|
||||||
// remove things from different skill levels or deathmatch
|
// remove things from different skill levels or deathmatch
|
||||||
if (pr->prune_edict && pr->prune_edict (pr, ent)) {
|
if (pr->prune_edict && pr->prune_edict (pr, ent)) {
|
||||||
|
@ -452,20 +431,10 @@ ED_ParseOld (progs_t *pr, script_t *script)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// immediately call spawn function
|
//XXX should the field be checked instead of going direct?
|
||||||
def = PR_FindField (pr, "classname");
|
func = PR_FindFunction (pr, classname);
|
||||||
if (!def) {
|
|
||||||
Sys_Printf ("No classname for:\n");
|
|
||||||
ED_Print (pr, ent);
|
|
||||||
ED_Free (pr, ent);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
classname = &ent->v[def->ofs];
|
|
||||||
|
|
||||||
// look for the spawn function
|
|
||||||
func = PR_FindFunction (pr, PR_GetString (pr, classname->string_var));
|
|
||||||
if (!func) {
|
if (!func) {
|
||||||
Sys_Printf ("No spawn function for:\n");
|
Sys_Printf ("No spawn function for :\n");
|
||||||
ED_Print (pr, ent);
|
ED_Print (pr, ent);
|
||||||
ED_Free (pr, ent);
|
ED_Free (pr, ent);
|
||||||
continue;
|
continue;
|
||||||
|
@ -476,14 +445,13 @@ ED_ParseOld (progs_t *pr, script_t *script)
|
||||||
if (pr->flush)
|
if (pr->flush)
|
||||||
pr->flush ();
|
pr->flush ();
|
||||||
}
|
}
|
||||||
|
|
||||||
Sys_DPrintf ("%i entities inhibited\n", inhibit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ED_LoadFromFile (progs_t *pr, const char *data)
|
ED_LoadFromFile (progs_t *pr, const char *data)
|
||||||
{
|
{
|
||||||
script_t *script;
|
script_t *script;
|
||||||
|
plitem_t *entity_list;
|
||||||
|
|
||||||
if (pr->edict_parse) {
|
if (pr->edict_parse) {
|
||||||
PR_PushFrame (pr);
|
PR_PushFrame (pr);
|
||||||
|
@ -498,17 +466,17 @@ ED_LoadFromFile (progs_t *pr, const char *data)
|
||||||
Script_Start (script, "ent data", data);
|
Script_Start (script, "ent data", data);
|
||||||
|
|
||||||
if (Script_GetToken (script, 1)) {
|
if (Script_GetToken (script, 1)) {
|
||||||
if (*script->token->str == '(') {
|
if (strequal (script->token->str, "(")) {
|
||||||
// new style (plist) entity data
|
// new style (plist) entity data
|
||||||
plitem_t *plist = PL_GetPropertyList (data);
|
entity_list = PL_GetPropertyList (data);
|
||||||
plist = plist;
|
|
||||||
} else {
|
} else {
|
||||||
// oldstyle entity data
|
// oldstyle entity data
|
||||||
Script_UngetToken (script);
|
Script_UngetToken (script);
|
||||||
ED_ParseOld (pr, script);
|
entity_list = ED_ConvertToPlist (pr, script);
|
||||||
}
|
}
|
||||||
|
Script_Delete (script);
|
||||||
|
ED_SpawnEntities (pr, entity_list);
|
||||||
}
|
}
|
||||||
Script_Delete (script);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -47,6 +47,7 @@ static __attribute__ ((used)) const char rcsid[] =
|
||||||
#include "QF/keys.h"
|
#include "QF/keys.h"
|
||||||
#include "QF/model.h"
|
#include "QF/model.h"
|
||||||
#include "QF/msg.h"
|
#include "QF/msg.h"
|
||||||
|
#include "QF/qfplist.h"
|
||||||
#include "QF/screen.h"
|
#include "QF/screen.h"
|
||||||
#include "QF/script.h"
|
#include "QF/script.h"
|
||||||
#include "QF/sys.h"
|
#include "QF/sys.h"
|
||||||
|
@ -521,11 +522,12 @@ Host_Loadgame_f (void)
|
||||||
QFile *f;
|
QFile *f;
|
||||||
char *mapname = 0;
|
char *mapname = 0;
|
||||||
script_t *script = 0;
|
script_t *script = 0;
|
||||||
|
plitem_t *list;
|
||||||
char *str = 0;
|
char *str = 0;
|
||||||
float time, tfloat;
|
float time, tfloat;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
edict_t *ent;
|
|
||||||
int entnum;
|
int entnum;
|
||||||
|
int count;
|
||||||
int version;
|
int version;
|
||||||
float spawn_parms[NUM_SPAWN_PARMS];
|
float spawn_parms[NUM_SPAWN_PARMS];
|
||||||
|
|
||||||
|
@ -614,26 +616,24 @@ Host_Loadgame_f (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the edicts out of the savegame file
|
// load the edicts out of the savegame file
|
||||||
|
list = ED_ConvertToPlist (&sv_pr_state, script);
|
||||||
|
|
||||||
entnum = -1; // -1 is the globals
|
entnum = -1; // -1 is the globals
|
||||||
while (Script_GetToken (script, 1)) {
|
count = PL_A_NumObjects (list) - 1;
|
||||||
if (strcmp (script->token->str, "{"))
|
for (entnum = -1; entnum < count; entnum++) {
|
||||||
Sys_Error ("First token isn't a brace");
|
plitem_t *entity = PL_ObjectAtIndex (list, entnum + 1);
|
||||||
|
if (entnum == -1) {
|
||||||
if (entnum == -1) { // parse the global vars
|
ED_InitGlobals (&sv_pr_state, entity);
|
||||||
ED_ParseGlobals (&sv_pr_state, script);
|
} else {
|
||||||
} else { // parse an edict
|
edict_t *ent = EDICT_NUM (&sv_pr_state, entnum);
|
||||||
|
|
||||||
ent = EDICT_NUM (&sv_pr_state, entnum);
|
|
||||||
memset (&ent->v, 0, sv_pr_state.progs->entityfields * 4);
|
memset (&ent->v, 0, sv_pr_state.progs->entityfields * 4);
|
||||||
ent->free = false;
|
ent->free = false;
|
||||||
ED_ParseEdict (&sv_pr_state, script, ent);
|
ED_InitEntity (&sv_pr_state, entity, ent);
|
||||||
|
|
||||||
// link it into the bsp tree
|
// link it into the bsp tree
|
||||||
if (!ent->free)
|
if (!ent->free)
|
||||||
SV_LinkEdict (ent, false);
|
SV_LinkEdict (ent, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
entnum++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sv.num_edicts = entnum;
|
sv.num_edicts = entnum;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue