Compare commits

...

113 Commits

Author SHA1 Message Date
SNMetamorph
ec5e9cb6e3 engine: client: send engine build information to masterserver 2024-06-10 20:53:59 +03:00
Alibek Omarov
f4b4546197 engine: temporarily fix loading studio models with split texture model 2024-06-10 14:57:00 +03:00
Alibek Omarov
f047749e61 engine: move studio model truncation into separate function, disable it by default 2024-06-10 13:34:02 +03:00
Alibek Omarov
87840ce91d engine: fix potential buffer overflow in Mod_StudioTexName
* Model names are 64 bytes wide, adding texture character means we needs 65 byte wide string.
* It never gets stored in memory anyway.
2024-06-10 13:28:01 +03:00
Alibek Omarov
bf31e9f634 engine: fix NO_ASAN macro usage with MSVC 2024-06-09 09:37:16 +03:00
Alibek Omarov
f86d84daed engine: platform: sdl: initialize window name string when building with old SDL 2024-06-09 09:16:45 +03:00
Alibek Omarov
41ed920d35 common: xash3d_types: fix build 2024-06-09 09:16:07 +03:00
Alibek Omarov
df23ddb545 engine: server: fix signed integer overflow in challenge generator 2024-06-09 07:05:24 +03:00
Alibek Omarov
767556ccad engine: temporarily disable ASan in MSG_WriteUBitLong (evil!) 2024-06-09 07:03:59 +03:00
Alibek Omarov
f9dab2ad19 engine: server: rename sv_allow_upload to sv_allowupload for compatibility 2024-06-09 07:02:50 +03:00
Alibek Omarov
66cb3a6120 engine: client: add room_off variable to toggle sound effects processing for GoldSrc compatibility
* Fixes Sven-Coop 4.8 client.
* Declare dsp_off deprecated.
2024-06-09 03:51:43 +03:00
Tuldok
7672a370da engine: Crashhandler support for Windows-on-ARM (arm/arm64) 2024-06-08 21:35:55 +03:00
Alibek Omarov
870e47ed03 engine: ensure character signness when checking for nonprintable characters 2024-06-07 22:22:13 +03:00
Alibek Omarov
32d4bdb80f engine: fix UTF-8 sequence input
Fixes: 2e0fc3e4c1 ("engine: client: do not repeatedly check cl_charset value, use generic Con_UtfProcessChar")
2024-06-07 22:16:32 +03:00
Alibek Omarov
929dfd2c71 mainui: update 2024-06-03 09:04:47 +03:00
Alibek Omarov
f437af6451 mainui: update 2024-06-03 07:57:10 +03:00
Alibek Omarov
413a0fb2e5 engine: client: improve accumulating rounding error, thanks @SNMetamorph for suggestion 2024-06-02 13:09:10 +03:00
Alibek Omarov
793adadb06 mainui: update 2024-06-02 12:51:30 +03:00
Alibek Omarov
999b43b89f engine: implement changing cursor type in gameui 2024-06-02 12:24:14 +03:00
Alibek Omarov
bd60c88c7d ref: soft: fix build with OpenMP under Visual Studio 2024-06-02 11:39:54 +03:00
Alibek Omarov
23b9a2eddf waf.bat: add checks for newer pythons, remove checks for pythons below 2.7 2024-06-02 11:39:54 +03:00
Alibek Omarov
0b57d97c8c vgui_support: update submodule 2024-06-02 11:35:57 +03:00
Alibek Omarov
6255293dd4 engine: fix using OpenMP PHS generation under Visual Studio 2024-06-02 10:34:10 +03:00
Alibek Omarov
04136d95a3 filesystem: fix build warning 2024-06-02 10:33:33 +03:00
Alibek Omarov
40aa29e42a ci: remove freebsd-13-2 task 2024-06-02 10:04:04 +03:00
Alibek Omarov
a709f30da9 engine: soundlib: libmpg: add wrappers on top of libc read & lseek in case they don't match internal mpg123 types
(we better migrate to upstream libmpg at some point)
2024-06-02 09:19:17 +03:00
Alibek Omarov
0796c14e79 engine: client: fix framerate depending player move 2024-06-02 04:15:17 +03:00
Alibek Omarov
a9c0a4be23 engine: server: add cvar to disable bandwidth test on server side 2024-06-01 05:27:35 +03:00
Alibek Omarov
3e1209d3a4 engine: client: do not rely on host.downloadcount when connecting to the server with HTTP enabled
* Replace cl.downloadUrl by cl.http_download
2024-06-01 04:30:21 +03:00
Alibek Omarov
caf14c1b7c engine: soundlib: libmpg: fix the inconsistent use of offset types in lseek() 2024-05-31 03:35:39 +03:00
Alibek Omarov
27f7d2c8d2 engine: common: ban few more executable types for COM_IsSafeFileToDownload 2024-05-31 00:43:28 +03:00
Alibek Omarov
8ee430eda2 engine: common: double check that resource starting with !MD5 doesn't have any extension 2024-05-31 00:42:44 +03:00
Alibek Omarov
484e4cb225 engine: common: net_ws: less verbose HTTP client, fix printing header size in case of an error 2024-05-31 00:07:14 +03:00
Alibek Omarov
b080ad9954 engine: moved link_t helpers to sv_world.c from world.c and made them static 2024-05-30 07:31:03 +03:00
Alibek Omarov
f6625d9188 engine: common: remove unused et_name array 2024-05-30 07:22:21 +03:00
Alibek Omarov
1eb2816bc4 engine: client: manually call FS_Rescan if we downloaded an archive while connecting to server 2024-05-30 06:48:17 +03:00
Alibek Omarov
077be5aaf3 engine: client: only strip DEFAULT_SOUNDPATH from t_sound resources 2024-05-30 06:47:46 +03:00
Alibek Omarov
d59875f114 engine: common: for automatic wad precache to work, we need to count the real wad usage on dedicated 2024-05-30 06:18:15 +03:00
Alibek Omarov
e89191ed39 engine: common: automatically precache wad files required by loaded map
Makes it easier to host server with multiplayer maps and broken .res files.
2024-05-30 05:58:41 +03:00
Alibek Omarov
ea21438637 engine: netchan: append .ztmp extension instead of replacing original extension
* so we don't send wrong file that has same name but different extension

* validate filename size so it won't get truncated in fragbuf_t
2024-05-30 04:50:58 +03:00
Alibek Omarov
0d2e8333e8 common: remove unused boneinfo.h header 2024-05-29 12:25:23 +03:00
Alibek Omarov
338399e622 engine: common: implement PHS calculation like in QuakeWorld/GoldSrc 2024-05-29 05:58:51 +03:00
Alibek Omarov
27cab8aad5 scripts: waifulib: compiler_optimizations: set HAVE_OPENMP=1 define if openmp feature was enabled during the build 2024-05-29 05:41:47 +03:00
Alibek Omarov
1545a49b4c engine: client: only allocate debug hulls polygons when they're requested
* Make the appropriate changes in ref_gl
2024-05-29 05:41:47 +03:00
Alibek Omarov
3ca15250e8 engine: common: use Mod_PointInLeaf in Mod_GetPVSForPoint instead of traversing nodes manually 2024-05-29 05:41:47 +03:00
Alibek Omarov
6cbac51731 engine: common: add function for compressing visdata 2024-05-29 05:41:47 +03:00
Alibek Omarov
e310c666b1 engine: common: add phs flag to Mod_FatPVS, unused currently 2024-05-29 05:41:47 +03:00
Alibek Omarov
677b0170aa engine: server: remove recalculating viewpoint for PVS hack, as it causes issues with inconsistency between real and "restored" view positions 2024-05-29 05:41:47 +03:00
Alibek Omarov
9150b770e4 engine: common: mod_bmodel: add function Mod_DecompressVisTo that will copy fat vis data into the provided buffer 2024-05-29 05:41:47 +03:00
Alibek Omarov
2ad6511c31 public: add Q_memor routine that binary OR's data from src to dst
Supposed to be compiled with optimizations enabled.
2024-05-29 05:41:33 +03:00
Alibek Omarov
0848f28d83 waf: upgrade to latest master 2024-05-26 19:32:14 +03:00
Alibek Omarov
5d9bc950ce wscript: do not load msvc manually, it will be loaded by compiler_{c,cxx} 2024-05-25 22:40:25 +03:00
Alibek Omarov
714da79395 mainui: update 2024-05-25 22:25:33 +03:00
Alibek Omarov
823fe9ebbd waf: upgrade to waf 2.1.1/waifu 1.3.0. Try to fix most optparse->argparse migration issues 2024-05-25 04:58:28 +03:00
Alibek Omarov
4bf72b5383 engine: forbid accessing cvars starting with con_ and scr_ through stufftext
Some stupid servers might mess up with console cvars values.
2024-05-25 02:26:42 +03:00
Alibek Omarov
51945f002b engine: server: check for invoker entity when filtering out host client during entities thinking 2024-05-23 02:06:54 +03:00
Alibek Omarov
bcca9387de engine: server: sv_pmove: always set FEV_NOTHOST for events coming from PMove (like GoldSrc) 2024-05-23 01:51:42 +03:00
Alibek Omarov
b8417fa46d ref: soft: search parent in both entity lists when drawing MOVETYPE_FOLLOW entities
Fixes the issue in Brutal Half-Life beta 2 with invisible scientist skin.

Fixes: 6862b14e59 ("ref: soft: only draw MOVETYPE_FOLLOW studio model if it's parent is visible")
2024-05-19 06:31:46 +03:00
Alibek Omarov
85b0699288 ref: gl: search parent in both entity lists when drawing MOVETYPE_FOLLOW entities
Fixes the issue in Brutal Half-Life beta 2 with invisible scientist skin.

Fixes: dc1d65f621 ("ref: gl: only draw MOVETYPE_FOLLOW studio model if it's parent is visible")
2024-05-19 06:29:22 +03:00
Alibek Omarov
6c03fb0226 engine: client: first attempt to use utflib to replace Con_UtfProcessCharForce calls 2024-05-15 05:25:53 +03:00
Alibek Omarov
a084dea07c public: add functions to convert from Unicode codepoints into CP1251 or CP1252 2024-05-15 05:07:18 +03:00
Alibek Omarov
2e0fc3e4c1 engine: client: do not repeatedly check cl_charset value, use generic Con_UtfProcessChar 2024-05-15 05:06:57 +03:00
Alibek Omarov
24f4d410ce filesystem: take FS_Read improvements from DarkPlaces and proper fix for buffer overflow 2024-05-15 03:43:02 +03:00
Alibek Omarov
052e0445ab engine: client: console: cleanup input buffer from line feed characters before pushing it to the console history 2024-05-15 03:08:22 +03:00
Alibek Omarov
758c908d5a public: add buffer size parameter to COM_RemoveLineFeed 2024-05-15 03:06:57 +03:00
Alibek Omarov
3917c2589d filesystem: fix buffer overflow in FS_Read when we pass single byte buffer to it with one character sitting in ungetc 2024-05-15 02:45:01 +03:00
Alibek Omarov
f4a77308ec engine: soundlib: fix possible buffer overflow in Sound_ConvertUpsample 2024-05-06 15:45:49 +03:00
Alibek Omarov
103b9724f9 scripts: waifulib: compiler_optimizations: fix linking OpenMP 2024-05-06 15:36:26 +03:00
Alibek Omarov
75a315ecf0 engine: client: add optional (compile time for now) setting to reconfigure engine to use 48kHz sounds 2024-05-06 15:10:34 +03:00
Alibek Omarov
63b3b9ef6d engine: client: fix missing upsampling for >32kHz sounds 2024-05-06 15:09:52 +03:00
Alibek Omarov
a6c2cfe89b engine: avoid constants in Q_strncpy third argument, where possible 2024-05-06 14:27:26 +03:00
Alibek Omarov
5120657386 engine: fix possible buffer overflow in S_StreamGetCurrentState 2024-05-06 06:53:22 +03:00
Alibek Omarov
e754de46d1 engine: client: fix buffer overflow in S_FindName 2024-05-06 06:42:47 +03:00
Alibek Omarov
5d718aa0d6 scripts: waifulib: compiler_optimizations: add flag for building with OpenMP (not used anywhere in the engine but let's keep it) 2024-05-06 06:42:15 +03:00
Alibek Omarov
55fcbc8880 engine: soundlib: implement linear interpolation in Sound_ResampleInternal
* split resampling into three functions
* added resampling using SDL_AudioCVT, it's slow, so isn't enabled by default
2024-05-06 06:41:23 +03:00
Alibek Omarov
e19aa001b2 engine: client: ref_common: slight refactoring, reorder ref_state_t 2024-05-06 01:59:50 +03:00
Alibek Omarov
b447ea9c18 engine: client: remove unused fields in client_static_t 2024-05-06 01:59:14 +03:00
Alibek Omarov
13274655d4 engine: client: sound: slight refactoring, removed unused s_listener.velocity 2024-05-06 01:30:06 +03:00
Alibek Omarov
3723ac60ef engine: client: s_mix: _inline -> static 2024-05-06 00:51:32 +03:00
Alibek Omarov
da578f47f1 engine: client: fix sounds being paused in menu and then blasted all at the same time in multiplayer 2024-05-06 00:41:38 +03:00
Alibek Omarov
433e7de686 engine: clean up unused soundlib flags, set SOUND_LOOPED flag on looped sounds 2024-05-05 06:16:57 +03:00
Alibek Omarov
e18e9ae2ea engine: platform: sdl: ignore keyboard events if text mode is active 2024-05-04 11:05:17 +03:00
Alibek Omarov
27d5123a61 mainui: update 2024-05-03 16:55:17 +03:00
Alibek Omarov
89b9f9ffe2 github: update SDL to 2.30.3 2024-05-03 16:04:13 +03:00
Alibek Omarov
a17b8aaa13 public: fix parameter name omitted error for older compilers 2024-05-03 16:01:24 +03:00
Alibek Omarov
e210969612 scripts: gha: build_linux: spew config.log on build failure 2024-05-03 15:57:26 +03:00
Alibek Omarov
1208356b92 ref: gl: gl2_shim: remove unused ALLOCA_H include 2024-05-03 15:53:57 +03:00
Alibek Omarov
d7cd74fe2f wscript: no need to pass PACKAGING into env 2024-05-03 15:45:20 +03:00
Alibek Omarov
31b63e9939 wscript: exclude executing large file test for PSVita 2024-05-03 15:44:35 +03:00
Alibek Omarov
b99c2c2df1 wscript: do not execute test for test for large files 2024-05-03 15:38:35 +03:00
Alibek Omarov
94d3eff9ce engine: host: fix build with Q_strchrnul returning const char * 2024-05-03 15:31:20 +03:00
Alibek Omarov
b78e9961c6 public: fix build on Windows
stristr doesn't exist actually
2024-05-03 15:30:42 +03:00
Alibek Omarov
b0704ca5d6 mainui: update 2024-05-03 06:38:21 +03:00
Alibek Omarov
31c0934108 engine: fix parsing -bugcomp flags, assume bugcomp flags only starts with alphabetic character 2024-05-03 06:28:48 +03:00
Alibek Omarov
37083c8aef ref: soft: mark sw_drawflat and sw_draworder as cheats 2024-05-01 00:52:45 +03:00
Alibek Omarov
af23b0c67b public: crtlib: refactoring with new macros, use system strlcpy/strlcat if possible 2024-04-30 02:20:14 +03:00
Alibek Omarov
a9e83fb9cf wscript: move std defining macros into libpublic's sdk_includes target, so we don't accidentally feed submodules our macros 2024-04-29 05:29:53 +03:00
Alibek Omarov
51126e1691 mainui: update 2024-04-29 05:28:41 +03:00
Alibek Omarov
dd410a2de5 engine: implement small Message Rewrite Facitility that allows to run mods that directly write internal GoldSrc messages 2024-04-28 06:59:18 +03:00
Alibek Omarov
7ccb0b5c02 public: make simple ctype functions inlined 2024-04-28 06:59:18 +03:00
Alibek Omarov
7f3e62e456 public: remove unneeded copy in Q_atov 2024-04-28 06:59:18 +03:00
Alibek Omarov
fcfc29d7ea public: fix variables types in COM_HashKey, they are all supposed to be unsigned integers 2024-04-28 06:59:18 +03:00
Alibek Omarov
2f3429a144 engine: common: base_cmd: use flexible array to store basecmd name 2024-04-28 06:59:18 +03:00
Alibek Omarov
20782693f4 engine: server: rename symbols for svs, sv and SV_DropClient to avoid AMXModX trying to acquire their pointers 2024-04-28 06:59:18 +03:00
Alibek Omarov
0cfb354374 common: add RENAME_SYMBOL macro that renames symbol for compatibility with nasty mods (also reformat this portion, while we're at it) 2024-04-28 06:59:18 +03:00
Alibek Omarov
9be5b7c6c9 engine: physint: empty-define ALLOC_CHECK if not defined by SDK, so this header can be freely moved to another SDK 2024-04-28 06:59:18 +03:00
Alibek Omarov
e7653d2ea6 engine: soundlib: fix searching for a RIFF/WAVE chunks in streams 2024-04-27 10:51:56 +03:00
Alibek Omarov
1494887e29 engine: soundlib: snd_wav: replace strncmp by IsFourCC helper function 2024-04-26 06:29:38 +03:00
Alibek Omarov
42dab2b1a5 engine: soundlib: snd_wav: attempt to fix misleading warning about truncated file 2024-04-26 06:25:18 +03:00
Alibek Omarov
36a0c1fb17 ref: if the entity is opaque, check the renderfx too, it might become translucent 2024-04-26 04:15:21 +03:00
Alibek Omarov
60c6767337 filesystem: copy absolute path to library in FS_FindLibrary for compatibility
Extend fullPath for longer absolute paths.
2024-04-22 04:02:46 +03:00
Alibek Omarov
75451cc7fa engine: client: print correct message names in legacymode 2024-04-22 04:02:46 +03:00
Alibek Omarov
db10035d9d engine: add GoldSrc protocol definitions 2024-04-22 04:02:46 +03:00
107 changed files with 2118 additions and 1296 deletions

View File

@@ -1,15 +1,3 @@
task:
name: freebsd-13-amd64
freebsd_instance:
image_family: freebsd-13-2
setup_script:
- pkg update
- pkg install -y pkgconf git sdl2 python fontconfig opus
- git submodule update --init --recursive
test_script:
- ./scripts/cirrus/build_freebsd.sh dedicated
- ./scripts/cirrus/build_freebsd.sh full
task: task:
name: freebsd-14-amd64 name: freebsd-14-amd64
freebsd_instance: freebsd_instance:

View File

@@ -44,7 +44,7 @@ jobs:
targetos: win32 targetos: win32
targetarch: i386 targetarch: i386
env: env:
SDL_VERSION: 2.28.5 SDL_VERSION: 2.30.3
GH_CPU_ARCH: ${{ matrix.targetarch }} GH_CPU_ARCH: ${{ matrix.targetarch }}
steps: steps:
- name: Checkout - name: Checkout

View File

@@ -13,3 +13,4 @@ When `-bugcomp` is specified with argument, it interpreted as flags separated wi
| Flag | Description | Games that require this flag | | Flag | Description | Games that require this flag |
| ------- | ----------- | ---------------------------- | | ------- | ----------- | ---------------------------- |
| `peoei` | Reverts `pfnPEntityOfEntIndex` behavior to GoldSrc, where it returns NULL for last player due to incorrect player index comparison | * Counter-Strike: Condition Zero - Deleted Scenes | | `peoei` | Reverts `pfnPEntityOfEntIndex` behavior to GoldSrc, where it returns NULL for last player due to incorrect player index comparison | * Counter-Strike: Condition Zero - Deleted Scenes |
| `gsmrf` | Rewrites message at the moment when Game DLL attempts to write an internal engine message, usually specific to GoldSrc protocol. Right now only supports `svc_spawnstaticsound`, more messages added by request. | * MetaMod/AMXModX based mods |

View File

@@ -1,25 +0,0 @@
/*
boneinfo.h - structure that send delta-compressed bones across network
Copyright (C) 2018 Uncle Mike
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 3 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.
*/
#ifndef BONEINFO_H
#define BONEINFO_H
typedef struct
{
vec3_t angles;
vec3_t origin;
} boneinfo_t;
#endif//BONEINFO_H

View File

@@ -71,45 +71,47 @@ typedef uint64_t longtime_t;
#define ColorIndex( c ) ((( c ) - '0' ) & 7 ) #define ColorIndex( c ) ((( c ) - '0' ) & 7 )
#if defined( __GNUC__ ) #if defined( __GNUC__ )
#ifdef __i386__ #if defined( __i386__ )
#define EXPORT __attribute__(( visibility( "default" ), force_align_arg_pointer )) #define EXPORT __attribute__(( visibility( "default" ), force_align_arg_pointer ))
#define GAME_EXPORT __attribute(( force_align_arg_pointer )) #define GAME_EXPORT __attribute(( force_align_arg_pointer ))
#else #else
#define EXPORT __attribute__(( visibility ( "default" ))) #define EXPORT __attribute__(( visibility ( "default" )))
#define GAME_EXPORT #define GAME_EXPORT
#endif #endif
#define _format(x) __attribute__((format(printf, x, x+1)))
#define NORETURN __attribute__(( noreturn )) #define NORETURN __attribute__(( noreturn ))
#define NONNULL __attribute__(( nonnull )) #define NONNULL __attribute__(( nonnull ))
#define _format( x ) __attribute__(( format( printf, x, x + 1 )))
#define ALLOC_CHECK( x ) __attribute__(( alloc_size( x ))) #define ALLOC_CHECK( x ) __attribute__(( alloc_size( x )))
#elif defined(_MSC_VER) #define NO_ASAN __attribute__(( no_sanitize( "address" )))
#define RENAME_SYMBOL( x ) asm( x )
#else
#if defined( _MSC_VER )
#define EXPORT __declspec( dllexport ) #define EXPORT __declspec( dllexport )
#define GAME_EXPORT #define NO_ASAN __declspec( no_sanitize_address )
#define _format(x)
#define NORETURN
#define NONNULL
#define ALLOC_CHECK(x)
#else #else
#define EXPORT #define EXPORT
#define NO_ASAN
#endif
#define GAME_EXPORT #define GAME_EXPORT
#define _format(x)
#define NORETURN #define NORETURN
#define NONNULL #define NONNULL
#define _format( x )
#define ALLOC_CHECK( x ) #define ALLOC_CHECK( x )
#define RENAME_SYMBOL( x )
#endif #endif
#if ( __GNUC__ >= 3 ) #if __GNUC__ >= 3
#define unlikely( x ) __builtin_expect( x, 0 ) #define unlikely( x ) __builtin_expect( x, 0 )
#define likely( x ) __builtin_expect( x, 1 ) #define likely( x ) __builtin_expect( x, 1 )
#elif defined( __has_builtin ) #elif defined( __has_builtin )
#if __has_builtin( __builtin_expect ) #if __has_builtin( __builtin_expect ) // this must be after defined() check
#define unlikely( x ) __builtin_expect( x, 0 ) #define unlikely( x ) __builtin_expect( x, 0 )
#define likely( x ) __builtin_expect( x, 1 ) #define likely( x ) __builtin_expect( x, 1 )
#else
#define unlikely(x) (x)
#define likely(x) (x)
#endif #endif
#else #endif
#if !defined( unlikely ) || !defined( likely )
#define unlikely( x ) ( x ) #define unlikely( x ) ( x )
#define likely( x ) ( x ) #define likely( x ) ( x )
#endif #endif
@@ -128,6 +130,14 @@ typedef uint64_t longtime_t;
#define STATIC_ASSERT( x, y ) STATIC_ASSERT_2( __LINE__, x, y ) #define STATIC_ASSERT( x, y ) STATIC_ASSERT_2( __LINE__, x, y )
#endif #endif
#if !defined( __cplusplus ) && __STDC_VERSION__ >= 199101L // not C++ and C99 or newer
#define XASH_RESTRICT restrict
#elif _MSC_VER || __GNUC__ || __clang__ // compiler-specific extensions
#define XASH_RESTRICT __restrict
#else
#define XASH_RESTRICT // nothing
#endif
#ifdef XASH_BIG_ENDIAN #ifdef XASH_BIG_ENDIAN
#define LittleLong(x) (((int)(((x)&255)<<24)) + ((int)((((x)>>8)&255)<<16)) + ((int)(((x)>>16)&255)<<8) + (((x) >> 24)&255)) #define LittleLong(x) (((int)(((x)&255)<<24)) + ((int)((((x)>>8)&255)<<16)) + ((int)(((x)>>16)&255)<<8) + (((x) >> 24)&255))
#define LittleLongSW(x) (x = LittleLong(x) ) #define LittleLongSW(x) (x = LittleLong(x) )

View File

@@ -70,16 +70,17 @@ qboolean CL_CheckFile( sizebuf_t *msg, resource_t *pResource )
return true; return true;
} }
if( cl.downloadUrl[0] ) host.downloadcount++;
if( cl.http_download )
{ {
HTTP_AddDownload( filepath, pResource->nDownloadSize, true ); HTTP_AddDownload( filepath, pResource->nDownloadSize, true );
host.downloadcount++;
return false;
} }
else
{
MSG_BeginClientCmd( msg, clc_stringcmd ); MSG_BeginClientCmd( msg, clc_stringcmd );
MSG_WriteStringf( msg, "dlfile %s", filepath ); MSG_WriteStringf( msg, "dlfile %s", filepath );
host.downloadcount++; }
return false; return false;
} }

View File

@@ -50,7 +50,15 @@ const char *CL_MsgInfo( int cmd )
if( cmd >= 0 && cmd <= svc_lastmsg ) if( cmd >= 0 && cmd <= svc_lastmsg )
{ {
// get engine message name // get engine message name
Q_strncpy( sz, svc_strings[cmd], sizeof( sz )); const char *svc_string = NULL;
if( cls.legacymode )
svc_string = svc_legacy_strings[cmd];
if( !svc_string )
svc_string = svc_strings[cmd];
Q_strncpy( sz, svc_string, sizeof( sz ));
} }
else if( cmd > svc_lastmsg && cmd <= ( svc_lastmsg + MAX_USER_MESSAGES )) else if( cmd > svc_lastmsg && cmd <= ( svc_lastmsg + MAX_USER_MESSAGES ))
{ {

View File

@@ -192,7 +192,7 @@ void CL_RegisterEvent( int lastnum, const char *szEvName, pfnEventHook func )
ev = clgame.events[lastnum]; ev = clgame.events[lastnum];
// NOTE: ev->index will be set later // NOTE: ev->index will be set later
Q_strncpy( ev->name, szEvName, MAX_QPATH ); Q_strncpy( ev->name, szEvName, sizeof( ev->name ));
ev->func = func; ev->func = func;
} }

View File

@@ -1097,6 +1097,20 @@ static void GAME_EXPORT pfnCon_DefaultColor( int r, int g, int b )
Con_DefaultColor( r, g, b, true ); Con_DefaultColor( r, g, b, true );
} }
static void GAME_EXPORT pfnSetCursor( void *hCursor )
{
uintptr_t cursor;
if( !gameui.use_extended_api )
return; // ignore original Xash menus
cursor = (uintptr_t)hCursor;
if( cursor < dc_user || cursor > dc_last )
return;
Platform_SetCursorType( cursor );
}
// engine callbacks // engine callbacks
static ui_enginefuncs_t gEngfuncs = static ui_enginefuncs_t gEngfuncs =
{ {
@@ -1176,7 +1190,7 @@ static ui_enginefuncs_t gEngfuncs =
pfnHostEndGame, pfnHostEndGame,
COM_RandomFloat, COM_RandomFloat,
COM_RandomLong, COM_RandomLong,
IN_SetCursor, pfnSetCursor,
pfnIsMapValid, pfnIsMapValid,
GL_ProcessTexture, GL_ProcessTexture,
COM_CompareFileTime, COM_CompareFileTime,
@@ -1286,7 +1300,7 @@ qboolean UI_LoadProgs( void )
} }
gameui.use_text_api = false; gameui.use_extended_api = false;
// make local copy of engfuncs to prevent overwrite it with user dll // make local copy of engfuncs to prevent overwrite it with user dll
memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs )); memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs ));
@@ -1313,7 +1327,7 @@ qboolean UI_LoadProgs( void )
if( GetExtAPI( MENU_EXTENDED_API_VERSION, &gameui.dllFuncs2, &gpExtendedfuncs ) ) if( GetExtAPI( MENU_EXTENDED_API_VERSION, &gameui.dllFuncs2, &gpExtendedfuncs ) )
{ {
Con_Reportf( "UI_LoadProgs: extended Menu API initialized\n" ); Con_Reportf( "UI_LoadProgs: extended Menu API initialized\n" );
gameui.use_text_api = true; gameui.use_extended_api = true;
} }
} }
else // otherwise, fallback to old and deprecated extensions else // otherwise, fallback to old and deprecated extensions
@@ -1325,7 +1339,7 @@ qboolean UI_LoadProgs( void )
if( GiveTextApi( &gpExtendedfuncs ) ) // they are binary compatible, so we can just pass extended funcs API to menu if( GiveTextApi( &gpExtendedfuncs ) ) // they are binary compatible, so we can just pass extended funcs API to menu
{ {
Con_Reportf( "UI_LoadProgs: extended text API initialized\n" ); Con_Reportf( "UI_LoadProgs: extended text API initialized\n" );
gameui.use_text_api = true; gameui.use_extended_api = true;
} }
} }

View File

