From 2945e1f65dfb5a3b087e34e0154bf5b2cecec3b2 Mon Sep 17 00:00:00 2001 From: Marco Cawthorne Date: Thu, 27 Oct 2022 20:03:03 -0700 Subject: [PATCH] Add support for Source Engine decal groups (scripts/decals.txt). --- src/client/entry.qc | 4 +- src/client/event.qc | 3 + src/server/entry.qc | 1 + src/shared/NSMaterial.h | 38 ---- src/shared/decalgroups.h | 35 ++++ src/shared/decalgroups.qc | 196 +++++++++++++++++++++ src/shared/defs.h | 4 +- src/shared/events.h | 1 + src/shared/include.src | 3 +- src/shared/materials.h | 57 ++++-- src/shared/{NSMaterial.qc => materials.qc} | 2 +- src/shared/surfaceproperties.h | 1 - src/shared/surfaceproperties.qc | 17 +- 13 files changed, 286 insertions(+), 76 deletions(-) delete mode 100644 src/shared/NSMaterial.h create mode 100644 src/shared/decalgroups.h create mode 100644 src/shared/decalgroups.qc rename src/shared/{NSMaterial.qc => materials.qc} (98%) diff --git a/src/client/entry.qc b/src/client/entry.qc index af1681d0..eef29705 100644 --- a/src/client/entry.qc +++ b/src/client/entry.qc @@ -53,7 +53,9 @@ CSQC_Init(float apilevel, string enginename, float engineversion) /* Sound shaders */ Sound_Init(); SurfData_Init(); - PropData_Init(); + PropData_Init(); + DecalGroups_Init(); + precache_sound("common/wpn_hudon.wav"); precache_sound("common/wpn_hudoff.wav"); precache_sound("common/wpn_moveselect.wav"); diff --git a/src/client/event.qc b/src/client/event.qc index c645d4a4..9be4d774 100644 --- a/src/client/event.qc +++ b/src/client/event.qc @@ -121,6 +121,9 @@ Event_Parse(float type) case EV_SURFIMPACT: SurfData_Impact_Parse(); break; + case EV_DECALGROUP: + DecalGroups_Receive(); + break; case EV_CLEARDECALS: CMD_Cleardecals(); break; diff --git a/src/server/entry.qc b/src/server/entry.qc index d552bd50..e7c9a277 100644 --- a/src/server/entry.qc +++ b/src/server/entry.qc @@ -319,6 +319,7 @@ init(float prevprogs) Sound_Init(); PropData_Init(); SurfData_Init(); + DecalGroups_Init(); } /** Called inside initents() to make sure the entities have their Respawn() diff --git a/src/shared/NSMaterial.h b/src/shared/NSMaterial.h deleted file mode 100644 index 29a775e9..00000000 --- a/src/shared/NSMaterial.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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. -*/ - -hashtable g_hashMaterials; -hashtable hashMaterials; - -void Materials_Init(void); - -/* legacy material compatibility */ - -/** hlmaterial to classname mapper table */ -typedef struct -{ - string id; - string matclass; -} hlmaterials_lut; - -hlmaterials_lut *g_hlmlut; -var int g_hlmlut_count; -var int g_hlmaterial_entries; - -var bool g_materialsAreLegacy; - -/* FIXME: world.... sigh, we should box this into a worldspawn class */ -.string materials_file; \ No newline at end of file diff --git a/src/shared/decalgroups.h b/src/shared/decalgroups.h new file mode 100644 index 00000000..f9145f23 --- /dev/null +++ b/src/shared/decalgroups.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2022, Vera Visions, L.L.C. All rights reserved. */ + +/* + Decal Property List Specs + + A decal group consists of one material per line: + + groupname + { + "textures/decals/foo" "1" + "textures/decals/bar" "1" + } + + And the weight is used to determine how often the decal gets used. + If you're unsure, put in "1". + + Also, any group named 'TranslationData' will be ignored. + That group is used in Source Engine games to map the 'gamematerial' + keys from surfaceproperties.txt over to a decal. + + The reason why we can't support it is simple: + In Source, decals are tied to surfaceproperties and in GoldSrc + the weapons are responsible for deciding which decals to use + on a surface. We obviously cannot do both, but the GoldSrc way + is the most appropriate one for our purposes. + +*/ + +/* public API */ +void DecalGroups_Init(void); +void DecalGroups_Place(string group, vector org); + +#ifdef CLIENT +void DecalGroups_Receive(void); +#endif \ No newline at end of file diff --git a/src/shared/decalgroups.qc b/src/shared/decalgroups.qc new file mode 100644 index 00000000..512f6389 --- /dev/null +++ b/src/shared/decalgroups.qc @@ -0,0 +1,196 @@ +/* Copyright (c) 2022, Vera Visions, L.L.C. All rights reserved. */ + +#ifdef CLIENT +typedef struct +{ + string materials; + int members; +} decalGroup_t; + +decalGroup_t *g_decalgroup; +int g_decalgroup_count; +#endif + +var hashtable g_hashdecalgroup; + +#ifdef CLIENT +static void +DecalGroups_CountLine(string line) +{ + int c; + string key; + static string t_name; + static int braced = 0; + + c = tokenize_console(line); + key = argv(0); + + switch(key) { + case "{": + braced++; + break; + case "}": + braced--; + t_name = ""; + break; + default: + /* new definition starts */ + if (c == 1 && braced == 0) { + t_name = strtolower(line); + + if (t_name) + g_decalgroup_count++; + } + } + return; +} +#endif + +static void +DecalGroups_Parse(string line) +{ + int c; + string key; + static string t_name; + static int braced = 0; + static int i; + + c = tokenize_console(line); + key = argv(0); + + switch(key) { + case "{": + braced++; + break; + case "}": + /* increase counter when done */ + if (t_name) + i++; + + braced--; + t_name = ""; + break; + default: + if (braced == 1 && t_name != "") { + /* the server doesn't need to know any of this */ +#ifdef CLIENT + /* valid material + weight combo */ + if (c == 2) { + if (g_decalgroup[i].members > 0) + g_decalgroup[i].materials = strcat(g_decalgroup[i].materials, ";", argv(0)); + else + g_decalgroup[i].materials = argv(0); + + g_decalgroup[i].members++; + } +#endif + } else if (braced == 0) { + t_name = strtolower(line); + hash_add(g_hashdecalgroup, t_name, (int)i); + } + } +} + +void +DecalGroups_Init(void) +{ + filestream fh; + string line; + + /* create the hash-table if it doesn't exist */ + if (!g_hashdecalgroup) { + g_hashdecalgroup = hash_createtab(2, EV_STRING | HASH_REPLACE); + } + + fh = fopen("scripts/decals.txt", FILE_READ); + if (fh < 0) { + print("^1[DECALS] Can't find scripts/decals.txt\n"); + return; + } + +#ifdef CLIENT + /* count content */ + while ((line = fgets(fh))) { + DecalGroups_CountLine(line); + } + + /* alocate our stuff */ + g_decalgroup = (decalGroup_t *)memalloc(sizeof(decalGroup_t) * g_decalgroup_count); + + /* Defaults */ + for (int i = 0; i < g_decalgroup_count; i++) { + g_decalgroup[i].materials = ""; + g_decalgroup[i].members = 0; + } +#endif + + fseek(fh, 0); + + while ((line = fgets(fh))) { + /* when we found it, quit */ + DecalGroups_Parse(line); + } + + fclose(fh); + +#ifdef CLIENT + for (int i = 0; i < g_decalgroup_count; i++) { + print(sprintf("%i (members: %i) %s\n", i, g_decalgroup[i].members, g_decalgroup[i].materials)); + } +#endif +} + +#ifdef CLIENT +void +DecalGroups_PlaceGroupID(int index, vector org) +{ + /* on the client we only need to go ahead and place the final decal */ + string material; + int r; + + /* get all materials of the group */ + tokenizebyseparator(g_decalgroup[index].materials, ";"); + + /* pick a random one. TODO: respects weights */ + r = random(0, (float)g_decalgroup[index].members); + + /* place a single one. */ + Decals_Place(org, argv(r)); +} +#endif + +void +DecalGroups_Place(string group, vector org) +{ + int index; + index = (int)hash_get(g_hashdecalgroup, group, -1); + +#ifdef SERVER + /* on the server we only need to tell the clients in the PVS + to go ahead and place a decal of id X at a certain position */ + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, EV_DECALGROUP); + WriteByte(MSG_MULTICAST, index); + WriteCoord(MSG_MULTICAST, org[0]); + WriteCoord(MSG_MULTICAST, org[1]); + WriteCoord(MSG_MULTICAST, org[2]); + multicast(org, MULTICAST_PVS); +#else + DecalGroups_PlaceGroupID(index, org); +#endif +} + +#ifdef CLIENT +void +DecalGroups_Receive(void) +{ + int index; + vector org; + + index = readbyte(); + org[0] = readcoord(); + org[1] = readcoord(); + org[2] = readcoord(); + DecalGroups_PlaceGroupID(index, org); +} +#endif diff --git a/src/shared/defs.h b/src/shared/defs.h index ad1e464e..a39b5af5 100644 --- a/src/shared/defs.h +++ b/src/shared/defs.h @@ -69,7 +69,7 @@ string __fullspawndata; #include "NSVehicle.h" -#include "NSMaterial.h" +#include "materials.h" #include "damage.h" #include "flags.h" #include "effects.h" @@ -77,13 +77,13 @@ string __fullspawndata; #include "events.h" #include "flags.h" #include "hitmesh.h" -#include "materials.h" #include "math.h" #include "pmove.h" #include "memory.h" #include "platform.h" #include "propdata.h" #include "surfaceproperties.h" +#include "decalgroups.h" #include "colors.h" #include "weapons.h" diff --git a/src/shared/events.h b/src/shared/events.h index d814e7b5..1adb854c 100644 --- a/src/shared/events.h +++ b/src/shared/events.h @@ -50,5 +50,6 @@ enum EV_VIEWMODEL, EV_CLEARDECALS, EV_SURFIMPACT, + EV_DECALGROUP, EV_SEPARATOR }; diff --git a/src/shared/include.src b/src/shared/include.src index 17f07949..c6647550 100644 --- a/src/shared/include.src +++ b/src/shared/include.src @@ -26,7 +26,8 @@ NSClientPlayer.qc player_pmove.qc propdata.qc surfaceproperties.qc -NSMaterial.qc +decalgroups.qc +materials.qc NSSpraylogo.qc util.qc weapons.qc diff --git a/src/shared/materials.h b/src/shared/materials.h index 88a80897..d62353e8 100644 --- a/src/shared/materials.h +++ b/src/shared/materials.h @@ -1,19 +1,42 @@ -/* - * 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. -*/ - +/* + * 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. +*/ + +hashtable g_hashMaterials; +hashtable hashMaterials; + +void Materials_Init(void); + +/* legacy material compatibility */ + +/** hlmaterial to classname mapper table */ +typedef struct +{ + string id; + string matclass; +} hlmaterials_lut; + +hlmaterials_lut *g_hlmlut; +var int g_hlmlut_count; +var int g_hlmaterial_entries; + +var bool g_materialsAreLegacy; + +/* FIXME: world.... sigh, we should box this into a worldspawn class */ +.string materials_file; + // Impact types typedef enum { @@ -189,4 +212,4 @@ Materials_FixName(string old_name) NSLog("%s > %s", old_name, tex_name); return tex_name; -} +} \ No newline at end of file diff --git a/src/shared/NSMaterial.qc b/src/shared/materials.qc similarity index 98% rename from src/shared/NSMaterial.qc rename to src/shared/materials.qc index c7eaf971..0d64eb82 100644 --- a/src/shared/NSMaterial.qc +++ b/src/shared/materials.qc @@ -169,7 +169,7 @@ Materials_LoadFromLegacyText(string filename) mat_type = Materials_Mapper_Lookup(strtoupper(argv(0))); tex_name = Materials_FixName(strtolower(argv(1))); hash_add(g_hashMaterials, tex_name, mat_type, EV_STRING); - print(sprintf("hlmaterial: %S %S\n", tex_name, mat_type)); + ///print(sprintf("hlmaterial: %S %S\n", tex_name, mat_type)); g_hlmaterial_entries++; } } diff --git a/src/shared/surfaceproperties.h b/src/shared/surfaceproperties.h index ebd36013..32b02c30 100644 --- a/src/shared/surfaceproperties.h +++ b/src/shared/surfaceproperties.h @@ -87,7 +87,6 @@ typedef struct string m_fxBulletImpact; float m_fxBulletImpactID; - string _name; } surfaceData_t; /* entity will have to have a .surfdata field pointing to an id */ diff --git a/src/shared/surfaceproperties.qc b/src/shared/surfaceproperties.qc index 0c8f337d..5312d756 100644 --- a/src/shared/surfaceproperties.qc +++ b/src/shared/surfaceproperties.qc @@ -121,6 +121,7 @@ SurfData_ParseField(int i, int a) g_surfdata[i].m_sndBreak = argv(1); break; case "fx_bulletimpact": + case "part_bulletimpact": g_surfdata[i].m_fxBulletImpact = argv(1); #ifdef CLIENT g_surfdata[i].m_fxBulletImpactID = particleeffectnum(g_surfdata[i].m_fxBulletImpact); @@ -159,7 +160,6 @@ SurfData_Parse(string line) SurfData_ParseField(i, c); } else if (braced == 0) { t_name = strtolower(line); - g_surfdata[i]._name = t_name; hash_add(g_hashsurfdata, t_name, (int)i); } } @@ -208,7 +208,7 @@ SurfData_CountLine(string line) break; default: /* new definition starts */ - if (braced == 0) { + if (c == 1 && braced == 0) { t_name = strtolower(line); if (t_name) @@ -236,19 +236,6 @@ SurfData_TexToSurfData(string tex_name) return SurfData_Load(mat); } -string -SurfData_DataForMatID(float matid) -{ - int id = -1; - for (int i = 0; i < g_surfdata_count; i++) { - if (matid == g_surfdata[i].m_flMaterial) { - return g_surfdata[i]._name; - } - } - - return 0; -} - /* Public API functions */ __variant SurfData_GetInfo(int i, int type)