From 251713121cf500ed6048203cdf38def17b1d4e6b Mon Sep 17 00:00:00 2001 From: Marco Hladik Date: Tue, 21 Sep 2021 20:33:09 +0200 Subject: [PATCH] PropData: Add support for the BreakModel info parsing. Any CBaseEntity can now be augmented. prop_physics entities can already make use of them. --- base/src/server/player.qc | 7 +- src/gs-entbase/server/basephysics.h | 1 + src/gs-entbase/server/basephysics.qc | 48 ++-- src/gs-entbase/shared/baseentity.qc | 6 +- src/server/entry.qc | 2 +- src/shared/propdata.h | 11 +- src/shared/propdata.qc | 320 +++++++++++++++++++++------ src/shared/sound.qc | 6 +- 8 files changed, 295 insertions(+), 106 deletions(-) diff --git a/base/src/server/player.qc b/base/src/server/player.qc index 5d62ea56..2fa102ef 100644 --- a/base/src/server/player.qc +++ b/base/src/server/player.qc @@ -85,8 +85,11 @@ void CSEv_PlayerSwitchWeapon_i(int w) { player pl = (player)self; - pl.activeweapon = w; - Weapons_Draw(); + + if (pl.activeweapon != w) { + pl.activeweapon = w; + Weapons_Draw(); + } } void diff --git a/src/gs-entbase/server/basephysics.h b/src/gs-entbase/server/basephysics.h index 6b7ca39c..2e444317 100644 --- a/src/gs-entbase/server/basephysics.h +++ b/src/gs-entbase/server/basephysics.h @@ -42,6 +42,7 @@ class CBasePhysics:CBaseEntity virtual void(void) touch; virtual void(void) TouchThink; virtual void(void) Pain; + virtual void(void) Death; virtual void(float) SetMass; virtual float(void) GetMass; diff --git a/src/gs-entbase/server/basephysics.qc b/src/gs-entbase/server/basephysics.qc index fa1eb6de..4fc778b2 100644 --- a/src/gs-entbase/server/basephysics.qc +++ b/src/gs-entbase/server/basephysics.qc @@ -20,10 +20,8 @@ CBasePhysics::PhysicsEnable(void) if (physics_supported() == TRUE) physics_enable(this, TRUE); else { - print("^1CBasePhysics::PhysicsEnable: "); - print("^7Physics simulator not enabled.\n"); SetMovetype(MOVETYPE_BOUNCE); - SetSolid(SOLID_NOT); + SetSolid(SOLID_CORPSE); } m_iEnabled = TRUE; } @@ -31,11 +29,9 @@ CBasePhysics::PhysicsEnable(void) void CBasePhysics::PhysicsDisable(void) { - if (physics_supported() == TRUE) + if (physics_supported() == TRUE) { physics_enable(this, FALSE); - else { - print("^1CBasePhysics::PhysicsDisable: "); - print("^7Physics simulator not enabled.\n"); + } else { SetMovetype(MOVETYPE_NONE); SetSolid(SOLID_NOT); } @@ -89,11 +85,9 @@ CBasePhysics::GetInertia(void) void CBasePhysics::ApplyForceCenter(vector vecForce) { - if (physics_supported() == TRUE) + if (physics_supported() == TRUE) { physics_addforce(this, vecForce, [0,0,0]); - else { - print("^1CBasePhysics::ApplyForceCenter: "); - print("^7Physics simulator not enabled.\n"); + } else { velocity = vecForce; } } @@ -101,11 +95,9 @@ CBasePhysics::ApplyForceCenter(vector vecForce) void CBasePhysics::ApplyForceOffset(vector vecForce, vector vecOffset) { - if (physics_supported() == TRUE) + if (physics_supported() == TRUE) { physics_addforce(this, vecForce, vecOffset); - else { - print("^1CBasePhysics::ApplyForceOffset: "); - print("^7Physics simulator not enabled.\n"); + } else { velocity = vecForce; } } @@ -116,8 +108,6 @@ CBasePhysics::ApplyTorqueCenter(vector vecTorque) if (physics_supported() == TRUE) physics_addtorque(this, vecTorque * m_flInertiaScale); else { - print("^1CBasePhysics::ApplyTorqueCenter: "); - print("^7Physics simulator not enabled.\n"); avelocity = vecTorque; velocity = vecTorque; velocity[2] = 96; @@ -193,7 +183,21 @@ CBasePhysics::Pain(void) PhysicsEnable(); makevectors(vectoangles(origin - trace_endpos)); ApplyForceOffset(v_forward * 20, origin - trace_endpos); - health = 100000; + + + if (!HasPropData()) { + health = 100000; + } +} + +void +CBasePhysics::Death(void) +{ + Hide(); + + string gibeffect = GetPropData(PROPINFO_BREAKMODEL); + int breakcount = GetPropData(PROPINFO_BREAKCOUNT); + BreakModel_Spawn(origin, [0,0,0], [100,100], 100, breakcount, gibeffect); } void @@ -204,7 +208,6 @@ CBasePhysics::Respawn(void) SetModel(GetSpawnModel()); geomtype = GEOMTYPE_BOX; takedamage = DAMAGE_YES; - health = 100000; PhysicsDisable(); SetFriction(2.0f); SetBounceFactor(0.25f); @@ -217,6 +220,12 @@ CBasePhysics::Respawn(void) think = TouchThink; nextthink = time + 0.1f; effects &= ~EF_NOSHADOW; + + if (HasPropData()) { + health = GetPropData(PROPINFO_HEALTH); + } else { + health = 100000; + } } void @@ -258,6 +267,5 @@ CBasePhysics::CBasePhysics(void) { mass = 1.0f; m_flInertiaScale = 1.0f; - CBaseEntity::CBaseEntity(); } diff --git a/src/gs-entbase/shared/baseentity.qc b/src/gs-entbase/shared/baseentity.qc index f1d6a43c..d4d623d2 100644 --- a/src/gs-entbase/shared/baseentity.qc +++ b/src/gs-entbase/shared/baseentity.qc @@ -816,9 +816,6 @@ CBaseEntity::SpawnInit(void) SpawnKey(argv(i), argv(i+1)); } - /* tokenization complete, now we can load propdata */ - PropData_Finish(); - /* some entity might involuntarily call SpawnInit as part of being a member of CBaseEntity. So we need to make sure that it doesn't inherit stuff from the last previously loaded entity */ @@ -899,6 +896,9 @@ CBaseEntity::CBaseEntity(void) SpawnInit(); + /* tokenization complete, now we can load propdata */ + m_iPropData = PropData_Finish(); + m_oldAngle = angles; m_oldOrigin = origin; m_oldSolid = solid; diff --git a/src/server/entry.qc b/src/server/entry.qc index eeb7fd6b..879ced19 100644 --- a/src/server/entry.qc +++ b/src/server/entry.qc @@ -387,6 +387,7 @@ init(float prevprogs) { iprint("Initializing Server-Module"); Plugin_Init(); + PropData_Init(); } /* @@ -427,7 +428,6 @@ initents(void) /* sound shader init */ Sound_Init(); - PropData_Init(); /* only bother doing so on Half-Life BSP */ if (serverkeyfloat("*bspversion") == BSPVER_HL) { diff --git a/src/shared/propdata.h b/src/shared/propdata.h index 126dca8b..13ad4b4e 100644 --- a/src/shared/propdata.h +++ b/src/shared/propdata.h @@ -91,7 +91,7 @@ int PropData_ForModel(string); /* called when we set a model, returns -1 when no //int PropData_Read(string); /* this just handles the contents of a prop_data model string */ void PropData_SetStage(string); -void PropData_Finish(void); +int PropData_Finish(void); /* querying API */ typedef enum @@ -110,13 +110,16 @@ __variant Prop_GetInfo(int, int); typedef struct { - string model; - float fadetime; + string name; + string data; } breakmodel_t; /* entity will have a .breakmodel field pointing to a breakmodel id */ -propdata_t *g_breakmodel; +breakmodel_t *g_breakmodel; int g_breakmodel_count; +var hashtable g_hashbreakmodel; + +void BreakModel_Spawn(vector pos, vector dir, vector spread, float speed, int count, string type); /* necessary API functions */ //void BreakModel_Init(void); diff --git a/src/shared/propdata.qc b/src/shared/propdata.qc index 9a287c67..aee41b5a 100644 --- a/src/shared/propdata.qc +++ b/src/shared/propdata.qc @@ -20,15 +20,14 @@ PropData_Shutdown(void) if (g_propdata) { memfree(g_propdata); } + if (g_breakmodel) { + memfree(g_breakmodel); + } g_propdata_count = 0; g_hashpropdata = 0; -} - -void -PropData_Init(void) -{ - PropData_Shutdown(); + g_breakmodel_count = 0; + g_hashbreakmodel = 0; } __variant @@ -97,11 +96,19 @@ PropData_ParseField(int i, int a) g_propdata[i].breakable_model = argv(1); break; case "breakable_count": - g_propdata[i].breakable_count = stof(argv(1)); + g_propdata[i].breakable_count = stoi(argv(1)); break; } } +void +BreakModel_ParseField(int i, int a) +{ + if (a == 2) { + g_breakmodel[i].data = sprintf("%s%S %S\n", g_breakmodel[i].data, argv(0), argv(1)); + } +}; + /* concerned with dealing with keeping track of braces and parsing lines */ int PropData_Parse(int i, string line, string type) @@ -129,7 +136,7 @@ PropData_Parse(int i, string line, string type) default: if (braced == 2 && t_name != "") { PropData_ParseField(i, c); - } else if (braced == 1) { + } else if (braced == 1 && key != "BreakableModels") { /* name/identifer of our message */ t_name = strtolower(key); @@ -145,66 +152,6 @@ PropData_Parse(int i, string line, string type) return (0); } -/* goes through and looks for a specifically named propdata type inside the scripts dir */ -int -PropData_Load(string type) -{ - searchhandle sh; - filestream fh; - string line; - int index; - - if (!type) - return -1; - - index = g_propdata_count; - type = strtolower(type); - - /* create the hash-table if it doesn't exist */ - if (!g_hashpropdata) { - g_hashpropdata = hash_createtab(2, HASH_ADD); - } - - /* check if it's already cached */ - for (int i = 0; i < g_propdata_count; i++) { - if (type == g_propdata[i].name) { - return i; - } - } - - g_propdata_count++; - g_propdata = (propdata_t *)memrealloc(g_propdata, sizeof(propdata_t), index, g_propdata_count); - - /* Defaults go here */ - - sh = search_begin("scripts/propdata*.txt", TRUE, TRUE); - - for (int i = 0; i < search_getsize(sh); i++) { - fh = fopen(search_getfilename(sh, i), FILE_READ); - if (fh < 0) { - continue; - } - - while ((line = fgets(fh))) { - /* when we found it, quit */ - if (PropData_Parse(index, line, type) == TRUE) { - search_end(sh); - fclose(fh); - hash_add(g_hashpropdata, type, (int)index); - return index; - } - } - fclose(fh); - } - - print("^1[PROPDATA] No type found for "); - print(type); - print("\n"); - - search_end(sh); - return -1; -} - /* goes through and looks for a specifically named propdata type inside the scripts dir */ int PropData_ForModel(string modelname) @@ -265,18 +212,249 @@ PropData_ForModel(string modelname) return -1; } +int +PropData_Load(string type) +{ + int index; + + if (!type) + return -1; + + type = strtolower(type); + + index = (int)hash_get(g_hashpropdata, type, -1); + + if (index < 0) { + crossprint(sprintf("^1 PropData_Load: type %s is not defined\n", type)); + return -1; + } else { + return index; + } +} + +/* stripped down ParseLine that just counts how many slots we have to allocate */ +void +PropData_CountLine(string line) +{ + int c; + string key; + static string t_name; + static int braced = 0; + static int inmodel = FALSE; + + c = tokenize_console(line); + key = argv(0); + + switch(key) { + case "{": + braced++; + break; + case "}": + braced--; + + /* move out of BreakableModels */ + if (inmodel == TRUE && braced == 1) + inmodel = FALSE; + + t_name = ""; + + /* done */ + if (braced == 0) + return; + break; + default: + if (key == "") { + break; + } else if (braced == 2 && t_name != "" && inmodel == FALSE) { + + } else if (braced == 3 && t_name != "" && inmodel == TRUE) { + + } else if (braced == 1) { + /* BreakableModels get parsed differently */ + if (key == "BreakableModels") { + inmodel = TRUE; + } else { + g_propdata_count++; + } + } else if (braced == 2 && inmodel == TRUE) { + g_breakmodel_count++; + } + } + return; +} + +int +PropData_ParseLine(string line) +{ + int c; + string key; + static string t_name; + static int braced = 0; + static int inmodel = FALSE; + static int i_p = -1; + static int i_b = -1; + + c = tokenize_console(line); + key = argv(0); + + switch(key) { + case "{": + braced++; + break; + case "}": + braced--; + + /* move out of BreakableModels */ + if (inmodel == TRUE && braced == 1) + inmodel = FALSE; + + t_name = ""; + + /* done */ + if (braced == 0) + return (1); + break; + default: + if (key == "") { + break; + } else if (braced == 2 && t_name != "" && inmodel == FALSE) { + PropData_ParseField(i_p, c); + } else if (braced == 3 && t_name != "" && inmodel == TRUE) { + BreakModel_ParseField(i_b, c); + } else if (braced == 1) { + /* BreakableModels get parsed differently */ + if (key == "BreakableModels") { + inmodel = TRUE; + } else { + i_p++; + g_propdata[i_p].name = strtolower(key); + t_name = g_propdata[i_p].name; + hash_add(g_hashpropdata, g_propdata[i_p].name, (int)i_p); + print(sprintf("Parsed propdata %s at index %i\n", key, i_p)); + } + } else if (braced == 2 && inmodel == TRUE) { + i_b++; + g_breakmodel[i_b].name = strtolower(key); + t_name = g_breakmodel[i_b].name; + hash_add(g_hashbreakmodel, g_breakmodel[i_b].name, (int)i_b); + print(sprintf("Parsed breakmodel %s at index %i\n", key, i_b)); + } + } + return (0); +} + +void +PropData_Init(void) +{ + + filestream fh; + string line; + int index; + + /* remove old data */ + PropData_Shutdown(); + + index = g_propdata_count; + + /* create the hash-table if it doesn't exist */ + if (!g_hashpropdata) { + g_hashpropdata = hash_createtab(2, HASH_ADD); + g_hashbreakmodel = hash_createtab(2, HASH_ADD); + } + + /* Defaults go here */ + + fh = fopen("scripts/propdata.txt", FILE_READ); + if (fh < 0) { + print("^1[PROPDATA] Can't find propdata.txt\n"); + return; + } + + /* count content */ + while ((line = fgets(fh))) { + PropData_CountLine(line); + } + + /* alocate our stuff */ + g_propdata = (propdata_t *)memalloc(sizeof(propdata_t) * g_propdata_count); + g_breakmodel = (breakmodel_t *)memalloc(sizeof(breakmodel_t) * g_breakmodel_count); + + fseek(fh, 0); + + while ((line = fgets(fh))) { + /* when we found it, quit */ + PropData_ParseLine(line); + } + fclose(fh); +} + /* we can only tokenize one thing at a time, so we save the type for the current entity away for later, so we can parse it properly by then when we've exited the SpawnKey loop. Using a global will save us some memory at least */ void PropData_SetStage(string type) { + print("Setting propdata\n"); g_curPropData = type; } -void +int PropData_Finish(void) { - PropData_Load(g_curPropData); - g_curPropData = ""; + string toload = g_curPropData; + g_curPropData = __NULL__; + + if (toload) { + return PropData_Load(toload); + } else { + return -1; + } + +} + +/* BreakModel related helper API */ +void +BreakModel_Spawn(vector pos, vector dir, vector spread, float speed, int count, string type) +{ + int index; + index = (int)hash_get(g_hashbreakmodel, type, -1); + + if (index < 0) { + crossprint(sprintf("^1 BreakModel_Spawn: type %s is not defined\n", type)); + return; + } + + float x = tokenize(g_breakmodel[index].data); + int modelcount = x / 2; + + print(sprintf("breakmodel: %s, %i\n", type, count)); + + for (int i = 0; i < count; i++) { + string mname; + float fadetime; + entity gib; + int r; + + /* pick a model between 0 and num) */ + r = floor(random(0, modelcount)); + + /* two entries, always have to skip by 2 */ + mname = argv((r * 2)); + fadetime = stof(argv((r * 2) + 1)); + + gib = spawn(); + setmodel(gib, mname); + setsize(gib, [0,0,0], [0,0,0]); + setorigin(gib, pos); + makevectors(dir); + gib.velocity = v_forward * speed; + gib.velocity += random(-1,1) * spread[0] * v_right; + gib.velocity += random(-1,1) * spread[1] * v_up; + gib.avelocity = vectoangles(gib.velocity); + gib.movetype = MOVETYPE_BOUNCE; + + #ifdef CLIENT + gib.drawmask = MASK_ENGINE; + #endif + } } diff --git a/src/shared/sound.qc b/src/shared/sound.qc index a815e7dd..4a05b087 100644 --- a/src/shared/sound.qc +++ b/src/shared/sound.qc @@ -356,11 +356,7 @@ Sound_Play(entity target, int chan, string shader) sample = (int)hash_get(g_hashsounds, shader, -1); if (sample < 0) { -#ifdef SERVER - print(sprintf("^1Sound_Play: shader %s is not precached (SERVER)\n", shader)); -#else - print(sprintf("^1Sound_Play: shader %s is not precached (CLIENT)\n", shader)); -#endif + crossprint(sprintf("^1Sound_Play: shader %s is not precached\n", shader)); return; }