Add support for Source Engine decal groups (scripts/decals.txt).
This commit is contained in:
parent
36fdd443d2
commit
2945e1f65d
13 changed files with 286 additions and 76 deletions
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
35
src/shared/decalgroups.h
Normal file
35
src/shared/decalgroups.h
Normal file
|
@ -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
|
196
src/shared/decalgroups.qc
Normal file
196
src/shared/decalgroups.qc
Normal file
|
@ -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
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -50,5 +50,6 @@ enum
|
|||
EV_VIEWMODEL,
|
||||
EV_CLEARDECALS,
|
||||
EV_SURFIMPACT,
|
||||
EV_DECALGROUP,
|
||||
EV_SEPARATOR
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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++;
|
||||
}
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue