From 7bdf911d3a5ec37ff7b7964e153cdae5c5c110cf Mon Sep 17 00:00:00 2001 From: Shpoike Date: Tue, 6 Jul 2021 00:25:06 +0100 Subject: [PATCH] Handle sound flags, providing reliable+unicast flags. Also handle other sound flags+networking that only fte clients will benefit from right now. --- Quake/cl_parse.c | 4 +-- Quake/common.c | 47 +++++++++++++++++++++++++++ Quake/common.h | 4 +++ Quake/gl_draw.c | 5 +-- Quake/pr_cmds.c | 14 ++++++++ Quake/pr_ext.c | 32 +++++++++++++++---- Quake/protocol.h | 24 ++++++++++---- Quake/server.h | 4 +-- Quake/sv_main.c | 83 +++++++++++++++++++++++++++++++++++++----------- 9 files changed, 179 insertions(+), 38 deletions(-) diff --git a/Quake/cl_parse.c b/Quake/cl_parse.c index 75f3805f..c9cc5255 100644 --- a/Quake/cl_parse.c +++ b/Quake/cl_parse.c @@ -1157,9 +1157,9 @@ static void CL_ParseStartSoundPacket(void) if (cl.protocol == PROTOCOL_VERSION_BJP3) field_mask |= SND_LARGESOUND; - //spike -- extra channel flags + //spike -- extra flags if (field_mask & SND_FTE_MOREFLAGS) - field_mask |= MSG_ReadByte()<<8; + field_mask |= MSG_ReadUInt64()<<8; if (field_mask & SND_VOLUME) volume = MSG_ReadByte (); diff --git a/Quake/common.c b/Quake/common.c index 6be257d2..3f47ffc5 100644 --- a/Quake/common.c +++ b/Quake/common.c @@ -929,6 +929,29 @@ void MSG_WriteLong (sizebuf_t *sb, int c) buf[3] = c>>24; } +void MSG_WriteUInt64 (sizebuf_t *sb, unsigned long long c) +{ //0* 10*,*, 110*,*,* etc, up to 0xff followed by 8 continuation bytes + byte *buf; + int b = 0; + unsigned long long l = 128; + while (c > l-1u) + { //count the extra bytes we need + b++; + l <<= 7; //each byte we add gains 8 bits, but we spend one on length. + } + buf = (byte*)SZ_GetSpace (sb, 1+b); + *buf++ = 0xffu<<(8-b) | (c >> (b*8)); + while(b --> 0) + *buf++ = (c >> (b*8))&0xff; +} +void MSG_WriteInt64 (sizebuf_t *sb, long long c) +{ //move the sign bit into the low bit and avoid sign extension for more efficient length coding. + if (c < 0) + MSG_WriteUInt64(sb, ((unsigned long long)(-1-c)<<1)|1); + else + MSG_WriteUInt64(sb, c<<1); +} + void MSG_WriteFloat (sizebuf_t *sb, float f) { union @@ -1099,6 +1122,30 @@ int MSG_ReadLong (void) return c; } +unsigned long long MSG_ReadUInt64 (void) +{ //0* 10*,*, 110*,*,* etc, up to 0xff followed by 8 continuation bytes + byte l=0x80, v, b = 0; + unsigned long long r; + v = MSG_ReadByte(); + for (; v&l; l>>=1) + { + v-=l; + b++; + } + r = v<<(b*8); + while(b --> 0) + r |= MSG_ReadByte()<<(b*8); + return r; +} +long long MSG_ReadInt64 (void) +{ //we do some fancy bit recoding for more efficient length coding. + unsigned long long c = MSG_ReadUInt64(); + if (c&1) + return -1-(long long)(c>>1); + else + return (long long)(c>>1); +} + float MSG_ReadFloat (void) { union diff --git a/Quake/common.h b/Quake/common.h index 5cd20eed..6385d66d 100644 --- a/Quake/common.h +++ b/Quake/common.h @@ -100,6 +100,8 @@ void MSG_WriteChar (sizebuf_t *sb, int c); void MSG_WriteByte (sizebuf_t *sb, int c); void MSG_WriteShort (sizebuf_t *sb, int c); void MSG_WriteLong (sizebuf_t *sb, int c); +void MSG_WriteUInt64 (sizebuf_t *sb, unsigned long long c); +void MSG_WriteInt64 (sizebuf_t *sb, long long c); void MSG_WriteFloat (sizebuf_t *sb, float f); void MSG_WriteStringUnterminated (sizebuf_t *sb, const char *s); void MSG_WriteString (sizebuf_t *sb, const char *s); @@ -118,6 +120,8 @@ int MSG_ReadChar (void); int MSG_ReadByte (void); int MSG_ReadShort (void); int MSG_ReadLong (void); +unsigned long long MSG_ReadUInt64 (void); +long long MSG_ReadInt64 (void); float MSG_ReadFloat (void); const char *MSG_ReadString (void); diff --git a/Quake/gl_draw.c b/Quake/gl_draw.c index e8476efb..d45276f0 100644 --- a/Quake/gl_draw.c +++ b/Quake/gl_draw.c @@ -241,8 +241,9 @@ qpic_t *Draw_PicFromWad2 (const char *name, unsigned int texflags) Con_SafePrintf ("W_GetLumpName: %s not found\n", name); return pic_nul; //johnfitz } - if (info->type != TYP_QPIC) Sys_Error ("Draw_PicFromWad: lump \"%s\" is not a qpic", name); - if (info->size < sizeof(int)*2 || 8+p->width*p->height < info->size) Sys_Error ("Draw_PicFromWad: pic \"%s\" truncated", name); + if (info->type != TYP_QPIC) {Con_SafePrintf ("Draw_PicFromWad: lump \"%s\" is not a qpic\n", name); return pic_nul;} + if (info->size < sizeof(int)*2) {Con_SafePrintf ("Draw_PicFromWad: pic \"%s\" is too small for its qpic header (%u bytes)\n", name, info->size); return pic_nul;} + if (8+p->width*p->height < info->size) Sys_Error ("Draw_PicFromWad: pic \"%s\" truncated (%u*%u requires %u bytes)\n", name, p->width,p->height, 8+p->width*p->height); //Spike -- if we're loading external images, and one exists, then use that instead. if (draw_load24bit && (gl.gltexture=TexMgr_LoadImage (NULL, name, 0, 0, SRC_EXTERNAL, NULL, va("gfx/%s", name), 0, texflags|TEXPREF_MIPMAP|TEXPREF_ALLOWMISSING))) diff --git a/Quake/pr_cmds.c b/Quake/pr_cmds.c index 340243bb..a39e1e3d 100644 --- a/Quake/pr_cmds.c +++ b/Quake/pr_cmds.c @@ -654,6 +654,9 @@ static void PF_sound (void) edict_t *entity; int volume; float attenuation; + float ratepct; + unsigned int flags; + float offset; entity = G_EDICT(OFS_PARM0); channel = G_FLOAT(OFS_PARM1); @@ -661,12 +664,23 @@ static void PF_sound (void) volume = G_FLOAT(OFS_PARM3) * 255; attenuation = G_FLOAT(OFS_PARM4); + ratepct = (qcvm->argc<6)?100:G_FLOAT(OFS_PARM5); + flags = (qcvm->argc<7)?0:G_FLOAT(OFS_PARM6); + offset = (qcvm->argc<8)?0:G_FLOAT(OFS_PARM7); + if (!*sample) { PR_RunWarning("PF_sound: empty string\n"); return; } + if (ratepct && ratepct != 100) + Con_DPrintf("sound() rate scaling is not supported\n"); + if (flags) + Con_DPrintf("sound() flags %#x not supported\n", flags); + if (offset) + Con_DPrintf("sound() time offsets are not supported\n"); + /* Spike -- these checks are redundant if (volume < 0 || volume > 255) Host_Error ("SV_StartSound: volume = %i", volume); diff --git a/Quake/pr_ext.c b/Quake/pr_ext.c index df0480c3..7540f442 100644 --- a/Quake/pr_ext.c +++ b/Quake/pr_ext.c @@ -2088,6 +2088,16 @@ static void PF_getsurfaceclippedpoint(void) getsurface_clippointpoly(model, surf, point, result, 0x7fffffff); } +enum +{ + SPA_POSITION = 0, + SPA_S_AXIS = 1, + SPA_T_AXIS = 2, + SPA_R_AXIS = 3, //normal + SPA_TEXCOORDS0 = 4, + SPA_LIGHTMAP0_TEXCOORDS = 5, + SPA_LIGHTMAP0_COLOR = 6, +}; static void PF_getsurfacepointattribute(void) { edict_t *ed = G_EDICT(OFS_PARM0); @@ -2109,11 +2119,11 @@ static void PF_getsurfacepointattribute(void) G_FLOAT(OFS_RETURN+1) = 0; G_FLOAT(OFS_RETURN+2) = 0; break; - case 0: //xyz coord + case SPA_POSITION: VectorCopy(v->position, G_VECTOR(OFS_RETURN)); break; - case 1: //s dir - case 2: //t dir + case SPA_S_AXIS: + case SPA_T_AXIS: { //figure out how similar to the normal it is, and negate any influence, so that its perpendicular float sc = -DotProduct(fa->plane->normal, fa->texinfo->vecs[attribute-1]); @@ -2121,22 +2131,22 @@ static void PF_getsurfacepointattribute(void) VectorNormalize(G_VECTOR(OFS_RETURN)); } break; - case 3: //normal + case SPA_R_AXIS: //normal VectorCopy(fa->plane->normal, G_VECTOR(OFS_RETURN)); if (fa->flags & SURF_PLANEBACK) VectorInverse(G_VECTOR(OFS_RETURN)); break; - case 4: //st coord + case SPA_TEXCOORDS0: G_FLOAT(OFS_RETURN+0) = (DotProduct(v->position, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3]) / fa->texinfo->texture->width; G_FLOAT(OFS_RETURN+1) = (DotProduct(v->position, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3]) / fa->texinfo->texture->height; G_FLOAT(OFS_RETURN+2) = 0; break; - case 5: //lmst coord, not actually very useful + case SPA_LIGHTMAP0_TEXCOORDS: //lmst coord, not actually very useful G_FLOAT(OFS_RETURN+0) = (DotProduct(v->position, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3] - fa->texturemins[0] + (fa->light_s+.5)*(1<lmshift)) / (LMBLOCK_WIDTH*(1<lmshift)); G_FLOAT(OFS_RETURN+1) = (DotProduct(v->position, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3] - fa->texturemins[1] + (fa->light_t+.5)*(1<lmshift)) / (LMBLOCK_HEIGHT*(1<lmshift)); G_FLOAT(OFS_RETURN+2) = 0; break; - case 6: //colour + case SPA_LIGHTMAP0_COLOR: //colour G_FLOAT(OFS_RETURN+0) = 1; G_FLOAT(OFS_RETURN+1) = 1; G_FLOAT(OFS_RETURN+2) = 1; @@ -8256,6 +8266,14 @@ void PR_DumpPlatform_f(void) fprintf(f, "const float CHAN_VOICE = %i;\n", 2); fprintf(f, "const float CHAN_ITEM = %i;\n", 3); fprintf(f, "const float CHAN_BODY = %i;\n", 4); + + fprintf(f, "const float SPA_POSITION = %i;\n", SPA_POSITION); + fprintf(f, "const float SPA_S_AXIS = %i;\n", SPA_S_AXIS); + fprintf(f, "const float SPA_T_AXIS = %i;\n", SPA_T_AXIS); + fprintf(f, "const float SPA_R_AXIS = %i;\n", SPA_R_AXIS); + fprintf(f, "const float SPA_TEXCOORDS0 = %i;\n", SPA_TEXCOORDS0); + fprintf(f, "const float SPA_LIGHTMAP0_TEXCOORDS = %i;\n", SPA_LIGHTMAP0_TEXCOORDS); + fprintf(f, "const float SPA_LIGHTMAP0_COLOR = %i;\n", SPA_LIGHTMAP0_COLOR); } if (targs & (CS|MN)) diff --git a/Quake/protocol.h b/Quake/protocol.h index a6965797..03179518 100644 --- a/Quake/protocol.h +++ b/Quake/protocol.h @@ -205,24 +205,36 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define DPSU_VIEWZOOM (1<<19) // byte factor (0 = 0.0 (not valid), 255 = 1.0) //spike +#define DEFAULT_SOUND_PACKET_VOLUME 255 +#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0 // a sound with no channel is a local only sound #define SND_VOLUME (1<<0) // a byte #define SND_ATTENUATION (1<<1) // a byte //#define SND_LOOPING (1<<2) // a long (unused in vanilla) - -#define DEFAULT_SOUND_PACKET_VOLUME 255 -#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0 - +//spike -- parsing, but not using at this time +#define SND_FTE_MOREFLAGS (1<<2) // a byte, for channel flags //johnfitz -- PROTOCOL_FITZQUAKE -- new bits #define SND_LARGEENTITY (1<<3) // a short + byte (instead of just a short) #define SND_LARGESOUND (1<<4) // a short soundindex (instead of a byte) //johnfitz -//spike -- parsing, but not using at this time -#define SND_FTE_MOREFLAGS (1<<2) // a byte, for channel flags #define SND_DP_PITCH (1<<5) //dp uses this for pitch... #define SND_FTE_TIMEOFS (1<<6) //signed short, in milliseconds. #define SND_FTE_PITCHADJ (1<<7) //a byte (speed percent (0=100%)) #define SND_FTE_VELOCITY (1<<8) //3 shorts (1/8th), for doppler or whatever. +#define SND_FTE_FORCELOOP (1<<9) //flag +#define SND_FTE_NOSPACIALISE (1<<10)//flag +#define SND_FTE_NOREVERB (1<<13) //flat +#define SND_FTE_FOLLOW (1<<14) //flag only +#define SND_FTE_NOREPLACE (1<<15) //flag only + +#define CF_RELIABLE (1<<0) //send over reliable channel +#define CF_FORCELOOP (1<<1) //force looping +#define CF_NOSPACIALISE (1<<2) //mono-ize. play on the local player to avoid distance fading. +#define CF_NOREVERB (1<<5) //disable reverb effects (for music, QS doesn't have reverb) +#define CF_FOLLOW (1<<6) //sound origin follows entity +#define CF_NOREPLACE (1<<7) //drop the sound if it would replace one. +#define CF_UNICAST (1<<8) //send only to msg_entity +#define CF_SENDVELOCITY (1<<9) //include the velocity, for doppler effects. //spike //johnfitz -- PROTOCOL_FITZQUAKE -- flags for entity baseline messages diff --git a/Quake/server.h b/Quake/server.h index f783c610..f6228410 100644 --- a/Quake/server.h +++ b/Quake/server.h @@ -308,8 +308,8 @@ extern edict_t *sv_player; void SV_Init (void); void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count); -void SV_StartSound (edict_t *entity, float *origin, int channel, - const char *sample, int volume, float attenuation); +void SV_StartSound (edict_t *entity, float *origin, int channel, const char *sample, int volume, float attenuation); +void SV_StartSound2 (edict_t *entity, float *origin, int channel, const char *sample, int volume, float attenuation, float speed, int flags, float timeoffset); void SV_DropClient (qboolean crash); diff --git a/Quake/sv_main.c b/Quake/sv_main.c index 9e9cecc9..c958ecfe 100644 --- a/Quake/sv_main.c +++ b/Quake/sv_main.c @@ -1587,12 +1587,13 @@ Larger attenuations will drop off. (max 4 attenuation) ================== */ -void SV_StartSound (edict_t *entity, float *origin, int channel, const char *sample, int volume, float attenuation) +void SV_StartSound2 (edict_t *entity, float *origin, int channel, const char *sample, int volume, float attenuation, float speed, int flags, float timeoffset) { unsigned int sound_num, ent; - int i, field_mask; + int i, field_mask, client_mask; int p; client_t *cl; + sizebuf_t *msg; if (volume < 0) Host_Error ("SV_StartSound: volume = %i", volume); @@ -1641,6 +1642,19 @@ void SV_StartSound (edict_t *entity, float *origin, int channel, const char *sam field_mask |= SND_LARGESOUND; //johnfitz + //spike + if (flags & CF_FORCELOOP) field_mask |= SND_FTE_FORCELOOP; + if (flags & CF_NOSPACIALISE) field_mask |= SND_FTE_NOSPACIALISE; +// if (flags & CF_PAUSED) field_mask |= SND_FTE_PAUSED; +// if (flags & CF_ABSVOLUME) field_mask |= SND_FTE_ABSVOLUME; + if (flags & CF_NOREVERB) field_mask |= SND_FTE_NOREVERB; + if (flags & CF_FOLLOW) field_mask |= SND_FTE_FOLLOW; + if (flags & CF_NOREPLACE) field_mask |= SND_FTE_NOREPLACE; + if (flags & CF_SENDVELOCITY) field_mask |= SND_FTE_VELOCITY; + if (speed && speed != 1) field_mask |= SND_FTE_PITCHADJ; + if (timeoffset) field_mask |= SND_FTE_TIMEOFS; + // + for (p = 0; p < svs.maxclients; p++) { cl = &svs.clients[p]; @@ -1654,43 +1668,74 @@ void SV_StartSound (edict_t *entity, float *origin, int channel, const char *sam if ((field_mask & (SND_LARGEENTITY|SND_LARGESOUND)) && (!cl->protocol_pext2 || sv.protocol == PROTOCOL_NETQUAKE)) continue; + if (flags & CF_UNICAST && cl->edict != PROG_TO_EDICT(pr_global_struct->msg_entity)) + continue; + if (flags & CF_RELIABLE) + msg = &cl->message; + else + msg = &cl->datagram; + client_mask = field_mask; + if (!(cl->protocol_pext2&PEXT2_REPLACEMENTDELTAS)) + client_mask &= (SND_VOLUME|SND_ATTENUATION|SND_LARGEENTITY|SND_LARGESOUND); + // directed messages go only to the entity the are targeted on - MSG_WriteByte (&cl->datagram, svc_sound); - MSG_WriteByte (&cl->datagram, field_mask); - if (field_mask & SND_VOLUME) - MSG_WriteByte (&cl->datagram, volume); - if (field_mask & SND_ATTENUATION) - MSG_WriteByte (&cl->datagram, attenuation*64); + MSG_WriteByte (msg, svc_sound); + MSG_WriteByte (msg, client_mask&0xff); + if (client_mask & SND_FTE_MOREFLAGS) + MSG_WriteUInt64 (msg, client_mask>>8); + if (client_mask & SND_VOLUME) + MSG_WriteByte (msg, volume); + if (client_mask & SND_ATTENUATION) + MSG_WriteByte (msg, attenuation*64); + + //spike -- stuff + if (client_mask & SND_FTE_PITCHADJ) + MSG_WriteByte (msg, CLAMP(1, speed*100, 255)); + if (client_mask & SND_FTE_TIMEOFS) + MSG_WriteShort (msg, CLAMP(-32768, timeoffset*1000, 32767)); + if (client_mask & SND_FTE_VELOCITY) + { + MSG_WriteShort (msg, CLAMP(-32768, entity->v.velocity[0]*8, 32767)); + MSG_WriteShort (msg, CLAMP(-32768, entity->v.velocity[1]*8, 32767)); + MSG_WriteShort (msg, CLAMP(-32768, entity->v.velocity[2]*8, 32767)); + } + if (client_mask & SND_DP_PITCH) + MSG_WriteShort (msg, CLAMP(-32768, speed*4000, 32767)); + //end spike //johnfitz -- PROTOCOL_FITZQUAKE - if (field_mask & SND_LARGEENTITY) + if (client_mask & SND_LARGEENTITY) { if ((cl->protocol_pext2 & PEXT2_REPLACEMENTDELTAS) && ent > 0x7fff) { - MSG_WriteShort(&cl->datagram, (ent>>8) | 0x8000); - MSG_WriteByte(&cl->datagram, ent & 0xff); + MSG_WriteShort(msg, (ent>>8) | 0x8000); + MSG_WriteByte(msg, ent & 0xff); } else - MSG_WriteShort (&cl->datagram, ent); - MSG_WriteByte (&cl->datagram, channel); + MSG_WriteShort (msg, ent); + MSG_WriteByte (msg, channel); } else - MSG_WriteShort (&cl->datagram, (ent<<3) | channel); - if ((field_mask & SND_LARGESOUND) || sv.protocol == PROTOCOL_VERSION_BJP3) - MSG_WriteShort (&cl->datagram, sound_num); + MSG_WriteShort (msg, (ent<<3) | channel); + if ((client_mask & SND_LARGESOUND) || sv.protocol == PROTOCOL_VERSION_BJP3) + MSG_WriteShort (msg, sound_num); else - MSG_WriteByte (&cl->datagram, sound_num); + MSG_WriteByte (msg, sound_num); //johnfitz for (i = 0; i < 3; i++) { if (origin) - MSG_WriteCoord (&cl->datagram, origin[i], sv.protocolflags); + MSG_WriteCoord (msg, origin[i], sv.protocolflags); else - MSG_WriteCoord (&cl->datagram, entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i]), sv.protocolflags); + MSG_WriteCoord (msg, entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i]), sv.protocolflags); } } } +void SV_StartSound (edict_t *entity, float *origin, int channel, const char *sample, int volume, float attenuation) +{ + SV_StartSound2 (entity, origin, channel, sample, volume, attenuation, 100, 0, 0); +} /* ==============================================================================