@@ -589,8 +589,9 @@ static void CL_CreateCmd( void )
{ {
usercmd_t nullcmd, *cmd; usercmd_t nullcmd, *cmd;
runcmd_t *pcmd; runcmd_t *pcmd;
vec3_t angles;
qboolean active; qboolean active;
double accurate_ms;
vec3_t angles;
int input_override; int input_override;
int i, ms; int i, ms;
@@ -599,9 +600,25 @@ static void CL_CreateCmd( void )
// store viewangles in case it's will be freeze // store viewangles in case it's will be freeze
VectorCopy( cl.viewangles, angles ); VectorCopy( cl.viewangles, angles );
ms = bound( 1, host.frametime * 1000, 255 );
input_override = 0; input_override = 0;
// fix rounding error and framerate depending player move
accurate_ms = host.frametime * 1000;
ms = (int)accurate_ms;
cl.frametime_remainder += accurate_ms - ms; // accumulate rounding error each frame
// add a ms if error accumulates enough
if( cl.frametime_remainder >= 1.0 )
{
int ms2 = (int)cl.frametime_remainder;
ms += ms2;
cl.frametime_remainder -= ms2;
}
// ms can't be negative, rely on error accumulation only if FPS > 1000
ms = Q_min( ms, 255 );
CL_SetSolidEntities(); CL_SetSolidEntities();
CL_PushPMStates(); CL_PushPMStates();
CL_SetSolidPlayers( cl.playernum ); CL_SetSolidPlayers( cl.playernum );
@@ -1618,8 +1635,16 @@ static size_t NONNULL CL_BuildMasterServerScanRequest( char *buf, size_t size, u
#ifndef XASH_ALL_SERVERS #ifndef XASH_ALL_SERVERS
Info_SetValueForKey( info, "gamedir", GI->gamefolder, remaining ); Info_SetValueForKey( info, "gamedir", GI->gamefolder, remaining );
#endif #endif
Info_SetValueForKey( info, "clver", XASH_VERSION, remaining ); // let master know about client version // let master know about client version
Info_SetValueForKey( info, "clver", XASH_VERSION, remaining );
Info_SetValueForKey( info, "nat", nat ? "1" : "0", remaining ); Info_SetValueForKey( info, "nat", nat ? "1" : "0", remaining );
Info_SetValueForKey( info, "commit", Q_buildcommit(), remaining );
Info_SetValueForKey( info, "branch", Q_buildbranch(), remaining );
Info_SetValueForKey( info, "os", Q_buildos(), remaining );
Info_SetValueForKey( info, "arch", Q_buildarch(), remaining );
Q_snprintf( temp, sizeof( temp ), "%d", Q_buildnum() );
Info_SetValueForKey( info, "buildnum", temp, remaining );
Q_snprintf( temp, sizeof( temp ), "%x", *key ); Q_snprintf( temp, sizeof( temp ), "%x", *key );
Info_SetValueForKey( info, "key", temp, remaining ); Info_SetValueForKey( info, "key", temp, remaining );
@@ -2510,11 +2535,6 @@ void CL_ProcessFile( qboolean successfully_received, const char *filename )
return; return;
} }
pfilename = filename;
if( !Q_strnicmp( filename, DEFAULT_SOUNDPATH, sound_len ))
pfilename += sound_len;
for( p = cl.resourcesneeded.pNext; p != &cl.resourcesneeded; p = p->pNext ) for( p = cl.resourcesneeded.pNext; p != &cl.resourcesneeded; p = p->pNext )
{ {
if( !Q_strnicmp( filename, "!MD5", 4 )) if( !Q_strnicmp( filename, "!MD5", 4 ))
@@ -2524,18 +2544,20 @@ void CL_ProcessFile( qboolean successfully_received, const char *filename )
if( !memcmp( p->rgucMD5_hash, rgucMD5_hash, 16 )) if( !memcmp( p->rgucMD5_hash, rgucMD5_hash, 16 ))
break; break;
} }
else else if( p->type == t_sound )
{
if( p->type == t_generic )
{
if( !Q_stricmp( p->szFileName, filename ))
break;
}
else
{ {
const char *pfilename = filename;
if( !Q_strnicmp( filename, DEFAULT_SOUNDPATH, sound_len ))
pfilename += sound_len;
if( !Q_stricmp( p->szFileName, pfilename )) if( !Q_stricmp( p->szFileName, pfilename ))
break; break;
} }
else
{
if( !Q_stricmp( p->szFileName, filename ))
break;
} }
} }
@@ -2600,7 +2622,7 @@ void CL_ProcessFile( qboolean successfully_received, const char *filename )
if( cls.netchan.tempbuffer ) if( cls.netchan.tempbuffer )
{ {
Con_Printf( "Received a decal %s, but didn't find it in resources needed list!\n", pfilename ); Con_Printf( "Received a decal %s, but didn't find it in resources needed list!\n", filename );
Mem_Free( cls.netchan.tempbuffer ); Mem_Free( cls.netchan.tempbuffer );
} }
@@ -2693,10 +2715,32 @@ static void CL_Physinfo_f( void )
Con_Printf( "Total %i symbols\n", Q_strlen( cls.physinfo )); Con_Printf( "Total %i symbols\n", Q_strlen( cls.physinfo ));
} }
static qboolean CL_ShouldRescanFilesystem( void )
{
resource_t *res;
for( res = cl.resourcesonhand.pNext; res && res != &cl.resourcesonhand; res = res->pNext )
{
if( res->type == t_generic )
{
const char *ext = COM_FileExtension( res->szFileName );
// TODO: query supported archives format from fs_stdio
// TODO: query if was already opened
if( !Q_stricmp( ext, "wad" ) || !Q_stricmp( ext, "pk3" ) || !Q_stricmp( ext, "pak" ))
return true;
}
}
return false;
}
qboolean CL_PrecacheResources( void ) qboolean CL_PrecacheResources( void )
{ {
resource_t *pRes; resource_t *pRes;
// if we downloaded new WAD files or any other archives they must be added to searchpath
if( CL_ShouldRescanFilesystem( ))
g_fsapi.Rescan();
// NOTE: world need to be loaded as first model // NOTE: world need to be loaded as first model
for( pRes = cl.resourcesonhand.pNext; pRes && pRes != &cl.resourcesonhand; pRes = pRes->pNext ) for( pRes = cl.resourcesonhand.pNext; pRes && pRes != &cl.resourcesonhand; pRes = pRes->pNext )
{ {

View File

@@ -458,6 +458,7 @@ void CL_BatchResourceRequest( qboolean initialize )
byte data[MAX_INIT_MSG]; byte data[MAX_INIT_MSG];
resource_t *p, *n; resource_t *p, *n;
sizebuf_t msg; sizebuf_t msg;
qboolean done_downloading = true;
MSG_Init( &msg, "Resource Batch", data, sizeof( data )); MSG_Init( &msg, "Resource Batch", data, sizeof( data ));
@@ -487,7 +488,10 @@ void CL_BatchResourceRequest( qboolean initialize )
case t_model: case t_model:
case t_eventscript: case t_eventscript:
if( !CL_CheckFile( &msg, p )) if( !CL_CheckFile( &msg, p ))
{
done_downloading = false;
break; break;
}
CL_MoveToOnHandList( p ); CL_MoveToOnHandList( p );
break; break;
case t_skin: case t_skin:
@@ -501,6 +505,7 @@ void CL_BatchResourceRequest( qboolean initialize )
MSG_BeginClientCmd( &msg, clc_stringcmd ); MSG_BeginClientCmd( &msg, clc_stringcmd );
MSG_WriteStringf( &msg, "dlfile !MD5%s", MD5_Print( p->rgucMD5_hash ));; MSG_WriteStringf( &msg, "dlfile !MD5%s", MD5_Print( p->rgucMD5_hash ));;
SetBits( p->ucFlags, RES_REQUESTED ); SetBits( p->ucFlags, RES_REQUESTED );
done_downloading = false;
} }
break; break;
} }
@@ -525,11 +530,7 @@ void CL_BatchResourceRequest( qboolean initialize )
if( cls.state != ca_disconnected ) if( cls.state != ca_disconnected )
{ {
if( !cl.downloadUrl[0] && !MSG_GetNumBytesWritten( &msg ) && CL_PrecacheResources( )) if( done_downloading && CL_PrecacheResources( ))
{
CL_RegisterResources( &msg );
}
if( cl.downloadUrl[0] && host.downloadcount == 0 && CL_PrecacheResources( ) )
{ {
CL_RegisterResources( &msg ); CL_RegisterResources( &msg );
} }
@@ -1843,10 +1844,7 @@ void CL_ParseResLocation( sizebuf_t *msg )
while(( data = COM_ParseFile( data, token, sizeof( token )))) while(( data = COM_ParseFile( data, token, sizeof( token ))))
{ {
Con_Reportf( "Adding %s as download location\n", token ); Con_Reportf( "Adding %s as download location\n", token );
cl.http_download = true;
if( !cl.downloadUrl[0] )
Q_strncpy( cl.downloadUrl, token, sizeof( token ) );
HTTP_AddCustomServer( token ); HTTP_AddCustomServer( token );
} }
} }
@@ -1877,8 +1875,12 @@ void CL_ParseHLTV( sizebuf_t *msg )
break; break;
case HLTV_LISTEN: case HLTV_LISTEN:
cls.signon = SIGNONS; cls.signon = SIGNONS;
#if 1
MSG_ReadString( msg );
#else
NET_StringToAdr( MSG_ReadString( msg ), &cls.hltv_listen_address ); NET_StringToAdr( MSG_ReadString( msg ), &cls.hltv_listen_address );
// NET_JoinGroup( cls.netchan.sock, cls.hltv_listen_address ); NET_JoinGroup( cls.netchan.sock, cls.hltv_listen_address );
#endif
SCR_EndLoadingPlaque(); SCR_EndLoadingPlaque();
break; break;
default: default:

View File

@@ -194,7 +194,7 @@ static void CL_LegacyPrecacheModel( sizebuf_t *msg )
if( modelIndex < 0 || modelIndex >= MAX_MODELS ) if( modelIndex < 0 || modelIndex >= MAX_MODELS )
Host_Error( "CL_PrecacheModel: bad modelindex %i\n", modelIndex ); Host_Error( "CL_PrecacheModel: bad modelindex %i\n", modelIndex );
Q_strncpy( model, MSG_ReadString( msg ), MAX_STRING ); Q_strncpy( model, MSG_ReadString( msg ), sizeof( model ));
//Q_strncpy( cl.model_precache[modelIndex], BF_ReadString( msg ), sizeof( cl.model_precache[0] )); //Q_strncpy( cl.model_precache[modelIndex], BF_ReadString( msg ), sizeof( cl.model_precache[0] ));
// when we loading map all resources is precached sequentially // when we loading map all resources is precached sequentially
@@ -261,7 +261,7 @@ static void CL_LegacyParseResourceList( sizebuf_t *msg )
for( i = 0; i < reslist.rescount; i++ ) for( i = 0; i < reslist.rescount; i++ )
{ {
reslist.restype[i] = MSG_ReadWord( msg ); reslist.restype[i] = MSG_ReadWord( msg );
Q_strncpy( reslist.resnames[i], MSG_ReadString( msg ), MAX_QPATH ); Q_strncpy( reslist.resnames[i], MSG_ReadString( msg ), sizeof( reslist.resnames[i] ));
} }
if( CL_IsPlaybackDemo() ) if( CL_IsPlaybackDemo() )

View File

@@ -853,7 +853,7 @@ static void CL_SetupPMove( playermove_t *pmove, const local_state_t *from, const
VectorCopy( cd->vuser4, pmove->vuser4 ); VectorCopy( cd->vuser4, pmove->vuser4 );
pmove->cmd = *ucmd; // copy current cmds pmove->cmd = *ucmd; // copy current cmds
Q_strncpy( pmove->physinfo, cls.physinfo, MAX_INFO_STRING ); Q_strncpy( pmove->physinfo, cls.physinfo, sizeof( pmove->physinfo ));
} }
static const void CL_FinishPMove( const playermove_t *pmove, local_state_t *to ) static const void CL_FinishPMove( const playermove_t *pmove, local_state_t *to )

View File

@@ -211,7 +211,7 @@ static void CL_ParseQuakeServerInfo( sizebuf_t *msg )
clgame.maxEntities = GI->max_edicts; clgame.maxEntities = GI->max_edicts;
clgame.maxEntities = bound( 600, clgame.maxEntities, MAX_EDICTS ); clgame.maxEntities = bound( 600, clgame.maxEntities, MAX_EDICTS );
clgame.maxModels = MAX_MODELS; clgame.maxModels = MAX_MODELS;
Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), MAX_STRING ); Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), sizeof( clgame.maptitle ));
// Re-init hud video, especially if we changed game directories // Re-init hud video, especially if we changed game directories
clgame.dllFuncs.pfnVidInit(); clgame.dllFuncs.pfnVidInit();

View File

@@ -20,7 +20,7 @@ GNU General Public License for more details.
int R_FatPVS( const vec3_t org, float radius, byte *visbuffer, qboolean merge, qboolean fullvis ) int R_FatPVS( const vec3_t org, float radius, byte *visbuffer, qboolean merge, qboolean fullvis )
{ {
return Mod_FatPVS( org, radius, visbuffer, world.visbytes, merge, fullvis ); return Mod_FatPVS( org, radius, visbuffer, world.visbytes, merge, fullvis, false );
} }
lightstyle_t *CL_GetLightStyle( int number ) lightstyle_t *CL_GetLightStyle( int number )

View File

