Server: add MapTweaks. A new feature that allows tinkerers to rewrite entity classnames under certain conditions (RFC)

This commit is contained in:
Marco Cawthorne 2023-04-22 02:37:17 -07:00
parent c5626ce347
commit cd3023eeba
Signed by: eukara
GPG Key ID: CE2032F0A2882A22
6 changed files with 232 additions and 1 deletions

View File

@ -491,6 +491,7 @@ worldspawn(void)
lightstyle(12, "mmnnmmnnnmmnn");
lightstyle(63, "a");
Skill_Init();
MapTweaks_Init();
precache_model("models/error.vvm");
@ -769,6 +770,9 @@ to remove in case we won't initialize it.
void
CheckSpawn(void() spawnfunc)
{
if (MapTweak_EntitySpawn(self))
return;
if (spawnfunc) {
spawnfunc();
self._mapspawned = true;

View File

@ -12,5 +12,6 @@ vote.qc
weapons.qc
modelevent.qc
mapcycle.qc
maptweaks.qc
entry.qc
#endlist

209
src/server/maptweaks.qc Normal file
View File

@ -0,0 +1,209 @@
/*
* Copyright (c) 2016-2022 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* early maptweaks implementation (RFC)
design notes:
needed system that handles entity renaming
or edits in an easy to understand syntax
replaces .ent file overrides for a lot of tasks
and can apply rules on all relevant maps based on
custom filters, either via serverinfo or via cvar.
TODO: immediately throw out things where cvar/infokey
checks fail and don't even cache them.
*/
typedef struct
{
string cvarCheck;
string serverinfoCheck;
string itemTable;
} mapTweak_t;
mapTweak_t *g_mapTweakTable;
var int g_mapTweakCount;
void
MapTweaks_Init(void)
{
filestream tweakFile;
string tempString;
string newCvar, newInfo, newItem;
int atTweak = 0i;
tweakFile = fopen("scripts/maptweaks.txt", FILE_READ);
g_mapTweakCount = 0;
newCvar = newInfo = newItem = "";
/* count valid entries. */
if (tweakFile >= 0) {
while ((tempString = fgets(tweakFile))) {
if (tokenize_console(tempString) == 1) {
if (argv(0) == "}")
g_mapTweakCount += 1;
}
}
} else {
return;
}
g_mapTweakTable = memalloc(sizeof(mapTweak_t) * g_mapTweakCount);
fseek(tweakFile, 0);
while ((tempString = fgets(tweakFile))) {
int segments = tokenize_console(tempString);
if (segments == 1) {
if (argv(0) == "}") {
g_mapTweakTable[atTweak].cvarCheck = newCvar;
g_mapTweakTable[atTweak].serverinfoCheck = newInfo;
g_mapTweakTable[atTweak].itemTable = newItem;
newCvar = newInfo = newItem = "";
atTweak++;
} else if (argv(0) == "{") {
/* ??? */
}
} else if (segments == 4) {
switch (argv(0)) {
case "when-cvar":
newCvar = strcat(newCvar, argv(1), " ", argv(2), " ", argv(3), " ");
break;
case "when-serverinfo":
newInfo = strcat(newInfo, argv(1), " ", argv(2), " ", argv(3), " ");
break;
}
} else if (segments == 3) {
switch (argv(0)) {
case "replace":
newItem = strcat(newItem, argv(1), " ", argv(2), " ");
break;
}
}
}
fclose(tweakFile);
}
static bool
MapTweak_Check(int id)
{
int segments = tokenize(g_mapTweakTable[id].cvarCheck);
/* cvars first */
for (int i = 0; i < segments; i += 3) {
string cvarName = argv(i);
string checkType = argv(i + 1);
float cvarValue = stof(argv(i + 2));
switch (checkType) {
case "equals":
if not (cvar(cvarName) == cvarValue)
return false;
break;
case "less-than":
if not (cvar(cvarName) < cvarValue)
return false;
break;
case "greater-than":
if not (cvar(cvarName) > cvarValue)
return false;
break;
case "is-not":
if not (cvar(cvarName) != cvarValue)
return false;
break;
}
}
segments = tokenize(g_mapTweakTable[id].serverinfoCheck);
/* infokeys second */
for (int i = 0; i < segments; i += 3) {
string infoName = argv(i);
string checkType = argv(i + 1);
float infoValue = stof(argv(i + 2));
switch (checkType) {
case "equals":
if not (serverkeyfloat(infoName) == infoValue)
return false;
break;
case "less-than":
if not (serverkeyfloat(infoName) < infoValue)
return false;
break;
case "greater-than":
if not (serverkeyfloat(infoName) > infoValue)
return false;
break;
case "is-not":
if not (serverkeyfloat(infoName) != infoValue)
return false;
break;
}
}
return true;
}
static void
MapTweak_FinishSpawn(entity targetEntity, string newClassname)
{
entity oldSelf = self;
self = targetEntity;
if (!isfunction(newClassname)) {
self.classname = strcat("spawnfunc_", newClassname);
} else {
self.classname = newClassname;
}
callfunction(self.classname);
self = oldSelf;
}
bool
MapTweak_EntitySpawn(entity targetEntity)
{
string classCheck = targetEntity.classname;
if (g_mapTweakCount <= 0)
return false;
for (int i = 0; i < g_mapTweakCount; i++) {
int segments = tokenize(g_mapTweakTable[i].itemTable);
for (int y = 0; y < segments; y += 2) {
string newEnt, oldEnt;
oldEnt = argv(y);
newEnt = argv(y + 1);
if (classCheck == oldEnt) {
if (MapTweak_Check(i) == true) {
MapTweak_FinishSpawn(targetEntity, newEnt);
return true;
} else {
break;
}
}
}
}
return false;
}

View File

@ -110,7 +110,6 @@ private:
#endif
PREDICTED_FLOAT(health)
PREDICTED_FLOAT(armor)
PREDICTED_FLOAT_N(colormap)
PREDICTED_FLOAT_N(gflags)

View File

@ -46,6 +46,8 @@ class NSSurfacePropEntity:NSRenderableEntity
private:
float m_flBurnNext;
PREDICTED_FLOAT(armor)
#ifdef SERVER
/* fire/burning */
entity m_eBurner;
@ -126,6 +128,11 @@ public:
/** Returns the maximum health the entity can have. */
nonvirtual float GetMaxHealth(void);
/** Sets the current armor of the entity. */
nonvirtual void SetArmor(float);
/** Returns the current armor of the entity. */
nonvirtual float GetArmor(void);
/** Returns the health the entity spawned with at map load */
nonvirtual float GetSpawnHealth(void);
/** Returns if the entity has prop data information set. */

View File

@ -402,6 +402,17 @@ NSSurfacePropEntity::GetSpawnHealth(void)
return m_oldHealth;
}
void
NSSurfacePropEntity::SetArmor(float new_armor)
{
armor = new_armor;
}
float
NSSurfacePropEntity::GetArmor(void)
{
return armor;
}
bool
NSSurfacePropEntity::HasPropData(void)
{