From 8a4556c3e4e34dac02c25dfa4a4a8ff106ba97f3 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 1 Nov 2023 22:05:03 +0300 Subject: [PATCH 001/167] Grab mouse when entering active state. Fixes #329. --- src/client/entities.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/client/entities.c b/src/client/entities.c index 36ed38170..e0fe64c1a 100644 --- a/src/client/entities.c +++ b/src/client/entities.c @@ -288,6 +288,8 @@ static void set_active_state(void) CL_UpdateFrameTimes(); + IN_Activate(); + if (!cls.demo.playback) { EXEC_TRIGGER(cl_beginmapcmd); Cmd_ExecTrigger("#cl_enterlevel"); From d79867feefa5e84f5e3831bb12c1032ccf2a01b4 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 1 Nov 2023 22:06:43 +0300 Subject: [PATCH 002/167] Fix some issues with libavcodec cinematics. Fix memory leaks. Fix draining decoder. --- src/client/ffcin.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/client/ffcin.c b/src/client/ffcin.c index 6d845f205..5aedcfd54 100644 --- a/src/client/ffcin.c +++ b/src/client/ffcin.c @@ -104,7 +104,7 @@ Called when either the cinematic completes, or it is aborted void SCR_FinishCinematic(void) { // stop cinematic, but keep static pic - if (cin.video.frame) { + if (cin.fmt_ctx) { SCR_StopCinematic(); SCR_BeginLoadingPlaque(); } @@ -224,19 +224,25 @@ static int decode_frames(DecoderState *s) // no A/V synchronization while (s->timestamp < cls.realtime - cin.start_time) { ret = avcodec_receive_frame(dec, frame); - if (ret == AVERROR_EOF) + if (ret == AVERROR_EOF) { + Com_DPrintf("%s from %s decoder\n", av_err2str(ret), + av_get_media_type_string(dec->codec->type)); return ret; + } // do we need a packet? if (ret == AVERROR(EAGAIN)) { - if (packet_queue_get(&s->queue, pkt)) - return cin.eof ? AVERROR_EOF : ret; - - // submit the packet to the decoder - ret = avcodec_send_packet(dec, pkt); - av_packet_unref(pkt); + if (packet_queue_get(&s->queue, pkt) < 0) { + // enter draining mode + ret = avcodec_send_packet(dec, NULL); + } else { + // submit the packet to the decoder + ret = avcodec_send_packet(dec, pkt); + av_packet_unref(pkt); + } if (ret < 0) { - Com_EPrintf("Error submitting a packet for decoding: %s\n", av_err2str(ret)); + Com_EPrintf("Error submitting %s packet for decoding: %s\n", + av_get_media_type_string(dec->codec->type), av_err2str(ret)); return ret; } @@ -244,7 +250,8 @@ static int decode_frames(DecoderState *s) } if (ret < 0) { - Com_EPrintf("Error during decoding: %s\n", av_err2str(ret)); + Com_EPrintf("Error during decoding %s: %s\n", + av_get_media_type_string(dec->codec->type), av_err2str(ret)); return ret; } @@ -306,6 +313,7 @@ static bool SCR_ReadNextFrame(void) ret = av_read_frame(cin.fmt_ctx, pkt); // idcin demuxer returns AVERROR(EIO) on EOF packet... if (ret == AVERROR_EOF || ret == AVERROR(EIO)) { + Com_DPrintf("%s from demuxer\n", av_err2str(ret)); cin.eof = true; break; } @@ -425,12 +433,14 @@ static bool open_codec_context(enum AVMediaType type) ret = avcodec_parameters_to_context(dec_ctx, st->codecpar); if (ret < 0) { Com_EPrintf("Failed to copy %s codec parameters to decoder context\n", av_get_media_type_string(type)); + avcodec_free_context(&dec_ctx); return false; } ret = avcodec_open2(dec_ctx, dec, NULL); if (ret < 0) { Com_EPrintf("Failed to open %s codec\n", av_get_media_type_string(type)); + avcodec_free_context(&dec_ctx); return false; } @@ -536,8 +546,8 @@ static bool SCR_StartCinematic(const char *name) } if (Q_snprintf(fullname, sizeof(fullname), "%s/video/%s", path, normalized) >= sizeof(fullname)) { - Com_EPrintf("Oversize cinematic name\n"); - return false; + ret = AVERROR(ENAMETOOLONG); + break; } ret = avformat_open_input(&cin.fmt_ctx, fullname, NULL, NULL); From 9442417fd8081e7d967cce985a9e7d8ee872ffb6 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 2 Nov 2023 02:33:35 +0300 Subject: [PATCH 003/167] Fix too early exit when one of the streams is shorter. --- src/client/ffcin.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/client/ffcin.c b/src/client/ffcin.c index 5aedcfd54..17ecd3b1a 100644 --- a/src/client/ffcin.c +++ b/src/client/ffcin.c @@ -39,6 +39,7 @@ typedef struct { unsigned timestamp; int stream_idx; AVFrame *frame; + bool eof; } DecoderState; typedef struct { @@ -216,7 +217,7 @@ static int decode_frames(DecoderState *s) AVCodecContext *dec = s->dec_ctx; int ret, video_frames = 0; - if (!dec) + if (!dec || s->eof) return 0; // naive decoding loop: keep reading frames until PTS >= current time @@ -227,14 +228,20 @@ static int decode_frames(DecoderState *s) if (ret == AVERROR_EOF) { Com_DPrintf("%s from %s decoder\n", av_err2str(ret), av_get_media_type_string(dec->codec->type)); - return ret; + s->eof = true; + return 0; } // do we need a packet? if (ret == AVERROR(EAGAIN)) { if (packet_queue_get(&s->queue, pkt) < 0) { - // enter draining mode - ret = avcodec_send_packet(dec, NULL); + if (cin.eof) { + // enter draining mode + ret = avcodec_send_packet(dec, NULL); + } else { + // wait for more packets... + return 0; + } } else { // submit the packet to the decoder ret = avcodec_send_packet(dec, pkt); @@ -336,12 +343,11 @@ static bool SCR_ReadNextFrame(void) } } - ret = decode_frames(&cin.video); - if (ret < 0 && ret != AVERROR(EAGAIN)) + if (decode_frames(&cin.video) < 0) return false; - - ret = decode_frames(&cin.audio); - if (ret < 0 && ret != AVERROR(EAGAIN)) + if (decode_frames(&cin.audio) < 0) + return false; + if (cin.video.eof && cin.audio.eof) return false; return true; @@ -381,7 +387,7 @@ void SCR_DrawCinematic(void) { R_DrawFill8(0, 0, r_config.width, r_config.height, 0); - if (cin.width > 0 && cin.height > cin.crop) { + if (cin.width > 0 && cin.height > cin.crop && !cin.video.eof) { float scale_w = (float)r_config.width / cin.width; float scale_h = (float)r_config.height / (cin.height - cin.crop); float scale = min(scale_w, scale_h); @@ -412,6 +418,8 @@ static bool open_codec_context(enum AVMediaType type) Com_EPrintf("Couldn't find video stream\n"); return false; } + // if there is no audio, pretend it hit EOF + cin.audio.eof = true; return true; } From 9b97f6552653bc62f899d746794cf56f5b8ef43d Mon Sep 17 00:00:00 2001 From: Dino <8dino2@gmail.com> Date: Wed, 1 Nov 2023 20:03:26 -0400 Subject: [PATCH 004/167] Changed branch name in workflow --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b07382cda..ad2e8d0ed 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,9 +2,9 @@ name: build on: push: - branches: [master, aqtion, alpha-aqtion, ci] + branches: [master, aqtion, aqtion-alpha, ci] pull_request: - branches: [master, aqtion, alpha-aqtion] + branches: [master, aqtion, aqtion-alpha] env: MESON_ARGS: >- From 3dee64a3a89002d0bd65d6ed519468c38b130787 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 3 Nov 2023 23:17:44 +0300 Subject: [PATCH 005/167] Drop raw samples when resetting wrap counter. --- src/client/sound/dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/sound/dma.c b/src/client/sound/dma.c index 2746d7d6e..f06b29c70 100644 --- a/src/client/sound/dma.c +++ b/src/client/sound/dma.c @@ -804,7 +804,7 @@ static int DMA_GetTime(void) if (s_paintedtime > 0x40000000) { // time to chop things off to avoid 32 bit limits buffers = 0; - s_paintedtime = fullsamples; + s_rawend = s_paintedtime = fullsamples; S_StopAllSounds(); } } From a3a01385db4f1b35c49c8ec2df19eb3fe64c745c Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 3 Nov 2023 23:19:15 +0300 Subject: [PATCH 006/167] Fix buffer underruns when in minimized state. If client is minimized, mix ahead 0.125 sec minimum. 0.1 sec results in choppy sound when client runs at 10 FPS. --- src/client/sound/dma.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/client/sound/dma.c b/src/client/sound/dma.c index f06b29c70..30970ed1c 100644 --- a/src/client/sound/dma.c +++ b/src/client/sound/dma.c @@ -818,6 +818,7 @@ static void DMA_Update(void) int i; channel_t *ch; int samples, soundtime, endtime; + float sec; // update spatialization for dynamic sounds for (i = 0, ch = s_channels; i < s_numchannels; i++, ch++) { @@ -870,7 +871,10 @@ static void DMA_Update(void) } // mix ahead of current position - endtime = soundtime + Cvar_ClampValue(s_mixahead, 0, 1) * dma.speed; + sec = Cvar_ClampValue(s_mixahead, 0, 1); + if (!cls.active) + sec = max(sec, 0.125f); + endtime = soundtime + sec * dma.speed; // mix to an even submission block size endtime = ALIGN(endtime, dma.submission_chunk); From b98f35b6819df3f91aada56c190d5acd05828967 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 4 Nov 2023 16:15:43 +0300 Subject: [PATCH 007/167] Wrap debug printf macros in do { } while (0). --- inc/common/common.h | 16 ++++++++-------- src/client/client.h | 12 ++++++------ src/common/files.c | 4 ++-- src/common/net/chan.c | 8 ++++---- src/server/mvd/parse.c | 4 ++-- src/server/server.h | 4 ++-- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/inc/common/common.h b/inc/common/common.h index 50ca5586d..470d3ddf0 100644 --- a/inc/common/common.h +++ b/inc/common/common.h @@ -114,17 +114,17 @@ void Com_AddConfigFile(const char *name, unsigned flags); #if USE_DEBUG #define Com_DPrintf(...) \ - if (developer && developer->integer > 0) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (developer && developer->integer > 0) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #define Com_DDPrintf(...) \ - if (developer && developer->integer > 1) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (developer && developer->integer > 1) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #define Com_DDDPrintf(...) \ - if (developer && developer->integer > 2) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (developer && developer->integer > 2) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #define Com_DDDDPrintf(...) \ - if (developer && developer->integer > 3) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (developer && developer->integer > 3) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #else #define Com_DPrintf(...) ((void)0) #define Com_DDPrintf(...) ((void)0) diff --git a/src/client/client.h b/src/client/client.h index 530d9b570..cff971b11 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -526,14 +526,14 @@ extern cvar_t *cl_nolerp; #if USE_DEBUG #define SHOWNET(level, ...) \ - if (cl_shownet->integer > level) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (cl_shownet->integer > level) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #define SHOWCLAMP(level, ...) \ - if (cl_showclamp->integer > level) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (cl_showclamp->integer > level) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #define SHOWMISS(...) \ - if (cl_showmiss->integer) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (cl_showmiss->integer) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) extern cvar_t *cl_shownet; extern cvar_t *cl_showmiss; extern cvar_t *cl_showclamp; diff --git a/src/common/files.c b/src/common/files.c index f912a12d2..9e57ebf24 100644 --- a/src/common/files.c +++ b/src/common/files.c @@ -70,8 +70,8 @@ QUAKE FILESYSTEM #if USE_DEBUG #define FS_DPrintf(...) \ - if (fs_debug && fs_debug->integer) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (fs_debug && fs_debug->integer) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #else #define FS_DPrintf(...) #endif diff --git a/src/common/net/chan.c b/src/common/net/chan.c index 1c1e6c0ef..ba682cf87 100644 --- a/src/common/net/chan.c +++ b/src/common/net/chan.c @@ -85,11 +85,11 @@ unacknowledged reliable static cvar_t *showpackets; static cvar_t *showdrop; #define SHOWPACKET(...) \ - if (showpackets->integer) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (showpackets->integer) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #define SHOWDROP(...) \ - if (showdrop->integer) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (showdrop->integer) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #else #define SHOWPACKET(...) #define SHOWDROP(...) diff --git a/src/server/mvd/parse.c b/src/server/mvd/parse.c index e25afdc73..3caeb2482 100644 --- a/src/server/mvd/parse.c +++ b/src/server/mvd/parse.c @@ -27,8 +27,8 @@ static bool match_ended_hack; #if USE_DEBUG #define SHOWNET(level, ...) \ - if (mvd_shownet->integer > level) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (mvd_shownet->integer > level) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) static const char *MVD_ServerCommandString(int cmd) { diff --git a/src/server/server.h b/src/server/server.h index 4208b6bd1..f539ebfb8 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -61,8 +61,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #if USE_DEBUG #define SV_DPrintf(level,...) \ - if (sv_debug && sv_debug->integer > level) \ - Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__) + do { if (sv_debug && sv_debug->integer > level) \ + Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__); } while (0) #else #define SV_DPrintf(...) #endif From 1b4a15ebe0a525635c75b65e6b5219cd25354a14 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 4 Nov 2023 18:26:42 +0300 Subject: [PATCH 008/167] Replace libogg/libvorbis music playback with libavcodec. Has the benefit of supporting more than just Ogg Vorbis format for music. --- .github/workflows/build.yml | 4 +- INSTALL.md | 9 +- inc/client/sound/sound.h | 5 +- meson.build | 18 +- meson_options.txt | 5 - src/client/ffcin.c | 13 +- src/client/sound/al.c | 4 +- src/client/sound/dma.c | 14 +- src/client/sound/main.c | 7 + src/client/sound/mem.c | 4 +- src/client/sound/ogg.c | 680 +++++++++++++++++++++++++++--------- src/client/sound/sound.h | 5 +- src/common/features.h | 6 +- subprojects/ogg.wrap | 12 - subprojects/vorbis.wrap | 14 - 15 files changed, 557 insertions(+), 243 deletions(-) delete mode 100644 subprojects/ogg.wrap delete mode 100644 subprojects/vorbis.wrap diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6c4b321b4..e18bcfe93 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,7 +21,6 @@ env: MESON_ARGS_WIN: >- -Dlibpng:werror=false -Dsdl2=disabled - -Dvorbis:werror=false -Dwayland=disabled -Dwrap_mode=forcefallback -Dx11=disabled @@ -96,8 +95,7 @@ jobs: sudo apt-get install -y meson libsdl2-dev libopenal-dev \ libpng-dev libjpeg-dev zlib1g-dev mesa-common-dev \ libcurl4-gnutls-dev libx11-dev libxi-dev \ - libwayland-dev wayland-protocols libdecor-0-dev \ - libogg-dev libvorbis-dev + libwayland-dev wayland-protocols libdecor-0-dev - name: Build run: | diff --git a/INSTALL.md b/INSTALL.md index ae9821253..0fb5c5f73 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -16,6 +16,9 @@ network protocol level. The rest of dependencies are optional. For JPEG support libjpeg-turbo is required, plain libjpeg will not work. Most Linux distributions already provide libjpeg-turbo in place of libjpeg. +For playing back cinematics in Ogg Theora format and music in Ogg Vorbis format +FFmpeg libraries are required. + To install the *full* set of dependencies for building Q2PRO on Debian or Ubuntu use the following command: @@ -23,7 +26,8 @@ Ubuntu use the following command: libpng-dev libjpeg-dev zlib1g-dev mesa-common-dev \ libcurl4-gnutls-dev libx11-dev libxi-dev \ libwayland-dev wayland-protocols libdecor-0-dev \ - libogg-dev libvorbis-dev + libavcodec-dev libavformat-dev libavutil-dev \ + libswresample-dev libswscale-dev Users of other distributions should look for equivalent development packages and install them. @@ -85,8 +89,7 @@ Q2PRO supports playback of background music ripped off original CD in Ogg Vorbis format. Music files should be placed in `music` subdirectory of the game directory in format `music/trackNN.ogg`, where `NN` corresponds to CD track number. `NN` should be typically in range 02-11 (track 01 is data track on -original CD and should never be used). Placing music in packfile will also -work. +original CD and should never be used). Note that so-called ‘GOG’ naming convention where music tracks are named ‘Track01’ to ‘Track21’ is not supported. diff --git a/inc/client/sound/sound.h b/inc/client/sound/sound.h index b99df01bf..33ec925df 100644 --- a/inc/client/sound/sound.h +++ b/inc/client/sound/sound.h @@ -38,9 +38,12 @@ void S_BeginRegistration(void); qhandle_t S_RegisterSound(const char *sample); void S_EndRegistration(void); +#define MAX_RAW_SAMPLES 8192 + void S_RawSamples(int samples, int rate, int width, int channels, const byte *data); +int S_GetSampleRate(void); -#if USE_OGG +#if USE_AVCODEC void OGG_Play(void); void OGG_Stop(void); void OGG_Update(void); diff --git a/meson.build b/meson.build index 8b9c2c229..cc0dfb567 100644 --- a/meson.build +++ b/meson.build @@ -319,21 +319,6 @@ if openal.found() config.set10('USE_OPENAL', true) endif -ogg = dependency('ogg', - required: get_option('ogg'), - default_options: fallback_opt, -) -vorbisfile = dependency('vorbisfile', - required: get_option('ogg'), - default_options: fallback_opt, -) -if ogg.found() and vorbisfile.found() - client_src += 'src/client/sound/ogg.c' - client_deps += ogg.partial_dependency(compile_args: true, includes: true) - client_deps += vorbisfile - config.set10('USE_OGG', true) -endif - # require FFmpeg >= 5.1.3 avcodec_opt = get_option('avcodec') avcodec = dependency('libavcodec', version: '>= 59.37.100', required: avcodec_opt) @@ -342,7 +327,7 @@ avutil = dependency('libavutil', version: '>= 57.28.100', required: avcodec_opt) swresample = dependency('libswresample', version: '>= 4.7.100', required: avcodec_opt) swscale = dependency('libswscale', version: '>= 6.7.100', required: avcodec_opt) if avcodec.found() and avformat.found() and avutil.found() and swresample.found() and swscale.found() - client_src += 'src/client/ffcin.c' + client_src += ['src/client/ffcin.c', 'src/client/sound/ogg.c'] client_deps += [avcodec, avformat, avutil, swresample, swscale] config.set10('USE_AVCODEC', true) else @@ -496,7 +481,6 @@ summary({ 'md5' : config.get('USE_MD5', 0) != 0, 'mvd-client' : config.get('USE_MVD_CLIENT', 0) != 0, 'mvd-server' : config.get('USE_MVD_SERVER', 0) != 0, - 'ogg' : config.get('USE_OGG', 0) != 0, 'openal' : config.get('USE_OPENAL', 0) != 0, 'packetdup-hack' : config.get('USE_PACKETDUP', 0) != 0, 'save-games' : config.get('USE_SAVEGAMES', 0) != 0, diff --git a/meson_options.txt b/meson_options.txt index 418c98aa4..dba718cb2 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -91,11 +91,6 @@ option('mvd-server', description: 'Enable local MVD recording and MVD/GTV server functionality. '+ 'Use this for hosting a GTV-capable game server.') -option('ogg', - type: 'feature', - value: 'auto', - description: 'Ogg Vorbis music and sound effects support') - option('openal', type: 'feature', value: 'auto', diff --git a/src/client/ffcin.c b/src/client/ffcin.c index 17ecd3b1a..e85370e41 100644 --- a/src/client/ffcin.c +++ b/src/client/ffcin.c @@ -25,7 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #define MAX_PACKETS 2048 // max packets in queue -#define MAX_SAMPLES 8192 // max audio samples in frame typedef struct { AVFifo *pkt_list; @@ -199,7 +198,7 @@ static int process_audio(void) AVFrame *out = cin.audio.frame; int ret; - out->nb_samples = MAX_SAMPLES; + out->nb_samples = MAX_RAW_SAMPLES; ret = swr_convert_frame(cin.swr_ctx, out, in); if (ret < 0) { Com_EPrintf("Error converting audio: %s\n", av_err2str(ret)); @@ -428,7 +427,7 @@ static bool open_codec_context(enum AVMediaType type) dec = avcodec_find_decoder(st->codecpar->codec_id); if (!dec) { - Com_EPrintf("Failed to find %s codec\n", av_get_media_type_string(type)); + Com_EPrintf("Failed to find %s codec %s\n", av_get_media_type_string(type), avcodec_get_name(st->codecpar->codec_id)); return false; } @@ -506,13 +505,17 @@ static bool open_codec_context(enum AVMediaType type) return false; } + int sample_rate = S_GetSampleRate(); + if (!sample_rate) + sample_rate = dec_ctx->sample_rate; + if (dec_ctx->ch_layout.nb_channels >= 2) out->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; else out->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; out->format = AV_SAMPLE_FMT_S16; - out->sample_rate = dec_ctx->sample_rate; - out->nb_samples = MAX_SAMPLES; + out->sample_rate = sample_rate; + out->nb_samples = MAX_RAW_SAMPLES; ret = av_frame_get_buffer(out, 0); if (ret < 0) { diff --git a/src/client/sound/al.c b/src/client/sound/al.c index 8195d014b..dbedea738 100644 --- a/src/client/sound/al.c +++ b/src/client/sound/al.c @@ -398,9 +398,9 @@ static void AL_StreamStop(void) Q_assert(!s_stream_buffers); } -static bool AL_NeedRawSamples(void) +static int AL_NeedRawSamples(void) { - return s_stream_buffers < 48; + return s_stream_buffers < 32 ? MAX_RAW_SAMPLES : 0; } static bool AL_RawSamples(int samples, int rate, int width, int channels, const byte *data, float volume) diff --git a/src/client/sound/dma.c b/src/client/sound/dma.c index 30970ed1c..f7c679edb 100644 --- a/src/client/sound/dma.c +++ b/src/client/sound/dma.c @@ -22,8 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #define PAINTBUFFER_SIZE 2048 -#define MAX_RAW_SAMPLES 8192 - typedef struct { float left; float right; @@ -154,9 +152,11 @@ static bool DMA_RawSamples(int samples, int rate, int width, int channels, const #undef RESAMPLE -static bool DMA_NeedRawSamples(void) +static int DMA_NeedRawSamples(void) { - return s_rawend - s_paintedtime < MAX_RAW_SAMPLES - 2048; + int avail = MAX_RAW_SAMPLES - (s_rawend - s_paintedtime); + clamp(avail, 0, MAX_RAW_SAMPLES); + return avail & ~127; } static void DMA_DropRawSamples(void) @@ -886,6 +886,11 @@ static void DMA_Update(void) snddma.submit(); } +static int DMA_GetSampleRate(void) +{ + return dma.speed; +} + const sndapi_t snd_dma = { .init = DMA_Init, .shutdown = DMA_Shutdown, @@ -900,4 +905,5 @@ const sndapi_t snd_dma = { .get_begin_ofs = DMA_DriftBeginofs, .play_channel = DMA_Spatialize, .stop_all_sounds = DMA_ClearBuffer, + .get_sample_rate = DMA_GetSampleRate, }; diff --git a/src/client/sound/main.c b/src/client/sound/main.c index 223c90c30..026299906 100644 --- a/src/client/sound/main.c +++ b/src/client/sound/main.c @@ -788,6 +788,13 @@ void S_RawSamples(int samples, int rate, int width, int channels, const byte *da s_api.raw_samples(samples, rate, width, channels, data, 1.0f); } +int S_GetSampleRate(void) +{ + if (s_started && s_api.get_sample_rate) + return s_api.get_sample_rate(); + return 0; +} + // ======================================================================= // Update sound buffer // ======================================================================= diff --git a/src/client/sound/mem.c b/src/client/sound/mem.c index 4479a5d66..59c1e55cb 100644 --- a/src/client/sound/mem.c +++ b/src/client/sound/mem.c @@ -62,7 +62,7 @@ static bool GetWavinfo(sizebuf_t *sz) tag = SZ_ReadLong(sz); -#if USE_OGG +#if USE_AVCODEC if (tag == MakeLittleLong('O','g','g','S') || !COM_CompareExtension(s_info.name, ".ogg")) { sz->readcount = 0; return OGG_Load(sz); @@ -258,7 +258,7 @@ sfxcache_t *S_LoadSound(sfx_t *s) sc = s_api.upload_sfx(s); -#if USE_OGG +#if USE_AVCODEC if (s_info.format != FORMAT_PCM) FS_FreeTempMem(s_info.data); #endif diff --git a/src/client/sound/ogg.c b/src/client/sound/ogg.c index 3510e15a6..ac151c2ff 100644 --- a/src/client/sound/ogg.c +++ b/src/client/sound/ogg.c @@ -16,22 +16,20 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#define OV_EXCLUDE_STATIC_CALLBACKS - #include "sound.h" -#include -#ifndef USE_BIG_ENDIAN -#define USE_BIG_ENDIAN 0 -#endif +#include +#include +#include typedef struct { - bool initialized; - OggVorbis_File vf; - qhandle_t f; - int channels; - int rate; - char path[MAX_QPATH]; + AVFormatContext *fmt_ctx; + AVCodecContext *dec_ctx; + AVPacket *pkt; + AVFrame *frame_in; + AVFrame *frame_out; + struct SwrContext *swr_ctx; + int stream_index; } ogg_state_t; static ogg_state_t ogg; @@ -44,63 +42,201 @@ static void **tracklist; static int trackcount; static int trackindex; -static size_t my_read(void *buf, size_t size, size_t nmemb, void *stream) -{ - if (!size || !nmemb) { - errno = 0; - return 0; - } +static char extensions[MAX_QPATH]; +static int supported; - if (size > INT_MAX / nmemb) { - errno = EINVAL; - return 0; - } +typedef struct { + const char *ext; + const char *fmt; + int codec_id; +} avformat_t; + +static const avformat_t formats[] = { + { ".flac", "flac", AV_CODEC_ID_FLAC }, + { ".opus", "ogg", AV_CODEC_ID_OPUS }, + { ".ogg", "ogg", AV_CODEC_ID_VORBIS }, + { ".mp3", "mp3", AV_CODEC_ID_MP3 }, + { ".wav", "wav", AV_CODEC_ID_NONE } +}; - int ret = FS_Read(buf, size * nmemb, ogg.f); - if (ret < 0) { - errno = EIO; - return 0; +static void init_formats(void) +{ + for (int i = 0; i < q_countof(formats); i++) { + const avformat_t *f = &formats[i]; + if (!av_find_input_format(f->fmt)) + continue; + if (f->codec_id != AV_CODEC_ID_NONE && + !avcodec_find_decoder(f->codec_id)) + continue; + supported |= BIT(i); + if (*extensions) + Q_strlcat(extensions, ";", sizeof(extensions)); + Q_strlcat(extensions, f->ext, sizeof(extensions)); } - errno = 0; - return ret / size; + Com_DPrintf("Supported music formats: %#x\n", supported); } static void ogg_stop(void) { - ov_clear(&ogg.vf); - FS_CloseFile(ogg.f); + avcodec_free_context(&ogg.dec_ctx); + avformat_close_input(&ogg.fmt_ctx); + av_packet_free(&ogg.pkt); + av_frame_free(&ogg.frame_in); + av_frame_free(&ogg.frame_out); + swr_free(&ogg.swr_ctx); + memset(&ogg, 0, sizeof(ogg)); } -static void ogg_play(void) +static AVFormatContext *ogg_open(const char *name, bool autoplay) { - int ret = ov_open_callbacks(&ogg, &ogg.vf, NULL, 0, (ov_callbacks){ my_read }); + char normalized[MAX_QPATH]; + char fullname[MAX_OSPATH]; + const char *path = NULL, *ext; + AVFormatContext *fmt_ctx = NULL; + int ret; + + fullname[0] = 0; + + if (FS_NormalizePathBuffer(normalized, name, sizeof(normalized)) >= sizeof(normalized)) { + ret = AVERROR(ENAMETOOLONG); + goto done; + } + + ext = COM_FileExtension(normalized); + + // open from filesystem only. since packfiles are downloadable, music from + // packfiles can pose security risk due to huge lavf/lavc attack surface. + while (1) { + path = FS_NextPath(path); + if (!path) { + ret = AVERROR(ENOENT); + break; + } + + // try original filename if it has an extension + if (*ext) { + if (Q_snprintf(fullname, sizeof(fullname), "%s/music/%s", path, normalized) >= sizeof(fullname)) { + ret = AVERROR(ENAMETOOLONG); + break; + } + + ret = avformat_open_input(&fmt_ctx, fullname, NULL, NULL); + if (ret != AVERROR(ENOENT)) + break; + } + + // try to append different extensions + for (int i = 0; i < q_countof(formats); i++) { + if (!(supported & BIT(i))) + continue; + + if (!Q_stricmp(ext, formats[i].ext)) + continue; + + if (Q_snprintf(fullname, sizeof(fullname), "%s/music/%s%s", + path, normalized, formats[i].ext) >= sizeof(fullname)) { + ret = AVERROR(ENAMETOOLONG); + goto done; + } + + ret = avformat_open_input(&fmt_ctx, fullname, NULL, NULL); + if (ret != AVERROR(ENOENT)) + goto done; + } + } + + if (ret == AVERROR(ENOENT) && autoplay) + return NULL; + +done: if (ret < 0) { - Com_EPrintf("%s does not appear to be an Ogg bitstream (error %d)\n", ogg.path, ret); - goto fail; + Com_LPrintf(ret == AVERROR(ENOENT) ? PRINT_ALL : PRINT_ERROR, + "Couldn't open %s: %s\n", ret == AVERROR(ENOENT) || + !*fullname ? normalized : fullname, av_err2str(ret)); + return NULL; } - vorbis_info *vi = ov_info(&ogg.vf, -1); - if (!vi) { - Com_EPrintf("Couldn't get info on %s\n", ogg.path); - goto fail; + return fmt_ctx; +} + +static bool ogg_play_(void) +{ + AVStream *st; + const AVCodec *dec; + AVCodecContext *dec_ctx; + int ret; + + ret = avformat_find_stream_info(ogg.fmt_ctx, NULL); + if (ret < 0) { + Com_EPrintf("Couldn't find stream info: %s\n", av_err2str(ret)); + return false; } - if (vi->channels < 1 || vi->channels > 2) { - Com_EPrintf("%s has bad number of channels\n", ogg.path); - goto fail; +#if USE_DEBUG + if (developer->integer) + av_dump_format(ogg.fmt_ctx, 0, ogg.fmt_ctx->url, 0); +#endif + + ret = av_find_best_stream(ogg.fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0); + if (ret < 0) { + Com_EPrintf("Couldn't find audio stream\n"); + return false; } - Com_DPrintf("Playing %s\n", ogg.path); + ogg.stream_index = ret; + st = ogg.fmt_ctx->streams[ogg.stream_index]; - ogg.initialized = true; - ogg.channels = vi->channels; - ogg.rate = vi->rate; - return; + dec = avcodec_find_decoder(st->codecpar->codec_id); + if (!dec) { + Com_EPrintf("Failed to find audio codec %s\n", avcodec_get_name(st->codecpar->codec_id)); + return false; + } -fail: - ogg_stop(); + ogg.dec_ctx = dec_ctx = avcodec_alloc_context3(dec); + if (!dec_ctx) { + Com_EPrintf("Failed to allocate audio codec context\n"); + return false; + } + + ret = avcodec_parameters_to_context(dec_ctx, st->codecpar); + if (ret < 0) { + Com_EPrintf("Failed to copy audio codec parameters to decoder context\n"); + return false; + } + + ret = avcodec_open2(dec_ctx, dec, NULL); + if (ret < 0) { + Com_EPrintf("Failed to open audio codec\n"); + return false; + } + + dec_ctx->pkt_timebase = st->time_base; + + ogg.pkt = av_packet_alloc(); + ogg.frame_in = av_frame_alloc(); + ogg.frame_out = av_frame_alloc(); + ogg.swr_ctx = swr_alloc(); + if (!ogg.pkt || !ogg.frame_in || !ogg.frame_out || !ogg.swr_ctx) { + Com_EPrintf("Couldn't allocate memory\n"); + return false; + } + + Com_DPrintf("Playing %s\n", ogg.fmt_ctx->url); + return true; +} + +static void ogg_play(AVFormatContext *fmt_ctx) +{ + if (!fmt_ctx) + return; + + Q_assert(!ogg.fmt_ctx); + ogg.fmt_ctx = fmt_ctx; + + if (!ogg_play_()) + ogg_stop(); } static void shuffle(void) @@ -128,22 +264,13 @@ void OGG_Play(void) if (ogg_shuffle->integer && trackcount) { if (trackindex == 0) shuffle(); - Q_strlcpy(ogg.path, tracklist[trackindex], sizeof(ogg.path)); + s = tracklist[trackindex]; trackindex = (trackindex + 1) % trackcount; } else if (COM_IsUint(s)) { - Q_snprintf(ogg.path, sizeof(ogg.path), "music/track%02d.ogg", atoi(s)); - } else { - Q_snprintf(ogg.path, sizeof(ogg.path), "music/%s.ogg", s); + s = va("track%02d", atoi(s)); } - int ret = FS_OpenFile(ogg.path, &ogg.f, FS_MODE_READ); - if (!ogg.f) { - if (ret != Q_ERR(ENOENT)) - Com_EPrintf("Couldn't open %s: %s\n", ogg.path, Q_ErrorString(ret)); - return; - } - - ogg_play(); + ogg_play(ogg_open(s, true)); } void OGG_Stop(void) @@ -154,187 +281,399 @@ void OGG_Stop(void) s_api.drop_raw_samples(); } -void OGG_Update(void) +static int read_packet(AVPacket *pkt) { - if (!ogg.initialized) - return; + while (1) { + int ret = av_read_frame(ogg.fmt_ctx, pkt); + if (ret < 0) + return ret; + if (pkt->stream_index == ogg.stream_index) + return ret; + av_packet_unref(pkt); + } +} - if (!s_started) - return; +static int decode_frame_(void) +{ + AVCodecContext *dec = ogg.dec_ctx; + AVPacket *pkt = ogg.pkt; + + while (1) { + int ret = avcodec_receive_frame(dec, ogg.frame_in); + + if (ret == AVERROR(EAGAIN)) { + ret = read_packet(pkt); + if (ret == AVERROR_EOF) { + ret = avcodec_send_packet(dec, NULL); + } else if (ret >= 0) { + ret = avcodec_send_packet(dec, pkt); + av_packet_unref(pkt); + } + if (ret < 0) + return ret; + continue; + } - if (!s_active) - return; + return ret; + } +} - while (s_api.need_raw_samples()) { - byte buffer[4096]; - int samples; +static bool decode_frame(void) +{ + int ret = decode_frame_(); + if (ret >= 0) + return true; - samples = ov_read(&ogg.vf, (char *)buffer, sizeof(buffer), USE_BIG_ENDIAN, 2, 1, NULL); - if (samples == 0 && (OGG_Play(), ogg.initialized)) - samples = ov_read(&ogg.vf, (char *)buffer, sizeof(buffer), USE_BIG_ENDIAN, 2, 1, NULL); + if (ret == AVERROR_EOF) + Com_DPrintf("%s decoding audio\n", av_err2str(ret)); + else + Com_EPrintf("Error decoding audio: %s\n", av_err2str(ret)); - if (samples <= 0) - break; + // play next file + OGG_Play(); - vorbis_info *vi = ov_info(&ogg.vf, -1); - if (!vi || vi->channels < 1 || vi->channels > 2) - break; + return ogg.dec_ctx && decode_frame_() >= 0; +} + +static int convert_samples(AVFrame *in) +{ + AVFrame *out = ogg.frame_out; + int ret; + + // exit if not configured yet + if (out->format < 0) + return 0; + + out->nb_samples = s_api.need_raw_samples(); + ret = swr_convert_frame(ogg.swr_ctx, out, in); + if (ret < 0) + return ret; + if (!out->nb_samples) + return 0; + + Com_DDDPrintf("%d raw samples\n", out->nb_samples); + + if (!s_api.raw_samples(out->nb_samples, out->sample_rate, 2, + out->ch_layout.nb_channels, + out->data[0], ogg_volume->value)) + s_api.drop_raw_samples(); + + return 1; +} + +static int reconfigure_swr(void) +{ + AVFrame *in = ogg.frame_in; + AVFrame *out = ogg.frame_out; + int sample_rate = S_GetSampleRate(); + + if (!sample_rate) + sample_rate = out->sample_rate; + if (!sample_rate) + sample_rate = in->sample_rate; + + swr_close(ogg.swr_ctx); + av_frame_unref(out); + + out->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; + out->format = AV_SAMPLE_FMT_S16; + out->sample_rate = sample_rate; + out->nb_samples = MAX_RAW_SAMPLES; + + return av_frame_get_buffer(out, 0); +} + +void OGG_Update(void) +{ + if (!s_started || !s_active || !ogg.dec_ctx) + return; - ogg.channels = vi->channels; - ogg.rate = vi->rate; + while (s_api.need_raw_samples() > 0) { + int ret = convert_samples(NULL); + + // if swr buffer is empty, decode more input + if (ret == 0) { + if (!decode_frame()) + break; + + // now that we have a frame, configure output + if (ogg.frame_out->format < 0) + ret = reconfigure_swr(); + + if (ret >= 0) { + ret = convert_samples(ogg.frame_in); + if (ret == AVERROR_INPUT_CHANGED) { + ret = reconfigure_swr(); + if (ret >= 0) + ret = convert_samples(ogg.frame_in); + } + } + } - if (!s_api.raw_samples(samples >> vi->channels, vi->rate, 2, - vi->channels, buffer, ogg_volume->value)) { - s_api.drop_raw_samples(); + if (ret < 0) { + Com_EPrintf("Error converting audio: %s\n", av_err2str(ret)); + OGG_Stop(); break; } } } -static size_t my_read_sz(void *buf, size_t size, size_t nmemb, void *datasource) +static int sz_read_packet(void *opaque, uint8_t *buf, int size) { - sizebuf_t *sz = datasource; - size_t bytes; - - if (!size || !nmemb) { - errno = 0; - return 0; - } + sizebuf_t *sz = opaque; - if (size > SIZE_MAX / nmemb) { - errno = EINVAL; - return 0; - } + if (size < 0) + return AVERROR(EINVAL); - bytes = min(size * nmemb, sz->cursize - sz->readcount); - if (bytes) { - memcpy(buf, sz->data + sz->readcount, bytes); - sz->readcount += bytes; - } + size = min(size, sz->cursize - sz->readcount); + if (!size) + return AVERROR_EOF; - errno = 0; - return bytes / size; + memcpy(buf, sz->data + sz->readcount, size); + sz->readcount += size; + return size; } -static int my_seek_sz(void *datasource, ogg_int64_t offset, int whence) +static int64_t sz_seek(void *opaque, int64_t offset, int whence) { - sizebuf_t *sz = datasource; + sizebuf_t *sz = opaque; switch (whence) { case SEEK_SET: if (offset < 0) - goto fail; + return AVERROR(EINVAL); sz->readcount = min(offset, sz->cursize); break; case SEEK_CUR: - if (offset < -(ogg_int64_t)sz->readcount) - goto fail; - sz->readcount += min(offset, (ogg_int64_t)(sz->cursize - sz->readcount)); + if (offset < -(int64_t)sz->readcount) + return AVERROR(EINVAL); + sz->readcount += min(offset, (int64_t)(sz->cursize - sz->readcount)); break; case SEEK_END: sz->readcount = sz->cursize; break; default: - fail: - errno = EINVAL; - return -1; + return AVERROR(EINVAL); } - errno = 0; - return 0; -} - -static long my_tell_sz(void *datasource) -{ - sizebuf_t *sz = datasource; return sz->readcount; } bool OGG_Load(sizebuf_t *sz) { - ov_callbacks cb = { - my_read_sz, - my_seek_sz, - NULL, - my_tell_sz - }; - - OggVorbis_File vf; - int ret = ov_open_callbacks(sz, &vf, NULL, 0, cb); - if (ret < 0) { - Com_DPrintf("%s does not appear to be an Ogg bitstream (error %d)\n", s_info.name, ret); + AVFormatContext *fmt_ctx = NULL; + AVIOContext *avio_ctx = NULL; + uint8_t *avio_ctx_buffer = NULL; + const size_t avio_ctx_buffer_size = 4096; + AVPacket *pkt = NULL; + AVFrame *frame = NULL, *out = NULL; + struct SwrContext *swr_ctx = NULL; + AVCodecContext *dec_ctx = NULL; + AVStream *st; + bool res = false; + int ret, sample_rate; + + const AVInputFormat *fmt = av_find_input_format("ogg"); + if (!fmt) { + Com_DPrintf("Ogg input format not found\n"); + return false; + } + + const AVCodec *dec = avcodec_find_decoder(AV_CODEC_ID_VORBIS); + if (!dec) { + Com_DPrintf("Vorbis decoder not found\n"); + return false; + } + + fmt_ctx = avformat_alloc_context(); + if (!fmt_ctx) { + Com_DPrintf("Failed to allocate format context\n"); return false; } - vorbis_info *vi = ov_info(&vf, 0); - if (!vi) { - Com_DPrintf("Couldn't get info on %s\n", s_info.name); + avio_ctx_buffer = av_malloc(avio_ctx_buffer_size); + if (!avio_ctx_buffer) { + Com_DPrintf("Failed to allocate avio buffer\n"); + goto fail; + } + + avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size, + 0, sz, sz_read_packet, NULL, sz_seek); + if (!avio_ctx) { + Com_DPrintf("Failed to allocate avio context\n"); + goto fail; + } + + fmt_ctx->pb = avio_ctx; + + ret = avformat_open_input(&fmt_ctx, NULL, fmt, NULL); + if (ret < 0) { + Com_DPrintf("Couldn't open %s: %s\n", s_info.name, av_err2str(ret)); + goto fail; + } + + if (fmt_ctx->nb_streams != 1) { + Com_DPrintf("Multiple streams in %s\n", s_info.name); goto fail; } - if (vi->channels < 1 || vi->channels > 2) { + st = fmt_ctx->streams[0]; + if (st->codecpar->codec_id != AV_CODEC_ID_VORBIS) { + Com_DPrintf("First stream is not Vorbis in %s\n", s_info.name); + goto fail; + } + + if (st->codecpar->ch_layout.nb_channels < 1 || st->codecpar->ch_layout.nb_channels > 2) { Com_DPrintf("%s has bad number of channels\n", s_info.name); goto fail; } - if (vi->rate < 8000 || vi->rate > 48000) { + if (st->codecpar->sample_rate < 8000 || st->codecpar->sample_rate > 48000) { Com_DPrintf("%s has bad rate\n", s_info.name); goto fail; } - ogg_int64_t samples = ov_pcm_total(&vf, 0); - if (samples < 1 || samples > MAX_LOADFILE >> vi->channels) { + if (st->duration < 1 || st->duration > MAX_LOADFILE >> st->codecpar->ch_layout.nb_channels) { Com_DPrintf("%s has bad number of samples\n", s_info.name); goto fail; } - int size = samples << vi->channels; + dec_ctx = avcodec_alloc_context3(dec); + if (!dec_ctx) { + Com_DPrintf("Failed to allocate codec context\n"); + goto fail; + } + + ret = avcodec_parameters_to_context(dec_ctx, st->codecpar); + if (ret < 0) { + Com_DPrintf("Failed to copy codec parameters to decoder context\n"); + goto fail; + } + + ret = avcodec_open2(dec_ctx, dec, NULL); + if (ret < 0) { + Com_DPrintf("Failed to open codec\n"); + goto fail; + } + + dec_ctx->pkt_timebase = st->time_base; + + pkt = av_packet_alloc(); + frame = av_frame_alloc(); + out = av_frame_alloc(); + swr_ctx = swr_alloc(); + if (!pkt || !frame || !out || !swr_ctx) { + Com_DPrintf("Failed to allocate memory\n"); + goto fail; + } + + sample_rate = S_GetSampleRate(); + if (!sample_rate) + sample_rate = dec_ctx->sample_rate; + + ret = av_channel_layout_copy(&out->ch_layout, &dec_ctx->ch_layout); + if (ret < 0) { + Com_DPrintf("Failed to copy channel layout\n"); + goto fail; + } + out->format = AV_SAMPLE_FMT_S16; + out->sample_rate = sample_rate; + out->nb_samples = MAX_RAW_SAMPLES; + + ret = av_frame_get_buffer(out, 0); + if (ret < 0) { + Com_DPrintf("Failed to allocate audio buffer\n"); + goto fail; + } + + int64_t nb_samples = st->duration; + + if (out->sample_rate != dec_ctx->sample_rate) { + nb_samples = av_rescale_rnd(st->duration + 2, out->sample_rate, dec_ctx->sample_rate, AV_ROUND_UP) + 2; + if (nb_samples > MAX_LOADFILE >> out->ch_layout.nb_channels) { + Com_DPrintf("Too many samples after resampling\n"); + goto fail; + } + } + + int bufsize = nb_samples << out->ch_layout.nb_channels; int offset = 0; + bool eof = false; - s_info.channels = vi->channels; - s_info.rate = vi->rate; + s_info.channels = out->ch_layout.nb_channels; + s_info.rate = out->sample_rate; s_info.width = 2; s_info.loopstart = -1; - s_info.data = FS_AllocTempMem(size); - - while (offset < size) { - int bitstream; + s_info.data = FS_AllocTempMem(bufsize); + + while (!eof) { + ret = avcodec_receive_frame(dec_ctx, frame); + + if (ret == AVERROR(EAGAIN)) { + ret = av_read_frame(fmt_ctx, pkt); + if (ret == AVERROR_EOF) { + ret = avcodec_send_packet(dec_ctx, NULL); + } else if (ret >= 0) { + ret = avcodec_send_packet(dec_ctx, pkt); + av_packet_unref(pkt); + } + if (ret < 0) + break; + continue; + } - ret = ov_read(&vf, (char *)s_info.data + offset, size - offset, USE_BIG_ENDIAN, 2, 1, &bitstream); - if (ret == 0 || bitstream) + out->nb_samples = MAX_RAW_SAMPLES; + if (ret == AVERROR_EOF) { + ret = swr_convert_frame(swr_ctx, out, NULL); + eof = true; + } else if (ret >= 0) { + ret = swr_convert_frame(swr_ctx, out, frame); + } + if (ret < 0) break; - if (ret < 0) { - Com_DPrintf("Error %d decoding %s\n", ret, s_info.name); - FS_FreeTempMem(s_info.data); - goto fail; + int size = out->nb_samples << out->ch_layout.nb_channels; + if (size > bufsize - offset) { + ret = AVERROR(ENOSPC); + break; } - offset += ret; + memcpy(s_info.data + offset, out->data[0], size); + offset += size; } - s_info.samples = offset >> s_info.channels; + if (ret < 0) { + Com_DPrintf("Error decoding %s: %s\n", s_info.name, av_err2str(ret)); + Z_Freep(&s_info.data); + goto fail; + } - ov_clear(&vf); - return true; + s_info.samples = offset >> s_info.channels; + res = true; fail: - ov_clear(&vf); - return false; + avformat_close_input(&fmt_ctx); + if (avio_ctx) + av_freep(&avio_ctx->buffer); + avio_context_free(&avio_ctx); + avcodec_free_context(&dec_ctx); + av_packet_free(&pkt); + av_frame_free(&frame); + av_frame_free(&out); + swr_free(&swr_ctx); + + return res; } void OGG_LoadTrackList(void) { FS_FreeList(tracklist); - tracklist = FS_ListFiles("music", ".ogg", FS_SEARCH_SAVEPATH, &trackcount); + tracklist = FS_ListFiles("music", extensions, FS_SEARCH_STRIPEXT, &trackcount); trackindex = 0; } static void OGG_Play_f(void) { - char buffer[MAX_QPATH]; - qhandle_t f; - if (Cmd_Argc() < 3) { Com_Printf("Usage: %s %s \n", Cmd_Argv(0), Cmd_Argv(1)); return; @@ -350,24 +689,23 @@ static void OGG_Play_f(void) return; } - f = FS_EasyOpenFile(buffer, sizeof(buffer), FS_MODE_READ, - "music/", Cmd_Argv(2), ".ogg"); - if (!f) + AVFormatContext *fmt_ctx = ogg_open(Cmd_Argv(2), false); + if (!fmt_ctx) return; OGG_Stop(); - Q_strlcpy(ogg.path, buffer, sizeof(ogg.path)); - ogg.f = f; - ogg_play(); + ogg_play(fmt_ctx); } static void OGG_Info_f(void) { - if (ogg.initialized) { - Com_Printf("Playing %s, %d Hz, %d ch\n", ogg.path, ogg.rate, ogg.channels); - } else if (ogg.path[0]) { - Com_Printf("Would play %s, but it failed to load.\n", ogg.path); + AVFrame *out = ogg.frame_out; + + if (out) { + Com_Printf("Playing %s, %s, %d Hz, %d ch\n", + ogg.fmt_ctx->url, ogg.dec_ctx->codec->name, + out->sample_rate, out->ch_layout.nb_channels); } else { Com_Printf("Playback stopped.\n"); } @@ -383,7 +721,7 @@ static void OGG_Cmd_c(genctx_t *ctx, int argnum) } if (argnum == 2 && !strcmp(Cmd_Argv(1), "play")) - FS_File_g("music", ".ogg", FS_SEARCH_STRIPEXT, ctx); + FS_File_g("music", extensions, FS_SEARCH_STRIPEXT, ctx); } static void OGG_Cmd_f(void) @@ -430,6 +768,8 @@ void OGG_Init(void) Cmd_Register(c_ogg); + init_formats(); + OGG_LoadTrackList(); } diff --git a/src/client/sound/sound.h b/src/client/sound/sound.h index 917ae0c95..c834145c4 100644 --- a/src/client/sound/sound.h +++ b/src/client/sound/sound.h @@ -115,12 +115,13 @@ typedef struct { void (*delete_sfx)(sfx_t *s); void (*page_in_sfx)(sfx_t *s); bool (*raw_samples)(int samples, int rate, int width, int channels, const byte *data, float volume); - bool (*need_raw_samples)(void); + int (*need_raw_samples)(void); void (*drop_raw_samples)(void); int (*get_begin_ofs)(float timeofs); void (*play_channel)(channel_t *ch); void (*stop_channel)(channel_t *ch); void (*stop_all_sounds)(void); + int (*get_sample_rate)(void); } sndapi_t; #if USE_SNDDMA @@ -187,6 +188,6 @@ void S_BuildSoundList(int *sounds); float S_GetEntityLoopVolume(const centity_state_t *ent); float S_GetEntityLoopDistMult(const centity_state_t *ent); -#if USE_OGG +#if USE_AVCODEC bool OGG_Load(sizebuf_t *sz); #endif diff --git a/src/common/features.h b/src/common/features.h index 5086eed02..2c568ad9b 100644 --- a/src/common/features.h +++ b/src/common/features.h @@ -25,6 +25,9 @@ static const char *Com_GetFeatures(void) #if USE_AUTOREPLY "auto-reply " #endif +#if USE_AVCODEC + "avcodec " +#endif #if USE_CLIENT_GTV "client-gtv " #endif @@ -58,9 +61,6 @@ static const char *Com_GetFeatures(void) #if USE_MVD_SERVER "mvd-server " #endif -#if USE_OGG - "ogg " -#endif #if USE_OPENAL "openal " #endif diff --git a/subprojects/ogg.wrap b/subprojects/ogg.wrap deleted file mode 100644 index 120b7c4cd..000000000 --- a/subprojects/ogg.wrap +++ /dev/null @@ -1,12 +0,0 @@ -[wrap-file] -directory = libogg-1.3.5 -source_url = https://downloads.xiph.org/releases/ogg/libogg-1.3.5.tar.xz -source_filename = libogg-1.3.5.tar.xz -source_hash = c4d91be36fc8e54deae7575241e03f4211eb102afb3fc0775fbbc1b740016705 -patch_filename = ogg_1.3.5-5_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/ogg_1.3.5-5/get_patch -patch_hash = 16b9d2a2b1b0a6edcaedf6521de786ba3e08f7416fe818967f6d75a621ae8156 -wrapdb_version = 1.3.5-5 - -[provide] -ogg = libogg_dep diff --git a/subprojects/vorbis.wrap b/subprojects/vorbis.wrap deleted file mode 100644 index 7425c11ec..000000000 --- a/subprojects/vorbis.wrap +++ /dev/null @@ -1,14 +0,0 @@ -[wrap-file] -directory = libvorbis-1.3.7 -source_url = https://downloads.xiph.org/releases/vorbis/libvorbis-1.3.7.tar.xz -source_filename = libvorbis-1.3.7.tar.xz -source_hash = b33cc4934322bcbf6efcbacf49e3ca01aadbea4114ec9589d1b1e9d20f72954b -patch_filename = vorbis_1.3.7-4_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/vorbis_1.3.7-4/get_patch -patch_hash = 979e22b24b16c927040700dfd8319cd6ba29bf52a14dbc66b1cb4ea60504f14a -wrapdb_version = 1.3.7-4 - -[provide] -vorbis = vorbis_dep -vorbisfile = vorbisfile_dep -vorbisenc = vorbisenc_dep From 9612988bc45b68fabb677d037e37c8affa760c31 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 4 Nov 2023 19:17:04 +0300 Subject: [PATCH 009/167] =?UTF-8?q?Refuse=20downloading=20to=20=E2=80=98mu?= =?UTF-8?q?sic=E2=80=99=20or=20=E2=80=98video=E2=80=99=20directories.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/client/download.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/client/download.c b/src/client/download.c index 4bf0f1e72..7491487cc 100644 --- a/src/client/download.c +++ b/src/client/download.c @@ -91,13 +91,18 @@ int CL_QueueDownload(const char *path, dltype_t type) CL_IgnoreDownload Returns true if specified path matches against an entry in download ignore -list. +list. Path should be converted to lower case by the caller. =============== */ bool CL_IgnoreDownload(const char *path) { string_entry_t *entry; + if (!strncmp(path, CONST_STR_LEN("music/"))) + return true; + if (!strncmp(path, CONST_STR_LEN("video/"))) + return true; + for (entry = cls.download.ignores; entry; entry = entry->next) { if (Com_WildCmp(entry->string, path)) { return true; From f0a36d0879eb8f99f45c7bce131503668c4e64ba Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 5 Nov 2023 10:38:51 +0300 Subject: [PATCH 010/167] Move casts in overflow checks. --- src/refresh/models.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/refresh/models.c b/src/refresh/models.c index 7d8d2ba03..2a37a3faf 100644 --- a/src/refresh/models.c +++ b/src/refresh/models.c @@ -233,10 +233,10 @@ static const char *MOD_ValidateMD2(const dmd2header_t *header, size_t length) ENSURE(header->framesize >= sizeof(dmd2frame_t) + (header->num_xyz - 1) * sizeof(dmd2trivertx_t), "too small frame size"); ENSURE(header->framesize <= MD2_MAX_FRAMESIZE, "too big frame size"); - ENSURE(header->ofs_tris + (uint64_t)header->num_tris * sizeof(dmd2triangle_t) <= length, "bad tris offset"); - ENSURE(header->ofs_st + (uint64_t)header->num_st * sizeof(dmd2stvert_t) <= length, "bad st offset"); - ENSURE(header->ofs_frames + (uint64_t)header->num_frames * header->framesize <= length, "bad frames offset"); - ENSURE(header->ofs_skins + (uint64_t)MD2_MAX_SKINNAME * header->num_skins <= length, "bad skins offset"); + ENSURE((uint64_t)header->ofs_tris + header->num_tris * sizeof(dmd2triangle_t) <= length, "bad tris offset"); + ENSURE((uint64_t)header->ofs_st + header->num_st * sizeof(dmd2stvert_t) <= length, "bad st offset"); + ENSURE((uint64_t)header->ofs_frames + header->num_frames * header->framesize <= length, "bad frames offset"); + ENSURE((uint64_t)header->ofs_skins + MD2_MAX_SKINNAME * header->num_skins <= length, "bad skins offset"); ENSURE(!(header->ofs_tris % q_alignof(dmd2triangle_t)), "odd tris offset"); ENSURE(!(header->ofs_st % q_alignof(dmd2stvert_t)), "odd st offset"); @@ -487,10 +487,10 @@ static const char *MOD_ValidateMD3Mesh(const model_t *model, const dmd3mesh_t *h ENSURE(header->num_tris <= TESS_MAX_INDICES / 3, "too many tris"); ENSURE(header->num_skins <= MD3_MAX_SKINS, "too many skins"); - ENSURE(header->ofs_skins + (uint64_t)header->num_skins * sizeof(dmd3skin_t) <= length, "bad skins offset"); - ENSURE(header->ofs_verts + (uint64_t)header->num_verts * model->numframes * sizeof(dmd3vertex_t) <= length, "bad verts offset"); - ENSURE(header->ofs_tcs + (uint64_t)header->num_verts * sizeof(dmd3coord_t) <= length, "bad tcs offset"); - ENSURE(header->ofs_indexes + (uint64_t)header->num_tris * 3 * sizeof(uint32_t) <= length, "bad indexes offset"); + ENSURE((uint64_t)header->ofs_skins + header->num_skins * sizeof(dmd3skin_t) <= length, "bad skins offset"); + ENSURE((uint64_t)header->ofs_verts + header->num_verts * model->numframes * sizeof(dmd3vertex_t) <= length, "bad verts offset"); + ENSURE((uint64_t)header->ofs_tcs + header->num_verts * sizeof(dmd3coord_t) <= length, "bad tcs offset"); + ENSURE((uint64_t)header->ofs_indexes + header->num_tris * 3 * sizeof(uint32_t) <= length, "bad indexes offset"); ENSURE(!(header->ofs_skins % q_alignof(dmd3skin_t)), "odd skins offset"); ENSURE(!(header->ofs_verts % q_alignof(dmd3vertex_t)), "odd verts offset"); @@ -609,7 +609,7 @@ static const char *MOD_ValidateMD3(const dmd3header_t *header, size_t length) { ENSURE(header->num_frames >= 1, "too few frames"); ENSURE(header->num_frames <= MD3_MAX_FRAMES, "too many frames"); - ENSURE(header->ofs_frames + (uint64_t)header->num_frames * sizeof(dmd3frame_t) <= length, "bad frames offset"); + ENSURE((uint64_t)header->ofs_frames + header->num_frames * sizeof(dmd3frame_t) <= length, "bad frames offset"); ENSURE(!(header->ofs_frames % q_alignof(dmd3frame_t)), "odd frames offset"); ENSURE(header->num_meshes >= 1, "too few meshes"); ENSURE(header->num_meshes <= MD3_MAX_MESHES, "too many meshes"); From 3487f3f6c13c80997a2b182164a2df83bd4f6f5a Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 5 Nov 2023 10:39:42 +0300 Subject: [PATCH 011/167] Fix crash if MD5 skin path is too long. --- src/refresh/models.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/refresh/models.c b/src/refresh/models.c index 2a37a3faf..5c9c19eb9 100644 --- a/src/refresh/models.c +++ b/src/refresh/models.c @@ -1317,8 +1317,12 @@ static void MOD_LoadMD5(model_t *model) // build md5 path if (Q_strlcat(skin_path, "md5/", sizeof(skin_path)) < sizeof(skin_path) && - Q_strlcat(skin_path, skin_name, sizeof(skin_path)) < sizeof(skin_path)) + Q_strlcat(skin_path, skin_name, sizeof(skin_path)) < sizeof(skin_path)) { model->skeleton->skins[i] = IMG_Find(skin_path, IT_SKIN, IF_NONE); + } else { + Com_WPrintf("MD5 skin path too long: %s\n", skin_path); + model->skeleton->skins[i] = R_NOTEXTURE; + } } Hunk_End(&model->skeleton_hunk); From f003fb037ca4d377f929e5c0d6612910c9d9044d Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 5 Nov 2023 22:54:36 +0300 Subject: [PATCH 012/167] Try different extensions for cinematics. --- inc/client/client.h | 3 ++ src/client/cin.c | 28 ++++++++++++++ src/client/client.h | 12 ++++++ src/client/ffcin.c | 85 +++++++++++++++++++++++++++++++++++------- src/client/main.c | 2 + src/client/sound/ogg.c | 6 --- src/server/init.c | 27 +------------- 7 files changed, 118 insertions(+), 45 deletions(-) diff --git a/inc/client/client.h b/inc/client/client.h index ce2eb246b..a11d3ec5e 100644 --- a/inc/client/client.h +++ b/inc/client/client.h @@ -95,6 +95,8 @@ void Con_Close(bool force); void SCR_BeginLoadingPlaque(void); void SCR_EndLoadingPlaque(void); +int SCR_CheckForCinematic(const char *name); + void SCR_ModeChanged(void); void SCR_UpdateScreen(void); @@ -145,5 +147,6 @@ float V_CalcFov(float fov_x, float width, float height); #define SCR_BeginLoadingPlaque() (void)0 #define SCR_EndLoadingPlaque() (void)0 +#define SCR_CheckForCinematic(name) Q_ERR_SUCCESS #endif // !USE_CLIENT diff --git a/src/client/cin.c b/src/client/cin.c index 2e62f0281..dd152263a 100644 --- a/src/client/cin.c +++ b/src/client/cin.c @@ -56,6 +56,16 @@ typedef struct { static cinematic_t cin; +/* +================== +SCR_InitCinematics +================== +*/ +void SCR_InitCinematics(void) +{ + // nothing to do here +} + /* ================== SCR_StopCinematic @@ -445,3 +455,21 @@ void SCR_PlayCinematic(const char *name) finish: SCR_FinishCinematic(); } + +/* +================== +SCR_CheckForCinematic + +Called by the server to check for cinematic existence. +Name should be in format "video/.cin". +================== +*/ +int SCR_CheckForCinematic(const char *name) +{ + int ret = FS_LoadFile(name, NULL); + + if (ret == Q_ERR(EFBIG)) + ret = Q_ERR_SUCCESS; + + return ret; +} diff --git a/src/client/client.h b/src/client/client.h index cff971b11..3025243bf 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -973,6 +973,18 @@ int SCR_GetCinematicCrop(unsigned framenum, int64_t filesize); // // cin.c // + +#if USE_AVCODEC + +typedef struct { + const char *ext; + const char *fmt; + int codec_id; +} avformat_t; + +#endif + +void SCR_InitCinematics(void); void SCR_StopCinematic(void); void SCR_FinishCinematic(void); void SCR_RunCinematic(void); diff --git a/src/client/ffcin.c b/src/client/ffcin.c index e85370e41..b08fc4e60 100644 --- a/src/client/ffcin.c +++ b/src/client/ffcin.c @@ -66,6 +66,35 @@ typedef struct { static cinematic_t cin; +static const avformat_t formats[] = { + { ".ogv", "ogg", AV_CODEC_ID_THEORA }, + { ".mkv", "matroska", AV_CODEC_ID_NONE }, + { ".mp4", "mp4", AV_CODEC_ID_H264 }, + { ".cin", "idcin", AV_CODEC_ID_IDCIN }, +}; + +static int supported; + +/* +================== +SCR_InitCinematics +================== +*/ +void SCR_InitCinematics(void) +{ + for (int i = 0; i < q_countof(formats); i++) { + const avformat_t *f = &formats[i]; + if (!av_find_input_format(f->fmt)) + continue; + if (f->codec_id != AV_CODEC_ID_NONE && + !avcodec_find_decoder(f->codec_id)) + continue; + supported |= BIT(i); + } + + Com_DPrintf("Supported cinematic formats: %#x\n", supported); +} + static void packet_queue_destroy(PacketQueue *q); /* @@ -546,6 +575,7 @@ static bool SCR_StartCinematic(const char *name) int ret; FS_NormalizePathBuffer(normalized, name, sizeof(normalized)); + *COM_FileExtension(normalized) = 0; // open from filesystem only. since packfiles are downloadable, videos from // packfiles can pose security risk due to huge lavf/lavc attack surface. @@ -556,26 +586,25 @@ static bool SCR_StartCinematic(const char *name) break; } - if (Q_snprintf(fullname, sizeof(fullname), "%s/video/%s", path, normalized) >= sizeof(fullname)) { - ret = AVERROR(ENAMETOOLONG); - break; - } + for (int i = 0; i < q_countof(formats); i++) { + if (!(supported & BIT(i))) + continue; - ret = avformat_open_input(&cin.fmt_ctx, fullname, NULL, NULL); + if (Q_snprintf(fullname, sizeof(fullname), "%s/video/%s%s", + path, normalized, formats[i].ext) >= sizeof(fullname)) { + ret = AVERROR(ENAMETOOLONG); + goto done; + } - // if .cin doesn't exist, check for .ogv - if (ret == AVERROR(ENOENT)) { - *COM_FileExtension(fullname) = 0; - Q_strlcat(fullname, ".ogv", sizeof(fullname)); ret = avformat_open_input(&cin.fmt_ctx, fullname, NULL, NULL); + if (ret != AVERROR(ENOENT)) + goto done; } - - if (ret != AVERROR(ENOENT)) - break; } +done: if (ret < 0) { - Com_EPrintf("Couldn't open video/%s: %s\n", normalized, av_err2str(ret)); + Com_EPrintf("Couldn't open %s: %s\n", ret == AVERROR(ENOENT) ? name : fullname, av_err2str(ret)); return false; } @@ -661,3 +690,33 @@ void SCR_PlayCinematic(const char *name) finish: SCR_FinishCinematic(); } + +/* +================== +SCR_CheckForCinematic + +Called by the server to check for cinematic existence. +Name should be in format "video/.cin". +================== +*/ +int SCR_CheckForCinematic(const char *name) +{ + int len = strlen(name); + int ret = Q_ERR(ENOENT); + + Q_assert(len >= 4); + + for (int i = 0; i < q_countof(formats); i++) { + if (!(supported & BIT(i))) + continue; + ret = FS_LoadFileEx(va("%.*s%s", len - 4, name, formats[i].ext), + NULL, FS_TYPE_REAL, TAG_FREE); + if (ret != Q_ERR(ENOENT)) + break; + } + + if (ret == Q_ERR(EFBIG)) + ret = Q_ERR_SUCCESS; + + return ret; +} diff --git a/src/client/main.c b/src/client/main.c index fdd5dae48..526163b0c 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -3386,7 +3386,9 @@ void CL_Init(void) Q_assert(inflateInit2(&cls.z, -MAX_WBITS) == Z_OK); #endif + SCR_InitCinematics(); OGG_Init(); + CL_LoadDownloadIgnores(); CL_LoadStuffTextWhiteList(); diff --git a/src/client/sound/ogg.c b/src/client/sound/ogg.c index ac151c2ff..1e6e98565 100644 --- a/src/client/sound/ogg.c +++ b/src/client/sound/ogg.c @@ -45,12 +45,6 @@ static int trackindex; static char extensions[MAX_QPATH]; static int supported; -typedef struct { - const char *ext; - const char *fmt; - int codec_id; -} avformat_t; - static const avformat_t formats[] = { { ".flac", "flac", AV_CODEC_ID_FLAC }, { ".opus", "ogg", AV_CODEC_ID_OPUS }, diff --git a/src/server/init.c b/src/server/init.c index 9039f4fc2..87eda760c 100644 --- a/src/server/init.c +++ b/src/server/init.c @@ -223,31 +223,6 @@ void SV_SpawnServer(const mapcmd_t *cmd) Com_Printf("-------------------------------------\n"); } -static int check_cinematic(const char *expanded) -{ - int ret; - -#if USE_AVCODEC - // open from filesystem only - ret = FS_LoadFileEx(expanded, NULL, FS_TYPE_REAL, TAG_FREE); - - // if .cin doesn't exist, check for .ogv - if (ret == Q_ERR(ENOENT)) { - char tmp[MAX_QPATH]; - COM_StripExtension(tmp, expanded, sizeof(tmp)); - Q_strlcat(tmp, ".ogv", sizeof(tmp)); - ret = FS_LoadFileEx(tmp, NULL, FS_TYPE_REAL, TAG_FREE); - } -#else - ret = FS_LoadFile(expanded, NULL); -#endif - - if (ret == Q_ERR(EFBIG)) - ret = Q_ERR_SUCCESS; - - return ret; -} - static bool check_server(mapcmd_t *cmd, const char *server, bool nextserver) { char expanded[MAX_QPATH]; @@ -277,7 +252,7 @@ static bool check_server(mapcmd_t *cmd, const char *server, bool nextserver) if (!sv_cinematics->integer && nextserver) return false; // skip it if (Q_concat(expanded, sizeof(expanded), "video/", s) < sizeof(expanded)) { - ret = COM_DEDICATED ? Q_ERR_SUCCESS : check_cinematic(expanded); + ret = SCR_CheckForCinematic(expanded); } cmd->state = ss_cinematic; } else { From c8c04432d30fa7f60bca5621d027539e96e562c9 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 6 Nov 2023 01:03:07 +0300 Subject: [PATCH 013/167] Initialize configstring mapping before serverdata. Some broken servers/demos may try to send configstring updates before serverdata. This would result in error because configstring mapping is not initialized yet. Fixes #330. --- src/client/demo.c | 1 + src/client/main.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/client/demo.c b/src/client/demo.c index 858737f4c..db29229cb 100644 --- a/src/client/demo.c +++ b/src/client/demo.c @@ -755,6 +755,7 @@ static void CL_PlayDemo_f(void) cls.state = ca_connected; Q_strlcpy(cls.servername, COM_SkipPath(name), sizeof(cls.servername)); cls.serverAddress.type = NA_LOOPBACK; + cl.csr = cs_remap_old; Con_Popup(true); SCR_UpdateScreen(); diff --git a/src/client/main.c b/src/client/main.c index 526163b0c..ad1f45e3f 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -1406,6 +1406,7 @@ static void CL_ConnectionlessPacket(void) cls.state = ca_connected; cls.connect_count = 0; Q_strlcpy(cl.mapname, mapname, sizeof(cl.mapname)); // for levelshot screen + cl.csr = cs_remap_old; return; } From c32121e40827d955f76e166a54cbc7a0b084ff3e Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 9 Nov 2023 17:27:18 +0300 Subject: [PATCH 014/167] Account for terminating NUL for EntString lump. --- src/common/bsp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/common/bsp.c b/src/common/bsp.c index 26fe782a4..ca7954554 100644 --- a/src/common/bsp.c +++ b/src/common/bsp.c @@ -1407,6 +1407,10 @@ int BSP_Load(const char *name, bsp_t **bsp_p) lump_ofs[i] = ofs; lump_count[i] = count; + // account for terminating NUL for EntString lump + if (!info->lump) + count++; + // round to cacheline memsize += ALIGN(count * info->memsize, 64); maxpos = max(maxpos, end); From 03b7bda77a8ea334a61e0aeb906db9af6cf63d33 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 9 Nov 2023 21:14:46 +0300 Subject: [PATCH 015/167] Store edge/surfedge indices rather than pointers. --- inc/common/bsp.h | 6 +++--- src/common/bsp.c | 4 ++-- src/refresh/sky.c | 8 ++++++-- src/refresh/surf.c | 4 ++-- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/inc/common/bsp.h b/inc/common/bsp.h index 4fa5276d6..19bd16dea 100644 --- a/inc/common/bsp.h +++ b/inc/common/bsp.h @@ -64,12 +64,12 @@ typedef struct { } mvertex_t; typedef struct { - mvertex_t *v[2]; + uint32_t v[2]; } medge_t; typedef struct { - medge_t *edge; - int vert; + uint32_t edge: 31; + uint32_t vert: 1; } msurfedge_t; #define SURF_TRANS_MASK (SURF_TRANS33 | SURF_TRANS66) diff --git a/src/common/bsp.c b/src/common/bsp.c index ca7954554..8bc029ea5 100644 --- a/src/common/bsp.c +++ b/src/common/bsp.c @@ -326,7 +326,7 @@ LOAD(Edges) DEBUG("bad vertnum"); return Q_ERR_INVALID_FORMAT; } - out->v[j] = bsp->vertices + vertnum; + out->v[j] = vertnum; } } @@ -357,7 +357,7 @@ LOAD(SurfEdges) return Q_ERR_INVALID_FORMAT; } - out->edge = bsp->edges + index; + out->edge = index; out->vert = vert; } diff --git a/src/refresh/sky.c b/src/refresh/sky.c index 670e1c1e8..1dfcded90 100644 --- a/src/refresh/sky.c +++ b/src/refresh/sky.c @@ -239,6 +239,8 @@ void R_AddSkySurface(mface_t *fa) vec3_t temp; msurfedge_t *surfedge; mvertex_t *vert; + medge_t *edge; + bsp_t *bsp = gl_static.world.cache; if (fa->numsurfedges > MAX_CLIP_VERTS) { Com_DPrintf("%s: too many verts\n", __func__); @@ -252,13 +254,15 @@ void R_AddSkySurface(mface_t *fa) SetupRotationMatrix(skymatrix, skyaxis, glr.fd.time * skyrotate); for (i = 0; i < fa->numsurfedges; i++, surfedge++) { - vert = surfedge->edge->v[surfedge->vert]; + edge = bsp->edges + surfedge->edge; + vert = bsp->vertices + edge->v[surfedge->vert]; VectorSubtract(vert->point, glr.fd.vieworg, temp); SkyInverseRotate(verts[i], temp); } } else { for (i = 0; i < fa->numsurfedges; i++, surfedge++) { - vert = surfedge->edge->v[surfedge->vert]; + edge = bsp->edges + surfedge->edge; + vert = bsp->vertices + edge->v[surfedge->vert]; VectorSubtract(vert->point, glr.fd.vieworg, verts[i]); } } diff --git a/src/refresh/surf.c b/src/refresh/surf.c index f993f10f2..f067b2878 100644 --- a/src/refresh/surf.c +++ b/src/refresh/surf.c @@ -584,8 +584,8 @@ static void build_surface_poly(mface_t *surf, vec_t *vbo) src_surfedge = surf->firstsurfedge; for (i = 0; i < surf->numsurfedges; i++) { - src_edge = src_surfedge->edge; - src_vert = src_edge->v[src_surfedge->vert]; + src_edge = bsp->edges + src_surfedge->edge; + src_vert = bsp->vertices + src_edge->v[src_surfedge->vert]; src_surfedge++; // vertex coordinates From 2cb4cc00f2fe7c69cccd61381a56cf491beacd27 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 12 Nov 2023 13:47:50 +0300 Subject: [PATCH 016/167] Fix dynamic lights on alpha faces. --- src/refresh/world.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/refresh/world.c b/src/refresh/world.c index 633ac7635..32cec395a 100644 --- a/src/refresh/world.c +++ b/src/refresh/world.c @@ -495,16 +495,16 @@ void GL_DrawBspModel(mmodel_t *model) continue; } + if (gl_dynamic->integer) { + GL_PushLights(face); + } + if (face->drawflags & SURF_TRANS_MASK) { if (model->drawframe != glr.drawframe) GL_AddAlphaFace(face, ent); continue; } - if (gl_dynamic->integer) { - GL_PushLights(face); - } - GL_DrawFace(face); } @@ -582,15 +582,15 @@ static inline void GL_DrawNode(mnode_t *node) continue; } + if (gl_dynamic->integer) { + GL_PushLights(face); + } + if (face->drawflags & SURF_TRANS_MASK) { GL_AddAlphaFace(face, &gl_world); continue; } - if (gl_dynamic->integer) { - GL_PushLights(face); - } - if (gl_hash_faces->integer) { GL_AddSolidFace(face); } else { From ecce3b8694c841facfe89a548eca98088e234833 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 12 Nov 2023 14:10:47 +0300 Subject: [PATCH 017/167] =?UTF-8?q?Add=20=E2=80=98autosave=E2=80=99=20comm?= =?UTF-8?q?and.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just save to fixed ‘save1’ slot for now. Needed to differentiate regular saves from autosaves in the menu. --- src/server/save.c | 57 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/src/server/save.c b/src/server/save.c index 210ff008a..2f1b9bfae 100644 --- a/src/server/save.c +++ b/src/server/save.c @@ -25,9 +25,21 @@ with this program; if not, write to the Free Software Foundation, Inc., #define SAVE_CURRENT ".current" #define SAVE_AUTO "save0" +typedef enum { + SAVE_MANUAL, // manual save + SAVE_LEVEL_START, // autosave at level start + SAVE_AUTOSAVE // remaster "autosave" +} savetype_t; + +typedef enum { + LOAD_NONE, // not a savegame load + LOAD_NORMAL, // regular savegame, or remaster "autosave" + LOAD_LEVEL_START, // autosave at level start +} loadtype_t; + static cvar_t *sv_noreload; -static int write_server_file(bool autosave) +static int write_server_file(savetype_t autosave) { char name[MAX_OSPATH]; cvar_t *var; @@ -70,7 +82,7 @@ static int write_server_file(bool autosave) if (Q_snprintf(name, MAX_OSPATH, "%s/save/" SAVE_CURRENT "/game.ssv", fs_gamedir) >= MAX_OSPATH) return -1; - ge->WriteGame(name, autosave); + ge->WriteGame(name, autosave == SAVE_LEVEL_START); return 0; } @@ -274,9 +286,12 @@ char *SV_GetSaveInfo(const char *dir) autosave = MSG_ReadByte(); MSG_ReadString(name, sizeof(name)); - if (autosave) + if (autosave == SAVE_LEVEL_START) return Z_CopyString(va("ENTERING %s", name)); + if (autosave == SAVE_AUTOSAVE) + return Z_CopyString(va("AUTOSAVE %s", name)); + // get current year t = time(NULL); tm = localtime(&t); @@ -322,10 +337,10 @@ static int read_server_file(void) // read the comment field MSG_ReadLong64(); - if (MSG_ReadByte()) - cmd.loadgame = 2; // autosave + if (MSG_ReadByte() == SAVE_LEVEL_START) + cmd.loadgame = LOAD_LEVEL_START; else - cmd.loadgame = 1; // regular savegame + cmd.loadgame = LOAD_NORMAL; MSG_ReadString(NULL, 0); // read the mapcmd @@ -505,7 +520,7 @@ void SV_AutoSaveEnd(void) return; // save server state - if (write_server_file(true)) { + if (write_server_file(SAVE_LEVEL_START)) { Com_EPrintf("Couldn't write server file.\n"); return; } @@ -533,7 +548,7 @@ void SV_CheckForSavegame(const mapcmd_t *cmd) if (read_level_file()) { // only warn when loading a regular savegame. autosave without level // file is ok and simply starts the map from the beginning. - if (cmd->loadgame == 1) + if (cmd->loadgame == LOAD_NORMAL) Com_EPrintf("Couldn't read level file.\n"); return; } @@ -622,6 +637,7 @@ static void SV_Loadgame_f(void) static void SV_Savegame_f(void) { char *dir; + savetype_t type; if (sv.state != ss_game) { Com_Printf("You must be in a game to save.\n"); @@ -649,15 +665,21 @@ static void SV_Savegame_f(void) } } - if (Cmd_Argc() != 2) { - Com_Printf("Usage: %s \n", Cmd_Argv(0)); - return; - } + if (!strcmp(Cmd_Argv(0), "autosave")) { + dir = "save1"; + type = SAVE_AUTOSAVE; + } else { + if (Cmd_Argc() != 2) { + Com_Printf("Usage: %s \n", Cmd_Argv(0)); + return; + } - dir = Cmd_Argv(1); - if (!COM_IsPath(dir)) { - Com_Printf("Bad savedir.\n"); - return; + dir = Cmd_Argv(1); + if (!COM_IsPath(dir)) { + Com_Printf("Bad savedir.\n"); + return; + } + type = SAVE_MANUAL; } // archive current level, including all client edicts. @@ -669,7 +691,7 @@ static void SV_Savegame_f(void) } // save server state - if (write_server_file(false)) { + if (write_server_file(type)) { Com_Printf("Couldn't write server file.\n"); return; } @@ -690,6 +712,7 @@ static void SV_Savegame_f(void) } static const cmdreg_t c_savegames[] = { + { "autosave", SV_Savegame_f }, { "save", SV_Savegame_f, SV_Savegame_c }, { "load", SV_Loadgame_f, SV_Savegame_c }, { NULL } From a707d074ccde4e242ca60a61a82f30a98ed9126d Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 13 Nov 2023 21:53:19 +0300 Subject: [PATCH 018/167] Bind white texture for flare occlusion test. Fixes GL_INVALID_ENUM error with GL ES 3.x. --- src/refresh/main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/refresh/main.c b/src/refresh/main.c index 6cb87207c..c413c81e1 100644 --- a/src/refresh/main.c +++ b/src/refresh/main.c @@ -434,8 +434,7 @@ static void GL_OccludeFlares(void) GL_StateBits(GLS_DEPTHMASK_FALSE); GL_ArrayBits(GLA_VERTEX); qglColorMask(0, 0, 0, 0); - GL_ActiveTexture(0); - qglDisable(GL_TEXTURE_2D); + GL_BindTexture(0, TEXNUM_WHITE); GL_VertexPointer(3, 0, &points[0][0]); for (i = 0, e = glr.fd.entities; i < glr.fd.num_entities; i++, e++) { @@ -462,7 +461,6 @@ static void GL_OccludeFlares(void) q->pending = true; } - qglEnable(GL_TEXTURE_2D); qglColorMask(1, 1, 1, 1); } From 40e0023578388964f02b6bd272e1b9c20c2b8f4a Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 14 Nov 2023 11:21:26 +0300 Subject: [PATCH 019/167] Reduce number of BSP_RecursiveLightPoint() arguments. --- src/common/bsp.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/common/bsp.c b/src/common/bsp.c index 8bc029ea5..336b312ce 100644 --- a/src/common/bsp.c +++ b/src/common/bsp.c @@ -1499,8 +1499,9 @@ HELPER FUNCTIONS #if USE_REF static lightpoint_t *light_point; +static int light_mask; -static bool BSP_RecursiveLightPoint(mnode_t *node, float p1f, float p2f, const vec3_t p1, const vec3_t p2, int nolm_mask) +static bool BSP_RecursiveLightPoint(mnode_t *node, float p1f, float p2f, const vec3_t p1, const vec3_t p2) { vec_t d1, d2, frac, midf, s, t; vec3_t mid; @@ -1525,13 +1526,13 @@ static bool BSP_RecursiveLightPoint(mnode_t *node, float p1f, float p2f, const v LerpVector(p1, p2, frac, mid); // check near side - if (BSP_RecursiveLightPoint(node->children[side], p1f, midf, p1, mid, nolm_mask)) + if (BSP_RecursiveLightPoint(node->children[side], p1f, midf, p1, mid)) return true; for (i = 0, surf = node->firstface; i < node->numfaces; i++, surf++) { if (!surf->lightmap) continue; - if (surf->drawflags & nolm_mask) + if (surf->drawflags & light_mask) continue; s = DotProduct(surf->lm_axis[0], mid) + surf->lm_offset[0]; @@ -1550,7 +1551,7 @@ static bool BSP_RecursiveLightPoint(mnode_t *node, float p1f, float p2f, const v } // check far side - return BSP_RecursiveLightPoint(node->children[side ^ 1], midf, p2f, mid, p2, nolm_mask); + return BSP_RecursiveLightPoint(node->children[side ^ 1], midf, p2f, mid, p2); } return false; @@ -1561,8 +1562,9 @@ void BSP_LightPoint(lightpoint_t *point, const vec3_t start, const vec3_t end, m light_point = point; light_point->surf = NULL; light_point->fraction = 1; + light_mask = nolm_mask; - BSP_RecursiveLightPoint(headnode, 0, 1, start, end, nolm_mask); + BSP_RecursiveLightPoint(headnode, 0, 1, start, end); } void BSP_TransformedLightPoint(lightpoint_t *point, const vec3_t start, const vec3_t end, @@ -1574,6 +1576,7 @@ void BSP_TransformedLightPoint(lightpoint_t *point, const vec3_t start, const ve light_point = point; light_point->surf = NULL; light_point->fraction = 1; + light_mask = nolm_mask; // subtract origin offset VectorSubtract(start, origin, start_l); @@ -1587,7 +1590,7 @@ void BSP_TransformedLightPoint(lightpoint_t *point, const vec3_t start, const ve } // sweep the line through the model - if (!BSP_RecursiveLightPoint(headnode, 0, 1, start_l, end_l, nolm_mask)) + if (!BSP_RecursiveLightPoint(headnode, 0, 1, start_l, end_l)) return; // rotate plane normal into the worlds frame of reference From a417338241cc6294e5c7d478ceae9d1c7741e090 Mon Sep 17 00:00:00 2001 From: Frank Richter Date: Mon, 6 Nov 2023 00:11:38 +0100 Subject: [PATCH 020/167] Add struct for common frametime Shared struct fields and computations common to client and server. --- inc/common/utils.h | 16 ++++++++++++++++ src/client/client.h | 9 ++++----- src/client/entities.c | 8 ++++---- src/client/parse.c | 20 +++++++------------- src/server/init.c | 14 ++++---------- src/server/main.c | 8 +++++--- src/server/mvd/client.c | 3 +-- src/server/send.c | 6 +++--- src/server/server.h | 9 ++++----- src/server/user.c | 6 +++--- 10 files changed, 51 insertions(+), 48 deletions(-) diff --git a/inc/common/utils.h b/inc/common/utils.h index 7966ce477..b750738f2 100644 --- a/inc/common/utils.h +++ b/inc/common/utils.h @@ -81,3 +81,19 @@ static inline size_t CS_SIZE(const cs_remap_t *csr, int cs) return MAX_QPATH; } + +#if USE_FPS +typedef struct frametime_s { + int time; // variable server frame time + int div; // BASE_FRAMETIME/frametime +} frametime_t; + +// Compute frametime based on requested frame rate +static inline frametime_t Com_ComputeFrametime(int rate) +{ + int framediv = rate / BASE_FRAMERATE; + clamp(framediv, 1, MAX_FRAMEDIV); + return (frametime_t){ .time = BASE_FRAMETIME / framediv, .div = framediv }; +} + +#endif // USE_FPS diff --git a/src/client/client.h b/src/client/client.h index 3025243bf..9ebc3ae65 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -138,10 +138,10 @@ typedef struct { // variable server FPS #if USE_FPS -#define CL_FRAMETIME cl.frametime +#define CL_FRAMETIME cl.frametime.time #define CL_1_FRAMETIME cl.frametime_inv -#define CL_FRAMEDIV cl.framediv -#define CL_FRAMESYNC !(cl.frame.number % cl.framediv) +#define CL_FRAMEDIV cl.frametime.div +#define CL_FRAMESYNC !(cl.frame.number % cl.frametime.div) #define CL_KEYPS &cl.keyframe.ps #define CL_OLDKEYPS &cl.oldkeyframe.ps #define CL_KEYLERPFRAC cl.keylerpfrac @@ -265,9 +265,8 @@ typedef struct client_state_s { pmoveParams_t pmp; #if USE_FPS - int frametime; // variable server frame time + frametime_t frametime; float frametime_inv; // 1/frametime - int framediv; // BASE_FRAMETIME/frametime #endif configstring_t baseconfigstrings[MAX_CONFIGSTRINGS]; diff --git a/src/client/entities.c b/src/client/entities.c index e0fe64c1a..c1527ce6a 100644 --- a/src/client/entities.c +++ b/src/client/entities.c @@ -76,7 +76,7 @@ entity_update_old(centity_t *ent, const centity_state_t *state, const vec_t *ori // check for new event if (state->event != ent->current.event) ent->event_frame = cl.frame.number; // new - else if (cl.frame.number - ent->event_frame >= cl.framediv) + else if (cl.frame.number - ent->event_frame >= cl.frametime.div) ent->event_frame = cl.frame.number; // refreshed else event = 0; // duplicated @@ -110,7 +110,7 @@ entity_update_old(centity_t *ent, const centity_state_t *state, const vec_t *ori // start alias model animation if (state->frame != ent->current.frame) { ent->prev_frame = ent->current.frame; - ent->anim_start = cl.servertime - cl.frametime; + ent->anim_start = cl.servertime - cl.frametime.time; } #endif @@ -379,7 +379,7 @@ void CL_DeltaFrame(void) framenum = cl.frame.number - cl.serverdelta; cl.servertime = framenum * CL_FRAMETIME; #if USE_FPS - cl.keyservertime = (framenum / cl.framediv) * BASE_FRAMETIME; + cl.keyservertime = (framenum / cl.frametime.div) * BASE_FRAMETIME; #endif // rebuild the list of solid entities for this frame @@ -426,7 +426,7 @@ void CL_DeltaFrame(void) #if USE_FPS if (CL_FRAMESYNC) - check_player_lerp(&cl.oldkeyframe, &cl.keyframe, cl.framediv); + check_player_lerp(&cl.oldkeyframe, &cl.keyframe, cl.frametime.div); #endif CL_CheckPredictionError(); diff --git a/src/client/parse.c b/src/client/parse.c index d0013e4f4..2eb24e904 100644 --- a/src/client/parse.c +++ b/src/client/parse.c @@ -566,9 +566,8 @@ static void CL_ParseServerData(void) #if USE_FPS // setup default frame times - cl.frametime = BASE_FRAMETIME; - cl.frametime_inv = BASE_1_FRAMETIME; - cl.framediv = 1; + cl.frametime = Com_ComputeFrametime(BASE_FRAMERATE); + cl.frametime_inv = cl.frametime.div * BASE_1_FRAMETIME; #endif // setup default server state @@ -1176,22 +1175,17 @@ static void CL_ParseZPacket(void) #if USE_FPS static void set_server_fps(int value) { - int framediv = value / BASE_FRAMERATE; - - clamp(framediv, 1, MAX_FRAMEDIV); - - cl.frametime = BASE_FRAMETIME / framediv; - cl.frametime_inv = framediv * BASE_1_FRAMETIME; - cl.framediv = framediv; + cl.frametime = Com_ComputeFrametime(value); + cl.frametime_inv = cl.frametime.div * BASE_1_FRAMETIME; // fix time delta if (cls.state == ca_active) { - int delta = cl.frame.number - cl.servertime / cl.frametime; - cl.serverdelta = Q_align(delta, framediv); + int delta = cl.frame.number - cl.servertime / cl.frametime.time; + cl.serverdelta = Q_align(delta, cl.frametime.div); } Com_DPrintf("client framediv=%d time=%d delta=%d\n", - framediv, cl.servertime, cl.serverdelta); + cl.frametime.div, cl.servertime, cl.serverdelta); } #endif diff --git a/src/server/init.c b/src/server/init.c index 87eda760c..9fcb757d6 100644 --- a/src/server/init.c +++ b/src/server/init.c @@ -40,18 +40,12 @@ void SV_ClientReset(client_t *client) static void set_frame_time(void) { #if USE_FPS - int framediv; - if (g_features->integer & GMF_VARIABLE_FPS) - framediv = sv_fps->integer / BASE_FRAMERATE; + sv.frametime = Com_ComputeFrametime(sv_fps->integer); else - framediv = 1; - - clamp(framediv, 1, MAX_FRAMEDIV); + sv.frametime = Com_ComputeFrametime(BASE_FRAMERATE); - sv.framerate = framediv * BASE_FRAMERATE; - sv.frametime = BASE_FRAMETIME / framediv; - sv.framediv = framediv; + sv.framerate = sv.frametime.div * BASE_FRAMERATE; Cvar_SetInteger(sv_fps, sv.framerate, FROM_CODE); #endif @@ -361,7 +355,7 @@ void SV_InitGame(unsigned mvd_spawn) #if USE_FPS // set up default frametime for main loop - sv.frametime = BASE_FRAMETIME; + sv.frametime = Com_ComputeFrametime(BASE_FRAMERATE); #endif } diff --git a/src/server/main.c b/src/server/main.c index fe8d54e5d..d9e8e00d5 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -1109,7 +1109,7 @@ static void SVC_DirectConnect(void) Q_strlcpy(newcl->reconnect_var, params.reconnect_var, sizeof(newcl->reconnect_var)); Q_strlcpy(newcl->reconnect_val, params.reconnect_val, sizeof(newcl->reconnect_val)); #if USE_FPS - newcl->framediv = sv.framediv; + newcl->framediv = sv.frametime.div; newcl->settings[CLS_FPS] = BASE_FRAMERATE; #endif @@ -2267,7 +2267,8 @@ void SV_Init(void) #if USE_FPS // set up default frametime for main loop - sv.frametime = BASE_FRAMETIME; + sv.framerate = BASE_FRAMERATE; + sv.frametime = Com_ComputeFrametime(sv.framerate); #endif // set up default pmove parameters @@ -2388,7 +2389,8 @@ void SV_Shutdown(const char *finalmsg, error_type_t type) #if USE_FPS // set up default frametime for main loop - sv.frametime = BASE_FRAMETIME; + sv.framerate = BASE_FRAMERATE; + sv.frametime = Com_ComputeFrametime(sv.framerate); #endif sv_client = NULL; diff --git a/src/server/mvd/client.c b/src/server/mvd/client.c index fb70bde36..b92dfc9c8 100644 --- a/src/server/mvd/client.c +++ b/src/server/mvd/client.c @@ -1697,8 +1697,7 @@ void MVD_Spawn(void) #if USE_FPS // just fixed base FPS sv.framerate = BASE_FRAMERATE; - sv.frametime = BASE_FRAMETIME; - sv.framediv = 1; + sv.frametime = Com_ComputeFrametime(sv.framerate); #endif // set externally visible server name diff --git a/src/server/send.c b/src/server/send.c index 6e420d209..1499b74d0 100644 --- a/src/server/send.c +++ b/src/server/send.c @@ -71,7 +71,7 @@ static bool SV_RateDrop(client_t *client) } #if USE_FPS - total = total * sv.framediv / client->framediv; + total = total * sv.frametime.div / client->framediv; #endif if (total > client->rate) { @@ -878,8 +878,8 @@ static void finish_frame(client_t *client) #if USE_DEBUG && USE_FPS static void check_key_sync(client_t *client) { - int div = sv.framediv / client->framediv; - int key1 = !(sv.framenum % sv.framediv); + int div = sv.frametime.div / client->framediv; + int key1 = !(sv.framenum % sv.frametime.div); int key2 = !(client->framenum % div); if (key1 != key2) { diff --git a/src/server/server.h b/src/server/server.h index f539ebfb8..f3cb336f9 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -134,9 +134,9 @@ typedef struct { // variable server FPS #if USE_FPS #define SV_FRAMERATE sv.framerate -#define SV_FRAMETIME sv.frametime -#define SV_FRAMEDIV sv.framediv -#define SV_FRAMESYNC !(sv.framenum % sv.framediv) +#define SV_FRAMETIME sv.frametime.time +#define SV_FRAMEDIV sv.frametime.div +#define SV_FRAMESYNC !(sv.framenum % sv.frametime.div) #define SV_CLIENTSYNC(cl) !(sv.framenum % (cl)->framediv) #else #define SV_FRAMERATE BASE_FRAMERATE @@ -156,8 +156,7 @@ typedef struct { #if USE_FPS int framerate; - int frametime; - int framediv; + frametime_t frametime; #endif int framenum; diff --git a/src/server/user.c b/src/server/user.c index 00fef3af1..a8a2fb228 100644 --- a/src/server/user.c +++ b/src/server/user.c @@ -1475,7 +1475,7 @@ static void SV_ParseDeltaUserinfo(void) #if USE_FPS void SV_AlignKeyFrames(client_t *client) { - int framediv = sv.framediv / client->framediv; + int framediv = sv.frametime.div / client->framediv; int framenum = sv.framenum / client->framediv; int frameofs = framenum % framediv; int newnum = frameofs + Q_align(client->framenum, framediv); @@ -1497,11 +1497,11 @@ static void set_client_fps(int value) clamp(framediv, 1, MAX_FRAMEDIV); - framediv = sv.framediv / Q_gcd(sv.framediv, framediv); + framediv = sv.frametime.div / Q_gcd(sv.frametime.div, framediv); framerate = sv.framerate / framediv; Com_DDPrintf("[%d] client div=%d, server div=%d, rate=%d\n", - sv.framenum, framediv, sv.framediv, framerate); + sv.framenum, framediv, sv.frametime.div, framerate); sv_client->framediv = framediv; From 64aced410fd8cf151faf8bbbe6987627896c8ef6 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 15 Nov 2023 20:32:03 +0300 Subject: [PATCH 021/167] Treat LOAD_LEVEL_START the same as level re-enter. If we are loading LOAD_LEVEL_START autosave with existing level file, this means we have re-entered this level from another level, and we need to run it for 10 seconds. Fixes buggy mgu3m2 -> mgu3m3 -> mgu3m2 transition if after re-entering mgu3m2 player is killed and level is reloaded. --- src/server/save.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/save.c b/src/server/save.c index 2f1b9bfae..f95ff8472 100644 --- a/src/server/save.c +++ b/src/server/save.c @@ -553,7 +553,7 @@ void SV_CheckForSavegame(const mapcmd_t *cmd) return; } - if (cmd->loadgame) { + if (cmd->loadgame == LOAD_NORMAL) { // called from SV_Loadgame_f ge->RunFrame(); ge->RunFrame(); From 1ead80c7a198daab4245482744c143b9ac02055c Mon Sep 17 00:00:00 2001 From: Dino <8dino2@gmail.com> Date: Wed, 15 Nov 2023 14:33:09 -0500 Subject: [PATCH 022/167] Added ffmpeg deps --- .github/workflows/build.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4dc6f8eb1..6a5ec3fe7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,8 +19,7 @@ env: -Dwerror=false -Daqtion-build=true -Ddiscord-sdk=true - -Davcodec=disabled -# Disabled avcodec for now, because AQtion doesn't use it, but it's there if we do cinematics one day + -Davcodec=enabled MESON_ARGS_WIN: >- -Dlibpng:werror=false @@ -132,7 +131,9 @@ jobs: sudo apt-get install -y python3 python3-pip libsdl2-dev libopenal-dev \ libpng-dev libjpeg-dev zlib1g-dev mesa-common-dev \ libcurl4-openssl-dev libx11-dev libxi-dev \ - libogg-dev libvorbis-dev uuid-dev patchelf + libavcodec-dev libavformat-dev libavutil-dev \ + libswresample-dev libswscale-dev\ + uuid-dev patchelf pip3 install meson ninja - name: Build @@ -175,7 +176,9 @@ jobs: libpng-dev libjpeg-dev zlib1g-dev mesa-common-dev \ libcurl4-openssl-dev libx11-dev libxi-dev \ libwayland-dev wayland-protocols libdecor-0-dev \ - libogg-dev libvorbis-dev uuid-dev patchelf + libavcodec-dev libavformat-dev libavutil-dev \ + libswresample-dev libswscale-dev \ + uuid-dev patchelf - name: Build run: | @@ -248,7 +251,7 @@ jobs: - name: Install dependencies run: | - brew install pkg-config meson libpng sdl2 openal-soft zlib curl libvorbis jpeg-turbo + brew install pkg-config meson libpng sdl2 openal-soft zlib curl ffmpeg jpeg-turbo - name: Build run: | From 083a8b0700b468dee35cb6660335317e6c8bb810 Mon Sep 17 00:00:00 2001 From: Dino <8dino2@gmail.com> Date: Wed, 15 Nov 2023 14:41:39 -0500 Subject: [PATCH 023/167] Missed a space --- .github/workflows/build.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6a5ec3fe7..5ac0fb2d0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,6 @@ env: -Dwerror=false -Daqtion-build=true -Ddiscord-sdk=true - -Davcodec=enabled MESON_ARGS_WIN: >- -Dlibpng:werror=false @@ -62,7 +61,9 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y gcc-mingw-w64 meson nasm uuid-dev + sudo apt-get install -y gcc-mingw-w64 meson nasm uuid-dev \ + libavcodec-dev libavformat-dev libavutil-dev \ + libswresample-dev libswscale-dev \ - name: Build run: | @@ -132,7 +133,7 @@ jobs: libpng-dev libjpeg-dev zlib1g-dev mesa-common-dev \ libcurl4-openssl-dev libx11-dev libxi-dev \ libavcodec-dev libavformat-dev libavutil-dev \ - libswresample-dev libswscale-dev\ + libswresample-dev libswscale-dev \ uuid-dev patchelf pip3 install meson ninja From 92d2e239539b068b9d9638cd656d8101b98ae7fa Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Wed, 15 Nov 2023 15:35:52 -0500 Subject: [PATCH 024/167] Sync to aqtion alpha (#142) * Added listsound command for server * Updated comment * Backwards compat is broken currently * Encapsulated AQtion-specific items with preprocessors * Still no dice yet * Works locally * Had to hard-set some enums * Converted #ifdef to #if for USE_AQTION --- inc/common/protocol.h | 21 +++++------ src/client/effects.c | 24 +++++++++++++ src/client/entities.c | 3 +- src/client/main.c | 8 ++--- src/client/parse.c | 80 +++++++++++++++++++++-------------------- src/client/ui/servers.c | 4 +-- src/common/msg.c | 12 +++---- src/server/commands.c | 18 +++++++++- src/server/user.c | 2 ++ 9 files changed, 106 insertions(+), 66 deletions(-) diff --git a/inc/common/protocol.h b/inc/common/protocol.h index 51a9e6c79..94ae3e5ac 100644 --- a/inc/common/protocol.h +++ b/inc/common/protocol.h @@ -62,7 +62,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #define PROTOCOL_VERSION_AQTION_GHUD 3012 // game dll defined hud elements #define PROTOCOL_VERSION_AQTION_CVARSYNC 3013 #define PROTOCOL_VERSION_AQTION_GHUD2 3014 -#define PROTOCOL_VERSION_AQTION_CURRENT 3014 +#define PROTOCOL_VERSION_AQTION_EXTENDED_LIMITS 3015 +#define PROTOCOL_VERSION_AQTION_CURRENT 3015 #endif @@ -164,20 +165,16 @@ typedef enum { svc_gamestate, // q2pro specific, means svc_playerupdate in r1q2 svc_setting, - svc_reserved1, - svc_reserved2, - svc_reserved3, - svc_reserved4, - - svc_ghudupdate, - - svc_extend = 30, - svc_userstatistic, - svc_cvarsync, - // q2pro specific operations + // q2pro rerelease svc_configstringstream, svc_baselinestream, + // AQtion + svc_ghudupdate = 29, + svc_extend = 30, + svc_userstatistic = 31, + svc_cvarsync = 32, + svc_num_types } svc_ops_t; diff --git a/src/client/effects.c b/src/client/effects.c index a1d73b775..3ea54a111 100644 --- a/src/client/effects.c +++ b/src/client/effects.c @@ -187,6 +187,7 @@ void CL_MuzzleFlash(void) switch (mz.weapon) { case MZ_BLASTER: // MK23 + #if USE_AQTION mk23snd = atoi(cl_mk23_sound->string); if (mk23snd > MAX_WEAPON_SOUND || mk23snd <= MIN_WEAPON_SOUND) { @@ -200,8 +201,12 @@ void CL_MuzzleFlash(void) Q_snprintf(soundname, sizeof(soundname), "weapons/mk23fire%i.wav", mk23snd); break; } + #else + Q_snprintf(soundname, sizeof(soundname), "weapons/mk23fire.wav"); + #endif case MZ_MACHINEGUN: // MP5/10 Submachinegun + #if USE_AQTION mp5snd = atoi(cl_mp5_sound->string); if (mp5snd > MAX_WEAPON_SOUND || mp5snd <= MIN_WEAPON_SOUND) { @@ -215,8 +220,12 @@ void CL_MuzzleFlash(void) Q_snprintf(soundname, sizeof(soundname), "weapons/mp5fire%i.wav", mp5snd); break; } + #else + Q_snprintf(soundname, sizeof(soundname), "weapons/mp5fire.wav"); + #endif case MZ_ROCKET: // M4 Assault Rifle + #if USE_AQTION m4snd = atoi(cl_m4_sound->string); if (m4snd > MAX_WEAPON_SOUND || m4snd <= MIN_WEAPON_SOUND) { @@ -230,8 +239,12 @@ void CL_MuzzleFlash(void) Q_snprintf(soundname, sizeof(soundname), "weapons/m4a1fire%i.wav", m4snd); break; } + #else + Q_snprintf(soundname, sizeof(soundname), "weapons/m4a1fire.wav"); + #endif case MZ_SHOTGUN: // M3 Shotgun + #if USE_AQTION m3snd = atoi(cl_m3_sound->string); if (m3snd > MAX_WEAPON_SOUND || m3snd <= MIN_WEAPON_SOUND) { @@ -245,8 +258,12 @@ void CL_MuzzleFlash(void) Q_snprintf(soundname, sizeof(soundname), "weapons/shotgf1b%i.wav", m3snd); break; } + #else + Q_snprintf(soundname, sizeof(soundname), "weapons/shotgf1b.wav"); + #endif case MZ_SSHOTGUN: // Handcannon -- needs adjustment for single barrel vs double + #if USE_AQTION hcsnd = atoi(cl_hc_sound->string); if (hcsnd > MAX_WEAPON_SOUND || hcsnd <= MIN_WEAPON_SOUND) { @@ -260,8 +277,12 @@ void CL_MuzzleFlash(void) Q_snprintf(soundname, sizeof(soundname), "weapons/cannon_fire%i.wav", hcsnd); break; } + #else + Q_snprintf(soundname, sizeof(soundname), "weapons/cannon_fire.wav"); + #endif case MZ_HYPERBLASTER: // SSG 3000 Sniper Rifle + #if USE_AQTION ssgsnd = atoi(cl_ssg_sound->string); if (ssgsnd > MAX_WEAPON_SOUND || ssgsnd <= MIN_WEAPON_SOUND) { @@ -275,6 +296,9 @@ void CL_MuzzleFlash(void) Q_snprintf(soundname, sizeof(soundname), "weapons/ssgfire%i.wav", ssgsnd); break; } + #else + Q_snprintf(soundname, sizeof(soundname), "weapons/ssgfire.wav"); + #endif } // Play the sound defined in the case statement above diff --git a/src/client/entities.c b/src/client/entities.c index 54ab1fa9d..1e5a12e3b 100644 --- a/src/client/entities.c +++ b/src/client/entities.c @@ -221,7 +221,7 @@ static void parse_entity_event(int number) CL_TeleportParticles(cent->current.origin); break; case EV_FOOTSTEP: - if (cl_footsteps->integer) + if (cl_footsteps->integer) { if (strcmp(cl_enhanced_footsteps->string, "0") == 0) { CL_PlayFootstepSfx(-1, number, 1.0f, ATTN_NORM); //S_StartSound(NULL, number, CHAN_BODY, cl_sfx_footsteps[Q_rand() & 3], 1, ATTN_NORM, 0); @@ -239,6 +239,7 @@ static void parse_entity_event(int number) cl_laststep = r; } CL_PlayFootstepSfx(-1, number, 1.0f, ATTN_NORM); + } break; case EV_OTHER_FOOTSTEP: if (cl.csr.extended && cl_footsteps->integer) diff --git a/src/client/main.c b/src/client/main.c index e8dc1cb63..fbc85f3c6 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -3974,7 +3974,7 @@ static void CL_InitLocal(void) cl_enhanced_footsteps= Cvar_Get("cl_enhanced_footsteps", "0", 0); -#if USE_DISCORD && USE_CURL //rekkie -- discord -- s +#if USE_DISCORD && USE_CURL && USE_AQTION //rekkie -- discord -- s //rekkie -- external ip -- s cl_extern_ip = Cvar_Get("cl_extern_ip", "", CVAR_ROM); CL_GetExternalIP(); // Get external IP @@ -4070,7 +4070,7 @@ static void CL_InitLocal(void) info_gender = Cvar_Get("gender", "male", CVAR_USERINFO | CVAR_ARCHIVE); info_gender->modified = false; // clear this so we know when user sets it manually info_uf = Cvar_Get("uf", "", CVAR_USERINFO); - #if USE_CLIENT + #if USE_CLIENT && USE_AQTION info_steamid = Cvar_Get("steamid", "", CVAR_USERINFO); info_steamcloudappenabled = Cvar_Get("steamcloudappenabled", "", CVAR_USERINFO); info_steamclouduserenabled = Cvar_Get("steamclouduserenabled", "", CVAR_USERINFO); @@ -4593,7 +4593,7 @@ bool CL_ProcessEvents(void) CL_GTV_Run(); -#if USE_DISCORD && USE_CURL //rekkie -- discord -- s +#if USE_DISCORD && USE_CURL && USE_AQTION //rekkie -- discord -- s CL_RunDiscord(); #endif //rekkie -- discord -- e @@ -4677,7 +4677,7 @@ void CL_Shutdown(void) CL_GTV_Shutdown(); -#if USE_DISCORD && USE_CURL //rekkie -- discord -- s +#if USE_DISCORD && USE_CURL && USE_AQTION //rekkie -- discord -- s if (discord.init) CL_ShutdownDiscord(); #endif //rekkie -- discord -- e diff --git a/src/client/parse.c b/src/client/parse.c index 061d4fc12..d7e55c1e5 100644 --- a/src/client/parse.c +++ b/src/client/parse.c @@ -641,6 +641,46 @@ static void CL_ParseServerData(void) cl.esFlags |= MSG_ES_LONGSOLID; } cl.pmp.speedmult = 2; + + // This check must come before any specific >= subprotocol checks + } else if (cls.serverProtocol == PROTOCOL_VERSION_AQTION) { + i = MSG_ReadShort(); + if (!AQTION_SUPPORTED(i)) { + Com_Error(ERR_DROP, + "AQTION server reports unsupported protocol version %d.\n" + "Current client version is %d.", i, PROTOCOL_VERSION_AQTION_CURRENT); + } + Com_DPrintf("Using minor AQTION protocol version %d\n", i); + cls.protocolVersion = i; + i = MSG_ReadByte(); + Com_DPrintf("AQTION server state %d\n", i); + cl.serverstate = i; + + i = MSG_ReadByte(); + if (i) { + Com_DPrintf("AQTION strafejump hack enabled\n"); + cl.pmp.strafehack = true; + } + i = MSG_ReadByte(); //atu QWMod + if (i) { + Com_DPrintf("AQTION QW mode enabled\n"); + PmoveEnableQW(&cl.pmp); + } + cl.esFlags |= MSG_ES_UMASK; + cl.esFlags |= MSG_ES_LONGSOLID; + cl.esFlags |= MSG_ES_BEAMORIGIN; + cl.esFlags |= MSG_ES_SHORTANGLES; + + // waterjump hack + i = MSG_ReadByte(); + if (i) { + Com_DPrintf("AQTION waterjump hack enabled\n"); + cl.pmp.waterhack = true; + } + + cl.pmp.speedmult = 2; + cl.pmp.flyhack = true; // fly hack is unconditionally enabled + cl.pmp.flyfriction = 4; } else if (cls.serverProtocol == PROTOCOL_VERSION_Q2PRO) { i = MSG_ReadWord(); if (!Q2PRO_SUPPORTED(i)) { @@ -698,44 +738,6 @@ static void CL_ParseServerData(void) cl.pmp.speedmult = 2; cl.pmp.flyhack = true; // fly hack is unconditionally enabled cl.pmp.flyfriction = 4; - } else if (cls.serverProtocol == PROTOCOL_VERSION_AQTION) { - i = MSG_ReadShort(); - if (!AQTION_SUPPORTED(i)) { - Com_Error(ERR_DROP, - "AQTION server reports unsupported protocol version %d.\n" - "Current client version is %d.", i, PROTOCOL_VERSION_AQTION_CURRENT); - } - Com_DPrintf("Using minor AQTION protocol version %d\n", i); - cls.protocolVersion = i; - i = MSG_ReadByte(); - Com_DPrintf("AQTION server state %d\n", i); - cl.serverstate = i; - - i = MSG_ReadByte(); - if (i) { - Com_DPrintf("AQTION strafejump hack enabled\n"); - cl.pmp.strafehack = true; - } - i = MSG_ReadByte(); //atu QWMod - if (i) { - Com_DPrintf("AQTION QW mode enabled\n"); - PmoveEnableQW(&cl.pmp); - } - cl.esFlags |= MSG_ES_UMASK; - cl.esFlags |= MSG_ES_LONGSOLID; - cl.esFlags |= MSG_ES_BEAMORIGIN; - cl.esFlags |= MSG_ES_SHORTANGLES; - - // waterjump hack - i = MSG_ReadByte(); - if (i) { - Com_DPrintf("AQTION waterjump hack enabled\n"); - cl.pmp.waterhack = true; - } - - cl.pmp.speedmult = 2; - cl.pmp.flyhack = true; // fly hack is unconditionally enabled - cl.pmp.flyfriction = 4; } else { cls.protocolVersion = 0; } @@ -1500,9 +1502,9 @@ void CL_ParseServerMessage(void) CL_ParseDownload(cmd); continue; - case svc_gamestate: case svc_configstringstream: case svc_baselinestream: + case svc_gamestate: if (cls.serverProtocol != PROTOCOL_VERSION_Q2PRO && cls.serverProtocol != PROTOCOL_VERSION_AQTION) { goto badbyte; } diff --git a/src/client/ui/servers.c b/src/client/ui/servers.c index ec8d0d2b8..522aaf423 100644 --- a/src/client/ui/servers.c +++ b/src/client/ui/servers.c @@ -260,8 +260,8 @@ void UI_StatusEvent(const serverStatus_t *status) FreeSlot(slot); } - #ifdef USE_AQTION const char *am = "No"; + #if USE_AQTION size_t ambci; const char *hasBotsCheck = Info_ValueForKey(status->infostring, "am"); @@ -312,7 +312,7 @@ void UI_StatusEvent(const serverStatus_t *status) if (ping > 999) ping = 999; - #ifdef USE_AQTION + #if USE_AQTION slot = UI_FormatColumns(SLOT_EXTRASIZE, host, am, map, va("%d/%s", playerCount, maxclients), va("%u", ping), diff --git a/src/common/msg.c b/src/common/msg.c index e6c9d6341..b008604b0 100644 --- a/src/common/msg.c +++ b/src/common/msg.c @@ -2527,7 +2527,9 @@ void MSG_ParseDeltaPlayerstate_Enhanced(const player_state_t *from, } if (extraflags & EPS_M_VELOCITY2) + { to->pmove.velocity[2] = MSG_ReadShort(); + } if (flags & PS_M_TIME) { @@ -3088,15 +3090,11 @@ const char *MSG_ServerCommandString(int cmd) S(zdownload) S(gamestate) S(setting) - S(reserved1) - S(reserved2) - S(reserved3) - S(reserved4) - S(ghudupdate) - S(extend) - S(userstatistic) S(configstringstream) + S(ghudupdate) + S(extend) S(baselinestream) + S(userstatistic) #undef S } } diff --git a/src/server/commands.c b/src/server/commands.c index a46ccafdd..0660e4f6f 100644 --- a/src/server/commands.c +++ b/src/server/commands.c @@ -1729,6 +1729,22 @@ static void SV_Stop_f(void) #endif +/* +SV_ListSounds_f +Lists all loaded sounds, good for debugging PF_SoundIndex overflows +*/ +void SV_ListSounds_f(void) +{ + int i; + char *string; + + Com_Printf("-- List of Loaded Sounds:\n"); + for (i = 1; i < MAX_SOUNDS; i++) { + string = sv.configstrings[CS_SOUNDS + i]; + Com_Printf("%i: %s\n", i, string); + } +} + //=========================================================== static const cmdreg_t c_server[] = { @@ -1775,6 +1791,7 @@ static const cmdreg_t c_server[] = { { "adduserinfoban", SV_AddInfoBan_f }, { "deluserinfoban", SV_DelInfoBan_f }, { "listuserinfobans", SV_ListInfoBans_f }, + { "listsounds", SV_ListSounds_f }, #if USE_MVD_CLIENT || USE_MVD_SERVER { "mvdrecord", SV_Record_f, SV_Record_c }, { "mvdstop", SV_Stop_f }, @@ -1783,7 +1800,6 @@ static const cmdreg_t c_server[] = { { NULL } }; - /* ================== SV_InitOperatorCommands diff --git a/src/server/user.c b/src/server/user.c index 92c49c2d7..af30cf43f 100644 --- a/src/server/user.c +++ b/src/server/user.c @@ -909,6 +909,7 @@ static void SV_PacketdupHack_f(void) } #endif +#if USE_AQTION static void SV_CvarSync_f(void) { if (!sv_client->edict->client) @@ -957,6 +958,7 @@ static void SV_CvarSync_f(void) } } } +#endif static bool match_cvar_val(const char *s, const char *v) { From 99aef0be8986e91b03f1c94ec8ff322d96a09614 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 16 Nov 2023 23:58:19 +0300 Subject: [PATCH 025/167] Remove unused explosion type. --- src/client/tent.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/client/tent.c b/src/client/tent.c index 19d3965c0..6f4b796c3 100644 --- a/src/client/tent.c +++ b/src/client/tent.c @@ -303,7 +303,6 @@ EXPLOSION MANAGEMENT typedef struct { enum { ex_free, - ex_explosion, ex_misc, ex_flash, ex_mflash, @@ -482,7 +481,7 @@ static void CL_AddExplosions(void) ent->flags |= RF_TRANSLUCENT; break; default: - break; + Q_assert(!"bad type"); } if (ex->type == ex_free) From 99a269a9bec5edfc635f2a4bf777004e85d4a298 Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Thu, 16 Nov 2023 16:23:54 -0500 Subject: [PATCH 026/167] Added handy message for badbyte, ListSounds prototype add --- src/client/parse.c | 5 ++++- src/server/server.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/client/parse.c b/src/client/parse.c index d7e55c1e5..8da7d3210 100644 --- a/src/client/parse.c +++ b/src/client/parse.c @@ -1412,7 +1412,10 @@ void CL_ParseServerMessage(void) switch (cmd) { default: badbyte: - Com_Error(ERR_DROP, "%s: illegible server message: %d", __func__, cmd); + Com_Error(ERR_DROP, "%s: illegible server message: %d", __func__, cmd); + #if USE_AQTION + Com_Printf("Please update your AQtion client to the latest version in Steam\n"); + #endif break; case svc_nop: diff --git a/src/server/server.h b/src/server/server.h index 478cd9ec4..a94725605 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -678,6 +678,7 @@ void SV_MvdStartSound(int entnum, int channel, int flags, void SV_MvdRecord_f(void); void SV_MvdStop_f(void); +void SV_ListSounds_f(void); #else #define SV_MvdRegister() (void)0 #define SV_MvdPreInit() (void)0 From da2a8f19431310667672234456e0642fa24e007e Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 17 Nov 2023 00:02:17 +0300 Subject: [PATCH 027/167] Add monster muzzleflashes. From Jonathan --- src/client/client.h | 19 +++++++++++++++++ src/client/effects.c | 45 +++++++++++++++++++++++++++++++++++--- src/client/tent.c | 51 ++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 108 insertions(+), 7 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index 9ebc3ae65..e03924ebd 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -770,6 +770,25 @@ typedef struct cl_sustain_s { void (*think)(struct cl_sustain_s *self); } cl_sustain_t; +typedef enum { + MFLASH_MACHN, + MFLASH_SHOTG2, + MFLASH_SHOTG, + MFLASH_ROCKET, + MFLASH_RAIL, + MFLASH_LAUNCH, + MFLASH_ETF_RIFLE, + MFLASH_DIST, + MFLASH_BOOMER, + MFLASH_BLAST, // 0 = orange, 1 = blue, 2 = green + MFLASH_BFG, + MFLASH_BEAMER, + + MFLASH_TOTAL +} cl_muzzlefx_t; + +void CL_AddMuzzleFX(const vec3_t origin, const vec3_t angles, cl_muzzlefx_t fx, int skin, float scale); + void CL_SmokeAndFlash(const vec3_t origin); void CL_DrawBeam(const vec3_t org, const vec3_t end, qhandle_t model); void CL_PlayFootstepSfx(int step_id, int entnum, float volume, float attenuation); diff --git a/src/client/effects.c b/src/client/effects.c index e2206efdc..b2c73f069 100644 --- a/src/client/effects.c +++ b/src/client/effects.c @@ -338,20 +338,27 @@ CL_MuzzleFlash2 void CL_MuzzleFlash2(void) { centity_t *ent; - vec3_t origin; - const vec_t *ofs; + vec3_t ofs, origin, flash_origin; cdlight_t *dl; vec3_t forward, right; char soundname[MAX_QPATH]; + float scale; // locate the origin ent = &cl_entities[mz.entity]; AngleVectors(ent->current.angles, forward, right, NULL); - ofs = monster_flash_offset[mz.weapon]; + + scale = ent->current.scale; + if (!scale) + scale = 1.0f; + + VectorScale(monster_flash_offset[mz.weapon], scale, ofs); origin[0] = ent->current.origin[0] + forward[0] * ofs[0] + right[0] * ofs[1]; origin[1] = ent->current.origin[1] + forward[1] * ofs[0] + right[1] * ofs[1]; origin[2] = ent->current.origin[2] + forward[2] * ofs[0] + right[2] * ofs[1] + ofs[2]; + VectorMA(origin, 4.0f * scale, forward, flash_origin); + dl = CL_AllocDlight(mz.entity); VectorCopy(origin, dl->origin); dl->radius = 200 + (Q_rand() & 31); @@ -384,6 +391,7 @@ void CL_MuzzleFlash2(void) CL_ParticleEffect(origin, vec3_origin, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 18.0f * scale); break; case MZ2_SOLDIER_MACHINEGUN_1: @@ -399,6 +407,7 @@ void CL_MuzzleFlash2(void) CL_ParticleEffect(origin, vec3_origin, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("soldier/solatck3.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 13.0f * scale); break; case MZ2_GUNNER_MACHINEGUN_1: @@ -413,6 +422,7 @@ void CL_MuzzleFlash2(void) CL_ParticleEffect(origin, vec3_origin, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("gunner/gunatck2.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 24.0f * scale); break; case MZ2_ACTOR_MACHINEGUN_1: @@ -427,6 +437,7 @@ void CL_MuzzleFlash2(void) CL_ParticleEffect(origin, vec3_origin, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 32.0f * scale); break; case MZ2_BOSS2_MACHINEGUN_L1: @@ -440,6 +451,7 @@ void CL_MuzzleFlash2(void) CL_ParticleEffect(origin, vec3_origin, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NONE, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 32.0f * scale); break; case MZ2_SOLDIER_BLASTER_1: @@ -454,12 +466,14 @@ void CL_MuzzleFlash2(void) case MZ2_TURRET_BLASTER: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("soldier/solatck2.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 0, 8.0f * scale); break; case MZ2_FLYER_BLASTER_1: case MZ2_FLYER_BLASTER_2: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("flyer/flyatck3.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 0, 8.0f * scale); break; case MZ2_MEDIC_BLASTER_1: @@ -477,17 +491,20 @@ void CL_MuzzleFlash2(void) case MZ2_MEDIC_HYPERBLASTER1_12: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("medic/medatck1.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 0, 8.0f * scale); break; case MZ2_HOVER_BLASTER_1: case MZ2_HOVER_BLASTER_2: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("hover/hovatck1.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 0, 8.0f * scale); break; case MZ2_FLOAT_BLASTER_1: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("floater/fltatck1.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 0, 8.0f * scale); break; case MZ2_SOLDIER_SHOTGUN_1: @@ -502,6 +519,7 @@ void CL_MuzzleFlash2(void) VectorSet(dl->color, 1, 1, 0); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("soldier/solatck1.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_SHOTG, 0, 17.0f * scale); break; case MZ2_TANK_BLASTER_1: @@ -509,6 +527,7 @@ void CL_MuzzleFlash2(void) case MZ2_TANK_BLASTER_3: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 0, 24.0f * scale); break; case MZ2_TANK_MACHINEGUN_1: @@ -535,12 +554,14 @@ void CL_MuzzleFlash2(void) CL_SmokeAndFlash(origin); Q_snprintf(soundname, sizeof(soundname), "tank/tnkatk2%c.wav", 'a' + Q_rand() % 5); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound(soundname), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 20.0f * scale); break; case MZ2_CHICK_ROCKET_1: case MZ2_TURRET_ROCKET: VectorSet(dl->color, 1, 0.5f, 0.2f); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("chick/chkatck2.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_ROCKET, 0, 16.0f * scale); break; case MZ2_TANK_ROCKET_1: @@ -548,6 +569,7 @@ void CL_MuzzleFlash2(void) case MZ2_TANK_ROCKET_3: VectorSet(dl->color, 1, 0.5f, 0.2f); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("tank/tnkatck1.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_ROCKET, 0, 28.0f * scale); break; case MZ2_SUPERTANK_ROCKET_1: @@ -563,6 +585,7 @@ void CL_MuzzleFlash2(void) // case MZ2_CARRIER_ROCKET_4: VectorSet(dl->color, 1, 0.5f, 0.2f); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("tank/rocket.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_ROCKET, 0, 28.0f * scale); break; case MZ2_GUNNER_GRENADE_1: @@ -577,6 +600,7 @@ void CL_MuzzleFlash2(void) case MZ2_SUPERTANK_GRENADE_2: VectorSet(dl->color, 1, 0.5f, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("gunner/gunatck3.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_LAUNCH, 0, 18.0f * scale); break; case MZ2_GLADIATOR_RAILGUN_1: @@ -588,11 +612,13 @@ void CL_MuzzleFlash2(void) case MZ2_ARACHNID_RAIL_UP1: case MZ2_ARACHNID_RAIL_UP2: VectorSet(dl->color, 0.5f, 0.5f, 1.0f); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_RAIL, 0, 32.0f * scale); break; case MZ2_MAKRON_BFG: VectorSet(dl->color, 0.5f, 1, 0.5f); //S_StartSound (NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("makron/bfg_fire.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BFG, 0, 64.0f * scale); break; case MZ2_MAKRON_BLASTER_1: @@ -614,6 +640,7 @@ void CL_MuzzleFlash2(void) case MZ2_MAKRON_BLASTER_17: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("makron/blaster.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 0, 22.0f * scale); break; case MZ2_JORG_MACHINEGUN_L1: @@ -626,6 +653,7 @@ void CL_MuzzleFlash2(void) CL_ParticleEffect(origin, vec3_origin, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("boss3/xfire.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 32.0f * scale); break; case MZ2_JORG_MACHINEGUN_R1: @@ -637,10 +665,12 @@ void CL_MuzzleFlash2(void) VectorSet(dl->color, 1, 1, 0); CL_ParticleEffect(origin, vec3_origin, 0, 40); CL_SmokeAndFlash(origin); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 32.0f * scale); break; case MZ2_JORG_BFG_1: VectorSet(dl->color, 0.5f, 1, 0.5f); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BFG, 0, 64.0f * scale); break; case MZ2_BOSS2_MACHINEGUN_R1: @@ -653,6 +683,7 @@ void CL_MuzzleFlash2(void) VectorSet(dl->color, 1, 1, 0); CL_ParticleEffect(origin, vec3_origin, 0, 40); CL_SmokeAndFlash(origin); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_MACHN, 0, 32.0f * scale); break; case MZ2_STALKER_BLASTER: @@ -709,11 +740,13 @@ void CL_MuzzleFlash2(void) case MZ2_MEDIC_HYPERBLASTER2_12: VectorSet(dl->color, 0, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 2, 22.0f * scale); break; case MZ2_WIDOW_DISRUPTOR: VectorSet(dl->color, -1, -1, -1); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_DIST, 0, 32.0f * scale); break; case MZ2_WIDOW_PLASMABEAM: @@ -736,6 +769,7 @@ void CL_MuzzleFlash2(void) dl->radius = 300 + (Q_rand() & 100); VectorSet(dl->color, 1, 1, 0); dl->die = cl.time + 200; + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BEAMER, 0, 32.0f * scale); break; case MZ2_SOLDIER_RIPPER_1: @@ -749,6 +783,7 @@ void CL_MuzzleFlash2(void) case MZ2_SOLDIER_RIPPER_9: VectorSet(dl->color, 1, 0.5f, 0.5f); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/rippfire.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BOOMER, 0, 32.0f * scale); break; case MZ2_SOLDIER_HYPERGUN_1: @@ -762,17 +797,20 @@ void CL_MuzzleFlash2(void) case MZ2_SOLDIER_HYPERGUN_9: VectorSet(dl->color, 0, 0, 1); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 1, 8.0f * scale); break; case MZ2_GUARDIAN_BLASTER: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_BLAST, 0, 16.0f * scale); break; case MZ2_GUNCMDR_CHAINGUN_1: case MZ2_GUNCMDR_CHAINGUN_2: VectorSet(dl->color, 0, 0, 1); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("guncmdr/gcdratck2.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_ETF_RIFLE, 0, 16.0f * scale); break; case MZ2_GUNCMDR_GRENADE_MORTAR_1: @@ -783,6 +821,7 @@ void CL_MuzzleFlash2(void) case MZ2_GUNCMDR_GRENADE_FRONT_3: VectorSet(dl->color, 1, 0.5f, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("guncmdr/gcdratck3.wav"), 1, ATTN_NORM, 0); + CL_AddMuzzleFX(flash_origin, ent->current.angles, MFLASH_LAUNCH, 0, 18.0f * scale); break; } } diff --git a/src/client/tent.c b/src/client/tent.c index 6f4b796c3..aff13ad18 100644 --- a/src/client/tent.c +++ b/src/client/tent.c @@ -50,6 +50,8 @@ qhandle_t cl_mod_lightning; qhandle_t cl_mod_heatbeam; qhandle_t cl_mod_explo4_big; +qhandle_t cl_mod_muzzles[MFLASH_TOTAL]; + qhandle_t cl_img_flare; #define MAX_FOOTSTEP_SFX 9 @@ -282,6 +284,19 @@ void CL_RegisterTEntModels(void) cl_mod_heatbeam = R_RegisterModel("models/proj/beam/tris.md2"); cl_mod_explo4_big = R_RegisterModel("models/objects/r_explode2/tris.md2"); + cl_mod_muzzles[MFLASH_MACHN] = R_RegisterModel("models/weapons/v_machn/flash/tris.md2"); + cl_mod_muzzles[MFLASH_SHOTG2] = R_RegisterModel("models/weapons/v_shotg2/flash/tris.md2"); + cl_mod_muzzles[MFLASH_SHOTG] = R_RegisterModel("models/weapons/v_shotg/flash/tris.md2"); + cl_mod_muzzles[MFLASH_ROCKET] = R_RegisterModel("models/weapons/v_rocket/flash/tris.md2"); + cl_mod_muzzles[MFLASH_RAIL] = R_RegisterModel("models/weapons/v_rail/flash/tris.md2"); + cl_mod_muzzles[MFLASH_LAUNCH] = R_RegisterModel("models/weapons/v_launch/flash/tris.md2"); + cl_mod_muzzles[MFLASH_ETF_RIFLE] = R_RegisterModel("models/weapons/v_etf_rifle/flash/tris.md2"); + cl_mod_muzzles[MFLASH_DIST] = R_RegisterModel("models/weapons/v_dist/flash/tris.md2"); + cl_mod_muzzles[MFLASH_BOOMER] = R_RegisterModel("models/weapons/v_boomer/flash/tris.md2"); + cl_mod_muzzles[MFLASH_BLAST] = R_RegisterModel("models/weapons/v_blast/flash/tris.md2"); + cl_mod_muzzles[MFLASH_BFG] = R_RegisterModel("models/weapons/v_bfg/flash/tris.md2"); + cl_mod_muzzles[MFLASH_BEAMER] = R_RegisterModel("models/weapons/v_beamer/flash/tris.md2"); + cl_img_flare = R_RegisterSprite("misc/flare.tga"); // check for remaster powerscreen model (ugly!) @@ -388,6 +403,29 @@ static void CL_BFGExplosion(const vec3_t pos) ex->frames = 4; } +void CL_AddMuzzleFX(const vec3_t origin, const vec3_t angles, cl_muzzlefx_t fx, int skin, float scale) +{ + explosion_t *ex; + + Q_assert(fx < q_countof(cl_mod_muzzles)); + + if (!cl_mod_muzzles[fx]) + return; + + ex = CL_AllocExplosion(); + VectorCopy(origin, ex->ent.origin); + VectorCopy(angles, ex->ent.angles); + ex->type = ex_mflash; + ex->ent.flags = RF_TRANSLUCENT | RF_NOSHADOW | RF_FULLBRIGHT; + ex->ent.alpha = 1.0f; + ex->start = cl.servertime - CL_FRAMETIME; + ex->ent.model = cl_mod_muzzles[fx]; + ex->ent.skinnum = skin; + ex->ent.scale = scale; + if (fx != MFLASH_BOOMER) + ex->ent.angles[2] = Q_rand() % 360; +} + /* ================= CL_SmokeAndFlash @@ -425,16 +463,21 @@ static void CL_AddExplosions(void) for (i = 0, ex = cl_explosions; i < MAX_EXPLOSIONS; i++, ex++) { if (ex->type == ex_free) continue; + + if (ex->type == ex_mflash) { + if (cl.time - ex->start > 50) + ex->type = ex_free; + else + V_AddEntity(&ex->ent); + continue; + } + frac = (cl.time - ex->start) * BASE_1_FRAMETIME; f = floor(frac); ent = &ex->ent; switch (ex->type) { - case ex_mflash: - if (f >= ex->frames - 1) - ex->type = ex_free; - break; case ex_misc: case ex_light: if (f >= ex->frames - 1) { From f6b72ef00bb08da5f2f2f9f085aebdd09ad500e1 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 17 Nov 2023 00:42:30 +0300 Subject: [PATCH 028/167] Add more remaster muzzleflash definitions. --- inc/shared/shared.h | 8 ++++++-- src/client/effects.c | 21 +++++++++++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/inc/shared/shared.h b/inc/shared/shared.h index 06eac4e33..68967659e 100644 --- a/inc/shared/shared.h +++ b/inc/shared/shared.h @@ -966,10 +966,14 @@ enum { MZ_BLUEHYPERBLASTER, MZ_PHALANX, +// KEX + MZ_BFG2, + MZ_PHALANX2, + //ROGUE MZ_ETF_RIFLE = 30, - MZ_UNUSED, - MZ_SHOTGUN2, + MZ_PROX, // KEX + MZ_SHOTGUN2, // MZ_ETF_RIFLE_2 in KEX MZ_HEATBEAM, MZ_BLASTER2, MZ_TRACKER, diff --git a/src/client/effects.c b/src/client/effects.c index b2c73f069..cc7c79040 100644 --- a/src/client/effects.c +++ b/src/client/effects.c @@ -251,6 +251,9 @@ void CL_MuzzleFlash(void) VectorSet(dl->color, 0, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/bfg__f1y.wav"), volume, ATTN_NORM, 0); break; + case MZ_BFG2: + VectorSet(dl->color, 0, 1, 0); + break; case MZ_LOGIN: VectorSet(dl->color, 0, 1, 0); @@ -271,18 +274,32 @@ void CL_MuzzleFlash(void) VectorSet(dl->color, 1, 0.5f, 0.5f); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/plasshot.wav"), volume, ATTN_NORM, 0); break; + case MZ_PHALANX2: + VectorSet(dl->color, 1, 0.5f, 0.5f); + break; case MZ_IONRIPPER: VectorSet(dl->color, 1, 0.5f, 0.5f); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/rippfire.wav"), volume, ATTN_NORM, 0); break; + case MZ_PROX: + VectorSet(dl->color, 1, 0.5f, 0); + S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), volume, ATTN_NORM, 0); + S_StartSound(NULL, mz.entity, CHAN_AUTO, S_RegisterSound("weapons/proxlr1a.wav"), volume, ATTN_NORM, 0.1f); + break; case MZ_ETF_RIFLE: VectorSet(dl->color, 0.9f, 0.7f, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/nail1.wav"), volume, ATTN_NORM, 0); break; case MZ_SHOTGUN2: - VectorSet(dl->color, 1, 1, 0); - S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/shotg2.wav"), volume, ATTN_NORM, 0); + // remaster overloads this as MZ_ETF_RIFLE_2 + if (cl.csr.extended) { + VectorSet(dl->color, 0.9f, 0.7f, 0); + S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/nail1.wav"), volume, ATTN_NORM, 0); + } else { + VectorSet(dl->color, 1, 1, 0); + S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/shotg2.wav"), volume, ATTN_NORM, 0); + } break; case MZ_HEATBEAM: VectorSet(dl->color, 1, 1, 0); From 74258008c1adfbe7efb4134d3839ff9297169e1a Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 17 Nov 2023 14:21:29 +0300 Subject: [PATCH 029/167] Add view weapon muzzleflashes. From Jonathan --- src/client/client.h | 11 +++++++++++ src/client/effects.c | 19 +++++++++++++++++++ src/client/entities.c | 29 +++++++++++++++++++++++++++++ src/client/tent.c | 20 ++++++++++++++++++++ src/refresh/mesh.c | 16 ++++++++-------- 5 files changed, 87 insertions(+), 8 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index e03924ebd..c81c0752f 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -298,6 +298,16 @@ typedef struct client_state_s { int numWeaponModels; bool need_powerscreen_scale; + + // data for view weapon + struct { + struct { + qhandle_t model; + int time; + float roll, scale; + vec3_t offset; + } muzzle; + } weapon; } client_state_t; extern client_state_t cl; @@ -787,6 +797,7 @@ typedef enum { MFLASH_TOTAL } cl_muzzlefx_t; +void CL_AddWeaponMuzzleFX(cl_muzzlefx_t fx, const vec3_t offset, float scale); void CL_AddMuzzleFX(const vec3_t origin, const vec3_t angles, cl_muzzlefx_t fx, int skin, float scale); void CL_SmokeAndFlash(const vec3_t origin); diff --git a/src/client/effects.c b/src/client/effects.c index cc7c79040..ee7f6885b 100644 --- a/src/client/effects.c +++ b/src/client/effects.c @@ -186,6 +186,7 @@ void CL_MuzzleFlash(void) case MZ_BLASTER: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0); + CL_AddWeaponMuzzleFX(MFLASH_BLAST, (const vec3_t) { 27.0f, 7.4f, -6.6f }, 8.0f); break; case MZ_BLUEHYPERBLASTER: VectorSet(dl->color, 0, 0, 1); @@ -194,26 +195,31 @@ void CL_MuzzleFlash(void) case MZ_HYPERBLASTER: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0); + CL_AddWeaponMuzzleFX(MFLASH_BLAST, (const vec3_t) { 23.5f, 6.0f, -6.0f }, 9.0f); break; case MZ_MACHINEGUN: VectorSet(dl->color, 1, 1, 0); Q_snprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (Q_rand() % 5) + 1); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0); + CL_AddWeaponMuzzleFX(MFLASH_MACHN, (const vec3_t) { 29.0f, 9.7f, -8.0f }, 12.0f); break; case MZ_SHOTGUN: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/shotgf1b.wav"), volume, ATTN_NORM, 0); S_StartSound(NULL, mz.entity, CHAN_AUTO, S_RegisterSound("weapons/shotgr1b.wav"), volume, ATTN_NORM, 0.1f); + CL_AddWeaponMuzzleFX(MFLASH_SHOTG, (const vec3_t) { 26.5f, 8.6f, -9.5f }, 12.0f); break; case MZ_SSHOTGUN: VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/sshotf1b.wav"), volume, ATTN_NORM, 0); + CL_AddWeaponMuzzleFX(MFLASH_SHOTG2, (const vec3_t) { 20.0f, 7.0f, -5.5f }, 12.0f); break; case MZ_CHAINGUN1: dl->radius = 200 + (Q_rand() & 31); VectorSet(dl->color, 1, 0.25f, 0); Q_snprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (Q_rand() % 5) + 1); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0); + CL_AddWeaponMuzzleFX(MFLASH_MACHN, (const vec3_t) { 29.0f, 9.7f, -10.0f }, 12.0f); break; case MZ_CHAINGUN2: dl->radius = 225 + (Q_rand() & 31); @@ -222,6 +228,7 @@ void CL_MuzzleFlash(void) S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0); Q_snprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (Q_rand() % 5) + 1); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.05f); + CL_AddWeaponMuzzleFX(MFLASH_MACHN, (const vec3_t) { 29.0f, 9.7f, -10.0f }, 16.0f); break; case MZ_CHAINGUN3: dl->radius = 250 + (Q_rand() & 31); @@ -232,20 +239,24 @@ void CL_MuzzleFlash(void) S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.033f); Q_snprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (Q_rand() % 5) + 1); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound(soundname), volume, ATTN_NORM, 0.066f); + CL_AddWeaponMuzzleFX(MFLASH_MACHN, (const vec3_t) { 29.0f, 9.7f, -10.0f }, 20.0f); break; case MZ_RAILGUN: VectorSet(dl->color, 0.5f, 0.5f, 1.0f); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/railgf1a.wav"), volume, ATTN_NORM, 0); + CL_AddWeaponMuzzleFX(MFLASH_RAIL, (const vec3_t) { 20.0f, 5.2f, -7.0f }, 12.0f); break; case MZ_ROCKET: VectorSet(dl->color, 1, 0.5f, 0.2f); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/rocklf1a.wav"), volume, ATTN_NORM, 0); S_StartSound(NULL, mz.entity, CHAN_AUTO, S_RegisterSound("weapons/rocklr1b.wav"), volume, ATTN_NORM, 0.1f); + CL_AddWeaponMuzzleFX(MFLASH_ROCKET, (const vec3_t) { 18.0f, 5.0f, -11.0f }, 10.0f); break; case MZ_GRENADE: VectorSet(dl->color, 1, 0.5f, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), volume, ATTN_NORM, 0); S_StartSound(NULL, mz.entity, CHAN_AUTO, S_RegisterSound("weapons/grenlr1b.wav"), volume, ATTN_NORM, 0.1f); + CL_AddWeaponMuzzleFX(MFLASH_LAUNCH, (const vec3_t) { 18.0f, 6.0f, -6.5f }, 9.0f); break; case MZ_BFG: VectorSet(dl->color, 0, 1, 0); @@ -253,6 +264,7 @@ void CL_MuzzleFlash(void) break; case MZ_BFG2: VectorSet(dl->color, 0, 1, 0); + CL_AddWeaponMuzzleFX(MFLASH_BFG, (const vec3_t) { 18.0f, 8.0f, -7.5f }, 16.0f); break; case MZ_LOGIN: @@ -276,26 +288,31 @@ void CL_MuzzleFlash(void) break; case MZ_PHALANX2: VectorSet(dl->color, 1, 0.5f, 0.5f); + CL_AddWeaponMuzzleFX(MFLASH_ROCKET, (const vec3_t) { 18.0f, 10.0f, -6.0f }, 9.0f); break; case MZ_IONRIPPER: VectorSet(dl->color, 1, 0.5f, 0.5f); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/rippfire.wav"), volume, ATTN_NORM, 0); + CL_AddWeaponMuzzleFX(MFLASH_BOOMER, (const vec3_t) { 18.0f, 3.8f, -4.5f }, 15.0f); break; case MZ_PROX: VectorSet(dl->color, 1, 0.5f, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/grenlf1a.wav"), volume, ATTN_NORM, 0); S_StartSound(NULL, mz.entity, CHAN_AUTO, S_RegisterSound("weapons/proxlr1a.wav"), volume, ATTN_NORM, 0.1f); + CL_AddWeaponMuzzleFX(MFLASH_LAUNCH, (const vec3_t) { 18.0f, 6.0f, -6.5f }, 9.0f); break; case MZ_ETF_RIFLE: VectorSet(dl->color, 0.9f, 0.7f, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/nail1.wav"), volume, ATTN_NORM, 0); + CL_AddWeaponMuzzleFX(MFLASH_ETF_RIFLE, (const vec3_t) { 18.0f, 4.25f, -4.5f }, 4.0f); break; case MZ_SHOTGUN2: // remaster overloads this as MZ_ETF_RIFLE_2 if (cl.csr.extended) { VectorSet(dl->color, 0.9f, 0.7f, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/nail1.wav"), volume, ATTN_NORM, 0); + CL_AddWeaponMuzzleFX(MFLASH_ETF_RIFLE, (const vec3_t) { 18.0f, 3.0f, -4.5f }, 4.0f); } else { VectorSet(dl->color, 1, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/shotg2.wav"), volume, ATTN_NORM, 0); @@ -305,6 +322,7 @@ void CL_MuzzleFlash(void) VectorSet(dl->color, 1, 1, 0); dl->die = cl.time + 100; // S_StartSound (NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/bfg__l1a.wav"), volume, ATTN_NORM, 0); + CL_AddWeaponMuzzleFX(MFLASH_BEAMER, (const vec3_t) { 18.0f, 6.0f, -8.5f }, 16.0f); break; case MZ_BLASTER2: VectorSet(dl->color, 0, 1, 0); @@ -315,6 +333,7 @@ void CL_MuzzleFlash(void) // negative flashes handled the same in gl/soft until CL_AddDLights VectorSet(dl->color, -1, -1, -1); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/disint2.wav"), volume, ATTN_NORM, 0); + CL_AddWeaponMuzzleFX(MFLASH_DIST, (const vec3_t) { 18.0f, 6.0f, -6.5f }, 10.0f); break; case MZ_NUKE1: VectorSet(dl->color, 1, 0, 0); diff --git a/src/client/entities.c b/src/client/entities.c index c1527ce6a..9d9c85232 100644 --- a/src/client/entities.c +++ b/src/client/entities.c @@ -1114,6 +1114,35 @@ static void CL_AddViewWeapon(void) gun.flags |= flags | RF_TRANSLUCENT; V_AddEntity(&gun); } + + // add muzzle flash + if (!cl.weapon.muzzle.model) + return; + + if (cl.time - cl.weapon.muzzle.time > 50) { + cl.weapon.muzzle.model = 0; + return; + } + + gun.flags = RF_FULLBRIGHT | RF_DEPTHHACK | RF_WEAPONMODEL | RF_TRANSLUCENT; + gun.alpha = 1.0f; + gun.model = cl.weapon.muzzle.model; + gun.skinnum = 0; + gun.scale = cl.weapon.muzzle.scale; + gun.backlerp = 0.0f; + gun.frame = gun.oldframe = 0; + + vec3_t forward, right, up; + AngleVectors(gun.angles, forward, right, up); + + VectorMA(gun.origin, cl.weapon.muzzle.offset[0], forward, gun.origin); + VectorMA(gun.origin, cl.weapon.muzzle.offset[1], right, gun.origin); + VectorMA(gun.origin, cl.weapon.muzzle.offset[2], up, gun.origin); + + VectorCopy(cl.refdef.viewangles, gun.angles); + gun.angles[2] += cl.weapon.muzzle.roll; + + V_AddEntity(&gun); } static void CL_SetupFirstPersonView(void) diff --git a/src/client/tent.c b/src/client/tent.c index aff13ad18..a18110e2a 100644 --- a/src/client/tent.c +++ b/src/client/tent.c @@ -403,6 +403,26 @@ static void CL_BFGExplosion(const vec3_t pos) ex->frames = 4; } +void CL_AddWeaponMuzzleFX(cl_muzzlefx_t fx, const vec3_t offset, float scale) +{ + if (mz.entity != cl.frame.clientNum + 1) + return; + + Q_assert(fx < q_countof(cl_mod_muzzles)); + + if (!cl_mod_muzzles[fx]) + return; + + cl.weapon.muzzle.model = cl_mod_muzzles[fx]; + cl.weapon.muzzle.scale = scale; + if (fx == MFLASH_MACHN || fx == MFLASH_BEAMER) + cl.weapon.muzzle.roll = Q_rand() % 360; + else + cl.weapon.muzzle.roll = 0; + VectorCopy(offset, cl.weapon.muzzle.offset); + cl.weapon.muzzle.time = cl.servertime - CL_FRAMETIME; +} + void CL_AddMuzzleFX(const vec3_t origin, const vec3_t angles, cl_muzzlefx_t fx, int skin, float scale) { explosion_t *ex; diff --git a/src/refresh/mesh.c b/src/refresh/mesh.c index 384e03ccb..976b36a4f 100644 --- a/src/refresh/mesh.c +++ b/src/refresh/mesh.c @@ -564,11 +564,11 @@ static void draw_alias_mesh(const maliasmesh_t *mesh) if (dotshading) state |= GLS_SHADE_SMOOTH; - if (glr.ent->flags & RF_TRANSLUCENT) + if (glr.ent->flags & RF_TRANSLUCENT) { state |= GLS_BLEND_BLEND; - - if ((glr.ent->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL)) == RF_TRANSLUCENT) - state |= GLS_DEPTHMASK_FALSE; + if (!(glr.ent->flags & RF_WEAPONMODEL) || (glr.ent->flags & RF_FULLBRIGHT)) + state |= GLS_DEPTHMASK_FALSE; + } if (skin->glow_texnum) state |= GLS_GLOWMAP_ENABLE; @@ -708,11 +708,11 @@ static void draw_skeleton_mesh(const md5_model_t *model, const md5_mesh_t *mesh, if (dotshading) state |= GLS_SHADE_SMOOTH; - if (glr.ent->flags & RF_TRANSLUCENT) + if (glr.ent->flags & RF_TRANSLUCENT) { state |= GLS_BLEND_BLEND; - - if ((glr.ent->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL)) == RF_TRANSLUCENT) - state |= GLS_DEPTHMASK_FALSE; + if (!(glr.ent->flags & RF_WEAPONMODEL) || (glr.ent->flags & RF_FULLBRIGHT)) + state |= GLS_DEPTHMASK_FALSE; + } if (skin->glow_texnum) state |= GLS_GLOWMAP_ENABLE; From 6a93e69a428e27cddb260790b124103d260c626f Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 17 Nov 2023 20:17:33 +0300 Subject: [PATCH 030/167] Const-ify pointers to indices. --- src/refresh/gl.h | 2 +- src/refresh/mesh.c | 4 ++-- src/refresh/state.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/refresh/gl.h b/src/refresh/gl.h index b0bf00375..48b3fa5e2 100644 --- a/src/refresh/gl.h +++ b/src/refresh/gl.h @@ -587,7 +587,7 @@ void GL_ForceTexture(GLuint tmu, GLuint texnum); void GL_BindTexture(GLuint tmu, GLuint texnum); void GL_CommonStateBits(GLbitfield bits); void GL_ScrollSpeed(vec2_t scroll, GLbitfield bits); -void GL_DrawOutlines(GLsizei count, QGL_INDEX_TYPE *indices); +void GL_DrawOutlines(GLsizei count, const QGL_INDEX_TYPE *indices); void GL_Ortho(GLfloat xmin, GLfloat xmax, GLfloat ymin, GLfloat ymax, GLfloat znear, GLfloat zfar); void GL_Frustum(GLfloat fov_x, GLfloat fov_y, GLfloat reflect_x); void GL_Setup2D(void); diff --git a/src/refresh/mesh.c b/src/refresh/mesh.c index 976b36a4f..39e176816 100644 --- a/src/refresh/mesh.c +++ b/src/refresh/mesh.c @@ -419,7 +419,7 @@ static void setup_celshading(void) celscale = 1.0f - Distance(origin, glr.fd.vieworg) / 700.0f; } -static void draw_celshading(QGL_INDEX_TYPE *indices, int num_indices) +static void draw_celshading(const QGL_INDEX_TYPE *indices, int num_indices) { if (celscale < 0.01f || celscale > 1) return; @@ -492,7 +492,7 @@ static void setup_shadow(void) GL_MultMatrix(shadowmatrix, tmp, matrix); } -static void draw_shadow(QGL_INDEX_TYPE *indices, int num_indices) +static void draw_shadow(const QGL_INDEX_TYPE *indices, int num_indices) { if (shadowmatrix[15] < 0.5f) return; diff --git a/src/refresh/state.c b/src/refresh/state.c index 420453952..320a2b3fd 100644 --- a/src/refresh/state.c +++ b/src/refresh/state.c @@ -270,7 +270,7 @@ void GL_Setup3D(bool waterwarp) qglClear(GL_DEPTH_BUFFER_BIT | gl_static.stencil_buffer_bit); } -void GL_DrawOutlines(GLsizei count, QGL_INDEX_TYPE *indices) +void GL_DrawOutlines(GLsizei count, const QGL_INDEX_TYPE *indices) { GL_BindTexture(0, TEXNUM_WHITE); GL_StateBits(GLS_DEPTHMASK_FALSE | GLS_TEXTURE_REPLACE); From 834262da01220f947774557f12c80f6982adbf5b Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 17 Nov 2023 20:18:08 +0300 Subject: [PATCH 031/167] Reduce mesh drawing code duplication. --- src/refresh/mesh.c | 91 ++++++++++++++-------------------------------- 1 file changed, 27 insertions(+), 64 deletions(-) diff --git a/src/refresh/mesh.c b/src/refresh/mesh.c index 39e176816..d5eefd3f2 100644 --- a/src/refresh/mesh.c +++ b/src/refresh/mesh.c @@ -553,10 +553,10 @@ static image_t *skin_for_mesh(image_t **skins, int num_skins) return skins[ent->skinnum]; } -static void draw_alias_mesh(const maliasmesh_t *mesh) +static void begin_alias_mesh(image_t **skins, int num_skins) { glStateBits_t state = GLS_INTENSITY_ENABLE; - image_t *skin = skin_for_mesh(mesh->skins, mesh->numskins); + image_t *skin = skin_for_mesh(skins, num_skins); // fall back to entity matrix GL_LoadMatrix(glr.entmatrix); @@ -579,10 +579,11 @@ static void draw_alias_mesh(const maliasmesh_t *mesh) if (skin->glow_texnum) GL_BindTexture(2, skin->glow_texnum); +} - (*tessfunc)(mesh); - c.trisDrawn += mesh->numtris; - +static void end_alias_mesh(const QGL_INDEX_TYPE *indices, int num_indices, int num_verts, + const GLfloat *tcoords, GLsizei tc_stride) +{ if (dotshading) { GL_ArrayBits(GLA_VERTEX | GLA_TC | GLA_COLOR); GL_VertexPointer(3, VERTEX_SIZE, tess.vertices); @@ -593,25 +594,35 @@ static void draw_alias_mesh(const maliasmesh_t *mesh) GL_Color(color[0], color[1], color[2], color[3]); } - GL_TexCoordPointer(2, 0, (GLfloat *)mesh->tcoords); + GL_TexCoordPointer(2, tc_stride, tcoords); - GL_LockArrays(mesh->numverts); + GL_LockArrays(num_verts); - qglDrawElements(GL_TRIANGLES, mesh->numindices, QGL_INDEX_ENUM, - mesh->indices); + qglDrawElements(GL_TRIANGLES, num_indices, QGL_INDEX_ENUM, indices); + c.trisDrawn += num_indices / 3; - draw_celshading(mesh->indices, mesh->numindices); + draw_celshading(indices, num_indices); if (gl_showtris->integer) { - GL_DrawOutlines(mesh->numindices, mesh->indices); + GL_DrawOutlines(num_indices, indices); } // FIXME: unlock arrays before changing matrix? - draw_shadow(mesh->indices, mesh->numindices); + draw_shadow(indices, num_indices); GL_UnlockArrays(); } +static void draw_alias_mesh(const maliasmesh_t *mesh) +{ + begin_alias_mesh(mesh->skins, mesh->numskins); + + (*tessfunc)(mesh); + + end_alias_mesh(mesh->indices, mesh->numindices, + mesh->numverts, mesh->tcoords->st, 0); +} + #if USE_MD5 // for the given vertex, set of weights & skeleton, calculate @@ -699,30 +710,7 @@ static void lerp_alias_skeleton(const md5_model_t *model) static void draw_skeleton_mesh(const md5_model_t *model, const md5_mesh_t *mesh, const md5_joint_t *skel) { - glStateBits_t state = GLS_INTENSITY_ENABLE; - image_t *skin = skin_for_mesh(model->skins, model->num_skins); - - // fall back to entity matrix - GL_LoadMatrix(glr.entmatrix); - - if (dotshading) - state |= GLS_SHADE_SMOOTH; - - if (glr.ent->flags & RF_TRANSLUCENT) { - state |= GLS_BLEND_BLEND; - if (!(glr.ent->flags & RF_WEAPONMODEL) || (glr.ent->flags & RF_FULLBRIGHT)) - state |= GLS_DEPTHMASK_FALSE; - } - - if (skin->glow_texnum) - state |= GLS_GLOWMAP_ENABLE; - - GL_StateBits(state); - - GL_BindTexture(0, skin->texnum); - - if (skin->glow_texnum) - GL_BindTexture(2, skin->glow_texnum); + begin_alias_mesh(model->skins, model->num_skins); if (glr.ent->flags & RF_SHELL_MASK) tess_shell_skel(mesh, skel); @@ -731,34 +719,9 @@ static void draw_skeleton_mesh(const md5_model_t *model, const md5_mesh_t *mesh, else tess_plain_skel(mesh, skel); - c.trisDrawn += mesh->num_indices / 3; - - if (dotshading) { - GL_ArrayBits(GLA_VERTEX | GLA_TC | GLA_COLOR); - GL_VertexPointer(3, VERTEX_SIZE, tess.vertices); - GL_ColorFloatPointer(4, VERTEX_SIZE, tess.vertices + 4); - } else { - GL_ArrayBits(GLA_VERTEX | GLA_TC); - GL_VertexPointer(3, 4, tess.vertices); - GL_Color(color[0], color[1], color[2], color[3]); - } - - GL_TexCoordPointer(2, sizeof(mesh->vertices[0]) / sizeof(float), mesh->vertices->st); - - GL_LockArrays(mesh->num_verts); - - qglDrawElements(GL_TRIANGLES, mesh->num_indices, QGL_INDEX_ENUM, mesh->indices); - - draw_celshading(mesh->indices, mesh->num_indices); - - if (gl_showtris->integer) { - GL_DrawOutlines(mesh->num_indices, mesh->indices); - } - - // FIXME: unlock arrays before changing matrix? - draw_shadow(mesh->indices, mesh->num_indices); - - GL_UnlockArrays(); + end_alias_mesh(mesh->indices, mesh->num_indices, + mesh->num_verts, mesh->vertices->st, + sizeof(mesh->vertices[0]) / sizeof(float)); } static void draw_alias_skeleton(const md5_model_t *model) From cf887067fe72d9f8ab997b6fb56f2a6ab73976b8 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 17 Nov 2023 21:00:50 +0300 Subject: [PATCH 032/167] Allow muzzleflashes to be disabled. --- doc/client.asciidoc | 3 +++ src/client/tent.c | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/doc/client.asciidoc b/doc/client.asciidoc index 849bb7ee7..37bfb105f 100644 --- a/doc/client.asciidoc +++ b/doc/client.asciidoc @@ -265,6 +265,9 @@ cl_gun_y:: cl_gun_z:: Specifies custom gun model offset. Default value is 0. +cl_muzzleflashes:: + Specifies if muzzleflash effects are enabled. Default value is 1. + Sound Subsystem ~~~~~~~~~~~~~~~ diff --git a/src/client/tent.c b/src/client/tent.c index a18110e2a..2eb8fdc54 100644 --- a/src/client/tent.c +++ b/src/client/tent.c @@ -54,6 +54,8 @@ qhandle_t cl_mod_muzzles[MFLASH_TOTAL]; qhandle_t cl_img_flare; +static cvar_t *cl_muzzleflashes; + #define MAX_FOOTSTEP_SFX 9 typedef struct { @@ -405,6 +407,8 @@ static void CL_BFGExplosion(const vec3_t pos) void CL_AddWeaponMuzzleFX(cl_muzzlefx_t fx, const vec3_t offset, float scale) { + if (!cl_muzzleflashes->integer) + return; if (mz.entity != cl.frame.clientNum + 1) return; @@ -427,6 +431,9 @@ void CL_AddMuzzleFX(const vec3_t origin, const vec3_t angles, cl_muzzlefx_t fx, { explosion_t *ex; + if (!cl_muzzleflashes->integer) + return; + Q_assert(fx < q_countof(cl_mod_muzzles)); if (!cl_mod_muzzles[fx]) @@ -1619,6 +1626,7 @@ void CL_ClearTEnts(void) void CL_InitTEnts(void) { + cl_muzzleflashes = Cvar_Get("cl_muzzleflashes", "1", 0); cl_railtrail_type = Cvar_Get("cl_railtrail_type", "0", 0); cl_railtrail_time = Cvar_Get("cl_railtrail_time", "1.0", 0); cl_railtrail_time->changed = cl_timeout_changed; From 84167685b8a3e6eb122e1e670d41cd3a1be090a2 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 17 Nov 2023 21:19:02 +0300 Subject: [PATCH 033/167] Allow custom footsteps to be disabled. --- doc/client.asciidoc | 5 ++++- src/client/tent.c | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/client.asciidoc b/doc/client.asciidoc index 37bfb105f..bbedf0705 100644 --- a/doc/client.asciidoc +++ b/doc/client.asciidoc @@ -107,7 +107,10 @@ cl_gun:: cl_footsteps:: Controls footstep sounds. When using Q2PRO protocol, disabling this saves some bandwidth since the server stops sending footstep events at all. - Default value is 1 (enabled). + Default value is 1. + - 0 — footsteps disabled + - 1 — use custom footsteps per surface (if found) + - 2 — use default footstep sound cl_updaterate:: Specifies the perferred update rate requested from Q2PRO servers. Only used diff --git a/src/client/tent.c b/src/client/tent.c index 2eb8fdc54..608d30554 100644 --- a/src/client/tent.c +++ b/src/client/tent.c @@ -83,6 +83,10 @@ static int CL_FindFootstepSurface(int entnum) if (cl_num_footsteps <= FOOTSTEP_RESERVED_COUNT) return footstep_id; + // allow custom footsteps to be disabled + if (cl_footsteps->integer >= 2) + return footstep_id; + // use an X/Y only mins/maxs copy of the entity, // since we don't want it to get caught inside of any geometry above or below const vec3_t trace_mins = { cent->mins[0], cent->mins[1], 0 }; From 6ba7075feac925c8d51b768cc5e3330e230558b4 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 18 Nov 2023 12:28:37 +0300 Subject: [PATCH 034/167] Enable lit alpha faces for N64 maps too. --- src/refresh/surf.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/refresh/surf.c b/src/refresh/surf.c index f067b2878..457cc6b67 100644 --- a/src/refresh/surf.c +++ b/src/refresh/surf.c @@ -933,7 +933,7 @@ void GL_LoadWorld(const char *name) bsp_t *bsp; mtexinfo_t *info; mface_t *surf; - int i, ret; + int i, n64surfs, ret; ret = BSP_Load(name, &bsp); if (!bsp) { @@ -975,13 +975,15 @@ void GL_LoadWorld(const char *name) // calculate vertex buffer size in bytes size = 0; - for (i = 0, surf = bsp->faces; i < bsp->numfaces; i++, surf++) { + for (i = n64surfs = 0, surf = bsp->faces; i < bsp->numfaces; i++, surf++) { // hack surface flags into drawflags for faster access surf->drawflags |= surf->texinfo->c.flags & ~DSURF_PLANEBACK; // don't count sky surfaces if (surf->drawflags & (SURF_SKY | SURF_NODRAW)) continue; + if (surf->drawflags & SURF_N64_UV) + n64surfs++; size += surf->numsurfedges * VERTEX_SIZE * sizeof(vec_t); } @@ -1002,7 +1004,7 @@ void GL_LoadWorld(const char *name) // only supported in DECOUPLED_LM maps because vanilla maps have broken // lightofs for liquids/alphas. legacy renderer doesn't support lightmapped // liquids too. - if (bsp->lm_decoupled && gl_static.use_shaders) { + if ((bsp->lm_decoupled || n64surfs > 100) && gl_static.use_shaders) { gl_static.nolm_mask = SURF_NOLM_MASK_REMASTER; } From 6a9bcc08a8f8baf630308f322b1cae9f2c27f2c4 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 18 Nov 2023 12:29:55 +0300 Subject: [PATCH 035/167] Sync monster_flash_offset[] definitions with remaster. Remaster fixes some offsets to better match the models. --- src/shared/m_flash.c | 180 ++++++++++++++++++++++++------------------- 1 file changed, 99 insertions(+), 81 deletions(-) diff --git a/src/shared/m_flash.c b/src/shared/m_flash.c index 13d9438ac..827918559 100644 --- a/src/shared/m_flash.c +++ b/src/shared/m_flash.c @@ -24,111 +24,126 @@ with this program; if not, write to the Free Software Foundation, Inc., // the game needs it to source shot locations, the client // needs it to position muzzle flashes const vec3_t monster_flash_offset[MZ2_LAST] = { - [MZ2_TANK_BLASTER_1] = { 20.7f, -18.5f, 28.7f }, - [MZ2_TANK_BLASTER_2] = { 16.6f, -21.5f, 30.1f }, - [MZ2_TANK_BLASTER_3] = { 11.8f, -23.9f, 32.1f }, + [MZ2_TANK_BLASTER_1] = { 28.7f, -18.5f, 28.7f }, + [MZ2_TANK_BLASTER_2] = { 24.6f, -21.5f, 30.1f }, + [MZ2_TANK_BLASTER_3] = { 19.8f, -23.9f, 32.1f }, [MZ2_TANK_MACHINEGUN_1] = { 22.9f, -0.7f, 25.3f }, [MZ2_TANK_MACHINEGUN_2] = { 22.2f, 6.2f, 22.3f }, [MZ2_TANK_MACHINEGUN_3] = { 19.4f, 13.1f, 18.6f }, [MZ2_TANK_MACHINEGUN_4] = { 19.4f, 18.8f, 18.6f }, - [MZ2_TANK_MACHINEGUN_5] = { 17.9f, 25, 18.6f }, + [MZ2_TANK_MACHINEGUN_5] = { 17.9f, 25.0f, 18.6f }, [MZ2_TANK_MACHINEGUN_6] = { 14.1f, 30.5f, 20.6f }, [MZ2_TANK_MACHINEGUN_7] = { 9.3f, 35.3f, 22.1f }, [MZ2_TANK_MACHINEGUN_8] = { 4.7f, 38.4f, 22.1f }, [MZ2_TANK_MACHINEGUN_9] = { -1.1f, 40.4f, 24.1f }, [MZ2_TANK_MACHINEGUN_10] = { -6.5f, 41.2f, 24.1f }, [MZ2_TANK_MACHINEGUN_11] = { 3.2f, 40.1f, 24.7f }, - [MZ2_TANK_MACHINEGUN_12] = { 11.7f, 36.7f, 26 }, - [MZ2_TANK_MACHINEGUN_13] = { 18.9f, 31.3f, 26 }, + [MZ2_TANK_MACHINEGUN_12] = { 11.7f, 36.7f, 26.0f }, + [MZ2_TANK_MACHINEGUN_13] = { 18.9f, 31.3f, 26.0f }, [MZ2_TANK_MACHINEGUN_14] = { 24.4f, 24.4f, 26.4f }, [MZ2_TANK_MACHINEGUN_15] = { 27.1f, 17.1f, 27.2f }, - [MZ2_TANK_MACHINEGUN_16] = { 28.5f, 9.1f, 28 }, - [MZ2_TANK_MACHINEGUN_17] = { 27.1f, 2.2f, 28 }, - [MZ2_TANK_MACHINEGUN_18] = { 24.9f, -2.8f, 28 }, - [MZ2_TANK_MACHINEGUN_19] = { 21.6f, -7, 26.4f }, + [MZ2_TANK_MACHINEGUN_16] = { 28.5f, 9.1f, 28.0f }, + [MZ2_TANK_MACHINEGUN_17] = { 27.1f, 2.2f, 28.0f }, + [MZ2_TANK_MACHINEGUN_18] = { 24.9f, -2.8f, 28.0f }, + [MZ2_TANK_MACHINEGUN_19] = { 21.6f, -7.0f, 26.4f }, [MZ2_TANK_ROCKET_1] = { 6.2f, 29.1f, 49.1f }, [MZ2_TANK_ROCKET_2] = { 6.9f, 23.8f, 49.1f }, [MZ2_TANK_ROCKET_3] = { 8.3f, 17.8f, 49.5f }, + [MZ2_INFANTRY_MACHINEGUN_1] = { 26.6f, 7.1f, 13.1f }, [MZ2_INFANTRY_MACHINEGUN_2] = { 18.2f, 7.5f, 15.4f }, [MZ2_INFANTRY_MACHINEGUN_3] = { 17.2f, 10.3f, 17.9f }, - [MZ2_INFANTRY_MACHINEGUN_4] = { 17, 12.8f, 20.1f }, + [MZ2_INFANTRY_MACHINEGUN_4] = { 17.0f, 12.8f, 20.1f }, [MZ2_INFANTRY_MACHINEGUN_5] = { 15.1f, 14.1f, 21.8f }, [MZ2_INFANTRY_MACHINEGUN_6] = { 11.8f, 17.2f, 23.1f }, - [MZ2_INFANTRY_MACHINEGUN_7] = { 11.4f, 20.2f, 21 }, - [MZ2_INFANTRY_MACHINEGUN_8] = { 9, 23, 18.9f }, + [MZ2_INFANTRY_MACHINEGUN_7] = { 11.4f, 20.2f, 21.0f }, + [MZ2_INFANTRY_MACHINEGUN_8] = { 9.0f, 23.0f, 18.9f }, [MZ2_INFANTRY_MACHINEGUN_9] = { 13.9f, 18.6f, 17.7f }, [MZ2_INFANTRY_MACHINEGUN_10] = { 15.4f, 15.6f, 15.8f }, [MZ2_INFANTRY_MACHINEGUN_11] = { 10.2f, 15.2f, 25.1f }, [MZ2_INFANTRY_MACHINEGUN_12] = { -1.9f, 15.1f, 28.2f }, - [MZ2_INFANTRY_MACHINEGUN_13] = { -12.4f, 13, 20.2f }, - [MZ2_SOLDIER_BLASTER_1] = { 12.72f, 9.24f, 9.36f }, - [MZ2_SOLDIER_BLASTER_2] = { 25.32f, 4.32f, 22.8f }, - [MZ2_SOLDIER_SHOTGUN_1] = { 12.72f, 9.24f, 9.36f }, - [MZ2_SOLDIER_SHOTGUN_2] = { 25.32f, 4.32f, 22.8f }, - [MZ2_SOLDIER_MACHINEGUN_1] = { 12.72f, 9.24f, 9.36f }, - [MZ2_SOLDIER_MACHINEGUN_2] = { 25.32f, 4.32f, 22.8f }, - [MZ2_GUNNER_MACHINEGUN_1] = { 34.615f, 4.485f, 22.54f }, - [MZ2_GUNNER_MACHINEGUN_2] = { 33.465f, 2.875f, 23.805f }, - [MZ2_GUNNER_MACHINEGUN_3] = { 32.43f, 2.875f, 25.53f }, - [MZ2_GUNNER_MACHINEGUN_4] = { 32.43f, 4.14f, 25.3f }, - [MZ2_GUNNER_MACHINEGUN_5] = { 30.935f, 2.3f, 26.91f }, - [MZ2_GUNNER_MACHINEGUN_6] = { 30.475f, 0.69f, 23.92f }, - [MZ2_GUNNER_MACHINEGUN_7] = { 30.935f, 0.575f, 24.725f }, - [MZ2_GUNNER_MACHINEGUN_8] = { 33.35f, 2.76f, 22.425f }, - [MZ2_GUNNER_GRENADE_1] = { 5.29f, -19.32f, 8.395f }, - [MZ2_GUNNER_GRENADE_2] = { 5.29f, -19.32f, 8.395f }, - [MZ2_GUNNER_GRENADE_3] = { 5.29f, -19.32f, 8.395f }, - [MZ2_GUNNER_GRENADE_4] = { 5.29f, -19.32f, 8.395f }, - [MZ2_CHICK_ROCKET_1] = { 24.8f, -9, 39 }, - [MZ2_FLYER_BLASTER_1] = { 12.1f, 13.4f, -14.5f }, - [MZ2_FLYER_BLASTER_2] = { 12.1f, -7.4f, -14.5f }, - [MZ2_MEDIC_BLASTER_1] = { 12.1f, 5.4f, 16.5f }, + [MZ2_INFANTRY_MACHINEGUN_13] = { -12.4f, 13.0f, 20.2f }, + + [MZ2_SOLDIER_BLASTER_1] = { 10.6f * 1.2f, 7.7f * 1.2f, 7.8f * 1.2f }, + [MZ2_SOLDIER_BLASTER_2] = { 25.1f * 1.2f, 3.6f * 1.2f, 19.0f * 1.2f }, + [MZ2_SOLDIER_SHOTGUN_1] = { 10.6f * 1.2f, 7.7f * 1.2f, 7.8f * 1.2f }, + [MZ2_SOLDIER_SHOTGUN_2] = { 25.1f * 1.2f, 3.6f * 1.2f, 19.0f * 1.2f }, + [MZ2_SOLDIER_MACHINEGUN_1] = { 10.6f * 1.2f, 7.7f * 1.2f, 7.8f * 1.2f }, + [MZ2_SOLDIER_MACHINEGUN_2] = { 25.1f * 1.2f, 3.6f * 1.2f, 19.0f * 1.2f }, + + [MZ2_GUNNER_MACHINEGUN_1] = { 30.1f * 1.15f, 3.9f * 1.15f, 19.6f * 1.15f }, + [MZ2_GUNNER_MACHINEGUN_2] = { 29.1f * 1.15f, 2.5f * 1.15f, 20.7f * 1.15f }, + [MZ2_GUNNER_MACHINEGUN_3] = { 28.2f * 1.15f, 2.5f * 1.15f, 22.2f * 1.15f }, + [MZ2_GUNNER_MACHINEGUN_4] = { 28.2f * 1.15f, 3.6f * 1.15f, 22.0f * 1.15f }, + [MZ2_GUNNER_MACHINEGUN_5] = { 26.9f * 1.15f, 2.0f * 1.15f, 23.4f * 1.15f }, + [MZ2_GUNNER_MACHINEGUN_6] = { 26.5f * 1.15f, 0.6f * 1.15f, 20.8f * 1.15f }, + [MZ2_GUNNER_MACHINEGUN_7] = { 26.9f * 1.15f, 0.5f * 1.15f, 21.5f * 1.15f }, + [MZ2_GUNNER_MACHINEGUN_8] = { 29.0f * 1.15f, 2.4f * 1.15f, 19.5f * 1.15f }, + [MZ2_GUNNER_GRENADE_1] = { 4.6f * 1.15f, -16.8f * 1.15f, 7.3f * 1.15f }, + [MZ2_GUNNER_GRENADE_2] = { 4.6f * 1.15f, -16.8f * 1.15f, 7.3f * 1.15f }, + [MZ2_GUNNER_GRENADE_3] = { 4.6f * 1.15f, -16.8f * 1.15f, 7.3f * 1.15f }, + [MZ2_GUNNER_GRENADE_4] = { 4.6f * 1.15f, -16.8f * 1.15f, 7.3f * 1.15f }, + + [MZ2_CHICK_ROCKET_1] = { 24.8f, -9.0f, 39.0f }, + + [MZ2_FLYER_BLASTER_1] = { 14.1f, 13.4f, -7.0f }, + [MZ2_FLYER_BLASTER_2] = { 14.1f, -13.4f, -7.0f }, + + [MZ2_MEDIC_BLASTER_1] = { 44.0f, 3.0f, 14.4f }, + [MZ2_GLADIATOR_RAILGUN_1] = { 30, 18, 28 }, - [MZ2_HOVER_BLASTER_1] = { 32.5f, -0.8f, 10 }, + + [MZ2_HOVER_BLASTER_1] = { 1.7f, 7.0f, 11.3f }, + [MZ2_ACTOR_MACHINEGUN_1] = { 18.4f, 7.4f, 9.6f }, - [MZ2_SUPERTANK_MACHINEGUN_1] = { 30, 30, 88.5f }, - [MZ2_SUPERTANK_MACHINEGUN_2] = { 30, 30, 88.5f }, - [MZ2_SUPERTANK_MACHINEGUN_3] = { 30, 30, 88.5f }, - [MZ2_SUPERTANK_MACHINEGUN_4] = { 30, 30, 88.5f }, - [MZ2_SUPERTANK_MACHINEGUN_5] = { 30, 30, 88.5f }, - [MZ2_SUPERTANK_MACHINEGUN_6] = { 30, 30, 88.5f }, - [MZ2_SUPERTANK_ROCKET_1] = { 16, -22.5f, 91.2f }, - [MZ2_SUPERTANK_ROCKET_2] = { 16, -33.4f, 86.7f }, - [MZ2_SUPERTANK_ROCKET_3] = { 16, -42.8f, 83.3f }, + + [MZ2_SUPERTANK_MACHINEGUN_1] = { 30.0f, 39.0f, 85.5f }, + [MZ2_SUPERTANK_MACHINEGUN_2] = { 30.0f, 39.0f, 85.5f }, + [MZ2_SUPERTANK_MACHINEGUN_3] = { 30.0f, 39.0f, 85.5f }, + [MZ2_SUPERTANK_MACHINEGUN_4] = { 30.0f, 39.0f, 85.5f }, + [MZ2_SUPERTANK_MACHINEGUN_5] = { 30.0f, 39.0f, 85.5f }, + [MZ2_SUPERTANK_MACHINEGUN_6] = { 30.0f, 39.0f, 85.5f }, + [MZ2_SUPERTANK_ROCKET_1] = { 16.0f, -22.5f, 108.7f }, + [MZ2_SUPERTANK_ROCKET_2] = { 16.0f, -33.4f, 106.7f }, + [MZ2_SUPERTANK_ROCKET_3] = { 16.0f, -42.8f, 104.7f }, + [MZ2_BOSS2_MACHINEGUN_L1] = { 32, -40, 70 }, [MZ2_BOSS2_MACHINEGUN_L2] = { 32, -40, 70 }, [MZ2_BOSS2_MACHINEGUN_L3] = { 32, -40, 70 }, [MZ2_BOSS2_MACHINEGUN_L4] = { 32, -40, 70 }, [MZ2_BOSS2_MACHINEGUN_L5] = { 32, -40, 70 }, + [MZ2_BOSS2_ROCKET_1] = { 22, 16, 10 }, [MZ2_BOSS2_ROCKET_2] = { 22, 8, 10 }, [MZ2_BOSS2_ROCKET_3] = { 22, -8, 10 }, [MZ2_BOSS2_ROCKET_4] = { 22, -16, 10 }, + [MZ2_FLOAT_BLASTER_1] = { 32.5f, -0.8f, 10 }, - [MZ2_SOLDIER_BLASTER_3] = { 24.96f, 12.12f, -3.24f }, - [MZ2_SOLDIER_SHOTGUN_3] = { 24.96f, 12.12f, -3.24f }, - [MZ2_SOLDIER_MACHINEGUN_3] = { 24.96f, 12.12f, -3.24f }, - [MZ2_SOLDIER_BLASTER_4] = { 9.12f, 11.16f, 0.96f }, - [MZ2_SOLDIER_SHOTGUN_4] = { 9.12f, 11.16f, 0.96f }, - [MZ2_SOLDIER_MACHINEGUN_4] = { 9.12f, 11.16f, 0.96f }, - [MZ2_SOLDIER_BLASTER_5] = { 36.6f, 11.88f, -22.44f }, - [MZ2_SOLDIER_SHOTGUN_5] = { 36.6f, 11.88f, -22.44f }, - [MZ2_SOLDIER_MACHINEGUN_5] = { 36.6f, 11.88f, -22.44f }, - [MZ2_SOLDIER_BLASTER_6] = { 33.12f, 4.08f, -12.48f }, - [MZ2_SOLDIER_SHOTGUN_6] = { 33.12f, 4.08f, -12.48f }, - [MZ2_SOLDIER_MACHINEGUN_6] = { 33.12f, 4.08f, -12.48f }, - [MZ2_SOLDIER_BLASTER_7] = { 34.68f, 5.52f, -9.72f }, - [MZ2_SOLDIER_SHOTGUN_7] = { 34.68f, 5.52f, -9.72f }, - [MZ2_SOLDIER_MACHINEGUN_7] = { 34.68f, 5.52f, -9.72f }, - [MZ2_SOLDIER_BLASTER_8] = { 37.8f, 11.52f, 12.12f }, - [MZ2_SOLDIER_SHOTGUN_8] = { 41.4f, 11.52f, 7.32f }, - [MZ2_SOLDIER_MACHINEGUN_8] = { 41.4f, 11.52f, 7.32f }, + + [MZ2_SOLDIER_BLASTER_3] = { 20.8f * 1.2f, 10.1f * 1.2f, -2.7f * 1.2f }, + [MZ2_SOLDIER_SHOTGUN_3] = { 20.8f * 1.2f, 10.1f * 1.2f, -2.7f * 1.2f }, + [MZ2_SOLDIER_MACHINEGUN_3] = { 20.8f * 1.2f, 10.1f * 1.2f, -2.7f * 1.2f }, + [MZ2_SOLDIER_BLASTER_4] = { 7.6f * 1.2f, 9.3f * 1.2f, 0.8f * 1.2f }, + [MZ2_SOLDIER_SHOTGUN_4] = { 7.6f * 1.2f, 9.3f * 1.2f, 0.8f * 1.2f }, + [MZ2_SOLDIER_MACHINEGUN_4] = { 7.6f * 1.2f, 9.3f * 1.2f, 0.8f * 1.2f }, + [MZ2_SOLDIER_BLASTER_5] = { 30.5f * 1.2f, 9.9f * 1.2f, -18.7f * 1.2f }, + [MZ2_SOLDIER_SHOTGUN_5] = { 30.5f * 1.2f, 9.9f * 1.2f, -18.7f * 1.2f }, + [MZ2_SOLDIER_MACHINEGUN_5] = { 30.5f * 1.2f, 9.9f * 1.2f, -18.7f * 1.2f }, + [MZ2_SOLDIER_BLASTER_6] = { 27.6f * 1.2f, 3.4f * 1.2f, -10.4f * 1.2f }, + [MZ2_SOLDIER_SHOTGUN_6] = { 27.6f * 1.2f, 3.4f * 1.2f, -10.4f * 1.2f }, + [MZ2_SOLDIER_MACHINEGUN_6] = { 27.6f * 1.2f, 3.4f * 1.2f, -10.4f * 1.2f }, + [MZ2_SOLDIER_BLASTER_7] = { 28.9f * 1.2f, 4.6f * 1.2f, -8.1f * 1.2f }, + [MZ2_SOLDIER_SHOTGUN_7] = { 28.9f * 1.2f, 4.6f * 1.2f, -8.1f * 1.2f }, + [MZ2_SOLDIER_MACHINEGUN_7] = { 28.9f * 1.2f, 4.6f * 1.2f, -8.1f * 1.2f }, + [MZ2_SOLDIER_BLASTER_8] = { 31.5f * 1.2f, 9.6f * 1.2f, 10.1f * 1.2f }, + [MZ2_SOLDIER_SHOTGUN_8] = { 34.5f * 1.2f, 9.6f * 1.2f, 6.1f * 1.2f }, + [MZ2_SOLDIER_MACHINEGUN_8] = { 34.5f * 1.2f, 9.6f * 1.2f, 6.1f * 1.2f }, + [MZ2_MAKRON_BFG] = { 17, -19.5f, 62.9f }, [MZ2_MAKRON_BLASTER_1] = { -3.6f, -24.1f, 59.5f }, [MZ2_MAKRON_BLASTER_2] = { -1.6f, -19.3f, 59.5f }, [MZ2_MAKRON_BLASTER_3] = { -0.1f, -14.4f, 59.5f }, - [MZ2_MAKRON_BLASTER_4] = { 2, -7.6f, 59.5f }, + [MZ2_MAKRON_BLASTER_4] = { 2.0f, -7.6f, 59.5f }, [MZ2_MAKRON_BLASTER_5] = { 3.4f, 1.3f, 59.5f }, [MZ2_MAKRON_BLASTER_6] = { 3.7f, 11.1f, 59.5f }, [MZ2_MAKRON_BLASTER_7] = { -0.3f, 22.3f, 59.5f }, @@ -142,7 +157,8 @@ const vec3_t monster_flash_offset[MZ2_LAST] = { [MZ2_MAKRON_BLASTER_15] = { 4.2f, -14.1f, 59.5f }, [MZ2_MAKRON_BLASTER_16] = { 2.4f, -18.8f, 59.5f }, [MZ2_MAKRON_BLASTER_17] = { -1.8f, -25.5f, 59.5f }, - [MZ2_MAKRON_RAILGUN_1] = { -17.3f, 7.8f, 72.4f }, + [MZ2_MAKRON_RAILGUN_1] = { 18.1f, 7.8f, 74.4f }, + [MZ2_JORG_MACHINEGUN_L1] = { 78.5f, -47.1f, 96 }, [MZ2_JORG_MACHINEGUN_L2] = { 78.5f, -47.1f, 96 }, [MZ2_JORG_MACHINEGUN_L3] = { 78.5f, -47.1f, 96 }, @@ -156,22 +172,24 @@ const vec3_t monster_flash_offset[MZ2_LAST] = { [MZ2_JORG_MACHINEGUN_R5] = { 78.5f, 46.7f, 96 }, [MZ2_JORG_MACHINEGUN_R6] = { 78.5f, 46.7f, 96 }, [MZ2_JORG_BFG_1] = { 6.3f, -9, 111.2f }, + [MZ2_BOSS2_MACHINEGUN_R1] = { 32, 40, 70 }, [MZ2_BOSS2_MACHINEGUN_R2] = { 32, 40, 70 }, [MZ2_BOSS2_MACHINEGUN_R3] = { 32, 40, 70 }, [MZ2_BOSS2_MACHINEGUN_R4] = { 32, 40, 70 }, [MZ2_BOSS2_MACHINEGUN_R5] = { 32, 40, 70 }, + [MZ2_CARRIER_MACHINEGUN_L1] = { 56, -32, 32 }, [MZ2_CARRIER_MACHINEGUN_R1] = { 56, 32, 32 }, [MZ2_CARRIER_GRENADE] = { 42, 24, 50 }, - [MZ2_TURRET_MACHINEGUN] = { 16, 0, 0 }, - [MZ2_TURRET_ROCKET] = { 16, 0, 0 }, - [MZ2_TURRET_BLASTER] = { 16, 0, 0 }, + [MZ2_TURRET_MACHINEGUN] = { 20, 0, 0 }, + [MZ2_TURRET_ROCKET] = { 20, 0, 0 }, + [MZ2_TURRET_BLASTER] = { 20, 0, 0 }, [MZ2_STALKER_BLASTER] = { 24, 0, 6 }, - [MZ2_DAEDALUS_BLASTER] = { 32.5f, -0.8f, 10 }, - [MZ2_MEDIC_BLASTER_2] = { 12.1f, 5.4f, 16.5f }, + [MZ2_DAEDALUS_BLASTER] = { 1.7f, 7.0f, 11.3f }, + [MZ2_MEDIC_BLASTER_2] = { 44.0f, 3.0f, 14.4f }, [MZ2_CARRIER_RAILGUN] = { 32, 0, 6 }, - [MZ2_WIDOW_DISRUPTOR] = { 57.72f, 14.5f, 88.81f }, + [MZ2_WIDOW_DISRUPTOR] = { 64.72f, 14.50f, 88.81f }, [MZ2_WIDOW_BLASTER] = { 56, 32, 32 }, [MZ2_WIDOW_RAIL] = { 62, -20, 84 }, [MZ2_WIDOW_PLASMABEAM] = { 32, 0, 6 }, @@ -218,22 +236,22 @@ const vec3_t monster_flash_offset[MZ2_LAST] = { [MZ2_CARRIER_ROCKET_2] = { 0, 0, -5 }, [MZ2_CARRIER_ROCKET_3] = { 0, 0, -5 }, [MZ2_CARRIER_ROCKET_4] = { 0, 0, -5 }, - [MZ2_WIDOW2_BEAMER_1] = { 69, -17.63f, 93.77f }, - [MZ2_WIDOW2_BEAMER_2] = { 69, -17.08f, 89.82f }, - [MZ2_WIDOW2_BEAMER_3] = { 69, -18.4f, 90.7f }, - [MZ2_WIDOW2_BEAMER_4] = { 69, -18.34f, 94.32f }, - [MZ2_WIDOW2_BEAMER_5] = { 69, -18.3f, 97.98f }, + [MZ2_WIDOW2_BEAMER_1] = { 69.00f, -17.63f, 93.77f }, + [MZ2_WIDOW2_BEAMER_2] = { 69.00f, -17.08f, 89.82f }, + [MZ2_WIDOW2_BEAMER_3] = { 69.00f, -18.40f, 90.70f }, + [MZ2_WIDOW2_BEAMER_4] = { 69.00f, -18.34f, 94.32f }, + [MZ2_WIDOW2_BEAMER_5] = { 69.00f, -18.30f, 97.98f }, [MZ2_WIDOW2_BEAM_SWEEP_1] = { 45.04f, -59.02f, 92.24f }, - [MZ2_WIDOW2_BEAM_SWEEP_2] = { 50.68f, -54.7f, 91.96f }, + [MZ2_WIDOW2_BEAM_SWEEP_2] = { 50.68f, -54.70f, 91.96f }, [MZ2_WIDOW2_BEAM_SWEEP_3] = { 56.57f, -47.72f, 91.65f }, [MZ2_WIDOW2_BEAM_SWEEP_4] = { 61.75f, -38.75f, 91.38f }, [MZ2_WIDOW2_BEAM_SWEEP_5] = { 65.55f, -28.76f, 91.24f }, - [MZ2_WIDOW2_BEAM_SWEEP_6] = { 67.79f, -18.9f, 91.22f }, - [MZ2_WIDOW2_BEAM_SWEEP_7] = { 68.6f, -9.52f, 91.23f }, + [MZ2_WIDOW2_BEAM_SWEEP_6] = { 67.79f, -18.90f, 91.22f }, + [MZ2_WIDOW2_BEAM_SWEEP_7] = { 68.60f, -9.52f, 91.23f }, [MZ2_WIDOW2_BEAM_SWEEP_8] = { 68.08f, 0.18f, 91.32f }, [MZ2_WIDOW2_BEAM_SWEEP_9] = { 66.14f, 9.79f, 91.44f }, [MZ2_WIDOW2_BEAM_SWEEP_10] = { 62.77f, 18.91f, 91.65f }, - [MZ2_WIDOW2_BEAM_SWEEP_11] = { 58.29f, 27.11f, 92 }, + [MZ2_WIDOW2_BEAM_SWEEP_11] = { 58.29f, 27.11f, 92.00f }, [MZ2_SOLDIER_RIPPER_1] = { 10.6f * 1.2f, 7.7f * 1.2f, 7.8f * 1.2f }, [MZ2_SOLDIER_RIPPER_2] = { 25.1f * 1.2f, 3.6f * 1.2f, 19.0f * 1.2f }, From 408b0d8730843d6506e3490834a72ec52208b7ec Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 18 Nov 2023 13:08:33 +0300 Subject: [PATCH 036/167] Store MD5 texcoords in a separate array. --- src/refresh/gl.h | 7 +------ src/refresh/mesh.c | 12 +++++------- src/refresh/models.c | 9 +++++---- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/refresh/gl.h b/src/refresh/gl.h index 48b3fa5e2..f1f9187d8 100644 --- a/src/refresh/gl.h +++ b/src/refresh/gl.h @@ -321,18 +321,12 @@ typedef struct { /* Vertex */ typedef struct { - vec2_t st; vec3_t normal; uint32_t start; /* start weight */ uint32_t count; /* weight count */ } md5_vertex_t; -/* Triangle */ -typedef struct { - int index[3]; -} md5_triangle_t; - /* Weight */ typedef struct { int joint; @@ -348,6 +342,7 @@ typedef struct { int num_weights; md5_vertex_t *vertices; + maliastc_t *tcoords; QGL_INDEX_TYPE *indices; md5_weight_t *weights; } md5_mesh_t; diff --git a/src/refresh/mesh.c b/src/refresh/mesh.c index d5eefd3f2..8ef6d97f3 100644 --- a/src/refresh/mesh.c +++ b/src/refresh/mesh.c @@ -581,8 +581,8 @@ static void begin_alias_mesh(image_t **skins, int num_skins) GL_BindTexture(2, skin->glow_texnum); } -static void end_alias_mesh(const QGL_INDEX_TYPE *indices, int num_indices, int num_verts, - const GLfloat *tcoords, GLsizei tc_stride) +static void end_alias_mesh(const QGL_INDEX_TYPE *indices, int num_indices, + const maliastc_t *tcoords, int num_verts) { if (dotshading) { GL_ArrayBits(GLA_VERTEX | GLA_TC | GLA_COLOR); @@ -594,7 +594,7 @@ static void end_alias_mesh(const QGL_INDEX_TYPE *indices, int num_indices, int n GL_Color(color[0], color[1], color[2], color[3]); } - GL_TexCoordPointer(2, tc_stride, tcoords); + GL_TexCoordPointer(2, 0, tcoords->st); GL_LockArrays(num_verts); @@ -620,7 +620,7 @@ static void draw_alias_mesh(const maliasmesh_t *mesh) (*tessfunc)(mesh); end_alias_mesh(mesh->indices, mesh->numindices, - mesh->numverts, mesh->tcoords->st, 0); + mesh->tcoords, mesh->numverts); } #if USE_MD5 @@ -719,9 +719,7 @@ static void draw_skeleton_mesh(const md5_model_t *model, const md5_mesh_t *mesh, else tess_plain_skel(mesh, skel); - end_alias_mesh(mesh->indices, mesh->num_indices, - mesh->num_verts, mesh->vertices->st, - sizeof(mesh->vertices[0]) / sizeof(float)); + end_alias_mesh(mesh->indices, mesh->num_indices, mesh->tcoords, mesh->num_verts); } static void draw_alias_skeleton(const md5_model_t *model) diff --git a/src/refresh/models.c b/src/refresh/models.c index 5c9c19eb9..925f65617 100644 --- a/src/refresh/models.c +++ b/src/refresh/models.c @@ -931,6 +931,7 @@ static bool MOD_LoadMD5Mesh(model_t *model, const char *path) MD5_UINT(&num_verts); MD5_ENSURE(num_verts <= TESS_MAX_VERTICES, "too many verts"); OOM_CHECK(mesh->vertices = MD5_Malloc(num_verts * sizeof(mesh->vertices[0]))); + OOM_CHECK(mesh->tcoords = MD5_Malloc(num_verts * sizeof(mesh->tcoords[0]))); mesh->num_verts = num_verts; for (j = 0; j < num_verts; j++) { @@ -940,13 +941,13 @@ static bool MOD_LoadMD5Mesh(model_t *model, const char *path) MD5_UINT(&vert_index); MD5_ENSURE(vert_index < num_verts, "bad vert index"); - md5_vertex_t *vert = &mesh->vertices[vert_index]; - + maliastc_t *tc = &mesh->tcoords[vert_index]; MD5_EXPECT("("); - MD5_FLOAT(&vert->st[0]); - MD5_FLOAT(&vert->st[1]); + MD5_FLOAT(&tc->st[0]); + MD5_FLOAT(&tc->st[1]); MD5_EXPECT(")"); + md5_vertex_t *vert = &mesh->vertices[vert_index]; MD5_UINT(&vert->start); MD5_UINT(&vert->count); } From b3512e0c3f6d88e7ec84d12285fde6c9aa50383f Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 19 Nov 2023 20:38:18 +0300 Subject: [PATCH 037/167] Replace qboolean with bool in hash map code. --- inc/common/hash_map.h | 8 ++++---- src/common/hash_map.c | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/inc/common/hash_map.h b/inc/common/hash_map.h index 6c629ecf9..ed949d4b0 100644 --- a/inc/common/hash_map.h +++ b/inc/common/hash_map.h @@ -22,11 +22,11 @@ typedef struct hash_map_s hash_map_t; hash_map_t *HashMap_CreateImpl(const uint32_t key_size, const uint32_t value_size, uint32_t (*hasher)(const void *const), - qboolean (*comp)(const void *const, const void *const)); + bool (*comp)(const void *const, const void *const)); void HashMap_Destroy(hash_map_t *map); void HashMap_Reserve(hash_map_t *map, int capacity); -qboolean HashMap_InsertImpl(hash_map_t *map, const uint32_t key_size, const uint32_t value_size, const void *const key, const void *const value); -qboolean HashMap_EraseImpl(hash_map_t *map, const uint32_t key_size, const void *const key); +bool HashMap_InsertImpl(hash_map_t *map, const uint32_t key_size, const uint32_t value_size, const void *const key, const void *const value); +bool HashMap_EraseImpl(hash_map_t *map, const uint32_t key_size, const void *const key); void *HashMap_LookupImpl(hash_map_t *map, const uint32_t key_size, const void *const key); uint32_t HashMap_Size(hash_map_t *map); void *HashMap_GetKeyImpl(hash_map_t *map, uint32_t index); @@ -119,7 +119,7 @@ static inline uint32_t HashStr(const void *const val) return hval; } -static inline qboolean HashStrCmp(const void *const a, const void *const b) +static inline bool HashStrCmp(const void *const a, const void *const b) { const char *str_a = *(const char **)a; const char *str_b = *(const char **)b; diff --git a/src/common/hash_map.c b/src/common/hash_map.c index 2766e5e11..caa6d0ec8 100644 --- a/src/common/hash_map.c +++ b/src/common/hash_map.c @@ -32,7 +32,7 @@ typedef struct hash_map_s { uint32_t key_size; uint32_t value_size; uint32_t (*hasher)(const void *const); - qboolean (*comp)(const void *const, const void *const); + bool (*comp)(const void *const, const void *const); uint32_t *hash_to_index; uint32_t *index_chain; void *keys; @@ -100,7 +100,7 @@ HashMap_CreateImpl */ hash_map_t *HashMap_CreateImpl(const uint32_t key_size, const uint32_t value_size, uint32_t (*hasher)(const void *const), - qboolean (*comp)(const void *const, const void *const)) + bool (*comp)(const void *const, const void *const)) { hash_map_t *map = Z_Mallocz(sizeof(hash_map_t)); map->key_size = key_size; @@ -144,7 +144,7 @@ void HashMap_Reserve(hash_map_t *map, int capacity) HashMap_InsertImpl ================= */ -qboolean HashMap_InsertImpl(hash_map_t *map, const uint32_t key_size, const uint32_t value_size, const void *const key, const void *const value) +bool HashMap_InsertImpl(hash_map_t *map, const uint32_t key_size, const uint32_t value_size, const void *const key, const void *const value) { Q_assert(map->key_size == key_size); Q_assert(map->value_size == value_size); @@ -182,7 +182,7 @@ qboolean HashMap_InsertImpl(hash_map_t *map, const uint32_t key_size, const uint HashMap_EraseImpl ================= */ -qboolean HashMap_EraseImpl(hash_map_t *map, const uint32_t key_size, const void *const key) +bool HashMap_EraseImpl(hash_map_t *map, const uint32_t key_size, const void *const key) { Q_assert(key_size == map->key_size); if (map->num_entries == 0) @@ -217,7 +217,7 @@ qboolean HashMap_EraseImpl(hash_map_t *map, const uint32_t key_size, const void if (map->hash_to_index[last_hash_index] == last_index) map->hash_to_index[last_hash_index] = map->index_chain[last_index]; else { - qboolean found = false; + bool found = false; for (uint32_t last_storage_index = map->hash_to_index[last_hash_index]; last_storage_index != UINT32_MAX; last_storage_index = map->index_chain[last_storage_index]) { if (map->index_chain[last_storage_index] == last_index) { From 876673b9eb3a8291b829209700a27596b0c66831 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 20 Nov 2023 16:25:03 +0300 Subject: [PATCH 038/167] List images that have glowmaps. --- src/refresh/images.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/refresh/images.c b/src/refresh/images.c index 076c4738e..285b0131a 100644 --- a/src/refresh/images.c +++ b/src/refresh/images.c @@ -1411,6 +1411,7 @@ static void IMG_List_f(void) "\nFlags legend:\n" "T: transparent\n" "S: scrap\n" + "G: glowmap\n" "*: permanent\n" ); return; @@ -1438,7 +1439,7 @@ static void IMG_List_f(void) Com_Printf("%c%c%c%c %4i %4i %s: %s\n", types[image->type > IT_MAX ? IT_MAX : image->type], (image->flags & IF_TRANSPARENT) ? 'T' : ' ', - (image->flags & IF_SCRAP) ? 'S' : ' ', + (image->flags & IF_SCRAP) ? 'S' : image->glow_texnum ? 'G' : ' ', (image->flags & IF_PERMANENT) ? '*' : ' ', image->upload_width, image->upload_height, From c9f74f7cd8788a91dcd7f6458d454f208afac77f Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 20 Nov 2023 16:25:41 +0300 Subject: [PATCH 039/167] List models that have MD5 replacements. --- src/refresh/models.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/refresh/models.c b/src/refresh/models.c index 925f65617..393d3a73f 100644 --- a/src/refresh/models.c +++ b/src/refresh/models.c @@ -89,11 +89,15 @@ static void MOD_List_f(void) continue; } size_t model_size = model->hunk.mapped; + int flag = ' '; #if USE_MD5 - model_size += model->skeleton_hunk.mapped; + if (model->skeleton) { + model_size += model->skeleton_hunk.mapped; + flag = '*'; + } #endif - Com_Printf("%c %8zu : %s\n", types[model->type], - model_size, model->name); + Com_Printf("%c%c %8zu : %s\n", types[model->type], + flag, model_size, model->name); bytes += model_size; count++; } From 39c488d9588fb2223dd64a03cb18a15e2e99674e Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 20 Nov 2023 19:49:05 +0300 Subject: [PATCH 040/167] Make Win32 pthread wrapper symbols static. Should avoid linking issues if some other library defines these symbols as reported in #336. Also simplify wrapper to avoid having global thread list. --- inc/system/pthread.h | 38 +++++++++++++--- src/windows/meson.build | 2 +- src/windows/pthread.c | 96 ----------------------------------------- 3 files changed, 33 insertions(+), 103 deletions(-) delete mode 100644 src/windows/pthread.c diff --git a/inc/system/pthread.h b/inc/system/pthread.h index 62b88e524..bb6fc18e7 100644 --- a/inc/system/pthread.h +++ b/inc/system/pthread.h @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define WIN32_LEAN_AND_MEAN #include +#include #include #define PTHREAD_MUTEX_INITIALIZER {0} @@ -30,7 +31,6 @@ with this program; if not, write to the Free Software Foundation, Inc., typedef void pthread_attr_t; typedef void pthread_mutexattr_t; typedef void pthread_condattr_t; -typedef unsigned int pthread_t; typedef struct { SRWLOCK srw; @@ -40,6 +40,37 @@ typedef struct { CONDITION_VARIABLE cond; } pthread_cond_t; +typedef struct { + void *(*func)(void *); + void *arg, *ret; + HANDLE handle; +} pthread_t; + +static unsigned __stdcall thread_func(void *arg) +{ + pthread_t *t = arg; + t->ret = t->func(t->arg); + return 0; +} + +static inline int pthread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg) +{ + thread->func = start_routine; + thread->arg = arg; + thread->handle = (HANDLE)_beginthreadex(NULL, 0, thread_func, thread, 0, NULL); + return thread->handle ? 0 : EAGAIN; +} + +static inline int pthread_join(pthread_t thread, void **retval) +{ + int ret = WaitForSingleObject(thread.handle, INFINITE); + CloseHandle(thread.handle); + if (retval) + *retval = thread.ret; + return ret ? EINVAL : 0; +} + static inline int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr) { InitializeSRWLock(&mutex->srw); @@ -90,11 +121,6 @@ static inline int pthread_cond_destroy(pthread_cond_t *cond) return 0; } -int pthread_create(pthread_t *thread, const pthread_attr_t *attr, - void *(*start_routine)(void *), void *arg); - -int pthread_join(pthread_t thread, void **retval); - #else #include #endif diff --git a/src/windows/meson.build b/src/windows/meson.build index d82ed2ad3..659cd5c5c 100644 --- a/src/windows/meson.build +++ b/src/windows/meson.build @@ -1,7 +1,7 @@ windows = import('windows') common_src += files('system.c', 'hunk.c') -client_src += files('client.c', 'wgl.c', 'pthread.c') +client_src += files('client.c', 'wgl.c') common_deps += cc.find_library('ws2_32') client_deps += cc.find_library('opengl32') diff --git a/src/windows/pthread.c b/src/windows/pthread.c deleted file mode 100644 index 4e4b5a8cf..000000000 --- a/src/windows/pthread.c +++ /dev/null @@ -1,96 +0,0 @@ -/* -Copyright (C) 2023 Andrey Nazarov - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#include "client.h" -#include "shared/list.h" -#include "system/pthread.h" -#include - -typedef struct { - list_t entry; - void *(*func)(void *); - void *arg, *ret; - HANDLE handle; - DWORD id; -} winthread_t; - -static LIST_DECL(threads); -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - -static winthread_t *find_thread(pthread_t thread) -{ - winthread_t *t; - - LIST_FOR_EACH(winthread_t, t, &threads, entry) - if (t->id == thread) - return t; - - return NULL; -} - -static unsigned __stdcall thread_func(void *arg) -{ - winthread_t *t = arg; - t->ret = t->func(t->arg); - return 0; -} - -int pthread_create(pthread_t *thread, const pthread_attr_t *attr, - void *(*start_routine)(void *), void *arg) -{ - int ret = 0; - pthread_mutex_lock(&mutex); - winthread_t *t = malloc(sizeof(*t)); - if (!t) { - ret = EAGAIN; - goto done; - } - t->func = start_routine; - t->arg = arg; - t->handle = (HANDLE)_beginthreadex(NULL, 0, thread_func, t, 0, thread); - if (!t->handle) { - free(t); - ret = EAGAIN; - goto done; - } - t->id = *thread; - List_Append(&threads, &t->entry); -done: - pthread_mutex_unlock(&mutex); - return ret; -} - -int pthread_join(pthread_t thread, void **retval) -{ - int ret = 0; - pthread_mutex_lock(&mutex); - winthread_t *t = find_thread(thread); - if (!t) { - ret = ESRCH; - goto done; - } - WaitForSingleObject(t->handle, INFINITE); - CloseHandle(t->handle); - List_Remove(&t->entry); - if (retval) - *retval = t->ret; - free(t); -done: - pthread_mutex_unlock(&mutex); - return ret; -} From e567bd8a0b70e1ff5180835ba57792592f86bdf1 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 20 Nov 2023 19:55:47 +0300 Subject: [PATCH 041/167] Add Meson 1.3.0 warning workaround. When building with MSVC, Meson 1.3.0 now complains that c_std=gnu99 isn't supported. Switch to gnu11 and add a fallback to c11 for MSVC. Multiple c_std values only work with Meson >= 1.3.0 so make this conditional on Meson version. --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index cc0dfb567..a2dac92a1 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,7 @@ project('q2pro', 'c', version: run_command(find_program('python3'), 'version.py', check: true).stdout().strip(), meson_version: '>= 0.59.0', default_options: [ - 'c_std=gnu99', + meson.version().version_compare('>=1.3.0') ? 'c_std=gnu11,c11' : 'c_std=gnu11', 'buildtype=debugoptimized', ], ) From 31f26e04b4a7ca72e391eda36817d1daa465dd30 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 24 Nov 2023 17:54:57 +0300 Subject: [PATCH 042/167] Remove unused prototypes. --- src/client/client.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index c81c0752f..6802db029 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -872,7 +872,6 @@ void CL_TeleportParticles(const vec3_t org); void CL_ParticleEffect(const vec3_t org, const vec3_t dir, int color, int count); void CL_ParticleEffect2(const vec3_t org, const vec3_t dir, int color, int count); cparticle_t *CL_AllocParticle(void); -void CL_RunParticles(void); void CL_AddParticles(void); cdlight_t *CL_AllocDlight(int key); void CL_AddDLights(void); @@ -978,12 +977,9 @@ extern vrect_t scr_vrect; // position of render window void SCR_Init(void); void SCR_Shutdown(void); void SCR_UpdateScreen(void); -void SCR_SizeUp(void); -void SCR_SizeDown(void); void SCR_CenterPrint(const char *str); void SCR_BeginLoadingPlaque(void); void SCR_EndLoadingPlaque(void); -void SCR_TouchPics(void); void SCR_RegisterMedia(void); void SCR_ModeChanged(void); void SCR_LagSample(void); From 8583bbacec4581e8b6d7798dcb2d29df0fa6bde3 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 24 Nov 2023 17:55:23 +0300 Subject: [PATCH 043/167] Fix typo. --- src/common/cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/cmd.c b/src/common/cmd.c index 509c457e3..9720ec749 100644 --- a/src/common/cmd.c +++ b/src/common/cmd.c @@ -1752,7 +1752,7 @@ static char *unescape_string(char *dst, const char *src) src += 2; break; default: - if (src[0] >= '0' && src[1] <= '7') { + if (src[1] >= '0' && src[1] <= '7') { *p++ = strtoul(&src[1], (char **)&src, 8); src -= 2; } else { From aff9aa80d2206732998f0137da5cf939496d3843 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 24 Nov 2023 17:56:06 +0300 Subject: [PATCH 044/167] Convert MSG_* flags to BIT() macro. --- src/server/server.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/server/server.h b/src/server/server.h index f3cb336f9..1bc6151da 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -213,10 +213,10 @@ typedef enum { #define MSG_POOLSIZE 1024 #define MSG_TRESHOLD (62 - sizeof(list_t)) // keep message_packet_t 64 bytes aligned -#define MSG_RELIABLE 1 -#define MSG_CLEAR 2 -#define MSG_COMPRESS 4 -#define MSG_COMPRESS_AUTO 8 +#define MSG_RELIABLE BIT(0) +#define MSG_CLEAR BIT(1) +#define MSG_COMPRESS BIT(2) +#define MSG_COMPRESS_AUTO BIT(3) #define ZPACKET_HEADER 5 From 54809f7804ad86ee651bd6d1b0d8a4d71c5ea8d8 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 25 Nov 2023 13:32:17 +0300 Subject: [PATCH 045/167] =?UTF-8?q?Refuse=20downloading=20to=20=E2=80=98sa?= =?UTF-8?q?ve=E2=80=99=20directory.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/client/download.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/client/download.c b/src/client/download.c index 7491487cc..5663005e1 100644 --- a/src/client/download.c +++ b/src/client/download.c @@ -98,6 +98,8 @@ bool CL_IgnoreDownload(const char *path) { string_entry_t *entry; + if (!strncmp(path, CONST_STR_LEN("save/"))) + return true; if (!strncmp(path, CONST_STR_LEN("music/"))) return true; if (!strncmp(path, CONST_STR_LEN("video/"))) From 4e25d995cb088760842d38e1a0e586f1305b9960 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 25 Nov 2023 17:02:44 +0300 Subject: [PATCH 046/167] Add Z_ReallocArray(). Use it to safeguard hash map allocations against integer overflow. --- inc/common/zone.h | 1 + src/common/hash_map.c | 10 +++++----- src/common/zone.c | 6 ++++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/inc/common/zone.h b/inc/common/zone.h index 703e73009..443a5efc2 100644 --- a/inc/common/zone.h +++ b/inc/common/zone.h @@ -45,6 +45,7 @@ void Z_Init(void); void Z_Free(void *ptr); void Z_Freep(void *ptr); void *Z_Realloc(void *ptr, size_t size); +void *Z_ReallocArray(void *ptr, size_t nmemb, size_t size); void *Z_Malloc(size_t size) q_malloc; void *Z_Mallocz(size_t size) q_malloc; void *Z_TagMalloc(size_t size, memtag_t tag) q_malloc; diff --git a/src/common/hash_map.c b/src/common/hash_map.c index caa6d0ec8..6911744b9 100644 --- a/src/common/hash_map.c +++ b/src/common/hash_map.c @@ -69,7 +69,7 @@ static void HashMap_Rehash(hash_map_t *map, const uint32_t new_size) if (map->hash_size >= new_size) return; map->hash_size = new_size; - map->hash_to_index = Z_Realloc(map->hash_to_index, map->hash_size * sizeof(uint32_t)); + map->hash_to_index = Z_ReallocArray(map->hash_to_index, map->hash_size, sizeof(uint32_t)); memset(map->hash_to_index, 0xFF, map->hash_size * sizeof(uint32_t)); for (uint32_t i = 0; i < map->num_entries; ++i) { void *key = HashMap_GetKeyImpl(map, i); @@ -87,9 +87,9 @@ HashMap_ExpandKeyValueStorage */ static void HashMap_ExpandKeyValueStorage(hash_map_t *map, const uint32_t new_size) { - map->keys = Z_Realloc(map->keys, new_size * map->key_size); - map->values = Z_Realloc(map->values, new_size * map->value_size); - map->index_chain = Z_Realloc(map->index_chain, new_size * sizeof(uint32_t)); + map->keys = Z_ReallocArray(map->keys, new_size, map->key_size); + map->values = Z_ReallocArray(map->values, new_size, map->value_size); + map->index_chain = Z_ReallocArray(map->index_chain, new_size, sizeof(uint32_t)); map->key_value_storage_size = new_size; } @@ -102,7 +102,7 @@ hash_map_t *HashMap_CreateImpl(const uint32_t key_size, const uint32_t value_siz uint32_t (*hasher)(const void *const), bool (*comp)(const void *const, const void *const)) { - hash_map_t *map = Z_Mallocz(sizeof(hash_map_t)); + hash_map_t *map = Z_Mallocz(sizeof(*map)); map->key_size = key_size; map->value_size = value_size; map->hasher = hasher; diff --git a/src/common/zone.c b/src/common/zone.c index 9addeb5ff..e5f941fb7 100644 --- a/src/common/zone.c +++ b/src/common/zone.c @@ -197,6 +197,12 @@ void *Z_Realloc(void *ptr, size_t size) return z + 1; } +void *Z_ReallocArray(void *ptr, size_t nmemb, size_t size) +{ + Q_assert(!size || nmemb <= INT_MAX / size); + return Z_Realloc(ptr, nmemb * size); +} + /* ======================== Z_Stats_f From 7cf1ed1cd18352fbcdaddc27d78ff25d16a6f817 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 25 Nov 2023 21:05:03 +0300 Subject: [PATCH 047/167] Discard raw texture data when stopping cinematic. --- src/client/cin.c | 3 +++ src/client/ffcin.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/client/cin.c b/src/client/cin.c index dd152263a..82fe354d5 100644 --- a/src/client/cin.c +++ b/src/client/cin.c @@ -73,6 +73,9 @@ SCR_StopCinematic */ void SCR_StopCinematic(void) { + if (cin.pic) + R_UpdateRawPic(0, 0, NULL); + Z_Free(cin.pic); FS_CloseFile(cin.file); memset(&cin, 0, sizeof(cin)); diff --git a/src/client/ffcin.c b/src/client/ffcin.c index b08fc4e60..85c81e0e8 100644 --- a/src/client/ffcin.c +++ b/src/client/ffcin.c @@ -104,6 +104,9 @@ SCR_StopCinematic */ void SCR_StopCinematic(void) { + if (cin.video.frame) + R_UpdateRawPic(0, 0, NULL); + avcodec_free_context(&cin.video.dec_ctx); avcodec_free_context(&cin.audio.dec_ctx); From 42cd25f7d04ae53721f9e2dd8af9dbefd8b3ec79 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 25 Nov 2023 21:55:26 +0300 Subject: [PATCH 048/167] Fix decoding last frame in OGG_Load(). Last frame can be longer than remaining duration and needs to be truncated. --- src/client/sound/ogg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/sound/ogg.c b/src/client/sound/ogg.c index 1e6e98565..feed112a2 100644 --- a/src/client/sound/ogg.c +++ b/src/client/sound/ogg.c @@ -628,8 +628,8 @@ bool OGG_Load(sizebuf_t *sz) int size = out->nb_samples << out->ch_layout.nb_channels; if (size > bufsize - offset) { - ret = AVERROR(ENOSPC); - break; + size = bufsize - offset; + eof = true; } memcpy(s_info.data + offset, out->data[0], size); From 00019b834bd6065ea00bc94ab83a846809abaff4 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 26 Nov 2023 00:39:16 +0300 Subject: [PATCH 049/167] Fix crash when resampling too long WAV file. DMA resampler can't handle more than 2^23-1 input samples, make this a hard limit for WAV. --- src/client/sound/dma.c | 2 ++ src/client/sound/mem.c | 4 ++-- src/client/sound/sound.h | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/client/sound/dma.c b/src/client/sound/dma.c index f7c679edb..5d13e1824 100644 --- a/src/client/sound/dma.c +++ b/src/client/sound/dma.c @@ -72,6 +72,8 @@ static sfxcache_t *DMA_UploadSfx(sfx_t *sfx) sc->channels = s_info.channels; sc->size = size; + Q_assert(stepscale == 1 || s_info.samples <= MAX_SFX_SAMPLES); + // resample / decimate to the current source rate if (stepscale == 1) // fast special case memcpy(sc->data, s_info.data, size); diff --git a/src/client/sound/mem.c b/src/client/sound/mem.c index 59c1e55cb..b6d93705a 100644 --- a/src/client/sound/mem.c +++ b/src/client/sound/mem.c @@ -135,8 +135,8 @@ static bool GetWavinfo(sizebuf_t *sz) // calculate length in samples s_info.samples = chunk_len / (s_info.width * s_info.channels); - if (!s_info.samples) { - Com_DPrintf("%s has zero length\n", s_info.name); + if (s_info.samples < 1 || s_info.samples > MAX_SFX_SAMPLES) { + Com_DPrintf("%s has bad number of samples\n", s_info.name); return false; } diff --git a/src/client/sound/sound.h b/src/client/sound/sound.h index c834145c4..a64186ab0 100644 --- a/src/client/sound/sound.h +++ b/src/client/sound/sound.h @@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/sound/dma.h" #endif +#define MAX_SFX_SAMPLES ((1 << 23) - 1) + typedef struct sfxcache_s { int length; int loopstart; From 7577ceef461d5e6bab235bb24412faf37d4e0b3c Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 26 Nov 2023 00:55:18 +0300 Subject: [PATCH 050/167] Optimize sfx resampling for big-endian. --- src/client/sound/dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/sound/dma.c b/src/client/sound/dma.c index 5d13e1824..65f551d5e 100644 --- a/src/client/sound/dma.c +++ b/src/client/sound/dma.c @@ -80,7 +80,7 @@ static sfxcache_t *DMA_UploadSfx(sfx_t *sfx) else if (sc->width == 1 && sc->channels == 1) RESAMPLE sc->data[i] = s_info.data[j]; else if (sc->width == 2 && sc->channels == 2) - RESAMPLE WL32(sc->data + i * 4, RL32(s_info.data + j * 4)); + RESAMPLE memcpy(sc->data + i * 4, s_info.data + j * 4, 4); else RESAMPLE ((uint16_t *)sc->data)[i] = ((uint16_t *)s_info.data)[j]; From 385d89cc4c65e6962748d3b23d37e625cce55a3d Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 26 Nov 2023 01:10:11 +0300 Subject: [PATCH 051/167] Show MD5 feature if enabled. --- src/common/features.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/common/features.h b/src/common/features.h index 2c568ad9b..abc00b839 100644 --- a/src/common/features.h +++ b/src/common/features.h @@ -55,6 +55,9 @@ static const char *Com_GetFeatures(void) #if USE_MD3 "md3 " #endif +#if USE_MD5 + "md5 " +#endif #if USE_MVD_CLIENT "mvd-client " #endif From b9c1b66c18938f869c917af70ba92ac7eb13a871 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 26 Nov 2023 01:16:05 +0300 Subject: [PATCH 052/167] Limit OGG files to MAX_SFX_SAMPLES for symmetry with WAV. --- src/client/sound/ogg.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/client/sound/ogg.c b/src/client/sound/ogg.c index feed112a2..28d5a4323 100644 --- a/src/client/sound/ogg.c +++ b/src/client/sound/ogg.c @@ -527,7 +527,7 @@ bool OGG_Load(sizebuf_t *sz) goto fail; } - if (st->duration < 1 || st->duration > MAX_LOADFILE >> st->codecpar->ch_layout.nb_channels) { + if (st->duration < 1 || st->duration > MAX_SFX_SAMPLES) { Com_DPrintf("%s has bad number of samples\n", s_info.name); goto fail; } @@ -584,10 +584,7 @@ bool OGG_Load(sizebuf_t *sz) if (out->sample_rate != dec_ctx->sample_rate) { nb_samples = av_rescale_rnd(st->duration + 2, out->sample_rate, dec_ctx->sample_rate, AV_ROUND_UP) + 2; - if (nb_samples > MAX_LOADFILE >> out->ch_layout.nb_channels) { - Com_DPrintf("Too many samples after resampling\n"); - goto fail; - } + Q_assert(nb_samples <= INT_MAX >> out->ch_layout.nb_channels); } int bufsize = nb_samples << out->ch_layout.nb_channels; From c8e84a770d2a657bb7e92bba88506ac2a29d12bc Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 27 Nov 2023 20:04:34 +0300 Subject: [PATCH 053/167] =?UTF-8?q?Fix=20=E2=80=98ogg=20info=E2=80=99=20di?= =?UTF-8?q?splay.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Show source sample rate and number of channels. Skip path which can be too long. --- src/client/sound/ogg.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/client/sound/ogg.c b/src/client/sound/ogg.c index 28d5a4323..20c75b1e6 100644 --- a/src/client/sound/ogg.c +++ b/src/client/sound/ogg.c @@ -691,12 +691,12 @@ static void OGG_Play_f(void) static void OGG_Info_f(void) { - AVFrame *out = ogg.frame_out; + AVCodecContext *dec = ogg.dec_ctx; - if (out) { + if (dec) { Com_Printf("Playing %s, %s, %d Hz, %d ch\n", - ogg.fmt_ctx->url, ogg.dec_ctx->codec->name, - out->sample_rate, out->ch_layout.nb_channels); + COM_SkipPath(ogg.fmt_ctx->url), dec->codec->name, + dec->sample_rate, dec->ch_layout.nb_channels); } else { Com_Printf("Playback stopped.\n"); } From f895a5f798bade3c384db93c776825593df07789 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 27 Nov 2023 21:13:58 +0300 Subject: [PATCH 054/167] Use entity radius for tracker shell and power splash effects. Also fix tracker shell to use current lerp origin rather than from previous frame. --- src/client/client.h | 3 ++- src/client/entities.c | 11 ++++++----- src/client/newfx.c | 18 ++++++++++++++---- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index 6802db029..db12b6318 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -75,6 +75,7 @@ typedef struct centity_s { centity_state_t prev; // will always be valid, but might just be a copy of current vec3_t mins, maxs; + float radius; // from mid point int serverframe; // if not current, this ent isn't in the frame @@ -893,7 +894,7 @@ void CL_ParticleSteamEffect(const vec3_t org, const vec3_t dir, int color, int c void CL_TrackerTrail(const vec3_t start, const vec3_t end, int particleColor); void CL_TagTrail(const vec3_t start, const vec3_t end, int color); void CL_ColorFlash(const vec3_t pos, int ent, int intensity, float r, float g, float b); -void CL_Tracker_Shell(const vec3_t origin); +void CL_Tracker_Shell(const centity_t *cent, const vec3_t origin); void CL_MonsterPlasma_Shell(const vec3_t origin); void CL_ColorExplosionParticles(const vec3_t org, int color, int run); void CL_ParticleSmokeEffect(const vec3_t org, const vec3_t dir, int color, int count, int magnitude); diff --git a/src/client/entities.c b/src/client/entities.c index 9d9c85232..cb6d143f2 100644 --- a/src/client/entities.c +++ b/src/client/entities.c @@ -157,9 +157,11 @@ static void parse_entity_update(const centity_state_t *state) MSG_UnpackSolid32_Ver1(state->solid, ent->mins, ent->maxs); else MSG_UnpackSolid16(state->solid, ent->mins, ent->maxs); + ent->radius = Distance(ent->maxs, ent->mins) * 0.5f; } else { VectorClear(ent->mins); VectorClear(ent->maxs); + ent->radius = 0; } // work around Q2PRO server bandwidth optimization @@ -906,14 +908,13 @@ static void CL_AddPacketEntities(void) // remaster powerscreen is tiny and needs scaling if (cl.need_powerscreen_scale) { - vec3_t forward, mid, size, tmp; + vec3_t forward, mid, tmp; VectorCopy(ent.origin, tmp); - VectorSubtract(cent->maxs, cent->mins, size); VectorAvg(cent->mins, cent->maxs, mid); VectorAdd(ent.origin, mid, ent.origin); AngleVectors(ent.angles, forward, NULL, NULL); - VectorMA(ent.origin, size[1] * 0.5f, forward, ent.origin); - ent.scale = VectorLength(size) * 0.4f; + VectorMA(ent.origin, cent->maxs[1], forward, ent.origin); + ent.scale = cent->radius * 0.8f; ent.flags |= RF_FULLBRIGHT; V_AddEntity(&ent); VectorCopy(tmp, ent.origin); @@ -985,7 +986,7 @@ static void CL_AddPacketEntities(void) float intensity = 50 + (500 * (sin(cl.time / 500.0f) + 1.0f)); V_AddLight(ent.origin, intensity, -1.0f, -1.0f, -1.0f); } else { - CL_Tracker_Shell(cent->lerp_origin); + CL_Tracker_Shell(cent, ent.origin); V_AddLight(ent.origin, 155, -1.0f, -1.0f, -1.0f); } } else if (effects & EF_TRACKER) { diff --git a/src/client/newfx.c b/src/client/newfx.c index 4842c31bb..08d03bd8a 100644 --- a/src/client/newfx.c +++ b/src/client/newfx.c @@ -343,11 +343,21 @@ void CL_TrackerTrail(const vec3_t start, const vec3_t end, int particleColor) } } -void CL_Tracker_Shell(const vec3_t origin) +void CL_Tracker_Shell(const centity_t *ent, const vec3_t origin) { - vec3_t dir; + vec3_t org, dir, mid; int i; cparticle_t *p; + float radius; + + if (cl.csr.extended) { + VectorAvg(ent->mins, ent->maxs, mid); + VectorAdd(origin, mid, org); + radius = ent->radius; + } else { + VectorCopy(origin, org); + radius = 40.0f; + } for (i = 0; i < 300; i++) { p = CL_AllocParticle(); @@ -366,7 +376,7 @@ void CL_Tracker_Shell(const vec3_t origin) dir[2] = crand(); VectorNormalize(dir); - VectorMA(origin, 40, dir, p->org); + VectorMA(org, radius, dir, p->org); } } @@ -944,7 +954,7 @@ void CL_PowerSplash(void) dir[1] = crand(); dir[2] = crand(); VectorNormalize(dir); - VectorMA(org, 45.0f, dir, p->org); + VectorMA(org, ent->radius, dir, p->org); VectorScale(dir, 40.0f, p->vel); VectorClear(p->accel); From a851181aa2ffbe90a969aa276a488544319480a5 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 29 Nov 2023 22:43:38 +0300 Subject: [PATCH 055/167] Fix wrong axis. --- src/client/entities.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/entities.c b/src/client/entities.c index cb6d143f2..e762f77fc 100644 --- a/src/client/entities.c +++ b/src/client/entities.c @@ -913,7 +913,7 @@ static void CL_AddPacketEntities(void) VectorAvg(cent->mins, cent->maxs, mid); VectorAdd(ent.origin, mid, ent.origin); AngleVectors(ent.angles, forward, NULL, NULL); - VectorMA(ent.origin, cent->maxs[1], forward, ent.origin); + VectorMA(ent.origin, cent->maxs[0], forward, ent.origin); ent.scale = cent->radius * 0.8f; ent.flags |= RF_FULLBRIGHT; V_AddEntity(&ent); From 55d29784ea949ddff57e860fc726979ae98a69f2 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 29 Nov 2023 22:45:04 +0300 Subject: [PATCH 056/167] =?UTF-8?q?Allow=20more=20fine-grained=20=E2=80=98?= =?UTF-8?q?gl=5Fshowtris=E2=80=99=20control.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/refresh/mesh.c | 2 +- src/refresh/tess.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/refresh/mesh.c b/src/refresh/mesh.c index 8ef6d97f3..af8480b26 100644 --- a/src/refresh/mesh.c +++ b/src/refresh/mesh.c @@ -603,7 +603,7 @@ static void end_alias_mesh(const QGL_INDEX_TYPE *indices, int num_indices, draw_celshading(indices, num_indices); - if (gl_showtris->integer) { + if (gl_showtris->integer & BIT(1)) { GL_DrawOutlines(num_indices, indices); } diff --git a/src/refresh/tess.c b/src/refresh/tess.c index 2784ecdca..33e08a639 100644 --- a/src/refresh/tess.c +++ b/src/refresh/tess.c @@ -57,7 +57,7 @@ void GL_Flush2D(void) qglDrawElements(GL_TRIANGLES, tess.numindices, QGL_INDEX_ENUM, tess.indices); - if (gl_showtris->integer > 1) { + if (gl_showtris->integer & BIT(2)) { GL_DrawOutlines(tess.numindices, tess.indices); } @@ -147,7 +147,7 @@ void GL_DrawParticles(void) qglDrawArrays(GL_TRIANGLES, 0, numverts); - if (gl_showtris->integer) { + if (gl_showtris->integer & BIT(2)) { GL_DrawOutlines(numverts, NULL); } } while (total); @@ -374,7 +374,7 @@ void GL_Flush3D(void) qglDrawElements(GL_TRIANGLES, tess.numindices, QGL_INDEX_ENUM, tess.indices); - if (gl_showtris->integer) { + if (gl_showtris->integer & BIT(0)) { GL_DrawOutlines(tess.numindices, tess.indices); } From 3ab33941830790bae1803b6ed2c758e9d359edb7 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 29 Nov 2023 22:51:21 +0300 Subject: [PATCH 057/167] Merge begin_/end_alias_mesh(). --- src/refresh/mesh.c | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/src/refresh/mesh.c b/src/refresh/mesh.c index af8480b26..eda096f49 100644 --- a/src/refresh/mesh.c +++ b/src/refresh/mesh.c @@ -18,8 +18,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "gl.h" -typedef void (*tessfunc_t)(const maliasmesh_t *); - static int oldframenum; static int newframenum; static float frontlerp; @@ -29,7 +27,6 @@ static vec3_t oldscale; static vec3_t newscale; static vec3_t translate; static vec_t shellscale; -static tessfunc_t tessfunc; static vec4_t color; static vec3_t shadedir; @@ -553,7 +550,9 @@ static image_t *skin_for_mesh(image_t **skins, int num_skins) return skins[ent->skinnum]; } -static void begin_alias_mesh(image_t **skins, int num_skins) +static void draw_alias_mesh(const QGL_INDEX_TYPE *indices, int num_indices, + const maliastc_t *tcoords, int num_verts, + image_t **skins, int num_skins) { glStateBits_t state = GLS_INTENSITY_ENABLE; image_t *skin = skin_for_mesh(skins, num_skins); @@ -579,11 +578,7 @@ static void begin_alias_mesh(image_t **skins, int num_skins) if (skin->glow_texnum) GL_BindTexture(2, skin->glow_texnum); -} -static void end_alias_mesh(const QGL_INDEX_TYPE *indices, int num_indices, - const maliastc_t *tcoords, int num_verts) -{ if (dotshading) { GL_ArrayBits(GLA_VERTEX | GLA_TC | GLA_COLOR); GL_VertexPointer(3, VERTEX_SIZE, tess.vertices); @@ -613,16 +608,6 @@ static void end_alias_mesh(const QGL_INDEX_TYPE *indices, int num_indices, GL_UnlockArrays(); } -static void draw_alias_mesh(const maliasmesh_t *mesh) -{ - begin_alias_mesh(mesh->skins, mesh->numskins); - - (*tessfunc)(mesh); - - end_alias_mesh(mesh->indices, mesh->numindices, - mesh->tcoords, mesh->numverts); -} - #if USE_MD5 // for the given vertex, set of weights & skeleton, calculate @@ -710,8 +695,6 @@ static void lerp_alias_skeleton(const md5_model_t *model) static void draw_skeleton_mesh(const md5_model_t *model, const md5_mesh_t *mesh, const md5_joint_t *skel) { - begin_alias_mesh(model->skins, model->num_skins); - if (glr.ent->flags & RF_SHELL_MASK) tess_shell_skel(mesh, skel); else if (dotshading) @@ -719,7 +702,9 @@ static void draw_skeleton_mesh(const md5_model_t *model, const md5_mesh_t *mesh, else tess_plain_skel(mesh, skel); - end_alias_mesh(mesh->indices, mesh->num_indices, mesh->tcoords, mesh->num_verts); + draw_alias_mesh(mesh->indices, mesh->num_indices, + mesh->tcoords, mesh->num_verts, + model->skins, model->num_skins); } static void draw_alias_skeleton(const md5_model_t *model) @@ -773,6 +758,7 @@ void GL_DrawAliasModel(const model_t *model) { const entity_t *ent = glr.ent; glCullResult_t cull; + void (*tessfunc)(const maliasmesh_t *); int i; newframenum = ent->frame; @@ -838,8 +824,13 @@ void GL_DrawAliasModel(const model_t *model) draw_alias_skeleton(model->skeleton); else #endif - for (i = 0; i < model->nummeshes; i++) - draw_alias_mesh(&model->meshes[i]); + for (i = 0; i < model->nummeshes; i++) { + const maliasmesh_t *mesh = &model->meshes[i]; + (*tessfunc)(mesh); + draw_alias_mesh(mesh->indices, mesh->numindices, + mesh->tcoords, mesh->numverts, + mesh->skins, mesh->numskins); + } if (ent->flags & RF_DEPTHHACK) GL_DepthRange(0, 1); From 87d28b42fe63412fe770db2c898c6b5b85019253 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 29 Nov 2023 23:25:03 +0300 Subject: [PATCH 058/167] Improve drawing transparent gun. Make shell effect on re-release MD5 models a bit less ugly by not drawing hidden faces. --- src/refresh/mesh.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/refresh/mesh.c b/src/refresh/mesh.c index eda096f49..da1e49356 100644 --- a/src/refresh/mesh.c +++ b/src/refresh/mesh.c @@ -556,18 +556,28 @@ static void draw_alias_mesh(const QGL_INDEX_TYPE *indices, int num_indices, { glStateBits_t state = GLS_INTENSITY_ENABLE; image_t *skin = skin_for_mesh(skins, num_skins); + bool is_alpha_gun = (glr.ent->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL | RF_FULLBRIGHT)) == (RF_TRANSLUCENT | RF_WEAPONMODEL); // fall back to entity matrix GL_LoadMatrix(glr.entmatrix); + // avoid drawing hidden faces for transparent gun + if (is_alpha_gun) { + GL_StateBits(GLS_DEFAULT); + GL_ArrayBits(GLA_VERTEX); + GL_BindTexture(0, TEXNUM_WHITE); + GL_VertexPointer(3, dotshading ? VERTEX_SIZE : 4, tess.vertices); + qglColorMask(0, 0, 0, 0); + qglDrawElements(GL_TRIANGLES, num_indices, QGL_INDEX_ENUM, indices); + qglColorMask(1, 1, 1, 1); + qglDepthFunc(GL_LEQUAL); + } + if (dotshading) state |= GLS_SHADE_SMOOTH; - if (glr.ent->flags & RF_TRANSLUCENT) { - state |= GLS_BLEND_BLEND; - if (!(glr.ent->flags & RF_WEAPONMODEL) || (glr.ent->flags & RF_FULLBRIGHT)) - state |= GLS_DEPTHMASK_FALSE; - } + if (glr.ent->flags & RF_TRANSLUCENT) + state |= GLS_BLEND_BLEND | GLS_DEPTHMASK_FALSE; if (skin->glow_texnum) state |= GLS_GLOWMAP_ENABLE; @@ -596,6 +606,9 @@ static void draw_alias_mesh(const QGL_INDEX_TYPE *indices, int num_indices, qglDrawElements(GL_TRIANGLES, num_indices, QGL_INDEX_ENUM, indices); c.trisDrawn += num_indices / 3; + if (is_alpha_gun) + qglDepthFunc(GL_LESS); + draw_celshading(indices, num_indices); if (gl_showtris->integer & BIT(1)) { From 5ccb2acc3d03c120fcc60b6315f918fc8382ffca Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 30 Nov 2023 01:01:51 +0300 Subject: [PATCH 059/167] Avoid depth func manipulation. It's already set to GL_LEQUAL by GL_ClearState(). --- src/refresh/mesh.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/refresh/mesh.c b/src/refresh/mesh.c index da1e49356..e3c6a9351 100644 --- a/src/refresh/mesh.c +++ b/src/refresh/mesh.c @@ -556,13 +556,12 @@ static void draw_alias_mesh(const QGL_INDEX_TYPE *indices, int num_indices, { glStateBits_t state = GLS_INTENSITY_ENABLE; image_t *skin = skin_for_mesh(skins, num_skins); - bool is_alpha_gun = (glr.ent->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL | RF_FULLBRIGHT)) == (RF_TRANSLUCENT | RF_WEAPONMODEL); // fall back to entity matrix GL_LoadMatrix(glr.entmatrix); // avoid drawing hidden faces for transparent gun - if (is_alpha_gun) { + if ((glr.ent->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL | RF_FULLBRIGHT)) == (RF_TRANSLUCENT | RF_WEAPONMODEL)) { GL_StateBits(GLS_DEFAULT); GL_ArrayBits(GLA_VERTEX); GL_BindTexture(0, TEXNUM_WHITE); @@ -570,7 +569,6 @@ static void draw_alias_mesh(const QGL_INDEX_TYPE *indices, int num_indices, qglColorMask(0, 0, 0, 0); qglDrawElements(GL_TRIANGLES, num_indices, QGL_INDEX_ENUM, indices); qglColorMask(1, 1, 1, 1); - qglDepthFunc(GL_LEQUAL); } if (dotshading) @@ -606,9 +604,6 @@ static void draw_alias_mesh(const QGL_INDEX_TYPE *indices, int num_indices, qglDrawElements(GL_TRIANGLES, num_indices, QGL_INDEX_ENUM, indices); c.trisDrawn += num_indices / 3; - if (is_alpha_gun) - qglDepthFunc(GL_LESS); - draw_celshading(indices, num_indices); if (gl_showtris->integer & BIT(1)) { From c2a1ef2f6f900bcd197535d2b8f9546ad713a1d5 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 1 Dec 2023 20:11:59 +0300 Subject: [PATCH 060/167] Simplify assert. --- src/client/download.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/client/download.c b/src/client/download.c index 5663005e1..6642b3783 100644 --- a/src/client/download.c +++ b/src/client/download.c @@ -316,8 +316,7 @@ static bool inflate_udp_download(byte *data, int size, int decompressed_size) int ret; // initialize stream if not done yet - if (!z->state) - Q_assert(inflateInit2(z, -MAX_WBITS) == Z_OK); + Q_assert(z->state || inflateInit2(z, -MAX_WBITS) == Z_OK); if (!size) return true; From f3d91209d59b33f9f962e271d82cf0fd79049dc6 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 2 Dec 2023 21:32:25 +0300 Subject: [PATCH 061/167] Fix UB if LM_MAX_LIGHTMAPS is exceeded. --- src/refresh/surf.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/refresh/surf.c b/src/refresh/surf.c index 457cc6b67..68beff608 100644 --- a/src/refresh/surf.c +++ b/src/refresh/surf.c @@ -309,13 +309,7 @@ LIGHTMAPS BUILDING static void LM_InitBlock(void) { - int i; - - for (i = 0; i < LM_BLOCK_WIDTH; i++) { - lm.inuse[i] = 0; - } - - lm.dirty = false; + memset(lm.inuse, 0, sizeof(lm.inuse)); } static void LM_UploadBlock(void) @@ -324,11 +318,15 @@ static void LM_UploadBlock(void) return; } - GL_ForceTexture(1, lm.texnums[lm.nummaps++]); + Q_assert(lm.nummaps < LM_MAX_LIGHTMAPS); + GL_ForceTexture(1, lm.texnums[lm.nummaps]); qglTexImage2D(GL_TEXTURE_2D, 0, lm.comp, LM_BLOCK_WIDTH, LM_BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lm.buffer); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + lm.nummaps++; + lm.dirty = false; } static void build_style_map(int dynamic) @@ -360,6 +358,7 @@ static void LM_BeginBuilding(void) // lightmap textures are not deleted from memory when changing maps, // they are merely reused lm.nummaps = 0; + lm.dirty = false; LM_InitBlock(); @@ -405,6 +404,9 @@ static void LM_BuildSurface(mface_t *surf, vec_t *vbo) { int smax, tmax, s, t; + if (lm.nummaps == LM_MAX_LIGHTMAPS) + return; // can't have any more + smax = surf->lm_width; tmax = surf->lm_height; From ddee7ffe09336d8ba2b3cf08a5bb431e779c9e26 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 2 Dec 2023 21:47:25 +0300 Subject: [PATCH 062/167] Make BSP face hashing always on. Lightmap batching will require it. --- src/refresh/gl.h | 2 -- src/refresh/main.c | 2 -- src/refresh/tess.c | 2 +- src/refresh/world.c | 18 ++++++++---------- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/refresh/gl.h b/src/refresh/gl.h index f1f9187d8..5f3b31d5c 100644 --- a/src/refresh/gl.h +++ b/src/refresh/gl.h @@ -222,7 +222,6 @@ extern cvar_t *gl_nobind; extern cvar_t *gl_test; #endif extern cvar_t *gl_cull_nodes; -extern cvar_t *gl_hash_faces; extern cvar_t *gl_clear; extern cvar_t *gl_novis; extern cvar_t *gl_lockpvs; @@ -666,7 +665,6 @@ void GL_DrawBeams(void); void GL_BindArrays(void); void GL_Flush3D(void); -void GL_DrawFace(mface_t *surf); void GL_AddAlphaFace(mface_t *face, entity_t *ent); void GL_AddSolidFace(mface_t *face); diff --git a/src/refresh/main.c b/src/refresh/main.c index c413c81e1..c13561f80 100644 --- a/src/refresh/main.c +++ b/src/refresh/main.c @@ -76,7 +76,6 @@ cvar_t *gl_cull_nodes; cvar_t *gl_cull_models; cvar_t *gl_clear; cvar_t *gl_finish; -cvar_t *gl_hash_faces; cvar_t *gl_novis; cvar_t *gl_lockpvs; cvar_t *gl_lightmap; @@ -936,7 +935,6 @@ static void GL_Register(void) #endif gl_cull_nodes = Cvar_Get("gl_cull_nodes", "1", 0); gl_cull_models = Cvar_Get("gl_cull_models", "1", 0); - gl_hash_faces = Cvar_Get("gl_hash_faces", "1", 0); gl_clear = Cvar_Get("gl_clear", "0", 0); gl_finish = Cvar_Get("gl_finish", "0", 0); gl_novis = Cvar_Get("gl_novis", "0", 0); diff --git a/src/refresh/tess.c b/src/refresh/tess.c index 33e08a639..4237c9a2f 100644 --- a/src/refresh/tess.c +++ b/src/refresh/tess.c @@ -422,7 +422,7 @@ static image_t *GL_TextureAnimation(mtexinfo_t *tex) return tex->image; } -void GL_DrawFace(mface_t *surf) +static void GL_DrawFace(mface_t *surf) { int numtris = surf->numsurfedges - 2; int numindices = numtris * 3; diff --git a/src/refresh/world.c b/src/refresh/world.c index 32cec395a..30737e4a2 100644 --- a/src/refresh/world.c +++ b/src/refresh/world.c @@ -481,6 +481,8 @@ void GL_DrawBspModel(mmodel_t *model) GL_BindArrays(); + GL_ClearSolidFaces(); + // draw visible faces last = model->firstface + model->numfaces; for (face = model->firstface; face < last; face++) { @@ -505,9 +507,11 @@ void GL_DrawBspModel(mmodel_t *model) continue; } - GL_DrawFace(face); + GL_AddSolidFace(face); } + GL_DrawSolidFaces(); + GL_Flush3D(); // protect against infinite loop if the same inline model @@ -591,11 +595,7 @@ static inline void GL_DrawNode(mnode_t *node) continue; } - if (gl_hash_faces->integer) { - GL_AddSolidFace(face); - } else { - GL_DrawFace(face); - } + GL_AddSolidFace(face); } c.nodesDrawn++; @@ -645,14 +645,12 @@ void GL_DrawWorld(void) GL_BindArrays(); - if (gl_hash_faces->integer) - GL_ClearSolidFaces(); + GL_ClearSolidFaces(); GL_WorldNode_r(gl_static.world.cache->nodes, gl_cull_nodes->integer ? NODE_CLIPPED : NODE_UNCLIPPED); - if (gl_hash_faces->integer) - GL_DrawSolidFaces(); + GL_DrawSolidFaces(); GL_Flush3D(); From 22aefb067ba4bad86c54bc9d06c1662a08b91891 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 2 Dec 2023 21:54:47 +0300 Subject: [PATCH 063/167] Batch lightmap updates. Attempt to crutch up inefficient drivers that can't handle lots of glTexSubImage2D() calls per frame. --- inc/common/bsp.h | 1 + src/refresh/gl.h | 17 +++-- src/refresh/qgl.c | 1 + src/refresh/qgl.h | 1 + src/refresh/surf.c | 148 ++++++++++++++++++++++++++++---------------- src/refresh/world.c | 8 +++ 6 files changed, 117 insertions(+), 59 deletions(-) diff --git a/inc/common/bsp.h b/inc/common/bsp.h index 19bd16dea..34b57bfb6 100644 --- a/inc/common/bsp.h +++ b/inc/common/bsp.h @@ -110,6 +110,7 @@ typedef struct mface_s { unsigned dlightframe; uint64_t dlightbits; + struct lightmap_s *light_m; struct entity_s *entity; struct mface_s *next; } mface_t; diff --git a/src/refresh/gl.h b/src/refresh/gl.h index 5f3b31d5c..b6942a397 100644 --- a/src/refresh/gl.h +++ b/src/refresh/gl.h @@ -407,24 +407,31 @@ qhandle_t R_RegisterModel(const char *name); #define LIGHT_STYLE(i) \ &glr.fd.lightstyles[gl_static.lightstylemap[(i)]] -#define LM_MAX_LIGHTMAPS 32 -#define LM_BLOCK_WIDTH 512 -#define LM_BLOCK_HEIGHT 512 +#define LM_MAX_LIGHTMAPS 128 +#define LM_BLOCK_WIDTH 256 +#define LM_BLOCK_HEIGHT 256 -typedef struct { - int inuse[LM_BLOCK_WIDTH]; +typedef struct lightmap_s { byte buffer[LM_BLOCK_WIDTH * LM_BLOCK_HEIGHT * 4]; + int mins[2]; + int maxs[2]; +} lightmap_t; + +typedef struct { bool dirty; int comp; float add, modulate, scale; int nummaps; + int inuse[LM_BLOCK_WIDTH]; GLuint texnums[LM_MAX_LIGHTMAPS]; + lightmap_t lightmaps[LM_MAX_LIGHTMAPS]; } lightmap_builder_t; extern lightmap_builder_t lm; void GL_AdjustColor(vec3_t color); void GL_PushLights(mface_t *surf); +void GL_UploadLightmaps(void); void GL_RebuildLighting(void); void GL_FreeWorld(void); diff --git a/src/refresh/qgl.c b/src/refresh/qgl.c index 8d85b8c01..008225779 100644 --- a/src/refresh/qgl.c +++ b/src/refresh/qgl.c @@ -65,6 +65,7 @@ static const glsection_t sections[] = { QGL_FN(GetString), QGL_FN(IsEnabled), QGL_FN(LineWidth), + QGL_FN(PixelStorei), QGL_FN(PolygonOffset), QGL_FN(ReadPixels), QGL_FN(Scissor), diff --git a/src/refresh/qgl.h b/src/refresh/qgl.h index 579ad04ab..7671ca4ca 100644 --- a/src/refresh/qgl.h +++ b/src/refresh/qgl.h @@ -62,6 +62,7 @@ QGLAPI void (APIENTRYP qglGetIntegerv)(GLenum pname, GLint *data); QGLAPI const GLubyte *(APIENTRYP qglGetString)(GLenum name); QGLAPI GLboolean (APIENTRYP qglIsEnabled)(GLenum cap); QGLAPI void (APIENTRYP qglLineWidth)(GLfloat width); +QGLAPI void (APIENTRYP qglPixelStorei)(GLenum pname, GLint param); QGLAPI void (APIENTRYP qglPolygonOffset)(GLfloat factor, GLfloat units); QGLAPI void (APIENTRYP qglReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); QGLAPI void (APIENTRYP qglScissor)(GLint x, GLint y, GLsizei width, GLsizei height); diff --git a/src/refresh/surf.c b/src/refresh/surf.c index 68beff608..316e71c81 100644 --- a/src/refresh/surf.c +++ b/src/refresh/surf.c @@ -94,16 +94,16 @@ DYNAMIC BLOCKLIGHTS ============================================================================= */ -#define MAX_SURFACE_EXTENTS 2048 -#define MAX_LIGHTMAP_EXTENTS ((MAX_SURFACE_EXTENTS >> 4) + 1) +#define MAX_LIGHTMAP_EXTENTS 256 #define MAX_BLOCKLIGHTS (MAX_LIGHTMAP_EXTENTS * MAX_LIGHTMAP_EXTENTS) static float blocklights[MAX_BLOCKLIGHTS * 3]; -static void put_blocklights(byte *out, int smax, int tmax, int stride) +static void put_blocklights(mface_t *surf) { float *bl, add, modulate, scale = lm.scale; - int i, j; + int i, j, smax, tmax; + byte *out; if (gl_static.use_shaders) { add = 0; @@ -113,7 +113,12 @@ static void put_blocklights(byte *out, int smax, int tmax, int stride) modulate = lm.modulate; } - for (i = 0, bl = blocklights; i < tmax; i++, out += stride) { + smax = surf->lm_width; + tmax = surf->lm_height; + + out = surf->light_m->buffer + (surf->light_t * LM_BLOCK_WIDTH + surf->light_s) * 4; + + for (i = 0, bl = blocklights; i < tmax; i++, out += LM_BLOCK_WIDTH * 4) { byte *dst; for (j = 0, dst = out; j < smax; j++, bl += 3, dst += 4) { vec3_t tmp; @@ -185,12 +190,12 @@ static void add_dynamic_lights(mface_t *surf) } } -static void add_light_styles(mface_t *surf, int size) +static void add_light_styles(mface_t *surf) { lightstyle_t *style; byte *src; float *bl; - int i, j; + int i, j, size = surf->lm_width * surf->lm_height; if (!surf->numstyles) { // should this ever happen? @@ -236,15 +241,10 @@ static void add_light_styles(mface_t *surf, int size) static void update_dynamic_lightmap(mface_t *surf) { - byte temp[MAX_BLOCKLIGHTS * 4]; - int smax, tmax, size; - - smax = surf->lm_width; - tmax = surf->lm_height; - size = smax * tmax; + int s0, t0, s1, t1; // add all the lightmaps - add_light_styles(surf, size); + add_light_styles(surf); // add all the dynamic lights if (surf->dlightframe == glr.dlightframe) { @@ -254,17 +254,25 @@ static void update_dynamic_lightmap(mface_t *surf) } // put into texture format - put_blocklights(temp, smax, tmax, smax * 4); + put_blocklights(surf); + + // add to dirty region + s0 = surf->light_s; + t0 = surf->light_t; - // upload lightmap subimage - GL_ForceTexture(1, surf->texnum[1]); - qglTexSubImage2D(GL_TEXTURE_2D, 0, - surf->light_s, surf->light_t, smax, tmax, - GL_RGBA, GL_UNSIGNED_BYTE, temp); + s1 = s0 + surf->lm_width; + t1 = t0 + surf->lm_height; - c.texUploads++; + lightmap_t *m = surf->light_m; + + m->mins[0] = min(m->mins[0], s0); + m->mins[1] = min(m->mins[1], t0); + + m->maxs[0] = max(m->maxs[0], s1); + m->maxs[1] = max(m->maxs[1], t1); } +// updates lightmaps in RAM void GL_PushLights(mface_t *surf) { lightstyle_t *style; @@ -296,6 +304,50 @@ void GL_PushLights(mface_t *surf) } } +static void clear_dirty_region(lightmap_t *m) +{ + m->mins[0] = LM_BLOCK_WIDTH; + m->mins[1] = LM_BLOCK_HEIGHT; + m->maxs[0] = 0; + m->maxs[1] = 0; +} + +// uploads dirty lightmap regions to GL +void GL_UploadLightmaps(void) +{ + lightmap_t *m; + bool set = false; + int i; + + for (i = 0, m = lm.lightmaps; i < lm.nummaps; i++, m++) { + int x, y, w, h; + + if (m->mins[0] >= m->maxs[0] || m->mins[1] >= m->maxs[1]) + continue; + + x = m->mins[0]; + y = m->mins[1]; + w = m->maxs[0] - x; + h = m->maxs[1] - y; + + if (!set) { + qglPixelStorei(GL_UNPACK_ROW_LENGTH, LM_BLOCK_WIDTH); + set = true; + } + + // upload lightmap subimage + GL_ForceTexture(1, lm.texnums[i]); + qglTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, + GL_RGBA, GL_UNSIGNED_BYTE, + m->buffer + ((y * LM_BLOCK_WIDTH) + x) * 4); + clear_dirty_region(m); + c.texUploads++; + } + + if (set) + qglPixelStorei(GL_UNPACK_ROW_LENGTH, 0); +} + /* ============================================================================= @@ -319,9 +371,14 @@ static void LM_UploadBlock(void) } Q_assert(lm.nummaps < LM_MAX_LIGHTMAPS); + + lightmap_t *m = &lm.lightmaps[lm.nummaps]; + clear_dirty_region(m); + GL_ForceTexture(1, lm.texnums[lm.nummaps]); - qglTexImage2D(GL_TEXTURE_2D, 0, lm.comp, LM_BLOCK_WIDTH, LM_BLOCK_HEIGHT, 0, - GL_RGBA, GL_UNSIGNED_BYTE, lm.buffer); + qglTexImage2D(GL_TEXTURE_2D, 0, lm.comp, + LM_BLOCK_WIDTH, LM_BLOCK_HEIGHT, 0, + GL_RGBA, GL_UNSIGNED_BYTE, m->buffer); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -384,20 +441,13 @@ static void LM_EndBuilding(void) static void build_primary_lightmap(mface_t *surf) { - int smax, tmax, size; - - smax = surf->lm_width; - tmax = surf->lm_height; - size = smax * tmax; - // add all the lightmaps - add_light_styles(surf, size); + add_light_styles(surf); surf->dlightframe = 0; // put into texture format - put_blocklights(lm.buffer + surf->light_t * LM_BLOCK_WIDTH * 4 + surf->light_s * 4, - smax, tmax, LM_BLOCK_WIDTH * 4); + put_blocklights(surf); } static void LM_BuildSurface(mface_t *surf, vec_t *vbo) @@ -429,6 +479,7 @@ static void LM_BuildSurface(mface_t *surf, vec_t *vbo) // store the surface lightmap parameters surf->light_s = s; surf->light_t = t; + surf->light_m = &lm.lightmaps[lm.nummaps]; surf->texnum[1] = lm.texnums[lm.nummaps]; // build the primary lightmap @@ -439,7 +490,8 @@ static void LM_RebuildSurfaces(void) { bsp_t *bsp = gl_static.world.cache; mface_t *surf; - int i, texnum; + lightmap_t *m; + int i; build_style_map(gl_dynamic->integer); @@ -447,9 +499,6 @@ static void LM_RebuildSurfaces(void) return; } - GL_ForceTexture(1, lm.texnums[0]); - texnum = lm.texnums[0]; - for (i = 0, surf = bsp->faces; i < bsp->numfaces; i++, surf++) { if (!surf->lightmap) { continue; @@ -460,27 +509,18 @@ static void LM_RebuildSurfaces(void) if (!surf->texnum[1]) { continue; } - - if (surf->texnum[1] != texnum) { - // done with previous lightmap - qglTexImage2D(GL_TEXTURE_2D, 0, lm.comp, - LM_BLOCK_WIDTH, LM_BLOCK_HEIGHT, 0, - GL_RGBA, GL_UNSIGNED_BYTE, lm.buffer); - GL_ForceTexture(1, surf->texnum[1]); - texnum = surf->texnum[1]; - - c.texUploads++; - } - build_primary_lightmap(surf); } - // upload the last lightmap - qglTexImage2D(GL_TEXTURE_2D, 0, lm.comp, - LM_BLOCK_WIDTH, LM_BLOCK_HEIGHT, 0, - GL_RGBA, GL_UNSIGNED_BYTE, lm.buffer); - - c.texUploads++; + // upload all lightmaps + for (i = 0, m = lm.lightmaps; i < lm.nummaps; i++, m++) { + GL_ForceTexture(1, lm.texnums[i]); + qglTexImage2D(GL_TEXTURE_2D, 0, lm.comp, + LM_BLOCK_WIDTH, LM_BLOCK_HEIGHT, 0, + GL_RGBA, GL_UNSIGNED_BYTE, m->buffer); + clear_dirty_region(m); + c.texUploads++; + } } diff --git a/src/refresh/world.c b/src/refresh/world.c index 30737e4a2..8b7c56290 100644 --- a/src/refresh/world.c +++ b/src/refresh/world.c @@ -510,6 +510,10 @@ void GL_DrawBspModel(mmodel_t *model) GL_AddSolidFace(face); } + if (gl_dynamic->integer) { + GL_UploadLightmaps(); + } + GL_DrawSolidFaces(); GL_Flush3D(); @@ -650,6 +654,10 @@ void GL_DrawWorld(void) GL_WorldNode_r(gl_static.world.cache->nodes, gl_cull_nodes->integer ? NODE_CLIPPED : NODE_UNCLIPPED); + if (gl_dynamic->integer) { + GL_UploadLightmaps(); + } + GL_DrawSolidFaces(); GL_Flush3D(); From 7c50405f331b3a94cc03678cabbc0e48567a0e4c Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 2 Dec 2023 22:51:36 +0300 Subject: [PATCH 064/167] Draw all lightmaps for debugging. --- src/refresh/draw.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/refresh/draw.c b/src/refresh/draw.c index 461431ca8..fe046f846 100644 --- a/src/refresh/draw.c +++ b/src/refresh/draw.c @@ -366,13 +366,16 @@ void Draw_Stats(void) void Draw_Lightmaps(void) { - int i, x, y; - - for (i = 0; i < lm.nummaps; i++) { - x = i & 1; - y = i >> 1; - _GL_StretchPic(256 * x, 256 * y, 256, 256, - 0, 0, 1, 1, U32_WHITE, lm.texnums[i], 0); + int rows = max(r_config.height / 256, 1); + int cols = max(lm.nummaps / rows, 1); + + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + int k = j * cols + i; + if (k < lm.nummaps) + _GL_StretchPic(256 * i, 256 * j, 256, 256, + 0, 0, 1, 1, U32_WHITE, lm.texnums[k], 0); + } } } From f59c8ed8d928d28933bb05b8ff0d8f0b3ebaf412 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 3 Dec 2023 00:53:42 +0300 Subject: [PATCH 065/167] Print lightmap extents if out of range. Also change errors to warnings. --- src/refresh/surf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/refresh/surf.c b/src/refresh/surf.c index 316e71c81..16dd44980 100644 --- a/src/refresh/surf.c +++ b/src/refresh/surf.c @@ -738,7 +738,7 @@ static void build_surface_light(mface_t *surf, vec_t *vbo) // validate lightmap extents if (smax < 1 || tmax < 1 || smax > MAX_LIGHTMAP_EXTENTS || tmax > MAX_LIGHTMAP_EXTENTS) { - Com_EPrintf("%s: bad lightmap extents\n", __func__); + Com_WPrintf("Bad lightmap extents: %d x %d\n", smax, tmax); surf->lightmap = NULL; // don't use this lightmap return; } @@ -747,7 +747,7 @@ static void build_surface_light(mface_t *surf, vec_t *vbo) size = smax * tmax; ofs = surf->lightmap - bsp->lightmap; if (surf->numstyles * size * 3 > bsp->numlightmapbytes - ofs) { - Com_EPrintf("%s: bad surface lightmap\n", __func__); + Com_WPrintf("Bad surface lightmap\n"); surf->lightmap = NULL; // don't use this lightmap return; } From 83339050f61a12a8042ba6a8266439fa3c29bf50 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 3 Dec 2023 02:19:35 +0300 Subject: [PATCH 066/167] Simplify checks for lightmap. --- src/refresh/surf.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/src/refresh/surf.c b/src/refresh/surf.c index 16dd44980..29d62b5fb 100644 --- a/src/refresh/surf.c +++ b/src/refresh/surf.c @@ -278,13 +278,7 @@ void GL_PushLights(mface_t *surf) lightstyle_t *style; int i; - if (!surf->lightmap) { - return; - } - if (surf->drawflags & gl_static.nolm_mask) { - return; - } - if (!surf->texnum[1]) { + if (!surf->light_m) { return; } @@ -500,16 +494,9 @@ static void LM_RebuildSurfaces(void) } for (i = 0, surf = bsp->faces; i < bsp->numfaces; i++, surf++) { - if (!surf->lightmap) { - continue; - } - if (surf->drawflags & gl_static.nolm_mask) { - continue; - } - if (!surf->texnum[1]) { - continue; + if (surf->light_m) { + build_primary_lightmap(surf); } - build_primary_lightmap(surf); } // upload all lightmaps @@ -883,11 +870,12 @@ static void upload_world_surfaces(void) tess.numverts += surf->numsurfedges; } + surf->light_m = NULL; // start with no lightmap surf->firstvert = currvert; build_surface_poly(surf, vbo); build_surface_light(surf, vbo); - if (surf->texnum[1]) + if (surf->light_m) normalize_surface_lmtc(surf, vbo); else duplicate_surface_lmtc(surf, vbo); From d50b52bb76eb9ad70f1927f329b6c8a6d954c96a Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 4 Dec 2023 17:20:09 +0300 Subject: [PATCH 067/167] =?UTF-8?q?Don't=20spam=20about=20missing=20glowma?= =?UTF-8?q?ps=20with=20=E2=80=98developer=202=E2=80=99.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/refresh/images.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/refresh/images.c b/src/refresh/images.c index 285b0131a..339925f61 100644 --- a/src/refresh/images.c +++ b/src/refresh/images.c @@ -1661,7 +1661,9 @@ static void print_error(const char *name, imageflags_t flags, int err) msg = Com_GetLastError(); break; case Q_ERR(ENOENT): - if (flags & IF_PERMANENT) { + if (flags == -1) { + return; + } else if (flags & IF_PERMANENT) { // ugly hack for console code if (strcmp(name, "pics/conchars.pcx")) level = PRINT_WARNING; @@ -1752,7 +1754,7 @@ static void check_for_glow_map(image_t *image) ret = load_image_data(&temporary, IM_PCX, false, &glow_pic); if (ret < 0) { - print_error(temporary.name, 0, ret); + print_error(temporary.name, -1, ret); return; } From 80636a5424ecd5ab0d09719a2fde5c58dbf3db8e Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 4 Dec 2023 17:21:08 +0300 Subject: [PATCH 068/167] =?UTF-8?q?Print=20BSPX=20lumps=20found=20with=20?= =?UTF-8?q?=E2=80=98developer=202=E2=80=99.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/bsp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/bsp.c b/src/common/bsp.c index 336b312ce..4fd28abbc 100644 --- a/src/common/bsp.c +++ b/src/common/bsp.c @@ -1305,6 +1305,8 @@ static size_t BSP_ParseExtensionHeader(bsp_t *bsp, lump_t *out, const byte *buf, break; } + Com_DDPrintf("Found %s lump\n", e->name); + if (e->parse_header) extrasize += e->parse_header(bsp, buf + ofs, len); From b3286ea5e4090260de371efa80dcb49cd2316a6d Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 7 Dec 2023 00:03:13 +0300 Subject: [PATCH 069/167] Use larger lightmaps for DECOUPLED_LM maps. --- src/refresh/gl.h | 12 ++++---- src/refresh/surf.c | 77 ++++++++++++++++++++++++++++++---------------- 2 files changed, 57 insertions(+), 32 deletions(-) diff --git a/src/refresh/gl.h b/src/refresh/gl.h index b6942a397..588516d74 100644 --- a/src/refresh/gl.h +++ b/src/refresh/gl.h @@ -407,24 +407,24 @@ qhandle_t R_RegisterModel(const char *name); #define LIGHT_STYLE(i) \ &glr.fd.lightstyles[gl_static.lightstylemap[(i)]] -#define LM_MAX_LIGHTMAPS 128 -#define LM_BLOCK_WIDTH 256 -#define LM_BLOCK_HEIGHT 256 +#define LM_MAX_LIGHTMAPS 32 +#define LM_BLOCK_WIDTH (1 << 10) typedef struct lightmap_s { - byte buffer[LM_BLOCK_WIDTH * LM_BLOCK_HEIGHT * 4]; int mins[2]; int maxs[2]; + byte *buffer; } lightmap_t; typedef struct { bool dirty; - int comp; + int comp, block_size, block_shift; float add, modulate, scale; - int nummaps; + int nummaps, maxmaps; int inuse[LM_BLOCK_WIDTH]; GLuint texnums[LM_MAX_LIGHTMAPS]; lightmap_t lightmaps[LM_MAX_LIGHTMAPS]; + byte buffer[0x4000000]; } lightmap_builder_t; extern lightmap_builder_t lm; diff --git a/src/refresh/surf.c b/src/refresh/surf.c index 29d62b5fb..67d21acfb 100644 --- a/src/refresh/surf.c +++ b/src/refresh/surf.c @@ -94,7 +94,7 @@ DYNAMIC BLOCKLIGHTS ============================================================================= */ -#define MAX_LIGHTMAP_EXTENTS 256 +#define MAX_LIGHTMAP_EXTENTS 513 #define MAX_BLOCKLIGHTS (MAX_LIGHTMAP_EXTENTS * MAX_LIGHTMAP_EXTENTS) static float blocklights[MAX_BLOCKLIGHTS * 3]; @@ -102,7 +102,7 @@ static float blocklights[MAX_BLOCKLIGHTS * 3]; static void put_blocklights(mface_t *surf) { float *bl, add, modulate, scale = lm.scale; - int i, j, smax, tmax; + int i, j, smax, tmax, stride = 1 << lm.block_shift; byte *out; if (gl_static.use_shaders) { @@ -116,9 +116,9 @@ static void put_blocklights(mface_t *surf) smax = surf->lm_width; tmax = surf->lm_height; - out = surf->light_m->buffer + (surf->light_t * LM_BLOCK_WIDTH + surf->light_s) * 4; + out = surf->light_m->buffer + (surf->light_t << lm.block_shift) + surf->light_s * 4; - for (i = 0, bl = blocklights; i < tmax; i++, out += LM_BLOCK_WIDTH * 4) { + for (i = 0, bl = blocklights; i < tmax; i++, out += stride) { byte *dst; for (j = 0, dst = out; j < smax; j++, bl += 3, dst += 4) { vec3_t tmp; @@ -300,8 +300,8 @@ void GL_PushLights(mface_t *surf) static void clear_dirty_region(lightmap_t *m) { - m->mins[0] = LM_BLOCK_WIDTH; - m->mins[1] = LM_BLOCK_HEIGHT; + m->mins[0] = lm.block_size; + m->mins[1] = lm.block_size; m->maxs[0] = 0; m->maxs[1] = 0; } @@ -325,7 +325,7 @@ void GL_UploadLightmaps(void) h = m->maxs[1] - y; if (!set) { - qglPixelStorei(GL_UNPACK_ROW_LENGTH, LM_BLOCK_WIDTH); + qglPixelStorei(GL_UNPACK_ROW_LENGTH, lm.block_size); set = true; } @@ -333,7 +333,7 @@ void GL_UploadLightmaps(void) GL_ForceTexture(1, lm.texnums[i]); qglTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, - m->buffer + ((y * LM_BLOCK_WIDTH) + x) * 4); + m->buffer + (y << lm.block_shift) + x * 4); clear_dirty_region(m); c.texUploads++; } @@ -351,7 +351,7 @@ LIGHTMAPS BUILDING */ #define LM_AllocBlock(w, h, s, t) \ - GL_AllocBlock(LM_BLOCK_WIDTH, LM_BLOCK_HEIGHT, lm.inuse, w, h, s, t) + GL_AllocBlock(lm.block_size, lm.block_size, lm.inuse, w, h, s, t) static void LM_InitBlock(void) { @@ -364,14 +364,14 @@ static void LM_UploadBlock(void) return; } - Q_assert(lm.nummaps < LM_MAX_LIGHTMAPS); + Q_assert(lm.nummaps < lm.maxmaps); lightmap_t *m = &lm.lightmaps[lm.nummaps]; clear_dirty_region(m); GL_ForceTexture(1, lm.texnums[lm.nummaps]); qglTexImage2D(GL_TEXTURE_2D, 0, lm.comp, - LM_BLOCK_WIDTH, LM_BLOCK_HEIGHT, 0, + lm.block_size, lm.block_size, 0, GL_RGBA, GL_UNSIGNED_BYTE, m->buffer); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -404,29 +404,54 @@ static void build_style_map(int dynamic) } } +static bool no_lightmaps(void) +{ + return gl_fullbright->integer || gl_vertexlight->integer; +} + static void LM_BeginBuilding(void) { + bsp_t *bsp = gl_static.world.cache; + int size_shift, bits; + + // start up with fullbright styles + build_style_map(0); + // lightmap textures are not deleted from memory when changing maps, // they are merely reused - lm.nummaps = 0; + lm.nummaps = lm.maxmaps = 0; lm.dirty = false; - LM_InitBlock(); + if (no_lightmaps()) + return; - // start up with fullbright styles - build_style_map(0); + // use larger lightmaps for DECOUPLED_LM maps + bits = 8 + bsp->lm_decoupled * 2; + + lm.block_size = 1 << bits; + lm.block_shift = bits + 2; + + size_shift = bits * 2 + 2; + lm.maxmaps = min(sizeof(lm.buffer) >> size_shift, LM_MAX_LIGHTMAPS); + + for (int i = 0; i < lm.maxmaps; i++) + lm.lightmaps[i].buffer = lm.buffer + (i << size_shift); + + Com_DDPrintf("%s: %d lightmaps, %d block size\n", __func__, lm.maxmaps, lm.block_size); + + LM_InitBlock(); } static void LM_EndBuilding(void) { + // vertex lighting implies fullbright styles + if (no_lightmaps()) + return; + // upload the last lightmap LM_UploadBlock(); LM_InitBlock(); - // vertex lighting implies fullbright styles - if (gl_fullbright->integer || gl_vertexlight->integer) - return; - // now build the real lightstyle map build_style_map(gl_dynamic->integer); @@ -448,7 +473,7 @@ static void LM_BuildSurface(mface_t *surf, vec_t *vbo) { int smax, tmax, s, t; - if (lm.nummaps == LM_MAX_LIGHTMAPS) + if (lm.nummaps >= lm.maxmaps) return; // can't have any more smax = surf->lm_width; @@ -456,8 +481,8 @@ static void LM_BuildSurface(mface_t *surf, vec_t *vbo) if (!LM_AllocBlock(smax, tmax, &s, &t)) { LM_UploadBlock(); - if (lm.nummaps == LM_MAX_LIGHTMAPS) { - Com_EPrintf("%s: LM_MAX_LIGHTMAPS exceeded\n", __func__); + if (lm.nummaps >= lm.maxmaps) { + Com_EPrintf("%s: too many lightmaps\n", __func__); return; } LM_InitBlock(); @@ -503,7 +528,7 @@ static void LM_RebuildSurfaces(void) for (i = 0, m = lm.lightmaps; i < lm.nummaps; i++, m++) { GL_ForceTexture(1, lm.texnums[i]); qglTexImage2D(GL_TEXTURE_2D, 0, lm.comp, - LM_BLOCK_WIDTH, LM_BLOCK_HEIGHT, 0, + lm.block_size, lm.block_size, 0, GL_RGBA, GL_UNSIGNED_BYTE, m->buffer); clear_dirty_region(m); c.texUploads++; @@ -757,8 +782,8 @@ static void normalize_surface_lmtc(mface_t *surf, vec_t *vbo) for (i = 0; i < surf->numsurfedges; i++) { vbo[6] += s; vbo[7] += t; - vbo[6] *= 1.0f / LM_BLOCK_WIDTH; - vbo[7] *= 1.0f / LM_BLOCK_HEIGHT; + vbo[6] *= 1.0f / lm.block_size; + vbo[7] *= 1.0f / lm.block_size; vbo += VERTEX_SIZE; } @@ -922,7 +947,7 @@ void GL_RebuildLighting(void) return; // if doing vertex lighting, rebuild all surfaces - if (gl_fullbright->integer || gl_vertexlight->integer) { + if (no_lightmaps()) { upload_world_surfaces(); return; } From c528c920ecdb5518e3b65671394d316d067dcdb0 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 7 Dec 2023 00:04:42 +0300 Subject: [PATCH 070/167] Fit debug lightmaps on screen. --- src/refresh/draw.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/refresh/draw.c b/src/refresh/draw.c index fe046f846..3fb833a49 100644 --- a/src/refresh/draw.c +++ b/src/refresh/draw.c @@ -366,14 +366,22 @@ void Draw_Stats(void) void Draw_Lightmaps(void) { - int rows = max(r_config.height / 256, 1); - int cols = max(lm.nummaps / rows, 1); + int block = lm.block_size; + int rows = 0, cols = 0; + + while (block) { + rows = max(r_config.height / block, 1); + cols = max(lm.nummaps / rows, 1); + if (cols * block <= r_config.width) + break; + block >>= 1; + } for (int i = 0; i < cols; i++) { for (int j = 0; j < rows; j++) { int k = j * cols + i; if (k < lm.nummaps) - _GL_StretchPic(256 * i, 256 * j, 256, 256, + _GL_StretchPic(block * i, block * j, block, block, 0, 0, 1, 1, U32_WHITE, lm.texnums[k], 0); } } From 3cb974ba4dfbc3227a0901a1024c0810d1f3e076 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 7 Dec 2023 00:32:30 +0300 Subject: [PATCH 071/167] Count uploaded lightmap texels. --- src/refresh/draw.c | 3 ++- src/refresh/gl.h | 1 + src/refresh/surf.c | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/refresh/draw.c b/src/refresh/draw.c index 3fb833a49..f14150880 100644 --- a/src/refresh/draw.c +++ b/src/refresh/draw.c @@ -338,7 +338,7 @@ void Draw_Stats(void) int x = 10, y = 10; R_SetScale(1.0f / get_auto_scale()); - R_DrawFill8(8, 8, 24*8, 20*10+2, 4); + R_DrawFill8(8, 8, 25*8, 21*10+2, 4); Draw_Stringf(x, y, "Nodes visible : %i", c.nodesVisible); y += 10; Draw_Stringf(x, y, "Nodes culled : %i", c.nodesCulled); y += 10; @@ -352,6 +352,7 @@ void Draw_Stats(void) Draw_Stringf(x, y, "Tris drawn : %i", c.trisDrawn); y += 10; Draw_Stringf(x, y, "Tex switches : %i", c.texSwitches); y += 10; Draw_Stringf(x, y, "Tex uploads : %i", c.texUploads); y += 10; + Draw_Stringf(x, y, "LM texels : %i", c.lightTexels); y += 10; Draw_Stringf(x, y, "Batches drawn : %i", c.batchesDrawn); y += 10; Draw_Stringf(x, y, "Faces / batch : %.1f", c.batchesDrawn ? (float)c.facesDrawn / c.batchesDrawn : 0.0f); y += 10; Draw_Stringf(x, y, "Tris / batch : %.1f", c.batchesDrawn ? (float)c.facesTris / c.batchesDrawn : 0.0f); y += 10; diff --git a/src/refresh/gl.h b/src/refresh/gl.h index 588516d74..dd5c91e6d 100644 --- a/src/refresh/gl.h +++ b/src/refresh/gl.h @@ -178,6 +178,7 @@ typedef struct { int facesTris; int texSwitches; int texUploads; + int lightTexels; int trisDrawn; int batchesDrawn; int nodesCulled; diff --git a/src/refresh/surf.c b/src/refresh/surf.c index 67d21acfb..3146c4b22 100644 --- a/src/refresh/surf.c +++ b/src/refresh/surf.c @@ -336,6 +336,7 @@ void GL_UploadLightmaps(void) m->buffer + (y << lm.block_shift) + x * 4); clear_dirty_region(m); c.texUploads++; + c.lightTexels += w * h; } if (set) From 9ff231ddae0a5d33f62526e5d86f8de02866f8b5 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 8 Dec 2023 00:51:16 +0300 Subject: [PATCH 072/167] Update libcurl to 8.5.0. --- subprojects/libcurl.wrap | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/subprojects/libcurl.wrap b/subprojects/libcurl.wrap index 879a511da..a484de0a4 100644 --- a/subprojects/libcurl.wrap +++ b/subprojects/libcurl.wrap @@ -1,11 +1,11 @@ [wrap-file] -directory = curl-8.4.0 -source_url = https://curl.se/download/curl-8.4.0.tar.xz -source_filename = curl-8.4.0.tar.xz -source_hash = 16c62a9c4af0f703d28bda6d7bbf37ba47055ad3414d70dec63e2e6336f2a82d -patch_url = https://skuller.net/meson/libcurl_8.4.0-1_patch.zip -patch_filename = libcurl_8.4.0-1_patch.zip -patch_hash = a4115c0e9ea51b25ec19461420b0b396350056c72bb6832aed4a339a62f11502 +directory = curl-8.5.0 +source_url = https://curl.se/download/curl-8.5.0.tar.xz +source_filename = curl-8.5.0.tar.xz +source_hash = 42ab8db9e20d8290a3b633e7fbb3cec15db34df65fd1015ef8ac1e4723750eeb +patch_url = https://skuller.net/meson/libcurl_8.5.0-1_patch.zip +patch_filename = libcurl_8.5.0-1_patch.zip +patch_hash = 3073ef9547660cdf73ab0f6ed672215dbe03185a158de4fcb7f32003f526fa7f [provide] libcurl = libcurl_dep From d6fb3da55c4e01a8e613f7ea842967e63b6b3285 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 8 Dec 2023 01:34:04 +0300 Subject: [PATCH 073/167] Simplify GL_RebuildLighting(). It's more correct to call LM_BeginBuilding() if toggling lightmaps off, because it will reset nummaps/maxmaps. --- src/refresh/surf.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/refresh/surf.c b/src/refresh/surf.c index 3146c4b22..dbb956edd 100644 --- a/src/refresh/surf.c +++ b/src/refresh/surf.c @@ -947,13 +947,7 @@ void GL_RebuildLighting(void) if (!gl_static.world.cache) return; - // if doing vertex lighting, rebuild all surfaces - if (no_lightmaps()) { - upload_world_surfaces(); - return; - } - - // if did vertex lighting previously, rebuild all surfaces and lightmaps + // rebuild all surfaces if toggling lightmaps off/on if (gl_fullbright->modified || gl_vertexlight->modified) { LM_BeginBuilding(); upload_world_surfaces(); From 4001f13ee32e351b6ca7ec0aafb9abdfd17f70b4 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 8 Dec 2023 02:46:47 +0300 Subject: [PATCH 074/167] Fix previous commit and clean up. Vertex lighting still needs full surface rebuild if lighting parameters change. Also merge LM_(Begin|End)Building calls into upload_world_surfaces(). --- src/refresh/surf.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/refresh/surf.c b/src/refresh/surf.c index dbb956edd..fa960c5f9 100644 --- a/src/refresh/surf.c +++ b/src/refresh/surf.c @@ -872,6 +872,9 @@ static void upload_world_surfaces(void) if (!qglActiveTexture || (!qglClientActiveTexture && !gl_static.use_shaders)) Cvar_Set("gl_vertexlight", "1"); + // begin building lightmaps + LM_BeginBuilding(); + if (!gl_static.world.vertices) qglBindBuffer(GL_ARRAY_BUFFER, gl_static.world.bufnum); @@ -917,6 +920,9 @@ static void upload_world_surfaces(void) qglBindBuffer(GL_ARRAY_BUFFER, 0); } + // end building lightmaps + LM_EndBuilding(); + gl_fullbright->modified = false; gl_vertexlight->modified = false; } @@ -949,9 +955,16 @@ void GL_RebuildLighting(void) // rebuild all surfaces if toggling lightmaps off/on if (gl_fullbright->modified || gl_vertexlight->modified) { - LM_BeginBuilding(); upload_world_surfaces(); - LM_EndBuilding(); + return; + } + + if (gl_fullbright->integer) + return; + + // rebuild all surfaces if doing vertex lighting (and not fullbright) + if (gl_vertexlight->integer) { + upload_world_surfaces(); return; } @@ -1058,14 +1071,8 @@ void GL_LoadWorld(const char *name) gl_static.nolm_mask = SURF_NOLM_MASK_REMASTER; } - // begin building lightmaps - LM_BeginBuilding(); - // post process all surfaces upload_world_surfaces(); - // end building lightmaps - LM_EndBuilding(); - GL_ShowErrors(__func__); } From 0f265471bc65cc421c83c65262211036f18d8ecb Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 8 Dec 2023 15:48:01 +0300 Subject: [PATCH 075/167] Fix UB after GL_RebuildLighting(). GL_RebuildLighting() replaces glr.fd.lightstyles with single fake lightstyle, which can lead to out of array access later in frame. To fix this, move GL_RebuildLighting() call up to ensure that glr.fd.lightstyles gets overwritten with correct table. --- src/refresh/main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/refresh/main.c b/src/refresh/main.c index c13561f80..e0f207c68 100644 --- a/src/refresh/main.c +++ b/src/refresh/main.c @@ -668,6 +668,11 @@ void R_RenderFrame(refdef_t *fd) Q_assert(gl_static.world.cache || (fd->rdflags & RDF_NOWORLDMODEL)); + if (lm.dirty) { + GL_RebuildLighting(); + lm.dirty = false; + } + glr.drawframe++; glr.rand_seed = fd->time * 20; @@ -679,11 +684,6 @@ void R_RenderFrame(refdef_t *fd) glr.fd.num_dlights = 0; } - if (lm.dirty) { - GL_RebuildLighting(); - lm.dirty = false; - } - bool waterwarp = (glr.fd.rdflags & RDF_UNDERWATER) && gl_static.use_shaders && gl_waterwarp->integer; if (waterwarp) { From df70ccf2886a5a1c2f7ec76cdc10dcb87c5fec27 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 8 Dec 2023 15:53:44 +0300 Subject: [PATCH 076/167] Fix transparent surfaces with vertex lighting. --- src/refresh/surf.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/refresh/surf.c b/src/refresh/surf.c index fa960c5f9..aa1d33449 100644 --- a/src/refresh/surf.c +++ b/src/refresh/surf.c @@ -709,6 +709,9 @@ static void sample_surface_verts(mface_t *surf, vec_t *vbo) vec3_t color; byte *dst; + if (surf->drawflags & SURF_COLOR_MASK) + return; + glr.lightpoint.surf = surf; for (i = 0; i < surf->numsurfedges; i++) { From de93e69223085b149206eb3ff8df511796f1e22c Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 9 Dec 2023 00:52:51 +0300 Subject: [PATCH 077/167] Test ent->area.next to determine if entity is linked. list_t structure has next/prev members swapped compared to link_t. This technically breaks game ABI, but doesn't matter in practice because game library should never be using these fields, except for testing them for NULL to determine if entity is linked. Change the code to test the first structure member like original code does to improve ABI compatibility. --- src/game/g_phys.c | 2 +- src/server/world.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/game/g_phys.c b/src/game/g_phys.c index 10029b7e3..216422ace 100644 --- a/src/game/g_phys.c +++ b/src/game/g_phys.c @@ -418,7 +418,7 @@ bool SV_Push(edict_t *pusher, vec3_t move, vec3_t amove) || check->movetype == MOVETYPE_NOCLIP) continue; - if (!check->area.prev) + if (!check->area.next) continue; // not linked in anywhere // if the entity is standing on the pusher, it will definitely be moved diff --git a/src/server/world.c b/src/server/world.c index 1ba33f3ac..8b29461ae 100644 --- a/src/server/world.c +++ b/src/server/world.c @@ -115,7 +115,7 @@ void SV_ClearWorld(void) // make sure all entities are unlinked for (i = 0; i < ge->max_edicts; i++) { ent = EDICT_NUM(i); - ent->area.prev = ent->area.next = NULL; + ent->area.next = ent->area.prev = NULL; } } @@ -228,10 +228,10 @@ void PF_UnlinkEdict(edict_t *ent) { if (!ent) Com_Error(ERR_DROP, "%s: NULL", __func__); - if (!ent->area.prev) + if (!ent->area.next) return; // not linked in anywhere List_Remove(&ent->area); - ent->area.prev = ent->area.next = NULL; + ent->area.next = ent->area.prev = NULL; } static uint32_t SV_PackSolid32(edict_t *ent) @@ -276,7 +276,7 @@ void PF_LinkEdict(edict_t *ent) if (!ent) Com_Error(ERR_DROP, "%s: NULL", __func__); - if (ent->area.prev) + if (ent->area.next) PF_UnlinkEdict(ent); // unlink from old position if (ent == ge->edicts) From ba7f4830899ee1e6bcb5a5d5b2744434926fe9f8 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 9 Dec 2023 20:40:04 +0300 Subject: [PATCH 078/167] Fix UB in MenuList_PrevColumn(). --- src/client/ui/menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/ui/menu.c b/src/client/ui/menu.c index 05035b3f1..4110db6cd 100644 --- a/src/client/ui/menu.c +++ b/src/client/ui/menu.c @@ -913,7 +913,7 @@ static menuSound_t MenuList_PrevColumn(menuList_t *l) return MenuList_FindColumn(l, 1); do { - if (col < 0) { + if (col == 0) { col = l->numcolumns - 1; } else { col--; From 7d251e56e6fc4e888bce25ba93c1e07e8cb1855c Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 9 Dec 2023 20:41:21 +0300 Subject: [PATCH 079/167] Don't always scroll menu list when sorting. --- src/client/ui/menu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/client/ui/menu.c b/src/client/ui/menu.c index 4110db6cd..bce198c07 100644 --- a/src/client/ui/menu.c +++ b/src/client/ui/menu.c @@ -877,6 +877,7 @@ static menuSound_t MenuList_SetColumn(menuList_t *l, int value) } if (l->sort) { l->sort(l); + MenuList_AdjustPrestep(l); } return QMS_SILENT; } @@ -1482,9 +1483,6 @@ void MenuList_Sort(menuList_t *l, int offset, int (*cmpfunc)(const void *, const break; } } - - if (n) - MenuList_AdjustPrestep(l); } /* From 6204d3f2b9496fd7511c0301f8db2a62224d6466 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 9 Dec 2023 22:22:28 +0300 Subject: [PATCH 080/167] Fix UB in touch functions when plane is NULL. --- src/game/g_weapon.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c index 87b571427..2fea1880c 100644 --- a/src/game/g_weapon.c +++ b/src/game/g_weapon.c @@ -277,6 +277,7 @@ Fires a single blaster bolt. Used by the blaster and hyper blaster. */ void blaster_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) { + vec_t *normal = NULL; int mod; if (other == self->owner) @@ -290,20 +291,20 @@ void blaster_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *s if (self->owner->client) PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT); + if (plane) + normal = plane->normal; + if (other->takedamage) { if (self->spawnflags & 1) mod = MOD_HYPERBLASTER; else mod = MOD_BLASTER; - T_Damage(other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 1, DAMAGE_ENERGY, mod); + T_Damage(other, self, self->owner, self->velocity, self->s.origin, normal, self->dmg, 1, DAMAGE_ENERGY, mod); } else { gi.WriteByte(svc_temp_entity); gi.WriteByte(TE_BLASTER); gi.WritePosition(self->s.origin); - if (!plane) - gi.WriteDir(vec3_origin); - else - gi.WriteDir(plane->normal); + gi.WriteDir(normal); gi.multicast(self->s.origin, MULTICAST_PVS); } @@ -548,7 +549,7 @@ void rocket_touch(edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *sur VectorMA(ent->s.origin, -0.02f, ent->velocity, origin); if (other->takedamage) { - T_Damage(other, ent, ent->owner, ent->velocity, ent->s.origin, plane->normal, ent->dmg, 0, 0, MOD_ROCKET); + T_Damage(other, ent, ent->owner, ent->velocity, ent->s.origin, plane ? plane->normal : NULL, ent->dmg, 0, 0, MOD_ROCKET); } else { // don't throw any debris in net games if (!deathmatch->value && !coop->value) { @@ -729,7 +730,7 @@ void bfg_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) // core explosion - prevents firing it into the wall/floor if (other->takedamage) - T_Damage(other, self, self->owner, self->velocity, self->s.origin, plane->normal, 200, 0, 0, MOD_BFG_BLAST); + T_Damage(other, self, self->owner, self->velocity, self->s.origin, plane ? plane->normal : NULL, 200, 0, 0, MOD_BFG_BLAST); T_RadiusDamage(self, self->owner, 200, other, 100, MOD_BFG_BLAST); gi.sound(self, CHAN_VOICE, gi.soundindex("weapons/bfg__x1b.wav"), 1, ATTN_NORM, 0); From e020bdcf60e7b6beea5476cfd616c9976b5ad9cc Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 10 Dec 2023 22:56:12 +0300 Subject: [PATCH 081/167] Support PRINT_TYPEWRITER and centerprint queue. --- inc/shared/shared.h | 14 ++++-- src/client/client.h | 3 +- src/client/main.c | 1 + src/client/parse.c | 7 ++- src/client/screen.c | 109 ++++++++++++++++++++++++++++++++++---------- 5 files changed, 104 insertions(+), 30 deletions(-) diff --git a/inc/shared/shared.h b/inc/shared/shared.h index 68967659e..a9272210d 100644 --- a/inc/shared/shared.h +++ b/inc/shared/shared.h @@ -117,10 +117,16 @@ q_noreturn q_printf(2, 3); do { if (!(expr)) Com_Error(ERR_FATAL, "%s: assertion `%s' failed", __func__, #expr); } while (0) // game print flags -#define PRINT_LOW 0 // pickup messages -#define PRINT_MEDIUM 1 // death messages -#define PRINT_HIGH 2 // critical messages -#define PRINT_CHAT 3 // chat messages +enum { + PRINT_LOW, // pickup messages + PRINT_MEDIUM, // death messages + PRINT_HIGH, // critical messages + PRINT_CHAT, // chat messages +// KEX + PRINT_TYPEWRITER, + PRINT_CENTER, +// KEX +}; // destination class for gi.multicast() typedef enum { diff --git a/src/client/client.h b/src/client/client.h index db12b6318..d429c7c34 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -978,7 +978,8 @@ extern vrect_t scr_vrect; // position of render window void SCR_Init(void); void SCR_Shutdown(void); void SCR_UpdateScreen(void); -void SCR_CenterPrint(const char *str); +void SCR_CenterPrint(const char *str, bool typewrite); +void SCR_ClearCenterPrints(void); void SCR_BeginLoadingPlaque(void); void SCR_EndLoadingPlaque(void); void SCR_RegisterMedia(void); diff --git a/src/client/main.c b/src/client/main.c index ad1f45e3f..96f4260d1 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -680,6 +680,7 @@ void CL_ClearState(void) S_StopAllSounds(); OGG_Stop(); SCR_StopCinematic(); + SCR_ClearCenterPrints(); CL_ClearEffects(); CL_ClearTEnts(); LOC_FreeLocations(); diff --git a/src/client/parse.c b/src/client/parse.c index 2eb24e904..0353d27c3 100644 --- a/src/client/parse.c +++ b/src/client/parse.c @@ -1004,7 +1004,10 @@ static void CL_ParsePrint(void) SHOWNET(2, " %i \"%s\"\n", level, Com_MakePrintable(s)); if (level != PRINT_CHAT) { - Com_Printf("%s", s); + if (cl.csr.extended && (level == PRINT_TYPEWRITER || level == PRINT_CENTER)) + SCR_CenterPrint(s, level == PRINT_TYPEWRITER); + else + Com_Printf("%s", s); if (!cls.demo.playback && cl.serverstate != ss_broadcast) { COM_strclr(s); Cmd_ExecTrigger(s); @@ -1060,7 +1063,7 @@ static void CL_ParseCenterPrint(void) MSG_ReadString(s, sizeof(s)); SHOWNET(2, " \"%s\"\n", Com_MakePrintable(s)); - SCR_CenterPrint(s); + SCR_CenterPrint(s, false); if (!cls.demo.playback && cl.serverstate != ss_broadcast) { COM_strclr(s); diff --git a/src/client/screen.c b/src/client/screen.c index 3460fd4c3..3b760c665 100644 --- a/src/client/screen.c +++ b/src/client/screen.c @@ -58,6 +58,7 @@ static struct { static cvar_t *scr_viewsize; static cvar_t *scr_centertime; +static cvar_t *scr_printspeed; static cvar_t *scr_showpause; #if USE_DEBUG static cvar_t *scr_showstats; @@ -168,18 +169,16 @@ void SCR_DrawStringMulti(int x, int y, int flags, size_t maxlen, char *p; size_t len; - while (*s) { + while (*s && maxlen) { p = strchr(s, '\n'); if (!p) { SCR_DrawStringEx(x, y, flags, maxlen, s, font); break; } - len = p - s; - if (len > maxlen) { - len = maxlen; - } + len = min(p - s, maxlen); SCR_DrawStringEx(x, y, flags, len, s, font); + maxlen -= len; y += CHAR_HEIGHT; s = p + 1; @@ -379,9 +378,24 @@ CENTER PRINTING =============================================================================== */ -static char scr_centerstring[MAX_STRING_CHARS]; -static unsigned scr_centertime_start; // for slow victory printing -static int scr_center_lines; +#define MAX_CENTERPRINTS_REAL 4 +#define MAX_CENTERPRINTS (cl.csr.extended ? MAX_CENTERPRINTS_REAL : 1) + +typedef struct { + char string[MAX_STRING_CHARS - 8]; + uint32_t start; + uint16_t lines; + uint16_t typewrite; // msec to typewrite (0 if instant) +} centerprint_t; + +static centerprint_t scr_centerprints[MAX_CENTERPRINTS_REAL]; +static unsigned scr_centerhead, scr_centertail; + +void SCR_ClearCenterPrints(void) +{ + memset(scr_centerprints, 0, sizeof(scr_centerprints)); + scr_centerhead = scr_centertail = 0; +} /* ============== @@ -391,53 +405,99 @@ Called for important messages that should stay in the center of the screen for a few moments ============== */ -void SCR_CenterPrint(const char *str) +void SCR_CenterPrint(const char *str, bool typewrite) { - const char *s; + centerprint_t *cp; + const char *s; - scr_centertime_start = cls.realtime; - if (!strcmp(scr_centerstring, str)) { + // refresh duplicate message + cp = &scr_centerprints[(scr_centerhead - 1) & (MAX_CENTERPRINTS - 1)]; + if (!strcmp(cp->string, str)) { + if (cp->start) + cp->start = cls.realtime; + if (scr_centertail == scr_centerhead) + scr_centertail--; return; } - Q_strlcpy(scr_centerstring, str, sizeof(scr_centerstring)); + cp = &scr_centerprints[scr_centerhead & (MAX_CENTERPRINTS - 1)]; + Q_strlcpy(cp->string, str, sizeof(cp->string)); // count the number of lines for centering - scr_center_lines = 1; - s = str; + cp->lines = 1; + s = cp->string; while (*s) { if (*s == '\n') - scr_center_lines++; + cp->lines++; s++; } + cp->start = 0; // not yet displayed + cp->typewrite = 0; + + // for typewritten strings set minimum display time, + // but no longer than 30 sec + if (typewrite && scr_printspeed->value > 0) { + size_t nb_chars = strlen(cp->string) - cp->lines + 2; + cp->typewrite = min(nb_chars * 1000 / scr_printspeed->value + 300, 30000); + } + // echo it to the console - Com_Printf("%s\n", scr_centerstring); + Com_Printf("%s\n", cp->string); Con_ClearNotify_f(); + + scr_centerhead++; + if (scr_centerhead - scr_centertail > MAX_CENTERPRINTS) + scr_centertail++; } static void SCR_DrawCenterString(void) { + centerprint_t *cp; int y; float alpha; + size_t maxlen; - Cvar_ClampValue(scr_centertime, 0.3f, 10.0f); - - alpha = SCR_FadeAlpha(scr_centertime_start, scr_centertime->value * 1000, 300); - if (!alpha) { + if (!scr_centertime->integer) { + scr_centertail = scr_centerhead; return; } + while (1) { + if (scr_centertail == scr_centerhead) + return; + cp = &scr_centerprints[scr_centertail & (MAX_CENTERPRINTS - 1)]; + if (!cp->start) + cp->start = cls.realtime; + alpha = SCR_FadeAlpha(cp->start, max(scr_centertime->integer, cp->typewrite), 300); + if (alpha > 0) + break; + scr_centertail++; + } + R_SetAlpha(alpha * scr_alpha->value); - y = scr.hud_height / 4 - scr_center_lines * 8 / 2; + y = scr.hud_height / 4 - cp->lines * CHAR_HEIGHT / 2; + + if (cp->typewrite) + maxlen = scr_printspeed->value * 0.001f * (cls.realtime - cp->start); + else + maxlen = MAX_STRING_CHARS; SCR_DrawStringMulti(scr.hud_width / 2, y, UI_CENTER, - MAX_STRING_CHARS, scr_centerstring, scr.font_pic); + maxlen, cp->string, scr.font_pic); R_SetAlpha(scr_alpha->value); } +static void scr_centertime_changed(cvar_t *self) +{ + if (self->value > 0) + self->integer = 1000 * Cvar_ClampValue(self, 1.0f, 30.0f); + else + self->integer = 0; +} + /* =============================================================================== @@ -1250,6 +1310,9 @@ void SCR_Init(void) scr_viewsize = Cvar_Get("viewsize", "100", CVAR_ARCHIVE); scr_showpause = Cvar_Get("scr_showpause", "1", 0); scr_centertime = Cvar_Get("scr_centertime", "2.5", 0); + scr_centertime->changed = scr_centertime_changed; + scr_centertime->changed(scr_centertime); + scr_printspeed = Cvar_Get("scr_printspeed", "16", 0); scr_demobar = Cvar_Get("scr_demobar", "1", 0); scr_font = Cvar_Get("scr_font", "conchars", 0); scr_font->changed = scr_font_changed; From 525ce14b5f5b21974d5a45253413bb5a05bfc618 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 11 Dec 2023 23:00:21 +0300 Subject: [PATCH 082/167] Give more time to read typewritten string. --- src/client/screen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/screen.c b/src/client/screen.c index 3b760c665..268417640 100644 --- a/src/client/screen.c +++ b/src/client/screen.c @@ -469,7 +469,7 @@ static void SCR_DrawCenterString(void) cp = &scr_centerprints[scr_centertail & (MAX_CENTERPRINTS - 1)]; if (!cp->start) cp->start = cls.realtime; - alpha = SCR_FadeAlpha(cp->start, max(scr_centertime->integer, cp->typewrite), 300); + alpha = SCR_FadeAlpha(cp->start, scr_centertime->integer + cp->typewrite, 300); if (alpha > 0) break; scr_centertail++; From f60108f153c97d16d0e950b1c480a3ab9fcf227d Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Thu, 14 Dec 2023 11:59:43 -0500 Subject: [PATCH 083/167] Made String layout errors easier to debug --- src/client/ascii.c | 8 ++++---- src/client/screen.c | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/client/ascii.c b/src/client/ascii.c index b574b50e9..510eeebe2 100644 --- a/src/client/ascii.c +++ b/src/client/ascii.c @@ -234,7 +234,7 @@ static void TH_DrawLayoutString(char *dst, const char *s) token = COM_Parse(&s); value = atoi(token); if (value < 0 || value >= MAX_STATS) { - Com_Error(ERR_DROP, "%s: invalid stat index", __func__); + Com_Error(ERR_DROP, "%s: invalid stat index for num: %i", __func__, value); } value = cl.frame.ps.stats[value]; TH_DrawNumber(dst, x, y, width, value); @@ -245,11 +245,11 @@ static void TH_DrawLayoutString(char *dst, const char *s) token = COM_Parse(&s); index = atoi(token); if (index < 0 || index >= MAX_STATS) { - Com_Error(ERR_DROP, "%s: invalid string index", __func__); + Com_Error(ERR_DROP, "%s: invalid string index for stat_string: %i", __func__, index); } index = cl.frame.ps.stats[index]; if (index < 0 || index >= cl.csr.end) { - Com_Error(ERR_DROP, "%s: invalid string index", __func__); + Com_Error(ERR_DROP, "%s: invalid string index for stat_string: %i", __func__, index); } len = strlen(cl.configstrings[index]); TH_DrawString(dst, x, y, cl.configstrings[index], len); @@ -274,7 +274,7 @@ static void TH_DrawLayoutString(char *dst, const char *s) token = COM_Parse(&s); value = atoi(token); if (value < 0 || value >= MAX_STATS) { - Com_Error(ERR_DROP, "%s: invalid stat index", __func__); + Com_Error(ERR_DROP, "%s: invalid stat index for if: %i", __func__, value); } value = cl.frame.ps.stats[value]; if (!value) { // skip to endif diff --git a/src/client/screen.c b/src/client/screen.c index 511b920ca..4115bf693 100644 --- a/src/client/screen.c +++ b/src/client/screen.c @@ -1701,11 +1701,11 @@ static void SCR_ExecuteLayoutString(const char *s) token = COM_Parse(&s); value = atoi(token); if (value < 0 || value >= MAX_STATS) { - Com_Error(ERR_DROP, "%s: invalid stat index", __func__); + Com_Error(ERR_DROP, "%s: invalid stat index for pic: %i", __func__, value); } value = cl.frame.ps.stats[value]; if (value < 0 || value >= cl.csr.max_images) { - Com_Error(ERR_DROP, "%s: invalid pic index", __func__); + Com_Error(ERR_DROP, "%s: invalid pic index for pic: %i", __func__, value); } token = cl.configstrings[cl.csr.images + value]; if (token[0]) { @@ -1816,7 +1816,7 @@ static void SCR_ExecuteLayoutString(const char *s) token = COM_Parse(&s); value = atoi(token); if (value < 0 || value >= MAX_STATS) { - Com_Error(ERR_DROP, "%s: invalid stat index", __func__); + Com_Error(ERR_DROP, "%s: invalid stat index for num: %i", __func__, value); } value = cl.frame.ps.stats[value]; HUD_DrawNumber(x, y, 0, width, value); @@ -1886,11 +1886,11 @@ static void SCR_ExecuteLayoutString(const char *s) token = COM_Parse(&s); index = atoi(token); if (index < 0 || index >= MAX_STATS) { - Com_Error(ERR_DROP, "%s: invalid stat index", __func__); + Com_Error(ERR_DROP, "%s: invalid stat index for stat_: %i", __func__, index); } index = cl.frame.ps.stats[index]; if (index < 0 || index >= cl.csr.end) { - Com_Error(ERR_DROP, "%s: invalid string index", __func__); + Com_Error(ERR_DROP, "%s: invalid string index for stat_: %i", __func__, index); } token = cl.configstrings[index]; if (!strcmp(cmd, "string")) @@ -1948,7 +1948,7 @@ static void SCR_ExecuteLayoutString(const char *s) token = COM_Parse(&s); value = atoi(token); if (value < 0 || value >= MAX_STATS) { - Com_Error(ERR_DROP, "%s: invalid stat index", __func__); + Com_Error(ERR_DROP, "%s: invalid stat index for if: %i", __func__, value); } value = cl.frame.ps.stats[value]; if (!value) { // skip to endif From 7148b8eef875befe525b62fad317d6a7c13a49ab Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Thu, 14 Dec 2023 13:05:47 -0500 Subject: [PATCH 084/167] Lag scale graph scaling engage --- src/client/client.h | 1 + src/client/screen.c | 44 ++++++++++++++++++++++++++++++---------- src/client/ui/q2pro.menu | 1 + 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index 9181cb228..014021486 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -987,6 +987,7 @@ void SCR_RegisterMedia(void); void SCR_ModeChanged(void); void SCR_LagSample(void); void SCR_LagClear(void); +void init_lag_graph_dimensions(void); void SCR_SetCrosshairColor(void); float SCR_FadeAlpha(unsigned startTime, unsigned visTime, unsigned fadeTime); diff --git a/src/client/screen.c b/src/client/screen.c index 4115bf693..dfa6ec414 100644 --- a/src/client/screen.c +++ b/src/client/screen.c @@ -59,6 +59,7 @@ static struct { int hud_x, hud_y; int hud_width, hud_height; float hud_scale; + int lag_draw_scale; } scr; static cvar_t *scr_viewsize; @@ -76,6 +77,7 @@ static cvar_t *scr_lag_y; static cvar_t *scr_lag_draw; static cvar_t *scr_lag_min; static cvar_t *scr_lag_max; +static cvar_t *scr_lag_draw_scale; static cvar_t *scr_alpha; static cvar_t *scr_hudborder_x; @@ -469,8 +471,15 @@ LAGOMETER =============================================================================== */ -#define LAG_WIDTH 48 -#define LAG_HEIGHT 48 +#define LAG_WIDTH 48 +#define LAG_HEIGHT 48 +int DRAW_LAG_WIDTH; +int DRAW_LAG_HEIGHT; +// Scaling support for lag graph +void init_lag_graph_dimensions(void) { + DRAW_LAG_WIDTH = LAG_WIDTH * scr_lag_draw_scale->integer; + DRAW_LAG_HEIGHT = LAG_HEIGHT * scr_lag_draw_scale->integer; +} #define LAG_WARN_BIT BIT(30) #define LAG_CRIT_BIT BIT(31) @@ -524,13 +533,13 @@ static void SCR_LagDraw(int x, int y) if (v_range < 1) return; - for (i = 0; i < LAG_WIDTH; i++) { + for (i = 0; i < DRAW_LAG_WIDTH; i++) { j = lag.head - i - 1; if (j < 0) { break; } - v = lag.samples[j % LAG_WIDTH]; + v = lag.samples[j % DRAW_LAG_WIDTH]; if (v & LAG_CRIT_BIT) { c = LAG_CRIT; @@ -541,10 +550,10 @@ static void SCR_LagDraw(int x, int y) } v &= ~(LAG_WARN_BIT | LAG_CRIT_BIT); - v = (v - v_min) * LAG_HEIGHT / v_range; - clamp(v, 0, LAG_HEIGHT); + v = (v - v_min) * DRAW_LAG_HEIGHT / v_range; + clamp(v, 0, DRAW_LAG_HEIGHT); - R_DrawFill8(x + LAG_WIDTH - i - 1, y + LAG_HEIGHT - v, 1, v, c); + R_DrawFill8(x + DRAW_LAG_WIDTH - i - 1, y + DRAW_LAG_HEIGHT - v, 1, v, c); } } @@ -553,17 +562,19 @@ static void SCR_DrawNet(void) int x = scr_lag_x->integer + scr.hud_x; int y = scr_lag_y->integer + scr.hud_y; + init_lag_graph_dimensions(); + if (scr_lag_x->integer < 0) { - x += scr.hud_width - LAG_WIDTH + 1; + x += scr.hud_width - DRAW_LAG_WIDTH + 1; } if (scr_lag_y->integer < 0) { - y += scr.hud_height - LAG_HEIGHT + 1; + y += scr.hud_height - DRAW_LAG_HEIGHT + 1; } // draw ping graph if (scr_lag_draw->integer) { if (scr_lag_draw->integer > 1) { - R_DrawFill8(x, y, LAG_WIDTH, LAG_HEIGHT, 4); + R_DrawFill8(x, y, DRAW_LAG_WIDTH, DRAW_LAG_HEIGHT, 4); } SCR_LagDraw(x, y); } @@ -571,7 +582,7 @@ static void SCR_DrawNet(void) // draw phone jack if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged >= CMD_BACKUP) { if ((cls.realtime >> 8) & 3) { - R_DrawStretchPic(x, y, LAG_WIDTH, LAG_HEIGHT, scr.net_pic); + R_DrawStretchPic(x, y, DRAW_LAG_WIDTH, DRAW_LAG_HEIGHT, scr.net_pic); } } } @@ -1266,6 +1277,13 @@ static void scr_scale_changed(cvar_t *self) scr_crosshair_changed(scr_crosshair); } +static void scr_lag_draw_scale_changed(cvar_t *self) +{ + scr.lag_draw_scale = R_ClampScale(self); + + DRAW_LAG_WIDTH = LAG_WIDTH * scr_lag_draw_scale->value; + DRAW_LAG_HEIGHT = LAG_HEIGHT * scr_lag_draw_scale->value; +} static const cmdreg_t scr_cmds[] = { { "timerefresh", SCR_TimeRefresh_f }, @@ -1304,6 +1322,9 @@ void SCR_Init(void) scr_chathud_x = Cvar_Get("scr_chathud_x", "8", 0); scr_chathud_y = Cvar_Get("scr_chathud_y", "-64", 0); + scr_lag_draw_scale = Cvar_Get("scr_lag_draw_scale", "1", 0); + scr_lag_draw_scale->changed = scr_lag_draw_scale_changed; + xhair_dot = Cvar_Get("xhair_dot", "1",0); xhair_length = Cvar_Get("xhair_length","4",0); xhair_gap = Cvar_Get("xhair_gap", "10",0); @@ -1355,6 +1376,7 @@ void SCR_Init(void) scr_scale_changed(scr_scale); scr_crosshair_changed(scr_crosshair); + scr_lag_draw_scale_changed(scr_lag_draw_scale); scr.initialized = true; } diff --git a/src/client/ui/q2pro.menu b/src/client/ui/q2pro.menu index 6c3512428..1a9d2c8a6 100644 --- a/src/client/ui/q2pro.menu +++ b/src/client/ui/q2pro.menu @@ -163,6 +163,7 @@ begin screen pairs "HUD scale" scr_scale auto 0 1x 1 2x 2 4x 4 pairs "console scale" con_scale auto 0 1x 1 2x 2 4x 4 pairs "menu scale" ui_scale auto 0 1x 1 2x 2 4x 4 + pairs "Lag graph scale" scr_lag_draw_scale default 1 2x 2 3x 3 blank action --align "crosshair setup..." pushmenu crosshair end From 528b27dbfbd8bff7d68ee51b836f5d027d50399d Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Thu, 14 Dec 2023 13:20:09 -0500 Subject: [PATCH 085/167] Updated meson.build to support c11 fallback --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 49120721b..00b21e3fe 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,7 @@ project('q2pro', 'c', version: run_command(find_program('python3'), 'version.py', check: true).stdout().strip(), meson_version: '>= 0.59.0', default_options: [ - 'c_std=gnu99', + 'c_std=gnu99,c11', 'buildtype=debugoptimized', ], ) From 97204b6fe8ded4c388db99c3cf11b6296472d1b5 Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Thu, 14 Dec 2023 13:23:34 -0500 Subject: [PATCH 086/167] Updated meson.build to support c11 fallback --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 00b21e3fe..c65e4cb33 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,7 @@ project('q2pro', 'c', version: run_command(find_program('python3'), 'version.py', check: true).stdout().strip(), meson_version: '>= 0.59.0', default_options: [ - 'c_std=gnu99,c11', + meson.version().version_compare('>=1.3.0') ? 'c_std=gnu11,c11' : 'c_std=gnu11', 'buildtype=debugoptimized', ], ) From 02d534dfc124c64b2106e830730fa44052077152 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 13 Dec 2023 19:43:30 +0300 Subject: [PATCH 087/167] Reduce sizebuf_t size. --- inc/common/sizebuf.h | 10 +++++----- src/client/demo.c | 8 ++++---- src/client/parse.c | 22 +++++++++++----------- src/common/net/chan.c | 16 ++++++++-------- src/common/sizebuf.c | 4 +++- src/server/ac.c | 2 +- src/server/main.c | 2 +- src/server/mvd/client.c | 2 +- src/server/mvd/parse.c | 29 +++++++++++++++-------------- src/server/send.c | 6 +++--- 10 files changed, 52 insertions(+), 49 deletions(-) diff --git a/inc/common/sizebuf.h b/inc/common/sizebuf.h index 076a1bb52..29826ba49 100644 --- a/inc/common/sizebuf.h +++ b/inc/common/sizebuf.h @@ -22,12 +22,12 @@ typedef struct { bool allowoverflow; bool allowunderflow; bool overflowed; // set to true if the buffer size failed - byte *data; - size_t maxsize; - size_t cursize; - size_t readcount; + uint32_t maxsize; + uint32_t cursize; + uint32_t readcount; uint32_t bits_buf; uint32_t bits_left; + byte *data; const char *tag; // for debugging } sizebuf_t; @@ -45,7 +45,7 @@ static inline void *SZ_Write(sizebuf_t *buf, const void *data, size_t len) return memcpy(SZ_GetSpace(buf, len), data, len); } -static inline size_t SZ_Remaining(const sizebuf_t *buf) +static inline uint32_t SZ_Remaining(const sizebuf_t *buf) { if (buf->readcount > buf->cursize) return 0; diff --git a/src/client/demo.c b/src/client/demo.c index db29229cb..8a704e839 100644 --- a/src/client/demo.c +++ b/src/client/demo.c @@ -61,7 +61,7 @@ bool CL_WriteDemoMessage(sizebuf_t *buf) if (ret != buf->cursize) goto fail; - Com_DDPrintf("%s: wrote %zu bytes\n", __func__, buf->cursize); + Com_DDPrintf("%s: wrote %u bytes\n", __func__, buf->cursize); SZ_Clear(buf); return true; @@ -225,13 +225,13 @@ void CL_EmitDemoFrame(void) emit_delta_frame(oldframe, &cl.frame, lastframe, FRAME_CUR); if (cls.demo.buffer.cursize + msg_write.cursize > cls.demo.buffer.maxsize) { - Com_DPrintf("Demo frame overflowed (%zu + %zu > %zu)\n", + Com_DPrintf("Demo frame overflowed (%u + %u > %u)\n", cls.demo.buffer.cursize, msg_write.cursize, cls.demo.buffer.maxsize); cls.demo.frames_dropped++; // warn the user if drop rate is too high if (cls.demo.frames_written < 10 && cls.demo.frames_dropped == 50) - Com_WPrintf("Too many demo frames don't fit into %zu bytes.\n" + Com_WPrintf("Too many demo frames don't fit into %u bytes.\n" "Try to increase 'cl_demomsglen' value and restart recording.\n", cls.demo.buffer.maxsize); } else { @@ -861,7 +861,7 @@ void CL_EmitDemoSnapshot(void) cls.demo.snapshots = Z_Realloc(cls.demo.snapshots, sizeof(snap) * ALIGN(cls.demo.numsnapshots + 1, MIN_SNAPSHOTS)); cls.demo.snapshots[cls.demo.numsnapshots++] = snap; - Com_DPrintf("[%d] snaplen %zu\n", cls.demo.frames_read, msg_write.cursize); + Com_DPrintf("[%d] snaplen %u\n", cls.demo.frames_read, msg_write.cursize); SZ_Clear(&msg_write); diff --git a/src/client/parse.c b/src/client/parse.c index 0353d27c3..567479113 100644 --- a/src/client/parse.c +++ b/src/client/parse.c @@ -312,7 +312,7 @@ static void CL_ParseFrame(int extrabits) } } - SHOWNET(2, "%3zu:playerinfo\n", msg_read.readcount - 1); + SHOWNET(2, "%3u:playerinfo\n", msg_read.readcount - 1); // parse playerstate bits = MSG_ReadWord(); @@ -361,7 +361,7 @@ static void CL_ParseFrame(int extrabits) } } - SHOWNET(2, "%3zu:packetentities\n", msg_read.readcount - 1); + SHOWNET(2, "%3u:packetentities\n", msg_read.readcount - 1); CL_ParsePacketEntities(oldframe, &frame); @@ -372,7 +372,7 @@ static void CL_ParseFrame(int extrabits) if (cl_shownet->integer > 2) { int seq = cls.netchan.incoming_acknowledged & CMD_MASK; int rtt = cls.demo.playback ? 0 : cls.realtime - cl.history[seq].sent; - Com_LPrintf(PRINT_DEVELOPER, "%3zu:frame:%d delta:%d rtt:%d\n", + Com_LPrintf(PRINT_DEVELOPER, "%3u:frame:%d delta:%d rtt:%d\n", msg_read.readcount - 1, frame.number, frame.delta, rtt); } #endif @@ -1219,12 +1219,12 @@ CL_ParseServerMessage void CL_ParseServerMessage(void) { int cmd, index, extrabits; - size_t readcount; + uint32_t readcount; uint64_t bits; #if USE_DEBUG if (cl_shownet->integer == 1) { - Com_LPrintf(PRINT_DEVELOPER, "%zu ", msg_read.cursize); + Com_LPrintf(PRINT_DEVELOPER, "%u ", msg_read.cursize); } else if (cl_shownet->integer > 1) { Com_LPrintf(PRINT_DEVELOPER, "------------------\n"); } @@ -1238,7 +1238,7 @@ void CL_ParseServerMessage(void) while (1) { readcount = msg_read.readcount; if (readcount == msg_read.cursize) { - SHOWNET(1, "%3zu:END OF MESSAGE\n", readcount); + SHOWNET(1, "%3u:END OF MESSAGE\n", readcount); break; } @@ -1249,7 +1249,7 @@ void CL_ParseServerMessage(void) extrabits = cmd >> SVCMD_BITS; cmd &= SVCMD_MASK; - SHOWNET(1, "%3zu:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); + SHOWNET(1, "%3u:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); // other commands switch (cmd) { @@ -1364,7 +1364,7 @@ void CL_ParseServerMessage(void) // if recording demos, copy off protocol invariant stuff if (cls.demo.recording && !cls.demo.paused) { - size_t len = msg_read.readcount - readcount; + uint32_t len = msg_read.readcount - readcount; // it is very easy to overflow standard 1390 bytes // demo frame with modern servers... attempt to preserve @@ -1398,7 +1398,7 @@ bool CL_SeekDemoMessage(void) #if USE_DEBUG if (cl_shownet->integer == 1) { - Com_LPrintf(PRINT_DEVELOPER, "%zu ", msg_read.cursize); + Com_LPrintf(PRINT_DEVELOPER, "%u ", msg_read.cursize); } else if (cl_shownet->integer > 1) { Com_LPrintf(PRINT_DEVELOPER, "------------------\n"); } @@ -1411,12 +1411,12 @@ bool CL_SeekDemoMessage(void) // while (1) { if (msg_read.readcount == msg_read.cursize) { - SHOWNET(1, "%3zu:END OF MESSAGE\n", msg_read.readcount); + SHOWNET(1, "%3u:END OF MESSAGE\n", msg_read.readcount); break; } cmd = MSG_ReadByte(); - SHOWNET(1, "%3zu:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); + SHOWNET(1, "%3u:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); // other commands switch (cmd) { diff --git a/src/common/net/chan.c b/src/common/net/chan.c index ba682cf87..f6e79ace9 100644 --- a/src/common/net/chan.c +++ b/src/common/net/chan.c @@ -250,7 +250,7 @@ static size_t NetchanOld_Transmit(netchan_t *chan, size_t length, const void *da else Com_WPrintf("%s: dumped unreliable\n", NET_AdrToString(&chan->remote_address)); - SHOWPACKET("send %4zu : s=%d ack=%d rack=%d", + SHOWPACKET("send %4u : s=%d ack=%d rack=%d", send.cursize, chan->outgoing_sequence, chan->incoming_sequence, @@ -311,7 +311,7 @@ static bool NetchanOld_Process(netchan_t *chan) sequence &= OLD_MASK; sequence_ack &= OLD_MASK; - SHOWPACKET("recv %4zu : s=%d ack=%d rack=%d", + SHOWPACKET("recv %4u : s=%d ack=%d rack=%d", msg_read.cursize, sequence, sequence_ack, @@ -395,7 +395,7 @@ static size_t NetchanNew_TransmitNextFragment(netchan_t *chan) byte send_buf[MAX_PACKETLEN]; bool send_reliable, more_fragments; int w1, w2, offset; - size_t fragment_length; + unsigned fragment_length; send_reliable = chan->reliable_length; @@ -439,8 +439,8 @@ static size_t NetchanNew_TransmitNextFragment(netchan_t *chan) // write fragment contents SZ_Write(&send, chan->fragment_out.data + chan->fragment_out.readcount, fragment_length); - SHOWPACKET("send %4zu : s=%d ack=%d rack=%d " - "fragment_offset=%zu more_fragments=%d", + SHOWPACKET("send %4u : s=%d ack=%d rack=%d " + "fragment_offset=%u more_fragments=%d", send.cursize, chan->outgoing_sequence, chan->incoming_sequence, @@ -552,7 +552,7 @@ static size_t NetchanNew_Transmit(netchan_t *chan, size_t length, const void *da // add the unreliable part SZ_Write(&send, data, length); - SHOWPACKET("send %4zu : s=%d ack=%d rack=%d", + SHOWPACKET("send %4u : s=%d ack=%d rack=%d", send.cursize, chan->outgoing_sequence, chan->incoming_sequence, @@ -583,7 +583,7 @@ static bool NetchanNew_Process(netchan_t *chan) { int sequence, sequence_ack, fragment_offset; bool reliable_message, reliable_ack, fragmented_message, more_fragments; - size_t length; + unsigned length; // get sequence numbers MSG_BeginReading(); @@ -616,7 +616,7 @@ static bool NetchanNew_Process(netchan_t *chan) return false; } - SHOWPACKET("recv %4zu : s=%d ack=%d rack=%d", + SHOWPACKET("recv %4u : s=%d ack=%d rack=%d", msg_read.cursize, sequence, sequence_ack, reliable_ack); if (fragmented_message) { SHOWPACKET(" fragment_offset=%d more_fragments=%d", diff --git a/src/common/sizebuf.c b/src/common/sizebuf.c index 212fab3a5..686c57e40 100644 --- a/src/common/sizebuf.c +++ b/src/common/sizebuf.c @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., void SZ_TagInit(sizebuf_t *buf, void *data, size_t size, const char *tag) { + Q_assert(size <= INT32_MAX); memset(buf, 0, sizeof(*buf)); buf->data = data; buf->maxsize = size; @@ -31,6 +32,7 @@ void SZ_TagInit(sizebuf_t *buf, void *data, size_t size, const char *tag) void SZ_Init(sizebuf_t *buf, void *data, size_t size) { + Q_assert(size <= INT32_MAX); memset(buf, 0, sizeof(*buf)); buf->data = data; buf->maxsize = size; @@ -59,7 +61,7 @@ void *SZ_GetSpace(sizebuf_t *buf, size_t len) if (len > buf->maxsize - buf->cursize) { if (len > buf->maxsize) { Com_Error(ERR_FATAL, - "%s: %s: %zu is > full buffer size %zu", + "%s: %s: %zu is > full buffer size %u", __func__, buf->tag, len, buf->maxsize); } diff --git a/src/server/ac.c b/src/server/ac.c index 02131c794..131d0c52b 100644 --- a/src/server/ac.c +++ b/src/server/ac.c @@ -972,7 +972,7 @@ static bool AC_ParseMessage(void) } if (msg_read.readcount > msg_read.cursize) { - Com_WPrintf("ANTICHEAT: Read %zu bytes past end of message %d\n", + Com_WPrintf("ANTICHEAT: Read %u bytes past end of message %d\n", msg_read.readcount - msg_read.cursize, cmd); } diff --git a/src/server/main.c b/src/server/main.c index d9e8e00d5..3689cb467 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -1789,7 +1789,7 @@ static void SV_RunGameFrame(void) #endif if (msg_write.cursize) { - Com_WPrintf("Game left %zu bytes " + Com_WPrintf("Game left %u bytes " "in multicast buffer, cleared.\n", msg_write.cursize); SZ_Clear(&msg_write); diff --git a/src/server/mvd/client.c b/src/server/mvd/client.c index b92dfc9c8..7e303ba79 100644 --- a/src/server/mvd/client.c +++ b/src/server/mvd/client.c @@ -644,7 +644,7 @@ static void demo_emit_snapshot(mvd_t *mvd) mvd->snapshots = Z_Realloc(mvd->snapshots, sizeof(snap) * ALIGN(mvd->numsnapshots + 1, MIN_SNAPSHOTS)); mvd->snapshots[mvd->numsnapshots++] = snap; - Com_DPrintf("[%d] snaplen %zu\n", mvd->framenum, msg_write.cursize); + Com_DPrintf("[%d] snaplen %u\n", mvd->framenum, msg_write.cursize); SZ_Clear(&msg_write); diff --git a/src/server/mvd/parse.c b/src/server/mvd/parse.c index 3caeb2482..4a577101a 100644 --- a/src/server/mvd/parse.c +++ b/src/server/mvd/parse.c @@ -257,7 +257,8 @@ static void MVD_UnicastString(mvd_t *mvd, bool reliable, mvd_player_t *player) char string[MAX_QPATH]; mvd_cs_t *cs; byte *data; - size_t readcount, length; + size_t length; + uint32_t readcount; data = msg_read.data + msg_read.readcount - 1; readcount = msg_read.readcount - 1; @@ -302,7 +303,7 @@ static void MVD_UnicastPrint(mvd_t *mvd, bool reliable, mvd_player_t *player) { int level; byte *data; - size_t readcount, length; + uint32_t readcount, length; mvd_client_t *client; client_t *cl; mvd_player_t *target; @@ -342,7 +343,7 @@ static void MVD_UnicastStuff(mvd_t *mvd, bool reliable, mvd_player_t *player) { char string[8]; byte *data; - size_t readcount, length; + uint32_t readcount, length; if (mvd->demoseeking) { MSG_ReadString(NULL, 0); @@ -370,7 +371,7 @@ layouts, etc. Give up as soon as unknown command byte is encountered. static void MVD_ParseUnicast(mvd_t *mvd, mvd_ops_t op, int extrabits) { int clientNum; - size_t length, last; + uint32_t length, last; mvd_player_t *player; byte *data; bool reliable; @@ -396,7 +397,7 @@ static void MVD_ParseUnicast(mvd_t *mvd, mvd_ops_t op, int extrabits) while (msg_read.readcount < last) { cmd = MSG_ReadByte(); - SHOWNET(1, "%3zu:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); + SHOWNET(1, "%3u:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); switch (cmd) { case svc_layout: @@ -412,7 +413,7 @@ static void MVD_ParseUnicast(mvd_t *mvd, mvd_ops_t op, int extrabits) MVD_UnicastStuff(mvd, reliable, player); break; default: - SHOWNET(1, "%3zu:SKIPPING UNICAST\n", msg_read.readcount - 1); + SHOWNET(1, "%3u:SKIPPING UNICAST\n", msg_read.readcount - 1); // send remaining data and return data = msg_read.data + msg_read.readcount - 1; length = last - msg_read.readcount + 1; @@ -423,7 +424,7 @@ static void MVD_ParseUnicast(mvd_t *mvd, mvd_ops_t op, int extrabits) } } - SHOWNET(1, "%3zu:END OF UNICAST\n", msg_read.readcount); + SHOWNET(1, "%3u:END OF UNICAST\n", msg_read.readcount); if (msg_read.readcount > last) { MVD_Destroyf(mvd, "%s: read past end of unicast", __func__); @@ -789,11 +790,11 @@ static void MVD_ParseFrame(mvd_t *mvd) if (!mvd->demoseeking) CM_SetPortalStates(&mvd->cm, data, length); - SHOWNET(1, "%3zu:playerinfo\n", msg_read.readcount); + SHOWNET(1, "%3u:playerinfo\n", msg_read.readcount); MVD_ParsePacketPlayers(mvd); - SHOWNET(1, "%3zu:packetentities\n", msg_read.readcount); + SHOWNET(1, "%3u:packetentities\n", msg_read.readcount); MVD_ParsePacketEntities(mvd); - SHOWNET(1, "%3zu:frame:%u\n", msg_read.readcount, mvd->framenum); + SHOWNET(1, "%3u:frame:%u\n", msg_read.readcount, mvd->framenum); MVD_PlayerToEntityStates(mvd); // update clients now so that effects datagram that @@ -1058,7 +1059,7 @@ bool MVD_ParseMessage(mvd_t *mvd) #if USE_DEBUG if (mvd_shownet->integer == 1) { - Com_LPrintf(PRINT_DEVELOPER, "%zu ", msg_read.cursize); + Com_LPrintf(PRINT_DEVELOPER, "%u ", msg_read.cursize); } else if (mvd_shownet->integer > 1) { Com_LPrintf(PRINT_DEVELOPER, "------------------\n"); } @@ -1073,7 +1074,7 @@ bool MVD_ParseMessage(mvd_t *mvd) MVD_Destroyf(mvd, "Read past end of message"); } if (msg_read.readcount == msg_read.cursize) { - SHOWNET(1, "%3zu:END OF MESSAGE\n", msg_read.readcount); + SHOWNET(1, "%3u:END OF MESSAGE\n", msg_read.readcount); break; } @@ -1081,7 +1082,7 @@ bool MVD_ParseMessage(mvd_t *mvd) extrabits = cmd >> SVCMD_BITS; cmd &= SVCMD_MASK; - SHOWNET(1, "%3zu:%s\n", msg_read.readcount - 1, MVD_ServerCommandString(cmd)); + SHOWNET(1, "%3u:%s\n", msg_read.readcount - 1, MVD_ServerCommandString(cmd)); switch (cmd) { case mvd_serverdata: @@ -1115,7 +1116,7 @@ bool MVD_ParseMessage(mvd_t *mvd) case mvd_nop: break; default: - MVD_Destroyf(mvd, "Illegible command at %zu: %d", + MVD_Destroyf(mvd, "Illegible command at %u: %d", msg_read.readcount - 1, cmd); } } diff --git a/src/server/send.c b/src/server/send.c index 1499b74d0..8f1298cbc 100644 --- a/src/server/send.c +++ b/src/server/send.c @@ -358,7 +358,7 @@ static int compress_message(client_t *client) deflateReset(&svs.z); if (ret != Z_STREAM_END) { - Com_WPrintf("Error %d compressing %zu bytes message for %s\n", + Com_WPrintf("Error %d compressing %u bytes message for %s\n", ret, msg_write.cursize, client->name); return 0; } @@ -405,11 +405,11 @@ void SV_ClientAddMessage(client_t *client, int flags) if ((flags & MSG_COMPRESS) && (len = compress_message(client)) && len < msg_write.cursize) { client->AddMessage(client, get_compressed_data(), len, flags & MSG_RELIABLE); - SV_DPrintf(0, "Compressed %sreliable message to %s: %zu into %d\n", + SV_DPrintf(0, "Compressed %sreliable message to %s: %u into %d\n", (flags & MSG_RELIABLE) ? "" : "un", client->name, msg_write.cursize, len); } else { client->AddMessage(client, msg_write.data, msg_write.cursize, flags & MSG_RELIABLE); - SV_DPrintf(1, "Added %sreliable message to %s: %zu bytes\n", + SV_DPrintf(1, "Added %sreliable message to %s: %u bytes\n", (flags & MSG_RELIABLE) ? "" : "un", client->name, msg_write.cursize); } From 4f8e9559fc2e10cbbeedaaf7e1c7ef258f147575 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 14 Dec 2023 01:04:48 +0300 Subject: [PATCH 088/167] Avoid using size_t where int is sufficient. --- inc/common/net/chan.h | 8 ++++---- src/client/client.h | 4 ++-- src/client/input.c | 15 ++++++++------- src/common/net/chan.c | 8 ++++---- src/server/ac.c | 2 +- src/server/commands.c | 4 ++-- src/server/main.c | 4 ++-- src/server/mvd/client.c | 2 +- src/server/mvd/client.h | 4 ++-- src/server/send.c | 34 +++++++++++++++++----------------- src/server/server.h | 2 +- 11 files changed, 44 insertions(+), 43 deletions(-) diff --git a/inc/common/net/chan.h b/inc/common/net/chan.h index fd43c2f2c..9782a6dc3 100644 --- a/inc/common/net/chan.h +++ b/inc/common/net/chan.h @@ -30,7 +30,7 @@ typedef enum netchan_type_e { typedef struct netchan_s { netchan_type_t type; int protocol; - size_t maxpacketlen; + unsigned maxpacketlen; bool fatal_error; @@ -48,7 +48,7 @@ typedef struct netchan_s { sizebuf_t message; // writing buffer for reliable data - size_t reliable_length; + unsigned reliable_length; bool reliable_ack_pending; // set to true each time reliable is received bool fragment_pending; @@ -76,8 +76,8 @@ typedef struct netchan_s { byte *fragment_out_buf; // common methods - size_t (*Transmit)(struct netchan_s *, size_t, const void *, int); - size_t (*TransmitNextFragment)(struct netchan_s *); + int (*Transmit)(struct netchan_s *, size_t, const void *, int); + int (*TransmitNextFragment)(struct netchan_s *); bool (*Process)(struct netchan_s *); bool (*ShouldUpdate)(struct netchan_s *); } netchan_t; diff --git a/src/client/client.h b/src/client/client.h index d429c7c34..083d355ab 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -373,8 +373,8 @@ typedef struct { typedef struct { int framenum; + unsigned msglen; int64_t filepos; - size_t msglen; byte data[1]; } demosnap_t; @@ -486,7 +486,7 @@ typedef struct client_static_s { connstate_t state; netstream_t stream; - size_t msglen; + unsigned msglen; player_packed_t ps; entity_packed_t entities[MAX_EDICTS]; diff --git a/src/client/input.c b/src/client/input.c index ce6bc7ebd..4d87f5b72 100644 --- a/src/client/input.c +++ b/src/client/input.c @@ -869,7 +869,8 @@ CL_SendDefaultCmd */ static void CL_SendDefaultCmd(void) { - size_t cursize q_unused, checksumIndex; + int cursize q_unused; + uint32_t checksumIndex; usercmd_t *cmd, *oldcmd; client_history_t *history; int version; @@ -944,7 +945,7 @@ static void CL_SendDefaultCmd(void) cursize = cls.netchan.Transmit(&cls.netchan, msg_write.cursize, msg_write.data, 1); #if USE_DEBUG if (cl_showpackets->integer) { - Com_Printf("%zu ", cursize); + Com_Printf("%i ", cursize); } #endif @@ -961,7 +962,7 @@ static void CL_SendBatchedCmd(void) int i, j, seq, bits q_unused; int numCmds, numDups; int totalCmds, totalMsec; - size_t cursize q_unused; + int cursize q_unused; usercmd_t *cmd, *oldcmd; client_history_t *history, *oldest; byte *patch; @@ -1044,9 +1045,9 @@ static void CL_SendBatchedCmd(void) cursize = cls.netchan.Transmit(&cls.netchan, msg_write.cursize, msg_write.data, 1); #if USE_DEBUG if (cl_showpackets->integer == 1) { - Com_Printf("%zu(%i) ", cursize, totalCmds); + Com_Printf("%i(%i) ", cursize, totalCmds); } else if (cl_showpackets->integer == 2) { - Com_Printf("%zu(%i) ", cursize, totalMsec); + Com_Printf("%i(%i) ", cursize, totalMsec); } else if (cl_showpackets->integer == 3) { Com_Printf(" | "); } @@ -1058,7 +1059,7 @@ static void CL_SendBatchedCmd(void) static void CL_SendKeepAlive(void) { client_history_t *history; - size_t cursize q_unused; + int cursize q_unused; // archive this packet history = &cl.history[cls.netchan.outgoing_sequence & CMD_MASK]; @@ -1073,7 +1074,7 @@ static void CL_SendKeepAlive(void) cursize = cls.netchan.Transmit(&cls.netchan, 0, "", 1); #if USE_DEBUG if (cl_showpackets->integer) { - Com_Printf("%zu ", cursize); + Com_Printf("%i ", cursize); } #endif } diff --git a/src/common/net/chan.c b/src/common/net/chan.c index f6e79ace9..7afc9230f 100644 --- a/src/common/net/chan.c +++ b/src/common/net/chan.c @@ -166,7 +166,7 @@ void Netchan_OutOfBand(netsrc_t sock, const netadr_t *address, const char *forma // ============================================================================ -static size_t NetchanOld_TransmitNextFragment(netchan_t *netchan) +static int NetchanOld_TransmitNextFragment(netchan_t *netchan) { Q_assert(!"not implemented"); return 0; @@ -182,7 +182,7 @@ transmition / retransmition of the reliable messages. A 0 length will still generate a packet and deal with the reliable messages. ================ */ -static size_t NetchanOld_Transmit(netchan_t *chan, size_t length, const void *data, int numpackets) +static int NetchanOld_Transmit(netchan_t *chan, size_t length, const void *data, int numpackets) { sizebuf_t send; byte send_buf[MAX_PACKETLEN]; @@ -389,7 +389,7 @@ static bool NetchanOld_ShouldUpdate(netchan_t *chan) NetchanNew_TransmitNextFragment ================ */ -static size_t NetchanNew_TransmitNextFragment(netchan_t *chan) +static int NetchanNew_TransmitNextFragment(netchan_t *chan) { sizebuf_t send; byte send_buf[MAX_PACKETLEN]; @@ -473,7 +473,7 @@ static size_t NetchanNew_TransmitNextFragment(netchan_t *chan) NetchanNew_Transmit ================ */ -static size_t NetchanNew_Transmit(netchan_t *chan, size_t length, const void *data, int numpackets) +static int NetchanNew_Transmit(netchan_t *chan, size_t length, const void *data, int numpackets) { sizebuf_t send; byte send_buf[MAX_PACKETLEN]; diff --git a/src/server/ac.c b/src/server/ac.c index 131d0c52b..3fc0d2697 100644 --- a/src/server/ac.c +++ b/src/server/ac.c @@ -90,7 +90,7 @@ typedef struct { bool ping_pending; unsigned last_ping; netstream_t stream; - size_t msglen; + unsigned msglen; } ac_locals_t; typedef struct { diff --git a/src/server/commands.c b/src/server/commands.c index a46ccafdd..a8f9be696 100644 --- a/src/server/commands.c +++ b/src/server/commands.c @@ -631,7 +631,7 @@ static void dump_protocols(void) "--- --------------- ----- ----- ------ ---- ----\n"); FOR_EACH_CLIENT(cl) { - Com_Printf("%3i %-15.15s %5d %5d %6zu %s %s\n", + Com_Printf("%3i %-15.15s %5d %5d %6u %s %s\n", cl->number, cl->name, cl->protocol, cl->version, cl->netchan.maxpacketlen, cl->has_zlib ? "yes" : "no ", @@ -773,7 +773,7 @@ void SV_PrintMiscInfo(void) sv_client->version_string ? sv_client->version_string : "-"); Com_Printf("protocol (maj/min) %d/%d\n", sv_client->protocol, sv_client->version); - Com_Printf("maxmsglen %zu\n", sv_client->netchan.maxpacketlen); + Com_Printf("maxmsglen %u\n", sv_client->netchan.maxpacketlen); Com_Printf("zlib support %s\n", sv_client->has_zlib ? "yes" : "no"); Com_Printf("netchan type %s\n", sv_client->netchan.type ? "new" : "old"); Com_Printf("ping %d\n", sv_client->ping); diff --git a/src/server/main.c b/src/server/main.c index 3689cb467..8bc68443f 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -1565,7 +1565,7 @@ static void SV_PacketEvent(void) static void update_client_mtu(client_t *client, int ee_info) { netchan_t *netchan = &client->netchan; - size_t newpacketlen; + unsigned newpacketlen; // sanity check discovered MTU if (ee_info < 576 || ee_info > 4096) @@ -1585,7 +1585,7 @@ static void update_client_mtu(client_t *client, int ee_info) if (newpacketlen >= netchan->maxpacketlen) return; - Com_Printf("Fixing up maxmsglen for %s: %zu --> %zu\n", + Com_Printf("Fixing up maxmsglen for %s: %u --> %u\n", client->name, netchan->maxpacketlen, newpacketlen); netchan->maxpacketlen = newpacketlen; } diff --git a/src/server/mvd/client.c b/src/server/mvd/client.c index 7e303ba79..50a7787b0 100644 --- a/src/server/mvd/client.c +++ b/src/server/mvd/client.c @@ -60,7 +60,7 @@ typedef struct gtv_s { netstream_t stream; char address[MAX_QPATH]; byte *data; - size_t msglen; + unsigned msglen; unsigned flags; #if USE_ZLIB bool z_act; // true when actively inflating diff --git a/src/server/mvd/client.h b/src/server/mvd/client.h index 87310706f..27dc782a9 100644 --- a/src/server/mvd/client.h +++ b/src/server/mvd/client.h @@ -115,8 +115,8 @@ typedef enum { typedef struct { int framenum; + unsigned msglen; int64_t filepos; - size_t msglen; byte data[1]; } mvd_snap_t; @@ -144,7 +144,7 @@ typedef struct mvd_s { // delay buffer fifo_t delay; - size_t msglen; + unsigned msglen; unsigned num_packets, min_packets; unsigned underflows, overflows; int framenum; diff --git a/src/server/send.c b/src/server/send.c index 8f1298cbc..b02dc23c5 100644 --- a/src/server/send.c +++ b/src/server/send.c @@ -86,7 +86,7 @@ static bool SV_RateDrop(client_t *client) return false; } -static void SV_CalcSendTime(client_t *client, size_t size) +static void SV_CalcSendTime(client_t *client, unsigned size) { // never drop over the loopback if (!client->rate) { @@ -565,7 +565,7 @@ static void emit_snd(client_t *client, message_packet_t *msg) } } -static inline void write_snd(client_t *client, message_packet_t *msg, size_t maxsize) +static inline void write_snd(client_t *client, message_packet_t *msg, unsigned maxsize) { // if this msg fits, write it if (msg_write.cursize + MAX_SOUND_PACKET <= maxsize) { @@ -575,7 +575,7 @@ static inline void write_snd(client_t *client, message_packet_t *msg, size_t max List_Insert(&client->msg_free_list, &msg->entry); } -static inline void write_msg(client_t *client, message_packet_t *msg, size_t maxsize) +static inline void write_msg(client_t *client, message_packet_t *msg, unsigned maxsize) { // if this msg fits, write it if (msg_write.cursize + msg->cursize <= maxsize) { @@ -584,7 +584,7 @@ static inline void write_msg(client_t *client, message_packet_t *msg, size_t max free_msg_packet(client, msg); } -static inline void write_unreliables(client_t *client, size_t maxsize) +static inline void write_unreliables(client_t *client, unsigned maxsize) { message_packet_t *msg, *next; @@ -621,7 +621,7 @@ static void add_message_old(client_t *client, byte *data, } // this should be the only place data is ever written to netchan message for old clients -static void write_reliables_old(client_t *client, size_t maxsize) +static void write_reliables_old(client_t *client, unsigned maxsize) { message_packet_t *msg, *next; int count; @@ -654,7 +654,7 @@ static void write_reliables_old(client_t *client, size_t maxsize) } // unreliable portion doesn't fit, then throw out low priority effects -static void repack_unreliables(client_t *client, size_t maxsize) +static void repack_unreliables(client_t *client, unsigned maxsize) { message_packet_t *msg, *next; @@ -713,7 +713,7 @@ static void repack_unreliables(client_t *client, size_t maxsize) static void write_datagram_old(client_t *client) { message_packet_t *msg; - size_t maxsize, cursize; + unsigned maxsize, cursize; // determine how much space is left for unreliable data maxsize = client->netchan.maxpacketlen; @@ -734,7 +734,7 @@ static void write_datagram_old(client_t *client) // and the player_state_t client->WriteFrame(client); if (msg_write.cursize > maxsize) { - size_t size = msg_write.cursize; + unsigned size = msg_write.cursize; int len = 0; // try to compress if it has a chance to fit @@ -745,11 +745,11 @@ static void write_datagram_old(client_t *client) SZ_Clear(&msg_write); if (len > 0 && len <= maxsize) { - SV_DPrintf(0, "Frame %d compressed for %s: %zu into %d\n", + SV_DPrintf(0, "Frame %d compressed for %s: %u into %d\n", client->framenum, client->name, size, len); SZ_Write(&msg_write, get_compressed_data(), len); } else { - SV_DPrintf(0, "Frame %d overflowed for %s: %zu > %zu (comp %d)\n", + SV_DPrintf(0, "Frame %d overflowed for %s: %u > %u (comp %d)\n", client->framenum, client->name, size, maxsize, len); } } @@ -770,7 +770,7 @@ static void write_datagram_old(client_t *client) #if USE_DEBUG if (sv_pad_packets->integer > 0) { - size_t pad = min(MAX_PACKETLEN - 8, sv_pad_packets->integer); + int pad = min(MAX_PACKETLEN - 8, sv_pad_packets->integer); while (msg_write.cursize < pad) MSG_WriteByte(svc_nop); @@ -812,7 +812,7 @@ static void add_message_new(client_t *client, byte *data, static void write_datagram_new(client_t *client) { - size_t cursize; + int cursize; // send over all the relevant entity_state_t // and the player_state_t @@ -836,7 +836,7 @@ static void write_datagram_new(client_t *client) #if USE_DEBUG if (sv_pad_packets->integer > 0) { - size_t pad = min(msg_write.maxsize, sv_pad_packets->integer); + int pad = min(msg_write.maxsize, sv_pad_packets->integer); while (msg_write.cursize < pad) MSG_WriteByte(svc_nop); @@ -901,7 +901,7 @@ Clients in earlier connection state are handled in SV_SendAsyncPackets. void SV_SendClientMessages(void) { client_t *client; - size_t cursize; + int cursize; // send a message to each connected client FOR_EACH_CLIENT(client) { @@ -1001,7 +1001,7 @@ void SV_SendAsyncPackets(void) bool retransmit; client_t *client; netchan_t *netchan; - size_t cursize; + int cursize; FOR_EACH_CLIENT(client) { // don't overrun bandwidth @@ -1014,7 +1014,7 @@ void SV_SendAsyncPackets(void) // make sure all fragments are transmitted first if (netchan->fragment_pending) { cursize = netchan->TransmitNextFragment(netchan); - SV_DPrintf(1, "%s: frag: %zu\n", client->name, cursize); + SV_DPrintf(1, "%s: frag: %d\n", client->name, cursize); goto calctime; } @@ -1042,7 +1042,7 @@ void SV_SendAsyncPackets(void) if (netchan->message.cursize || netchan->reliable_ack_pending || netchan->reliable_length || retransmit) { cursize = netchan->Transmit(netchan, 0, "", 1); - SV_DPrintf(1, "%s: send: %zu\n", client->name, cursize); + SV_DPrintf(1, "%s: send: %d\n", client->name, cursize); calctime: SV_CalcSendTime(client, cursize); } diff --git a/src/server/server.h b/src/server/server.h index 1bc6151da..14e838475 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -474,7 +474,7 @@ typedef struct server_static_s { #if USE_ZLIB z_stream z; // for compressing messages at once byte *z_buffer; - size_t z_buffer_size; + unsigned z_buffer_size; #endif cs_remap_t csr; From ade77dd12ca2fe0bca4815730d291777b5097ce9 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 14 Dec 2023 01:16:44 +0300 Subject: [PATCH 089/167] Avoid having redundant fields in netchan_t. --- inc/common/net/chan.h | 5 ----- src/common/net/chan.c | 27 +++++++++++++-------------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/inc/common/net/chan.h b/inc/common/net/chan.h index 9782a6dc3..0a0309043 100644 --- a/inc/common/net/chan.h +++ b/inc/common/net/chan.h @@ -64,16 +64,11 @@ typedef struct netchan_s { int last_reliable_sequence; // sequence number of last send int fragment_sequence; - byte *message_buf; // leave space for header - // message is copied to this buffer when it is first transfered byte *reliable_buf; // unacked reliable message sizebuf_t fragment_in; - byte *fragment_in_buf; - sizebuf_t fragment_out; - byte *fragment_out_buf; // common methods int (*Transmit)(struct netchan_s *, size_t, const void *, int); diff --git a/src/common/net/chan.c b/src/common/net/chan.c index 7afc9230f..c5804bb5c 100644 --- a/src/common/net/chan.c +++ b/src/common/net/chan.c @@ -207,7 +207,7 @@ static int NetchanOld_Transmit(netchan_t *chan, size_t length, const void *data, // if the reliable transmit buffer is empty, copy the current message out if (!chan->reliable_length && chan->message.cursize) { send_reliable = true; - memcpy(chan->reliable_buf, chan->message_buf, chan->message.cursize); + memcpy(chan->reliable_buf, chan->message.data, chan->message.cursize); chan->reliable_length = chan->message.cursize; chan->message.cursize = 0; chan->reliable_sequence ^= 1; @@ -502,7 +502,7 @@ static int NetchanNew_Transmit(netchan_t *chan, size_t length, const void *data, // if the reliable transmit buffer is empty, copy the current message out if (!chan->reliable_length && chan->message.cursize) { send_reliable = true; - memcpy(chan->reliable_buf, chan->message_buf, chan->message.cursize); + memcpy(chan->reliable_buf, chan->message.data, chan->message.cursize); chan->reliable_length = chan->message.cursize; chan->message.cursize = 0; chan->reliable_sequence ^= 1; @@ -740,9 +740,10 @@ void Netchan_Setup(netchan_t *chan, netsrc_t sock, netchan_type_t type, const netadr_t *adr, int qport, size_t maxpacketlen, int protocol) { memtag_t tag = sock == NS_SERVER ? TAG_SERVER : TAG_GENERAL; + byte *buf; Q_assert(chan); - Q_assert(!chan->message_buf); + Q_assert(!chan->message.data); Q_assert(adr); Q_assert(maxpacketlen >= MIN_PACKETLEN); Q_assert(maxpacketlen <= MAX_PACKETLEN_WRITABLE); @@ -765,10 +766,10 @@ void Netchan_Setup(netchan_t *chan, netsrc_t sock, netchan_type_t type, chan->TransmitNextFragment = NetchanOld_TransmitNextFragment; chan->ShouldUpdate = NetchanOld_ShouldUpdate; - chan->message_buf = Z_TagMalloc(maxpacketlen * 2, tag); - chan->reliable_buf = chan->message_buf + maxpacketlen; + buf = Z_TagMalloc(maxpacketlen * 2, tag); + chan->reliable_buf = buf + maxpacketlen; - SZ_Init(&chan->message, chan->message_buf, maxpacketlen); + SZ_Init(&chan->message, buf, maxpacketlen); break; case NETCHAN_NEW: @@ -777,14 +778,12 @@ void Netchan_Setup(netchan_t *chan, netsrc_t sock, netchan_type_t type, chan->TransmitNextFragment = NetchanNew_TransmitNextFragment; chan->ShouldUpdate = NetchanNew_ShouldUpdate; - chan->message_buf = Z_TagMalloc(MAX_MSGLEN * 4, tag); - chan->reliable_buf = chan->message_buf + MAX_MSGLEN; - chan->fragment_in_buf = chan->message_buf + MAX_MSGLEN * 2; - chan->fragment_out_buf = chan->message_buf + MAX_MSGLEN * 3; + buf = Z_TagMalloc(MAX_MSGLEN * 4, tag); + chan->reliable_buf = buf + MAX_MSGLEN; - SZ_Init(&chan->message, chan->message_buf, MAX_MSGLEN); - SZ_TagInit(&chan->fragment_in, chan->fragment_in_buf, MAX_MSGLEN, "nc_frg_in"); - SZ_TagInit(&chan->fragment_out, chan->fragment_out_buf, MAX_MSGLEN, "nc_frg_out"); + SZ_Init(&chan->message, buf, MAX_MSGLEN); + SZ_TagInit(&chan->fragment_in, buf + MAX_MSGLEN * 2, MAX_MSGLEN, "nc_frg_in"); + SZ_TagInit(&chan->fragment_out, buf + MAX_MSGLEN * 3, MAX_MSGLEN, "nc_frg_out"); break; default: @@ -800,6 +799,6 @@ Netchan_Close void Netchan_Close(netchan_t *chan) { Q_assert(chan); - Z_Free(chan->message_buf); + Z_Free(chan->message.data); memset(chan, 0, sizeof(*chan)); } From fed8177d880429f8fb4793b2f5d54565f8295493 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 14 Dec 2023 01:48:56 +0300 Subject: [PATCH 090/167] Avoid storing netchan methods in netchan_t. --- inc/common/net/chan.h | 14 +++++----- src/client/input.c | 8 +++--- src/client/main.c | 6 ++--- src/common/net/chan.c | 63 +++++++++++++++++-------------------------- src/server/main.c | 6 ++--- src/server/send.c | 22 +++++++-------- 6 files changed, 52 insertions(+), 67 deletions(-) diff --git a/inc/common/net/chan.h b/inc/common/net/chan.h index 0a0309043..10a9490d8 100644 --- a/inc/common/net/chan.h +++ b/inc/common/net/chan.h @@ -69,12 +69,6 @@ typedef struct netchan_s { sizebuf_t fragment_in; sizebuf_t fragment_out; - - // common methods - int (*Transmit)(struct netchan_s *, size_t, const void *, int); - int (*TransmitNextFragment)(struct netchan_s *); - bool (*Process)(struct netchan_s *); - bool (*ShouldUpdate)(struct netchan_s *); } netchan_t; extern cvar_t *net_qport; @@ -84,9 +78,13 @@ extern cvar_t *net_chantype; void Netchan_Init(void); void Netchan_OutOfBand(netsrc_t sock, const netadr_t *adr, const char *format, ...) q_printf(3, 4); -void Netchan_Setup(netchan_t *netchan, netsrc_t sock, netchan_type_t type, +void Netchan_Setup(netchan_t *chan, netsrc_t sock, netchan_type_t type, const netadr_t *adr, int qport, size_t maxpacketlen, int protocol); -void Netchan_Close(netchan_t *netchan); +int Netchan_Transmit(netchan_t *chan, size_t length, const void *data, int numpackets); +int Netchan_TransmitNextFragment(netchan_t *chan); +bool Netchan_Process(netchan_t *chan); +bool Netchan_ShouldUpdate(netchan_t *chan); +void Netchan_Close(netchan_t *chan); #define OOB_PRINT(sock, addr, data) \ NET_SendPacket(sock, CONST_STR_LEN("\xff\xff\xff\xff" data), addr) diff --git a/src/client/input.c b/src/client/input.c index 4d87f5b72..6bef7f11d 100644 --- a/src/client/input.c +++ b/src/client/input.c @@ -942,7 +942,7 @@ static void CL_SendDefaultCmd(void) // // deliver the message // - cursize = cls.netchan.Transmit(&cls.netchan, msg_write.cursize, msg_write.data, 1); + cursize = Netchan_Transmit(&cls.netchan, msg_write.cursize, msg_write.data, 1); #if USE_DEBUG if (cl_showpackets->integer) { Com_Printf("%i ", cursize); @@ -1042,7 +1042,7 @@ static void CL_SendBatchedCmd(void) // // deliver the message // - cursize = cls.netchan.Transmit(&cls.netchan, msg_write.cursize, msg_write.data, 1); + cursize = Netchan_Transmit(&cls.netchan, msg_write.cursize, msg_write.data, 1); #if USE_DEBUG if (cl_showpackets->integer == 1) { Com_Printf("%i(%i) ", cursize, totalCmds); @@ -1071,7 +1071,7 @@ static void CL_SendKeepAlive(void) cl.lastTransmitCmdNumber = cl.cmdNumber; cl.lastTransmitCmdNumberReal = cl.cmdNumber; - cursize = cls.netchan.Transmit(&cls.netchan, 0, "", 1); + cursize = Netchan_Transmit(&cls.netchan, 0, "", 1); #if USE_DEBUG if (cl_showpackets->integer) { Com_Printf("%i ", cursize); @@ -1141,7 +1141,7 @@ void CL_SendCmd(void) CL_SendReliable(); // just keepalive or update reliable - if (cls.netchan.ShouldUpdate(&cls.netchan)) { + if (Netchan_ShouldUpdate(&cls.netchan)) { CL_SendKeepAlive(); } diff --git a/src/client/main.c b/src/client/main.c index 96f4260d1..d3a75cffb 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -743,7 +743,7 @@ void CL_Disconnect(error_type_t type) MSG_WriteByte(clc_stringcmd); MSG_WriteData("disconnect", 11); - cls.netchan.Transmit(&cls.netchan, msg_write.cursize, msg_write.data, 3); + Netchan_Transmit(&cls.netchan, msg_write.cursize, msg_write.data, 3); SZ_Clear(&msg_write); @@ -1385,7 +1385,7 @@ static void CL_ConnectionlessPacket(void) if (anticheat) { MSG_WriteByte(clc_nop); MSG_FlushTo(&cls.netchan.message); - cls.netchan.Transmit(&cls.netchan, 0, "", 3); + Netchan_Transmit(&cls.netchan, 0, "", 3); S_StopAllSounds(); cls.connect_count = -1; Com_Printf("Loading anticheat, this may take a few moments...\n"); @@ -1488,7 +1488,7 @@ static void CL_PacketEvent(void) return; } - if (!cls.netchan.Process(&cls.netchan)) + if (!Netchan_Process(&cls.netchan)) return; // wasn't accepted for some reason #if USE_ICMP diff --git a/src/common/net/chan.c b/src/common/net/chan.c index c5804bb5c..3a4af42fb 100644 --- a/src/common/net/chan.c +++ b/src/common/net/chan.c @@ -120,16 +120,13 @@ Netchan_Init */ void Netchan_Init(void) { - int port; - #if USE_DEBUG showpackets = Cvar_Get("showpackets", "0", 0); showdrop = Cvar_Get("showdrop", "0", 0); #endif // pick a port value that should be nice and random - port = Sys_Milliseconds() & 0xffff; - net_qport = Cvar_Get("qport", va("%d", port), 0); + net_qport = Cvar_Get("qport", va("%d", Sys_Milliseconds() & 0xffff), 0); net_maxmsglen = Cvar_Get("net_maxmsglen", va("%d", MAX_PACKETLEN_WRITABLE_DEFAULT), 0); net_maxmsglen->changed = net_maxmsglen_changed; net_chantype = Cvar_Get("net_chantype", "1", 0); @@ -166,12 +163,6 @@ void Netchan_OutOfBand(netsrc_t sock, const netadr_t *address, const char *forma // ============================================================================ -static int NetchanOld_TransmitNextFragment(netchan_t *netchan) -{ - Q_assert(!"not implemented"); - return 0; -} - /* =============== NetchanOld_Transmit @@ -370,26 +361,14 @@ static bool NetchanOld_Process(netchan_t *chan) return true; } -/* -=============== -NetchanOld_ShouldUpdate -================ -*/ -static bool NetchanOld_ShouldUpdate(netchan_t *chan) -{ - return chan->message.cursize - || chan->reliable_ack_pending - || com_localTime - chan->last_sent > 1000; -} - // ============================================================================ /* =============== -NetchanNew_TransmitNextFragment +Netchan_TransmitNextFragment ================ */ -static int NetchanNew_TransmitNextFragment(netchan_t *chan) +int Netchan_TransmitNextFragment(netchan_t *chan) { sizebuf_t send; byte send_buf[MAX_PACKETLEN]; @@ -397,6 +376,8 @@ static int NetchanNew_TransmitNextFragment(netchan_t *chan) int w1, w2, offset; unsigned fragment_length; + Q_assert(chan->type); + send_reliable = chan->reliable_length; // write the packet header @@ -488,7 +469,7 @@ static int NetchanNew_Transmit(netchan_t *chan, size_t length, const void *data, } if (chan->fragment_pending) { - return NetchanNew_TransmitNextFragment(chan); + return Netchan_TransmitNextFragment(chan); } send_reliable = false; @@ -519,7 +500,7 @@ static int NetchanNew_Transmit(netchan_t *chan, size_t length, const void *data, SZ_Write(&chan->fragment_out, data, length); else Com_WPrintf("%s: dumped unreliable\n", NET_AdrToString(&chan->remote_address)); - return NetchanNew_TransmitNextFragment(chan); + return Netchan_TransmitNextFragment(chan); } // write the packet header @@ -718,12 +699,28 @@ static bool NetchanNew_Process(netchan_t *chan) return true; } +bool Netchan_Process(netchan_t *chan) +{ + if (chan->type) + return NetchanNew_Process(chan); + + return NetchanOld_Process(chan); +} + +int Netchan_Transmit(netchan_t *chan, size_t length, const void *data, int numpackets) +{ + if (chan->type) + return NetchanNew_Transmit(chan, length, data, numpackets); + + return NetchanOld_Transmit(chan, length, data, numpackets); +} + /* ============== -NetchanNew_ShouldUpdate +Netchan_ShouldUpdate ============== */ -static bool NetchanNew_ShouldUpdate(netchan_t *chan) +bool Netchan_ShouldUpdate(netchan_t *chan) { return chan->message.cursize || chan->reliable_ack_pending @@ -761,11 +758,6 @@ void Netchan_Setup(netchan_t *chan, netsrc_t sock, netchan_type_t type, switch (type) { case NETCHAN_OLD: - chan->Process = NetchanOld_Process; - chan->Transmit = NetchanOld_Transmit; - chan->TransmitNextFragment = NetchanOld_TransmitNextFragment; - chan->ShouldUpdate = NetchanOld_ShouldUpdate; - buf = Z_TagMalloc(maxpacketlen * 2, tag); chan->reliable_buf = buf + maxpacketlen; @@ -773,11 +765,6 @@ void Netchan_Setup(netchan_t *chan, netsrc_t sock, netchan_type_t type, break; case NETCHAN_NEW: - chan->Process = NetchanNew_Process; - chan->Transmit = NetchanNew_Transmit; - chan->TransmitNextFragment = NetchanNew_TransmitNextFragment; - chan->ShouldUpdate = NetchanNew_ShouldUpdate; - buf = Z_TagMalloc(MAX_MSGLEN * 4, tag); chan->reliable_buf = buf + MAX_MSGLEN; diff --git a/src/server/main.c b/src/server/main.c index 8bc68443f..fc7080cb0 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -1539,7 +1539,7 @@ static void SV_PacketEvent(void) netchan->remote_address.port = net_from.port; } - if (!netchan->Process(netchan)) + if (!Netchan_Process(netchan)) break; if (client->state == cs_zombie) @@ -2322,9 +2322,9 @@ static void SV_FinalMessage(const char *message, error_type_t type) } netchan = &client->netchan; while (netchan->fragment_pending) { - netchan->TransmitNextFragment(netchan); + Netchan_TransmitNextFragment(netchan); } - netchan->Transmit(netchan, msg_write.cursize, msg_write.data, 1); + Netchan_Transmit(netchan, msg_write.cursize, msg_write.data, 1); } } diff --git a/src/server/send.c b/src/server/send.c index b02dc23c5..cb6337292 100644 --- a/src/server/send.c +++ b/src/server/send.c @@ -778,10 +778,10 @@ static void write_datagram_old(client_t *client) #endif // send the datagram - cursize = client->netchan.Transmit(&client->netchan, - msg_write.cursize, - msg_write.data, - client->numpackets); + cursize = Netchan_Transmit(&client->netchan, + msg_write.cursize, + msg_write.data, + client->numpackets); // record the size for rate estimation SV_CalcSendTime(client, cursize); @@ -844,10 +844,10 @@ static void write_datagram_new(client_t *client) #endif // send the datagram - cursize = client->netchan.Transmit(&client->netchan, - msg_write.cursize, - msg_write.data, - client->numpackets); + cursize = Netchan_Transmit(&client->netchan, + msg_write.cursize, + msg_write.data, + client->numpackets); // record the size for rate estimation SV_CalcSendTime(client, cursize); @@ -931,7 +931,7 @@ void SV_SendClientMessages(void) // don't write any frame data until all fragments are sent if (client->netchan.fragment_pending) { client->frameflags |= FF_SUPPRESSED; - cursize = client->netchan.TransmitNextFragment(&client->netchan); + cursize = Netchan_TransmitNextFragment(&client->netchan); SV_CalcSendTime(client, cursize); goto advance; } @@ -1013,7 +1013,7 @@ void SV_SendAsyncPackets(void) // make sure all fragments are transmitted first if (netchan->fragment_pending) { - cursize = netchan->TransmitNextFragment(netchan); + cursize = Netchan_TransmitNextFragment(netchan); SV_DPrintf(1, "%s: frag: %d\n", client->name, cursize); goto calctime; } @@ -1041,7 +1041,7 @@ void SV_SendAsyncPackets(void) if (netchan->message.cursize || netchan->reliable_ack_pending || netchan->reliable_length || retransmit) { - cursize = netchan->Transmit(netchan, 0, "", 1); + cursize = Netchan_Transmit(netchan, 0, "", 1); SV_DPrintf(1, "%s: send: %d\n", client->name, cursize); calctime: SV_CalcSendTime(client, cursize); From b5ac66997d413c655491bb8dc28f50f8d8342e6e Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 14 Dec 2023 01:52:06 +0300 Subject: [PATCH 091/167] Unify netchan message overflow check. Also remove useless fatal_error field. --- inc/common/net/chan.h | 2 -- src/common/net/chan.c | 20 ++++++-------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/inc/common/net/chan.h b/inc/common/net/chan.h index 10a9490d8..4302be726 100644 --- a/inc/common/net/chan.h +++ b/inc/common/net/chan.h @@ -32,8 +32,6 @@ typedef struct netchan_s { int protocol; unsigned maxpacketlen; - bool fatal_error; - netsrc_t sock; int dropped; // between last packet and previous diff --git a/src/common/net/chan.c b/src/common/net/chan.c index 3a4af42fb..fe31417bd 100644 --- a/src/common/net/chan.c +++ b/src/common/net/chan.c @@ -180,13 +180,6 @@ static int NetchanOld_Transmit(netchan_t *chan, size_t length, const void *data, bool send_reliable; int i, w1, w2; -// check for message overflow - if (chan->message.overflowed) { - chan->fatal_error = true; - Com_WPrintf("%s: outgoing message overflow\n", NET_AdrToString(&chan->remote_address)); - return 0; - } - send_reliable = false; // if the remote side dropped the last reliable message, resend it @@ -461,13 +454,6 @@ static int NetchanNew_Transmit(netchan_t *chan, size_t length, const void *data, bool send_reliable; int i, w1, w2; -// check for message overflow - if (chan->message.overflowed) { - chan->fatal_error = true; - Com_WPrintf("%s: outgoing message overflow\n", NET_AdrToString(&chan->remote_address)); - return 0; - } - if (chan->fragment_pending) { return Netchan_TransmitNextFragment(chan); } @@ -709,6 +695,12 @@ bool Netchan_Process(netchan_t *chan) int Netchan_Transmit(netchan_t *chan, size_t length, const void *data, int numpackets) { + // overflow is detected externally now, so this should never happen. + if (chan->message.overflowed) { + Com_WPrintf("%s: outgoing message overflow\n", NET_AdrToString(&chan->remote_address)); + return 0; + } + if (chan->type) return NetchanNew_Transmit(chan, length, data, numpackets); From 33a3baf598f741a495666f60e13583571ea64234 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 14 Dec 2023 01:57:22 +0300 Subject: [PATCH 092/167] Reorder netchan_t fields to make it smaller. --- inc/common/net/chan.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/inc/common/net/chan.h b/inc/common/net/chan.h index 4302be726..09d6ede1a 100644 --- a/inc/common/net/chan.h +++ b/inc/common/net/chan.h @@ -22,12 +22,12 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/net/net.h" #include "common/sizebuf.h" -typedef enum netchan_type_e { +typedef enum { NETCHAN_OLD, NETCHAN_NEW } netchan_type_t; -typedef struct netchan_s { +typedef struct { netchan_type_t type; int protocol; unsigned maxpacketlen; @@ -41,8 +41,8 @@ typedef struct netchan_s { unsigned last_received; // for timeouts unsigned last_sent; // for retransmits - netadr_t remote_address; int qport; // qport value to write when transmitting + netadr_t remote_address; sizebuf_t message; // writing buffer for reliable data From 4369511865cdda32aabdc991b416f3a3541f557a Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 14 Dec 2023 10:17:56 +0300 Subject: [PATCH 093/167] Simplify packing mvd_unicast/multicast length. --- src/client/gtv.c | 8 ++------ src/server/mvd.c | 8 ++------ src/server/mvd/client.c | 8 +++----- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/src/client/gtv.c b/src/client/gtv.c index 2faf05e33..1ce647b6f 100644 --- a/src/client/gtv.c +++ b/src/client/gtv.c @@ -219,8 +219,6 @@ static void write_message(gtv_serverop_t op) void CL_GTV_WriteMessage(byte *data, size_t len) { - int bits; - if (cls.gtv.state != ca_active) return; @@ -241,15 +239,13 @@ void CL_GTV_WriteMessage(byte *data, size_t len) break; case svc_layout: case svc_stufftext: - bits = ((len >> 8) & 7) << SVCMD_BITS; - SZ_WriteByte(&cls.gtv.message, mvd_unicast | bits); + SZ_WriteByte(&cls.gtv.message, mvd_unicast | (len >> 8 << SVCMD_BITS)); SZ_WriteByte(&cls.gtv.message, len & 255); SZ_WriteByte(&cls.gtv.message, cl.clientNum); SZ_Write(&cls.gtv.message, data, len); break; default: - bits = ((len >> 8) & 7) << SVCMD_BITS; - SZ_WriteByte(&cls.gtv.message, mvd_multicast_all | bits); + SZ_WriteByte(&cls.gtv.message, mvd_multicast_all | (len >> 8 << SVCMD_BITS)); SZ_WriteByte(&cls.gtv.message, len & 255); SZ_Write(&cls.gtv.message, data, len); break; diff --git a/src/server/mvd.c b/src/server/mvd.c index 031a2539b..92047c23f 100644 --- a/src/server/mvd.c +++ b/src/server/mvd.c @@ -1113,7 +1113,6 @@ void SV_MvdMulticast(int leafnum, multicast_t to) { mvd_ops_t op; sizebuf_t *buf; - int bits; // do nothing if not active if (!mvd.active) { @@ -1130,9 +1129,8 @@ void SV_MvdMulticast(int leafnum, multicast_t to) op = mvd_multicast_all + to; buf = to < MULTICAST_ALL_R ? &mvd.datagram : &mvd.message; - bits = (msg_write.cursize >> 8) & 7; - SZ_WriteByte(buf, op | (bits << SVCMD_BITS)); + SZ_WriteByte(buf, op | (msg_write.cursize >> 8 << SVCMD_BITS)); SZ_WriteByte(buf, msg_write.cursize & 255); if (op != mvd_multicast_all && op != mvd_multicast_all_r) { @@ -1183,7 +1181,6 @@ void SV_MvdUnicast(edict_t *ent, int clientNum, bool reliable) { mvd_ops_t op; sizebuf_t *buf; - int bits; // do nothing if not active if (!mvd.active) { @@ -1214,8 +1211,7 @@ void SV_MvdUnicast(edict_t *ent, int clientNum, bool reliable) } // write it - bits = (msg_write.cursize >> 8) & 7; - SZ_WriteByte(buf, op | (bits << SVCMD_BITS)); + SZ_WriteByte(buf, op | (msg_write.cursize >> 8 << SVCMD_BITS)); SZ_WriteByte(buf, msg_write.cursize & 255); SZ_WriteByte(buf, clientNum); SZ_Write(buf, msg_write.data, msg_write.cursize); diff --git a/src/server/mvd/client.c b/src/server/mvd/client.c index 50a7787b0..03fabf01b 100644 --- a/src/server/mvd/client.c +++ b/src/server/mvd/client.c @@ -557,7 +557,7 @@ static void demo_emit_snapshot(mvd_t *mvd) int64_t pos; char *from, *to; size_t len; - int i, bits; + int i; if (mvd_snaps->integer <= 0) return; @@ -610,8 +610,7 @@ static void demo_emit_snapshot(mvd_t *mvd) for (cs = player->configstrings; cs; cs = cs->next) len += 4 + strlen(cs->string); - bits = (len >> 8) & 7; - MSG_WriteByte(mvd_unicast | (bits << SVCMD_BITS)); + MSG_WriteByte(mvd_unicast | (len >> 8 << SVCMD_BITS)); MSG_WriteByte(len & 255); MSG_WriteByte(i); for (cs = player->configstrings; cs; cs = cs->next) { @@ -624,8 +623,7 @@ static void demo_emit_snapshot(mvd_t *mvd) // write layout if (mvd->clientNum != -1) { len = 2 + strlen(mvd->layout); - bits = (len >> 8) & 7; - MSG_WriteByte(mvd_unicast | (bits << SVCMD_BITS)); + MSG_WriteByte(mvd_unicast | (len >> 8 << SVCMD_BITS)); MSG_WriteByte(len & 255); MSG_WriteByte(mvd->clientNum); MSG_WriteByte(svc_layout); From 5dafe2da7e1920ad6d642476ed58c1c0ac26f77b Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 14 Dec 2023 10:27:45 +0300 Subject: [PATCH 094/167] Avoid caching some sound indices. --- src/game/g_local.h | 1 - src/game/g_main.c | 1 - src/game/g_spawn.c | 3 +-- src/game/g_trigger.c | 6 ++---- src/game/p_view.c | 2 +- 5 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/game/g_local.h b/src/game/g_local.h index e70f85b65..de1e22d85 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -431,7 +431,6 @@ extern game_export_t globals; extern spawn_temp_t st; extern int sm_meat_index; -extern int snd_fry; //extern int jacket_armor_index; //extern int combat_armor_index; diff --git a/src/game/g_main.c b/src/game/g_main.c index 91ba5072b..1df65b717 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -25,7 +25,6 @@ game_export_t globals; spawn_temp_t st; int sm_meat_index; -int snd_fry; int meansOfDeath; edict_t *g_edicts; diff --git a/src/game/g_spawn.c b/src/game/g_spawn.c index 7171603fb..c40192cf8 100644 --- a/src/game/g_spawn.c +++ b/src/game/g_spawn.c @@ -880,8 +880,7 @@ void SP_worldspawn(edict_t *ent) else gi.cvar_set("sv_gravity", st.gravity); - snd_fry = gi.soundindex("player/fry.wav"); // standing in lava / slime - + gi.soundindex("player/fry.wav"); // standing in lava / slime gi.soundindex("player/lava_in.wav"); gi.soundindex("player/burn1.wav"); gi.soundindex("player/burn2.wav"); diff --git a/src/game/g_trigger.c b/src/game/g_trigger.c index 3ae40327a..1c7ebb26e 100644 --- a/src/game/g_trigger.c +++ b/src/game/g_trigger.c @@ -351,8 +351,6 @@ trigger_push #define PUSH_ONCE 1 -static int windsound; - void trigger_push_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) { if (strcmp(other->classname, "grenade") == 0) { @@ -365,7 +363,7 @@ void trigger_push_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface VectorCopy(other->velocity, other->client->oldvelocity); if (other->fly_sound_debounce_framenum < level.framenum) { other->fly_sound_debounce_framenum = level.framenum + 1.5f * BASE_FRAMERATE; - gi.sound(other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0); + gi.sound(other, CHAN_AUTO, gi.soundindex("misc/windfly.wav"), 1, ATTN_NORM, 0); } } } @@ -380,7 +378,7 @@ Pushes the player void SP_trigger_push(edict_t *self) { InitTrigger(self); - windsound = gi.soundindex("misc/windfly.wav"); + gi.soundindex("misc/windfly.wav"); self->touch = trigger_push_touch; if (!self->speed) self->speed = 1000; diff --git a/src/game/p_view.c b/src/game/p_view.c index c11b0974c..41d577a86 100644 --- a/src/game/p_view.c +++ b/src/game/p_view.c @@ -750,7 +750,7 @@ void G_SetClientSound(edict_t *ent) weap = ""; if (ent->waterlevel && (ent->watertype & (CONTENTS_LAVA | CONTENTS_SLIME))) - ent->s.sound = snd_fry; + ent->s.sound = gi.soundindex("player/fry.wav"); else if (strcmp(weap, "weapon_railgun") == 0) ent->s.sound = gi.soundindex("weapons/rg_hum.wav"); else if (strcmp(weap, "weapon_bfg") == 0) From 35b109afedc675e1060fe173b9ca634face0338d Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 14 Dec 2023 10:28:45 +0300 Subject: [PATCH 095/167] Refresh global precache indices after savegame load. Fixes long standing Quake 2 bug when loading savegame would mess up monster sounds if SpawnEntities() precache order has changed compared to savegame. --- src/game/g_local.h | 13 ++++++++ src/game/g_main.c | 2 ++ src/game/g_save.c | 3 ++ src/game/g_spawn.c | 69 +++++++++++++++++++++++++++++++++++++++++- src/game/m_berserk.c | 17 +++++++---- src/game/m_boss2.c | 15 ++++++--- src/game/m_boss31.c | 21 ++++++++----- src/game/m_boss32.c | 2 +- src/game/m_brain.c | 21 ++++++++----- src/game/m_chick.c | 21 ++++++++----- src/game/m_flipper.c | 21 ++++++++----- src/game/m_float.c | 19 +++++++----- src/game/m_flyer.c | 19 +++++++----- src/game/m_gladiator.c | 21 ++++++++----- src/game/m_gunner.c | 19 +++++++----- src/game/m_hover.c | 19 +++++++----- src/game/m_infantry.c | 21 ++++++++----- src/game/m_insane.c | 21 ++++++++----- src/game/m_medic.c | 21 ++++++++----- src/game/m_mutant.c | 21 ++++++++----- src/game/m_parasite.c | 21 ++++++++----- src/game/m_soldier.c | 44 ++++++++++++++++++++------- src/game/m_supertank.c | 19 +++++++----- src/game/m_tank.c | 21 ++++++++----- 24 files changed, 344 insertions(+), 147 deletions(-) diff --git a/src/game/g_local.h b/src/game/g_local.h index de1e22d85..eb474c3f4 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -247,6 +247,11 @@ typedef struct gitem_s { const char *const *precaches; // array of all models, sounds, and images this item will use } gitem_t; +typedef struct precache_s { + struct precache_s *next; + void (*func)(void); +} precache_t; + // // this structure is left intact through an entire game // it should be initialized at dll load time, and read/written to @@ -277,6 +282,8 @@ typedef struct { bool autosaved; cs_remap_t csr; + + precache_t *precaches; } game_locals_t; // @@ -782,6 +789,12 @@ void ChaseNext(edict_t *ent); void ChasePrev(edict_t *ent); void GetChaseTarget(edict_t *ent); +// +// g_spawn.c +// +void G_AddPrecache(void (*func)(void)); +void G_RefreshPrecaches(void); + //============================================================================ // client_t->anim_priority diff --git a/src/game/g_main.c b/src/game/g_main.c index 1df65b717..ea4d8ba46 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -93,6 +93,8 @@ void ShutdownGame(void) { gi.dprintf("==== ShutdownGame ====\n"); + memset(&game, 0, sizeof(game)); + gi.FreeTags(TAG_LEVEL); gi.FreeTags(TAG_GAME); } diff --git a/src/game/g_save.c b/src/game/g_save.c index 7562f80d3..908da650a 100644 --- a/src/game/g_save.c +++ b/src/game/g_save.c @@ -1043,4 +1043,7 @@ void ReadLevel(const char *filename) } } } + + // refresh global precache indices + G_RefreshPrecaches(); } diff --git a/src/game/g_spawn.c b/src/game/g_spawn.c index c40192cf8..6ed6d8a22 100644 --- a/src/game/g_spawn.c +++ b/src/game/g_spawn.c @@ -554,6 +554,64 @@ void G_FindTeams(void) gi.dprintf("%i teams with %i entities\n", c, c2); } +/* +============== +G_AddPrecache + +Register new global precache function and call it (once). +============== +*/ +void G_AddPrecache(void (*func)(void)) +{ + precache_t *prec; + + for (prec = game.precaches; prec; prec = prec->next) + if (prec->func == func) + return; + + prec = gi.TagMalloc(sizeof(*prec), TAG_GAME); + prec->func = func; + prec->next = game.precaches; + game.precaches = prec; + + prec->func(); +} + +/* +============== +G_RefreshPrecaches + +Called from ReadLevel() to refresh all global precache indices registered by +spawn functions. +============== +*/ +void G_RefreshPrecaches(void) +{ + precache_t *prec; + + for (prec = game.precaches; prec; prec = prec->next) + prec->func(); +} + +/* +============== +G_FreePrecaches + +Free precache functions from previous level. +============== +*/ +static void G_FreePrecaches(void) +{ + precache_t *prec, *next; + + for (prec = game.precaches; prec; prec = next) { + next = prec->next; + gi.TagFree(prec); + } + + game.precaches = NULL; +} + /* ============== SpawnEntities @@ -579,6 +637,8 @@ void SpawnEntities(const char *mapname, const char *entities, const char *spawnp gi.FreeTags(TAG_LEVEL); + G_FreePrecaches(); + memset(&level, 0, sizeof(level)); memset(g_edicts, 0, game.maxentities * sizeof(g_edicts[0])); @@ -808,6 +868,11 @@ static const char *const lightstyles[] = { "abcdefghijklmnopqrrqponmlkjihgfedcba", }; +static void worldspawn_precache(void) +{ + sm_meat_index = gi.modelindex("models/objects/gibs/sm_meat/tris.md2"); +} + /*QUAKED worldspawn (0 0 0) ? Only used for the world. @@ -958,7 +1023,7 @@ void SP_worldspawn(edict_t *ent) gi.soundindex("infantry/inflies1.wav"); - sm_meat_index = gi.modelindex("models/objects/gibs/sm_meat/tris.md2"); + gi.modelindex("models/objects/gibs/sm_meat/tris.md2"); gi.modelindex("models/objects/gibs/arm/tris.md2"); gi.modelindex("models/objects/gibs/bone/tris.md2"); gi.modelindex("models/objects/gibs/bone2/tris.md2"); @@ -966,6 +1031,8 @@ void SP_worldspawn(edict_t *ent) gi.modelindex("models/objects/gibs/skull/tris.md2"); gi.modelindex("models/objects/gibs/head2/tris.md2"); + G_AddPrecache(worldspawn_precache); + // // Setup light animation tables. 'a' is total darkness, 'z' is doublebright. // diff --git a/src/game/m_berserk.c b/src/game/m_berserk.c index d0c534577..c4ecda1eb 100644 --- a/src/game/m_berserk.c +++ b/src/game/m_berserk.c @@ -376,6 +376,16 @@ void berserk_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damag self->monsterinfo.currentmove = &berserk_move_death2; } +static void berserk_precache(void) +{ + sound_pain = gi.soundindex("berserk/berpain2.wav"); + sound_die = gi.soundindex("berserk/berdeth2.wav"); + sound_idle = gi.soundindex("berserk/beridle1.wav"); + sound_punch = gi.soundindex("berserk/attack.wav"); + sound_search = gi.soundindex("berserk/bersrch1.wav"); + sound_sight = gi.soundindex("berserk/sight.wav"); +} + /*QUAKED monster_berserk (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_berserk(edict_t *self) @@ -386,12 +396,7 @@ void SP_monster_berserk(edict_t *self) } // pre-caches - sound_pain = gi.soundindex("berserk/berpain2.wav"); - sound_die = gi.soundindex("berserk/berdeth2.wav"); - sound_idle = gi.soundindex("berserk/beridle1.wav"); - sound_punch = gi.soundindex("berserk/attack.wav"); - sound_search = gi.soundindex("berserk/bersrch1.wav"); - sound_sight = gi.soundindex("berserk/sight.wav"); + G_AddPrecache(berserk_precache); self->s.modelindex = gi.modelindex("models/monsters/berserk/tris.md2"); VectorSet(self->mins, -16, -16, -24); diff --git a/src/game/m_boss2.c b/src/game/m_boss2.c index 0311de7da..fde1f6eb0 100644 --- a/src/game/m_boss2.c +++ b/src/game/m_boss2.c @@ -547,6 +547,15 @@ bool Boss2_CheckAttack(edict_t *self) return false; } +static void boss2_precache(void) +{ + sound_pain1 = gi.soundindex("bosshovr/bhvpain1.wav"); + sound_pain2 = gi.soundindex("bosshovr/bhvpain2.wav"); + sound_pain3 = gi.soundindex("bosshovr/bhvpain3.wav"); + sound_death = gi.soundindex("bosshovr/bhvdeth1.wav"); + sound_search1 = gi.soundindex("bosshovr/bhvunqv1.wav"); +} + /*QUAKED monster_boss2 (1 .5 0) (-56 -56 0) (56 56 80) Ambush Trigger_Spawn Sight */ void SP_monster_boss2(edict_t *self) @@ -556,11 +565,7 @@ void SP_monster_boss2(edict_t *self) return; } - sound_pain1 = gi.soundindex("bosshovr/bhvpain1.wav"); - sound_pain2 = gi.soundindex("bosshovr/bhvpain2.wav"); - sound_pain3 = gi.soundindex("bosshovr/bhvpain3.wav"); - sound_death = gi.soundindex("bosshovr/bhvdeth1.wav"); - sound_search1 = gi.soundindex("bosshovr/bhvunqv1.wav"); + G_AddPrecache(boss2_precache); self->s.sound = gi.soundindex("bosshovr/bhvengn1.wav"); diff --git a/src/game/m_boss31.c b/src/game/m_boss31.c index 3fdeae472..aa5cfd9ee 100644 --- a/src/game/m_boss31.c +++ b/src/game/m_boss31.c @@ -603,15 +603,8 @@ bool Jorg_CheckAttack(edict_t *self) void MakronPrecache(void); -/*QUAKED monster_jorg (1 .5 0) (-80 -80 0) (90 90 140) Ambush Trigger_Spawn Sight -*/ -void SP_monster_jorg(edict_t *self) +static void jorg_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_pain1 = gi.soundindex("boss3/bs3pain1.wav"); sound_pain2 = gi.soundindex("boss3/bs3pain2.wav"); sound_pain3 = gi.soundindex("boss3/bs3pain3.wav"); @@ -628,6 +621,18 @@ void SP_monster_jorg(edict_t *self) sound_death_hit = gi.soundindex("boss3/d_hit.wav"); MakronPrecache(); +} + +/*QUAKED monster_jorg (1 .5 0) (-80 -80 0) (90 90 140) Ambush Trigger_Spawn Sight +*/ +void SP_monster_jorg(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(jorg_precache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_boss32.c b/src/game/m_boss32.c index f71ffb999..9df873585 100644 --- a/src/game/m_boss32.c +++ b/src/game/m_boss32.c @@ -768,7 +768,7 @@ void SP_monster_makron(edict_t *self) return; } - MakronPrecache(); + G_AddPrecache(MakronPrecache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_brain.c b/src/game/m_brain.c index 3a1c59318..7fb15a3ad 100644 --- a/src/game/m_brain.c +++ b/src/game/m_brain.c @@ -512,14 +512,8 @@ void brain_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, self->monsterinfo.currentmove = &brain_move_death2; } -/*QUAKED monster_brain (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight -*/ -void SP_monster_brain(edict_t *self) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - +static void brain_precache(void) +{ sound_chest_open = gi.soundindex("brain/brnatck1.wav"); sound_tentacles_extend = gi.soundindex("brain/brnatck2.wav"); sound_tentacles_retract = gi.soundindex("brain/brnatck3.wav"); @@ -534,6 +528,17 @@ void SP_monster_brain(edict_t *self) { sound_melee1 = gi.soundindex("brain/melee1.wav"); sound_melee2 = gi.soundindex("brain/melee2.wav"); sound_melee3 = gi.soundindex("brain/melee3.wav"); +} + +/*QUAKED monster_brain (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight +*/ +void SP_monster_brain(edict_t *self) { + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(brain_precache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_chick.c b/src/game/m_chick.c index 3cf243fcf..ee3b9a878 100644 --- a/src/game/m_chick.c +++ b/src/game/m_chick.c @@ -579,15 +579,8 @@ void chick_sight(edict_t *self, edict_t *other) gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0); } -/*QUAKED monster_chick (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight -*/ -void SP_monster_chick(edict_t *self) +static void chick_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_missile_prelaunch = gi.soundindex("chick/chkatck1.wav"); sound_missile_launch = gi.soundindex("chick/chkatck2.wav"); sound_melee_swing = gi.soundindex("chick/chkatck3.wav"); @@ -603,6 +596,18 @@ void SP_monster_chick(edict_t *self) sound_pain3 = gi.soundindex("chick/chkpain3.wav"); sound_sight = gi.soundindex("chick/chksght1.wav"); sound_search = gi.soundindex("chick/chksrch1.wav"); +} + +/*QUAKED monster_chick (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight +*/ +void SP_monster_chick(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(chick_precache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_flipper.c b/src/game/m_flipper.c index 1a63e0c84..1f53befa8 100644 --- a/src/game/m_flipper.c +++ b/src/game/m_flipper.c @@ -339,15 +339,8 @@ void flipper_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damag self->monsterinfo.currentmove = &flipper_move_death; } -/*QUAKED monster_flipper (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight -*/ -void SP_monster_flipper(edict_t *self) +static void flipper_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_pain1 = gi.soundindex("flipper/flppain1.wav"); sound_pain2 = gi.soundindex("flipper/flppain2.wav"); sound_death = gi.soundindex("flipper/flpdeth1.wav"); @@ -356,6 +349,18 @@ void SP_monster_flipper(edict_t *self) sound_idle = gi.soundindex("flipper/flpidle1.wav"); sound_search = gi.soundindex("flipper/flpsrch1.wav"); sound_sight = gi.soundindex("flipper/flpsght1.wav"); +} + +/*QUAKED monster_flipper (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight +*/ +void SP_monster_flipper(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(flipper_precache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_float.c b/src/game/m_float.c index e91d4316b..15a510d58 100644 --- a/src/game/m_float.c +++ b/src/game/m_float.c @@ -582,6 +582,17 @@ void floater_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damag BecomeExplosion1(self); } +static void floater_precache(void) +{ + sound_attack2 = gi.soundindex("floater/fltatck2.wav"); + sound_attack3 = gi.soundindex("floater/fltatck3.wav"); + sound_death1 = gi.soundindex("floater/fltdeth1.wav"); + sound_idle = gi.soundindex("floater/fltidle1.wav"); + sound_pain1 = gi.soundindex("floater/fltpain1.wav"); + sound_pain2 = gi.soundindex("floater/fltpain2.wav"); + sound_sight = gi.soundindex("floater/fltsght1.wav"); +} + /*QUAKED monster_floater (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_floater(edict_t *self) @@ -591,13 +602,7 @@ void SP_monster_floater(edict_t *self) return; } - sound_attack2 = gi.soundindex("floater/fltatck2.wav"); - sound_attack3 = gi.soundindex("floater/fltatck3.wav"); - sound_death1 = gi.soundindex("floater/fltdeth1.wav"); - sound_idle = gi.soundindex("floater/fltidle1.wav"); - sound_pain1 = gi.soundindex("floater/fltpain1.wav"); - sound_pain2 = gi.soundindex("floater/fltpain2.wav"); - sound_sight = gi.soundindex("floater/fltsght1.wav"); + G_AddPrecache(floater_precache); gi.soundindex("floater/fltatck1.wav"); diff --git a/src/game/m_flyer.c b/src/game/m_flyer.c index c9c00f15b..b64b9a1ae 100644 --- a/src/game/m_flyer.c +++ b/src/game/m_flyer.c @@ -525,6 +525,17 @@ void flyer_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, BecomeExplosion1(self); } +static void flyer_precache(void) +{ + sound_sight = gi.soundindex("flyer/flysght1.wav"); + sound_idle = gi.soundindex("flyer/flysrch1.wav"); + sound_pain1 = gi.soundindex("flyer/flypain1.wav"); + sound_pain2 = gi.soundindex("flyer/flypain2.wav"); + sound_slash = gi.soundindex("flyer/flyatck2.wav"); + sound_sproing = gi.soundindex("flyer/flyatck1.wav"); + sound_die = gi.soundindex("flyer/flydeth1.wav"); +} + /*QUAKED monster_flyer (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_flyer(edict_t *self) @@ -540,13 +551,7 @@ void SP_monster_flyer(edict_t *self) self->target = NULL; } - sound_sight = gi.soundindex("flyer/flysght1.wav"); - sound_idle = gi.soundindex("flyer/flysrch1.wav"); - sound_pain1 = gi.soundindex("flyer/flypain1.wav"); - sound_pain2 = gi.soundindex("flyer/flypain2.wav"); - sound_slash = gi.soundindex("flyer/flyatck2.wav"); - sound_sproing = gi.soundindex("flyer/flyatck1.wav"); - sound_die = gi.soundindex("flyer/flydeth1.wav"); + G_AddPrecache(flyer_precache); gi.soundindex("flyer/flyatck3.wav"); diff --git a/src/game/m_gladiator.c b/src/game/m_gladiator.c index 99b1acc0c..46329b51f 100644 --- a/src/game/m_gladiator.c +++ b/src/game/m_gladiator.c @@ -313,15 +313,8 @@ void gladiator_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int dam self->monsterinfo.currentmove = &gladiator_move_death; } -/*QUAKED monster_gladiator (1 .5 0) (-32 -32 -24) (32 32 64) Ambush Trigger_Spawn Sight -*/ -void SP_monster_gladiator(edict_t *self) +static void gladiator_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_pain1 = gi.soundindex("gladiator/pain.wav"); sound_pain2 = gi.soundindex("gladiator/gldpain2.wav"); sound_die = gi.soundindex("gladiator/glddeth2.wav"); @@ -332,6 +325,18 @@ void SP_monster_gladiator(edict_t *self) sound_idle = gi.soundindex("gladiator/gldidle1.wav"); sound_search = gi.soundindex("gladiator/gldsrch1.wav"); sound_sight = gi.soundindex("gladiator/sight.wav"); +} + +/*QUAKED monster_gladiator (1 .5 0) (-32 -32 -24) (32 32 64) Ambush Trigger_Spawn Sight +*/ +void SP_monster_gladiator(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(gladiator_precache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_gunner.c b/src/game/m_gunner.c index ba70980d4..0fb400a65 100644 --- a/src/game/m_gunner.c +++ b/src/game/m_gunner.c @@ -537,6 +537,17 @@ void gunner_refire_chain(edict_t *self) self->monsterinfo.currentmove = &gunner_move_endfire_chain; } +static void gunner_precache(void) +{ + sound_death = gi.soundindex("gunner/death1.wav"); + sound_pain = gi.soundindex("gunner/gunpain2.wav"); + sound_pain2 = gi.soundindex("gunner/gunpain1.wav"); + sound_idle = gi.soundindex("gunner/gunidle1.wav"); + sound_open = gi.soundindex("gunner/gunatck1.wav"); + sound_search = gi.soundindex("gunner/gunsrch1.wav"); + sound_sight = gi.soundindex("gunner/sight1.wav"); +} + /*QUAKED monster_gunner (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_gunner(edict_t *self) @@ -546,13 +557,7 @@ void SP_monster_gunner(edict_t *self) return; } - sound_death = gi.soundindex("gunner/death1.wav"); - sound_pain = gi.soundindex("gunner/gunpain2.wav"); - sound_pain2 = gi.soundindex("gunner/gunpain1.wav"); - sound_idle = gi.soundindex("gunner/gunidle1.wav"); - sound_open = gi.soundindex("gunner/gunatck1.wav"); - sound_search = gi.soundindex("gunner/gunsrch1.wav"); - sound_sight = gi.soundindex("gunner/sight1.wav"); + G_AddPrecache(gunner_precache); gi.soundindex("gunner/gunatck2.wav"); gi.soundindex("gunner/gunatck3.wav"); diff --git a/src/game/m_hover.c b/src/game/m_hover.c index 74eb340fa..95c492548 100644 --- a/src/game/m_hover.c +++ b/src/game/m_hover.c @@ -534,6 +534,17 @@ void hover_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, self->monsterinfo.currentmove = &hover_move_death1; } +static void hover_precache(void) +{ + sound_pain1 = gi.soundindex("hover/hovpain1.wav"); + sound_pain2 = gi.soundindex("hover/hovpain2.wav"); + sound_death1 = gi.soundindex("hover/hovdeth1.wav"); + sound_death2 = gi.soundindex("hover/hovdeth2.wav"); + sound_sight = gi.soundindex("hover/hovsght1.wav"); + sound_search1 = gi.soundindex("hover/hovsrch1.wav"); + sound_search2 = gi.soundindex("hover/hovsrch2.wav"); +} + /*QUAKED monster_hover (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_hover(edict_t *self) @@ -543,13 +554,7 @@ void SP_monster_hover(edict_t *self) return; } - sound_pain1 = gi.soundindex("hover/hovpain1.wav"); - sound_pain2 = gi.soundindex("hover/hovpain2.wav"); - sound_death1 = gi.soundindex("hover/hovdeth1.wav"); - sound_death2 = gi.soundindex("hover/hovdeth2.wav"); - sound_sight = gi.soundindex("hover/hovsght1.wav"); - sound_search1 = gi.soundindex("hover/hovsrch1.wav"); - sound_search2 = gi.soundindex("hover/hovsrch2.wav"); + G_AddPrecache(hover_precache); gi.soundindex("hover/hovatck1.wav"); diff --git a/src/game/m_infantry.c b/src/game/m_infantry.c index b2bad416c..0e051d121 100644 --- a/src/game/m_infantry.c +++ b/src/game/m_infantry.c @@ -511,15 +511,8 @@ void infantry_attack(edict_t *self) self->monsterinfo.currentmove = &infantry_move_attack1; } -/*QUAKED monster_infantry (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight -*/ -void SP_monster_infantry(edict_t *self) +static void infantry_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_pain1 = gi.soundindex("infantry/infpain1.wav"); sound_pain2 = gi.soundindex("infantry/infpain2.wav"); sound_die1 = gi.soundindex("infantry/infdeth1.wav"); @@ -533,6 +526,18 @@ void SP_monster_infantry(edict_t *self) sound_sight = gi.soundindex("infantry/infsght1.wav"); sound_search = gi.soundindex("infantry/infsrch1.wav"); sound_idle = gi.soundindex("infantry/infidle1.wav"); +} + +/*QUAKED monster_infantry (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight +*/ +void SP_monster_infantry(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(infantry_precache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_insane.c b/src/game/m_insane.c index 130a87bed..edec16a5c 100644 --- a/src/game/m_insane.c +++ b/src/game/m_insane.c @@ -576,15 +576,8 @@ void insane_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage } } -/*QUAKED misc_insane (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn CRAWL CRUCIFIED STAND_GROUND ALWAYS_STAND -*/ -void SP_misc_insane(edict_t *self) +static void insane_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_fist = gi.soundindex("insane/insane11.wav"); sound_shake = gi.soundindex("insane/insane5.wav"); sound_moan = gi.soundindex("insane/insane7.wav"); @@ -596,6 +589,18 @@ void SP_misc_insane(edict_t *self) sound_scream[5] = gi.soundindex("insane/insane8.wav"); sound_scream[6] = gi.soundindex("insane/insane9.wav"); sound_scream[7] = gi.soundindex("insane/insane10.wav"); +} + +/*QUAKED misc_insane (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn CRAWL CRUCIFIED STAND_GROUND ALWAYS_STAND +*/ +void SP_misc_insane(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(insane_precache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_medic.c b/src/game/m_medic.c index a79456f87..7bfc713bf 100644 --- a/src/game/m_medic.c +++ b/src/game/m_medic.c @@ -668,15 +668,8 @@ bool medic_checkattack(edict_t *self) return M_CheckAttack(self); } -/*QUAKED monster_medic (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight -*/ -void SP_monster_medic(edict_t *self) +static void medic_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_idle1 = gi.soundindex("medic/idle.wav"); sound_pain1 = gi.soundindex("medic/medpain1.wav"); sound_pain2 = gi.soundindex("medic/medpain2.wav"); @@ -687,6 +680,18 @@ void SP_monster_medic(edict_t *self) sound_hook_hit = gi.soundindex("medic/medatck3.wav"); sound_hook_heal = gi.soundindex("medic/medatck4.wav"); sound_hook_retract = gi.soundindex("medic/medatck5.wav"); +} + +/*QUAKED monster_medic (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight +*/ +void SP_monster_medic(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(medic_precache); gi.soundindex("medic/medatck1.wav"); diff --git a/src/game/m_mutant.c b/src/game/m_mutant.c index 5b94fcaad..334ab06a2 100644 --- a/src/game/m_mutant.c +++ b/src/game/m_mutant.c @@ -566,15 +566,8 @@ void mutant_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage // SPAWN // -/*QUAKED monster_mutant (1 .5 0) (-32 -32 -24) (32 32 32) Ambush Trigger_Spawn Sight -*/ -void SP_monster_mutant(edict_t *self) +static void mutant_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_swing = gi.soundindex("mutant/mutatck1.wav"); sound_hit = gi.soundindex("mutant/mutatck2.wav"); sound_hit2 = gi.soundindex("mutant/mutatck3.wav"); @@ -588,6 +581,18 @@ void SP_monster_mutant(edict_t *self) sound_step2 = gi.soundindex("mutant/step2.wav"); sound_step3 = gi.soundindex("mutant/step3.wav"); sound_thud = gi.soundindex("mutant/thud1.wav"); +} + +/*QUAKED monster_mutant (1 .5 0) (-32 -32 -24) (32 32 32) Ambush Trigger_Spawn Sight +*/ +void SP_monster_mutant(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(mutant_precache); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_parasite.c b/src/game/m_parasite.c index 45ac48859..570a5704e 100644 --- a/src/game/m_parasite.c +++ b/src/game/m_parasite.c @@ -422,15 +422,8 @@ End Death Stuff === */ -/*QUAKED monster_parasite (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight -*/ -void SP_monster_parasite(edict_t *self) +static void parasite_precache(void) { - if (deathmatch->value) { - G_FreeEdict(self); - return; - } - sound_pain1 = gi.soundindex("parasite/parpain1.wav"); sound_pain2 = gi.soundindex("parasite/parpain2.wav"); sound_die = gi.soundindex("parasite/pardeth1.wav"); @@ -442,6 +435,18 @@ void SP_monster_parasite(edict_t *self) sound_tap = gi.soundindex("parasite/paridle1.wav"); sound_scratch = gi.soundindex("parasite/paridle2.wav"); sound_search = gi.soundindex("parasite/parsrch1.wav"); +} + +/*QUAKED monster_parasite (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight +*/ +void SP_monster_parasite(edict_t *self) +{ + if (deathmatch->value) { + G_FreeEdict(self); + return; + } + + G_AddPrecache(parasite_precache); self->s.modelindex = gi.modelindex("models/monsters/parasite/tris.md2"); VectorSet(self->mins, -16, -16, -24); diff --git a/src/game/m_soldier.c b/src/game/m_soldier.c index 58f3f0226..033336416 100644 --- a/src/game/m_soldier.c +++ b/src/game/m_soldier.c @@ -1067,9 +1067,16 @@ void soldier_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damag // SPAWN // -void SP_monster_soldier_x(edict_t *self) +static void soldier_precache_x(void) { + sound_idle = gi.soundindex("soldier/solidle1.wav"); + sound_sight1 = gi.soundindex("soldier/solsght1.wav"); + sound_sight2 = gi.soundindex("soldier/solsrch1.wav"); + sound_cock = gi.soundindex("infantry/infatck3.wav"); +} +static void SP_monster_soldier_x(edict_t *self) +{ self->s.modelindex = gi.modelindex("models/monsters/soldier/tris.md2"); self->monsterinfo.scale = MODEL_SCALE; VectorSet(self->mins, -16, -16, -24); @@ -1077,10 +1084,7 @@ void SP_monster_soldier_x(edict_t *self) self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; - sound_idle = gi.soundindex("soldier/solidle1.wav"); - sound_sight1 = gi.soundindex("soldier/solsght1.wav"); - sound_sight2 = gi.soundindex("soldier/solsrch1.wav"); - sound_cock = gi.soundindex("infantry/infatck3.wav"); + G_AddPrecache(soldier_precache_x); self->mass = 100; @@ -1102,6 +1106,12 @@ void SP_monster_soldier_x(edict_t *self) walkmonster_start(self); } +static void soldier_precache_light(void) +{ + sound_pain_light = gi.soundindex("soldier/solpain2.wav"); + sound_death_light = gi.soundindex("soldier/soldeth2.wav"); +} + /*QUAKED monster_soldier_light (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_soldier_light(edict_t *self) @@ -1113,8 +1123,8 @@ void SP_monster_soldier_light(edict_t *self) SP_monster_soldier_x(self); - sound_pain_light = gi.soundindex("soldier/solpain2.wav"); - sound_death_light = gi.soundindex("soldier/soldeth2.wav"); + G_AddPrecache(soldier_precache_light); + gi.modelindex("models/objects/laser/tris.md2"); gi.soundindex("misc/lasfly.wav"); gi.soundindex("soldier/solatck2.wav"); @@ -1124,6 +1134,12 @@ void SP_monster_soldier_light(edict_t *self) self->gib_health = -30; } +static void soldier_precache(void) +{ + sound_pain = gi.soundindex("soldier/solpain1.wav"); + sound_death = gi.soundindex("soldier/soldeth1.wav"); +} + /*QUAKED monster_soldier (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_soldier(edict_t *self) @@ -1135,8 +1151,8 @@ void SP_monster_soldier(edict_t *self) SP_monster_soldier_x(self); - sound_pain = gi.soundindex("soldier/solpain1.wav"); - sound_death = gi.soundindex("soldier/soldeth1.wav"); + G_AddPrecache(soldier_precache); + gi.soundindex("soldier/solatck1.wav"); self->s.skinnum = 2; @@ -1144,6 +1160,12 @@ void SP_monster_soldier(edict_t *self) self->gib_health = -30; } +static void soldier_precache_ss(void) +{ + sound_pain_ss = gi.soundindex("soldier/solpain3.wav"); + sound_death_ss = gi.soundindex("soldier/soldeth3.wav"); +} + /*QUAKED monster_soldier_ss (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_soldier_ss(edict_t *self) @@ -1155,8 +1177,8 @@ void SP_monster_soldier_ss(edict_t *self) SP_monster_soldier_x(self); - sound_pain_ss = gi.soundindex("soldier/solpain3.wav"); - sound_death_ss = gi.soundindex("soldier/soldeth3.wav"); + G_AddPrecache(soldier_precache_ss); + gi.soundindex("soldier/solatck3.wav"); self->s.skinnum = 4; diff --git a/src/game/m_supertank.c b/src/game/m_supertank.c index 7f7077f58..14fa1fcde 100644 --- a/src/game/m_supertank.c +++ b/src/game/m_supertank.c @@ -624,6 +624,17 @@ void supertank_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int dam // monster_supertank // +static void supertank_precache(void) +{ + sound_pain1 = gi.soundindex("bosstank/btkpain1.wav"); + sound_pain2 = gi.soundindex("bosstank/btkpain2.wav"); + sound_pain3 = gi.soundindex("bosstank/btkpain3.wav"); + sound_death = gi.soundindex("bosstank/btkdeth1.wav"); + sound_search1 = gi.soundindex("bosstank/btkunqv1.wav"); + sound_search2 = gi.soundindex("bosstank/btkunqv2.wav"); + tread_sound = gi.soundindex("bosstank/btkengn1.wav"); +} + /*QUAKED monster_supertank (1 .5 0) (-64 -64 0) (64 64 72) Ambush Trigger_Spawn Sight */ void SP_monster_supertank(edict_t *self) @@ -633,15 +644,9 @@ void SP_monster_supertank(edict_t *self) return; } - sound_pain1 = gi.soundindex("bosstank/btkpain1.wav"); - sound_pain2 = gi.soundindex("bosstank/btkpain2.wav"); - sound_pain3 = gi.soundindex("bosstank/btkpain3.wav"); - sound_death = gi.soundindex("bosstank/btkdeth1.wav"); - sound_search1 = gi.soundindex("bosstank/btkunqv1.wav"); - sound_search2 = gi.soundindex("bosstank/btkunqv2.wav"); + G_AddPrecache(supertank_precache); // self->s.sound = gi.soundindex ("bosstank/btkengn1.wav"); - tread_sound = gi.soundindex("bosstank/btkengn1.wav"); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; diff --git a/src/game/m_tank.c b/src/game/m_tank.c index 24bdaf47b..e49c90d10 100644 --- a/src/game/m_tank.c +++ b/src/game/m_tank.c @@ -734,6 +734,18 @@ void tank_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, // monster_tank // +static void tank_precache(void) +{ + sound_pain = gi.soundindex("tank/tnkpain2.wav"); + sound_thud = gi.soundindex("tank/tnkdeth2.wav"); + sound_idle = gi.soundindex("tank/tnkidle1.wav"); + sound_die = gi.soundindex("tank/death.wav"); + sound_step = gi.soundindex("tank/step.wav"); + sound_windup = gi.soundindex("tank/tnkatck4.wav"); + sound_strike = gi.soundindex("tank/tnkatck5.wav"); + sound_sight = gi.soundindex("tank/sight1.wav"); +} + /*QUAKED monster_tank (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight */ /*QUAKED monster_tank_commander (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight @@ -751,14 +763,7 @@ void SP_monster_tank(edict_t *self) self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; - sound_pain = gi.soundindex("tank/tnkpain2.wav"); - sound_thud = gi.soundindex("tank/tnkdeth2.wav"); - sound_idle = gi.soundindex("tank/tnkidle1.wav"); - sound_die = gi.soundindex("tank/death.wav"); - sound_step = gi.soundindex("tank/step.wav"); - sound_windup = gi.soundindex("tank/tnkatck4.wav"); - sound_strike = gi.soundindex("tank/tnkatck5.wav"); - sound_sight = gi.soundindex("tank/sight1.wav"); + G_AddPrecache(tank_precache); gi.soundindex("tank/tnkatck1.wav"); gi.soundindex("tank/tnkatk2a.wav"); From a3e8cb8b6b02bd7dfdc8bc14c55db65feb10eb74 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 14 Dec 2023 20:12:53 +0300 Subject: [PATCH 096/167] Allow SZ_Write() with NULL data if len == 0. --- inc/common/sizebuf.h | 5 +++-- src/client/input.c | 2 +- src/client/main.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/inc/common/sizebuf.h b/inc/common/sizebuf.h index 29826ba49..91348c15f 100644 --- a/inc/common/sizebuf.h +++ b/inc/common/sizebuf.h @@ -40,9 +40,10 @@ void SZ_WriteShort(sizebuf_t *sb, int c); void SZ_WriteLong(sizebuf_t *sb, int c); void SZ_WriteString(sizebuf_t *sb, const char *s); -static inline void *SZ_Write(sizebuf_t *buf, const void *data, size_t len) +static inline void SZ_Write(sizebuf_t *buf, const void *data, size_t len) { - return memcpy(SZ_GetSpace(buf, len), data, len); + if (len) + memcpy(SZ_GetSpace(buf, len), data, len); } static inline uint32_t SZ_Remaining(const sizebuf_t *buf) diff --git a/src/client/input.c b/src/client/input.c index 6bef7f11d..fe3ef8ddc 100644 --- a/src/client/input.c +++ b/src/client/input.c @@ -1071,7 +1071,7 @@ static void CL_SendKeepAlive(void) cl.lastTransmitCmdNumber = cl.cmdNumber; cl.lastTransmitCmdNumberReal = cl.cmdNumber; - cursize = Netchan_Transmit(&cls.netchan, 0, "", 1); + cursize = Netchan_Transmit(&cls.netchan, 0, NULL, 1); #if USE_DEBUG if (cl_showpackets->integer) { Com_Printf("%i ", cursize); diff --git a/src/client/main.c b/src/client/main.c index d3a75cffb..837a2003f 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -1385,7 +1385,7 @@ static void CL_ConnectionlessPacket(void) if (anticheat) { MSG_WriteByte(clc_nop); MSG_FlushTo(&cls.netchan.message); - Netchan_Transmit(&cls.netchan, 0, "", 3); + Netchan_Transmit(&cls.netchan, 0, NULL, 3); S_StopAllSounds(); cls.connect_count = -1; Com_Printf("Loading anticheat, this may take a few moments...\n"); From b8bc79dbebb8d0cc59e684dd36932779844ba83f Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 15 Dec 2023 21:09:14 +0300 Subject: [PATCH 097/167] Revert "Fix UB after GL_RebuildLighting()." This reverts commit 0f265471bc65cc421c83c65262211036f18d8ecb. --- src/refresh/main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/refresh/main.c b/src/refresh/main.c index e0f207c68..c13561f80 100644 --- a/src/refresh/main.c +++ b/src/refresh/main.c @@ -668,11 +668,6 @@ void R_RenderFrame(refdef_t *fd) Q_assert(gl_static.world.cache || (fd->rdflags & RDF_NOWORLDMODEL)); - if (lm.dirty) { - GL_RebuildLighting(); - lm.dirty = false; - } - glr.drawframe++; glr.rand_seed = fd->time * 20; @@ -684,6 +679,11 @@ void R_RenderFrame(refdef_t *fd) glr.fd.num_dlights = 0; } + if (lm.dirty) { + GL_RebuildLighting(); + lm.dirty = false; + } + bool waterwarp = (glr.fd.rdflags & RDF_UNDERWATER) && gl_static.use_shaders && gl_waterwarp->integer; if (waterwarp) { From d7e4d98b51a69e4bc0f9394626d7227e59c4c628 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 15 Dec 2023 21:17:58 +0300 Subject: [PATCH 098/167] Properly fix UB after GL_RebuildLighting(). Fix without crashing in LM_RebuildSurfaces() this time. --- src/refresh/surf.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/refresh/surf.c b/src/refresh/surf.c index aa1d33449..46583e4d9 100644 --- a/src/refresh/surf.c +++ b/src/refresh/surf.c @@ -383,12 +383,10 @@ static void LM_UploadBlock(void) static void build_style_map(int dynamic) { - static const lightstyle_t fake = { 1 }; int i; if (!dynamic) { // make all styles fullbright - glr.fd.lightstyles = (lightstyle_t *)&fake; memset(gl_static.lightstylemap, 0, sizeof(gl_static.lightstylemap)); return; } @@ -1074,8 +1072,12 @@ void GL_LoadWorld(const char *name) gl_static.nolm_mask = SURF_NOLM_MASK_REMASTER; } + glr.fd.lightstyles = &(lightstyle_t){ 1 }; + // post process all surfaces upload_world_surfaces(); + glr.fd.lightstyles = NULL; + GL_ShowErrors(__func__); } From 5b29fa375e868e694640b395480bb2a32ca8a84a Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 18 Dec 2023 18:47:17 +0300 Subject: [PATCH 099/167] Merge SV_HullForEntity2() into SV_HullForEntity(). --- src/server/world.c | 36 ++++++++---------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/src/server/world.c b/src/server/world.c index 8b29461ae..edfceff23 100644 --- a/src/server/world.c +++ b/src/server/world.c @@ -437,37 +437,17 @@ Returns a headnode that can be used for testing or clipping an object of mins/maxs size. ================ */ -static mnode_t *SV_HullForEntity(edict_t *ent) +static mnode_t *SV_HullForEntity(edict_t *ent, bool triggers) { - if (ent->solid == SOLID_BSP) { - int i = ent->s.modelindex - 1; - - // explicit hulls in the BSP model - if (i <= 0 || i >= sv.cm.cache->nummodels) - Com_Error(ERR_DROP, "%s: inline model %d out of range", __func__, i); - - return sv.cm.cache->models[i].headnode; - } - - // create a temp hull from bounding box sizes - return CM_HeadnodeForBox(ent->mins, ent->maxs); -} - -/* -============= -SV_HullForEntity2 - -Can be used to clip to SOLID_TRIGGER by its BSP tree -============= -*/ -static mnode_t *SV_HullForEntity2(edict_t *ent) -{ - if (ent->solid == SOLID_BSP || ent->solid == SOLID_TRIGGER) { + if (ent->solid == SOLID_BSP || (triggers && ent->solid == SOLID_TRIGGER)) { int i = ent->s.modelindex - 1; // explicit hulls in the BSP model if (i > 0 && i < sv.cm.cache->nummodels) return sv.cm.cache->models[i].headnode; + + if (!triggers) + Com_Error(ERR_DROP, "%s: inline model %d out of range", __func__, i); } // create a temp hull from bounding box sizes @@ -505,7 +485,7 @@ int SV_PointContents(const vec3_t p) hit = touch[i]; // might intersect, so do an exact clip - contents |= CM_TransformedPointContents(p, SV_HullForEntity(hit), + contents |= CM_TransformedPointContents(p, SV_HullForEntity(hit, false), hit->s.origin, hit->s.angles); } @@ -572,7 +552,7 @@ static void SV_ClipMoveToEntities(const vec3_t start, const vec3_t mins, // might intersect, so do an exact clip CM_TransformedBoxTrace(&trace, start, end, mins, maxs, - SV_HullForEntity(touch), contentmask, + SV_HullForEntity(touch, false), contentmask, touch->s.origin, touch->s.angles); CM_ClipEntity(tr, &trace, touch); @@ -632,7 +612,7 @@ trace_t q_gameabi SV_Clip(const vec3_t start, const vec3_t mins, CM_BoxTrace(&trace, start, end, mins, maxs, SV_WorldNodes(), contentmask); else CM_TransformedBoxTrace(&trace, start, end, mins, maxs, - SV_HullForEntity2(clip), contentmask, + SV_HullForEntity(clip, true), contentmask, clip->s.origin, clip->s.angles); trace.ent = clip; return trace; From 2cd1a76174cee67fd95cd27bb39a038adae80961 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 18 Dec 2023 18:48:15 +0300 Subject: [PATCH 100/167] Add q_cold attribute and mark Com_Error() as such. --- inc/shared/platform.h | 2 ++ inc/shared/shared.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/inc/shared/platform.h b/inc/shared/platform.h index 0407152d8..9eed15eac 100644 --- a/inc/shared/platform.h +++ b/inc/shared/platform.h @@ -99,6 +99,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #else #define q_sentinel #endif +#define q_cold __attribute__((cold)) #define q_likely(x) __builtin_expect(!!(x), 1) #define q_unlikely(x) __builtin_expect(!!(x), 0) @@ -130,6 +131,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define q_noinline #define q_malloc #define q_sentinel +#define q_cold #define q_likely(x) (x) #define q_unlikely(x) (x) diff --git a/inc/shared/shared.h b/inc/shared/shared.h index a9272210d..69aa9abc8 100644 --- a/inc/shared/shared.h +++ b/inc/shared/shared.h @@ -106,7 +106,7 @@ typedef enum { void Com_LPrintf(print_type_t type, const char *fmt, ...) q_printf(2, 3); void Com_Error(error_type_t code, const char *fmt, ...) -q_noreturn q_printf(2, 3); +q_cold q_noreturn q_printf(2, 3); #define Com_Printf(...) Com_LPrintf(PRINT_ALL, __VA_ARGS__) #define Com_WPrintf(...) Com_LPrintf(PRINT_WARNING, __VA_ARGS__) From d0db0cb033e82b87f3aa06b1035ee7cbf6387384 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 18 Dec 2023 19:29:49 +0300 Subject: [PATCH 101/167] Replace some Com_LPrintf with specific macros. --- src/client/main.c | 2 +- src/windows/ac.c | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/client/main.c b/src/client/main.c index 837a2003f..9a5fbb604 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -1393,7 +1393,7 @@ static void CL_ConnectionlessPacket(void) if (!Sys_GetAntiCheatAPI()) { Com_Printf("Trying to connect without anticheat.\n"); } else { - Com_LPrintf(PRINT_NOTICE, "Anticheat loaded successfully.\n"); + Com_NPrintf("Anticheat loaded successfully.\n"); } } #else diff --git a/src/windows/ac.c b/src/windows/ac.c index cd33508e5..9bac4c42e 100644 --- a/src/windows/ac.c +++ b/src/windows/ac.c @@ -36,7 +36,7 @@ bool Sys_GetAntiCheatAPI(void) if (anticheatInit) { anticheatApi = anticheatInit(); if (!anticheatApi) { - Com_LPrintf(PRINT_ERROR, "Anticheat failed to reinitialize!\n"); + Com_EPrintf("Anticheat failed to reinitialize!\n"); FreeLibrary(anticheatHandle); anticheatHandle = NULL; anticheatInit = NULL; @@ -48,15 +48,14 @@ bool Sys_GetAntiCheatAPI(void) reInit: anticheatHandle = LoadLibrary("anticheat"); if (!anticheatHandle) { - Com_LPrintf(PRINT_ERROR, "Anticheat failed to load.\n"); + Com_EPrintf("Anticheat failed to load.\n"); return false; } //this should never fail unless the anticheat.dll is bad anticheatInit = (FNINIT)GetProcAddress(anticheatHandle, "Initialize"); if (!anticheatInit) { - Com_LPrintf(PRINT_ERROR, - "Couldn't get API of anticheat.dll!\n" + Com_EPrintf("Couldn't get API of anticheat.dll!\n" "Please check you are using a valid " "anticheat.dll from http://antiche.at/"); FreeLibrary(anticheatHandle); @@ -77,7 +76,7 @@ bool Sys_GetAntiCheatAPI(void) goto reInit; } - Com_LPrintf(PRINT_ERROR, "Anticheat failed to initialize.\n"); + Com_EPrintf("Anticheat failed to initialize.\n"); return false; } From ac68409f0f4aed45a60c895c53fc62910102875b Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Tue, 19 Dec 2023 13:52:46 -0500 Subject: [PATCH 102/167] Fixing protocol issue --- src/client/effects.c | 62 +++++++++++++++++++------------------------- src/client/parse.c | 3 +++ 2 files changed, 29 insertions(+), 36 deletions(-) diff --git a/src/client/effects.c b/src/client/effects.c index 99ea92ffe..f37e7b083 100644 --- a/src/client/effects.c +++ b/src/client/effects.c @@ -164,7 +164,6 @@ void CL_MuzzleFlash(void) centity_t *pl; float volume; char soundname[MAX_QPATH]; - int mk23snd,mp5snd,m4snd,m3snd,hcsnd,ssgsnd; #if USE_DEBUG if (developer->integer) @@ -190,17 +189,18 @@ void CL_MuzzleFlash(void) #if USE_AQTION // New muzzleflash items to test: // example: CL_AddWeaponMuzzleFX(MFLASH_BLAST, (const vec3_t) { 27.0f, 7.4f, -6.6f }, 8.0f); - mk23snd = atoi(cl_mk23_sound->string); + //mk23snd = atoi(cl_mk23_sound->string); + //CL_AddWeaponMuzzleFX(MFLASH_BLAST, (const vec3_t) { 27.0f, 7.4f, -6.6f }, 8.0f); - if (mk23snd > MAX_WEAPON_SOUND || mk23snd <= MIN_WEAPON_SOUND) { - mk23snd = MIN_WEAPON_SOUND; + if (cl_mk23_sound->integer > MAX_WEAPON_SOUND || cl_mk23_sound->integer <= MIN_WEAPON_SOUND) { + cl_mk23_sound->integer = MIN_WEAPON_SOUND; } - if (mk23snd == 0) { + if (cl_mk23_sound->integer == 0) { Q_snprintf(soundname, sizeof(soundname), "weapons/mk23fire.wav"); break; } else { - Q_snprintf(soundname, sizeof(soundname), "weapons/mk23fire%i.wav", mk23snd); + Q_snprintf(soundname, sizeof(soundname), "weapons/mk23fire%i.wav", cl_mk23_sound->integer); break; } #else @@ -209,17 +209,15 @@ void CL_MuzzleFlash(void) case MZ_MACHINEGUN: // MP5/10 Submachinegun #if USE_AQTION - mp5snd = atoi(cl_mp5_sound->string); - - if (mp5snd > MAX_WEAPON_SOUND || mp5snd <= MIN_WEAPON_SOUND) { - mp5snd = MIN_WEAPON_SOUND; + if (cl_mp5_sound->integer > MAX_WEAPON_SOUND || cl_mp5_sound->integer <= MIN_WEAPON_SOUND) { + cl_mp5_sound->integer = MIN_WEAPON_SOUND; } - if (mp5snd == 0) { + if (cl_mp5_sound->integer == 0) { Q_snprintf(soundname, sizeof(soundname), "weapons/mp5fire.wav"); break; } else { - Q_snprintf(soundname, sizeof(soundname), "weapons/mp5fire%i.wav", mp5snd); + Q_snprintf(soundname, sizeof(soundname), "weapons/mp5fire%i.wav", cl_mp5_sound->integer); break; } #else @@ -228,17 +226,15 @@ void CL_MuzzleFlash(void) case MZ_ROCKET: // M4 Assault Rifle #if USE_AQTION - m4snd = atoi(cl_m4_sound->string); - - if (m4snd > MAX_WEAPON_SOUND || m4snd <= MIN_WEAPON_SOUND) { - m4snd = MIN_WEAPON_SOUND; + if (cl_m4_sound->integer > MAX_WEAPON_SOUND || cl_m4_sound->integer <= MIN_WEAPON_SOUND) { + cl_m4_sound->integer = MIN_WEAPON_SOUND; } - if (m4snd == 0) { + if (cl_m4_sound->integer == 0) { Q_snprintf(soundname, sizeof(soundname), "weapons/m4a1fire.wav"); break; } else { - Q_snprintf(soundname, sizeof(soundname), "weapons/m4a1fire%i.wav", m4snd); + Q_snprintf(soundname, sizeof(soundname), "weapons/m4a1fire%i.wav", cl_m4_sound->integer); break; } #else @@ -247,17 +243,15 @@ void CL_MuzzleFlash(void) case MZ_SHOTGUN: // M3 Shotgun #if USE_AQTION - m3snd = atoi(cl_m3_sound->string); - - if (m3snd > MAX_WEAPON_SOUND || m3snd <= MIN_WEAPON_SOUND) { - m3snd = MIN_WEAPON_SOUND; + if (cl_m3_sound->integer > MAX_WEAPON_SOUND || cl_m3_sound->integer <= MIN_WEAPON_SOUND) { + cl_m3_sound->integer = MIN_WEAPON_SOUND; } - if (m3snd == 0) { + if (cl_m3_sound->integer == 0) { Q_snprintf(soundname, sizeof(soundname), "weapons/shotgf1b.wav"); break; } else { - Q_snprintf(soundname, sizeof(soundname), "weapons/shotgf1b%i.wav", m3snd); + Q_snprintf(soundname, sizeof(soundname), "weapons/shotgf1b%i.wav", cl_m3_sound->integer); break; } #else @@ -266,17 +260,15 @@ void CL_MuzzleFlash(void) case MZ_SSHOTGUN: // Handcannon -- needs adjustment for single barrel vs double #if USE_AQTION - hcsnd = atoi(cl_hc_sound->string); - - if (hcsnd > MAX_WEAPON_SOUND || hcsnd <= MIN_WEAPON_SOUND) { - hcsnd = MIN_WEAPON_SOUND; + if (cl_hc_sound->integer > MAX_WEAPON_SOUND || cl_hc_sound->integer <= MIN_WEAPON_SOUND) { + cl_hc_sound->integer = MIN_WEAPON_SOUND; } - if (hcsnd == 0) { + if (cl_hc_sound->integer == 0) { Q_snprintf(soundname, sizeof(soundname), "weapons/cannon_fire.wav"); break; } else { - Q_snprintf(soundname, sizeof(soundname), "weapons/cannon_fire%i.wav", hcsnd); + Q_snprintf(soundname, sizeof(soundname), "weapons/cannon_fire%i.wav", cl_hc_sound->integer); break; } #else @@ -285,17 +277,15 @@ void CL_MuzzleFlash(void) case MZ_HYPERBLASTER: // SSG 3000 Sniper Rifle #if USE_AQTION - ssgsnd = atoi(cl_ssg_sound->string); - - if (ssgsnd > MAX_WEAPON_SOUND || ssgsnd <= MIN_WEAPON_SOUND) { - ssgsnd = MIN_WEAPON_SOUND; + if (cl_ssg_sound->integer > MAX_WEAPON_SOUND || cl_ssg_sound->integer <= MIN_WEAPON_SOUND) { + cl_ssg_sound->integer = MIN_WEAPON_SOUND; } - if (ssgsnd == 0) { + if (cl_ssg_sound->integer == 0) { Q_snprintf(soundname, sizeof(soundname), "weapons/ssgfire.wav"); break; } else { - Q_snprintf(soundname, sizeof(soundname), "weapons/ssgfire%i.wav", ssgsnd); + Q_snprintf(soundname, sizeof(soundname), "weapons/ssgfire%i.wav", cl_ssg_sound->integer); break; } #else diff --git a/src/client/parse.c b/src/client/parse.c index 5c6a783ee..f6070ce5d 100644 --- a/src/client/parse.c +++ b/src/client/parse.c @@ -1406,6 +1406,9 @@ void CL_ParseServerMessage(void) extrabits = cmd >> SVCMD_BITS; cmd &= SVCMD_MASK; + if (cmd == svc_extend) + cmd = MSG_ReadByte(); + SHOWNET(1, "%3u:%s\n", msg_read.readcount - 1, MSG_ServerCommandString(cmd)); // other commands From 17d3300b507738b3445ad1fa9cdac2572edee6a7 Mon Sep 17 00:00:00 2001 From: Dino <8dino2@gmail.com> Date: Wed, 20 Dec 2023 23:17:22 -0500 Subject: [PATCH 103/167] Scope stuff? --- inc/common/common.h | 1 + inc/shared/shared.h | 2 +- src/client/client.h | 4 ++++ src/client/main.c | 6 ++++++ src/common/common.c | 2 ++ src/game/g_local.h | 1 + src/game/g_main.c | 2 ++ src/game/p_client.c | 2 ++ 8 files changed, 19 insertions(+), 1 deletion(-) diff --git a/inc/common/common.h b/inc/common/common.h index 2067aebaa..9e8f80848 100644 --- a/inc/common/common.h +++ b/inc/common/common.h @@ -149,6 +149,7 @@ extern cvar_t *dedicated; extern cvar_t *steamid; extern cvar_t *steamcloudappenabled; extern cvar_t *steamclouduserenabled; +extern cvar_t *scopename; #endif #if USE_CLIENT extern cvar_t *host_speeds; diff --git a/inc/shared/shared.h b/inc/shared/shared.h index 04591ec69..15f285ac6 100644 --- a/inc/shared/shared.h +++ b/inc/shared/shared.h @@ -1314,7 +1314,7 @@ enum { #define DF_QUADFIRE_DROP BIT(16) //ROGUE -#define DF_NO_MINES BIT(17) +#define DF_NO_MINES BIT(17) // In AQtion, this is the dmflag for Darkmatch #define DF_NO_STACK_DOUBLE BIT(18) #define DF_NO_NUKES BIT(19) #define DF_NO_SPHERES BIT(20) diff --git a/src/client/client.h b/src/client/client.h index 9181cb228..e941a1e0d 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -51,6 +51,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/ui.h" #include "client/video.h" +#if USE_AQTION +#include "steam/steam_api.h" +#endif + #if USE_ZLIB #include #endif diff --git a/src/client/main.c b/src/client/main.c index fbc85f3c6..9752ac661 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -101,6 +101,7 @@ cvar_t *info_uf; cvar_t *info_steamid; cvar_t *info_steamcloudappenabled; cvar_t *info_steamclouduserenabled; +cvar_t *info_scopename; cvar_t *cl_mk23_sound; cvar_t *cl_mp5_sound; cvar_t *cl_m4_sound; @@ -4074,6 +4075,7 @@ static void CL_InitLocal(void) info_steamid = Cvar_Get("steamid", "", CVAR_USERINFO); info_steamcloudappenabled = Cvar_Get("steamcloudappenabled", "", CVAR_USERINFO); info_steamclouduserenabled = Cvar_Get("steamclouduserenabled", "", CVAR_USERINFO); + info_scopename = Cvar_Get("scopename", "", CVAR_USERINFO); #endif info_version = Cvar_Get("version", "", CVAR_USERINFO); @@ -4632,6 +4634,10 @@ void CL_Init(void) Q_assert(inflateInit2(&cls.z, -MAX_WBITS) == Z_OK); #endif +if USE_AQTION + CL_RetrieveSteamID(); +#endif + SCR_InitCinematics(); OGG_Init(); diff --git a/src/common/common.c b/src/common/common.c index 6eea8b0c5..3e2c0eb28 100644 --- a/src/common/common.c +++ b/src/common/common.c @@ -87,6 +87,7 @@ cvar_t *dedicated; cvar_t *steamid; cvar_t *steamcloudappenabled; cvar_t *steamclouduserenabled; +cvar_t *scopename; #endif cvar_t *com_version; @@ -894,6 +895,7 @@ void Qcommon_Init(int argc, char **argv) steamid = Cvar_Get("steamid", "0", CVAR_NOSET); steamcloudappenabled = Cvar_Get("steamcloudappenabled", "0", CVAR_NOSET); steamclouduserenabled = Cvar_Get("steamclouduserenabled", "0", CVAR_NOSET); + scopename = Cvar_Get("scopename", "", CVAR_USERINFO); cl_running = Cvar_Get("cl_running", "0", CVAR_ROM); cl_paused = Cvar_Get("cl_paused", "0", CVAR_ROM); #else diff --git a/src/game/g_local.h b/src/game/g_local.h index 11e3723d7..2c6d4cc34 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -503,6 +503,7 @@ extern cvar_t *dedicated; extern cvar_t *steamid; extern cvar_t *steamcloudappenabled; extern cvar_t *steamclouduserenabled; +extern cvar_t *scopename; #endif extern cvar_t *filterban; diff --git a/src/game/g_main.c b/src/game/g_main.c index b873c9523..53c6ceb41 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -49,6 +49,7 @@ cvar_t *steamid; #if USE_CLIENT cvar_t *steamcloudappenabled; cvar_t *steamclouduserenabled; +cvar_t *scopename; #endif cvar_t *filterban; @@ -136,6 +137,7 @@ void InitGame(void) steamid = gi.cvar("steamid", "0", CVAR_USERINFO | CVAR_NOSET); steamcloudappenabled = gi.cvar("steamcloudappenabled", "", CVAR_USERINFO); steamclouduserenabled = gi.cvar("steamclouduserenabled", "", CVAR_USERINFO); + scopename = gi.cvar("scopename", "scopexyz", CVAR_USERINFO); #endif // latched vars diff --git a/src/game/p_client.c b/src/game/p_client.c index 88de3994b..33d419f6d 100644 --- a/src/game/p_client.c +++ b/src/game/p_client.c @@ -1362,6 +1362,8 @@ void ClientUserinfoChanged(edict_t *ent, char *userinfo) ent->client->pers.hand = atoi(s); } + ent->client->ps. + // save off the userinfo in case we want to check something later Q_strlcpy(ent->client->pers.userinfo, userinfo, sizeof(ent->client->pers.userinfo)); } From 6e8e10803e52a2af3a2d8e827a5a79e313e5692d Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Fri, 22 Dec 2023 10:48:28 -0500 Subject: [PATCH 104/167] Fixing Github huge screwup on not syncing parse.c correctly --- src/client/precache.c | 2 +- src/server/mvd/game.c | 4 ++-- src/server/mvd/parse.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/client/precache.c b/src/client/precache.c index cf442098c..09bda49bb 100644 --- a/src/client/precache.c +++ b/src/client/precache.c @@ -238,7 +238,7 @@ void CL_RegisterBspModels(void) Com_WPrintf("Local map version differs from demo: %i != %s\n", cl.bsp->checksum, cl.configstrings[CS_MAPCHECKSUM]); } else { - Com_Error(ERR_DROP, "Local map version differs from server: %i != %s\nRecommend removing %s locally and reconnecting", + Com_Error(ERR_DROP, "Local map version differs from server: %i != %s\nRecommend removing %s locally and reconnecting\n", cl.bsp->checksum, cl.configstrings[CS_MAPCHECKSUM], cl.bsp->name); } } diff --git a/src/server/mvd/game.c b/src/server/mvd/game.c index b13052e31..6db045056 100644 --- a/src/server/mvd/game.c +++ b/src/server/mvd/game.c @@ -1785,8 +1785,8 @@ static void MVD_GameInit(void) Com_EPrintf("Couldn't load %s for the Waiting Room: %s\n", buffer, BSP_ErrorString(ret)); Cvar_Reset(mvd_default_map); - strcpy(buffer, "maps/q2dm1.bsp"); - checksum = 80717714; + strcpy(buffer, "maps/wfall.bsp"); + checksum = 917713192; VectorSet(mvd->spawnOrigin, 984, 192, 784); VectorSet(mvd->spawnAngles, 25, 72, 0); } else { diff --git a/src/server/mvd/parse.c b/src/server/mvd/parse.c index 8bde61198..4b53be5a6 100644 --- a/src/server/mvd/parse.c +++ b/src/server/mvd/parse.c @@ -1007,8 +1007,8 @@ static void MVD_ParseServerData(mvd_t *mvd, int extrabits) if (ret) { Com_EPrintf("[%s] =!= Couldn't load %s: %s\n", mvd->name, string, BSP_ErrorString(ret)); // continue with null visibility - } else if (mvd->cm.cache->checksum != atoi(mvd->configstrings[CS_MAPCHECKSUM])) { - Com_EPrintf("[%s] =!= Local map version differs from server!\nRecommend removing that file and reconnecting", mvd->name); + } else if (mvd->cm.cache->checksum != atoi(mvd->configstrings[mvd->csr->mapchecksum])){ + Com_EPrintf("[%s] =!= Local map version differs from server!\nRecommend removing %s locally and reconnecting\n", mvd->name, mvd->mapname); CM_FreeMap(&mvd->cm); } From b7a965f0fb46f3700c1aa9deb50804ebc9f74701 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 24 Dec 2023 23:11:04 +0300 Subject: [PATCH 105/167] Add SignExtend() function. --- inc/shared/shared.h | 5 +++++ src/common/msg.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/inc/shared/shared.h b/inc/shared/shared.h index 69aa9abc8..bcc7745bb 100644 --- a/inc/shared/shared.h +++ b/inc/shared/shared.h @@ -543,6 +543,11 @@ static inline float LongToFloat(uint32_t l) return dat.f; } +static inline int32_t SignExtend(uint32_t v, int bits) +{ + return (int32_t)(v << (32 - bits)) >> (32 - bits); +} + #if USE_LITTLE_ENDIAN #define BigShort ShortSwap #define BigLong LongSwap diff --git a/src/common/msg.c b/src/common/msg.c index 3a34d95f2..775d6f400 100644 --- a/src/common/msg.c +++ b/src/common/msg.c @@ -1735,7 +1735,7 @@ int MSG_ReadBits(int bits) msg_read.bits_left = bits_left - bits; if (sgn) { - return (int32_t)(value << (32 - bits)) >> (32 - bits); + return SignExtend(value, bits); } return value; From aec56b8b8e2257f4f8b73aa074ed9d31a0916b69 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 24 Dec 2023 23:19:40 +0300 Subject: [PATCH 106/167] Fix more whitespace issues in game code. --- src/game/g_main.c | 4 +-- src/game/g_weapon.c | 2 +- src/game/m_boss31.c | 5 ++- src/game/m_brain.c | 84 +++++++++++++++++++++++++-------------------- 4 files changed, 51 insertions(+), 44 deletions(-) diff --git a/src/game/g_main.c b/src/game/g_main.c index ea4d8ba46..013c9e9e0 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -131,8 +131,8 @@ void InitGame(void) // latched vars sv_cheats = gi.cvar("cheats", "0", CVAR_SERVERINFO | CVAR_LATCH); - gi.cvar("gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_LATCH); - gi.cvar("gamedate", __DATE__ , CVAR_SERVERINFO | CVAR_LATCH); + gi.cvar("gamename", GAMEVERSION, CVAR_SERVERINFO | CVAR_LATCH); + gi.cvar("gamedate", __DATE__, CVAR_SERVERINFO | CVAR_LATCH); maxclients = gi.cvar("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH); maxspectators = gi.cvar("maxspectators", "4", CVAR_SERVERINFO); diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c index 2fea1880c..d854a4583 100644 --- a/src/game/g_weapon.c +++ b/src/game/g_weapon.c @@ -636,7 +636,7 @@ void fire_rail(edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick) } else { //ZOID--added so rail goes through SOLID_BBOX entities (gibs, etc) if (((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client) || - (tr.ent->solid == SOLID_BBOX)) && (lastfrac + tr.fraction > 0)) + (tr.ent->solid == SOLID_BBOX)) && (lastfrac + tr.fraction > 0)) ignore = tr.ent; else ignore = NULL; diff --git a/src/game/m_boss31.c b/src/game/m_boss31.c index aa5cfd9ee..b8f144dc6 100644 --- a/src/game/m_boss31.c +++ b/src/game/m_boss31.c @@ -374,14 +374,14 @@ const mmove_t jorg_move_end_attack1 = {FRAME_attak115, FRAME_attak118, jorg_fram void jorg_reattack1(edict_t *self) { - if (visible(self, self->enemy)) + if (visible(self, self->enemy)) { if (random() < 0.9f) self->monsterinfo.currentmove = &jorg_move_attack1; else { self->s.sound = 0; self->monsterinfo.currentmove = &jorg_move_end_attack1; } - else { + } else { self->s.sound = 0; self->monsterinfo.currentmove = &jorg_move_end_attack1; } @@ -394,7 +394,6 @@ void jorg_attack1(edict_t *self) void jorg_pain(edict_t *self, edict_t *other, float kick, int damage) { - if (self->health < (self->max_health / 2)) self->s.skinnum = 1; diff --git a/src/game/m_brain.c b/src/game/m_brain.c index 7fb15a3ad..ab216009a 100644 --- a/src/game/m_brain.c +++ b/src/game/m_brain.c @@ -163,12 +163,12 @@ static const mframe_t brain_frames_walk1[] = { }; const mmove_t brain_move_walk1 = {FRAME_walk101, FRAME_walk111, brain_frames_walk1, NULL}; -void brain_walk(edict_t *self) { +void brain_walk(edict_t *self) +{ self->monsterinfo.currentmove = &brain_move_walk1; } -static const mframe_t brain_frames_defense[] = -{ +static const mframe_t brain_frames_defense[] = { { ai_move, 0, NULL }, { ai_move, 0, NULL }, { ai_move, 0, NULL }, @@ -181,8 +181,7 @@ static const mframe_t brain_frames_defense[] = }; const mmove_t brain_move_defense = {FRAME_defens01, FRAME_defens08, brain_frames_defense, NULL}; -static const mframe_t brain_frames_pain3[] = -{ +static const mframe_t brain_frames_pain3[] = { { ai_move, -2, NULL }, { ai_move, 2, NULL }, { ai_move, 1, NULL }, @@ -192,8 +191,7 @@ static const mframe_t brain_frames_pain3[] = }; const mmove_t brain_move_pain3 = {FRAME_pain301, FRAME_pain306, brain_frames_pain3, brain_run}; -static const mframe_t brain_frames_pain2[] = -{ +static const mframe_t brain_frames_pain2[] = { { ai_move, -2, NULL }, { ai_move, 0, NULL }, { ai_move, 0, NULL }, @@ -205,8 +203,7 @@ static const mframe_t brain_frames_pain2[] = }; const mmove_t brain_move_pain2 = {FRAME_pain201, FRAME_pain208, brain_frames_pain2, brain_run}; -static const mframe_t brain_frames_pain1[] = -{ +static const mframe_t brain_frames_pain1[] = { { ai_move, -6, NULL }, { ai_move, -2, NULL }, { ai_move, -6, NULL }, @@ -235,7 +232,8 @@ const mmove_t brain_move_pain1 = {FRAME_pain101, FRAME_pain121, brain_frames_pai // DUCK // -void brain_duck_down(edict_t *self) { +void brain_duck_down(edict_t *self) +{ if (self->monsterinfo.aiflags & AI_DUCKED) return; self->monsterinfo.aiflags |= AI_DUCKED; @@ -244,22 +242,23 @@ void brain_duck_down(edict_t *self) { gi.linkentity(self); } -void brain_duck_hold(edict_t *self) { +void brain_duck_hold(edict_t *self) +{ if (level.framenum >= self->monsterinfo.pause_framenum) self->monsterinfo.aiflags &= ~AI_HOLD_FRAME; else self->monsterinfo.aiflags |= AI_HOLD_FRAME; } -void brain_duck_up(edict_t *self) { +void brain_duck_up(edict_t *self) +{ self->monsterinfo.aiflags &= ~AI_DUCKED; self->maxs[2] += 32; self->takedamage = DAMAGE_AIM; gi.linkentity(self); } -static const mframe_t brain_frames_duck[] = -{ +static const mframe_t brain_frames_duck[] = { { ai_move, 0, NULL }, { ai_move, -2, brain_duck_down }, { ai_move, 17, brain_duck_hold }, @@ -271,7 +270,8 @@ static const mframe_t brain_frames_duck[] = }; const mmove_t brain_move_duck = {FRAME_duck01, FRAME_duck08, brain_frames_duck, brain_run}; -void brain_dodge(edict_t *self, edict_t *attacker, float eta) { +void brain_dodge(edict_t *self, edict_t *attacker, float eta) +{ if (random() > 0.25f) return; @@ -282,8 +282,7 @@ void brain_dodge(edict_t *self, edict_t *attacker, float eta) { self->monsterinfo.currentmove = &brain_move_duck; } -static const mframe_t brain_frames_death2[] = -{ +static const mframe_t brain_frames_death2[] = { { ai_move, 0, NULL }, { ai_move, 0, NULL }, { ai_move, 0, NULL }, @@ -292,8 +291,7 @@ static const mframe_t brain_frames_death2[] = }; const mmove_t brain_move_death2 = {FRAME_death201, FRAME_death205, brain_frames_death2, brain_dead}; -static const mframe_t brain_frames_death1[] = -{ +static const mframe_t brain_frames_death1[] = { { ai_move, 0, NULL }, { ai_move, 0, NULL }, { ai_move, -2, NULL }, @@ -319,11 +317,13 @@ const mmove_t brain_move_death1 = {FRAME_death101, FRAME_death118, brain_frames_ // MELEE // -void brain_swing_right(edict_t *self) { +void brain_swing_right(edict_t *self) +{ gi.sound(self, CHAN_BODY, sound_melee1, 1, ATTN_NORM, 0); } -void brain_hit_right(edict_t *self) { +void brain_hit_right(edict_t *self) +{ vec3_t aim; VectorSet(aim, MELEE_DISTANCE, self->maxs[0], 8); @@ -331,11 +331,13 @@ void brain_hit_right(edict_t *self) { gi.sound(self, CHAN_WEAPON, sound_melee3, 1, ATTN_NORM, 0); } -void brain_swing_left(edict_t *self) { +void brain_swing_left(edict_t *self) +{ gi.sound(self, CHAN_BODY, sound_melee2, 1, ATTN_NORM, 0); } -void brain_hit_left(edict_t *self) { +void brain_hit_left(edict_t *self) +{ vec3_t aim; VectorSet(aim, MELEE_DISTANCE, self->mins[0], 8); @@ -343,8 +345,7 @@ void brain_hit_left(edict_t *self) { gi.sound(self, CHAN_WEAPON, sound_melee3, 1, ATTN_NORM, 0); } -static const mframe_t brain_frames_attack1[] = -{ +static const mframe_t brain_frames_attack1[] = { { ai_charge, 8, NULL }, { ai_charge, 3, NULL }, { ai_charge, 5, NULL }, @@ -366,13 +367,15 @@ static const mframe_t brain_frames_attack1[] = }; const mmove_t brain_move_attack1 = {FRAME_attak101, FRAME_attak118, brain_frames_attack1, brain_run}; -void brain_chest_open(edict_t *self) { +void brain_chest_open(edict_t *self) +{ self->spawnflags &= ~65536; self->monsterinfo.power_armor_type = POWER_ARMOR_NONE; gi.sound(self, CHAN_BODY, sound_chest_open, 1, ATTN_NORM, 0); } -void brain_tentacle_attack(edict_t *self) { +void brain_tentacle_attack(edict_t *self) +{ vec3_t aim; VectorSet(aim, MELEE_DISTANCE, 0, 8); @@ -381,7 +384,8 @@ void brain_tentacle_attack(edict_t *self) { gi.sound(self, CHAN_WEAPON, sound_tentacles_retract, 1, ATTN_NORM, 0); } -void brain_chest_closed(edict_t *self) { +void brain_chest_closed(edict_t *self) +{ self->monsterinfo.power_armor_type = POWER_ARMOR_SCREEN; if (self->spawnflags & 65536) { self->spawnflags &= ~65536; @@ -389,8 +393,7 @@ void brain_chest_closed(edict_t *self) { } } -static const mframe_t brain_frames_attack2[] = -{ +static const mframe_t brain_frames_attack2[] = { { ai_charge, 5, NULL }, { ai_charge, -4, NULL }, { ai_charge, -4, NULL }, @@ -411,7 +414,8 @@ static const mframe_t brain_frames_attack2[] = }; const mmove_t brain_move_attack2 = {FRAME_attak201, FRAME_attak217, brain_frames_attack2, brain_run}; -void brain_melee(edict_t *self) { +void brain_melee(edict_t *self) +{ if (random() <= 0.5f) self->monsterinfo.currentmove = &brain_move_attack1; else @@ -422,8 +426,7 @@ void brain_melee(edict_t *self) { // RUN // -static const mframe_t brain_frames_run[] = -{ +static const mframe_t brain_frames_run[] = { { ai_run, 9, NULL }, { ai_run, 2, NULL }, { ai_run, 3, NULL }, @@ -438,7 +441,8 @@ static const mframe_t brain_frames_run[] = }; const mmove_t brain_move_run = {FRAME_walk101, FRAME_walk111, brain_frames_run, NULL}; -void brain_run(edict_t *self) { +void brain_run(edict_t *self) +{ self->monsterinfo.power_armor_type = POWER_ARMOR_SCREEN; if (self->monsterinfo.aiflags & AI_STAND_GROUND) self->monsterinfo.currentmove = &brain_move_stand; @@ -446,7 +450,8 @@ void brain_run(edict_t *self) { self->monsterinfo.currentmove = &brain_move_run; } -void brain_pain(edict_t *self, edict_t *other, float kick, int damage) { +void brain_pain(edict_t *self, edict_t *other, float kick, int damage) +{ float r; if (self->health < (self->max_health / 2)) @@ -472,7 +477,8 @@ void brain_pain(edict_t *self, edict_t *other, float kick, int damage) { } } -void brain_dead(edict_t *self) { +void brain_dead(edict_t *self) +{ VectorSet(self->mins, -16, -16, -24); VectorSet(self->maxs, 16, 16, -8); self->movetype = MOVETYPE_TOSS; @@ -481,7 +487,8 @@ void brain_dead(edict_t *self) { gi.linkentity(self); } -void brain_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) { +void brain_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) +{ int n; self->s.effects = 0; @@ -532,7 +539,8 @@ static void brain_precache(void) /*QUAKED monster_brain (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ -void SP_monster_brain(edict_t *self) { +void SP_monster_brain(edict_t *self) +{ if (deathmatch->value) { G_FreeEdict(self); return; From 322173ff18f4e211e83990ce75e234795219efd8 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 24 Dec 2023 23:25:05 +0300 Subject: [PATCH 107/167] Use initializer for aim vector. --- src/game/m_berserk.c | 6 +++--- src/game/m_brain.c | 9 +++------ src/game/m_chick.c | 3 +-- src/game/m_flipper.c | 3 +-- src/game/m_float.c | 3 ++- src/game/m_flyer.c | 6 ++---- src/game/m_gladiator.c | 3 +-- src/game/m_infantry.c | 3 +-- src/game/m_mutant.c | 6 ++---- 9 files changed, 16 insertions(+), 26 deletions(-) diff --git a/src/game/m_berserk.c b/src/game/m_berserk.c index c4ecda1eb..8a02b0c80 100644 --- a/src/game/m_berserk.c +++ b/src/game/m_berserk.c @@ -158,7 +158,8 @@ void berserk_run(edict_t *self) void berserk_attack_spike(edict_t *self) { - vec3_t aim = {MELEE_DISTANCE, 0, -24}; + vec3_t aim = { MELEE_DISTANCE, 0, -24 }; + fire_hit(self, aim, (15 + (Q_rand() % 6)), 400); // Faster attack -- upwards and backwards } @@ -181,9 +182,8 @@ const mmove_t berserk_move_attack_spike = {FRAME_att_c1, FRAME_att_c8, berserk_f void berserk_attack_club(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, self->mins[0], -4 }; - VectorSet(aim, MELEE_DISTANCE, self->mins[0], -4); fire_hit(self, aim, (5 + (Q_rand() % 6)), 400); // Slower attack } diff --git a/src/game/m_brain.c b/src/game/m_brain.c index ab216009a..09258fe24 100644 --- a/src/game/m_brain.c +++ b/src/game/m_brain.c @@ -324,9 +324,8 @@ void brain_swing_right(edict_t *self) void brain_hit_right(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, self->maxs[0], 8 }; - VectorSet(aim, MELEE_DISTANCE, self->maxs[0], 8); if (fire_hit(self, aim, (15 + (Q_rand() % 5)), 40)) gi.sound(self, CHAN_WEAPON, sound_melee3, 1, ATTN_NORM, 0); } @@ -338,9 +337,8 @@ void brain_swing_left(edict_t *self) void brain_hit_left(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, self->mins[0], 8 }; - VectorSet(aim, MELEE_DISTANCE, self->mins[0], 8); if (fire_hit(self, aim, (15 + (Q_rand() % 5)), 40)) gi.sound(self, CHAN_WEAPON, sound_melee3, 1, ATTN_NORM, 0); } @@ -376,9 +374,8 @@ void brain_chest_open(edict_t *self) void brain_tentacle_attack(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, 0, 8 }; - VectorSet(aim, MELEE_DISTANCE, 0, 8); if (fire_hit(self, aim, (10 + (Q_rand() % 5)), -600) && skill->value > 0) self->spawnflags |= 65536; gi.sound(self, CHAN_WEAPON, sound_tentacles_retract, 1, ATTN_NORM, 0); diff --git a/src/game/m_chick.c b/src/game/m_chick.c index ee3b9a878..95071b0b1 100644 --- a/src/game/m_chick.c +++ b/src/game/m_chick.c @@ -417,9 +417,8 @@ void chick_dodge(edict_t *self, edict_t *attacker, float eta) void ChickSlash(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, self->mins[0], 10 }; - VectorSet(aim, MELEE_DISTANCE, self->mins[0], 10); gi.sound(self, CHAN_WEAPON, sound_melee_swing, 1, ATTN_NORM, 0); fire_hit(self, aim, (10 + (Q_rand() % 6)), 100); } diff --git a/src/game/m_flipper.c b/src/game/m_flipper.c index 1f53befa8..dced1f519 100644 --- a/src/game/m_flipper.c +++ b/src/game/m_flipper.c @@ -168,9 +168,8 @@ const mmove_t flipper_move_pain1 = {FRAME_flppn201, FRAME_flppn205, flipper_fram void flipper_bite(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, 0, 0 }; - VectorSet(aim, MELEE_DISTANCE, 0, 0); fire_hit(self, aim, 5, 0); } diff --git a/src/game/m_float.c b/src/game/m_float.c index 15a510d58..bbe7285b7 100644 --- a/src/game/m_float.c +++ b/src/game/m_float.c @@ -495,7 +495,8 @@ void floater_walk(edict_t *self) void floater_wham(edict_t *self) { - vec3_t aim = {MELEE_DISTANCE, 0, 0}; + vec3_t aim = { MELEE_DISTANCE, 0, 0 }; + gi.sound(self, CHAN_WEAPON, sound_attack3, 1, ATTN_NORM, 0); fire_hit(self, aim, 5 + Q_rand() % 6, -50); } diff --git a/src/game/m_flyer.c b/src/game/m_flyer.c index b64b9a1ae..96d33e5bf 100644 --- a/src/game/m_flyer.c +++ b/src/game/m_flyer.c @@ -398,18 +398,16 @@ const mmove_t flyer_move_attack2 = {FRAME_attak201, FRAME_attak217, flyer_frames void flyer_slash_left(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, self->mins[0], 0 }; - VectorSet(aim, MELEE_DISTANCE, self->mins[0], 0); fire_hit(self, aim, 5, 0); gi.sound(self, CHAN_WEAPON, sound_slash, 1, ATTN_NORM, 0); } void flyer_slash_right(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, self->maxs[0], 0 }; - VectorSet(aim, MELEE_DISTANCE, self->maxs[0], 0); fire_hit(self, aim, 5, 0); gi.sound(self, CHAN_WEAPON, sound_slash, 1, ATTN_NORM, 0); } diff --git a/src/game/m_gladiator.c b/src/game/m_gladiator.c index 46329b51f..1b5ac6611 100644 --- a/src/game/m_gladiator.c +++ b/src/game/m_gladiator.c @@ -118,9 +118,8 @@ void gladiator_run(edict_t *self) void GaldiatorMelee(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, self->mins[0], -4 }; - VectorSet(aim, MELEE_DISTANCE, self->mins[0], -4); if (fire_hit(self, aim, (20 + (Q_rand() % 5)), 300)) gi.sound(self, CHAN_AUTO, sound_cleaver_hit, 1, ATTN_NORM, 0); else diff --git a/src/game/m_infantry.c b/src/game/m_infantry.c index 0e051d121..e9c8e431f 100644 --- a/src/game/m_infantry.c +++ b/src/game/m_infantry.c @@ -484,9 +484,8 @@ void infantry_swing(edict_t *self) void infantry_smack(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, 0, 0 }; - VectorSet(aim, MELEE_DISTANCE, 0, 0); if (fire_hit(self, aim, (5 + (Q_rand() % 5)), 50)) gi.sound(self, CHAN_WEAPON, sound_punch_hit, 1, ATTN_NORM, 0); } diff --git a/src/game/m_mutant.c b/src/game/m_mutant.c index 334ab06a2..d624b62ff 100644 --- a/src/game/m_mutant.c +++ b/src/game/m_mutant.c @@ -241,9 +241,8 @@ void mutant_run(edict_t *self) void mutant_hit_left(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, self->mins[0], 8 }; - VectorSet(aim, MELEE_DISTANCE, self->mins[0], 8); if (fire_hit(self, aim, (10 + (Q_rand() % 5)), 100)) gi.sound(self, CHAN_WEAPON, sound_hit, 1, ATTN_NORM, 0); else @@ -252,9 +251,8 @@ void mutant_hit_left(edict_t *self) void mutant_hit_right(edict_t *self) { - vec3_t aim; + vec3_t aim = { MELEE_DISTANCE, self->maxs[0], 8 }; - VectorSet(aim, MELEE_DISTANCE, self->maxs[0], 8); if (fire_hit(self, aim, (10 + (Q_rand() % 5)), 100)) gi.sound(self, CHAN_WEAPON, sound_hit2, 1, ATTN_NORM, 0); else From 466ff91dbbd93423a818e663fffa61d683450d71 Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Fri, 12 Jan 2024 12:28:51 -0500 Subject: [PATCH 108/167] Precaching hitsounds --- src/client/tent.c | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/src/client/tent.c b/src/client/tent.c index 3ef8e976c..0ff1d7e45 100644 --- a/src/client/tent.c +++ b/src/client/tent.c @@ -238,6 +238,34 @@ static void CL_RegisterFootsteps(void) } } +static void CL_RegisterAQtionSounds(void) +{ + int i; + char name[MAX_QPATH]; + + // Register all AQtion gun sounds + char gunsounds[][64] = {"mk23fire", "mp5fire", "m4a1fire", "shotgf1b", "cannon_fire", "ssgfire"}; + size_t guncount = sizeof(gunsounds) / sizeof(gunsounds[0]); + + for (size_t j = 0; j < guncount; j++) { + Q_snprintf(name, sizeof(name), "weapons/%s.wav", gunsounds[j]); + S_RegisterSound(name); + for (i = MIN_WEAPON_SOUND; i < MAX_WEAPON_SOUND; i++) { + Q_snprintf(name, sizeof(name), "weapons/%s%i.wav", gunsounds[j], i + 1); + S_RegisterSound(name); + } + } + + // Register all AQtion hit sounds + char hitsounds[][64] = {"aphelmet", "apvest", "body", "chest", "headshot", "leg", "stomach", "vest"}; + size_t hitsoundcount = sizeof(hitsounds) / sizeof(hitsounds[0]); + + for (size_t j = 0; j < hitsoundcount; j++) { + Q_snprintf(name, sizeof(name), "hitsounds/%s.wav", hitsounds[j]); + S_RegisterSound(name); + } +} + /* ================= CL_RegisterTEntSounds @@ -271,22 +299,10 @@ void CL_RegisterTEntSounds(void) } CL_RegisterFootsteps(); + CL_RegisterAQtionSounds(); cl_sfx_lightning = S_RegisterSound("weapons/tesla.wav"); - cl_sfx_disrexp = S_RegisterSound("weapons/disrupthit.wav"); - - // Register all AQtion gun sounds - char gunsounds[][64] = {"mk23fire", "mp5fire", "m4a1fire", "shotgf1b", "cannon_fire", "ssgfire"}; - size_t guncount = sizeof(gunsounds) / sizeof(gunsounds[0]); - - for (size_t j = 0; j < guncount; j++) { - Q_snprintf(name, sizeof(name), "weapons/%s.wav", gunsounds[j]); - S_RegisterSound(name); - for (i = MIN_WEAPON_SOUND; i < MAX_WEAPON_SOUND; i++) { - Q_snprintf(name, sizeof(name), "weapons/%s%i.wav", gunsounds[j], i + 1); - S_RegisterSound(name); - } - } + cl_sfx_disrexp = S_RegisterSound("weapons/disrupthit.wav"); } /* From d1f7ff76ad343e3bb82c076785595859f6719bca Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Fri, 12 Jan 2024 12:31:42 -0500 Subject: [PATCH 109/167] Removed unused sounds --- src/client/tent.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/client/tent.c b/src/client/tent.c index 0ff1d7e45..1556ab725 100644 --- a/src/client/tent.c +++ b/src/client/tent.c @@ -34,9 +34,6 @@ qhandle_t cl_sfx_watrexp; qhandle_t cl_sfx_footsteps[12]; qhandle_t cl_sfx_landing[8]; -qhandle_t cl_sfx_lightning; -qhandle_t cl_sfx_disrexp; - //qhandle_t cl_mod_explode; qhandle_t cl_mod_smoke; qhandle_t cl_mod_flash; @@ -300,9 +297,6 @@ void CL_RegisterTEntSounds(void) CL_RegisterFootsteps(); CL_RegisterAQtionSounds(); - - cl_sfx_lightning = S_RegisterSound("weapons/tesla.wav"); - cl_sfx_disrexp = S_RegisterSound("weapons/disrupthit.wav"); } /* @@ -1518,7 +1512,7 @@ void CL_ParseTEnt(void) break; case TE_LIGHTNING: - S_StartSound(NULL, te.entity1, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0); + S_StartSound(NULL, te.entity1, CHAN_WEAPON, NULL, 1, ATTN_NORM, 0); VectorClear(te.offset); CL_ParseBeam(cl_mod_lightning); break; @@ -1586,7 +1580,7 @@ void CL_ParseTEnt(void) case TE_TRACKER_EXPLOSION: CL_ColorFlash(te.pos1, 0, 150, -1, -1, -1); CL_ColorExplosionParticles(te.pos1, 0, 1); - S_StartSound(te.pos1, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0); + S_StartSound(te.pos1, 0, 0, NULL, 1, ATTN_NORM, 0); break; case TE_TELEPORT_EFFECT: From 342c88bc05bad6119503101bd93e88074f26d688 Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Fri, 12 Jan 2024 12:32:13 -0500 Subject: [PATCH 110/167] Removed unused sounds again --- src/client/tent.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/tent.c b/src/client/tent.c index 1556ab725..71fc6534f 100644 --- a/src/client/tent.c +++ b/src/client/tent.c @@ -1512,7 +1512,7 @@ void CL_ParseTEnt(void) break; case TE_LIGHTNING: - S_StartSound(NULL, te.entity1, CHAN_WEAPON, NULL, 1, ATTN_NORM, 0); + //S_StartSound(NULL, te.entity1, CHAN_WEAPON, NULL, 1, ATTN_NORM, 0); VectorClear(te.offset); CL_ParseBeam(cl_mod_lightning); break; @@ -1580,7 +1580,7 @@ void CL_ParseTEnt(void) case TE_TRACKER_EXPLOSION: CL_ColorFlash(te.pos1, 0, 150, -1, -1, -1); CL_ColorExplosionParticles(te.pos1, 0, 1); - S_StartSound(te.pos1, 0, 0, NULL, 1, ATTN_NORM, 0); + //S_StartSound(te.pos1, 0, 0, NULL, 1, ATTN_NORM, 0); break; case TE_TELEPORT_EFFECT: From 70f89712102eb90e07d8675becad58bdc63306c8 Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Fri, 12 Jan 2024 16:42:47 -0500 Subject: [PATCH 111/167] Allows for multiple scopes --- src/client/screen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/screen.c b/src/client/screen.c index 7302a9569..8df73644a 100644 --- a/src/client/screen.c +++ b/src/client/screen.c @@ -1796,7 +1796,7 @@ static void SCR_ExecuteLayoutString(const char *s) if (token[0]) { qhandle_t pic = cl.image_precache[value]; // hack for action mod scope scaling - if (Com_WildCmp("scope?x", token)) { + if (Com_WildCmp("scope?x", token) || Com_WildCmp("scopes/*/scope?x", token)) { int x = scr.hud_x + (scr.hud_width - scr.scope_width) / 2; int y = scr.hud_y + (scr.hud_height - scr.scope_height) / 2; From b7f5d8171153d4ad35ede29356de82eadd411571 Mon Sep 17 00:00:00 2001 From: Dino <8dino2@gmail.com> Date: Mon, 15 Jan 2024 20:07:20 -0500 Subject: [PATCH 112/167] Enable zoom autosensitivity --- src/client/client.h | 4 ---- src/client/main.c | 4 ---- src/client/view.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index f76678d2f..fc704a58a 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -51,10 +51,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/ui.h" #include "client/video.h" -#if USE_AQTION -#include "steam/steam_api.h" -#endif - #if USE_ZLIB #include #endif diff --git a/src/client/main.c b/src/client/main.c index 01780d432..f8ebf24bb 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -4635,10 +4635,6 @@ void CL_Init(void) Q_assert(inflateInit2(&cls.z, -MAX_WBITS) == Z_OK); #endif -if USE_AQTION - CL_RetrieveSteamID(); -#endif - SCR_InitCinematics(); OGG_Init(); diff --git a/src/client/view.c b/src/client/view.c index 5af9c5da7..02109b495 100644 --- a/src/client/view.c +++ b/src/client/view.c @@ -44,6 +44,14 @@ static cvar_t *cl_stats; cvar_t *cl_adjustfov; +#if USE_AQTION +static cvar_t *cl_zoom_autosens; +static cvar_t *cl_zoom_1x; +static cvar_t *cl_zoom_2x; +static cvar_t *cl_zoom_4x; +static cvar_t *cl_zoom_6x; +#endif + int r_numdlights; dlight_t r_dlights[MAX_DLIGHTS]; @@ -344,6 +352,22 @@ float V_CalcFov(float fov_x, float width, float height) return a; } +#if USE_AQTION +static void cl_zoom_autosens_changed(float fov) +{ + if (cl.fov_x >= 90.0f) // No zoom + Cvar_Set("sensitivity", cl_zoom_1x->string); + else if (cl.fov_x == 45.0f && cl_zoom_2x->value) // 2x scope + Cvar_Set("sensitivity", cl_zoom_2x->string); + else if (cl.fov_x == 20.0f && cl_zoom_4x->value) // 4x scope + Cvar_Set("sensitivity", cl_zoom_4x->string); + else if (cl.fov_x == 10.0f && cl_zoom_6x->value) // 6x scope + Cvar_Set("sensitivity", cl_zoom_6x->string); + else // Safe default back to 1x + Cvar_Set("sensitivity", cl_zoom_1x->string); +} +#endif + /* ================== @@ -399,6 +423,10 @@ void V_RenderView(void) cl.refdef.fov_y = V_CalcFov(cl.refdef.fov_x, cl.refdef.width, cl.refdef.height); } + if (cl_zoom_autosens->value) { + cl_zoom_autosens_changed(cl.fov_x); + } + cl.refdef.time = cl.time * 0.001f; if (cl.frame.areabytes) { @@ -487,6 +515,14 @@ void V_Init(void) cl_add_blend->changed = cl_add_blend_changed; cl_adjustfov = Cvar_Get("cl_adjustfov", "1", 0); + + #if USE_AQTION + cl_zoom_autosens = Cvar_Get("cl_zoom_autosens", "0", CVAR_ARCHIVE); + cl_zoom_1x = Cvar_Get("cl_zoom_1x", "0", CVAR_ARCHIVE); + cl_zoom_2x = Cvar_Get("cl_zoom_2x", "0", CVAR_ARCHIVE); + cl_zoom_4x = Cvar_Get("cl_zoom_4x", "0", CVAR_ARCHIVE); + cl_zoom_6x = Cvar_Get("cl_zoom_6x", "0", CVAR_ARCHIVE); + #endif } void V_Shutdown(void) From d997b50f52a3697e59e1dc6002baf8be3171bd9a Mon Sep 17 00:00:00 2001 From: Dino <8dino2@gmail.com> Date: Mon, 15 Jan 2024 20:10:04 -0500 Subject: [PATCH 113/167] Got rid of some nonsense --- inc/common/common.h | 1 - src/client/main.c | 2 -- src/common/common.c | 2 -- src/game/g_local.h | 1 - src/game/g_main.c | 2 -- src/game/p_client.c | 3 --- 6 files changed, 11 deletions(-) diff --git a/inc/common/common.h b/inc/common/common.h index 9e8f80848..2067aebaa 100644 --- a/inc/common/common.h +++ b/inc/common/common.h @@ -149,7 +149,6 @@ extern cvar_t *dedicated; extern cvar_t *steamid; extern cvar_t *steamcloudappenabled; extern cvar_t *steamclouduserenabled; -extern cvar_t *scopename; #endif #if USE_CLIENT extern cvar_t *host_speeds; diff --git a/src/client/main.c b/src/client/main.c index f8ebf24bb..0ecd6b3a4 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -101,7 +101,6 @@ cvar_t *info_uf; cvar_t *info_steamid; cvar_t *info_steamcloudappenabled; cvar_t *info_steamclouduserenabled; -cvar_t *info_scopename; cvar_t *cl_mk23_sound; cvar_t *cl_mp5_sound; cvar_t *cl_m4_sound; @@ -4076,7 +4075,6 @@ static void CL_InitLocal(void) info_steamid = Cvar_Get("steamid", "", CVAR_USERINFO); info_steamcloudappenabled = Cvar_Get("steamcloudappenabled", "", CVAR_USERINFO); info_steamclouduserenabled = Cvar_Get("steamclouduserenabled", "", CVAR_USERINFO); - info_scopename = Cvar_Get("scopename", "", CVAR_USERINFO); #endif info_version = Cvar_Get("version", "", CVAR_USERINFO); diff --git a/src/common/common.c b/src/common/common.c index 3e2c0eb28..6eea8b0c5 100644 --- a/src/common/common.c +++ b/src/common/common.c @@ -87,7 +87,6 @@ cvar_t *dedicated; cvar_t *steamid; cvar_t *steamcloudappenabled; cvar_t *steamclouduserenabled; -cvar_t *scopename; #endif cvar_t *com_version; @@ -895,7 +894,6 @@ void Qcommon_Init(int argc, char **argv) steamid = Cvar_Get("steamid", "0", CVAR_NOSET); steamcloudappenabled = Cvar_Get("steamcloudappenabled", "0", CVAR_NOSET); steamclouduserenabled = Cvar_Get("steamclouduserenabled", "0", CVAR_NOSET); - scopename = Cvar_Get("scopename", "", CVAR_USERINFO); cl_running = Cvar_Get("cl_running", "0", CVAR_ROM); cl_paused = Cvar_Get("cl_paused", "0", CVAR_ROM); #else diff --git a/src/game/g_local.h b/src/game/g_local.h index 6c38205f8..bed1319ab 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -509,7 +509,6 @@ extern cvar_t *dedicated; extern cvar_t *steamid; extern cvar_t *steamcloudappenabled; extern cvar_t *steamclouduserenabled; -extern cvar_t *scopename; #endif extern cvar_t *filterban; diff --git a/src/game/g_main.c b/src/game/g_main.c index a5e72a510..868c86fd0 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -48,7 +48,6 @@ cvar_t *steamid; #if USE_CLIENT cvar_t *steamcloudappenabled; cvar_t *steamclouduserenabled; -cvar_t *scopename; #endif cvar_t *filterban; @@ -138,7 +137,6 @@ void InitGame(void) steamid = gi.cvar("steamid", "0", CVAR_USERINFO | CVAR_NOSET); steamcloudappenabled = gi.cvar("steamcloudappenabled", "", CVAR_USERINFO); steamclouduserenabled = gi.cvar("steamclouduserenabled", "", CVAR_USERINFO); - scopename = gi.cvar("scopename", "scopexyz", CVAR_USERINFO); #endif // latched vars diff --git a/src/game/p_client.c b/src/game/p_client.c index 33d419f6d..480a2cd60 100644 --- a/src/game/p_client.c +++ b/src/game/p_client.c @@ -1361,9 +1361,6 @@ void ClientUserinfoChanged(edict_t *ent, char *userinfo) if (strlen(s)) { ent->client->pers.hand = atoi(s); } - - ent->client->ps. - // save off the userinfo in case we want to check something later Q_strlcpy(ent->client->pers.userinfo, userinfo, sizeof(ent->client->pers.userinfo)); } From 7ffe61a33dddbb228b57595ea99893613d04fcf1 Mon Sep 17 00:00:00 2001 From: Dino <8dino2@gmail.com> Date: Mon, 15 Jan 2024 20:11:38 -0500 Subject: [PATCH 114/167] Got rid of some nonsense --- inc/shared/shared.h | 2 +- src/client/view.c | 2 ++ src/game/p_client.c | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/inc/shared/shared.h b/inc/shared/shared.h index c9a51a7e2..224c59d2c 100644 --- a/inc/shared/shared.h +++ b/inc/shared/shared.h @@ -1324,7 +1324,7 @@ enum { #define DF_QUADFIRE_DROP BIT(16) //ROGUE -#define DF_NO_MINES BIT(17) // In AQtion, this is the dmflag for Darkmatch +#define DF_NO_MINES BIT(17) #define DF_NO_STACK_DOUBLE BIT(18) #define DF_NO_NUKES BIT(19) #define DF_NO_SPHERES BIT(20) diff --git a/src/client/view.c b/src/client/view.c index 02109b495..2956fe487 100644 --- a/src/client/view.c +++ b/src/client/view.c @@ -423,9 +423,11 @@ void V_RenderView(void) cl.refdef.fov_y = V_CalcFov(cl.refdef.fov_x, cl.refdef.width, cl.refdef.height); } + #if USE_AQTION if (cl_zoom_autosens->value) { cl_zoom_autosens_changed(cl.fov_x); } + #endif cl.refdef.time = cl.time * 0.001f; diff --git a/src/game/p_client.c b/src/game/p_client.c index 480a2cd60..88de3994b 100644 --- a/src/game/p_client.c +++ b/src/game/p_client.c @@ -1361,6 +1361,7 @@ void ClientUserinfoChanged(edict_t *ent, char *userinfo) if (strlen(s)) { ent->client->pers.hand = atoi(s); } + // save off the userinfo in case we want to check something later Q_strlcpy(ent->client->pers.userinfo, userinfo, sizeof(ent->client->pers.userinfo)); } From 2b9fcb0c051f80de8c1ab6173bb13a3b62b4f8e3 Mon Sep 17 00:00:00 2001 From: Dino <8dino2@gmail.com> Date: Mon, 15 Jan 2024 20:19:15 -0500 Subject: [PATCH 115/167] Cleaning up some stuff + fix openal site link --- inc/common/common.h | 1 - inc/shared/shared.h | 2 +- src/client/main.c | 2 -- src/common/common.c | 2 -- src/game/g_local.h | 1 - src/game/g_main.c | 2 -- subprojects/openal-soft.wrap | 2 +- 7 files changed, 2 insertions(+), 10 deletions(-) diff --git a/inc/common/common.h b/inc/common/common.h index 9e8f80848..2067aebaa 100644 --- a/inc/common/common.h +++ b/inc/common/common.h @@ -149,7 +149,6 @@ extern cvar_t *dedicated; extern cvar_t *steamid; extern cvar_t *steamcloudappenabled; extern cvar_t *steamclouduserenabled; -extern cvar_t *scopename; #endif #if USE_CLIENT extern cvar_t *host_speeds; diff --git a/inc/shared/shared.h b/inc/shared/shared.h index c9a51a7e2..224c59d2c 100644 --- a/inc/shared/shared.h +++ b/inc/shared/shared.h @@ -1324,7 +1324,7 @@ enum { #define DF_QUADFIRE_DROP BIT(16) //ROGUE -#define DF_NO_MINES BIT(17) // In AQtion, this is the dmflag for Darkmatch +#define DF_NO_MINES BIT(17) #define DF_NO_STACK_DOUBLE BIT(18) #define DF_NO_NUKES BIT(19) #define DF_NO_SPHERES BIT(20) diff --git a/src/client/main.c b/src/client/main.c index 01780d432..cecaebe41 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -101,7 +101,6 @@ cvar_t *info_uf; cvar_t *info_steamid; cvar_t *info_steamcloudappenabled; cvar_t *info_steamclouduserenabled; -cvar_t *info_scopename; cvar_t *cl_mk23_sound; cvar_t *cl_mp5_sound; cvar_t *cl_m4_sound; @@ -4076,7 +4075,6 @@ static void CL_InitLocal(void) info_steamid = Cvar_Get("steamid", "", CVAR_USERINFO); info_steamcloudappenabled = Cvar_Get("steamcloudappenabled", "", CVAR_USERINFO); info_steamclouduserenabled = Cvar_Get("steamclouduserenabled", "", CVAR_USERINFO); - info_scopename = Cvar_Get("scopename", "", CVAR_USERINFO); #endif info_version = Cvar_Get("version", "", CVAR_USERINFO); diff --git a/src/common/common.c b/src/common/common.c index 3e2c0eb28..6eea8b0c5 100644 --- a/src/common/common.c +++ b/src/common/common.c @@ -87,7 +87,6 @@ cvar_t *dedicated; cvar_t *steamid; cvar_t *steamcloudappenabled; cvar_t *steamclouduserenabled; -cvar_t *scopename; #endif cvar_t *com_version; @@ -895,7 +894,6 @@ void Qcommon_Init(int argc, char **argv) steamid = Cvar_Get("steamid", "0", CVAR_NOSET); steamcloudappenabled = Cvar_Get("steamcloudappenabled", "0", CVAR_NOSET); steamclouduserenabled = Cvar_Get("steamclouduserenabled", "0", CVAR_NOSET); - scopename = Cvar_Get("scopename", "", CVAR_USERINFO); cl_running = Cvar_Get("cl_running", "0", CVAR_ROM); cl_paused = Cvar_Get("cl_paused", "0", CVAR_ROM); #else diff --git a/src/game/g_local.h b/src/game/g_local.h index 6c38205f8..bed1319ab 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -509,7 +509,6 @@ extern cvar_t *dedicated; extern cvar_t *steamid; extern cvar_t *steamcloudappenabled; extern cvar_t *steamclouduserenabled; -extern cvar_t *scopename; #endif extern cvar_t *filterban; diff --git a/src/game/g_main.c b/src/game/g_main.c index a5e72a510..868c86fd0 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -48,7 +48,6 @@ cvar_t *steamid; #if USE_CLIENT cvar_t *steamcloudappenabled; cvar_t *steamclouduserenabled; -cvar_t *scopename; #endif cvar_t *filterban; @@ -138,7 +137,6 @@ void InitGame(void) steamid = gi.cvar("steamid", "0", CVAR_USERINFO | CVAR_NOSET); steamcloudappenabled = gi.cvar("steamcloudappenabled", "", CVAR_USERINFO); steamclouduserenabled = gi.cvar("steamclouduserenabled", "", CVAR_USERINFO); - scopename = gi.cvar("scopename", "scopexyz", CVAR_USERINFO); #endif // latched vars diff --git a/subprojects/openal-soft.wrap b/subprojects/openal-soft.wrap index 8292a54cd..89aefc3d9 100644 --- a/subprojects/openal-soft.wrap +++ b/subprojects/openal-soft.wrap @@ -1,6 +1,6 @@ [wrap-file] directory = openal-soft-1.22.2 -source_url = https://openal-soft.org/openal-releases/openal-soft-1.22.2.tar.bz2 +source_url = https://github.com/kcat/openal-soft/releases/download/1.22.2/openal-soft-1.22.2.tar.bz2 source_filename = openal-soft-1.22.2.tar.bz2 source_hash = ae94cc95cda76b7cc6e92e38c2531af82148e76d3d88ce996e2928a1ea7c3d20 patch_url = https://skuller.net/meson/openal-soft_1.22.2-1_patch.zip From d1a987e58d3d7030f9686975069e00d0eb6260e0 Mon Sep 17 00:00:00 2001 From: Dino <8dino2@gmail.com> Date: Mon, 15 Jan 2024 20:20:38 -0500 Subject: [PATCH 116/167] More fixes --- src/client/client.h | 4 ---- src/client/main.c | 4 ---- src/game/p_client.c | 2 -- 3 files changed, 10 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index f76678d2f..fc704a58a 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -51,10 +51,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/ui.h" #include "client/video.h" -#if USE_AQTION -#include "steam/steam_api.h" -#endif - #if USE_ZLIB #include #endif diff --git a/src/client/main.c b/src/client/main.c index cecaebe41..0ecd6b3a4 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -4633,10 +4633,6 @@ void CL_Init(void) Q_assert(inflateInit2(&cls.z, -MAX_WBITS) == Z_OK); #endif -if USE_AQTION - CL_RetrieveSteamID(); -#endif - SCR_InitCinematics(); OGG_Init(); diff --git a/src/game/p_client.c b/src/game/p_client.c index 33d419f6d..88de3994b 100644 --- a/src/game/p_client.c +++ b/src/game/p_client.c @@ -1362,8 +1362,6 @@ void ClientUserinfoChanged(edict_t *ent, char *userinfo) ent->client->pers.hand = atoi(s); } - ent->client->ps. - // save off the userinfo in case we want to check something later Q_strlcpy(ent->client->pers.userinfo, userinfo, sizeof(ent->client->pers.userinfo)); } From 67bd7d8d90e4b687f491dfa78b3856c7c2678e0c Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Tue, 16 Jan 2024 10:59:45 -0500 Subject: [PATCH 117/167] Trying something a little different --- src/client/client.h | 2 ++ src/client/view.c | 30 ++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index fc704a58a..15c94c9e3 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -321,6 +321,8 @@ typedef struct client_state_s { vec3_t offset; } muzzle; } weapon; + + float oldsens; } client_state_t; extern client_state_t cl; diff --git a/src/client/view.c b/src/client/view.c index 2956fe487..338b75482 100644 --- a/src/client/view.c +++ b/src/client/view.c @@ -355,20 +355,34 @@ float V_CalcFov(float fov_x, float width, float height) #if USE_AQTION static void cl_zoom_autosens_changed(float fov) { - if (cl.fov_x >= 90.0f) // No zoom - Cvar_Set("sensitivity", cl_zoom_1x->string); - else if (cl.fov_x == 45.0f && cl_zoom_2x->value) // 2x scope + qboolean savesens; + + // Allocate memory for tmp and save cl.oldsens as a string + char tmp[32]; + if (cl.oldsens == 0.0f) + snprintf(tmp, sizeof(tmp), "%f", cl.oldsens); + + // Adjust sensitivity based on zoom level + if (cl.fov_x >= 90.0f) { // No zoom + Cvar_Set("sensitivity", tmp); + savesens = true; + } else if (cl.fov_x == 45.0f && cl_zoom_2x->value) { // 2x scope Cvar_Set("sensitivity", cl_zoom_2x->string); - else if (cl.fov_x == 20.0f && cl_zoom_4x->value) // 4x scope + } else if (cl.fov_x == 20.0f && cl_zoom_4x->value) { // 4x scope Cvar_Set("sensitivity", cl_zoom_4x->string); - else if (cl.fov_x == 10.0f && cl_zoom_6x->value) // 6x scope + } else if (cl.fov_x == 10.0f && cl_zoom_6x->value) { // 6x scope Cvar_Set("sensitivity", cl_zoom_6x->string); - else // Safe default back to 1x - Cvar_Set("sensitivity", cl_zoom_1x->string); + } else { // Safe default back to 1x + Cvar_Set("sensitivity", tmp); + savesens = true; + } + + // Update cl.oldsens so we know what to restore from + if (savesens) + cl.oldsens = atof(Cvar_Get("sensitivity", "0", 0)->string); } #endif - /* ================== V_RenderView From 6394dcf6069779b3de4857e411c006d485e345ac Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Tue, 16 Jan 2024 12:11:28 -0500 Subject: [PATCH 118/167] Using a cvar rather than a struct entry --- src/client/client.h | 1 - src/client/input.c | 2 ++ src/client/view.c | 22 +++++++--------------- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index 15c94c9e3..287b1d2b3 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -322,7 +322,6 @@ typedef struct client_state_s { } muzzle; } weapon; - float oldsens; } client_state_t; extern client_state_t cl; diff --git a/src/client/input.c b/src/client/input.c index c966bc9cf..ea20e4504 100644 --- a/src/client/input.c +++ b/src/client/input.c @@ -45,6 +45,7 @@ static cvar_t *freelook; static cvar_t *lookspring; static cvar_t *lookstrafe; static cvar_t *sensitivity; +static cvar_t *oldsens; static cvar_t *m_pitch; static cvar_t *m_yaw; @@ -715,6 +716,7 @@ void CL_RegisterInput(void) lookspring = Cvar_Get("lookspring", "0", CVAR_ARCHIVE); lookstrafe = Cvar_Get("lookstrafe", "0", CVAR_ARCHIVE); sensitivity = Cvar_Get("sensitivity", "3", CVAR_ARCHIVE); + oldsens = Cvar_Get("oldsens", sensitivity->string, CVAR_NOARCHIVE); m_pitch = Cvar_Get("m_pitch", "0.022", CVAR_ARCHIVE); m_yaw = Cvar_Get("m_yaw", "0.022", 0); diff --git a/src/client/view.c b/src/client/view.c index 338b75482..547266f4a 100644 --- a/src/client/view.c +++ b/src/client/view.c @@ -355,17 +355,15 @@ float V_CalcFov(float fov_x, float width, float height) #if USE_AQTION static void cl_zoom_autosens_changed(float fov) { - qboolean savesens; + cvar_t *sensitivity = Cvar_Get("sensitivity", "0", CVAR_ARCHIVE); + cvar_t *oldsens = Cvar_Get("oldsens", "0", CVAR_NOARCHIVE); - // Allocate memory for tmp and save cl.oldsens as a string - char tmp[32]; - if (cl.oldsens == 0.0f) - snprintf(tmp, sizeof(tmp), "%f", cl.oldsens); + oldsens->value = atof(sensitivity->string); + Com_Printf("Saving sensitivity: %f\n", oldsens->value); // Adjust sensitivity based on zoom level if (cl.fov_x >= 90.0f) { // No zoom - Cvar_Set("sensitivity", tmp); - savesens = true; + Cvar_Set("sensitivity", oldsens->string); } else if (cl.fov_x == 45.0f && cl_zoom_2x->value) { // 2x scope Cvar_Set("sensitivity", cl_zoom_2x->string); } else if (cl.fov_x == 20.0f && cl_zoom_4x->value) { // 4x scope @@ -373,13 +371,8 @@ static void cl_zoom_autosens_changed(float fov) } else if (cl.fov_x == 10.0f && cl_zoom_6x->value) { // 6x scope Cvar_Set("sensitivity", cl_zoom_6x->string); } else { // Safe default back to 1x - Cvar_Set("sensitivity", tmp); - savesens = true; + Cvar_Set("sensitivity", oldsens->string); } - - // Update cl.oldsens so we know what to restore from - if (savesens) - cl.oldsens = atof(Cvar_Get("sensitivity", "0", 0)->string); } #endif @@ -438,9 +431,8 @@ void V_RenderView(void) } #if USE_AQTION - if (cl_zoom_autosens->value) { + if (cl_zoom_autosens->value && cl.fov_x < 90) cl_zoom_autosens_changed(cl.fov_x); - } #endif cl.refdef.time = cl.time * 0.001f; From 4ee13a8cd6476faf15ef7282209aeceb791edeae Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Tue, 16 Jan 2024 12:53:00 -0500 Subject: [PATCH 119/167] Removed unused cvar, removed debug print --- src/client/view.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/client/view.c b/src/client/view.c index 547266f4a..22c40bbcf 100644 --- a/src/client/view.c +++ b/src/client/view.c @@ -46,7 +46,6 @@ cvar_t *cl_adjustfov; #if USE_AQTION static cvar_t *cl_zoom_autosens; -static cvar_t *cl_zoom_1x; static cvar_t *cl_zoom_2x; static cvar_t *cl_zoom_4x; static cvar_t *cl_zoom_6x; @@ -358,8 +357,8 @@ static void cl_zoom_autosens_changed(float fov) cvar_t *sensitivity = Cvar_Get("sensitivity", "0", CVAR_ARCHIVE); cvar_t *oldsens = Cvar_Get("oldsens", "0", CVAR_NOARCHIVE); + // Anchor value so we return to it after zooming oldsens->value = atof(sensitivity->string); - Com_Printf("Saving sensitivity: %f\n", oldsens->value); // Adjust sensitivity based on zoom level if (cl.fov_x >= 90.0f) { // No zoom @@ -431,7 +430,7 @@ void V_RenderView(void) } #if USE_AQTION - if (cl_zoom_autosens->value && cl.fov_x < 90) + if (cl_zoom_autosens->value) cl_zoom_autosens_changed(cl.fov_x); #endif @@ -526,7 +525,6 @@ void V_Init(void) #if USE_AQTION cl_zoom_autosens = Cvar_Get("cl_zoom_autosens", "0", CVAR_ARCHIVE); - cl_zoom_1x = Cvar_Get("cl_zoom_1x", "0", CVAR_ARCHIVE); cl_zoom_2x = Cvar_Get("cl_zoom_2x", "0", CVAR_ARCHIVE); cl_zoom_4x = Cvar_Get("cl_zoom_4x", "0", CVAR_ARCHIVE); cl_zoom_6x = Cvar_Get("cl_zoom_6x", "0", CVAR_ARCHIVE); From 459678b66b0a2bab63b1a62b048b130ced927a62 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 14 Jan 2024 03:12:08 +0300 Subject: [PATCH 120/167] Misc game code simplifications. --- src/game/g_ai.c | 33 ++++++++++++--------------------- src/game/g_cmds.c | 2 +- src/game/g_combat.c | 7 +++---- src/game/g_func.c | 18 ++++++++---------- src/game/g_items.c | 2 +- src/game/g_misc.c | 18 ++++-------------- src/game/g_monster.c | 5 ++--- src/game/g_target.c | 12 ++++-------- src/game/g_trigger.c | 6 ++---- src/game/g_utils.c | 15 +++++++-------- src/game/g_weapon.c | 14 ++++++-------- src/game/m_move.c | 42 ++++++++++++++++-------------------------- src/game/p_view.c | 9 +++------ 13 files changed, 69 insertions(+), 114 deletions(-) diff --git a/src/game/g_ai.c b/src/game/g_ai.c index bfda9c967..444610d82 100644 --- a/src/game/g_ai.c +++ b/src/game/g_ai.c @@ -59,9 +59,7 @@ void AI_SetSightClient(void) if (check > game.maxclients) check = 1; ent = &g_edicts[check]; - if (ent->inuse - && ent->health > 0 - && !(ent->flags & FL_NOTARGET)) { + if (ent->inuse && ent->health > 0 && !(ent->flags & FL_NOTARGET)) { level.sight_client = ent; return; // got one } @@ -380,10 +378,9 @@ bool FindTarget(edict_t *self) int r; if (self->monsterinfo.aiflags & AI_GOOD_GUY) { - if (self->goalentity && self->goalentity->inuse && self->goalentity->classname) { + if (self->goalentity && self->goalentity->inuse && self->goalentity->classname) if (strcmp(self->goalentity->classname, "target_actor") == 0) return false; - } //FIXME look for monsters? return false; @@ -403,9 +400,8 @@ bool FindTarget(edict_t *self) heardit = false; if ((level.sight_entity_framenum >= (level.framenum - 1)) && !(self->spawnflags & 1)) { client = level.sight_entity; - if (client->enemy == self->enemy) { + if (client->enemy == self->enemy) return false; - } } else if (level.sound_entity_framenum >= (level.framenum - 1)) { client = level.sound_entity; heardit = true; @@ -451,18 +447,15 @@ bool FindTarget(edict_t *self) if (client->light_level <= 5) return false; - if (!visible(self, client)) { + if (!visible(self, client)) return false; - } if (r == RANGE_NEAR) { - if (client->show_hostile < level.framenum && !infront(self, client)) { + if (client->show_hostile < level.framenum && !infront(self, client)) return false; - } } else if (r == RANGE_MID) { - if (!infront(self, client)) { + if (!infront(self, client)) return false; - } } self->enemy = client; @@ -491,9 +484,8 @@ bool FindTarget(edict_t *self) VectorSubtract(client->s.origin, self->s.origin, temp); - if (VectorLength(temp) > 1000) { // too far to hear + if (VectorLength(temp) > 1000) // too far to hear return false; - } // check area portals - if they are different and not connected then we can't hear it if (client->areanum != self->areanum) @@ -581,17 +573,16 @@ bool M_CheckAttack(edict_t *self) if (enemy_range == RANGE_FAR) return false; - if (self->monsterinfo.aiflags & AI_STAND_GROUND) { + if (self->monsterinfo.aiflags & AI_STAND_GROUND) chance = 0.4f; - } else if (enemy_range == RANGE_MELEE) { + else if (enemy_range == RANGE_MELEE) chance = 0.2f; - } else if (enemy_range == RANGE_NEAR) { + else if (enemy_range == RANGE_NEAR) chance = 0.1f; - } else if (enemy_range == RANGE_MID) { + else if (enemy_range == RANGE_MID) chance = 0.02f; - } else { + else return false; - } if (skill->value == 0) chance *= 0.5f; diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index 7744e26a1..c63ed3f74 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -633,7 +633,7 @@ void Cmd_Players_f(edict_t *ent) int count; char small[64]; char large[1280]; - int index[256]; + int index[MAX_CLIENTS]; count = 0; for (i = 0; i < maxclients->value; i++) diff --git a/src/game/g_combat.c b/src/game/g_combat.c index ba921fd8d..6ff9e31d8 100644 --- a/src/game/g_combat.c +++ b/src/game/g_combat.c @@ -34,8 +34,7 @@ bool CanDamage(edict_t *targ, edict_t *inflictor) // bmodels need special checking because their origin is 0,0,0 if (targ->movetype == MOVETYPE_PUSH) { - VectorAdd(targ->absmin, targ->absmax, dest); - VectorScale(dest, 0.5f, dest); + VectorAvg(targ->absmin, targ->absmax, dest); trace = gi.trace(inflictor->s.origin, vec3_origin, vec3_origin, dest, inflictor, MASK_SOLID); if (trace.fraction == 1.0f) return true; @@ -515,8 +514,8 @@ void T_RadiusDamage(edict_t *inflictor, edict_t *attacker, float damage, edict_t if (!ent->takedamage) continue; - VectorAdd(ent->mins, ent->maxs, v); - VectorMA(ent->s.origin, 0.5f, v, v); + VectorAvg(ent->mins, ent->maxs, v); + VectorAdd(ent->s.origin, v, v); VectorSubtract(inflictor->s.origin, v, v); points = damage - 0.5f * VectorLength(v); if (ent == attacker) diff --git a/src/game/g_func.c b/src/game/g_func.c index 3c3595825..2b52c8956 100644 --- a/src/game/g_func.c +++ b/src/game/g_func.c @@ -97,7 +97,7 @@ void Move_Begin(edict_t *ent) return; } VectorScale(ent->moveinfo.dir, ent->moveinfo.speed, ent->velocity); - frames = floor((ent->moveinfo.remaining_distance / ent->moveinfo.speed) / FRAMETIME); + frames = floorf((ent->moveinfo.remaining_distance / ent->moveinfo.speed) / FRAMETIME); ent->moveinfo.remaining_distance -= frames * ent->moveinfo.speed * FRAMETIME; ent->nextthink = level.framenum + frames; ent->think = Move_Final; @@ -105,7 +105,7 @@ void Move_Begin(edict_t *ent) void Think_AccelMove(edict_t *ent); -void Move_Calc(edict_t *ent, const vec3_t dest, void(*func)(edict_t*)) +void Move_Calc(edict_t *ent, const vec3_t dest, void (*func)(edict_t *)) { VectorClear(ent->velocity); VectorSubtract(dest, ent->s.origin, ent->moveinfo.dir); @@ -181,7 +181,7 @@ void AngleMove_Begin(edict_t *ent) return; } - frames = floor(traveltime / FRAMETIME); + frames = floorf(traveltime / FRAMETIME); // scale the destdelta vector by the time spent traveling to get velocity VectorScale(destdelta, 1.0f / traveltime, ent->avelocity); @@ -191,7 +191,7 @@ void AngleMove_Begin(edict_t *ent) ent->think = AngleMove_Final; } -void AngleMove_Calc(edict_t *ent, void(*func)(edict_t*)) +void AngleMove_Calc(edict_t *ent, void (*func)(edict_t *)) { VectorClear(ent->avelocity); ent->moveinfo.endfunc = func; @@ -744,7 +744,7 @@ void SP_func_button(edict_t *ent) abs_movedir[0] = fabsf(ent->movedir[0]); abs_movedir[1] = fabsf(ent->movedir[1]); abs_movedir[2] = fabsf(ent->movedir[2]); - dist = abs_movedir[0] * ent->size[0] + abs_movedir[1] * ent->size[1] + abs_movedir[2] * ent->size[2] - st.lip; + dist = DotProduct(abs_movedir, ent->size) - st.lip; VectorMA(ent->pos1, dist, ent->movedir, ent->pos2); ent->use = button_use; @@ -1106,7 +1106,7 @@ void SP_func_door(edict_t *ent) abs_movedir[0] = fabsf(ent->movedir[0]); abs_movedir[1] = fabsf(ent->movedir[1]); abs_movedir[2] = fabsf(ent->movedir[2]); - ent->moveinfo.distance = abs_movedir[0] * ent->size[0] + abs_movedir[1] * ent->size[1] + abs_movedir[2] * ent->size[2] - st.lip; + ent->moveinfo.distance = DotProduct(abs_movedir, ent->size) - st.lip; VectorMA(ent->pos1, ent->moveinfo.distance, ent->movedir, ent->pos2); // if it starts open, switch the positions @@ -1323,7 +1323,7 @@ void SP_func_water(edict_t *self) abs_movedir[0] = fabsf(self->movedir[0]); abs_movedir[1] = fabsf(self->movedir[1]); abs_movedir[2] = fabsf(self->movedir[2]); - self->moveinfo.distance = abs_movedir[0] * self->size[0] + abs_movedir[1] * self->size[1] + abs_movedir[2] * self->size[2] - st.lip; + self->moveinfo.distance = DotProduct(abs_movedir, self->size) - st.lip; VectorMA(self->pos1, self->moveinfo.distance, self->movedir, self->pos2); // if it starts open, switch the positions @@ -1866,9 +1866,7 @@ void SP_func_door_secret(edict_t *ent) if (!ent->wait) ent->wait = 5; - ent->moveinfo.accel = - ent->moveinfo.decel = - ent->moveinfo.speed = 50; + ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = 50; // calculate positions AngleVectors(ent->s.angles, forward, right, up); diff --git a/src/game/g_items.c b/src/game/g_items.c index 3c08ed3ee..3315c8088 100644 --- a/src/game/g_items.c +++ b/src/game/g_items.c @@ -1933,7 +1933,7 @@ void SP_item_health_mega(edict_t *self) void InitItems(void) { - game.num_items = sizeof(itemlist) / sizeof(itemlist[0]) - 1; + game.num_items = q_countof(itemlist) - 1; } /* diff --git a/src/game/g_misc.c b/src/game/g_misc.c index ad32a8338..e5fcb7f06 100644 --- a/src/game/g_misc.c +++ b/src/game/g_misc.c @@ -1506,18 +1506,12 @@ static void func_clock_format_countdown(edict_t *self) } if (self->style == 1) { - Q_snprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i", self->health / 60, self->health % 60); - if (self->message[3] == ' ') - self->message[3] = '0'; + Q_snprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%02i", self->health / 60, self->health % 60); return; } if (self->style == 2) { - Q_snprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", self->health / 3600, (self->health - (self->health / 3600) * 3600) / 60, self->health % 60); - if (self->message[3] == ' ') - self->message[3] = '0'; - if (self->message[6] == ' ') - self->message[6] = '0'; + Q_snprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%02i:%02i", self->health / 3600, (self->health - (self->health / 3600) * 3600) / 60, self->health % 60); return; } } @@ -1543,13 +1537,9 @@ void func_clock_think(edict_t *self) gmtime = time(NULL); ltime = localtime(&gmtime); if (ltime) - Q_snprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", ltime->tm_hour, ltime->tm_min, ltime->tm_sec); + Q_snprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%02i:%02i", ltime->tm_hour, ltime->tm_min, ltime->tm_sec); else strcpy(self->message, "00:00:00"); - if (self->message[3] == ' ') - self->message[3] = '0'; - if (self->message[6] == ' ') - self->message[6] = '0'; } self->enemy->message = self->message; @@ -1607,7 +1597,7 @@ void SP_func_clock(edict_t *self) } if ((self->spawnflags & 1) && (!self->count)) - self->count = 60 * 60;; + self->count = 60 * 60; func_clock_reset(self); diff --git a/src/game/g_monster.c b/src/game/g_monster.c index 33422d815..9b8b415a7 100644 --- a/src/game/g_monster.c +++ b/src/game/g_monster.c @@ -419,11 +419,10 @@ void monster_triggered_spawn(edict_t *self) monster_start_go(self); - if (self->enemy && !(self->spawnflags & 1) && !(self->enemy->flags & FL_NOTARGET)) { + if (self->enemy && !(self->spawnflags & 1) && !(self->enemy->flags & FL_NOTARGET)) FoundTarget(self); - } else { + else self->enemy = NULL; - } } void monster_triggered_spawn_use(edict_t *self, edict_t *other, edict_t *activator) diff --git a/src/game/g_target.c b/src/game/g_target.c index bc9de6f8f..886fd86f3 100644 --- a/src/game/g_target.c +++ b/src/game/g_target.c @@ -460,7 +460,7 @@ void target_crosslevel_target_think(edict_t *self) void SP_target_crosslevel_target(edict_t *self) { - if (! self->delay) + if (!self->delay) self->delay = 1; self->svflags = SVF_NOCLIENT; @@ -640,12 +640,8 @@ void target_lightramp_think(edict_t *self) if (diff < self->speed) { self->nextthink = level.framenum + 1; } else if (self->spawnflags & 1) { - char temp; - - temp = self->movedir[0]; - self->movedir[0] = self->movedir[1]; - self->movedir[1] = temp; - self->movedir[2] *= -1; + SWAP(float, self->movedir[0], self->movedir[1]); + self->movedir[2] = -self->movedir[2]; } } @@ -726,7 +722,7 @@ void target_earthquake_think(edict_t *self) self->last_move_framenum = level.framenum + 0.5f * BASE_FRAMERATE; } - for (i = 1, e = g_edicts + i; i < globals.num_edicts; i++, e++) { + for (i = 1, e = g_edicts + i; i <= game.maxclients; i++, e++) { if (!e->inuse) continue; if (!e->client) diff --git a/src/game/g_trigger.c b/src/game/g_trigger.c index 1c7ebb26e..ac381a0e1 100644 --- a/src/game/g_trigger.c +++ b/src/game/g_trigger.c @@ -432,10 +432,8 @@ void hurt_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf else self->timestamp = level.framenum + 0.1f * BASE_FRAMERATE; - if (!(self->spawnflags & 4)) { - if ((level.framenum % 10) == 0) - gi.sound(other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0); - } + if (!(self->spawnflags & 4) && !(level.framenum % BASE_FRAMERATE)) + gi.sound(other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0); if (self->spawnflags & 8) dflags = DAMAGE_NO_PROTECTION; diff --git a/src/game/g_utils.c b/src/game/g_utils.c index 1f542a10a..02cfdb156 100644 --- a/src/game/g_utils.c +++ b/src/game/g_utils.c @@ -72,7 +72,7 @@ findradius (origin, radius) edict_t *findradius(edict_t *from, vec3_t org, float rad) { vec3_t eorg; - int j; + vec3_t mid; if (!from) from = g_edicts; @@ -83,9 +83,9 @@ edict_t *findradius(edict_t *from, vec3_t org, float rad) continue; if (from->solid == SOLID_NOT) continue; - for (j = 0; j < 3; j++) - eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j]) * 0.5f); - if (VectorLength(eorg) > rad) + VectorAvg(from->mins, from->maxs, mid); + VectorAdd(from->s.origin, mid, eorg); + if (Distance(eorg, org) > rad) continue; return from; } @@ -236,13 +236,12 @@ static const vec3_t MOVEDIR_DOWN = { 0, 0, -1 }; void G_SetMovedir(vec3_t angles, vec3_t movedir) { - if (VectorCompare(angles, VEC_UP)) { + if (VectorCompare(angles, VEC_UP)) VectorCopy(MOVEDIR_UP, movedir); - } else if (VectorCompare(angles, VEC_DOWN)) { + else if (VectorCompare(angles, VEC_DOWN)) VectorCopy(MOVEDIR_DOWN, movedir); - } else { + else AngleVectors(angles, movedir, NULL, NULL); - } VectorClear(angles); } diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c index d854a4583..3e78e7a14 100644 --- a/src/game/g_weapon.c +++ b/src/game/g_weapon.c @@ -34,10 +34,8 @@ static void check_dodge(edict_t *self, vec3_t start, vec3_t dir, int speed) float eta; // easy mode only ducks one quarter the time - if (skill->value == 0) { - if (random() > 0.25f) - return; - } + if (skill->value == 0 && random() > 0.25f) + return; VectorMA(start, 8192, dir, end); tr = gi.trace(start, NULL, NULL, end, self, MASK_SHOT); if ((tr.ent) && (tr.ent->svflags & SVF_MONSTER) && (tr.ent->health > 0) && (tr.ent->monsterinfo.dodge) && infront(tr.ent, self)) { @@ -377,8 +375,8 @@ void Grenade_Explode(edict_t *ent) vec3_t v; vec3_t dir; - VectorAdd(ent->enemy->mins, ent->enemy->maxs, v); - VectorMA(ent->enemy->s.origin, 0.5f, v, v); + VectorAvg(ent->enemy->mins, ent->enemy->maxs, v); + VectorAdd(ent->enemy->s.origin, v, v); VectorSubtract(ent->s.origin, v, v); points = ent->dmg - 0.5f * VectorLength(v); VectorSubtract(ent->enemy->s.origin, ent->s.origin, dir); @@ -693,8 +691,8 @@ void bfg_explode(edict_t *self) if (!CanDamage(ent, self->owner)) continue; - VectorAdd(ent->mins, ent->maxs, v); - VectorMA(ent->s.origin, 0.5f, v, v); + VectorAvg(ent->mins, ent->maxs, v); + VectorAdd(ent->s.origin, v, v); VectorSubtract(self->s.origin, v, v); dist = VectorLength(v); points = self->radius_dmg * (1.0f - sqrtf(dist / self->dmg_radius)); diff --git a/src/game/m_move.c b/src/game/m_move.c index 2ee04150e..c46d77b64 100644 --- a/src/game/m_move.c +++ b/src/game/m_move.c @@ -30,8 +30,6 @@ is not a staircase. ============= */ -int c_yes, c_no; - bool M_CheckBottom(edict_t *ent) { vec3_t mins, maxs, start, stop; @@ -54,11 +52,9 @@ bool M_CheckBottom(edict_t *ent) goto realcheck; } - c_yes++; return true; // we got out easy realcheck: - c_no++; // // check it for real... // @@ -88,7 +84,6 @@ bool M_CheckBottom(edict_t *ent) return false; } - c_yes++; return true; } @@ -365,7 +360,7 @@ SV_NewChaseDir void SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist) { float deltax, deltay; - float d[3]; + float d1, d2; float tdir, olddir, turnaround; //FIXME: how did we get here with no enemy @@ -378,42 +373,37 @@ void SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist) deltax = enemy->s.origin[0] - actor->s.origin[0]; deltay = enemy->s.origin[1] - actor->s.origin[1]; if (deltax > 10) - d[1] = 0; + d1 = 0; else if (deltax < -10) - d[1] = 180; + d1 = 180; else - d[1] = DI_NODIR; + d1 = DI_NODIR; if (deltay < -10) - d[2] = 270; + d2 = 270; else if (deltay > 10) - d[2] = 90; + d2 = 90; else - d[2] = DI_NODIR; + d2 = DI_NODIR; // try direct route - if (d[1] != DI_NODIR && d[2] != DI_NODIR) { - if (d[1] == 0) - tdir = d[2] == 90 ? 45 : 315; + if (d1 != DI_NODIR && d2 != DI_NODIR) { + if (d1 == 0) + tdir = d2 == 90 ? 45 : 315; else - tdir = d[2] == 90 ? 135 : 215; + tdir = d2 == 90 ? 135 : 215; if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) return; } // try other directions - if (((Q_rand() & 3) & 1) || fabsf(deltay) > fabsf(deltax)) { - tdir = d[1]; - d[1] = d[2]; - d[2] = tdir; - } + if ((Q_rand() & 1) || fabsf(deltay) > fabsf(deltax)) + SWAP(float, d1, d2); - if (d[1] != DI_NODIR && d[1] != turnaround - && SV_StepDirection(actor, d[1], dist)) + if (d1 != DI_NODIR && d1 != turnaround && SV_StepDirection(actor, d1, dist)) return; - if (d[2] != DI_NODIR && d[2] != turnaround - && SV_StepDirection(actor, d[2], dist)) + if (d2 != DI_NODIR && d2 != turnaround && SV_StepDirection(actor, d2, dist)) return; /* there is no direct path to the player, so pick another direction */ @@ -477,7 +467,7 @@ void M_MoveToGoal(edict_t *ent, float dist) return; // if the next step hits the enemy, return immediately - if (ent->enemy && SV_CloseEnough(ent, ent->enemy, dist)) + if (ent->enemy && SV_CloseEnough(ent, ent->enemy, dist)) return; // bump around... diff --git a/src/game/p_view.c b/src/game/p_view.c index 41d577a86..b48de48cc 100644 --- a/src/game/p_view.c +++ b/src/game/p_view.c @@ -138,10 +138,7 @@ void P_DamageFeedback(edict_t *player) if (client->damage_alpha < 0) client->damage_alpha = 0; client->damage_alpha += count * 0.01f; - if (client->damage_alpha < 0.2f) - client->damage_alpha = 0.2f; - if (client->damage_alpha > 0.6f) - client->damage_alpha = 0.6f; // don't go too saturated + clamp(client->damage_alpha, 0.2f, 0.6f); // don't go too saturated // the color of the blend will vary based on how much was absorbed // by different armors @@ -149,9 +146,9 @@ void P_DamageFeedback(edict_t *player) if (client->damage_parmor) VectorMA(v, (float)client->damage_parmor / realcount, power_color, v); if (client->damage_armor) - VectorMA(v, (float)client->damage_armor / realcount, acolor, v); + VectorMA(v, (float)client->damage_armor / realcount, acolor, v); if (client->damage_blood) - VectorMA(v, (float)client->damage_blood / realcount, bcolor, v); + VectorMA(v, (float)client->damage_blood / realcount, bcolor, v); VectorCopy(v, client->damage_blend); // From 2f271a328f2f8768f2b169c93dc06859a46d317d Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 14 Jan 2024 03:13:24 +0300 Subject: [PATCH 121/167] Fix maps with 255 inline models and more. --- src/server/init.c | 12 +++++++++--- src/server/world.c | 9 +++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/server/init.c b/src/server/init.c index 9fcb757d6..55a8508dd 100644 --- a/src/server/init.c +++ b/src/server/init.c @@ -103,7 +103,7 @@ clients along with it. */ void SV_SpawnServer(const mapcmd_t *cmd) { - int i; + int i, j; client_t *client; SCR_BeginLoadingPlaque(); // for local system @@ -155,10 +155,16 @@ void SV_SpawnServer(const mapcmd_t *cmd) sv.cm = cmd->cm; sprintf(sv.configstrings[svs.csr.mapchecksum], "%d", sv.cm.checksum); + // model indices 0 and 255 are reserved + if (sv.cm.cache->nummodels > svs.csr.max_models - 2) + Com_Error(ERR_DROP, "Too many inline models"); + // set inline model names Q_concat(sv.configstrings[svs.csr.models + 1], MAX_QPATH, "maps/", cmd->server, ".bsp"); - for (i = 1; i < sv.cm.cache->nummodels; i++) { - sprintf(sv.configstrings[svs.csr.models + 1 + i], "*%d", i); + for (i = 1, j = 2; i < sv.cm.cache->nummodels; i++, j++) { + if (j == MODELINDEX_PLAYER) + j++; // skip reserved index + sprintf(sv.configstrings[svs.csr.models + j], "*%d", i); } } else { // no real map diff --git a/src/server/world.c b/src/server/world.c index edfceff23..12593c408 100644 --- a/src/server/world.c +++ b/src/server/world.c @@ -440,11 +440,16 @@ object of mins/maxs size. static mnode_t *SV_HullForEntity(edict_t *ent, bool triggers) { if (ent->solid == SOLID_BSP || (triggers && ent->solid == SOLID_TRIGGER)) { + bsp_t *bsp = sv.cm.cache; int i = ent->s.modelindex - 1; + // account for "hole" in configstring namespace + if (i >= MODELINDEX_PLAYER && bsp->nummodels >= MODELINDEX_PLAYER) + i--; + // explicit hulls in the BSP model - if (i > 0 && i < sv.cm.cache->nummodels) - return sv.cm.cache->models[i].headnode; + if (i > 0 && i < bsp->nummodels) + return bsp->models[i].headnode; if (!triggers) Com_Error(ERR_DROP, "%s: inline model %d out of range", __func__, i); From 45058020c6748d25ec1ba230b93a0f6c048d75d3 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 17 Jan 2024 10:26:00 +0300 Subject: [PATCH 122/167] Free edicts without classname or spawn function. --- src/game/g_spawn.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/game/g_spawn.c b/src/game/g_spawn.c index 6ed6d8a22..ced6c622d 100644 --- a/src/game/g_spawn.c +++ b/src/game/g_spawn.c @@ -346,6 +346,7 @@ void ED_CallSpawn(edict_t *ent) if (!ent->classname) { gi.dprintf("ED_CallSpawn: NULL classname\n"); + G_FreeEdict(ent); return; } @@ -368,7 +369,9 @@ void ED_CallSpawn(edict_t *ent) return; } } + gi.dprintf("%s doesn't have a spawn function\n", ent->classname); + G_FreeEdict(ent); } /* From b7996d9c879823518aed13f8c39f51fbc8189204 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 17 Jan 2024 13:55:34 +0300 Subject: [PATCH 123/167] Use game.maxclients instead of maxclients->value. --- src/game/g_ai.c | 1 - src/game/g_chase.c | 6 +++--- src/game/g_cmds.c | 4 ++-- src/game/g_main.c | 8 ++++---- src/game/g_save.c | 4 ++-- src/game/g_spawn.c | 2 +- src/game/g_utils.c | 2 +- src/game/p_client.c | 8 ++++---- src/game/p_hud.c | 8 ++++---- 9 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/game/g_ai.c b/src/game/g_ai.c index 444610d82..bb7b31d03 100644 --- a/src/game/g_ai.c +++ b/src/game/g_ai.c @@ -20,7 +20,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "g_local.h" bool FindTarget(edict_t *self); -extern cvar_t *maxclients; bool ai_checkattack(edict_t *self, float dist); diff --git a/src/game/g_chase.c b/src/game/g_chase.c index f33dc2611..c2d971f8c 100644 --- a/src/game/g_chase.c +++ b/src/game/g_chase.c @@ -115,7 +115,7 @@ void ChaseNext(edict_t *ent) i = ent->client->chase_target - g_edicts; do { i++; - if (i > maxclients->value) + if (i > game.maxclients) i = 1; e = g_edicts + i; if (!e->inuse) @@ -140,7 +140,7 @@ void ChasePrev(edict_t *ent) do { i--; if (i < 1) - i = maxclients->value; + i = game.maxclients; e = g_edicts + i; if (!e->inuse) continue; @@ -157,7 +157,7 @@ void GetChaseTarget(edict_t *ent) int i; edict_t *other; - for (i = 1; i <= maxclients->value; i++) { + for (i = 1; i <= game.maxclients; i++) { other = g_edicts + i; if (other->inuse && !other->client->resp.spectator) { ent->client->chase_target = other; diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index c63ed3f74..c1c598c5d 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -636,7 +636,7 @@ void Cmd_Players_f(edict_t *ent) int index[MAX_CLIENTS]; count = 0; - for (i = 0; i < maxclients->value; i++) + for (i = 0; i < game.maxclients; i++) if (game.clients[i].pers.connected) { index[count] = i; count++; @@ -808,7 +808,7 @@ void Cmd_PlayerList_f(edict_t *ent) // connect time, ping, score, name *text = 0; - for (i = 0, e2 = g_edicts + 1; i < maxclients->value; i++, e2++) { + for (i = 0, e2 = g_edicts + 1; i < game.maxclients; i++, e2++) { if (!e2->inuse) continue; diff --git a/src/game/g_main.c b/src/game/g_main.c index 013c9e9e0..a3e0ae293 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -283,7 +283,7 @@ void ClientEndServerFrames(void) // calc the player views now that all pushing // and damage has been added - for (i = 0; i < maxclients->value; i++) { + for (i = 0; i < game.maxclients; i++) { ent = g_edicts + 1 + i; if (!ent->inuse || !ent->client) continue; @@ -419,7 +419,7 @@ void CheckDMRules(void) } if (fraglimit->value) { - for (i = 0; i < maxclients->value; i++) { + for (i = 0; i < game.maxclients; i++) { cl = game.clients + i; if (!g_edicts[i + 1].inuse) continue; @@ -451,7 +451,7 @@ void ExitLevel(void) level.intermission_framenum = 0; // clear some things before going to next level - for (i = 0; i < maxclients->value; i++) { + for (i = 0; i < game.maxclients; i++) { ent = g_edicts + 1 + i; if (!ent->inuse) continue; @@ -507,7 +507,7 @@ void G_RunFrame(void) } } - if (i > 0 && i <= maxclients->value) { + if (i > 0 && i <= game.maxclients) { ClientBeginServerFrame(ent); continue; } diff --git a/src/game/g_save.c b/src/game/g_save.c index 908da650a..dfa4053c3 100644 --- a/src/game/g_save.c +++ b/src/game/g_save.c @@ -973,7 +973,7 @@ void ReadLevel(const char *filename) // wipe all the entities memset(g_edicts, 0, game.maxentities * sizeof(g_edicts[0])); - globals.num_edicts = maxclients->value + 1; + globals.num_edicts = game.maxclients + 1; i = read_int(f); if (i != SAVE_MAGIC2) { @@ -1016,7 +1016,7 @@ void ReadLevel(const char *filename) gzclose(f); // mark all clients as unconnected - for (i = 0; i < maxclients->value; i++) { + for (i = 0; i < game.maxclients; i++) { ent = &g_edicts[i + 1]; ent->client = game.clients + i; ent->client->pers.connected = false; diff --git a/src/game/g_spawn.c b/src/game/g_spawn.c index ced6c622d..7249b5f8d 100644 --- a/src/game/g_spawn.c +++ b/src/game/g_spawn.c @@ -927,7 +927,7 @@ void SP_worldspawn(edict_t *ent) else gi.configstring(CS_CDTRACK, va("%i", ent->sounds)); - gi.configstring(game.csr.maxclients, va("%i", (int)(maxclients->value))); + gi.configstring(game.csr.maxclients, va("%i", game.maxclients)); // status bar program if (deathmatch->value) diff --git a/src/game/g_utils.c b/src/game/g_utils.c index 02cfdb156..5e318aaf9 100644 --- a/src/game/g_utils.c +++ b/src/game/g_utils.c @@ -359,7 +359,7 @@ void G_FreeEdict(edict_t *ed) { gi.unlinkentity(ed); // unlink from world - if ((ed - g_edicts) <= (maxclients->value + BODY_QUEUE_SIZE)) { + if ((ed - g_edicts) <= (game.maxclients + BODY_QUEUE_SIZE)) { // gi.dprintf("tried to free special edict\n"); return; } diff --git a/src/game/p_client.c b/src/game/p_client.c index 88de3994b..2bd6d03aa 100644 --- a/src/game/p_client.c +++ b/src/game/p_client.c @@ -656,7 +656,7 @@ float PlayersRangeFromSpot(edict_t *spot) bestplayerdistance = 9999999; - for (n = 1; n <= maxclients->value; n++) { + for (n = 1; n <= game.maxclients; n++) { player = &g_edicts[n]; if (!player->inuse) @@ -974,7 +974,7 @@ void spectator_respawn(edict_t *ent) } // count spectators - for (i = 1, numspec = 0; i <= maxclients->value; i++) + for (i = 1, numspec = 0; i <= game.maxclients; i++) if (g_edicts[i].inuse && g_edicts[i].client->pers.spectator) numspec++; @@ -1402,7 +1402,7 @@ qboolean ClientConnect(edict_t *ent, char *userinfo) } // count spectators - for (i = numspec = 0; i < maxclients->value; i++) + for (i = numspec = 0; i < game.maxclients; i++) if (g_edicts[i + 1].inuse && g_edicts[i + 1].client->pers.spectator) numspec++; @@ -1665,7 +1665,7 @@ void ClientThink(edict_t *ent, usercmd_t *ucmd) } // update chase cam if being followed - for (i = 1; i <= maxclients->value; i++) { + for (i = 1; i <= game.maxclients; i++) { other = g_edicts + i; if (other->inuse && other->client->chase_target == ent) UpdateChaseCam(other); diff --git a/src/game/p_hud.c b/src/game/p_hud.c index b9c8c6661..540bffd52 100644 --- a/src/game/p_hud.c +++ b/src/game/p_hud.c @@ -87,7 +87,7 @@ void BeginIntermission(edict_t *targ) game.autosaved = false; // respawn any dead clients - for (i = 0; i < maxclients->value; i++) { + for (i = 0; i < game.maxclients; i++) { client = g_edicts + 1 + i; if (!client->inuse) continue; @@ -100,7 +100,7 @@ void BeginIntermission(edict_t *targ) if (strchr(level.changemap, '*')) { if (coop->value) { - for (i = 0; i < maxclients->value; i++) { + for (i = 0; i < game.maxclients; i++) { client = g_edicts + 1 + i; if (!client->inuse) continue; @@ -144,7 +144,7 @@ void BeginIntermission(edict_t *targ) } // move all clients to the intermission point - for (i = 0; i < maxclients->value; i++) { + for (i = 0; i < game.maxclients; i++) { client = g_edicts + 1 + i; if (!client->inuse) continue; @@ -508,7 +508,7 @@ void G_CheckChaseStats(edict_t *ent) int i; gclient_t *cl; - for (i = 1; i <= maxclients->value; i++) { + for (i = 1; i <= game.maxclients; i++) { cl = g_edicts[i].client; if (!g_edicts[i].inuse || cl->chase_target != ent) continue; From b39cfd7c21338965e26d0438d8225d7d13ce1fed Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 21 Jan 2024 12:07:25 +0300 Subject: [PATCH 124/167] Use BIT_ULL() for all U_* defines. Should prevent surprises if trying to do e.g. (mask & ~U_SOMEBIT). --- inc/common/protocol.h | 64 +++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/inc/common/protocol.h b/inc/common/protocol.h index d8d589d55..b4a116488 100644 --- a/inc/common/protocol.h +++ b/inc/common/protocol.h @@ -309,44 +309,44 @@ typedef enum { // entity_state_t communication // try to pack the common update flags into the first byte -#define U_ORIGIN1 BIT(0) -#define U_ORIGIN2 BIT(1) -#define U_ANGLE2 BIT(2) -#define U_ANGLE3 BIT(3) -#define U_FRAME8 BIT(4) // frame is a byte -#define U_EVENT BIT(5) -#define U_REMOVE BIT(6) // REMOVE this entity, don't add it -#define U_MOREBITS1 BIT(7) // read one additional byte +#define U_ORIGIN1 BIT_ULL(0) +#define U_ORIGIN2 BIT_ULL(1) +#define U_ANGLE2 BIT_ULL(2) +#define U_ANGLE3 BIT_ULL(3) +#define U_FRAME8 BIT_ULL(4) // frame is a byte +#define U_EVENT BIT_ULL(5) +#define U_REMOVE BIT_ULL(6) // REMOVE this entity, don't add it +#define U_MOREBITS1 BIT_ULL(7) // read one additional byte // second byte -#define U_NUMBER16 BIT(8) // NUMBER8 is implicit if not set -#define U_ORIGIN3 BIT(9) -#define U_ANGLE1 BIT(10) -#define U_MODEL BIT(11) -#define U_RENDERFX8 BIT(12) // fullbright, etc -#define U_ANGLE16 BIT(13) -#define U_EFFECTS8 BIT(14) // autorotate, trails, etc -#define U_MOREBITS2 BIT(15) // read one additional byte +#define U_NUMBER16 BIT_ULL(8) // NUMBER8 is implicit if not set +#define U_ORIGIN3 BIT_ULL(9) +#define U_ANGLE1 BIT_ULL(10) +#define U_MODEL BIT_ULL(11) +#define U_RENDERFX8 BIT_ULL(12) // fullbright, etc +#define U_ANGLE16 BIT_ULL(13) +#define U_EFFECTS8 BIT_ULL(14) // autorotate, trails, etc +#define U_MOREBITS2 BIT_ULL(15) // read one additional byte // third byte -#define U_SKIN8 BIT(16) -#define U_FRAME16 BIT(17) // frame is a short -#define U_RENDERFX16 BIT(18) // 8 + 16 = 32 -#define U_EFFECTS16 BIT(19) // 8 + 16 = 32 -#define U_MODEL2 BIT(20) // weapons, flags, etc -#define U_MODEL3 BIT(21) -#define U_MODEL4 BIT(22) -#define U_MOREBITS3 BIT(23) // read one additional byte +#define U_SKIN8 BIT_ULL(16) +#define U_FRAME16 BIT_ULL(17) // frame is a short +#define U_RENDERFX16 BIT_ULL(18) // 8 + 16 = 32 +#define U_EFFECTS16 BIT_ULL(19) // 8 + 16 = 32 +#define U_MODEL2 BIT_ULL(20) // weapons, flags, etc +#define U_MODEL3 BIT_ULL(21) +#define U_MODEL4 BIT_ULL(22) +#define U_MOREBITS3 BIT_ULL(23) // read one additional byte // fourth byte -#define U_OLDORIGIN BIT(24) // FIXME: get rid of this -#define U_SKIN16 BIT(25) -#define U_SOUND BIT(26) -#define U_SOLID BIT(27) -#define U_MODEL16 BIT(28) -#define U_MOREFX8 BIT(29) -#define U_ALPHA BIT(30) -#define U_MOREBITS4 BIT(31) // read one additional byte +#define U_OLDORIGIN BIT_ULL(24) // FIXME: get rid of this +#define U_SKIN16 BIT_ULL(25) +#define U_SOUND BIT_ULL(26) +#define U_SOLID BIT_ULL(27) +#define U_MODEL16 BIT_ULL(28) +#define U_MOREFX8 BIT_ULL(29) +#define U_ALPHA BIT_ULL(30) +#define U_MOREBITS4 BIT_ULL(31) // read one additional byte // fifth byte #define U_SCALE BIT_ULL(32) From 337f9d335f8eeba84b62974a7710c19703893a42 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 22 Jan 2024 14:29:42 +0300 Subject: [PATCH 125/167] Reduce size of some BoxEdicts() lists. --- src/game/g_utils.c | 8 ++++---- src/server/world.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/game/g_utils.c b/src/game/g_utils.c index 5e318aaf9..f685c504e 100644 --- a/src/game/g_utils.c +++ b/src/game/g_utils.c @@ -379,13 +379,13 @@ G_TouchTriggers void G_TouchTriggers(edict_t *ent) { int i, num; - edict_t *touch[MAX_EDICTS], *hit; + edict_t *touch[MAX_EDICTS_OLD], *hit; // dead things don't activate triggers! if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0)) return; - num = gi.BoxEdicts(ent->absmin, ent->absmax, touch, MAX_EDICTS, AREA_TRIGGERS); + num = gi.BoxEdicts(ent->absmin, ent->absmax, touch, q_countof(touch), AREA_TRIGGERS); // be careful, it is possible to have an entity in this // list removed before we get to it (killtriggered) @@ -410,9 +410,9 @@ to force all entities it covers to immediately touch it void G_TouchSolids(edict_t *ent) { int i, num; - edict_t *touch[MAX_EDICTS], *hit; + edict_t *touch[MAX_EDICTS_OLD], *hit; - num = gi.BoxEdicts(ent->absmin, ent->absmax, touch, MAX_EDICTS, AREA_SOLID); + num = gi.BoxEdicts(ent->absmin, ent->absmax, touch, q_countof(touch), AREA_SOLID); // be careful, it is possible to have an entity in this // list removed before we get to it (killtriggered) diff --git a/src/server/world.c b/src/server/world.c index 12593c408..7f3edd576 100644 --- a/src/server/world.c +++ b/src/server/world.c @@ -476,7 +476,7 @@ SV_PointContents */ int SV_PointContents(const vec3_t p) { - edict_t *touch[MAX_EDICTS], *hit; + edict_t *touch[MAX_EDICTS_OLD], *hit; int i, num; int contents; @@ -484,7 +484,7 @@ int SV_PointContents(const vec3_t p) contents = CM_PointContents(p, SV_WorldNodes()); // or in contents from all the other entities - num = SV_AreaEdicts(p, p, touch, MAX_EDICTS, AREA_SOLID); + num = SV_AreaEdicts(p, p, touch, q_countof(touch), AREA_SOLID); for (i = 0; i < num; i++) { hit = touch[i]; From d487c85d03f58ea6376cfbfe7560dc1edf242319 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 25 Jan 2024 17:55:32 +0300 Subject: [PATCH 126/167] Get rid of clamp() macro. Also add more efficient functions (stolen from FFmpeg) to clip integers to power of two ranges. Add SSE optimized Q_clipf(). --- inc/common/msg.h | 20 ++++++------- inc/common/utils.h | 3 +- inc/shared/shared.h | 61 +++++++++++++++++++++++++++++++++++++--- src/client/console.c | 6 +--- src/client/demo.c | 2 +- src/client/input.c | 15 ++++------ src/client/main.c | 3 +- src/client/parse.c | 2 +- src/client/screen.c | 3 +- src/client/sound/dma.c | 10 +++---- src/client/sound/sound.h | 6 ---- src/client/ui/menu.c | 20 +++++-------- src/client/ui/servers.c | 7 ++--- src/client/ui/ui.c | 4 +-- src/common/cmodel.c | 7 +++-- src/common/cvar.c | 2 +- src/common/msg.c | 27 ++++-------------- src/common/pmove.c | 6 ++-- src/game/g_main.c | 3 +- src/game/g_misc.c | 6 ++-- src/game/g_phys.c | 7 +++-- src/game/g_spawn.c | 7 ++--- src/game/p_view.c | 12 ++++---- src/refresh/images.c | 4 +-- src/refresh/mesh.c | 6 ++-- src/refresh/texture.c | 4 +-- src/refresh/world.c | 8 ++---- src/server/main.c | 20 ++++++------- src/server/mvd/client.c | 2 +- src/server/user.c | 5 +--- src/unix/video/sdl.c | 2 +- src/unix/video/wayland.c | 6 ++-- src/unix/video/x11.c | 2 +- src/windows/client.c | 4 +-- 34 files changed, 153 insertions(+), 149 deletions(-) diff --git a/inc/common/msg.h b/inc/common/msg.h index 8f70eda40..ddd1396c3 100644 --- a/inc/common/msg.h +++ b/inc/common/msg.h @@ -189,9 +189,9 @@ static inline int MSG_PackSolid16(const vec3_t mins, const vec3_t maxs) int zd = -mins[2] / 8; int zu = (maxs[2] + 32) / 8; - clamp(x, 1, 31); - clamp(zd, 1, 31); - clamp(zu, 1, 63); + x = Q_clip(x, 1, 31); + zd = Q_clip(zd, 1, 31); + zu = Q_clip(zu, 1, 63); return (zu << 10) | (zd << 5) | x; } @@ -202,9 +202,9 @@ static inline uint32_t MSG_PackSolid32_Ver1(const vec3_t mins, const vec3_t maxs int zd = -mins[2]; int zu = maxs[2] + 32768; - clamp(x, 1, 255); - clamp(zd, 0, 255); - clamp(zu, 0, 65535); + x = Q_clip(x, 1, 255); + zd = Q_clip_uint8(zd); + zu = Q_clip_uint16(zu); return ((uint32_t)zu << 16) | (zd << 8) | x; } @@ -216,10 +216,10 @@ static inline uint32_t MSG_PackSolid32_Ver2(const vec3_t mins, const vec3_t maxs int zd = -mins[2]; int zu = maxs[2] + 32; - clamp(x, 1, 255); - clamp(y, 1, 255); - clamp(zd, 0, 255); - clamp(zu, 0, 255); + x = Q_clip(x, 1, 255); + y = Q_clip(y, 1, 255); + zd = Q_clip_uint8(zd); + zu = Q_clip_uint8(zu); return MakeLittleLong(x, y, zd, zu); } diff --git a/inc/common/utils.h b/inc/common/utils.h index b750738f2..23a9bcac0 100644 --- a/inc/common/utils.h +++ b/inc/common/utils.h @@ -91,8 +91,7 @@ typedef struct frametime_s { // Compute frametime based on requested frame rate static inline frametime_t Com_ComputeFrametime(int rate) { - int framediv = rate / BASE_FRAMERATE; - clamp(framediv, 1, MAX_FRAMEDIV); + int framediv = Q_clip(rate / BASE_FRAMERATE, 1, MAX_FRAMEDIV); return (frametime_t){ .time = BASE_FRAMETIME / framediv, .div = framediv }; } diff --git a/inc/shared/shared.h b/inc/shared/shared.h index bcc7745bb..d950aca7d 100644 --- a/inc/shared/shared.h +++ b/inc/shared/shared.h @@ -333,12 +333,65 @@ void Q_srand(uint32_t seed); uint32_t Q_rand(void); uint32_t Q_rand_uniform(uint32_t n); -#define clamp(a,b,c) ((a)<(b)?(a)=(b):(a)>(c)?(a)=(c):(a)) -#define cclamp(a,b,c) ((b)>(c)?clamp(a,c,b):clamp(a,b,c)) - static inline int Q_clip(int a, int b, int c) { - return clamp(a, b, c); + if (a < b) + return b; + if (a > c) + return c; + return a; +} + +static inline float Q_clipf(float a, float b, float c) +{ +#if defined(__GNUC__) && defined(__SSE__) + __asm__("maxss %1, %0 \n\t" + "minss %2, %0 \n\t" + : "+&x"(a) : "xm"(b), "xm"(c)); + return a; +#else + if (a < b) + return b; + if (a > c) + return c; + return a; +#endif +} + +static inline float Q_circ_clipf(float a, float b, float c) +{ + return b > c ? Q_clipf(a, c, b) : Q_clipf(a, b, c); +} + +static inline int8_t Q_clip_int8(int a) +{ + return ((a + 0x80U) & ~0xFF) ? (a >> 31) ^ 0x7F : a; +} + +static inline int16_t Q_clip_int16(int a) +{ + return ((a + 0x8000U) & ~0xFFFF) ? (a >> 31) ^ 0x7FFF : a; +} + +static inline int32_t Q_clip_int32(int64_t a) +{ + return ((a + 0x80000000ULL) & ~0xFFFFFFFFULL) ? (a >> 63) ^ 0x7FFFFFFF : a; +} + +#ifdef _LP64 +#define Q_clipl_int32(a) Q_clip_int32(a) +#else +#define Q_clipl_int32(a) (a) +#endif + +static inline uint8_t Q_clip_uint8(int a) +{ + return (a & ~0xFF) ? ~a >> 31 : a; +} + +static inline uint16_t Q_clip_uint16(int a) +{ + return (a & ~0xFFFF) ? ~a >> 31 : a; } #ifndef max diff --git a/src/client/console.c b/src/client/console.c index c305b8b44..732446e44 100644 --- a/src/client/console.c +++ b/src/client/console.c @@ -366,16 +366,12 @@ If the line width has changed, reformat the buffer. */ void Con_CheckResize(void) { - int width; - con.scale = R_ClampScale(con_scale); con.vidWidth = Q_rint(r_config.width * con.scale); con.vidHeight = Q_rint(r_config.height * con.scale); - width = con.vidWidth / CHAR_WIDTH - 2; - - con.linewidth = clamp(width, 0, CON_LINEWIDTH); + con.linewidth = Q_clip(con.vidWidth / CHAR_WIDTH - 2, 0, CON_LINEWIDTH); con.prompt.inputLine.visibleChars = con.linewidth; con.prompt.widthInChars = con.linewidth; con.chatPrompt.inputLine.visibleChars = con.linewidth; diff --git a/src/client/demo.c b/src/client/demo.c index 8a704e839..ebe8a2c14 100644 --- a/src/client/demo.c +++ b/src/client/demo.c @@ -984,7 +984,7 @@ static void CL_Seek_f(void) return; } - clamp(percent, 0, 100); + percent = Q_clipf(percent, 0, 100); dest = cls.demo.file_offset + cls.demo.file_size * percent / 100; byte_seek = true; diff --git a/src/client/input.c b/src/client/input.c index fe3ef8ddc..dea54ae7d 100644 --- a/src/client/input.c +++ b/src/client/input.c @@ -417,7 +417,6 @@ Returns the fraction of the frame that the key was down static float CL_KeyState(kbutton_t *key) { unsigned msec = key->msec; - float val; if (key->state & 1) { // still down @@ -431,9 +430,7 @@ static float CL_KeyState(kbutton_t *key) return (float)(key->state & 1); } - val = (float)msec / cl.cmd.msec; - - return clamp(val, 0, 1); + return Q_clipf((float)msec / cl.cmd.msec, 0, 1); } //========================================================================== @@ -567,11 +564,11 @@ static void CL_BaseMove(vec3_t move) static void CL_ClampSpeed(vec3_t move) { - float speed = 400; // default (maximum) running speed + const float speed = 400; // default (maximum) running speed - clamp(move[0], -speed, speed); - clamp(move[1], -speed, speed); - clamp(move[2], -speed, speed); + move[0] = Q_clipf(move[0], -speed, speed); + move[1] = Q_clipf(move[1], -speed, speed); + move[2] = Q_clipf(move[2], -speed, speed); } static void CL_ClampPitch(void) @@ -586,7 +583,7 @@ static void CL_ClampPitch(void) if (angle > 180) angle -= 360; // wrapped - clamp(angle, -89, 89); + angle = Q_clipf(angle, -89, 89); cl.viewangles[PITCH] = angle - pitch; } diff --git a/src/client/main.c b/src/client/main.c index 9a5fbb604..5f594e8c2 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -568,8 +568,7 @@ static void CL_FollowIP_f(void) if (Cmd_Argc() > 1) { // optional second argument references less recent address - j = atoi(Cmd_Argv(1)) + 1; - clamp(j, 1, RECENT_ADDR); + j = Q_clip(atoi(Cmd_Argv(1)), 0, RECENT_ADDR - 1) + 1; } else { j = 1; } diff --git a/src/client/parse.c b/src/client/parse.c index 567479113..5cb75a3b5 100644 --- a/src/client/parse.c +++ b/src/client/parse.c @@ -588,7 +588,7 @@ static void CL_ParseServerData(void) "R1Q2 server reports unsupported protocol version %d.\n" "Assuming it really uses our current client version %d.\n" "Things will break if it does not!\n", i, PROTOCOL_VERSION_R1Q2_CURRENT); - clamp(i, PROTOCOL_VERSION_R1Q2_MINIMUM, PROTOCOL_VERSION_R1Q2_CURRENT); + i = Q_clip(i, PROTOCOL_VERSION_R1Q2_MINIMUM, PROTOCOL_VERSION_R1Q2_CURRENT); } Com_DPrintf("Using minor R1Q2 protocol version %d\n", i); cls.protocolVersion = i; diff --git a/src/client/screen.c b/src/client/screen.c index 268417640..5cb977e85 100644 --- a/src/client/screen.c +++ b/src/client/screen.c @@ -578,8 +578,7 @@ static void SCR_LagDraw(int x, int y) } v &= ~(LAG_WARN_BIT | LAG_CRIT_BIT); - v = (v - v_min) * LAG_HEIGHT / v_range; - clamp(v, 0, LAG_HEIGHT); + v = Q_clip((v - v_min) * LAG_HEIGHT / v_range, 0, LAG_HEIGHT); R_DrawFill8(x + LAG_WIDTH - i - 1, y + LAG_HEIGHT - v, 1, v, c); } diff --git a/src/client/sound/dma.c b/src/client/sound/dma.c index 65f551d5e..927a62491 100644 --- a/src/client/sound/dma.c +++ b/src/client/sound/dma.c @@ -157,7 +157,7 @@ static bool DMA_RawSamples(int samples, int rate, int width, int channels, const static int DMA_NeedRawSamples(void) { int avail = MAX_RAW_SAMPLES - (s_rawend - s_paintedtime); - clamp(avail, 0, MAX_RAW_SAMPLES); + avail = Q_clip(avail, 0, MAX_RAW_SAMPLES); return avail & ~127; } @@ -189,8 +189,8 @@ static void TransferStereo16(samplepair_t *samp, int endtime) // write a linear blast of samples int16_t *out = (int16_t *)dma.buffer + (lpos << 1); for (int i = 0; i < count; i++, samp++, out += 2) { - out[0] = clip16(samp->left); - out[1] = clip16(samp->right); + out[0] = Q_clip_int16(samp->left); + out[1] = Q_clip_int16(samp->right); } ltime += count; @@ -211,7 +211,7 @@ static void TransferStereo(samplepair_t *samp, int endtime) while (count--) { val = *p; p += step; - out[out_idx] = clip16(val); + out[out_idx] = Q_clip_int16(val); out_idx = (out_idx + 1) & out_mask; } } else if (dma.samplebits == 8) { @@ -219,7 +219,7 @@ static void TransferStereo(samplepair_t *samp, int endtime) while (count--) { val = *p; p += step; - out[out_idx] = (clip16(val) >> 8) + 128; + out[out_idx] = (Q_clip_int16(val) >> 8) + 128; out_idx = (out_idx + 1) & out_mask; } } diff --git a/src/client/sound/sound.h b/src/client/sound/sound.h index a64186ab0..6d1824009 100644 --- a/src/client/sound/sound.h +++ b/src/client/sound/sound.h @@ -167,12 +167,6 @@ extern cvar_t *s_show; extern cvar_t *s_underwater; extern cvar_t *s_underwater_gain_hf; -// clip integer to [-0x8000, 0x7FFF] range (stolen from FFmpeg) -static inline int clip16(int v) -{ - return ((v + 0x8000U) & ~0xFFFF) ? (v >> 31) ^ 0x7FFF : v; -} - #define S_IsFullVolume(ch) \ ((ch)->entnum == -1 || (ch)->entnum == listener_entnum || (ch)->dist_mult == 0) diff --git a/src/client/ui/menu.c b/src/client/ui/menu.c index bce198c07..7d368b504 100644 --- a/src/client/ui/menu.c +++ b/src/client/ui/menu.c @@ -1498,15 +1498,14 @@ static menuSound_t Slider_DoSlide(menuSlider_t *s, int dir); static void Slider_Push(menuSlider_t *s) { s->modified = false; - s->curvalue = s->cvar->value; - cclamp(s->curvalue, s->minvalue, s->maxvalue); + s->curvalue = Q_circ_clipf(s->cvar->value, s->minvalue, s->maxvalue); } static void Slider_Pop(menuSlider_t *s) { if (s->modified) { - cclamp(s->curvalue, s->minvalue, s->maxvalue); - Cvar_SetValue(s->cvar, s->curvalue, FROM_MENU); + float val = Q_circ_clipf(s->curvalue, s->minvalue, s->maxvalue); + Cvar_SetValue(s->cvar, val, FROM_MENU); } } @@ -1535,8 +1534,7 @@ static menuSound_t Slider_Click(menuSlider_t *s) float pos; int x; - pos = (s->curvalue - s->minvalue) / (s->maxvalue - s->minvalue); - clamp(pos, 0, 1); + pos = Q_clipf((s->curvalue - s->minvalue) / (s->maxvalue - s->minvalue), 0, 1); x = CHAR_WIDTH + (SLIDER_RANGE - 1) * CHAR_WIDTH * pos; @@ -1578,9 +1576,8 @@ static menuSound_t Slider_MouseMove(menuSlider_t *s) return QMS_NOTHANDLED; pos = (uis.mouseCoords[0] - (s->generic.x + RCOLUMN_OFFSET + CHAR_WIDTH)) * (1.0f / (SLIDER_RANGE * CHAR_WIDTH)); - clamp(pos, 0, 1); - value = pos * (s->maxvalue - s->minvalue); + value = Q_clipf(pos, 0, 1) * (s->maxvalue - s->minvalue); steps = Q_rint(value / s->step); s->modified = true; @@ -1615,9 +1612,7 @@ Slider_DoSlide static menuSound_t Slider_DoSlide(menuSlider_t *s, int dir) { s->modified = true; - s->curvalue += dir * s->step; - - cclamp(s->curvalue, s->minvalue, s->maxvalue); + s->curvalue = Q_circ_clipf(s->curvalue + dir * s->step, s->minvalue, s->maxvalue); if (s->generic.change) { menuSound_t sound = s->generic.change(&s->generic); @@ -1657,8 +1652,7 @@ static void Slider_Draw(menuSlider_t *s) UI_DrawChar(RCOLUMN_OFFSET + s->generic.x + i * CHAR_WIDTH + CHAR_WIDTH, s->generic.y, flags | UI_LEFT, 130); - pos = (s->curvalue - s->minvalue) / (s->maxvalue - s->minvalue); - clamp(pos, 0, 1); + pos = Q_clipf((s->curvalue - s->minvalue) / (s->maxvalue - s->minvalue), 0, 1); UI_DrawChar(CHAR_WIDTH + RCOLUMN_OFFSET + s->generic.x + (SLIDER_RANGE - 1) * CHAR_WIDTH * pos, s->generic.y, flags | UI_LEFT, 131); } diff --git a/src/client/ui/servers.c b/src/client/ui/servers.c index b85bd472f..c5c56f63d 100644 --- a/src/client/ui/servers.c +++ b/src/client/ui/servers.c @@ -668,14 +668,13 @@ static void FinishPingStage(void) static void CalcPingRate(void) { extern cvar_t *info_rate; + + // don't allow more than 100 packets/sec int rate = Cvar_ClampInteger(ui_pingrate, 0, 100); // assume average 450 bytes per reply packet if (!rate) - rate = info_rate->integer / 450; - - // don't allow more than 100 packets/sec - clamp(rate, 1, 100); + rate = Q_clip(info_rate->integer / 450, 1, 100); // drop rate by stage m_servers.pingtime = (1000 * PING_STAGES) / (rate * m_servers.pingstage); diff --git a/src/client/ui/ui.c b/src/client/ui/ui.c index 9be1aa46f..eaaf0908f 100644 --- a/src/client/ui/ui.c +++ b/src/client/ui/ui.c @@ -394,8 +394,8 @@ UI_MouseEvent */ void UI_MouseEvent(int x, int y) { - clamp(x, 0, r_config.width - 1); - clamp(y, 0, r_config.height - 1); + x = Q_clip(x, 0, r_config.width - 1); + y = Q_clip(y, 0, r_config.height - 1); uis.mouseCoords[0] = Q_rint(x * uis.scale); uis.mouseCoords[1] = Q_rint(y * uis.scale); diff --git a/src/common/cmodel.c b/src/common/cmodel.c index 1b91f0c5a..dc386cb7a 100644 --- a/src/common/cmodel.c +++ b/src/common/cmodel.c @@ -732,14 +732,17 @@ static void CM_RecursiveHullCheck(mnode_t *node, float p1f, float p2f, const vec frac2 = 0; } + frac = Q_clipf(frac, 0, 1); + frac2 = Q_clipf(frac2, 0, 1); + // move up to the node - midf = p1f + (p2f - p1f) * clamp(frac, 0, 1); + midf = p1f + (p2f - p1f) * frac; LerpVector(p1, p2, frac, mid); CM_RecursiveHullCheck(node->children[side], p1f, midf, p1, mid); // go past the node - midf = p1f + (p2f - p1f) * clamp(frac2, 0, 1); + midf = p1f + (p2f - p1f) * frac2; LerpVector(p1, p2, frac2, mid); CM_RecursiveHullCheck(node->children[side ^ 1], midf, p2f, mid, p2); diff --git a/src/common/cvar.c b/src/common/cvar.c index 2f636d204..226c6b98a 100644 --- a/src/common/cvar.c +++ b/src/common/cvar.c @@ -158,7 +158,7 @@ static void parse_string_value(cvar_t *var) if (s[0] == '0' && s[1] == 'x') { long v = strtol(s, NULL, 16); - var->integer = clamp(v, INT_MIN, INT_MAX); + var->integer = Q_clipl_int32(v); var->value = (float)var->integer; } else { var->integer = atoi(s); diff --git a/src/common/msg.c b/src/common/msg.c index 775d6f400..a79c450c3 100644 --- a/src/common/msg.c +++ b/src/common/msg.c @@ -450,11 +450,6 @@ void MSG_WriteDir(const vec3_t dir) MSG_WriteByte(best); } -static inline int clip_byte(int v) -{ - return clamp(v, 0, 255); -} - void MSG_PackEntity(entity_packed_t *out, const entity_state_t *in, const entity_state_extension_t *ext) { // allow 0 to accomodate empty baselines @@ -482,14 +477,14 @@ void MSG_PackEntity(entity_packed_t *out, const entity_state_t *in, const entity out->event = in->event; if (ext) { out->morefx = ext->morefx; - out->alpha = clip_byte(ext->alpha * 255.0f); - out->scale = clip_byte(ext->scale * 16.0f); - out->loop_volume = clip_byte(ext->loop_volume * 255.0f); + out->alpha = Q_clip_uint8(ext->alpha * 255.0f); + out->scale = Q_clip_uint8(ext->scale * 16.0f); + out->loop_volume = Q_clip_uint8(ext->loop_volume * 255.0f); // encode ATTN_STATIC (192) as 0, and ATTN_LOOP_NONE (-1) as 192 if (ext->loop_attenuation == ATTN_LOOP_NONE) { out->loop_attenuation = 192; } else { - out->loop_attenuation = clip_byte(ext->loop_attenuation * 64.0f); + out->loop_attenuation = Q_clip_uint8(ext->loop_attenuation * 64.0f); if (out->loop_attenuation == 192) out->loop_attenuation = 0; } @@ -786,17 +781,7 @@ void MSG_WriteDeltaEntity(const entity_packed_t *from, MSG_WriteByte(to->scale); } -static inline int OFFSET2CHAR(float x) -{ - int v = x * 4; - return clamp(v, -128, 127); -} - -static inline int BLEND2BYTE(float x) -{ - int v = x * 255; - return clamp(v, 0, 255); -} +#define OFFSET2CHAR(x) Q_clip_int8((x) * 4) void MSG_PackPlayer(player_packed_t *out, const player_state_t *in) { @@ -811,7 +796,7 @@ void MSG_PackPlayer(player_packed_t *out, const player_state_t *in) out->gunindex = in->gunindex; out->gunframe = in->gunframe; for (i = 0; i < 4; i++) - out->blend[i] = BLEND2BYTE(in->blend[i]); + out->blend[i] = Q_clip_uint8(in->blend[i] * 255); out->fov = (int)in->fov; out->rdflags = in->rdflags; for (i = 0; i < MAX_STATS; i++) diff --git a/src/common/pmove.c b/src/common/pmove.c index c3e1eb325..3ded287d4 100644 --- a/src/common/pmove.c +++ b/src/common/pmove.c @@ -373,8 +373,8 @@ static void PM_AddCurrents(vec3_t wishvel) wishvel[2] = 0; // limit horizontal speed when on a ladder - clamp(wishvel[0], -25, 25); - clamp(wishvel[1], -25, 25); + wishvel[0] = Q_clipf(wishvel[0], -25, 25); + wishvel[1] = Q_clipf(wishvel[1], -25, 25); } // @@ -1012,7 +1012,7 @@ static void PM_ClampAngles(void) } // don't let the player look up or down more than 90 degrees - clamp(pm->viewangles[PITCH], -89, 89); + pm->viewangles[PITCH] = Q_clipf(pm->viewangles[PITCH], -89, 89); } AngleVectors(pm->viewangles, pml.forward, pml.right, pml.up); } diff --git a/src/game/g_main.c b/src/game/g_main.c index a3e0ae293..54e3d944a 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -188,8 +188,7 @@ void InitGame(void) game.helpmessage2[0] = 0; // initialize all entities for this game - game.maxentities = maxentities->value; - clamp(game.maxentities, (int)maxclients->value + 1, game.csr.max_edicts); + game.maxentities = Q_clip(maxentities->value, (int)maxclients->value + 1, game.csr.max_edicts); g_edicts = gi.TagMalloc(game.maxentities * sizeof(g_edicts[0]), TAG_GAME); globals.edicts = g_edicts; globals.max_edicts = game.maxentities; diff --git a/src/game/g_misc.c b/src/game/g_misc.c index e5fcb7f06..ee3c9aec4 100644 --- a/src/game/g_misc.c +++ b/src/game/g_misc.c @@ -65,9 +65,9 @@ void VelocityForDamage(int damage, vec3_t v) void ClipGibVelocity(edict_t *ent) { - clamp(ent->velocity[0], -300, 300); - clamp(ent->velocity[1], -300, 300); - clamp(ent->velocity[2], 200, 500); // always some upwards + ent->velocity[0] = Q_clipf(ent->velocity[0], -300, 300); + ent->velocity[1] = Q_clipf(ent->velocity[1], -300, 300); + ent->velocity[2] = Q_clipf(ent->velocity[2], 200, 500); // always some upwards } /* diff --git a/src/game/g_phys.c b/src/game/g_phys.c index 216422ace..ef365f798 100644 --- a/src/game/g_phys.c +++ b/src/game/g_phys.c @@ -66,13 +66,14 @@ SV_CheckVelocity */ void SV_CheckVelocity(edict_t *ent) { - int i; + float speed = sv_maxvelocity->value; // // bound velocity // - for (i = 0; i < 3; i++) - clamp(ent->velocity[i], -sv_maxvelocity->value, sv_maxvelocity->value); + ent->velocity[0] = Q_clipf(ent->velocity[0], -speed, speed); + ent->velocity[1] = Q_clipf(ent->velocity[1], -speed, speed); + ent->velocity[2] = Q_clipf(ent->velocity[2], -speed, speed); } /* diff --git a/src/game/g_spawn.c b/src/game/g_spawn.c index 7249b5f8d..be0afa9df 100644 --- a/src/game/g_spawn.c +++ b/src/game/g_spawn.c @@ -629,12 +629,11 @@ void SpawnEntities(const char *mapname, const char *entities, const char *spawnp int inhibit; char *com_token; int i; - float skill_level; + int skill_level; - skill_level = floor(skill->value); - clamp(skill_level, 0, 3); + skill_level = Q_clip(skill->value, 0, 3); if (skill->value != skill_level) - gi.cvar_forceset("skill", va("%f", skill_level)); + gi.cvar_forceset("skill", va("%d", skill_level)); SaveClientData(); diff --git a/src/game/p_view.c b/src/game/p_view.c index b48de48cc..123a72660 100644 --- a/src/game/p_view.c +++ b/src/game/p_view.c @@ -138,7 +138,7 @@ void P_DamageFeedback(edict_t *player) if (client->damage_alpha < 0) client->damage_alpha = 0; client->damage_alpha += count * 0.01f; - clamp(client->damage_alpha, 0.2f, 0.6f); // don't go too saturated + client->damage_alpha = Q_clipf(client->damage_alpha, 0.2f, 0.6f); // don't go too saturated // the color of the blend will vary based on how much was absorbed // by different armors @@ -297,11 +297,9 @@ void SV_CalcViewOffset(edict_t *ent) // absolutely bound offsets // so the view can never be outside the player box - clamp(v[0], -14, 14); - clamp(v[1], -14, 14); - clamp(v[2], -22, 30); - - VectorCopy(v, ent->client->ps.viewoffset); + ent->client->ps.viewoffset[0] = Q_clipf(v[0], -14, 14); + ent->client->ps.viewoffset[1] = Q_clipf(v[1], -14, 14); + ent->client->ps.viewoffset[2] = Q_clipf(v[2], -22, 30); } /* @@ -331,7 +329,7 @@ void SV_CalcGunOffset(edict_t *ent) delta -= 360; if (delta < -180) delta += 360; - clamp(delta, -45, 45); + delta = Q_clipf(delta, -45, 45); if (i == YAW) ent->client->ps.gunangles[ROLL] += 0.1f * delta; ent->client->ps.gunangles[i] += 0.2f * delta; diff --git a/src/refresh/images.c b/src/refresh/images.c index 339925f61..ca34359dc 100644 --- a/src/refresh/images.c +++ b/src/refresh/images.c @@ -734,7 +734,7 @@ static int my_jpeg_compress(j_compress_ptr cinfo, JSAMPARRAY row_pointers, scree cinfo->in_color_space = s->bpp == 4 ? JCS_EXT_RGBA : JCS_RGB; jpeg_set_defaults(cinfo); - jpeg_set_quality(cinfo, clamp(s->param, 0, 100), TRUE); + jpeg_set_quality(cinfo, Q_clip(s->param, 0, 100), TRUE); jpeg_start_compress(cinfo, TRUE); jpeg_write_scanlines(cinfo, row_pointers, s->height); @@ -973,7 +973,7 @@ static int my_png_write_image(png_structp png_ptr, png_infop info_ptr, png_init_io(png_ptr, s->fp); png_set_IHDR(png_ptr, info_ptr, s->width, s->height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - png_set_compression_level(png_ptr, clamp(s->param, 0, 9)); + png_set_compression_level(png_ptr, Q_clip(s->param, 0, 9)); png_set_rows(png_ptr, info_ptr, row_pointers); png_write_png(png_ptr, info_ptr, s->bpp == 4 ? PNG_TRANSFORM_STRIP_FILLER_AFTER : 0, NULL); return 0; diff --git a/src/refresh/mesh.c b/src/refresh/mesh.c index e3c6a9351..43c3eddc3 100644 --- a/src/refresh/mesh.c +++ b/src/refresh/mesh.c @@ -386,9 +386,9 @@ static void setup_color(void) } } - for (i = 0; i < 3; i++) { - clamp(color[i], 0, 1); - } + color[0] = Q_clipf(color[0], 0, 1); + color[1] = Q_clipf(color[1], 0, 1); + color[2] = Q_clipf(color[2], 0, 1); } if (flags & RF_TRANSLUCENT) { diff --git a/src/refresh/texture.c b/src/refresh/texture.c index fa150b436..716e10dd3 100644 --- a/src/refresh/texture.c +++ b/src/refresh/texture.c @@ -893,7 +893,7 @@ static void GL_InitParticleTexture(void) dst[0] = 255; dst[1] = 255; dst[2] = 255; - dst[3] = 255 * clamp(f, 0, 1 - shape * 0.2f); + dst[3] = 255 * Q_clipf(f, 0, 1 - shape * 0.2f); dst += 4; } } @@ -946,7 +946,7 @@ static void GL_InitBeamTexture(void) dst[0] = 255; dst[1] = 255; dst[2] = 255; - dst[3] = 255 * clamp(f, 0, 1); + dst[3] = 255 * Q_clipf(f, 0, 1); dst += 4; } } diff --git a/src/refresh/world.c b/src/refresh/world.c index 8b7c56290..fb7117c2f 100644 --- a/src/refresh/world.c +++ b/src/refresh/world.c @@ -331,13 +331,11 @@ void GL_LightPoint(const vec3_t origin, vec3_t color) void R_LightPoint(const vec3_t origin, vec3_t color) { - int i; - GL_LightPoint(origin, color); - for (i = 0; i < 3; i++) { - clamp(color[i], 0, 1); - } + color[0] = Q_clipf(color[0], 0, 1); + color[1] = Q_clipf(color[1], 0, 1); + color[2] = Q_clipf(color[2], 0, 1); } static void GL_MarkLeaves(void) diff --git a/src/server/main.c b/src/server/main.c index fc7080cb0..aa3895342 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -766,10 +766,9 @@ static bool parse_enhanced_params(conn_params_t *p) // set minor protocol version s = Cmd_Argv(6); if (*s) { - p->version = atoi(s); - clamp(p->version, - PROTOCOL_VERSION_R1Q2_MINIMUM, - PROTOCOL_VERSION_R1Q2_CURRENT); + p->version = Q_clip(atoi(s), + PROTOCOL_VERSION_R1Q2_MINIMUM, + PROTOCOL_VERSION_R1Q2_CURRENT); } else { p->version = PROTOCOL_VERSION_R1Q2_MINIMUM; } @@ -793,10 +792,9 @@ static bool parse_enhanced_params(conn_params_t *p) // set minor protocol version s = Cmd_Argv(8); if (*s) { - p->version = atoi(s); - clamp(p->version, - PROTOCOL_VERSION_Q2PRO_MINIMUM, - PROTOCOL_VERSION_Q2PRO_CURRENT); + p->version = Q_clip(atoi(s), + PROTOCOL_VERSION_Q2PRO_MINIMUM, + PROTOCOL_VERSION_Q2PRO_CURRENT); if (p->version == PROTOCOL_VERSION_Q2PRO_RESERVED) { p->version--; // never use this version } @@ -2028,8 +2026,7 @@ void SV_UserinfoChanged(client_t *cl) // rate command val = Info_ValueForKey(cl->userinfo, "rate"); if (*val) { - cl->rate = atoi(val); - clamp(cl->rate, sv_min_rate->integer, sv_max_rate->integer); + cl->rate = Q_clip(atoi(val), sv_min_rate->integer, sv_max_rate->integer); } else { cl->rate = 5000; } @@ -2048,8 +2045,7 @@ void SV_UserinfoChanged(client_t *cl) // msg command val = Info_ValueForKey(cl->userinfo, "msg"); if (*val) { - cl->messagelevel = atoi(val); - clamp(cl->messagelevel, PRINT_LOW, PRINT_CHAT + 1); + cl->messagelevel = Q_clip(atoi(val), PRINT_LOW, PRINT_CHAT + 1); } } diff --git a/src/server/mvd/client.c b/src/server/mvd/client.c index 03fabf01b..3e5a76111 100644 --- a/src/server/mvd/client.c +++ b/src/server/mvd/client.c @@ -2262,7 +2262,7 @@ static void MVD_Seek_f(void) return; } - clamp(percent, 0, 100); + percent = Q_clipf(percent, 0, 100); dest = gtv->demoofs + gtv->demosize * percent / 100; byte_seek = true; diff --git a/src/server/user.c b/src/server/user.c index a8a2fb228..30b96de38 100644 --- a/src/server/user.c +++ b/src/server/user.c @@ -1493,10 +1493,7 @@ static void set_client_fps(int value) if (!value) value = sv.framerate; - framediv = value / BASE_FRAMERATE; - - clamp(framediv, 1, MAX_FRAMEDIV); - + framediv = Q_clip(value / BASE_FRAMERATE, 1, MAX_FRAMEDIV); framediv = sv.frametime.div / Q_gcd(sv.frametime.div, framediv); framerate = sv.framerate / framediv; diff --git a/src/unix/video/sdl.c b/src/unix/video/sdl.c index 6d780fe44..1be4b1d6c 100644 --- a/src/unix/video/sdl.c +++ b/src/unix/video/sdl.c @@ -233,7 +233,7 @@ static int get_dpi_scale(void) int scale_x = (sdl.width + sdl.win_width / 2) / sdl.win_width; int scale_y = (sdl.height + sdl.win_height / 2) / sdl.win_height; if (scale_x == scale_y) - return clamp(scale_x, 1, 10); + return Q_clip(scale_x, 1, 10); } return 1; diff --git a/src/unix/video/wayland.c b/src/unix/video/wayland.c index 5362cb590..a9f507d23 100644 --- a/src/unix/video/wayland.c +++ b/src/unix/video/wayland.c @@ -890,10 +890,8 @@ static void handle_relative_motion(void *data, struct zwp_relative_pointer_v1 *z wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel) { if (Key_GetDest() & KEY_MENU) { - wl.abs_mouse_x += dx; - wl.abs_mouse_y += dy; - clamp(wl.abs_mouse_x, 0, wl_fixed_from_int(wl.width * wl.scale_factor) - 1); - clamp(wl.abs_mouse_y, 0, wl_fixed_from_int(wl.height * wl.scale_factor) - 1); + wl.abs_mouse_x = Q_clip(wl.abs_mouse_x + dx, 0, wl_fixed_from_int(wl.width * wl.scale_factor) - 1); + wl.abs_mouse_y = Q_clip(wl.abs_mouse_y + dy, 0, wl_fixed_from_int(wl.height * wl.scale_factor) - 1); UI_MouseEvent(wl_fixed_to_int(wl.abs_mouse_x), wl_fixed_to_int(wl.abs_mouse_y)); } diff --git a/src/unix/video/x11.c b/src/unix/video/x11.c index cc853863c..1e1f3c2fc 100644 --- a/src/unix/video/x11.c +++ b/src/unix/video/x11.c @@ -302,7 +302,7 @@ static bool init(void) int scale_x = Q_rint(dpi_x / 96.0f); int scale_y = Q_rint(dpi_y / 96.0f); if (scale_x == scale_y) - x11.dpi_scale = clamp(scale_x, 1, 10); + x11.dpi_scale = Q_clip(scale_x, 1, 10); } XSizeHints hints = { diff --git a/src/windows/client.c b/src/windows/client.c index c68e1bc69..7cc023a0b 100644 --- a/src/windows/client.c +++ b/src/windows/client.c @@ -349,7 +349,7 @@ int Win_GetDpiScale(void) int dpi = win.GetDpiForWindow(win.wnd); if (dpi) { int scale = (dpi + USER_DEFAULT_SCREEN_DPI / 2) / USER_DEFAULT_SCREEN_DPI; - return clamp(scale, 1, 10); + return Q_clip(scale, 1, 10); } } return 1; @@ -621,7 +621,7 @@ static void mouse_wheel_event(int delta) if (Key_GetDest() & KEY_CONSOLE) { SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &lines, 0); - clamp(lines, 1, 9); + lines = Q_clip(lines, 1, 9); } else { lines = 1; } From 26b9feb007356ad3edcfbbfd4cb0e2b7778ad768 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 25 Jan 2024 21:43:20 +0300 Subject: [PATCH 127/167] Add and use Q_atoi(). Windows version of atoi() clamps returned value to INT_MIN/INT_MAX on overflow. Add Q_atoi() to make this consistent on all platforms. --- inc/shared/shared.h | 6 ++++++ src/client/ascii.c | 42 ++++++++++++++++++------------------ src/client/input.c | 10 ++++----- src/client/main.c | 14 ++++++------ src/client/precache.c | 6 +++--- src/client/screen.c | 48 ++++++++++++++++++++--------------------- src/client/sound/ogg.c | 2 +- src/client/ui/script.c | 4 ++-- src/client/ui/servers.c | 8 +++---- src/common/bsp.c | 2 +- src/common/cmd.c | 2 +- src/common/cvar.c | 2 +- src/common/tests.c | 6 +++--- src/common/utils.c | 2 +- src/game/g_cmds.c | 6 +++--- src/game/g_spawn.c | 2 +- src/game/g_svcmds.c | 2 +- src/game/g_trigger.c | 2 +- src/game/p_client.c | 6 +++--- src/refresh/images.c | 4 ++-- src/refresh/models.c | 2 +- src/server/ac.c | 2 +- src/server/commands.c | 12 +++++------ src/server/main.c | 22 +++++++++---------- src/server/mvd.c | 2 +- src/server/mvd/client.c | 10 ++++----- src/server/mvd/game.c | 8 +++---- src/server/mvd/parse.c | 4 ++-- src/server/user.c | 6 +++--- src/shared/shared.c | 7 ++++++ 30 files changed, 132 insertions(+), 119 deletions(-) diff --git a/inc/shared/shared.h b/inc/shared/shared.h index d950aca7d..a6eb33edb 100644 --- a/inc/shared/shared.h +++ b/inc/shared/shared.h @@ -516,6 +516,12 @@ char *Q_strchrnul(const char *s, int c); void *Q_memccpy(void *dst, const void *src, int c, size_t size); size_t Q_strnlen(const char *s, size_t maxlen); +#ifdef _WIN32 +#define Q_atoi(s) atoi(s) +#else +int Q_atoi(const char *s); +#endif + char *COM_SkipPath(const char *pathname); size_t COM_StripExtension(char *out, const char *in, size_t size); size_t COM_DefaultExtension(char *path, const char *ext, size_t size); diff --git a/src/client/ascii.c b/src/client/ascii.c index b574b50e9..d586e4a8b 100644 --- a/src/client/ascii.c +++ b/src/client/ascii.c @@ -111,19 +111,19 @@ static void TH_DrawLayoutString(char *dst, const char *s) if (token[0] == 'x') { if (token[1] == 'l') { token = COM_Parse(&s); - x = atoi(token) / 8; + x = Q_atoi(token) / 8; continue; } if (token[1] == 'r') { token = COM_Parse(&s); - x = TH_WIDTH + atoi(token) / 8; + x = TH_WIDTH + Q_atoi(token) / 8; continue; } if (token[1] == 'v') { token = COM_Parse(&s); - x = TH_WIDTH / 2 - 20 + atoi(token) / 8; + x = TH_WIDTH / 2 - 20 + Q_atoi(token) / 8; continue; } } @@ -131,19 +131,19 @@ static void TH_DrawLayoutString(char *dst, const char *s) if (token[0] == 'y') { if (token[1] == 't') { token = COM_Parse(&s); - y = atoi(token) / 8; + y = Q_atoi(token) / 8; continue; } if (token[1] == 'b') { token = COM_Parse(&s); - y = TH_HEIGHT + atoi(token) / 8; + y = TH_HEIGHT + Q_atoi(token) / 8; continue; } if (token[1] == 'v') { token = COM_Parse(&s); - y = TH_HEIGHT / 2 - 15 + atoi(token) / 8; + y = TH_HEIGHT / 2 - 15 + Q_atoi(token) / 8; continue; } } @@ -160,25 +160,25 @@ static void TH_DrawLayoutString(char *dst, const char *s) int score, ping, time; token = COM_Parse(&s); - x = TH_WIDTH / 2 - 20 + atoi(token) / 8; + x = TH_WIDTH / 2 - 20 + Q_atoi(token) / 8; token = COM_Parse(&s); - y = TH_HEIGHT / 2 - 15 + atoi(token) / 8; + y = TH_HEIGHT / 2 - 15 + Q_atoi(token) / 8; token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_CLIENTS) { Com_Error(ERR_DROP, "%s: invalid client index", __func__); } ci = &cl.clientinfo[value]; token = COM_Parse(&s); - score = atoi(token); + score = Q_atoi(token); token = COM_Parse(&s); - ping = atoi(token); + ping = Q_atoi(token); token = COM_Parse(&s); - time = atoi(token); + time = Q_atoi(token); len = strlen(ci->name); TH_DrawString(dst, x + 4, y, ci->name, len); @@ -196,22 +196,22 @@ static void TH_DrawLayoutString(char *dst, const char *s) int score, ping; token = COM_Parse(&s); - x = TH_WIDTH / 2 - 20 + atoi(token) / 8; + x = TH_WIDTH / 2 - 20 + Q_atoi(token) / 8; token = COM_Parse(&s); - y = TH_HEIGHT / 2 - 15 + atoi(token) / 8; + y = TH_HEIGHT / 2 - 15 + Q_atoi(token) / 8; token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_CLIENTS) { Com_Error(ERR_DROP, "%s: invalid client index", __func__); } ci = &cl.clientinfo[value]; token = COM_Parse(&s); - score = atoi(token); + score = Q_atoi(token); token = COM_Parse(&s); - ping = atoi(token); + ping = Q_atoi(token); if (ping > 999) ping = 999; @@ -230,9 +230,9 @@ static void TH_DrawLayoutString(char *dst, const char *s) if (!strcmp(token, "num")) { // draw a number token = COM_Parse(&s); - width = atoi(token); + width = Q_atoi(token); token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_STATS) { Com_Error(ERR_DROP, "%s: invalid stat index", __func__); } @@ -243,7 +243,7 @@ static void TH_DrawLayoutString(char *dst, const char *s) if (!strcmp(token, "stat_string")) { token = COM_Parse(&s); - index = atoi(token); + index = Q_atoi(token); if (index < 0 || index >= MAX_STATS) { Com_Error(ERR_DROP, "%s: invalid string index", __func__); } @@ -272,7 +272,7 @@ static void TH_DrawLayoutString(char *dst, const char *s) if (!strcmp(token, "if")) { token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_STATS) { Com_Error(ERR_DROP, "%s: invalid stat index", __func__); } diff --git a/src/client/input.c b/src/client/input.c index dea54ae7d..cfeae0ed5 100644 --- a/src/client/input.c +++ b/src/client/input.c @@ -251,7 +251,7 @@ static void KeyDown(kbutton_t *b) c = Cmd_Argv(1); if (c[0]) - k = atoi(c); + k = Q_atoi(c); else k = -1; // typed manually at the console for continuous down @@ -272,7 +272,7 @@ static void KeyDown(kbutton_t *b) // save timestamp c = Cmd_Argv(2); - b->downtime = atoi(c); + b->downtime = Q_atoi(c); if (!b->downtime) { b->downtime = com_eventTime - 100; } @@ -288,7 +288,7 @@ static void KeyUp(kbutton_t *b) c = Cmd_Argv(1); if (c[0]) - k = atoi(c); + k = Q_atoi(c); else { // typed manually at the console, assume for unsticking, so clear all b->down[0] = b->down[1] = 0; @@ -310,7 +310,7 @@ static void KeyUp(kbutton_t *b) // save timestamp c = Cmd_Argv(2); - uptime = atoi(c); + uptime = Q_atoi(c); if (!uptime) { b->msec += 10; } else if (uptime > b->downtime) { @@ -386,7 +386,7 @@ static void IN_UseUp(void) static void IN_Impulse(void) { - in_impulse = atoi(Cmd_Argv(1)); + in_impulse = Q_atoi(Cmd_Argv(1)); } static void IN_CenterView(void) diff --git a/src/client/main.c b/src/client/main.c index 5f594e8c2..54c695e6d 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -568,7 +568,7 @@ static void CL_FollowIP_f(void) if (Cmd_Argc() > 1) { // optional second argument references less recent address - j = Q_clip(atoi(Cmd_Argv(1)), 0, RECENT_ADDR - 1) + 1; + j = Q_clip(Q_atoi(Cmd_Argv(1)), 0, RECENT_ADDR - 1) + 1; } else { j = 1; } @@ -869,8 +869,8 @@ static void CL_ParseStatusResponse(serverStatus_t *status, const char *string) status->numPlayers = 0; while (status->numPlayers < MAX_STATUS_PLAYERS) { player = &status->players[status->numPlayers]; - player->score = atoi(COM_Parse(&s)); - player->ping = atoi(COM_Parse(&s)); + player->score = Q_atoi(COM_Parse(&s)); + player->ping = Q_atoi(COM_Parse(&s)); Q_strlcpy(player->name, COM_Parse(&s), sizeof(player->name)); if (!s) break; @@ -1260,7 +1260,7 @@ static void CL_ConnectionlessPacket(void) return; } - cls.challenge = atoi(Cmd_Argv(1)); + cls.challenge = Q_atoi(Cmd_Argv(1)); cls.state = ca_connecting; cls.connect_time -= CONNECT_INSTANT; // fire immediately //cls.connect_count = 0; @@ -1349,12 +1349,12 @@ static void CL_ConnectionlessPacket(void) if (!strncmp(s, "ac=", 3)) { s += 3; if (*s) { - anticheat = atoi(s); + anticheat = Q_atoi(s); } } else if (!strncmp(s, "nc=", 3)) { s += 3; if (*s) { - type = atoi(s); + type = Q_atoi(s); if (type != NETCHAN_OLD && type != NETCHAN_NEW) { Com_Error(ERR_DISCONNECT, "Server returned invalid netchan type"); @@ -1739,7 +1739,7 @@ static void CL_Precache_f(void) return; } - precache_spawncount = atoi(Cmd_Argv(1)); + precache_spawncount = Q_atoi(Cmd_Argv(1)); CL_ResetPrecacheCheck(); CL_RequestNextDownload(); diff --git a/src/client/precache.c b/src/client/precache.c index aa0a5583d..4ba971531 100644 --- a/src/client/precache.c +++ b/src/client/precache.c @@ -230,7 +230,7 @@ void CL_RegisterBspModels(void) Com_Error(ERR_DROP, "Couldn't load %s: %s", name, BSP_ErrorString(ret)); } - if (cl.bsp->checksum != atoi(cl.configstrings[cl.csr.mapchecksum])) { + if (cl.bsp->checksum != Q_atoi(cl.configstrings[cl.csr.mapchecksum])) { if (cls.demo.playback) { Com_WPrintf("Local map version differs from demo: %i != %s\n", cl.bsp->checksum, cl.configstrings[cl.csr.mapchecksum]); @@ -419,12 +419,12 @@ void CL_UpdateConfigstring(int index) const char *s = cl.configstrings[index]; if (index == cl.csr.maxclients) { - cl.maxclients = atoi(s); + cl.maxclients = Q_atoi(s); return; } if (index == cl.csr.airaccel) { - cl.pmp.airaccelerate = cl.pmp.qwmode || atoi(s); + cl.pmp.airaccelerate = cl.pmp.qwmode || Q_atoi(s); return; } diff --git a/src/client/screen.c b/src/client/screen.c index 5cb977e85..ab098e006 100644 --- a/src/client/screen.c +++ b/src/client/screen.c @@ -690,8 +690,8 @@ static void SCR_Draw_f(void) flags = UI_IGNORECOLOR; s = Cmd_Argv(1); - x = atoi(Cmd_Argv(2)); - y = atoi(Cmd_Argv(3)); + x = Q_atoi(Cmd_Argv(2)); + y = Q_atoi(Cmd_Argv(3)); if (x < 0) { flags |= UI_RIGHT; @@ -1663,19 +1663,19 @@ static void SCR_ExecuteLayoutString(const char *s) if (token[0] == 'x') { if (token[1] == 'l') { token = COM_Parse(&s); - x = atoi(token); + x = Q_atoi(token); continue; } if (token[1] == 'r') { token = COM_Parse(&s); - x = scr.hud_width + atoi(token); + x = scr.hud_width + Q_atoi(token); continue; } if (token[1] == 'v') { token = COM_Parse(&s); - x = scr.hud_width / 2 - 160 + atoi(token); + x = scr.hud_width / 2 - 160 + Q_atoi(token); continue; } } @@ -1683,19 +1683,19 @@ static void SCR_ExecuteLayoutString(const char *s) if (token[0] == 'y') { if (token[1] == 't') { token = COM_Parse(&s); - y = atoi(token); + y = Q_atoi(token); continue; } if (token[1] == 'b') { token = COM_Parse(&s); - y = scr.hud_height + atoi(token); + y = scr.hud_height + Q_atoi(token); continue; } if (token[1] == 'v') { token = COM_Parse(&s); - y = scr.hud_height / 2 - 120 + atoi(token); + y = scr.hud_height / 2 - 120 + Q_atoi(token); continue; } } @@ -1704,7 +1704,7 @@ static void SCR_ExecuteLayoutString(const char *s) if (!strcmp(token, "pic")) { // draw a pic from a stat number token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_STATS) { Com_Error(ERR_DROP, "%s: invalid stat index", __func__); } @@ -1737,25 +1737,25 @@ static void SCR_ExecuteLayoutString(const char *s) int score, ping, time; token = COM_Parse(&s); - x = scr.hud_width / 2 - 160 + atoi(token); + x = scr.hud_width / 2 - 160 + Q_atoi(token); token = COM_Parse(&s); - y = scr.hud_height / 2 - 120 + atoi(token); + y = scr.hud_height / 2 - 120 + Q_atoi(token); token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_CLIENTS) { Com_Error(ERR_DROP, "%s: invalid client index", __func__); } ci = &cl.clientinfo[value]; token = COM_Parse(&s); - score = atoi(token); + score = Q_atoi(token); token = COM_Parse(&s); - ping = atoi(token); + ping = Q_atoi(token); token = COM_Parse(&s); - time = atoi(token); + time = Q_atoi(token); HUD_DrawAltString(x + 32, y, ci->name); HUD_DrawString(x + 32, y + CHAR_HEIGHT, "Score: "); @@ -1778,22 +1778,22 @@ static void SCR_ExecuteLayoutString(const char *s) int score, ping; token = COM_Parse(&s); - x = scr.hud_width / 2 - 160 + atoi(token); + x = scr.hud_width / 2 - 160 + Q_atoi(token); token = COM_Parse(&s); - y = scr.hud_height / 2 - 120 + atoi(token); + y = scr.hud_height / 2 - 120 + Q_atoi(token); token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_CLIENTS) { Com_Error(ERR_DROP, "%s: invalid client index", __func__); } ci = &cl.clientinfo[value]; token = COM_Parse(&s); - score = atoi(token); + score = Q_atoi(token); token = COM_Parse(&s); - ping = atoi(token); + ping = Q_atoi(token); if (ping > 999) ping = 999; @@ -1817,9 +1817,9 @@ static void SCR_ExecuteLayoutString(const char *s) if (!strcmp(token, "num")) { // draw a number token = COM_Parse(&s); - width = atoi(token); + width = Q_atoi(token); token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_STATS) { Com_Error(ERR_DROP, "%s: invalid stat index", __func__); } @@ -1889,7 +1889,7 @@ static void SCR_ExecuteLayoutString(const char *s) if (!strncmp(token, "stat_", 5)) { char *cmd = token + 5; token = COM_Parse(&s); - index = atoi(token); + index = Q_atoi(token); if (index < 0 || index >= MAX_STATS) { Com_Error(ERR_DROP, "%s: invalid stat index", __func__); } @@ -1951,7 +1951,7 @@ static void SCR_ExecuteLayoutString(const char *s) if (!strcmp(token, "if")) { token = COM_Parse(&s); - value = atoi(token); + value = Q_atoi(token); if (value < 0 || value >= MAX_STATS) { Com_Error(ERR_DROP, "%s: invalid stat index", __func__); } diff --git a/src/client/sound/ogg.c b/src/client/sound/ogg.c index 20c75b1e6..216c666df 100644 --- a/src/client/sound/ogg.c +++ b/src/client/sound/ogg.c @@ -261,7 +261,7 @@ void OGG_Play(void) s = tracklist[trackindex]; trackindex = (trackindex + 1) % trackcount; } else if (COM_IsUint(s)) { - s = va("track%02d", atoi(s)); + s = va("track%02d", Q_atoi(s)); } ogg_play(ogg_open(s, true)); diff --git a/src/client/ui/script.c b/src/client/ui/script.c index 40d274ccf..bd464843d 100644 --- a/src/client/ui/script.c +++ b/src/client/ui/script.c @@ -421,7 +421,7 @@ static void Parse_Toggle(menuFrameWork_t *menu) b++; } if (*b) { - bit = atoi(b); + bit = Q_atoi(b); if (bit < 0 || bit >= 32) { Com_Printf("Invalid bit number: %d\n", bit); return; @@ -472,7 +472,7 @@ static void Parse_Field(menuFrameWork_t *menu) status = cmd_optarg; break; case 'w': - width = atoi(cmd_optarg); + width = Q_atoi(cmd_optarg); if (width < 1 || width > 32) { Com_Printf("Invalid width\n"); return; diff --git a/src/client/ui/servers.c b/src/client/ui/servers.c index c5c56f63d..87e6fe2de 100644 --- a/src/client/ui/servers.c +++ b/src/client/ui/servers.c @@ -188,10 +188,10 @@ static serverslot_t *FindSlot(const netadr_t *search, int *index_p) static uint32_t ColorForStatus(const serverStatus_t *status, unsigned ping) { - if (atoi(Info_ValueForKey(status->infostring, "needpass")) >= 1) + if (Q_atoi(Info_ValueForKey(status->infostring, "needpass")) >= 1) return uis.color.disabled.u32; - if (atoi(Info_ValueForKey(status->infostring, "anticheat")) >= 2) + if (Q_atoi(Info_ValueForKey(status->infostring, "anticheat")) >= 2) return uis.color.disabled.u32; if (Q_stricmp(Info_ValueForKey(status->infostring, "NoFake"), "ENABLED") == 0) @@ -776,8 +776,8 @@ static int namecmp(serverslot_t *s1, serverslot_t *s2, int col) static int pingcmp(serverslot_t *s1, serverslot_t *s2) { - int n1 = atoi(UI_GetColumn(s1->name, COL_RTT)); - int n2 = atoi(UI_GetColumn(s2->name, COL_RTT)); + int n1 = Q_atoi(UI_GetColumn(s1->name, COL_RTT)); + int n2 = Q_atoi(UI_GetColumn(s2->name, COL_RTT)); return (n1 - n2) * m_servers.list.sortdir; } diff --git a/src/common/bsp.c b/src/common/bsp.c index 4fd28abbc..016aaf949 100644 --- a/src/common/bsp.c +++ b/src/common/bsp.c @@ -1720,7 +1720,7 @@ mmodel_t *BSP_InlineModel(bsp_t *bsp, const char *name) Q_assert(name); Q_assert(name[0] == '*'); - num = atoi(name + 1); + num = Q_atoi(name + 1); if (num < 1 || num >= bsp->nummodels) { Com_Error(ERR_DROP, "%s: bad number: %d", __func__, num); } diff --git a/src/common/cmd.c b/src/common/cmd.c index 9720ec749..86227379b 100644 --- a/src/common/cmd.c +++ b/src/common/cmd.c @@ -56,7 +56,7 @@ bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2" */ static void Cmd_Wait_f(void) { - int count = atoi(Cmd_Argv(1)); + int count = Q_atoi(Cmd_Argv(1)); cmd_current->waitCount += max(count, 1); } diff --git a/src/common/cvar.c b/src/common/cvar.c index 226c6b98a..b5cf09f85 100644 --- a/src/common/cvar.c +++ b/src/common/cvar.c @@ -161,7 +161,7 @@ static void parse_string_value(cvar_t *var) var->integer = Q_clipl_int32(v); var->value = (float)var->integer; } else { - var->integer = atoi(s); + var->integer = Q_atoi(s); var->value = atof(s); if (var->value != 0.0f && !isnormal(var->value)) var->value = 0.0f; diff --git a/src/common/tests.c b/src/common/tests.c index d3f31e067..907a387cc 100644 --- a/src/common/tests.c +++ b/src/common/tests.c @@ -49,7 +49,7 @@ static void Com_Activate_f(void) return; } - act = atoi(Cmd_Argv(1)); + act = Q_atoi(Cmd_Argv(1)); if (act < ACT_MINIMIZED || act > ACT_ACTIVATED) { Com_Printf("Bad mode\n"); return; @@ -90,7 +90,7 @@ static void Com_Crash_f(void) { static byte buf1[16]; byte buf2[16], *buf3; - int i = atoi(Cmd_Argv(1)); + int i = Q_atoi(Cmd_Argv(1)); switch (i) { case 1: @@ -148,7 +148,7 @@ static void Com_PrintJunk_f(void) buf[Q_rand() % (sizeof(buf) - 1)] = ' '; if (Cmd_Argc() > 1) - count = atoi(Cmd_Argv(1)); + count = Q_atoi(Cmd_Argv(1)); else count = 1; diff --git a/src/common/utils.c b/src/common/utils.c index ad5dd218b..c8073244f 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -207,7 +207,7 @@ color_index_t Com_ParseColor(const char *s) color_index_t i; if (COM_IsUint(s)) { - i = atoi(s); + i = Q_atoi(s); if (i < 0 || i >= COLOR_COUNT) { return COLOR_NONE; } diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index c1c598c5d..d9eb14476 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -164,7 +164,7 @@ void Cmd_Give_f(edict_t *ent) if (give_all || Q_stricmp(gi.argv(1), "health") == 0) { if (gi.argc() == 3) - ent->health = atoi(gi.argv(2)); + ent->health = Q_atoi(gi.argv(2)); else ent->health = ent->max_health; if (!give_all) @@ -258,7 +258,7 @@ void Cmd_Give_f(edict_t *ent) if (it->flags & IT_AMMO) { if (gi.argc() == 3) - ent->client->pers.inventory[index] = atoi(gi.argv(2)); + ent->client->pers.inventory[index] = Q_atoi(gi.argv(2)); else ent->client->pers.inventory[index] += it->quantity; } else { @@ -672,7 +672,7 @@ void Cmd_Wave_f(edict_t *ent) { int i; - i = atoi(gi.argv(1)); + i = Q_atoi(gi.argv(1)); // can't wave when ducked if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) diff --git a/src/game/g_spawn.c b/src/game/g_spawn.c index be0afa9df..a886f3719 100644 --- a/src/game/g_spawn.c +++ b/src/game/g_spawn.c @@ -435,7 +435,7 @@ static bool ED_ParseField(const spawn_field_t *fields, const char *key, const ch ((float *)(b + f->ofs))[2] = vec[2]; break; case F_INT: - *(int *)(b + f->ofs) = atoi(value); + *(int *)(b + f->ofs) = Q_atoi(value); break; case F_FLOAT: *(float *)(b + f->ofs) = atof(value); diff --git a/src/game/g_svcmds.c b/src/game/g_svcmds.c index 36b07625f..4381400a0 100644 --- a/src/game/g_svcmds.c +++ b/src/game/g_svcmds.c @@ -89,7 +89,7 @@ static bool StringToFilter(char *s, ipfilter_t *f) num[j++] = *s++; } num[j] = 0; - b.bytes[i] = atoi(num); + b.bytes[i] = Q_atoi(num); if (b.bytes[i] != 0) m.bytes[i] = 255; diff --git a/src/game/g_trigger.c b/src/game/g_trigger.c index ac381a0e1..80dd39e63 100644 --- a/src/game/g_trigger.c +++ b/src/game/g_trigger.c @@ -491,7 +491,7 @@ void SP_trigger_gravity(edict_t *self) } InitTrigger(self); - self->gravity = atoi(st.gravity); + self->gravity = Q_atoi(st.gravity); self->touch = trigger_gravity_touch; } diff --git a/src/game/p_client.c b/src/game/p_client.c index 2bd6d03aa..2c3163c47 100644 --- a/src/game/p_client.c +++ b/src/game/p_client.c @@ -1130,7 +1130,7 @@ void PutClientInServer(edict_t *ent) if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV)) { client->ps.fov = 90; } else { - client->ps.fov = atoi(Info_ValueForKey(client->pers.userinfo, "fov")); + client->ps.fov = Q_atoi(Info_ValueForKey(client->pers.userinfo, "fov")); if (client->ps.fov < 1) client->ps.fov = 90; else if (client->ps.fov > 160) @@ -1349,7 +1349,7 @@ void ClientUserinfoChanged(edict_t *ent, char *userinfo) if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV)) { ent->client->ps.fov = 90; } else { - ent->client->ps.fov = atoi(Info_ValueForKey(userinfo, "fov")); + ent->client->ps.fov = Q_atoi(Info_ValueForKey(userinfo, "fov")); if (ent->client->ps.fov < 1) ent->client->ps.fov = 90; else if (ent->client->ps.fov > 160) @@ -1359,7 +1359,7 @@ void ClientUserinfoChanged(edict_t *ent, char *userinfo) // handedness s = Info_ValueForKey(userinfo, "hand"); if (strlen(s)) { - ent->client->pers.hand = atoi(s); + ent->client->pers.hand = Q_atoi(s); } // save off the userinfo in case we want to check something later diff --git a/src/refresh/images.c b/src/refresh/images.c index ca34359dc..5fa5daa46 100644 --- a/src/refresh/images.c +++ b/src/refresh/images.c @@ -1280,7 +1280,7 @@ static void IMG_ScreenShotJPG_f(void) } if (Cmd_Argc() > 2) { - quality = atoi(Cmd_Argv(2)); + quality = Q_atoi(Cmd_Argv(2)); } else { quality = r_screenshot_quality->integer; } @@ -1301,7 +1301,7 @@ static void IMG_ScreenShotPNG_f(void) } if (Cmd_Argc() > 2) { - compression = atoi(Cmd_Argv(2)); + compression = Q_atoi(Cmd_Argv(2)); } else { compression = r_screenshot_compression->integer; } diff --git a/src/refresh/models.c b/src/refresh/models.c index 393d3a73f..4e0421832 100644 --- a/src/refresh/models.c +++ b/src/refresh/models.c @@ -1399,7 +1399,7 @@ qhandle_t R_RegisterModel(const char *name) if (*name == '*') { // inline bsp model - index = atoi(name + 1); + index = Q_atoi(name + 1); return ~index; } diff --git a/src/server/ac.c b/src/server/ac.c index 3fc0d2697..e55cf6cbe 100644 --- a/src/server/ac.c +++ b/src/server/ac.c @@ -1576,7 +1576,7 @@ void AC_Info_f(void) filesubstring = Cmd_Argv(2); if (COM_IsUint(substring)) { - clientID = atoi(substring); + clientID = Q_atoi(substring); if (clientID < 0 || clientID >= sv_maxclients->integer) { Com_Printf("Invalid client ID.\n"); return; diff --git a/src/server/commands.c b/src/server/commands.c index a8f9be696..a6d3f6962 100644 --- a/src/server/commands.c +++ b/src/server/commands.c @@ -125,7 +125,7 @@ client_t *SV_GetPlayer(const char *s, bool partial) // numeric values are just slot numbers if (COM_IsUint(s)) { - i = atoi(s); + i = Q_atoi(s); if (i < 0 || i >= sv_maxclients->integer) { Com_Printf("Bad client slot number: %d\n", i); return NULL; @@ -1046,7 +1046,7 @@ static bool parse_mask(char *s, netadr_t *addr, netadr_t *mask) Com_Printf("Please specify a mask after '/'.\n"); return false; } - bits = atoi(p); + bits = Q_atoi(p); } else { bits = -1; } @@ -1144,7 +1144,7 @@ void SV_DelMatch_f(list_t *list) // numeric values are just slot numbers if (COM_IsUint(s)) { - i = atoi(s); + i = Q_atoi(s); match = LIST_INDEX(addrmatch_t, i - 1, list, entry); if (match) { goto remove; @@ -1271,7 +1271,7 @@ static void SV_DelStuffCmd(list_t *list, int arg, const char *what) } if (COM_IsUint(s)) { - i = atoi(s); + i = Q_atoi(s); stuff = LIST_INDEX(stuffcmd_t, i - 1, list, entry); if (!stuff) { Com_Printf("No such %scmd index: %d\n", what, i); @@ -1469,7 +1469,7 @@ static void SV_DelFilterCmd_f(void) } if (COM_IsUint(s)) { - i = atoi(s); + i = Q_atoi(s); filter = LIST_INDEX(filtercmd_t, i - 1, &sv_filterlist, entry); if (!filter) { Com_Printf("No such filtercmd index: %d\n", i); @@ -1591,7 +1591,7 @@ static void SV_DelCvarBan(list_t *list, const char *what) } if (COM_IsUint(s)) { - i = atoi(s); + i = Q_atoi(s); ban = LIST_INDEX(cvarban_t, i - 1, list, entry); if (!ban) { Com_Printf("No such %sban index: %d\n", what, i); diff --git a/src/server/main.c b/src/server/main.c index aa3895342..1990a74e0 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -530,7 +530,7 @@ static void SVC_Info(void) if (sv_maxclients->integer == 1) return; // ignore in single player - version = atoi(Cmd_Argv(1)); + version = Q_atoi(Cmd_Argv(1)); if (version < PROTOCOL_VERSION_DEFAULT || version > PROTOCOL_VERSION_Q2PRO) return; // ignore invalid versions @@ -635,9 +635,9 @@ typedef struct { static bool parse_basic_params(conn_params_t *p) { - p->protocol = atoi(Cmd_Argv(1)); - p->qport = atoi(Cmd_Argv(2)) ; - p->challenge = atoi(Cmd_Argv(3)); + p->protocol = Q_atoi(Cmd_Argv(1)); + p->qport = Q_atoi(Cmd_Argv(2)) ; + p->challenge = Q_atoi(Cmd_Argv(3)); // check for invalid protocol version if (p->protocol < PROTOCOL_VERSION_OLD || @@ -735,7 +735,7 @@ static bool parse_packet_length(conn_params_t *p) if (p->protocol >= PROTOCOL_VERSION_R1Q2) { s = Cmd_Argv(5); if (*s) { - p->maxlength = atoi(s); + p->maxlength = Q_atoi(s); if (p->maxlength < 0 || p->maxlength > MAX_PACKETLEN_WRITABLE) return reject("Invalid maximum message length.\n"); @@ -766,7 +766,7 @@ static bool parse_enhanced_params(conn_params_t *p) // set minor protocol version s = Cmd_Argv(6); if (*s) { - p->version = Q_clip(atoi(s), + p->version = Q_clip(Q_atoi(s), PROTOCOL_VERSION_R1Q2_MINIMUM, PROTOCOL_VERSION_R1Q2_CURRENT); } else { @@ -778,7 +778,7 @@ static bool parse_enhanced_params(conn_params_t *p) // set netchan type s = Cmd_Argv(6); if (*s) { - p->nctype = atoi(s); + p->nctype = Q_atoi(s); if (p->nctype < NETCHAN_OLD || p->nctype > NETCHAN_NEW) return reject("Invalid netchan type.\n"); } else { @@ -787,12 +787,12 @@ static bool parse_enhanced_params(conn_params_t *p) // set zlib s = Cmd_Argv(7); - p->has_zlib = !*s || atoi(s); + p->has_zlib = !*s || Q_atoi(s); // set minor protocol version s = Cmd_Argv(8); if (*s) { - p->version = Q_clip(atoi(s), + p->version = Q_clip(Q_atoi(s), PROTOCOL_VERSION_Q2PRO_MINIMUM, PROTOCOL_VERSION_Q2PRO_CURRENT); if (p->version == PROTOCOL_VERSION_Q2PRO_RESERVED) { @@ -2026,7 +2026,7 @@ void SV_UserinfoChanged(client_t *cl) // rate command val = Info_ValueForKey(cl->userinfo, "rate"); if (*val) { - cl->rate = Q_clip(atoi(val), sv_min_rate->integer, sv_max_rate->integer); + cl->rate = Q_clip(Q_atoi(val), sv_min_rate->integer, sv_max_rate->integer); } else { cl->rate = 5000; } @@ -2045,7 +2045,7 @@ void SV_UserinfoChanged(client_t *cl) // msg command val = Info_ValueForKey(cl->userinfo, "msg"); if (*val) { - cl->messagelevel = Q_clip(atoi(val), PRINT_LOW, PRINT_CHAT + 1); + cl->messagelevel = Q_clip(Q_atoi(val), PRINT_LOW, PRINT_CHAT + 1); } } diff --git a/src/server/mvd.c b/src/server/mvd.c index 92047c23f..0e5c6667f 100644 --- a/src/server/mvd.c +++ b/src/server/mvd.c @@ -142,7 +142,7 @@ static char dummy_buffer_text[MAX_STRING_CHARS]; static void dummy_wait_f(void) { - int count = atoi(Cmd_Argv(1)); + int count = Q_atoi(Cmd_Argv(1)); dummy_buffer.waitCount += max(count, 1); } diff --git a/src/server/mvd/client.c b/src/server/mvd/client.c index 3e5a76111..c19b27d62 100644 --- a/src/server/mvd/client.c +++ b/src/server/mvd/client.c @@ -255,7 +255,7 @@ mvd_t *MVD_SetChannel(int arg) } else #endif if (COM_IsUint(s)) { - id = atoi(s); + id = Q_atoi(s); FOR_EACH_MVD(mvd) { if (mvd->id == id) { return mvd; @@ -355,7 +355,7 @@ static gtv_t *gtv_set_conn(int arg) } if (COM_IsUint(s)) { - id = atoi(s); + id = Q_atoi(s); FOR_EACH_GTV(gtv) { if (gtv->id == id) { return gtv; @@ -2200,7 +2200,7 @@ static void MVD_Skip_f(void) return; } - count = atoi(Cmd_Argv(2)); + count = Q_atoi(Cmd_Argv(2)); if (count < 1) { count = 1; } @@ -2455,7 +2455,7 @@ static void MVD_Control_f(void) Cmd_PrintHelp(options); return; case 'l': - loop = atoi(cmd_optarg); + loop = Q_atoi(cmd_optarg); if (loop < 0) { Com_Printf("Invalid value for %s option.\n", cmd_optopt); Cmd_PrintHint(); @@ -2536,7 +2536,7 @@ static void MVD_Play_f(void) "Prepend slash to specify raw path.\n"); return; case 'l': - loop = atoi(cmd_optarg); + loop = Q_atoi(cmd_optarg); if (loop < 0) { Com_Printf("Invalid value for %s option.\n", cmd_optopt); Cmd_PrintHint(); diff --git a/src/server/mvd/game.c b/src/server/mvd/game.c index b8e1a7b2c..7228e70db 100644 --- a/src/server/mvd/game.c +++ b/src/server/mvd/game.c @@ -1027,7 +1027,7 @@ static mvd_player_t *MVD_SetPlayer(mvd_client_t *client, const char *s) // numeric values are just slot numbers if (COM_IsUint(s)) { - i = atoi(s); + i = Q_atoi(s); if (i < 0 || i >= mvd->maxclients) { SV_ClientPrintf(client->cl, PRINT_HIGH, "[MVD] Player slot number %d is invalid.\n", i); @@ -1230,7 +1230,7 @@ static void MVD_AutoFollow_f(mvd_client_t *client) memset(client->chase_bitmap, 0, sizeof(client->chase_bitmap)); for (i = 2; i < argc; i++) { - j = atoi(Cmd_Argv(i)); + j = Q_atoi(Cmd_Argv(i)); if (j >= 0 && j < mvd->maxclients) Q_SetBit(client->chase_bitmap, j); } @@ -1946,9 +1946,9 @@ static void MVD_GameClientUserinfoChanged(edict_t *ent, char *userinfo) mvd_client_t *client = EDICT_MVDCL(ent); int fov; - client->uf = atoi(Info_ValueForKey(userinfo, "uf")); + client->uf = Q_atoi(Info_ValueForKey(userinfo, "uf")); - fov = atoi(Info_ValueForKey(userinfo, "fov")); + fov = Q_atoi(Info_ValueForKey(userinfo, "fov")); if (fov < 1) { fov = 90; } else if (fov > 160) { diff --git a/src/server/mvd/parse.c b/src/server/mvd/parse.c index 4a577101a..12fa26a53 100644 --- a/src/server/mvd/parse.c +++ b/src/server/mvd/parse.c @@ -958,7 +958,7 @@ static void MVD_ParseServerData(mvd_t *mvd, int extrabits) } // parse maxclients - index = atoi(mvd->configstrings[mvd->csr->maxclients]); + index = Q_atoi(mvd->configstrings[mvd->csr->maxclients]); if (index < 1 || index > MAX_CLIENTS) { MVD_Destroyf(mvd, "Invalid maxclients"); } @@ -1007,7 +1007,7 @@ static void MVD_ParseServerData(mvd_t *mvd, int extrabits) if (ret) { Com_EPrintf("[%s] =!= Couldn't load %s: %s\n", mvd->name, string, BSP_ErrorString(ret)); // continue with null visibility - } else if (mvd->cm.cache->checksum != atoi(mvd->configstrings[mvd->csr->mapchecksum])) { + } else if (mvd->cm.cache->checksum != Q_atoi(mvd->configstrings[mvd->csr->mapchecksum])) { Com_EPrintf("[%s] =!= Local map version differs from server!\n", mvd->name); CM_FreeMap(&mvd->cm); } diff --git a/src/server/user.c b/src/server/user.c index 30b96de38..5d3e6f78e 100644 --- a/src/server/user.c +++ b/src/server/user.c @@ -584,7 +584,7 @@ static void SV_BeginDownload_f(void) len = FS_NormalizePath(name); if (Cmd_Argc() > 2) - offset = atoi(Cmd_Argv(2)); // downloaded offset + offset = Q_atoi(Cmd_Argv(2)); // downloaded offset // hacked by zoid to allow more conrol over download // first off, no .. or global allow check @@ -752,7 +752,7 @@ static void SV_NextServer_f(void) if (sv.state == ss_pic && !Cvar_VariableInteger("coop")) return; // ss_pic can be nextserver'd in coop mode - if (atoi(Cmd_Argv(1)) != sv.spawncount) + if (Q_atoi(Cmd_Argv(1)) != sv.spawncount) return; // leftover from last server sv.spawncount ^= 1; // make sure another doesn't sneak in @@ -832,7 +832,7 @@ static void SV_PacketdupHack_f(void) int numdups = sv_client->numpackets - 1; if (Cmd_Argc() > 1) { - numdups = atoi(Cmd_Argv(1)); + numdups = Q_atoi(Cmd_Argv(1)); if (numdups < 0 || numdups > sv_packetdup_hack->integer) { SV_ClientPrintf(sv_client, PRINT_HIGH, "Packetdup of %d is not allowed on this server.\n", numdups); diff --git a/src/shared/shared.c b/src/shared/shared.c index b5fc0fd90..1affae0c5 100644 --- a/src/shared/shared.c +++ b/src/shared/shared.c @@ -863,6 +863,13 @@ size_t Q_strnlen(const char *s, size_t maxlen) return p ? p - s : maxlen; } +#ifndef _WIN32 +int Q_atoi(const char *s) +{ + return Q_clipl_int32(strtol(s, NULL, 10)); +} +#endif + /* ===================================================================== From 309b732a56329fb86029e896adda07e42782a7ee Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 28 Jan 2024 12:07:40 +0300 Subject: [PATCH 128/167] Allow client messagelevel up to 256. --- src/server/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/main.c b/src/server/main.c index 1990a74e0..5067fe665 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -2045,7 +2045,7 @@ void SV_UserinfoChanged(client_t *cl) // msg command val = Info_ValueForKey(cl->userinfo, "msg"); if (*val) { - cl->messagelevel = Q_clip(Q_atoi(val), PRINT_LOW, PRINT_CHAT + 1); + cl->messagelevel = Q_clip(Q_atoi(val), PRINT_LOW, 256); } } From 45e658e0d5fd1ca6c61b540c20cc1a9236b3e55f Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 30 Jan 2024 12:14:45 +0300 Subject: [PATCH 129/167] Check for zero JPEG/PNG image dimensions. This should never happen, but check anyway for completeness. --- src/refresh/images.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/refresh/images.c b/src/refresh/images.c index 5fa5daa46..a7993f1ca 100644 --- a/src/refresh/images.c +++ b/src/refresh/images.c @@ -656,7 +656,8 @@ static int my_jpeg_start_decompress(j_decompress_ptr cinfo, byte *rawdata, size_ return Q_ERR_INVALID_FORMAT; } - if (cinfo->output_width > MAX_TEXTURE_SIZE || cinfo->output_height > MAX_TEXTURE_SIZE) { + if (cinfo->output_width < 1 || cinfo->output_width > MAX_TEXTURE_SIZE || + cinfo->output_height < 1 || cinfo->output_height > MAX_TEXTURE_SIZE) { Com_SetLastError("invalid image dimensions"); return Q_ERR_INVALID_FORMAT; } @@ -842,7 +843,7 @@ static int my_png_read_header(png_structp png_ptr, png_infop info_ptr, return Q_ERR_FAILURE; } - if (w > MAX_TEXTURE_SIZE || h > MAX_TEXTURE_SIZE) { + if (w < 1 || h < 1 || w > MAX_TEXTURE_SIZE || h > MAX_TEXTURE_SIZE) { Com_SetLastError("invalid image dimensions"); return Q_ERR_INVALID_FORMAT; } From 4a360a69698b850de0d77d7839ab7610034dca9d Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 30 Jan 2024 12:17:12 +0300 Subject: [PATCH 130/167] Make CL_ParseZPacket() length variables unsigned. Doesn't matter in practice, but makes code less surprising. --- src/client/parse.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/client/parse.c b/src/client/parse.c index 5cb75a3b5..57f72726c 100644 --- a/src/client/parse.c +++ b/src/client/parse.c @@ -1139,7 +1139,8 @@ static void CL_ParseZPacket(void) #if USE_ZLIB sizebuf_t temp; byte buffer[MAX_MSGLEN]; - int ret, inlen, outlen; + uInt inlen, outlen; + int ret; if (msg_read.data != msg_read_buffer) { Com_Error(ERR_DROP, "%s: recursively entered", __func__); @@ -1154,9 +1155,9 @@ static void CL_ParseZPacket(void) inflateReset(&cls.z); cls.z.next_in = MSG_ReadData(inlen); - cls.z.avail_in = (uInt)inlen; + cls.z.avail_in = inlen; cls.z.next_out = buffer; - cls.z.avail_out = (uInt)outlen; + cls.z.avail_out = outlen; ret = inflate(&cls.z, Z_FINISH); if (ret != Z_STREAM_END) { Com_Error(ERR_DROP, "%s: inflate() failed with error %d", __func__, ret); From fcf63daf0373edc62663b7b7474d4bcdfa36bc04 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 30 Jan 2024 15:06:03 +0300 Subject: [PATCH 131/167] Use MAX_EDICTS instead of magic constants. --- src/client/demo.c | 4 ++-- src/client/parse.c | 14 +++++++------- src/server/entities.c | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/client/demo.c b/src/client/demo.c index ebe8a2c14..dee10c086 100644 --- a/src/client/demo.c +++ b/src/client/demo.c @@ -104,7 +104,7 @@ static void emit_packet_entities(server_frame_t *from, server_frame_t *to) oldent = newent = NULL; while (newindex < to->numEntities || oldindex < from_num_entities) { if (newindex >= to->numEntities) { - newnum = 9999; + newnum = MAX_EDICTS; } else { i = (to->firstEntity + newindex) & PARSE_ENTITIES_MASK; newent = &cl.entityStates[i]; @@ -112,7 +112,7 @@ static void emit_packet_entities(server_frame_t *from, server_frame_t *to) } if (oldindex >= from_num_entities) { - oldnum = 9999; + oldnum = MAX_EDICTS; } else { i = (from->firstEntity + oldindex) & PARSE_ENTITIES_MASK; oldent = &cl.entityStates[i]; diff --git a/src/client/parse.c b/src/client/parse.c index 57f72726c..23720dff2 100644 --- a/src/client/parse.c +++ b/src/client/parse.c @@ -87,10 +87,10 @@ static void CL_ParsePacketEntities(server_frame_t *oldframe, oldindex = 0; oldstate = NULL; if (!oldframe) { - oldnum = 99999; + oldnum = MAX_EDICTS; } else { if (oldindex >= oldframe->numEntities) { - oldnum = 99999; + oldnum = MAX_EDICTS; } else { i = oldframe->firstEntity + oldindex; oldstate = &cl.entityStates[i & PARSE_ENTITIES_MASK]; @@ -116,7 +116,7 @@ static void CL_ParsePacketEntities(server_frame_t *oldframe, oldindex++; if (oldindex >= oldframe->numEntities) { - oldnum = 99999; + oldnum = MAX_EDICTS; } else { i = oldframe->firstEntity + oldindex; oldstate = &cl.entityStates[i & PARSE_ENTITIES_MASK]; @@ -137,7 +137,7 @@ static void CL_ParsePacketEntities(server_frame_t *oldframe, oldindex++; if (oldindex >= oldframe->numEntities) { - oldnum = 99999; + oldnum = MAX_EDICTS; } else { i = oldframe->firstEntity + oldindex; oldstate = &cl.entityStates[i & PARSE_ENTITIES_MASK]; @@ -157,7 +157,7 @@ static void CL_ParsePacketEntities(server_frame_t *oldframe, oldindex++; if (oldindex >= oldframe->numEntities) { - oldnum = 99999; + oldnum = MAX_EDICTS; } else { i = oldframe->firstEntity + oldindex; oldstate = &cl.entityStates[i & PARSE_ENTITIES_MASK]; @@ -179,7 +179,7 @@ static void CL_ParsePacketEntities(server_frame_t *oldframe, } // any remaining entities in the old frame are copied over - while (oldnum != 99999) { + while (oldnum != MAX_EDICTS) { // one or more entities from the old packet are unchanged SHOWNET(3, " unchanged: %i\n", oldnum); CL_ParseDeltaEntity(frame, oldnum, oldstate, 0); @@ -187,7 +187,7 @@ static void CL_ParsePacketEntities(server_frame_t *oldframe, oldindex++; if (oldindex >= oldframe->numEntities) { - oldnum = 99999; + oldnum = MAX_EDICTS; } else { i = oldframe->firstEntity + oldindex; oldstate = &cl.entityStates[i & PARSE_ENTITIES_MASK]; diff --git a/src/server/entities.c b/src/server/entities.c index 891ac4678..4e861f6c5 100644 --- a/src/server/entities.c +++ b/src/server/entities.c @@ -62,7 +62,7 @@ static void SV_EmitPacketEntities(client_t *client, } if (newindex >= to->num_entities) { - newnum = 9999; + newnum = MAX_EDICTS; } else { i = (to->first_entity + newindex) % svs.num_entities; newent = &svs.entities[i]; @@ -70,7 +70,7 @@ static void SV_EmitPacketEntities(client_t *client, } if (oldindex >= from_num_entities) { - oldnum = 9999; + oldnum = MAX_EDICTS; } else { i = (from->first_entity + oldindex) % svs.num_entities; oldent = &svs.entities[i]; From 9ea8e6acf2d98e6a0a2c90ff99f7c61395b483f4 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 30 Jan 2024 15:42:15 +0300 Subject: [PATCH 132/167] Properly check inuse flag in blocked functions. --- src/game/g_func.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/game/g_func.c b/src/game/g_func.c index 2b52c8956..c4653ec1e 100644 --- a/src/game/g_func.c +++ b/src/game/g_func.c @@ -378,7 +378,7 @@ void plat_blocked(edict_t *self, edict_t *other) // give it a chance to go away on it's own terms (like gibs) T_Damage(other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH); // if it's still there, nuke it - if (other) + if (other->inuse) BecomeExplosion1(other); return; } @@ -1019,7 +1019,7 @@ void door_blocked(edict_t *self, edict_t *other) // give it a chance to go away on it's own terms (like gibs) T_Damage(other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH); // if it's still there, nuke it - if (other) + if (other->inuse) BecomeExplosion1(other); return; } @@ -1380,7 +1380,7 @@ void train_blocked(edict_t *self, edict_t *other) // give it a chance to go away on it's own terms (like gibs) T_Damage(other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH); // if it's still there, nuke it - if (other) + if (other->inuse) BecomeExplosion1(other); return; } @@ -1818,7 +1818,7 @@ void door_secret_blocked(edict_t *self, edict_t *other) // give it a chance to go away on it's own terms (like gibs) T_Damage(other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH); // if it's still there, nuke it - if (other) + if (other->inuse) BecomeExplosion1(other); return; } From 8473ee5cf3685aebe85e7a6cd5b7094eef36467c Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 30 Jan 2024 15:44:41 +0300 Subject: [PATCH 133/167] Make HashMap_Reserve() capacity argument unsigned. --- inc/common/hash_map.h | 2 +- src/common/hash_map.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/common/hash_map.h b/inc/common/hash_map.h index ed949d4b0..bd6961253 100644 --- a/inc/common/hash_map.h +++ b/inc/common/hash_map.h @@ -24,7 +24,7 @@ hash_map_t *HashMap_CreateImpl(const uint32_t key_size, const uint32_t value_siz uint32_t (*hasher)(const void *const), bool (*comp)(const void *const, const void *const)); void HashMap_Destroy(hash_map_t *map); -void HashMap_Reserve(hash_map_t *map, int capacity); +void HashMap_Reserve(hash_map_t *map, uint32_t capacity); bool HashMap_InsertImpl(hash_map_t *map, const uint32_t key_size, const uint32_t value_size, const void *const key, const void *const value); bool HashMap_EraseImpl(hash_map_t *map, const uint32_t key_size, const void *const key); void *HashMap_LookupImpl(hash_map_t *map, const uint32_t key_size, const void *const key); diff --git a/src/common/hash_map.c b/src/common/hash_map.c index 6911744b9..8589813fa 100644 --- a/src/common/hash_map.c +++ b/src/common/hash_map.c @@ -129,7 +129,7 @@ void HashMap_Destroy(hash_map_t *map) HashMap_Reserve ================= */ -void HashMap_Reserve(hash_map_t *map, int capacity) +void HashMap_Reserve(hash_map_t *map, uint32_t capacity) { const uint32_t new_key_value_storage_size = Q_npot32(capacity); if (map->key_value_storage_size < new_key_value_storage_size) From 66993817d0849982656021cdda16f02d63b15908 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 30 Jan 2024 19:13:13 +0300 Subject: [PATCH 134/167] Fix use of uninitialized variable. --- src/game/p_weapon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/p_weapon.c b/src/game/p_weapon.c index d11286181..23410bf65 100644 --- a/src/game/p_weapon.c +++ b/src/game/p_weapon.c @@ -1234,7 +1234,7 @@ void weapon_bfg_fire(edict_t *ent) ent->client->ps.gunframe++; - PlayerNoise(ent, start, PNOISE_WEAPON); + PlayerNoise(ent, ent->s.origin, PNOISE_WEAPON); return; } From 796df133e418538230864747811b677d28a5d2d7 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 30 Jan 2024 19:26:41 +0300 Subject: [PATCH 135/167] Change MAX_MSGLEN back to 32 KiB. Commit 6b4f63 bumped MAX_MSGLEN to 64 KiB without taking into account that netchan fragmentation layer only allows up to 32 KiB messages. --- inc/common/protocol.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/common/protocol.h b/inc/common/protocol.h index b4a116488..f7cfc6b34 100644 --- a/inc/common/protocol.h +++ b/inc/common/protocol.h @@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., // protocol.h -- communications protocols // -#define MAX_MSGLEN 0x10000 // max length of a message, 64k +#define MAX_MSGLEN 0x8000 // max length of a message, 32 KiB #define PROTOCOL_VERSION_OLD 26 #define PROTOCOL_VERSION_DEFAULT 34 From 7fd2b4bc855171db855c6f9558b456c7dc6b4dbc Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 30 Jan 2024 22:21:54 +0300 Subject: [PATCH 136/167] Scan client inventory up to game.num_items. Should prevent out of array access if client inventory contains non-zero values at positions >= game.num_items. --- src/game/g_cmds.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index d9eb14476..0d548f6b1 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -72,8 +72,8 @@ void SelectNextItem(edict_t *ent, int itflags) } // scan for the next valid one - for (i = 1; i <= MAX_ITEMS; i++) { - index = (cl->pers.selected_item + i) % MAX_ITEMS; + for (i = 1; i <= game.num_items; i++) { + index = (cl->pers.selected_item + i) % game.num_items; if (!cl->pers.inventory[index]) continue; it = &itemlist[index]; @@ -103,8 +103,8 @@ void SelectPrevItem(edict_t *ent, int itflags) } // scan for the next valid one - for (i = 1; i <= MAX_ITEMS; i++) { - index = (cl->pers.selected_item + MAX_ITEMS - i) % MAX_ITEMS; + for (i = 1; i <= game.num_items; i++) { + index = (cl->pers.selected_item + game.num_items - i) % game.num_items; if (!cl->pers.inventory[index]) continue; it = &itemlist[index]; @@ -477,8 +477,8 @@ void Cmd_WeapPrev_f(edict_t *ent) selected_weapon = ITEM_INDEX(cl->pers.weapon); // scan for the next valid one - for (i = 1; i <= MAX_ITEMS; i++) { - index = (selected_weapon + i) % MAX_ITEMS; + for (i = 1; i <= game.num_items; i++) { + index = (selected_weapon + i) % game.num_items; if (!cl->pers.inventory[index]) continue; it = &itemlist[index]; @@ -512,8 +512,8 @@ void Cmd_WeapNext_f(edict_t *ent) selected_weapon = ITEM_INDEX(cl->pers.weapon); // scan for the next valid one - for (i = 1; i <= MAX_ITEMS; i++) { - index = (selected_weapon + MAX_ITEMS - i) % MAX_ITEMS; + for (i = 1; i <= game.num_items; i++) { + index = (selected_weapon + game.num_items - i) % game.num_items; if (!cl->pers.inventory[index]) continue; it = &itemlist[index]; From 7fa6d69be7f564e509e6af5bc2edad8ec83d5840 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 30 Jan 2024 22:42:54 +0300 Subject: [PATCH 137/167] Simplify sky drawing code. --- src/refresh/sky.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/refresh/sky.c b/src/refresh/sky.c index 1dfcded90..1e301d8f7 100644 --- a/src/refresh/sky.c +++ b/src/refresh/sky.c @@ -33,7 +33,7 @@ static const vec3_t skyclip[6] = { }; // 1 = s, 2 = t, 3 = 2048 -static const int st_to_vec[6][3] = { +static const int8_t st_to_vec[6][3] = { { 3, -1, 2 }, { -3, 1, 2 }, @@ -45,7 +45,7 @@ static const int st_to_vec[6][3] = { }; // s = [0]/[2], t = [1]/[2] -static const int vec_to_st[6][3] = { +static const int8_t vec_to_st[6][3] = { { -2, 3, 1 }, { 2, 3, -1 }, @@ -314,17 +314,8 @@ static void MakeSkyVec(float s, float t, int axis, vec_t *out) } // avoid bilerp seam - s = (s + 1) * 0.5f; - t = (t + 1) * 0.5f; - - if (s < sky_min) - s = sky_min; - else if (s > sky_max) - s = sky_max; - if (t < sky_min) - t = sky_min; - else if (t > sky_max) - t = sky_max; + s = Q_clipf((s + 1) * 0.5f, sky_min, sky_max); + t = Q_clipf((t + 1) * 0.5f, sky_min, sky_max); out[3] = s; out[4] = 1.0f - t; @@ -341,7 +332,7 @@ R_DrawSkyBox */ void R_DrawSkyBox(void) { - static const int skytexorder[6] = {0, 2, 1, 3, 4, 5}; + static const uint8_t skytexorder[6] = {0, 2, 1, 3, 4, 5}; vec5_t verts[4]; int i; From f068cd7c474708a95cab441b54d52ad87f5cd182 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 31 Jan 2024 10:28:44 +0300 Subject: [PATCH 138/167] Avoid signed integer overflow in SortPlayers(). --- src/client/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/client/main.c b/src/client/main.c index 54c695e6d..6e2225c8f 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -834,7 +834,11 @@ static int SortPlayers(const void *v1, const void *v2) const playerStatus_t *p1 = (const playerStatus_t *)v1; const playerStatus_t *p2 = (const playerStatus_t *)v2; - return p2->score - p1->score; + if (p1->score < p2->score) + return 1; + if (p1->score > p2->score) + return -1; + return 0; } /* From 5e4c5d172090c97a9b99dc1482f68cdae07a9897 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 1 Feb 2024 00:24:17 +0300 Subject: [PATCH 139/167] Prefer libc versions of some string functions. --- inc/shared/shared.h | 14 ++++++++++++++ src/shared/shared.c | 6 ++++++ src/unix/meson.build | 12 ++++++++++++ 3 files changed, 32 insertions(+) diff --git a/inc/shared/shared.h b/inc/shared/shared.h index a6eb33edb..d453a3428 100644 --- a/inc/shared/shared.h +++ b/inc/shared/shared.h @@ -512,9 +512,23 @@ char *Q_strcasestr(const char *s1, const char *s2); #define Q_stricmpn Q_strncasecmp #define Q_stristr Q_strcasestr +#ifdef HAVE_STRCHRNUL +#define Q_strchrnul strchrnul +#else char *Q_strchrnul(const char *s, int c); +#endif + +#ifdef HAVE_MEMCCPY +#define Q_memccpy memccpy +#else void *Q_memccpy(void *dst, const void *src, int c, size_t size); +#endif + +#ifdef HAVE_STRNLEN +#define Q_strnlen strnlen +#else size_t Q_strnlen(const char *s, size_t maxlen); +#endif #ifdef _WIN32 #define Q_atoi(s) atoi(s) diff --git a/src/shared/shared.c b/src/shared/shared.c index 1affae0c5..0f907e5e3 100644 --- a/src/shared/shared.c +++ b/src/shared/shared.c @@ -827,6 +827,7 @@ size_t Q_scnprintf(char *dest, size_t size, const char *fmt, ...) return ret; } +#ifndef HAVE_STRCHRNUL char *Q_strchrnul(const char *s, int c) { while (*s && *s != c) { @@ -834,7 +835,9 @@ char *Q_strchrnul(const char *s, int c) } return (char *)s; } +#endif +#ifndef HAVE_MEMCCPY /* =============== Q_memccpy @@ -856,12 +859,15 @@ void *Q_memccpy(void *dst, const void *src, int c, size_t size) return NULL; } +#endif +#ifndef HAVE_STRNLEN size_t Q_strnlen(const char *s, size_t maxlen) { char *p = memchr(s, 0, maxlen); return p ? p - s : maxlen; } +#endif #ifndef _WIN32 int Q_atoi(const char *s) diff --git a/src/unix/meson.build b/src/unix/meson.build index d6e82d16a..924f9263a 100644 --- a/src/unix/meson.build +++ b/src/unix/meson.build @@ -29,3 +29,15 @@ if not config.has('USE_SDL') and not config.has('USE_X11') and not config.has('U warning('No video drivers enabled, client will not be built') client_deps += disabler() endif + +test_funcs = [ + 'memccpy', + 'strchrnul', + 'strnlen', +] + +foreach func: test_funcs + if cc.has_function(func, args: '-D_GNU_SOURCE', prefix: '#include ') + config.set('HAVE_' + func.to_upper(), true) + endif +endforeach From ce429123027c3f7f2c53fca9d35e0226e546e893 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 1 Feb 2024 12:19:21 +0300 Subject: [PATCH 140/167] Avoid using sizeof on pointer variable. --- src/client/demo.c | 2 +- src/server/mvd/client.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/client/demo.c b/src/client/demo.c index dee10c086..31840c692 100644 --- a/src/client/demo.c +++ b/src/client/demo.c @@ -858,7 +858,7 @@ void CL_EmitDemoSnapshot(void) snap->msglen = msg_write.cursize; memcpy(snap->data, msg_write.data, msg_write.cursize); - cls.demo.snapshots = Z_Realloc(cls.demo.snapshots, sizeof(snap) * ALIGN(cls.demo.numsnapshots + 1, MIN_SNAPSHOTS)); + cls.demo.snapshots = Z_Realloc(cls.demo.snapshots, sizeof(cls.demo.snapshots[0]) * ALIGN(cls.demo.numsnapshots + 1, MIN_SNAPSHOTS)); cls.demo.snapshots[cls.demo.numsnapshots++] = snap; Com_DPrintf("[%d] snaplen %u\n", cls.demo.frames_read, msg_write.cursize); diff --git a/src/server/mvd/client.c b/src/server/mvd/client.c index c19b27d62..f781b0994 100644 --- a/src/server/mvd/client.c +++ b/src/server/mvd/client.c @@ -637,9 +637,9 @@ static void demo_emit_snapshot(mvd_t *mvd) memcpy(snap->data, msg_write.data, msg_write.cursize); if (!mvd->snapshots) - mvd->snapshots = MVD_Malloc(sizeof(snap) * MIN_SNAPSHOTS); + mvd->snapshots = MVD_Malloc(sizeof(mvd->snapshots[0]) * MIN_SNAPSHOTS); else - mvd->snapshots = Z_Realloc(mvd->snapshots, sizeof(snap) * ALIGN(mvd->numsnapshots + 1, MIN_SNAPSHOTS)); + mvd->snapshots = Z_Realloc(mvd->snapshots, sizeof(mvd->snapshots[0]) * ALIGN(mvd->numsnapshots + 1, MIN_SNAPSHOTS)); mvd->snapshots[mvd->numsnapshots++] = snap; Com_DPrintf("[%d] snaplen %u\n", mvd->framenum, msg_write.cursize); From dc0a9b48f6d870978d73520f85c77ddeeb3f69f1 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 1 Feb 2024 12:37:46 +0300 Subject: [PATCH 141/167] Properly check inuse flag in ai_run(). --- src/game/g_ai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/g_ai.c b/src/game/g_ai.c index bb7b31d03..b4fd347a7 100644 --- a/src/game/g_ai.c +++ b/src/game/g_ai.c @@ -952,6 +952,6 @@ void ai_run(edict_t *self, float dist) G_FreeEdict(tempgoal); - if (self) + if (self->inuse) self->goalentity = save; } From fca90a025d44425970529d26514ab8eab2560b80 Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Fri, 2 Feb 2024 14:53:59 -0500 Subject: [PATCH 142/167] Debug print statements for sound caching --- src/client/tent.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/client/tent.c b/src/client/tent.c index 71fc6534f..263abdeab 100644 --- a/src/client/tent.c +++ b/src/client/tent.c @@ -252,6 +252,7 @@ static void CL_RegisterAQtionSounds(void) S_RegisterSound(name); } } + Com_DPrintf("%s: All gun sounds precached\n", __func__); // Register all AQtion hit sounds char hitsounds[][64] = {"aphelmet", "apvest", "body", "chest", "headshot", "leg", "stomach", "vest"}; @@ -261,6 +262,7 @@ static void CL_RegisterAQtionSounds(void) Q_snprintf(name, sizeof(name), "hitsounds/%s.wav", hitsounds[j]); S_RegisterSound(name); } + Com_DPrintf("%s: All hit sounds precached\n", __func__); } /* From ce89c772e6c6a3961fccf518dbd887cd6dcdabb0 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 1 Feb 2024 16:32:18 +0300 Subject: [PATCH 143/167] Simplify hash map lookup code. --- src/common/hash_map.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/common/hash_map.c b/src/common/hash_map.c index 8589813fa..226039375 100644 --- a/src/common/hash_map.c +++ b/src/common/hash_map.c @@ -256,7 +256,6 @@ HashMap_LookupImpl void *HashMap_LookupImpl(hash_map_t *map, const uint32_t key_size, const void *const key) { Q_assert(map->key_size == key_size); - if (map->num_entries == 0) return NULL; @@ -266,7 +265,7 @@ void *HashMap_LookupImpl(hash_map_t *map, const uint32_t key_size, const void *c while (storage_index != UINT32_MAX) { const void *const storage_key = HashMap_GetKeyImpl(map, storage_index); if (map->comp ? map->comp(key, storage_key) : (memcmp(key, storage_key, key_size) == 0)) - return (byte *)map->values + (storage_index * map->value_size); + return HashMap_GetValueImpl(map, storage_index); storage_index = map->index_chain[storage_index]; } From a01f449fc937a71879d01f112493d347f9540a80 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 2 Feb 2024 12:10:21 +0300 Subject: [PATCH 144/167] Clean up UI player models listing. --- src/client/ui/playerconfig.c | 4 +- src/client/ui/playermodels.c | 76 +++++++++--------------------------- 2 files changed, 21 insertions(+), 59 deletions(-) diff --git a/src/client/ui/playerconfig.c b/src/client/ui/playerconfig.c index a1b67c644..c53ddf428 100644 --- a/src/client/ui/playerconfig.c +++ b/src/client/ui/playerconfig.c @@ -43,7 +43,7 @@ typedef struct m_player_s { unsigned time; unsigned oldTime; - char *pmnames[MAX_PLAYERMODELS]; + char *pmnames[MAX_PLAYERMODELS + 1]; } m_player_t; static m_player_t m_player; @@ -203,7 +203,7 @@ static menuSound_t Change(menuCommon_t *self) static void Pop(menuFrameWork_t *self) { - char scratch[MAX_OSPATH]; + char scratch[MAX_QPATH]; Cvar_SetEx("name", m_player.name.field.text, FROM_CONSOLE); diff --git a/src/client/ui/playermodels.c b/src/client/ui/playermodels.c index e60c6aa7a..f4bc2e621 100644 --- a/src/client/ui/playermodels.c +++ b/src/client/ui/playermodels.c @@ -30,13 +30,13 @@ PLAYER MODELS static bool IconOfSkinExists(char *skin, char **pcxfiles, int npcxfiles) { int i; - char scratch[MAX_OSPATH]; + char scratch[MAX_QPATH]; COM_StripExtension(scratch, skin, sizeof(scratch)); Q_strlcat(scratch, "_i.pcx", sizeof(scratch)); for (i = 0; i < npcxfiles; i++) { - if (strcmp(pcxfiles[i], scratch) == 0) + if (Q_stricmp(pcxfiles[i], scratch) == 0) return true; } @@ -51,69 +51,30 @@ static int pmicmpfnc(const void *_a, const void *_b) /* ** sort by male, female, then alphabetical */ - if (strcmp(a->directory, "male") == 0) + if (Q_stricmp(a->directory, "male") == 0) return -1; - else if (strcmp(b->directory, "male") == 0) + if (Q_stricmp(b->directory, "male") == 0) return 1; - if (strcmp(a->directory, "female") == 0) + if (Q_stricmp(a->directory, "female") == 0) return -1; - else if (strcmp(b->directory, "female") == 0) + if (Q_stricmp(b->directory, "female") == 0) return 1; - return strcmp(a->directory, b->directory); + return Q_stricmp(a->directory, b->directory); } void PlayerModel_Load(void) { char scratch[MAX_QPATH]; - int ndirs = 0; - char *dirnames[MAX_PLAYERMODELS]; - int i, j; - char **list; - char *s, *p; - int numFiles; + int i, ndirs; + char **dirnames; playerModelInfo_t *pmi; - uis.numPlayerModels = 0; + Q_assert(!uis.numPlayerModels); // get a list of directories - if (!(list = (char **)FS_ListFiles(NULL, "players/*/tris.md2", FS_SEARCH_BYFILTER, &numFiles))) { - return; - } - - for (i = 0; i < numFiles; i++) { - if (Q_strlcpy(scratch, list[i], sizeof(scratch)) >= sizeof(scratch)) - continue; - - // make short name for the model - if (!(s = strchr(scratch, '/'))) - continue; - s++; - - if (!(p = strchr(s, '/'))) - continue; - *p = 0; - - for (j = 0; j < ndirs; j++) { - if (!strcmp(dirnames[j], s)) { - break; - } - } - - if (j != ndirs) { - continue; - } - - dirnames[ndirs++] = UI_CopyString(s); - if (ndirs == MAX_PLAYERMODELS) { - break; - } - } - - FS_FreeList((void **)list); - - if (!ndirs) { + if (!(dirnames = (char **)FS_ListFiles("players", NULL, FS_SEARCH_DIRSONLY, &ndirs))) { return; } @@ -128,14 +89,14 @@ void PlayerModel_Load(void) // verify the existence of tris.md2 Q_concat(scratch, sizeof(scratch), "players/", dirnames[i], "/tris.md2"); if (!FS_FileExists(scratch)) { - goto skip; + continue; } // verify the existence of at least one pcx skin Q_concat(scratch, sizeof(scratch), "players/", dirnames[i]); pcxnames = (char **)FS_ListFiles(scratch, ".pcx", 0, &npcxfiles); if (!pcxnames) { - goto skip; + continue; } // count valid skins, which consist of a skin with a matching "_i" icon @@ -149,7 +110,7 @@ void PlayerModel_Load(void) if (!nskins) { FS_FreeList((void **)pcxnames); - goto skip; + continue; } skinnames = UI_Malloc(sizeof(char *) * (nskins + 1)); @@ -171,13 +132,14 @@ void PlayerModel_Load(void) pmi = &uis.pmi[uis.numPlayerModels++]; pmi->nskins = nskins; pmi->skindisplaynames = skinnames; - pmi->directory = dirnames[i]; - continue; + pmi->directory = UI_CopyString(dirnames[i]); -skip: - Z_Free(dirnames[i]); + if (uis.numPlayerModels == MAX_PLAYERMODELS) + break; } + FS_FreeList((void **)dirnames); + qsort(uis.pmi, uis.numPlayerModels, sizeof(uis.pmi[0]), pmicmpfnc); } From 03707f42bb0228ade3b577aef23bee5a06ffaae7 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 4 Feb 2024 01:20:50 +0300 Subject: [PATCH 145/167] Update zlib to 1.3.1. --- meson.build | 2 +- subprojects/zlib.wrap | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/meson.build b/meson.build index a2dac92a1..0ea7deb28 100644 --- a/meson.build +++ b/meson.build @@ -252,7 +252,7 @@ fallback_opt = ['default_library=static'] zlib = dependency('zlib', required: get_option('zlib'), - default_options: fallback_opt, + default_options: fallback_opt + [ 'tests=disabled' ], ) if not zlib.found() diff --git a/subprojects/zlib.wrap b/subprojects/zlib.wrap index 589cb26b0..851fe2b4d 100644 --- a/subprojects/zlib.wrap +++ b/subprojects/zlib.wrap @@ -1,12 +1,12 @@ [wrap-file] -directory = zlib-1.3 -source_url = https://github.com/madler/zlib/releases/download/v1.3/zlib-1.3.tar.xz -source_filename = zlib-1.3.tar.xz -source_hash = 8a9ba2898e1d0d774eca6ba5b4627a11e5588ba85c8851336eb38de4683050a7 -patch_filename = zlib_1.3-3_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/zlib_1.3-3/get_patch -patch_hash = dcb86003e945761dc47aed34b6179003c5e68ddbca4cf71ebc5875ae57b76b8e -wrapdb_version = 1.3-3 +directory = zlib-1.3.1 +source_url = https://github.com/madler/zlib/releases/download/v1.3.1/zlib-1.3.1.tar.xz +source_filename = zlib-1.3.1.tar.xz +source_hash = 38ef96b8dfe510d42707d9c781877914792541133e1870841463bfa73f883e32 +patch_filename = zlib_1.3.1-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/zlib_1.3.1-1/get_patch +patch_hash = e79b98eb24a75392009cec6f99ca5cdca9881ff20bfa174e8b8926d5c7a47095 +wrapdb_version = 1.3.1-1 [provide] zlib = zlib_dep From 14b2530cc8a420b815a8683e8e840af0dab76d8a Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 4 Feb 2024 01:22:49 +0300 Subject: [PATCH 146/167] Update libpng to 1.6.42. --- src/refresh/images.c | 2 +- subprojects/libpng.wrap | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/refresh/images.c b/src/refresh/images.c index a7993f1ca..216e576c5 100644 --- a/src/refresh/images.c +++ b/src/refresh/images.c @@ -917,7 +917,7 @@ IMG_LOAD(PNG) if (rawlen < 8) return Q_ERR_FILE_TOO_SMALL; - if (!png_check_sig(rawdata, 8)) + if (png_sig_cmp(rawdata, 0, 8)) return Q_ERR_UNKNOWN_FORMAT; my_err.filename = image->name; diff --git a/subprojects/libpng.wrap b/subprojects/libpng.wrap index 8ba5a95f0..7548f2e4d 100644 --- a/subprojects/libpng.wrap +++ b/subprojects/libpng.wrap @@ -1,11 +1,12 @@ [wrap-file] -directory = libpng-1.6.40 -source_url = https://downloads.sourceforge.net/libpng/libpng-1.6.40.tar.xz -source_filename = libpng-1.6.40.tar.xz -source_hash = 535b479b2467ff231a3ec6d92a525906fb8ef27978be4f66dbe05d3f3a01b3a1 -patch_url = https://skuller.net/meson/libpng_1.6.40-1_patch.zip -patch_filename = libpng_1.6.40-1_patch.zip -patch_hash = aeffbd55f18ec363354080f927ef19d52bb29ccc75cc1ed53e7cb916acf5f0ae +directory = libpng-1.6.42 +source_url = https://downloads.sourceforge.net/libpng/libpng-1.6.42.tar.xz +source_filename = libpng-1.6.42.tar.xz +source_hash = c919dbc11f4c03b05aba3f8884d8eb7adfe3572ad228af972bb60057bdb48450 +patch_filename = libpng_1.6.42-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/libpng_1.6.42-1/get_patch +patch_hash = b5c709da83556da3e970550d1b5bd2286f44da88db34be8215d17765bcbb356a +wrapdb_version = 1.6.42-1 [provide] libpng = libpng_dep From 340a0e0bb4d130a2995edbcb9cf482f2181c10c6 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 4 Feb 2024 01:24:45 +0300 Subject: [PATCH 147/167] Update libjpeg-turbo to 3.0.2. --- meson.build | 2 +- subprojects/libjpeg-turbo.wrap | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/meson.build b/meson.build index 0ea7deb28..3d2a3c524 100644 --- a/meson.build +++ b/meson.build @@ -292,7 +292,7 @@ game_deps = [zlib] jpeg = dependency('libjpeg', required: get_option('libjpeg'), - default_options: fallback_opt, + default_options: fallback_opt + [ 'jpeg-turbo=disabled', 'tests=disabled' ] ) if jpeg.found() if jpeg.type_name() == 'internal' diff --git a/subprojects/libjpeg-turbo.wrap b/subprojects/libjpeg-turbo.wrap index 024732366..77d491fc7 100644 --- a/subprojects/libjpeg-turbo.wrap +++ b/subprojects/libjpeg-turbo.wrap @@ -1,13 +1,13 @@ [wrap-file] -directory = libjpeg-turbo-2.1.5.1 -source_url = https://downloads.sourceforge.net/libjpeg-turbo/libjpeg-turbo-2.1.5.1.tar.gz -source_filename = libjpeg-turbo-2.1.5.1.tar.gz -source_hash = 2fdc3feb6e9deb17adec9bafa3321419aa19f8f4e5dea7bf8486844ca22207bf -patch_filename = libjpeg-turbo_2.1.5.1-1_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/libjpeg-turbo_2.1.5.1-1/get_patch -patch_hash = 7daf69a0795f0fe3aecf2d1bcde78266d7a60a36df8573fe3b442e0adcbb4ca0 -source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/libjpeg-turbo_2.1.5.1-1/libjpeg-turbo-2.1.5.1.tar.gz -wrapdb_version = 2.1.5.1-1 +directory = libjpeg-turbo-3.0.2 +source_url = https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/3.0.2/libjpeg-turbo-3.0.2.tar.gz +source_filename = libjpeg-turbo-3.0.2.tar.gz +source_hash = c2ce515a78d91b09023773ef2770d6b0df77d674e144de80d63e0389b3a15ca6 +patch_filename = libjpeg-turbo_3.0.2-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/libjpeg-turbo_3.0.2-1/get_patch +patch_hash = 271788065332bcb52d504edc86466dc802a705c64b825e018ed927371ac53cf1 +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/libjpeg-turbo_3.0.2-1/libjpeg-turbo-3.0.2.tar.gz +wrapdb_version = 3.0.2-1 [provide] -dependency_names = libjpeg +dependency_names = libjpeg, libturbojpeg From b0cc9f598f2cb51571395e0714c54ea052ee0175 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 4 Feb 2024 01:25:06 +0300 Subject: [PATCH 148/167] Update libcurl to 8.6.0. --- subprojects/libcurl.wrap | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/subprojects/libcurl.wrap b/subprojects/libcurl.wrap index a484de0a4..eedb518b3 100644 --- a/subprojects/libcurl.wrap +++ b/subprojects/libcurl.wrap @@ -1,11 +1,11 @@ [wrap-file] -directory = curl-8.5.0 -source_url = https://curl.se/download/curl-8.5.0.tar.xz -source_filename = curl-8.5.0.tar.xz -source_hash = 42ab8db9e20d8290a3b633e7fbb3cec15db34df65fd1015ef8ac1e4723750eeb -patch_url = https://skuller.net/meson/libcurl_8.5.0-1_patch.zip -patch_filename = libcurl_8.5.0-1_patch.zip -patch_hash = 3073ef9547660cdf73ab0f6ed672215dbe03185a158de4fcb7f32003f526fa7f +directory = curl-8.6.0 +source_url = https://curl.se/download/curl-8.6.0.tar.xz +source_filename = curl-8.6.0.tar.xz +source_hash = 3ccd55d91af9516539df80625f818c734dc6f2ecf9bada33c76765e99121db15 +patch_url = https://skuller.net/meson/libcurl_8.6.0-1_patch.zip +patch_filename = libcurl_8.6.0-1_patch.zip +patch_hash = 0bfb2990a3db9b83ed359a62c68aa25a8007853b8872480d90a040fd3736761d [provide] libcurl = libcurl_dep From a268fd40178dc162441bf0b3c54a3ee7a3f31fcc Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 4 Feb 2024 17:22:19 +0300 Subject: [PATCH 149/167] Shorten code. --- src/common/net/chan.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/common/net/chan.c b/src/common/net/chan.c index fe31417bd..ef25f947c 100644 --- a/src/common/net/chan.c +++ b/src/common/net/chan.c @@ -732,7 +732,7 @@ void Netchan_Setup(netchan_t *chan, netsrc_t sock, netchan_type_t type, byte *buf; Q_assert(chan); - Q_assert(!chan->message.data); + Q_assert(!chan->reliable_buf); Q_assert(adr); Q_assert(maxpacketlen >= MIN_PACKETLEN); Q_assert(maxpacketlen <= MAX_PACKETLEN_WRITABLE); @@ -750,17 +750,13 @@ void Netchan_Setup(netchan_t *chan, netsrc_t sock, netchan_type_t type, switch (type) { case NETCHAN_OLD: - buf = Z_TagMalloc(maxpacketlen * 2, tag); - chan->reliable_buf = buf + maxpacketlen; - - SZ_Init(&chan->message, buf, maxpacketlen); + chan->reliable_buf = buf = Z_TagMalloc(maxpacketlen * 2, tag); + SZ_Init(&chan->message, buf + maxpacketlen, maxpacketlen); break; case NETCHAN_NEW: - buf = Z_TagMalloc(MAX_MSGLEN * 4, tag); - chan->reliable_buf = buf + MAX_MSGLEN; - - SZ_Init(&chan->message, buf, MAX_MSGLEN); + chan->reliable_buf = buf = Z_TagMalloc(MAX_MSGLEN * 4, tag); + SZ_Init(&chan->message, buf + MAX_MSGLEN, MAX_MSGLEN); SZ_TagInit(&chan->fragment_in, buf + MAX_MSGLEN * 2, MAX_MSGLEN, "nc_frg_in"); SZ_TagInit(&chan->fragment_out, buf + MAX_MSGLEN * 3, MAX_MSGLEN, "nc_frg_out"); break; @@ -778,6 +774,6 @@ Netchan_Close void Netchan_Close(netchan_t *chan) { Q_assert(chan); - Z_Free(chan->message.data); + Z_Free(chan->reliable_buf); memset(chan, 0, sizeof(*chan)); } From 392c9bb59210df021713bb3ee4629b33bdfc638c Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 4 Feb 2024 19:03:02 +0300 Subject: [PATCH 150/167] Update CI workflow. --- .ci/i686-w64-mingw32.txt | 1 + .ci/x86_64-w64-mingw32.txt | 1 + .github/workflows/build.yml | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.ci/i686-w64-mingw32.txt b/.ci/i686-w64-mingw32.txt index 3fa260c56..783095616 100644 --- a/.ci/i686-w64-mingw32.txt +++ b/.ci/i686-w64-mingw32.txt @@ -4,6 +4,7 @@ cpp = 'i686-w64-mingw32-g++' ar = 'i686-w64-mingw32-ar' strip = 'i686-w64-mingw32-strip' windres = 'i686-w64-mingw32-windres' +nasm = 'nasm' [host_machine] system = 'windows' diff --git a/.ci/x86_64-w64-mingw32.txt b/.ci/x86_64-w64-mingw32.txt index 30b736e1c..c61705200 100644 --- a/.ci/x86_64-w64-mingw32.txt +++ b/.ci/x86_64-w64-mingw32.txt @@ -4,6 +4,7 @@ cpp = 'x86_64-w64-mingw32-g++' ar = 'x86_64-w64-mingw32-ar' strip = 'x86_64-w64-mingw32-strip' windres = 'x86_64-w64-mingw32-windres' +nasm = 'nasm' [host_machine] system = 'windows' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e18bcfe93..721b08df3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,6 @@ env: -Dwerror=true MESON_ARGS_WIN: >- - -Dlibpng:werror=false -Dsdl2=disabled -Dwayland=disabled -Dwrap_mode=forcefallback @@ -46,7 +45,8 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y gcc-mingw-w64 meson nasm + sudo apt-get install -y gcc-mingw-w64 nasm python3-pip ninja-build + sudo python3 -m pip install meson - name: Build run: | From d82d13a6391aef1965290e6d2564fe08d27caa89 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 4 Feb 2024 22:01:55 +0300 Subject: [PATCH 151/167] Simplify code. --- src/server/send.c | 2 +- src/server/user.c | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/server/send.c b/src/server/send.c index cb6337292..6396193be 100644 --- a/src/server/send.c +++ b/src/server/send.c @@ -1041,7 +1041,7 @@ void SV_SendAsyncPackets(void) if (netchan->message.cursize || netchan->reliable_ack_pending || netchan->reliable_length || retransmit) { - cursize = Netchan_Transmit(netchan, 0, "", 1); + cursize = Netchan_Transmit(netchan, 0, NULL, 1); SV_DPrintf(1, "%s: send: %d\n", client->name, cursize); calctime: SV_CalcSendTime(client, cursize); diff --git a/src/server/user.c b/src/server/user.c index 5d3e6f78e..629cd5a55 100644 --- a/src/server/user.c +++ b/src/server/user.c @@ -461,16 +461,14 @@ void SV_New_f(void) return; // send gamestate - if (sv_client->netchan.type == NETCHAN_NEW) { - if (sv_client->version >= PROTOCOL_VERSION_Q2PRO_EXTENDED_LIMITS) { - write_configstring_stream(); - write_baseline_stream(); - } else { - write_gamestate(); - } - } else { + if (sv_client->netchan.type == NETCHAN_OLD) { write_configstrings(); write_baselines(); + } else if (sv_client->version >= PROTOCOL_VERSION_Q2PRO_EXTENDED_LIMITS) { + write_configstring_stream(); + write_baseline_stream(); + } else { + write_gamestate(); } // send next command From a952279e4f5591b4c4b03a2a89c42656cb53c9a6 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 5 Feb 2024 00:24:54 +0300 Subject: [PATCH 152/167] Fix message overflow check. --- src/server/user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/user.c b/src/server/user.c index 629cd5a55..ee237fa12 100644 --- a/src/server/user.c +++ b/src/server/user.c @@ -174,7 +174,7 @@ static void write_configstring_stream(void) length = Q_strnlen(string, MAX_QPATH); // check if this configstring will overflow - if (msg_write.cursize + length + 4 > msg_write.maxsize) { + if (msg_write.cursize + length + 5 > msg_write.maxsize) { MSG_WriteShort(sv_client->csr->end); SV_ClientAddMessage(sv_client, MSG_GAMESTATE); MSG_WriteByte(svc_configstringstream); From 01f4496ad240a2436a807315dff55536163876b9 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 5 Feb 2024 00:29:30 +0300 Subject: [PATCH 153/167] Update comment. --- inc/common/msg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/common/msg.h b/inc/common/msg.h index ddd1396c3..899bd549b 100644 --- a/inc/common/msg.h +++ b/inc/common/msg.h @@ -21,7 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/protocol.h" #include "common/sizebuf.h" -#define MAX_PACKETENTITY_BYTES 64 // rough estimate +#define MAX_PACKETENTITY_BYTES 64 // 62 bytes worst case + margin // entity and player states are pre-quantized before sending to make delta // comparsion easier From 49b9c7ede0420f66ae941f3211875ec7d4338c8c Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Mon, 5 Feb 2024 16:06:57 +0300 Subject: [PATCH 154/167] Add link to nightly builds. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ac160e3fb..b8dfcf74e 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,9 @@ Features include: * recording from demos, forward and backward seeking * server side multiview demos and GTV capabilities -For building Q2PRO, consult the INSTALL file. +For building Q2PRO, consult the INSTALL.md file. + +Nightly Windows builds are available at https://skuller.net/q2pro/ For information on using and configuring Q2PRO, refer to client and server manuals available in doc/ subdirectory. From e5516c4a1f63d4270fb531d68dfd5f90d489ebf0 Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Tue, 6 Feb 2024 16:07:09 -0500 Subject: [PATCH 155/167] Forgot to save file --- .github/workflows/build.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 93f1c076d..34e33f209 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -60,14 +60,8 @@ jobs: - name: Install dependencies run: | sudo apt-get update -<<<<<<< HEAD - sudo apt-get install -y gcc-mingw-w64 meson nasm uuid-dev \ - libavcodec-dev libavformat-dev libavutil-dev \ - libswresample-dev libswscale-dev \ -======= sudo apt-get install -y gcc-mingw-w64 nasm python3-pip ninja-build sudo python3 -m pip install meson ->>>>>>> 49b9c7ede0420f66ae941f3211875ec7d4338c8c - name: Build run: | From 89f8b1a8fa5c30fbcee2ac9dcfc1efe536275d38 Mon Sep 17 00:00:00 2001 From: bAron Date: Sun, 21 Apr 2024 01:05:18 +0200 Subject: [PATCH 156/167] Fixed an issue in CL_PlayFootstepSfx where it always played a random step sound from all loaded step sounds in the player's sound directory. This was problematic because the default pak-file for action now contains twelve step sounds, unintentionally activating the func cl_enhanced_footsteps for everyone. This was not optimal as many players have only four original step sounds in their personal pak-files, resulting in the player having their personal step1.wav - step4.wav mixed up with step5 - step12.wav from baseaq/pak0.pkz To address this, the use of the cvar cl_enhanced_footsteps has been enforced. Now, it must be set to 1 for CL_PlayFootstepSfx to play more than the first four step#.wav sounds. --- src/client/entities.c | 40 ++++++++++++---------------------------- src/client/tent.c | 11 +++++++++-- 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/src/client/entities.c b/src/client/entities.c index eaeda5fad..3e72c4f78 100644 --- a/src/client/entities.c +++ b/src/client/entities.c @@ -224,22 +224,6 @@ static void parse_entity_event(int number) break; case EV_FOOTSTEP: if (cl_footsteps->integer) { - if (strcmp(cl_enhanced_footsteps->string, "0") == 0) { - CL_PlayFootstepSfx(-1, number, 1.0f, ATTN_NORM); - //S_StartSound(NULL, number, CHAN_BODY, cl_sfx_footsteps[Q_rand() & 3], 1, ATTN_NORM, 0); - } else { - int r = Q_rand() % 12; - if ( r == cl_laststep ) { - if ( r < 11) { - r++; //use next step if same as last time was generated - } else { - r = 0; //use first stepsound if 12 where used twice - } - } - CL_PlayFootstepSfx(-1, number, 1.0f, ATTN_NORM); - //S_StartSound(NULL, number, CHAN_BODY, cl_sfx_footsteps[r], 1, ATTN_NORM, 0); - cl_laststep = r; - } CL_PlayFootstepSfx(-1, number, 1.0f, ATTN_NORM); } break; @@ -627,9 +611,9 @@ static void CL_AddPacketEntities(void) } #if USE_AQTION - if (IS_INDICATOR(renderfx) && !cl_indicators->integer && cls.demo.playback) { - goto skip; - } + if (IS_INDICATOR(renderfx) && !cl_indicators->integer && cls.demo.playback) { + goto skip; + } #endif if ((effects & EF_GIB) && !cl_gibs->integer) goto skip; @@ -1323,7 +1307,7 @@ void CL_CalcViewValues(void) float backlerp = lerp - 1.0f; VectorMA(cl.predicted_origin, backlerp, cl.prediction_error, cl.refdef.vieworg); - LerpVector(ops->viewoffset, ps->viewoffset, lerp, viewoffset); + LerpVector(ops->viewoffset, ps->viewoffset, lerp, viewoffset); // smooth out stair climbing if (cl.predicted_step < 127 * 0.125f) { @@ -1333,16 +1317,16 @@ void CL_CalcViewValues(void) cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01f; } - if (cl_predict_crouch->integer == 2 || (cl_predict_crouch->integer && cl.view_predict)) - { + if (cl_predict_crouch->integer == 2 || (cl_predict_crouch->integer && cl.view_predict)) + { #if USE_FPS - viewoffset[2] = cl.predicted_viewheight[1]; - viewoffset[2] -= (cl.predicted_viewheight[1] - cl.predicted_viewheight[0]) * cl.keylerpfrac; + viewoffset[2] = cl.predicted_viewheight[1]; + viewoffset[2] -= (cl.predicted_viewheight[1] - cl.predicted_viewheight[0]) * cl.keylerpfrac; #else - viewoffset[2] = cl.predicted_viewheight[1]; - viewoffset[2] -= (cl.predicted_viewheight[1] - cl.predicted_viewheight[0]) * lerp; + viewoffset[2] = cl.predicted_viewheight[1]; + viewoffset[2] -= (cl.predicted_viewheight[1] - cl.predicted_viewheight[0]) * lerp; #endif - } + } } else { int i; @@ -1353,7 +1337,7 @@ void CL_CalcViewValues(void) lerp * (ps->pmove.origin[i] - ops->pmove.origin[i])); } - LerpVector(ops->viewoffset, ps->viewoffset, lerp, viewoffset); + LerpVector(ops->viewoffset, ps->viewoffset, lerp, viewoffset); } // if not running a demo or on a locked frame, add the local angle movement diff --git a/src/client/tent.c b/src/client/tent.c index 263abdeab..005652ed5 100644 --- a/src/client/tent.c +++ b/src/client/tent.c @@ -161,8 +161,15 @@ void CL_PlayFootstepSfx(int step_id, int entnum, float volume, float attenuation if (!sfx->num_sfx) return; // no footsteps, not even fallbacks - // pick a random footstep sound, but avoid playing the same one twice in a row - sfx_num = Q_rand_uniform(sfx->num_sfx); + // check if cl_enhanced_footsteps->string is "0" and sfx->num_sfx has more than four items + if (strcmp(cl_enhanced_footsteps->string, "0") == 0 && sfx->num_sfx > 4) { + // pick a random footstep sound from the first four items, important for compatibility with players using the old four stepsounds + sfx_num = Q_rand_uniform(4); + } else { + // pick a random footstep sound + sfx_num = Q_rand_uniform(sfx->num_sfx); + } + // avoid playing the same one twice in a row footstep_sfx = sfx->sfx[sfx_num]; if (footstep_sfx == cl_last_footstep) footstep_sfx = sfx->sfx[(sfx_num + 1) % sfx->num_sfx]; From accaecaf353af5c4a48770f3dd70797bf566761c Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Mon, 29 Apr 2024 10:32:53 -0400 Subject: [PATCH 157/167] Set defines for referencing OpenAL header files for MacOS --- src/client/sound/qal.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/client/sound/qal.h b/src/client/sound/qal.h index db5005182..9bb3d4e2a 100644 --- a/src/client/sound/qal.h +++ b/src/client/sound/qal.h @@ -19,9 +19,15 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once #define AL_NO_PROTOTYPES +#ifdef __APPLE__ +#include +#include +#include +#else #include #include #include +#endif #ifndef QALAPI #define QALAPI extern From 94b45ce589cada751eb8b0249595a3df594481e6 Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Mon, 29 Apr 2024 10:39:12 -0400 Subject: [PATCH 158/167] Changed PKG_CONFIG_PATH for Darwin build --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 34e33f209..bd52077c7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -258,7 +258,7 @@ jobs: meson compile -vC builddir env: CC: "gcc" - PKG_CONFIG_PATH: "/usr/local/opt/openal-soft/lib/pkgconfig" + PKG_CONFIG_PATH: "/opt/homebrew/opt/openal-soft/lib/pkgconfig" CFLAGS: "-mmacosx-version-min=10.7" - name: Set binaries as executable From e54adfeaebc669dd7ba863af84ad3b51528b73b8 Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Mon, 29 Apr 2024 10:41:21 -0400 Subject: [PATCH 159/167] Revert AL import change as a test --- src/client/sound/qal.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/client/sound/qal.h b/src/client/sound/qal.h index 9bb3d4e2a..db5005182 100644 --- a/src/client/sound/qal.h +++ b/src/client/sound/qal.h @@ -19,15 +19,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once #define AL_NO_PROTOTYPES -#ifdef __APPLE__ -#include -#include -#include -#else #include #include #include -#endif #ifndef QALAPI #define QALAPI extern From 43ac8434bca8d0bc51534f9f7bac4cdd9ff556ab Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Mon, 29 Apr 2024 11:12:01 -0400 Subject: [PATCH 160/167] Testing Mac ARM builds --- .github/workflows/build.yml | 81 ++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bd52077c7..3dbce10a7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,7 +18,7 @@ env: -Dvariable-fps=true -Dwerror=false -Daqtion-build=true - -Ddiscord-sdk=true + -Ddiscord-sdk=false MESON_ARGS_WIN: >- -Dsdl2=disabled @@ -50,9 +50,9 @@ jobs: #arch: ["i686", "x86_64"] arch: ["x86_64"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: subprojects/packagecache key: ${{ hashFiles('subprojects/*.wrap') }} @@ -85,9 +85,9 @@ jobs: #arch: ["x86", "x64"] arch: ["x64"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: subprojects/packagecache key: ${{ hashFiles('subprojects/*.wrap') }} @@ -122,7 +122,7 @@ jobs: matrix: cc: [gcc, clang] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install dependencies run: | @@ -166,7 +166,7 @@ jobs: matrix: cc: [gcc, clang] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install dependencies run: | @@ -222,7 +222,7 @@ jobs: - name: Build run: | - meson setup ${{ env.MESON_ARGS }} ${{ env.MESON_ARGS_LINUX }} builddir + meson setup ${{ env.MESON_ARGS }} ${{ env.MESON_ARGS_LINUX_X11 }} builddir meson compile -vC builddir env: CC: ${{ matrix.cc }} @@ -242,9 +242,6 @@ jobs: darwin: runs-on: macos-latest - strategy: - matrix: - arch: [x86_64] steps: - uses: actions/checkout@v2 @@ -268,39 +265,39 @@ jobs: - name: Generate Mac archives uses: actions/upload-artifact@v3 with: - name: q2pro-darwin-${{ matrix.arch }} + name: q2pro-darwin-x86_64 path: | builddir/q2pro builddir/q2proded builddir/gamex86_64.dylib - # Github does not support Apple Silicon yet - # macARM64: - # runs-on: macos-latest - # steps: - # - uses: actions/checkout@v2 - - # - name: Setup Homebrew for ARM64 and dependencies - # run: | - # arch -arm64 brew install meson libpng jpeg sdl2 openal-soft zlib curl libvorbis - - # - name: Build - # run: | - # meson setup ${{ env.MESON_ARGS }} builddir - # ninja -vC builddir - # env: - # CC: "gcc" - # PKG_CONFIG_PATH: "/opt/homebrew/Cellar/openal-soft/1.22.2/lib/pkgconfig/:/opt/homebrew/Cellar/jpeg/9e/lib/pkgconfig/" - # CFLAGS: "-target arm64-apple-macos11" - - # - name: Set binaries as executable - # run: | - # chmod +x builddir/q2pro* - - # - name: Generate Mac archives - # uses: actions/upload-artifact@v3 - # with: - # name: q2pro-mac-arm64 - # path: | - # builddir/q2pro - # builddir/q2proded + darwin-arm64: + runs-on: macos-14-arm64 + steps: + - uses: actions/checkout@v4 + + - name: Setup Homebrew for ARM64 and dependencies + run: | + brew install pkg-config meson libpng sdl2 openal-soft zlib curl ffmpeg jpeg-turbo + + - name: Build + run: | + meson setup ${{ env.MESON_ARGS }} ${{ env.MESON_ARGS_MAC }} builddir + meson compile -vC builddir + env: + CC: "gcc" + PKG_CONFIG_PATH: "/opt/homebrew/opt/openal-soft/lib/pkgconfig" + CFLAGS: "-target arm64-apple-macos11" + + - name: Set binaries as executable + run: | + chmod +x builddir/q2pro* + + - name: Generate Mac archives + uses: actions/upload-artifact@v3 + with: + name: q2pro-darwin-arm64 + path: | + builddir/q2pro + builddir/q2proded + builddir/gamex86_64.dylib From 9f5ec03b551ea8d7e1046e0e66ebb7a3744572a0 Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Mon, 29 Apr 2024 11:15:34 -0400 Subject: [PATCH 161/167] Changed tag --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3dbce10a7..5ae090b76 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -272,7 +272,7 @@ jobs: builddir/gamex86_64.dylib darwin-arm64: - runs-on: macos-14-arm64 + runs-on: macos-14 steps: - uses: actions/checkout@v4 From e86e9425345d33ebf479d9fe65f63642438fb30e Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Mon, 29 Apr 2024 11:23:21 -0400 Subject: [PATCH 162/167] macos-latest is now ARM64, trying macos-13 for Intel builds --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5ae090b76..c60cbe9c6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -241,7 +241,7 @@ jobs: builddir/gamearm.so darwin: - runs-on: macos-latest + runs-on: macos-13 steps: - uses: actions/checkout@v2 @@ -276,7 +276,7 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Setup Homebrew for ARM64 and dependencies + - name: Install dependencies run: | brew install pkg-config meson libpng sdl2 openal-soft zlib curl ffmpeg jpeg-turbo From 6b90d2fa5c9b4c8db67fd6715cc632987db5dfb5 Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Mon, 29 Apr 2024 11:26:04 -0400 Subject: [PATCH 163/167] Reverted pkgconfig path for Intel homebrew --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c60cbe9c6..9956e0ed0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -255,7 +255,7 @@ jobs: meson compile -vC builddir env: CC: "gcc" - PKG_CONFIG_PATH: "/opt/homebrew/opt/openal-soft/lib/pkgconfig" + PKG_CONFIG_PATH: "/usr/local/opt/openal-soft/lib/pkgconfig" CFLAGS: "-mmacosx-version-min=10.7" - name: Set binaries as executable From 11528cc56cea22b47817186151b7583a1a940439 Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Mon, 29 Apr 2024 11:33:02 -0400 Subject: [PATCH 164/167] Updated arm release steps --- .github/workflows/build.yml | 4 ++-- .github/workflows/release.yml | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9956e0ed0..3aadceb00 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -209,7 +209,7 @@ jobs: matrix: cc: [gcc] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 # - name: Install dependencies # run: | @@ -243,7 +243,7 @@ jobs: darwin: runs-on: macos-13 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install dependencies run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ed4e7c7a1..8d2aa93cb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -101,6 +101,13 @@ jobs: name: q2pro-darwin-x86_64 skip_unpack: true + - name: Download Darwin arm64 build artifacts + uses: dawidd6/action-download-artifact@v2 + with: + workflow: build.yml + name: q2pro-darwin-arm64 + skip_unpack: true + - name: Upload dist tarball to release uses: softprops/action-gh-release@v1 env: @@ -117,6 +124,7 @@ jobs: q2pro-lin-wayland-gcc.zip q2pro-lin-wayland-clang.zip q2pro-darwin-x86_64.zip + q2pro-darwin-arm64.zip From 3cd3f7982c65aabcf5fc597365b601a3aaaae920 Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Mon, 29 Apr 2024 11:41:57 -0400 Subject: [PATCH 165/167] Updated upload-artifact to v4 --- .github/workflows/build.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3aadceb00..b960166cb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -70,7 +70,7 @@ jobs: meson compile -vC builddir - name: Generate Win Mingw archives - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: q2pro-mingw-${{ matrix.arch }} path: | @@ -107,7 +107,7 @@ jobs: meson compile -C builddir - name: Generate Win MSVC archives - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: q2pro-msvc-${{ matrix.arch }} path: | @@ -151,7 +151,7 @@ jobs: chmod +x builddir/q2pro* - name: Generate Linux x64 archives - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: q2pro-lin-${{ matrix.cc }} path: | @@ -195,7 +195,7 @@ jobs: chmod +x builddir/q2pro* - name: Generate Linux x64 archives - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: q2pro-lin-wayland-${{ matrix.cc }} path: | @@ -232,7 +232,7 @@ jobs: chmod +x builddir/q2pro* - name: Generate Linux ARM archives - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: q2pro-lin-arm64 path: | @@ -263,7 +263,7 @@ jobs: chmod +x builddir/q2pro* - name: Generate Mac archives - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: q2pro-darwin-x86_64 path: | @@ -294,7 +294,7 @@ jobs: chmod +x builddir/q2pro* - name: Generate Mac archives - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: q2pro-darwin-arm64 path: | From 52d156282ffd394a5c5d2dcb8ca33ce1cd0b1fe9 Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Mon, 29 Apr 2024 11:42:51 -0400 Subject: [PATCH 166/167] Updated checkout and upload actions --- .github/workflows/build.yml | 4 ++-- .github/workflows/release.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b960166cb..fe628f88d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -209,7 +209,7 @@ jobs: matrix: cc: [gcc] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # - name: Install dependencies # run: | @@ -243,7 +243,7 @@ jobs: darwin: runs-on: macos-13 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install dependencies run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8d2aa93cb..60aff21af 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: actionquake/q2pro ref: ${{ github.ref }} From 8ebe6ae531f5924ede66630b3f73c38ce7457392 Mon Sep 17 00:00:00 2001 From: Aaron Dean <8dino2@gmail.com> Date: Mon, 29 Apr 2024 11:49:20 -0400 Subject: [PATCH 167/167] Updated openal for Mac users --- src/client/sound/qal.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/client/sound/qal.c b/src/client/sound/qal.c index ebe610ce4..834cfd900 100644 --- a/src/client/sound/qal.c +++ b/src/client/sound/qal.c @@ -142,6 +142,8 @@ void QAL_Shutdown(void) static const char *const al_drivers[] = { #ifdef _WIN32 "soft_oal", "openal32" +#elif defined(__APPLE__) + "libopenal.dylib.1", "libopenal.dylib" #else "libopenal.so.1", "libopenal.so" #endif