From 343ee56c1d670e35dc4bd57ab50755e79066817e Mon Sep 17 00:00:00 2001 From: Shpoike Date: Mon, 8 Mar 2021 00:23:12 +0000 Subject: [PATCH] Sythesize extension fields for mods that don't define them. This allows scale+colormod to be used, even for classic. --- Quake/pr_edict.c | 97 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 11 deletions(-) diff --git a/Quake/pr_edict.c b/Quake/pr_edict.c index 1323f4f2..df9682d1 100644 --- a/Quake/pr_edict.c +++ b/Quake/pr_edict.c @@ -1136,6 +1136,8 @@ void PR_ClearProgs(qcvm_t *vm) if (qcvm->knownstrings) Z_Free ((void *)qcvm->knownstrings); free(qcvm->edicts); // ericw -- sv.edicts switched to use malloc() + if (qcvm->fielddefs != (ddef_t *)((byte *)qcvm->progs + qcvm->progs->ofs_fielddefs)) + free(qcvm->fielddefs); free(qcvm->progs); // spike -- pr_progs switched to use malloc (so menuqc doesn't end up stuck on the early hunk nor wiped on every map change) memset(qcvm, 0, sizeof(*qcvm)); @@ -1143,6 +1145,88 @@ void PR_ClearProgs(qcvm_t *vm) PR_SwitchQCVM(oldvm); } +//makes sure extension fields are actually registered so they can be used for mappers without qc changes. eg so scale can be used. +static void PR_MergeEngineFieldDefs (void) +{ + struct { + const char *fname; + etype_t type; + int newidx; + } extrafields[] = + { //table of engine fields to add. we'll be using ED_FindFieldOffset for these later. + //this is useful for fields that should be defined for mappers which are not defined by the mod. + //future note: mutators will need to edit the mutator's globaldefs table too. remember to handle vectors and their 3 globals too. + {"alpha", ev_float}, //just because we can (though its already handled in a weird hacky way) + {"scale", ev_float}, //hurrah for being able to rescale entities. + {"emiteffectnum", ev_float}, //constantly emitting particles, even without moving. + {"traileffectnum", ev_float}, //custom effect for trails + //{"glow_size", ev_float}, //deprecated particle trail rubbish + //{"glow_color", ev_float}, //deprecated particle trail rubbish + {"tag_entity", ev_float}, //for setattachment to not bug out when omitted. + {"tag_index", ev_float}, //for setattachment to not bug out when omitted. + {"modelflags", ev_float}, //deprecated rubbish to fill the high 8 bits of effects. + //{"vw_index", ev_float}, //modelindex2 + //{"pflags", ev_float}, //for rtlights + //{"drawflags", ev_float}, //hexen2 compat + //{"abslight", ev_float}, //hexen2 compat + {"colormod", ev_vector}, //lighting tints + //{"glowmod", ev_vector}, //fullbright tints + //{"fatness", ev_float}, //bloated rendering... + //{"gravitydir", ev_vector}, //says which direction gravity should act for this ent... + + }; + int maxofs = qcvm->progs->entityfields; + int maxdefs = qcvm->progs->numfielddefs; + unsigned int j, a; + + //figure out where stuff goes + for (j = 0; j < countof(extrafields); j++) + { + extrafields[j].newidx = ED_FindFieldOffset(extrafields[j].fname); + if (extrafields[j].newidx < 0) + { + extrafields[j].newidx = maxofs; + maxdefs++; + if (extrafields[j].type == ev_vector) + maxdefs+=3; + maxofs+=type_size[extrafields[j].type]; + } + } + + if (maxdefs != qcvm->progs->numfielddefs) + { //we now know how many entries we need to add... + ddef_t *olddefs = qcvm->fielddefs; + qcvm->fielddefs = malloc(maxdefs * sizeof(*qcvm->fielddefs)); + memcpy(qcvm->fielddefs, olddefs, qcvm->progs->numfielddefs*sizeof(*qcvm->fielddefs)); + if (olddefs != (ddef_t *)((byte *)qcvm->progs + qcvm->progs->ofs_fielddefs)) + free(olddefs); + + //allocate the extra defs + for (j = 0; j < countof(extrafields); j++) + { + if (extrafields[j].newidx >= qcvm->progs->entityfields && extrafields[j].newidx < maxofs) + { //looks like its new. make sure ED_FindField can find it. + qcvm->fielddefs[qcvm->progs->numfielddefs].ofs = extrafields[j].newidx; + qcvm->fielddefs[qcvm->progs->numfielddefs].type = extrafields[j].type; + qcvm->fielddefs[qcvm->progs->numfielddefs].s_name = ED_NewString(extrafields[j].fname); + qcvm->progs->numfielddefs++; + + if (extrafields[j].type == ev_vector) + { //vectors are weird and annoying. + for (a = 0; a < 3; a++) + { + qcvm->fielddefs[qcvm->progs->numfielddefs].ofs = extrafields[j].newidx+a; + qcvm->fielddefs[qcvm->progs->numfielddefs].type = ev_float; + qcvm->fielddefs[qcvm->progs->numfielddefs].s_name = ED_NewString(va("%s_%c", extrafields[j].fname, 'x'+a)); + qcvm->progs->numfielddefs++; + } + } + } + } + qcvm->progs->entityfields = maxofs; + } +} + /* =============== PR_LoadProgs @@ -1151,7 +1235,6 @@ PR_LoadProgs qboolean PR_LoadProgs (const char *filename, qboolean fatal, unsigned int needcrc, builtin_t *builtins, size_t numbuiltins) { int i; - unsigned int u; PR_ClearProgs(qcvm); //just in case. @@ -1259,9 +1342,6 @@ qboolean PR_LoadProgs (const char *filename, qboolean fatal, unsigned int needcr qcvm->globaldefs[i].s_name = LittleLong (qcvm->globaldefs[i].s_name); } - for (u = 0; u < sizeof(qcvm->extfields)/sizeof(int); u++) - ((int*)&qcvm->extfields)[u] = -1; - for (i = 0; i < qcvm->progs->numfielddefs; i++) { qcvm->fielddefs[i].type = LittleShort (qcvm->fielddefs[i].type); @@ -1278,6 +1358,7 @@ qboolean PR_LoadProgs (const char *filename, qboolean fatal, unsigned int needcr qcvm->numbuiltins = numbuiltins; //spike: detect extended fields from progs + PR_MergeEngineFieldDefs(); #define QCEXTFIELD(n,t) qcvm->extfields.n = ED_FindFieldOffset(#n); QCEXTFIELDS_ALL QCEXTFIELDS_GAME @@ -1286,13 +1367,7 @@ qboolean PR_LoadProgs (const char *filename, qboolean fatal, unsigned int needcr QCEXTFIELDS_SS #undef QCEXTFIELD - i = qcvm->progs->entityfields; - if (qcvm->extfields.emiteffectnum < 0) - qcvm->extfields.emiteffectnum = i++; - if (qcvm->extfields.traileffectnum < 0) - qcvm->extfields.traileffectnum = i++; - - qcvm->edict_size = i * 4 + sizeof(edict_t) - sizeof(entvars_t); + qcvm->edict_size = qcvm->progs->entityfields * 4 + sizeof(edict_t) - sizeof(entvars_t); // round off to next highest whole word address (esp for Alpha) // this ensures that pointers in the engine data area are always // properly aligned