@@ -229,7 +229,7 @@ typedef struct
char serverinfo[MAX_SERVERINFO_STRING]; char serverinfo[MAX_SERVERINFO_STRING];
player_info_t players[MAX_CLIENTS]; // collected info about all other players include himself player_info_t players[MAX_CLIENTS]; // collected info about all other players include himself
double lastresourcecheck; double lastresourcecheck;
string downloadUrl; qboolean http_download;
event_state_t events; event_state_t events;
// predicting stuff but not only... // predicting stuff but not only...
@@ -276,6 +276,8 @@ typedef struct
model_t *worldmodel; // pointer to world model_t *worldmodel; // pointer to world
int lostpackets; // count lost packets and show dialog in menu int lostpackets; // count lost packets and show dialog in menu
double frametime_remainder;
} client_t; } client_t;
/* /*
@@ -518,7 +520,7 @@ typedef struct
int logo_yres; int logo_yres;
float logo_length; float logo_length;
qboolean use_text_api; qboolean use_extended_api;
} gameui_static_t; } gameui_static_t;
typedef struct typedef struct
@@ -539,12 +541,8 @@ typedef struct
poolhandle_t mempool; // client premamnent pool: edicts etc poolhandle_t mempool; // client premamnent pool: edicts etc
netadr_t hltv_listen_address;
int signon; // 0 to SIGNONS, for the signon sequence. int signon; // 0 to SIGNONS, for the signon sequence.
int quakePort; // a 16 bit value that allows quake servers
// to work around address translating routers
// g-cont. this port allow many copies of engine in multiplayer game
// connection information // connection information
char servername[MAX_QPATH]; // name of server from original connect char servername[MAX_QPATH]; // name of server from original connect
double connect_time; // for connection retransmits double connect_time; // for connection retransmits
@@ -634,6 +632,9 @@ typedef struct
int extensions; int extensions;
netadr_t serveradr; netadr_t serveradr;
// do we accept utf8 as input
qboolean accept_utf8;
} client_static_t; } client_static_t;
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -21,6 +21,7 @@ GNU General Public License for more details.
#include "qfont.h" #include "qfont.h"
#include "wadfile.h" #include "wadfile.h"
#include "input.h" #include "input.h"
#include "utflib.h"
static CVAR_DEFINE_AUTO( scr_conspeed, "600", FCVAR_ARCHIVE, "console moving speed" ); static CVAR_DEFINE_AUTO( scr_conspeed, "600", FCVAR_ARCHIVE, "console moving speed" );
static CVAR_DEFINE_AUTO( con_notifytime, "3", FCVAR_ARCHIVE, "notify time to live" ); static CVAR_DEFINE_AUTO( con_notifytime, "3", FCVAR_ARCHIVE, "notify time to live" );
@@ -34,7 +35,6 @@ static CVAR_DEFINE_AUTO( scr_drawversion, "1", FCVAR_ARCHIVE, "draw version in m
static CVAR_DEFINE_AUTO( con_oldfont, "0", 0, "use legacy font from gfx.wad, might be missing or broken" ); static CVAR_DEFINE_AUTO( con_oldfont, "0", 0, "use legacy font from gfx.wad, might be missing or broken" );
static int g_codepage = 0; static int g_codepage = 0;
static qboolean g_utf8 = false;
static qboolean g_messagemode_privileged = true; static qboolean g_messagemode_privileged = true;
@@ -610,19 +610,6 @@ static void Con_LoadConchars( void )
con.curFont = &con.chars[fontSize]; con.curFont = &con.chars[fontSize];
} }
// CP1251 table
int table_cp1251[64] = {
0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
0x007F, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457
};
/* /*
============================ ============================
Con_UtfProcessChar Con_UtfProcessChar
@@ -632,84 +619,28 @@ Convert utf char to current font's single-byte encoding
*/ */
int Con_UtfProcessCharForce( int in ) int Con_UtfProcessCharForce( int in )
{ {
static int m = -1, k = 0; //multibyte state // TODO: get rid of global state where possible
static int uc = 0; //unicode char static utfstate_t state = { 0 };
if( !in ) int ch = Q_DecodeUTF8( &state, in );
{
m = -1;
k = 0;
uc = 0;
return 0;
}
// Get character length
if(m == -1)
{
uc = 0;
if( in >= 0xF8 )
return 0;
else if( in >= 0xF0 )
uc = in & 0x07, m = 3;
else if( in >= 0xE0 )
uc = in & 0x0F, m = 2;
else if( in >= 0xC0 )
uc = in & 0x1F, m = 1;
else if( in <= 0x7F)
return in; //ascii
// return 0 if we need more chars to decode one
k=0;
return 0;
}
// get more chars
else if( k <= m )
{
uc <<= 6;
uc += in & 0x3F;
k++;
}
if( in > 0xBF || m < 0 )
{
m = -1;
return 0;
}
if( k == m )
{
k = m = -1;
if( g_codepage == 1251 ) if( g_codepage == 1251 )
{ return Q_UnicodeToCP1251( ch );
// cp1251 now if( g_codepage == 1252 )
if( uc >= 0x0410 && uc <= 0x042F ) return Q_UnicodeToCP1252( ch );
return uc - 0x410 + 0xC0;
if( uc >= 0x0430 && uc <= 0x044F )
return uc - 0x430 + 0xE0;
else
{
int i;
for( i = 0; i < 64; i++ )
if( table_cp1251[i] == uc )
return i + 0x80;
}
}
else if( g_codepage == 1252 )
{
if( uc < 255 )
return uc;
}
// not implemented yet return '?'; // not implemented yet
return '?';
}
return 0;
} }
int GAME_EXPORT Con_UtfProcessChar( int in ) int GAME_EXPORT Con_UtfProcessChar( int in )
{ {
if( !g_utf8 ) if( !cls.accept_utf8 ) // incoming character is not a UTF-8 sequence
return in; return in;
else
// otherwise, decode it and convert to selected codepage
return Con_UtfProcessCharForce( in ); return Con_UtfProcessCharForce( in );
} }
/* /*
================= =================
Con_UtfMoveLeft Con_UtfMoveLeft
@@ -719,16 +650,22 @@ get position of previous printful char
*/ */
int Con_UtfMoveLeft( char *str, int pos ) int Con_UtfMoveLeft( char *str, int pos )
{ {
int i, k = 0; utfstate_t state = { 0 };
// int j; int k = 0;
if( !g_utf8 ) int i;
if( !cls.accept_utf8 ) // incoming character is not a UTF-8 sequence
return pos - 1; return pos - 1;
Con_UtfProcessChar( 0 );
if(pos == 1) return 0; if( pos == 1 )
return 0;
for( i = 0; i < pos - 1; i++ ) for( i = 0; i < pos - 1; i++ )
if( Con_UtfProcessChar( (unsigned char)str[i] ) ) {
if( Q_DecodeUTF8( &state, (byte)str[i] ))
k = i + 1; k = i + 1;
Con_UtfProcessChar( 0 ); }
return k; return k;
} }
@@ -741,16 +678,18 @@ get next of previous printful char
*/ */
int Con_UtfMoveRight( char *str, int pos, int length ) int Con_UtfMoveRight( char *str, int pos, int length )
{ {
utfstate_t state = { 0 };
int i; int i;
if( !g_utf8 )
if( !cls.accept_utf8 ) // incoming character is not a UTF-8 sequence
return pos + 1; return pos + 1;
Con_UtfProcessChar( 0 );
for( i = pos; i <= length; i++ ) for( i = pos; i <= length; i++ )
{ {
if( Con_UtfProcessChar( (unsigned char)str[i] ) ) if( Q_DecodeUTF8( &state, (byte)str[i] ))
return i + 1; return i + 1;
} }
Con_UtfProcessChar( 0 );
return pos + 1; return pos + 1;
} }
@@ -1138,7 +1077,7 @@ Field_Set
static void Field_Set( field_t *f, const char *string ) static void Field_Set( field_t *f, const char *string )
{ {
f->scroll = 0; f->scroll = 0;
f->cursor = Q_strncpy( f->buffer, string, MAX_STRING ); f->cursor = Q_strncpy( f->buffer, string, sizeof( f->buffer ));
} }
/* /*
@@ -1549,6 +1488,9 @@ void Key_Console( int key )
Con_Printf( ">%s\n", con.input.buffer ); Con_Printf( ">%s\n", con.input.buffer );
// copy line to history buffer // copy line to history buffer
// just in case, remove all CR and LF characters pushing it to the history
// not sure how they get even added in the first place
COM_RemoveLineFeed( con.input.buffer, sizeof( con.input.buffer ));
Con_HistoryAppend( &con.history, &con.input ); Con_HistoryAppend( &con.history, &con.input );
Con_ClearField( &con.input ); Con_ClearField( &con.input );
@@ -2157,7 +2099,7 @@ void Con_RunConsole( void )
g_codepage = 1252; g_codepage = 1252;
} }
g_utf8 = !Q_stricmp( cl_charset.string, "utf-8" ); cls.accept_utf8 = !Q_stricmp( cl_charset.string, "utf-8" );
Con_InvalidateFonts(); Con_InvalidateFonts();
Con_LoadConchars(); Con_LoadConchars();
ClearBits( con_charset.flags, FCVAR_CHANGED ); ClearBits( con_charset.flags, FCVAR_CHANGED );

View File

@@ -17,6 +17,7 @@ GNU General Public License for more details.
#include "input.h" #include "input.h"
#include "client.h" #include "client.h"
#include "vgui_draw.h" #include "vgui_draw.h"
#include "cursor_type.h"
#if XASH_SDL #if XASH_SDL
#include <SDL.h> #include <SDL.h>
@@ -123,11 +124,6 @@ static void IN_StartupMouse( void )
in_mouseinitialized = true; in_mouseinitialized = true;
} }
void GAME_EXPORT IN_SetCursor( void *hCursor )
{
// stub
}
/* /*
=========== ===========
IN_MouseSavePos IN_MouseSavePos

View File

@@ -40,7 +40,6 @@ void IN_DeactivateMouse( void );
void IN_MouseSavePos( void ); void IN_MouseSavePos( void );
void IN_MouseRestorePos( void ); void IN_MouseRestorePos( void );
void IN_ToggleClientMouse( int newstate, int oldstate ); void IN_ToggleClientMouse( int newstate, int oldstate );
void IN_SetCursor( void *hCursor );
uint IN_CollectInputDevices( void ); uint IN_CollectInputDevices( void );
void IN_LockInputDevices( qboolean lock ); void IN_LockInputDevices( qboolean lock );

View File

@@ -553,7 +553,7 @@ static void Key_AddKeyCommands( int key, const char *kb, qboolean down )
} }
buttonPtr = button; buttonPtr = button;
while(( kb[i] <= ' ' || kb[i] == ';' ) && kb[i] != 0 ) while((((byte)kb[i]) <= ' ' || kb[i] == ';' ) && kb[i] != 0 )
i++; i++;
} }
@@ -749,10 +749,10 @@ void GAME_EXPORT Key_Event( int key, int down )
if( cls.key_dest == key_menu ) if( cls.key_dest == key_menu )
{ {
// only non printable keys passed // only non printable keys passed
if( !gameui.use_text_api ) if( !gameui.use_extended_api )
Key_EnableTextInput( true, false ); Key_EnableTextInput( true, false );
//pass printable chars for old menus //pass printable chars for old menus
if( !gameui.use_text_api && !host.textmode && down && ( key >= 32 ) && ( key <= 'z' ) ) if( !gameui.use_extended_api && !host.textmode && down && ( key >= 32 ) && ( key <= 'z' ) )
{ {
if( Key_IsDown( K_SHIFT ) ) if( Key_IsDown( K_SHIFT ) )
{ {
@@ -1055,18 +1055,16 @@ static qboolean OSK_KeyEvent( int key, int down )
break; break;
} }
if( !Q_stricmp( cl_charset.string, "utf-8" ) ) ch = (byte)osk.curbutton.val;
ch = (unsigned char)osk.curbutton.val;
else // do not pass UTF-8 sequence into the engine, convert it here
ch = Con_UtfProcessCharForce( (unsigned char)osk.curbutton.val ); if( !cls.accept_utf8 )
ch = Con_UtfProcessCharForce( ch );
if( !ch ) if( !ch )
break; break;
Con_CharEvent( ch ); CL_CharEvent( ch );
if( cls.key_dest == key_menu )
UI_CharEvent ( ch );
break; break;
} }
} }
@@ -1121,7 +1119,6 @@ static void OSK_EnableTextInput( qboolean enable, qboolean force )
{ {
osk.curlayout = 0; osk.curlayout = 0;
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x]; osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
} }
} }

View File

@@ -685,6 +685,9 @@ void Mod_CreatePolygonsForHull( int hullnum )
if( hullnum < 1 || hullnum > 3 ) if( hullnum < 1 || hullnum > 3 )
return; return;
if( !world.num_hull_models )
Mod_InitDebugHulls( mod ); // FIXME: build hulls for separate bmodels (shells, medkits etc)
Con_Printf( "generating polygons for hull %u...\n", hullnum ); Con_Printf( "generating polygons for hull %u...\n", hullnum );
start = Sys_DoubleTime(); start = Sys_DoubleTime();

View File

@@ -22,13 +22,12 @@ GNU General Public License for more details.
struct ref_state_s struct ref_state_s
{ {
qboolean initialized;
HINSTANCE hInstance; HINSTANCE hInstance;
qboolean initialized;
int numRenderers;
ref_interface_t dllFuncs; ref_interface_t dllFuncs;
// depends on build configuration // depends on build configuration
int numRenderers;
const char **shortNames; const char **shortNames;
const char **readableNames; const char **readableNames;
}; };

View File

@@ -154,7 +154,8 @@ static const sx_preset_t rgsxpre_hlalpha052[] =
static const sx_preset_t *ptable = rgsxpre; static const sx_preset_t *ptable = rgsxpre;
// cvars // cvars
static CVAR_DEFINE_AUTO( dsp_off, "0", FCVAR_ARCHIVE, "disable DSP processing" ); static CVAR_DEFINE_AUTO( dsp_off, "0", FCVAR_ARCHIVE, "disable DSP processing (deprecated)" );
static CVAR_DEFINE_AUTO( room_off, "0", FCVAR_ARCHIVE, "disable DSP processing (GoldSrc compatible cvar)" );
static CVAR_DEFINE_AUTO( dsp_coeff_table, "0", FCVAR_ARCHIVE, "select DSP coefficient table: 0 for release or 1 for alpha 0.52" ); static CVAR_DEFINE_AUTO( dsp_coeff_table, "0", FCVAR_ARCHIVE, "select DSP coefficient table: 0 for release or 1 for alpha 0.52" );
static CVAR_DEFINE_AUTO( room_type, "0", 0, "current room type preset" ); static CVAR_DEFINE_AUTO( room_type, "0", 0, "current room type preset" );
@@ -232,6 +233,7 @@ void SX_Init( void )
sxmod2cur = sxmod2 = 450 * ( idsp_dma_speed / SOUND_11k ); sxmod2cur = sxmod2 = 450 * ( idsp_dma_speed / SOUND_11k );
Cvar_RegisterVariable( &dsp_off ); Cvar_RegisterVariable( &dsp_off );
Cvar_RegisterVariable( &room_off );
Cvar_RegisterVariable( &dsp_coeff_table ); Cvar_RegisterVariable( &dsp_coeff_table );
Cvar_RegisterVariable( &roomwater_type ); Cvar_RegisterVariable( &roomwater_type );
@@ -809,7 +811,7 @@ DSP_Process
*/ */
void DSP_Process( portable_samplepair_t *pbfront, int sampleCount ) void DSP_Process( portable_samplepair_t *pbfront, int sampleCount )
{ {
if( dsp_off.value || !sampleCount ) if( dsp_off.value || room_off.value || !sampleCount )
return; return;
// preset is already installed by CheckNewDspPresets // preset is already installed by CheckNewDspPresets
@@ -843,7 +845,7 @@ CheckNewDspPresets
*/ */
void CheckNewDspPresets( void ) void CheckNewDspPresets( void )
{ {
if( dsp_off.value != 0.0f ) if( dsp_off.value || room_off.value )
return; return;
if( FBitSet( dsp_coeff_table.flags, FCVAR_CHANGED )) if( FBitSet( dsp_coeff_table.flags, FCVAR_CHANGED ))

View File

@@ -52,8 +52,11 @@ void S_SoundList_f( void )
{ {
totalSize += sc->size; totalSize += sc->size;
if( sc->loopStart >= 0 ) Con_Printf( "L" ); if( FBitSet( sc->flags, SOUND_LOOPED ))
else Con_Printf( " " ); Con_Printf( "L" );
else
Con_Printf( " " );
if( sfx->name[0] == '*' || !Q_strncmp( sfx->name, DEFAULT_SOUNDPATH, sizeof( DEFAULT_SOUNDPATH ) - 1 )) if( sfx->name[0] == '*' || !Q_strncmp( sfx->name, DEFAULT_SOUNDPATH, sizeof( DEFAULT_SOUNDPATH ) - 1 ))
Con_Printf( " (%2db) %s : %s\n", sc->width * 8, Q_memprint( sc->size ), sfx->name ); Con_Printf( " (%2db) %s : %s\n", sc->width * 8, Q_memprint( sc->size ), sfx->name );
else Con_Printf( " (%2db) %s : " DEFAULT_SOUNDPATH "%s\n", sc->width * 8, Q_memprint( sc->size ), sfx->name ); else Con_Printf( " (%2db) %s : " DEFAULT_SOUNDPATH "%s\n", sc->width * 8, Q_memprint( sc->size ), sfx->name );
@@ -110,7 +113,7 @@ static wavdata_t *S_CreateDefaultSound( void )
sc->width = 2; sc->width = 2;
sc->channels = 1; sc->channels = 1;
sc->loopStart = -1; sc->loopStart = 0;
sc->rate = SOUND_DMA_SPEED; sc->rate = SOUND_DMA_SPEED;
sc->samples = SOUND_DMA_SPEED; sc->samples = SOUND_DMA_SPEED;
sc->size = sc->samples * sc->width * sc->channels; sc->size = sc->samples * sc->width * sc->channels;
@@ -155,7 +158,7 @@ wavdata_t *S_LoadSound( sfx_t *sfx )
Sound_Process( &sc, SOUND_11k, sc->width, SOUND_RESAMPLE ); Sound_Process( &sc, SOUND_11k, sc->width, SOUND_RESAMPLE );
else if( sc->rate > SOUND_11k && sc->rate < SOUND_22k ) // some bad sounds else if( sc->rate > SOUND_11k && sc->rate < SOUND_22k ) // some bad sounds
Sound_Process( &sc, SOUND_22k, sc->width, SOUND_RESAMPLE ); Sound_Process( &sc, SOUND_22k, sc->width, SOUND_RESAMPLE );
else if( sc->rate > SOUND_22k && sc->rate <= SOUND_32k ) // some bad sounds else if( sc->rate > SOUND_22k && sc->rate < SOUND_44k ) // some bad sounds
Sound_Process( &sc, SOUND_44k, sc->width, SOUND_RESAMPLE ); Sound_Process( &sc, SOUND_44k, sc->width, SOUND_RESAMPLE );
sfx->cache = sc; sfx->cache = sc;
@@ -218,7 +221,7 @@ sfx_t *S_FindName( const char *pname, int *pfInCache )
sfx = &s_knownSfx[i]; sfx = &s_knownSfx[i];
memset( sfx, 0, sizeof( *sfx )); memset( sfx, 0, sizeof( *sfx ));
if( pfInCache ) *pfInCache = false; if( pfInCache ) *pfInCache = false;
Q_strncpy( sfx->name, name, MAX_STRING ); Q_strncpy( sfx->name, name, sizeof( sfx->name ));
sfx->servercount = cl.servercount; sfx->servercount = cl.servercount;
sfx->hashValue = COM_HashKey( sfx->name, MAX_SFX_HASH ); sfx->hashValue = COM_HashKey( sfx->name, MAX_SFX_HASH );
@@ -377,7 +380,7 @@ S_InitSounds
void S_InitSounds( void ) void S_InitSounds( void )
{ {
// create unused 0-entry // create unused 0-entry
Q_strncpy( s_knownSfx->name, "*default", MAX_QPATH ); Q_strncpy( s_knownSfx->name, "*default", sizeof( s_knownSfx->name ));
s_knownSfx->hashValue = COM_HashKey( s_knownSfx->name, MAX_SFX_HASH ); s_knownSfx->hashValue = COM_HashKey( s_knownSfx->name, MAX_SFX_HASH );
s_knownSfx->hashNext = s_sfxHashList[s_knownSfx->hashValue]; s_knownSfx->hashNext = s_sfxHashList[s_knownSfx->hashValue];
s_sfxHashList[s_knownSfx->hashValue] = s_knownSfx; s_sfxHashList[s_knownSfx->hashValue] = s_knownSfx;

View File

@@ -70,6 +70,12 @@ float S_GetMasterVolume( void )
return 0.0f; return 0.0f;
} }
if( s_listener.inmenu && !ui_renderworld.value && !Host_IsLocalGame( ))
{
// mute sounds in menu when it's not transparent and we're in multiplayer
return 0.0f;
}
if( !s_listener.inmenu && soundfade.percent != 0 ) if( !s_listener.inmenu && soundfade.percent != 0 )
{ {
scale = bound( 0.0f, soundfade.percent / 100.0f, 1.0f ); scale = bound( 0.0f, soundfade.percent / 100.0f, 1.0f );
@@ -328,7 +334,7 @@ channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx, qboolean
// don't restart looping sounds for the same entity // don't restart looping sounds for the same entity
wavdata_t *sc = channels[first_to_die].sfx->cache; wavdata_t *sc = channels[first_to_die].sfx->cache;
if( sc && sc->loopStart != -1 ) if( sc && FBitSet( sc->flags, SOUND_LOOPED ))
{ {
channel_t *ch = &channels[first_to_die]; channel_t *ch = &channels[first_to_die];
@@ -503,7 +509,7 @@ static void SND_Spatialize( channel_t *ch )
pSource = ch->sfx->cache; pSource = ch->sfx->cache;
if( ch->use_loop && pSource && pSource->loopStart != -1 ) if( ch->use_loop && pSource && FBitSet( pSource->flags, SOUND_LOOPED ))
looping = true; looping = true;
if( !ch->staticsound ) if( !ch->staticsound )
@@ -641,7 +647,7 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv
if( !target_chan->leftvol && !target_chan->rightvol ) if( !target_chan->leftvol && !target_chan->rightvol )
{ {
// looping sounds don't use this optimization because they should stick around until they're killed. // looping sounds don't use this optimization because they should stick around until they're killed.
if( !sfx->cache || sfx->cache->loopStart == -1 ) if( !sfx->cache || !FBitSet( sfx->cache->flags, SOUND_LOOPED ))
{ {
// if this is a streaming sound, play the whole thing. // if this is a streaming sound, play the whole thing.
if( chan != CHAN_STREAM ) if( chan != CHAN_STREAM )
@@ -893,7 +899,7 @@ int S_GetCurrentStaticSounds( soundlist_t *pout, int size )
VectorCopy( channels[i].origin, pout->origin ); VectorCopy( channels[i].origin, pout->origin );
pout->volume = (float)channels[i].master_vol / 255.0f; pout->volume = (float)channels[i].master_vol / 255.0f;
pout->attenuation = channels[i].dist_mult * SND_CLIP_DISTANCE; pout->attenuation = channels[i].dist_mult * SND_CLIP_DISTANCE;
pout->looping = ( channels[i].use_loop && channels[i].sfx->cache->loopStart != -1 ); pout->looping = ( channels[i].use_loop && FBitSet( channels[i].sfx->cache->flags, SOUND_LOOPED ));
pout->pitch = channels[i].basePitch; pout->pitch = channels[i].basePitch;
pout->channel = channels[i].entchannel; pout->channel = channels[i].entchannel;
pout->wordIndex = channels[i].wordIndex; pout->wordIndex = channels[i].wordIndex;
@@ -928,7 +934,7 @@ int S_GetCurrentDynamicSounds( soundlist_t *pout, int size )
if( !channels[i].sfx || !channels[i].sfx->name[0] || !Q_stricmp( channels[i].sfx->name, "*default" )) if( !channels[i].sfx || !channels[i].sfx->name[0] || !Q_stricmp( channels[i].sfx->name, "*default" ))
continue; // don't serialize default sounds continue; // don't serialize default sounds
looped = ( channels[i].use_loop && channels[i].sfx->cache->loopStart != -1 ); looped = ( channels[i].use_loop && FBitSet( channels[i].sfx->cache->flags, SOUND_LOOPED ));
if( channels[i].entchannel == CHAN_STATIC && looped && !Host_IsQuakeCompatible()) if( channels[i].entchannel == CHAN_STATIC && looped && !Host_IsQuakeCompatible())
continue; // never serialize static looped sounds. It will be restoring in game code continue; // never serialize static looped sounds. It will be restoring in game code
@@ -1599,7 +1605,6 @@ void SND_UpdateSound( void )
// release raw-channels that no longer used more than 10 secs // release raw-channels that no longer used more than 10 secs
S_FreeIdleRawChannels(); S_FreeIdleRawChannels();
VectorCopy( cl.simvel, s_listener.velocity );
s_listener.frametime = (cl.time - cl.oldtime); s_listener.frametime = (cl.time - cl.oldtime);
s_listener.waterlevel = cl.local.waterlevel; s_listener.waterlevel = cl.local.waterlevel;
s_listener.active = CL_IsInGame(); s_listener.active = CL_IsInGame();

View File

@@ -17,13 +17,20 @@ GNU General Public License for more details.
#include "sound.h" #include "sound.h"
#include "client.h" #include "client.h"
#define IPAINTBUFFER 0 enum
#define IROOMBUFFER 1 {
#define ISTREAMBUFFER 2 IPAINTBUFFER = 0,
IROOMBUFFER,
ISTREAMBUFFER,
CPAINTBUFFERS,
};
#define FILTERTYPE_NONE 0 enum
#define FILTERTYPE_LINEAR 1 {
#define FILTERTYPE_CUBIC 2 FILTERTYPE_NONE = 0,
FILTERTYPE_LINEAR,
FILTERTYPE_CUBIC,
};
#define CCHANVOLUMES 2 #define CCHANVOLUMES 2
@@ -31,16 +38,35 @@ GNU General Public License for more details.
#define SND_SCALE_SHIFT ( 8 - SND_SCALE_BITS ) #define SND_SCALE_SHIFT ( 8 - SND_SCALE_BITS )
#define SND_SCALE_LEVELS ( 1 << SND_SCALE_BITS ) #define SND_SCALE_LEVELS ( 1 << SND_SCALE_BITS )
portable_samplepair_t *g_curpaintbuffer; // sound mixing buffer
portable_samplepair_t streambuffer[(PAINTBUFFER_SIZE+1)]; #define CPAINTFILTERMEM 3
portable_samplepair_t paintbuffer[(PAINTBUFFER_SIZE+1)]; #define CPAINTFILTERS 4 // maximum number of consecutive upsample passes per paintbuffer
portable_samplepair_t roombuffer[(PAINTBUFFER_SIZE+1)];
portable_samplepair_t facingbuffer[(PAINTBUFFER_SIZE+1)];
portable_samplepair_t temppaintbuffer[(PAINTBUFFER_SIZE+1)];
paintbuffer_t paintbuffers[CPAINTBUFFERS];
int snd_scaletable[SND_SCALE_LEVELS][256]; // fixed point stuff for real-time resampling
#define FIX_BITS 28
#define FIX_SCALE ( 1 << FIX_BITS )
#define FIX_MASK (( 1 << FIX_BITS ) - 1 )
#define FIX_FLOAT( a ) ((int)(( a ) * FIX_SCALE ))
#define FIX( a ) (((int)( a )) << FIX_BITS )
#define FIX_INTPART( a ) (((int)( a )) >> FIX_BITS )
#define FIX_FRACPART( a ) (( a ) & FIX_MASK )
typedef struct
{
qboolean factive; // if true, mix to this paintbuffer using flags
portable_samplepair_t *pbuf; // front stereo mix buffer, for 2 or 4 channel mixing
int ifilter; // current filter memory buffer to use for upsampling pass
portable_samplepair_t fltmem[CPAINTFILTERS][CPAINTFILTERMEM];
} paintbuffer_t;
static portable_samplepair_t *g_curpaintbuffer;
static portable_samplepair_t streambuffer[(PAINTBUFFER_SIZE+1)];
static portable_samplepair_t paintbuffer[(PAINTBUFFER_SIZE+1)];
static portable_samplepair_t roombuffer[(PAINTBUFFER_SIZE+1)];
static portable_samplepair_t temppaintbuffer[(PAINTBUFFER_SIZE+1)];
static paintbuffer_t paintbuffers[CPAINTBUFFERS];
static int snd_scaletable[SND_SCALE_LEVELS][256];
void S_InitScaletable( void ) void S_InitScaletable( void )
{ {
int i, j; int i, j;
@@ -67,7 +93,7 @@ static void S_TransferPaintBuffer( int endtime )
dword *pbuf; dword *pbuf;
pbuf = (dword *)dma.buffer; pbuf = (dword *)dma.buffer;
snd_p = (int *)PAINTBUFFER; snd_p = (int *)g_curpaintbuffer;
lpaintedtime = paintedtime; lpaintedtime = paintedtime;
sampleMask = ((dma.samples >> 1) - 1); sampleMask = ((dma.samples >> 1) - 1);
@@ -111,20 +137,20 @@ static void S_TransferPaintBuffer( int endtime )
//=============================================================================== //===============================================================================
// Activate a paintbuffer. All active paintbuffers are mixed in parallel within // Activate a paintbuffer. All active paintbuffers are mixed in parallel within
// MIX_MixChannelsToPaintbuffer, according to flags // MIX_MixChannelsToPaintbuffer, according to flags
_inline void MIX_ActivatePaintbuffer( int ipaintbuffer ) static void MIX_ActivatePaintbuffer( int ipaintbuffer )
{ {
Assert( ipaintbuffer < CPAINTBUFFERS ); Assert( ipaintbuffer < CPAINTBUFFERS );
paintbuffers[ipaintbuffer].factive = true; paintbuffers[ipaintbuffer].factive = true;
} }
_inline void MIX_SetCurrentPaintbuffer( int ipaintbuffer ) static void MIX_SetCurrentPaintbuffer( int ipaintbuffer )
{ {
Assert( ipaintbuffer < CPAINTBUFFERS ); Assert( ipaintbuffer < CPAINTBUFFERS );
g_curpaintbuffer = paintbuffers[ipaintbuffer].pbuf; g_curpaintbuffer = paintbuffers[ipaintbuffer].pbuf;
Assert( g_curpaintbuffer != NULL ); Assert( g_curpaintbuffer != NULL );
} }
_inline int MIX_GetCurrentPaintbufferIndex( void ) static int MIX_GetCurrentPaintbufferIndex( void )
{ {
int i; int i;
@@ -136,7 +162,7 @@ _inline int MIX_GetCurrentPaintbufferIndex( void )
return 0; return 0;
} }
_inline paintbuffer_t *MIX_GetCurrentPaintbufferPtr( void ) static paintbuffer_t *MIX_GetCurrentPaintbufferPtr( void )
{ {
int ipaint = MIX_GetCurrentPaintbufferIndex(); int ipaint = MIX_GetCurrentPaintbufferIndex();
@@ -145,7 +171,7 @@ _inline paintbuffer_t *MIX_GetCurrentPaintbufferPtr( void )
} }
// Don't mix into any paintbuffers // Don't mix into any paintbuffers
_inline void MIX_DeactivateAllPaintbuffers( void ) static void MIX_DeactivateAllPaintbuffers( void )
{ {
int i; int i;
@@ -154,7 +180,7 @@ _inline void MIX_DeactivateAllPaintbuffers( void )
} }
// set upsampling filter indexes back to 0 // set upsampling filter indexes back to 0
_inline void MIX_ResetPaintbufferFilterCounters( void ) static void MIX_ResetPaintbufferFilterCounters( void )
{ {
int i; int i;
@@ -163,13 +189,13 @@ _inline void MIX_ResetPaintbufferFilterCounters( void )
} }
// return pointer to front paintbuffer pbuf, given index // return pointer to front paintbuffer pbuf, given index
_inline portable_samplepair_t *MIX_GetPFrontFromIPaint( int ipaintbuffer ) static portable_samplepair_t *MIX_GetPFrontFromIPaint( int ipaintbuffer )
{ {
Assert( ipaintbuffer < CPAINTBUFFERS ); Assert( ipaintbuffer < CPAINTBUFFERS );
return paintbuffers[ipaintbuffer].pbuf; return paintbuffers[ipaintbuffer].pbuf;
} }
_inline paintbuffer_t *MIX_GetPPaintFromIPaint( int ipaint ) static paintbuffer_t *MIX_GetPPaintFromIPaint( int ipaint )
{ {
Assert( ipaint < CPAINTBUFFERS ); Assert( ipaint < CPAINTBUFFERS );
return &paintbuffers[ipaint]; return &paintbuffers[ipaint];
@@ -523,6 +549,7 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
wavdata_t *pSource; wavdata_t *pSource;
int i, sampleCount; int i, sampleCount;
qboolean bZeroVolume; qboolean bZeroVolume;
qboolean local = Host_IsLocalGame();
// mix each channel into paintbuffer // mix each channel into paintbuffer
ch = channels; ch = channels;
@@ -549,7 +576,7 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
{ {
// play, playvol // play, playvol
} }
else if(( s_listener.inmenu || s_listener.paused ) && !ch->localsound ) else if(( s_listener.inmenu || s_listener.paused ) && !ch->localsound && local )
{ {
// play only local sounds, keep pause for other // play only local sounds, keep pause for other
continue; continue;
@@ -567,6 +594,7 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
// Don't mix sound data for sounds with zero volume. If it's a non-looping sound, // Don't mix sound data for sounds with zero volume. If it's a non-looping sound,
// just remove the sound when its volume goes to zero. // just remove the sound when its volume goes to zero.
bZeroVolume = !ch->leftvol && !ch->rightvol; bZeroVolume = !ch->leftvol && !ch->rightvol;
if( !bZeroVolume ) if( !bZeroVolume )
@@ -576,7 +604,7 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
bZeroVolume = true; bZeroVolume = true;
} }
if( !pSource || ( bZeroVolume && pSource->loopStart == -1 )) if( !pSource || ( bZeroVolume && !FBitSet( pSource->flags, SOUND_LOOPED )))
{ {
if( !pSource ) if( !pSource )
{ {
@@ -629,7 +657,7 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
} }
// pass in index -1...count+2, return pointer to source sample in either paintbuffer or delay buffer // pass in index -1...count+2, return pointer to source sample in either paintbuffer or delay buffer
_inline portable_samplepair_t *S_GetNextpFilter( int i, portable_samplepair_t *pbuffer, portable_samplepair_t *pfiltermem ) static portable_samplepair_t *S_GetNextpFilter( int i, portable_samplepair_t *pbuffer, portable_samplepair_t *pfiltermem )
{ {
// The delay buffer is assumed to precede the paintbuffer by 6 duplicated samples // The delay buffer is assumed to precede the paintbuffer by 6 duplicated samples
if( i == -1 ) return (&(pfiltermem[0])); if( i == -1 ) return (&(pfiltermem[0]));
@@ -838,6 +866,14 @@ static void MIX_MixPaintbuffers( int ibuf1, int ibuf2, int ibuf3, int count, flo
pbuf2 = paintbuffers[ibuf2].pbuf; pbuf2 = paintbuffers[ibuf2].pbuf;
pbuf3 = paintbuffers[ibuf3].pbuf; pbuf3 = paintbuffers[ibuf3].pbuf;
if( !gain )
{
// do not mix buf2 into buf3, just copy
if( pbuf1 != pbuf3 )
memcpy( pbuf3, pbuf1, sizeof( *pbuf1 ) * count );
return;
}
// destination buffer stereo - average n chans down to stereo // destination buffer stereo - average n chans down to stereo
// destination 2ch: // destination 2ch:

View File

@@ -142,7 +142,7 @@ S_StreamGetCurrentState
save\restore code save\restore code
================= =================
*/ */
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position ) qboolean S_StreamGetCurrentState( char *currentTrack, size_t currentTrackSize, char *loopTrack, size_t loopTrackSize, int *position )
{ {
if( !s_bgTrack.stream ) if( !s_bgTrack.stream )
return false; // not active return false; // not active
@@ -150,15 +150,15 @@ qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *posi
if( currentTrack ) if( currentTrack )
{ {
if( s_bgTrack.current[0] ) if( s_bgTrack.current[0] )
Q_strncpy( currentTrack, s_bgTrack.current, MAX_STRING ); Q_strncpy( currentTrack, s_bgTrack.current, currentTrackSize );
else Q_strncpy( currentTrack, "*", MAX_STRING ); // no track else Q_strncpy( currentTrack, "*", currentTrackSize ); // no track
} }
if( loopTrack ) if( loopTrack )
{ {
if( s_bgTrack.loopName[0] ) if( s_bgTrack.loopName[0] )
Q_strncpy( loopTrack, s_bgTrack.loopName, MAX_STRING ); Q_strncpy( loopTrack, s_bgTrack.loopName, loopTrackSize );
else Q_strncpy( loopTrack, "*", MAX_STRING ); // no track else Q_strncpy( loopTrack, "*", loopTrackSize ); // no track
} }
if( position ) if( position )

View File

@@ -27,7 +27,7 @@ int S_ConvertLoopedPosition( wavdata_t *pSource, int samplePosition, qboolean us
// convert to a position within the loop // convert to a position within the loop
// At the end of the loop, we return a short buffer, and subsequent call // At the end of the loop, we return a short buffer, and subsequent call
// will loop back and get the rest of the buffer // will loop back and get the rest of the buffer
if( pSource->loopStart >= 0 && samplePosition >= pSource->samples && use_loop ) if( FBitSet( pSource->flags, SOUND_LOOPED ) && samplePosition >= pSource->samples && use_loop )
{ {
// size of loop // size of loop
int loopSize = pSource->samples - pSource->loopStart; int loopSize = pSource->samples - pSource->loopStart;

View File

@@ -20,57 +20,37 @@ extern poolhandle_t sndpool;
#include "xash3d_mathlib.h" #include "xash3d_mathlib.h"
// sound engine rate defines #define XASH_AUDIO_CD_QUALITY 1 // some platforms might need this
#define SOUND_DMA_SPEED 44100 // hardware playback rate
#define SOUND_11k 11025 // 11khz sample rate
#define SOUND_16k 16000 // 16khz sample rate
#define SOUND_22k 22050 // 22khz sample rate
#define SOUND_32k 32000 // 32khz sample rate
#define SOUND_44k 44100 // 44khz sample rate
#define DMA_MSEC_PER_SAMPLE ((float)(1000.0 / SOUND_DMA_SPEED))
// fixed point stuff for real-time resampling // sound engine rate defines
#define FIX_BITS 28 #if XASH_AUDIO_CD_QUALITY
#define FIX_SCALE (1 << FIX_BITS) #define SOUND_11k 11025 // 11khz sample rate
#define FIX_MASK ((1 << FIX_BITS)-1) #define SOUND_22k 22050 // 22khz sample rate
#define FIX_FLOAT(a) ((int)((a) * FIX_SCALE)) #define SOUND_44k 44100 // 44khz sample rate
#define FIX(a) (((int)(a)) << FIX_BITS) #else // XASH_AUDIO_CD_QUALITY
#define FIX_INTPART(a) (((int)(a)) >> FIX_BITS) #define SOUND_11k 12000 // 11khz sample rate
#define FIX_FRACTION(a,b) (FIX(a)/(b)) #define SOUND_22k 24000 // 22khz sample rate
#define FIX_FRACPART(a) ((a) & FIX_MASK) #define SOUND_44k 48000 // 44khz sample rate
#endif // XASH_AUDIO_CD_QUALITY
#define SOUND_DMA_SPEED SOUND_44k // hardware playback rate
// NOTE: clipped sound at 32760 to avoid overload // NOTE: clipped sound at 32760 to avoid overload
#define CLIP( x ) (( x ) > 32760 ? 32760 : (( x ) < -32760 ? -32760 : ( x ))) #define CLIP( x ) (( x ) > 32760 ? 32760 : (( x ) < -32760 ? -32760 : ( x )))
#define PAINTBUFFER_SIZE 1024 // 44k: was 512 #define PAINTBUFFER_SIZE 1024 // 44k: was 512
#define PAINTBUFFER (g_curpaintbuffer)
#define CPAINTBUFFERS 3
// sound mixing buffer
#define CPAINTFILTERMEM 3
#define CPAINTFILTERS 4 // maximum number of consecutive upsample passes per paintbuffer
#define S_RAW_SOUND_IDLE_SEC 10 // time interval for idling raw sound before it's freed #define S_RAW_SOUND_IDLE_SEC 10 // time interval for idling raw sound before it's freed
#define S_RAW_SOUND_BACKGROUNDTRACK -2 #define S_RAW_SOUND_BACKGROUNDTRACK -2
#define S_RAW_SOUND_SOUNDTRACK -1 #define S_RAW_SOUND_SOUNDTRACK -1
#define S_RAW_SAMPLES_PRECISION_BITS 14 #define S_RAW_SAMPLES_PRECISION_BITS 14
#define CIN_FRAMETIME (1.0f / 30.0f)
typedef struct typedef struct
{ {
int left; int left;
int right; int right;
} portable_samplepair_t; } portable_samplepair_t;
typedef struct
{
qboolean factive; // if true, mix to this paintbuffer using flags
portable_samplepair_t *pbuf; // front stereo mix buffer, for 2 or 4 channel mixing
int ifilter; // current filter memory buffer to use for upsampling pass
portable_samplepair_t fltmem[CPAINTFILTERS][CPAINTFILTERMEM];
} paintbuffer_t;
typedef struct sfx_s typedef struct sfx_s
{ {
char name[MAX_QPATH]; char name[MAX_QPATH];
@@ -81,12 +61,6 @@ typedef struct sfx_s
struct sfx_s *hashNext; struct sfx_s *hashNext;
} sfx_t; } sfx_t;
extern portable_samplepair_t paintbuffer[];
extern portable_samplepair_t roombuffer[];
extern portable_samplepair_t temppaintbuffer[];
extern portable_samplepair_t *g_curpaintbuffer;
extern paintbuffer_t paintbuffers[];
// structure used for fading in and out client sound volume. // structure used for fading in and out client sound volume.
typedef struct typedef struct
{ {
@@ -105,9 +79,9 @@ typedef struct
typedef struct snd_format_s typedef struct snd_format_s
{ {
unsigned int speed; uint speed;
unsigned int width; byte width;
unsigned int channels; byte channels;
} snd_format_t; } snd_format_t;
typedef struct typedef struct
@@ -115,8 +89,8 @@ typedef struct
snd_format_t format; snd_format_t format;
int samples; // mono samples in buffer int samples; // mono samples in buffer
int samplepos; // in mono samples int samplepos; // in mono samples
byte *buffer;
qboolean initialized; // sound engine is active qboolean initialized; // sound engine is active
byte *buffer;
const char *backendName; const char *backendName;
} dma_t; } dma_t;
@@ -125,7 +99,6 @@ typedef struct
typedef struct typedef struct
{ {
double sample; double sample;
wavdata_t *pData; wavdata_t *pData;
double forcedEndSample; double forcedEndSample;
qboolean finished; qboolean finished;
@@ -140,15 +113,15 @@ typedef struct rawchan_s
float dist_mult; // distance multiplier (attenuation/clipK) float dist_mult; // distance multiplier (attenuation/clipK)
vec3_t origin; // only use if fixed_origin is set vec3_t origin; // only use if fixed_origin is set
volatile uint s_rawend; volatile uint s_rawend;
wavdata_t sound_info; // advance play position
float oldtime; // catch time jumps float oldtime; // catch time jumps
wavdata_t sound_info; // advance play position
size_t max_samples; // buffer length size_t max_samples; // buffer length
portable_samplepair_t rawsamples[1]; // variable sized portable_samplepair_t rawsamples[1]; // variable sized
} rawchan_t; } rawchan_t;
typedef struct channel_s typedef struct channel_s
{ {
char name[16]; // keept sentence name char name[16]; // keep sentence name
sfx_t *sfx; // sfx number sfx_t *sfx; // sfx number
int leftvol; // 0-255 left volume int leftvol; // 0-255 left volume
@@ -159,7 +132,6 @@ typedef struct channel_s
vec3_t origin; // only use if fixed_origin is set vec3_t origin; // only use if fixed_origin is set
float dist_mult; // distance multiplier (attenuation/clipK) float dist_mult; // distance multiplier (attenuation/clipK)
int master_vol; // 0-255 master volume int master_vol; // 0-255 master volume
qboolean isSentence; // bit who indicated sentence
int basePitch; // base pitch percent (100% is normal pitch playback) int basePitch; // base pitch percent (100% is normal pitch playback)
float pitch; // real-time pitch after any modulation or shift by dynamic data float pitch; // real-time pitch after any modulation or shift by dynamic data
qboolean use_loop; // don't loop default and local sounds qboolean use_loop; // don't loop default and local sounds
@@ -168,6 +140,7 @@ typedef struct channel_s
mixer_t pMixer; mixer_t pMixer;
// sentence mixer // sentence mixer
qboolean isSentence; // bit indicating sentence
int wordIndex; int wordIndex;
mixer_t *currentWord; // NULL if sentence is finished mixer_t *currentWord; // NULL if sentence is finished
voxword_t words[CVOXWORDMAX]; voxword_t words[CVOXWORDMAX];
@@ -176,7 +149,6 @@ typedef struct channel_s
typedef struct typedef struct
{ {
vec3_t origin; // simorg + view_ofs vec3_t origin; // simorg + view_ofs
vec3_t velocity;
vec3_t forward; vec3_t forward;
vec3_t right; vec3_t right;
vec3_t up; vec3_t up;
@@ -219,7 +191,7 @@ extern dma_t dma;
extern convar_t s_musicvolume; extern convar_t s_musicvolume;
extern convar_t s_lerping; extern convar_t s_lerping;
extern convar_t s_test; // cvar to testify new effects extern convar_t s_test; // cvar to test new effects
extern convar_t s_samplecount; extern convar_t s_samplecount;
extern convar_t s_warn_late_precache; extern convar_t s_warn_late_precache;
@@ -292,7 +264,6 @@ void SND_ForceCloseMouth( int entnum );
// //
void S_StreamSoundTrack( void ); void S_StreamSoundTrack( void );
void S_StreamBackgroundTrack( void ); void S_StreamBackgroundTrack( void );
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position );
void S_PrintBackgroundTrackState( void ); void S_PrintBackgroundTrackState( void );
void S_FadeMusicVolume( float fadePercent ); void S_FadeMusicVolume( float fadePercent );

View File

@@ -31,7 +31,7 @@ typedef struct OpusCustomMode OpusCustomMode;
#define VOICE_PCM_CHANNELS 1 // always mono #define VOICE_PCM_CHANNELS 1 // always mono
// never change these parameters when using opuscustom // never change these parameters when using opuscustom
#define VOICE_OPUS_CUSTOM_SAMPLERATE SOUND_44k #define VOICE_OPUS_CUSTOM_SAMPLERATE 44100
// must follow opus custom requirements // must follow opus custom requirements
// also be divisible with MAX_RAW_SAMPLES // also be divisible with MAX_RAW_SAMPLES
#define VOICE_OPUS_CUSTOM_FRAME_SIZE 1024 #define VOICE_OPUS_CUSTOM_FRAME_SIZE 1024

View File

@@ -17,7 +17,6 @@ GNU General Public License for more details.
#define VOX_H #define VOX_H
#define CVOXWORDMAX 64 #define CVOXWORDMAX 64
#define SENTENCE_INDEX -99999 // unique sentence index #define SENTENCE_INDEX -99999 // unique sentence index
typedef struct voxword_s typedef struct voxword_s

View File

@@ -19,13 +19,15 @@ GNU General Public License for more details.
#define HASH_SIZE 128 // 128 * 4 * 4 == 2048 bytes #define HASH_SIZE 128 // 128 * 4 * 4 == 2048 bytes
typedef struct base_command_hashmap_s typedef struct base_command_hashmap_s base_command_hashmap_t;
struct base_command_hashmap_s
{ {
base_command_t *basecmd; // base command: cvar, alias or command base_command_t *basecmd; // base command: cvar, alias or command
const char *name; // key for searching base_command_hashmap_t *next;
base_command_type_e type; // type for faster searching base_command_type_e type; // type for faster searching
struct base_command_hashmap_s *next; char name[1]; // key for searching
} base_command_hashmap_t; };
static base_command_hashmap_t *hashed_cmds[HASH_SIZE]; static base_command_hashmap_t *hashed_cmds[HASH_SIZE];
@@ -124,11 +126,12 @@ void BaseCmd_Insert( base_command_type_e type, base_command_t *basecmd, const ch
{ {
base_command_hashmap_t *elem, *cur, *find; base_command_hashmap_t *elem, *cur, *find;
uint hash = BaseCmd_HashKey( name ); uint hash = BaseCmd_HashKey( name );
size_t len = Q_strlen( name );
elem = Z_Malloc( sizeof( base_command_hashmap_t ) ); elem = Z_Malloc( sizeof( base_command_hashmap_t ) + len );
elem->basecmd = basecmd; elem->basecmd = basecmd;
elem->type = type; elem->type = type;
elem->name = name; Q_strncpy( elem->name, name, len + 1 );
// link the variable in alphanumerical order // link the variable in alphanumerical order
for( cur = NULL, find = hashed_cmds[hash]; for( cur = NULL, find = hashed_cmds[hash];

View File

@@ -31,8 +31,6 @@ typedef enum base_command_type
typedef void base_command_t; typedef void base_command_t;
void BaseCmd_Init( void ); void BaseCmd_Init( void );
base_command_t *BaseCmd_Find( base_command_type_e type, const char *name ); base_command_t *BaseCmd_Find( base_command_type_e type, const char *name );
void BaseCmd_FindAll( const char *name, void BaseCmd_FindAll( const char *name,

View File

@@ -640,7 +640,7 @@ void Cmd_TokenizeString( const char *text )
while( 1 ) while( 1 )
{ {
// skip whitespace up to a /n // skip whitespace up to a /n
while( *text && *text <= ' ' && *text != '\r' && *text != '\n' ) while( *text && ((byte)*text ) <= ' ' && *text != '\r' && *text != '\n' )
text++; text++;
if( *text == '\n' || *text == '\r' ) if( *text == '\n' || *text == '\r' )
@@ -949,7 +949,7 @@ static void Cmd_Else_f( void )
static qboolean Cmd_ShouldAllowCommand( cmd_t *cmd, qboolean isPrivileged ) static qboolean Cmd_ShouldAllowCommand( cmd_t *cmd, qboolean isPrivileged )
{ {
const char *prefixes[] = { "cl_", "gl_", "r_", "m_", "hud_", "joy_" }; const char *prefixes[] = { "cl_", "gl_", "r_", "m_", "hud_", "joy_", "con_", "scr_" };
int i; int i;
// always allow local commands // always allow local commands
@@ -1015,7 +1015,7 @@ static void Cmd_ExecuteStringWithPrivilegeCheck( const char *text, qboolean isPr
*ptoken++ = *text++; *ptoken++ = *text++;
*ptoken = 0; *ptoken = 0;
len += Q_strncpy( pcmd, Cvar_VariableString( token ), MAX_CMD_LINE - len ); len += Q_strncpy( pcmd, Cvar_VariableString( token ), sizeof( token ) - len );
pcmd = command + len; pcmd = command + len;
if( !*text ) break; if( !*text ) break;

View File

@@ -25,16 +25,19 @@ GNU General Public License for more details.
static const char *file_exts[] = static const char *file_exts[] =
{ {
"cfg", // ban text files that don't make sense as resource
"lst", "cfg", "lst", "ini", "log",
"exe",
"vbs", // ban Windows code
"com", "exe", "vbs", "com", "bat",
"bat", "dll", "sys", "ps1",
"dll",
"ini", // ban common unix code
"log", // NOTE: in unix anything can be executed as long it has access flag
"sys", "so", "sh", "dylib",
// ban mobile archives
"apk", "ipa",
}; };
#ifdef _DEBUG #ifdef _DEBUG
@@ -900,7 +903,10 @@ qboolean COM_IsSafeFileToDownload( const char *filename )
if( !COM_CheckString( filename )) if( !COM_CheckString( filename ))
return false; return false;
if( !Q_strncmp( filename, "!MD5", 4 )) ext = COM_FileExtension( lwrfilename );
// only allow extensionless files that start with !MD5
if( !Q_strncmp( filename, "!MD5", 4 ) && ext[0] == 0 )
return true; return true;
Q_strnlwr( filename, lwrfilename, sizeof( lwrfilename )); Q_strnlwr( filename, lwrfilename, sizeof( lwrfilename ));
@@ -923,8 +929,6 @@ qboolean COM_IsSafeFileToDownload( const char *filename )
if( Q_strlen( first ) != 4 ) if( Q_strlen( first ) != 4 )
return false; return false;
ext = COM_FileExtension( lwrfilename );
for( i = 0; i < ARRAYSIZE( file_exts ); i++ ) for( i = 0; i < ARRAYSIZE( file_exts ); i++ )
{ {
if( !Q_stricmp( ext, file_exts[i] )) if( !Q_stricmp( ext, file_exts[i] ))

View File

@@ -275,6 +275,10 @@ typedef enum bugcomp_e
{ {
// reverts fix for pfnPEntityOfEntIndex for bug compatibility with GoldSrc // reverts fix for pfnPEntityOfEntIndex for bug compatibility with GoldSrc
BUGCOMP_PENTITYOFENTINDEX_FLAG = BIT( 0 ), BUGCOMP_PENTITYOFENTINDEX_FLAG = BIT( 0 ),
// rewrites mod's attempts to write GoldSrc-specific messages into Xash protocol
// (new wrappers are added by request)
BUGCOMP_MESSAGE_REWRITE_FACILITY_FLAG = BIT( 1 ),
} bugcomp_t; } bugcomp_t;
typedef struct host_parm_s typedef struct host_parm_s
@@ -475,14 +479,6 @@ typedef enum
WF_TOTALCOUNT, // must be last WF_TOTALCOUNT, // must be last
} sndformat_t; } sndformat_t;
// soundlib global settings
typedef enum
{
SL_USE_LERPING = BIT(0), // lerping sounds during resample
SL_KEEP_8BIT = BIT(1), // don't expand 8bit sounds automatically up to 16 bit
SL_ALLOW_OVERWRITE = BIT(2), // allow to overwrite stored sounds
} slFlags_t;
// wavdata output flags // wavdata output flags
typedef enum typedef enum
{ {
@@ -492,7 +488,6 @@ typedef enum
// Sound_Process manipulation flags // Sound_Process manipulation flags
SOUND_RESAMPLE = BIT( 12 ), // resample sound to specified rate SOUND_RESAMPLE = BIT( 12 ), // resample sound to specified rate
SOUND_CONVERT16BIT = BIT(13), // change sound resolution from 8 bit to 16
} sndFlags_t; } sndFlags_t;
typedef struct typedef struct
@@ -500,8 +495,8 @@ typedef struct
word rate; // num samples per second (e.g. 11025 - 11 khz) word rate; // num samples per second (e.g. 11025 - 11 khz)
byte width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2) byte width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2)
byte channels; // num channels (1 - mono, 2 - stereo) byte channels; // num channels (1 - mono, 2 - stereo)
int loopStart; // offset at this point sound will be looping while playing more than only once uint loopStart; // offset at this point sound will be looping while playing more than only once
int samples; // total samplecount in wav uint samples; // total samplecount in wav
uint type; // compression type uint type; // compression type
uint flags; // misc sound flags uint flags; // misc sound flags
byte *buffer; // sound buffer byte *buffer; // sound buffer
@@ -700,7 +695,7 @@ void Log_Printf( const char *fmt, ... ) _format( 1 );
void SV_BroadcastCommand( const char *fmt, ... ) _format( 1 ); void SV_BroadcastCommand( const char *fmt, ... ) _format( 1 );
void SV_BroadcastPrintf( struct sv_client_s *ignore, const char *fmt, ... ) _format( 2 ); void SV_BroadcastPrintf( struct sv_client_s *ignore, const char *fmt, ... ) _format( 2 );
void CL_ClearStaticEntities( void ); void CL_ClearStaticEntities( void );
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position ); qboolean S_StreamGetCurrentState( char *currentTrack, size_t currentTrackSize, char *loopTrack, size_t loopTrackSize, int *position );
void CL_ServerCommand( qboolean reliable, const char *fmt, ... ) _format( 2 ); void CL_ServerCommand( qboolean reliable, const char *fmt, ... ) _format( 2 );
void CL_HudMessage( const char *pMessage ); void CL_HudMessage( const char *pMessage );
const char *CL_MsgInfo( int cmd ); const char *CL_MsgInfo( int cmd );

View File

@@ -465,7 +465,7 @@ static qboolean Cmd_GetSoundList( const char *s, char *completedname, int length
t = FS_Search( va( "%s%s*.*", DEFAULT_SOUNDPATH, s ), true, false ); t = FS_Search( va( "%s%s*.*", DEFAULT_SOUNDPATH, s ), true, false );
if( !t ) return false; if( !t ) return false;
Q_strncpy( matchbuf, t->filenames[0] + sizeof( DEFAULT_SOUNDPATH ) - 1, MAX_STRING ); Q_strncpy( matchbuf, t->filenames[0] + sizeof( DEFAULT_SOUNDPATH ) - 1, sizeof( matchbuf ));
COM_StripExtension( matchbuf ); COM_StripExtension( matchbuf );
if( completedname && length ) if( completedname && length )
Q_strncpy( completedname, matchbuf, length ); Q_strncpy( completedname, matchbuf, length );
@@ -478,7 +478,7 @@ static qboolean Cmd_GetSoundList( const char *s, char *completedname, int length
if( Q_stricmp( ext, "wav" ) && Q_stricmp( ext, "mp3" )) if( Q_stricmp( ext, "wav" ) && Q_stricmp( ext, "mp3" ))
continue; continue;
Q_strncpy( matchbuf, t->filenames[i] + sizeof( DEFAULT_SOUNDPATH ) - 1, MAX_STRING ); Q_strncpy( matchbuf, t->filenames[i] + sizeof( DEFAULT_SOUNDPATH ) - 1, sizeof( matchbuf ));
COM_StripExtension( matchbuf ); COM_StripExtension( matchbuf );
Con_Printf( "%16s\n", matchbuf ); Con_Printf( "%16s\n", matchbuf );
numsounds++; numsounds++;
@@ -764,14 +764,14 @@ static qboolean Cmd_GetGamesList( const char *s, char *completedname, int length
} }
if( !numgamedirs ) return false; if( !numgamedirs ) return false;
Q_strncpy( matchbuf, gamedirs[0], MAX_STRING ); Q_strncpy( matchbuf, gamedirs[0], sizeof( matchbuf ));
if( completedname && length ) if( completedname && length )
Q_strncpy( completedname, matchbuf, length ); Q_strncpy( completedname, matchbuf, length );
if( numgamedirs == 1 ) return true; if( numgamedirs == 1 ) return true;
for( i = 0; i < numgamedirs; i++ ) for( i = 0; i < numgamedirs; i++ )
{ {
Q_strncpy( matchbuf, gamedirs[i], MAX_STRING ); Q_strncpy( matchbuf, gamedirs[i], sizeof( matchbuf ));
Con_Printf( "%16s\n", matchbuf ); Con_Printf( "%16s\n", matchbuf );
} }
@@ -825,14 +825,14 @@ static qboolean Cmd_GetCDList( const char *s, char *completedname, int length )
} }
if( !numcdcommands ) return false; if( !numcdcommands ) return false;
Q_strncpy( matchbuf, cdcommands[0], MAX_STRING ); Q_strncpy( matchbuf, cdcommands[0], sizeof( matchbuf ));
if( completedname && length ) if( completedname && length )
Q_strncpy( completedname, matchbuf, length ); Q_strncpy( completedname, matchbuf, length );
if( numcdcommands == 1 ) return true; if( numcdcommands == 1 ) return true;
for( i = 0; i < numcdcommands; i++ ) for( i = 0; i < numcdcommands; i++ )
{ {
Q_strncpy( matchbuf, cdcommands[i], MAX_STRING ); Q_strncpy( matchbuf, cdcommands[i], sizeof( matchbuf ));
Con_Printf( "%16s\n", matchbuf ); Con_Printf( "%16s\n", matchbuf );
} }
@@ -901,12 +901,10 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
if( f ) if( f )
{ {
qboolean have_spawnpoints = false; qboolean have_spawnpoints = false;
dheader_t *header;
dlump_t entities; dlump_t entities;
memset( buf, 0, MAX_SYSPATH ); memset( buf, 0, MAX_SYSPATH );
FS_Read( f, buf, MAX_SYSPATH ); FS_Read( f, buf, MAX_SYSPATH );
header = (dheader_t *)buf;
// check all the lumps and some other errors // check all the lumps and some other errors
if( !Mod_TestBmodelLumps( f, t->filenames[i], buf, true, &entities )) if( !Mod_TestBmodelLumps( f, t->filenames[i], buf, true, &entities ))
@@ -937,7 +935,7 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
char token[MAX_TOKEN]; char token[MAX_TOKEN];
qboolean worldspawn = true; qboolean worldspawn = true;
Q_strncpy( message, "No Title", MAX_STRING ); Q_strncpy( message, "No Title", sizeof( message ));
pfile = ents; pfile = ents;
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL ) while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )

View File

@@ -129,6 +129,22 @@ static void Sys_StackTrace( PEXCEPTION_POINTERS pInfo )
stackframe.AddrBStore.Mode = AddrModeFlat; stackframe.AddrBStore.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.IntSp; stackframe.AddrStack.Offset = context.IntSp;
stackframe.AddrStack.Mode = AddrModeFlat; stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_ARM
image = IMAGE_FILE_MACHINE_ARMNT;
stackframe.AddrPC.Offset = context.Pc;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.R11;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Sp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_ARM64
image = IMAGE_FILE_MACHINE_ARM64;
stackframe.AddrPC.Offset = context.Pc;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Fp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Sp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif #elif
#error #error
#endif #endif

View File

@@ -955,7 +955,7 @@ static void Cvar_SetGL( const char *name, const char *value )
static qboolean Cvar_ShouldSetCvar( convar_t *v, qboolean isPrivileged ) static qboolean Cvar_ShouldSetCvar( convar_t *v, qboolean isPrivileged )
{ {
const char *prefixes[] = { "cl_", "gl_", "m_", "r_", "hud_", "joy_" }; const char *prefixes[] = { "cl_", "gl_", "m_", "r_", "hud_", "joy_", "con_", "scr_" };
int i; int i;
if( isPrivileged ) if( isPrivileged )

View File

@@ -89,32 +89,32 @@ qboolean FS_LoadProgs( void )
if( !fs_hInstance ) if( !fs_hInstance )
{ {
Host_Error( "FS_LoadProgs: can't load filesystem library %s: %s\n", name, COM_GetLibraryError() ); Host_Error( "%s: can't load filesystem library %s: %s\n", __func__, name, COM_GetLibraryError() );
return false; return false;
} }
if( !( GetFSAPI = (FSAPI)COM_GetProcAddress( fs_hInstance, GET_FS_API ))) if( !( GetFSAPI = (FSAPI)COM_GetProcAddress( fs_hInstance, GET_FS_API )))
{ {
FS_UnloadProgs(); FS_UnloadProgs();
Host_Error( "FS_LoadProgs: can't find GetFSAPI entry point in %s\n", name ); Host_Error( "%s: can't find GetFSAPI entry point in %s\n", __func__, name );
return false; return false;
} }
if( !GetFSAPI( FS_API_VERSION, &g_fsapi, &FI, &fs_memfuncs )) if( GetFSAPI( FS_API_VERSION, &g_fsapi, &FI, &fs_memfuncs ) != FS_API_VERSION )
{ {
FS_UnloadProgs(); FS_UnloadProgs();
Host_Error( "FS_LoadProgs: can't initialize filesystem API: wrong version\n" ); Host_Error( "%s: can't initialize filesystem API: wrong version\n", __func__ );
return false; return false;
} }
if( !( fs_pfnCreateInterface = (pfnCreateInterface_t)COM_GetProcAddress( fs_hInstance, "CreateInterface" ))) if( !( fs_pfnCreateInterface = (pfnCreateInterface_t)COM_GetProcAddress( fs_hInstance, "CreateInterface" )))
{ {
FS_UnloadProgs(); FS_UnloadProgs();
Host_Error( "FS_LoadProgs: can't find CreateInterface entry point in %s\n", name ); Host_Error( "%s: can't find CreateInterface entry point in %s\n", __func__, name );
return false; return false;
} }
Con_DPrintf( "FS_LoadProgs: filesystem_stdio successfully loaded\n" ); Con_DPrintf( "%s: filesystem_stdio successfully loaded\n", __func__ );
return true; return true;
} }

View File

@@ -75,6 +75,7 @@ typedef struct feature_message_s
static feature_message_t bugcomp_features[] = static feature_message_t bugcomp_features[] =
{ {
{ BUGCOMP_PENTITYOFENTINDEX_FLAG, "pfnPEntityOfEntIndex bugfix revert", "peoei" }, { BUGCOMP_PENTITYOFENTINDEX_FLAG, "pfnPEntityOfEntIndex bugfix revert", "peoei" },
{ BUGCOMP_MESSAGE_REWRITE_FACILITY_FLAG, "GoldSrc Message Rewrite Facility", "gsmrf" },
}; };
static feature_message_t engine_features[] = static feature_message_t engine_features[] =
@@ -864,7 +865,7 @@ void GAME_EXPORT Host_Error( const char *error, ... )
} }
recursive = true; recursive = true;
Q_strncpy( hosterror2, hosterror1, MAX_SYSPATH ); Q_strncpy( hosterror2, hosterror1, sizeof( hosterror2 ));
host.errorframe = host.framecount; // to avoid multply calls per frame host.errorframe = host.framecount; // to avoid multply calls per frame
Q_snprintf( host.finalmsg, sizeof( host.finalmsg ), "Server crashed: %s", hosterror1 ); Q_snprintf( host.finalmsg, sizeof( host.finalmsg ), "Server crashed: %s", hosterror1 );
@@ -958,15 +959,15 @@ static void Host_RunTests( int stage )
static uint32_t Host_CheckBugcomp( void ) static uint32_t Host_CheckBugcomp( void )
{ {
const char *prev, *next;
uint32_t flags = 0; uint32_t flags = 0;
string args, arg; string args, arg;
char *prev, *next;
size_t i; size_t i;
if( !Sys_CheckParm( "-bugcomp" )) if( !Sys_CheckParm( "-bugcomp" ))
return 0; return 0;
if( Sys_GetParmFromCmdLine( "-bugcomp", args ) && args[0] != '-' ) if( Sys_GetParmFromCmdLine( "-bugcomp", args ) && isalpha( args[0] ))
{ {
for( prev = args, next = Q_strchrnul( prev, '+' ); ; prev = next + 1, next = Q_strchrnul( prev, '+' )) for( prev = args, next = Q_strchrnul( prev, '+' ); ; prev = next + 1, next = Q_strchrnul( prev, '+' ))
{ {

View File

@@ -24,7 +24,8 @@ typedef struct dll_user_s
qboolean custom_loader; // a bit who indicated loader type qboolean custom_loader; // a bit who indicated loader type
qboolean encrypted; // dll is crypted (some client.dll in HL, CS etc) qboolean encrypted; // dll is crypted (some client.dll in HL, CS etc)
char dllName[32]; // for debug messages char dllName[32]; // for debug messages
string fullPath, shortPath; // actual dll paths char fullPath[2048];
string shortPath; // actual dll paths
// ordinals stuff, valid only on Win32 // ordinals stuff, valid only on Win32
word *ordinals; word *ordinals;

View File

@@ -262,7 +262,7 @@ static void NET_AddMaster( const char *addr, qboolean save )
} }
master = Mem_Malloc( host.mempool, sizeof( master_t ) ); master = Mem_Malloc( host.mempool, sizeof( master_t ) );
Q_strncpy( master->address, addr, MAX_STRING ); Q_strncpy( master->address, addr, sizeof( master->address ));
master->sent = false; master->sent = false;
master->save = save; master->save = save;
master->next = NULL; master->next = NULL;

View File

@@ -24,6 +24,9 @@ GNU General Public License for more details.
#include "client.h" #include "client.h"
#include "server.h" // LUMP_ error codes #include "server.h" // LUMP_ error codes
#include "ref_common.h" #include "ref_common.h"
#if defined( HAVE_OPENMP )
#include <omp.h>
#endif // HAVE_OPENMP
#define MIPTEX_CUSTOM_PALETTE_SIZE_BYTES ( sizeof( int16_t ) + 768 ) #define MIPTEX_CUSTOM_PALETTE_SIZE_BYTES ( sizeof( int16_t ) + 768 )
@@ -578,6 +581,42 @@ void Mod_PrintWorldStats_f( void )
=============================================================================== ===============================================================================
*/ */
/*
===================
Mod_DecompressPVS
TODO: replace all Mod_DecompressPVS calls by this
===================
*/
static void Mod_DecompressPVSTo( byte *const out, const byte *in, size_t visbytes )
{
byte *dst = out;
if( !in ) // no visinfo, make all visible
{
memset( out, 0xFF, visbytes );
return;
}
while( dst < out + visbytes )
{
if( *in ) // uncompressed
{
*dst++ = *in++;
}
else // zero repeated `c` times
{
size_t c = in[1];
if( c > out + visbytes - dst )
c = out + visbytes - dst;
memset( dst, 0, c );
in += 2;
dst += c;
}
}
}
/* /*
=================== ===================
Mod_DecompressPVS Mod_DecompressPVS
@@ -585,41 +624,36 @@ Mod_DecompressPVS
*/ */
static byte *Mod_DecompressPVS( const byte *in, int visbytes ) static byte *Mod_DecompressPVS( const byte *in, int visbytes )
{ {
byte *out; Mod_DecompressPVSTo( g_visdata, in, visbytes );
int c;
out = g_visdata;
if( !in )
{
// no vis info, so make all visible
while( visbytes )
{
*out++ = 0xff;
visbytes--;
}
return g_visdata; return g_visdata;
} }
do static size_t Mod_CompressPVS( byte *const out, const byte *in, size_t inbytes )
{ {
if( *in ) size_t i;
byte *dst = out;
for( i = 0; i < inbytes; i++ )
{ {
*out++ = *in++; size_t j = i + 1, rep = 1;
*dst++ = in[i];
// only compress zeros
if( in[i] )
continue; continue;
}
c = in[1]; for( ; j < inbytes && rep != 255; j++, rep++ )
in += 2;
while( c )
{ {
*out++ = 0; if( in[j] )
c--; break;
} }
} while( out - g_visdata < visbytes );
return g_visdata; *dst++ = rep;
i = j - 1;
}
return dst - out;
} }
/* /*
@@ -653,22 +687,11 @@ NOTE: can return NULL
*/ */
byte *Mod_GetPVSForPoint( const vec3_t p ) byte *Mod_GetPVSForPoint( const vec3_t p )
{ {
mnode_t *node; mleaf_t *leaf;
mleaf_t *leaf = NULL;
ASSERT( worldmodel != NULL ); ASSERT( worldmodel != NULL );
node = worldmodel->nodes; leaf = Mod_PointInLeaf( p, worldmodel->nodes );
while( 1 )
{
if( node->contents < 0 )
{
leaf = (mleaf_t *)node;
break; // we found a leaf
}
node = node->children[PlaneDiff( p, node->plane ) <= 0];
}
if( leaf && leaf->cluster >= 0 ) if( leaf && leaf->cluster >= 0 )
return Mod_DecompressPVS( leaf->compressed_vis, world.visbytes ); return Mod_DecompressPVS( leaf->compressed_vis, world.visbytes );
@@ -681,7 +704,7 @@ Mod_FatPVS_RecursiveBSPNode
================== ==================
*/ */
static void Mod_FatPVS_RecursiveBSPNode( const vec3_t org, float radius, byte *visbuffer, int visbytes, mnode_t *node ) static void Mod_FatPVS_RecursiveBSPNode( const vec3_t org, float radius, byte *visbuffer, int visbytes, mnode_t *node, qboolean phs )
{ {
int i; int i;
@@ -696,7 +719,7 @@ static void Mod_FatPVS_RecursiveBSPNode( const vec3_t org, float radius, byte *v
else else
{ {
// go down both sides // go down both sides
Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, visbytes, node->children[0] ); Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, visbytes, node->children[0], phs );
node = node->children[1]; node = node->children[1];
} }
} }
@@ -704,10 +727,19 @@ static void Mod_FatPVS_RecursiveBSPNode( const vec3_t org, float radius, byte *v
// if this leaf is in a cluster, accumulate the vis bits // if this leaf is in a cluster, accumulate the vis bits
if(((mleaf_t *)node)->cluster >= 0 ) if(((mleaf_t *)node)->cluster >= 0 )
{ {
byte *vis = Mod_DecompressPVS( ((mleaf_t *)node)->compressed_vis, world.visbytes ); byte *vis;
for( i = 0; i < visbytes; i++ ) if( phs )
visbuffer[i] |= vis[i]; {
int i = ((mleaf_t *)node)->cluster + 1;
vis = Mod_DecompressPVS( &world.compressed_phs[world.phsofs[i]], world.visbytes );
}
else
{
vis = Mod_DecompressPVS( ((mleaf_t *)node)->compressed_vis, world.visbytes );
}
Q_memor( visbuffer, vis, visbytes );
} }
} }
@@ -719,7 +751,7 @@ Calculates a PVS that is the inclusive or of all leafs
within radius pixels of the given point. within radius pixels of the given point.
================== ==================
*/ */
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis ) int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis, qboolean phs )
{ {
int bytes = world.visbytes; int bytes = world.visbytes;
mleaf_t *leaf = NULL; mleaf_t *leaf = NULL;
@@ -736,9 +768,17 @@ int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, q
return bytes; return bytes;
} }
// requested PHS but we don't have PHS for some reason
// enable full visibility
if( phs && !( world.compressed_phs && world.phsofs ))
{
memset( visbuffer, 0xFF, bytes );
return bytes;
}
if( !merge ) memset( visbuffer, 0x00, bytes ); if( !merge ) memset( visbuffer, 0x00, bytes );
Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, bytes, worldmodel->nodes ); Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, bytes, worldmodel->nodes, phs );
return bytes; return bytes;
} }
@@ -1823,8 +1863,8 @@ static void Mod_LoadEntities( model_t *mod, dbspmodel_t *bmod )
{ {
char *pszWadFile; char *pszWadFile;
Q_strncpy( wadstring, token, MAX_TOKEN - 2 ); Q_strncpy( wadstring, token, sizeof( wadstring ) - 2 );
wadstring[MAX_TOKEN - 2] = 0; wadstring[sizeof( wadstring ) - 2] = 0;
if( !Q_strchr( wadstring, ';' )) if( !Q_strchr( wadstring, ';' ))
Q_strncat( wadstring, ";", sizeof( wadstring )); Q_strncat( wadstring, ";", sizeof( wadstring ));
@@ -1835,7 +1875,7 @@ static void Mod_LoadEntities( model_t *mod, dbspmodel_t *bmod )
COM_FixSlashes( pszWadFile ); COM_FixSlashes( pszWadFile );
COM_FileBase( pszWadFile, token, sizeof( token )); COM_FileBase( pszWadFile, token, sizeof( token ));
// make sure what wad is really exist // make sure that wad is really exist
if( FS_FileExists( va( "%s.wad", token ), false )) if( FS_FileExists( va( "%s.wad", token ), false ))
{ {
int num = bmod->wadlist.count++; int num = bmod->wadlist.count++;
@@ -2028,18 +2068,16 @@ static qboolean Mod_LooksLikeWaterTexture( const char *name )
static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureIndex ) static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureIndex )
{ {
#if !XASH_DEDICATED
texture_t *texture = NULL; texture_t *texture = NULL;
mip_t *mipTex = NULL; mip_t *mipTex = NULL;
qboolean usesCustomPalette = false; qboolean usesCustomPalette = false;
uint32_t txFlags = 0; uint32_t txFlags = 0;
// Don't load texture data on dedicated server, as there is no renderer. // don't load texture data on dedicated server, as there is no renderer.
// but count the wadusage for automatic precache
//
// FIXME: for ENGINE_IMPROVED_LINETRACE we need to load textures on server too // FIXME: for ENGINE_IMPROVED_LINETRACE we need to load textures on server too
// but there is no facility for this yet // but there is no facility for this yet
if( Host_IsDedicated( ))
return;
texture = mod->textures[textureIndex]; texture = mod->textures[textureIndex];
mipTex = Mod_GetMipTexForTexture( bmod, textureIndex ); mipTex = Mod_GetMipTexForTexture( bmod, textureIndex );
@@ -2054,11 +2092,16 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
// check for multi-layered sky texture (quake1 specific) // check for multi-layered sky texture (quake1 specific)
if( bmod->isworld && Q_strncmp( mipTex->name, "sky", 3 ) == 0 && ( mipTex->width / mipTex->height ) == 2 ) if( bmod->isworld && Q_strncmp( mipTex->name, "sky", 3 ) == 0 && ( mipTex->width / mipTex->height ) == 2 )
{
#if !XASH_DEDICATED
if( !Host_IsDedicated( ))
{ {
ref.dllFuncs.R_InitSkyClouds( mipTex, texture, usesCustomPalette ); // load quake sky ref.dllFuncs.R_InitSkyClouds( mipTex, texture, usesCustomPalette ); // load quake sky
if( R_GetBuiltinTexture( REF_SOLIDSKY_TEXTURE ) && R_GetBuiltinTexture( REF_ALPHASKY_TEXTURE )) if( R_GetBuiltinTexture( REF_SOLIDSKY_TEXTURE ) && R_GetBuiltinTexture( REF_ALPHASKY_TEXTURE ))
SetBits( world.flags, FWORLD_SKYSPHERE ); SetBits( world.flags, FWORLD_SKYSPHERE );
}
#endif // !XASH_DEDICATED
// No texture to load in this case, so just exit. // No texture to load in this case, so just exit.
return; return;
@@ -2076,11 +2119,18 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
if( wadIndex >= 0 ) if( wadIndex >= 0 )
{ {
#if !XASH_DEDICATED
if( !Host_IsDedicated( ))
texture->gl_texturenum = ref.dllFuncs.GL_LoadTexture( texpath, NULL, 0, txFlags ); texture->gl_texturenum = ref.dllFuncs.GL_LoadTexture( texpath, NULL, 0, txFlags );
#endif // !XASH_DEDICATED
bmod->wadlist.wadusage[wadIndex]++; bmod->wadlist.wadusage[wadIndex]++;
} }
} }
#if !XASH_DEDICATED
if( Host_IsDedicated( ))
return;
// WAD failed, so use internal texture (if present) // WAD failed, so use internal texture (if present)
if( mipTex->offsets[0] > 0 && texture->gl_texturenum == 0 ) if( mipTex->offsets[0] > 0 && texture->gl_texturenum == 0 )
{ {
@@ -2709,6 +2759,153 @@ static void Mod_LoadLeafs( model_t *mod, dbspmodel_t *bmod )
SetBits( world.flags, FWORLD_WATERALPHA ); SetBits( world.flags, FWORLD_WATERALPHA );
} }
/*
===========
Mod_CalcPHS
To be called while loading world for multiplayer game server
===========
*/
static void Mod_CalcPHS( model_t *mod )
{
const qboolean vis_stats = host_developer.value >= DEV_EXTENDED;
const size_t rowbytes = ALIGN( world.visbytes, 4 ); // force align rows by 32-bit boundary
const size_t count = mod->numleafs + 1; // same as mod->submodels[0].visleafs + 1
double t1;
double t2;
size_t total_compressed_size = 0;
size_t hcount = 0;
size_t vcount = 0;
int i;
byte *uncompressed_pvs;
byte *uncompressed_phs;
if( !mod->visdata )
return;
#if defined( HAVE_OPENMP )
Con_Reportf( "Building PHS in %d threads...\n", omp_get_max_threads( ));
#else
Con_Reportf( "Building PHS...\n" );
#endif
uncompressed_pvs = Mem_Calloc( mod->mempool, rowbytes * count * 2 );
uncompressed_phs = &uncompressed_pvs[rowbytes * count];
world.phsofs = Mem_Calloc( mod->mempool, sizeof( size_t ) * count );
world.compressed_phs = NULL;
t1 = Platform_DoubleTime();
#pragma omp parallel
{
// uncompress pvs first
#pragma omp for schedule( static, 256 ) // there might be thousands of leafs, split by 256
for( i = 0; i < count; i++ )
Mod_DecompressPVSTo( &uncompressed_pvs[rowbytes * i], mod->leafs[i].compressed_vis, world.visbytes );
// now create phs
#pragma omp for schedule( static, 256 ) reduction( + : vcount, hcount )
for( i = 0; i < count; i++ )
{
const byte *scan = &uncompressed_pvs[rowbytes * i];
byte *dst = &uncompressed_phs[rowbytes * i]; // rowbytes, not rowwords!
size_t j;
memcpy( dst, scan, rowbytes );
for( j = 0; j < rowbytes; j++ )
{
size_t k;
uint bitbyte = scan[j];
if( bitbyte == 0 )
continue;
for( k = 0; k < 8; k++ )
{
size_t index;
if( !FBitSet( bitbyte, BIT( k )))
continue;
// OR this pvs row into the phs
// +1 because pvs is 1 based
index = (( j * 8 ) + k + 1 );
if( index >= count )
continue;
Q_memor( dst, &uncompressed_pvs[rowbytes * index], rowbytes );
}
}
if( vis_stats && i != 0 )
{
size_t j;
for( j = 0; j < count; j++ )
{
if( CHECKVISBIT( scan, j ))
vcount++;
if( CHECKVISBIT( dst, j ))
hcount++;
}
}
}
}
// since I can't predict at which spot compressed array
// should be put, this loop is single threaded
for( i = 0; i < count; i++ )
{
const byte *src = &uncompressed_phs[rowbytes * i];
byte temp_compressed_row[(MAX_MAP_LEAFS+1)/4]; // compression for this row might be ineffective
size_t compressed_size;
compressed_size = Mod_CompressPVS( temp_compressed_row, src, rowbytes );
world.compressed_phs = Mem_Realloc( mod->mempool, world.compressed_phs, total_compressed_size + compressed_size );
memcpy( &world.compressed_phs[total_compressed_size], temp_compressed_row, compressed_size );
world.phsofs[i] = total_compressed_size;
total_compressed_size += compressed_size;
}
t2 = Platform_DoubleTime();
if( vis_stats )
Con_Reportf( "Average leaves visible / audible / total: %i / %i / %i\n", vcount / count, hcount / count, count );
Con_Reportf( "Uncompressed PHS size: %s\n", Q_memprint( rowbytes * count ));
Con_Reportf( "Compressed PHS size: %s\n", Q_memprint( total_compressed_size + sizeof( *world.phsofs ) * count ));
Con_Reportf( "PHS building time: %.2f ms\n", ( t2 - t1 ) * 1000.0f );
// TODO: rewrite this into a unit test
// NOTE: how to get GoldSrc fat PHS and PVS data
// start a multiplayer server with some op4_bootcamp (for example)
// attach to process with GDB:
// (gdb) p gPAS[0]
// $0 = (byte *) ...
// (gdb) p gPAS[gPVSRowBytes * (cl.worldmodel->numleafs + 1)]
// $1 = (byte *) ...
// (gdb) dump binary memory op4_bootcamp_gs.phs $0 $1
// (gdb) p gPVS[0]
// $2 = (byte *) ...
// (gdb) p gPVS[gPVSRowBytes * (cl.worldmodel->numleafs + 1)]
// $3 = (byte *) ...
// (gdb) dump binary memory op4_bootcamp_gs.pvs $0 $1
//
// NOTE: as of writing, uncompressed PVS and PHS data do match! hooray!
//
// FS_WriteFile( "op4_bootcamp.pvs", uncompressed_pvs, rowbytes * count );
// FS_WriteFile( "op4_bootcamp.phs", uncompressed_phs, rowbytes * count );
// release uncompressed data
Mem_Free( uncompressed_pvs );
// TODO: cache the PHS somewhere, it might take a long time on giant maps
}
/* /*
================= =================
Mod_LoadClipnodes Mod_LoadClipnodes
@@ -2906,6 +3103,7 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, const byte *mod_base, qboolea
char wadvalue[2048]; char wadvalue[2048];
size_t len = 0; size_t len = 0;
int i, ret, flags = 0; int i, ret, flags = 0;
qboolean wadlist_warn = false;
// always reset the intermediate struct // always reset the intermediate struct
memset( bmod, 0, sizeof( dbspmodel_t )); memset( bmod, 0, sizeof( dbspmodel_t ));
@@ -3000,24 +3198,38 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, const byte *mod_base, qboolea
{ {
world.version = bmod->version; world.version = bmod->version;
#if !XASH_DEDICATED #if !XASH_DEDICATED
Mod_InitDebugHulls( mod ); // FIXME: build hulls for separate bmodels (shells, medkits etc)
world.deluxedata = bmod->deluxedata_out; // deluxemap data pointer world.deluxedata = bmod->deluxedata_out; // deluxemap data pointer
world.shadowdata = bmod->shadowdata_out; // occlusion data pointer world.shadowdata = bmod->shadowdata_out; // occlusion data pointer
#endif // XASH_DEDICATED #endif // XASH_DEDICATED
if( SV_Active() && svs.maxclients > 1 )
Mod_CalcPHS( mod );
} }
for( i = 0; i < bmod->wadlist.count; i++ ) for( i = 0; i < bmod->wadlist.count; i++ )
{ {
string wadname;
if( !bmod->wadlist.wadusage[i] ) if( !bmod->wadlist.wadusage[i] )
continue; continue;
ret = Q_snprintf( &wadvalue[len], sizeof( wadvalue ), "%s.wad; ", bmod->wadlist.wadnames[i] );
Q_snprintf( wadname, sizeof( wadname ), "%s.wad", bmod->wadlist.wadnames[i] );
// a1ba: automatically precache used wad files so client will download it
if( SV_Active( ))
SV_GenericIndex( wadname );
if( !wadlist_warn )
{
ret = Q_snprintf( &wadvalue[len], sizeof( wadvalue ), "%s; ", wadname );
if( ret == -1 ) if( ret == -1 )
{ {
Con_DPrintf( S_WARN "Too many wad files for output!\n" ); Con_DPrintf( S_WARN "Too many wad files for output!\n" );
break; wadlist_warn = true;
} }
len += ret; len += ret;
} }
}
if( COM_CheckString( wadvalue )) if( COM_CheckString( wadvalue ))
{ {

View File

@@ -33,7 +33,7 @@ GNU General Public License for more details.
#define REFPVS_RADIUS 2.0f // radius for rendering #define REFPVS_RADIUS 2.0f // radius for rendering
#define FATPVS_RADIUS 8.0f // FatPVS use radius smaller than the FatPHS #define FATPVS_RADIUS 8.0f // FatPVS use radius smaller than the FatPHS
#define FATPHS_RADIUS 16.0f #define FATPHS_RADIUS 8.0f // see SV_AddToFatPAS in GoldSrc
#define WORLD_INDEX (1) // world index is always 1 #define WORLD_INDEX (1) // world index is always 1
@@ -115,6 +115,10 @@ typedef struct world_static_s
int max_recursion; int max_recursion;
uint32_t version; // BSP version uint32_t version; // BSP version
// Potentially Hearable Set
byte *compressed_phs;
size_t *phsofs;
} world_static_t; } world_static_t;
#ifndef REF_DLL #ifndef REF_DLL
@@ -151,7 +155,7 @@ void Mod_FreeUnused( void );
void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *loaded ); void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *loaded );
qboolean Mod_TestBmodelLumps( file_t *f, const char *name, const byte *mod_base, qboolean silent, dlump_t *entities ); qboolean Mod_TestBmodelLumps( file_t *f, const char *name, const byte *mod_base, qboolean silent, dlump_t *entities );
qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, int *lastleaf ); qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, int *lastleaf );
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis ); int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis, qboolean false );
qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbits ); qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbits );
int Mod_CheckLump( const char *filename, const int lump, int *lumpsize ); int Mod_CheckLump( const char *filename, const int lump, int *lumpsize );
int Mod_ReadLump( const char *filename, const int lump, void **lumpdata, int *lumpsize ); int Mod_ReadLump( const char *filename, const int lump, void **lumpdata, int *lumpsize );

View File

@@ -780,7 +780,7 @@ extract texture filename from modelname
*/ */
const char *Mod_StudioTexName( const char *modname ) const char *Mod_StudioTexName( const char *modname )
{ {
static char texname[MAX_QPATH]; static char texname[MAX_QPATH+1];
Q_strncpy( texname, modname, sizeof( texname )); Q_strncpy( texname, modname, sizeof( texname ));
COM_StripExtension( texname ); COM_StripExtension( texname );
@@ -841,6 +841,22 @@ static studiohdr_t *R_StudioLoadHeader( model_t *mod, const void *buffer )
return (studiohdr_t *)buffer; return (studiohdr_t *)buffer;
} }
static studiohdr_t *Mod_MaybeTruncateStudioTextureData( model_t *mod )
{
#if XASH_LOW_MEMORY
studiohdr_t *phdr = (studiohdr_t *)mod->cache.data;
mod->cache.data = Mem_Realloc( mod->mempool, mod->cache.data, phdr->texturedataindex );
phdr = (studiohdr_t *)mod->cache.data; // get the new pointer on studiohdr
phdr->length = phdr->texturedataindex; // update model size
return phdr;
#else
// NOTE: some mods potentially might require full studio model data
return (studiohdr_t *)mod->cache.data;
#endif
}
/* /*
================= =================
Mod_LoadStudioModel Mod_LoadStudioModel
@@ -860,26 +876,21 @@ void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded )
phdr = R_StudioLoadHeader( mod, buffer ); phdr = R_StudioLoadHeader( mod, buffer );
if( !phdr ) return; // bad model if( !phdr ) return; // bad model
if( !Host_IsDedicated() ) if( !Host_IsDedicated( ) && phdr->numtextures == 0 )
{
if( phdr->numtextures == 0 )
{ {
studiohdr_t *thdr; studiohdr_t *thdr;
byte *in, *out; void *buffer2;
void *buffer2 = NULL;
size_t size1, size2;
buffer2 = FS_LoadFile( Mod_StudioTexName( mod->name ), NULL, false ); buffer2 = FS_LoadFile( Mod_StudioTexName( mod->name ), NULL, false );
thdr = R_StudioLoadHeader( mod, buffer2 ); thdr = R_StudioLoadHeader( mod, buffer2 );
if( !thdr ) if( thdr != NULL )
{
Con_Printf( S_WARN "Mod_LoadStudioModel: %s missing textures file\n", mod->name );
if( buffer2 ) Mem_Free( buffer2 );
}
else
{ {
byte *in, *out;
size_t size1, size2;
#if !XASH_DEDICATED #if !XASH_DEDICATED
// TODO: Mod_StudioLoadTextures will crash if passed a merged studio model!
ref.dllFuncs.Mod_StudioLoadTextures( mod, thdr ); ref.dllFuncs.Mod_StudioLoadTextures( mod, thdr );
#endif #endif
@@ -899,33 +910,27 @@ void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded )
out = (byte *)phdr + phdr->textureindex; out = (byte *)phdr + phdr->textureindex;
memcpy( out, in, size1 + size2 ); // copy textures + skinrefs memcpy( out, in, size1 + size2 ); // copy textures + skinrefs
phdr->length += size1 + size2; phdr->length += size1 + size2;
Mem_Free( buffer2 ); // release T.mdl
} }
else Con_Printf( S_WARN "%s: %s missing textures file\n", __func__, mod->name );
if( buffer2 )
Mem_Free( buffer2 ); // release T.mdl
} }
else else
{ {
// NOTE: don't modify source buffer because it's used for CRC computing // NOTE: don't modify source buffer because it's used for CRC computing
mod->cache.data = Mem_Calloc( mod->mempool, phdr->length ); mod->cache.data = Mem_Calloc( mod->mempool, phdr->length );
memcpy( mod->cache.data, buffer, phdr->length ); memcpy( mod->cache.data, buffer, phdr->length );
phdr = (studiohdr_t *)mod->cache.data; // get the new pointer on studiohdr phdr = mod->cache.data;
#if !XASH_DEDICATED #if !XASH_DEDICATED
if( !Host_IsDedicated( ))
ref.dllFuncs.Mod_StudioLoadTextures( mod, phdr ); ref.dllFuncs.Mod_StudioLoadTextures( mod, phdr );
#endif #endif
}
// NOTE: we wan't keep raw textures in memory. just cutoff model pointer above texture base // NOTE: we may not want to keep raw textures in memory. just cutoff model pointer above texture base
mod->cache.data = Mem_Realloc( mod->mempool, mod->cache.data, phdr->texturedataindex ); phdr = Mod_MaybeTruncateStudioTextureData( mod );
phdr = (studiohdr_t *)mod->cache.data; // get the new pointer on studiohdr
phdr->length = phdr->texturedataindex; // update model size
}
}
else
{
// just copy model into memory
mod->cache.data = Mem_Calloc( mod->mempool, phdr->length );
memcpy( mod->cache.data, buffer, phdr->length );
phdr = mod->cache.data;
}
// setup bounding box // setup bounding box
if( !VectorCompare( vec3_origin, phdr->bbmin )) if( !VectorCompare( vec3_origin, phdr->bbmin ))

View File

@@ -114,6 +114,11 @@ void Mod_FreeModel( model_t *mod )
world.version = 0; world.version = 0;
world.shadowdata = NULL; world.shadowdata = NULL;
world.deluxedata = NULL; world.deluxedata = NULL;
// data already freed by Mem_FreePool above
world.hull_models = NULL;
world.compressed_phs = NULL;
world.phsofs = NULL;
} }
memset( mod, 0, sizeof( *mod )); memset( mod, 0, sizeof( *mod ));

View File

@@ -89,6 +89,36 @@ const char *svc_strings[svc_lastmsg+1] =
"svc_exec", "svc_exec",
}; };
const char *svc_legacy_strings[svc_lastmsg+1] =
{
[svc_legacy_changing] = "svc_legacy_changing",
[svc_legacy_ambientsound] = "svc_legacy_ambientsound",
[svc_legacy_soundindex] = "svc_legacy_soundindex",
[svc_legacy_ambientsound] = "svc_legacy_ambientsound",
[svc_legacy_modelindex] = "svc_legacy_modelindex",
[svc_legacy_eventindex] = "svc_legacy_eventindex",
[svc_legacy_chokecount] = "svc_legacy_chokecount",
};
const char *svc_goldsrc_strings[svc_lastmsg+1] =
{
[svc_goldsrc_version] = "svc_goldsrc_version",
[svc_goldsrc_serverinfo] = "svc_goldsrc_serverinfo",
[svc_goldsrc_deltadescription] = "svc_goldsrc_deltadescription",
[svc_goldsrc_stopsound] = "svc_goldsrc_stopsound",
[svc_goldsrc_damage] = "svc_goldsrc_damage",
[svc_goldsrc_killedmonster] = "svc_goldsrc_killedmonster",
[svc_goldsrc_foundsecret] = "svc_goldsrc_foundsecret",
[svc_goldsrc_spawnstaticsound] = "svc_goldsrc_spawnstaticsound",
[svc_goldsrc_decalname] = "svc_goldsrc_decalname",
[svc_goldsrc_newusermsg] = "svc_goldsrc_newusermsg",
[svc_goldsrc_newmovevars] = "svc_goldsrc_newmovevars",
[svc_goldsrc_sendextrainfo] = "svc_goldsrc_sendextrainfo",
[svc_goldsrc_timescale] = "svc_goldsrc_timescale",
[svc_goldsrc_sendcvarvalue] = "svc_goldsrc_sendcvarvalue",
[svc_goldsrc_sendcvarvalue2] = "svc_goldsrc_sendcvarvalue2",
};
void MSG_InitMasks( void ) void MSG_InitMasks( void )
{ {
uint startbit, endbit; uint startbit, endbit;

View File

@@ -174,7 +174,7 @@ void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
// Bit-write functions // Bit-write functions
void MSG_WriteOneBit( sizebuf_t *sb, int nValue ); void MSG_WriteOneBit( sizebuf_t *sb, int nValue );
void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits ); NO_ASAN void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits );
void MSG_WriteSBitLong( sizebuf_t *sb, int data, int numbits ); void MSG_WriteSBitLong( sizebuf_t *sb, int data, int numbits );
void MSG_WriteBitLong( sizebuf_t *sb, uint data, int numbits, qboolean bSigned ); void MSG_WriteBitLong( sizebuf_t *sb, uint data, int numbits, qboolean bSigned );
qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits ); qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits );

View File

@@ -919,13 +919,20 @@ int Netchan_CreateFileFragments( netchan_t *chan, const char *filename )
int remaining; int remaining;
int bufferid = 1; int bufferid = 1;
fs_offset_t filesize = 0; fs_offset_t filesize = 0;
char compressedfilename[MAX_OSPATH];
int compressedFileTime; int compressedFileTime;
int fileTime; int fileTime;
qboolean firstfragment = true; qboolean firstfragment = true;
qboolean bCompressed = false; qboolean bCompressed = false;
fragbufwaiting_t *wait, *p; fragbufwaiting_t *wait, *p;
fragbuf_t *buf; fragbuf_t *buf;
char compressedfilename[sizeof( buf->filename ) + 5];
// shouldn't be critical, but just in case
if( Q_strlen( filename ) > sizeof( buf->filename ) - 1 )
{
Con_Printf( S_WARN "Unable to transfer %s due to path length overflow\n", filename );
return 0;
}
if(( filesize = FS_FileSize( filename, false )) <= 0 ) if(( filesize = FS_FileSize( filename, false )) <= 0 )
{ {
@@ -937,8 +944,7 @@ int Netchan_CreateFileFragments( netchan_t *chan, const char *filename )
chunksize = chan->pfnBlockSize( chan->client, FRAGSIZE_FRAG ); chunksize = chan->pfnBlockSize( chan->client, FRAGSIZE_FRAG );
else chunksize = FRAGMENT_MAX_SIZE; // fallback else chunksize = FRAGMENT_MAX_SIZE; // fallback
Q_strncpy( compressedfilename, filename, sizeof( compressedfilename )); Q_snprintf( compressedfilename, sizeof( compressedfilename ), "%s.ztmp", filename );
COM_ReplaceExtension( compressedfilename, ".ztmp", sizeof( compressedfilename ));
compressedFileTime = FS_FileTime( compressedfilename, false ); compressedFileTime = FS_FileTime( compressedfilename, false );
fileTime = FS_FileTime( filename, false ); fileTime = FS_FileTime( filename, false );
@@ -1521,10 +1527,9 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
if( pbuf->iscompressed ) if( pbuf->iscompressed )
{ {
char compressedfilename[MAX_OSPATH]; char compressedfilename[sizeof( pbuf->filename ) + 5];
Q_strncpy( compressedfilename, pbuf->filename, sizeof( compressedfilename )); Q_snprintf( compressedfilename, sizeof( compressedfilename ), "%s.ztmp", pbuf->filename );
COM_ReplaceExtension( compressedfilename, ".ztmp", sizeof( compressedfilename ));
file = FS_Open( compressedfilename, "rb", false ); file = FS_Open( compressedfilename, "rb", false );
} }
else file = FS_Open( pbuf->filename, "rb", false ); else file = FS_Open( pbuf->filename, "rb", false );

View File

@@ -2375,7 +2375,7 @@ static qboolean HTTP_ProcessStream( httpfile_t *curfile )
if( curfile->header_size >= sizeof( buf )) if( curfile->header_size >= sizeof( buf ))
{ {
Con_Reportf( S_ERROR "Header too big, the size is %s\n", curfile->header_size ); Con_Reportf( S_ERROR "Header too big, the size is %d\n", curfile->header_size );
HTTP_FreeFile( curfile, true ); HTTP_FreeFile( curfile, true );
return false; return false;
} }
@@ -2395,8 +2395,6 @@ static qboolean HTTP_ProcessStream( httpfile_t *curfile )
int cutheadersize = begin - curfile->buf + 4; // after that begin of data int cutheadersize = begin - curfile->buf + 4; // after that begin of data
char *content_length_line; char *content_length_line;
Con_Reportf( "HTTP: Got response!\n" );
if( !Q_strstr( curfile->buf, "200 OK" )) if( !Q_strstr( curfile->buf, "200 OK" ))
{ {
*begin = 0; // cut string to print out response *begin = 0; // cut string to print out response
@@ -2420,10 +2418,10 @@ static qboolean HTTP_ProcessStream( httpfile_t *curfile )
content_length_line += sizeof( "Content-Length: " ) - 1; content_length_line += sizeof( "Content-Length: " ) - 1;
size = Q_atoi( content_length_line ); size = Q_atoi( content_length_line );
Con_Reportf( "HTTP: File size is %d\n", size ); Con_Reportf( "HTTP: Got 200 OK! File size is %d\n", size );
if( ( curfile->size != -1 ) && ( curfile->size != size )) // check size if specified, not used if( ( curfile->size != -1 ) && ( curfile->size != size )) // check size if specified, not used
Con_Reportf( S_WARN "Server reports wrong file size!\n" ); Con_Reportf( S_WARN "Server reports wrong file size for %s!\n", curfile->path );
curfile->size = size; curfile->size = size;
curfile->header_size = 0; curfile->header_size = 0;
@@ -2535,7 +2533,7 @@ void HTTP_Run( void )
if( !curfile->file ) if( !curfile->file )
{ {
Con_Printf( S_ERROR "cannot open %s!\n", name ); Con_Printf( S_ERROR "HTTP: cannot open %s!\n", name );
HTTP_FreeFile( curfile, true ); HTTP_FreeFile( curfile, true );
break; break;
} }

View File

@@ -278,6 +278,8 @@ GNU General Public License for more details.
#define SU_WEAPON (1<<14) #define SU_WEAPON (1<<14)
extern const char *svc_strings[svc_lastmsg+1]; extern const char *svc_strings[svc_lastmsg+1];
extern const char *svc_legacy_strings[svc_lastmsg+1];
extern const char *svc_goldsrc_strings[svc_lastmsg+1];
extern const char *clc_strings[clc_lastmsg+1]; extern const char *clc_strings[clc_lastmsg+1];
// FWGS extensions // FWGS extensions
@@ -316,4 +318,40 @@ extern const char *clc_strings[clc_lastmsg+1];
// Master Server protocol // Master Server protocol
#define MS_SCAN_REQUEST "1\xFF" "0.0.0.0:0\0" // TODO: implement IP filter #define MS_SCAN_REQUEST "1\xFF" "0.0.0.0:0\0" // TODO: implement IP filter
// GoldSrc protocol definitions
#define PROTOCOL_GOLDSRC_VERSION_REAL 48
#define PROTOCOL_GOLDSRC_VERSION (PROTOCOL_GOLDSRC_VERSION_REAL | (BIT( 7 ))) // should be 48, only to differentiate it from PROTOCOL_LEGACY_VERSION
#define svc_goldsrc_version svc_changing
#define svc_goldsrc_serverinfo svc_serverdata
#define svc_goldsrc_deltadescription svc_deltatable
#define svc_goldsrc_stopsound svc_resource
#define svc_goldsrc_damage svc_restoresound
#define svc_goldsrc_killedmonster 27
#define svc_goldsrc_foundsecret 28
#define svc_goldsrc_spawnstaticsound 29
#define svc_goldsrc_decalname svc_bspdecal
#define svc_goldsrc_newusermsg svc_usermessage
#define svc_goldsrc_newmovevars svc_deltamovevars
#define svc_goldsrc_sendextrainfo 54
#define svc_goldsrc_timescale 55
#define svc_goldsrc_sendcvarvalue svc_querycvarvalue
#define svc_goldsrc_sendcvarvalue2 svc_querycvarvalue2
#define clc_goldsrc_hltv clc_requestcvarvalue // 9
#define clc_goldsrc_requestcvarvalue clc_requestcvarvalue2 // 10
#define clc_goldsrc_requestcvarvalue2 11
#define clc_goldsrc_lastmsg 12
#define S2C_REJECT_BADPASSWORD '8'
#define S2C_REJECT '9'
#define S2C_CHALLENGE "A00000000"
#define S2C_CONNECTION "B"
#define MAX_GOLDSRC_RESOURCE_BITS 12
#define MAX_GOLDSRC_ENTITY_BITS 11
// #define MAX_GOLDSRC_EDICTS BIT( MAX_ENTITY_BITS )
#define MAX_GOLDSRC_EDICTS ( BIT( MAX_ENTITY_BITS ) + ( MAX_CLIENTS * 15 ))
#define LAST_GOLDSRC_EDICT ( BIT( MAX_ENTITY_BITS ) - 1 )
#endif//NET_PROTOCOL_H #endif//NET_PROTOCOL_H

View File

@@ -87,7 +87,7 @@ int open_mpeg_stream( void *mpg, void *file, pfread f_read, pfseek f_seek, wavin
if( !mh || !sc ) return 0; if( !mh || !sc ) return 0;
ret = mpg123_replace_reader_handle( mh, (void *)f_read, (void *)f_seek, NULL ); ret = mpg123_replace_reader_handle( mh, f_read, f_seek, NULL );
if( ret != MPG123_OK ) if( ret != MPG123_OK )
return 0; return 0;

View File

@@ -34,9 +34,15 @@ typedef struct
int playtime; // stream size in milliseconds int playtime; // stream size in milliseconds
} wavinfo_t; } wavinfo_t;
#ifdef _MSC_VER // a1ba: MSVC6 don't have ssize_t
typedef long mpg_ssize_t;
#else
typedef ssize_t mpg_ssize_t;
#endif
// custom stdio // custom stdio
typedef long (*pfread)( void *handle, void *buf, size_t count ); typedef mpg_ssize_t (*pfread)( void *handle, void *buf, size_t count );
typedef long (*pfseek)( void *handle, long offset, int whence ); typedef fs_offset_t (*pfseek)( void *handle, fs_offset_t offset, int whence );
extern void *create_decoder( int *error ); extern void *create_decoder( int *error );
extern int feed_mpeg_header( void *mpg, const byte *data, long bufsize, long streamsize, wavinfo_t *sc ); extern int feed_mpeg_header( void *mpg, const byte *data, long bufsize, long streamsize, wavinfo_t *sc );

View File

@@ -32,6 +32,7 @@ typedef struct mpg123_handle_s mpg123_handle_t;
#include <stdlib.h> #include <stdlib.h>
#include "fmt123.h" #include "fmt123.h"
#include STDINT_H #include STDINT_H
#include "xash3d_types.h"
#ifndef FALSE #ifndef FALSE
#define FALSE 0 #define FALSE 0
@@ -50,7 +51,7 @@ typedef unsigned char byte;
typedef unsigned short word; typedef unsigned short word;
typedef unsigned long ulong; typedef unsigned long ulong;
typedef unsigned int uint; typedef unsigned int uint;
typedef long mpg_off_t; typedef fs_offset_t mpg_off_t;
#ifdef _MSC_VER // a1ba: MSVC6 don't have ssize_t #ifdef _MSC_VER // a1ba: MSVC6 don't have ssize_t
typedef long mpg_ssize_t; typedef long mpg_ssize_t;

View File

@@ -853,11 +853,21 @@ int open_feed( mpg123_handle_t *fr )
return 0; return 0;
} }
static mpg_ssize_t read_mpgtypes( int fd, void *buf, size_t count )
{
return read( fd, buf, count );
}
static mpg_off_t lseek_mpgtypes( int fd, mpg_off_t offset, int whence )
{
return lseek( fd, offset, whence );
}
static int default_init( mpg123_handle_t *fr ) static int default_init( mpg123_handle_t *fr )
{ {
fr->rdat.fdread = plain_read; fr->rdat.fdread = plain_read;
fr->rdat.read = fr->rdat.r_read != NULL ? fr->rdat.r_read : read; fr->rdat.read = fr->rdat.r_read != NULL ? fr->rdat.r_read : read_mpgtypes;
fr->rdat.lseek = fr->rdat.r_lseek != NULL ? fr->rdat.r_lseek : lseek; fr->rdat.lseek = fr->rdat.r_lseek != NULL ? fr->rdat.r_lseek : lseek_mpgtypes;
fr->rdat.filelen = get_fileinfo( fr ); fr->rdat.filelen = get_fileinfo( fr );
fr->rdat.filepos = 0; fr->rdat.filepos = 0;

View File

@@ -216,7 +216,7 @@ wavdata_t *FS_StreamInfo( stream_t *stream )
if( !stream ) return NULL; if( !stream ) return NULL;
// fill structure // fill structure
info.loopStart = -1; info.loopStart = 0;
info.rate = stream->rate; info.rate = stream->rate;
info.width = stream->width; info.width = stream->width;
info.channels = stream->channels; info.channels = stream->channels;

View File

@@ -74,7 +74,10 @@ static uint32_t Sound_ParseSynchInteger( uint32_t v )
static void Sound_HandleCustomID3Comment( const char *key, const char *value ) static void Sound_HandleCustomID3Comment( const char *key, const char *value )
{ {
if( !Q_strcmp( key, "LOOP_START" ) || !Q_strcmp( key, "LOOPSTART" )) if( !Q_strcmp( key, "LOOP_START" ) || !Q_strcmp( key, "LOOPSTART" ))
{
sound.loopstart = Q_atoi( value ); sound.loopstart = Q_atoi( value );
SetBits( sound.flags, SOUND_LOOPED );
}
// unknown comment is not an error // unknown comment is not an error
} }
@@ -233,7 +236,6 @@ qboolean Sound_LoadMPG( const char *name, const byte *buffer, fs_offset_t filesi
sound.channels = sc.channels; sound.channels = sc.channels;
sound.rate = sc.rate; sound.rate = sc.rate;
sound.width = 2; // always 16-bit PCM sound.width = 2; // always 16-bit PCM
sound.loopstart = -1;
sound.size = ( sound.channels * sound.rate * sound.width ) * ( sc.playtime / 1000 ); // in bytes sound.size = ( sound.channels * sound.rate * sound.width ) * ( sc.playtime / 1000 ); // in bytes
padsize = sound.size % FRAME_SIZE; padsize = sound.size % FRAME_SIZE;
pos += FRAME_SIZE; // evaluate pos pos += FRAME_SIZE; // evaluate pos
@@ -241,7 +243,6 @@ qboolean Sound_LoadMPG( const char *name, const byte *buffer, fs_offset_t filesi
if( !Sound_ParseID3Tag( buffer, filesize )) if( !Sound_ParseID3Tag( buffer, filesize ))
{ {
Con_DPrintf( S_WARN "Sound_LoadMPG: (%s) failed to extract LOOP_START tag\n", name ); Con_DPrintf( S_WARN "Sound_LoadMPG: (%s) failed to extract LOOP_START tag\n", name );
sound.loopstart = -1;
} }
if( !sound.size ) if( !sound.size )
@@ -290,14 +291,14 @@ qboolean Sound_LoadMPG( const char *name, const byte *buffer, fs_offset_t filesi
return true; return true;
} }
/* static fs_offset_t FS_SeekMpg( void *file, fs_offset_t offset, int whence )
=================
FS_SeekEx
=================
*/
static fs_offset_t FS_SeekEx( file_t *file, fs_offset_t offset, int whence )
{ {
return FS_Seek( file, offset, whence ) == -1 ? -1 : FS_Tell( file ); return g_fsapi.Seek((file_t *)file, offset, whence ) == -1 ? -1 : g_fsapi.Tell((file_t *)file );
}
static mpg_ssize_t FS_ReadMpg( void *file, void *buf, size_t count )
{
return g_fsapi.Read((file_t *)file, buf, count );
} }
/* /*
@@ -333,7 +334,7 @@ stream_t *Stream_OpenMPG( const char *filename )
if( ret ) Con_DPrintf( S_ERROR "%s\n", get_error( mpeg )); if( ret ) Con_DPrintf( S_ERROR "%s\n", get_error( mpeg ));
// trying to open stream and read header // trying to open stream and read header
if( !open_mpeg_stream( mpeg, file, (void*)FS_Read, (void*)FS_SeekEx, &sc )) if( !open_mpeg_stream( mpeg, file, FS_ReadMpg, FS_SeekMpg, &sc ))
{ {
Con_DPrintf( S_ERROR "Stream_OpenMPG: failed to load (%s): %s\n", filename, get_error( mpeg )); Con_DPrintf( S_ERROR "Stream_OpenMPG: failed to load (%s): %s\n", filename, get_error( mpeg ));
close_decoder( mpeg ); close_decoder( mpeg );

View File

@@ -14,6 +14,9 @@ GNU General Public License for more details.
*/ */
#include "soundlib.h" #include "soundlib.h"
#if XASH_SDL
#include <SDL_audio.h>
#endif // XASH_SDL
/* /*
============================================================================= =============================================================================
@@ -130,7 +133,309 @@ uint GAME_EXPORT Sound_GetApproxWavePlayLen( const char *filepath )
return msecs; return msecs;
} }
#define drint( v ) (int)( v + 0.5 ) static qboolean Sound_ConvertNoResample( wavdata_t *sc, int inwidth, int outwidth, int outcount )
{
size_t i;
if( inwidth == 1 && outwidth == 2 ) // S8 to S16
{
for( i = 0; i < outcount * sc->channels; i++ )
((int16_t*)sound.tempbuffer)[i] = ((int8_t *)sc->buffer)[i] * 256;
return true;
}
if( inwidth == 2 && outwidth == 1 ) // S16 to S8
{
for( i = 0; i < outcount * sc->channels; i++ )
((int8_t*)sound.tempbuffer)[i] = ((int16_t *)sc->buffer)[i] / 256;
return true;
}
return false;
}
static qboolean Sound_ConvertDownsample( wavdata_t *sc, int inwidth, int outwidth, int outcount, double stepscale )
{
size_t i;
double j;
if( inwidth == 1 && outwidth == 1 )
{
int8_t *data = (int8_t *)sc->buffer;
if( outwidth == 1 )
{
int8_t *outdata = (int8_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0];
outdata[i*2+1] = data[((int)j)*2+1];
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j];
}
}
return true;
}
if( outwidth == 2 )
{
int16_t *outdata = (int16_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0] * 256;
outdata[i*2+1] = data[((int)j)*2+1] * 256;
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j] * 256;
}
}
return true;
}
}
if( inwidth == 2 )
{
int16_t *data = (int16_t *)sc->buffer;
if( outwidth == 1 )
{
int8_t *outdata = (int8_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0] / 256;
outdata[i*2+1] = data[((int)j)*2+1] / 256;
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j] / 256;
}
}
return true;
}
if( outwidth == 2 )
{
int16_t *outdata = (int16_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0];
outdata[i*2+1] = data[((int)j)*2+1];
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j];
}
}
return true;
}
}
return false;
}
static qboolean Sound_ConvertUpsample( wavdata_t *sc, int inwidth, int outwidth, int outcount, int incount, double stepscale )
{
size_t i;
double j;
double frac;
incount--; // to not go past last sample while interpolating
if( inwidth == 1 )
{
int8_t *data = (int8_t *)sc->buffer;
if( outwidth == 1 )
{
int8_t *outdata = (int8_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0];
outdata[i*2+1] = data[((int)j)*2+1];
if( j != (int)j && j < incount )
{
frac = j - (int)j;
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
}
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j];
if( j != (int)j && j < incount )
{
frac = j - (int)j;
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
}
}
}
return true;
}
if( outwidth == 2 )
{
int16_t *outdata = (int16_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0] * 256;
outdata[i*2+1] = data[((int)j)*2+1] * 256;
if( j != (int)j && j < incount )
{
frac = ( j - (int)j ) * 256;
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
}
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j] * 256;
if( j != (int)j && j < incount )
{
frac = ( j - (int)j ) * 256;
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
}
}
}
return true;
}
}
if( inwidth == 2 )
{
int16_t *data = (int16_t *)sc->buffer;
if( outwidth == 1 )
{
int8_t *outdata = (int8_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0] / 256;
outdata[i*2+1] = data[((int)j)*2+1] / 256;
if( j != (int)j && j < incount )
{
frac = ( j - (int)j ) / 256;
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
}
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j] / 256;
if( j != (int)j && j < incount )
{
frac = ( j - (int)j ) / 256;
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
}
}
}
return true;
}
if( outwidth == 2 )
{
int16_t *outdata = (int16_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0];
outdata[i*2+1] = data[((int)j)*2+1];
if( j != (int)j && j < incount )
{
frac = j - (int)j;
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
}
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j];
if( j != (int)j && j < incount )
{
frac = j - (int)j;
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
}
}
}
return true;
}
}
return false;
}
/* /*
================ ================
@@ -141,125 +446,70 @@ We need convert sound to signed even if nothing to resample
*/ */
static qboolean Sound_ResampleInternal( wavdata_t *sc, int inrate, int inwidth, int outrate, int outwidth ) static qboolean Sound_ResampleInternal( wavdata_t *sc, int inrate, int inwidth, int outrate, int outwidth )
{ {
double stepscale, j; const size_t oldsize = sc->size;
int outcount;
int i;
qboolean handled = false; qboolean handled = false;
double stepscale;
double t1, t2;
int outcount, incount = sc->samples;
if( inrate == outrate && inwidth == outwidth ) if( inrate == outrate && inwidth == outwidth )
return false; return false;
t1 = Sys_DoubleTime();
stepscale = (double)inrate / outrate; // this is usually 0.5, 1, or 2 stepscale = (double)inrate / outrate; // this is usually 0.5, 1, or 2
outcount = sc->samples / stepscale; outcount = sc->samples / stepscale;
sc->size = outcount * outwidth * sc->channels; sc->size = outcount * outwidth * sc->channels;
sound.tempbuffer = (byte *)Mem_Realloc( host.soundpool, sound.tempbuffer, sc->size );
sc->samples = outcount; sc->samples = outcount;
if( sc->loopStart != -1 ) if( FBitSet( sc->flags, SOUND_LOOPED ))
sc->loopStart = sc->loopStart / stepscale; sc->loopStart = sc->loopStart / stepscale;
if( inrate == outrate ) #if 0 && XASH_SDL // slow but somewhat accurate
{ {
if( inwidth == 1 && outwidth == 2 ) // S8 to S16 const SDL_AudioFormat infmt = inwidth == 1 ? AUDIO_S8 : AUDIO_S16;
{ const SDL_AudioFormat outfmt = outwidth == 1 ? AUDIO_S8 : AUDIO_S16;
for( i = 0; i < outcount * sc->channels; i++ ) SDL_AudioCVT cvt;
((int16_t*)sound.tempbuffer)[i] = ((int8_t *)sc->buffer)[i] * 256;
handled = true;
}
else if( inwidth == 2 && outwidth == 1 ) // S16 to S8
{
for( i = 0; i < outcount * sc->channels; i++ )
((int8_t*)sound.tempbuffer)[i] = ((int16_t *)sc->buffer)[i] / 256;
handled = true;
}
}
else // resample case
{
if( inwidth == 1 )
{
int8_t *data = (int8_t *)sc->buffer;
if( outwidth == 1 ) // SDL_AudioCVT does conversion in place, original buffer is used for it
if( SDL_BuildAudioCVT( &cvt, infmt, sc->channels, inrate, outfmt, sc->channels, outrate ) > 0 && cvt.needed )
{ {
if( sc->channels == 2 ) sc->buffer = (byte *)Mem_Realloc( host.soundpool, sc->buffer, oldsize * cvt.len_mult );
{ cvt.len = oldsize;
for( i = 0, j = 0; i < outcount; i++, j += stepscale ) cvt.buf = sc->buffer;
{
((int8_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0];
((int8_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1];
}
}
else
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
((int8_t*)sound.tempbuffer)[i] = data[(int)j];
}
handled = true;
}
else if( outwidth == 2 )
{
if( sc->channels == 2 )
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
{
((int16_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0] * 256;
((int16_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1] * 256;
}
}
else
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
((int16_t*)sound.tempbuffer)[i] = data[(int)j] * 256;
}
handled = true;
}
}
else if( inwidth == 2 )
{
int16_t *data = (int16_t *)sc->buffer;
if( outwidth == 1 ) if( !SDL_ConvertAudio( &cvt ))
{ {
if( sc->channels == 2 ) t2 = Sys_DoubleTime();
{ Con_Reportf( "Sound_Resample: from [%d bit %d Hz] to [%d bit %d Hz] (took %.3fs through SDL)\n", inwidth * 8, inrate, outwidth * 8, outrate, t2 - t1 );
for( i = 0, j = 0; i < outcount; i++, j += stepscale ) sc->rate = outrate;
{ sc->width = outwidth;
((int8_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0] / 256; return false; // HACKHACK: return false so Sound_Process won't reallocate buffer
((int8_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1] / 256;
}
}
else
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
((int8_t*)sound.tempbuffer)[i] = data[(int)j] / 256;
}
handled = true;
}
else if( outwidth == 2 )
{
if( sc->channels == 2 )
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
{
((int16_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0];
((int16_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1];
}
}
else
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
((int16_t*)sound.tempbuffer)[i] = data[(int)j];
}
handled = true;
} }
} }
} }
#endif
sound.tempbuffer = (byte *)Mem_Realloc( host.soundpool, sound.tempbuffer, sc->size );
if( inrate == outrate ) // no resampling, just copy data
handled = Sound_ConvertNoResample( sc, inwidth, outwidth, outcount );
else if( inrate > outrate ) // fast case, usually downsample but is also ok for upsampling
handled = Sound_ConvertDownsample( sc, inwidth, outwidth, outcount, stepscale );
else // upsample case, w/ interpolation
handled = Sound_ConvertUpsample( sc, inwidth, outwidth, outcount, incount, stepscale );
t2 = Sys_DoubleTime();
if( handled ) if( handled )
Con_Reportf( "Sound_Resample: from [%d bit %d Hz] to [%d bit %d Hz]\n", inwidth * 8, inrate, outwidth * 8, outrate ); {
if( t2 - t1 > 0.01f ) // critical, report to mod developer
Con_Printf( S_WARN "Sound_Resample: from [%d bit %d Hz] to [%d bit %d Hz] (took %.3fs)\n", inwidth * 8, inrate, outwidth * 8, outrate, t2 - t1 );
else else
Con_Reportf( S_ERROR "Sound_Resample: unsupported from [%d bit %d Hz] to [%d bit %d Hz]\n", inwidth * 8, inrate, outwidth * 8, outrate ); Con_Reportf( "Sound_Resample: from [%d bit %d Hz] to [%d bit %d Hz] (took %.3fs)\n", inwidth * 8, inrate, outwidth * 8, outrate, t2 - t1 );
}
else
Con_Printf( S_ERROR "Sound_Resample: unsupported from [%d bit %d Hz] to [%d bit %d Hz]\n", inwidth * 8, inrate, outwidth * 8, outrate );
sc->rate = outrate; sc->rate = outrate;
sc->width = outwidth; sc->width = outwidth;
@@ -276,23 +526,20 @@ qboolean Sound_Process( wavdata_t **wav, int rate, int width, uint flags )
if( !snd || !snd->buffer ) if( !snd || !snd->buffer )
return false; return false;
if(( flags & SOUND_RESAMPLE ) && ( width > 0 || rate > 0 )) if( FBitSet( flags, SOUND_RESAMPLE ) && ( width > 0 || rate > 0 ))
{ {
if( Sound_ResampleInternal( snd, snd->rate, snd->width, rate, width )) result = Sound_ResampleInternal( snd, snd->rate, snd->width, rate, width );
if( result )
{ {
Mem_Free( snd->buffer ); // free original image buffer Mem_Free( snd->buffer ); // free original image buffer
snd->buffer = Sound_Copy( snd->size ); // unzone buffer (don't touch image.tempbuffer) snd->buffer = Sound_Copy( snd->size ); // unzone buffer (don't touch sound.tempbuffer)
}
else
{
// not resampled
result = false;
} }
} }
*wav = snd; *wav = snd;
return false; return result;
} }
qboolean Sound_SupportedFileFormat( const char *fileext ) qboolean Sound_SupportedFileFormat( const char *fileext )

View File

@@ -23,6 +23,11 @@ static const byte *iff_end;
static const byte *iff_lastChunk; static const byte *iff_lastChunk;
static int iff_chunkLen; static int iff_chunkLen;
static int IsFourCC( const byte *ptr, const byte *fourcc )
{
return 0 == memcmp( ptr, fourcc, 4 );
}
/* /*
================= =================
GetLittleShort GetLittleShort
@@ -85,8 +90,22 @@ static void FindNextChunk( const char *filename, const char *name )
} }
if( iff_chunkLen > remaining ) if( iff_chunkLen > remaining )
{
// only print this warning if selected chunk is truncated
//
// otherwise this warning becomes misleading because some
// idiot programs like CoolEdit (i.e. Adobe Audition) don't always
// respect pad byte. The file isn't actually truncated, it just
// can't be reliably parsed as a whole
if( IsFourCC( iff_lastChunk, "RIFF" )
|| IsFourCC( iff_lastChunk, "fmt " )
|| IsFourCC( iff_lastChunk, "cue " )
|| IsFourCC( iff_lastChunk, "LIST" )
|| IsFourCC( iff_lastChunk, "data" ))
{ {
Con_DPrintf( "%s: '%s' truncated by %i bytes\n", __func__, filename, iff_chunkLen - remaining ); Con_DPrintf( "%s: '%s' truncated by %i bytes\n", __func__, filename, iff_chunkLen - remaining );
}
iff_chunkLen = remaining; iff_chunkLen = remaining;
} }
@@ -96,7 +115,7 @@ static void FindNextChunk( const char *filename, const char *name )
iff_lastChunk = iff_dataPtr + 8 + iff_chunkLen; iff_lastChunk = iff_dataPtr + 8 + iff_chunkLen;
if(( iff_chunkLen & 1 ) && remaining ) if(( iff_chunkLen & 1 ) && remaining )
iff_lastChunk++; iff_lastChunk++;
if (!Q_strncmp(iff_dataPtr, name, 4)) if( IsFourCC( iff_dataPtr, name ))
return; return;
} }
} }
@@ -130,15 +149,18 @@ static qboolean StreamFindNextChunk( file_t *file, const char *name, int *last_c
return false; // didn't find the chunk return false; // didn't find the chunk
FS_Seek( file, 4, SEEK_CUR ); FS_Seek( file, 4, SEEK_CUR );
FS_Read( file, &iff_chunk_len, sizeof( iff_chunk_len )); if( FS_Read( file, &iff_chunk_len, sizeof( iff_chunk_len )) != sizeof( iff_chunk_len ))
return false;
if( iff_chunk_len < 0 ) if( iff_chunk_len < 0 )
return false; // didn't find the chunk return false; // didn't find the chunk
FS_Seek( file, -8, SEEK_CUR ); FS_Seek( file, -8, SEEK_CUR );
*last_chunk = FS_Tell( file ) + 8 + (( iff_chunk_len + 1 ) & ~1 ); *last_chunk = FS_Tell( file ) + 8 + (( iff_chunk_len + 1 ) & ~1 );
FS_Read( file, chunkName, 4 ); if( FS_Read( file, chunkName, sizeof( chunkName )) != sizeof( chunkName ))
return false;
if( !Q_strncmp( chunkName, name, 4 )) if( IsFourCC( chunkName, name ))
return true; return true;
} }
@@ -164,7 +186,7 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
// find "RIFF" chunk // find "RIFF" chunk
FindChunk( name, "RIFF" ); FindChunk( name, "RIFF" );
if( !( iff_dataPtr && !Q_strncmp( (const char *)iff_dataPtr + 8, "WAVE", 4 ))) if( !iff_dataPtr || !IsFourCC( iff_dataPtr + 8, "WAVE" ))
{ {
Con_DPrintf( S_ERROR "Sound_LoadWAV: %s missing 'RIFF/WAVE' chunks\n", name ); Con_DPrintf( S_ERROR "Sound_LoadWAV: %s missing 'RIFF/WAVE' chunks\n", name );
return false; return false;
@@ -223,11 +245,12 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
{ {
iff_dataPtr += 32; iff_dataPtr += 32;
sound.loopstart = GetLittleLong(); sound.loopstart = GetLittleLong();
SetBits( sound.flags, SOUND_LOOPED );
FindNextChunk( name, "LIST" ); // if the next chunk is a LIST chunk, look for a cue length marker FindNextChunk( name, "LIST" ); // if the next chunk is a LIST chunk, look for a cue length marker
if( iff_dataPtr ) if( iff_dataPtr )
{ {
if( !Q_strncmp( (const char *)iff_dataPtr + 28, "mark", 4 )) if( IsFourCC( iff_dataPtr + 28, "mark" ))
{ {
// this is not a proper parse, but it works with CoolEdit... // this is not a proper parse, but it works with CoolEdit...
iff_dataPtr += 24; iff_dataPtr += 24;
@@ -237,7 +260,7 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
} }
else else
{ {
sound.loopstart = -1; sound.loopstart = 0;
sound.samples = 0; sound.samples = 0;
} }
@@ -342,8 +365,16 @@ stream_t *Stream_OpenWAV( const char *filename )
return NULL; return NULL;
} }
FS_Read( file, chunkName, 4 ); FS_Seek( file, 4, SEEK_CUR );
if( !Q_strncmp( chunkName, "WAVE", 4 ))
if( FS_Read( file, chunkName, 4 ) != 4 )
{
Con_DPrintf( S_ERROR "%s: %s missing WAVE chunk, truncated\n", filename );
FS_Close( file );
return false;
}
if( !IsFourCC( chunkName, "WAVE" ))
{ {
Con_DPrintf( S_ERROR "Stream_OpenWAV: %s missing WAVE chunk\n", filename ); Con_DPrintf( S_ERROR "Stream_OpenWAV: %s missing WAVE chunk\n", filename );
FS_Close( file ); FS_Close( file );
@@ -351,7 +382,7 @@ stream_t *Stream_OpenWAV( const char *filename )
} }
// get "fmt " chunk // get "fmt " chunk
iff_data = FS_Tell( file ) + 4; iff_data = FS_Tell( file );
last_chunk = iff_data; last_chunk = iff_data;
if( !StreamFindNextChunk( file, "fmt ", &last_chunk )) if( !StreamFindNextChunk( file, "fmt ", &last_chunk ))
{ {

View File

@@ -50,7 +50,7 @@ typedef struct sndlib_s
int rate; // num samples per second (e.g. 11025 - 11 khz) int rate; // num samples per second (e.g. 11025 - 11 khz)
int width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2) int width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2)
int channels; // num channels (1 - mono, 2 - stereo) int channels; // num channels (1 - mono, 2 - stereo)
int loopstart; // start looping from uint loopstart; // start looping from
uint samples; // total samplecount in sound uint samples; // total samplecount in sound
uint flags; // additional sound flags uint flags; // additional sound flags
size_t size; // sound unpacked size (for bounds checking) size_t size; // sound unpacked size (for bounds checking)

View File

@@ -20,63 +20,6 @@ GNU General Public License for more details.
#include "xash3d_mathlib.h" #include "xash3d_mathlib.h"
#include "studio.h" #include "studio.h"
// just for debug
const char *et_name[] =
{
"normal",
"player",
"tempentity",
"beam",
"fragmented",
};
/*
===============================================================================
ENTITY LINKING
===============================================================================
*/
/*
===============
ClearLink
ClearLink is used for new headnodes
===============
*/
void ClearLink( link_t *l )
{
l->prev = l->next = l;
}
/*
===============
RemoveLink
remove link from chain
===============
*/
void RemoveLink( link_t *l )
{
l->next->prev = l->prev;
l->prev->next = l->next;
}
/*
===============
InsertLinkBefore
kept trigger and solid entities seperate
===============
*/
void InsertLinkBefore( link_t *l, link_t *before )
{
l->next = before;
l->prev = before->prev;
l->prev->next = l;
l->next->prev = l;
}
/* /*
================== ==================
World_MoveBounds World_MoveBounds

View File

@@ -35,13 +35,6 @@ ENTITY AREA CHECKING
#include "lightstyle.h" #include "lightstyle.h"
extern const char *et_name[];
// linked list
void InsertLinkBefore( link_t *l, link_t *before );
void RemoveLink( link_t *l );
void ClearLink( link_t *l );
// trace common // trace common
void World_MoveBounds( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, vec3_t boxmins, vec3_t boxmaxs ); void World_MoveBounds( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, vec3_t boxmins, vec3_t boxmaxs );
void World_TransformAABB( matrix4x4 transform, const vec3_t mins, const vec3_t maxs, vec3_t outmins, vec3_t outmaxs ); void World_TransformAABB( matrix4x4 transform, const vec3_t mins, const vec3_t maxs, vec3_t outmins, vec3_t outmaxs );

View File

@@ -50,6 +50,10 @@ GNU General Public License for more details.
#define LUMP_SAVE_NO_DATA 7 #define LUMP_SAVE_NO_DATA 7
#define LUMP_SAVE_CORRUPTED 8 #define LUMP_SAVE_CORRUPTED 8
#ifndef ALLOC_CHECK
#define ALLOC_CHECK( x )
#endif
typedef struct areanode_s typedef struct areanode_s
{ {
int axis; // -1 = leaf node int axis; // -1 = leaf node

View File

@@ -175,11 +175,13 @@ void Evdev_Autodetect_f( void )
if( evdev.devices >= MAX_EVDEV_DEVICES ) if( evdev.devices >= MAX_EVDEV_DEVICES )
continue; continue;
Q_snprintf( path, MAX_STRING, "/dev/input/%s", entry->d_name ); Q_snprintf( path, sizeof( path ), "/dev/input/%s", entry->d_name );
for( i = 0; i < evdev.devices; i++ ) for( i = 0; i < evdev.devices; i++ )
if( !Q_strncmp( evdev.paths[i], path, MAX_STRING ) ) {
if( !Q_strncmp( evdev.paths[i], path, sizeof( evdev.paths[i] ))
goto next; goto next;
}
if( Q_strncmp( entry->d_name, "event", 5 ) ) if( Q_strncmp( entry->d_name, "event", 5 ) )
continue; continue;
@@ -220,7 +222,7 @@ void Evdev_Autodetect_f( void )
} }
goto close; goto close;
open: open:
Q_strncpy( evdev.paths[evdev.devices], path, MAX_STRING ); Q_strncpy( evdev.paths[evdev.devices], path, sizeof( evdev.paths[0] ));
evdev.fds[evdev.devices++] = fd; evdev.fds[evdev.devices++] = fd;
Con_Printf( "Opened device %s\n", path ); Con_Printf( "Opened device %s\n", path );
#if XASH_INPUT == INPUT_EVDEV #if XASH_INPUT == INPUT_EVDEV
@@ -260,7 +262,7 @@ void Evdev_OpenDevice ( const char *path )
for( i = 0; i < evdev.devices; i++ ) for( i = 0; i < evdev.devices; i++ )
{ {
if( !Q_strncmp( evdev.paths[i], path, MAX_STRING ) ) if( !Q_strncmp( evdev.paths[i], path, sizeof( evdev.paths[i] )))
{ {
Con_Printf( "device %s already open!\n", path ); Con_Printf( "device %s already open!\n", path );
return; return;
@@ -275,7 +277,7 @@ void Evdev_OpenDevice ( const char *path )
} }
Con_Printf( "Input device #%d: %s opened sucessfully\n", evdev.devices, path ); Con_Printf( "Input device #%d: %s opened sucessfully\n", evdev.devices, path );
evdev.fds[evdev.devices] = ret; evdev.fds[evdev.devices] = ret;
Q_strncpy( evdev.paths[evdev.devices++], path, MAX_STRING ); Q_strncpy( evdev.paths[evdev.devices++], path, sizeof( evdev.paths[0] ));
#if XASH_INPUT == INPUT_EVDEV #if XASH_INPUT == INPUT_EVDEV
if( Sys_CheckParm( "-grab" ) ) if( Sys_CheckParm( "-grab" ) )
@@ -309,7 +311,7 @@ void Evdev_CloseDevice_f ( void )
if( Q_isdigit( arg ) ) if( Q_isdigit( arg ) )
i = Q_atoi( arg ); i = Q_atoi( arg );
else for( i = 0; i < evdev.devices; i++ ) else for( i = 0; i < evdev.devices; i++ )
if( !Q_strncmp( evdev.paths[i], arg, MAX_STRING ) ) if( !Q_strncmp( evdev.paths[i], arg, sizeof( evdev.paths[i] )))
break; break;
if( i >= evdev.devices ) if( i >= evdev.devices )
@@ -324,7 +326,7 @@ void Evdev_CloseDevice_f ( void )
for( ; i < evdev.devices; i++ ) for( ; i < evdev.devices; i++ )
{ {
Q_strncpy( evdev.paths[i], evdev.paths[i+1], MAX_STRING ); Q_strncpy( evdev.paths[i], evdev.paths[i+1], sizeof( evdev.paths[i] ));
evdev.fds[i] = evdev.fds[i+1]; evdev.fds[i] = evdev.fds[i+1];
} }
} }

View File

@@ -148,7 +148,6 @@ static void SDLash_KeyEvent( SDL_KeyboardEvent key )
#else #else
int keynum = key.keysym.sym; int keynum = key.keysym.sym;
#endif #endif
qboolean numLock = FBitSet( SDL_GetModState(), KMOD_NUM );
#if XASH_ANDROID #if XASH_ANDROID
if( keynum == SDL_SCANCODE_VOLUMEUP || keynum == SDL_SCANCODE_VOLUMEDOWN ) if( keynum == SDL_SCANCODE_VOLUMEUP || keynum == SDL_SCANCODE_VOLUMEDOWN )
@@ -157,7 +156,10 @@ static void SDLash_KeyEvent( SDL_KeyboardEvent key )
} }
#endif #endif
if( SDL_IsTextInputActive() && down && cls.key_dest != key_game ) if( SDL_IsTextInputActive( ))
{
// this is how engine understands ctrl+c, ctrl+v and other hotkeys
if( down && cls.key_dest != key_game )
{ {
if( FBitSet( SDL_GetModState(), KMOD_CTRL )) if( FBitSet( SDL_GetModState(), KMOD_CTRL ))
{ {
@@ -169,20 +171,24 @@ static void SDLash_KeyEvent( SDL_KeyboardEvent key )
return; return;
} }
}
#if !SDL_VERSION_ATLEAST( 2, 0, 0 ) #if SDL_VERSION_ATLEAST( 2, 0, 0 )
// ignore printable keys, they are coming through SDL_TEXTINPUT
if(( keynum >= SDL_SCANCODE_A && keynum <= SDL_SCANCODE_Z )
|| ( keynum >= SDL_SCANCODE_1 && keynum <= SDL_SCANCODE_0 )
|| ( keynum >= SDL_SCANCODE_KP_1 && keynum <= SDL_SCANCODE_KP_0 ))
return;
#else
if( keynum >= SDLK_KP0 && keynum <= SDLK_KP9 ) if( keynum >= SDLK_KP0 && keynum <= SDLK_KP9 )
keynum -= SDLK_KP0 + '0'; keynum -= SDLK_KP0 + '0';
if( isprint( keynum )) if( isprint( keynum ))
{ {
if( FBitSet( SDL_GetModState(), KMOD_SHIFT )) if( FBitSet( SDL_GetModState(), KMOD_SHIFT ))
{
keynum = Key_ToUpper( keynum ); keynum = Key_ToUpper( keynum );
}
CL_CharEvent( keynum ); CL_CharEvent( keynum );
return;
} }
#endif #endif
} }
@@ -198,6 +204,8 @@ static void SDLash_KeyEvent( SDL_KeyboardEvent key )
else DECLARE_KEY_RANGE( SDL_SCANCODE_F1, SDL_SCANCODE_F12, K_F1 ) else DECLARE_KEY_RANGE( SDL_SCANCODE_F1, SDL_SCANCODE_F12, K_F1 )
else else
{ {
qboolean numLock = FBitSet( SDL_GetModState(), KMOD_NUM );
switch( keynum ) switch( keynum )
{ {
case SDL_SCANCODE_GRAVE: keynum = '`'; break; case SDL_SCANCODE_GRAVE: keynum = '`'; break;
@@ -349,16 +357,17 @@ SDLash_InputEvent
#if SDL_VERSION_ATLEAST( 2, 0, 0 ) #if SDL_VERSION_ATLEAST( 2, 0, 0 )
static void SDLash_InputEvent( SDL_TextInputEvent input ) static void SDLash_InputEvent( SDL_TextInputEvent input )
{ {
char *text; const char *text;
VGui_ReportTextInput( input.text ); VGui_ReportTextInput( input.text );
for( text = input.text; *text; text++ ) for( text = input.text; *text; text++ )
{ {
int ch; int ch = (byte)*text;
if( !Q_stricmp( cl_charset.string, "utf-8" ) ) // do not pass UTF-8 sequence into the engine, convert it here
ch = (unsigned char)*text; if( !cls.accept_utf8 )
else ch = Con_UtfProcessCharForce( ch );
ch = Con_UtfProcessCharForce( (unsigned char)*text );
if( !ch ) if( !ch )
continue; continue;
@@ -448,7 +457,7 @@ SDLash_EventFilter
============= =============
*/ */
static void SDLash_EventFilter( SDL_Event *event ) static void SDLash_EventHandler( SDL_Event *event )
{ {
switch ( event->type ) switch ( event->type )
{ {
@@ -679,7 +688,7 @@ void Platform_RunEvents( void )
SDL_Event event; SDL_Event event;
while( !host.crashed && !host.shutdown_issued && SDL_PollEvent( &event ) ) while( !host.crashed && !host.shutdown_issued && SDL_PollEvent( &event ) )
SDLash_EventFilter( &event ); SDLash_EventHandler( &event );
#if XASH_PSVITA #if XASH_PSVITA
PSVita_InputUpdate(); PSVita_InputUpdate();

View File

@@ -843,6 +843,8 @@ qboolean VID_CreateWindow( int width, int height, window_mode_t window_mode )
#else // SDL_VERSION_ATLEAST( 2, 0, 0 ) #else // SDL_VERSION_ATLEAST( 2, 0, 0 )
Uint32 flags = 0; Uint32 flags = 0;
Q_strncpy( wndname, GI->title, sizeof( wndname ));
if( window_mode != WINDOW_MODE_WINDOWED ) if( window_mode != WINDOW_MODE_WINDOWED )
SetBits( flags, SDL_FULLSCREEN|SDL_HWSURFACE ); SetBits( flags, SDL_FULLSCREEN|SDL_HWSURFACE );

View File

@@ -329,6 +329,8 @@ typedef struct
int msg_realsize; // left in bytes int msg_realsize; // left in bytes
int msg_index; // for debug messages int msg_index; // for debug messages
int msg_dest; // msg destination ( MSG_ONE, MSG_ALL etc ) int msg_dest; // msg destination ( MSG_ONE, MSG_ALL etc )
int msg_rewrite_index;
int msg_rewrite_pos;
qboolean msg_started; // to avoid recursive included messages qboolean msg_started; // to avoid recursive included messages
edict_t *msg_ent; // user message member entity edict_t *msg_ent; // user message member entity
vec3_t msg_org; // user message member origin vec3_t msg_org; // user message member origin
@@ -392,8 +394,8 @@ typedef struct
//============================================================================= //=============================================================================
extern server_static_t svs; // persistant server info extern server_static_t svs RENAME_SYMBOL( "svs_" ); // persistant server info
extern server_t sv; // local server extern server_t sv RENAME_SYMBOL( "sv_" ); // local server
extern svgame_static_t svgame; // persistant game info extern svgame_static_t svgame; // persistant game info
extern areanode_t sv_areanodes[]; // AABB dynamic tree extern areanode_t sv_areanodes[]; // AABB dynamic tree
@@ -473,6 +475,7 @@ extern convar_t sv_fullupdate_penalty_time;
extern convar_t sv_log_outofband; extern convar_t sv_log_outofband;
extern convar_t sv_allow_autoaim; extern convar_t sv_allow_autoaim;
extern convar_t sv_aim; extern convar_t sv_aim;
extern convar_t sv_allow_testpacket;
//=========================================================== //===========================================================
// //
@@ -480,7 +483,7 @@ extern convar_t sv_aim;
// //
void SV_FinalMessage( const char *message, qboolean reconnect ); void SV_FinalMessage( const char *message, qboolean reconnect );
void SV_KickPlayer( sv_client_t *cl, const char *fmt, ... ) _format( 2 ); void SV_KickPlayer( sv_client_t *cl, const char *fmt, ... ) _format( 2 );
void SV_DropClient( sv_client_t *cl, qboolean crash ); void SV_DropClient( sv_client_t *cl, qboolean crash ) RENAME_SYMBOL( "SV_DropClient_" );
void SV_UpdateMovevars( qboolean initialize ); void SV_UpdateMovevars( qboolean initialize );
int SV_ModelIndex( const char *name ); int SV_ModelIndex( const char *name );
int SV_SoundIndex( const char *name ); int SV_SoundIndex( const char *name );
@@ -501,6 +504,7 @@ void SV_ActivateServer( int runPhysics );
qboolean SV_SpawnServer( const char *server, const char *startspot, qboolean background ); qboolean SV_SpawnServer( const char *server, const char *startspot, qboolean background );
model_t *SV_ModelHandle( int modelindex ); model_t *SV_ModelHandle( int modelindex );
void SV_DeactivateServer( void ); void SV_DeactivateServer( void );
void SV_FreeTestPacket( void );
// //
// sv_phys.c // sv_phys.c

View File

@@ -108,7 +108,7 @@ static void SV_GetChallenge( netadr_t from )
if( i == MAX_CHALLENGES ) if( i == MAX_CHALLENGES )
{ {
// this is the first time this client has asked for a challenge // this is the first time this client has asked for a challenge
svs.challenges[oldest].challenge = (COM_RandomLong( 0, 0xFFFF ) << 16) | COM_RandomLong( 0, 0xFFFF ); svs.challenges[oldest].challenge = (COM_RandomLong( 0, 0x7FFF ) << 16) | COM_RandomLong( 0, 0xFFFF );
svs.challenges[oldest].adr = from; svs.challenges[oldest].adr = from;
svs.challenges[oldest].time = host.realtime; svs.challenges[oldest].time = host.realtime;
svs.challenges[oldest].connected = false; svs.challenges[oldest].connected = false;
@@ -417,7 +417,7 @@ static void SV_ConnectClient( netadr_t from )
newcl->userid = g_userid++; // create unique userid newcl->userid = g_userid++; // create unique userid
newcl->state = cs_connected; newcl->state = cs_connected;
newcl->extensions = extensions & (NET_EXT_SPLITSIZE); newcl->extensions = extensions & (NET_EXT_SPLITSIZE);
Q_strncpy( newcl->useragent, protinfo, MAX_INFO_STRING ); Q_strncpy( newcl->useragent, protinfo, sizeof( newcl->useragent ));
// reset viewentities (from previous level) // reset viewentities (from previous level)
memset( newcl->viewentity, 0, sizeof( newcl->viewentity )); memset( newcl->viewentity, 0, sizeof( newcl->viewentity ));
@@ -852,7 +852,7 @@ static void SV_TestBandWidth( netadr_t from )
} }
// quickly reject invalid packets // quickly reject invalid packets
if( !svs.testpacket_buf || if( !sv_allow_testpacket.value || !svs.testpacket_buf ||
( packetsize <= FRAGMENT_MIN_SIZE ) || ( packetsize <= FRAGMENT_MIN_SIZE ) ||
( packetsize > FRAGMENT_MAX_SIZE )) ( packetsize > FRAGMENT_MAX_SIZE ))
{ {

View File

@@ -690,7 +690,7 @@ static void SV_ConSay_f( void )
} }
p = Cmd_Args(); p = Cmd_Args();
Q_strncpy( text, *p == '"' ? p + 1 : p, MAX_SYSPATH ); Q_strncpy( text, *p == '"' ? p + 1 : p, sizeof( text ));
if( *p == '"' ) if( *p == '"' )
{ {

View File

@@ -30,10 +30,8 @@ GNU General Public License for more details.
static int GAME_EXPORT pfnModelIndex( const char *m ); static int GAME_EXPORT pfnModelIndex( const char *m );
// fatpvs stuff // fatpvs stuff
static byte fatpvs[MAX_MAP_LEAFS/8]; static byte fatphs[(MAX_MAP_LEAFS+7)/8];
static byte fatphs[MAX_MAP_LEAFS/8]; static byte clientpvs[(MAX_MAP_LEAFS+7)/8]; // for find client in PVS
static byte clientpvs[MAX_MAP_LEAFS/8]; // for find client in PVS
static vec3_t viewPoint[MAX_CLIENTS];
// exports // exports
typedef void (__cdecl *LINK_ENTITY_FUNC)( entvars_t *pev ); typedef void (__cdecl *LINK_ENTITY_FUNC)( entvars_t *pev );
@@ -258,7 +256,7 @@ void GAME_EXPORT SV_SetModel( edict_t *ent, const char *modelname )
return; return;
} }
if( !modelname || modelname[0] <= ' ' ) if( !modelname || ((byte)modelname[0] ) <= ' ' )
{ {
Con_Printf( S_WARN "SV_SetModel: null name\n" ); Con_Printf( S_WARN "SV_SetModel: null name\n" );
return; return;
@@ -339,11 +337,12 @@ static qboolean SV_CheckClientVisiblity( sv_client_t *cl, const byte *mask )
if( !mask ) return true; // GoldSrc rules if( !mask ) return true; // GoldSrc rules
clientnum = cl - svs.clients; clientnum = cl - svs.clients;
VectorCopy( viewPoint[clientnum], vieworg );
// Invasion issues: wrong camera position received in ENGINE_SET_PVS // Invasion issues: wrong camera position received in ENGINE_SET_PVS
if( cl->pViewEntity && !VectorCompare( vieworg, cl->pViewEntity->v.origin )) if( cl->pViewEntity )
VectorCopy( cl->pViewEntity->v.origin, vieworg ); VectorCopy( cl->pViewEntity->v.origin, vieworg );
else
VectorCopy( cl->edict->v.origin, vieworg );
leaf = Mod_PointInLeaf( vieworg, sv.worldmodel->nodes ); leaf = Mod_PointInLeaf( vieworg, sv.worldmodel->nodes );
@@ -422,7 +421,7 @@ static int SV_Multicast( int dest, const vec3_t origin, const edict_t *ent, qboo
case MSG_PAS: case MSG_PAS:
if( origin == NULL ) return false; if( origin == NULL ) return false;
// NOTE: GoldSource not using PHS for singleplayer // NOTE: GoldSource not using PHS for singleplayer
Mod_FatPVS( origin, FATPHS_RADIUS, fatphs, world.fatbytes, false, ( svs.maxclients == 1 )); Mod_FatPVS( origin, FATPHS_RADIUS, fatphs, world.fatbytes, false, ( svs.maxclients == 1 ), true );
mask = fatphs; // using the FatPVS like a PHS mask = fatphs; // using the FatPVS like a PHS
break; break;
case MSG_PVS_R: case MSG_PVS_R:
@@ -666,7 +665,7 @@ void SV_RestartAmbientSounds( void )
#if !XASH_DEDICATED // TODO: ??? #if !XASH_DEDICATED // TODO: ???
// restart soundtrack // restart soundtrack
if( S_StreamGetCurrentState( curtrack, looptrack, &position )) if( S_StreamGetCurrentState( curtrack, sizeof( curtrack ), looptrack, sizeof( looptrack ), &position ))
{ {
SV_StartMusic( curtrack, looptrack, position ); SV_StartMusic( curtrack, looptrack, position );
} }
@@ -2501,6 +2500,62 @@ int GAME_EXPORT pfnDecalIndex( const char *m )
return -1; return -1;
} }
static int SV_CanRewriteMessage( int msg_num )
{
// feature is disabled
if( !FBitSet( host.bugcomp, BUGCOMP_MESSAGE_REWRITE_FACILITY_FLAG ))
return 0;
switch( msg_num )
{
case svc_goldsrc_spawnstaticsound:
return svc_sound;
}
return 0;
}
static qboolean SV_RewriteMessage( void )
{
vec3_t origin;
const char *sample = NULL;
float vol, attn;
int ent, pitch, flags, idx;
int cmd;
MSG_SeekToBit( &sv.multicast, svgame.msg_rewrite_pos, SEEK_SET );
cmd = MSG_ReadCmd( &sv.multicast, NS_SERVER );
switch( cmd )
{
case svc_goldsrc_spawnstaticsound:
MSG_ReadVec3Coord( &sv.multicast, origin );
idx = MSG_ReadShort( &sv.multicast );
vol = MSG_ReadByte( &sv.multicast );
attn = MSG_ReadByte( &sv.multicast ) / 64.0f;
ent = MSG_ReadShort( &sv.multicast );
pitch = MSG_ReadByte( &sv.multicast );
flags = MSG_ReadByte( &sv.multicast );
if( FBitSet( flags, SND_SENTENCE ))
sample = va( "!%i", idx );
else if( idx >= 0 && idx < MAX_SOUNDS )
sample = sv.sound_precache[idx];
if( !COM_CheckString( sample ))
{
Con_Printf( S_ERROR "%s: unrecognized sample in svc_spawnstaticsound, index %d, flags 0x%x\n", __func__, idx, flags );
return false;
}
MSG_SeekToBit( &sv.multicast, svgame.msg_rewrite_pos, SEEK_SET );
return SV_BuildSoundMsg( &sv.multicast, EDICT_NUM( ent ), CHAN_STATIC, sample, vol, attn, flags, pitch, origin );
}
return false;
}
/* /*
============= =============
pfnMessageBegin pfnMessageBegin
@@ -2518,10 +2573,24 @@ static void GAME_EXPORT pfnMessageBegin( int msg_dest, int msg_num, const float
// check range // check range
msg_num = bound( svc_bad, msg_num, 255 ); msg_num = bound( svc_bad, msg_num, 255 );
svgame.msg_rewrite_index = 0;
svgame.msg_rewrite_pos = 0;
if( msg_num <= svc_lastmsg ) if( msg_num <= svc_lastmsg )
{
// check if we should rewrite this message into something else...
if( SV_CanRewriteMessage( msg_num ))
{
svgame.msg_index = -SV_CanRewriteMessage( msg_num );
svgame.msg_name = svc_goldsrc_strings[msg_num] ? svc_goldsrc_strings[msg_num] : svc_strings[msg_num];
svgame.msg_rewrite_index = msg_num;
svgame.msg_rewrite_pos = MSG_TellBit( &sv.multicast );
}
else
{ {
svgame.msg_index = -msg_num; // this is a system message svgame.msg_index = -msg_num; // this is a system message
svgame.msg_name = svc_strings[msg_num]; svgame.msg_name = svc_strings[msg_num];
}
if( msg_num == svc_temp_entity ) if( msg_num == svc_temp_entity )
iSize = -1; // temp entity have variable size iSize = -1; // temp entity have variable size
@@ -2596,6 +2665,25 @@ static void GAME_EXPORT pfnMessageEnd( void )
return; return;
} }
if( svgame.msg_rewrite_index != 0 )
{
if( SV_RewriteMessage( ))
{
if( MSG_CheckOverflow( &sv.multicast ))
{
Con_Printf( S_ERROR "MessageEnd: %s has overflow multicast buffer (post-rewrite)\n", name );
MSG_Clear( &sv.multicast );
return;
}
}
else
{
Con_Printf( S_ERROR "MessageEnd: failed to rewrite message %s\n", name );
MSG_Clear( &sv.multicast );
return;
}
}
// check for system message // check for system message
if( svgame.msg_index < 0 ) if( svgame.msg_index < 0 )
{ {
@@ -2662,9 +2750,7 @@ static void GAME_EXPORT pfnMessageEnd( void )
// update some messages in case their was format was changed and we want to keep backward compatibility // update some messages in case their was format was changed and we want to keep backward compatibility
if( svgame.msg_index < 0 ) if( svgame.msg_index < 0 )
{ {
int svc_msg = abs( svgame.msg_index ); if(( svgame.msg_index == -svc_finale || svgame.msg_index == -svc_cutscene ) && svgame.msg_realsize == 0 )
if(( svc_msg == svc_finale || svc_msg == svc_cutscene ) && svgame.msg_realsize == 0 )
MSG_WriteChar( &sv.multicast, 0 ); // write null string MSG_WriteChar( &sv.multicast, 0 ); // write null string
} }
@@ -4070,7 +4156,7 @@ void GAME_EXPORT SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word
// setup pvs cluster for invoker // setup pvs cluster for invoker
if( !FBitSet( flags, FEV_GLOBAL )) if( !FBitSet( flags, FEV_GLOBAL ))
{ {
Mod_FatPVS( pvspoint, FATPHS_RADIUS, fatphs, world.fatbytes, false, ( svs.maxclients == 1 )); Mod_FatPVS( pvspoint, FATPHS_RADIUS, fatphs, world.fatbytes, false, ( svs.maxclients == 1 ), true );
mask = fatphs; // using the FatPVS like a PHS mask = fatphs; // using the FatPVS like a PHS
} }
@@ -4095,7 +4181,16 @@ void GAME_EXPORT SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word
continue; continue;
} }
if( FBitSet( flags, FEV_NOTHOST ) && cl == sv.current_client && FBitSet( cl->flags, FCL_LOCAL_WEAPONS )) // a1ba: GoldSrc never cleans up host_client pointer (similar to sv.current_client)
// so it's always points at some client and in singleplayer this check always succeedes
// in Xash, however, sv.current_client might be reset and set to NULL
// this is especially dangerous when weapons play events in Think functions
//
// IMHO, it doesn't make sense to me to compare it against current client when we have
// invoker edict pointer but to preserve behaviour check for them both
//
// if it breaks some mods, probably sv.current_client semantics must be reworked to match GoldSrc
if( FBitSet( flags, FEV_NOTHOST ) && ( cl == sv.current_client || cl->edict == pInvoker ) && FBitSet( cl->flags, FCL_LOCAL_WEAPONS ))
continue; // will be played on client side continue; // will be played on client side
if( FBitSet( flags, FEV_HOSTONLY ) && cl->edict != pInvoker ) if( FBitSet( flags, FEV_HOSTONLY ) && cl->edict != pInvoker )
@@ -4182,43 +4277,16 @@ so we can't use a single PVS point
*/ */
static byte *GAME_EXPORT pfnSetFatPVS( const float *org ) static byte *GAME_EXPORT pfnSetFatPVS( const float *org )
{ {
qboolean fullvis = false; static byte fatpvs[(MAX_MAP_LEAFS+7)/8];
qboolean fullvis = false, merge = false;
if( !sv.worldmodel->visdata || sv_novis.value || !org || CL_DisableVisibility( )) if( !sv.worldmodel->visdata || sv_novis.value || !org || CL_DisableVisibility( ))
fullvis = true; fullvis = true;
// portals can't change viewpoint! if( FBitSet( sv.hostflags, SVF_MERGE_VISIBILITY ))
if( !FBitSet( sv.hostflags, SVF_MERGE_VISIBILITY )) merge = true;
{
vec3_t viewPos, offset;
qboolean client_active = pfnGetCurrentPlayer() != -1;
// see code from client.cpp for understanding: Mod_FatPVS( org, FATPVS_RADIUS, fatpvs, world.fatbytes, merge, fullvis, false );
// org = pView->v.origin + pView->v.view_ofs;
// if ( pView->v.flags & FL_DUCKING )
// {
// org = org + ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN );
// }
// so we have unneeded duck calculations who have affect when player
// is ducked into water. Remove offset to restore right PVS position
if( client_active && FBitSet( sv.current_client->edict->v.flags, FL_DUCKING ))
{
VectorSubtract( svgame.pmove->player_mins[0], svgame.pmove->player_mins[1], offset );
VectorSubtract( org, offset, viewPos );
}
else VectorCopy( org, viewPos );
// build a new PVS frame
Mod_FatPVS( viewPos, FATPVS_RADIUS, fatpvs, world.fatbytes, false, fullvis );
if( client_active )
VectorCopy( viewPos, viewPoint[pfnGetCurrentPlayer()] );
}
else
{
// merge PVS
Mod_FatPVS( org, FATPVS_RADIUS, fatpvs, world.fatbytes, true, fullvis );
}
return fatpvs; return fatpvs;
} }
@@ -4233,40 +4301,15 @@ so we can't use a single PHS point
*/ */
static byte *GAME_EXPORT pfnSetFatPAS( const float *org ) static byte *GAME_EXPORT pfnSetFatPAS( const float *org )
{ {
qboolean fullvis = false; qboolean fullvis = false, merge = false;
if( !sv.worldmodel->visdata || sv_novis.value || !org || CL_DisableVisibility( )) if( !sv.worldmodel->visdata || sv_novis.value || !org || CL_DisableVisibility( ))
fullvis = true; fullvis = true;
// portals can't change viewpoint! if( FBitSet( sv.hostflags, SVF_MERGE_VISIBILITY ))
if( !FBitSet( sv.hostflags, SVF_MERGE_VISIBILITY )) merge = true;
{
vec3_t viewPos, offset;
qboolean client_active = pfnGetCurrentPlayer() != -1;
// see code from client.cpp for understanding: Mod_FatPVS( org, FATPHS_RADIUS, fatphs, world.fatbytes, merge, fullvis, true );
// org = pView->v.origin + pView->v.view_ofs;
// if ( pView->v.flags & FL_DUCKING )
// {
// org = org + ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN );
// }
// so we have unneeded duck calculations who have affect when player
// is ducked into water. Remove offset to restore right PVS position
if( client_active && FBitSet( sv.current_client->edict->v.flags, FL_DUCKING ))
{
VectorSubtract( svgame.pmove->player_mins[0], svgame.pmove->player_mins[1], offset );
VectorSubtract( org, offset, viewPos );
}
else VectorCopy( org, viewPos );
// build a new PHS frame
Mod_FatPVS( viewPos, FATPHS_RADIUS, fatphs, world.fatbytes, false, fullvis );
}
else
{
// merge PHS
Mod_FatPVS( org, FATPHS_RADIUS, fatphs, world.fatbytes, true, fullvis );
}
return fatphs; return fatphs;
} }

View File

@@ -906,6 +906,21 @@ qboolean CRC32_MapFile( dword *crcvalue, const char *filename, qboolean multipla
return 1; return 1;
} }
void SV_FreeTestPacket( void )
{
if( svs.testpacket_buf )
{
Mem_Free( svs.testpacket_buf );
svs.testpacket_buf = NULL;
}
if( svs.testpacket_crcs )
{
Mem_Free( svs.testpacket_crcs );
svs.testpacket_crcs = NULL;
}
}
/* /*
================ ================
SV_GenerateTestPacket SV_GenerateTestPacket
@@ -917,7 +932,13 @@ static void SV_GenerateTestPacket( void )
uint32_t crc; uint32_t crc;
file_t *file; file_t *file;
byte *filepos; byte *filepos;
int i, filesize; int i;
if( !sv_allow_testpacket.value )
{
SV_FreeTestPacket();
return;
}
// testpacket already generated once, exit // testpacket already generated once, exit
// testpacket and lookup table takes ~300k of memory // testpacket and lookup table takes ~300k of memory

View File

@@ -48,7 +48,7 @@ CVAR_DEFINE_AUTO( sv_proxies, "1", FCVAR_SERVER, "maximum count of allowed proxi
CVAR_DEFINE_AUTO( sv_send_logos, "1", 0, "send custom decal logo to other players so they can view his too" ); CVAR_DEFINE_AUTO( sv_send_logos, "1", 0, "send custom decal logo to other players so they can view his too" );
CVAR_DEFINE_AUTO( sv_send_resources, "1", 0, "allow to download missed resources for players" ); CVAR_DEFINE_AUTO( sv_send_resources, "1", 0, "allow to download missed resources for players" );
CVAR_DEFINE_AUTO( sv_logbans, "0", 0, "print into the server log info about player bans" ); CVAR_DEFINE_AUTO( sv_logbans, "0", 0, "print into the server log info about player bans" );
CVAR_DEFINE_AUTO( sv_allow_upload, "1", FCVAR_SERVER, "allow uploading custom resources on a server" ); CVAR_DEFINE( sv_allow_upload, "sv_allowupload", "1", FCVAR_SERVER, "allow uploading custom resources on a server" );
CVAR_DEFINE( sv_allow_download, "sv_allowdownload", "1", FCVAR_SERVER, "allow downloading custom resources to the client" ); CVAR_DEFINE( sv_allow_download, "sv_allowdownload", "1", FCVAR_SERVER, "allow downloading custom resources to the client" );
static CVAR_DEFINE_AUTO( sv_allow_dlfile, "1", 0, "compatibility cvar, does nothing" ); static CVAR_DEFINE_AUTO( sv_allow_dlfile, "1", 0, "compatibility cvar, does nothing" );
CVAR_DEFINE_AUTO( sv_uploadmax, "0.5", FCVAR_SERVER, "max size to upload custom resources (500 kB as default)" ); CVAR_DEFINE_AUTO( sv_uploadmax, "0.5", FCVAR_SERVER, "max size to upload custom resources (500 kB as default)" );
@@ -150,6 +150,8 @@ CVAR_DEFINE_AUTO( sv_userinfo_penalty_attempts, "4", FCVAR_ARCHIVE, "if max atte
CVAR_DEFINE_AUTO( sv_fullupdate_penalty_time, "1", FCVAR_ARCHIVE, "allow fullupdate command only once in this timewindow (set 0 to disable)" ); CVAR_DEFINE_AUTO( sv_fullupdate_penalty_time, "1", FCVAR_ARCHIVE, "allow fullupdate command only once in this timewindow (set 0 to disable)" );
CVAR_DEFINE_AUTO( sv_log_outofband, "0", FCVAR_ARCHIVE, "log out of band messages, can be useful for server admins and for engine debugging" ); CVAR_DEFINE_AUTO( sv_log_outofband, "0", FCVAR_ARCHIVE, "log out of band messages, can be useful for server admins and for engine debugging" );
CVAR_DEFINE_AUTO( sv_allow_testpacket, "1", FCVAR_ARCHIVE, "allow generating and sending a big blob of data to test maximum packet size" );
//============================================================================ //============================================================================
/* /*
================ ================
@@ -973,6 +975,7 @@ void SV_Init( void )
Cvar_RegisterVariable( &sv_userinfo_penalty_attempts ); Cvar_RegisterVariable( &sv_userinfo_penalty_attempts );
Cvar_RegisterVariable( &sv_fullupdate_penalty_time ); Cvar_RegisterVariable( &sv_fullupdate_penalty_time );
Cvar_RegisterVariable( &sv_log_outofband ); Cvar_RegisterVariable( &sv_log_outofband );
Cvar_RegisterVariable( &sv_allow_testpacket );
// when we in developer-mode automatically turn cheats on // when we in developer-mode automatically turn cheats on
if( host_developer.value ) Cvar_SetValue( "sv_cheats", 1.0f ); if( host_developer.value ) Cvar_SetValue( "sv_cheats", 1.0f );
@@ -1115,6 +1118,9 @@ void SV_Shutdown( const char *finalmsg )
SV_FreeClients(); SV_FreeClients();
svs.maxclients = 0; svs.maxclients = 0;
// release test packet blob
SV_FreeTestPacket();
// release all models // release all models
Mod_FreeAll(); Mod_FreeAll();

View File

@@ -418,10 +418,8 @@ static void GAME_EXPORT pfnPlaybackEventFull( int flags, int clientindex, word e
ent = EDICT_NUM( clientindex + 1 ); ent = EDICT_NUM( clientindex + 1 );
if( !SV_IsValidEdict( ent )) return; if( !SV_IsValidEdict( ent )) return;
if( Host_IsDedicated() ) // GoldSrc always sets FEV_NOTHOST in PMove version of this function
flags |= FEV_NOTHOST; // no local clients for dedicated server SV_PlaybackEventFull( flags | FEV_NOTHOST, ent, eventindex,
SV_PlaybackEventFull( flags, ent, eventindex,
delay, origin, angles, delay, origin, angles,
fparam1, fparam2, fparam1, fparam2,
iparam1, iparam2, iparam1, iparam2,
@@ -590,7 +588,7 @@ static void SV_SetupPMove( playermove_t *pmove, sv_client_t *cl, usercmd_t *ucmd
pmove->cmd = *ucmd; // setup current cmds pmove->cmd = *ucmd; // setup current cmds
pmove->runfuncs = true; pmove->runfuncs = true;
Q_strncpy( pmove->physinfo, physinfo, MAX_INFO_STRING ); Q_strncpy( pmove->physinfo, physinfo, sizeof( pmove->physinfo ));
// setup physents // setup physents
pmove->numvisent = 0; pmove->numvisent = 0;

View File

@@ -652,7 +652,7 @@ static void DirectoryCopy( const char *pPath, file_t *pFile )
fileSize = FS_FileLength( pCopy ); fileSize = FS_FileLength( pCopy );
memset( szName, 0, sizeof( szName )); // clearing the string to prevent garbage in output file memset( szName, 0, sizeof( szName )); // clearing the string to prevent garbage in output file
Q_strncpy( szName, COM_FileWithoutPath( t->filenames[i] ), MAX_OSPATH ); Q_strncpy( szName, COM_FileWithoutPath( t->filenames[i] ), sizeof( szName ));
FS_Write( pFile, szName, MAX_OSPATH ); FS_Write( pFile, szName, MAX_OSPATH );
FS_Write( pFile, &fileSize, sizeof( int )); FS_Write( pFile, &fileSize, sizeof( int ));
FS_FileCopy( pFile, pCopy, fileSize ); FS_FileCopy( pFile, pCopy, fileSize );
@@ -1202,7 +1202,7 @@ static void SaveClientState( SAVERESTOREDATA *pSaveData, const char *level, int
header.soundCount = S_GetCurrentDynamicSounds( soundInfo, MAX_CHANNELS ); header.soundCount = S_GetCurrentDynamicSounds( soundInfo, MAX_CHANNELS );
#if !XASH_DEDICATED #if !XASH_DEDICATED
// music not reqiured to save position: it's just continue playing on a next level // music not reqiured to save position: it's just continue playing on a next level
S_StreamGetCurrentState( header.introTrack, header.mainTrack, &header.trackPosition ); S_StreamGetCurrentState( header.introTrack, sizeof( header.introTrack ), header.mainTrack, sizeof( header.mainTrack ), &header.trackPosition );
#endif #endif
} }

View File

@@ -358,6 +358,53 @@ static hull_t *SV_HullForStudioModel( edict_t *ent, vec3_t mins, vec3_t maxs, ve
return SV_HullForEntity( ent, mins, maxs, offset ); return SV_HullForEntity( ent, mins, maxs, offset );
} }
/*
===============================================================================
ENTITY LINKING
===============================================================================
*/
/*
===============
ClearLink
ClearLink is used for new headnodes
===============
*/
static void ClearLink( link_t *l )
{
l->prev = l->next = l;
}
/*
===============
RemoveLink
remove link from chain
===============
*/
static void RemoveLink( link_t *l )
{
l->next->prev = l->prev;
l->prev->next = l->next;
}
/*
===============
InsertLinkBefore
kept trigger and solid entities seperate
===============
*/
static void InsertLinkBefore( link_t *l, link_t *before )
{
l->next = before;
l->prev = before->prev;
l->prev->next = l;
l->next->prev = l;
}
/* /*
=============================================================================== ===============================================================================

View File

@@ -21,16 +21,16 @@ def options(opt):
help = 'enable custom swap allocator. For devices with no swap support') help = 'enable custom swap allocator. For devices with no swap support')
grp.add_option('--enable-legacy-sdl', action = 'store_true', dest = 'SDL12', default = False, grp.add_option('--enable-legacy-sdl', action = 'store_true', dest = 'SDL12', default = False,
help = 'enable using SDL1.2 instead of SDL2(not recommended) [default: %default]') help = 'enable using SDL1.2 instead of SDL2(not recommended) [default: %(default)s]')
grp.add_option('--enable-static-binary', action = 'store_true', dest = 'STATIC', default = False, grp.add_option('--enable-static-binary', action = 'store_true', dest = 'STATIC', default = False,
help = 'build static binary(not recommended, --single-binary required) [default: %default]') help = 'build static binary(not recommended, --single-binary required) [default: %(default)s]')
grp.add_option('--enable-engine-tests', action = 'store_true', dest = 'ENGINE_TESTS', default = False, grp.add_option('--enable-engine-tests', action = 'store_true', dest = 'ENGINE_TESTS', default = False,
help = 'embed tests into the engine, jump into them by -runtests command line switch [default: %default]') help = 'embed tests into the engine, jump into them by -runtests command line switch [default: %(default)s]')
grp.add_option('--enable-engine-fuzz', action = 'store_true', dest = 'ENGINE_FUZZ', default = False, grp.add_option('--enable-engine-fuzz', action = 'store_true', dest = 'ENGINE_FUZZ', default = False,
help = 'add LLVM libFuzzer [default: %default]' ) help = 'add LLVM libFuzzer [default: %(default)s]' )
opt.load('sdl2') opt.load('sdl2')

View File

@@ -1363,8 +1363,13 @@ static qboolean FS_FindLibrary( const char *dllname, qboolean directpath, fs_dll
if( index >= 0 && !dllInfo->encrypted && search ) if( index >= 0 && !dllInfo->encrypted && search )
{ {
Q_snprintf( dllInfo->fullPath, sizeof( dllInfo->fullPath ), // gamedll might resolve it's own path using dladdr()
"%s%s", search->filename, dllInfo->shortPath ); // combine it with engine returned path to gamedir
// it might lead to double gamedir like this
// - valve/valve/dlls/hl.so
// instead of expected
// - valve/dlls/hl.so
Q_snprintf( dllInfo->fullPath, sizeof( dllInfo->fullPath ), "%s/%s%s", fs_rootdir, search->filename, dllInfo->shortPath );
dllInfo->custom_loader = false; // we can loading from disk and use normal debugging dllInfo->custom_loader = false; // we can loading from disk and use normal debugging
} }
else else
@@ -2120,7 +2125,7 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
{ {
fs_offset_t done; fs_offset_t done;
fs_offset_t nb; fs_offset_t nb;
size_t count; fs_offset_t count;
// nothing to copy // nothing to copy
if( buffersize == 0 ) return 1; if( buffersize == 0 ) return 1;
@@ -2139,12 +2144,13 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
if( file->buff_ind < file->buff_len ) if( file->buff_ind < file->buff_len )
{ {
count = file->buff_len - file->buff_ind; count = file->buff_len - file->buff_ind;
count = ( buffersize > count ) ? count : (fs_offset_t)buffersize;
done += ( buffersize > count ) ? (fs_offset_t)count : (fs_offset_t)buffersize; done += count;
memcpy( buffer, &file->buff[file->buff_ind], done ); memcpy( buffer, &file->buff[file->buff_ind], count );
file->buff_ind += done; file->buff_ind += count;
buffersize -= done; buffersize -= count;
if( buffersize == 0 ) if( buffersize == 0 )
return done; return done;
} }
@@ -2158,10 +2164,10 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
// if we have a lot of data to get, put them directly into "buffer" // if we have a lot of data to get, put them directly into "buffer"
if( buffersize > sizeof( file->buff ) / 2 ) if( buffersize > sizeof( file->buff ) / 2 )
{ {
if( count > buffersize ) if( count > (fs_offset_t)buffersize )
count = buffersize; count = (fs_offset_t)buffersize;
lseek( file->handle, file->offset + file->position, SEEK_SET ); lseek( file->handle, file->offset + file->position, SEEK_SET );
nb = read( file->handle, (byte *)buffer + done, count ); nb = read( file->handle, &((byte *)buffer)[done], count );
if( nb > 0 ) if( nb > 0 )
{ {
@@ -2173,8 +2179,8 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
} }
else else
{ {
if( count > sizeof( file->buff )) if( count > (fs_offset_t)sizeof( file->buff ))
count = sizeof( file->buff ); count = (fs_offset_t)sizeof( file->buff );
lseek( file->handle, file->offset + file->position, SEEK_SET ); lseek( file->handle, file->offset + file->position, SEEK_SET );
nb = read( file->handle, file->buff, count ); nb = read( file->handle, file->buff, count );
@@ -2419,7 +2425,7 @@ static void *FS_CustomAlloc( size_t size )
static void FS_CustomFree( void *data ) static void FS_CustomFree( void *data )
{ {
return Mem_Free( data ); Mem_Free( data );
} }
/* /*

View File

@@ -31,7 +31,7 @@ extern "C"
{ {
#endif // __cplusplus #endif // __cplusplus
#define FS_API_VERSION 2 // not stable yet! #define FS_API_VERSION 3 // not stable yet!
#define FS_API_CREATEINTERFACE_TAG "XashFileSystem002" // follow FS_API_VERSION!!! #define FS_API_CREATEINTERFACE_TAG "XashFileSystem002" // follow FS_API_VERSION!!!
#define FILESYSTEM_INTERFACE_VERSION "VFileSystem009" // never change this! #define FILESYSTEM_INTERFACE_VERSION "VFileSystem009" // never change this!
@@ -121,8 +121,8 @@ typedef enum
typedef struct fs_dllinfo_t typedef struct fs_dllinfo_t
{ {
string fullPath; char fullPath[2048]; // absolute disk path
string shortPath; string shortPath; // vfs path
qboolean encrypted; qboolean encrypted;
qboolean custom_loader; qboolean custom_loader;
} fs_dllinfo_t; } fs_dllinfo_t;

View File

@@ -12,7 +12,7 @@ def options(opt):
grp = opt.add_option_group('Game launcher options') grp = opt.add_option_group('Game launcher options')
grp.add_option('--disable-menu-changegame', action = 'store_true', dest = 'DISABLE_MENU_CHANGEGAME', default = False, grp.add_option('--disable-menu-changegame', action = 'store_true', dest = 'DISABLE_MENU_CHANGEGAME', default = False,
help = 'disable changing the game from the menu [default: %default]') help = 'disable changing the game from the menu [default: %(default)s]')
def configure(conf): def configure(conf):
if conf.env.DEST_OS == 'win32': if conf.env.DEST_OS == 'win32':

View File

@@ -434,7 +434,7 @@ returns hash key for string
*/ */
uint COM_HashKey( const char *string, uint hashSize ) uint COM_HashKey( const char *string, uint hashSize )
{ {
int hashKey = 5381; uint hashKey = 5381;
unsigned char i; unsigned char i;
while(( i = *string++ )) while(( i = *string++ ))

View File

@@ -18,7 +18,6 @@ GNU General Public License for more details.
#include "const.h" #include "const.h"
#include <math.h> #include <math.h>
#include <stdarg.h> #include <stdarg.h>
#include <ctype.h>
#include <time.h> #include <time.h>
#include "stdio.h" #include "stdio.h"
#include "crtlib.h" #include "crtlib.h"
@@ -38,26 +37,6 @@ void Q_strnlwr( const char *in, char *out, size_t size_out )
*out = '\0'; *out = '\0';
} }
qboolean Q_isdigit( const char *str )
{
if( str && *str )
{
while( isdigit( *str )) str++;
if( !*str ) return true;
}
return false;
}
qboolean Q_isspace( const char *str )
{
if( str && *str )
{
while( isspace( *str ) ) str++;
if( !*str ) return true;
}
return false;
}
size_t Q_colorstr( const char *string ) size_t Q_colorstr( const char *string )
{ {
size_t len; size_t len;
@@ -81,59 +60,6 @@ size_t Q_colorstr( const char *string )
return len; return len;
} }
char Q_toupper( const char in )
{
char out;
if( in >= 'a' && in <= 'z' )
out = in + 'A' - 'a';
else out = in;
return out;
}
char Q_tolower( const char in )
{
char out;
if( in >= 'A' && in <= 'Z' )
out = in + 'a' - 'A';
else out = in;
return out;
}
size_t Q_strncat( char *dst, const char *src, size_t size )
{
register char *d = dst;
register const char *s = src;
register size_t n = size;
size_t dlen;
if( !dst || !src || !size )
return 0;
// find the end of dst and adjust bytes left but don't go past end
while( n-- != 0 && *d != '\0' ) d++;
dlen = d - dst;
n = size - dlen;
if( n == 0 ) return( dlen + Q_strlen( s ));
while( *s != '\0' )
{
if( n != 1 )
{
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return( dlen + ( s - src )); // count does not include NULL
}
int Q_atoi( const char *str ) int Q_atoi( const char *str )
{ {
int val = 0; int val = 0;
@@ -253,13 +179,11 @@ float Q_atof( const char *str )
void Q_atov( float *vec, const char *str, size_t siz ) void Q_atov( float *vec, const char *str, size_t siz )
{ {
string buffer; const char *pstr, *pfront;
char *pstr, *pfront;
int j; int j;
Q_strncpy( buffer, str, sizeof( buffer ));
memset( vec, 0, sizeof( vec_t ) * siz ); memset( vec, 0, sizeof( vec_t ) * siz );
pstr = pfront = buffer; pstr = pfront = str;
for( j = 0; j < siz; j++ ) for( j = 0; j < siz; j++ )
{ {
@@ -350,6 +274,13 @@ const byte *Q_memmem( const byte *haystack, size_t haystacklen, const byte *need
return NULL; return NULL;
} }
void Q_memor( byte *XASH_RESTRICT dst, const byte *XASH_RESTRICT src, size_t len )
{
size_t i;
for( i = 0; i < len; i++ ) // msvc likes to optimize this loop form
dst[i] |= src[i];
}
const char* Q_timestamp( int format ) const char* Q_timestamp( int format )
{ {
static string timestamp; static string timestamp;
@@ -394,7 +325,7 @@ const char* Q_timestamp( int format )
return timestamp; return timestamp;
} }
#if !defined( HAVE_STRCASESTR ) #if !HAVE_STRCASESTR
char *Q_stristr( const char *string, const char *string2 ) char *Q_stristr( const char *string, const char *string2 )
{ {
int c; int c;
@@ -721,14 +652,14 @@ void COM_ReplaceExtension( char *path, const char *extension, size_t size )
COM_RemoveLineFeed COM_RemoveLineFeed
============ ============
*/ */
void COM_RemoveLineFeed( char *str ) void COM_RemoveLineFeed( char *str, size_t bufsize )
{ {
while( *str != '\0' ) size_t i;
for( i = 0; i < bufsize && *str != '\0'; i++, str++ )
{ {
if( *str == '\r' || *str == '\n' ) if( *str == '\r' || *str == '\n' )
*str = '\0'; *str = '\0';
++str;
} }
} }

View File

@@ -18,6 +18,7 @@ GNU General Public License for more details.
#include <string.h> #include <string.h>
#include <stdarg.h> #include <stdarg.h>
#include <ctype.h>
#include "build.h" #include "build.h"
#include "xash3d_types.h" #include "xash3d_types.h"
@@ -44,6 +45,10 @@ enum
#define PFILE_TOKEN_MAX_LENGTH 1024 #define PFILE_TOKEN_MAX_LENGTH 1024
#define PFILE_FS_TOKEN_MAX_LENGTH 512 #define PFILE_FS_TOKEN_MAX_LENGTH 512
#ifdef __cplusplus
#define restrict
#endif // __cplusplus
// //
// build.c // build.c
// //
@@ -63,11 +68,6 @@ const char *Q_buildbranch( void );
void Q_strnlwr( const char *in, char *out, size_t size_out ); void Q_strnlwr( const char *in, char *out, size_t size_out );
#define Q_strlen( str ) (( str ) ? strlen(( str )) : 0 ) #define Q_strlen( str ) (( str ) ? strlen(( str )) : 0 )
size_t Q_colorstr( const char *string ); size_t Q_colorstr( const char *string );
char Q_toupper( const char in );
char Q_tolower( const char in );
size_t Q_strncat( char *dst, const char *src, size_t siz );
qboolean Q_isdigit( const char *str );
qboolean Q_isspace( const char *str );
int Q_atoi( const char *str ); int Q_atoi( const char *str );
float Q_atof( const char *str ); float Q_atof( const char *str );
void Q_atov( float *vec, const char *str, size_t siz ); void Q_atov( float *vec, const char *str, size_t siz );
@@ -76,6 +76,7 @@ void Q_atov( float *vec, const char *str, size_t siz );
qboolean Q_stricmpext( const char *pattern, const char *text ); qboolean Q_stricmpext( const char *pattern, const char *text );
qboolean Q_strnicmpext( const char *pattern, const char *text, size_t minimumlen ); qboolean Q_strnicmpext( const char *pattern, const char *text, size_t minimumlen );
const byte *Q_memmem( const byte *haystack, size_t haystacklen, const byte *needle, size_t needlelen ); const byte *Q_memmem( const byte *haystack, size_t haystacklen, const byte *needle, size_t needlelen );
void Q_memor( byte *XASH_RESTRICT dst, const byte *XASH_RESTRICT src, size_t len );
const char *Q_timestamp( int format ); const char *Q_timestamp( int format );
int Q_vsnprintf( char *buffer, size_t buffersize, const char *format, va_list args ); int Q_vsnprintf( char *buffer, size_t buffersize, const char *format, va_list args );
int Q_snprintf( char *buffer, size_t buffersize, const char *format, ... ) _format( 3 ); int Q_snprintf( char *buffer, size_t buffersize, const char *format, ... ) _format( 3 );
@@ -90,7 +91,7 @@ void COM_ReplaceExtension( char *path, const char *extension, size_t size );
void COM_ExtractFilePath( const char *path, char *dest ); void COM_ExtractFilePath( const char *path, char *dest );
const char *COM_FileWithoutPath( const char *in ); const char *COM_FileWithoutPath( const char *in );
void COM_StripExtension( char *path ); void COM_StripExtension( char *path );
void COM_RemoveLineFeed( char *str ); void COM_RemoveLineFeed( char *str, size_t bufsize );
void COM_FixSlashes( char *pname ); void COM_FixSlashes( char *pname );
void COM_PathSlashFix( char *path ); void COM_PathSlashFix( char *path );
char COM_Hex2Char( uint8_t hex ); char COM_Hex2Char( uint8_t hex );
@@ -103,91 +104,186 @@ char *COM_ParseFileSafe( char *data, char *token, const int size, unsigned int f
int matchpattern( const char *in, const char *pattern, qboolean caseinsensitive ); int matchpattern( const char *in, const char *pattern, qboolean caseinsensitive );
int matchpattern_with_separator( const char *in, const char *pattern, qboolean caseinsensitive, const char *separators, qboolean wildcard_least_one ); int matchpattern_with_separator( const char *in, const char *pattern, qboolean caseinsensitive, const char *separators, qboolean wildcard_least_one );
// libc implementations static inline char Q_toupper( const char in )
{
char out;
if( in >= 'a' && in <= 'z' )
out = in + 'A' - 'a';
else out = in;
return out;
}
static inline char Q_tolower( const char in )
{
char out;
if( in >= 'A' && in <= 'Z' )
out = in + 'a' - 'A';
else out = in;
return out;
}
static inline qboolean Q_isdigit( const char *str )
{
if( likely( str && *str ))
{
while( isdigit( *str )) str++;
if( !*str ) return true;
}
return false;
}
static inline qboolean Q_isspace( const char *str )
{
if( likely( str && *str ))
{
while( isspace( *str ) ) str++;
if( !*str ) return true;
}
return false;
}
static inline int Q_strcmp( const char *s1, const char *s2 ) static inline int Q_strcmp( const char *s1, const char *s2 )
{ {
return unlikely(!s1) ? if( likely( s1 && s2 ))
( !s2 ? 0 : -1 ) : return strcmp( s1, s2 );
( unlikely(!s2) ? 1 : strcmp( s1, s2 )); return ( s1 ? 1 : 0 ) - ( s2 ? 1 : 0 );
} }
static inline int Q_strncmp( const char *s1, const char *s2, size_t n ) static inline int Q_strncmp( const char *s1, const char *s2, size_t n )
{ {
return unlikely(!s1) ? if( likely( s1 && s2 ))
( !s2 ? 0 : -1 ) : return strncmp( s1, s2, n );
( unlikely(!s2) ? 1 : strncmp( s1, s2, n )); return ( s1 ? 1 : 0 ) - ( s2 ? 1 : 0 );
} }
static inline char *Q_strstr( const char *s1, const char *s2 ) static inline char *Q_strstr( const char *s1, const char *s2 )
{ {
return unlikely( !s1 || !s2 ) ? NULL : (char*)strstr( s1, s2 ); if( likely( s1 && s2 ))
return (char *)strstr( s1, s2 );
return NULL;
} }
// Q_strncpy is the same as strlcpy // libc extensions, be careful what to enable or what not
static inline size_t Q_strncpy( char *dst, const char *src, size_t siz ) static inline size_t Q_strncpy( char *dst, const char *src, size_t size )
{ {
#if HAVE_STRLCPY
if( unlikely( !dst || !src || !size ))
return 0;
return strlcpy( dst, src, size );
#else
size_t len; size_t len;
if( unlikely( !dst || !src || !size ))
if( unlikely( !dst || !src || !siz ))
return 0; return 0;
len = strlen( src ); len = strlen( src );
if( len + 1 > siz ) // check if truncate if( len + 1 > size ) // check if truncate
{ {
memcpy( dst, src, siz - 1 ); memcpy( dst, src, size - 1 );
dst[siz - 1] = 0; dst[size - 1] = 0;
} }
else memcpy( dst, src, len + 1 ); else memcpy( dst, src, len + 1 );
return len; // count does not include NULL return len; // count does not include NULL
#endif
} }
// libc extensions, be careful static inline size_t Q_strncat( char *dst, const char *src, size_t size )
{
#if HAVE_STRLCAT
if( unlikely( !dst || !src || !size ))
return 0;
return strlcat( dst, src, size );
#else
char *d = dst;
const char *s = src;
size_t n = size;
size_t dlen;
#if XASH_WIN32 if( unlikely( !dst || !src || !size ))
#define strcasecmp stricmp return 0;
#define strncasecmp strnicmp
#endif // XASH_WIN32
// find the end of dst and adjust bytes left but don't go past end
while( n-- != 0 && *d != '\0' ) d++;
dlen = d - dst;
n = size - dlen;
if( n == 0 ) return( dlen + Q_strlen( s ));
while( *s != '\0' )
{
if( n != 1 )
{
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return( dlen + ( s - src )); // count does not include NULL
#endif
}
#if HAVE_STRICMP || HAVE_STRCASECMP
static inline int Q_stricmp( const char *s1, const char *s2 ) static inline int Q_stricmp( const char *s1, const char *s2 )
{ {
return unlikely(!s1) ? if( likely( s1 && s2 ))
( !s2 ? 0 : -1 ) : {
( unlikely(!s2) ? 1 : strcasecmp( s1, s2 )); #if HAVE_STRICMP
return stricmp( s1, s2 );
#elif HAVE_STRCASECMP
return strcasecmp( s1, s2 );
#endif
} }
return ( s1 ? 1 : 0 ) - ( s2 ? 1 : 0 );
}
#else
int Q_stricmp( const char *s1, const char *s2 );
#endif
#if HAVE_STRICMP || HAVE_STRCASECMP
static inline int Q_strnicmp( const char *s1, const char *s2, size_t n ) static inline int Q_strnicmp( const char *s1, const char *s2, size_t n )
{ {
return unlikely(!s1) ? if( likely( s1 && s2 ))
( !s2 ? 0 : -1 ) : {
( unlikely(!s2) ? 1 : strncasecmp( s1, s2, n )); #if HAVE_STRICMP
} return strnicmp( s1, s2, n );
#elif HAVE_STRCASECMP
#if defined( HAVE_STRCASESTR ) return strncasecmp( s1, s2, n );
#if XASH_WIN32
#define strcasestr stristr
#endif #endif
}
return ( s1 ? 1 : 0 ) - ( s2 ? 1 : 0 );
}
#else
int Q_strnicmp( const char *s1, const char *s2, size_t n );
#endif
#if HAVE_STRCASESTR
static inline char *Q_stristr( const char *s1, const char *s2 ) static inline char *Q_stristr( const char *s1, const char *s2 )
{ {
return unlikely( !s1 || !s2 ) ? NULL : (char *)strcasestr( s1, s2 ); if( likely( s1 && s2 ))
return (char *)strcasestr( s1, s2 );
return NULL;
} }
#else // defined( HAVE_STRCASESTR ) #else // !HAVE_STRCASESTR
char *Q_stristr( const char *s1, const char *s2 ); char *Q_stristr( const char *s1, const char *s2 );
#endif // defined( HAVE_STRCASESTR ) #endif // !HAVE_STRCASESTR
#if defined( HAVE_STRCHRNUL ) #if HAVE_STRCHRNUL
#define Q_strchrnul strchrnul #define Q_strchrnul strchrnul
#else #else // !HAVE_STRCHRNUL
static inline const char *Q_strchrnul( const char *s, int c ) static inline const char *Q_strchrnul( const char *s, int c )
{ {
const char *p = Q_strchr( s, c ); const char *p = Q_strchr( s, c );
if( p ) return p;
if( p )
return p;
return s + Q_strlen( s ); return s + Q_strlen( s );
} }
#endif #endif // !HAVE_STRCHRNUL
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -205,3 +205,42 @@ size_t Q_UTF16ToUTF8( char *dst, size_t dstsize, const uint16_t *src, size_t src
return dsti; return dsti;
} }
static uint16_t table_cp1251[64] = {
0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
0x007F, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457
};
uint32_t Q_UnicodeToCP1251( uint32_t uc )
{
size_t i;
if( uc < 0x80 )
return uc;
if( uc >= 0x0410 && uc <= 0x042F )
return uc - 0x410 + 0xC0;
if( uc >= 0x0430 && uc <= 0x044F )
return uc - 0x430 + 0xE0;
for( i = 0; i < sizeof( table_cp1251 ) / sizeof( table_cp1251[0] ); i++ )
{
if( uc == (uint32_t)table_cp1251[i] )
return i + 0x80;
}
return '?';
}
uint32_t Q_UnicodeToCP1252( uint32_t uc )
{
// this is NOT valid way to convert Unicode codepoint back to CP1252!!!
return uc < 0xFF ? uc : '?';
}

View File

@@ -37,4 +37,8 @@ size_t Q_UTF8Length( const char *s );
// srcsize in byte pairs // srcsize in byte pairs
size_t Q_UTF16ToUTF8( char *dst, size_t dstsize, const uint16_t *src, size_t srcsize ); size_t Q_UTF16ToUTF8( char *dst, size_t dstsize, const uint16_t *src, size_t srcsize );
// function to convert Unicode codepoints into CP1251 or CP1252
uint32_t Q_UnicodeToCP1251( uint32_t uc );
uint32_t Q_UnicodeToCP1252( uint32_t uc );
#endif // UTFLIB_H #endif // UTFLIB_H

View File

@@ -2,22 +2,110 @@
# encoding: utf-8 # encoding: utf-8
# mittorn, 2018 # mittorn, 2018
from waflib import Logs from waflib import Logs, Configure
import os import os
top = '.' top = '.'
TGMATH_H_TEST = '''#include <tgmath.h>
const float val = 2, val2 = 3;
int main(void){ return (int)(-asin(val) + cos(val2)); }'''
STRNCASECMP_TEST = '''#include <string.h>
int main(int argc, char **argv) { return strncasecmp(argv[1], argv[2], 10); }'''
STRCASECMP_TEST = '''#include <string.h>
int main(int argc, char **argv) { return strcasecmp(argv[1], argv[2]); }'''
STRCASESTR_TEST = '''#include <string.h>
int main(int argc, char **argv) { argv[0] = strcasestr(argv[1], argv[2]); return 0; }'''
STRCHRNUL_TEST = '''#include <string.h>
int main(int argc, char **argv) { argv[2] = strchrnul(argv[1], 'x'); return 0; }'''
STRLCPY_TEST = '''#include <string.h>
int main(int argc, char **argv) { return strlcpy(argv[1], argv[2], 10); }'''
STRLCAT_TEST = '''#include <string.h>
int main(int argc, char **argv) { return strlcat(argv[1], argv[2], 10); }'''
ALLOCA_TEST = '''#include <%s>
int main(void) { alloca(1); return 0; }'''
HEADER_TEST = '''#include <%s>
int main(void) { return 0; }
'''
def options(opt): def options(opt):
# stub # stub
return return
def header_frag(header_name):
return '#include <%s>' % header_name + EMPTY_PROGRAM
@Configure.conf
def export_define(conf, define, value=1):
if not value:
return
if value is True:
value = 1 # so python won't define it as string True
conf.env.EXPORT_DEFINES_LIST += ['%s=%s' % (define, value)]
@Configure.conf
def simple_check(conf, fragment, msg, mandatory=False, **kw):
return conf.check_cc(fragment=fragment, msg='Checking for %s' % msg, mandatory=mandatory, **kw)
def configure(conf): def configure(conf):
# private to libpublic
conf.load('gitversion') conf.load('gitversion')
conf.define('XASH_BUILD_COMMIT', conf.env.GIT_VERSION if conf.env.GIT_VERSION else 'unknown-commit') conf.define('XASH_BUILD_COMMIT', conf.env.GIT_VERSION if conf.env.GIT_VERSION else 'unknown-commit')
conf.define('XASH_BUILD_BRANCH', conf.env.GIT_BRANCH if conf.env.GIT_BRANCH else 'unknown-branch') conf.define('XASH_BUILD_BRANCH', conf.env.GIT_BRANCH if conf.env.GIT_BRANCH else 'unknown-branch')
# need to expose it for everyone using libpublic headers
conf.env.EXPORT_DEFINES_LIST = []
conf.export_define('_CRT_SILENCE_NONCONFORMING_TGMATH_H', conf.env.COMPILER_CC == 'msvc')
conf.export_define('_GNU_SOURCE', conf.env.DEST_OS != 'win32')
# create temporary uselib that just enables extensions
conf.env.DEFINES_export = list(conf.env.EXPORT_DEFINES_LIST)
# check platform-specific header name for alloca(3)
if conf.simple_check(ALLOCA_TEST % 'alloca.h', msg='alloca in alloca.h'):
conf.export_define('ALLOCA_H', '<alloca.h>')
elif conf.simple_check(ALLOCA_TEST % 'malloc.h', msg='alloca in malloc.h'):
conf.export_define('ALLOCA_H', '<malloc.h>')
elif conf.simple_check(ALLOCA_TEST % 'stdlib.h', msg='alloca in stdlib.h'):
conf.export_define('ALLOCA_H', '<stdlib.h>')
conf.export_define('STDINT_H', '<stdint.h>' if conf.simple_check(HEADER_TEST % 'stdint.h', 'stdint.h') else '<pstdint.h>')
conf.export_define('HAVE_TGMATH_H', conf.simple_check(TGMATH_H_TEST, 'tgmath.h', use='M werror export'))
# save some time on Windows, msvc is too slow
# these calls must be available with both msvc and mingw
if conf.env.DEST_OS == 'win32':
conf.export_define('HAVE_STRNICMP')
conf.export_define('HAVE_STRICMP')
else:
# TODO: multicheck for speed
def check_libc_extension(frag, msg, define):
conf.export_define(define, conf.simple_check(frag, msg, use='werror export'))
check_libc_extension(STRNCASECMP_TEST, 'strncasecmp', 'HAVE_STRNCASECMP')
check_libc_extension(STRCASECMP_TEST, 'strcasecmp', 'HAVE_STRCASECMP')
check_libc_extension(STRCASESTR_TEST, 'strcasestr', 'HAVE_STRCASESTR')
check_libc_extension(STRCHRNUL_TEST, 'strchrnul', 'HAVE_STRCHRNUL')
check_libc_extension(STRLCPY_TEST, 'strlcpy', 'HAVE_STRLCPY')
check_libc_extension(STRLCAT_TEST, 'strlcat', 'HAVE_STRLCAT')
# kill temporary uselib
del conf.env.DEFINES_export
def build(bld): def build(bld):
bld(name = 'sdk_includes', export_includes = '. ../common ../pm_shared ../engine') bld(name = 'sdk_includes',
export_includes = '. ../common ../pm_shared ../engine',
export_defines = bld.env.EXPORT_DEFINES_LIST)
bld.stlib(source = bld.path.ant_glob('*.c'), bld.stlib(source = bld.path.ant_glob('*.c'),
target = 'public', target = 'public',
features = 'c', features = 'c',

View File

@@ -34,7 +34,6 @@ Limitations:
#include "gl_local.h" #include "gl_local.h"
#ifndef XASH_GL_STATIC #ifndef XASH_GL_STATIC
#include "gl2_shim.h" #include "gl2_shim.h"
#include ALLOCA_H
#define MAX_SHADERLEN 4096 #define MAX_SHADERLEN 4096
// increase this when adding more attributes // increase this when adding more attributes

View File

@@ -28,7 +28,7 @@ GNU General Public License for more details.
// REFTODO: rewrite in triapi // REFTODO: rewrite in triapi
void R_DrawWorldHull( void ) void R_DrawWorldHull( void )
{ {
hull_model_t *hull = &tr.world->hull_models[0]; hull_model_t *hull;
winding_t *poly; winding_t *poly;
int i; int i;
@@ -42,6 +42,8 @@ void R_DrawWorldHull( void )
if( !r_showhull->value ) if( !r_showhull->value )
return; return;
hull = &tr.world->hull_models[0];
pglDisable( GL_TEXTURE_2D ); pglDisable( GL_TEXTURE_2D );
list_for_each_entry( poly, &hull->polys, chain ) list_for_each_entry( poly, &hull->polys, chain )

View File

@@ -64,7 +64,16 @@ Opaque entity can be brush or studio model but sprite
qboolean R_OpaqueEntity( cl_entity_t *ent ) qboolean R_OpaqueEntity( cl_entity_t *ent )
{ {
if( R_GetEntityRenderMode( ent ) == kRenderNormal ) if( R_GetEntityRenderMode( ent ) == kRenderNormal )
{
switch( ent->curstate.renderfx )
{
case kRenderFxNone:
case kRenderFxDeadPlayer:
case kRenderFxLightMultiplier:
case kRenderFxExplode:
return true; return true;
}
}
return false; return false;
} }

View File

@@ -3560,6 +3560,19 @@ static void R_StudioDrawModelInternal( cl_entity_t *e, int flags )
} }
} }
static cl_entity_t *R_FindParentEntity( cl_entity_t *e, cl_entity_t **entities, uint num_entities )
{
uint i;
for( i = 0; i < num_entities; i++ )
{
if( entities[i]->index == e->curstate.aiment )
return entities[i];
}
return NULL;
}
/* /*
================= =================
R_DrawStudioModel R_DrawStudioModel
@@ -3576,38 +3589,27 @@ void R_DrawStudioModel( cl_entity_t *e )
{ {
R_StudioDrawModelInternal( e, STUDIO_RENDER|STUDIO_EVENTS ); R_StudioDrawModelInternal( e, STUDIO_RENDER|STUDIO_EVENTS );
} }
else if( e->curstate.movetype == MOVETYPE_FOLLOW && e->curstate.aiment > 0 ) else if( e->curstate.movetype == MOVETYPE_FOLLOW )
{ {
cl_entity_t *parent = CL_GetEntityByIndex( e->curstate.aiment ), **entities; cl_entity_t *parent = CL_GetEntityByIndex( e->curstate.aiment );
uint i, num_entities;
if( !parent || !parent->model || parent->model->type != mod_studio ) if( !parent || !parent->model || parent->model->type != mod_studio )
return; return;
if( R_OpaqueEntity( parent )) parent = R_FindParentEntity( e, tr.draw_list->solid_entities, tr.draw_list->num_solid_entities );
{
entities = tr.draw_list->solid_entities;
num_entities = tr.draw_list->num_solid_entities;
}
else
{
entities = tr.draw_list->trans_entities;
num_entities = tr.draw_list->num_solid_entities;
}
for( i = 0; i < num_entities; i++ ) if( !parent )
{ parent = R_FindParentEntity( e, tr.draw_list->trans_entities, tr.draw_list->num_trans_entities );
if( (*entities)[i].index != e->curstate.aiment )
continue;
RI.currententity = &(*entities)[i]; if( parent )
{
RI.currententity = parent;
R_StudioDrawModelInternal( RI.currententity, 0 ); R_StudioDrawModelInternal( RI.currententity, 0 );
VectorCopy( RI.currententity->curstate.origin, e->curstate.origin ); VectorCopy( RI.currententity->curstate.origin, e->curstate.origin );
VectorCopy( RI.currententity->origin, e->origin ); VectorCopy( RI.currententity->origin, e->origin );
RI.currententity = e; RI.currententity = e;
R_StudioDrawModelInternal( e, STUDIO_RENDER|STUDIO_EVENTS ); R_StudioDrawModelInternal( e, STUDIO_RENDER|STUDIO_EVENTS );
break;
} }
} }
else else

View File

@@ -11,7 +11,7 @@ def options(opt):
grp = opt.add_option_group('ref_gl options') grp = opt.add_option_group('ref_gl options')
grp.add_option('--enable-static-gl', action='store_true', dest='GL_STATIC', default=False, grp.add_option('--enable-static-gl', action='store_true', dest='GL_STATIC', default=False,
help = 'enable direct linking to opengl [default: %default]') help = 'enable direct linking to opengl [default: %(default)s]')
# stub # stub
return return

View File

@@ -66,10 +66,10 @@ Draw_StretchPicImplementation
static void R_DrawStretchPicImplementation( int x, int y, int w, int h, int s1, int t1, int s2, int t2, image_t *pic ) static void R_DrawStretchPicImplementation( int x, int y, int w, int h, int s1, int t1, int s2, int t2, image_t *pic )
{ {
pixel_t *source, *dest; pixel_t *source, *dest;
unsigned int v, u, sv; unsigned int u, sv;
unsigned int height; unsigned int height;
unsigned int f, fstep; unsigned int f, fstep;
int skip; int skip, v;
qboolean transparent = false; qboolean transparent = false;
pixel_t *buffer; pixel_t *buffer;
@@ -212,9 +212,9 @@ void GAME_EXPORT R_DrawStretchPic( float x, float y, float w, float h, float s1,
void Draw_Fill (int x, int y, int w, int h) void Draw_Fill (int x, int y, int w, int h)
{ {
pixel_t *dest; pixel_t *dest;
unsigned int v, u; unsigned int u;
unsigned int height; unsigned int height;
int skip; int skip, v;
pixel_t src = vid.color; pixel_t src = vid.color;
int alpha = vid.alpha; int alpha = vid.alpha;

View File

@@ -410,19 +410,10 @@ void R_EntityRemoveDecals( model_t *mod );
void R_ClearDecals( void ); void R_ClearDecals( void );
void R_DecalComputeBasis( msurface_t *surf, int flags, vec3_t textureSpaceBasis[3] ); void R_DecalComputeBasis( msurface_t *surf, int flags, vec3_t textureSpaceBasis[3] );
#if 0
//
// gl_drawhulls.c
//
void R_DrawWorldHull( void );
void R_DrawModelHull( void );
#endif
void GL_Bind( int tmu, unsigned int texnum ); void GL_Bind( int tmu, unsigned int texnum );
// //
// gl_draw.cM_PI // gl_draw.c
// //
void R_Set2DMode( qboolean enable ); void R_Set2DMode( qboolean enable );
void R_DrawTileClear( int texnum, int x, int y, int w, int h ); void R_DrawTileClear( int texnum, int x, int y, int w, int h );

View File

@@ -57,8 +57,8 @@ int r_screenwidth;
int r_viewcluster, r_oldviewcluster; int r_viewcluster, r_oldviewcluster;
CVAR_DEFINE_AUTO( sw_clearcolor, "48999", 0, "screen clear color"); CVAR_DEFINE_AUTO( sw_clearcolor, "48999", 0, "screen clear color");
CVAR_DEFINE_AUTO( sw_drawflat, "0", 0, ""); CVAR_DEFINE_AUTO( sw_drawflat, "0", FCVAR_CHEAT, "");
CVAR_DEFINE_AUTO( sw_draworder, "0", 0, ""); CVAR_DEFINE_AUTO( sw_draworder, "0", FCVAR_CHEAT, "");
CVAR_DEFINE_AUTO( sw_maxedges, "32", 0, ""); CVAR_DEFINE_AUTO( sw_maxedges, "32", 0, "");
static CVAR_DEFINE_AUTO( sw_maxsurfs, "0", 0, ""); static CVAR_DEFINE_AUTO( sw_maxsurfs, "0", 0, "");
CVAR_DEFINE_AUTO( sw_mipscale, "1", FCVAR_GLCONFIG, "nothing"); CVAR_DEFINE_AUTO( sw_mipscale, "1", FCVAR_GLCONFIG, "nothing");
@@ -150,7 +150,16 @@ qboolean R_OpaqueEntity( cl_entity_t *ent )
int rendermode = R_GetEntityRenderMode( ent ); int rendermode = R_GetEntityRenderMode( ent );
if( rendermode == kRenderNormal ) if( rendermode == kRenderNormal )
{
switch( ent->curstate.renderfx )
{
case kRenderFxNone:
case kRenderFxDeadPlayer:
case kRenderFxLightMultiplier:
case kRenderFxExplode:
return true; return true;
}
}
if( sw_notransbrushes.value && ent->model && ent->model->type == mod_brush && rendermode == kRenderTransTexture ) if( sw_notransbrushes.value && ent->model && ent->model->type == mod_brush && rendermode == kRenderTransTexture )
return true; return true;

View File

@@ -3326,6 +3326,19 @@ static void R_StudioDrawModelInternal( cl_entity_t *e, int flags )
} }
} }
static cl_entity_t *R_FindParentEntity( cl_entity_t *e, cl_entity_t **entities, uint num_entities )
{
uint i;
for( i = 0; i < num_entities; i++ )
{
if( entities[i]->index == e->curstate.aiment )
return entities[i];
}
return NULL;
}
/* /*
================= =================
R_DrawStudioModel R_DrawStudioModel
@@ -3342,38 +3355,27 @@ void R_DrawStudioModel( cl_entity_t *e )
{ {
R_StudioDrawModelInternal( e, STUDIO_RENDER|STUDIO_EVENTS ); R_StudioDrawModelInternal( e, STUDIO_RENDER|STUDIO_EVENTS );
} }
else if( e->curstate.movetype == MOVETYPE_FOLLOW && e->curstate.aiment > 0 ) else if( e->curstate.movetype == MOVETYPE_FOLLOW )
{ {
cl_entity_t *parent = CL_GetEntityByIndex( e->curstate.aiment ), **entities; cl_entity_t *parent = CL_GetEntityByIndex( e->curstate.aiment );
uint i, num_entities;
if( !parent || !parent->model || parent->model->type != mod_studio ) if( !parent || !parent->model || parent->model->type != mod_studio )
return; return;
if( R_OpaqueEntity( parent )) parent = R_FindParentEntity( e, tr.draw_list->solid_entities, tr.draw_list->num_solid_entities );
{
entities = tr.draw_list->solid_entities;
num_entities = tr.draw_list->num_solid_entities;
}
else
{
entities = tr.draw_list->trans_entities;
num_entities = tr.draw_list->num_solid_entities;
}
for( i = 0; i < num_entities; i++ ) if( !parent )
{ parent = R_FindParentEntity( e, tr.draw_list->trans_entities, tr.draw_list->num_trans_entities );
if( (*entities)[i].index != e->curstate.aiment )
continue;
RI.currententity = &(*entities)[i]; if( parent )
{
RI.currententity = parent;
R_StudioDrawModelInternal( RI.currententity, 0 ); R_StudioDrawModelInternal( RI.currententity, 0 );
VectorCopy( RI.currententity->curstate.origin, e->curstate.origin ); VectorCopy( RI.currententity->curstate.origin, e->curstate.origin );
VectorCopy( RI.currententity->origin, e->origin ); VectorCopy( RI.currententity->origin, e->origin );
RI.currententity = e; RI.currententity = e;
R_StudioDrawModelInternal( e, STUDIO_RENDER|STUDIO_EVENTS ); R_StudioDrawModelInternal( e, STUDIO_RENDER|STUDIO_EVENTS );
break;
} }
} }
else else

View File

@@ -52,12 +52,12 @@ build_engine()
if [ "$1" = "dedicated" ]; then if [ "$1" = "dedicated" ]; then
./waf configure -T release -d $AMD64 --enable-tests --enable-lto || die_configure ./waf configure -T release -d $AMD64 --enable-tests --enable-lto || die_configure
elif [ "$1" = "full" ]; then elif [ "$1" = "full" ]; then
./waf configure --sdl2=SDL2_linux -T release --enable-stb $AMD64 --enable-utils --enable-tests --enable-lto || die_confgure ./waf configure --sdl2=SDL2_linux -T release --enable-stb $AMD64 --enable-utils --enable-tests --enable-lto || die_configure
else else
die die
fi fi
./waf build || die ./waf build || die_configure
} }
build_appimage() build_appimage()

View File

@@ -137,10 +137,8 @@ def options(opt):
:param opt: Options context from the *waf* build environment. :param opt: Options context from the *waf* build environment.
:type opt: waflib.Options.OptionsContext :type opt: waflib.Options.OptionsContext
''' '''
opt.add_option('--cmake', dest='cmake', default=False, opt.add_option('--cmake', dest='cmake', default=False, action='store_true', help='select cmake for export/import actions')
action='store_true', help='select cmake for export/import actions') opt.add_option('--cmake-clean', dest='cmake_clean', default=False, action='store_true', help='delete exported cmake files')
opt.add_option('--clean', dest='clean', default=False,
action='store_true', help='delete exported files')
def configure(conf): def configure(conf):
@@ -179,7 +177,7 @@ class CMakeContext(BuildContext):
pass pass
self.cmake = True self.cmake = True
if self.options.clean: if self.options.cmake_clean:
cleanup(self) cleanup(self)
else: else:
export(self) export(self)
@@ -224,7 +222,7 @@ def cleanup(bld):
:param bld: a *waf* build instance from the top level *wscript*. :param bld: a *waf* build instance from the top level *wscript*.
:type bld: waflib.Build.BuildContext :type bld: waflib.Build.BuildContext
''' '''
if not bld.options.clean: if not bld.options.cmake_clean:
return return
loc = bld.path.relpath().replace('\\', '/') loc = bld.path.relpath().replace('\\', '/')

View File

@@ -121,6 +121,17 @@ POLLY_CFLAGS = {
# msvc sosat :( # msvc sosat :(
} }
OPENMP_CFLAGS = {
'gcc': ['-fopenmp', '-DHAVE_OPENMP=1'],
'clang': ['-fopenmp', '-DHAVE_OPENMP=1'],
'msvc': ['/openmp', '/DHAVE_OPENMP=1']
}
OPENMP_LINKFLAGS = {
'gcc': ['-fopenmp'],
'clang': ['-fopenmp'],
}
PROFILE_GENERATE_CFLAGS = { PROFILE_GENERATE_CFLAGS = {
'gcc': ['-fprofile-generate=xash3d-prof'], 'gcc': ['-fprofile-generate=xash3d-prof'],
} }
@@ -144,16 +155,19 @@ def options(opt):
help = 'build type: debug, release or none(custom flags)') help = 'build type: debug, release or none(custom flags)')
grp.add_option('--enable-lto', action = 'store_true', dest = 'LTO', default = False, grp.add_option('--enable-lto', action = 'store_true', dest = 'LTO', default = False,
help = 'enable Link Time Optimization if possible [default: %default]') help = 'enable Link Time Optimization if possible [default: %(default)s]')
grp.add_option('--enable-poly-opt', action = 'store_true', dest = 'POLLY', default = False, grp.add_option('--enable-poly-opt', action = 'store_true', dest = 'POLLY', default = False,
help = 'enable polyhedral optimization if possible [default: %default]') help = 'enable polyhedral optimization if possible [default: %(default)s]')
grp.add_option('--enable-openmp', action = 'store_true', dest = 'OPENMP', default = False,
help = 'enable OpenMP extensions [default: %(default)s]')
grp.add_option('--enable-profile', action = 'store_true', dest = 'PROFILE_GENERATE', default = False, grp.add_option('--enable-profile', action = 'store_true', dest = 'PROFILE_GENERATE', default = False,
help = 'enable profile generating build (stored in xash3d-prof directory) [default: %default]') help = 'enable profile generating build (stored in xash3d-prof directory) [default: %(default)s]')
grp.add_option('--use-profile', action = 'store', dest = 'PROFILE_USE', default = None, grp.add_option('--use-profile', action = 'store', dest = 'PROFILE_USE', default = None,
help = 'use profile during build [default: %default]') help = 'use profile during build [default: %(default)s]')
def configure(conf): def configure(conf):
conf.start_msg('Build type') conf.start_msg('Build type')
@@ -171,6 +185,7 @@ def configure(conf):
conf.msg('LTO build', 'yes' if conf.options.LTO else 'no') conf.msg('LTO build', 'yes' if conf.options.LTO else 'no')
conf.msg('PolyOpt build', 'yes' if conf.options.POLLY else 'no') conf.msg('PolyOpt build', 'yes' if conf.options.POLLY else 'no')
conf.msg('OpenMP build', 'yes' if conf.options.OPENMP else 'no')
conf.msg('Generate profile', 'yes' if conf.options.PROFILE_GENERATE else 'no') conf.msg('Generate profile', 'yes' if conf.options.PROFILE_GENERATE else 'no')
conf.msg('Use profile', conf.options.PROFILE_USE if not conf.options.PROFILE_GENERATE else 'no') conf.msg('Use profile', conf.options.PROFILE_USE if not conf.options.PROFILE_GENERATE else 'no')
@@ -203,6 +218,10 @@ def get_optimization_flags(conf):
if conf.options.POLLY: if conf.options.POLLY:
cflags += conf.get_flags_by_compiler(POLLY_CFLAGS, conf.env.COMPILER_CC) cflags += conf.get_flags_by_compiler(POLLY_CFLAGS, conf.env.COMPILER_CC)
if conf.options.OPENMP:
linkflags+= conf.get_flags_by_compiler(OPENMP_LINKFLAGS, conf.env.COMPILER_CC)
cflags += conf.get_flags_by_compiler(OPENMP_CFLAGS, conf.env.COMPILER_CC)
if conf.options.PROFILE_GENERATE: if conf.options.PROFILE_GENERATE:
linkflags+= conf.get_flags_by_compiler(PROFILE_GENERATE_LINKFLAGS, conf.env.COMPILER_CC) linkflags+= conf.get_flags_by_compiler(PROFILE_GENERATE_LINKFLAGS, conf.env.COMPILER_CC)
cflags += conf.get_flags_by_compiler(PROFILE_GENERATE_CFLAGS, conf.env.COMPILER_CC) cflags += conf.get_flags_by_compiler(PROFILE_GENERATE_CFLAGS, conf.env.COMPILER_CC)

Some files were not shown because too many files have changed in this diff Show More