Compare commits

...
Author SHA1 Message Date
Alibek Omarov 8c9cd59c71 engine: http: fix the bug where maxconnections wasn't followed when many files were queued at once, bump it back to 5 concurrent connections 2026-06-07 17:29:41 +05:00
Alibek Omarov c79b29687c engine: http: cache resolve result in httpserver_t 2026-06-07 17:18:28 +05:00
Alibek Omarov 1eb922a0f1 engine: http: also lazy allocate buffer for query/response 2026-06-07 17:17:54 +05:00
Alibek Omarov f6e36994be engine: http: lazy open download files, to avoid wasting too much file descriptors 2026-06-07 17:09:59 +05:00
Alibek Omarov e83ba6509e 3rdparty: mbedtls: make common compat.c for all platforms we want to support 2026-06-07 07:08:24 +05:00
Alibek Omarov 5cfb67940b 3rdparty: mbedtls: add psvita support 2026-06-07 06:39:50 +05:00
Alibek Omarov e31c893852 wscript: enable bcrypt on Windows, add entropy generator that avoids usage of bcrypt for our 32-bit builds, allowing them to run on Windows XP 2026-06-07 06:39:50 +05:00
Alibek Omarov 85e5f032d8 scripts: gha: remove bundled mbedTLS on Switch 2026-06-07 06:39:50 +05:00
Alibek Omarov 92fd51ad99 engine: http: don't allow CRLF in URLs, fix memory leaks 2026-06-07 06:11:39 +05:00
Alibek Omarov 5480055997 engine: http: use thin TLS backend in HTTP client 2026-06-07 05:56:54 +05:00
Alibek Omarov d634c6aad5 engine: http: use separate mempool for HTTP client 2026-06-07 05:56:54 +05:00
Alibek Omarov 034efb3b31 engine: http: add TLS backend using mbedTLS 2026-06-07 05:56:54 +05:00
Alibek Omarov eae45b2e81 engine: wscript: link in mbedtls 2026-06-07 05:56:54 +05:00
Alibek Omarov 567d279007 engine: wscript: drop unfinished work on curl 2026-06-07 05:56:54 +05:00
Alibek Omarov 27f8385bb1 wscript: wire up mbedtls 2026-06-07 05:56:54 +05:00
Alibek Omarov 1cfabd5ec9 3rdparty: mbedtls: initial add 2026-06-07 05:56:54 +05:00
Alibek Omarov ab6672fb8a 3rdparty: xash-extras: update in preparation for TLS integration 2026-06-07 03:46:11 +05:00
Alibek Omarov 2d39a7fa24 engine: fix skewed ping calculation, drop --debug-all-servers 2026-06-07 03:17:45 +05:00
Alibek Omarov 7db12ade3a 3rdparty: mainui: update 2026-06-07 03:16:57 +05:00
Alibek Omarov 61a84f6953 engine: cache negative master server DNS failures longer, remove dead UDP master server addresses 2026-06-07 02:24:30 +05:00
Alibek Omarov 75ffba64c5 engine: http: add support for redirects 2026-06-06 22:55:47 +05:00
Alibek Omarov c134840148 engine: masterlist: add UDP master server deprecation notice, fix static master list address 2026-06-06 19:53:37 +05:00
Alibek Omarov 51d1bfbe08 3rdparty: mainui :update 2026-06-06 03:30:26 +05:00
Alibek Omarov 79ff8332ac 3rdparty: mainui: update 2026-06-06 02:51:41 +05:00
Alibek Omarov f155005bb1 engine: move out MAX_CLIENTS definition 2026-06-06 02:50:30 +05:00
Alibek Omarov a8de8cf5e6 Documentation: protocol: document new static master protocol 2026-06-06 02:47:39 +05:00
Alibek Omarov 74fcab9bfb engine: implement new static master server protocol 2026-06-06 02:47:39 +05:00
Alibek Omarov efad71bcc9 engine: in-memory HTTP downloader 2026-06-06 02:47:39 +05:00
Alibek Omarov c444ab882a engine: client: drop key ms protocol extension 2026-06-06 02:47:39 +05:00
🗣🗣: "ùồầỳ hợp lý quãi chất thế nhờ"🤫🗿🔥🔥anda1batross 8fad3bbad6 public: wrap macro arguments in parentheses 2026-06-05 21:55:59 +05:00
Alibek Omarov 4cd6d25ee6 engine: common: account for header size when sending first file fragment (which contains filename + compressor on goldsrc) 2026-06-05 08:42:46 +05:00
Alibek Omarov 33e47ef5a9 engine: fix engine.log output 2026-06-02 06:44:39 +05:00
Alibek Omarov d19e9606e9 3rdparty: mainui: update 2026-06-02 06:25:52 +05:00
Alibek Omarov fe1827f5e4 engine: common: don't let executing @ prefixed commands and cvars for unprivileged mode 2026-06-02 06:13:59 +05:00
Alibek Omarov 918323fcea engine: upload logo on connect always, add @cl_logoupdate cvar to clearly signal logo changes from DLL side 2026-06-02 06:10:24 +05:00
Alibek Omarov e75256ec9d 3rdparty: mainui: update 2026-06-02 05:59:09 +05:00
Alibek Omarov 47582182e6 engine: server: set flag that we are expecting resource list to come from the client to not apply resource list rate limit 2026-06-02 02:56:19 +05:00
Alibek Omarov 4a2c218cfc engine: common: xrcon: oops, fix build, forgot to stage the change 2026-06-01 21:32:45 +05:00
Alibek Omarov 376817478d engine: platform: sdl2: add expiremntal flag -nosteaminput that would remove set by Steam SDL environment variables and let us use gamepad directly 2026-06-01 18:55:38 +05:00
Alibek Omarov b96dc61e31 engine: common: xrcon: do not print misleading "client disconnected" message on engine shutdown 2026-06-01 18:49:50 +05:00
Alibek Omarov b997d5657b engine: common: xrcon: refactor macros and magic numbers 2026-06-01 18:49:50 +05:00
Alibek Omarov e9f5bca5c4 engine: common: make single shared print buffer with stripped colorcodes
- in xrcon, make delay and timeout macros into cvars
2026-06-01 18:49:50 +05:00
Alibek Omarov b36f107a2e engine: common: xrcon: use uint32_t for message types instead of null terminated small strings 2026-06-01 18:49:50 +05:00
Alibek Omarov a305ffb33f engine: common: xrcon: replace XRCON_STATE with XRCON_PARSER for parser state machine types 2026-06-01 18:49:50 +05:00
Alibek Omarov 1cc1b60b10 engine: common: xrcon: add NUL at the end of print message 2026-06-01 18:49:50 +05:00
Alibek Omarov 648db4a2b3 engine: common: xrcon: fix potential overflow and another recursion case 2026-06-01 18:49:50 +05:00
SNMetamorphandAlibek Omarov 2c0c20dfe6 Documentation: added XRCON protocol description 2026-06-01 18:49:50 +05:00
SNMetamorphandAlibek Omarov 17e167432a engine: common: xrcon: various code fixes 2026-06-01 18:49:50 +05:00
SNMetamorphandAlibek Omarov 97b8ca6b38 engine: common: xrcon: strip color codes before sending message to client 2026-06-01 18:49:50 +05:00
SNMetamorphandAlibek Omarov 6dabc6f2c5 engine: common: initial implementation of XRCON server 2026-06-01 18:49:50 +05:00
SNMetamorphandAlibek Omarov e808038fee engine: common: add function NET_MakeSocketReuseAddr 2026-06-01 18:49:50 +05:00
Владислав Суховanda1batross a60d0d142d engine: add support for legacy 'm' query responses 2026-05-31 03:11:01 +05:00
Alibek Omarov bf5d88d9a4 engine: net_chan: reset file fragment buffers early, right after they are consumed 2026-05-30 03:57:12 +05:00
Alibek Omarov adca77672a engine: client: fix crash when loading a save that references non-existing word 2026-05-30 03:53:16 +05:00
Alibek Omarov ef5295c5ab engine: workaround the misalignment issue when reading textures in BSP 2026-05-30 03:53:16 +05:00
Alibek Omarov 37da317133 filesystem: tests: fix build on Windows 2026-05-27 15:17:20 +05:00
Alibek Omarov c93cb49a9e engine: client: fix typo in COM_RandomLong 2026-05-27 01:06:27 +05:00
Alibek Omarov 4f342fb19a filesystem: tests: reduce boilerplate, add filecopy test 2026-05-27 00:39:07 +05:00
Alibek Omarov 8ee3544507 filesystem: use sendfile for faster FS_FileCopy on Linux 2026-05-27 00:34:49 +05:00
Alibek Omarov d44e6d5db7 android: drop 64-bit x86 build, as no known 64-bit only (i.e. with no 32-bit support) x86 deployments of Android are known 2026-05-26 23:11:23 +05:00
Alibek Omarov 21cc9feca7 engine: client: don't require cookie echo when server didn't negotiate NET_EXT_NETCHAN_COOKIE 2026-05-26 03:10:31 +05:00
Alibek Omarov e87b14468d ref: when entity model is NULL, the entity is player and we're drawing in menu, skip this entity silently
The menu relies on the fact that model is set from player's userinfo, and if it has bogus model, it will
trip on the nullptr model assert
2026-05-26 02:57:47 +05:00
Alibek Omarov e01921dd10 engine: server: bump datagram overflow messages to -dev 2 2026-05-26 02:57:47 +05:00
Alibek Omarov e5c4e49782 engine: client: introduce cookie protocol extension, when client connects to the server, it provides randomized 64-bit value to be prefixed into netchan messages
* Prevent clientuseragent from leaking data.
* Process qport in netchan, cleaning up code
2026-05-26 02:14:58 +05:00
Alibek Omarov d61983a5d2 engine: randomize outgoing_sequence on server side 2026-05-26 02:14:58 +05:00
Alibek Omarov c3f4eb026b engine: only allow net_sequence_window packets, prevent sudden, usually impossible, jumps 2026-05-26 02:14:58 +05:00
SNMetamorphanda1batross fe9b8bcaca engine: enable warning when client or server tries to access non-existent cvar 2026-05-25 13:44:26 +05:00
CzarintaxandGitHub 33cd20b21b engine: server: fix SV_ProcessFile crash from short malformed filename (#2606) 2026-05-25 13:42:03 +05:00
SNMetamorphandVladimir 78a3b958dd engine: client: disable saving testing cvars that potentially could break game 2026-05-24 15:14:15 +04:00
SNMetamorphandVladimir 0e56fa10f9 engine: client: make cvar cl_ticket_generator privileged 2026-05-24 15:14:15 +04:00
SNMetamorphandVladimir b6a67b56b0 engine: client: make cvar cl_steam_broker_addr privileged
(cherry picked from commit e97442f1b04c81ee406779963bd7d58cd586aecf)
2026-05-24 15:14:15 +04:00
Alibek Omarov eb9de1cac8 engine: fix NET_IsReservedAdr checks for IPv6, treat IPv4-mapped-as-IPv6 as IPv4 2026-05-23 21:23:10 +05:00
Alibek Omarov 24abd2deb2 engine: host: improve missing game libraries message so it's easier to understand 2026-05-23 21:23:10 +05:00
Alibek Omarov 996dcc637d engine: tighten file fragment msg by the (possibly) trunctated frag_message 2026-05-23 21:23:10 +05:00
Alibek Omarov 8b89bdca6f engine: validate size of the message before passing it to COM_UnMunge2 2026-05-23 21:23:10 +05:00
Alibek Omarov 3a6e3ba3ca engine: change Xash split packet id to unsigned short, as it never should be negative 2026-05-23 21:23:10 +05:00
Alibek Omarov 42ab099a07 engine: check server address if client received split packet 2026-05-23 21:23:10 +05:00
Alibek Omarov 09f15042fe engine: add target buffer size argument to MSG_ReadBits and MSG_ReadBytes 2026-05-23 21:23:10 +05:00
SNMetamorphanda1batross 344712b990 3rdparty: update extras 2026-05-23 21:09:31 +05:00
SNMetamorphanda1batross 2904c3e88b scripts: gha: set default touch configuration file for PS Vita platform 2026-05-23 21:09:31 +05:00
Alibek Omarov 25ca2ecb12 engine: fix Netchan_Validate units bug allowing oversized fragments 2026-05-23 03:12:23 +05:00
Alibek Omarov f6b28e32e2 engine: fix use-after-free in Netchan_CopyNormalFragments on decompression failure; reject oversized fragmented messages. 2026-05-23 02:53:26 +05:00
Alibek Omarov e118376735 engine: take total size to decompressors in Netchan_CopyNormalFragments, fix underflow when decompressing bzip2 stream 2026-05-23 02:42:28 +05:00
Alibek Omarov 5ef6123f03 engine: append log to the crash log on Android 2026-05-22 18:47:31 +05:00
Владислав Суховanda1batross e4600b5fe0 engine: input: fix PS Vita gyro axis mapping and add gyro debug visualization 2026-05-22 00:53:11 +05:00
Xav101anda1batross 074bd8b2b3 public: add unaligned access handlers for new big endian port 2026-05-21 14:25:33 +05:00
Alibek Omarov fca347dd00 engine: platform: psvita: add Atlas_AllocBlock to the vrtld export list temporarily 2026-05-21 03:07:15 +05:00
SNMetamorphanda1batross 2a284090ef engine: common: add console command "fs_find" 2026-05-21 02:45:27 +05:00
SNMetamorphanda1batross ecd74a0a7f filesystem: add implementation of "fs_find" console command 2026-05-21 02:45:27 +05:00
Alibek Omarov 853a67b0c5 scripts: gha: lock PSVita SDL2 fork to last known good revision 2026-05-21 01:04:43 +05:00
Alibek Omarov 80ec1c83f1 engine: platform: psvita: add dummy Atlas_AllocBlock call 2026-05-21 01:04:12 +05:00
Alibek Omarov 41681229f9 3rdparty: gl4es: update from upstream, add patch for fixing pixelated textures on Adreno 2026-05-21 00:53:51 +05:00
Alibek Omarov 7fce99481f ref: gl: fix crash in gl2_shim caused by MapBufferRange returning NULL 2026-05-21 00:03:36 +05:00
Alibek Omarov 142dc7b87a ref: use vector initializer macros 2026-05-20 23:24:36 +05:00
Alibek Omarov 3e24d5a347 engine: use vector initializer macros 2026-05-20 23:24:36 +05:00
Alibek Omarov 64b1b54f5b ref: use designated initializers where possible 2026-05-20 23:24:36 +05:00
Alibek Omarov 1fed340330 filesystem: use designated initializers where possible 2026-05-20 23:24:36 +05:00
Alibek Omarov 64be4251c8 engine: use designated initializers where possible 2026-05-20 23:24:36 +05:00
Alibek Omarov c5a8160c32 public: add Vec2, Vec3 and Vec4 macros used for initializers 2026-05-20 23:24:36 +05:00
Alibek Omarov 3c1cf81c2d engine: platform: refactor variable declarations 2026-05-20 23:24:36 +05:00
Alibek Omarov c6c1163aa0 engine: common: refactor variable declarations 2026-05-20 23:24:36 +05:00
Alibek Omarov e8845fc404 engine: client: refactor variable declarations 2026-05-20 23:24:36 +05:00
Alibek Omarov d49178d5b6 engine: server: refactor variable declarations 2026-05-20 23:24:36 +05:00
Alibek Omarov e2cf580818 ref: gl: refactor variable declarations 2026-05-20 23:24:36 +05:00
Alibek Omarov d0a98447c4 ref: soft: refactor variable declarations 2026-05-20 23:24:36 +05:00
Alibek Omarov 29a9fcf76c ref: common: refactor variable declarations 2026-05-20 23:24:36 +05:00
Alibek Omarov 37d9791f00 filesystem: refactor variable declarations 2026-05-20 23:24:36 +05:00
Alibek Omarov c5fbc98d16 public: refactor variable declarations 2026-05-20 23:24:36 +05:00
a1batrossandGitHub 4c2302ec6c engine: pass customization file fragments into IsSafeFileToDownload
This function already validates customization filenames.
2026-05-20 01:03:03 +05:00
Владислав Суховanda1batross de585f80fb 3rdparty: mainui: update 2026-05-19 19:38:12 +05:00
Владислав Суховanda1batross af58ef4a2a engine: menu_int: add flags for mipmaps and alpha channel support in image handling 2026-05-19 19:38:12 +05:00
Владислав Суховanda1batross dbe3f42485 engine: update player logo color to RGB format 2026-05-19 19:38:12 +05:00
Alibek Omarov 0053edbe7b scripts: gha: drop signing step from build_android.sh, as it's done on gradle level now 2026-05-18 13:01:22 +05:00
Alibek Omarov 61f3369957 filesystem: refactor large filesystem.c into smaller files 2026-05-18 12:50:08 +05:00
Alibek Omarov 334bebb1fb engine: use memcpy when reading sprite model to avoid unaligned access 2026-05-17 12:34:21 +05:00
Alibek Omarov 463ed05340 android: add auto-updater to the launcher 2026-05-17 12:12:40 +05:00
Alibek Omarov 92bad81d9a engine: client: fix off-by-one 2026-05-17 11:48:20 +05:00
Alibek Omarov 4c667d9d8c engine: client: bound current_position with HISTORY_MASK, in case of something passes invalid values 2026-05-17 11:45:22 +05:00
Alibek Omarov cb04e9cbd5 engine: server: also use constant time string comparison for sv_password 2026-05-17 11:26:53 +05:00
Alibek Omarov c2c781f039 engine: server: harden rcon, use constant time comparison, do not output untrusted data to log 2026-05-17 11:23:55 +05:00
Alibek Omarov dbe1a2742e public: add Q_strcmp_constant_time 2026-05-17 11:23:08 +05:00
Alibek Omarov fe2019ee06 engine: common: add more cases to COM_IsSafeToDownload 2026-05-17 11:20:00 +05:00
Alibek Omarov e5c091c303 engine: client: fix off-by-one error in CL_ParseResource 2026-05-17 11:17:42 +05:00
Alibek Omarov 9d050e7ed3 engine: limit decompressed buffer alloc size to 64MiB 2026-05-17 11:17:23 +05:00
Alibek Omarov be35b3503e engine: limit maximum amount of pending fragbufs 2026-05-17 10:54:51 +05:00
Alibek Omarov 5fad4ae6ca engine: client: mark rcon and connect commands privileged 2026-05-17 10:51:44 +05:00
Alibek Omarov 2290ae0239 public: disable Amiga's double-slash check in CheckNastyPath 2026-05-17 10:42:22 +05:00
Alibek Omarov 9082a47348 engine: validate paths before downloading 2026-05-17 10:41:59 +05:00
Alibek Omarov 5d7ed9d8a7 public: add CheckNastyPath from Darkplaces's VFS so it can be used in engine for path traversal checks 2026-05-16 21:28:51 +05:00
Alibek Omarov 8120669e5b engine: restore bounds check in Delta_FindStructByIndex, as it gets passed arbitrary numbers too 2026-05-16 21:27:51 +05:00
Alibek Omarov fb6c4a224c engine: check for overflow in split packet reassembly 2026-05-16 21:13:47 +05:00
Alibek Omarov 166763a887 engine: common: limit amount of delta encoded fields by 64 in GoldSrc protocol (because this is the maximum it allows anyway) 2026-05-16 21:12:49 +05:00
Alibek Omarov e56cf4e1da engine: client: validate player index and max players 2026-05-16 21:00:50 +05:00
Alibek Omarov fc4b982ecc engine: client: correctly skip message that would overflow temp entity buffer 2026-05-16 20:59:57 +05:00
Alibek Omarov d305292340 engine: zone: in CheckAlloc walk through over both allocation chains, so that we don't read out of bounds if passed pointer is not allocated by zone allocator 2026-05-16 12:56:49 +05:00
Alibek Omarov 9ee6be87d7 engine: host: try to avoid recursive Host_Error 2026-05-16 12:37:08 +05:00
Alibek Omarov 4e4a54ab68 engine: despite byte-swapping code is no-op on little endian, it still fires and can read out of bounds on some models, leading to crash 2026-05-16 12:21:46 +05:00
Alibek Omarov 516554b704 public: update miniz to latest version 2026-05-15 12:36:56 +05:00
Alibek Omarov 7be955c493 gitignore: do not even try adding slop generators garbage 2026-05-15 11:39:45 +05:00
Владислав Суховanda1batross c6fb702fb1 engine: add MenuFactory native object 2026-05-15 08:48:58 +05:00
Alibek Omarov cae1d32c66 3rdparty: gl-wes-v2: update 2026-05-13 11:14:32 +05:00
Alibek Omarov 5e70995989 ref: gl: more maybe unused stuff 2026-05-13 11:13:46 +05:00
Alibek Omarov 50f7f3bb87 engine: server: mark str64 as maybe unused 2026-05-13 11:12:19 +05:00
Alibek Omarov 7c3da8c381 3rdparty: gl-wes-v2: update 2026-05-13 11:11:41 +05:00
Alibek Omarov e38d3511b5 3rdparty: nanogl: update 2026-05-13 11:11:32 +05:00
Alibek Omarov d4fcebb377 3rdparty: MultiEmulator: update 2026-05-13 11:11:22 +05:00
Alibek Omarov 996f0e906b engine: client: drop double free check from dbghulls 2026-05-13 10:53:21 +05:00
Alibek Omarov 0f490a2f16 engine: client: fix warnings, cleanup unused or maybe-uninitialized variables 2026-05-13 10:48:37 +05:00
Alibek Omarov cef6cb58bb ref: gl: fix maybe-uninitialized 2026-05-13 10:47:15 +05:00
Alibek Omarov 47aad1b3a3 ref: soft: cleanup unused variables 2026-05-13 10:46:59 +05:00
Alibek Omarov ff8efebba2 engine: fix more warnings 2026-05-13 10:46:44 +05:00
Alibek Omarov be6571a6a2 3rdparty: library_suffix: update 2026-05-13 10:45:50 +05:00
Alibek Omarov 1d67585df4 3rdparty: mainui: update 2026-05-13 10:45:39 +05:00
Alibek Omarov 10d441f825 public: fix warnings, add guards around some of the macros, remove unused variable 2026-05-13 10:30:35 +05:00
Alibek Omarov 2dc132f817 engine: common: fix up warnings, clean up unused variables 2026-05-13 10:13:52 +05:00
Alibek Omarov e9bdbf2f33 ref: gl: mark maybe unused globals 2026-05-13 10:11:47 +05:00
Alibek Omarov b630a84447 common: xash3d_types: add macro MAYBE_UNUSED 2026-05-13 10:11:21 +05:00
Alibek Omarov dccd076b92 engine: platform: sdl2: cleanup unused variables 2026-05-13 10:09:49 +05:00
Alibek Omarov cb7ea5729a engine: server: cleanup unused variables 2026-05-13 10:09:37 +05:00
Alibek Omarov 9bad17505e filesystem: cleanup unused variables 2026-05-13 10:09:19 +05:00
Alibek Omarov bf990d1040 ref: gl: cleanup unused variables 2026-05-13 10:09:09 +05:00
Alibek Omarov 63e112bf4c engine: client: soundlib: add more broken null files 2026-05-13 09:32:50 +05:00
Alibek Omarov 0aac2e4d32 engine: zone: add small allocation optimization, reducing the size of <255 bytes allocations at the cost of less debug info
Keep it opt-in through a flag at pool alloc time.
Opt-in console related allocations, they are usually small enough strings.
2026-05-13 09:32:50 +05:00
Alibek Omarov 33b3cdb0f5 engine: client: soundlib: catch broken null.wav and replace it with silence 2026-05-10 03:02:24 +05:00
Alibek Omarov 9c4edaed21 engine: client: sound: switch to single-pass mixing, now channels gets upscaled directly to DMA speed, fixing the issue with s_lerping 2026-05-10 02:48:23 +05:00
Alibek Omarov d4205867dd public: simplify COM_Strip and COM_DefaultExtension by reusing extension extraction function. Add moar tests for them 2026-05-10 00:56:44 +05:00
Alibek Omarov 3c07680263 android: pack crash log to ZIP file, put system and intent info alongside it. Properly handle if multple email clients are installed on device (tested with gmail, outlook and k-9). 2026-05-10 00:32:29 +05:00
282 changed files with 21450 additions and 20038 deletions
+13
View File
@@ -361,3 +361,16 @@ cmake-build-*
3rdparty/SDL 3rdparty/SDL
3rdparty/hlsdk-portable 3rdparty/hlsdk-portable
!scripts/build-ninja.py !scripts/build-ninja.py
# slop
CLAUDE.md
AGENTS.md
GEMINI.md
.claude/
.gemini/
.cursor*
.windsurf*
.aider*
.continue/
.codeium/
.github/copilot-instructions.md
+3
View File
@@ -43,3 +43,6 @@
[submodule "3rdparty/library_suffix"] [submodule "3rdparty/library_suffix"]
path = 3rdparty/library_suffix path = 3rdparty/library_suffix
url = https://github.com/FWGS/library-suffix.git url = https://github.com/FWGS/library-suffix.git
[submodule "3rdparty/mbedtls/mbedtls"]
path = 3rdparty/mbedtls/mbedtls
url = https://github.com/FWGS/mbedtls-releases.git
+1 -1
View File
@@ -23,6 +23,6 @@ def build(bld):
bld(features='zip', bld(features='zip',
name = 'extras.pk3', name = 'extras.pk3',
files = srcdir.ant_glob('**/*'), files = srcdir.ant_glob('**/*', excl=['scripts/**']),
relative_to = srcdir, relative_to = srcdir,
install_path = install_path) install_path = install_path)
+107
View File
@@ -0,0 +1,107 @@
/*
compat.c - mbedTLS platform overrides for targets upstream doesn't cover
Copyright (C) 2026 Xash3D FWGS contributors
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.
*/
/*
WinXP: legacy CryptGenRandom via advapi32
Source: ttps://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom
PSVita: sceKernelGetRandomNumber from psp2/kernel/rng.h (64-byte cap).
Source: https://github.com/vitasdk/vita-headers/blob/master/include/psp2/kernel/rng.h
NSwitch: randomGet from libnx.
Source: https://github.com/switchbrew/libnx/blob/master/nx/include/switch/kernel/random.h
*/
#include "mbedtls/platform.h"
#include "psa/crypto.h"
#if defined( MBEDTLS_PLATFORM_MS_TIME_ALT )
mbedtls_ms_time_t mbedtls_ms_time( void )
{
extern double Platform_DoubleTime( void );
return (mbedtls_ms_time_t)( Platform_DoubleTime() * 1000.0 );
}
#endif /* MBEDTLS_PLATFORM_MS_TIME_ALT */
#if defined( MBEDTLS_PSA_DRIVER_GET_ENTROPY )
#if defined( _WIN32 ) && !defined( _WIN64 )
#include <windows.h>
#include <wincrypt.h>
int mbedtls_platform_get_entropy( psa_driver_get_entropy_flags_t flags, size_t *estimate_bits, unsigned char *output, size_t output_size )
{
if( flags != 0 )
return PSA_ERROR_NOT_SUPPORTED;
HCRYPTPROV prov;
if( !CryptAcquireContextW( &prov, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT | CRYPT_SILENT ))
return PSA_ERROR_INSUFFICIENT_ENTROPY;
if( !CryptGenRandom( prov, (DWORD)output_size, output ))
{
CryptReleaseContext( prov, 0 );
return PSA_ERROR_INSUFFICIENT_ENTROPY;
}
CryptReleaseContext( prov, 0 );
*estimate_bits = 8 * output_size;
return 0;
}
#elif defined( __vita__ )
#include <psp2/kernel/rng.h>
int mbedtls_platform_get_entropy( psa_driver_get_entropy_flags_t flags, size_t *estimate_bits, unsigned char *output, size_t output_size )
{
if( flags != 0 )
return PSA_ERROR_NOT_SUPPORTED;
size_t total = 0;
while( total < output_size )
{
size_t chunk = output_size - total;
if( chunk > 64 )
chunk = 64;
if( sceKernelGetRandomNumber( output + total, chunk ) != 0 )
return PSA_ERROR_INSUFFICIENT_ENTROPY;
total += chunk;
}
*estimate_bits = 8 * output_size;
return 0;
}
#elif defined( __SWITCH__ )
#include <switch.h>
int mbedtls_platform_get_entropy( psa_driver_get_entropy_flags_t flags, size_t *estimate_bits, unsigned char *output, size_t output_size )
{
if( flags != 0 )
return PSA_ERROR_NOT_SUPPORTED;
randomGet( output, output_size );
*estimate_bits = 8 * output_size;
return 0;
}
#else
#error "MBEDTLS_PSA_DRIVER_GET_ENTROPY enabled but no platform impl in compat.c"
#endif
#endif /* MBEDTLS_PSA_DRIVER_GET_ENTROPY */
Vendored Submodule
+1
+67
View File
@@ -0,0 +1,67 @@
#! /usr/bin/env python
# encoding: utf-8
def options(opt):
grp = opt.add_option_group('mbedTLS options')
grp.add_option('--disable-mbedtls', action='store_false', dest='MBEDTLS', default=True,
help='disable bundled mbedTLS and built-in HTTPS support [default: enabled]')
def configure(conf):
conf.env.MBEDTLS = conf.options.MBEDTLS
if not conf.env.MBEDTLS:
return
if not conf.path.find_dir('mbedtls') or not conf.path.find_dir('mbedtls/library'):
conf.fatal('Can\'t find mbedtls submodule. Run `git submodule update --init --recursive`.')
if not conf.path.find_dir('mbedtls/tf-psa-crypto/core'):
conf.fatal('mbedTLS nested submodule tf-psa-crypto is missing. Run `git submodule update --init --recursive`.')
def build(bld):
if not bld.env.MBEDTLS:
return
sources = bld.path.ant_glob([
'mbedtls/library/*.c',
'mbedtls/tf-psa-crypto/core/*.c',
'mbedtls/tf-psa-crypto/extras/*.c',
'mbedtls/tf-psa-crypto/platform/*.c',
'mbedtls/tf-psa-crypto/utilities/*.c',
'mbedtls/tf-psa-crypto/drivers/builtin/src/*.c',
])
sources += ['compat.c']
defines = [
'MBEDTLS_USER_CONFIG_FILE="xash_mbedtls_config.h"',
'TF_PSA_CRYPTO_USER_CONFIG_FILE="xash_psa_config.h"',
]
includes = [
'.',
'mbedtls/include',
'mbedtls/library',
'mbedtls/tf-psa-crypto/include',
'mbedtls/tf-psa-crypto/drivers/builtin/include',
'mbedtls/tf-psa-crypto/core',
'mbedtls/tf-psa-crypto/drivers/builtin/src',
'mbedtls/tf-psa-crypto/utilities',
'mbedtls/tf-psa-crypto/extras',
'mbedtls/tf-psa-crypto/platform',
'mbedtls/tf-psa-crypto/dispatch',
]
bld.stlib(
source = sources,
target = 'mbedtls',
features = 'c',
includes = includes,
defines = defines,
export_defines = ['XASH_MBEDTLS'],
export_includes = [
'.',
'mbedtls/include',
'mbedtls/tf-psa-crypto/include',
'mbedtls/tf-psa-crypto/drivers/builtin/include',
]
)
+36
View File
@@ -0,0 +1,36 @@
#ifndef XASH_MBEDTLS_CONFIG_H
#define XASH_MBEDTLS_CONFIG_H
#undef MBEDTLS_NET_C
#undef MBEDTLS_PKCS7_C
#undef MBEDTLS_TIMING_C
#undef MBEDTLS_SSL_SRV_C
#undef MBEDTLS_SSL_PROTO_DTLS
#undef MBEDTLS_SSL_DTLS_ANTI_REPLAY
#undef MBEDTLS_SSL_DTLS_CONNECTION_ID
#undef MBEDTLS_SSL_DTLS_HELLO_VERIFY
#undef MBEDTLS_SSL_DTLS_SRTP
#undef MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE
#undef MBEDTLS_SSL_COOKIE_C
#undef MBEDTLS_SSL_CACHE_C
#undef MBEDTLS_SSL_TICKET_C
#undef MBEDTLS_SSL_SESSION_TICKETS
#undef MBEDTLS_SSL_RENEGOTIATION
#undef MBEDTLS_SSL_CONTEXT_SERIALIZATION
#undef MBEDTLS_SSL_KEYING_MATERIAL_EXPORT
#undef MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
#undef MBEDTLS_SSL_ALL_ALERT_MESSAGES
#undef MBEDTLS_SSL_ALPN
#undef MBEDTLS_SSL_ENCRYPT_THEN_MAC
#undef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#undef MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
#undef MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED
#undef MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
#undef MBEDTLS_X509_CREATE_C
#undef MBEDTLS_X509_CRT_WRITE_C
#undef MBEDTLS_X509_CSR_PARSE_C
#undef MBEDTLS_X509_CSR_WRITE_C
#undef MBEDTLS_X509_CRL_PARSE_C
#undef MBEDTLS_VERSION_FEATURES
#endif /* XASH_MBEDTLS_CONFIG_H */
+82
View File
@@ -0,0 +1,82 @@
#ifndef XASH_PSA_CONFIG_H
#define XASH_PSA_CONFIG_H
#if (defined( _WIN32 ) && !defined( _WIN64 )) || defined( __vita__ ) || defined( __SWITCH__ )
/* WinXP, PSVita and NSwitch use entropy paths upstream doesn't cover.
compat.c provides mbedtls_platform_get_entropy() for all three. */
#undef MBEDTLS_PSA_BUILTIN_GET_ENTROPY
#define MBEDTLS_PSA_DRIVER_GET_ENTROPY
#endif
#if defined( __vita__ ) || defined( __SWITCH__ )
/* Upstream has no Vita/NSW support; compat.c fills in */
#define MBEDTLS_PLATFORM_MS_TIME_ALT
#endif
#undef MBEDTLS_FS_IO
#undef MBEDTLS_PSA_ITS_FILE_C
#undef MBEDTLS_PSA_CRYPTO_STORAGE_C
#undef MBEDTLS_SELF_TEST
#undef MBEDTLS_HMAC_DRBG_C
#undef MBEDTLS_LMS_C
#undef MBEDTLS_NIST_KW_C
#undef MBEDTLS_PKCS5_C
#undef PSA_WANT_ALG_CCM
#undef PSA_WANT_ALG_CCM_STAR_NO_TAG
#undef PSA_WANT_ALG_CBC_NO_PADDING
#undef PSA_WANT_ALG_CBC_PKCS7
#undef PSA_WANT_ALG_CFB
#undef PSA_WANT_ALG_CMAC
#undef PSA_WANT_ALG_CTR
#undef PSA_WANT_ALG_ECB_NO_PADDING
#undef PSA_WANT_ALG_OFB
#undef PSA_WANT_ALG_STREAM_CIPHER
#undef PSA_WANT_ALG_JPAKE
#undef PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS
#undef PSA_WANT_ALG_TLS12_PSK_TO_MS
#undef PSA_WANT_ALG_FFDH
#undef PSA_WANT_ALG_PBKDF2_HMAC
#undef PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128
#undef PSA_WANT_KEY_TYPE_PASSWORD
#undef PSA_WANT_KEY_TYPE_PASSWORD_HASH
#undef PSA_WANT_ALG_SHA3_224
#undef PSA_WANT_ALG_SHA3_256
#undef PSA_WANT_ALG_SHA3_384
#undef PSA_WANT_ALG_SHA3_512
#undef PSA_WANT_ALG_SHAKE128
#undef PSA_WANT_ALG_SHAKE256
#undef PSA_WANT_ALG_SHA_224
#undef PSA_WANT_ALG_SHA_1
#undef PSA_WANT_ALG_MD5
#undef PSA_WANT_ALG_RIPEMD160
#undef PSA_WANT_KEY_TYPE_ARIA
#undef PSA_WANT_KEY_TYPE_CAMELLIA
#undef PSA_WANT_ECC_BRAINPOOL_P_R1_256
#undef PSA_WANT_ECC_BRAINPOOL_P_R1_384
#undef PSA_WANT_ECC_BRAINPOOL_P_R1_512
#undef PSA_WANT_ECC_SECP_K1_256
#undef PSA_WANT_ECC_MONTGOMERY_448
#undef PSA_WANT_ECC_SECP_R1_521
#undef PSA_WANT_DH_RFC7919_2048
#undef PSA_WANT_DH_RFC7919_3072
#undef PSA_WANT_DH_RFC7919_4096
#undef PSA_WANT_DH_RFC7919_6144
#undef PSA_WANT_DH_RFC7919_8192
#undef PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC
#undef PSA_WANT_KEY_TYPE_DH_KEY_PAIR_EXPORT
#undef PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE
#undef PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT
#undef PSA_WANT_KEY_TYPE_DH_PUBLIC_KEY
#undef PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT
#undef PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT
#undef PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT
#undef PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE
#undef PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT
#undef MBEDTLS_PEM_WRITE_C
#undef MBEDTLS_PK_WRITE_C
#undef MBEDTLS_PK_PARSE_EC_COMPRESSED
#undef MBEDTLS_PK_PARSE_EC_EXTENDED
#undef MBEDTLS_ASN1_WRITE_C
#endif /* XASH_PSA_CONFIG_H */
@@ -16,6 +16,7 @@ Only these objects are guaranteed to be available on all targets.
|-------------|-----------| |-------------|-----------|
| `VFileSystem009` | Provides C++ interface to filesystem, binary-compatible with Valve's VFileSystem009. | | `VFileSystem009` | Provides C++ interface to filesystem, binary-compatible with Valve's VFileSystem009. |
| `XashFileSystemXXX` | Provides C interface to filesystem. This interface is unstable and not recommended for generic use, outside of engine internals. For more info about current version look into `filesystem.h`. | | `XashFileSystemXXX` | Provides C interface to filesystem. This interface is unstable and not recommended for generic use, outside of engine internals. For more info about current version look into `filesystem.h`. |
| `MenuFactory` | Returns a `CreateInterface` function pointer (`pfnCreateInterface_t`) for the currently loaded menu library. |
#### Android-specific objects #### Android-specific objects
+181
View File
@@ -0,0 +1,181 @@
# XRCON Protocol Specification
## Overview
XRCON is a TCP-based remote console protocol implemented as a server within the engine. It provides an alternative to the legacy RCON (which operates over UDP as out-of-band packets). XRCON uses a framed binary protocol over a single persistent TCP connection, accepting at most one client at a time.
Key characteristics:
- Based on TCP (stream-oriented, reliable)
- Default port is 27000
- Maximum only one concurrent client
- Binary framed protocol with a 12-byte header + variable-length payload
## Configuration
The XRCON server is controlled by two configuration variables, both restricted to privileged users:
| Variable | Default | Description |
|---|---|---|
| `xrcon_enable` | `0` (disabled) | Master switch; when enabled, the server starts listening for connections |
| `xrcon_address` | `127.0.0.1:27000` | Bind address and port; supports both IPv4 and IPv6. Changing this at runtime triggers a XRCON server restart (stop + rebind) |
By default, XRCON binds only to localhost (`127.0.0.1`), providing a degree of access control. The server will not start listening until explicitly enabled.
## Frame Format
All XRCON messages are encapsulated in a framed binary format. Each frame consists of a fixed 12-byte header followed by a variable-length payload.
### Header (12 bytes)
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 4 | Type | 4-character message type string (null-terminated, occupies 5 bytes in the structure but the 5th byte is padding) |
| 4 | 4 | Version | Protocol version (32-bit unsigned integer, network byte order) |
| 8 | 2 | Length | Total frame length in bytes, including the header (16-bit unsigned integer, network byte order) |
| 10 | 2 | Handle | Handle or sequence number (16-bit unsigned integer, network byte order; currently always zero) |
### Protocol Version
The current protocol version is `0x000000D4` (212 decimal). The server also accepts `0x00D40000` for compatibility with certain third-party clients (e.g., CS2RemoteConsole).
### Maximum Frame Size
- Maximum payload per frame: 4096 bytes
- Maximum total packet size (header + payload): approximately 4136 bytes
- Receive buffer size: 4096 + 64 bytes
- Transmit buffer size: 16384 bytes (4 × maximum frame size)
### Byte Order
Multi-byte integer fields (version, length, handle) are transmitted in **network byte order** (big-endian).
## Message Types
| Type | Direction | Description |
|---|---|---|
| `CMND` | Client → Server | Execute a console command |
| `PRNT` | Server → Client | Console output / print message |
| `CHAN` | Server → Client | Channel list (channel metadata) |
| `AINF` | Server → Client | Application / server info |
| `ADON` | Server → Client | Additional info / server name |
### CMND — Client Command
**Direction**: Client → Server
Sent by the client to execute a console command on the server.
| Section | Size | Description |
|---|---|---|
| Header | 12 bytes | Type = `"CMND"`, version, length, handle |
| Payload | Variable | Raw command string (null-terminated) |
The command string is injected into the engine's command buffer for execution. There is **no authentication** — any connected client may execute arbitrary commands.
### PRNT — Server Print
**Direction**: Server → Client
Sent by the server to stream console output to the connected client.
| Section | Size | Description |
|---|---|---|
| Header | 12 bytes | Type = `"PRNT"`, version, length, handle |
| Channel ID | 4 bytes | Channel identifier (unsigned 32-bit integer; always 0 for "Console") |
| Padding | 20 bytes | Reserved (5 × 32-bit unsigned integers, all zero) |
| Red | 1 byte | Red color component (always 255) |
| Green | 1 byte | Green color component (always 255) |
| Blue | 1 byte | Blue color component (always 255) |
| Alpha | 1 byte | Alpha / opacity component (always 255) |
| Text | Variable | The console output text (up to 4096 bytes) |
### CHAN — Channel List
**Direction**: Server → Client
Sent by the server during the initial handshake (and potentially later) to describe the available console output channels.
| Section | Size | Description |
|---|---|---|
| Header | 12 bytes | Type = `"CHAN"`, version, length, handle |
| Channel Count | 2 bytes | Number of channel records (unsigned 16-bit integer; always 1) |
Each channel record (58 bytes):
| Field | Size | Description |
|---|---|---|
| Channel ID | 4 bytes | Unique channel identifier (unsigned 32-bit integer; always 0) |
| Unknown 1 | 4 bytes | Reserved (unsigned 32-bit integer; always 0) |
| Unknown 2 | 4 bytes | Reserved (unsigned 32-bit integer; always 0) |
| Default Verbosity | 4 bytes | Default verbosity level (unsigned 32-bit integer; always 5) |
| Current Verbosity | 4 bytes | Current verbosity level (unsigned 32-bit integer; always 5) |
| Red | 1 byte | Red color component for the channel (always 255) |
| Green | 1 byte | Green color component (always 255) |
| Blue | 1 byte | Blue color component (always 255) |
| Alpha | 1 byte | Alpha component (always 255) |
| Name | 34 bytes | Channel name string, null-padded (always `"Console"`) |
Total payload size for this frame: 2 + 58 = 60 bytes.
### AINF — Application Info
**Direction**: Server → Client
Sent by the server immediately after a client connects, before `ADON` and `CHAN`.
| Section | Size | Description |
|---|---|---|
| Header | 12 bytes | Type = `"AINF"`, version, length, handle |
| Payload | 77 bytes | All zeros (placeholder / reserved for structured application information) |
This packet currently serves as a placeholder and contains no meaningful data. It may be extended in future versions to carry structured metadata about the server application.
### ADON — Additional Info
**Direction**: Server → Client
Sent by the server immediately after `AINF` during the connection handshake.
| Section | Size | Description |
|---|---|---|
| Header | 12 bytes | Type = `"ADON"`, version, length, handle |
| Unknown | 2 bytes | Reserved (unsigned 16-bit integer; always 0) |
| Name Length | 2 bytes | Length of the name string (unsigned 16-bit integer) |
| Name | Variable | Server name / identifier string (e.g., `"HLDS"`) |
This packet carries the server application name, which is a short string identifying the server type (e.g., `"HLDS"` for Half-Life Dedicated Server).
## Security
XRCON has **no built-in authentication or encryption**. There is no password validation or transport-layer security. Any client that can establish a TCP connection to the XRCON port has full command execution access to the engine console.
The only security measures are:
1. **Default localhost binding**: The server binds to `127.0.0.1` by default, accepting connections only from the local machine.
2. **Disabled by default**: The `xrcon_enable` variable defaults to `0`, so the server does not listen unless explicitly enabled.
3. **Privileged variables**: Both configuration variables are restricted to privileged users and cannot be modified through unprivileged console commands or external access.
## Comparison with Legacy RCON
| Feature | XRCON | Legacy RCON |
|---|---|---|
| Transport | TCP (stream) | UDP (datagram, out-of-band) |
| Port | Configurable, default 27000 | Game port (default 27015) |
| Framing | Binary frame header | Plain text over UDP |
| Authentication | None | Password-based |
| Max clients | 1 | Multiple |
| Interaction format | Full console access | Request-response only for submitted command |
| Supported environments | Client and server | Server only |
@@ -0,0 +1,71 @@
# Static HTTP server list
Replacement for the UDP `S2M_SCAN_REQUEST` / `M2A_SERVERSLIST` exchange
described in [02-connectionless.md](02-connectionless.md). Read-only HTTP,
no NAT punching, no filtering or pagination in the request.
## URL
`xashcomm.lst` carries a base URL per source:
```
masterstatic http://master.example.org/server-list
```
The engine appends `/v1/servers/<gamedir>` and `GET`s the result. For
`gamedir = valve`:
```
GET http://master.example.org/server-list/v1/servers/valve
```
Trailing slashes on the base URL are stripped. Multiple `masterstatic`
lines are allowed; results are merged.
The request is bare: no body, no auth, no cookies, no compressed encodings.
Only the standard `User-Agent` is set. `POST` / `PUT` / `DELETE` are not
used; servers register out of band.
## Response
UTF-8 text, tokenized with `COM_ParseFileSafe` (whitespace separates,
`//` and `#` start line comments, `"..."` quotes a token). One directive
per record:
* `ip <address>` — Xash3D server (protocol 49).
* `gs <address>` — GoldSrc server (protocol 48).
`<address>` is parsed by `NET_StringToAdr` (`1.2.3.4:27015`,
`[2001:db8::1]:27015`, hostnames). Port defaults to `27015`. Unknown
directives are skipped together with one operand so new keywords can be
added without breaking older clients.
`Content-Type` is not inspected, `text/plain; charset=utf-8` expected.
### Example
```
# diffusion servers
ip 192.0.2.10:27015
ip [2001:db8::1]:27015
gs 198.51.100.5:27015
```
A file with zero records is valid and represents an empty list.
### Versioning
The `/v1/` segment is fixed in this revision. A future protocol revision
adds a sibling `/v2/...` resource without breaking older clients.
## Client behaviour
Each `ip` / `gs` record from the response triggers a probe to the listed
address, identical to a server discovered through the UDP master. DNS
errors, non-200 responses, and malformed bodies are reported to the
console.
## Server behaviour
Any static HTTP server works. A typical setup is a periodic job that
probes a set of known addresses and writes `v1/servers/<gamedir>`.
+1
View File
@@ -12,3 +12,4 @@ release/
*.hprof *.hprof
.vscode/ .vscode/
*.bak *.bak
.kotlin/
+16 -1
View File
@@ -20,10 +20,12 @@ extensions.configure<ApplicationExtension> {
minSdk = 21 minSdk = 21
targetSdk = 35 targetSdk = 35
buildConfigField("String", "GIT_HASH", "\"${getGitHash()}\"")
externalNativeBuild { externalNativeBuild {
val engineRoot = projectDir.parentFile.parent val engineRoot = projectDir.parentFile.parent
experimentalProperties["ninja.abiFilters"] = setOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64") experimentalProperties["ninja.abiFilters"] = setOf("armeabi-v7a", "arm64-v8a", "x86")
experimentalProperties["ninja.path"] = File(engineRoot, "wscript").path experimentalProperties["ninja.path"] = File(engineRoot, "wscript").path
experimentalProperties["ninja.configure"] = "run-python" experimentalProperties["ninja.configure"] = "run-python"
experimentalProperties["ninja.arguments"] = setOf( experimentalProperties["ninja.arguments"] = setOf(
@@ -58,6 +60,15 @@ extensions.configure<ApplicationExtension> {
buildConfig = true buildConfig = true
} }
signingConfigs {
create("androidDebugKey") {
storeFile = File(projectDir.parentFile, "debug.keystore")
storePassword = "android"
keyAlias = "androiddebugkey"
keyPassword = "android"
}
}
lint { lint {
abortOnError = false abortOnError = false
} }
@@ -91,6 +102,7 @@ extensions.configure<ApplicationExtension> {
proguardFiles( proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
) )
buildConfigField("boolean", "ENABLE_AUTO_UPDATE", "false")
} }
release { release {
@@ -99,6 +111,7 @@ extensions.configure<ApplicationExtension> {
proguardFiles( proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
) )
buildConfigField("boolean", "ENABLE_AUTO_UPDATE", "false")
} }
register("asan") { register("asan") {
@@ -108,6 +121,8 @@ extensions.configure<ApplicationExtension> {
register("continuous") { register("continuous") {
initWith(getByName("release")) initWith(getByName("release"))
applicationIdSuffix = ".test" applicationIdSuffix = ".test"
buildConfigField("boolean", "ENABLE_AUTO_UPDATE", "true")
signingConfig = signingConfigs.getByName("androidDebugKey")
} }
} }
} }
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name" translatable="false">Xash3D FWGS (Test)</string> <string name="app_name" translatable="false">Xash3D FWGS (Test)</string>
<string name="authority" translatable="false">su.xash.engine.test.documents</string>
</resources> </resources>
+15 -1
View File
@@ -48,6 +48,8 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<!-- Dedicated server --> <!-- Dedicated server -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- Self-update: install downloaded APK -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<application <application
android:name=".MainApplication" android:name=".MainApplication"
@@ -76,8 +78,16 @@
android:grantUriPermissions="true"> android:grantUriPermissions="true">
<meta-data <meta-data
android:name="android.support.FILE_PROVIDER_PATHS" android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" /> android:resource="@xml/paths" />
</provider> </provider>
<receiver
android:name=".model.InstallStatusReceiver"
android:exported="false">
<intent-filter>
<action android:name="su.xash.engine.INSTALL_RESULT" />
</intent-filter>
</receiver>
<activity <activity
android:name=".XashActivity" android:name=".XashActivity"
android:alwaysRetainTaskState="true" android:alwaysRetainTaskState="true"
@@ -95,5 +105,9 @@
<intent> <intent>
<action android:name="su.xash.engine.MOD" /> <action android:name="su.xash.engine.MOD" />
</intent> </intent>
<intent>
<action android:name="android.intent.action.SENDTO" />
<data android:scheme="mailto" />
</intent>
</queries> </queries>
</manifest> </manifest>
@@ -1,15 +1,26 @@
package su.xash.engine package su.xash.engine
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.provider.Settings
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.net.toUri
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupActionBarWithNavController
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.launch
import su.xash.engine.databinding.ActivityMainBinding import su.xash.engine.databinding.ActivityMainBinding
import su.xash.engine.model.AppUpdater
import su.xash.engine.util.CrashReports import su.xash.engine.util.CrashReports
import su.xash.engine.util.monospaceTextView
import su.xash.engine.util.showDownloadProgressDialog
import java.io.File import java.io.File
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
@@ -36,6 +47,94 @@ class MainActivity : AppCompatActivity() {
CrashReports.prune(this) CrashReports.prune(this)
showPendingCrashReport() showPendingCrashReport()
checkForEngineUpdate()
}
private fun checkForEngineUpdate() {
val prefs = getSharedPreferences(UPDATE_PREFS, Context.MODE_PRIVATE)
val now = System.currentTimeMillis()
if (now - prefs.getLong(KEY_LAST_CHECK, 0L) < CHECK_INTERVAL_MS)
return
val updater = AppUpdater(this)
lifecycleScope.launch {
val info = updater.checkForUpdate()
prefs.edit().putLong(KEY_LAST_CHECK, now).apply()
if (info == null)
return@launch
if (prefs.getInt(KEY_DISMISSED_BUILDNUM, -1) >= info.buildNum)
return@launch
val changelog = updater.fetchChangelog(BuildConfig.GIT_HASH, info.tagName)
showEngineUpdateDialog(updater, info.buildNum, changelog, prefs)
}
}
private fun showEngineUpdateDialog(
updater: AppUpdater,
remoteBuildNum: Int,
changelog: List<AppUpdater.CommitInfo>?,
prefs: android.content.SharedPreferences,
) {
val builder = MaterialAlertDialogBuilder(this)
.setTitle(R.string.engine_update_available)
.setMessage(getString(R.string.engine_update_message, remoteBuildNum))
.setPositiveButton(R.string.engine_update_download) { _, _ ->
showEngineDownloadDialog(updater)
}
.setNegativeButton(R.string.engine_update_later) { _, _ ->
prefs.edit().putInt(KEY_DISMISSED_BUILDNUM, remoteBuildNum).apply()
}
if (!changelog.isNullOrEmpty()) {
val text = buildString {
append(getString(R.string.engine_update_changelog_header))
val shown = changelog.take(CHANGELOG_MAX_LINES)
for (c in shown)
append("\n").append(c.subject)
val extra = changelog.size - shown.size
if (extra > 0)
append("\n").append(getString(R.string.engine_update_changelog_more, extra))
}
builder.setView(monospaceTextView(this, text))
}
builder.show()
}
private fun showEngineDownloadDialog(updater: AppUpdater) {
if (!updater.canInstall()) {
promptForInstallPermission()
return
}
showDownloadProgressDialog(
ctx = this,
titleRes = R.string.engine_update_downloading,
cancelable = true,
scope = lifecycleScope,
download = { onProgress -> updater.downloadAndInstall(onProgress) },
)
}
private fun promptForInstallPermission() {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.engine_update_permission_needed)
.setMessage(R.string.engine_update_permission_message)
.setPositiveButton(R.string.engine_update_open_settings) { _, _ ->
val packageIntent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,
"package:$packageName".toUri())
try {
startActivity(packageIntent)
} catch (_: ActivityNotFoundException) {
try {
startActivity(Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES))
} catch (_: ActivityNotFoundException) {
// no settings screen — nothing more we can do
}
}
}
.setNegativeButton(android.R.string.cancel, null)
.show()
} }
override fun onSupportNavigateUp(): Boolean { override fun onSupportNavigateUp(): Boolean {
@@ -43,26 +142,45 @@ class MainActivity : AppCompatActivity() {
} }
private fun showPendingCrashReport() { private fun showPendingCrashReport() {
val pending = CrashReports.pendingFile(this) val pending = CrashReports.pendingStacktrace(this)
if (!pending.exists() || pending.length() == 0L) if (!pending.exists() || pending.length() == 0L)
return return
val historyDir = CrashReports.historyDir(this).apply { mkdirs() } val historyDir = CrashReports.historyDir(this).apply { mkdirs() }
val ts = SimpleDateFormat("yyyyMMdd-HHmmss", Locale.US).format(Date()) val ts = SimpleDateFormat("yyyyMMdd-HHmmss", Locale.US).format(Date())
val archived = File(historyDir, "crash-$ts.log") val entryDir = File(historyDir, "crash-$ts").apply { mkdirs() }
if (!pending.renameTo(archived)) {
// fall back to in-place read if move failed; still consume the file
archived.writeText(pending.readText())
pending.delete()
}
val content = archived.readText() moveOrCopy(pending, File(entryDir, CrashReports.STACKTRACE_NAME))
moveOrCopy(CrashReports.pendingSysinfo(this), File(entryDir, CrashReports.SYSINFO_NAME))
moveOrCopy(CrashReports.pendingIntent(this), File(entryDir, CrashReports.INTENT_NAME))
moveOrCopy(CrashReports.pendingEngineLog(this), File(entryDir, CrashReports.ENGINELOG_NAME))
val entry = CrashReports.Entry(entryDir)
AlertDialog.Builder(this) AlertDialog.Builder(this)
.setTitle(R.string.crash_dialog_title) .setTitle(R.string.crash_dialog_title)
.setView(CrashReports.buildContentView(this, content)) .setView(monospaceTextView(this, entry.summary()))
.setPositiveButton(R.string.crash_send_to_developers) { _, _ -> CrashReports.sendByEmail(this, content) } .setPositiveButton(R.string.crash_send_to_developers) { _, _ -> CrashReports.sendByEmail(this, entry) }
.setNeutralButton(R.string.crash_share) { _, _ -> CrashReports.share(this, archived) } .setNeutralButton(R.string.crash_share) { _, _ -> CrashReports.share(this, entry) }
.setNegativeButton(R.string.crash_dismiss, null) .setNegativeButton(R.string.crash_dismiss, null)
.show() .show()
} }
private fun moveOrCopy(src: File, dst: File) {
if (!src.exists())
return
if (src.renameTo(dst))
return
src.copyTo(dst, overwrite = true)
src.delete()
}
companion object {
private const val CHANGELOG_MAX_LINES = 15
private const val UPDATE_PREFS = "app_updater"
private const val KEY_LAST_CHECK = "last_check_ms"
private const val KEY_DISMISSED_BUILDNUM = "dismissed_buildnum"
private const val CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000L
}
} }
@@ -1,6 +1,7 @@
package su.xash.engine; package su.xash.engine;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.os.Build; import android.os.Build;
@@ -14,6 +15,7 @@ import android.view.WindowManager;
import org.libsdl.app.SDLActivity; import org.libsdl.app.SDLActivity;
import su.xash.engine.util.AndroidBug5497Workaround; import su.xash.engine.util.AndroidBug5497Workaround;
import su.xash.engine.util.CrashReports;
import java.io.File; import java.io.File;
import java.util.Arrays; import java.util.Arrays;
@@ -121,6 +123,45 @@ public class XashActivity extends SDLActivity {
return getWindow().superDispatchKeyEvent(event); return getWindow().superDispatchKeyEvent(event);
} }
private static void appendStringExtra(StringBuilder sb, Intent intent, String key) {
String value = intent.getStringExtra(key);
if (value != null)
sb.append(" ").append(key).append(" = ").append(value).append('\n');
}
// record intent info, so that it could be consumed later for crash reporting
private void recordLaunchInfo() {
// do not overwrite current launch info with pending crash log, shouldn't happen but might
File pendingCrash = new File(getFilesDir(), "crashes/" + CrashReports.STACKTRACE_NAME);
if (pendingCrash.exists() && pendingCrash.length() > 0)
return;
// write Android version, fingerprint, supported abis, etc
CrashReports.writeSystemInfo(this);
// now create intent info and pass it to crash reporting
Intent intent = getIntent();
if (intent == null)
return;
StringBuilder sb = new StringBuilder();
sb.append("Action: ").append(intent.getAction()).append('\n');
sb.append("Data: ").append(intent.getDataString()).append('\n');
sb.append("Calling package: ").append(getCallingPackage()).append('\n');
sb.append("Extras:\n");
// only write intent extras that we care about
appendStringExtra(sb, intent, "gamedir");
appendStringExtra(sb, intent, "gamelibdir");
appendStringExtra(sb, intent, "pakfile");
appendStringExtra(sb, intent, "basedir");
appendStringExtra(sb, intent, "package");
appendStringExtra(sb, intent, "argv");
sb.append(" usevolume = ").append(intent.getBooleanExtra("usevolume", false)).append('\n');
String[] env = intent.getStringArrayExtra("env");
if (env != null)
sb.append(" env = ").append(Arrays.toString(env)).append('\n');
CrashReports.writeIntentInfo(this, sb.toString());
}
// TODO: REMOVE LATER, temporary launchers support? // TODO: REMOVE LATER, temporary launchers support?
@Override @Override
protected String[] getArguments() { protected String[] getArguments() {
@@ -128,6 +169,8 @@ public class XashActivity extends SDLActivity {
crashDir.mkdirs(); crashDir.mkdirs();
nativeSetenv("XASH3D_CRASH_DIR", crashDir.getAbsolutePath()); nativeSetenv("XASH3D_CRASH_DIR", crashDir.getAbsolutePath());
recordLaunchInfo();
String gamedir = getIntent().getStringExtra("gamedir"); String gamedir = getIntent().getStringExtra("gamedir");
if (gamedir == null) gamedir = "valve"; if (gamedir == null) gamedir = "valve";
nativeSetenv("XASH3D_GAME", gamedir); nativeSetenv("XASH3D_GAME", gamedir);
@@ -0,0 +1,205 @@
package su.xash.engine.model
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller
import android.os.Build
import android.util.Log
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.withContext
import org.json.JSONException
import org.json.JSONObject
import su.xash.engine.BuildConfig
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.net.HttpURLConnection
import java.net.URL
import kotlin.coroutines.coroutineContext
class AppUpdater(private val context: Context) {
data class UpdateInfo(val buildNum: Int, val tagName: String)
data class CommitInfo(val sha: String, val subject: String)
fun canInstall(): Boolean =
Build.VERSION.SDK_INT < Build.VERSION_CODES.O ||
context.packageManager.canRequestPackageInstalls()
suspend fun checkForUpdate(): UpdateInfo? {
if (!BuildConfig.ENABLE_AUTO_UPDATE) return null
return withContext(Dispatchers.IO) {
var connection: HttpURLConnection? = null
try {
connection = URL(RELEASE_API_URL).openConnection() as HttpURLConnection
connection.connectTimeout = 5000
connection.readTimeout = 5000
connection.setRequestProperty("Accept", "application/vnd.github+json")
connection.connect()
if (connection.responseCode != HttpURLConnection.HTTP_OK) {
Log.w(TAG, "Release API check failed: HTTP ${connection.responseCode}")
return@withContext null
}
val release = JSONObject(connection.inputStream.bufferedReader().readText())
val body = release.optString("body", "")
val tagName = release.optString("tag_name").ifEmpty { TAG_CONTINUOUS }
// buildnum is days-since-2015-04-01, same metric as VERSION_CODE / 10000
val remote = BUILDNUM_REGEX.find(body)?.groupValues?.get(1)?.toIntOrNull()
val localDays = BuildConfig.VERSION_CODE / 10000
Log.i(TAG, "Remote buildnum: $remote (tag=$tagName), local: $localDays")
if (remote != null && remote - localDays >= STALENESS_DAYS)
UpdateInfo(remote, tagName)
else
null
} catch (e: CancellationException) {
throw e
} catch (e: IOException) {
Log.w(TAG, "Update check failed: ${e.message}")
null
} catch (e: JSONException) {
Log.w(TAG, "Update check parse failed: ${e.message}")
null
} finally {
connection?.disconnect()
}
}
}
suspend fun fetchChangelog(fromRef: String, toRef: String): List<CommitInfo>? {
if (fromRef.isEmpty() || toRef.isEmpty())
return null
return withContext(Dispatchers.IO) {
var connection: HttpURLConnection? = null
try {
connection = URL("$COMPARE_API_BASE/$fromRef...$toRef").openConnection() as HttpURLConnection
connection.connectTimeout = 5000
connection.readTimeout = 5000
connection.setRequestProperty("Accept", "application/vnd.github+json")
connection.connect()
if (connection.responseCode != HttpURLConnection.HTTP_OK) {
Log.w(TAG, "Compare API failed: HTTP ${connection.responseCode}")
return@withContext null
}
val json = JSONObject(connection.inputStream.bufferedReader().readText())
val commits = json.optJSONArray("commits") ?: return@withContext null
val result = ArrayList<CommitInfo>(commits.length())
for (i in 0 until commits.length()) {
val c = commits.getJSONObject(i)
val sha = c.optString("sha").ifEmpty { continue }
val msg = c.optJSONObject("commit")?.optString("message") ?: continue
val subject = msg.substringBefore('\n').trim()
if (subject.isNotEmpty())
result.add(CommitInfo(sha, subject))
}
// GitHub returns oldest first
result.reverse()
result
} catch (e: CancellationException) {
throw e
} catch (e: IOException) {
Log.w(TAG, "Changelog fetch failed: ${e.message}")
null
} catch (e: JSONException) {
Log.w(TAG, "Changelog parse failed: ${e.message}")
null
} finally {
connection?.disconnect()
}
}
}
suspend fun downloadAndInstall(onProgress: (Long, Long) -> Unit): Result<Unit> {
return withContext(Dispatchers.IO) {
val tempFile = File(context.cacheDir, "xash3d-fwgs-update.apk")
var connection: HttpURLConnection? = null
try {
connection = URL(APK_URL).openConnection() as HttpURLConnection
connection.connectTimeout = 10000
connection.readTimeout = 30000
connection.instanceFollowRedirects = true
connection.connect()
if (connection.responseCode != HttpURLConnection.HTTP_OK)
return@withContext Result.failure(IOException("HTTP ${connection.responseCode}"))
val total = connection.contentLengthLong
var downloaded = 0L
var lastEmit = 0L
connection.inputStream.use { input ->
FileOutputStream(tempFile).use { output ->
val buffer = ByteArray(65536)
while (true) {
coroutineContext.ensureActive()
val read = input.read(buffer)
if (read < 0)
break
output.write(buffer, 0, read)
downloaded += read
val now = System.currentTimeMillis()
if (now - lastEmit >= PROGRESS_INTERVAL_MS) {
lastEmit = now
withContext(Dispatchers.Main) { onProgress(downloaded, total) }
}
}
}
}
withContext(Dispatchers.Main) { onProgress(downloaded, total) }
Log.i(TAG, "Downloaded APK: ${tempFile.length()} bytes -> ${tempFile.absolutePath}")
triggerInstall(tempFile)
Result.success(Unit)
} catch (e: CancellationException) {
tempFile.delete()
throw e
} catch (e: IOException) {
tempFile.delete()
Result.failure(e)
} finally {
connection?.disconnect()
}
}
}
private fun triggerInstall(apk: File) {
val installer = context.packageManager.packageInstaller
val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
val sessionId = installer.createSession(params)
installer.openSession(sessionId).use { session ->
session.openWrite("base.apk", 0, apk.length()).use { out ->
apk.inputStream().use { it.copyTo(out) }
session.fsync(out)
}
val statusIntent = Intent(INSTALL_ACTION).setPackage(context.packageName)
val piFlags = PendingIntent.FLAG_UPDATE_CURRENT or
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) PendingIntent.FLAG_MUTABLE else 0
val pi = PendingIntent.getBroadcast(context, sessionId, statusIntent, piFlags)
session.commit(pi.intentSender)
}
}
companion object {
private const val TAG = "AppUpdater"
private const val STALENESS_DAYS = 3
private const val PROGRESS_INTERVAL_MS = 100L
private const val TAG_CONTINUOUS = "continuous"
private const val INSTALL_ACTION = "su.xash.engine.INSTALL_RESULT"
private const val APK_URL =
"https://github.com/FWGS/xash3d-fwgs/releases/download/continuous/xash3d-fwgs-android.apk"
private const val RELEASE_API_URL =
"https://api.github.com/repos/FWGS/xash3d-fwgs/releases/tags/continuous"
private const val COMPARE_API_BASE =
"https://api.github.com/repos/FWGS/xash3d-fwgs/compare"
private val BUILDNUM_REGEX = Regex("""buildnum\s+(\d+)""")
}
}
@@ -6,17 +6,15 @@ import android.content.pm.PackageInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.view.LayoutInflater
import android.widget.TextView
import androidx.core.net.toUri import androidx.core.net.toUri
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.progressindicator.LinearProgressIndicator
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import su.xash.engine.R import su.xash.engine.R
import su.xash.engine.XashActivity import su.xash.engine.XashActivity
import su.xash.engine.util.showDownloadProgressDialog
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
@@ -139,44 +137,14 @@ class Game(val ctx: Context, val basedir: File, val gameInfoFile: File) {
} }
private fun showDownloadDialog(ctx: Context, downloader: GameLibDownloader, commandLineArgs: String) { private fun showDownloadDialog(ctx: Context, downloader: GameLibDownloader, commandLineArgs: String) {
val view = LayoutInflater.from(ctx).inflate(R.layout.dialog_download_progress, null) showDownloadProgressDialog(
val progressBar = view.findViewById<LinearProgressIndicator>(R.id.downloadProgress) ctx = ctx,
val statusText = view.findViewById<TextView>(R.id.downloadStatus) titleRes = R.string.downloading_game_libs,
cancelable = true,
val dialog = MaterialAlertDialogBuilder(ctx) scope = CoroutineScope(Dispatchers.Main + SupervisorJob()),
.setTitle(R.string.downloading_game_libs) download = { onProgress -> downloader.download(basedir.name, onProgress) },
.setView(view) onSuccess = { launchEngine(ctx, commandLineArgs) },
.setCancelable(true) )
.setNegativeButton(android.R.string.cancel) { d, _ -> d.dismiss() }
.create()
dialog.show()
val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
val job = scope.launch {
val result = downloader.download(basedir.name) { progress ->
progressBar.isIndeterminate = false
progressBar.progress = (progress * 100).toInt()
statusText.text = ctx.getString(R.string.download_progress, (progress * 100).toInt())
}
if (!dialog.isShowing) return@launch
dialog.dismiss()
if (result.isSuccess) {
launchEngine(ctx, commandLineArgs)
} else {
MaterialAlertDialogBuilder(ctx)
.setTitle(R.string.download_failed)
.setMessage(result.exceptionOrNull()?.message
?: ctx.getString(R.string.download_error))
.setPositiveButton(android.R.string.ok, null)
.show()
}
}
dialog.setOnDismissListener { job.cancel() }
} }
private fun showManifestErrorDialog(ctx: Context, commandLineArgs: String, cause: Throwable) { private fun showManifestErrorDialog(ctx: Context, commandLineArgs: String, cause: Throwable) {
@@ -199,7 +199,7 @@ class GameLibDownloader(private val context: Context) {
private suspend fun tryDownload( private suspend fun tryDownload(
url: String, url: String,
dest: File, dest: File,
onProgress: (Float) -> Unit onProgress: (Long, Long) -> Unit
): Exception? { ): Exception? {
var connection: HttpURLConnection? = null var connection: HttpURLConnection? = null
try { try {
@@ -215,6 +215,7 @@ class GameLibDownloader(private val context: Context) {
val total = connection.contentLengthLong val total = connection.contentLengthLong
var downloaded = 0L var downloaded = 0L
var lastEmit = 0L
connection.inputStream.use { input -> connection.inputStream.use { input ->
FileOutputStream(dest).use { output -> FileOutputStream(dest).use { output ->
@@ -226,13 +227,15 @@ class GameLibDownloader(private val context: Context) {
break break
output.write(buffer, 0, read) output.write(buffer, 0, read)
downloaded += read downloaded += read
if (total > 0) { val now = System.currentTimeMillis()
val progress = downloaded.toFloat() / total if (now - lastEmit >= PROGRESS_INTERVAL_MS) {
withContext(Dispatchers.Main) { onProgress(progress) } lastEmit = now
withContext(Dispatchers.Main) { onProgress(downloaded, total) }
} }
} }
} }
} }
withContext(Dispatchers.Main) { onProgress(downloaded, total) }
return null return null
} catch (e: Exception) { } catch (e: Exception) {
@@ -242,7 +245,7 @@ class GameLibDownloader(private val context: Context) {
} }
} }
suspend fun download(gamedir: String, onProgress: (Float) -> Unit): Result<Unit> { suspend fun download(gamedir: String, onProgress: (Long, Long) -> Unit): Result<Unit> {
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
val manifest = fetchManifest() val manifest = fetchManifest()
?: return@withContext Result.failure(IOException("Failed to fetch manifest")) ?: return@withContext Result.failure(IOException("Failed to fetch manifest"))
@@ -364,6 +367,7 @@ class GameLibDownloader(private val context: Context) {
companion object { companion object {
private const val TAG = "GameLibDownloader" private const val TAG = "GameLibDownloader"
private const val PROGRESS_INTERVAL_MS = 100L
private const val RELEASE_BASE_URL = private const val RELEASE_BASE_URL =
"https://github.com/FWGS/hlsdk-mega-build/releases/download/continuous" "https://github.com/FWGS/hlsdk-mega-build/releases/download/continuous"
private const val MANIFEST_URL = private const val MANIFEST_URL =
@@ -0,0 +1,42 @@
package su.xash.engine.model
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller
import android.os.Build
import android.util.Log
import android.widget.Toast
import su.xash.engine.R
class InstallStatusReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -1)
when (status) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
val confirm: Intent? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
} else {
@Suppress("DEPRECATION")
intent.getParcelableExtra(Intent.EXTRA_INTENT)
}
confirm?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
confirm?.let { context.startActivity(it) }
}
PackageInstaller.STATUS_SUCCESS -> Log.i(TAG, "Install succeeded")
else -> {
val msg = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE).orEmpty()
Log.w(TAG, "Install status $status: $msg")
Toast.makeText(
context,
context.getString(R.string.engine_install_failed, msg),
Toast.LENGTH_LONG,
).show()
}
}
}
companion object {
private const val TAG = "InstallStatus"
}
}
@@ -6,7 +6,7 @@ import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import su.xash.engine.R import su.xash.engine.R
import su.xash.engine.util.CrashReports import su.xash.engine.util.CrashReports
import java.io.File import su.xash.engine.util.monospaceTextView
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
@@ -26,9 +26,12 @@ class CrashLogsFragment : PreferenceFragmentCompat() {
val ctx = requireContext() val ctx = requireContext()
preferenceScreen.removeAll() preferenceScreen.removeAll()
val files = CrashReports.historyDir(ctx).listFiles()?.sortedByDescending { it.lastModified() } ?: emptyList() val dirs = CrashReports.historyDir(ctx).listFiles()
?.filter { it.isDirectory }
?.sortedByDescending { it.lastModified() }
?: emptyList()
if (files.isEmpty()) { if (dirs.isEmpty()) {
preferenceScreen.addPreference(Preference(ctx).apply { preferenceScreen.addPreference(Preference(ctx).apply {
setTitle(R.string.crash_logs_empty) setTitle(R.string.crash_logs_empty)
isSelectable = false isSelectable = false
@@ -37,28 +40,27 @@ class CrashLogsFragment : PreferenceFragmentCompat() {
} }
val fmt = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US) val fmt = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US)
files.forEach { file -> dirs.forEach { dir ->
preferenceScreen.addPreference(Preference(ctx).apply { preferenceScreen.addPreference(Preference(ctx).apply {
title = fmt.format(Date(file.lastModified())) title = fmt.format(Date(dir.lastModified()))
summary = file.name summary = dir.name
setOnPreferenceClickListener { setOnPreferenceClickListener {
showCrashLog(file) showCrashLog(CrashReports.Entry(dir))
true true
} }
}) })
} }
} }
private fun showCrashLog(file: File) { private fun showCrashLog(entry: CrashReports.Entry) {
val ctx = requireContext() val ctx = requireContext()
val content = file.readText()
AlertDialog.Builder(ctx) AlertDialog.Builder(ctx)
.setTitle(file.name) .setTitle(entry.name)
.setView(CrashReports.buildContentView(ctx, content)) .setView(monospaceTextView(ctx, entry.summary()))
.setPositiveButton(R.string.crash_send_to_developers) { _, _ -> CrashReports.sendByEmail(ctx, content) } .setPositiveButton(R.string.crash_send_to_developers) { _, _ -> CrashReports.sendByEmail(ctx, entry) }
.setNeutralButton(R.string.crash_share) { _, _ -> CrashReports.share(ctx, file) } .setNeutralButton(R.string.crash_share) { _, _ -> CrashReports.share(ctx, entry) }
.setNegativeButton(R.string.crash_log_delete) { _, _ -> .setNegativeButton(R.string.crash_log_delete) { _, _ ->
file.delete() entry.dir.deleteRecursively()
populate() populate()
} }
.show() .show()
@@ -2,16 +2,17 @@ package su.xash.engine.util
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Typeface
import android.net.Uri import android.net.Uri
import android.util.TypedValue import android.os.Build
import android.view.View import androidx.appcompat.app.AlertDialog
import android.widget.ScrollView
import android.widget.TextView
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import su.xash.engine.BuildConfig import su.xash.engine.BuildConfig
import su.xash.engine.R import su.xash.engine.R
import java.io.BufferedOutputStream
import java.io.File import java.io.File
import java.io.FileOutputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
object CrashReports { object CrashReports {
private const val PREFS = "crash_reports" private const val PREFS = "crash_reports"
@@ -20,7 +21,40 @@ object CrashReports {
private const val D = "9c8d9e8c97bf9988988cd1989e86" private const val D = "9c8d9e8c97bf9988988cd1989e86"
fun pendingFile(ctx: Context): File = File(ctx.filesDir, "crashes/crash.log") const val STACKTRACE_NAME = "crash.log"
const val SYSINFO_NAME = "sysinfo.txt"
const val INTENT_NAME = "intent.txt"
const val ENGINELOG_NAME = "engine.log"
class Entry(val dir: File) {
val name: String get() = dir.name
val timestamp: Long get() = dir.lastModified()
val stacktrace: File get() = File(dir, STACKTRACE_NAME)
val sysinfo: File get() = File(dir, SYSINFO_NAME)
val intent: File get() = File(dir, INTENT_NAME)
val engineLog: File get() = File(dir, ENGINELOG_NAME)
fun attachments(): List<File> = listOf(stacktrace, sysinfo, intent, engineLog).filter { it.exists() && it.length() > 0 }
fun summary(): String = buildString {
if (stacktrace.exists())
append(stacktrace.readText())
if (sysinfo.exists()) {
append("\n--- System info ---\n").append(sysinfo.readText())
}
if (intent.exists()) {
append("\n--- XashActivity intent ---\n").append(intent.readText())
}
}
}
fun pendingDir(ctx: Context): File = File(ctx.filesDir, "crashes")
fun pendingStacktrace(ctx: Context): File = File(pendingDir(ctx), STACKTRACE_NAME)
fun pendingSysinfo(ctx: Context): File = File(pendingDir(ctx), SYSINFO_NAME)
fun pendingIntent(ctx: Context): File = File(pendingDir(ctx), INTENT_NAME)
fun pendingEngineLog(ctx: Context): File = File(pendingDir(ctx), ENGINELOG_NAME)
fun historyDir(ctx: Context): File = File(ctx.filesDir, "crashes/history") fun historyDir(ctx: Context): File = File(ctx.filesDir, "crashes/history")
// wipe everything on app update; otherwise drop logs older than 30 days // wipe everything on app update; otherwise drop logs older than 30 days
@@ -30,47 +64,109 @@ object CrashReports {
val currentVersion = BuildConfig.VERSION_CODE val currentVersion = BuildConfig.VERSION_CODE
if (lastVersion != currentVersion) { if (lastVersion != currentVersion) {
historyDir(ctx).listFiles()?.forEach { it.delete() } historyDir(ctx).deleteRecursively()
pendingFile(ctx).delete() pendingStacktrace(ctx).delete()
pendingSysinfo(ctx).delete()
pendingIntent(ctx).delete()
pendingEngineLog(ctx).delete()
prefs.edit().putInt(KEY_LAST_VERSION, currentVersion).apply() prefs.edit().putInt(KEY_LAST_VERSION, currentVersion).apply()
return return
} }
val cutoff = System.currentTimeMillis() - MAX_AGE_MS val cutoff = System.currentTimeMillis() - MAX_AGE_MS
historyDir(ctx).listFiles()?.forEach { f -> historyDir(ctx).listFiles()?.forEach { entry ->
if (f.lastModified() < cutoff) f.delete() if (entry.lastModified() < cutoff)
entry.deleteRecursively()
} }
} }
fun sendByEmail(ctx: Context, content: String) { @JvmStatic
val addr = D.chunked(2) { (it.toString().toInt(16) xor 0xFF).toChar() }.joinToString("") fun writeSystemInfo(ctx: Context) {
val intent = Intent(Intent.ACTION_SENDTO).apply { val text = buildString {
data = Uri.fromParts("mailto", addr, null) append("App version: ").append(BuildConfig.VERSION_NAME).append(" (code ").append(BuildConfig.VERSION_CODE).append(")\n")
putExtra(Intent.EXTRA_SUBJECT, ctx.getString(R.string.crash_email_subject)) append("Application ID: ").append(BuildConfig.APPLICATION_ID).append('\n')
putExtra(Intent.EXTRA_TEXT, content) append("Android: ").append(Build.VERSION.RELEASE).append(" (SDK ").append(Build.VERSION.SDK_INT).append(")\n")
append("Manufacturer: ").append(Build.MANUFACTURER).append('\n')
append("Brand: ").append(Build.BRAND).append('\n')
append("Model: ").append(Build.MODEL).append('\n')
append("Device: ").append(Build.DEVICE).append('\n')
append("Product: ").append(Build.PRODUCT).append('\n')
append("Hardware: ").append(Build.HARDWARE).append('\n')
append("Fingerprint: ").append(Build.FINGERPRINT).append('\n')
append("Supported ABIs: ").append(Build.SUPPORTED_ABIS.joinToString(", ")).append('\n')
} }
if (intent.resolveActivity(ctx.packageManager) != null) {
ctx.startActivity(intent) runCatching {
pendingDir(ctx).mkdirs()
pendingSysinfo(ctx).writeText(text)
} }
} }
fun buildContentView(ctx: Context, content: String): View { @JvmStatic
val pad = (16 * ctx.resources.displayMetrics.density).toInt() fun writeIntentInfo(ctx: Context, text: String) {
val text = TextView(ctx).apply { runCatching {
text = content pendingDir(ctx).mkdirs()
typeface = Typeface.MONOSPACE pendingIntent(ctx).writeText(text)
setTextIsSelectable(true)
setTextSize(TypedValue.COMPLEX_UNIT_SP, 12f)
setPadding(pad, pad, pad, pad)
} }
return ScrollView(ctx).apply { addView(text) }
} }
fun share(ctx: Context, file: File) { private fun zipUri(ctx: Context, entry: Entry): Uri {
val zipDir = File(ctx.cacheDir, "crashes").apply { mkdirs() }
val zip = File(zipDir, "${entry.name}.zip")
ZipOutputStream(BufferedOutputStream(FileOutputStream(zip))).use { zos ->
entry.attachments().forEach { f ->
zos.putNextEntry(ZipEntry(f.name))
f.inputStream().use { it.copyTo(zos) }
zos.closeEntry()
}
}
val authority = "${BuildConfig.APPLICATION_ID}.fileprovider" val authority = "${BuildConfig.APPLICATION_ID}.fileprovider"
val uri = FileProvider.getUriForFile(ctx, authority, file) return FileProvider.getUriForFile(ctx, authority, zip)
}
fun sendByEmail(ctx: Context, entry: Entry) {
val addr = D.chunked(2) { (it.toString().toInt(16) xor 0xFF).toChar() }.joinToString("")
val mailtoProbe = Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", addr, null))
val mailApps = ctx.packageManager.queryIntentActivities(mailtoProbe, 0)
if (mailApps.isEmpty()) {
AlertDialog.Builder(ctx)
.setTitle(R.string.crash_no_mail_app_title)
.setMessage(R.string.crash_no_mail_app_message)
.setPositiveButton(android.R.string.ok, null)
.show()
return
}
val uri = zipUri(ctx, entry)
val baseSend = Intent(Intent.ACTION_SEND).apply {
type = "application/zip"
putExtra(Intent.EXTRA_EMAIL, arrayOf(addr))
putExtra(Intent.EXTRA_SUBJECT, ctx.getString(R.string.crash_email_subject))
putExtra(Intent.EXTRA_TEXT, ctx.getString(R.string.crash_email_body))
putExtra(Intent.EXTRA_STREAM, uri)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
val targeted = mailApps.map { ri ->
Intent(baseSend).apply { setPackage(ri.activityInfo.packageName) }
}
if (targeted.size == 1) {
ctx.startActivity(targeted[0])
return
}
// Multiple mail apps — show a chooser limited to them, no other share targets
val chooser = Intent.createChooser(targeted[0], ctx.getString(R.string.crash_send_to_developers))
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targeted.drop(1).toTypedArray())
ctx.startActivity(chooser)
}
fun share(ctx: Context, entry: Entry) {
val uri = zipUri(ctx, entry)
val intent = Intent(Intent.ACTION_SEND).apply { val intent = Intent(Intent.ACTION_SEND).apply {
type = "text/plain" type = "application/zip"
putExtra(Intent.EXTRA_SUBJECT, ctx.getString(R.string.crash_email_subject)) putExtra(Intent.EXTRA_SUBJECT, ctx.getString(R.string.crash_email_subject))
putExtra(Intent.EXTRA_STREAM, uri) putExtra(Intent.EXTRA_STREAM, uri)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
@@ -0,0 +1,69 @@
package su.xash.engine.util
import android.content.Context
import android.text.format.Formatter
import android.view.LayoutInflater
import android.widget.TextView
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.progressindicator.LinearProgressIndicator
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import su.xash.engine.R
fun showDownloadProgressDialog(
ctx: Context,
titleRes: Int,
cancelable: Boolean,
scope: CoroutineScope,
download: suspend ((Long, Long) -> Unit) -> Result<Unit>,
onSuccess: (() -> Unit)? = null,
) {
val view = LayoutInflater.from(ctx).inflate(R.layout.dialog_download_progress, null)
val progressBar = view.findViewById<LinearProgressIndicator>(R.id.downloadProgress)
val statusText = view.findViewById<TextView>(R.id.downloadStatus)
val dialog = MaterialAlertDialogBuilder(ctx)
.setTitle(titleRes)
.setView(view)
.setCancelable(cancelable)
.apply {
if (cancelable)
setNegativeButton(android.R.string.cancel) { d, _ -> d.dismiss() }
}
.create()
dialog.show()
val job = scope.launch {
val result = download { downloaded, total ->
val downloadedStr = Formatter.formatShortFileSize(ctx, downloaded)
if (total > 0) {
progressBar.isIndeterminate = false
progressBar.progress = (downloaded * 100 / total).toInt()
val totalStr = Formatter.formatShortFileSize(ctx, total)
statusText.text = ctx.getString(R.string.download_progress, downloadedStr, totalStr)
} else {
statusText.text = ctx.getString(R.string.download_progress_unknown, downloadedStr)
}
}
if (!dialog.isShowing)
return@launch
dialog.dismiss()
if (result.isSuccess) {
onSuccess?.invoke()
} else {
MaterialAlertDialogBuilder(ctx)
.setTitle(R.string.download_failed)
.setMessage(result.exceptionOrNull()?.message
?: ctx.getString(R.string.download_error))
.setPositiveButton(android.R.string.ok, null)
.show()
}
}
if (cancelable)
dialog.setOnDismissListener { job.cancel() }
}
@@ -0,0 +1,19 @@
package su.xash.engine.util
import android.content.Context
import android.graphics.Typeface
import android.util.TypedValue
import android.view.View
import android.widget.ScrollView
import android.widget.TextView
fun monospaceTextView(ctx: Context, content: String): View {
val pad = (16 * ctx.resources.displayMetrics.density).toInt()
val text = TextView(ctx).apply {
text = content
typeface = Typeface.MONOSPACE
setTextSize(TypedValue.COMPLEX_UNIT_SP, 12f)
setPadding(pad, pad, pad, pad)
}
return ScrollView(ctx).apply { addView(text) }
}
+16 -1
View File
@@ -30,9 +30,13 @@
<string name="crash_logs">Журналы сбоев</string> <string name="crash_logs">Журналы сбоев</string>
<string name="crash_logs_empty">Нет сохранённых журналов сбоев</string> <string name="crash_logs_empty">Нет сохранённых журналов сбоев</string>
<string name="crash_log_delete">Удалить</string> <string name="crash_log_delete">Удалить</string>
<string name="crash_email_body">К письму прикреплены подробности сбоя. Опишите, пожалуйста, как можно подробнее, что вы делали, когда игра вылетела — любая мелочь поможет нам исправить ошибку!</string>
<string name="crash_no_mail_app_title">Почтовое приложение не найдено</string>
<string name="crash_no_mail_app_message">На этом устройстве нет почтового клиента. Установите его (или воспользуйтесь кнопкой «Поделиться», чтобы отправить отчёт другим способом) и попробуйте снова.</string>
<string name="downloading_game_libs">Загрузка игровых библиотек</string> <string name="downloading_game_libs">Загрузка игровых библиотек</string>
<string name="downloading">Загрузка…</string> <string name="downloading">Загрузка…</string>
<string name="download_progress">Загрузка… %1$d%%</string> <string name="download_progress">Загрузка… %1$s / %2$s</string>
<string name="download_progress_unknown">Загрузка… %1$s</string>
<string name="download_failed">Ошибка загрузки</string> <string name="download_failed">Ошибка загрузки</string>
<string name="download_error">Произошла ошибка при загрузке игровых библиотек.</string> <string name="download_error">Произошла ошибка при загрузке игровых библиотек.</string>
<string name="update_available">Доступно обновление</string> <string name="update_available">Доступно обновление</string>
@@ -46,4 +50,15 @@
<string name="source_branch">Ветка</string> <string name="source_branch">Ветка</string>
<string name="source_commit">Коммит</string> <string name="source_commit">Коммит</string>
<string name="downloaded_at">Загружено</string> <string name="downloaded_at">Загружено</string>
<string name="engine_update_available">Доступно обновление движка</string>
<string name="engine_update_message">Доступна сборка %1$d. Обновить?</string>
<string name="engine_update_changelog_header">Изменения с вашей сборки:</string>
<string name="engine_update_changelog_more">+ ещё %1$d коммитов</string>
<string name="engine_update_download">Обновить</string>
<string name="engine_update_later">Позже</string>
<string name="engine_update_downloading">Загрузка обновления</string>
<string name="engine_update_permission_needed">Нужно разрешение</string>
<string name="engine_update_permission_message">Чтобы установить обновление, разрешите Xash3D FWGS устанавливать неизвестные приложения в настройках системы.</string>
<string name="engine_update_open_settings">Открыть настройки</string>
<string name="engine_install_failed">Не удалось установить обновление: %1$s</string>
</resources> </resources>
+16 -1
View File
@@ -32,9 +32,13 @@
<string name="crash_logs_empty">No crash logs recorded</string> <string name="crash_logs_empty">No crash logs recorded</string>
<string name="crash_log_delete">Delete</string> <string name="crash_log_delete">Delete</string>
<string name="crash_email_subject" translatable="false">Xash3D FWGS crash report</string> <string name="crash_email_subject" translatable="false">Xash3D FWGS crash report</string>
<string name="crash_email_body">Crash details are attached. Please describe in as much detail as possible what you were doing when the game crashed — every little thing helps us fix it!</string>
<string name="crash_no_mail_app_title">No mail app found</string>
<string name="crash_no_mail_app_message">No email client is installed on this device. Install one (or use Share to send the report another way) and try again.</string>
<string name="downloading_game_libs">Downloading Game Libraries</string> <string name="downloading_game_libs">Downloading Game Libraries</string>
<string name="downloading">Downloading…</string> <string name="downloading">Downloading…</string>
<string name="download_progress">Downloading… %1$d%%</string> <string name="download_progress">Downloading… %1$s / %2$s</string>
<string name="download_progress_unknown">Downloading… %1$s</string>
<string name="download_failed">Download Failed</string> <string name="download_failed">Download Failed</string>
<string name="download_error">An error occurred while downloading game libraries.</string> <string name="download_error">An error occurred while downloading game libraries.</string>
<string name="update_available">Update Available</string> <string name="update_available">Update Available</string>
@@ -48,4 +52,15 @@
<string name="source_branch">Branch</string> <string name="source_branch">Branch</string>
<string name="source_commit">Commit</string> <string name="source_commit">Commit</string>
<string name="downloaded_at">Downloaded</string> <string name="downloaded_at">Downloaded</string>
<string name="engine_update_available">Engine Update Available</string>
<string name="engine_update_message">Build %1$d is available. Update now?</string>
<string name="engine_update_changelog_header">Changes since your build:</string>
<string name="engine_update_changelog_more">+ %1$d more commits</string>
<string name="engine_update_download">Update</string>
<string name="engine_update_later">Later</string>
<string name="engine_update_downloading">Downloading Update</string>
<string name="engine_update_permission_needed">Permission Required</string>
<string name="engine_update_permission_message">To install the update, allow Xash3D FWGS to install unknown apps in system settings.</string>
<string name="engine_update_open_settings">Open settings</string>
<string name="engine_install_failed">Update install failed: %1$s</string>
</resources> </resources>
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<paths> <paths>
<files-path name="crashes" path="crashes/" /> <cache-path name="crash_zips" path="crashes/" />
</paths> </paths>
+16
View File
@@ -16,6 +16,10 @@
#define CS_SIZE 64 // size of one config string #define CS_SIZE 64 // size of one config string
#define CS_TIME 16 // size of time string #define CS_TIME 16 // size of time string
// FIXME: find better place for the shared definition
#define MAX_CLIENT_BITS 5
#define MAX_CLIENTS (1<<MAX_CLIENT_BITS)// 5 bits == 32 clients ( int32 limit )
// platform-specific alignment for types, to not break ABI // platform-specific alignment for types, to not break ABI
#if XASH_PSP #if XASH_PSP
#define MAYBE_ALIGNED( x ) __attribute__(( aligned( 16 ))) #define MAYBE_ALIGNED( x ) __attribute__(( aligned( 16 )))
@@ -114,6 +118,7 @@ typedef int qboolean;
#define FORMAT_CHECK( x ) __attribute__(( format( printf, x, x + 1 ))) #define FORMAT_CHECK( x ) __attribute__(( format( printf, x, x + 1 )))
#define ALLOC_CHECK( x ) __attribute__(( alloc_size( x ))) #define ALLOC_CHECK( x ) __attribute__(( alloc_size( x )))
#define WARN_UNUSED_RESULT __attribute__(( warn_unused_result )) #define WARN_UNUSED_RESULT __attribute__(( warn_unused_result ))
#define MAYBE_UNUSED __attribute__(( unused ))
#define RENAME_SYMBOL( x ) asm( x ) #define RENAME_SYMBOL( x ) asm( x )
#if !defined( offsetof ) #if !defined( offsetof )
#define offsetof( s, m ) __builtin_offsetof( s, m ) #define offsetof( s, m ) __builtin_offsetof( s, m )
@@ -198,6 +203,10 @@ typedef int qboolean;
#define WARN_UNUSED_RESULT #define WARN_UNUSED_RESULT
#endif // !defined( WARN_UNUSED_RESULT ) #endif // !defined( WARN_UNUSED_RESULT )
#if !defined( MAYBE_UNUSED )
#define MAYBE_UNUSED
#endif // !defined( MAYBE_UNUSED )
#if !defined( RENAME_SYMBOL ) #if !defined( RENAME_SYMBOL )
#define RENAME_SYMBOL( x ) #define RENAME_SYMBOL( x )
#endif // !defined( RENAME_SYMBOL ) #endif // !defined( RENAME_SYMBOL )
@@ -268,4 +277,11 @@ typedef int qboolean;
#define HostFourCC( a, b, c, d ) LittleFourCC( a, b, c, d ) #define HostFourCC( a, b, c, d ) LittleFourCC( a, b, c, d )
#endif #endif
static inline short UnalignedShort( short *x )
{
short y;
memcpy( &y, x, sizeof( y ) );
return y;
}
#endif // XASH_TYPES_H #endif // XASH_TYPES_H
+8 -12
View File
@@ -195,7 +195,6 @@ static int AVI_OpenCodecContext( AVCodecContext **dst_dec_ctx, AVFormatContext *
AVI_SpewError( quiet, S_ERROR "Failed to allocate %s codec context", dec->name ); AVI_SpewError( quiet, S_ERROR "Failed to allocate %s codec context", dec->name );
return AVERROR( ENOMEM ); return AVERROR( ENOMEM );
} }
if(( ret = pavcodec_parameters_to_context( dec_ctx, st->codecpar )) < 0 ) if(( ret = pavcodec_parameters_to_context( dec_ctx, st->codecpar )) < 0 )
{ {
AVI_SpewAvError( quiet, "avcodec_parameters_to_context", ret ); AVI_SpewAvError( quiet, "avcodec_parameters_to_context", ret );
@@ -251,8 +250,7 @@ byte *AVI_GetVideoFrame( movie_state_t *Avi, int target )
static void AVI_StreamAudio( movie_state_t *Avi ) static void AVI_StreamAudio( movie_state_t *Avi )
{ {
int buffer_samples, file_samples, file_bytes; rawchan_t *ch;
rawchan_t *ch = NULL;
// keep the same semantics, when S_RAW_SOUND_SOUNDTRACK doesn't play if S_StartStreaming wasn't enabled // keep the same semantics, when S_RAW_SOUND_SOUNDTRACK doesn't play if S_StartStreaming wasn't enabled
qboolean disable_stream = Avi->entnum == S_RAW_SOUND_SOUNDTRACK ? !snd.streaming : false; qboolean disable_stream = Avi->entnum == S_RAW_SOUND_SOUNDTRACK ? !snd.streaming : false;
@@ -273,11 +271,11 @@ static void AVI_StreamAudio( movie_state_t *Avi )
while( ch->s_rawend < snd.soundtime + ch->max_samples ) while( ch->s_rawend < snd.soundtime + ch->max_samples )
{ {
int buffer_samples = ch->max_samples - (ch->s_rawend - snd.soundtime);
int file_samples = buffer_samples * ((float)Avi->rate / SOUND_DMA_SPEED);
int file_bytes;
size_t copy; size_t copy;
buffer_samples = ch->max_samples - (ch->s_rawend - snd.soundtime);
file_samples = buffer_samples * ((float)Avi->rate / SOUND_DMA_SPEED);
if( file_samples <= 1 ) return; // no more samples need if( file_samples <= 1 ) return; // no more samples need
file_bytes = file_samples * pav_get_bytes_per_sample( Avi->s_fmt ) * Avi->channels; file_bytes = file_samples * pav_get_bytes_per_sample( Avi->s_fmt ) * Avi->channels;
@@ -308,8 +306,6 @@ static void AVI_HandleAudio( movie_state_t *Avi, const AVFrame *frame )
{ {
int samples = frame->nb_samples; int samples = frame->nb_samples;
size_t len = samples * pav_get_bytes_per_sample( Avi->s_fmt ) * Avi->channels; size_t len = samples * pav_get_bytes_per_sample( Avi->s_fmt ) * Avi->channels;
int outsamples;
uint8_t *ptr;
// allocate data // allocate data
if( !Avi->cached_audio ) if( !Avi->cached_audio )
@@ -337,8 +333,8 @@ static void AVI_HandleAudio( movie_state_t *Avi, const AVFrame *frame )
} }
} }
ptr = Avi->cached_audio + Avi->cached_audio_len; uint8_t *ptr = Avi->cached_audio + Avi->cached_audio_len;
outsamples = pswr_convert( Avi->swr_ctx, &ptr, samples, (void *)frame->data, samples ); int outsamples = pswr_convert( Avi->swr_ctx, &ptr, samples, (void *)frame->data, samples );
Avi->cached_audio_len += outsamples * pav_get_bytes_per_sample( Avi->s_fmt ) * Avi->channels; Avi->cached_audio_len += outsamples * pav_get_bytes_per_sample( Avi->s_fmt ) * Avi->channels;
// Con_Printf( "%s: got audio chunk of size %d samples\n", __func__, outsamples ); // Con_Printf( "%s: got audio chunk of size %d samples\n", __func__, outsamples );
@@ -463,8 +459,6 @@ qboolean AVI_Think( movie_state_t *Avi )
void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, int quiet ) void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, int quiet )
{ {
byte *dst[4];
int dst_linesize[4];
int ret; int ret;
if( Avi->active ) if( Avi->active )
@@ -529,6 +523,8 @@ void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audi
return; return;
} }
byte *dst[4];
int dst_linesize[4];
if(( ret = pav_image_alloc( dst, dst_linesize, Avi->xres, Avi->yres, AV_PIX_FMT_BGR0, 1 )) < 0 ) if(( ret = pav_image_alloc( dst, dst_linesize, Avi->xres, Avi->yres, AV_PIX_FMT_BGR0, 1 )) < 0 )
{ {
AVI_SpewAvError( quiet, "av_image_alloc", ret ); AVI_SpewAvError( quiet, "av_image_alloc", ret );
+6 -14
View File
@@ -61,16 +61,14 @@ Emulate audio-cd system
*/ */
void CL_PlayCDTrack_f( void ) void CL_PlayCDTrack_f( void )
{ {
const char *command;
const char *pszTrack;
static int track = 0; static int track = 0;
static qboolean paused = false; static qboolean paused = false;
static qboolean looped = false; static qboolean looped = false;
static qboolean enabled = true; static qboolean enabled = true;
if( Cmd_Argc() < 2 ) return; if( Cmd_Argc() < 2 ) return;
command = Cmd_Argv( 1 ); const char *command = Cmd_Argv( 1 );
pszTrack = Cmd_Argv( 2 ); const char *pszTrack = Cmd_Argv( 2 );
if( !enabled && Q_stricmp( command, "on" )) if( !enabled && Q_stricmp( command, "on" ))
return; // CD-player is disabled return; // CD-player is disabled
@@ -238,9 +236,7 @@ static scrshot_t CL_GetScreenshotTypeFromString( const char *string )
void CL_GenericShot_f( void ) void CL_GenericShot_f( void )
{ {
const char *argv0 = Cmd_Argv( 0 ); const char *argv0 = Cmd_Argv( 0 );
scrshot_t type; scrshot_t type = CL_GetScreenshotTypeFromString( argv0 );
type = CL_GetScreenshotTypeFromString( argv0 );
if( type == scrshot_normal || type == scrshot_snapshot ) if( type == scrshot_normal || type == scrshot_snapshot )
{ {
@@ -272,7 +268,6 @@ void CL_GenericShot_f( void )
case scrshot_snapshot: case scrshot_snapshot:
{ {
string checkname; string checkname;
int i;
// allow overriding screenshot by users request // allow overriding screenshot by users request
if( Cmd_Argc() > 1 ) if( Cmd_Argc() > 1 )
@@ -284,7 +279,7 @@ void CL_GenericShot_f( void )
if( type == scrshot_snapshot ) if( type == scrshot_snapshot )
FS_AllowDirectPaths( true ); FS_AllowDirectPaths( true );
for( i = 0; i < 9999; i++ ) for( int i = 0; i < 9999; i++ )
{ {
int ret; int ret;
@@ -383,17 +378,14 @@ CL_WavePlayLen_f
*/ */
void CL_WavePlayLen_f( void ) void CL_WavePlayLen_f( void )
{ {
const char *name;
uint msecs;
if( Cmd_Argc() != 2 ) if( Cmd_Argc() != 2 )
{ {
Con_Printf( "waveplaylen <wave file name>: returns approximate number of milliseconds a wave file will take to play.\n" ); Con_Printf( "waveplaylen <wave file name>: returns approximate number of milliseconds a wave file will take to play.\n" );
return; return;
} }
name = Cmd_Argv( 1 ); const char *name = Cmd_Argv( 1 );
msecs = Sound_GetApproxWavePlayLen( name ); uint msecs = Sound_GetApproxWavePlayLen( name );
if( msecs == 0 ) if( msecs == 0 )
{ {
+1 -3
View File
@@ -130,9 +130,7 @@ void CL_MoveToOnHandList( resource_t *pResource )
static void CL_ClearResourceList( resource_t *pList ) static void CL_ClearResourceList( resource_t *pList )
{ {
resource_t *p, *n; for( resource_t *p = pList->pNext, *n; p != pList && p; p = n )
for( p = pList->pNext; p != pList && p; p = n )
{ {
n = p->pNext; n = p->pNext;
+5 -11
View File
@@ -71,9 +71,7 @@ const char *CL_MsgInfo( int cmd )
} }
else if( cmd > svc_lastmsg && cmd <= ( svc_lastmsg + MAX_USER_MESSAGES )) else if( cmd > svc_lastmsg && cmd <= ( svc_lastmsg + MAX_USER_MESSAGES ))
{ {
int i; for( int i = 0; i < MAX_USER_MESSAGES; i++ )
for( i = 0; i < MAX_USER_MESSAGES; i++ )
{ {
if( clgame.msg[i].number == cmd ) if( clgame.msg[i].number == cmd )
{ {
@@ -106,11 +104,9 @@ record new message params into debug buffer
*/ */
void CL_Parse_RecordCommand( int cmd, int startoffset ) void CL_Parse_RecordCommand( int cmd, int startoffset )
{ {
int slot;
if( cmd == svc_nop ) return; if( cmd == svc_nop ) return;
slot = ( cls_message_debug.currentcmd++ & MSG_MASK ); int slot = ( cls_message_debug.currentcmd++ & MSG_MASK );
cls_message_debug.oldcmd[slot].command = cmd; cls_message_debug.oldcmd[slot].command = cmd;
cls_message_debug.oldcmd[slot].starting_offset = startoffset; cls_message_debug.oldcmd[slot].starting_offset = startoffset;
cls_message_debug.oldcmd[slot].frame_number = host.framecount; cls_message_debug.oldcmd[slot].frame_number = host.framecount;
@@ -141,9 +137,7 @@ write net_message into buffer.dat for debugging
static void CL_WriteErrorMessage( int current_count, sizebuf_t *msg ) static void CL_WriteErrorMessage( int current_count, sizebuf_t *msg )
{ {
const char *buffer_file = "buffer.dat"; const char *buffer_file = "buffer.dat";
file_t *fp; file_t *fp = FS_Open( buffer_file, "wb", false );
fp = FS_Open( buffer_file, "wb", false );
if( !fp ) if( !fp )
{ {
Con_Printf( S_ERROR "%s: can't open %s for write\n", __func__, buffer_file ); Con_Printf( S_ERROR "%s: can't open %s for write\n", __func__, buffer_file );
@@ -170,7 +164,7 @@ void CL_WriteMessageHistory( void )
{ {
oldcmd_t *old; oldcmd_t *old;
sizebuf_t *msg = &net_message; sizebuf_t *msg = &net_message;
int i, thecmd; int thecmd;
if( !cls.initialized || cls.state == ca_disconnected ) if( !cls.initialized || cls.state == ca_disconnected )
return; return;
@@ -184,7 +178,7 @@ void CL_WriteMessageHistory( void )
thecmd = cls_message_debug.currentcmd - 1; thecmd = cls_message_debug.currentcmd - 1;
thecmd -= ( MSG_COUNT - 1 ); // back up to here thecmd -= ( MSG_COUNT - 1 ); // back up to here
for( i = 0; i < MSG_COUNT - 1; i++ ) for( int i = 0; i < MSG_COUNT - 1; i++ )
{ {
thecmd &= MSG_MASK; thecmd &= MSG_MASK;
old = &cls_message_debug.oldcmd[thecmd]; old = &cls_message_debug.oldcmd[thecmd];
+21 -39
View File
@@ -245,8 +245,6 @@ Writes the demo command header and time-delta
*/ */
static void CL_WriteDemoCmdHeader( byte cmd, file_t *file ) static void CL_WriteDemoCmdHeader( byte cmd, file_t *file )
{ {
float dt;
Assert( cmd >= 1 && cmd <= dem_lastcmd ); Assert( cmd >= 1 && cmd <= dem_lastcmd );
if( !file ) return; if( !file ) return;
@@ -254,7 +252,7 @@ static void CL_WriteDemoCmdHeader( byte cmd, file_t *file )
FS_Write( file, &cmd, sizeof( byte )); FS_Write( file, &cmd, sizeof( byte ));
// time offset // time offset
dt = (float)(CL_GetDemoRecordClock() - demo.starttime); float dt = (float)(CL_GetDemoRecordClock() - demo.starttime);
FS_Write( file, &dt, sizeof( float )); FS_Write( file, &dt, sizeof( float ));
} }
@@ -395,11 +393,6 @@ Write demo header
*/ */
static void CL_WriteDemoHeader( const char *name ) static void CL_WriteDemoHeader( const char *name )
{ {
double maxfps;
int copysize;
int savepos;
int curpos;
Con_Printf( "recording to %s.\n", name ); Con_Printf( "recording to %s.\n", name );
cls.demofile = FS_Open( name, "wb", false ); cls.demofile = FS_Open( name, "wb", false );
cls.demotime = 0.0; cls.demotime = 0.0;
@@ -413,7 +406,7 @@ static void CL_WriteDemoHeader( const char *name )
cls.demorecording = true; cls.demorecording = true;
cls.demowaiting = true; // don't start saving messages until a non-delta compressed message is received cls.demowaiting = true; // don't start saving messages until a non-delta compressed message is received
maxfps = fps_override.value ? MAX_FPS_HARD : MAX_FPS_SOFT; double maxfps = fps_override.value ? MAX_FPS_HARD : MAX_FPS_SOFT;
memset( &demo.header, 0, sizeof( demo.header )); memset( &demo.header, 0, sizeof( demo.header ));
@@ -442,6 +435,7 @@ static void CL_WriteDemoHeader( const char *name )
FS_Flush( cls.demoheader ); FS_Flush( cls.demoheader );
// now copy the stuff we cached from the server. // now copy the stuff we cached from the server.
int copysize, savepos;
copysize = savepos = FS_Tell( cls.demoheader ); copysize = savepos = FS_Tell( cls.demoheader );
FS_Seek( cls.demoheader, 0, SEEK_SET ); FS_Seek( cls.demoheader, 0, SEEK_SET );
@@ -458,7 +452,7 @@ static void CL_WriteDemoHeader( const char *name )
cls.td_lastframe = -1; // get a new message this frame cls.td_lastframe = -1; // get a new message this frame
// now move on to entry # 1, the first data chunk. // now move on to entry # 1, the first data chunk.
curpos = FS_Tell( cls.demofile ); int curpos = FS_Tell( cls.demofile );
demo.entry->length = curpos - demo.entry->offset; demo.entry->length = curpos - demo.entry->offset;
// now we are writing the first real lump. // now we are writing the first real lump.
@@ -487,19 +481,15 @@ finish recording demo
*/ */
static void CL_StopRecord( void ) static void CL_StopRecord( void )
{ {
int i, curpos;
float stoptime;
int frames;
if( !cls.demorecording ) return; if( !cls.demorecording ) return;
// demo playback should read this as an incoming message. // demo playback should read this as an incoming message.
CL_WriteDemoCmdHeader( dem_stop, cls.demofile ); CL_WriteDemoCmdHeader( dem_stop, cls.demofile );
stoptime = CL_GetDemoRecordClock(); float stoptime = CL_GetDemoRecordClock();
if( clgame.hInstance ) clgame.dllFuncs.pfnReset(); if( clgame.hInstance ) clgame.dllFuncs.pfnReset();
curpos = FS_Tell( cls.demofile ); int curpos = FS_Tell( cls.demofile );
demo.entry->length = curpos - demo.entry->offset; demo.entry->length = curpos - demo.entry->offset;
demo.entry->playback_time = stoptime - demo.realstarttime; demo.entry->playback_time = stoptime - demo.realstarttime;
demo.entry->playback_frames = demo.framecount; demo.entry->playback_frames = demo.framecount;
@@ -507,7 +497,7 @@ static void CL_StopRecord( void )
// Now write out the directory and free it and touch up the demo header. // Now write out the directory and free it and touch up the demo header.
FS_Write( cls.demofile, &demo.directory.numentries, sizeof( int )); FS_Write( cls.demofile, &demo.directory.numentries, sizeof( int ));
for( i = 0; i < demo.directory.numentries; i++ ) for( int i = 0; i < demo.directory.numentries; i++ )
FS_Write( cls.demofile, &demo.directory.entries[i], sizeof( demoentry_t )); FS_Write( cls.demofile, &demo.directory.entries[i], sizeof( demoentry_t ));
Mem_Free( demo.directory.entries ); Mem_Free( demo.directory.entries );
@@ -525,7 +515,7 @@ static void CL_StopRecord( void )
gameui.globals->demoname[0] = '\0'; gameui.globals->demoname[0] = '\0';
demo.header.host_fps = 0.0; demo.header.host_fps = 0.0;
frames = cls.td_lastframe - cls.td_startframe; int frames = cls.td_lastframe - cls.td_startframe;
Con_Printf( "Completed demo\nRecording time: %02d:%02d, frames %i\n", (int)(cls.demotime / 60.0f), (int)fmod(cls.demotime, 60.0f), frames ); Con_Printf( "Completed demo\nRecording time: %02d:%02d, frames %i\n", (int)(cls.demotime / 60.0f), (int)fmod(cls.demotime, 60.0f), frames );
cls.demotime = 0.0; cls.demotime = 0.0;
} }
@@ -539,13 +529,12 @@ void CL_DrawDemoRecording( void )
{ {
char string[64]; char string[64];
rgba_t color = { 255, 255, 255, 255 }; rgba_t color = { 255, 255, 255, 255 };
int pos;
int len; int len;
if(!( host_developer.value && cls.demorecording )) if(!( host_developer.value && cls.demorecording ))
return; return;
pos = FS_Tell( cls.demofile ); int pos = FS_Tell( cls.demofile );
Q_snprintf( string, sizeof( string ), "^1RECORDING:^7 %s: %s time: %02d:%02d", cls.demoname, Q_snprintf( string, sizeof( string ), "^1RECORDING:^7 %s: %s time: %02d:%02d", cls.demoname,
Q_memprint( pos ), (int)(cls.demotime / 60.0f ), (int)fmod( cls.demotime, 60.0f )); Q_memprint( pos ), (int)(cls.demotime / 60.0f ), (int)fmod( cls.demotime, 60.0f ));
@@ -847,7 +836,6 @@ static qboolean CL_DemoReadMessageQuake( byte *buffer, size_t *length )
{ {
vec3_t viewangles; vec3_t viewangles;
int msglen = 0; int msglen = 0;
demoangle_t *a;
*length = 0; // assume we fail *length = 0; // assume we fail
@@ -888,7 +876,7 @@ static qboolean CL_DemoReadMessageQuake( byte *buffer, size_t *length )
{ {
// select entry into circular buffer // select entry into circular buffer
demo.angle_position = (demo.angle_position + 1) & ANGLE_MASK; demo.angle_position = (demo.angle_position + 1) & ANGLE_MASK;
a = &demo.cmds[demo.angle_position]; demoangle_t *a = &demo.cmds[demo.angle_position];
// record update // record update
a->starttime = demo.timestamp; a->starttime = demo.timestamp;
@@ -1060,8 +1048,7 @@ qboolean CL_DemoReadMessage( byte *buffer, size_t *length )
static void CL_DemoFindInterpolatedViewAngles( float t, float *frac, demoangle_t **prev, demoangle_t **next ) static void CL_DemoFindInterpolatedViewAngles( float t, float *frac, demoangle_t **prev, demoangle_t **next )
{ {
int i, i0, i1, imod; int i0, i1, imod;
float at;
if( cls.timedemo ) return; if( cls.timedemo ) return;
@@ -1071,9 +1058,9 @@ static void CL_DemoFindInterpolatedViewAngles( float t, float *frac, demoangle_t
if( demo.cmds[i0].starttime >= t ) if( demo.cmds[i0].starttime >= t )
{ {
for( i = 0; i < ANGLE_BACKUP - 2; i++ ) for( int i = 0; i < ANGLE_BACKUP - 2; i++ )
{ {
at = demo.cmds[imod & ANGLE_MASK].starttime; float at = demo.cmds[imod & ANGLE_MASK].starttime;
if( at == 0.0f ) break; if( at == 0.0f ) break;
if( at < t ) if( at < t )
@@ -1114,7 +1101,6 @@ void CL_DemoInterpolateAngles( void )
{ {
demoangle_t *prev = NULL, *next = NULL; demoangle_t *prev = NULL, *next = NULL;
float frac = 0.0f; float frac = 0.0f;
float curtime;
if( cls.demoplayback == DEMO_QUAKE1 ) if( cls.demoplayback == DEMO_QUAKE1 )
{ {
@@ -1126,7 +1112,7 @@ void CL_DemoInterpolateAngles( void )
} }
else else
{ {
curtime = (CL_GetDemoPlaybackClock() - demo.starttime) - host.frametime; float curtime = (CL_GetDemoPlaybackClock() - demo.starttime) - host.frametime;
if( curtime > demo.timestamp ) if( curtime > demo.timestamp )
curtime = demo.timestamp; // don't run too far curtime = demo.timestamp; // don't run too far
@@ -1239,7 +1225,6 @@ int GAME_EXPORT CL_GetDemoComment( const char *demoname, char *comment )
demodirectory_t directory; demodirectory_t directory;
demoentry_t entry; demoentry_t entry;
float playtime = 0.0f; float playtime = 0.0f;
int i;
if( !comment ) return false; if( !comment ) return false;
@@ -1279,7 +1264,7 @@ int GAME_EXPORT CL_GetDemoComment( const char *demoname, char *comment )
return false; return false;
} }
for( i = 0; i < directory.numentries; i++ ) for( int i = 0; i < directory.numentries; i++ )
{ {
FS_Read( demfile, &entry, sizeof( demoentry_t )); FS_Read( demfile, &entry, sizeof( demoentry_t ));
playtime += entry.playback_time; playtime += entry.playback_time;
@@ -1388,7 +1373,6 @@ void CL_Record_f( void )
{ {
string demoname, demopath; string demoname, demopath;
const char *name; const char *name;
int n;
if( Cmd_Argc() == 1 ) if( Cmd_Argc() == 1 )
{ {
@@ -1425,6 +1409,7 @@ void CL_Record_f( void )
if( !Q_stricmp( name, "new" )) if( !Q_stricmp( name, "new" ))
{ {
// scan for a free filename // scan for a free filename
int n;
for( n = 0; n < 10000; n++ ) for( n = 0; n < 10000; n++ )
{ {
CL_DemoGetName( n, demoname, sizeof( demoname )); CL_DemoGetName( n, demoname, sizeof( demoname ));
@@ -1511,7 +1496,7 @@ void CL_PlayDemo_f( void )
{ {
char filename[MAX_QPATH]; char filename[MAX_QPATH];
char demoname[MAX_QPATH]; char demoname[MAX_QPATH];
int i, ident; int ident;
if( Cmd_Argc() < 2 ) if( Cmd_Argc() < 2 )
{ {
@@ -1584,7 +1569,7 @@ void CL_PlayDemo_f( void )
// allocate demo entries // allocate demo entries
demo.directory.entries = Mem_Malloc( cls.mempool, sizeof( *demo.directory.entries ) * demo.directory.numentries ); demo.directory.entries = Mem_Malloc( cls.mempool, sizeof( *demo.directory.entries ) * demo.directory.numentries );
for( i = 0; i < demo.directory.numentries; i++ ) for( int i = 0; i < demo.directory.numentries; i++ )
{ {
demoentry_t *entry = &demo.directory.entries[i]; demoentry_t *entry = &demo.directory.entries[i];
@@ -1640,15 +1625,13 @@ CL_StartDemos_f
*/ */
void CL_StartDemos_f( void ) void CL_StartDemos_f( void )
{ {
int i, c;
if( cls.key_dest != key_menu ) if( cls.key_dest != key_menu )
{ {
Con_Printf( "'startdemos' is not valid from the console\n" ); Con_Printf( "'startdemos' is not valid from the console\n" );
return; return;
} }
c = Cmd_Argc() - 1; int c = Cmd_Argc() - 1;
if( c > MAX_DEMOS ) if( c > MAX_DEMOS )
{ {
Con_DPrintf( S_WARN "%s: max %i demos in demoloop\n", __func__, MAX_DEMOS ); Con_DPrintf( S_WARN "%s: max %i demos in demoloop\n", __func__, MAX_DEMOS );
@@ -1657,7 +1640,7 @@ void CL_StartDemos_f( void )
Con_Printf( "%i demo%s in loop\n", c, (c > 1) ? "s" : "" ); Con_Printf( "%i demo%s in loop\n", c, (c > 1) ? "s" : "" );
for( i = 1; i < c + 1; i++ ) for( int i = 1; i < c + 1; i++ )
Q_strncpy( cls.demos[i-1], Cmd_Argv( i ), sizeof( cls.demos[0] )); Q_strncpy( cls.demos[i-1], Cmd_Argv( i ), sizeof( cls.demos[0] ));
cls.demos_pending = true; cls.demos_pending = true;
} }
@@ -1717,7 +1700,6 @@ void CL_ListDemo_f( void )
file_t *f; file_t *f;
char filename[MAX_QPATH]; char filename[MAX_QPATH];
char demoname[MAX_QPATH]; char demoname[MAX_QPATH];
int i;
if( Cmd_Argc() < 2 ) if( Cmd_Argc() < 2 )
{ {
@@ -1751,7 +1733,7 @@ void CL_ListDemo_f( void )
filename, hdr.net_protocol, hdr.dem_protocol, hdr.host_fps, hdr.mapname, filename, hdr.net_protocol, hdr.dem_protocol, hdr.host_fps, hdr.mapname,
hdr.comment, hdr.gamedir ); hdr.comment, hdr.gamedir );
for( i = 0; i < num_entries; i++ ) for( int i = 0; i < num_entries; i++ )
{ {
demoentry_t entry; demoentry_t entry;
+7 -10
View File
@@ -39,7 +39,6 @@ static efrag_t *cl_efrags;
static efrag_t *CL_AllocEfrags( int num ) static efrag_t *CL_AllocEfrags( int num )
{ {
int i;
efrag_t *efrags; efrag_t *efrags;
if( !cl.worldmodel ) if( !cl.worldmodel )
@@ -55,7 +54,7 @@ static efrag_t *CL_AllocEfrags( int num )
efrags = Mem_Calloc( cl.worldmodel->mempool, sizeof( *efrags ) * num ); efrags = Mem_Calloc( cl.worldmodel->mempool, sizeof( *efrags ) * num );
// initialize linked list // initialize linked list
for( i = 0; i < num - 1; i++ ) for( int i = 0; i < num - 1; i++ )
efrags[i].entnext = &efrags[i + 1]; efrags[i].entnext = &efrags[i + 1];
cl_efrags_num += num; cl_efrags_num += num;
@@ -81,8 +80,6 @@ R_SplitEntityOnNode
*/ */
static void R_SplitEntityOnNode( mnode_t *node ) static void R_SplitEntityOnNode( mnode_t *node )
{ {
efrag_t *ef;
mleaf_t *leaf;
int sides; int sides;
if( node->contents == CONTENTS_SOLID ) if( node->contents == CONTENTS_SOLID )
@@ -91,6 +88,9 @@ static void R_SplitEntityOnNode( mnode_t *node )
// add an efrag if the node is a leaf // add an efrag if the node is a leaf
if( node->contents < 0 ) if( node->contents < 0 )
{ {
efrag_t *ef;
mleaf_t *leaf;
if( !r_pefragtopnode ) if( !r_pefragtopnode )
r_pefragtopnode = node; r_pefragtopnode = node;
@@ -142,7 +142,6 @@ void R_AddEfrags( cl_entity_t *ent )
{ {
matrix3x4 transform; matrix3x4 transform;
vec3_t outmins, outmaxs; vec3_t outmins, outmaxs;
int i;
if( !ent->model ) if( !ent->model )
return; return;
@@ -155,7 +154,7 @@ void R_AddEfrags( cl_entity_t *ent )
Matrix3x4_CreateFromEntity( transform, ent->angles, vec3_origin, 1.0f ); Matrix3x4_CreateFromEntity( transform, ent->angles, vec3_origin, 1.0f );
Matrix3x4_TransformAABB( transform, ent->model->mins, ent->model->maxs, outmins, outmaxs ); Matrix3x4_TransformAABB( transform, ent->model->mins, ent->model->maxs, outmins, outmaxs );
for( i = 0; i < 3; i++ ) for( int i = 0; i < 3; i++ )
{ {
r_emins[i] = ent->origin[i] + outmins[i]; r_emins[i] = ent->origin[i] + outmins[i];
r_emaxs[i] = ent->origin[i] + outmaxs[i]; r_emaxs[i] = ent->origin[i] + outmaxs[i];
@@ -174,13 +173,11 @@ R_StoreEfrags
void R_StoreEfrags( efrag_t **ppefrag, int framecount ) void R_StoreEfrags( efrag_t **ppefrag, int framecount )
{ {
efrag_t *pefrag; efrag_t *pefrag;
cl_entity_t *pent;
model_t *clmodel;
while(( pefrag = *ppefrag ) != NULL ) while(( pefrag = *ppefrag ) != NULL )
{ {
pent = pefrag->entity; cl_entity_t *pent = pefrag->entity;
clmodel = pent->model; model_t *clmodel = pent->model;
// how this could happen? // how this could happen?
if( unlikely( clmodel->type < mod_brush || clmodel->type > mod_studio )) if( unlikely( clmodel->type < mod_brush || clmodel->type > mod_studio ))
+97 -173
View File
@@ -44,21 +44,17 @@ find nearest color in particle palette
*/ */
short GAME_EXPORT R_LookupColor( byte r, byte g, byte b ) short GAME_EXPORT R_LookupColor( byte r, byte g, byte b )
{ {
int i, best; float bestdiff = 999999;
float diff, bestdiff; int best = -1;
float rf, gf, bf;
bestdiff = 999999; for( int i = 0; i < 256; i++ )
best = -1;
for( i = 0; i < 256; i++ )
{ {
rf = r - clgame.palette[i].r; float rf = r - clgame.palette[i].r;
gf = g - clgame.palette[i].g; float gf = g - clgame.palette[i].g;
bf = b - clgame.palette[i].b; float bf = b - clgame.palette[i].b;
// convert color to monochrome // convert color to monochrome
diff = rf * (rf * 0.2f) + gf * (gf * 0.5f) + bf * (bf * 0.3f); float diff = rf * (rf * 0.2f) + gf * (gf * 0.5f) + bf * (bf * 0.3f);
if ( diff < bestdiff ) if ( diff < bestdiff )
{ {
@@ -90,13 +86,11 @@ CL_InitParticles
*/ */
void CL_InitParticles( void ) void CL_InitParticles( void )
{ {
int i;
cl_particles = Mem_Calloc( cls.mempool, sizeof( particle_t ) * GI->max_particles ); cl_particles = Mem_Calloc( cls.mempool, sizeof( particle_t ) * GI->max_particles );
CL_ClearParticles (); CL_ClearParticles ();
// this is used for EF_BRIGHTFIELD // this is used for EF_BRIGHTFIELD
for( i = 0; i < NUMVERTEXNORMALS; i++ ) for( int i = 0; i < NUMVERTEXNORMALS; i++ )
{ {
cl_avelocities[i][0] = COM_RandomFloat( 0.0f, 2.55f ); cl_avelocities[i][0] = COM_RandomFloat( 0.0f, 2.55f );
cl_avelocities[i][1] = COM_RandomFloat( 0.0f, 2.55f ); cl_avelocities[i][1] = COM_RandomFloat( 0.0f, 2.55f );
@@ -116,15 +110,13 @@ CL_ClearParticles
*/ */
void CL_ClearParticles( void ) void CL_ClearParticles( void )
{ {
int i;
if( !cl_particles ) return; if( !cl_particles ) return;
cl_free_particles = cl_particles; cl_free_particles = cl_particles;
cl_active_particles = NULL; cl_active_particles = NULL;
cl_active_tracers = NULL; cl_active_tracers = NULL;
for( i = 0; i < GI->max_particles - 1; i++ ) for( int i = 0; i < GI->max_particles - 1; i++ )
cl_particles[i].next = &cl_particles[i+1]; cl_particles[i].next = &cl_particles[i+1];
cl_particles[GI->max_particles-1].next = NULL; cl_particles[GI->max_particles-1].next = NULL;
@@ -357,15 +349,13 @@ CL_ClearViewBeams
*/ */
void CL_ClearViewBeams( void ) void CL_ClearViewBeams( void )
{ {
int i;
if( !cl_viewbeams ) return; if( !cl_viewbeams ) return;
// clear beams // clear beams
cl_free_beams = cl_viewbeams; cl_free_beams = cl_viewbeams;
cl_active_beams = NULL; cl_active_beams = NULL;
for( i = 0; i < GI->max_beams - 1; i++ ) for( int i = 0; i < GI->max_beams - 1; i++ )
cl_viewbeams[i].next = &cl_viewbeams[i+1]; cl_viewbeams[i].next = &cl_viewbeams[i+1];
cl_viewbeams[GI->max_beams - 1].next = NULL; cl_viewbeams[GI->max_beams - 1].next = NULL;
} }
@@ -416,7 +406,6 @@ void CL_KillDeadBeams( cl_entity_t *pDeadEntity )
while( pbeam ) while( pbeam )
{ {
cl_entity_t *beament;
pnext = pbeam->next; pnext = pbeam->next;
// link into new list. // link into new list.
@@ -471,16 +460,13 @@ Optimized version of pointfile - use beams instead of particles
*/ */
void CL_ReadLineFile_f( void ) void CL_ReadLineFile_f( void )
{ {
byte *afile;
char *pfile;
vec3_t p1, p2; vec3_t p1, p2;
int count, modelIndex; int modelIndex;
char filename[MAX_QPATH]; char filename[MAX_QPATH];
model_t *model;
string token; string token;
Q_snprintf( filename, sizeof( filename ), "maps/%s.lin", clgame.mapname ); Q_snprintf( filename, sizeof( filename ), "maps/%s.lin", clgame.mapname );
afile = FS_LoadFile( filename, NULL, false ); byte *afile = FS_LoadFile( filename, NULL, false );
if( !afile ) if( !afile )
{ {
@@ -490,9 +476,9 @@ void CL_ReadLineFile_f( void )
Con_Printf( "Reading %s...\n", filename ); Con_Printf( "Reading %s...\n", filename );
count = 0; int count = 0;
pfile = (char *)afile; char *pfile = (char *)afile;
model = CL_LoadModel( DEFAULT_LASERBEAM_PATH, &modelIndex ); model_t *model = CL_LoadModel( DEFAULT_LASERBEAM_PATH, &modelIndex );
while( 1 ) while( 1 )
{ {
@@ -1064,25 +1050,20 @@ set EF_BRIGHTFIELD effect
*/ */
void GAME_EXPORT R_EntityParticles( cl_entity_t *ent ) void GAME_EXPORT R_EntityParticles( cl_entity_t *ent )
{ {
float angle; for( int i = 0; i < NUMVERTEXNORMALS; i++ )
float sr, sp, sy, cr, cp, cy;
vec3_t forward;
particle_t *p;
int i;
for( i = 0; i < NUMVERTEXNORMALS; i++ )
{ {
p = R_AllocParticle( NULL ); particle_t *p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
angle = cl.time * cl_avelocities[i][0]; float sr, sp, sy, cr, cp, cy;
float angle = cl.time * cl_avelocities[i][0];
SinCos( angle, &sy, &cy ); SinCos( angle, &sy, &cy );
angle = cl.time * cl_avelocities[i][1]; angle = cl.time * cl_avelocities[i][1];
SinCos( angle, &sp, &cp ); SinCos( angle, &sp, &cp );
angle = cl.time * cl_avelocities[i][2]; angle = cl.time * cl_avelocities[i][2];
SinCos( angle, &sr, &cr ); SinCos( angle, &sr, &cr );
VectorSet( forward, cp * cy, cp * sy, -sp ); vec3_t forward = { cp * cy, cp * sy, -sp };
p->die = cl.time + 0.001f; p->die = cl.time + 0.001f;
p->color = 111; // yellow p->color = 111; // yellow
@@ -1099,19 +1080,16 @@ R_ParticleExplosion
*/ */
void GAME_EXPORT R_ParticleExplosion( const vec3_t org ) void GAME_EXPORT R_ParticleExplosion( const vec3_t org )
{ {
particle_t *p; for( int i = 0; i < 1024; i++ )
int i, j;
for( i = 0; i < 1024; i++ )
{ {
p = R_AllocParticle( NULL ); particle_t *p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
p->die = cl.time + 5.0f; p->die = cl.time + 5.0f;
p->ramp = COM_RandomLong( 0, 3 ); p->ramp = COM_RandomLong( 0, 3 );
p->color = ramp1[0]; p->color = ramp1[0];
for( j = 0; j < 3; j++ ) for( int j = 0; j < 3; j++ )
{ {
p->org[j] = org[j] + COM_RandomFloat( -16.0f, 16.0f ); p->org[j] = org[j] + COM_RandomFloat( -16.0f, 16.0f );
p->vel[j] = COM_RandomFloat( -256.0f, 256.0f ); p->vel[j] = COM_RandomFloat( -256.0f, 256.0f );
@@ -1130,15 +1108,12 @@ R_ParticleExplosion2
*/ */
void GAME_EXPORT R_ParticleExplosion2( const vec3_t org, int colorStart, int colorLength ) void GAME_EXPORT R_ParticleExplosion2( const vec3_t org, int colorStart, int colorLength )
{ {
int i, j; int colorMod = 0;
int colorMod = 0, packedColor; int packedColor = Host_IsQuakeCompatible( ) ? 255 : 0; // use old code for blob particles
particle_t *p;
packedColor = Host_IsQuakeCompatible( ) ? 255 : 0; // use old code for blob particles for( int i = 0; i < 512; i++ )
for( i = 0; i < 512; i++ )
{ {
p = R_AllocParticle( NULL ); particle_t *p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
p->die = cl.time + 0.3f; p->die = cl.time + 0.3f;
@@ -1148,7 +1123,7 @@ void GAME_EXPORT R_ParticleExplosion2( const vec3_t org, int colorStart, int col
p->type = pt_blob; p->type = pt_blob;
for( j = 0; j < 3; j++ ) for( int j = 0; j < 3; j++ )
{ {
p->org[j] = org[j] + COM_RandomFloat( -16.0f, 16.0f ); p->org[j] = org[j] + COM_RandomFloat( -16.0f, 16.0f );
p->vel[j] = COM_RandomFloat( -256.0f, 256.0f ); p->vel[j] = COM_RandomFloat( -256.0f, 256.0f );
@@ -1164,14 +1139,11 @@ R_BlobExplosion
*/ */
void GAME_EXPORT R_BlobExplosion( const vec3_t org ) void GAME_EXPORT R_BlobExplosion( const vec3_t org )
{ {
particle_t *p; int packedColor = Host_IsQuakeCompatible( ) ? 255 : 0; // use old code for blob particles
int i, j, packedColor;
packedColor = Host_IsQuakeCompatible( ) ? 255 : 0; // use old code for blob particles for( int i = 0; i < 1024; i++ )
for( i = 0; i < 1024; i++ )
{ {
p = R_AllocParticle( NULL ); particle_t *p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
p->die = cl.time + COM_RandomFloat( 1.0f, 1.4f ); p->die = cl.time + COM_RandomFloat( 1.0f, 1.4f );
@@ -1188,7 +1160,7 @@ void GAME_EXPORT R_BlobExplosion( const vec3_t org )
p->color = COM_RandomLong( 150, 155 ); p->color = COM_RandomLong( 150, 155 );
} }
for( j = 0; j < 3; j++ ) for( int j = 0; j < 3; j++ )
{ {
p->org[j] = org[j] + COM_RandomFloat( -16.0f, 16.0f ); p->org[j] = org[j] + COM_RandomFloat( -16.0f, 16.0f );
p->vel[j] = COM_RandomFloat( -256.0f, 256.0f ); p->vel[j] = COM_RandomFloat( -256.0f, 256.0f );
@@ -1205,9 +1177,6 @@ PARTICLE_EFFECT on server
*/ */
void GAME_EXPORT R_RunParticleEffect( const vec3_t org, const vec3_t dir, int color, int count ) void GAME_EXPORT R_RunParticleEffect( const vec3_t org, const vec3_t dir, int color, int count )
{ {
particle_t *p;
int i;
if( count == 1024 ) if( count == 1024 )
{ {
// rocket explosion // rocket explosion
@@ -1215,9 +1184,9 @@ void GAME_EXPORT R_RunParticleEffect( const vec3_t org, const vec3_t dir, int co
return; return;
} }
for( i = 0; i < count; i++ ) for( int i = 0; i < count; i++ )
{ {
p = R_AllocParticle( NULL ); particle_t *p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
p->color = (color & ~7) + COM_RandomLong( 0, 7 ); p->color = (color & ~7) + COM_RandomLong( 0, 7 );
@@ -1239,20 +1208,18 @@ particle spray
void GAME_EXPORT R_Blood( const vec3_t org, const vec3_t ndir, int pcolor, int speed ) void GAME_EXPORT R_Blood( const vec3_t org, const vec3_t ndir, int pcolor, int speed )
{ {
vec3_t pos, dir, vec; vec3_t pos, dir, vec;
int i, j;
int pspeed = speed * 3; int pspeed = speed * 3;
particle_t *p;
VectorNormalize2( ndir, dir ); VectorNormalize2( ndir, dir );
for( i = 0; i < (speed / 2); i++ ) for( int i = 0; i < (speed / 2); i++ )
{ {
VectorAddScalar( org, COM_RandomFloat( -3.0f, 3.0f ), pos ); VectorAddScalar( org, COM_RandomFloat( -3.0f, 3.0f ), pos );
VectorAddScalar( dir, COM_RandomFloat( -0.06f, 0.06f ), vec ); VectorAddScalar( dir, COM_RandomFloat( -0.06f, 0.06f ), vec );
for( j = 0; j < 8; j++ ) for( int j = 0; j < 8; j++ )
{ {
p = R_AllocParticle( NULL ); particle_t *p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
p->die = cl.time + 1.5f; p->die = cl.time + 1.5f;
@@ -1276,17 +1243,15 @@ particle spray 2
*/ */
void GAME_EXPORT R_BloodStream( const vec3_t org, const vec3_t ndir, int pcolor, int speed ) void GAME_EXPORT R_BloodStream( const vec3_t org, const vec3_t ndir, int pcolor, int speed )
{ {
particle_t *p;
int i, j;
float arc;
int accel = speed; // must be integer due to bug in GoldSrc int accel = speed; // must be integer due to bug in GoldSrc
vec3_t dir; vec3_t dir;
VectorNormalize2( ndir, dir ); VectorNormalize2( ndir, dir );
for( arc = 0.05f, i = 0; i < 100; i++ ) float arc = 0.05f;
for( int i = 0; i < 100; i++ )
{ {
p = R_AllocParticle( NULL ); particle_t *p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
p->die = cl.time + 2.0f; p->die = cl.time + 2.0f;
@@ -1302,11 +1267,10 @@ void GAME_EXPORT R_BloodStream( const vec3_t org, const vec3_t ndir, int pcolor,
accel -= 0.00001f; // so last few will drip accel -= 0.00001f; // so last few will drip
} }
for( arc = 0.075f, i = 0; i < ( speed / 5 ); i++ ) arc = 0.075f;
for( int i = 0; i < ( speed / 5 ); i++ )
{ {
float num; particle_t *p = R_AllocParticle( NULL );
p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
p->die = cl.time + 3.0f; p->die = cl.time + 3.0f;
@@ -1319,14 +1283,14 @@ void GAME_EXPORT R_BloodStream( const vec3_t org, const vec3_t ndir, int pcolor,
p->vel[2] -= arc; p->vel[2] -= arc;
arc -= 0.005f; arc -= 0.005f;
num = COM_RandomFloat( 0.0f, 1.0f ); float num = COM_RandomFloat( 0.0f, 1.0f );
accel = speed * num; accel = speed * num;
num *= 1.7f; num *= 1.7f;
VectorScale( p->vel, num, p->vel ); VectorScale( p->vel, num, p->vel );
VectorScale( p->vel, accel, p->vel ); VectorScale( p->vel, accel, p->vel );
for( j = 0; j < 2; j++ ) for( int j = 0; j < 2; j++ )
{ {
p = R_AllocParticle( NULL ); p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
@@ -1353,18 +1317,15 @@ R_LavaSplash
*/ */
void GAME_EXPORT R_LavaSplash( const vec3_t org ) void GAME_EXPORT R_LavaSplash( const vec3_t org )
{ {
particle_t *p;
float vel;
vec3_t dir; vec3_t dir;
int i, j, k;
for( i = -16; i < 16; i++ ) for( int i = -16; i < 16; i++ )
{ {
for( j = -16; j <16; j++ ) for( int j = -16; j <16; j++ )
{ {
for( k = 0; k < 1; k++ ) for( int k = 0; k < 1; k++ )
{ {
p = R_AllocParticle( NULL ); particle_t *p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
p->die = cl.time + COM_RandomFloat( 2.0f, 2.62f ); p->die = cl.time + COM_RandomFloat( 2.0f, 2.62f );
@@ -1380,7 +1341,7 @@ void GAME_EXPORT R_LavaSplash( const vec3_t org )
p->org[2] = org[2] + COM_RandomFloat( 0.0f, 63.0f ); p->org[2] = org[2] + COM_RandomFloat( 0.0f, 63.0f );
VectorNormalize( dir ); VectorNormalize( dir );
vel = COM_RandomFloat( 50.0f, 113.0f ); float vel = COM_RandomFloat( 50.0f, 113.0f );
VectorScale( dir, vel, p->vel ); VectorScale( dir, vel, p->vel );
} }
} }
@@ -1395,16 +1356,13 @@ R_ParticleBurst
*/ */
void GAME_EXPORT R_ParticleBurst( const vec3_t org, int size, int color, float life ) void GAME_EXPORT R_ParticleBurst( const vec3_t org, int size, int color, float life )
{ {
particle_t *p;
vec3_t dir, dest; vec3_t dir, dest;
int i, j;
float dist;
for( i = 0; i < 32; i++ ) for( int i = 0; i < 32; i++ )
{ {
for( j = 0; j < 32; j++ ) for( int j = 0; j < 32; j++ )
{ {
p = R_AllocParticle( NULL ); particle_t *p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
p->die = cl.time + life + COM_RandomFloat( -0.5f, 0.5f ); p->die = cl.time + life + COM_RandomFloat( -0.5f, 0.5f );
@@ -1414,7 +1372,7 @@ void GAME_EXPORT R_ParticleBurst( const vec3_t org, int size, int color, float l
VectorCopy( org, p->org ); VectorCopy( org, p->org );
VectorAddScalar( org, COM_RandomFloat( -size, size ), dest ); VectorAddScalar( org, COM_RandomFloat( -size, size ), dest );
VectorSubtract( dest, p->org, dir ); VectorSubtract( dest, p->org, dir );
dist = VectorNormalizeLength( dir ); float dist = VectorNormalizeLength( dir );
VectorScale( dir, ( dist / life ), p->vel ); VectorScale( dir, ( dist / life ), p->vel );
} }
} }
@@ -1428,16 +1386,13 @@ R_LargeFunnel
*/ */
void GAME_EXPORT R_LargeFunnel( const vec3_t org, int reverse ) void GAME_EXPORT R_LargeFunnel( const vec3_t org, int reverse )
{ {
particle_t *p;
float vel, dist;
vec3_t dir, dest; vec3_t dir, dest;
int i, j;
for( i = -8; i < 8; i++ ) for( int i = -8; i < 8; i++ )
{ {
for( j = -8; j < 8; j++ ) for( int j = -8; j < 8; j++ )
{ {
p = R_AllocParticle( NULL ); particle_t *p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
dest[0] = (i * 32.0f) + org[0]; dest[0] = (i * 32.0f) + org[0];
@@ -1455,10 +1410,10 @@ void GAME_EXPORT R_LargeFunnel( const vec3_t org, int reverse )
VectorSubtract( org, p->org, dir ); VectorSubtract( org, p->org, dir );
} }
vel = dest[2] / 8.0f; float vel = dest[2] / 8.0f;
if( vel < 64.0f ) vel = 64.0f; if( vel < 64.0f ) vel = 64.0f;
dist = VectorNormalizeLength( dir ); float dist = VectorNormalizeLength( dir );
vel += COM_RandomFloat( 64.0f, 128.0f ); vel += COM_RandomFloat( 64.0f, 128.0f );
VectorScale( dir, vel, p->vel ); VectorScale( dir, vel, p->vel );
p->die = cl.time + (dist / vel ); p->die = cl.time + (dist / vel );
@@ -1475,18 +1430,15 @@ R_TeleportSplash
*/ */
void GAME_EXPORT R_TeleportSplash( const vec3_t org ) void GAME_EXPORT R_TeleportSplash( const vec3_t org )
{ {
particle_t *p;
vec3_t dir; vec3_t dir;
float vel;
int i, j, k;
for( i = -16; i < 16; i += 4 ) for( int i = -16; i < 16; i += 4 )
{ {
for( j = -16; j < 16; j += 4 ) for( int j = -16; j < 16; j += 4 )
{ {
for( k = -24; k < 32; k += 4 ) for( int k = -24; k < 32; k += 4 )
{ {
p = R_AllocParticle( NULL ); particle_t *p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
p->die = cl.time + COM_RandomFloat( 0.2f, 0.34f ); p->die = cl.time + COM_RandomFloat( 0.2f, 0.34f );
@@ -1502,7 +1454,7 @@ void GAME_EXPORT R_TeleportSplash( const vec3_t org )
p->org[2] = org[2] + k + COM_RandomFloat( 0.0f, 3.0f ); p->org[2] = org[2] + k + COM_RandomFloat( 0.0f, 3.0f );
VectorNormalize( dir ); VectorNormalize( dir );
vel = COM_RandomFloat( 50.0f, 113.0f ); float vel = COM_RandomFloat( 50.0f, 113.0f );
VectorScale( dir, vel, p->vel ); VectorScale( dir, vel, p->vel );
} }
} }
@@ -1639,13 +1591,12 @@ draw line from particles
*/ */
static void PM_ParticleLine( const vec3_t start, const vec3_t end, int pcolor, float life, float zvel ) static void PM_ParticleLine( const vec3_t start, const vec3_t end, int pcolor, float life, float zvel )
{ {
float len, curdist;
vec3_t diff, pos; vec3_t diff, pos;
// determine distance // determine distance
VectorSubtract( end, start, diff ); VectorSubtract( end, start, diff );
len = VectorNormalizeLength( diff ); float len = VectorNormalizeLength( diff );
curdist = 0; float curdist = 0;
while( curdist <= len ) while( curdist <= len )
{ {
@@ -1679,9 +1630,8 @@ static void PM_DrawBBox( const vec3_t mins, const vec3_t maxs, const vec3_t orig
{ {
vec3_t p[8], tmp; vec3_t p[8], tmp;
float gap = BOX_GAP; float gap = BOX_GAP;
int i;
for( i = 0; i < 8; i++ ) for( int i = 0; i < 8; i++ )
{ {
tmp[0] = (i & 1) ? mins[0] - gap : maxs[0] + gap; tmp[0] = (i & 1) ? mins[0] - gap : maxs[0] + gap;
tmp[1] = (i & 2) ? mins[1] - gap : maxs[1] + gap ; tmp[1] = (i & 2) ? mins[1] - gap : maxs[1] + gap ;
@@ -1691,7 +1641,7 @@ static void PM_DrawBBox( const vec3_t mins, const vec3_t maxs, const vec3_t orig
VectorCopy( tmp, p[i] ); VectorCopy( tmp, p[i] );
} }
for( i = 0; i < 6; i++ ) for( int i = 0; i < 6; i++ )
{ {
PM_DrawRectangle( p[boxpnt[i][1]], p[boxpnt[i][0]], p[boxpnt[i][2]], p[boxpnt[i][3]], pcolor, life ); PM_DrawRectangle( p[boxpnt[i][1]], p[boxpnt[i][0]], p[boxpnt[i][2]], p[boxpnt[i][3]], pcolor, life );
} }
@@ -1705,9 +1655,7 @@ R_ParticleLine
*/ */
void GAME_EXPORT R_ParticleLine( const vec3_t start, const vec3_t end, byte r, byte g, byte b, float life ) void GAME_EXPORT R_ParticleLine( const vec3_t start, const vec3_t end, byte r, byte g, byte b, float life )
{ {
int pcolor; int pcolor = R_LookupColor( r, g, b );
pcolor = R_LookupColor( r, g, b );
PM_ParticleLine( start, end, pcolor, life, 0 ); PM_ParticleLine( start, end, pcolor, life, 0 );
} }
@@ -1721,9 +1669,8 @@ void GAME_EXPORT R_ParticleBox( const vec3_t absmin, const vec3_t absmax, byte r
{ {
vec3_t mins, maxs; vec3_t mins, maxs;
vec3_t origin; vec3_t origin;
int pcolor;
pcolor = R_LookupColor( r, g, b ); int pcolor = R_LookupColor( r, g, b );
VectorAverage( absmax, absmin, origin ); VectorAverage( absmax, absmin, origin );
VectorSubtract( absmax, origin, maxs ); VectorSubtract( absmax, origin, maxs );
@@ -1740,20 +1687,18 @@ R_ShowLine
*/ */
void GAME_EXPORT R_ShowLine( const vec3_t start, const vec3_t end ) void GAME_EXPORT R_ShowLine( const vec3_t start, const vec3_t end )
{ {
vec3_t dir, org; vec3_t dir;
float len;
particle_t *p;
VectorSubtract( end, start, dir ); VectorSubtract( end, start, dir );
len = VectorNormalizeLength( dir ); float len = VectorNormalizeLength( dir );
VectorScale( dir, 5.0f, dir ); VectorScale( dir, 5.0f, dir );
VectorCopy( start, org ); vec3_t org = Vec3( start );
while( len > 0 ) while( len > 0 )
{ {
len -= 5.0f; len -= 5.0f;
p = R_AllocParticle( NULL ); particle_t *p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
p->die = cl.time + 30; p->die = cl.time + 30;
@@ -1772,25 +1717,21 @@ R_BulletImpactParticles
*/ */
void GAME_EXPORT R_BulletImpactParticles( const vec3_t pos ) void GAME_EXPORT R_BulletImpactParticles( const vec3_t pos )
{ {
int i, quantity;
int color;
float dist;
vec3_t dir; vec3_t dir;
particle_t *p;
VectorSubtract( pos, refState.vieworg, dir ); VectorSubtract( pos, refState.vieworg, dir );
dist = VectorLength( dir ); float dist = VectorLength( dir );
if( dist > 1000.0f ) dist = 1000.0f; if( dist > 1000.0f ) dist = 1000.0f;
quantity = (1000.0f - dist) / 100.0f; int quantity = (1000.0f - dist) / 100.0f;
if( quantity == 0 ) quantity = 1; if( quantity == 0 ) quantity = 1;
color = 3 - ((30 * quantity) / 100 ); int color = 3 - ((30 * quantity) / 100 );
R_SparkStreaks( pos, 2, -200, 200 ); R_SparkStreaks( pos, 2, -200, 200 );
for( i = 0; i < quantity * 4; i++ ) for( int i = 0; i < quantity * 4; i++ )
{ {
p = R_AllocParticle( NULL ); particle_t *p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
VectorCopy( pos, p->org); VectorCopy( pos, p->org);
@@ -1814,12 +1755,9 @@ R_FlickerParticles
*/ */
void GAME_EXPORT R_FlickerParticles( const vec3_t org ) void GAME_EXPORT R_FlickerParticles( const vec3_t org )
{ {
particle_t *p; for( int i = 0; i < 15; i++ )
int i;
for( i = 0; i < 15; i++ )
{ {
p = R_AllocParticle( NULL ); particle_t *p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
VectorCopy( org, p->org ); VectorCopy( org, p->org );
@@ -1843,15 +1781,13 @@ create a splash of streaks
void GAME_EXPORT R_StreakSplash( const vec3_t pos, const vec3_t dir, int color, int count, float speed, int velocityMin, int velocityMax ) void GAME_EXPORT R_StreakSplash( const vec3_t pos, const vec3_t dir, int color, int count, float speed, int velocityMin, int velocityMax )
{ {
vec3_t vel, vel2; vec3_t vel, vel2;
particle_t *p;
int i;
VectorScale( dir, speed, vel ); VectorScale( dir, speed, vel );
for( i = 0; i < count; i++ ) for( int i = 0; i < count; i++ )
{ {
VectorAddScalar( vel, COM_RandomFloat( velocityMin, velocityMax ), vel2 ); VectorAddScalar( vel, COM_RandomFloat( velocityMin, velocityMax ), vel2 );
p = R_AllocTracer( pos, vel2, COM_RandomFloat( 0.1f, 0.5f )); particle_t *p = R_AllocTracer( pos, vel2, COM_RandomFloat( 0.1f, 0.5f ));
if( !p ) return; if( !p ) return;
p->type = pt_grav; p->type = pt_grav;
@@ -1869,9 +1805,7 @@ pmove debugging particle
*/ */
void CL_Particle( const vec3_t org, int color, float life, int zpos, int zvel ) void CL_Particle( const vec3_t org, int color, float life, int zpos, int zvel )
{ {
particle_t *p; particle_t *p = R_AllocParticle( NULL );
p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
if( org ) VectorCopy( org, p->org ); if( org ) VectorCopy( org, p->org );
@@ -1889,17 +1823,15 @@ R_TracerEffect
void GAME_EXPORT R_TracerEffect( const vec3_t start, const vec3_t end ) void GAME_EXPORT R_TracerEffect( const vec3_t start, const vec3_t end )
{ {
vec3_t pos, vel, dir; vec3_t pos, vel, dir;
float len, speed;
float offset;
speed = Q_max( tracerspeed.value, 3.0f ); float speed = Q_max( tracerspeed.value, 3.0f );
VectorSubtract( end, start, dir ); VectorSubtract( end, start, dir );
len = VectorLength( dir ); float len = VectorLength( dir );
if( len == 0.0f ) return; if( len == 0.0f ) return;
VectorScale( dir, 1.0f / len, dir ); // normalize VectorScale( dir, 1.0f / len, dir ); // normalize
offset = COM_RandomFloat( -10.0f, 9.0f ) + traceroffset.value; float offset = COM_RandomFloat( -10.0f, 9.0f ) + traceroffset.value;
VectorScale( dir, offset, vel ); VectorScale( dir, offset, vel );
VectorAdd( start, vel, pos ); VectorAdd( start, vel, pos );
VectorScale( dir, speed, vel ); VectorScale( dir, speed, vel );
@@ -1950,17 +1882,15 @@ create a streak tracers
*/ */
void GAME_EXPORT R_SparkStreaks( const vec3_t pos, int count, int velocityMin, int velocityMax ) void GAME_EXPORT R_SparkStreaks( const vec3_t pos, int count, int velocityMin, int velocityMax )
{ {
particle_t *p;
vec3_t vel; vec3_t vel;
int i;
for( i = 0; i<count; i++ ) for( int i = 0; i<count; i++ )
{ {
vel[0] = COM_RandomFloat( velocityMin, velocityMax ); vel[0] = COM_RandomFloat( velocityMin, velocityMax );
vel[1] = COM_RandomFloat( velocityMin, velocityMax ); vel[1] = COM_RandomFloat( velocityMin, velocityMax );
vel[2] = COM_RandomFloat( velocityMin, velocityMax ); vel[2] = COM_RandomFloat( velocityMin, velocityMax );
p = R_AllocTracer( pos, vel, COM_RandomFloat( 0.1f, 0.5f )); particle_t *p = R_AllocTracer( pos, vel, COM_RandomFloat( 0.1f, 0.5f ));
if( !p ) return; if( !p ) return;
p->color = 5; p->color = 5;
@@ -1980,14 +1910,11 @@ void GAME_EXPORT R_Implosion( const vec3_t end, float radius, int count, float l
{ {
float dist = ( radius / 100.0f ); float dist = ( radius / 100.0f );
vec3_t start, temp, vel; vec3_t start, temp, vel;
float factor;
particle_t *p;
int i;
if( life <= 0.0f ) life = 0.1f; // to avoid divide by zero if( life <= 0.0f ) life = 0.1f; // to avoid divide by zero
factor = -1.0 / life; float factor = -1.0 / life;
for ( i = 0; i < count; i++ ) for( int i = 0; i < count; i++ )
{ {
temp[0] = dist * COM_RandomFloat( -100.0f, 100.0f ); temp[0] = dist * COM_RandomFloat( -100.0f, 100.0f );
temp[1] = dist * COM_RandomFloat( -100.0f, 100.0f ); temp[1] = dist * COM_RandomFloat( -100.0f, 100.0f );
@@ -1995,7 +1922,8 @@ void GAME_EXPORT R_Implosion( const vec3_t end, float radius, int count, float l
VectorScale( temp, factor, vel ); VectorScale( temp, factor, vel );
VectorAdd( temp, end, start ); VectorAdd( temp, end, start );
if(( p = R_AllocTracer( start, vel, life )) == NULL ) particle_t *p = R_AllocTracer( start, vel, life );
if( p == NULL )
return; return;
p->type = pt_explode; p->type = pt_explode;
@@ -2060,16 +1988,12 @@ CL_ReadPointFile_f
*/ */
void CL_ReadPointFile_f( void ) void CL_ReadPointFile_f( void )
{ {
byte *afile;
char *pfile;
vec3_t org; vec3_t org;
int count;
particle_t *p;
char filename[64]; char filename[64];
string token; string token;
Q_snprintf( filename, sizeof( filename ), "maps/%s.pts", clgame.mapname ); Q_snprintf( filename, sizeof( filename ), "maps/%s.pts", clgame.mapname );
afile = FS_LoadFile( filename, NULL, false ); byte *afile = FS_LoadFile( filename, NULL, false );
if( !afile ) if( !afile )
{ {
@@ -2079,8 +2003,8 @@ void CL_ReadPointFile_f( void )
Con_Printf( "Reading %s...\n", filename ); Con_Printf( "Reading %s...\n", filename );
count = 0; int count = 0;
pfile = (char *)afile; char *pfile = (char *)afile;
while( 1 ) while( 1 )
{ {
@@ -2106,7 +2030,7 @@ void CL_ReadPointFile_f( void )
// NOTE: can't use R_AllocParticle because this command // NOTE: can't use R_AllocParticle because this command
// may be executed from the console, while frametime is 0 // may be executed from the console, while frametime is 0
p = cl_free_particles; particle_t *p = cl_free_particles;
cl_free_particles = p->next; cl_free_particles = p->next;
p->next = cl_active_particles; p->next = cl_active_particles;
cl_active_particles = p; cl_active_particles = p;
+39 -69
View File
@@ -42,10 +42,6 @@ compute velocity for a given client
*/ */
static void CL_CalcPlayerVelocity( int idx, vec3_t velocity ) static void CL_CalcPlayerVelocity( int idx, vec3_t velocity )
{ {
clientdata_t *pcd;
vec3_t delta;
double dt;
VectorClear( velocity ); VectorClear( velocity );
if( idx <= 0 || idx > cl.maxclients ) if( idx <= 0 || idx > cl.maxclients )
@@ -53,15 +49,16 @@ static void CL_CalcPlayerVelocity( int idx, vec3_t velocity )
if( idx == cl.playernum + 1 ) if( idx == cl.playernum + 1 )
{ {
pcd = &cl.frames[cl.parsecountmod].clientdata; clientdata_t *pcd = &cl.frames[cl.parsecountmod].clientdata;
VectorCopy( pcd->velocity, velocity ); VectorCopy( pcd->velocity, velocity );
} }
else else
{ {
dt = clgame.entities[idx].curstate.animtime - clgame.entities[idx].prevstate.animtime; double dt = clgame.entities[idx].curstate.animtime - clgame.entities[idx].prevstate.animtime;
if( dt != 0.0 ) if( dt != 0.0 )
{ {
vec3_t delta;
VectorSubtract( clgame.entities[idx].curstate.velocity, clgame.entities[idx].prevstate.velocity, delta ); VectorSubtract( clgame.entities[idx].curstate.velocity, clgame.entities[idx].prevstate.velocity, delta );
VectorScale( delta, 1.0f / dt, velocity ); VectorScale( delta, 1.0f / dt, velocity );
} }
@@ -130,16 +127,13 @@ CL_SetEventIndex
*/ */
void CL_SetEventIndex( const char *szEvName, int ev_index ) void CL_SetEventIndex( const char *szEvName, int ev_index )
{ {
cl_user_event_t *ev;
int i;
if( !szEvName || !*szEvName ) if( !szEvName || !*szEvName )
return; // ignore blank names return; // ignore blank names
// search event by name to link with // search event by name to link with
for( i = 0; i < MAX_EVENTS; i++ ) for( int i = 0; i < MAX_EVENTS; i++ )
{ {
ev = clgame.events[i]; cl_user_event_t *ev = clgame.events[i];
if( !ev ) break; if( !ev ) break;
if( !Q_stricmp( ev->name, szEvName )) if( !Q_stricmp( ev->name, szEvName ))
@@ -158,12 +152,10 @@ CL_EventIndex
*/ */
word CL_EventIndex( const char *name ) word CL_EventIndex( const char *name )
{ {
word i;
if( COM_StringEmptyOrNULL( name )) if( COM_StringEmptyOrNULL( name ))
return 0; return 0;
for( i = 1; i < MAX_EVENTS && cl.event_precache[i][0]; i++ ) for( word i = 1; i < MAX_EVENTS && cl.event_precache[i][0]; i++ )
{ {
if( !Q_stricmp( cl.event_precache[i], name )) if( !Q_stricmp( cl.event_precache[i], name ))
return i; return i;
@@ -204,28 +196,24 @@ CL_FireEvent
*/ */
static qboolean CL_FireEvent( event_info_t *ei, int slot ) static qboolean CL_FireEvent( event_info_t *ei, int slot )
{ {
cl_user_event_t *ev;
const char *name;
int i, idx;
if( !ei || !ei->index ) if( !ei || !ei->index )
return false; return false;
// get the func pointer // get the func pointer
for( i = 0; i < MAX_EVENTS; i++ ) for( int i = 0; i < MAX_EVENTS; i++ )
{ {
ev = clgame.events[i]; cl_user_event_t *ev = clgame.events[i];
if( !ev ) if( !ev )
{ {
idx = bound( 1, ei->index, ( MAX_EVENTS - 1 )); int idx = bound( 1, ei->index, ( MAX_EVENTS - 1 ));
Con_Reportf( S_ERROR "%s: %s not precached\n", __func__, cl.event_precache[idx] ); Con_Reportf( S_ERROR "%s: %s not precached\n", __func__, cl.event_precache[idx] );
break; break;
} }
if( ev->index == ei->index ) if( ev->index == ei->index )
{ {
name = cl.event_precache[ei->index]; const char *name = cl.event_precache[ei->index];
if( cl_trace_events.value ) if( cl_trace_events.value )
{ {
@@ -261,15 +249,11 @@ called right before draw frame
*/ */
void CL_FireEvents( void ) void CL_FireEvents( void )
{ {
event_state_t *es; event_state_t *es = &cl.events;
event_info_t *ei;
int i;
es = &cl.events; for( int i = 0; i < MAX_EVENT_QUEUE; i++ )
for( i = 0; i < MAX_EVENT_QUEUE; i++ )
{ {
ei = &es->ei[i]; event_info_t *ei = &es->ei[i];
if( ei->index == 0 ) if( ei->index == 0 )
continue; continue;
@@ -294,16 +278,12 @@ find first empty event
*/ */
static event_info_t *CL_FindEmptyEvent( void ) static event_info_t *CL_FindEmptyEvent( void )
{ {
int i; event_state_t *es = &cl.events;
event_state_t *es;
event_info_t *ei;
es = &cl.events;
// look for first slot where index is != 0 // look for first slot where index is != 0
for( i = 0; i < MAX_EVENT_QUEUE; i++ ) for( int i = 0; i < MAX_EVENT_QUEUE; i++ )
{ {
ei = &es->ei[i]; event_info_t *ei = &es->ei[i];
if( ei->index != 0 ) if( ei->index != 0 )
continue; continue;
return ei; return ei;
@@ -322,15 +302,11 @@ replace only unreliable events
*/ */
static event_info_t *CL_FindUnreliableEvent( void ) static event_info_t *CL_FindUnreliableEvent( void )
{ {
event_state_t *es; event_state_t *es = &cl.events;
event_info_t *ei;
int i;
es = &cl.events; for ( int i = 0; i < MAX_EVENT_QUEUE; i++ )
for ( i = 0; i < MAX_EVENT_QUEUE; i++ )
{ {
ei = &es->ei[i]; event_info_t *ei = &es->ei[i];
if( ei->index != 0 ) if( ei->index != 0 )
{ {
// it's reliable, so skip it // it's reliable, so skip it
@@ -423,16 +399,10 @@ CL_ParseEvent
*/ */
void CL_ParseEvent( sizebuf_t *msg, connprotocol_t proto ) void CL_ParseEvent( sizebuf_t *msg, connprotocol_t proto )
{ {
int event_index;
int i, num_events;
int packet_index;
const event_args_t nullargs = { 0 }; const event_args_t nullargs = { 0 };
event_args_t args = { 0 }; event_args_t args = { 0 };
entity_state_t *state;
float delay;
int entity_bits; int entity_bits;
int num_events = MSG_ReadUBitLong( msg, 5 );
num_events = MSG_ReadUBitLong( msg, 5 );
if( proto == PROTO_GOLDSRC ) if( proto == PROTO_GOLDSRC )
entity_bits = MAX_GOLDSRC_ENTITY_BITS; entity_bits = MAX_GOLDSRC_ENTITY_BITS;
@@ -440,9 +410,11 @@ void CL_ParseEvent( sizebuf_t *msg, connprotocol_t proto )
entity_bits = MAX_ENTITY_BITS; entity_bits = MAX_ENTITY_BITS;
// parse events queue // parse events queue
for( i = 0 ; i < num_events; i++ ) for( int i = 0 ; i < num_events; i++ )
{ {
event_index = MSG_ReadUBitLong( msg, MAX_EVENT_BITS ); int packet_index;
float delay;
int event_index = MSG_ReadUBitLong( msg, MAX_EVENT_BITS );
if( MSG_ReadOneBit( msg )) if( MSG_ReadOneBit( msg ))
{ {
@@ -467,7 +439,7 @@ void CL_ParseEvent( sizebuf_t *msg, connprotocol_t proto )
if( packet_index < frame->num_entities ) if( packet_index < frame->num_entities )
{ {
state = &cls.packet_entities[(frame->first_entity+packet_index)%cls.num_client_entities]; entity_state_t *state = &cls.packet_entities[(frame->first_entity+packet_index)%cls.num_client_entities];
args.entindex = state->number; args.entindex = state->number;
if( VectorIsNull( args.origin )) if( VectorIsNull( args.origin ))
@@ -515,8 +487,6 @@ CL_PlaybackEvent
void GAME_EXPORT CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, float delay, float *origin, void GAME_EXPORT CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, float delay, float *origin,
float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ) float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 )
{ {
event_args_t args;
if( FBitSet( flags, FEV_SERVER )) if( FBitSet( flags, FEV_SERVER ))
return; return;
@@ -538,20 +508,20 @@ void GAME_EXPORT CL_PlaybackEvent( int flags, const edict_t *pInvoker, word even
ClearBits( flags, FEV_NOTHOST|FEV_HOSTONLY|FEV_GLOBAL ); ClearBits( flags, FEV_NOTHOST|FEV_HOSTONLY|FEV_GLOBAL );
if( delay < 0.0f ) delay = 0.0f; // fixup negative delays if( delay < 0.0f ) delay = 0.0f; // fixup negative delays
memset( &args, 0, sizeof( args )); event_args_t args =
{
VectorCopy( origin, args.origin ); .origin = Vec3( origin ),
VectorCopy( angles, args.angles ); .angles = Vec3( angles ),
VectorCopy( cl.simvel, args.velocity ); .velocity = Vec3( cl.simvel ),
args.entindex = cl.playernum + 1; .entindex = cl.playernum + 1,
args.ducking = ( cl.local.usehull == 1 ); .ducking = ( cl.local.usehull == 1 ),
.fparam1 = fparam1,
args.fparam1 = fparam1; .fparam2 = fparam2,
args.fparam2 = fparam2; .iparam1 = iparam1,
args.iparam1 = iparam1; .iparam2 = iparam2,
args.iparam2 = iparam2; .bparam1 = bparam1,
args.bparam1 = bparam1; .bparam2 = bparam2,
args.bparam2 = bparam2; };
CL_QueueEvent( flags, eventindex, delay, &args ); CL_QueueEvent( flags, eventindex, delay, &args );
} }
+16 -23
View File
@@ -39,17 +39,14 @@ qboolean CL_FixedFont( cl_font_t *font )
static int CL_LoadFontTexture( const char *fontname, uint texFlags, int *width ) static int CL_LoadFontTexture( const char *fontname, uint texFlags, int *width )
{ {
int font_width;
int tex;
if( !g_fsapi.FileExists( fontname, false )) if( !g_fsapi.FileExists( fontname, false ))
return 0; return 0;
tex = ref.dllFuncs.GL_LoadTexture( fontname, NULL, 0, texFlags ); int tex = ref.dllFuncs.GL_LoadTexture( fontname, NULL, 0, texFlags );
if( !tex ) if( !tex )
return 0; return 0;
font_width = REF_GET_PARM( PARM_TEX_WIDTH, tex ); int font_width = REF_GET_PARM( PARM_TEX_WIDTH, tex );
if( !font_width ) if( !font_width )
{ {
ref.dllFuncs.GL_FreeTexture( tex ); ref.dllFuncs.GL_FreeTexture( tex );
@@ -89,7 +86,7 @@ void CL_SetFontColor( cl_font_t *font, const rgba_t color )
qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, convar_t *rendermode, uint texFlags ) qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, convar_t *rendermode, uint texFlags )
{ {
int font_width, i; int font_width;
if( !rendermode ) if( !rendermode )
return false; return false;
@@ -107,7 +104,7 @@ qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float sc
font->rendermode = rendermode; font->rendermode = rendermode;
font->charHeight = Q_rint( font_width / 16 * scale ); font->charHeight = Q_rint( font_width / 16 * scale );
for( i = 0; i < ARRAYSIZE( font->fontRc ); i++ ) for( int i = 0; i < ARRAYSIZE( font->fontRc ); i++ )
{ {
font->fontRc[i].left = ( i * font_width / 16 ) % font_width; font->fontRc[i].left = ( i * font_width / 16 ) % font_width;
font->fontRc[i].right = font->fontRc[i].left + font_width / 16; font->fontRc[i].right = font->fontRc[i].left + font_width / 16;
@@ -124,8 +121,7 @@ qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float
{ {
fs_offset_t length; fs_offset_t length;
qfont_t src; qfont_t src;
byte *pfile; int font_width;
int font_width, i;
if( !rendermode ) if( !rendermode )
return false; return false;
@@ -133,7 +129,7 @@ qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float
if( font->valid ) if( font->valid )
return true; return true;
pfile = g_fsapi.LoadFile( fontname, &length, false ); byte *pfile = g_fsapi.LoadFile( fontname, &length, false );
if( !pfile ) if( !pfile )
return false; return false;
@@ -157,7 +153,7 @@ qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float
font->rendermode = rendermode; font->rendermode = rendermode;
font->charHeight = Q_rint( src.rowheight * scale ); font->charHeight = Q_rint( src.rowheight * scale );
for( i = 0; i < ARRAYSIZE( font->fontRc ); i++ ) for( int i = 0; i < ARRAYSIZE( font->fontRc ); i++ )
{ {
const charinfo *ci = &src.fontinfo[i]; const charinfo *ci = &src.fontinfo[i];
@@ -195,11 +191,6 @@ static int CL_CalcTabStop( const cl_font_t *font, int x )
int CL_DrawCharacter( float x, float y, int number, const rgba_t color, cl_font_t *font, int flags ) int CL_DrawCharacter( float x, float y, int number, const rgba_t color, cl_font_t *font, int flags )
{ {
wrect_t *rc;
float w, h;
float s1, t1, s2, t2, half = 0.5f;
int texw, texh;
if( !font || !font->valid || y < -font->charHeight ) if( !font || !font->valid || y < -font->charHeight )
return 0; return 0;
@@ -220,21 +211,23 @@ int CL_DrawCharacter( float x, float y, int number, const rgba_t color, cl_font_
if( !number || !font->charWidths[number]) if( !number || !font->charWidths[number])
return 0; return 0;
int texw, texh;
R_GetTextureParms( &texw, &texh, font->hFontTexture ); R_GetTextureParms( &texw, &texh, font->hFontTexture );
if( !texw || !texh ) if( !texw || !texh )
return font->charWidths[number]; return font->charWidths[number];
rc = &font->fontRc[number]; wrect_t *rc = &font->fontRc[number];
float half = 0.5f;
if( font->scale <= 1.f || !REF_GET_PARM( PARM_TEX_FILTERING, font->hFontTexture )) if( font->scale <= 1.f || !REF_GET_PARM( PARM_TEX_FILTERING, font->hFontTexture ))
half = 0; half = 0;
s1 = ((float)rc->left + half ) / texw; float s1 = ((float)rc->left + half ) / texw;
t1 = ((float)rc->top + half ) / texh; float t1 = ((float)rc->top + half ) / texh;
s2 = ((float)rc->right - half ) / texw; float s2 = ((float)rc->right - half ) / texw;
t2 = ((float)rc->bottom - half ) / texh; float t2 = ((float)rc->bottom - half ) / texh;
w = ( rc->right - rc->left ) * font->scale; float w = ( rc->right - rc->left ) * font->scale;
h = ( rc->bottom - rc->top ) * font->scale; float h = ( rc->bottom - rc->top ) * font->scale;
if( FBitSet( flags, FONT_DRAW_HUD )) if( FBitSet( flags, FONT_DRAW_HUD ))
SPR_AdjustSize( &x, &y, &w, &h ); SPR_AdjustSize( &x, &y, &w, &h );
+50 -81
View File
@@ -41,12 +41,10 @@ Store another position into interpolation circular buffer
*/ */
static void CL_UpdatePositions( cl_entity_t *ent ) static void CL_UpdatePositions( cl_entity_t *ent )
{ {
position_history_t *ph, *prev; position_history_t *prev = &ent->ph[ent->current_position & HISTORY_MASK];
prev = &ent->ph[ent->current_position];
ent->current_position = (ent->current_position + 1) & HISTORY_MASK; ent->current_position = (ent->current_position + 1) & HISTORY_MASK;
ph = &ent->ph[ent->current_position]; position_history_t *ph = &ent->ph[ent->current_position];
VectorCopy( ent->curstate.origin, ph->origin ); VectorCopy( ent->curstate.origin, ph->origin );
VectorCopy( ent->curstate.angles, ph->angles ); VectorCopy( ent->curstate.angles, ph->angles );
@@ -74,11 +72,10 @@ Interpolation init or reset after teleporting
*/ */
static void CL_ResetPositions( cl_entity_t *ent ) static void CL_ResetPositions( cl_entity_t *ent )
{ {
position_history_t store; if( !ent )
return;
if( !ent ) return; position_history_t store = ent->ph[ent->current_position & HISTORY_MASK];
store = ent->ph[ent->current_position];
ent->current_position = 1; ent->current_position = 1;
memset( ent->ph, 0, sizeof( position_history_t ) * HISTORY_MAX ); memset( ent->ph, 0, sizeof( position_history_t ) * HISTORY_MAX );
@@ -95,14 +92,13 @@ we don't want interpolate this
*/ */
static qboolean CL_EntityTeleported( cl_entity_t *ent ) static qboolean CL_EntityTeleported( cl_entity_t *ent )
{ {
float len, maxlen;
vec3_t delta; vec3_t delta;
VectorSubtract( ent->curstate.origin, ent->prevstate.origin, delta ); VectorSubtract( ent->curstate.origin, ent->prevstate.origin, delta );
// compute potential max movement in units per frame and compare with entity movement // compute potential max movement in units per frame and compare with entity movement
maxlen = ( clgame.movevars.maxvelocity * ( 1.0f / GAME_FPS )); float maxlen = ( clgame.movevars.maxvelocity * ( 1.0f / GAME_FPS ));
len = VectorLength( delta ); float len = VectorLength( delta );
return (len > maxlen); return (len > maxlen);
} }
@@ -170,22 +166,23 @@ check for parametrical moved entities
*/ */
static qboolean CL_ParametricMove( cl_entity_t *ent ) static qboolean CL_ParametricMove( cl_entity_t *ent )
{ {
float frac, dt, t;
vec3_t delta; vec3_t delta;
if( ent->curstate.starttime == 0.0f || ent->curstate.impacttime == 0.0f ) if( ent->curstate.starttime == 0.0f || ent->curstate.impacttime == 0.0f )
return false; return false;
VectorSubtract( ent->curstate.endpos, ent->curstate.startpos, delta ); VectorSubtract( ent->curstate.endpos, ent->curstate.startpos, delta );
dt = ent->curstate.impacttime - ent->curstate.starttime; float dt = ent->curstate.impacttime - ent->curstate.starttime;
if( dt != 0.0f ) if( dt != 0.0f )
{ {
float t;
if( ent->lastmove > cl.time ) if( ent->lastmove > cl.time )
t = ent->lastmove; t = ent->lastmove;
else t = cl.time; else t = cl.time;
frac = ( t - ent->curstate.starttime ) / dt; float frac = ( t - ent->curstate.starttime ) / dt;
frac = bound( 0.0f, frac, 1.0f ); frac = bound( 0.0f, frac, 1.0f );
VectorMA( ent->curstate.startpos, frac, delta, ent->curstate.origin ); VectorMA( ent->curstate.startpos, frac, delta, ent->curstate.origin );
@@ -240,18 +237,14 @@ CL_GetStudioEstimatedFrame
*/ */
static float CL_GetStudioEstimatedFrame( cl_entity_t *ent ) static float CL_GetStudioEstimatedFrame( cl_entity_t *ent )
{ {
studiohdr_t *pstudiohdr;
mstudioseqdesc_t *pseqdesc;
int sequence;
if( ent->model != NULL && ent->model->type == mod_studio ) if( ent->model != NULL && ent->model->type == mod_studio )
{ {
pstudiohdr = (studiohdr_t *)Mod_StudioExtradata( ent->model ); studiohdr_t *pstudiohdr = (studiohdr_t *)Mod_StudioExtradata( ent->model );
if( pstudiohdr && pstudiohdr->numseq > 0 ) if( pstudiohdr && pstudiohdr->numseq > 0 )
{ {
sequence = bound( 0, ent->curstate.sequence, pstudiohdr->numseq - 1 ); int sequence = bound( 0, ent->curstate.sequence, pstudiohdr->numseq - 1 );
pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + sequence; mstudioseqdesc_t *pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + sequence;
return ref.dllFuncs.R_StudioEstimateFrame( ent, pseqdesc, cl.time ); return ref.dllFuncs.R_StudioEstimateFrame( ent, pseqdesc, cl.time );
} }
} }
@@ -302,8 +295,6 @@ apply changes since new frame received
*/ */
static void CL_ProcessEntityUpdate( cl_entity_t *ent ) static void CL_ProcessEntityUpdate( cl_entity_t *ent )
{ {
qboolean parametric;
ent->model = CL_ModelHandle( ent->curstate.modelindex ); ent->model = CL_ModelHandle( ent->curstate.modelindex );
ent->index = ent->curstate.number; ent->index = ent->curstate.number;
@@ -325,7 +316,7 @@ static void CL_ProcessEntityUpdate( cl_entity_t *ent )
VectorCopy( aiment->origin, ent->curstate.origin ); VectorCopy( aiment->origin, ent->curstate.origin );
} }
parametric = ent->curstate.starttime != 0.0f && ent->curstate.impacttime != 0.0f; qboolean parametric = ent->curstate.starttime != 0.0f && ent->curstate.impacttime != 0.0f;
// allow interpolation on bmodels too // allow interpolation on bmodels too
if( ent->model && ent->model->type == mod_brush ) if( ent->model && ent->model->type == mod_brush )
@@ -364,13 +355,11 @@ find two timestamps
static qboolean CL_FindInterpolationUpdates( cl_entity_t *ent, double targettime, position_history_t **ph0, position_history_t **ph1 ) static qboolean CL_FindInterpolationUpdates( cl_entity_t *ent, double targettime, position_history_t **ph0, position_history_t **ph1 )
{ {
qboolean extrapolate = true; qboolean extrapolate = true;
uint i, i0, i1, imod; uint imod = ent->current_position;
uint i0 = (imod - 0) & HISTORY_MASK; // curpos (lerp end)
uint i1 = (imod - 1) & HISTORY_MASK; // oldpos (lerp start)
imod = ent->current_position; for( uint i = 1; i < HISTORY_MAX - 1; i++ )
i0 = (imod - 0) & HISTORY_MASK; // curpos (lerp end)
i1 = (imod - 1) & HISTORY_MASK; // oldpos (lerp start)
for( i = 1; i < HISTORY_MAX - 1; i++ )
{ {
double at = ent->ph[( imod - i ) & HISTORY_MASK].animtime; double at = ent->ph[( imod - i ) & HISTORY_MASK].animtime;
@@ -402,19 +391,19 @@ non-local players interpolation
*/ */
static void CL_PureOrigin( cl_entity_t *ent, double t, vec3_t outorigin, vec3_t outangles ) static void CL_PureOrigin( cl_entity_t *ent, double t, vec3_t outorigin, vec3_t outangles )
{ {
double t1, t0, frac;
position_history_t *ph0, *ph1; position_history_t *ph0, *ph1;
vec3_t delta;
// NOTE: ph0 is next, ph1 is a prev // NOTE: ph0 is next, ph1 is a prev
CL_FindInterpolationUpdates( ent, t, &ph0, &ph1 ); CL_FindInterpolationUpdates( ent, t, &ph0, &ph1 );
t0 = ph0->animtime; double t0 = ph0->animtime;
t1 = ph1->animtime; double t1 = ph1->animtime;
if( t0 != 0.0 ) if( t0 != 0.0 )
{ {
vec4_t q, q1, q2; vec4_t q, q1, q2;
vec3_t delta;
double frac;
VectorSubtract( ph0->origin, ph1->origin, delta ); VectorSubtract( ph0->origin, ph1->origin, delta );
@@ -450,7 +439,6 @@ static int CL_InterpolateModel( cl_entity_t *e )
{ {
position_history_t *ph0 = NULL, *ph1 = NULL; position_history_t *ph0 = NULL, *ph1 = NULL;
vec3_t origin, angles, delta; vec3_t origin, angles, delta;
double t, t1, t2, frac;
vec4_t q, q1, q2; vec4_t q, q1, q2;
VectorCopy( e->curstate.origin, e->origin ); VectorCopy( e->curstate.origin, e->origin );
@@ -479,11 +467,11 @@ static int CL_InterpolateModel( cl_entity_t *e )
if( cl.local.moving && cl.local.onground == e->index ) if( cl.local.moving && cl.local.onground == e->index )
return 1; return 1;
t = cl.time - cl_interp.value; double t = cl.time - cl_interp.value;
CL_FindInterpolationUpdates( e, t, &ph0, &ph1 ); CL_FindInterpolationUpdates( e, t, &ph0, &ph1 );
t1 = ph1->animtime; double t1 = ph1->animtime;
t2 = ph0->animtime; double t2 = ph0->animtime;
if( t - t1 < 0.0f ) if( t - t1 < 0.0f )
return 0; return 0;
@@ -503,7 +491,7 @@ static int CL_InterpolateModel( cl_entity_t *e )
} }
VectorSubtract( ph0->origin, ph1->origin, delta ); VectorSubtract( ph0->origin, ph1->origin, delta );
frac = (t - t1) / (t2 - t1); double frac = (t - t1) / (t2 - t1);
if( frac < 0.0f ) if( frac < 0.0f )
return 0; return 0;
@@ -533,8 +521,6 @@ interpolate non-local clients
*/ */
void CL_ComputePlayerOrigin( cl_entity_t *ent ) void CL_ComputePlayerOrigin( cl_entity_t *ent )
{ {
double targettime;
vec4_t q, q1, q2;
vec3_t origin; vec3_t origin;
vec3_t angles; vec3_t angles;
@@ -550,6 +536,8 @@ void CL_ComputePlayerOrigin( cl_entity_t *ent )
if( cls.demoplayback == DEMO_QUAKE1 ) if( cls.demoplayback == DEMO_QUAKE1 )
{ {
vec4_t q, q1, q2;
// quake lerping is easy // quake lerping is easy
VectorLerp( ent->prevstate.origin, cl.lerpFrac, ent->curstate.origin, ent->origin ); VectorLerp( ent->prevstate.origin, cl.lerpFrac, ent->curstate.origin, ent->origin );
AngleQuaternion( ent->prevstate.angles, q1, false ); AngleQuaternion( ent->prevstate.angles, q1, false );
@@ -559,7 +547,7 @@ void CL_ComputePlayerOrigin( cl_entity_t *ent )
return; return;
} }
targettime = cl.time - cl_interp.value; double targettime = cl.time - cl_interp.value;
CL_PureOrigin( ent, targettime, origin, angles ); CL_PureOrigin( ent, targettime, origin, angles );
VectorCopy( angles, ent->angles ); VectorCopy( angles, ent->angles );
@@ -575,9 +563,7 @@ process player states after the new packet has received
*/ */
static void CL_ProcessPlayerState( int playerindex, entity_state_t *state ) static void CL_ProcessPlayerState( int playerindex, entity_state_t *state )
{ {
entity_state_t *ps; entity_state_t *ps = &cl.frames[cl.parsecountmod].playerstate[playerindex];
ps = &cl.frames[cl.parsecountmod].playerstate[playerindex];
ps->number = state->number; ps->number = state->number;
ps->messagenum = cl.parsecount; ps->messagenum = cl.parsecount;
ps->msg_time = cl.mtime[0]; ps->msg_time = cl.mtime[0];
@@ -618,19 +604,15 @@ process player states after the new packet has received
*/ */
void CL_ProcessPacket( frame_t *frame ) void CL_ProcessPacket( frame_t *frame )
{ {
entity_state_t *state; for( int pnum = 0; pnum < frame->num_entities; pnum++ )
cl_entity_t *ent;
int pnum;
for( pnum = 0; pnum < frame->num_entities; pnum++ )
{ {
// request the entity state from circular buffer // request the entity state from circular buffer
state = &cls.packet_entities[(frame->first_entity+pnum) % cls.num_client_entities]; entity_state_t *state = &cls.packet_entities[(frame->first_entity+pnum) % cls.num_client_entities];
state->messagenum = cl.parsecount; state->messagenum = cl.parsecount;
state->msg_time = cl.mtime[0]; state->msg_time = cl.mtime[0];
// mark all the players // mark all the players
ent = &clgame.entities[state->number]; cl_entity_t *ent = &clgame.entities[state->number];
ent->player = CL_IsPlayerIndex( state->number ); ent->player = CL_IsPlayerIndex( state->number );
if( state->number == ( cl.playernum + 1 )) if( state->number == ( cl.playernum + 1 ))
@@ -676,7 +658,6 @@ Read and ignore whole entity packet.
*/ */
static void CL_FlushEntityPacket( sizebuf_t *msg, connprotocol_t proto ) static void CL_FlushEntityPacket( sizebuf_t *msg, connprotocol_t proto )
{ {
int newnum;
entity_state_t from, to; entity_state_t from, to;
memset( &from, 0, sizeof( from )); memset( &from, 0, sizeof( from ));
@@ -687,6 +668,8 @@ static void CL_FlushEntityPacket( sizebuf_t *msg, connprotocol_t proto )
// read it all, but ignore it // read it all, but ignore it
while( 1 ) while( 1 )
{ {
int newnum;
if( !CL_ParseEntityNumFromPacket( msg, &newnum, proto )) if( !CL_ParseEntityNumFromPacket( msg, &newnum, proto ))
break; // done break; // done
@@ -816,22 +799,19 @@ rest of the data stream.
*/ */
int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta, connprotocol_t proto ) int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta, connprotocol_t proto )
{ {
frame_t *newframe, *oldframe; frame_t *oldframe;
int oldindex, newnum, oldnum; int oldindex, newnum, oldnum;
int playerbytes = 0; int playerbytes = 0;
int bufStart;
entity_state_t *oldent; entity_state_t *oldent;
qboolean player;
int count;
// save first uncompressed packet as timestamp // save first uncompressed packet as timestamp
if( cls.changelevel && !delta && cls.demorecording ) if( cls.changelevel && !delta && cls.demorecording )
CL_WriteDemoJumpTime(); CL_WriteDemoJumpTime();
// sentinel count. save it for debug checking // sentinel count. save it for debug checking
count = MSG_ReadUBitLong( msg, MAX_VISIBLE_PACKET_BITS ) + 1; int count = MSG_ReadUBitLong( msg, MAX_VISIBLE_PACKET_BITS ) + 1;
newframe = &cl.frames[cl.parsecountmod]; frame_t *newframe = &cl.frames[cl.parsecountmod];
// allocate parse entities // allocate parse entities
memset( newframe->flags, 0, sizeof( newframe->flags )); memset( newframe->flags, 0, sizeof( newframe->flags ));
@@ -872,7 +852,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta, connprotocol_t proto
if( MSG_CheckOverflow( msg )) if( MSG_CheckOverflow( msg ))
Host_Error( "%s: overflow\n", __func__ ); Host_Error( "%s: overflow\n", __func__ );
player = CL_IsPlayerIndex( newnum ); qboolean player = CL_IsPlayerIndex( newnum );
while( oldnum < newnum ) while( oldnum < newnum )
{ {
@@ -884,7 +864,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta, connprotocol_t proto
if( oldnum == newnum ) if( oldnum == newnum )
{ {
// delta from previous state // delta from previous state
bufStart = MSG_GetNumBytesRead( msg ); int bufStart = MSG_GetNumBytesRead( msg );
CL_DeltaEntity( msg, newframe, newnum, oldent, true ); CL_DeltaEntity( msg, newframe, newnum, oldent, true );
if( player ) playerbytes += MSG_GetNumBytesRead( msg ) - bufStart; if( player ) playerbytes += MSG_GetNumBytesRead( msg ) - bufStart;
oldnum = CL_UpdateOldEntNum( ++oldindex, oldframe, &oldent ); oldnum = CL_UpdateOldEntNum( ++oldindex, oldframe, &oldent );
@@ -894,7 +874,7 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta, connprotocol_t proto
if( oldnum > newnum ) if( oldnum > newnum )
{ {
// delta from baseline ? // delta from baseline ?
bufStart = MSG_GetNumBytesRead( msg ); int bufStart = MSG_GetNumBytesRead( msg );
CL_DeltaEntity( msg, newframe, newnum, NULL, true ); CL_DeltaEntity( msg, newframe, newnum, NULL, true );
if( player ) playerbytes += MSG_GetNumBytesRead( msg ) - bufStart; if( player ) playerbytes += MSG_GetNumBytesRead( msg ) - bufStart;
continue; continue;
@@ -1030,12 +1010,10 @@ for all current players
*/ */
static void CL_LinkPlayers( frame_t *frame ) static void CL_LinkPlayers( frame_t *frame )
{ {
cl_entity_t *ent = CL_GetLocalPlayer();
entity_state_t *state; entity_state_t *state;
cl_entity_t *ent;
int i; int i;
ent = CL_GetLocalPlayer();
// apply muzzleflash to weaponmodel // apply muzzleflash to weaponmodel
if( ent && FBitSet( ent->curstate.effects, EF_MUZZLEFLASH )) if( ent && FBitSet( ent->curstate.effects, EF_MUZZLEFLASH ))
SetBits( clgame.viewent.curstate.effects, EF_MUZZLEFLASH ); SetBits( clgame.viewent.curstate.effects, EF_MUZZLEFLASH );
@@ -1113,15 +1091,9 @@ CL_LinkPacketEntities
*/ */
static void CL_LinkPacketEntities( frame_t *frame ) static void CL_LinkPacketEntities( frame_t *frame )
{ {
cl_entity_t *ent; for( int i = 0; i < frame->num_entities; i++ )
entity_state_t *state;
qboolean parametric;
qboolean interpolate;
int i;
for( i = 0; i < frame->num_entities; i++ )
{ {
state = &cls.packet_entities[(frame->first_entity + i) % cls.num_client_entities]; entity_state_t *state = &cls.packet_entities[(frame->first_entity + i) % cls.num_client_entities];
// clients are should be done in CL_LinkPlayers // clients are should be done in CL_LinkPlayers
if( state->number >= 1 && state->number <= cl.maxclients ) if( state->number >= 1 && state->number <= cl.maxclients )
@@ -1131,7 +1103,7 @@ static void CL_LinkPacketEntities( frame_t *frame )
if( !state->modelindex || FBitSet( state->effects, EF_NODRAW )) if( !state->modelindex || FBitSet( state->effects, EF_NODRAW ))
continue; continue;
ent = CL_GetEntityByIndex( state->number ); cl_entity_t *ent = CL_GetEntityByIndex( state->number );
if( !ent ) if( !ent )
{ {
@@ -1142,7 +1114,7 @@ static void CL_LinkPacketEntities( frame_t *frame )
// animtime must keep an actual // animtime must keep an actual
ent->curstate.animtime = state->animtime; ent->curstate.animtime = state->animtime;
ent->curstate.frame = state->frame; ent->curstate.frame = state->frame;
interpolate = false; qboolean interpolate = false;
if( !ent->model ) continue; if( !ent->model ) continue;
@@ -1156,7 +1128,7 @@ static void CL_LinkPacketEntities( frame_t *frame )
} }
} }
parametric = ( ent->curstate.impacttime != 0.0f && ent->curstate.starttime != 0.0f ); qboolean parametric = ( ent->curstate.impacttime != 0.0f && ent->curstate.starttime != 0.0f );
if( !parametric && ent->curstate.movetype != MOVETYPE_COMPOUND ) if( !parametric && ent->curstate.movetype != MOVETYPE_COMPOUND )
{ {
@@ -1369,9 +1341,6 @@ SOUND ENGINE IMPLEMENTATION
*/ */
qboolean CL_GetEntitySpatialization( channel_t *ch ) qboolean CL_GetEntitySpatialization( channel_t *ch )
{ {
cl_entity_t *ent;
qboolean valid_origin;
if( ch->entnum == 0 ) if( ch->entnum == 0 )
{ {
SetBits( ch->flags, FL_CHAN_STATIC_SOUND ); SetBits( ch->flags, FL_CHAN_STATIC_SOUND );
@@ -1384,8 +1353,8 @@ qboolean CL_GetEntitySpatialization( channel_t *ch )
return true; return true;
} }
valid_origin = VectorIsNull( ch->origin ) ? false : true; qboolean valid_origin = VectorIsNull( ch->origin ) ? false : true;
ent = CL_GetEntityByIndex( ch->entnum ); cl_entity_t *ent = CL_GetEntityByIndex( ch->entnum );
// entity is not present on the client but has valid origin // entity is not present on the client but has valid origin
if( !ent || !ent->model || ent->curstate.messagenum != cl.parsecount ) if( !ent || !ent->model || ent->curstate.messagenum != cl.parsecount )
+309 -244
View File
@@ -13,6 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
*/ */
#include <inttypes.h>
#include "common.h" #include "common.h"
#include "client.h" #include "client.h"
#include "net_encode.h" #include "net_encode.h"
@@ -36,8 +37,9 @@ CVAR_DEFINE( cl_allow_download, "cl_allowdownload", "1", FCVAR_ARCHIVE, "allow t
static CVAR_DEFINE( cl_allow_upload, "cl_allowupload", "1", FCVAR_ARCHIVE, "allow to uploading resources to the server" ); static CVAR_DEFINE( cl_allow_upload, "cl_allowupload", "1", FCVAR_ARCHIVE, "allow to uploading resources to the server" );
CVAR_DEFINE_AUTO( cl_download_ingame, "1", FCVAR_ARCHIVE, "allow to downloading resources while client is active" ); CVAR_DEFINE_AUTO( cl_download_ingame, "1", FCVAR_ARCHIVE, "allow to downloading resources while client is active" );
static CVAR_DEFINE_AUTO( cl_logofile, "lambda", FCVAR_ARCHIVE, "player logo name" ); static CVAR_DEFINE_AUTO( cl_logofile, "lambda", FCVAR_ARCHIVE, "player logo name" );
static CVAR_DEFINE_AUTO( cl_logocolor, "orange", FCVAR_ARCHIVE, "player logo color" ); static CVAR_DEFINE_AUTO( cl_logocolor, "255 120 24", FCVAR_ARCHIVE, "player logo color" );
static CVAR_DEFINE_AUTO( cl_logoext, "bmp", FCVAR_ARCHIVE, "temporary cvar to tell engine which logo must be packed" ); static CVAR_DEFINE_AUTO( cl_logoext, "bmp", FCVAR_ARCHIVE, "temporary cvar to tell engine which logo must be packed" );
static CVAR_DEFINE( cl_logoupdate, "@cl_logoupdate", "0", 0, "set by menu to trigger clan logo update" );
CVAR_DEFINE_AUTO( cl_logomaxdim, "96", FCVAR_ARCHIVE, "maximum decal dimension" ); CVAR_DEFINE_AUTO( cl_logomaxdim, "96", FCVAR_ARCHIVE, "maximum decal dimension" );
static CVAR_DEFINE_AUTO( cl_test_bandwidth, "1", FCVAR_ARCHIVE, "test network bandwith before connection" ); static CVAR_DEFINE_AUTO( cl_test_bandwidth, "1", FCVAR_ARCHIVE, "test network bandwith before connection" );
@@ -47,18 +49,18 @@ CVAR_DEFINE( cl_draw_beams, "r_drawbeams", "1", FCVAR_CHEAT, "render beams" );
static CVAR_DEFINE_AUTO( rcon_address, "", FCVAR_PRIVILEGED, "remote control address" ); static CVAR_DEFINE_AUTO( rcon_address, "", FCVAR_PRIVILEGED, "remote control address" );
CVAR_DEFINE_AUTO( cl_timeout, "60", 0, "connect timeout (in-seconds)" ); CVAR_DEFINE_AUTO( cl_timeout, "60", 0, "connect timeout (in-seconds)" );
CVAR_DEFINE_AUTO( cl_nopred, "0", FCVAR_ARCHIVE|FCVAR_USERINFO, "disable client movement prediction" ); CVAR_DEFINE_AUTO( cl_nopred, "0", FCVAR_USERINFO, "disable client movement prediction" );
static CVAR_DEFINE_AUTO( cl_nodelta, "0", 0, "disable delta-compression for server messages" ); static CVAR_DEFINE_AUTO( cl_nodelta, "0", 0, "disable delta-compression for server messages" );
CVAR_DEFINE( cl_crosshair, "crosshair", "1", FCVAR_ARCHIVE, "show weapon chrosshair" ); CVAR_DEFINE( cl_crosshair, "crosshair", "1", FCVAR_ARCHIVE, "show weapon chrosshair" );
static CVAR_DEFINE_AUTO( cl_cmdbackup, "10", FCVAR_ARCHIVE, "how many additional history commands are sent" ); static CVAR_DEFINE_AUTO( cl_cmdbackup, "10", FCVAR_ARCHIVE, "how many additional history commands are sent" );
CVAR_DEFINE_AUTO( cl_showerror, "0", FCVAR_ARCHIVE, "show prediction error" ); CVAR_DEFINE_AUTO( cl_showerror, "0", FCVAR_ARCHIVE, "show prediction error" );
CVAR_DEFINE_AUTO( cl_bmodelinterp, "1", FCVAR_ARCHIVE, "enable bmodel interpolation" ); CVAR_DEFINE_AUTO( cl_bmodelinterp, "1", 0, "enable bmodel interpolation" );
static CVAR_DEFINE_AUTO( cl_lightstyle_lerping, "0", FCVAR_ARCHIVE, "enables animated light lerping (perfomance option)" ); static CVAR_DEFINE_AUTO( cl_lightstyle_lerping, "0", FCVAR_ARCHIVE, "enables animated light lerping (perfomance option)" );
CVAR_DEFINE_AUTO( cl_idealpitchscale, "0.8", 0, "how much to look up/down slopes and stairs when not using freelook" ); CVAR_DEFINE_AUTO( cl_idealpitchscale, "0.8", 0, "how much to look up/down slopes and stairs when not using freelook" );
CVAR_DEFINE_AUTO( cl_nosmooth, "0", FCVAR_ARCHIVE, "disable smooth up stair climbing" ); CVAR_DEFINE_AUTO( cl_nosmooth, "0", 0, "disable smooth up stair climbing" );
CVAR_DEFINE_AUTO( cl_smoothtime, "0.1", FCVAR_ARCHIVE, "time to smooth up" ); CVAR_DEFINE_AUTO( cl_smoothtime, "0.1", 0, "time to smooth up" );
CVAR_DEFINE_AUTO( cl_clockreset, "0.1", FCVAR_ARCHIVE, "frametime delta maximum value before reset" ); CVAR_DEFINE_AUTO( cl_clockreset, "0.1", 0, "frametime delta maximum value before reset" );
static CVAR_DEFINE_AUTO( cl_fixtimerate, "7.5", FCVAR_ARCHIVE, "time in msec to client clock adjusting" ); static CVAR_DEFINE_AUTO( cl_fixtimerate, "7.5", 0, "time in msec to client clock adjusting" );
CVAR_DEFINE_AUTO( hud_fontscale, "1.0", FCVAR_ARCHIVE|FCVAR_LATCH, "scale hud font texture" ); CVAR_DEFINE_AUTO( hud_fontscale, "1.0", FCVAR_ARCHIVE|FCVAR_LATCH, "scale hud font texture" );
CVAR_DEFINE_AUTO( hud_fontrender, "0", FCVAR_ARCHIVE, "hud font render mode (0: additive, 1: holes, 2: trans)" ); CVAR_DEFINE_AUTO( hud_fontrender, "0", FCVAR_ARCHIVE, "hud font render mode (0: additive, 1: holes, 2: trans)" );
CVAR_DEFINE_AUTO( hud_scale, "0", FCVAR_ARCHIVE|FCVAR_LATCH, "scale hud at current resolution" ); CVAR_DEFINE_AUTO( hud_scale, "0", FCVAR_ARCHIVE|FCVAR_LATCH, "scale hud at current resolution" );
@@ -94,7 +96,7 @@ static CVAR_DEFINE_AUTO( topcolor, "0", FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_FILTE
static CVAR_DEFINE_AUTO( bottomcolor, "0", FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_FILTERABLE, "player bottom color" ); static CVAR_DEFINE_AUTO( bottomcolor, "0", FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_FILTERABLE, "player bottom color" );
CVAR_DEFINE_AUTO( rate, "25000", FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_FILTERABLE, "player network rate" ); CVAR_DEFINE_AUTO( rate, "25000", FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_FILTERABLE, "player network rate" );
CVAR_DEFINE_AUTO( cl_ticket_generator, "revemu2013", FCVAR_ARCHIVE, "you wouldn't steal a car" ); CVAR_DEFINE_AUTO( cl_ticket_generator, "revemu2013", FCVAR_ARCHIVE|FCVAR_PRIVILEGED, "you wouldn't steal a car" );
static CVAR_DEFINE_AUTO( cl_advertise_engine_in_name, "1", FCVAR_ARCHIVE|FCVAR_PRIVILEGED, "add [Xash3D] to the nickname when connecting to GoldSrc servers" ); static CVAR_DEFINE_AUTO( cl_advertise_engine_in_name, "1", FCVAR_ARCHIVE|FCVAR_PRIVILEGED, "add [Xash3D] to the nickname when connecting to GoldSrc servers" );
static CVAR_DEFINE_AUTO( cl_log_outofband, "0", FCVAR_ARCHIVE, "log out of band messages, can be useful for server admins and for engine debugging" ); static CVAR_DEFINE_AUTO( cl_log_outofband, "0", FCVAR_ARCHIVE, "log out of band messages, can be useful for server admins and for engine debugging" );
static CVAR_DEFINE_AUTO( cl_autorecord, "0", 0, "automatically start recording a demo after joining the server" ); static CVAR_DEFINE_AUTO( cl_autorecord, "0", 0, "automatically start recording a demo after joining the server" );
@@ -195,6 +197,120 @@ void CL_SetCheatState( qboolean multiplayer, qboolean allow_cheats )
} }
} }
static resource_t *CL_AddResource( resourcetype_t type, const char *name, int size, qboolean bFatalIfMissing, int index )
{
resource_t *r = &cl.resourcelist[cl.num_resources];
if( cl.num_resources >= MAX_RESOURCES )
Host_Error( "Too many resources on client\n" );
cl.num_resources++;
Q_strncpy( r->szFileName, name, sizeof( r->szFileName ));
r->ucFlags |= bFatalIfMissing ? RES_FATALIFMISSING : 0;
r->nDownloadSize = size;
r->nIndex = index;
r->type = type;
return r;
}
static void CL_CreateResourceList( void )
{
char szFileName[MAX_OSPATH];
byte rgucMD5_hash[16] = { 0 };
HPAK_FlushHostQueue();
cl.num_resources = 0;
memset( rgucMD5_hash, 0, sizeof( rgucMD5_hash ));
ClearBits( cl_logoupdate.flags, FCVAR_CHANGED );
#if 1 // FIXME: deprecated, remove later
ClearBits( cl_logofile.flags, FCVAR_CHANGED );
ClearBits( cl_logocolor.flags, FCVAR_CHANGED );
ClearBits( cl_logoext.flags, FCVAR_CHANGED );
#endif
// sanitize cvar value
if( Q_strcmp( cl_logoext.string, "bmp" ) && Q_strcmp( cl_logoext.string, "png" ))
Cvar_DirectSet( &cl_logoext, "bmp" );
Q_snprintf( szFileName, sizeof( szFileName ), "logos/remapped.%s", cl_logoext.string );
if( cls.legacymode == PROTO_GOLDSRC )
{
CL_ConvertImageToWAD3( szFileName );
Q_strncpy( szFileName, "tempdecal.wad", sizeof( szFileName ));
}
file_t *fp = FS_Open( szFileName, "rb", true );
if( !fp )
return;
int nSize = FS_FileLength( fp );
if( nSize != 0 )
{
resource_t *pNewResource = CL_AddResource( t_decal, szFileName, nSize, false, 0 );
if( pNewResource )
{
MD5_HashFile( rgucMD5_hash, szFileName, NULL );
SetBits( pNewResource->ucFlags, RES_CUSTOM );
memcpy( pNewResource->rgucMD5_hash, rgucMD5_hash, 16 );
HPAK_AddLump( false, hpk_custom_file.string, pNewResource, NULL, fp );
}
}
FS_Close( fp );
}
/*
==================
CL_UpdateLogo
repackage the clan logo and upload it to the server
==================
*/
static void CL_UpdateLogo( void )
{
if( cls.state != ca_active )
return;
CL_CreateResourceList();
if( cl.num_resources == 0 )
return;
player_info_t *player = &cl.players[cl.playernum];
COM_ClearCustomizationList( &player->customdata, true );
for( int i = 0; i < cl.num_resources; i++ )
{
resource_t *pResource = &cl.resourcelist[i];
if( !COM_CreateCustomization( &player->customdata, pResource, cl.playernum, 0, NULL, NULL ))
Con_Printf( "Unable to create custom decal\n" );
}
CL_SendResourceList( cl.resourcelist, cl.num_resources );
}
static void CL_CheckLogoChanged( void )
{
if( FBitSet( cl_logoupdate.flags, FCVAR_CHANGED ))
{
CL_UpdateLogo();
return;
}
#if 1 // FIXME: deprecated, remove later
if( FBitSet( cl_logofile.flags | cl_logocolor.flags | cl_logoext.flags, FCVAR_CHANGED ))
{
CL_UpdateLogo();
return;
}
#endif
}
/* /*
=============== ===============
CL_CheckClientState CL_CheckClientState
@@ -213,6 +329,8 @@ static void CL_CheckClientState( void )
cls.changedemo = false; // changedemo is done cls.changedemo = false; // changedemo is done
cl.first_frame = true; // first rendering frame cl.first_frame = true; // first rendering frame
CL_UpdateLogo();
SCR_MakeLevelShot(); // make levelshot if needs SCR_MakeLevelShot(); // make levelshot if needs
Cvar_SetValue( "scr_loading", 0.0f ); // reset progress bar Cvar_SetValue( "scr_loading", 0.0f ); // reset progress bar
Netchan_ReportFlow( &cls.netchan ); Netchan_ReportFlow( &cls.netchan );
@@ -315,7 +433,6 @@ should be put at.
static float CL_LerpPoint( void ) static float CL_LerpPoint( void )
{ {
double f = cl_serverframetime(); double f = cl_serverframetime();
double frac;
if( f == 0.0 || cls.timedemo ) if( f == 0.0 || cls.timedemo )
{ {
@@ -332,7 +449,7 @@ static float CL_LerpPoint( void )
if( cl_interp.value <= 0.001 ) if( cl_interp.value <= 0.001 )
return 1.0f; return 1.0f;
frac = ( cl.time - cl.mtime[0] ) / cl_interp.value; double frac = ( cl.time - cl.mtime[0] ) / cl_interp.value;
return frac; return frac;
} }
@@ -346,20 +463,17 @@ Drift interpolation value (this is used for server unlag system)
*/ */
static int CL_DriftInterpolationAmount( int goal ) static int CL_DriftInterpolationAmount( int goal )
{ {
float fgoal, maxmove, diff; float fgoal = (float)goal / 1000.0f;
int msec;
fgoal = (float)goal / 1000.0f;
if( fgoal != cl.local.interp_amount ) if( fgoal != cl.local.interp_amount )
{ {
maxmove = host.frametime * 0.05; float maxmove = host.frametime * 0.05;
diff = fgoal - cl.local.interp_amount; float diff = fgoal - cl.local.interp_amount;
diff = bound( -maxmove, diff, maxmove ); diff = bound( -maxmove, diff, maxmove );
cl.local.interp_amount += diff; cl.local.interp_amount += diff;
} }
msec = cl.local.interp_amount * 1000.0f; int msec = cl.local.interp_amount * 1000.0f;
msec = bound( 0, msec, 100 ); msec = bound( 0, msec, 100 );
return msec; return msec;
@@ -420,14 +534,14 @@ CL_ComputePacketLoss
*/ */
static void CL_ComputePacketLoss( void ) static void CL_ComputePacketLoss( void )
{ {
int i, lost = 0; int lost = 0;
if( host.realtime < cls.packet_loss_recalc_time ) if( host.realtime < cls.packet_loss_recalc_time )
return; return;
cls.packet_loss_recalc_time = host.realtime + 1.0; cls.packet_loss_recalc_time = host.realtime + 1.0;
for( i = cls.netchan.incoming_sequence - CL_UPDATE_BACKUP + 1; i <= cls.netchan.incoming_sequence; i++ ) for( int i = cls.netchan.incoming_sequence - CL_UPDATE_BACKUP + 1; i <= cls.netchan.incoming_sequence; i++ )
{ {
if( cl.frames[i & CL_UPDATE_MASK].receivedtime == -1.0 ) if( cl.frames[i & CL_UPDATE_MASK].receivedtime == -1.0 )
lost++; lost++;
@@ -455,18 +569,15 @@ void CL_UpdateFrameLerp( void )
static void CL_FindInterpolatedAddAngle( float t, float *frac, pred_viewangle_t **prev, pred_viewangle_t **next ) static void CL_FindInterpolatedAddAngle( float t, float *frac, pred_viewangle_t **prev, pred_viewangle_t **next )
{ {
int i, i0, i1, imod; int imod = cl.angle_position - 1;
float at; int i0 = (imod + 1) & ANGLE_MASK;
int i1 = (imod + 0) & ANGLE_MASK;
imod = cl.angle_position - 1;
i0 = (imod + 1) & ANGLE_MASK;
i1 = (imod + 0) & ANGLE_MASK;
if( cl.predicted_angle[i0].starttime >= t ) if( cl.predicted_angle[i0].starttime >= t )
{ {
for( i = 0; i < ANGLE_BACKUP - 2; i++ ) for( int i = 0; i < ANGLE_BACKUP - 2; i++ )
{ {
at = cl.predicted_angle[imod & ANGLE_MASK].starttime; float at = cl.predicted_angle[imod & ANGLE_MASK].starttime;
if( at == 0.0f ) break; if( at == 0.0f ) break;
if( at < t ) if( at < t )
@@ -534,14 +645,12 @@ navigate around texture atlas
static qboolean CL_ProcessShowTexturesCmds( usercmd_t *cmd ) static qboolean CL_ProcessShowTexturesCmds( usercmd_t *cmd )
{ {
static int oldbuttons; static int oldbuttons;
int changed;
int released;
if( !r_showtextures.value || CL_IsDevOverviewMode( )) if( !r_showtextures.value || CL_IsDevOverviewMode( ))
return false; return false;
changed = (oldbuttons ^ cmd->buttons); int changed = (oldbuttons ^ cmd->buttons);
released = changed & (~cmd->buttons); int released = changed & (~cmd->buttons);
if( released & ( IN_RIGHT|IN_MOVERIGHT )) if( released & ( IN_RIGHT|IN_MOVERIGHT ))
Cvar_SetValue( "r_showtextures", r_showtextures.value + 1 ); Cvar_SetValue( "r_showtextures", r_showtextures.value + 1 );
@@ -613,17 +722,16 @@ tell the client.dll about player origin, angles, fov, etc
*/ */
static void CL_UpdateClientData( void ) static void CL_UpdateClientData( void )
{ {
client_data_t cdat;
if( cls.state != ca_active ) if( cls.state != ca_active )
return; return;
memset( &cdat, 0, sizeof( cdat ) ); client_data_t cdat =
{
VectorCopy( cl.viewangles, cdat.viewangles ); .viewangles = Vec3( cl.viewangles ),
VectorCopy( clgame.entities[cl.viewentity].origin, cdat.origin ); .origin = Vec3( clgame.entities[cl.viewentity].origin ),
cdat.iWeaponBits = cl.local.weapons; .iWeaponBits = cl.local.weapons,
cdat.fov = cl.local.scr_fov; .fov = cl.local.scr_fov,
};
if( clgame.dllFuncs.pfnUpdateClientData( &cdat, cl.time )) if( clgame.dllFuncs.pfnUpdateClientData( &cdat, cl.time ))
{ {
@@ -642,21 +750,18 @@ static void CL_CreateCmd( void )
{ {
usercmd_t nullcmd = { 0 }, *cmd; usercmd_t nullcmd = { 0 }, *cmd;
runcmd_t *pcmd; runcmd_t *pcmd;
qboolean active;
double accurate_ms;
vec3_t angles;
int input_override; int input_override;
int i, ms; int ms;
if( cls.state <= ca_connected || cls.state == ca_cinematic ) if( cls.state <= ca_connected || cls.state == ca_cinematic )
return; return;
// store viewangles in case it's will be freeze // store viewangles in case it's will be freeze
VectorCopy( cl.viewangles, angles ); vec3_t angles = Vec3( cl.viewangles );
input_override = 0; input_override = 0;
// fix rounding error and framerate depending player move // fix rounding error and framerate depending player move
accurate_ms = host.frametime * 1000; double accurate_ms = host.frametime * 1000;
ms = (int)accurate_ms; ms = (int)accurate_ms;
cl.frametime_remainder += accurate_ms - ms; // accumulate rounding error each frame cl.frametime_remainder += accurate_ms - ms; // accumulate rounding error each frame
@@ -677,7 +782,7 @@ static void CL_CreateCmd( void )
CL_SetSolidPlayers( cl.playernum ); CL_SetSolidPlayers( cl.playernum );
// message we are constructing. // message we are constructing.
i = cls.netchan.outgoing_sequence & CL_UPDATE_MASK; int i = cls.netchan.outgoing_sequence & CL_UPDATE_MASK;
pcmd = &cl.commands[i]; pcmd = &cl.commands[i];
if( !cls.demoplayback ) if( !cls.demoplayback )
@@ -695,7 +800,7 @@ static void CL_CreateCmd( void )
cmd = &nullcmd; cmd = &nullcmd;
} }
active = (( cls.signon == SIGNONS ) && !cl.paused && !cls.demoplayback ); qboolean active = (( cls.signon == SIGNONS ) && !cl.paused && !cls.demoplayback );
Platform_PreCreateMove(); Platform_PreCreateMove();
clgame.dllFuncs.CL_CreateMove( host.frametime, cmd, active ); clgame.dllFuncs.CL_CreateMove( host.frametime, cmd, active );
IN_EngineAppendMove( host.frametime, cmd, active ); IN_EngineAppendMove( host.frametime, cmd, active );
@@ -946,13 +1051,12 @@ CL_BeginUpload_f
*/ */
static void CL_BeginUpload_f( void ) static void CL_BeginUpload_f( void )
{ {
const char *name;
resource_t custResource; resource_t custResource;
byte *buf = NULL; byte *buf = NULL;
int size = 0; int size = 0;
byte md5[16]; byte md5[16];
name = Cmd_Argv( 1 ); const char *name = Cmd_Argv( 1 );
if( COM_StringEmptyOrNULL( name )) if( COM_StringEmptyOrNULL( name ))
return; return;
@@ -1038,9 +1142,8 @@ static void CL_GetCDKey( char *protinfo, size_t protinfosize )
byte hash[16] = { 0 }; byte hash[16] = { 0 };
MD5Context_t ctx = { 0 }; MD5Context_t ctx = { 0 };
char key[64]; char key[64];
int keylength;
keylength = Q_snprintf( key, sizeof( key ), "%u", COM_RandomLong( 0, 0x7ffffffe )); int keylength = Q_snprintf( key, sizeof( key ), "%u", COM_RandomLong( 0, 0x7ffffffe ));
MD5Init( &ctx ); MD5Init( &ctx );
MD5Update( &ctx, key, keylength ); MD5Update( &ctx, key, keylength );
@@ -1079,7 +1182,6 @@ static void CL_WriteSteamTicket( sizebuf_t *send )
void CL_SendGoldSrcConnectPacket( netadr_t adr, int challenge, const void *ticket, size_t ticketlen ) void CL_SendGoldSrcConnectPacket( netadr_t adr, int challenge, const void *ticket, size_t ticketlen )
{ {
const char *name;
sizebuf_t send; sizebuf_t send;
byte send_buf[2048]; byte send_buf[2048];
char protinfo[MAX_INFO_STRING]; char protinfo[MAX_INFO_STRING];
@@ -1090,7 +1192,7 @@ void CL_SendGoldSrcConnectPacket( netadr_t adr, int challenge, const void *ticke
Info_SetValueForKeyf( protinfo, "unique", sizeof( protinfo ), "%i", 0xffffffff ); Info_SetValueForKeyf( protinfo, "unique", sizeof( protinfo ), "%i", 0xffffffff );
Info_SetValueForKey( protinfo, "raw", "steam", sizeof( protinfo )); Info_SetValueForKey( protinfo, "raw", "steam", sizeof( protinfo ));
CL_GetCDKey( protinfo, sizeof( protinfo )); CL_GetCDKey( protinfo, sizeof( protinfo ));
name = Info_ValueForKey( cls.userinfo, "name" ); const char *name = Info_ValueForKey( cls.userinfo, "name" );
if( cl_advertise_engine_in_name.value && Q_strnicmp( name, "[Xash3D]", 8 )) if( cl_advertise_engine_in_name.value && Q_strnicmp( name, "[Xash3D]", 8 ))
Info_SetValueForKeyf( cls.userinfo, "name", sizeof( cls.userinfo ), "[Xash3D]%s", name ); Info_SetValueForKeyf( cls.userinfo, "name", sizeof( cls.userinfo ), "[Xash3D]%s", name );
@@ -1123,8 +1225,6 @@ static void CL_SendConnectPacket( connprotocol_t proto, int challenge )
{ {
char protinfo[MAX_INFO_STRING]; char protinfo[MAX_INFO_STRING];
netadr_t adr = { 0 }; netadr_t adr = { 0 };
int input_devices;
netadrtype_t adrtype;
protinfo[0] = 0; protinfo[0] = 0;
@@ -1135,11 +1235,11 @@ static void CL_SendConnectPacket( connprotocol_t proto, int challenge )
return; return;
} }
adrtype = NET_NetadrType( &adr ); netadrtype_t adrtype = NET_NetadrType( &adr );
if( adr.port == 0 ) adr.port = MSG_BigShort( PORT_SERVER ); if( adr.port == 0 ) adr.port = MSG_BigShort( PORT_SERVER );
input_devices = IN_CollectInputDevices(); int input_devices = IN_CollectInputDevices();
IN_LockInputDevices( adrtype != NA_LOOPBACK ? true : false ); IN_LockInputDevices( adrtype != NA_LOOPBACK ? true : false );
// GoldSrc doesn't need useragent string // GoldSrc doesn't need useragent string
@@ -1153,6 +1253,7 @@ static void CL_SendConnectPacket( connprotocol_t proto, int challenge )
} }
cls.broker_wait = false; cls.broker_wait = false;
cls.netchan_pending_cookie = 0;
if( proto == PROTO_GOLDSRC ) if( proto == PROTO_GOLDSRC )
{ {
@@ -1174,7 +1275,7 @@ static void CL_SendConnectPacket( connprotocol_t proto, int challenge )
else else
{ {
const char *qport = Cvar_VariableString( "net_qport" ); const char *qport = Cvar_VariableString( "net_qport" );
int extensions = adrtype == NA_LOOPBACK ? 0 : NET_EXT_SPLITSIZE; int extensions = adrtype == NA_LOOPBACK ? 0 : ( NET_EXT_SPLITSIZE | NET_EXT_NETCHAN_COOKIE );
string key; string key;
ID_GetMD5ForAddress( key, adr, sizeof( key )); ID_GetMD5ForAddress( key, adr, sizeof( key ));
@@ -1189,6 +1290,16 @@ static void CL_SendConnectPacket( connprotocol_t proto, int challenge )
Info_SetValueForKey( protinfo, "qport", qport, sizeof( protinfo )); Info_SetValueForKey( protinfo, "qport", qport, sizeof( protinfo ));
Info_SetValueForKeyf( protinfo, "ext", sizeof( protinfo ), "%d", extensions ); Info_SetValueForKeyf( protinfo, "ext", sizeof( protinfo ), "%d", extensions );
if( FBitSet( extensions, NET_EXT_NETCHAN_COOKIE ))
{
uint64_t a = COM_RandomLong( 0, 0xFFFF );
uint64_t b = COM_RandomLong( 0, 0xFFFF );
uint64_t c = COM_RandomLong( 0, 0xFFFF );
uint64_t d = COM_RandomLong( 0, 0xFFFF );
cls.netchan_pending_cookie = ( a << 48 ) | ( b << 32 ) | ( c << 16 ) | d;
Info_SetValueForKeyf( protinfo, "cookie", sizeof( protinfo ), "%016"PRIx64, cls.netchan_pending_cookie );
}
Netchan_OutOfBandPrint( NS_CLIENT, adr, C2S_CONNECT" %i %i \"%s\" \"%s\"\n", PROTOCOL_VERSION, challenge, protinfo, cls.userinfo ); Netchan_OutOfBandPrint( NS_CLIENT, adr, C2S_CONNECT" %i %i \"%s\" \"%s\"\n", PROTOCOL_VERSION, challenge, protinfo, cls.userinfo );
Con_Printf( "Trying to connect with modern protocol\n" ); Con_Printf( "Trying to connect with modern protocol\n" );
} }
@@ -1252,17 +1363,9 @@ Resend a connect message if the last one has timed out
static void CL_CheckForResend( void ) static void CL_CheckForResend( void )
{ {
netadr_t adr; netadr_t adr;
net_gai_state_t res;
float resend_time;
if( cls.internetservers_wait ) if( cls.internetservers_wait )
{ cls.internetservers_wait = NET_MasterQuery( 1, cls.internetservers_nat, cls.internetservers_customfilter );
cls.internetservers_wait = NET_MasterQuery(
cls.internetservers_key,
cls.internetservers_nat,
cls.internetservers_customfilter
);
}
// if the local server is running and we aren't then connect // if the local server is running and we aren't then connect
if( cls.state == ca_disconnected && SV_Active( )) if( cls.state == ca_disconnected && SV_Active( ))
@@ -1287,6 +1390,7 @@ static void CL_CheckForResend( void )
else if( cl_resend.value > CL_MAX_RESEND_TIME ) else if( cl_resend.value > CL_MAX_RESEND_TIME )
Cvar_DirectSetValue( &cl_resend, CL_MAX_RESEND_TIME ); Cvar_DirectSetValue( &cl_resend, CL_MAX_RESEND_TIME );
float resend_time;
if( cls.bandwidth_test.started && !cls.bandwidth_test.passed && !cls.bandwidth_test.failed ) if( cls.bandwidth_test.started && !cls.bandwidth_test.passed && !cls.bandwidth_test.failed )
resend_time = 2.0f; resend_time = 2.0f;
else else
@@ -1295,7 +1399,7 @@ static void CL_CheckForResend( void )
if(( host.realtime - cls.connect_time ) < resend_time ) if(( host.realtime - cls.connect_time ) < resend_time )
return; return;
res = NET_StringToAdrNB( cls.servername, &adr, false ); net_gai_state_t res = NET_StringToAdrNB( cls.servername, &adr, false );
if( res == NET_EAI_NONAME ) if( res == NET_EAI_NONAME )
{ {
@@ -1356,108 +1460,6 @@ static void CL_CheckForResend( void )
} }
} }
static resource_t *CL_AddResource( resourcetype_t type, const char *name, int size, qboolean bFatalIfMissing, int index )
{
resource_t *r = &cl.resourcelist[cl.num_resources];
if( cl.num_resources >= MAX_RESOURCES )
Host_Error( "Too many resources on client\n" );
cl.num_resources++;
Q_strncpy( r->szFileName, name, sizeof( r->szFileName ));
r->ucFlags |= bFatalIfMissing ? RES_FATALIFMISSING : 0;
r->nDownloadSize = size;
r->nIndex = index;
r->type = type;
return r;
}
static void CL_CreateResourceList( void )
{
char szFileName[MAX_OSPATH];
byte rgucMD5_hash[16] = { 0 };
resource_t *pNewResource;
int nSize;
file_t *fp;
HPAK_FlushHostQueue();
cl.num_resources = 0;
memset( rgucMD5_hash, 0, sizeof( rgucMD5_hash ));
ClearBits( cl_logofile.flags, FCVAR_CHANGED );
ClearBits( cl_logocolor.flags, FCVAR_CHANGED );
ClearBits( cl_logoext.flags, FCVAR_CHANGED );
// sanitize cvar value
if( Q_strcmp( cl_logoext.string, "bmp" ) && Q_strcmp( cl_logoext.string, "png" ))
Cvar_DirectSet( &cl_logoext, "bmp" );
Q_snprintf( szFileName, sizeof( szFileName ), "logos/remapped.%s", cl_logoext.string );
if( cls.legacymode == PROTO_GOLDSRC )
{
CL_ConvertImageToWAD3( szFileName );
Q_strncpy( szFileName, "tempdecal.wad", sizeof( szFileName ));
}
fp = FS_Open( szFileName, "rb", true );
if( !fp )
return;
nSize = FS_FileLength( fp );
if( nSize != 0 )
{
pNewResource = CL_AddResource( t_decal, szFileName, nSize, false, 0 );
if( pNewResource )
{
MD5_HashFile( rgucMD5_hash, szFileName, NULL );
SetBits( pNewResource->ucFlags, RES_CUSTOM );
memcpy( pNewResource->rgucMD5_hash, rgucMD5_hash, 16 );
HPAK_AddLump( false, hpk_custom_file.string, pNewResource, NULL, fp );
}
}
FS_Close( fp );
}
/*
==================
CL_CheckLogoChanged
==================
*/
static void CL_CheckLogoChanged( void )
{
player_info_t *player;
int i;
if( cls.state != ca_active )
return;
if( !FBitSet( cl_logofile.flags | cl_logocolor.flags | cl_logoext.flags, FCVAR_CHANGED ))
return;
CL_CreateResourceList();
if( cl.num_resources == 0 )
return;
player = &cl.players[cl.playernum];
COM_ClearCustomizationList( &player->customdata, true );
for( i = 0; i < cl.num_resources; i++ )
{
resource_t *pResource = &cl.resourcelist[i];
if( !COM_CreateCustomization( &player->customdata, pResource, cl.playernum, 0, NULL, NULL ))
Con_Printf( "Unable to create custom decal\n" );
}
CL_SendResourceList( cl.resourcelist, cl.num_resources );
}
static qboolean CL_StringToProtocol( const char *s, connprotocol_t *proto ) static qboolean CL_StringToProtocol( const char *s, connprotocol_t *proto )
{ {
if( !Q_stricmp( s, "current" ) || !Q_strcmp( s, "49" )) if( !Q_stricmp( s, "current" ) || !Q_strcmp( s, "49" ))
@@ -1533,7 +1535,6 @@ static void CL_Rcon_f( void )
char message[1024]; char message[1024];
sizebuf_t msg; sizebuf_t msg;
netadr_t to; netadr_t to;
int i;
if( COM_StringEmptyOrNULL( rcon_password.string )) if( COM_StringEmptyOrNULL( rcon_password.string ))
{ {
@@ -1565,7 +1566,7 @@ static void CL_Rcon_f( void )
MSG_WriteStringf( &msg, C2S_RCON" %s ", rcon_password.string ); MSG_WriteStringf( &msg, C2S_RCON" %s ", rcon_password.string );
MSG_SeekToBit( &msg, -8, SEEK_CUR ); MSG_SeekToBit( &msg, -8, SEEK_CUR );
for( i = 1; i < Cmd_Argc(); i++ ) for( int i = 1; i < Cmd_Argc(); i++ )
{ {
string command; string command;
@@ -1588,11 +1589,9 @@ CL_ClearState
*/ */
void CL_ClearState( void ) void CL_ClearState( void )
{ {
int i;
CL_ClearResourceLists(); CL_ClearResourceLists();
for( i = 0; i < MAX_CLIENTS; i++ ) for( int i = 0; i < MAX_CLIENTS; i++ )
COM_ClearCustomizationList( &cl.players[i].customdata, false ); COM_ClearCustomizationList( &cl.players[i].customdata, false );
S_StopAllSounds ( true ); S_StopAllSounds ( true );
@@ -1657,9 +1656,9 @@ static void CL_SendDisconnectMessage( connprotocol_t proto )
Netchan_TransmitBits( &cls.netchan, MSG_GetNumBitsWritten( &buf ), MSG_GetData( &buf )); Netchan_TransmitBits( &cls.netchan, MSG_GetNumBitsWritten( &buf ), MSG_GetData( &buf ));
} }
int CL_GetSplitSize( void ) size_t CL_GetSplitSize( void )
{ {
int splitsize = (int)cl_dlmax.value; size_t splitsize = (int)cl_dlmax.value;
if( !FBitSet( cls.extensions, NET_EXT_SPLITSIZE )) if( !FBitSet( cls.extensions, NET_EXT_SPLITSIZE ))
return 1400; return 1400;
@@ -1670,7 +1669,7 @@ int CL_GetSplitSize( void )
return FRAGMENT_DEFAULT_SIZE; return FRAGMENT_DEFAULT_SIZE;
} }
return (int)cl_dlmax.value; return splitsize;
} }
void CL_SetupNetchanForProtocol( connprotocol_t proto ) void CL_SetupNetchanForProtocol( connprotocol_t proto )
@@ -1692,10 +1691,19 @@ void CL_SetupNetchanForProtocol( connprotocol_t proto )
if( FBitSet( cls.extensions, NET_EXT_SPLITSIZE )) if( FBitSet( cls.extensions, NET_EXT_SPLITSIZE ))
Con_Reportf( "^2NET_EXT_SPLITSIZE enabled^7 (packet size is %d)\n", (int)cl_dlmax.value ); Con_Reportf( "^2NET_EXT_SPLITSIZE enabled^7 (packet size is %d)\n", (int)cl_dlmax.value );
if( FBitSet( cls.extensions, NET_EXT_NETCHAN_COOKIE ))
{
Con_Reportf( "^2NET_EXT_NETCHAN_COOKIE enabled^7\n" );
SetBits( flags, NETCHAN_USE_COOKIE );
}
break; break;
} }
Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableInteger( "net_qport" ), NULL, pfnBlockSize, flags ); Netchan_Setup( NS_CLIENT, &cls.netchan, net_from, Cvar_VariableInteger( "net_qport" ), NULL, pfnBlockSize, flags );
if( FBitSet( flags, NETCHAN_USE_COOKIE ))
Netchan_SetCookie( &cls.netchan, cls.netchan_pending_cookie );
} }
/* /*
@@ -1850,27 +1858,10 @@ static void CL_InternetServers_f( void )
cls.internetservers_nat = cl_nat.value != 0.0f; cls.internetservers_nat = cl_nat.value != 0.0f;
cls.internetservers_pending = true; cls.internetservers_pending = true;
cls.internetservers_key = COM_RandomLong( 0, 0xFFFFFFFF );
Q_strncpy( cls.internetservers_customfilter, Cmd_Argv( 1 ), sizeof( cls.internetservers_customfilter )); Q_strncpy( cls.internetservers_customfilter, Cmd_Argv( 1 ), sizeof( cls.internetservers_customfilter ));
cls.internetservers_wait = NET_MasterQuery( // the key is dead extension, keep for compatibility until we use UDP based master server protocol
cls.internetservers_key, cls.internetservers_wait = NET_MasterQuery( 1, cls.internetservers_nat, cls.internetservers_customfilter );
cls.internetservers_nat,
cls.internetservers_customfilter
);
}
static void CL_QueryServer( netadr_t adr, connprotocol_t proto )
{
switch( proto )
{
case PROTO_GOLDSRC:
Netchan_OutOfBand( NS_CLIENT, adr, sizeof( A2S_GOLDSRC_INFO ), A2S_GOLDSRC_INFO ); // includes null terminator!
break;
case PROTO_CURRENT:
Netchan_OutOfBandPrint( NS_CLIENT, adr, A2A_INFO" %i", PROTOCOL_VERSION );
break;
}
} }
static void CL_QueryServer_f( void ) static void CL_QueryServer_f( void )
@@ -1898,7 +1889,7 @@ static void CL_QueryServer_f( void )
if( !CL_StringToProtocol( Cmd_Argv( 2 ), &proto )) if( !CL_StringToProtocol( Cmd_Argv( 2 ), &proto ))
return; return;
CL_QueryServer( adr, proto ); NET_QueryServerByAddress( adr, proto );
} }
/* /*
@@ -1986,8 +1977,6 @@ all the keys and values must be ends with ^7
*/ */
static void CL_FixupColorStringsForInfoString( const char *in, char *out, size_t len ) static void CL_FixupColorStringsForInfoString( const char *in, char *out, size_t len )
{ {
qboolean hasPrefix = false;
qboolean endOfKeyVal = false;
int color = 7; int color = 7;
int count = 0; int count = 0;
@@ -2083,7 +2072,7 @@ static void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg )
UI_AddServerToList( from, infostring ); UI_AddServerToList( from, infostring );
} }
static void CL_ParseGoldSrcStatusMessage( netadr_t from, sizebuf_t *msg ) static void CL_ParseGoldSrcStatusMessage( netadr_t from, sizebuf_t *msg, qboolean legacy_format )
{ {
static char s[512+8]; static char s[512+8];
int p, numcl, maxcl, password, remaining, bots; int p, numcl, maxcl, password, remaining, bots;
@@ -2093,19 +2082,58 @@ static void CL_ParseGoldSrcStatusMessage( netadr_t from, sizebuf_t *msg )
// set to beginning but skip header // set to beginning but skip header
MSG_SeekToBit( msg, (sizeof( uint32_t ) + sizeof( uint8_t )) << 3, SEEK_SET ); MSG_SeekToBit( msg, (sizeof( uint32_t ) + sizeof( uint8_t )) << 3, SEEK_SET );
p = MSG_ReadByte( msg ); if( legacy_format )
Q_strncpy( host, MSG_ReadString( msg ), sizeof( host )); {
Q_strncpy( map, MSG_ReadString( msg ), sizeof( map )); string address;
Q_strncpy( gamedir, MSG_ReadString( msg ), sizeof( gamedir )); int mod;
MSG_ReadString( msg ); // game description
MSG_ReadShort( msg ); // app id p = MSG_ReadByte( msg );
numcl = MSG_ReadByte( msg ); Q_strncpy( address, MSG_ReadString( msg ), sizeof( address ));
maxcl = MSG_ReadByte( msg ); Q_strncpy( host, MSG_ReadString( msg ), sizeof( host ));
bots = MSG_ReadByte( msg ); // bots count Q_strncpy( map, MSG_ReadString( msg ), sizeof( map ));
MSG_ReadByte( msg ); // dedicated Q_strncpy( gamedir, MSG_ReadString( msg ), sizeof( gamedir ));
MSG_ReadByte( msg ); // operating system MSG_ReadString( msg ); // game description
password = MSG_ReadByte( msg ); numcl = MSG_ReadByte( msg );
Q_strncpy( version, MSG_ReadString( msg ), sizeof( version )); maxcl = MSG_ReadByte( msg );
MSG_ReadByte( msg ); // protocol version
MSG_ReadByte( msg ); // server type
MSG_ReadByte( msg ); // operating system
password = MSG_ReadByte( msg );
mod = MSG_ReadByte( msg ); // mod flag
if( mod == 1 )
{
MSG_ReadString( msg ); // mod URL
MSG_ReadString( msg ); // mod download URL
MSG_ReadLong( msg ); // mod version
MSG_ReadLong( msg ); // mod size
MSG_ReadByte( msg ); // mod type (SP/MP)
MSG_ReadByte( msg ); // custom DLL flag
Q_strncpy( version, MSG_ReadString( msg ), sizeof( version ));
bots = MSG_ReadByte( msg ); // bots count
}
else
{
Q_strncpy( version, MSG_ReadString( msg ), sizeof( version ));
bots = MSG_ReadByte( msg ); // bots count
}
}
else
{
p = MSG_ReadByte( msg );
Q_strncpy( host, MSG_ReadString( msg ), sizeof( host ));
Q_strncpy( map, MSG_ReadString( msg ), sizeof( map ));
Q_strncpy( gamedir, MSG_ReadString( msg ), sizeof( gamedir ));
MSG_ReadString( msg ); // game description
MSG_ReadShort( msg ); // app id
numcl = MSG_ReadByte( msg );
maxcl = MSG_ReadByte( msg );
bots = MSG_ReadByte( msg ); // bots count
MSG_ReadByte( msg ); // server type
MSG_ReadByte( msg ); // operating system
password = MSG_ReadByte( msg );
Q_strncpy( version, MSG_ReadString( msg ), sizeof( version ));
}
// sanity check // sanity check
if( maxcl > MAX_CLIENTS || numcl > MAX_CLIENTS || bots > MAX_CLIENTS || numcl > maxcl || bots > maxcl ) if( maxcl > MAX_CLIENTS || numcl > MAX_CLIENTS || bots > MAX_CLIENTS || numcl > maxcl || bots > maxcl )
@@ -2163,7 +2191,6 @@ static void CL_ParseNETInfoMessage( netadr_t from, const char *s )
int i, context, type; int i, context, type;
int errorBits = 0; int errorBits = 0;
const char *val; const char *val;
size_t slen;
context = Q_atoi( Cmd_Argv( 1 )); context = Q_atoi( Cmd_Argv( 1 ));
type = Q_atoi( Cmd_Argv( 2 )); type = Q_atoi( Cmd_Argv( 2 ));
@@ -2315,7 +2342,7 @@ CL_IsFromConnectingServer
Used for connectionless packets, when netchan may not be ready. Used for connectionless packets, when netchan may not be ready.
================= =================
*/ */
static qboolean CL_IsFromConnectingServer( netadr_t from ) qboolean CL_IsFromConnectingServer( netadr_t from )
{ {
return NET_IsLocalAddress( from ) || return NET_IsLocalAddress( from ) ||
NET_CompareAdr( cls.serveradr, from ); NET_CompareAdr( cls.serveradr, from );
@@ -2355,7 +2382,7 @@ static void CL_HandleTestPacket( netadr_t from, sizebuf_t *msg )
} }
// reading test buffer // reading test buffer
MSG_ReadBytes( msg, recv_buf, realsize ); MSG_ReadBytes( msg, recv_buf, sizeof( recv_buf ), realsize );
// procssing the CRC // procssing the CRC
CRC32_ProcessBuffer( &crcValue2, recv_buf, realsize ); CRC32_ProcessBuffer( &crcValue2, recv_buf, realsize );
@@ -2416,6 +2443,39 @@ static void CL_ClientConnect( connprotocol_t proto, const char *c, netadr_t from
return; return;
} }
if( cls.netchan_pending_cookie != 0 )
{
int server_extensions = Q_atoi( Info_ValueForKey( Cmd_Argv( 1 ), "ext" ));
if( FBitSet( server_extensions, NET_EXT_NETCHAN_COOKIE ))
{
const char *cookie_str = Info_ValueForKey( Cmd_Argv( 1 ), "cookie" );
if( Q_strlen( cookie_str ) != 16 )
{
Con_Reportf( S_WARN "%s: missing cookie echo from %s, ignoring (possible spoof)\n", __func__, NET_AdrToString( from ));
return;
}
byte buf[8];
COM_HexConvert( cookie_str, 16, buf );
uint64_t echoed = 0;
for( int i = 0; i < 8; i++ )
echoed = ( echoed << 8 ) | buf[i];
if( echoed != cls.netchan_pending_cookie )
{
Con_Reportf( S_WARN "%s: invalid cookie echo from %s, ignoring (possible spoof)\n", __func__, NET_AdrToString( from ));
return;
}
}
else
{
cls.netchan_pending_cookie = 0;
}
}
cls.build_num = 0; // not used in Xash3D protocols cls.build_num = 0; // not used in Xash3D protocols
cls.allow_cheats = Q_atoi( Info_ValueForKey( Cmd_Argv( 1 ), "cheats" )); cls.allow_cheats = Q_atoi( Info_ValueForKey( Cmd_Argv( 1 ), "cheats" ));
} }
@@ -2534,6 +2594,21 @@ static void CL_Reject( const char *c, const char *args, netadr_t from )
CL_Disconnect_f(); CL_Disconnect_f();
} }
/*
=================
CL_NotifyServerListResponse
=================
*/
void CL_NotifyServerListResponse( void )
{
if( !cls.internetservers_pending )
return;
UI_ResetPing();
cls.internetservers_pending = false;
}
static void CL_ServerList( netadr_t from, sizebuf_t *msg ) static void CL_ServerList( netadr_t from, sizebuf_t *msg )
{ {
connprotocol_t proto; connprotocol_t proto;
@@ -2544,25 +2619,13 @@ static void CL_ServerList( netadr_t from, sizebuf_t *msg )
return; return;
} }
// check the extra header
if( proto == PROTO_CURRENT ) if( proto == PROTO_CURRENT )
{ {
// dead extension
if( MSG_ReadByte( msg ) == 0x7f ) if( MSG_ReadByte( msg ) == 0x7f )
{ {
uint32_t key = MSG_ReadDword( msg ); MSG_ReadDword( msg ); // was key
MSG_ReadByte( msg ); // was reserved
if( cls.internetservers_key != key )
{
Con_Printf( S_WARN "unexpected server list packet from %s (invalid key)\n", NET_AdrToString( from ));
return;
}
MSG_ReadByte( msg ); // reserved byte
}
else
{
Con_Printf( S_WARN "invalid server list packet from %s (missing extra header)\n", NET_AdrToString( from ));
return;
} }
} }
@@ -2574,30 +2637,27 @@ static void CL_ServerList( netadr_t from, sizebuf_t *msg )
if( NET_NetadrType( &from ) == NA_IP6 ) // IPv6 master server only sends IPv6 addresses if( NET_NetadrType( &from ) == NA_IP6 ) // IPv6 master server only sends IPv6 addresses
{ {
MSG_ReadBytes( msg, addr, sizeof( addr )); MSG_ReadBytes( msg, addr, sizeof( addr ), sizeof( addr ));
NET_IP6BytesToNetadr( &servadr, addr ); NET_IP6BytesToNetadr( &servadr, addr );
NET_NetadrSetType( &servadr, NA_IP6 ); NET_NetadrSetType( &servadr, NA_IP6 );
} }
else else
{ {
MSG_ReadBytes( msg, servadr.ip, sizeof( servadr.ip )); // 4 bytes for IP MSG_ReadBytes( msg, servadr.ip, sizeof( servadr.ip ), sizeof( servadr.ip )); // 4 bytes for IP
NET_NetadrSetType( &servadr, NA_IP ); NET_NetadrSetType( &servadr, NA_IP );
} }
MSG_ReadBytes( msg, &servadr.port, sizeof( servadr.port )); // 2 bytes for Port, in network byte order
MSG_ReadBytes( msg, &servadr.port, sizeof( servadr.port ), sizeof( servadr.port )); // 2 bytes for Port, in network byte order
// list is ends here // list is ends here
if( !servadr.port ) if( !servadr.port )
break; break;
NET_Config( true, false ); // allow remote NET_Config( true, false ); // allow remote
CL_QueryServer( servadr, proto ); NET_QueryServerByAddress( servadr, proto );
} }
if( cls.internetservers_pending ) CL_NotifyServerListResponse();
{
UI_ResetPing();
cls.internetservers_pending = false;
}
} }
/* /*
@@ -2634,7 +2694,11 @@ static void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
} }
else if( c[0] == S2A_GOLDSRC_INFO ) else if( c[0] == S2A_GOLDSRC_INFO )
{ {
CL_ParseGoldSrcStatusMessage( from, msg ); CL_ParseGoldSrcStatusMessage( from, msg, false );
}
else if( c[0] == S2A_GOLDSRC_LEGACY_INFO )
{
CL_ParseGoldSrcStatusMessage( from, msg, true );
} }
else if( !Q_strcmp( c, A2A_NETINFO )) else if( !Q_strcmp( c, A2A_NETINFO ))
{ {
@@ -3428,6 +3492,7 @@ static void CL_InitLocal( void )
Cvar_RegisterVariable( &cl_logofile ); Cvar_RegisterVariable( &cl_logofile );
Cvar_RegisterVariable( &cl_logocolor ); Cvar_RegisterVariable( &cl_logocolor );
Cvar_RegisterVariable( &cl_logoext ); Cvar_RegisterVariable( &cl_logoext );
Cvar_RegisterVariable( &cl_logoupdate );
Cvar_RegisterVariable( &cl_logomaxdim ); Cvar_RegisterVariable( &cl_logomaxdim );
Cvar_RegisterVariable( &cl_test_bandwidth ); Cvar_RegisterVariable( &cl_test_bandwidth );
@@ -3552,11 +3617,11 @@ static void CL_InitLocal( void )
Cmd_AddCommand ("levelshot", CL_LevelShot_f, "same as \"screenshot\", used for create plaque images" ); Cmd_AddCommand ("levelshot", CL_LevelShot_f, "same as \"screenshot\", used for create plaque images" );
Cmd_AddCommand ("saveshot", CL_GenericShot_f, "used for create save previews with LoadGame menu" ); Cmd_AddCommand ("saveshot", CL_GenericShot_f, "used for create save previews with LoadGame menu" );
Cmd_AddCommand ("connect", CL_Connect_f, "connect to a server by hostname" ); Cmd_AddRestrictedCommand ("connect", CL_Connect_f, "connect to a server by hostname" );
Cmd_AddCommand ("reconnect", CL_Reconnect_f, "reconnect to current level" ); Cmd_AddCommand ("reconnect", CL_Reconnect_f, "reconnect to current level" );
Cmd_AddCommand ("retry", CL_Retry_f, "retry connection to last server" ); Cmd_AddCommand ("retry", CL_Retry_f, "retry connection to last server" );
Cmd_AddCommand ("rcon", CL_Rcon_f, "sends a command to the server console (rcon_password and rcon_address required)" ); Cmd_AddRestrictedCommand ("rcon", CL_Rcon_f, "sends a command to the server console (rcon_password and rcon_address required)" );
Cmd_AddCommand( "richpresence_gamemode", Cmd_Null_f, "compatibility command, does nothing" ); Cmd_AddCommand( "richpresence_gamemode", Cmd_Null_f, "compatibility command, does nothing" );
Cmd_AddCommand( "richpresence_update", Cmd_Null_f, "compatibility command, does nothing" ); Cmd_AddCommand( "richpresence_update", Cmd_Null_f, "compatibility command, does nothing" );
+21 -21
View File
@@ -118,8 +118,7 @@ static void NetGraph_InitColors( void )
byte mincolor[2][3]; byte mincolor[2][3];
byte maxcolor[2][3]; byte maxcolor[2][3];
float dc[2][3]; float dc[2][3];
int i, hfrac; int hfrac;
float f;
mincolor[0][0] = 63; mincolor[0][0] = 63;
mincolor[0][1] = 0; mincolor[0][1] = 0;
@@ -137,7 +136,7 @@ static void NetGraph_InitColors( void )
maxcolor[1][1] = 0; maxcolor[1][1] = 0;
maxcolor[1][2] = 0; maxcolor[1][2] = 0;
for( i = 0; i < 3; i++ ) for( int i = 0; i < 3; i++ )
{ {
dc[0][i] = (float)(maxcolor[0][i] - mincolor[0][i]); dc[0][i] = (float)(maxcolor[0][i] - mincolor[0][i]);
dc[1][i] = (float)(maxcolor[1][i] - mincolor[1][i]); dc[1][i] = (float)(maxcolor[1][i] - mincolor[1][i]);
@@ -145,8 +144,10 @@ static void NetGraph_InitColors( void )
hfrac = NETGRAPH_LERP_HEIGHT / 3; hfrac = NETGRAPH_LERP_HEIGHT / 3;
for( i = 0; i < NETGRAPH_LERP_HEIGHT; i++ ) for( int i = 0; i < NETGRAPH_LERP_HEIGHT; i++ )
{ {
float f;
if( i < hfrac ) if( i < hfrac )
{ {
f = (float)i / (float)hfrac; f = (float)i / (float)hfrac;
@@ -170,10 +171,9 @@ get frame data info, like chokes, packet losses, also update graph, packet and c
*/ */
static void NetGraph_GetFrameData( float *latency, int *latency_count ) static void NetGraph_GetFrameData( float *latency, int *latency_count )
{ {
int i, choke_count = 0, loss_count = 0; int choke_count = 0, loss_count = 0;
double newtime = Platform_DoubleTime(); double newtime = Platform_DoubleTime();
static double nexttime = 0; static double nexttime = 0;
float loss, choke;
*latency_count = 0; *latency_count = 0;
*latency = 0.0f; *latency = 0.0f;
@@ -185,7 +185,7 @@ static void NetGraph_GetFrameData( float *latency, int *latency_count )
nexttime = newtime + 0.05; nexttime = newtime + 0.05;
} }
for( i = cls.netchan.incoming_sequence - CL_UPDATE_BACKUP + 1; i <= cls.netchan.incoming_sequence; i++ ) for( int i = cls.netchan.incoming_sequence - CL_UPDATE_BACKUP + 1; i <= cls.netchan.incoming_sequence; i++ )
{ {
frame_t *f = cl.frames + ( i & CL_UPDATE_MASK ); frame_t *f = cl.frames + ( i & CL_UPDATE_MASK );
struct packet_latency_t *p = netstat_packet_latency + ( i & NET_TIMINGS_MASK ); struct packet_latency_t *p = netstat_packet_latency + ( i & NET_TIMINGS_MASK );
@@ -228,7 +228,7 @@ static void NetGraph_GetFrameData( float *latency, int *latency_count )
if( maxmsgbytes > 1000 ) if( maxmsgbytes > 1000 )
maxmsgbytes = 1000; maxmsgbytes = 1000;
for( i = cls.netchan.outgoing_sequence - CL_UPDATE_BACKUP + 1; i <= cls.netchan.outgoing_sequence; i++ ) for( int i = cls.netchan.outgoing_sequence - CL_UPDATE_BACKUP + 1; i <= cls.netchan.outgoing_sequence; i++ )
{ {
netstat_cmdinfo[i & NET_TIMINGS_MASK].cmd_lerp = cl.commands[i & CL_UPDATE_MASK].frame_lerp; netstat_cmdinfo[i & NET_TIMINGS_MASK].cmd_lerp = cl.commands[i & CL_UPDATE_MASK].frame_lerp;
netstat_cmdinfo[i & NET_TIMINGS_MASK].sent = cl.commands[i & CL_UPDATE_MASK].heldback ? false : true; netstat_cmdinfo[i & NET_TIMINGS_MASK].sent = cl.commands[i & CL_UPDATE_MASK].heldback ? false : true;
@@ -236,11 +236,11 @@ static void NetGraph_GetFrameData( float *latency, int *latency_count )
} }
// packet loss // packet loss
loss = 100.0f * (float)loss_count / CL_UPDATE_BACKUP; float loss = 100.0f * (float)loss_count / CL_UPDATE_BACKUP;
packet_loss = PACKETLOSS_AVG_FRAC * packet_loss + ( 1.0f - PACKETLOSS_AVG_FRAC ) * loss; packet_loss = PACKETLOSS_AVG_FRAC * packet_loss + ( 1.0f - PACKETLOSS_AVG_FRAC ) * loss;
// packet choke // packet choke
choke = 100.0f * (float)choke_count / CL_UPDATE_BACKUP; float choke = 100.0f * (float)choke_count / CL_UPDATE_BACKUP;
packet_choke = PACKETCHOKE_AVG_FRAC * packet_choke + ( 1.0f - PACKETCHOKE_AVG_FRAC ) * choke; packet_choke = PACKETCHOKE_AVG_FRAC * packet_choke + ( 1.0f - PACKETCHOKE_AVG_FRAC ) * choke;
} }
@@ -252,14 +252,13 @@ NetGraph_DrawTimes
*/ */
static void NetGraph_DrawTimes( wrect_t rect, int x, int w ) static void NetGraph_DrawTimes( wrect_t rect, int x, int w )
{ {
int i, j, extrap_point = NETGRAPH_LERP_HEIGHT / 3, a, h; int extrap_point = NETGRAPH_LERP_HEIGHT / 3;
rgba_t colors = { 0.9 * 255, 0.9 * 255, 0.7 * 255, 255 };
wrect_t fill; wrect_t fill;
for( a = 0; a < w; a++ ) for( int a = 0; a < w; a++ )
{ {
i = ( cls.netchan.outgoing_sequence - a ) & NET_TIMINGS_MASK; int i = ( cls.netchan.outgoing_sequence - a ) & NET_TIMINGS_MASK;
h = Q_min(( netstat_cmdinfo[i].cmd_lerp / 3.0f ) * NETGRAPH_LERP_HEIGHT, net_graphheight.value * 0.7f); int h = Q_min(( netstat_cmdinfo[i].cmd_lerp / 3.0f ) * NETGRAPH_LERP_HEIGHT, net_graphheight.value * 0.7f);
fill.left = x + w - a - 1; fill.left = x + w - a - 1;
fill.right = fill.bottom = 1; fill.right = fill.bottom = 1;
@@ -278,7 +277,7 @@ static void NetGraph_DrawTimes( wrect_t rect, int x, int w )
start = (h - 1); start = (h - 1);
} }
for( j = start; j < h; j++ ) for( int j = start; j < h; j++ )
{ {
int color = NETGRAPH_NET_COLORS + j + extrap_point; int color = NETGRAPH_NET_COLORS + j + extrap_point;
color = Q_min( color, ARRAYSIZE( netcolors ) - 1 ); color = Q_min( color, ARRAYSIZE( netcolors ) - 1 );
@@ -297,7 +296,7 @@ static void NetGraph_DrawTimes( wrect_t rect, int x, int w )
if( !net_graphsolid.value ) if( !net_graphsolid.value )
h = 1; h = 1;
for( j = 0; j < h; j++ ) for( int j = 0; j < h; j++ )
{ {
int color = NETGRAPH_NET_COLORS + j + oldh; int color = NETGRAPH_NET_COLORS + j + oldh;
color = Q_min( color, ARRAYSIZE( netcolors ) - 1 ); color = Q_min( color, ARRAYSIZE( netcolors ) - 1 );
@@ -496,15 +495,16 @@ NetGraph_DrawDataUsage
*/ */
static void NetGraph_DrawDataUsage( int x, int y, int w, int graphtype ) static void NetGraph_DrawDataUsage( int x, int y, int w, int graphtype )
{ {
int a, i, h, lastvalidh = 0, ping; int lastvalidh = 0;
int pingheight = net_graphheight.value - NETGRAPH_LERP_HEIGHT - 2; int pingheight = net_graphheight.value - NETGRAPH_LERP_HEIGHT - 2;
wrect_t fill = { 0 }; wrect_t fill = { 0 };
byte color[4]; byte color[4];
for( a = 0; a < w; a++ ) for( int a = 0; a < w; a++ )
{ {
i = (cls.netchan.incoming_sequence - a) & NET_TIMINGS_MASK; int ping;
h = netstat_packet_latency[i].latency; int i = (cls.netchan.incoming_sequence - a) & NET_TIMINGS_MASK;
int h = netstat_packet_latency[i].latency;
NetGraph_ColorForHeight( &netstat_packet_latency[i], color, &ping ); NetGraph_ColorForHeight( &netstat_packet_latency[i], color, &ping );
+7 -13
View File
@@ -43,7 +43,6 @@ return true if equal
*/ */
static qboolean CL_CmpStudioTextures( int numtexs, mstudiotexture_t *p1, remap_info_t *remap ) static qboolean CL_CmpStudioTextures( int numtexs, mstudiotexture_t *p1, remap_info_t *remap )
{ {
int i;
mstudiotexture_t *p2; mstudiotexture_t *p2;
if( !p1 ) // no textures if( !p1 ) // no textures
@@ -60,7 +59,7 @@ static qboolean CL_CmpStudioTextures( int numtexs, mstudiotexture_t *p1, remap_i
p2 = remap->ptexture; p2 = remap->ptexture;
for( i = 0; i < numtexs; i++, p1++, p2++ ) for( int i = 0; i < numtexs; i++, p1++, p2++ )
{ {
if( p1->flags & STUDIO_NF_COLORMAP ) if( p1->flags & STUDIO_NF_COLORMAP )
continue; // colormaps always has different indexes continue; // colormaps always has different indexes
@@ -116,18 +115,17 @@ static void CL_DuplicateTexture( cl_entity_t *entity, model_t *model, mstudiotex
const char *name; const char *name;
texture_t *tx = NULL; texture_t *tx = NULL;
char texname[128]; char texname[128];
int i, index;
size_t size; size_t size;
byte paletteBackup[768]; byte paletteBackup[768];
byte *raw, *pal; byte *raw, *pal;
int index = ptexture->index;
// save off the real texture index // save off the real texture index
index = ptexture->index;
name = ref.dllFuncs.GL_TextureName( index ); name = ref.dllFuncs.GL_TextureName( index );
Q_snprintf( texname, sizeof( texname ), "#%i_%s", entity->curstate.number, name + 1 ); Q_snprintf( texname, sizeof( texname ), "#%i_%s", entity->curstate.number, name + 1 );
// search for pixels // search for pixels
for( i = 0; i < model->numtextures; i++ ) for( int i = 0; i < model->numtextures; i++ )
{ {
tx = model->textures[i]; tx = model->textures[i];
if( tx->gl_texturenum == index ) if( tx->gl_texturenum == index )
@@ -161,7 +159,7 @@ static void CL_UpdateStudioTexture( cl_entity_t *entity, mstudiotexture_t *ptext
texture_t *tx = NULL; texture_t *tx = NULL;
char texname[128], name[128], mdlname[128]; char texname[128], name[128], mdlname[128];
const char *origtexname; const char *origtexname;
int i, index; int index;
size_t size; size_t size;
byte paletteBackup[768]; byte paletteBackup[768];
byte *raw, *pal; byte *raw, *pal;
@@ -180,7 +178,7 @@ static void CL_UpdateStudioTexture( cl_entity_t *entity, mstudiotexture_t *ptext
return; // couldn't find texture return; // couldn't find texture
// search for pixels // search for pixels
for( i = 0; i < entity->model->numtextures; i++ ) for( int i = 0; i < entity->model->numtextures; i++ )
{ {
tx = entity->model->textures[i]; tx = entity->model->textures[i];
if( tx->gl_texturenum == index ) if( tx->gl_texturenum == index )
@@ -259,12 +257,10 @@ Release remap info per entity
*/ */
static void CL_FreeRemapInfo( remap_info_t *info ) static void CL_FreeRemapInfo( remap_info_t *info )
{ {
int i;
Assert( info != NULL ); Assert( info != NULL );
// release all colormap texture copies // release all colormap texture copies
for( i = 0; i < info->numtextures; i++ ) for( int i = 0; i < info->numtextures; i++ )
{ {
if( info->ptexture != NULL ) if( info->ptexture != NULL )
{ {
@@ -438,11 +434,9 @@ Release all remap infos
*/ */
void CL_ClearAllRemaps( void ) void CL_ClearAllRemaps( void )
{ {
int i;
if( clgame.remap_info ) if( clgame.remap_info )
{ {
for( i = 0; i < clgame.maxRemapInfos; i++ ) for( int i = 0; i < clgame.maxRemapInfos; i++ )
{ {
if( clgame.remap_info[i] ) if( clgame.remap_info[i] )
CL_FreeRemapInfo( clgame.remap_info[i] ); CL_FreeRemapInfo( clgame.remap_info[i] );
+17 -28
View File
@@ -50,9 +50,7 @@ SCR_DrawFPS
*/ */
void SCR_DrawFPS( int height ) void SCR_DrawFPS( int height )
{ {
float calc;
rgba_t color; rgba_t color;
double newtime;
static double nexttime = 0, lasttime = 0; static double nexttime = 0, lasttime = 0;
static double framerate = 0; static double framerate = 0;
static int framecount = 0; static int framecount = 0;
@@ -73,7 +71,7 @@ void SCR_DrawFPS( int height )
default: return; default: return;
} }
newtime = Platform_DoubleTime(); double newtime = Platform_DoubleTime();
if( newtime >= nexttime ) if( newtime >= nexttime )
{ {
framerate = framecount / (newtime - lasttime); framerate = framecount / (newtime - lasttime);
@@ -82,7 +80,7 @@ void SCR_DrawFPS( int height )
framecount = 0; framecount = 0;
} }
calc = framerate; float calc = framerate;
framecount++; framecount++;
if( calc < 1.0f ) if( calc < 1.0f )
@@ -120,15 +118,13 @@ Draw local player position, angles and velocity
void SCR_DrawPos( void ) void SCR_DrawPos( void )
{ {
static char msg[MAX_SYSPATH]; static char msg[MAX_SYSPATH];
float speed;
cl_entity_t *ent;
rgba_t color; rgba_t color;
if( cls.state != ca_active || !cl_showpos.value || cl.background ) if( cls.state != ca_active || !cl_showpos.value || cl.background )
return; return;
ent = CL_GetLocalPlayer(); cl_entity_t *ent = CL_GetLocalPlayer();
speed = VectorLength( cl.simvel ); float speed = VectorLength( cl.simvel );
Q_snprintf( msg, MAX_SYSPATH, Q_snprintf( msg, MAX_SYSPATH,
"pos: %.2f %.2f %.2f\n" "pos: %.2f %.2f %.2f\n"
@@ -153,23 +149,22 @@ SCR_DrawEnts
void SCR_DrawEnts( void ) void SCR_DrawEnts( void )
{ {
rgba_t color = { 255, 255, 255, 255 }; rgba_t color = { 255, 255, 255, 255 };
int i;
if( cls.state != ca_active || !cl_showents.value || ( cl.maxclients > 1 && !cls.demoplayback )) if( cls.state != ca_active || !cl_showents.value || ( cl.maxclients > 1 && !cls.demoplayback ))
return; return;
// this probably better hook CL_AddVisibleEntities // this probably better hook CL_AddVisibleEntities
// as entities might get added by client.dll // as entities might get added by client.dll
for( i = 0; i < clgame.maxEntities; i++ ) for( int i = 0; i < clgame.maxEntities; i++ )
{ {
const cl_entity_t *ent = &clgame.entities[i]; const cl_entity_t *ent = &clgame.entities[i];
string msg; string msg;
vec3_t screen, pos; vec3_t screen;
if( ent->curstate.messagenum != cl.parsecount ) if( ent->curstate.messagenum != cl.parsecount )
continue; continue;
VectorCopy( ent->origin, pos ); vec3_t pos = Vec3( ent->origin );
if( ent->model != NULL ) if( ent->model != NULL )
{ {
@@ -241,12 +236,12 @@ void SCR_DrawUserCmd( void )
}; };
cl_font_t *font = Con_GetCurFont(); cl_font_t *font = Con_GetCurFont();
string msg; string msg;
int i, ypos = 100; int ypos = 100;
if( cls.state != ca_active || !cl_showcmd.value ) if( cls.state != ca_active || !cl_showcmd.value )
return; return;
for( i = 0; i < ARRAYSIZE( buttons ); i++ ) for( int i = 0; i < ARRAYSIZE( buttons ); i++ )
{ {
rgba_t rgba; rgba_t rgba;
@@ -280,7 +275,6 @@ same as r_speeds but for network channel
void SCR_NetSpeeds( void ) void SCR_NetSpeeds( void )
{ {
static char msg[MAX_SYSPATH]; static char msg[MAX_SYSPATH];
int x, y;
float time = cl.mtime[0]; float time = cl.mtime[0];
static int min_svfps = 100; static int min_svfps = 100;
static int max_svfps = 0; static int max_svfps = 0;
@@ -326,8 +320,8 @@ void SCR_NetSpeeds( void )
Q_memprint( cls.netchan.total_sended ) Q_memprint( cls.netchan.total_sended )
); );
x = refState.width - 320 * font->scale; int x = refState.width - 320 * font->scale;
y = 384; int y = 384;
MakeRGBA( color, 255, 255, 255, 255 ); MakeRGBA( color, 255, 255, 255, 255 );
CL_DrawString( x, y, msg, color, font, FONT_DRAW_RESETCOLORONLF ); CL_DrawString( x, y, msg, color, font, FONT_DRAW_RESETCOLORONLF );
@@ -347,12 +341,11 @@ void SCR_RSpeeds( void )
if( ref.dllFuncs.R_SpeedsMessage( msg, sizeof( msg ))) if( ref.dllFuncs.R_SpeedsMessage( msg, sizeof( msg )))
{ {
int x, y;
rgba_t color; rgba_t color;
cl_font_t *font = Con_GetCurFont(); cl_font_t *font = Con_GetCurFont();
x = refState.width - 340 * font->scale; int x = refState.width - 340 * font->scale;
y = 64; int y = 64;
MakeRGBA( color, 255, 255, 255, 255 ); MakeRGBA( color, 255, 255, 255, 255 );
CL_DrawString( x, y, msg, color, font, FONT_DRAW_RESETCOLORONLF ); CL_DrawString( x, y, msg, color, font, FONT_DRAW_RESETCOLORONLF );
@@ -386,11 +379,10 @@ static void VID_WriteOverviewScript( void )
{ {
ref_overview_t *ov = &clgame.overView; ref_overview_t *ov = &clgame.overView;
string filename; string filename;
file_t *f;
Q_snprintf( filename, sizeof( filename ), "overviews/%s.txt", clgame.mapname ); Q_snprintf( filename, sizeof( filename ), "overviews/%s.txt", clgame.mapname );
f = FS_Open( filename, "w", false ); file_t *f = FS_Open( filename, "w", false );
if( !f ) if( !f )
{ {
Con_Printf( S_ERROR "%s: can't open %s for write\n", __func__, filename ); Con_Printf( S_ERROR "%s: can't open %s for write\n", __func__, filename );
@@ -586,7 +578,6 @@ void SCR_TileClear( void )
{ {
int i, top, bottom, left, right, texnum; int i, top, bottom, left, right, texnum;
dirty_t clear; dirty_t clear;
float tw, th;
if( likely( scr_viewsize.value >= 120 )) if( likely( scr_viewsize.value >= 120 ))
return; // full screen rendering return; // full screen rendering
@@ -634,8 +625,8 @@ void SCR_TileClear( void )
left = clgame.viewport[0]; left = clgame.viewport[0];
right = left + clgame.viewport[2] - 1; right = left + clgame.viewport[2] - 1;
tw = REF_GET_PARM( PARM_TEX_SRC_WIDTH, texnum ); float tw = REF_GET_PARM( PARM_TEX_SRC_WIDTH, texnum );
th = REF_GET_PARM( PARM_TEX_SRC_HEIGHT, texnum ); float th = REF_GET_PARM( PARM_TEX_SRC_HEIGHT, texnum );
if( clear.y1 < top ) if( clear.y1 < top )
{ {
@@ -749,11 +740,9 @@ void SCR_LoadCreditsFont( void )
// copy font size for client.dll // copy font size for client.dll
if( success ) if( success )
{ {
int i;
clgame.scrInfo.iCharHeight = cls.creditsFont.charHeight; clgame.scrInfo.iCharHeight = cls.creditsFont.charHeight;
for( i = 0; i < ARRAYSIZE( cls.creditsFont.charWidths ); i++ ) for( int i = 0; i < ARRAYSIZE( cls.creditsFont.charWidths ); i++ )
clgame.scrInfo.charWidths[i] = cls.creditsFont.charWidths[i]; clgame.scrInfo.charWidths[i] = cls.creditsFont.charWidths[i];
} }
else Con_DPrintf( S_ERROR "failed to load HUD font\n" ); else Con_DPrintf( S_ERROR "failed to load HUD font\n" );
+5 -6
View File
@@ -27,10 +27,10 @@ GNU General Public License for more details.
static void CL_AdjustSprayDimensions( int *width, int *height ) static void CL_AdjustSprayDimensions( int *width, int *height )
{ {
float aspect = (float)( *width ) / (float)( *height ); float aspect = (float)( *width ) / (float)( *height );
int h, w;
for( h = (( *height ) / 16 ) * 16; h >= 16; h -= 16 ) for( int h = (( *height ) / 16 ) * 16; h >= 16; h -= 16 )
{ {
w = ((int)( h * aspect ) / 16 ) * 16; int w = ((int)( h * aspect ) / 16 ) * 16;
if( w < 16 || w > *width ) if( w < 16 || w > *width )
continue; continue;
@@ -107,7 +107,6 @@ qboolean CL_ConvertImageToWAD3( const char *filename )
{ {
qboolean is_indexed_img; qboolean is_indexed_img;
int width = 0, height = 0; int width = 0, height = 0;
int i;
byte palette[SPRAY_PALETTE_BYTES]; byte palette[SPRAY_PALETTE_BYTES];
byte *indexed = NULL; byte *indexed = NULL;
rgbdata_t *image = NULL; rgbdata_t *image = NULL;
@@ -122,7 +121,7 @@ qboolean CL_ConvertImageToWAD3( const char *filename )
if( is_indexed_img ) if( is_indexed_img )
{ {
// copy bmp palette from rgba to rgb // copy bmp palette from rgba to rgb
for( i = 0; i < 256; ++i ) for( int i = 0; i < 256; ++i )
{ {
palette[i * 3 + 0] = image->palette[i * 4 + 0]; // R palette[i * 3 + 0] = image->palette[i * 4 + 0]; // R
palette[i * 3 + 1] = image->palette[i * 4 + 1]; // G palette[i * 3 + 1] = image->palette[i * 4 + 1]; // G
@@ -141,7 +140,7 @@ qboolean CL_ConvertImageToWAD3( const char *filename )
// set index 255 for transparent pixels in rgba images // set index 255 for transparent pixels in rgba images
if( image->type == PF_RGBA_32 ) if( image->type == PF_RGBA_32 )
{ {
for( i = 0; i < width * height; ++i ) for( int i = 0; i < width * height; ++i )
{ {
if( image->buffer[i * 4 + 3] <= SPRAY_ALPHA_THRESHOLD ) if( image->buffer[i * 4 + 3] <= SPRAY_ALPHA_THRESHOLD )
quant->buffer[i] = 255; quant->buffer[i] = 255;
+13 -21
View File
@@ -33,11 +33,7 @@ assume pModel is valid
mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw ) mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw )
{ {
msprite_t *psprite; msprite_t *psprite;
mspritegroup_t *pspritegroup;
mspriteframe_t *pspriteframe = NULL; mspriteframe_t *pspriteframe = NULL;
float *pintervals, fullinterval;
int i, numframes;
float targettime;
if( !pModel ) if( !pModel )
return NULL; return NULL;
@@ -61,14 +57,15 @@ mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw )
} }
else if( psprite->frames[frame].type == SPR_GROUP ) else if( psprite->frames[frame].type == SPR_GROUP )
{ {
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr; mspritegroup_t *pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
pintervals = pspritegroup->intervals; float *pintervals = pspritegroup->intervals;
numframes = pspritegroup->numframes; int numframes = pspritegroup->numframes;
fullinterval = pintervals[numframes - 1]; float fullinterval = pintervals[numframes - 1];
// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values
// are positive, so we don't have to worry about division by zero // are positive, so we don't have to worry about division by zero
targettime = cl.time - ((int)( cl.time / fullinterval )) * fullinterval; float targettime = cl.time - ((int)( cl.time / fullinterval )) * fullinterval;
int i;
for( i = 0; i < ( numframes - 1 ); i++ ) for( i = 0; i < ( numframes - 1 ); i++ )
{ {
@@ -82,7 +79,7 @@ mspriteframe_t *R_GetSpriteFrame( const model_t *pModel, int frame, float yaw )
int angleframe = (int)( Q_rint(( refState.viewangles[1] - yaw + 45.0f ) / 360 * 8 ) - 4 ) & 7; int angleframe = (int)( Q_rint(( refState.viewangles[1] - yaw + 45.0f ) / 360 * 8 ) - 4 ) & 7;
// e.g. doom-style sprite monsters // e.g. doom-style sprite monsters
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr; mspritegroup_t *pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
pspriteframe = pspritegroup->frames[angleframe]; pspriteframe = pspritegroup->frames[angleframe];
} }
@@ -203,16 +200,13 @@ static const byte *Mod_SpriteLoadFrame( model_t *mod, const void *pin, mspritefr
static const byte *Mod_SpriteLoadGroup( model_t *mod, const void *pin, mspriteframe_t **ppframe, int framenum ) static const byte *Mod_SpriteLoadGroup( model_t *mod, const void *pin, mspriteframe_t **ppframe, int framenum )
{ {
const dspritegroup_t *pingroup; const dspritegroup_t *pingroup = (const dspritegroup_t *)pin;
mspritegroup_t *pspritegroup; mspritegroup_t *pspritegroup;
const dspriteinterval_t *pin_intervals; const dspriteinterval_t *pin_intervals;
float *poutintervals; float *poutintervals;
int i, groupsize, numframes; int groupsize, numframes = pingroup->numframes;
const void *ptemp; const void *ptemp;
pingroup = (const dspritegroup_t *)pin;
numframes = pingroup->numframes;
groupsize = sizeof( mspritegroup_t ) + ( numframes - 1 ) * sizeof( pspritegroup->frames[0] ); groupsize = sizeof( mspritegroup_t ) + ( numframes - 1 ) * sizeof( pspritegroup->frames[0] );
pspritegroup = Mem_Calloc( mod->mempool, groupsize ); pspritegroup = Mem_Calloc( mod->mempool, groupsize );
pspritegroup->numframes = numframes; pspritegroup->numframes = numframes;
@@ -222,7 +216,7 @@ static const byte *Mod_SpriteLoadGroup( model_t *mod, const void *pin, mspritefr
poutintervals = Mem_Calloc( mod->mempool, numframes * sizeof( float )); poutintervals = Mem_Calloc( mod->mempool, numframes * sizeof( float ));
pspritegroup->intervals = poutintervals; pspritegroup->intervals = poutintervals;
for( i = 0; i < numframes; i++ ) for( int i = 0; i < numframes; i++ )
{ {
*poutintervals = pin_intervals->interval; *poutintervals = pin_intervals->interval;
if( *poutintervals <= 0.0f ) if( *poutintervals <= 0.0f )
@@ -232,7 +226,7 @@ static const byte *Mod_SpriteLoadGroup( model_t *mod, const void *pin, mspritefr
} }
ptemp = (const void *)pin_intervals; ptemp = (const void *)pin_intervals;
for( i = 0; i < numframes; i++ ) for( int i = 0; i < numframes; i++ )
{ {
ptemp = Mod_SpriteLoadFrame( mod, ptemp, &pspritegroup->frames[i], framenum * 10 + i ); ptemp = Mod_SpriteLoadFrame( mod, ptemp, &pspritegroup->frames[i], framenum * 10 + i );
} }
@@ -330,13 +324,12 @@ void Mod_SpriteLoadTextures( model_t *mod, const void *buffer )
void Mod_SpriteUnloadTextures( void *data ) void Mod_SpriteUnloadTextures( void *data )
{ {
msprite_t *psprite = data; msprite_t *psprite = data;
int i;
if( !data ) if( !data )
return; return;
// release all textures // release all textures
for( i = 0; i < psprite->numframes; i++ ) for( int i = 0; i < psprite->numframes; i++ )
{ {
if( !psprite->frames[i].frameptr ) if( !psprite->frames[i].frameptr )
continue; continue;
@@ -348,9 +341,8 @@ void Mod_SpriteUnloadTextures( void *data )
else else
{ {
mspritegroup_t *pspritegroup = (mspritegroup_t *)psprite->frames[i].frameptr; mspritegroup_t *pspritegroup = (mspritegroup_t *)psprite->frames[i].frameptr;
int j;
for( j = 0; j < pspritegroup->numframes; j++ ) for( int j = 0; j < pspritegroup->numframes; j++ )
{ {
if( pspritegroup->frames[j] ) if( pspritegroup->frames[j] )
ref.dllFuncs.GL_FreeTexture( pspritegroup->frames[j]->gl_texturenum ); ref.dllFuncs.GL_FreeTexture( pspritegroup->frames[j]->gl_texturenum );
+8 -10
View File
@@ -45,7 +45,7 @@ GNU General Public License for more details.
#define SBRK_CONNECT_RETRY_DELAY 5.0 #define SBRK_CONNECT_RETRY_DELAY 5.0
#define SBRK_TICKET_SIZE_MAX 2048 #define SBRK_TICKET_SIZE_MAX 2048
static CVAR_DEFINE_AUTO( cl_steam_broker_addr, "127.0.0.1:27420", FCVAR_ARCHIVE, "address of steam broker instance" ); static CVAR_DEFINE_AUTO( cl_steam_broker_addr, "127.0.0.1:27420", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "address of steam broker instance" );
typedef enum typedef enum
{ {
@@ -220,7 +220,7 @@ static qboolean SteamBroker_ProcessFrame( void )
// verify frame header // verify frame header
char header[SBRK_FRAME_HEADER_SIZE]; char header[SBRK_FRAME_HEADER_SIZE];
if( !MSG_ReadBytes( &sb, header, SBRK_FRAME_HEADER_SIZE )) if( !MSG_ReadBytes( &sb, header, sizeof( header ), SBRK_FRAME_HEADER_SIZE ))
return false; return false;
if( memcmp( header, SBRK_FRAME_HEADER, SBRK_FRAME_HEADER_SIZE ) != 0 ) if( memcmp( header, SBRK_FRAME_HEADER, SBRK_FRAME_HEADER_SIZE ) != 0 )
@@ -237,7 +237,7 @@ static qboolean SteamBroker_ProcessFrame( void )
return false; // need more data return false; // need more data
char response_header[SBRK_RESPONSE_HEADER_SIZE]; char response_header[SBRK_RESPONSE_HEADER_SIZE];
if( MSG_ReadBytes( &sb, response_header, SBRK_RESPONSE_HEADER_SIZE )) if( MSG_ReadBytes( &sb, response_header, sizeof( response_header ), SBRK_RESPONSE_HEADER_SIZE ))
{ {
if( memcmp( response_header, SBRK_RESPONSE_HEADER, SBRK_RESPONSE_HEADER_SIZE ) == 0 ) if( memcmp( response_header, SBRK_RESPONSE_HEADER, SBRK_RESPONSE_HEADER_SIZE ) == 0 )
{ {
@@ -249,7 +249,7 @@ static qboolean SteamBroker_ProcessFrame( void )
else else
{ {
uint64_t steam_id; uint64_t steam_id;
MSG_ReadBytes( &sb, &steam_id, sizeof( steam_id )); MSG_ReadBytes( &sb, &steam_id, sizeof( steam_id ), sizeof( steam_id ));
uint32_t ticket_size = MSG_ReadDword( &sb ); uint32_t ticket_size = MSG_ReadDword( &sb );
uint8_t ticket_data[SBRK_TICKET_SIZE_MAX]; uint8_t ticket_data[SBRK_TICKET_SIZE_MAX];
@@ -257,7 +257,7 @@ static qboolean SteamBroker_ProcessFrame( void )
{ {
Con_Printf( S_ERROR "%s: ticket size exceeds limit (%u)\n", __func__, ticket_size ); Con_Printf( S_ERROR "%s: ticket size exceeds limit (%u)\n", __func__, ticket_size );
} }
else if( MSG_ReadBytes( &sb, ticket_data, ticket_size )) else if( MSG_ReadBytes( &sb, ticket_data, sizeof( ticket_data ), ticket_size ))
{ {
Con_Printf( "%s: SteamID: %"PRIu64", ticket: [%d, %d, %d, %d...]\n", __func__, steam_id, ticket_data[0], ticket_data[1], ticket_data[2], ticket_data[3] ); Con_Printf( "%s: SteamID: %"PRIu64", ticket: [%d, %d, %d, %d...]\n", __func__, steam_id, ticket_data[0], ticket_data[1], ticket_data[2], ticket_data[3] );
@@ -355,7 +355,7 @@ static void SteamBroker_UpdateIdle( void )
} }
} }
void SteamBroker_AnnounceGameStart( const char *gamedir ) static void SteamBroker_AnnounceGameStart( const char *gamedir )
{ {
if( Q_stricmp( cl_ticket_generator.string, "steam" ) != 0 ) if( Q_stricmp( cl_ticket_generator.string, "steam" ) != 0 )
return; return;
@@ -371,7 +371,7 @@ void SteamBroker_AnnounceGameStart( const char *gamedir )
SteamBroker_SendFrame( buf, len ); SteamBroker_SendFrame( buf, len );
} }
void SteamBroker_AnnounceGameShutdown( void ) static void SteamBroker_AnnounceGameShutdown( void )
{ {
if( Q_stricmp( cl_ticket_generator.string, "steam" ) != 0 ) if( Q_stricmp( cl_ticket_generator.string, "steam" ) != 0 )
return; return;
@@ -395,9 +395,7 @@ static void SteamBroker_UpdateConnecting( void )
FD_ZERO( &writefds ); FD_ZERO( &writefds );
FD_SET( broker.socket, &writefds ); FD_SET( broker.socket, &writefds );
struct timeval tv; struct timeval tv = { 0 };
tv.tv_sec = 0;
tv.tv_usec = 0;
#if XASH_WIN32 #if XASH_WIN32
int select_result = select( 0, NULL, &writefds, NULL, &tv ); int select_result = select( 0, NULL, &writefds, NULL, &tv );
+79 -132
View File
@@ -120,21 +120,20 @@ void CL_AddClientResources( void )
{ {
const char *snd; const char *snd;
char filepath[MAX_QPATH]; char filepath[MAX_QPATH];
int i;
// don't request resources from localhost or in quake-compatibility mode // don't request resources from localhost or in quake-compatibility mode
if( cl.maxclients <= 1 || Host_IsQuakeCompatible( )) if( cl.maxclients <= 1 || Host_IsQuakeCompatible( ))
return; return;
// check sprites first // check sprites first
for( i = 0; i < ARRAYSIZE( cl_default_sprites ); i++ ) for( int i = 0; i < ARRAYSIZE( cl_default_sprites ); i++ )
{ {
if( !FS_FileExists( cl_default_sprites[i], false )) if( !FS_FileExists( cl_default_sprites[i], false ))
CL_AddClientResource( cl_default_sprites[i], t_model ); CL_AddClientResource( cl_default_sprites[i], t_model );
} }
// then check sounds // then check sounds
for( i = 0; ( snd = SoundList_Get( BouncePlayerShell, i )); i++ ) for( int i = 0; ( snd = SoundList_Get( BouncePlayerShell, i )); i++ )
{ {
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd ); Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
@@ -142,7 +141,7 @@ void CL_AddClientResources( void )
CL_AddClientResource( snd, t_sound ); CL_AddClientResource( snd, t_sound );
} }
for( i = 0; ( snd = SoundList_Get( BounceWeaponShell, i )); i++ ) for( int i = 0; ( snd = SoundList_Get( BounceWeaponShell, i )); i++ )
{ {
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd ); Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
@@ -150,7 +149,7 @@ void CL_AddClientResources( void )
CL_AddClientResource( snd, t_sound ); CL_AddClientResource( snd, t_sound );
} }
for( i = 0; ( snd = SoundList_Get( Explode, i )); i++ ) for( int i = 0; ( snd = SoundList_Get( Explode, i )); i++ )
{ {
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd ); Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
@@ -159,7 +158,7 @@ void CL_AddClientResources( void )
} }
#if 0 // ric sounds was precached by server-side #if 0 // ric sounds was precached by server-side
for( i = 0; ( snd = SoundList_Get( Ricochet, i )); i++ ) for( int i = 0; ( snd = SoundList_Get( Ricochet, i )); i++ )
{ {
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd ); Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
@@ -177,11 +176,9 @@ CL_ClearTempEnts
*/ */
static void CL_ClearTempEnts( void ) static void CL_ClearTempEnts( void )
{ {
int i;
if( !cl_tempents ) return; if( !cl_tempents ) return;
for( i = 0; i < GI->max_tents - 1; i++ ) for( int i = 0; i < GI->max_tents - 1; i++ )
{ {
cl_tempents[i].next = &cl_tempents[i+1]; cl_tempents[i].next = &cl_tempents[i+1];
cl_tempents[i].entity.trivial_accept = INVALID_HANDLE; cl_tempents[i].entity.trivial_accept = INVALID_HANDLE;
@@ -270,14 +267,12 @@ play collide sound
*/ */
static void CL_TempEntPlaySound( TEMPENTITY *pTemp, float damp ) static void CL_TempEntPlaySound( TEMPENTITY *pTemp, float damp )
{ {
float fvol;
const char *soundname = NULL; const char *soundname = NULL;
qboolean isshellcasing = false; qboolean isshellcasing = false;
int zvel;
Assert( pTemp != NULL ); Assert( pTemp != NULL );
fvol = 0.8f; float fvol = 0.8f;
switch( pTemp->hitSound ) switch( pTemp->hitSound )
{ {
@@ -315,7 +310,7 @@ static void CL_TempEntPlaySound( TEMPENTITY *pTemp, float damp )
if( !soundname ) if( !soundname )
return; return;
zvel = abs( pTemp->entity.baseline.origin[2] ); int zvel = abs( pTemp->entity.baseline.origin[2] );
// only play one out of every n // only play one out of every n
if( isshellcasing ) if( isshellcasing )
@@ -333,7 +328,6 @@ static void CL_TempEntPlaySound( TEMPENTITY *pTemp, float damp )
if( damp > 0.0f ) if( damp > 0.0f )
{ {
int pitch; int pitch;
sound_t handle;
if( isshellcasing ) if( isshellcasing )
fvol *= Q_min( 1.0f, ((float)zvel) / 350.0f ); fvol *= Q_min( 1.0f, ((float)zvel) / 350.0f );
@@ -343,7 +337,7 @@ static void CL_TempEntPlaySound( TEMPENTITY *pTemp, float damp )
pitch = COM_RandomLong( 95, 105 ); pitch = COM_RandomLong( 95, 105 );
else pitch = PITCH_NORM; else pitch = PITCH_NORM;
handle = S_RegisterSound( soundname ); sound_t handle = S_RegisterSound( soundname );
S_StartSound( pTemp->entity.origin, -(pTemp - cl_tempents), CHAN_BODY, handle, fvol, ATTN_NORM, pitch, SND_STOP_LOOPING ); S_StartSound( pTemp->entity.origin, -(pTemp - cl_tempents), CHAN_BODY, handle, fvol, ATTN_NORM, pitch, SND_STOP_LOOPING );
} }
} }
@@ -571,15 +565,14 @@ void GAME_EXPORT R_FizzEffect( cl_entity_t *ent, int modelIndex, int density )
{ {
const float base_time = cl.time - 0.1f; const float base_time = cl.time - 0.1f;
model_t *mod = CL_ModelHandle( modelIndex ); model_t *mod = CL_ModelHandle( modelIndex );
vec3_t volume, mins, maxs; vec3_t volume;
vec2_t speed; vec2_t speed;
int i;
if( !ent || !ent->model || !modelIndex || !mod ) if( !ent || !ent->model || !modelIndex || !mod )
return; return;
VectorCopy( ent->model->mins, mins ); vec3_t mins = Vec3( ent->model->mins );
VectorCopy( ent->model->maxs, maxs ); vec3_t maxs = Vec3( ent->model->maxs );
if( ent->angles[1] != 0.0f ) if( ent->angles[1] != 0.0f )
{ {
@@ -592,12 +585,11 @@ void GAME_EXPORT R_FizzEffect( cl_entity_t *ent, int modelIndex, int density )
VectorSubtract( maxs, mins, volume ); VectorSubtract( maxs, mins, volume );
for( i = 0; i <= density; i++ ) for( int i = 0; i <= density; i++ )
{ {
TEMPENTITY *tent; TEMPENTITY *tent;
vec3_t origin; vec3_t origin = Vec3( mins );
VectorCopy( mins, origin );
origin[0] += COM_RandomLong( 0, (int)volume[0] - 1 ); origin[0] += COM_RandomLong( 0, (int)volume[0] - 1 );
origin[1] += COM_RandomLong( 0, (int)volume[1] - 1 ); origin[1] += COM_RandomLong( 0, (int)volume[1] - 1 );
@@ -628,16 +620,13 @@ Create bubbles
void GAME_EXPORT R_Bubbles( const vec3_t mins, const vec3_t maxs, float height, int modelIndex, int count, float speed ) void GAME_EXPORT R_Bubbles( const vec3_t mins, const vec3_t maxs, float height, int modelIndex, int count, float speed )
{ {
TEMPENTITY *pTemp; TEMPENTITY *pTemp;
float sine, cosine;
float angle, zspeed;
vec3_t origin; vec3_t origin;
model_t *mod; model_t *mod;
int i;
if(( mod = CL_ModelHandle( modelIndex )) == NULL ) if(( mod = CL_ModelHandle( modelIndex )) == NULL )
return; return;
for ( i = 0; i < count; i++ ) for( int i = 0; i < count; i++ )
{ {
origin[0] = COM_RandomLong( mins[0], maxs[0] ); origin[0] = COM_RandomLong( mins[0], maxs[0] );
origin[1] = COM_RandomLong( mins[1], maxs[1] ); origin[1] = COM_RandomLong( mins[1], maxs[1] );
@@ -649,10 +638,11 @@ void GAME_EXPORT R_Bubbles( const vec3_t mins, const vec3_t maxs, float height,
pTemp->x = origin[0]; pTemp->x = origin[0];
pTemp->y = origin[1]; pTemp->y = origin[1];
angle = COM_RandomFloat( -M_PI, M_PI ); float sine, cosine;
float angle = COM_RandomFloat( -M_PI, M_PI );
SinCos( angle, &sine, &cosine ); SinCos( angle, &sine, &cosine );
zspeed = COM_RandomLong( 80, 140 ); float zspeed = COM_RandomLong( 80, 140 );
VectorSet( pTemp->entity.baseline.origin, speed * cosine, speed * sine, zspeed ); VectorSet( pTemp->entity.baseline.origin, speed * cosine, speed * sine, zspeed );
pTemp->die = cl.time + ((height - (origin[2] - mins[2])) / zspeed) - 0.1f; pTemp->die = cl.time + ((height - (origin[2] - mins[2])) / zspeed) - 0.1f;
pTemp->entity.curstate.frame = COM_RandomLong( 0, pTemp->frameMax ); pTemp->entity.curstate.frame = COM_RandomLong( 0, pTemp->frameMax );
@@ -674,18 +664,15 @@ Create bubble trail
void GAME_EXPORT R_BubbleTrail( const vec3_t start, const vec3_t end, float height, int modelIndex, int count, float speed ) void GAME_EXPORT R_BubbleTrail( const vec3_t start, const vec3_t end, float height, int modelIndex, int count, float speed )
{ {
TEMPENTITY *pTemp; TEMPENTITY *pTemp;
float sine, cosine, zspeed;
float dist, angle;
vec3_t origin; vec3_t origin;
model_t *mod; model_t *mod;
int i;
if(( mod = CL_ModelHandle( modelIndex )) == NULL ) if(( mod = CL_ModelHandle( modelIndex )) == NULL )
return; return;
for( i = 0; i < count; i++ ) for( int i = 0; i < count; i++ )
{ {
dist = COM_RandomFloat( 0, 1.0 ); float dist = COM_RandomFloat( 0, 1.0 );
VectorLerp( start, dist, end, origin ); VectorLerp( start, dist, end, origin );
pTemp = CL_TempEntAlloc( origin, mod ); pTemp = CL_TempEntAlloc( origin, mod );
if( !pTemp ) return; if( !pTemp ) return;
@@ -694,10 +681,11 @@ void GAME_EXPORT R_BubbleTrail( const vec3_t start, const vec3_t end, float heig
pTemp->x = origin[0]; pTemp->x = origin[0];
pTemp->y = origin[1]; pTemp->y = origin[1];
angle = COM_RandomFloat( -M_PI, M_PI ); float sine, cosine;
float angle = COM_RandomFloat( -M_PI, M_PI );
SinCos( angle, &sine, &cosine ); SinCos( angle, &sine, &cosine );
zspeed = COM_RandomLong( 80, 140 ); float zspeed = COM_RandomLong( 80, 140 );
VectorSet( pTemp->entity.baseline.origin, speed * cosine, speed * sine, zspeed ); VectorSet( pTemp->entity.baseline.origin, speed * cosine, speed * sine, zspeed );
pTemp->die = cl.time + ((height - (origin[2] - start[2])) / zspeed) - 0.1f; pTemp->die = cl.time + ((height - (origin[2] - start[2])) / zspeed) - 0.1f;
pTemp->entity.curstate.frame = COM_RandomLong( 0, pTemp->frameMax ); pTemp->entity.curstate.frame = COM_RandomLong( 0, pTemp->frameMax );
@@ -719,7 +707,6 @@ Attaches entity to player
void GAME_EXPORT R_AttachTentToPlayer( int client, int modelIndex, float zoffset, float life ) void GAME_EXPORT R_AttachTentToPlayer( int client, int modelIndex, float zoffset, float life )
{ {
TEMPENTITY *pTemp; TEMPENTITY *pTemp;
vec3_t position;
cl_entity_t *pClient; cl_entity_t *pClient;
model_t *pModel; model_t *pModel;
@@ -734,7 +721,7 @@ void GAME_EXPORT R_AttachTentToPlayer( int client, int modelIndex, float zoffset
if(( pModel = CL_ModelHandle( modelIndex )) == NULL ) if(( pModel = CL_ModelHandle( modelIndex )) == NULL )
return; return;
VectorCopy( pClient->origin, position ); vec3_t position = Vec3( pClient->origin );
position[2] += zoffset; position[2] += zoffset;
pTemp = CL_TempEntAllocHigh( position, pModel ); pTemp = CL_TempEntAllocHigh( position, pModel );
@@ -848,11 +835,9 @@ Do muzzleflash
void GAME_EXPORT R_MuzzleFlash( const vec3_t pos, int type ) void GAME_EXPORT R_MuzzleFlash( const vec3_t pos, int type )
{ {
TEMPENTITY *pTemp; TEMPENTITY *pTemp;
int index;
float scale;
index = ( type % 10 ) % MAX_MUZZLEFLASH; int index = ( type % 10 ) % MAX_MUZZLEFLASH;
scale = ( type / 10 ) * 0.1f; float scale = ( type / 10 ) * 0.1f;
if( scale == 0.0f ) scale = 0.5f; if( scale == 0.0f ) scale = 0.5f;
if( !cl_sprite_muzzleflash[index] ) if( !cl_sprite_muzzleflash[index] )
@@ -887,20 +872,16 @@ and some blood drops. This is high-priority tent
void GAME_EXPORT R_BloodSprite( const vec3_t org, int colorIndex, int modelIndex, int modelIndex2, float size ) void GAME_EXPORT R_BloodSprite( const vec3_t org, int colorIndex, int modelIndex, int modelIndex2, float size )
{ {
model_t *pModel, *pModel2; model_t *pModel, *pModel2;
int impactindex;
int spatterindex;
int i, splatter;
TEMPENTITY *pTemp; TEMPENTITY *pTemp;
vec3_t pos;
colorIndex += COM_RandomLong( 1, 3 ); colorIndex += COM_RandomLong( 1, 3 );
impactindex = colorIndex; int impactindex = colorIndex;
spatterindex = colorIndex - 1; int spatterindex = colorIndex - 1;
// validate the model first // validate the model first
if(( pModel = CL_ModelHandle( modelIndex )) != NULL ) if(( pModel = CL_ModelHandle( modelIndex )) != NULL )
{ {
VectorCopy( org, pos ); vec3_t pos = Vec3( org );
pos[2] += COM_RandomFloat( 2.0f, 4.0f ); // make offset from ground (snarks issues) pos[2] += COM_RandomFloat( 2.0f, 4.0f ); // make offset from ground (snarks issues)
// large, single blood sprite is a high-priority tent // large, single blood sprite is a high-priority tent
@@ -926,9 +907,9 @@ void GAME_EXPORT R_BloodSprite( const vec3_t org, int colorIndex, int modelIndex
// validate the model first // validate the model first
if(( pModel2 = CL_ModelHandle( modelIndex2 )) != NULL ) if(( pModel2 = CL_ModelHandle( modelIndex2 )) != NULL )
{ {
splatter = size + ( COM_RandomLong( 1, 8 ) + COM_RandomLong( 1, 8 )); int splatter = size + ( COM_RandomLong( 1, 8 ) + COM_RandomLong( 1, 8 ));
for( i = 0; i < splatter; i++ ) for( int i = 0; i < splatter; i++ )
{ {
// create blood drips // create blood drips
if(( pTemp = CL_TempEntAlloc( org, pModel2 )) != NULL ) if(( pTemp = CL_TempEntAlloc( org, pModel2 )) != NULL )
@@ -973,13 +954,11 @@ void GAME_EXPORT R_BreakModel( const vec3_t pos, const vec3_t size, const vec3_t
{ {
TEMPENTITY *pTemp; TEMPENTITY *pTemp;
model_t *pmodel; model_t *pmodel;
char type;
int i, j;
if(( pmodel = CL_ModelHandle( modelIndex )) == NULL ) if(( pmodel = CL_ModelHandle( modelIndex )) == NULL )
return; return;
type = flags & BREAK_TYPEMASK; char type = flags & BREAK_TYPEMASK;
if( count == 0 ) if( count == 0 )
{ {
@@ -990,9 +969,10 @@ void GAME_EXPORT R_BreakModel( const vec3_t pos, const vec3_t size, const vec3_t
// limit to 100 pieces // limit to 100 pieces
if( count > 100 ) count = 100; if( count > 100 ) count = 100;
for( i = 0; i < count; i++ ) for( int i = 0; i < count; i++ )
{ {
vec3_t vecSpot; vec3_t vecSpot;
int j;
for( j = 0; j < 32; j++ ) for( j = 0; j < 32; j++ )
{ {
@@ -1209,14 +1189,12 @@ apply params for exploding sprite
*/ */
void GAME_EXPORT R_Sprite_Explode( TEMPENTITY *pTemp, float scale, int flags ) void GAME_EXPORT R_Sprite_Explode( TEMPENTITY *pTemp, float scale, int flags )
{ {
qboolean noadditive, drawalpha, rotate;
if( !pTemp ) if( !pTemp )
return; return;
noadditive = FBitSet( flags, TE_EXPLFLAG_NOADDITIVE ); qboolean noadditive = FBitSet( flags, TE_EXPLFLAG_NOADDITIVE );
drawalpha = FBitSet( flags, TE_EXPLFLAG_DRAWALPHA ); qboolean drawalpha = FBitSet( flags, TE_EXPLFLAG_DRAWALPHA );
rotate = FBitSet( flags, TE_EXPLFLAG_ROTATE ); qboolean rotate = FBitSet( flags, TE_EXPLFLAG_ROTATE );
pTemp->entity.curstate.scale = scale; pTemp->entity.curstate.scale = scale;
pTemp->entity.baseline.origin[2] = 8.0f; pTemp->entity.baseline.origin[2] = 8.0f;
@@ -1242,11 +1220,9 @@ apply params for smoke sprite
*/ */
void GAME_EXPORT R_Sprite_Smoke( TEMPENTITY *pTemp, float scale ) void GAME_EXPORT R_Sprite_Smoke( TEMPENTITY *pTemp, float scale )
{ {
int iColor;
if( !pTemp ) return; if( !pTemp ) return;
iColor = COM_RandomLong( 20, 35 ); int iColor = COM_RandomLong( 20, 35 );
pTemp->entity.curstate.rendermode = kRenderTransAlpha; pTemp->entity.curstate.rendermode = kRenderTransAlpha;
pTemp->entity.curstate.renderfx = kRenderFxNone; pTemp->entity.curstate.renderfx = kRenderFxNone;
pTemp->entity.baseline.origin[2] = 30; pTemp->entity.baseline.origin[2] = 30;
@@ -1262,7 +1238,6 @@ static void R_Spray_Generic( const char *func, const vec3_t pos, const vec3_t di
model_t *mod = CL_ModelHandle( modelIndex ); model_t *mod = CL_ModelHandle( modelIndex );
float noise = spread / 100.0f; float noise = spread / 100.0f;
float znoise = noise * 1.5f; float znoise = noise * 1.5f;
int i;
znoise = Q_min( 1.0f, znoise ); znoise = Q_min( 1.0f, znoise );
@@ -1272,10 +1247,9 @@ static void R_Spray_Generic( const char *func, const vec3_t pos, const vec3_t di
return; return;
} }
for( i = 0; i < count; i++ ) for( int i = 0; i < count; i++ )
{ {
TEMPENTITY *tent = CL_TempEntAlloc( pos, mod ); TEMPENTITY *tent = CL_TempEntAlloc( pos, mod );
float rand_speed;
vec3_t noise_vec, vout; vec3_t noise_vec, vout;
if( !tent ) if( !tent )
@@ -1290,7 +1264,7 @@ static void R_Spray_Generic( const char *func, const vec3_t pos, const vec3_t di
noise_vec[0] = COM_RandomFloat( -noise, noise ); noise_vec[0] = COM_RandomFloat( -noise, noise );
noise_vec[1] = COM_RandomFloat( -noise, noise ); noise_vec[1] = COM_RandomFloat( -noise, noise );
noise_vec[2] = COM_RandomFloat( 0.0f, znoise ); noise_vec[2] = COM_RandomFloat( 0.0f, znoise );
rand_speed = COM_RandomFloat( speed * 0.8f, speed * 1.2f ); float rand_speed = COM_RandomFloat( speed * 0.8f, speed * 1.2f );
VectorAdd( dir, noise_vec, vout ); VectorAdd( dir, noise_vec, vout );
VectorScale( vout, rand_speed, tent->entity.baseline.origin ); VectorScale( vout, rand_speed, tent->entity.baseline.origin );
@@ -1361,7 +1335,6 @@ void GAME_EXPORT R_Sprite_Trail( int type, vec3_t start, vec3_t end, int modelIn
TEMPENTITY *pTemp; TEMPENTITY *pTemp;
vec3_t delta, dir; vec3_t delta, dir;
model_t *pmodel; model_t *pmodel;
int i;
if(( pmodel = CL_ModelHandle( modelIndex )) == NULL ) if(( pmodel = CL_ModelHandle( modelIndex )) == NULL )
return; return;
@@ -1371,7 +1344,7 @@ void GAME_EXPORT R_Sprite_Trail( int type, vec3_t start, vec3_t end, int modelIn
amp /= 256.0f; amp /= 256.0f;
for( i = 0; i < count; i++ ) for( int i = 0; i < count; i++ )
{ {
vec3_t pos, vel; vec3_t pos, vel;
@@ -1412,9 +1385,7 @@ void GAME_EXPORT R_FunnelSprite( const vec3_t org, int modelIndex, int reverse )
{ {
TEMPENTITY *pTemp; TEMPENTITY *pTemp;
vec3_t dir, dest; vec3_t dir, dest;
float dist, vel;
model_t *pmodel; model_t *pmodel;
int i, j;
if(( pmodel = CL_ModelHandle( modelIndex )) == NULL ) if(( pmodel = CL_ModelHandle( modelIndex )) == NULL )
{ {
@@ -1422,9 +1393,9 @@ void GAME_EXPORT R_FunnelSprite( const vec3_t org, int modelIndex, int reverse )
return; return;
} }
for( i = -8; i < 8; i++ ) for( int i = -8; i < 8; i++ )
{ {
for( j = -8; j < 8; j++ ) for( int j = -8; j < 8; j++ )
{ {
pTemp = CL_TempEntAlloc( org, pmodel ); pTemp = CL_TempEntAlloc( org, pmodel );
if( !pTemp ) return; if( !pTemp ) return;
@@ -1451,9 +1422,9 @@ void GAME_EXPORT R_FunnelSprite( const vec3_t org, int modelIndex, int reverse )
pTemp->entity.curstate.framerate = COM_RandomFloat( 0.1f, 0.4f ); pTemp->entity.curstate.framerate = COM_RandomFloat( 0.1f, 0.4f );
pTemp->flags = FTENT_ROTATE|FTENT_FADEOUT; pTemp->flags = FTENT_ROTATE|FTENT_FADEOUT;
vel = dest[2] / 8.0f; float vel = dest[2] / 8.0f;
if( vel < 64.0f ) vel = 64.0f; if( vel < 64.0f ) vel = 64.0f;
dist = VectorNormalizeLength( dir ); float dist = VectorNormalizeLength( dir );
vel += COM_RandomFloat( 64.0f, 128.0f ); vel += COM_RandomFloat( 64.0f, 128.0f );
VectorScale( dir, vel, pTemp->entity.baseline.origin ); VectorScale( dir, vel, pTemp->entity.baseline.origin );
pTemp->die = cl.time + (dist / vel) - 0.5f; pTemp->die = cl.time + (dist / vel) - 0.5f;
@@ -1484,8 +1455,7 @@ Make a random ricochet sound
*/ */
static void R_RicochetSoundByName( const vec3_t pos, const char *name ) static void R_RicochetSoundByName( const vec3_t pos, const char *name )
{ {
sound_t handle; sound_t handle = S_RegisterSound( name );
handle = S_RegisterSound( name );
S_StartSound( pos, 0, CHAN_AUTO, handle, VOL_NORM, 1.0, 100, 0 ); S_StartSound( pos, 0, CHAN_AUTO, handle, VOL_NORM, 1.0, 100, 0 );
} }
@@ -1562,10 +1532,9 @@ Spherical shower of models, picks from set
void GAME_EXPORT R_TempSphereModel( const vec3_t pos, float speed, float life, int count, int modelIndex ) void GAME_EXPORT R_TempSphereModel( const vec3_t pos, float speed, float life, int count, int modelIndex )
{ {
TEMPENTITY *pTemp; TEMPENTITY *pTemp;
int i;
// create temp models // create temp models
for( i = 0; i < count; i++ ) for( int i = 0; i < count; i++ )
{ {
pTemp = CL_TempEntAlloc( pos, CL_ModelHandle( modelIndex )); pTemp = CL_TempEntAlloc( pos, CL_ModelHandle( modelIndex ));
if( !pTemp ) return; if( !pTemp ) return;
@@ -1609,8 +1578,6 @@ Create an explosion (scale is magnitude)
*/ */
void GAME_EXPORT R_Explosion( vec3_t pos, int model, float scale, float framerate, int flags ) void GAME_EXPORT R_Explosion( vec3_t pos, int model, float scale, float framerate, int flags )
{ {
sound_t hSound;
if( scale != 0.0f ) if( scale != 0.0f )
{ {
// create explosion sprite // create explosion sprite
@@ -1621,10 +1588,8 @@ void GAME_EXPORT R_Explosion( vec3_t pos, int model, float scale, float framerat
if( !FBitSet( flags, TE_EXPLFLAG_NODLIGHTS )) if( !FBitSet( flags, TE_EXPLFLAG_NODLIGHTS ))
{ {
dlight_t *dl;
// big flash // big flash
dl = CL_AllocDlight( 0 ); dlight_t *dl = CL_AllocDlight( 0 );
VectorCopy( pos, dl->origin ); VectorCopy( pos, dl->origin );
dl->radius = 200; dl->radius = 200;
dl->color.r = 250; dl->color.r = 250;
@@ -1650,7 +1615,7 @@ void GAME_EXPORT R_Explosion( vec3_t pos, int model, float scale, float framerat
const char *name = SoundList_GetRandom( Explode ); const char *name = SoundList_GetRandom( Explode );
if( name ) if( name )
{ {
hSound = S_RegisterSound( name ); sound_t hSound = S_RegisterSound( name );
S_StartSound( pos, 0, CHAN_STATIC, hSound, VOL_NORM, 0.3f, PITCH_NORM, 0 ); S_StartSound( pos, 0, CHAN_STATIC, hSound, VOL_NORM, 0.3f, PITCH_NORM, 0 );
} }
} }
@@ -1667,21 +1632,16 @@ void GAME_EXPORT R_PlayerSprites( int client, int modelIndex, int count, int siz
{ {
TEMPENTITY *pTemp; TEMPENTITY *pTemp;
cl_entity_t *pEnt; cl_entity_t *pEnt;
vec3_t position;
vec3_t dir; vec3_t dir;
float vel;
int i;
pEnt = CL_GetEntityByIndex( client ); pEnt = CL_GetEntityByIndex( client );
if( !pEnt || !pEnt->player ) if( !pEnt || !pEnt->player )
return; return;
vel = 128; for( int i = 0; i < count; i++ )
for( i = 0; i < count; i++ )
{ {
VectorCopy( pEnt->origin, position ); vec3_t position = Vec3( pEnt->origin );
position[0] += COM_RandomFloat( -10.0f, 10.0f ); position[0] += COM_RandomFloat( -10.0f, 10.0f );
position[1] += COM_RandomFloat( -10.0f, 10.0f ); position[1] += COM_RandomFloat( -10.0f, 10.0f );
position[2] += COM_RandomFloat( -20.0f, 36.0f ); position[2] += COM_RandomFloat( -20.0f, 36.0f );
@@ -1732,16 +1692,13 @@ void GAME_EXPORT R_FireField( float *org, int radius, int modelIndex, int count,
{ {
TEMPENTITY *pTemp; TEMPENTITY *pTemp;
model_t *pmodel; model_t *pmodel;
float time;
vec3_t pos;
int i;
if(( pmodel = CL_ModelHandle( modelIndex )) == NULL ) if(( pmodel = CL_ModelHandle( modelIndex )) == NULL )
return; return;
for( i = 0; i < count; i++ ) for( int i = 0; i < count; i++ )
{ {
VectorCopy( org, pos ); vec3_t pos = Vec3( org );
pos[0] += COM_RandomFloat( -radius, radius ); pos[0] += COM_RandomFloat( -radius, radius );
pos[1] += COM_RandomFloat( -radius, radius ); pos[1] += COM_RandomFloat( -radius, radius );
@@ -1770,7 +1727,7 @@ void GAME_EXPORT R_FireField( float *org, int radius, int modelIndex, int count,
} }
pTemp->entity.curstate.framerate = COM_RandomFloat( 0.75f, 1.25f ); pTemp->entity.curstate.framerate = COM_RandomFloat( 0.75f, 1.25f );
time = life + COM_RandomFloat( -0.25f, 0.5f ); float time = life + COM_RandomFloat( -0.25f, 0.5f );
pTemp->die = cl.time + time; pTemp->die = cl.time + time;
if( pTemp->frameMax > 1 ) if( pTemp->frameMax > 1 )
@@ -1807,13 +1764,12 @@ void GAME_EXPORT R_MultiGunshot( const vec3_t org, const vec3_t dir, const vec3_
{ {
pmtrace_t trace; pmtrace_t trace;
vec3_t right, up; vec3_t right, up;
vec3_t vecSrc, vecDir, vecEnd; vec3_t vecDir, vecEnd;
int i, j, decalIndex;
VectorVectors( dir, right, up ); VectorVectors( dir, right, up );
VectorCopy( org, vecSrc ); vec3_t vecSrc = Vec3( org );
for( i = 0; i < count; i++ ) for( int i = 0; i < count; i++ )
{ {
// get circular gaussian spread // get circular gaussian spread
float x, y, z; float x, y, z;
@@ -1823,7 +1779,7 @@ void GAME_EXPORT R_MultiGunshot( const vec3_t org, const vec3_t dir, const vec3_
z = x * x + y * y; z = x * x + y * y;
} while( z > 1.0f ); } while( z > 1.0f );
for( j = 0; j < 3; j++ ) for( int j = 0; j < 3; j++ )
{ {
vecDir[j] = dir[j] + x * noise[0] * right[j] + y * noise[1] * up[j]; vecDir[j] = dir[j] + x * noise[0] * right[j] + y * noise[1] * up[j];
vecEnd[j] = vecSrc[j] + 4096.0f * vecDir[j]; vecEnd[j] = vecSrc[j] + 4096.0f * vecDir[j];
@@ -1845,7 +1801,7 @@ void GAME_EXPORT R_MultiGunshot( const vec3_t org, const vec3_t dir, const vec3_
if( pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP )) if( pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP ))
{ {
cl_entity_t *e = CL_GetEntityByIndex( pe->info ); cl_entity_t *e = CL_GetEntityByIndex( pe->info );
decalIndex = CL_DecalIndex( decalIndices[COM_RandomLong( 0, decalCount-1 )] ); int decalIndex = CL_DecalIndex( decalIndices[COM_RandomLong( 0, decalCount-1 )] );
CL_DecalShoot( decalIndex, e->index, 0, trace.endpos, 0 ); CL_DecalShoot( decalIndex, e->index, 0, trace.endpos, 0 );
} }
} }
@@ -1884,7 +1840,6 @@ void CL_ParseTempEntity( sizebuf_t *msg, connprotocol_t proto )
{ {
sizebuf_t buf, *pbuf; sizebuf_t buf, *pbuf;
byte msg_data[2048]; byte msg_data[2048];
int iSize;
int type, color, count, flags; int type, color, count, flags;
int decalIndex = 0, modelIndex = 0, entityIndex = 0; int decalIndex = 0, modelIndex = 0, entityIndex = 0;
float scale, life, frameRate, vel, random; float scale, life, frameRate, vel, random;
@@ -1899,14 +1854,18 @@ void CL_ParseTempEntity( sizebuf_t *msg, connprotocol_t proto )
if( proto != PROTO_GOLDSRC ) if( proto != PROTO_GOLDSRC )
{ {
iSize = MSG_ReadWord( msg ); int iSize = MSG_ReadWord( msg );
// this will probably be fatal anyway // this will probably be fatal anyway
if( iSize > sizeof( msg_data )) if( iSize > sizeof( msg_data ))
{
Con_Printf( S_ERROR "%s: Temp buffer overflow!\n", __func__ ); Con_Printf( S_ERROR "%s: Temp buffer overflow!\n", __func__ );
MSG_SeekToBit( msg, iSize << 3, SEEK_CUR );
return;
}
// parse user message into buffer // parse user message into buffer
MSG_ReadBytes( msg, msg_data, iSize ); MSG_ReadBytes( msg, msg_data, sizeof( msg_data ), iSize );
// init a safe tempbuffer // init a safe tempbuffer
MSG_Init( &buf, "TempEntity", msg_data, iSize ); MSG_Init( &buf, "TempEntity", msg_data, iSize );
@@ -2429,28 +2388,25 @@ static void CL_ClearLightStyles( void )
void CL_SetLightstyle( int style, const char *s, float f ) void CL_SetLightstyle( int style, const char *s, float f )
{ {
int i;
lightstyle_t *ls;
if( unlikely( style < 0 || style >= MAX_LIGHTSTYLES )) if( unlikely( style < 0 || style >= MAX_LIGHTSTYLES ))
{ {
Con_Printf( S_WARN "%s: ignored invalid lightstyle id %d\n", __func__, style ); Con_Printf( S_WARN "%s: ignored invalid lightstyle id %d\n", __func__, style );
return; return;
} }
ls = &cl.lightstyles[style]; lightstyle_t *ls = &cl.lightstyles[style];
ls->length = Q_strncpy( ls->pattern, s, sizeof( ls->pattern )); ls->length = Q_strncpy( ls->pattern, s, sizeof( ls->pattern ));
ls->time = f; // set local time ls->time = f; // set local time
for( i = 0; i < ls->length; i++ ) for( int i = 0; i < ls->length; i++ )
ls->map[i] = (float)(s[i] - 'a'); ls->map[i] = (float)(s[i] - 'a');
ls->interp = (ls->length <= 1) ? false : true; ls->interp = (ls->length <= 1) ? false : true;
// check for allow interpolate // check for allow interpolate
// NOTE: fast flickering styles looks ugly when interpolation is running // NOTE: fast flickering styles looks ugly when interpolation is running
for( i = 0; i < ( ls->length - 1 ); i++ ) for( int i = 0; i < ( ls->length - 1 ); i++ )
{ {
float val1 = ls->map[( i + 0 ) % ls->length]; float val1 = ls->map[( i + 0 ) % ls->length];
float val2 = ls->map[( i + 1 ) % ls->length]; float val2 = ls->map[( i + 1 ) % ls->length];
@@ -2587,9 +2543,8 @@ void CL_DecayLights( void )
{ {
const float time = cl.time; const float time = cl.time;
const float dt = cl.time - cl.oldtime; const float dt = cl.time - cl.oldtime;
int i;
for( i = 0; i < MAX_DLIGHTS; i++ ) for( int i = 0; i < MAX_DLIGHTS; i++ )
{ {
dlight_t *dl = &cl_dlights[i]; dlight_t *dl = &cl_dlights[i];
@@ -2607,7 +2562,7 @@ void CL_DecayLights( void )
memset( dl, 0, sizeof( *dl )); memset( dl, 0, sizeof( *dl ));
} }
for( i = 0; i < MAX_ELIGHTS; i++ ) for( int i = 0; i < MAX_ELIGHTS; i++ )
{ {
dlight_t *dl = &cl_elights[i]; dlight_t *dl = &cl_elights[i];
@@ -2649,7 +2604,6 @@ static void CL_UpdateFlashlight( cl_entity_t *ent )
{ {
vec3_t forward, view_ofs; vec3_t forward, view_ofs;
vec3_t vecSrc, vecEnd; vec3_t vecSrc, vecEnd;
float falloff;
pmtrace_t trace; pmtrace_t trace;
cl_entity_t *hit; cl_entity_t *hit;
dlight_t *dl; dlight_t *dl;
@@ -2694,7 +2648,7 @@ static void CL_UpdateFlashlight( cl_entity_t *ent )
VectorCopy( trace->endpos, dl->origin ); VectorCopy( trace->endpos, dl->origin );
#endif #endif
// compute falloff // compute falloff
falloff = trace.fraction * FLASHLIGHT_DISTANCE; float falloff = trace.fraction * FLASHLIGHT_DISTANCE;
if( falloff < 500.0f ) falloff = 1.0f; if( falloff < 500.0f ) falloff = 1.0f;
else falloff = 500.0f / falloff; else falloff = 500.0f / falloff;
falloff *= falloff; falloff *= falloff;
@@ -2878,25 +2832,22 @@ if cl_testlights is set, create 32 lights models
*/ */
void CL_TestLights( void ) void CL_TestLights( void )
{ {
int i, j, numLights;
vec3_t forward, right; vec3_t forward, right;
float f, r;
dlight_t *dl;
if( !cl_testlights.value ) if( !cl_testlights.value )
return; return;
numLights = bound( 1, cl_testlights.value, MAX_DLIGHTS ); int numLights = bound( 1, cl_testlights.value, MAX_DLIGHTS );
AngleVectors( cl.viewangles, forward, right, NULL ); AngleVectors( cl.viewangles, forward, right, NULL );
for( i = 0; i < numLights; i++ ) for( int i = 0; i < numLights; i++ )
{ {
dl = &cl_dlights[i]; dlight_t *dl = &cl_dlights[i];
r = 64 * ((i % 4) - 1.5f ); float r = 64 * ((i % 4) - 1.5f );
f = 64 * ( i / 4) + 128; float f = 64 * ( i / 4) + 128;
for( j = 0; j < 3; j++ ) for( int j = 0; j < 3; j++ )
dl->origin[j] = cl.simorg[j] + forward[j] * f + right[j] * r; dl->origin[j] = cl.simorg[j] + forward[j] * f + right[j] * r;
dl->color.r = ((((i % 6) + 1) & 1)>>0) * 255; dl->color.r = ((((i % 6) + 1) & 1)>>0) * 255;
@@ -2996,13 +2947,11 @@ get decal global index from decalname
*/ */
int GAME_EXPORT CL_DecalIndexFromName( const char *name ) int GAME_EXPORT CL_DecalIndexFromName( const char *name )
{ {
int i;
if( COM_StringEmptyOrNULL( name )) if( COM_StringEmptyOrNULL( name ))
return 0; return 0;
// look through the loaded sprite name list for SpriteName // look through the loaded sprite name list for SpriteName
for( i = 1; i < MAX_DECALS && host.draw_decals[i][0]; i++ ) for( int i = 1; i < MAX_DECALS && host.draw_decals[i][0]; i++ )
{ {
if( !Q_stricmp( name, host.draw_decals[i] )) if( !Q_stricmp( name, host.draw_decals[i] ))
return i; return i;
@@ -3099,13 +3048,11 @@ e.g. by demo request
*/ */
void CL_ClearStaticEntities( void ) void CL_ClearStaticEntities( void )
{ {
int i;
if( host.type == HOST_DEDICATED ) if( host.type == HOST_DEDICATED )
return; return;
// clear out efrags in case the level hasn't been reloaded // clear out efrags in case the level hasn't been reloaded
for( i = 0; i < cl.worldmodel->numleafs; i++ ) for( int i = 0; i < cl.worldmodel->numleafs; i++ )
cl.worldmodel->leafs[i+1].efrags = NULL; cl.worldmodel->leafs[i+1].efrags = NULL;
clgame.numStatics = 0; clgame.numStatics = 0;
+1 -3
View File
@@ -192,11 +192,9 @@ SCR_PlayCinematic
qboolean SCR_PlayCinematic( const char *arg ) qboolean SCR_PlayCinematic( const char *arg )
{ {
int x, y, w, h; int x, y, w, h;
const char *fullpath; const char *fullpath = FS_GetDiskPath( arg, false );
double video_ratio, screen_ratio, scale; double video_ratio, screen_ratio, scale;
fullpath = FS_GetDiskPath( arg, false );
if( FS_FileExists( arg, false ) && !fullpath ) if( FS_FileExists( arg, false ) && !fullpath )
{ {
Con_Printf( S_ERROR "Couldn't load %s from packfile. Please extract it\n", arg ); Con_Printf( S_ERROR "Couldn't load %s from packfile. Please extract it\n", arg );
+9 -14
View File
@@ -187,18 +187,15 @@ merge refdef with overview settings
static void V_RefApplyOverview( ref_viewpass_t *rvp ) static void V_RefApplyOverview( ref_viewpass_t *rvp )
{ {
ref_overview_t *ov = &clgame.overView; ref_overview_t *ov = &clgame.overView;
float aspect;
float size_x, size_y;
vec2_t mins, maxs;
if( !CL_IsDevOverviewMode( )) if( !CL_IsDevOverviewMode( ))
return; return;
// NOTE: Xash3D may use 16:9 or 16:10 aspects // NOTE: Xash3D may use 16:9 or 16:10 aspects
aspect = (float)refState.width / (float)refState.height; float aspect = (float)refState.width / (float)refState.height;
size_x = fabs( 8192.0f / ov->flZoom ); float size_x = fabs( 8192.0f / ov->flZoom );
size_y = fabs( 8192.0f / (ov->flZoom * aspect )); float size_y = fabs( 8192.0f / (ov->flZoom * aspect ));
// compute rectangle // compute rectangle
ov->xLeft = -(size_x / 2); ov->xLeft = -(size_x / 2);
@@ -214,8 +211,8 @@ static void V_RefApplyOverview( ref_viewpass_t *rvp )
VectorCopy( ov->origin, rvp->vieworigin ); VectorCopy( ov->origin, rvp->vieworigin );
rvp->vieworigin[2] = ov->zFar + ov->zNear; rvp->vieworigin[2] = ov->zFar + ov->zNear;
Vector2Copy( rvp->vieworigin, mins ); vec2_t mins = Vec2( rvp->vieworigin );
Vector2Copy( rvp->vieworigin, maxs ); vec2_t maxs = Vec2( rvp->vieworigin );
mins[!ov->rotated] += ov->xLeft; mins[!ov->rotated] += ov->xLeft;
maxs[!ov->rotated] += ov->xRight; maxs[!ov->rotated] += ov->xRight;
@@ -238,13 +235,11 @@ V_CalcFov
*/ */
static float V_CalcFov( float *fov_x, float width, float height ) static float V_CalcFov( float *fov_x, float width, float height )
{ {
float x, half_fov_y;
if( *fov_x < 1.0f || *fov_x > 179.0f ) if( *fov_x < 1.0f || *fov_x > 179.0f )
*fov_x = 90.0f; // default value *fov_x = 90.0f; // default value
x = width / tan( DEG2RAD( *fov_x ) * 0.5f ); float x = width / tan( DEG2RAD( *fov_x ) * 0.5f );
half_fov_y = atan( height / x ); float half_fov_y = atan( height / x );
return RAD2DEG( half_fov_y ) * 2; return RAD2DEG( half_fov_y ) * 2;
} }
@@ -500,13 +495,12 @@ static void R_ShowTree( void )
{ {
float x = (float)((refState.width - (int)POINT_SIZE) >> 1); float x = (float)((refState.width - (int)POINT_SIZE) >> 1);
float y = NODE_INTERVAL_Y(1.0f); float y = NODE_INTERVAL_Y(1.0f);
mleaf_t *viewleaf;
if( !cl.worldmodel || !r_showtree.value ) if( !cl.worldmodel || !r_showtree.value )
return; return;
world.recursion_level = 0; world.recursion_level = 0;
viewleaf = Mod_PointInLeaf( refState.vieworg, cl.worldmodel->nodes, cl.worldmodel ); mleaf_t *viewleaf = Mod_PointInLeaf( refState.vieworg, cl.worldmodel->nodes, cl.worldmodel );
ref.dllFuncs.TriRenderMode( kRenderTransTexture ); ref.dllFuncs.TriRenderMode( kRenderTransTexture );
@@ -560,6 +554,7 @@ void V_PostRender( void )
SCR_DrawNetGraph(); SCR_DrawNetGraph();
SCR_DrawUserCmd(); SCR_DrawUserCmd();
Joy_DrawDebug(); Joy_DrawDebug();
IN_GyroDrawDebug();
SV_DrawOrthoTriangles(); SV_DrawOrthoTriangles();
CL_DrawDemoRecording(); CL_DrawDemoRecording();
CL_DrawHUD( CL_CHANGELEVEL ); CL_DrawHUD( CL_CHANGELEVEL );
+3 -2
View File
@@ -579,6 +579,7 @@ typedef struct
sizebuf_t datagram; // unreliable stuff. gets sent in CL_Move about cl_cmdrate times per second. sizebuf_t datagram; // unreliable stuff. gets sent in CL_Move about cl_cmdrate times per second.
byte datagram_buf[MAX_DATAGRAM]; byte datagram_buf[MAX_DATAGRAM];
uint64_t netchan_pending_cookie; // random NET_EXT_NETCHAN_COOKIE
netchan_t netchan; netchan_t netchan;
float packet_loss; float packet_loss;
@@ -644,7 +645,6 @@ typedef struct
qboolean internetservers_pending; // if true, clean master server pings qboolean internetservers_pending; // if true, clean master server pings
qboolean internetservers_nat; qboolean internetservers_nat;
string internetservers_customfilter; string internetservers_customfilter;
uint32_t internetservers_key; // compare key to validate master server reply
// multiprotocol support // multiprotocol support
connprotocol_t legacymode; connprotocol_t legacymode;
@@ -792,6 +792,7 @@ void CL_SignonReply( connprotocol_t proto );
void CL_ClearState( void ); void CL_ClearState( void );
void CL_SetCheatState( qboolean multiplayer, qboolean allow_cheats ); void CL_SetCheatState( qboolean multiplayer, qboolean allow_cheats );
void CL_SendGoldSrcConnectPacket( netadr_t adr, int challenge, const void *ticket, size_t ticketlen ); void CL_SendGoldSrcConnectPacket( netadr_t adr, int challenge, const void *ticket, size_t ticketlen );
void CL_NotifyServerListResponse( void );
// //
// cl_demo.c // cl_demo.c
@@ -1154,7 +1155,7 @@ void S_StopStreaming( void );
void S_BeginRegistration( void ); void S_BeginRegistration( void );
sound_t S_RegisterSound( const char *sample ); sound_t S_RegisterSound( const char *sample );
void S_EndRegistration( void ); void S_EndRegistration( void );
void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float fvol, float attn, int pitch, int flags, double sample, double end, int wordIndex ); void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float fvol, float attn, int pitch, int flags, double sample, double end, uint wordIndex );
void S_StartSound( const vec3_t pos, int ent, int chan, sound_t sfx, float vol, float attn, int pitch, int flags ); void S_StartSound( const vec3_t pos, int ent, int chan, sound_t sfx, float vol, float attn, int pitch, int flags );
void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, float attn, int pitch, int flags ); void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, float attn, int pitch, int flags );
void S_SoundFade( int fade_percent, int hold_time, int fade_out_seconds, int fade_in_seconds ); void S_SoundFade( int fade_percent, int hold_time, int fade_out_seconds, int fade_in_seconds );
+60 -104
View File
@@ -159,7 +159,7 @@ static void Con_SaveHistory( con_history_t *self );
Con_BackgroundMapActive Con_BackgroundMapActive
================ ================
*/ */
qboolean Con_BackgroundMapActive( void ) static qboolean Con_BackgroundMapActive( void )
{ {
return sv_background.value != 0.0f || cl.background; return sv_background.value != 0.0f || cl.background;
} }
@@ -182,13 +182,11 @@ Con_SetColor
*/ */
static void Con_SetColor( void ) static void Con_SetColor( void )
{ {
int r, g, b;
int num;
if( !FBitSet( con_color.flags, FCVAR_CHANGED )) if( !FBitSet( con_color.flags, FCVAR_CHANGED ))
return; return;
num = sscanf( con_color.string, "%i %i %i", &r, &g, &b ); int r, g, b;
int num = sscanf( con_color.string, "%i %i %i", &r, &g, &b );
switch( num ) switch( num )
{ {
@@ -213,9 +211,7 @@ Con_ClearNotify
*/ */
void Con_ClearNotify( void ) void Con_ClearNotify( void )
{ {
int i; for( int i = 0; i < CON_LINES_COUNT; i++ )
for( i = 0; i < CON_LINES_COUNT; i++ )
CON_LINES( i ).addtime = 0.0; CON_LINES( i ).addtime = 0.0;
} }
@@ -310,15 +306,13 @@ Con_SetTimes_f
*/ */
static void Con_SetTimes_f( void ) static void Con_SetTimes_f( void )
{ {
int newtimes;
if( Cmd_Argc() != 2 ) if( Cmd_Argc() != 2 )
{ {
Con_Printf( S_USAGE "contimes <n lines>\n" ); Con_Printf( S_USAGE "contimes <n lines>\n" );
return; return;
} }
newtimes = Q_atoi( Cmd_Argv( 1 ) ); int newtimes = Q_atoi( Cmd_Argv( 1 ) );
con.num_times = bound( CON_TIMES, newtimes, CON_MAX_TIMES ); con.num_times = bound( CON_TIMES, newtimes, CON_MAX_TIMES );
} }
@@ -333,15 +327,12 @@ went backwards)
*/ */
static void Con_FixTimes( void ) static void Con_FixTimes( void )
{ {
double diff;
int i;
if( con.lines_count <= 0 ) return; if( con.lines_count <= 0 ) return;
diff = cl.time - CON_LINES_LAST().addtime; double diff = cl.time - CON_LINES_LAST().addtime;
if( diff >= 0.0 ) return; // nothing to fix if( diff >= 0.0 ) return; // nothing to fix
for( i = 0; i < con.lines_count; i++ ) for( int i = 0; i < con.lines_count; i++ )
CON_LINES( i ).addtime += diff; CON_LINES( i ).addtime += diff;
} }
@@ -428,8 +419,7 @@ Appends a given string as a new line to the console.
*/ */
static void Con_AddLine( const char *line, int length, qboolean newline ) static void Con_AddLine( const char *line, int length, qboolean newline )
{ {
char *putpos; char *putpos;
con_lineinfo_t *p;
if( !con.initialized || !con.buffer ) if( !con.initialized || !con.buffer )
return; return;
@@ -442,6 +432,7 @@ static void Con_AddLine( const char *line, int length, qboolean newline )
while( !( putpos = Con_BytesLeft( length )) || con.lines_count >= con.maxlines ) while( !( putpos = Con_BytesLeft( length )) || con.lines_count >= con.maxlines )
Con_DeleteLine(); Con_DeleteLine();
con_lineinfo_t *p;
if( newline ) if( newline )
{ {
memcpy( putpos, line, length ); memcpy( putpos, line, length );
@@ -475,12 +466,11 @@ If the line width has changed, reformat the buffer.
static void Con_CheckResize( void ) static void Con_CheckResize( void )
{ {
int charWidth = 8; int charWidth = 8;
int i, width;
if( con.curFont && con.curFont->hFontTexture ) if( con.curFont && con.curFont->hFontTexture )
charWidth = con.curFont->charWidths['O'] - 1; charWidth = con.curFont->charWidths['O'] - 1;
width = ( refState.width / charWidth ) - 2; int width = ( refState.width / charWidth ) - 2;
if( !ref.initialized ) width = (640 / 5); if( !ref.initialized ) width = (640 / 5);
if( width == con.linewidth ) if( width == con.linewidth )
@@ -611,13 +601,12 @@ Con_LoadConchars
*/ */
static void Con_LoadConchars( void ) static void Con_LoadConchars( void )
{ {
int i, fontSize;
// load all the console fonts // load all the console fonts
for( i = 0; i < CON_NUMFONTS; i++ ) for( int i = 0; i < CON_NUMFONTS; i++ )
Con_LoadConsoleFont( i, con.chars + i ); Con_LoadConsoleFont( i, con.chars + i );
// select properly fontsize // select properly fontsize
int fontSize;
if( con_fontnum.value >= 0 && con_fontnum.value <= CON_NUMFONTS - 1 ) if( con_fontnum.value >= 0 && con_fontnum.value <= CON_NUMFONTS - 1 )
fontSize = con_fontnum.value; fontSize = con_fontnum.value;
else if( refState.width <= 640 ) else if( refState.width <= 640 )
@@ -675,7 +664,6 @@ int Con_UtfMoveLeft( char *str, int pos )
{ {
utfstate_t state = { 0 }; utfstate_t state = { 0 };
int k = 0; int k = 0;
int i;
if( !cls.accept_utf8 ) // incoming character is not a UTF-8 sequence if( !cls.accept_utf8 ) // incoming character is not a UTF-8 sequence
return pos - 1; return pos - 1;
@@ -683,7 +671,7 @@ int Con_UtfMoveLeft( char *str, int pos )
if( pos == 1 ) if( pos == 1 )
return 0; return 0;
for( i = 0; i < pos - 1; i++ ) for( int i = 0; i < pos - 1; i++ )
{ {
if( Q_DecodeUTF8( &state, (byte)str[i] )) if( Q_DecodeUTF8( &state, (byte)str[i] ))
k = i + 1; k = i + 1;
@@ -702,12 +690,11 @@ 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 }; utfstate_t state = { 0 };
int i;
if( !cls.accept_utf8 ) // incoming character is not a UTF-8 sequence if( !cls.accept_utf8 ) // incoming character is not a UTF-8 sequence
return pos + 1; return pos + 1;
for( i = pos; i <= length; i++ ) for( int i = pos; i <= length; i++ )
{ {
if( Q_DecodeUTF8( &state, (byte)str[i] )) if( Q_DecodeUTF8( &state, (byte)str[i] ))
return i + 1; return i + 1;
@@ -718,20 +705,15 @@ int Con_UtfMoveRight( char *str, int pos, int length )
static void Con_DrawCharToConback( int num, const byte *conchars, byte *dest ) static void Con_DrawCharToConback( int num, const byte *conchars, byte *dest )
{ {
int row, col; int row = num >> 4;
const byte *source; int col = num & 15;
int drawline; const byte *source = conchars + (row << 10) + (col << 3);
int x;
row = num >> 4; int drawline = 8;
col = num & 15;
source = conchars + (row << 10) + (col << 3);
drawline = 8;
while( drawline-- ) while( drawline-- )
{ {
for( x = 0; x < 8; x++ ) for( int x = 0; x < 8; x++ )
if( source[x] != 255 ) if( source[x] != 255 )
dest[x] = 0x60 + source[x]; dest[x] = 0x60 + source[x];
source += 128; source += 128;
@@ -1105,7 +1087,7 @@ static void Con_ClearField( field_t *edit )
Field_Set Field_Set
================ ================
*/ */
static void Field_Set( field_t *f, const char *string ) MAYBE_UNUSED static void Field_Set( field_t *f, const char *string )
{ {
f->scroll = 0; f->scroll = 0;
f->cursor = Q_strncpy( f->buffer, string, sizeof( f->buffer )); f->cursor = Q_strncpy( f->buffer, string, sizeof( f->buffer ));
@@ -1118,15 +1100,12 @@ Field_Paste
*/ */
static void Field_Paste( field_t *edit ) static void Field_Paste( field_t *edit )
{ {
char *cbd; char *cbd = Sys_GetClipboardData();
int i, pasteLen;
cbd = Sys_GetClipboardData();
if( !cbd ) return; if( !cbd ) return;
// send as if typed, so insert / overstrike works properly // send as if typed, so insert / overstrike works properly
pasteLen = Q_strlen( cbd ); int pasteLen = Q_strlen( cbd );
for( i = 0; i < pasteLen; i++ ) for( int i = 0; i < pasteLen; i++ )
Field_CharEvent( edit, cbd[i] ); Field_CharEvent( edit, cbd[i] );
} }
@@ -1154,8 +1133,6 @@ Key events are used for non-printable characters, others are gotten from char ev
*/ */
static void Field_KeyDownEvent( field_t *edit, int key ) static void Field_KeyDownEvent( field_t *edit, int key )
{ {
int len;
// shift-insert is paste // shift-insert is paste
if((( key == K_INS ) || ( key == K_KP_INS )) && Key_IsDown( K_SHIFT )) if((( key == K_INS ) || ( key == K_KP_INS )) && Key_IsDown( K_SHIFT ))
{ {
@@ -1163,7 +1140,7 @@ static void Field_KeyDownEvent( field_t *edit, int key )
return; return;
} }
len = Q_strlen( edit->buffer ); int len = Q_strlen( edit->buffer );
if( key == K_DEL ) if( key == K_DEL )
{ {
@@ -1225,8 +1202,6 @@ Field_CharEvent
*/ */
static void Field_CharEvent( field_t *edit, int ch ) static void Field_CharEvent( field_t *edit, int ch )
{ {
int len;
if( ch == 'v' - 'a' + 1 ) if( ch == 'v' - 'a' + 1 )
{ {
// ctrl-v is paste // ctrl-v is paste
@@ -1241,7 +1216,7 @@ static void Field_CharEvent( field_t *edit, int ch )
return; return;
} }
len = Q_strlen( edit->buffer ); int len = Q_strlen( edit->buffer );
if( ch == 'a' - 'a' + 1 ) if( ch == 'a' - 'a' + 1 )
{ {
@@ -1286,7 +1261,6 @@ Field_DrawInputLine
*/ */
static int Field_DrawInputLine( int x, int y, const field_t *edit, byte alpha, qboolean cursor ) static int Field_DrawInputLine( int x, int y, const field_t *edit, byte alpha, qboolean cursor )
{ {
int curPos;
char str[MAX_SYSPATH]; char str[MAX_SYSPATH];
rgba_t colorDefault; rgba_t colorDefault;
const int prestep = bound( 0, edit->scroll, sizeof( edit->buffer ) - 1 ); const int prestep = bound( 0, edit->scroll, sizeof( edit->buffer ) - 1 );
@@ -1303,6 +1277,7 @@ static int Field_DrawInputLine( int x, int y, const field_t *edit, byte alpha, q
// calc cursor position // calc cursor position
str[cursorCharPos] = 0; str[cursorCharPos] = 0;
int curPos;
CL_DrawStringLen( con.curFont, str, &curPos, NULL, FONT_DRAW_UTF8 ); CL_DrawStringLen( con.curFont, str, &curPos, NULL, FONT_DRAW_UTF8 );
// draw the cursor // draw the cursor
@@ -1415,10 +1390,7 @@ static void Con_HistoryAppend( con_history_t *self, const field_t *from )
static void Con_LoadHistory( con_history_t *self ) static void Con_LoadHistory( con_history_t *self )
{ {
file_t *fd; file_t *fd = FS_Open( "console_history.txt", "rb", true );
int i;
fd = FS_Open( "console_history.txt", "rb", true );
if( !fd ) if( !fd )
return; return;
@@ -1448,7 +1420,7 @@ static void Con_LoadHistory( con_history_t *self )
FS_Close( fd ); FS_Close( fd );
for( i = self->next; i < CON_HISTORY; i++ ) for( int i = self->next; i < CON_HISTORY; i++ )
{ {
history_line_t *f = &self->lines[i]; history_line_t *f = &self->lines[i];
@@ -1460,17 +1432,15 @@ static void Con_LoadHistory( con_history_t *self )
static void Con_SaveHistory( con_history_t *self ) static void Con_SaveHistory( con_history_t *self )
{ {
int historyStart = self->next - CON_HISTORY, i;
file_t *f;
// do not save history if nothing was executed // do not save history if nothing was executed
if( self->next == 0 ) if( self->next == 0 )
return; return;
int historyStart = self->next - CON_HISTORY;
if( historyStart < 0 ) if( historyStart < 0 )
historyStart = 0; historyStart = 0;
f = FS_Open( "console_history.txt", "wb", true ); file_t *f = FS_Open( "console_history.txt", "wb", true );
if( !f ) if( !f )
{ {
@@ -1478,7 +1448,7 @@ static void Con_SaveHistory( con_history_t *self )
return; return;
} }
for( i = historyStart; i < self->next; i++ ) for( int i = historyStart; i < self->next; i++ )
{ {
const char *s = self->lines[i % CON_HISTORY].buffer; const char *s = self->lines[i % CON_HISTORY].buffer;
@@ -1704,15 +1674,13 @@ The input line scrolls horizontally if typing goes beyond the right edge
*/ */
static void Con_DrawInput( int lines ) static void Con_DrawInput( int lines )
{ {
int x, y;
// don't draw anything (always draw if not active) // don't draw anything (always draw if not active)
if( cls.key_dest != key_console || !con.curFont ) if( cls.key_dest != key_console || !con.curFont )
return; return;
y = lines - ( con.curFont->charHeight * 2 ); int y = lines - ( con.curFont->charHeight * 2 );
CL_DrawCharacter( con.curFont->charWidths[' '], y, ']', g_color_table[7], con.curFont, 0 ); CL_DrawCharacter( con.curFont->charWidths[' '], y, ']', g_color_table[7], con.curFont, 0 );
x = Field_DrawInputLine( con.curFont->charWidths[' ']*2, y, &con.input, 255, true ); int x = Field_DrawInputLine( con.curFont->charWidths[' ']*2, y, &con.input, 255, true );
// HACKHACK: avoid rendering issues when scroll != 0 // HACKHACK: avoid rendering issues when scroll != 0
if( con_showcompletion.value && con.input.scroll == 0 ) if( con_showcompletion.value && con.input.scroll == 0 )
@@ -1744,18 +1712,16 @@ Custom debug messages
static int Con_DrawDebugLines( void ) static int Con_DrawDebugLines( void )
{ {
notify_t *notify = con.notify; notify_t *notify = con.notify;
int i, count = 0; int count = 0;
int defaultX;
int y = 20; int y = 20;
int fontTall;
if( !con.curFont || !con.curFont->valid ) if( !con.curFont || !con.curFont->valid )
return 0; return 0;
defaultX = refState.width / 4; int defaultX = refState.width / 4;
fontTall = con.curFont->charHeight + 1; int fontTall = con.curFont->charHeight + 1;
for( i = 0; i < ARRAYSIZE( con.notify ); i++, notify++ ) for( int i = 0; i < ARRAYSIZE( con.notify ); i++, notify++ )
{ {
int x, len; int x, len;
@@ -1789,19 +1755,18 @@ Draws the debug messages (not passed to console history)
void Con_DrawDebug( void ) void Con_DrawDebug( void )
{ {
static double timeStart; static double timeStart;
string dlstring;
int x, y;
if( scr_download.value != -1.0f ) if( scr_download.value != -1.0f )
{ {
string dlstring;
int length; int length;
Q_snprintf( dlstring, sizeof( dlstring ), "Downloading [%d remaining]: ^2%s^7 %5.1f%% time %.f secs", Q_snprintf( dlstring, sizeof( dlstring ), "Downloading [%d remaining]: ^2%s^7 %5.1f%% time %.f secs",
host.downloadcount, host.downloadfile, scr_download.value, Platform_DoubleTime() - timeStart ); host.downloadcount, host.downloadfile, scr_download.value, Platform_DoubleTime() - timeStart );
Con_DrawStringLen( dlstring, &length, NULL ); Con_DrawStringLen( dlstring, &length, NULL );
length = Q_max( length, 300 ); length = Q_max( length, 300 );
x = refState.width - length * 1.05f; int x = refState.width - length * 1.05f;
y = con.curFont->charHeight * 1.05f; int y = con.curFont->charHeight * 1.05f;
Con_DrawString( x, y, dlstring, g_color_table[7] ); Con_DrawString( x, y, dlstring, g_color_table[7] );
} }
else else
@@ -1829,15 +1794,15 @@ Draws the last few lines of output transparently over the game top
static void Con_DrawNotify( void ) static void Con_DrawNotify( void )
{ {
double time = cl.time; double time = cl.time;
int i, x, y = 0; int y = 0;
if( !con.curFont ) return; if( !con.curFont ) return;
x = con.curFont->charWidths[' ']; // offset one space at left screen side int x = con.curFont->charWidths[' ']; // offset one space at left screen side
if( host.allow_console && !Con_BackgroundMapActive( )) if( host.allow_console && !Con_BackgroundMapActive( ))
{ {
for( i = Q_max( 0, CON_LINES_COUNT - con.num_times ); i < CON_LINES_COUNT; i++ ) for( int i = Q_max( 0, CON_LINES_COUNT - con.num_times ); i < CON_LINES_COUNT; i++ )
{ {
con_lineinfo_t *l = &CON_LINES( i ); con_lineinfo_t *l = &CON_LINES( i );
@@ -1905,13 +1870,13 @@ of it based on con.backscroll.
*/ */
static void Con_LastVisibleLine( int *lastline ) static void Con_LastVisibleLine( int *lastline )
{ {
int i, lines_seen = 0; int lines_seen = 0;
con.backscroll = Q_max( 0, con.backscroll ); con.backscroll = Q_max( 0, con.backscroll );
*lastline = 0; *lastline = 0;
// now count until we saw con_backscroll actual lines // now count until we saw con_backscroll actual lines
for( i = CON_LINES_COUNT - 1; i >= 0; i-- ) for( int i = CON_LINES_COUNT - 1; i >= 0; i-- )
{ {
// line is the last visible line? // line is the last visible line?
*lastline = i; *lastline = i;
@@ -1935,10 +1900,10 @@ Draws the console with the solid background
*/ */
static void Con_DrawSolidConsole( int lines ) static void Con_DrawSolidConsole( int lines )
{ {
int i, x, y; int x, y;
float fraction; float fraction;
int start; int start;
int stringLen, width = 0, charH; int stringLen, charH;
string curbuild; string curbuild;
byte color[4]; byte color[4];
@@ -2086,8 +2051,6 @@ void Con_DrawVersion( void )
{ {
// draws the current build // draws the current build
byte *color = g_color_table[7]; byte *color = g_color_table[7];
int stringLen, charH = 0;
int start, height = refState.height;
string curbuild; string curbuild;
if( !scr_drawversion.value ) if( !scr_drawversion.value )
@@ -2116,9 +2079,10 @@ void Con_DrawVersion( void )
XASH_ENGINE_NAME " v%i/" XASH_VERSION " (%s-%s build %i)", PROTOCOL_VERSION, Q_buildos(), Q_buildarch(), Q_buildnum( )); XASH_ENGINE_NAME " v%i/" XASH_VERSION " (%s-%s build %i)", PROTOCOL_VERSION, Q_buildos(), Q_buildarch(), Q_buildnum( ));
} }
int stringLen, charH = 0;
Con_DrawStringLen( curbuild, &stringLen, &charH ); Con_DrawStringLen( curbuild, &stringLen, &charH );
start = refState.width - stringLen * 1.05f; int start = refState.width - stringLen * 1.05f;
height -= charH * 1.05f; int height = refState.height - charH * 1.05f;
Con_DrawString( start, height, curbuild, color ); Con_DrawString( start, height, curbuild, color );
} }
@@ -2132,8 +2096,6 @@ Scroll it up or down
*/ */
void Con_RunConsole( void ) void Con_RunConsole( void )
{ {
float lines_per_frame;
Con_SetColor( ); Con_SetColor( );
// decide on the destination height of the console // decide on the destination height of the console
@@ -2149,7 +2111,7 @@ void Con_RunConsole( void )
} }
else con.showlines = 0; // none visible else con.showlines = 0; // none visible
lines_per_frame = fabs( scr_conspeed.value ) * host.realframetime; float lines_per_frame = fabs( scr_conspeed.value ) * host.realframetime;
if( con.showlines < con.vislines ) if( con.showlines < con.vislines )
{ {
@@ -2224,9 +2186,7 @@ void Con_CharEvent( int key )
static int Con_LoadSimpleConback( const char *name, int flags ) static int Con_LoadSimpleConback( const char *name, int flags )
{ {
int i; for( int i = 0; i < 5; i++ )
for( i = 0; i < 5; i++ )
{ {
string path; string path;
@@ -2311,15 +2271,13 @@ void Con_VidInit( void )
{ {
lmp_t *cb = (lmp_t *)FS_LoadFile( "gfx/conback.lmp", &length, false ); lmp_t *cb = (lmp_t *)FS_LoadFile( "gfx/conback.lmp", &length, false );
char ver[64]; char ver[64];
byte *dest;
int x, y, len;
if( cb && cb->width == 320 && cb->height == 200 ) if( cb && cb->width == 320 && cb->height == 200 )
{ {
len = Q_snprintf( ver, 64, "%i", Q_buildnum( )); // can store only buildnum int len = Q_snprintf( ver, 64, "%i", Q_buildnum( )); // can store only buildnum
dest = (byte *)(cb + 1) + 320 * 186 + 320 - 11 - 8 * len; byte *dest = (byte *)(cb + 1) + 320 * 186 + 320 - 11 - 8 * len;
y = len; int y = len;
for( x = 0; x < y; x++ ) for( int x = 0; x < y; x++ )
Con_DrawCharToConback( ver[x], buf, dest + (x << 3)); Con_DrawCharToConback( ver[x], buf, dest + (x << 3));
con.background = ref.dllFuncs.GL_LoadTexture( "#gfx/conback.lmp", (byte *)cb, length, TF_IMAGE ); con.background = ref.dllFuncs.GL_LoadTexture( "#gfx/conback.lmp", (byte *)cb, length, TF_IMAGE );
} }
@@ -2344,8 +2302,7 @@ Con_InvalidateFonts
*/ */
void Con_InvalidateFonts( void ) void Con_InvalidateFonts( void )
{ {
int i; for( int i = 0; i < ARRAYSIZE( con.chars ); i++ )
for( i = 0; i < ARRAYSIZE( con.chars ); i++ )
CL_FreeFont( &con.chars[i] ); CL_FreeFont( &con.chars[i] );
con.curFont = NULL; con.curFont = NULL;
} }
@@ -2399,9 +2356,8 @@ static void Test_RunConHistory( void )
const char *strs1[] = { "map t0a0", "quit", "wtf", "wtf", "", "nyan" }; const char *strs1[] = { "map t0a0", "quit", "wtf", "wtf", "", "nyan" };
const char *strs2[] = { "nyan", "wtf", "quit", "map t0a0" }; const char *strs2[] = { "nyan", "wtf", "quit", "map t0a0" };
const char *testbackup = "unfinished_edit"; const char *testbackup = "unfinished_edit";
int i;
for( i = 0; i < ARRAYSIZE( strs1 ); i++ ) for( int i = 0; i < ARRAYSIZE( strs1 ); i++ )
{ {
Field_Set( &input, strs1[i] ); Field_Set( &input, strs1[i] );
Con_HistoryAppend( &hist, &input ); Con_HistoryAppend( &hist, &input );
@@ -2409,7 +2365,7 @@ static void Test_RunConHistory( void )
Field_Set( &input, testbackup ); Field_Set( &input, testbackup );
for( i = 0; i < ARRAYSIZE( strs2 ); i++ ) for( int i = 0; i < ARRAYSIZE( strs2 ); i++ )
{ {
Con_HistoryUp( &hist, &input ); Con_HistoryUp( &hist, &input );
TASSERT_STR( input.buffer, strs2[i] ); TASSERT_STR( input.buffer, strs2[i] );
@@ -2418,7 +2374,7 @@ static void Test_RunConHistory( void )
// check for overrun // check for overrun
Con_HistoryUp( &hist, &input ); Con_HistoryUp( &hist, &input );
for( i = ARRAYSIZE( strs2 ) - 1; i >= 0; i-- ) for( int i = ARRAYSIZE( strs2 ) - 1; i >= 0; i-- )
{ {
TASSERT_STR( input.buffer, strs2[i] ); TASSERT_STR( input.buffer, strs2[i] );
Con_HistoryDown( &hist, &input ); Con_HistoryDown( &hist, &input );
+77 -115
View File
@@ -172,8 +172,6 @@ Initialize CD playlist
*/ */
static void CL_InitCDAudio( const char *filename ) static void CL_InitCDAudio( const char *filename )
{ {
byte *afile;
char *pfile;
string token; string token;
int c = 0; int c = 0;
@@ -183,10 +181,10 @@ static void CL_InitCDAudio( const char *filename )
CL_CreatePlaylist( filename ); CL_CreatePlaylist( filename );
} }
afile = FS_LoadFile( filename, NULL, false ); byte *afile = FS_LoadFile( filename, NULL, false );
if( !afile ) return; if( !afile ) return;
pfile = (char *)afile; char *pfile = (char *)afile;
// format: trackname\n [num] // format: trackname\n [num]
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL ) while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
@@ -318,14 +316,12 @@ draw hudsprite routine
*/ */
void SPR_AdjustSize( float *x, float *y, float *w, float *h ) void SPR_AdjustSize( float *x, float *y, float *w, float *h )
{ {
float xscale, yscale;
if( refState.width == clgame.scrInfo.iWidth && refState.height == clgame.scrInfo.iHeight ) if( refState.width == clgame.scrInfo.iWidth && refState.height == clgame.scrInfo.iHeight )
return; return;
// scale for screen sizes // scale for screen sizes
xscale = refState.width / (float)clgame.scrInfo.iWidth; float xscale = refState.width / (float)clgame.scrInfo.iWidth;
yscale = refState.height / (float)clgame.scrInfo.iHeight; float yscale = refState.height / (float)clgame.scrInfo.iHeight;
*x *= xscale; *x *= xscale;
*y *= yscale; *y *= yscale;
@@ -369,7 +365,6 @@ draw hudsprite routine
static void SPR_DrawGeneric( int frame, float x, float y, float width, float height, const wrect_t *prc ) static void SPR_DrawGeneric( int frame, float x, float y, float width, float height, const wrect_t *prc )
{ {
float s1, s2, t1, t2; float s1, s2, t1, t2;
int texnum;
if( width == -1 && height == -1 ) if( width == -1 && height == -1 )
{ {
@@ -382,7 +377,7 @@ static void SPR_DrawGeneric( int frame, float x, float y, float width, float hei
height = h; height = h;
} }
texnum = R_GetSpriteTexture( clgame.ds.pSprite, frame ); int texnum = R_GetSpriteTexture( clgame.ds.pSprite, frame );
if( prc ) if( prc )
{ {
@@ -430,11 +425,8 @@ called each frame
void CL_DrawCenterPrint( void ) void CL_DrawCenterPrint( void )
{ {
cl_font_t *font = Con_GetCurFont(); cl_font_t *font = Con_GetCurFont();
char *pText; byte line[MAX_LINELENGTH];
int i, j, x, y; int charHeight;
int width, lineLength;
byte *colorDefault, line[MAX_LINELENGTH];
int charWidth, charHeight;
if( !clgame.centerPrint.time ) if( !clgame.centerPrint.time )
return; return;
@@ -446,17 +438,17 @@ void CL_DrawCenterPrint( void )
return; return;
} }
y = clgame.centerPrint.y; // start y int y = clgame.centerPrint.y; // start y
colorDefault = g_color_table[7]; byte *colorDefault = g_color_table[7];
pText = clgame.centerPrint.message; char *pText = clgame.centerPrint.message;
CL_DrawCharacterLen( font, 0, NULL, &charHeight ); CL_DrawCharacterLen( font, 0, NULL, &charHeight );
CL_SetFontRendermode( font ); CL_SetFontRendermode( font );
CL_SetFontColor( font, colorDefault ); CL_SetFontColor( font, colorDefault );
for( i = 0; i < clgame.centerPrint.lines; i++ ) for( int i = 0; i < clgame.centerPrint.lines; i++ )
{ {
lineLength = 0; int lineLength = 0;
width = 0; int width = 0;
while( *pText && *pText != '\n' && lineLength < MAX_LINELENGTH ) while( *pText && *pText != '\n' && lineLength < MAX_LINELENGTH )
{ {
@@ -466,6 +458,7 @@ void CL_DrawCenterPrint( void )
continue; continue;
line[lineLength] = number; line[lineLength] = number;
int charWidth;
CL_DrawCharacterLen( font, number, &charWidth, NULL ); CL_DrawCharacterLen( font, number, &charWidth, NULL );
width += charWidth; width += charWidth;
lineLength++; lineLength++;
@@ -477,9 +470,9 @@ void CL_DrawCenterPrint( void )
pText++; // Skip LineFeed pText++; // Skip LineFeed
line[lineLength] = 0; line[lineLength] = 0;
x = CL_AdjustXPos( -1, width, clgame.centerPrint.totalWidth ); int x = CL_AdjustXPos( -1, width, clgame.centerPrint.totalWidth );
for( j = 0; j < lineLength; j++ ) for( int j = 0; j < lineLength; j++ )
{ {
if( x >= 0 && y >= 0 && x <= refState.width ) if( x >= 0 && y >= 0 && x <= refState.width )
x += CL_DrawCharacter( x, y, line[j], NULL, font, FONT_DRAW_HUD | FONT_DRAW_NORENDERMODE | FONT_DRAW_NOCOLOR ); x += CL_DrawCharacter( x, y, line[j], NULL, font, FONT_DRAW_HUD | FONT_DRAW_NORENDERMODE | FONT_DRAW_NOCOLOR );
@@ -534,9 +527,7 @@ can be modulated
static void CL_DrawScreenFade( void ) static void CL_DrawScreenFade( void )
{ {
screenfade_t *sf = &clgame.fade; screenfade_t *sf = &clgame.fade;
int alpha; int alpha = V_FadeAlpha( sf );
alpha = V_FadeAlpha( sf );
if( !alpha ) if( !alpha )
return; return;
@@ -619,11 +610,9 @@ Parse TE_TEXTMESSAGE
void CL_ParseTextMessage( sizebuf_t *msg ) void CL_ParseTextMessage( sizebuf_t *msg )
{ {
static int msgindex = 0; static int msgindex = 0;
client_textmessage_t *text;
int channel;
// read channel ( 0 - auto) // read channel ( 0 - auto)
channel = MSG_ReadByte( msg ); int channel = MSG_ReadByte( msg );
if( channel <= 0 || channel > ( MAX_TEXTCHANNELS - 1 )) if( channel <= 0 || channel > ( MAX_TEXTCHANNELS - 1 ))
{ {
@@ -632,7 +621,7 @@ void CL_ParseTextMessage( sizebuf_t *msg )
} }
// grab message channel // grab message channel
text = &cl_textmessage[channel]; client_textmessage_t *text = &cl_textmessage[channel];
text->x = (float)(MSG_ReadShort( msg ) / 8192.0f); text->x = (float)(MSG_ReadShort( msg ) / 8192.0f);
text->y = (float)(MSG_ReadShort( msg ) / 8192.0f); text->y = (float)(MSG_ReadShort( msg ) / 8192.0f);
@@ -680,12 +669,9 @@ return soundname from index
*/ */
static const char *CL_SoundFromIndex( int index ) static const char *CL_SoundFromIndex( int index )
{ {
sfx_t *sfx = NULL;
int hSound;
// make sure what we in-bounds // make sure what we in-bounds
index = bound( 0, index, MAX_SOUNDS ); index = bound( 0, index, MAX_SOUNDS );
hSound = cl.sound_index[index]; int hSound = cl.sound_index[index];
if( !hSound ) if( !hSound )
{ {
@@ -693,7 +679,7 @@ static const char *CL_SoundFromIndex( int index )
return NULL; return NULL;
} }
sfx = S_GetSfxByHandle( hSound ); sfx_t *sfx = S_GetSfxByHandle( hSound );
if( !sfx ) if( !sfx )
{ {
Con_DPrintf( S_ERROR "%s: bad sfx for index %i\n", __func__, index ); Con_DPrintf( S_ERROR "%s: bad sfx for index %i\n", __func__, index );
@@ -740,8 +726,6 @@ perform common scissor test
*/ */
qboolean CL_Scissor( const scissor_state_t *scissor, float *x, float *y, float *width, float *height, float *u0, float *v0, float *u1, float *v1 ) qboolean CL_Scissor( const scissor_state_t *scissor, float *x, float *y, float *width, float *height, float *u0, float *v0, float *u1, float *v1 )
{ {
float dudx, dvdy;
if( !scissor->test ) if( !scissor->test )
return true; return true;
@@ -758,8 +742,8 @@ qboolean CL_Scissor( const scissor_state_t *scissor, float *x, float *y, float *
if( *y >= scissor->y + scissor->height ) if( *y >= scissor->y + scissor->height )
return false; return false;
dudx = (*u1 - *u0) / *width; float dudx = (*u1 - *u0) / *width;
dvdy = (*v1 - *v0) / *height; float dvdy = (*v1 - *v0) / *height;
if( *x < scissor->x ) if( *x < scissor->x )
{ {
@@ -946,9 +930,7 @@ void CL_DrawHUD( int state )
static void CL_ClearUserMessage( char *pszName, int svc_num ) static void CL_ClearUserMessage( char *pszName, int svc_num )
{ {
int i; for( int i = 0; i < MAX_USER_MESSAGES && clgame.msg[i].name[0]; i++ )
for( i = 0; i < MAX_USER_MESSAGES && clgame.msg[i].name[0]; i++ )
if( ( clgame.msg[i].number == svc_num ) && Q_stricmp( clgame.msg[i].name, pszName ) ) if( ( clgame.msg[i].number == svc_num ) && Q_stricmp( clgame.msg[i].name, pszName ) )
clgame.msg[i].number = 0; clgame.msg[i].number = 0;
} }
@@ -1072,9 +1054,7 @@ free studio cache on change level
*/ */
void CL_ClearSpriteTextures( void ) void CL_ClearSpriteTextures( void )
{ {
int i; for( int i = 1; i < MAX_CLIENT_SPRITES; i++ )
for( i = 1; i < MAX_CLIENT_SPRITES; i++ )
{ {
if( clgame.sprites[i].needload == NL_UNREFERENCED ) if( clgame.sprites[i].needload == NL_UNREFERENCED )
continue; continue;
@@ -1212,8 +1192,6 @@ upload sprite frames
*/ */
static qboolean CL_LoadHudSprite( const char *szSpriteName, model_t *m_pSprite, uint type, uint texFlags ) static qboolean CL_LoadHudSprite( const char *szSpriteName, model_t *m_pSprite, uint type, uint texFlags )
{ {
byte *buf;
fs_offset_t size;
qboolean loaded; qboolean loaded;
Assert( m_pSprite != NULL ); Assert( m_pSprite != NULL );
@@ -1243,7 +1221,8 @@ static qboolean CL_LoadHudSprite( const char *szSpriteName, model_t *m_pSprite,
} }
} }
buf = FS_LoadFile( szSpriteName, &size, false ); fs_offset_t size;
byte *buf = FS_LoadFile( szSpriteName, &size, false );
if( buf == NULL ) if( buf == NULL )
return false; return false;
@@ -1280,7 +1259,7 @@ static model_t *CL_LoadSpriteModel( const char *filename, uint type, uint texFla
{ {
char name[MAX_QPATH]; char name[MAX_QPATH];
model_t *mod; model_t *mod;
int i, start; int i;
if( COM_StringEmptyOrNULL( filename )) if( COM_StringEmptyOrNULL( filename ))
{ {
@@ -1310,7 +1289,7 @@ static model_t *CL_LoadSpriteModel( const char *filename, uint type, uint texFla
// find a free model slot spot // find a free model slot spot
// use low indices only for HUD sprites // use low indices only for HUD sprites
// for GoldSrc bug compatibility // for GoldSrc bug compatibility
start = type == SPR_HUDSPRITE ? 0 : MAX_CLIENT_SPRITES / 2; int start = type == SPR_HUDSPRITE ? 0 : MAX_CLIENT_SPRITES / 2;
for( i = 0, mod = &clgame.sprites[start]; i < MAX_CLIENT_SPRITES / 2; i++, mod++ ) for( i = 0, mod = &clgame.sprites[start]; i < MAX_CLIENT_SPRITES / 2; i++, mod++ )
{ {
@@ -1356,9 +1335,9 @@ pfnSPR_LoadExt
*/ */
HSPRITE pfnSPR_LoadExt( const char *szPicName, uint texFlags ) HSPRITE pfnSPR_LoadExt( const char *szPicName, uint texFlags )
{ {
model_t *spr; model_t *spr = CL_LoadSpriteModel( szPicName, SPR_CLIENT, texFlags );
if(( spr = CL_LoadSpriteModel( szPicName, SPR_CLIENT, texFlags )) == NULL ) if( spr == NULL )
return 0; return 0;
return (spr - clgame.sprites) + 1; // return index return (spr - clgame.sprites) + 1; // return index
@@ -1374,9 +1353,9 @@ function exported for support GoldSrc Monitor utility
HSPRITE EXPORT pfnSPR_Load( const char *szPicName ); HSPRITE EXPORT pfnSPR_Load( const char *szPicName );
HSPRITE EXPORT pfnSPR_Load( const char *szPicName ) HSPRITE EXPORT pfnSPR_Load( const char *szPicName )
{ {
model_t *spr; model_t *spr = CL_LoadSpriteModel( szPicName, SPR_HUDSPRITE, 0 );
if(( spr = CL_LoadSpriteModel( szPicName, SPR_HUDSPRITE, 0 )) == NULL ) if( spr == NULL )
return 0; return 0;
return (spr - clgame.sprites) + 1; // return index return (spr - clgame.sprites) + 1; // return index
@@ -1390,16 +1369,16 @@ CL_GetSpritePointer
*/ */
static const model_t *CL_GetSpritePointer( HSPRITE hSprite ) static const model_t *CL_GetSpritePointer( HSPRITE hSprite )
{ {
model_t *mod;
int index = hSprite - 1; int index = hSprite - 1;
if( index < 0 || index >= MAX_CLIENT_SPRITES ) if( index < 0 || index >= MAX_CLIENT_SPRITES )
return NULL; // bad image return NULL; // bad image
mod = &clgame.sprites[index];
model_t *mod = &clgame.sprites[index];
if( mod->needload == NL_NEEDS_LOADED ) if( mod->needload == NL_NEEDS_LOADED )
{ {
int type = FBitSet( mod->flags, MODEL_CLIENT ) ? SPR_HUDSPRITE : SPR_MAPSPRITE; int type = FBitSet( mod->flags, MODEL_CLIENT ) ? SPR_HUDSPRITE : SPR_MAPSPRITE;
if( CL_LoadHudSprite( mod->name, mod, type, mod->numtexinfo )) if( CL_LoadHudSprite( mod->name, mod, type, mod->numtexinfo ))
return mod; return mod;
@@ -1868,8 +1847,6 @@ pfnGetPlayerInfo
*/ */
static void GAME_EXPORT pfnGetPlayerInfo( int ent_num, hud_player_info_t *pinfo ) static void GAME_EXPORT pfnGetPlayerInfo( int ent_num, hud_player_info_t *pinfo )
{ {
player_info_t *player;
ent_num -= 1; // player list if offset by 1 from ents ent_num -= 1; // player list if offset by 1 from ents
if( ent_num >= cl.maxclients || ent_num < 0 || !cl.players[ent_num].name[0] ) if( ent_num >= cl.maxclients || ent_num < 0 || !cl.players[ent_num].name[0] )
@@ -1879,7 +1856,7 @@ static void GAME_EXPORT pfnGetPlayerInfo( int ent_num, hud_player_info_t *pinfo
return; return;
} }
player = &cl.players[ent_num]; player_info_t *player = &cl.players[ent_num];
pinfo->thisplayer = ( ent_num == cl.playernum ) ? true : false; pinfo->thisplayer = ( ent_num == cl.playernum ) ? true : false;
pinfo->name = player->name; pinfo->name = player->name;
pinfo->model = player->model; pinfo->model = player->model;
@@ -1910,11 +1887,9 @@ pfnPlaySoundByIndex
*/ */
static void GAME_EXPORT pfnPlaySoundByIndex( int iSound, float volume ) static void GAME_EXPORT pfnPlaySoundByIndex( int iSound, float volume )
{ {
int hSound;
// make sure what we in-bounds // make sure what we in-bounds
iSound = bound( 0, iSound, MAX_SOUNDS ); iSound = bound( 0, iSound, MAX_SOUNDS );
hSound = cl.sound_index[iSound]; int hSound = cl.sound_index[iSound];
if( !hSound ) return; if( !hSound ) return;
S_StartSound( NULL, cl.viewentity, CHAN_ITEM, hSound, volume, ATTN_NORM, PITCH_NORM, SND_STOP_LOOPING ); S_StartSound( NULL, cl.viewentity, CHAN_ITEM, hSound, volume, ATTN_NORM, PITCH_NORM, SND_STOP_LOOPING );
@@ -2200,8 +2175,6 @@ pfnCalcShake
static void GAME_EXPORT pfnCalcShake( void ) static void GAME_EXPORT pfnCalcShake( void )
{ {
screen_shake_t *const shake = &clgame.shake; screen_shake_t *const shake = &clgame.shake;
float frametime, fraction, freq;
int i;
if( cl.time > shake->time || shake->amplitude <= 0 || shake->frequency <= 0 || shake->duration <= 0 ) if( cl.time > shake->time || shake->amplitude <= 0 || shake->frequency <= 0 || shake->duration <= 0 )
{ {
@@ -2216,7 +2189,7 @@ static void GAME_EXPORT pfnCalcShake( void )
return; return;
} }
frametime = cl_clientframetime(); float frametime = cl_clientframetime();
if( cl.time > shake->next_shake ) if( cl.time > shake->next_shake )
{ {
@@ -2224,20 +2197,20 @@ static void GAME_EXPORT pfnCalcShake( void )
shake->next_shake = (float)cl.time + shake->frequency / shake->duration; shake->next_shake = (float)cl.time + shake->frequency / shake->duration;
// randomize each shake // randomize each shake
for( i = 0; i < 3; i++ ) for( int i = 0; i < 3; i++ )
shake->offset[i] = COM_RandomFloat( -shake->amplitude, shake->amplitude ); shake->offset[i] = COM_RandomFloat( -shake->amplitude, shake->amplitude );
shake->angle = COM_RandomFloat( -shake->amplitude * 0.25f, shake->amplitude * 0.25f ); shake->angle = COM_RandomFloat( -shake->amplitude * 0.25f, shake->amplitude * 0.25f );
} }
// get initial fraction and frequency values over the duration // get initial fraction and frequency values over the duration
fraction = ((float)cl.time - shake->time ) / shake->duration; float fraction = ((float)cl.time - shake->time ) / shake->duration;
freq = fraction != 0.0f ? ( shake->frequency / fraction ) * shake->frequency : 0.0f; float freq = fraction != 0.0f ? ( shake->frequency / fraction ) * shake->frequency : 0.0f;
// quickly approach zero but apply time over sine wave // quickly approach zero but apply time over sine wave
fraction *= fraction * sin( cl.time * freq ); fraction *= fraction * sin( cl.time * freq );
// apply shake offset // apply shake offset
for( i = 0; i < 3; i++ ) for( int i = 0; i < 3; i++ )
shake->applied_offset[i] = shake->offset[i] * fraction; shake->applied_offset[i] = shake->offset[i] * fraction;
// apply roll angle // apply roll angle
@@ -2349,10 +2322,7 @@ pfnKillEvent
*/ */
static void GAME_EXPORT pfnKillEvents( int entnum, const char *eventname ) static void GAME_EXPORT pfnKillEvents( int entnum, const char *eventname )
{ {
int i; word eventIndex = CL_EventIndex( eventname );
event_state_t *es;
event_info_t *ei;
word eventIndex = CL_EventIndex( eventname );
if( eventIndex >= MAX_EVENTS ) if( eventIndex >= MAX_EVENTS )
return; return;
@@ -2360,12 +2330,12 @@ static void GAME_EXPORT pfnKillEvents( int entnum, const char *eventname )
if( entnum < 0 || entnum >= clgame.maxEntities ) if( entnum < 0 || entnum >= clgame.maxEntities )
return; return;
es = &cl.events; event_state_t *es = &cl.events;
// find all events with specified index and kill it // find all events with specified index and kill it
for( i = 0; i < MAX_EVENT_QUEUE; i++ ) for( int i = 0; i < MAX_EVENT_QUEUE; i++ )
{ {
ei = &es->ei[i]; event_info_t *ei = &es->ei[i];
if( ei->index == eventIndex && ei->entity_index == entnum ) if( ei->index == eventIndex && ei->entity_index == entnum )
{ {
@@ -2395,7 +2365,6 @@ CL_FindModelIndex
static int GAME_EXPORT CL_FindModelIndex( const char *m ) static int GAME_EXPORT CL_FindModelIndex( const char *m )
{ {
char filepath[MAX_QPATH]; char filepath[MAX_QPATH];
int i;
if( COM_StringEmptyOrNULL( m )) if( COM_StringEmptyOrNULL( m ))
return 0; return 0;
@@ -2403,7 +2372,7 @@ static int GAME_EXPORT CL_FindModelIndex( const char *m )
Q_strncpy( filepath, m, sizeof( filepath )); Q_strncpy( filepath, m, sizeof( filepath ));
COM_FixSlashes( filepath ); COM_FixSlashes( filepath );
for( i = 0; i < cl.nummodels; i++ ) for( int i = 0; i < cl.nummodels; i++ )
{ {
if( !cl.models[i+1] ) if( !cl.models[i+1] )
continue; continue;
@@ -2735,9 +2704,7 @@ pfnLoadMapSprite
*/ */
static model_t *pfnLoadMapSprite( const char *filename ) static model_t *pfnLoadMapSprite( const char *filename )
{ {
model_t *mod; model_t *mod = Mod_FindName( filename, false );
mod = Mod_FindName( filename, false );
if( CL_LoadHudSprite( filename, mod, SPR_MAPSPRITE, 0 )) if( CL_LoadHudSprite( filename, mod, SPR_MAPSPRITE, 0 ))
return mod; return mod;
@@ -2813,12 +2780,10 @@ PlayerInfo_SetValueForKey
*/ */
static void GAME_EXPORT PlayerInfo_SetValueForKey( const char *key, const char *value ) static void GAME_EXPORT PlayerInfo_SetValueForKey( const char *key, const char *value )
{ {
convar_t *var;
if( !Q_strcmp( Info_ValueForKey( cls.userinfo, key ), value )) if( !Q_strcmp( Info_ValueForKey( cls.userinfo, key ), value ))
return; // no changes ? return; // no changes ?
var = Cvar_FindVar( key ); convar_t *var = Cvar_FindVar( key );
if( var && FBitSet( var->flags, FCVAR_USERINFO )) if( var && FBitSet( var->flags, FCVAR_USERINFO ))
{ {
@@ -2899,11 +2864,10 @@ pfnGetMousePos
*/ */
static void GAME_EXPORT pfnGetMousePos( struct tagPOINT *ppt ) static void GAME_EXPORT pfnGetMousePos( struct tagPOINT *ppt )
{ {
int x, y;
if( !ppt ) if( !ppt )
return; return;
int x, y;
Platform_GetMousePos( &x, &y ); Platform_GetMousePos( &x, &y );
ppt->x = x; ppt->x = x;
@@ -3052,11 +3016,11 @@ static int GAME_EXPORT pfnDrawStringReverse( int x, int y, const char *str, int
{ {
rgba_t color = { r, g, b, 255 }; rgba_t color = { r, g, b, 255 };
int flags = FONT_DRAW_HUD | FONT_DRAW_NOLF; int flags = FONT_DRAW_HUD | FONT_DRAW_NOLF;
int width;
if( hud_utf8.value ) if( hud_utf8.value )
SetBits( flags, FONT_DRAW_UTF8 ); SetBits( flags, FONT_DRAW_UTF8 );
int width;
CL_DrawStringLen( &cls.creditsFont, str, &width, NULL, flags ); CL_DrawStringLen( &cls.creditsFont, str, &width, NULL, flags );
x -= width; x -= width;
@@ -3236,11 +3200,9 @@ TriBrightness
*/ */
void TriBrightness( float brightness ) void TriBrightness( float brightness )
{ {
float r, g, b; float r = clgame.ds.triRGBA[0] * clgame.ds.triRGBA[3] * brightness;
float g = clgame.ds.triRGBA[1] * clgame.ds.triRGBA[3] * brightness;
r = clgame.ds.triRGBA[0] * clgame.ds.triRGBA[3] * brightness; float b = clgame.ds.triRGBA[2] * clgame.ds.triRGBA[3] * brightness;
g = clgame.ds.triRGBA[1] * clgame.ds.triRGBA[3] * brightness;
b = clgame.ds.triRGBA[2] * clgame.ds.triRGBA[3] * brightness;
ref.dllFuncs.Color4f( r, g, b, 1.0f ); ref.dllFuncs.Color4f( r, g, b, 1.0f );
} }
@@ -3287,11 +3249,9 @@ NOTE: dlights are ignored
*/ */
void TriLightAtPoint( float *pos, float *value ) void TriLightAtPoint( float *pos, float *value )
{ {
colorVec vLightColor;
if( !pos || !value ) return; if( !pos || !value ) return;
vLightColor = ref.dllFuncs.R_LightPoint( pos ); colorVec vLightColor = ref.dllFuncs.R_LightPoint( pos );
value[0] = vLightColor.r; value[0] = vLightColor.r;
value[1] = vLightColor.g; value[1] = vLightColor.g;
@@ -3324,9 +3284,9 @@ bind current texture
*/ */
int TriSpriteTexture( model_t *pSpriteModel, int frame ) int TriSpriteTexture( model_t *pSpriteModel, int frame )
{ {
int gl_texturenum; int gl_texturenum = R_GetSpriteTexture( pSpriteModel, frame );
if(( gl_texturenum = R_GetSpriteTexture( pSpriteModel, frame )) <= 0 ) if( gl_texturenum <= 0 )
return 0; return 0;
ref.dllFuncs.GL_Bind( XASH_TEXTURE0, gl_texturenum ); ref.dllFuncs.GL_Bind( XASH_TEXTURE0, gl_texturenum );
@@ -3467,13 +3427,10 @@ NetAPI_CancelRequest
*/ */
static void GAME_EXPORT NetAPI_CancelRequest( int context ) static void GAME_EXPORT NetAPI_CancelRequest( int context )
{ {
net_request_t *nr;
int i;
;
// find a specified request // find a specified request
for( i = 0; i < MAX_REQUESTS; i++ ) for( int i = 0; i < MAX_REQUESTS; i++ )
{ {
nr = &clgame.net_requests[i]; net_request_t *nr = &clgame.net_requests[i];
if( clgame.net_requests[i].resp.context == context ) if( clgame.net_requests[i].resp.context == context )
{ {
@@ -3498,13 +3455,10 @@ NetAPI_CancelAllRequests
*/ */
void GAME_EXPORT NetAPI_CancelAllRequests( void ) void GAME_EXPORT NetAPI_CancelAllRequests( void )
{ {
net_request_t *nr;
int i;
// tell the user about cancel // tell the user about cancel
for( i = 0; i < MAX_REQUESTS; i++ ) for( int i = 0; i < MAX_REQUESTS; i++ )
{ {
nr = &clgame.net_requests[i]; net_request_t *nr = &clgame.net_requests[i];
if( !nr->pfnFunc ) continue; // not used if( !nr->pfnFunc ) continue; // not used
SetBits( nr->resp.error, NET_ERROR_TIMEOUT ); SetBits( nr->resp.error, NET_ERROR_TIMEOUT );
nr->resp.ping = host.realtime - nr->timesend; nr->resp.ping = host.realtime - nr->timesend;
@@ -3614,6 +3568,16 @@ static void GAME_EXPORT VGui_ViewportPaintBackground( int extents[4] )
// stub // stub
} }
static cvar_t* GAME_EXPORT CL_CvarGetPointer( const char *szVarName )
{
cvar_t *result = (cvar_t *)Cvar_FindVar( szVarName );
if( !result )
Con_DPrintf( S_WARN "%s: client tried to get non-existent cvar \"%s\"\n", __func__, szVarName );
return result;
}
// shared between client and server // shared between client and server
triangleapi_t gTriApi; triangleapi_t gTriApi;
@@ -3836,7 +3800,7 @@ static cl_enginefunc_t gEngfuncs =
pfnHookEvent, pfnHookEvent,
Con_Visible, Con_Visible,
pfnGetGameDirectory, pfnGetGameDirectory,
pfnCVarGetPointer, CL_CvarGetPointer,
Key_LookupBinding, Key_LookupBinding,
pfnGetLevelName, pfnGetLevelName,
pfnGetScreenFade, pfnGetScreenFade,
@@ -3970,7 +3934,7 @@ static engine_studio_api_t gStudioAPI =
.Mod_ForName = pfnStudio_Mod_ForName, .Mod_ForName = pfnStudio_Mod_ForName,
.Mod_Extradata = pfnStudio_Mod_Extradata, .Mod_Extradata = pfnStudio_Mod_Extradata,
.GetModelByIndex = CL_ModelHandle, .GetModelByIndex = CL_ModelHandle,
.GetCvar = pfnCVarGetPointer, .GetCvar = CL_CvarGetPointer,
.GetChromeSprite = pfnStudio_GetChromeSprite, .GetChromeSprite = pfnStudio_GetChromeSprite,
.GetAliasScale = pfnStudio_GetAliasScale, .GetAliasScale = pfnStudio_GetAliasScale,
.StudioGetAliasTransform = pfnStudio_GetAliasTransform, .StudioGetAliasTransform = pfnStudio_GetAliasTransform,
@@ -3981,12 +3945,11 @@ static engine_studio_api_t gStudioAPI =
static void CL_InitStudioAPI( void ) static void CL_InitStudioAPI( void )
{ {
static r_studio_interface_t gDefaultStudioDraw; static r_studio_interface_t gDefaultStudioDraw;
r_studio_interface_t *pStudioDraw;
if( !ref.dllFuncs.R_StudioFillAPI( &gStudioAPI, &gDefaultStudioDraw )) if( !ref.dllFuncs.R_StudioFillAPI( &gStudioAPI, &gDefaultStudioDraw ))
return; return;
pStudioDraw = &gDefaultStudioDraw; r_studio_interface_t *pStudioDraw = &gDefaultStudioDraw;
if( clgame.dllFuncs.pfnGetStudioModelInterface ) if( clgame.dllFuncs.pfnGetStudioModelInterface )
clgame.dllFuncs.pfnGetStudioModelInterface( STUDIO_INTERFACE_VERSION, &pStudioDraw, &gStudioAPI ); clgame.dllFuncs.pfnGetStudioModelInterface( STUDIO_INTERFACE_VERSION, &pStudioDraw, &gStudioAPI );
@@ -4001,7 +3964,6 @@ qboolean CL_LoadProgs( const char *name )
qboolean valid_single_export = false; qboolean valid_single_export = false;
qboolean missed_exports = false; qboolean missed_exports = false;
qboolean try_internal_vgui_support = GI->internal_vgui_support; qboolean try_internal_vgui_support = GI->internal_vgui_support;
int i;
if( clgame.hInstance ) CL_UnloadProgs(); if( clgame.hInstance ) CL_UnloadProgs();
@@ -4057,7 +4019,7 @@ qboolean CL_LoadProgs( const char *name )
if( GetClientAPI != NULL ) // check critical functions again if( GetClientAPI != NULL ) // check critical functions again
valid_single_export = ValidateExports( cdll_exports, ARRAYSIZE( cdll_exports )); valid_single_export = ValidateExports( cdll_exports, ARRAYSIZE( cdll_exports ));
for( i = 0; i < ARRAYSIZE( cdll_exports ); i++ ) for( int i = 0; i < ARRAYSIZE( cdll_exports ); i++ )
{ {
if( *(cdll_exports[i].func) != NULL ) if( *(cdll_exports[i].func) != NULL )
continue; // already got through 'F' or 'GetClientAPI' continue; // already got through 'F' or 'GetClientAPI'
@@ -4088,7 +4050,7 @@ qboolean CL_LoadProgs( const char *name )
if( !valid_single_export ) if( !valid_single_export )
ClearExports( cdll_new_exports, ARRAYSIZE( cdll_new_exports )); ClearExports( cdll_new_exports, ARRAYSIZE( cdll_new_exports ));
for( i = 0; i < ARRAYSIZE( cdll_new_exports ); i++ ) for( int i = 0; i < ARRAYSIZE( cdll_new_exports ); i++ )
{ {
if( *(cdll_new_exports[i].func) != NULL ) if( *(cdll_new_exports[i].func) != NULL )
continue; // already gott through 'F' or 'GetClientAPI' continue; // already gott through 'F' or 'GetClientAPI'
+15 -18
View File
@@ -78,8 +78,6 @@ void UI_MouseMove( int x, int y )
void UI_SetActiveMenu( qboolean fActive ) void UI_SetActiveMenu( qboolean fActive )
{ {
movie_state_t *cin_state;
if( !gameui.hInstance ) if( !gameui.hInstance )
{ {
if( !fActive ) if( !fActive )
@@ -93,7 +91,7 @@ void UI_SetActiveMenu( qboolean fActive )
if( !fActive ) if( !fActive )
{ {
// close logo when menu is shutdown // close logo when menu is shutdown
cin_state = AVI_GetState( CIN_LOGO ); movie_state_t *cin_state = AVI_GetState( CIN_LOGO );
AVI_CloseVideo( cin_state ); AVI_CloseVideo( cin_state );
} }
} }
@@ -356,12 +354,10 @@ static float GAME_EXPORT UI_GetLogoLength( void )
static void UI_UpdateUserinfo( void ) static void UI_UpdateUserinfo( void )
{ {
player_info_t *player;
if( !host.userinfo_changed ) if( !host.userinfo_changed )
return; return;
player = &gameui.playerinfo; player_info_t *player = &gameui.playerinfo;
Q_strncpy( player->userinfo, cls.userinfo, sizeof( player->userinfo )); Q_strncpy( player->userinfo, cls.userinfo, sizeof( player->userinfo ));
Q_strncpy( player->name, Info_ValueForKey( player->userinfo, "name" ), sizeof( player->name )); Q_strncpy( player->name, Info_ValueForKey( player->userinfo, "name" ), sizeof( player->name ));
@@ -427,10 +423,8 @@ static void UI_ToOldGameInfo( GAMEINFO *out, const gameinfo2_t *in )
static void UI_GetModsInfo( void ) static void UI_GetModsInfo( void )
{ {
int i;
gameui.modsInfo = Mem_Calloc( gameui.mempool, sizeof( *gameui.modsInfo ) * FI->numgames ); gameui.modsInfo = Mem_Calloc( gameui.mempool, sizeof( *gameui.modsInfo ) * FI->numgames );
for( i = 0; i < FI->numgames; i++ ) for( int i = 0; i < FI->numgames; i++ )
UI_ConvertGameInfo( &gameui.modsInfo[i], FI->games[i] ); UI_ConvertGameInfo( &gameui.modsInfo[i], FI->games[i] );
} }
@@ -755,10 +749,9 @@ drawing string like a console string
*/ */
static int GAME_EXPORT UI_DrawConsoleString( int x, int y, const char *string ) static int GAME_EXPORT UI_DrawConsoleString( int x, int y, const char *string )
{ {
int drawLen;
if( !string || !*string ) return 0; // silent ignore if( !string || !*string ) return 0; // silent ignore
drawLen = Con_DrawString( x, y, string, gameui.ds.textColor );
int drawLen = Con_DrawString( x, y, string, gameui.ds.textColor );
MakeRGBA( gameui.ds.textColor, 255, 255, 255, 255 ); MakeRGBA( gameui.ds.textColor, 255, 255, 255, 255 );
return (x + drawLen); // exclude color prexfixes return (x + drawLen); // exclude color prexfixes
@@ -958,14 +951,12 @@ static GAMEINFO ** GAME_EXPORT pfnGetGamesList( int *numGames )
if( !gameui.oldModsInfo ) if( !gameui.oldModsInfo )
{ {
int i;
if( !gameui.modsInfo ) if( !gameui.modsInfo )
UI_GetModsInfo(); UI_GetModsInfo();
// first allocate array of pointers // first allocate array of pointers
gameui.oldModsInfo = Mem_Calloc( gameui.mempool, sizeof( *gameui.oldModsInfo ) * FI->numgames ); gameui.oldModsInfo = Mem_Calloc( gameui.mempool, sizeof( *gameui.oldModsInfo ) * FI->numgames );
for( i = 0; i < FI->numgames; i++ ) for( int i = 0; i < FI->numgames; i++ )
{ {
gameui.oldModsInfo[i] = Mem_Calloc( gameui.mempool, sizeof( *gameui.oldModsInfo[i] )); gameui.oldModsInfo[i] = Mem_Calloc( gameui.mempool, sizeof( *gameui.oldModsInfo[i] ));
UI_ToOldGameInfo( gameui.oldModsInfo[i], &gameui.modsInfo[i] ); UI_ToOldGameInfo( gameui.oldModsInfo[i], &gameui.modsInfo[i] );
@@ -1135,12 +1126,10 @@ static void GAME_EXPORT pfnCon_DefaultColor( int r, int g, int b )
static void GAME_EXPORT pfnSetCursor( void *hCursor ) static void GAME_EXPORT pfnSetCursor( void *hCursor )
{ {
uintptr_t cursor;
if( !gameui.use_extended_api ) if( !gameui.use_extended_api )
return; // ignore original Xash menus return; // ignore original Xash menus
cursor = (uintptr_t)hCursor; uintptr_t cursor = (uintptr_t)hCursor;
if( cursor < dc_user || cursor > dc_last ) if( cursor < dc_user || cursor > dc_last )
return; return;
@@ -1335,6 +1324,14 @@ void UI_UnloadProgs( void )
memset( &gameui, 0, sizeof( gameui )); memset( &gameui, 0, sizeof( gameui ));
} }
void *UI_GetMenuFactory( void )
{
if( !gameui.hInstance )
return NULL;
return COM_GetProcAddress( gameui.hInstance, "CreateInterface" );
}
qboolean UI_LoadProgs( void ) qboolean UI_LoadProgs( void )
{ {
static ui_enginefuncs_t gpEngfuncs; static ui_enginefuncs_t gpEngfuncs;
+1 -3
View File
@@ -63,12 +63,10 @@ static int pfnDrawScaledCharacter( int x, int y, int number, int r, int g, int b
if( fabs( g_font_scale - scale ) > 0.1f || if( fabs( g_font_scale - scale ) > 0.1f ||
g_scaled_font.hFontTexture != cls.creditsFont.hFontTexture ) g_scaled_font.hFontTexture != cls.creditsFont.hFontTexture )
{ {
int i;
g_scaled_font = cls.creditsFont; g_scaled_font = cls.creditsFont;
g_scaled_font.scale *= scale; g_scaled_font.scale *= scale;
g_scaled_font.charHeight *= scale; g_scaled_font.charHeight *= scale;
for( i = 0; i < ARRAYSIZE( g_scaled_font.charWidths ); i++ ) for( int i = 0; i < ARRAYSIZE( g_scaled_font.charWidths ); i++ )
g_scaled_font.charWidths[i] *= scale; g_scaled_font.charWidths[i] *= scale;
g_font_scale = scale; g_font_scale = scale;
+25 -39
View File
@@ -101,10 +101,9 @@ CL_SetIdealPitch
void CL_SetIdealPitch( void ) void CL_SetIdealPitch( void )
{ {
float angleval, sinval, cosval; float angleval, sinval, cosval;
int i, j, step, dir, steps; int i, dir, steps;
float z[MAX_FORWARD]; float z[MAX_FORWARD];
vec3_t top, bottom; vec3_t top, bottom;
pmtrace_t tr;
if( cl.local.onground == -1 ) if( cl.local.onground == -1 )
return; return;
@@ -116,6 +115,8 @@ void CL_SetIdealPitch( void )
// 160 or so units to see what's below // 160 or so units to see what's below
for( i = 0; i < MAX_FORWARD; i++ ) for( i = 0; i < MAX_FORWARD; i++ )
{ {
pmtrace_t tr;
top[0] = cl.simorg[0] + cosval * (i + 3.0f) * 12.0f; top[0] = cl.simorg[0] + cosval * (i + 3.0f) * 12.0f;
top[1] = cl.simorg[1] + sinval * (i + 3.0f) * 12.0f; top[1] = cl.simorg[1] + sinval * (i + 3.0f) * 12.0f;
top[2] = cl.simorg[2] + cl.viewheight[2]; top[2] = cl.simorg[2] + cl.viewheight[2];
@@ -137,9 +138,10 @@ void CL_SetIdealPitch( void )
dir = 0; dir = 0;
steps = 0; steps = 0;
for( j = 1; j < i; j++ ) for( int j = 1; j < i; j++ )
{ {
step = z[j] - z[j-1]; int step = z[j] - z[j-1];
if( step > -ON_EPSILON && step < ON_EPSILON ) if( step > -ON_EPSILON && step < ON_EPSILON )
continue; continue;
@@ -244,15 +246,10 @@ This sets up the first phase.
*/ */
void GAME_EXPORT CL_SetUpPlayerPrediction( int dopred, int bIncludeLocalClient ) void GAME_EXPORT CL_SetUpPlayerPrediction( int dopred, int bIncludeLocalClient )
{ {
entity_state_t *state; for( int i = 0; i < MAX_CLIENTS; i++ )
predicted_player_t *player;
cl_entity_t *ent;
int i;
for( i = 0; i < MAX_CLIENTS; i++ )
{ {
state = &cl.frames[cl.parsecountmod].playerstate[i]; entity_state_t *state = &cl.frames[cl.parsecountmod].playerstate[i];
player = &cls.predicted_players[i]; predicted_player_t *player = &cls.predicted_players[i];
player->active = false; player->active = false;
@@ -279,7 +276,7 @@ void GAME_EXPORT CL_SetUpPlayerPrediction( int dopred, int bIncludeLocalClient )
} }
else else
{ {
ent = CL_GetEntityByIndex( i + 1 ); cl_entity_t *ent = CL_GetEntityByIndex( i + 1 );
CL_ComputePlayerOrigin( ent ); CL_ComputePlayerOrigin( ent );
@@ -397,16 +394,13 @@ collect solid entities
*/ */
static void CL_AddLinksToPmove( frame_t *frame ) static void CL_AddLinksToPmove( frame_t *frame )
{ {
entity_state_t *state;
model_t *model;
physent_t *pe;
int i;
if( !frame->valid ) return; if( !frame->valid ) return;
for( i = 0; i < frame->num_entities; i++ ) for( int i = 0; i < frame->num_entities; i++ )
{ {
state = &cls.packet_entities[(frame->first_entity + i) % cls.num_client_entities]; entity_state_t *state = &cls.packet_entities[(frame->first_entity + i) % cls.num_client_entities];
model_t *model;
physent_t *pe;
if( state->number >= 1 && state->number <= cl.maxclients ) if( state->number >= 1 && state->number <= cl.maxclients )
continue; continue;
@@ -506,18 +500,14 @@ pmove must be setup with world and solid entity hulls before calling
*/ */
void GAME_EXPORT CL_SetSolidPlayers( int playernum ) void GAME_EXPORT CL_SetSolidPlayers( int playernum )
{ {
entity_state_t *state;
predicted_player_t *player;
physent_t *pe;
int i;
if( !cl_solid_players.value ) if( !cl_solid_players.value )
return; return;
for( i = 0; i < MAX_CLIENTS; i++ ) for( int i = 0; i < MAX_CLIENTS; i++ )
{ {
state = &cl.frames[cl.parsecountmod].playerstate[i]; entity_state_t *state = &cl.frames[cl.parsecountmod].playerstate[i];
player = &cls.predicted_players[i]; predicted_player_t *player = &cls.predicted_players[i];
physent_t *pe;
if( playernum == -1 ) if( playernum == -1 )
{ {
@@ -562,18 +552,17 @@ CL_WaterEntity
*/ */
int GAME_EXPORT CL_WaterEntity( const float *rgflPos ) int GAME_EXPORT CL_WaterEntity( const float *rgflPos )
{ {
physent_t *pe; int oldhull;
hull_t *hull;
vec3_t test, offset;
int i, oldhull;
if( !rgflPos ) return -1; if( !rgflPos ) return -1;
oldhull = clgame.pmove->usehull; oldhull = clgame.pmove->usehull;
for( i = 0; i < clgame.pmove->numphysent; i++ ) for( int i = 0; i < clgame.pmove->numphysent; i++ )
{ {
pe = &clgame.pmove->physents[i]; physent_t *pe = &clgame.pmove->physents[i];
hull_t *hull;
vec3_t test, offset;
if( pe->solid != SOLID_NOT ) // disabled ? if( pe->solid != SOLID_NOT ) // disabled ?
continue; continue;
@@ -657,9 +646,8 @@ returns water brush where inside pos
*/ */
cl_entity_t *CL_GetWaterEntity( const float *rgflPos ) cl_entity_t *CL_GetWaterEntity( const float *rgflPos )
{ {
int entnum; int entnum = CL_WaterEntity( rgflPos );
entnum = CL_WaterEntity( rgflPos );
if( entnum <= 0 ) return NULL; // world or not water if( entnum <= 0 ) return NULL; // world or not water
return CL_GetEntityByIndex( entnum ); return CL_GetEntityByIndex( entnum );
@@ -732,8 +720,6 @@ CL_InitClientMove
*/ */
void CL_InitClientMove( void ) void CL_InitClientMove( void )
{ {
int i;
Pmove_Init (); Pmove_Init ();
clgame.pmove->server = false; // running at client clgame.pmove->server = false; // running at client
@@ -741,7 +727,7 @@ void CL_InitClientMove( void )
clgame.pmove->runfuncs = false; clgame.pmove->runfuncs = false;
// enumerate client hulls // enumerate client hulls
for( i = 0; i < MAX_MAP_HULLS; i++ ) for( int i = 0; i < MAX_MAP_HULLS; i++ )
{ {
if( clgame.dllFuncs.pfnGetHullBounds( i, host.player_mins[i], host.player_maxs[i] )) if( clgame.dllFuncs.pfnGetHullBounds( i, host.player_mins[i], host.player_maxs[i] ))
Con_Reportf( "CL: hull%i, player_mins: %g %g %g, player_maxs: %g %g %g\n", i, Con_Reportf( "CL: hull%i, player_mins: %g %g %g, player_maxs: %g %g %g\n", i,
+5 -10
View File
@@ -72,18 +72,15 @@ static qboolean CheckSkybox( const char *name, char out[SKYBOX_MAX_SIDES][MAX_ST
{ {
static const char *skybox_ext[3] = { "dds", "tga", "bmp" }; static const char *skybox_ext[3] = { "dds", "tga", "bmp" };
static const char *skybox_delim[2] = { "", "_" }; // no space for HL style, underscore for Q1 style static const char *skybox_delim[2] = { "", "_" }; // no space for HL style, underscore for Q1 style
int i;
// search for skybox images // search for skybox images
for( i = 0; i < ARRAYSIZE( skybox_ext ); i++ ) for( int i = 0; i < ARRAYSIZE( skybox_ext ); i++ )
{ {
int j; for( int j = 0; j < ARRAYSIZE( skybox_delim ); j++ )
for( j = 0; j < ARRAYSIZE( skybox_delim ); j++ )
{ {
int k, num_checked_sides = 0; int num_checked_sides = 0;
for( k = 0; k < SKYBOX_MAX_SIDES; k++ ) for( int k = 0; k < SKYBOX_MAX_SIDES; k++ )
{ {
char sidename[MAX_VA_STRING]; char sidename[MAX_VA_STRING];
@@ -109,7 +106,6 @@ void R_SetupSky( const char *name )
char sidenames[SKYBOX_MAX_SIDES][MAX_STRING]; char sidenames[SKYBOX_MAX_SIDES][MAX_STRING];
int skyboxTextures[SKYBOX_MAX_SIDES] = { 0 }; int skyboxTextures[SKYBOX_MAX_SIDES] = { 0 };
int i, len; int i, len;
qboolean result;
if( COM_StringEmptyOrNULL( name )) if( COM_StringEmptyOrNULL( name ))
{ {
@@ -125,10 +121,9 @@ void R_SetupSky( const char *name )
if( loadname[len - 1] == '_' ) if( loadname[len - 1] == '_' )
loadname[len - 1] = '\0'; loadname[len - 1] = '\0';
result = CheckSkybox( loadname, sidenames );
// to prevent infinite recursion if default skybox was missed // to prevent infinite recursion if default skybox was missed
if( !result && Q_stricmp( name, DEFAULT_SKYBOX_NAME )) if( !CheckSkybox( loadname, sidenames ) && Q_stricmp( name, DEFAULT_SKYBOX_NAME ))
{ {
Con_Reportf( S_WARN "missed or incomplete skybox '%s'\n", name ); Con_Reportf( S_WARN "missed or incomplete skybox '%s'\n", name );
R_SetupSky( DEFAULT_SKYBOX_NAME ); // force to default R_SetupSky( DEFAULT_SKYBOX_NAME ); // force to default
+5 -10
View File
@@ -35,7 +35,6 @@ static CVAR_DEFINE( v_gamma, "gamma", "2.5", FCVAR_ARCHIVE, "gamma amount" );
static void BuildGammaTable( const float gamma, const float brightness, const float texgamma, const float lightgamma ) static void BuildGammaTable( const float gamma, const float brightness, const float texgamma, const float lightgamma )
{ {
float g1, g2, g3; float g1, g2, g3;
int i;
if( gamma != 0.0 ) if( gamma != 0.0 )
g1 = 1.0 / gamma; g1 = 1.0 / gamma;
@@ -50,7 +49,7 @@ static void BuildGammaTable( const float gamma, const float brightness, const fl
else else
g3 = 0.05; g3 = 0.05;
for( i = 0; i < 256; i++ ) for( int i = 0; i < 256; i++ )
{ {
// keep it float or texgamma test will fail with -ffast-math // keep it float or texgamma test will fail with -ffast-math
float d = pow( i / 255.0, (double)g2 ); float d = pow( i / 255.0, (double)g2 );
@@ -58,11 +57,9 @@ static void BuildGammaTable( const float gamma, const float brightness, const fl
texgammatable[i] = bound( 0, inf, 255 ); texgammatable[i] = bound( 0, inf, 255 );
} }
for( i = 0; i < 1024; i++ ) for( int i = 0; i < 1024; i++ )
{ {
double d;
float f = pow( i / 1023.0, (double)lightgamma ); float f = pow( i / 1023.0, (double)lightgamma );
int inf;
if( brightness > 1.0 ) if( brightness > 1.0 )
f *= brightness; f *= brightness;
@@ -72,8 +69,8 @@ static void BuildGammaTable( const float gamma, const float brightness, const fl
else else
f = (( f - g3 ) / ( 1.0 - g3 )) * 0.875 + 0.125; f = (( f - g3 ) / ( 1.0 - g3 )) * 0.875 + 0.125;
d = pow( (double)f, (double)g1 ); // do not remove the cast, or tests fail double d = pow( (double)f, (double)g1 ); // do not remove the cast, or tests fail
inf = d * 1023.0; int inf = d * 1023.0;
lightgammatable[i] = bound( 0, inf, 1023 ); lightgammatable[i] = bound( 0, inf, 1023 );
// do these calculations in the same loop... // do these calculations in the same loop...
@@ -255,11 +252,9 @@ static void Test_PrecomputedGammaTables( void )
while(( data = Test_GetGammaTables( i ))) while(( data = Test_GetGammaTables( i )))
{ {
int j;
BuildGammaTable( data->gamma, data->brightness, data->texgamma, data->lightgamma ); BuildGammaTable( data->gamma, data->brightness, data->texgamma, data->lightgamma );
for( j = 0; j < 1024; j++ ) for( int j = 0; j < 1024; j++ )
{ {
if( j < 256 ) if( j < 256 )
{ {
+9 -14
View File
@@ -80,7 +80,7 @@ static uint BloomFilter_Weight( bloomfilter_t value )
return weight; return weight;
} }
static qboolean BloomFilter_ContainsString( bloomfilter_t filter, const char *str ) MAYBE_UNUSED static qboolean BloomFilter_ContainsString( bloomfilter_t filter, const char *str )
{ {
bloomfilter_t value = BloomFilter_ProcessStr( str ); bloomfilter_t value = BloomFilter_ProcessStr( str );
@@ -102,9 +102,8 @@ static qboolean ID_ProcessFile( bloomfilter_t *value, const char *path );
static void ID_BloomFilter_f( void ) static void ID_BloomFilter_f( void )
{ {
bloomfilter_t value = 0; bloomfilter_t value = 0;
int i;
for( i = 1; i < Cmd_Argc(); i++ ) for( int i = 1; i < Cmd_Argc(); i++ )
value |= BloomFilter_ProcessStr( Cmd_Argv( i ) ); value |= BloomFilter_ProcessStr( Cmd_Argv( i ) );
Msg( "%d %016"PRIX64"\n", BloomFilter_Weight( value ), value ); Msg( "%d %016"PRIX64"\n", BloomFilter_Weight( value ), value );
@@ -119,7 +118,6 @@ static qboolean ID_VerifyHEX( const char *hex )
uint chars = 0; uint chars = 0;
char prev = 0; char prev = 0;
qboolean monotonic = true; // detect 11:22... qboolean monotonic = true; // detect 11:22...
int weight = 0;
while( *hex++ ) while( *hex++ )
{ {
@@ -142,6 +140,7 @@ static qboolean ID_VerifyHEX( const char *hex )
if( monotonic ) if( monotonic )
return false; return false;
int weight = 0;
while( chars ) while( chars )
{ {
if( chars & 1 ) if( chars & 1 )
@@ -170,7 +169,7 @@ static void ID_VerifyHEX_f( void )
static qboolean ID_ProcessCPUInfo( bloomfilter_t *value ) static qboolean ID_ProcessCPUInfo( bloomfilter_t *value )
{ {
int cpuinfofd = open( "/proc/cpuinfo", O_RDONLY ); int cpuinfofd = open( "/proc/cpuinfo", O_RDONLY );
char buffer[1024], *pbuf, *pbuf2; char buffer[1024];
int ret; int ret;
if( cpuinfofd < 0 ) if( cpuinfofd < 0 )
@@ -189,12 +188,12 @@ static qboolean ID_ProcessCPUInfo( bloomfilter_t *value )
if( !ret ) if( !ret )
return false; return false;
pbuf = Q_stristr( buffer, "Serial" ); char *pbuf = Q_stristr( buffer, "Serial" );
if( !pbuf ) if( !pbuf )
return false; return false;
pbuf += 6; pbuf += 6;
pbuf2 = Q_strchrnul( pbuf, '\n' ); char *pbuf2 = Q_strchrnul( pbuf, '\n' );
*pbuf2 = 0; *pbuf2 = 0;
if( !ID_VerifyHEX( pbuf ) ) if( !ID_VerifyHEX( pbuf ) )
@@ -207,20 +206,18 @@ static qboolean ID_ProcessCPUInfo( bloomfilter_t *value )
static qboolean ID_ValidateNetDevice( const char *dev ) static qboolean ID_ValidateNetDevice( const char *dev )
{ {
const char *prefix = "/sys/class/net"; const char *prefix = "/sys/class/net";
byte *pfile;
int assignType;
// These devices are fake, their mac address is generated each boot, while assign_type is 0 // These devices are fake, their mac address is generated each boot, while assign_type is 0
if( !Q_strnicmp( dev, "ccmni", sizeof( "ccmni" ) ) || if( !Q_strnicmp( dev, "ccmni", sizeof( "ccmni" ) ) ||
!Q_strnicmp( dev, "ifb", sizeof( "ifb" ) ) ) !Q_strnicmp( dev, "ifb", sizeof( "ifb" ) ) )
return false; return false;
pfile = FS_LoadDirectFile( va( "%s/%s/addr_assign_type", prefix, dev ), NULL ); byte *pfile = FS_LoadDirectFile( va( "%s/%s/addr_assign_type", prefix, dev ), NULL );
// if NULL, it may be old kernel // if NULL, it may be old kernel
if( pfile ) if( pfile )
{ {
assignType = Q_atoi( (char*)pfile ); int assignType = Q_atoi( (char*)pfile );
Mem_Free( pfile ); Mem_Free( pfile );
@@ -500,12 +497,10 @@ static int ID_CheckWMIC( bloomfilter_t value, const wchar_t *cmdline )
pbuf = COM_ParseFile( buffer, token, sizeof( token )); // Header pbuf = COM_ParseFile( buffer, token, sizeof( token )); // Header
while(( pbuf = COM_ParseFile( pbuf, token, sizeof( token )))) while(( pbuf = COM_ParseFile( pbuf, token, sizeof( token ))))
{ {
bloomfilter_t filter;
if( !ID_VerifyHEX( token )) if( !ID_VerifyHEX( token ))
continue; continue;
filter = BloomFilter_ProcessStr( token ); bloomfilter_t filter = BloomFilter_ProcessStr( token );
count += ( filter & value ) == filter; count += ( filter & value ) == filter;
} }
+1
View File
@@ -43,6 +43,7 @@ void IN_GyroInit( void );
void IN_GyroCheckAvailability( void ); void IN_GyroCheckAvailability( void );
void IN_GyroEvent( vec3_t data ); void IN_GyroEvent( vec3_t data );
void IN_GyroFinalizeMove( float *fw, float *side, float *dpitch, float *dyaw ); void IN_GyroFinalizeMove( float *fw, float *side, float *dpitch, float *dyaw );
void IN_GyroDrawDebug( void );
uint IN_CollectInputDevices( void ); uint IN_CollectInputDevices( void );
void IN_LockInputDevices( qboolean lock ); void IN_LockInputDevices( qboolean lock );
+115 -21
View File
@@ -25,9 +25,11 @@ static CVAR_DEFINE_AUTO( gyro_roll, "0.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "bu
static CVAR_DEFINE_AUTO( gyro_pitch_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope pitch axis deadzone (deg/s)" ); static CVAR_DEFINE_AUTO( gyro_pitch_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope pitch axis deadzone (deg/s)" );
static CVAR_DEFINE_AUTO( gyro_yaw_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope yaw axis deadzone (deg/s)" ); static CVAR_DEFINE_AUTO( gyro_yaw_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope yaw axis deadzone (deg/s)" );
static CVAR_DEFINE_AUTO( gyro_roll_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope roll axis deadzone (deg/s)" ); static CVAR_DEFINE_AUTO( gyro_roll_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope roll axis deadzone (deg/s)" );
static CVAR_DEFINE_AUTO( gyro_debug, "0", 0, "visualize built-in device gyroscope" );
// stores the latest instantaneous rotation rates from built-in gyroscope // stores the latest instantaneous rotation rates from built-in gyroscope
static vec3_t gyro_speed; static vec3_t gyro_speed;
static vec3_t gyro_speed_display;
/* /*
============== ==============
@@ -45,6 +47,7 @@ void IN_GyroInit( void )
Cvar_RegisterVariable( &gyro_pitch_deadzone ); Cvar_RegisterVariable( &gyro_pitch_deadzone );
Cvar_RegisterVariable( &gyro_yaw_deadzone ); Cvar_RegisterVariable( &gyro_yaw_deadzone );
Cvar_RegisterVariable( &gyro_roll_deadzone ); Cvar_RegisterVariable( &gyro_roll_deadzone );
Cvar_RegisterVariable( &gyro_debug );
} }
/* /*
@@ -79,6 +82,28 @@ void IN_GyroEvent( vec3_t data )
VectorCopy( data, gyro_speed ); VectorCopy( data, gyro_speed );
} }
static void IN_GyroMap( const vec3_t src, vec3_t dst )
{
float orient_scale = 1.0f;
platform_orientation_t orient = Platform_GetDisplayOrientation();
if( orient == ORIENTATION_LANDSCAPE_FLIPPED )
orient_scale = -1.0f;
#if XASH_ANDROID || XASH_IOS
// In Landscape mode axes are swapped relative to natural (Portrait) orientation
// Y axis rotation becomes Pitch (up/down)
// X axis rotation becomes Yaw (left/right)
dst[0] = -orient_scale * src[1] * ( 180.0f / M_PI );
dst[1] = orient_scale * src[0] * ( 180.0f / M_PI );
dst[2] = orient_scale * src[2] * ( 180.0f / M_PI );
#else
dst[0] = orient_scale * src[0] * ( 180.0f / M_PI );
dst[1] = orient_scale * src[1] * ( 180.0f / M_PI );
dst[2] = orient_scale * src[2] * ( 180.0f / M_PI );
#endif
}
/* /*
============= =============
IN_GyroFinalizeMove IN_GyroFinalizeMove
@@ -88,33 +113,102 @@ Apply gyro movement to view angles
*/ */
void IN_GyroFinalizeMove( float *fw, float *side, float *dpitch, float *dyaw ) void IN_GyroFinalizeMove( float *fw, float *side, float *dpitch, float *dyaw )
{ {
platform_orientation_t orient; vec3_t mapped_speed;
float orient_scale = 1.0f;
if( !gyro_enable.value || !gyro_available.value ) if( !gyro_enable.value || !gyro_available.value )
return; return;
orient = Platform_GetDisplayOrientation(); IN_GyroMap( gyro_speed, mapped_speed );
if( orient == ORIENTATION_LANDSCAPE_FLIPPED ) VectorCopy( mapped_speed, gyro_speed_display );
orient_scale = -1.0f;
// In Landscape mode axes are swapped relative to natural (Portrait) orientation if( fabs( mapped_speed[0] ) < gyro_pitch_deadzone.value )
// Y axis rotation becomes Pitch (up/down) mapped_speed[0] = 0.0f;
// X axis rotation becomes Yaw (left/right) if( fabs( mapped_speed[1] ) < gyro_yaw_deadzone.value )
float pitch_speed = -orient_scale * gyro_speed[1] * ( 180.0f / M_PI ); mapped_speed[1] = 0.0f;
float yaw_speed = orient_scale * gyro_speed[0] * ( 180.0f / M_PI ); if( fabs( mapped_speed[2] ) < gyro_roll_deadzone.value )
float roll_speed = orient_scale * gyro_speed[2] * ( 180.0f / M_PI ); mapped_speed[2] = 0.0f;
if( fabs( pitch_speed ) < gyro_pitch_deadzone.value ) *dpitch -= gyro_pitch.value * mapped_speed[0] * host.realframetime;
pitch_speed = 0.0f; *dyaw += gyro_yaw.value * mapped_speed[1] * host.realframetime;
if( fabs( yaw_speed ) < gyro_yaw_deadzone.value ) *dyaw += gyro_roll.value * mapped_speed[2] * host.realframetime;
yaw_speed = 0.0f;
if( fabs( roll_speed ) < gyro_roll_deadzone.value )
roll_speed = 0.0f;
*dpitch -= gyro_pitch.value * pitch_speed * host.realframetime;
*dyaw += gyro_yaw.value * yaw_speed * host.realframetime;
*dyaw += gyro_roll.value * roll_speed * host.realframetime;
VectorClear( gyro_speed ); VectorClear( gyro_speed );
} }
void IN_GyroDrawDebug( void )
{
cl_font_t *font = Con_GetCurFont();
if( !gyro_debug.value || !gyro_available.value )
return;
float x = 8;
float y = 100;
const float bar_w = 100;
const float halfbar_w = bar_w * 0.5f;
const float bar_h = font->charHeight - 2;
const float center = x + halfbar_w;
platform_orientation_t orient = Platform_GetDisplayOrientation();
const char *orient_name = "UNKNOWN";
switch( orient )
{
case ORIENTATION_LANDSCAPE:
orient_name = "LANDSCAPE";
break;
case ORIENTATION_LANDSCAPE_FLIPPED:
orient_name = "LANDSCAPE FLIPPED";
break;
case ORIENTATION_PORTRAIT:
orient_name = "PORTRAIT";
break;
case ORIENTATION_PORTRAIT_FLIPPED:
orient_name = "PORTRAIT FLIPPED";
break;
default:
orient_name = "UNKNOWN";
break;
}
char orient_text[32];
Q_snprintf( orient_text, sizeof( orient_text ), "ORIENT: %s", orient_name );
const rgba_t bar_backcolor = { 40, 40, 40, 180 };
const rgba_t bar_fillcolor = { 100, 200, 100, 200 };
static const char *gyronames[3] = { "GYRO P", "GYRO Y", "GYRO R" };
static const convar_t *const gyro_deadzone[3] =
{
&gyro_pitch_deadzone,
&gyro_yaw_deadzone,
&gyro_roll_deadzone,
};
for( int i = 0; i < 3; i++ )
{
float fval = gyro_speed_display[i] / 180.0f;
fval = bound( -1.0f, fval, 1.0f );
CL_DrawString( x, y, gyronames[i], g_color_table[7], font, 0 );
y += font->charHeight;
ref.dllFuncs.FillRGBA( kRenderTransTexture, x, y, bar_w, bar_h, bar_backcolor[0], bar_backcolor[1], bar_backcolor[2], bar_backcolor[3] );
float filled = fval * halfbar_w;
ref.dllFuncs.FillRGBA( kRenderTransTexture, center + Q_min( 0, filled ), y, fabs( filled ), bar_h, bar_fillcolor[0], bar_fillcolor[1], bar_fillcolor[2], bar_fillcolor[3] );
float fthreshold = gyro_deadzone[i]->value / 180.0f;
fthreshold = bound( 0.0f, fthreshold, 1.0f );
if( fthreshold > 0.0f )
{
float thresh_x = fthreshold * halfbar_w;
ref.dllFuncs.FillRGBA( kRenderTransTexture, center - thresh_x, y, thresh_x * 2, bar_h, 180, 40, 40, 120 );
ref.dllFuncs.FillRGBA( kRenderTransTexture, center + thresh_x, y, 1, bar_h, 255, 200, 0, 220 );
ref.dllFuncs.FillRGBA( kRenderTransTexture, center - thresh_x, y, 1, bar_h, 255, 200, 0, 220 );
}
ref.dllFuncs.FillRGBA( kRenderTransTexture, center, y, 1, bar_h, 180, 180, 180, 220 );
y += bar_h + 2;
}
CL_DrawString( x, y, orient_text, g_color_table[1], font, 0 );
}
+5 -6
View File
@@ -129,9 +129,8 @@ static void Joy_HatMotionEvent( int value )
{ JOY_HAT_LEFT, K_LEFTARROW }, { JOY_HAT_LEFT, K_LEFTARROW },
{ JOY_HAT_RIGHT, K_RIGHTARROW }, { JOY_HAT_RIGHT, K_RIGHTARROW },
}; };
int i;
for( i = 0; i < ARRAYSIZE( keys ); i++ ) for( int i = 0; i < ARRAYSIZE( keys ); i++ )
{ {
if( value & keys[i].mask ) if( value & keys[i].mask )
{ {
@@ -317,9 +316,8 @@ void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw )
if( FBitSet( joy_axis_binding.flags, FCVAR_CHANGED ) ) if( FBitSet( joy_axis_binding.flags, FCVAR_CHANGED ) )
{ {
const char *bind = joy_axis_binding.string; const char *bind = joy_axis_binding.string;
size_t i;
for( i = 0; bind[i] && i < MAX_AXES; i++ ) for( size_t i = 0; bind[i] && i < MAX_AXES; i++ )
{ {
switch( bind[i] ) switch( bind[i] )
{ {
@@ -535,8 +533,6 @@ void Joy_DrawDebug( void )
} }
qboolean pressed = Key_IsDown( buttons[i] ); qboolean pressed = Key_IsDown( buttons[i] );
int btn_w = 0;
rgba_t color;
string name; string name;
Q_strncpy( name, Key_KeynumToString( buttons[i] ), sizeof( name )); Q_strncpy( name, Key_KeynumToString( buttons[i] ), sizeof( name ));
@@ -545,8 +541,11 @@ void Joy_DrawDebug( void )
if( p ) if( p )
*p = 0; *p = 0;
rgba_t color;
MakeRGBA( color, pressed ? 0 : 255, pressed ? 255 : 0, 0, 255 ); MakeRGBA( color, pressed ? 0 : 255, pressed ? 255 : 0, 0, 255 );
CL_DrawString( x, y, name, color, font, 0 ); CL_DrawString( x, y, name, color, font, 0 );
int btn_w = 0;
CL_DrawStringLen( font, name, &btn_w, NULL, 0 ); CL_DrawStringLen( font, name, &btn_w, NULL, 0 );
x += btn_w + 6; x += btn_w + 6;
} }
+25 -50
View File
@@ -187,8 +187,6 @@ to be configured even if they don't have defined names.
*/ */
static int Key_StringToKeynum( const char *str ) static int Key_StringToKeynum( const char *str )
{ {
int i;
if( !str || !str[0] ) if( !str || !str[0] )
return -1; return -1;
@@ -207,7 +205,7 @@ static int Key_StringToKeynum( const char *str )
} }
// scan for a text match // scan for a text match
for( i = 0; i < ARRAYSIZE( keynames ); i++ ) for( int i = 0; i < ARRAYSIZE( keynames ); i++ )
{ {
if( !Q_stricmp( str, keynames[i].name )) if( !Q_stricmp( str, keynames[i].name ))
return keynames[i].keynum; return keynames[i].keynum;
@@ -293,19 +291,16 @@ Key_GetKey
*/ */
static int Key_GetKey( const char *pBinding ) static int Key_GetKey( const char *pBinding )
{ {
int i, len;
const char *p;
if( !pBinding ) return -1; if( !pBinding ) return -1;
len = Q_strlen( pBinding ); int len = Q_strlen( pBinding );
for( i = 0; i < ARRAYSIZE( keys ); i++ ) for( int i = 0; i < ARRAYSIZE( keys ); i++ )
{ {
if( !keys[i].binding ) if( !keys[i].binding )
continue; continue;
p = keys[i].binding; const char *p = keys[i].binding;
if( *p == '+' ) if( *p == '+' )
p++; p++;
@@ -340,15 +335,13 @@ Key_Unbind_f
*/ */
static void Key_Unbind_f( void ) static void Key_Unbind_f( void )
{ {
int b;
if( Cmd_Argc() != 2 ) if( Cmd_Argc() != 2 )
{ {
Con_Printf( S_USAGE "unbind <key> : remove commands from a key\n" ); Con_Printf( S_USAGE "unbind <key> : remove commands from a key\n" );
return; return;
} }
b = Key_StringToKeynum( Cmd_Argv( 1 )); int b = Key_StringToKeynum( Cmd_Argv( 1 ));
if( b == -1 ) if( b == -1 )
{ {
@@ -372,9 +365,7 @@ Key_Unbindall_f
*/ */
static void Key_Unbindall_f( void ) static void Key_Unbindall_f( void )
{ {
int i; for( int i = 0; i < ARRAYSIZE( keys ); i++ )
for( i = 0; i < ARRAYSIZE( keys ); i++ )
{ {
if( keys[i].binding ) if( keys[i].binding )
Key_SetBinding( i, "" ); Key_SetBinding( i, "" );
@@ -392,17 +383,15 @@ Key_Reset_f
*/ */
static void Key_Reset_f( void ) static void Key_Reset_f( void )
{ {
int i;
// clear all keys first // clear all keys first
for( i = 0; i < ARRAYSIZE( keys ); i++ ) for( int i = 0; i < ARRAYSIZE( keys ); i++ )
{ {
if( keys[i].binding ) if( keys[i].binding )
Key_SetBinding( i, "" ); Key_SetBinding( i, "" );
} }
// apply default values // apply default values
for( i = 0; i < ARRAYSIZE( keynames ); i++ ) for( int i = 0; i < ARRAYSIZE( keynames ); i++ )
Key_SetBinding( keynames[i].keynum, keynames[i].binding ); Key_SetBinding( keynames[i].keynum, keynames[i].binding );
} }
@@ -413,10 +402,7 @@ Key_Bind_f
*/ */
static void Key_Bind_f( void ) static void Key_Bind_f( void )
{ {
char cmd[1024]; int c = Cmd_Argc();
int i, c, b;
c = Cmd_Argc();
if( c < 2 ) if( c < 2 )
{ {
@@ -424,7 +410,7 @@ static void Key_Bind_f( void )
return; return;
} }
b = Key_StringToKeynum( Cmd_Argv( 1 )); int b = Key_StringToKeynum( Cmd_Argv( 1 ));
if( b == -1 ) if( b == -1 )
{ {
@@ -441,9 +427,10 @@ static void Key_Bind_f( void )
} }
// copy the rest of the command line // copy the rest of the command line
char cmd[1024];
cmd[0] = 0; // start out with a null string cmd[0] = 0; // start out with a null string
for( i = 2; i < c; i++ ) for( int i = 2; i < c; i++ )
{ {
Q_strncat( cmd, Cmd_Argv( i ), sizeof( cmd )); Q_strncat( cmd, Cmd_Argv( i ), sizeof( cmd ));
if( i != ( c - 1 )) Q_strncat( cmd, " ", sizeof( cmd )); if( i != ( c - 1 )) Q_strncat( cmd, " ", sizeof( cmd ));
@@ -461,18 +448,16 @@ Writes lines containing "bind key value"
*/ */
void Key_WriteBindings( file_t *f ) void Key_WriteBindings( file_t *f )
{ {
int i;
string newCommand;
if( !f ) return; if( !f ) return;
FS_Printf( f, "unbindall\n" ); FS_Printf( f, "unbindall\n" );
for( i = 0; i < ARRAYSIZE( keys ); i++ ) for( int i = 0; i < ARRAYSIZE( keys ); i++ )
{ {
if( COM_StringEmptyOrNULL( keys[i].binding )) if( COM_StringEmptyOrNULL( keys[i].binding ))
continue; continue;
string newCommand;
Cmd_Escape( newCommand, keys[i].binding, sizeof( newCommand )); Cmd_Escape( newCommand, keys[i].binding, sizeof( newCommand ));
// NOTE: as TheKingFireS figured out, some particular mods (like CoF) do not // NOTE: as TheKingFireS figured out, some particular mods (like CoF) do not
@@ -491,9 +476,7 @@ Key_Bindlist_f
*/ */
static void Key_Bindlist_f( void ) static void Key_Bindlist_f( void )
{ {
int i; for( int i = 0; i < ARRAYSIZE( keys ); i++ )
for( i = 0; i < ARRAYSIZE( keys ); i++ )
{ {
if( COM_StringEmptyOrNULL( keys[i].binding )) if( COM_StringEmptyOrNULL( keys[i].binding ))
continue; continue;
@@ -514,10 +497,9 @@ qboolean Cmd_GetKeysList( const char *s, char *completedname, int length, qboole
size_t i, numkeys; size_t i, numkeys;
string keys_strings[ARRAYSIZE( keys )]; string keys_strings[ARRAYSIZE( keys )];
string matchbuf; string matchbuf;
int len;
// compare keys list with current keyword // compare keys list with current keyword
len = Q_strlen( s ); int len = Q_strlen( s );
for( i = 0, numkeys = 0; i < ARRAYSIZE( keys ); i++ ) for( i = 0, numkeys = 0; i < ARRAYSIZE( keys ); i++ )
{ {
@@ -569,8 +551,6 @@ Key_Init
*/ */
void Key_Init( void ) void Key_Init( void )
{ {
int i;
// register our functions // register our functions
Cmd_AddRestrictedCommand( "bind", Key_Bind_f, "binds a command to the specified key in bindmap" ); Cmd_AddRestrictedCommand( "bind", Key_Bind_f, "binds a command to the specified key in bindmap" );
Cmd_AddRestrictedCommand( "unbind", Key_Unbind_f, "removes a command on the specified key in bindmap" ); Cmd_AddRestrictedCommand( "unbind", Key_Unbind_f, "removes a command on the specified key in bindmap" );
@@ -580,7 +560,7 @@ void Key_Init( void )
Cmd_AddCommand( "makehelp", Key_EnumCmds_f, "write help.txt that contains all console cvars and cmds" ); Cmd_AddCommand( "makehelp", Key_EnumCmds_f, "write help.txt that contains all console cvars and cmds" );
// setup default binding. "unbindall" from config.cfg will be reset it // setup default binding. "unbindall" from config.cfg will be reset it
for( i = 0; i < ARRAYSIZE( keynames ); i++ ) for( int i = 0; i < ARRAYSIZE( keynames ); i++ )
Key_SetBinding( keynames[i].keynum, keynames[i].binding ); Key_SetBinding( keynames[i].keynum, keynames[i].binding );
Cvar_RegisterVariable( &key_rotate ); Cvar_RegisterVariable( &key_rotate );
@@ -594,21 +574,20 @@ Key_AddKeyCommands
*/ */
static void Key_AddKeyCommands( int key, const char *kb, qboolean down ) static void Key_AddKeyCommands( int key, const char *kb, qboolean down )
{ {
char button[1024];
char *buttonPtr;
char cmd[1024];
int i;
if( !kb ) return; if( !kb ) return;
buttonPtr = button;
for( i = 0; ; i++ ) char button[1024];
char *buttonPtr = button;
for( int i = 0; ; i++ )
{ {
if( kb[i] == ';' || !kb[i] ) if( kb[i] == ';' || !kb[i] )
{ {
*buttonPtr = '\0'; *buttonPtr = '\0';
if( button[0] == '+' ) if( button[0] == '+' )
{ {
char cmd[1024];
// button commands add keynum as a parm // button commands add keynum as a parm
if( down ) Q_snprintf( cmd, sizeof( cmd ), "%s %i\n", button, key ); if( down ) Q_snprintf( cmd, sizeof( cmd ), "%s %i\n", button, key );
else Q_snprintf( cmd, sizeof( cmd ), "-%s %i\n", button + 1, key ); else Q_snprintf( cmd, sizeof( cmd ), "-%s %i\n", button + 1, key );
@@ -708,8 +687,6 @@ Called by the system for both key up and key down events
*/ */
void GAME_EXPORT Key_Event( int key, int down ) void GAME_EXPORT Key_Event( int key, int down )
{ {
const char *kb;
key = Key_Rotate( key ); key = Key_Rotate( key );
if( OSK_KeyEvent( key, down ) ) if( OSK_KeyEvent( key, down ) )
@@ -719,7 +696,7 @@ void GAME_EXPORT Key_Event( int key, int down )
if( !keys[key].down && !down ) if( !keys[key].down && !down )
return; return;
kb = keys[key].binding; const char *kb = keys[key].binding;
keys[key].down = down ? true : false; keys[key].down = down ? true : false;
#ifdef HACKS_RELATED_HLMODS #ifdef HACKS_RELATED_HLMODS
@@ -917,13 +894,11 @@ Key_ClearStates
*/ */
void GAME_EXPORT Key_ClearStates( void ) void GAME_EXPORT Key_ClearStates( void )
{ {
int i;
// don't clear keys during changelevel // don't clear keys during changelevel
if( cls.changelevel ) if( cls.changelevel )
return; return;
for( i = 0; i < ARRAYSIZE( keys ); i++ ) for( int i = 0; i < ARRAYSIZE( keys ); i++ )
{ {
if( i >= K_MOUSE1 && i <= K_MOUSE5 ) if( i >= K_MOUSE1 && i <= K_MOUSE5 )
IN_MouseEvent( i - K_MOUSE1, false ); IN_MouseEvent( i - K_MOUSE1, false );
+1 -3
View File
@@ -144,8 +144,6 @@ qboolean OSK_KeyEvent( int key, int down )
break; break;
default: default:
{ {
int ch;
if( !down ) if( !down )
{ {
if( osk.shift && osk.curlayout & 1 ) if( osk.shift && osk.curlayout & 1 )
@@ -156,7 +154,7 @@ qboolean OSK_KeyEvent( int key, int down )
break; break;
} }
ch = (byte)osk.curbutton.val; int ch = (byte)osk.curbutton.val;
// do not pass UTF-8 sequence into the engine, convert it here // do not pass UTF-8 sequence into the engine, convert it here
if( !cls.accept_utf8 ) if( !cls.accept_utf8 )
+44 -91
View File
@@ -249,10 +249,7 @@ Dump config to file
*/ */
static qboolean Touch_DumpConfig( const char *name, const char *profilename ) static qboolean Touch_DumpConfig( const char *name, const char *profilename )
{ {
file_t *f; file_t *f = FS_Open( name, "w", true );
const touch_button_t *button;
f = FS_Open( name, "w", true );
if( !f ) if( !f )
{ {
@@ -299,7 +296,7 @@ static qboolean Touch_DumpConfig( const char *name, const char *profilename )
FS_Printf( f, "touch_removeall\n" ); FS_Printf( f, "touch_removeall\n" );
FS_Printf( f, "touch_aspectratio %g\n", Touch_AspectRatio()); FS_Printf( f, "touch_aspectratio %g\n", Touch_AspectRatio());
for( button = touch.list_user.first; button; button = button->next ) for( const touch_button_t *button = touch.list_user.first; button; button = button->next )
Touch_ExportButtonToConfig( f, button, false ); Touch_ExportButtonToConfig( f, button, false );
FS_Close( f ); FS_Close( f );
@@ -347,9 +344,6 @@ export current touch configuration into profile
*/ */
static void Touch_ExportConfig_f( void ) static void Touch_ExportConfig_f( void )
{ {
const char *name;
string profilename;
if( Cmd_Argc() != 2 ) if( Cmd_Argc() != 2 )
{ {
Con_Printf( S_USAGE "touch_exportconfig <name>\n" ); Con_Printf( S_USAGE "touch_exportconfig <name>\n" );
@@ -362,7 +356,8 @@ static void Touch_ExportConfig_f( void )
return; return;
} }
name = Cmd_Argv( 1 ); const char *name = Cmd_Argv( 1 );
string profilename;
if( Q_strstr( name, "touch_presets/" )) if( Q_strstr( name, "touch_presets/" ))
{ {
@@ -386,7 +381,6 @@ export current touch configuration into C code
*/ */
static void Touch_GenerateCode_f( void ) static void Touch_GenerateCode_f( void )
{ {
const touch_button_t *button;
rgba_t c = { 0 }; rgba_t c = { 0 };
if( !touch.list_user.first ) if( !touch.list_user.first )
@@ -395,11 +389,9 @@ static void Touch_GenerateCode_f( void )
return; return;
} }
for( button = touch.list_user.first; button; button = button->next ) for( const touch_button_t *button = touch.list_user.first; button; button = button->next )
{ {
float aspect;
int flags = button->flags; int flags = button->flags;
int round;
if( FBitSet( flags, TOUCH_FL_CLIENT )) if( FBitSet( flags, TOUCH_FL_CLIENT ))
continue; // skip temporary buttons continue; // skip temporary buttons
@@ -410,7 +402,7 @@ static void Touch_GenerateCode_f( void )
if( FBitSet( flags, TOUCH_FL_DEF_HIDE )) if( FBitSet( flags, TOUCH_FL_DEF_HIDE ))
SetBits( flags, TOUCH_FL_HIDE ); SetBits( flags, TOUCH_FL_HIDE );
aspect = ( button->y2 - button->y1 ) / (( button->x2 - button->x1 ) / Touch_AspectRatio( )); float aspect = ( button->y2 - button->y1 ) / (( button->x2 - button->x1 ) / Touch_AspectRatio( ));
if( memcmp( c, button->color, sizeof( c ))) if( memcmp( c, button->color, sizeof( c )))
{ {
@@ -419,6 +411,7 @@ static void Touch_GenerateCode_f( void )
memcpy( c, button->color, sizeof( c )); memcpy( c, button->color, sizeof( c ));
} }
int round;
if( button->type == touch_command ) if( button->type == touch_command )
{ {
if( fabs( aspect - 1.0f ) < 0.001 ) if( fabs( aspect - 1.0f ) < 0.001 )
@@ -438,22 +431,18 @@ static void Touch_GenerateCode_f( void )
static void Touch_RoundAll_f( void ) static void Touch_RoundAll_f( void )
{ {
touch_button_t *button;
if( !touch_grid_enable.value ) if( !touch_grid_enable.value )
return; return;
for( button = touch.list_user.first; button; button = button->next ) for( touch_button_t *button = touch.list_user.first; button; button = button->next )
IN_TouchCheckCoords( &button->x1, &button->y1, &button->x2, &button->y2 ); IN_TouchCheckCoords( &button->x1, &button->y1, &button->x2, &button->y2 );
} }
static void Touch_ListButtons_f( void ) static void Touch_ListButtons_f( void )
{ {
touch_button_t *button;
Touch_InitConfig(); Touch_InitConfig();
for( button = touch.list_user.first; button; button = button->next ) for( touch_button_t *button = touch.list_user.first; button; button = button->next )
{ {
Con_Printf( "%s %s %s %g %g %g %g %d %d %d %d %d\n", Con_Printf( "%s %s %s %g %g %g %g %d %d %d %d %d\n",
button->name, button->texture, button->command, button->name, button->texture, button->command,
@@ -483,9 +472,7 @@ static void Touch_Stroke_f( void )
static touch_button_t *Touch_FindNextNoPattern( touch_button_t *buttons, const char *name, qboolean privileged ) static touch_button_t *Touch_FindNextNoPattern( touch_button_t *buttons, const char *name, qboolean privileged )
{ {
touch_button_t *b; for( touch_button_t *b = buttons; b; b = b->next )
for( b = buttons; b; b = b->next )
{ {
if( !privileged && !FBitSet( b->flags, TOUCH_FL_UNPRIVILEGED )) if( !privileged && !FBitSet( b->flags, TOUCH_FL_UNPRIVILEGED ))
continue; continue;
@@ -504,13 +491,12 @@ static touch_button_t *Touch_FindButtonNoPattern( touchbuttonlist_t *list, const
static touch_button_t *Touch_FindNext( touch_button_t *buttons, const char *name, qboolean privileged ) static touch_button_t *Touch_FindNext( touch_button_t *buttons, const char *name, qboolean privileged )
{ {
touch_button_t *b;
qboolean has_pattern = Q_strchr( name, '*' ) != NULL; qboolean has_pattern = Q_strchr( name, '*' ) != NULL;
if( !has_pattern ) if( !has_pattern )
return Touch_FindNextNoPattern( buttons, name, privileged ); return Touch_FindNextNoPattern( buttons, name, privileged );
for( b = buttons; b; b = b->next ) for( touch_button_t *b = buttons; b; b = b->next )
{ {
if( !privileged && !FBitSet( b->flags, TOUCH_FL_UNPRIVILEGED )) if( !privileged && !FBitSet( b->flags, TOUCH_FL_UNPRIVILEGED ))
continue; continue;
@@ -584,10 +570,9 @@ static void Touch_SetClientOnly_f( void )
static void Touch_RemoveButtonFromList( touchbuttonlist_t *list, const char *name, qboolean privileged ) static void Touch_RemoveButtonFromList( touchbuttonlist_t *list, const char *name, qboolean privileged )
{ {
touch_button_t *button;
IN_TouchEditClear(); IN_TouchEditClear();
touch_button_t *button;
while(( button = Touch_FindFirst( list, name, privileged ))) while(( button = Touch_FindFirst( list, name, privileged )))
{ {
if( button->prev ) if( button->prev )
@@ -640,9 +625,7 @@ static void Touch_RemoveAll_f( void )
static void Touch_SetColor( touchbuttonlist_t *list, const char *name, byte *color, qboolean privileged ) static void Touch_SetColor( touchbuttonlist_t *list, const char *name, byte *color, qboolean privileged )
{ {
touch_button_t *b; for( touch_button_t *b = Touch_FindFirst( list, name, privileged ); b != NULL; b = Touch_FindNext( b->next, name, privileged ))
for( b = Touch_FindFirst( list, name, privileged ); b != NULL; b = Touch_FindNext( b->next, name, privileged ))
Vector4Copy( color, b->color ); Vector4Copy( color, b->color );
} }
@@ -677,9 +660,7 @@ static void Touch_SetCommand( touch_button_t *button, const char *command )
void Touch_HideButtons( const char *name, byte hide, qboolean privileged ) void Touch_HideButtons( const char *name, byte hide, qboolean privileged )
{ {
touch_button_t *b; for( touch_button_t *b = Touch_FindFirst( &touch.list_user, name, privileged ); b != NULL; b = Touch_FindNext( b->next, name, privileged ))
for( b = Touch_FindFirst( &touch.list_user, name, privileged ); b != NULL; b = Touch_FindNext( b->next, name, privileged ))
{ {
if( hide ) if( hide )
SetBits( b->flags, TOUCH_FL_HIDE ); SetBits( b->flags, TOUCH_FL_HIDE );
@@ -718,9 +699,7 @@ static void Touch_Show_f( void )
static void Touch_FadeButtons( touchbuttonlist_t *list, const char *name, float speed, float end, float start, qboolean privileged ) static void Touch_FadeButtons( touchbuttonlist_t *list, const char *name, float speed, float end, float start, qboolean privileged )
{ {
touch_button_t *b; for( touch_button_t *b = Touch_FindFirst( list, name, privileged ); b != NULL; b = Touch_FindNext( b->next, name, privileged ))
for( b = Touch_FindFirst( list, name, privileged ); b != NULL; b = Touch_FindNext( b->next, name, privileged ))
{ {
if( start >= 0 ) if( start >= 0 )
b->fade = start; b->fade = start;
@@ -855,8 +834,6 @@ static touch_button_t *Touch_AddButton( touchbuttonlist_t *list, const char *nam
void Touch_AddClientButton( const char *name, const char *texture, const char *command, float x1, float y1, float x2, float y2, byte *color, int round, float aspect, int flags ) void Touch_AddClientButton( const char *name, const char *texture, const char *command, float x1, float y1, float x2, float y2, byte *color, int round, float aspect, int flags )
{ {
touch_button_t *button;
if( !touch.initialized ) if( !touch.initialized )
return; return;
@@ -865,15 +842,14 @@ void Touch_AddClientButton( const char *name, const char *texture, const char *c
if( round == round_aspect ) if( round == round_aspect )
y2 = y1 + ( x2 - x1 ) / (Touch_AspectRatio()) * aspect; y2 = y1 + ( x2 - x1 ) / (Touch_AspectRatio()) * aspect;
button = Touch_AddButton( &touch.list_user, name, texture, command, x1, y1, x2, y2, color, true ); touch_button_t *button = Touch_AddButton( &touch.list_user, name, texture, command, x1, y1, x2, y2, color, true );
SetBits( button->flags, TOUCH_FL_CLIENT | TOUCH_FL_NOEDIT ); SetBits( button->flags, TOUCH_FL_CLIENT | TOUCH_FL_NOEDIT );
button->aspect = aspect; button->aspect = aspect;
} }
static void Touch_LoadDefaults_f( void ) static void Touch_LoadDefaults_f( void )
{ {
int i; for( int i = 0; i < g_DefaultButtonsLength; i++ )
for( i = 0; i < g_DefaultButtonsLength; i++ )
{ {
touch_button_t *button; touch_button_t *button;
float x1 = g_DefaultButtons[i].x1, float x1 = g_DefaultButtons[i].x1,
@@ -903,11 +879,9 @@ static void Touch_LoadDefaults_f( void )
// Add default button from client // Add default button from client
void Touch_AddDefaultButton( const char *name, const char *texture, const char *command, float x1, float y1, float x2, float y2, byte *color, int round, float aspect, int flags ) void Touch_AddDefaultButton( const char *name, const char *texture, const char *command, float x1, float y1, float x2, float y2, byte *color, int round, float aspect, int flags )
{ {
touchdefaultbutton_t *b;
g_DefaultButtons = Mem_Realloc( touch.mempool, g_DefaultButtons, sizeof( *g_DefaultButtons ) * ( g_DefaultButtonsLength + 1 )); g_DefaultButtons = Mem_Realloc( touch.mempool, g_DefaultButtons, sizeof( *g_DefaultButtons ) * ( g_DefaultButtonsLength + 1 ));
b = &g_DefaultButtons[g_DefaultButtonsLength]; touchdefaultbutton_t *b = &g_DefaultButtons[g_DefaultButtonsLength];
Q_strncpy( b->name, name, sizeof( b->name )); Q_strncpy( b->name, name, sizeof( b->name ));
Q_strncpy( b->texture, texture, sizeof( b->texture )); Q_strncpy( b->texture, texture, sizeof( b->texture ));
@@ -938,22 +912,18 @@ void Touch_ResetDefaultButtons( void )
static void Touch_AddButton_f( void ) static void Touch_AddButton_f( void )
{ {
rgba_t color = { 255, 255, 255, 255 };
touch_button_t *button = NULL;
const char *name, *command;
float x1 = 0.4f, y1 = 0.4f, x2 = 0.6f, y2 = 0.6f;
qboolean privileged = Cmd_CurrentCommandIsPrivileged();
string texture;
if( Cmd_Argc( ) < 4 ) if( Cmd_Argc( ) < 4 )
{ {
Con_Printf( S_USAGE "touch_addbutton <name> <texture> <command> [<x1> <y1> <x2> <y2> [ r g b a ] ]\n" ); Con_Printf( S_USAGE "touch_addbutton <name> <texture> <command> [<x1> <y1> <x2> <y2> [ r g b a ] ]\n" );
return; return;
} }
name = Cmd_Argv( 1 ); const char *name = Cmd_Argv( 1 );
string texture;
Q_strncpy( texture, Cmd_Argv( 2 ), sizeof( texture )); Q_strncpy( texture, Cmd_Argv( 2 ), sizeof( texture ));
command = Cmd_Argv( 3 ); const char *command = Cmd_Argv( 3 );
float x1 = 0.4f, y1 = 0.4f, x2 = 0.6f, y2 = 0.6f;
rgba_t color = { 255, 255, 255, 255 };
// HACKHACK: old engine specifically used .tga for touch buttons // HACKHACK: old engine specifically used .tga for touch buttons
// and because new engine extras.pk3 don't have .tga textures // and because new engine extras.pk3 don't have .tga textures
@@ -980,7 +950,8 @@ static void Touch_AddButton_f( void )
color[3] = Q_atoi( Cmd_Argv( 11 )); color[3] = Q_atoi( Cmd_Argv( 11 ));
} }
button = Touch_AddButton( &touch.list_user, name, texture, command, x1, y1, x2, y2, color, privileged ); qboolean privileged = Cmd_CurrentCommandIsPrivileged();
touch_button_t *button = Touch_AddButton( &touch.list_user, name, texture, command, x1, y1, x2, y2, color, privileged );
if( Cmd_Argc( ) >= 13 ) if( Cmd_Argc( ) >= 13 )
SetBits( button->flags, Q_atoi( Cmd_Argv( 12 ))); SetBits( button->flags, Q_atoi( Cmd_Argv( 12 )));
@@ -1023,9 +994,7 @@ static void Touch_EnableEdit_f( void )
// convert coordinates to actual aspect ratio after it was updated // convert coordinates to actual aspect ratio after it was updated
if( touch.config_aspect_ratio != touch.actual_aspect_ratio ) if( touch.config_aspect_ratio != touch.actual_aspect_ratio )
{ {
touch_button_t *button; for( touch_button_t *button = touch.list_user.first; button; button = button->next )
for( button = touch.list_user.first; button; button = button->next )
{ {
button->y1 /= touch.actual_aspect_ratio / touch.config_aspect_ratio; button->y1 /= touch.actual_aspect_ratio / touch.config_aspect_ratio;
button->y2 /= touch.actual_aspect_ratio / touch.config_aspect_ratio; button->y2 /= touch.actual_aspect_ratio / touch.config_aspect_ratio;
@@ -1315,10 +1284,6 @@ static void IN_TouchCheckCoords( float *x1, float *y1, float *x2, float *y2 )
static float Touch_DrawCharacter( float x, float y, int number, float size ) static float Touch_DrawCharacter( float x, float y, int number, float size )
{ {
float s1, s2, t1, t2, width, height;
int w, h;
wrect_t *prc;
if( !cls.creditsFont.valid ) if( !cls.creditsFont.valid )
return 0; return 0;
@@ -1328,16 +1293,17 @@ static float Touch_DrawCharacter( float x, float y, int number, float size )
if( !number ) if( !number )
return 0; return 0;
int w, h;
R_GetTextureParms( &w, &h, cls.creditsFont.hFontTexture ); R_GetTextureParms( &w, &h, cls.creditsFont.hFontTexture );
prc = &cls.creditsFont.fontRc[number]; wrect_t *prc = &cls.creditsFont.fontRc[number];
s1 = prc->left / (float)w; float s1 = prc->left / (float)w;
t1 = prc->top / (float)h; float t1 = prc->top / (float)h;
s2 = prc->right / (float)w; float s2 = prc->right / (float)w;
t2 = prc->bottom / (float)h; float t2 = prc->bottom / (float)h;
width = ( prc->right - prc->left ) / 1024.0f * size; float width = ( prc->right - prc->left ) / 1024.0f * size;
height = ( prc->bottom - prc->top ) / 1024.0f * size; float height = ( prc->bottom - prc->top ) / 1024.0f * size;
ref.dllFuncs.R_DrawStretchPic( TO_SCRN_X( x ), TO_SCRN_Y( y ), TO_SCRN_X( width ), TO_SCRN_X( height ), ref.dllFuncs.R_DrawStretchPic( TO_SCRN_X( x ), TO_SCRN_Y( y ), TO_SCRN_X( width ), TO_SCRN_X( height ),
s1, t1, s2, t2, cls.creditsFont.hFontTexture ); s1, t1, s2, t2, cls.creditsFont.hFontTexture );
@@ -1384,9 +1350,7 @@ static float Touch_DrawText( float x1, float y1, float x2, float y2, const char
static void Touch_DrawButtons( touchbuttonlist_t *list ) static void Touch_DrawButtons( touchbuttonlist_t *list )
{ {
touch_button_t *b; for( touch_button_t *b = list->first; b; b = b->next )
for( b = list->first; b; b = b->next )
{ {
if( Touch_IsVisible( b )) if( Touch_IsVisible( b ))
{ {
@@ -1506,17 +1470,15 @@ void Touch_Draw( void )
if( touch.state >= state_edit && touch_grid_enable.value ) if( touch.state >= state_edit && touch_grid_enable.value )
{ {
float x;
if( touch_in_menu.value ) if( touch_in_menu.value )
ref.dllFuncs.FillRGBA( kRenderTransTexture, 0, 0, 1, 1, 32, 32, 32, 255 ); ref.dllFuncs.FillRGBA( kRenderTransTexture, 0, 0, 1, 1, 32, 32, 32, 255 );
else else
ref.dllFuncs.FillRGBA( kRenderTransTexture, 0, 0, 1, 1, 0, 0, 0, 112 ); ref.dllFuncs.FillRGBA( kRenderTransTexture, 0, 0, 1, 1, 0, 0, 0, 112 );
for( x = 0.0f; x < 1.0f; x += GRID_X ) for( float x = 0.0f; x < 1.0f; x += GRID_X )
ref.dllFuncs.FillRGBA( kRenderTransTexture, TO_SCRN_X( x ), 0, 1, TO_SCRN_Y( 1 ), 0, 224, 224, 112 ); ref.dllFuncs.FillRGBA( kRenderTransTexture, TO_SCRN_X( x ), 0, 1, TO_SCRN_Y( 1 ), 0, 224, 224, 112 );
for( x = 0.0f; x < 1.0f; x += GRID_Y ) for( float x = 0.0f; x < 1.0f; x += GRID_Y )
ref.dllFuncs.FillRGBA( kRenderTransTexture, 0, TO_SCRN_Y( x ), TO_SCRN_X( 1 ), 1, 0, 224, 224, 112 ); ref.dllFuncs.FillRGBA( kRenderTransTexture, 0, TO_SCRN_Y( x ), TO_SCRN_X( 1 ), 1, 0, 224, 224, 112 );
} }
@@ -1738,16 +1700,14 @@ static void Touch_Motion( int fingerID, float x, float y, float dx, float dy )
if( touch_nonlinear_look.value ) if( touch_nonlinear_look.value )
{ {
float dabs, dcos, dsin;
// save angle, modify only velocity // save angle, modify only velocity
dabs = sqrt( dx * dx + dy * dy ); float dabs = sqrt( dx * dx + dy * dy );
if( dabs < 0.000001f ) if( dabs < 0.000001f )
return; // no motion, avoid division by zero return; // no motion, avoid division by zero
dcos = dx / dabs; float dcos = dx / dabs;
dsin = dy / dabs; float dsin = dy / dabs;
if( touch_exp_mult.value > 1 ) if( touch_exp_mult.value > 1 )
dabs = ( exp( dabs * touch_exp_mult.value ) - 1 ) / touch_exp_mult.value; dabs = ( exp( dabs * touch_exp_mult.value ) - 1 ) / touch_exp_mult.value;
@@ -1771,14 +1731,13 @@ static void Touch_Motion( int fingerID, float x, float y, float dx, float dy )
static qboolean Touch_ButtonPress( touchbuttonlist_t *list, touchEventType type, int fingerID, float x, float y ) static qboolean Touch_ButtonPress( touchbuttonlist_t *list, touchEventType type, int fingerID, float x, float y )
{ {
touch_button_t *button;
qboolean result = false; qboolean result = false;
if( type != event_down && type != event_up ) if( type != event_down && type != event_up )
return false; return false;
// run from end(front) to start(back) // run from end(front) to start(back)
for( button = list->last; button; button = button->prev ) for( touch_button_t *button = list->last; button; button = button->prev )
{ {
// skip invisible buttons // skip invisible buttons
if( !Touch_IsVisible( button )) if( !Touch_IsVisible( button ))
@@ -1850,14 +1809,12 @@ static qboolean Touch_ButtonPress( touchbuttonlist_t *list, touchEventType type,
if( touch.look_finger == fingerID ) if( touch.look_finger == fingerID )
{ {
touch_button_t *newbutton;
// this is an error, try recover // this is an error, try recover
touch.move_finger = touch.look_finger = -1; touch.move_finger = touch.look_finger = -1;
// player touched touch_move with enabled look mode // player touched touch_move with enabled look mode
// and same finger id. release all move triggers // and same finger id. release all move triggers
for( newbutton = list->first; newbutton; newbutton = newbutton->next ) for( touch_button_t *newbutton = list->first; newbutton; newbutton = newbutton->next )
{ {
if( newbutton->type == touch_move || newbutton->type == touch_look ) if( newbutton->type == touch_move || newbutton->type == touch_look )
newbutton->finger = -1; newbutton->finger = -1;
@@ -1910,14 +1867,12 @@ static qboolean Touch_ButtonPress( touchbuttonlist_t *list, touchEventType type,
if( touch.move_finger == fingerID ) if( touch.move_finger == fingerID )
{ {
touch_button_t *newbutton;
// this is an error, try recover // this is an error, try recover
touch.move_finger = touch.look_finger = -1; touch.move_finger = touch.look_finger = -1;
// player touched touch_move with enabled look mode // player touched touch_move with enabled look mode
// and same finger id. release all move triggers // and same finger id. release all move triggers
for( newbutton = list->first; newbutton; newbutton = newbutton->next ) for( touch_button_t *newbutton = list->first; newbutton; newbutton = newbutton->next )
{ {
if( newbutton->type == touch_move || newbutton->type == touch_look ) if( newbutton->type == touch_move || newbutton->type == touch_look )
newbutton->finger = -1; newbutton->finger = -1;
@@ -1994,8 +1949,6 @@ static qboolean Touch_ButtonPress( touchbuttonlist_t *list, touchEventType type,
static qboolean Touch_ButtonEdit( touchEventType type, int fingerID, float x, float y ) static qboolean Touch_ButtonEdit( touchEventType type, int fingerID, float x, float y )
{ {
touch_button_t *button;
// edit buttons are on y1 // edit buttons are on y1
if( type == event_down ) if( type == event_down )
{ {
@@ -2010,7 +1963,7 @@ static qboolean Touch_ButtonEdit( touchEventType type, int fingerID, float x, fl
} }
// run from end(front) to start(back) // run from end(front) to start(back)
for( button = touch.list_user.last; button; button = button->prev ) for( touch_button_t *button = touch.list_user.last; button; button = button->prev )
{ {
if( type == event_down ) if( type == event_down )
{ {
+2 -7
View File
@@ -28,7 +28,6 @@ GNU General Public License for more details.
static qboolean in_mouseactive; // false when not focus app static qboolean in_mouseactive; // false when not focus app
static qboolean in_mouseinitialized; static qboolean in_mouseinitialized;
static qboolean in_mouse_suspended;
static struct static struct
{ {
int x, y; int x, y;
@@ -338,8 +337,6 @@ IN_MouseMove
*/ */
static void IN_MouseMove( void ) static void IN_MouseMove( void )
{ {
int x, y;
if( !in_mouseinitialized ) if( !in_mouseinitialized )
return; return;
@@ -351,6 +348,7 @@ static void IN_MouseMove( void )
} }
// find mouse movement // find mouse movement
int x, y;
Platform_GetMousePos( &x, &y ); Platform_GetMousePos( &x, &y );
VGui_MouseMove( x, y ); VGui_MouseMove( x, y );
@@ -587,18 +585,15 @@ Called from cl_main.c after generating command in client
*/ */
void IN_EngineAppendMove( float frametime, usercmd_t *cmd, qboolean active ) void IN_EngineAppendMove( float frametime, usercmd_t *cmd, qboolean active )
{ {
float forward, side, pitch, yaw;
if( clgame.dllFuncs.pfnLookEvent ) if( clgame.dllFuncs.pfnLookEvent )
return; return;
if( cls.key_dest != key_game || cl.paused || cl.intermission ) if( cls.key_dest != key_game || cl.paused || cl.intermission )
return; return;
forward = side = pitch = yaw = 0;
if( active ) if( active )
{ {
float forward = 0, side = 0, pitch = 0, yaw = 0;
float sensitivity = 1;//( (float)cl.local.scr_fov / (float)90.0f ); float sensitivity = 1;//( (float)cl.local.scr_fov / (float)90.0f );
IN_CollectInput( &forward, &side, &pitch, &yaw, false ); IN_CollectInput( &forward, &side, &pitch, &yaw, false );
+48 -65
View File
@@ -67,18 +67,13 @@ static winding_t * winding_alloc( uint numpoints )
static void free_winding( winding_t *w ) static void free_winding( winding_t *w )
{ {
// simple sentinel by Carmack
if( *(unsigned *)w == 0xDEADC0DE )
Host_Error( "%s: freed a freed winding\n", __func__ );
*(unsigned *)w = 0xDEADC0DE; *(unsigned *)w = 0xDEADC0DE;
free( w ); free( w );
} }
static winding_t *winding_copy( winding_t *w ) static winding_t *winding_copy( winding_t *w )
{ {
winding_t *neww; winding_t *neww = winding_alloc( w->numpoints );
neww = winding_alloc( w->numpoints );
memcpy( neww, w, offsetof( winding_t, p[w->numpoints] ) ); memcpy( neww, w, offsetof( winding_t, p[w->numpoints] ) );
return neww; return neww;
@@ -86,12 +81,9 @@ static winding_t *winding_copy( winding_t *w )
static void winding_reverse( winding_t *w ) static void winding_reverse( winding_t *w )
{ {
vec3_t point; for( int i = 0; i < w->numpoints / 2; i++ )
int i;
for( i = 0; i < w->numpoints / 2; i++ )
{ {
VectorCopy( w->p[i], point ); vec3_t point = Vec3( w->p[i] );
VectorCopy( w->p[w->numpoints - i - 1], w->p[i] ); VectorCopy( w->p[w->numpoints - i - 1], w->p[i] );
VectorCopy( point, w->p[w->numpoints - i - 1] ); VectorCopy( point, w->p[w->numpoints - i - 1] );
} }
@@ -120,15 +112,13 @@ winding_for_plane
static winding_t *winding_for_plane( const mplane_t *p ) static winding_t *winding_for_plane( const mplane_t *p )
{ {
vec3_t org, vright, vup; vec3_t org, vright, vup;
int i, axis; vec_t v;
vec_t max, v;
winding_t *w;
// find the major axis // find the major axis
max = -BOGUS_RANGE; vec_t max = -BOGUS_RANGE;
axis = -1; int axis = -1;
for( i = 0; i < 3; i++ ) for( int i = 0; i < 3; i++ )
{ {
v = fabs( p->normal[i] ); v = fabs( p->normal[i] );
if( v > max ) if( v > max )
@@ -162,7 +152,7 @@ static winding_t *winding_for_plane( const mplane_t *p )
VectorScale( vright, BOGUS_RANGE, vright ); VectorScale( vright, BOGUS_RANGE, vright );
// project a really big axis aligned box onto the plane // project a really big axis aligned box onto the plane
w = winding_alloc( 4 ); winding_t *w = winding_alloc( 4 );
memset( w->p, 0, sizeof( vec3_t ) * 4 ); memset( w->p, 0, sizeof( vec3_t ) * 4 );
w->numpoints = 4; w->numpoints = 4;
w->plane = p; w->plane = p;
@@ -251,46 +241,42 @@ If keepon is true, an exactly on-plane winding will be saved, otherwise
*/ */
static winding_t *winding_clip( winding_t *in, const mplane_t *split, qboolean keepon, int side, vec_t epsilon ) static winding_t *winding_clip( winding_t *in, const mplane_t *split, qboolean keepon, int side, vec_t epsilon )
{ {
vec_t *dists;
int *sides;
int counts[3]; int counts[3];
vec_t dot;
int i, j;
winding_t *neww;
vec_t *p1, *p2, *mid;
int maxpts;
dists = (vec_t *)malloc(( in->numpoints + 1 ) * sizeof( vec_t )); vec_t *dists = (vec_t *)malloc(( in->numpoints + 1 ) * sizeof( vec_t ));
sides = (int *)malloc(( in->numpoints + 1 ) * sizeof( int )); int *sides = (int *)malloc(( in->numpoints + 1 ) * sizeof( int ));
CalcSides( in, split, sides, dists, counts, epsilon ); CalcSides( in, split, sides, dists, counts, epsilon );
if( keepon && !counts[SIDE_FRONT] && !counts[SIDE_BACK] ) if( keepon && !counts[SIDE_FRONT] && !counts[SIDE_BACK] )
{ {
neww = in; free( dists );
goto out_free; free( sides );
return in;
} }
if( !counts[side] ) if( !counts[side] )
{ {
free_winding( in ); free_winding( in );
neww = NULL; free( dists );
goto out_free; free( sides );
return NULL;
} }
if( !counts[side ^ 1] ) if( !counts[side ^ 1] )
{ {
neww = in; free( dists );
goto out_free; free( sides );
return in;
} }
maxpts = in->numpoints + 4; int maxpts = in->numpoints + 4;
neww = winding_alloc( maxpts ); winding_t *neww = winding_alloc( maxpts );
neww->numpoints = 0; neww->numpoints = 0;
neww->plane = in->plane; neww->plane = in->plane;
for( i = 0; i < in->numpoints; i++ ) for( int i = 0; i < in->numpoints; i++ )
{ {
p1 = in->p[i]; vec_t *p1 = in->p[i];
if( sides[i] == SIDE_ON ) if( sides[i] == SIDE_ON )
{ {
@@ -309,11 +295,11 @@ static winding_t *winding_clip( winding_t *in, const mplane_t *split, qboolean k
continue; continue;
// generate a split point // generate a split point
p2 = in->p[(i + 1) % in->numpoints]; vec_t *p2 = in->p[(i + 1) % in->numpoints];
mid = neww->p[neww->numpoints++]; vec_t *mid = neww->p[neww->numpoints++];
dot = dists[i] / (dists[i] - dists[i + 1]); vec_t dot = dists[i] / (dists[i] - dists[i + 1]);
for( j = 0; j < 3; j++ ) for( int j = 0; j < 3; j++ )
{ {
// avoid round off error when possible // avoid round off error when possible
if( in->plane->normal[j] == 1.0f ) if( in->plane->normal[j] == 1.0f )
@@ -336,7 +322,6 @@ static winding_t *winding_clip( winding_t *in, const mplane_t *split, qboolean k
// Shrink the winding back to just what it needs... // Shrink the winding back to just what it needs...
neww = winding_shrink(neww); neww = winding_shrink(neww);
out_free:
free( dists ); free( dists );
free( sides ); free( sides );
@@ -355,17 +340,10 @@ new windings will be created.
*/ */
static void winding_split( winding_t *in, const mplane_t *split, winding_t **pfront, winding_t **pback ) static void winding_split( winding_t *in, const mplane_t *split, winding_t **pfront, winding_t **pback )
{ {
vec_t *dists;
int *sides;
int counts[3]; int counts[3];
vec_t dot;
int i, j;
winding_t *front, *back;
vec_t *p1, *p2, *mid;
int maxpts;
dists = (vec_t *)malloc(( in->numpoints + 1 ) * sizeof( vec_t )); vec_t *dists = (vec_t *)malloc(( in->numpoints + 1 ) * sizeof( vec_t ));
sides = (int *)malloc(( in->numpoints + 1 ) * sizeof( int )); int *sides = (int *)malloc(( in->numpoints + 1 ) * sizeof( int ));
CalcSides(in, split, sides, dists, counts, 0.04f ); CalcSides(in, split, sides, dists, counts, 0.04f );
if( !counts[0] && !counts[1] ) if( !counts[0] && !counts[1] )
@@ -373,34 +351,40 @@ static void winding_split( winding_t *in, const mplane_t *split, winding_t **pfr
// winding on the split plane - return copies on both sides // winding on the split plane - return copies on both sides
*pfront = winding_copy( in ); *pfront = winding_copy( in );
*pback = winding_copy( in ); *pback = winding_copy( in );
goto out_free; free( dists );
free( sides );
return;
} }
if( !counts[0] ) if( !counts[0] )
{ {
*pfront = NULL; *pfront = NULL;
*pback = in; *pback = in;
goto out_free; free( dists );
free( sides );
return;
} }
if( !counts[1] ) if( !counts[1] )
{ {
*pfront = in; *pfront = in;
*pback = NULL; *pback = NULL;
goto out_free; free( dists );
free( sides );
return;
} }
maxpts = in->numpoints + 4; int maxpts = in->numpoints + 4;
front = winding_alloc( maxpts ); winding_t *front = winding_alloc( maxpts );
front->numpoints = 0; front->numpoints = 0;
front->plane = in->plane; front->plane = in->plane;
back = winding_alloc( maxpts ); winding_t *back = winding_alloc( maxpts );
back->numpoints = 0; back->numpoints = 0;
back->plane = in->plane; back->plane = in->plane;
for( i = 0; i < in->numpoints; i++ ) for( int i = 0; i < in->numpoints; i++ )
{ {
p1 = in->p[i]; vec_t *p1 = in->p[i];
if( sides[i] == SIDE_ON ) if( sides[i] == SIDE_ON )
{ {
@@ -426,11 +410,11 @@ static void winding_split( winding_t *in, const mplane_t *split, winding_t **pfr
continue; continue;
// generate a split point // generate a split point
p2 = in->p[(i + 1) % in->numpoints]; vec_t *p2 = in->p[(i + 1) % in->numpoints];
mid = front->p[front->numpoints++]; vec_t *mid = front->p[front->numpoints++];
dot = dists[i] / (dists[i] - dists[i + 1]); vec_t dot = dists[i] / (dists[i] - dists[i + 1]);
for( j = 0; j < 3; j++ ) for( int j = 0; j < 3; j++ )
{ {
// avoid round off error when possible // avoid round off error when possible
if( in->plane->normal[j] == 1.0f ) if( in->plane->normal[j] == 1.0f )
@@ -452,7 +436,6 @@ static void winding_split( winding_t *in, const mplane_t *split, winding_t **pfr
*pfront = winding_shrink( front ); *pfront = winding_shrink( front );
*pback = winding_shrink( back ); *pback = winding_shrink( back );
out_free:
free( dists ); free( dists );
free( sides ); free( sides );
} }
@@ -725,7 +708,7 @@ static void R_DrawHull( hull_model_t *hull )
{ {
int i; int i;
srand((unsigned int)poly ); srand((unsigned int)(uintptr_t)poly );
ref.dllFuncs.Color4ub( rand() & 255, rand() & 255, rand() & 255, 255 ); ref.dllFuncs.Color4ub( rand() & 255, rand() & 255, rand() & 255, 255 );
ref.dllFuncs.Begin( TRI_POLYGON ); ref.dllFuncs.Begin( TRI_POLYGON );
+131 -185
View File
@@ -60,35 +60,33 @@ CL_ParseSoundPacket
*/ */
static void CL_ParseSoundPacket( sizebuf_t *msg, qboolean restore ) static void CL_ParseSoundPacket( sizebuf_t *msg, qboolean restore )
{ {
vec3_t pos; int flags = MSG_ReadUBitLong( msg, MAX_SND_FLAGS_BITS );
int chan, sound; int sound = MSG_ReadUBitLong( msg, MAX_SOUND_BITS );
float volume, attn; int chan = MSG_ReadUBitLong( msg, MAX_SND_CHAN_BITS );
int flags, pitch, entnum, wordIndex = 0;
sound_t handle = 0;
double samplePos = 0, forcedEnd = 0;
flags = MSG_ReadUBitLong( msg, MAX_SND_FLAGS_BITS );
sound = MSG_ReadUBitLong( msg, MAX_SOUND_BITS );
chan = MSG_ReadUBitLong( msg, MAX_SND_CHAN_BITS );
float volume;
if( FBitSet( flags, SND_VOLUME )) if( FBitSet( flags, SND_VOLUME ))
volume = (float)MSG_ReadByte( msg ) / 255.0f; volume = (float)MSG_ReadByte( msg ) / 255.0f;
else volume = VOL_NORM; else volume = VOL_NORM;
float attn;
if( FBitSet( flags, SND_ATTENUATION )) if( FBitSet( flags, SND_ATTENUATION ))
attn = (float)MSG_ReadByte( msg ) / 64.0f; attn = (float)MSG_ReadByte( msg ) / 64.0f;
else attn = ATTN_NONE; else attn = ATTN_NONE;
int pitch;
if( FBitSet( flags, SND_PITCH )) if( FBitSet( flags, SND_PITCH ))
pitch = MSG_ReadByte( msg ); pitch = MSG_ReadByte( msg );
else pitch = PITCH_NORM; else pitch = PITCH_NORM;
// entity reletive // entity reletive
entnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS ); int entnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
// positioned in space // positioned in space
vec3_t pos;
MSG_ReadVec3Coord( msg, pos ); MSG_ReadVec3Coord( msg, pos );
sound_t handle = 0;
if( FBitSet( flags, SND_SENTENCE )) if( FBitSet( flags, SND_SENTENCE ))
{ {
char sentenceName[32]; char sentenceName[32];
@@ -101,13 +99,15 @@ static void CL_ParseSoundPacket( sizebuf_t *msg, qboolean restore )
} }
else handle = cl.sound_index[sound]; // see precached sound else handle = cl.sound_index[sound]; // see precached sound
uint wordIndex = 0;
double samplePos = 0, forcedEnd = 0;
if( restore ) if( restore )
{ {
wordIndex = MSG_ReadByte( msg ); wordIndex = MSG_ReadByte( msg );
// 16 bytes here // 16 bytes here
MSG_ReadBytes( msg, &samplePos, sizeof( samplePos )); MSG_ReadBytes( msg, &samplePos, sizeof( samplePos ), sizeof( samplePos ));
MSG_ReadBytes( msg, &forcedEnd, sizeof( forcedEnd )); MSG_ReadBytes( msg, &forcedEnd, sizeof( forcedEnd ), sizeof( forcedEnd ));
} }
if( !cl.audio_prepped ) if( !cl.audio_prepped )
@@ -129,8 +129,6 @@ CL_ParseServerTime
*/ */
void CL_ParseServerTime( sizebuf_t *msg, connprotocol_t proto ) void CL_ParseServerTime( sizebuf_t *msg, connprotocol_t proto )
{ {
double dt;
cl.mtime[1] = cl.mtime[0]; cl.mtime[1] = cl.mtime[0];
cl.mtime[0] = MSG_ReadFloat( msg ); cl.mtime[0] = MSG_ReadFloat( msg );
@@ -140,7 +138,7 @@ void CL_ParseServerTime( sizebuf_t *msg, connprotocol_t proto )
if( cl.maxclients == 1 ) if( cl.maxclients == 1 )
cl.time = cl.mtime[0]; cl.time = cl.mtime[0];
dt = cl.time - cl.mtime[0]; double dt = cl.time - cl.mtime[0];
if( fabs( dt ) > cl_clockreset.value ) // 0.1 by default if( fabs( dt ) > cl_clockreset.value ) // 0.1 by default
{ {
@@ -212,29 +210,26 @@ CL_ParseParticles
*/ */
static void CL_ParseParticles( sizebuf_t *msg, connprotocol_t proto ) static void CL_ParseParticles( sizebuf_t *msg, connprotocol_t proto )
{ {
vec3_t org, dir; vec3_t org, dir;
int i, count, color;
float life;
MSG_ReadVec3Coord( msg, org ); MSG_ReadVec3Coord( msg, org );
for( i = 0; i < 3; i++ ) for( int i = 0; i < 3; i++ )
dir[i] = MSG_ReadChar( msg ) * 0.0625f; dir[i] = MSG_ReadChar( msg ) * 0.0625f;
count = MSG_ReadByte( msg ); int count = MSG_ReadByte( msg );
color = MSG_ReadByte( msg ); int color = MSG_ReadByte( msg );
if( count == 255 ) if( count == 255 )
count = 1024; count = 1024;
float life;
if( proto == PROTO_GOLDSRC ) if( proto == PROTO_GOLDSRC )
life = 0.0f; life = 0.0f;
else life = MSG_ReadByte( msg ) * 0.125f; else life = MSG_ReadByte( msg ) * 0.125f;
if( life != 0.0f && count == 1 ) if( life != 0.0f && count == 1 )
{ {
particle_t *p; particle_t *p = R_AllocParticle( NULL );
p = R_AllocParticle( NULL );
if( !p ) return; if( !p ) return;
p->die += life; p->die += life;
@@ -256,25 +251,23 @@ static client entity
*/ */
static void CL_ParseStaticEntity( sizebuf_t *msg ) static void CL_ParseStaticEntity( sizebuf_t *msg )
{ {
int i, newnum;
const entity_state_t from = { 0 }; const entity_state_t from = { 0 };
entity_state_t to; entity_state_t to;
cl_entity_t *ent;
if( !clgame.static_entities ) if( !clgame.static_entities )
clgame.static_entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES ); clgame.static_entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS ); MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
MSG_ReadDeltaEntity( msg, &from, &to, 0, DELTA_STATIC, cl.mtime[0] ); MSG_ReadDeltaEntity( msg, &from, &to, 0, DELTA_STATIC, cl.mtime[0] );
i = clgame.numStatics; int i = clgame.numStatics;
if( i >= MAX_STATIC_ENTITIES ) if( i >= MAX_STATIC_ENTITIES )
{ {
Con_Printf( S_ERROR "MAX_STATIC_ENTITIES limit exceeded!\n" ); Con_Printf( S_ERROR "MAX_STATIC_ENTITIES limit exceeded!\n" );
return; return;
} }
ent = &clgame.static_entities[i]; cl_entity_t *ent = &clgame.static_entities[i];
clgame.numStatics++; clgame.numStatics++;
// all states are same // all states are same
@@ -315,7 +308,7 @@ Set new weapon animation
*/ */
void GAME_EXPORT CL_WeaponAnim( int iAnim, int body ) void GAME_EXPORT CL_WeaponAnim( int iAnim, int body )
{ {
cl_entity_t *view = &clgame.viewent; cl_entity_t *view = &clgame.viewent;
cl.local.weaponstarttime = 0.0f; cl.local.weaponstarttime = 0.0f;
cl.local.weaponsequence = iAnim; cl.local.weaponsequence = iAnim;
@@ -339,20 +332,18 @@ CL_ParseStaticDecal
*/ */
void CL_ParseStaticDecal( sizebuf_t *msg ) void CL_ParseStaticDecal( sizebuf_t *msg )
{ {
vec3_t origin; vec3_t origin;
int decalIndex, entityIndex, modelIndex;
float scale;
int flags;
MSG_ReadVec3Coord( msg, origin ); MSG_ReadVec3Coord( msg, origin );
decalIndex = MSG_ReadWord( msg ); int decalIndex = MSG_ReadWord( msg );
entityIndex = MSG_ReadShort( msg ); int entityIndex = MSG_ReadShort( msg );
int modelIndex;
if( entityIndex > 0 ) if( entityIndex > 0 )
modelIndex = MSG_ReadWord( msg ); modelIndex = MSG_ReadWord( msg );
else modelIndex = 0; else modelIndex = 0;
flags = MSG_ReadByte( msg ); int flags = MSG_ReadByte( msg );
scale = (float)MSG_ReadWord( msg ) / 4096.0f; float scale = (float)MSG_ReadWord( msg ) / 4096.0f;
CL_FireCustomDecal( CL_DecalIndex( decalIndex ), entityIndex, modelIndex, origin, flags, scale ); CL_FireCustomDecal( CL_DecalIndex( decalIndex ), entityIndex, modelIndex, origin, flags, scale );
} }
@@ -381,11 +372,9 @@ CL_RequestMissingResources
*/ */
qboolean CL_RequestMissingResources( void ) qboolean CL_RequestMissingResources( void )
{ {
resource_t *p;
if( !cls.dl.doneregistering && ( cls.dl.custom || cls.state == ca_validate )) if( !cls.dl.doneregistering && ( cls.dl.custom || cls.state == ca_validate ))
{ {
p = cl.resourcesneeded.pNext; resource_t *p = cl.resourcesneeded.pNext;
if( p == &cl.resourcesneeded ) if( p == &cl.resourcesneeded )
{ {
@@ -404,17 +393,16 @@ qboolean CL_RequestMissingResources( void )
void CL_BatchResourceRequest( qboolean initialize ) void CL_BatchResourceRequest( qboolean initialize )
{ {
byte data[MAX_INIT_MSG]; byte data[MAX_INIT_MSG];
resource_t *p, *n; sizebuf_t msg;
sizebuf_t msg; qboolean done_downloading = true;
qboolean done_downloading = true;
MSG_Init( &msg, "Resource Batch", data, sizeof( data )); MSG_Init( &msg, "Resource Batch", data, sizeof( data ));
// client resources is not precached by server // client resources is not precached by server
if( initialize ) CL_AddClientResources(); if( initialize ) CL_AddClientResources();
for( p = cl.resourcesneeded.pNext; p && p != &cl.resourcesneeded; p = n ) for( resource_t *p = cl.resourcesneeded.pNext, *n; p && p != &cl.resourcesneeded; p = n )
{ {
n = p->pNext; n = p->pNext;
@@ -491,10 +479,9 @@ void CL_BatchResourceRequest( qboolean initialize )
int CL_EstimateNeededResources( void ) int CL_EstimateNeededResources( void )
{ {
resource_t *p; int nTotalSize = 0;
int nTotalSize = 0;
for( p = cl.resourcesneeded.pNext; p != &cl.resourcesneeded; p = p->pNext ) for( resource_t *p = cl.resourcesneeded.pNext; p != &cl.resourcesneeded; p = p->pNext )
{ {
switch( p->type ) switch( p->type )
{ {
@@ -570,9 +557,7 @@ static void CL_StartResourceDownloading( const char *pszMessage, qboolean bCusto
static customization_t *CL_PlayerHasCustomization( int nPlayerNum, resourcetype_t type ) static customization_t *CL_PlayerHasCustomization( int nPlayerNum, resourcetype_t type )
{ {
customization_t *pList; for( customization_t *pList = cl.players[nPlayerNum].customdata.pNext; pList; pList = pList->pNext )
for( pList = cl.players[nPlayerNum].customdata.pNext; pList; pList = pList->pNext )
{ {
if( pList->resource.type == type ) if( pList->resource.type == type )
return pList; return pList;
@@ -582,10 +567,8 @@ static customization_t *CL_PlayerHasCustomization( int nPlayerNum, resourcetype_
static void CL_RemoveCustomization( int nPlayerNum, customization_t *pRemove ) static void CL_RemoveCustomization( int nPlayerNum, customization_t *pRemove )
{ {
customization_t *pList; customization_t *pNext;
customization_t *pNext; for( customization_t *pList = cl.players[nPlayerNum].customdata.pNext; pList; pList = pNext )
for( pList = cl.players[nPlayerNum].customdata.pNext; pList; pList = pNext )
{ {
pNext = pList->pNext; pNext = pList->pNext;
@@ -619,17 +602,11 @@ CL_ParseCustomization
*/ */
static void CL_ParseCustomization( sizebuf_t *msg ) static void CL_ParseCustomization( sizebuf_t *msg )
{ {
customization_t *pExistingCustomization; int i = MSG_ReadByte( msg );
customization_t *pList;
qboolean bFound;
resource_t *pRes;
int i;
i = MSG_ReadByte( msg );
if( i >= MAX_CLIENTS ) if( i >= MAX_CLIENTS )
Host_Error( "Bogus player index during customization parsing.\n" ); Host_Error( "Bogus player index during customization parsing.\n" );
pRes = Mem_Calloc( cls.mempool, sizeof( resource_t )); resource_t *pRes = Mem_Calloc( cls.mempool, sizeof( resource_t ));
pRes->type = MSG_ReadByte( msg ); pRes->type = MSG_ReadByte( msg );
Q_strncpy( pRes->szFileName, MSG_ReadString( msg ), sizeof( pRes->szFileName )); Q_strncpy( pRes->szFileName, MSG_ReadString( msg ), sizeof( pRes->szFileName ));
@@ -639,7 +616,7 @@ static void CL_ParseCustomization( sizebuf_t *msg )
pRes->pNext = pRes->pPrev = NULL; pRes->pNext = pRes->pPrev = NULL;
if( FBitSet( pRes->ucFlags, RES_CUSTOM )) if( FBitSet( pRes->ucFlags, RES_CUSTOM ))
MSG_ReadBytes( msg, pRes->rgucMD5_hash, 16 ); MSG_ReadBytes( msg, pRes->rgucMD5_hash, sizeof( pRes->rgucMD5_hash ), 16 );
pRes->playernum = i; pRes->playernum = i;
if( !cl_allow_download.value ) if( !cl_allow_download.value )
@@ -656,13 +633,13 @@ static void CL_ParseCustomization( sizebuf_t *msg )
return; return;
} }
pExistingCustomization = CL_PlayerHasCustomization( i, pRes->type ); customization_t *pExistingCustomization = CL_PlayerHasCustomization( i, pRes->type );
if( pExistingCustomization ) if( pExistingCustomization )
CL_RemoveCustomization( i, pExistingCustomization ); CL_RemoveCustomization( i, pExistingCustomization );
bFound = false;
for( pList = cl.players[pRes->playernum].customdata.pNext; pList; pList = pList->pNext ) qboolean bFound = false;
for( customization_t *pList = cl.players[pRes->playernum].customdata.pNext; pList; pList = pList->pNext )
{ {
if( !memcmp( pList->resource.rgucMD5_hash, pRes->rgucMD5_hash, 16 )) if( !memcmp( pList->resource.rgucMD5_hash, pRes->rgucMD5_hash, 16 ))
{ {
@@ -673,11 +650,11 @@ static void CL_ParseCustomization( sizebuf_t *msg )
if( HPAK_GetDataPointer( hpk_custom_file.string, pRes, NULL, NULL )) if( HPAK_GetDataPointer( hpk_custom_file.string, pRes, NULL, NULL ))
{ {
qboolean bError = false; qboolean bError = false;
if( !bFound ) if( !bFound )
{ {
pList = &cl.players[pRes->playernum].customdata; customization_t *pList = &cl.players[pRes->playernum].customdata;
if( !COM_CreateCustomization( pList, pRes, pRes->playernum, FCUST_FROMHPAK, NULL, NULL )) if( !COM_CreateCustomization( pList, pRes, pRes->playernum, FCUST_FROMHPAK, NULL, NULL ))
bError = true; bError = true;
@@ -707,15 +684,14 @@ CL_ParseResourceRequest
*/ */
void CL_SendResourceList( const resource_t *list, int count ) void CL_SendResourceList( const resource_t *list, int count )
{ {
byte buffer[MAX_INIT_MSG]; byte buffer[MAX_INIT_MSG];
sizebuf_t sbuf; sizebuf_t sbuf;
int i;
MSG_Init( &sbuf, "ResourceBlock", buffer, sizeof( buffer )); MSG_Init( &sbuf, "ResourceBlock", buffer, sizeof( buffer ));
MSG_BeginClientCmd( &sbuf, clc_resourcelist ); MSG_BeginClientCmd( &sbuf, clc_resourcelist );
MSG_WriteShort( &sbuf, count ); MSG_WriteShort( &sbuf, count );
for( i = 0; i < count; i++ ) for( int i = 0; i < count; i++ )
{ {
MSG_WriteString( &sbuf, list[i].szFileName ); MSG_WriteString( &sbuf, list[i].szFileName );
MSG_WriteByte( &sbuf, list[i].type ); MSG_WriteByte( &sbuf, list[i].type );
@@ -733,10 +709,8 @@ void CL_SendResourceList( const resource_t *list, int count )
static void CL_ParseResourceRequest( sizebuf_t *msg ) static void CL_ParseResourceRequest( sizebuf_t *msg )
{ {
int arg, nStartIndex; int arg = MSG_ReadLong( msg );
int nStartIndex = MSG_ReadLong( msg );
arg = MSG_ReadLong( msg );
nStartIndex = MSG_ReadLong( msg );
if( cl.servercount != arg ) if( cl.servercount != arg )
return; return;
@@ -756,16 +730,12 @@ loading custom decal for self
*/ */
static void CL_CreateCustomizationList( void ) static void CL_CreateCustomizationList( void )
{ {
resource_t *pResource; player_info_t *pPlayer = &cl.players[cl.playernum];
player_info_t *pPlayer;
int i;
pPlayer = &cl.players[cl.playernum];
pPlayer->customdata.pNext = NULL; pPlayer->customdata.pNext = NULL;
for( i = 0; i < cl.num_resources; i++ ) for( int i = 0; i < cl.num_resources; i++ )
{ {
pResource = &cl.resourcelist[i]; resource_t *pResource = &cl.resourcelist[i];
if( !COM_CreateCustomization( &pPlayer->customdata, pResource, cl.playernum, 0, NULL, NULL )) if( !COM_CreateCustomization( &pPlayer->customdata, pResource, cl.playernum, 0, NULL, NULL ))
Con_Printf( "problem with client customization %s, ignoring...", pResource->szFileName ); Con_Printf( "problem with client customization %s, ignoring...", pResource->szFileName );
@@ -843,7 +813,7 @@ static void CL_ParseServerData( sizebuf_t *msg, connprotocol_t proto )
byte clientdllmd5[16]; byte clientdllmd5[16];
const char *s; const char *s;
MSG_ReadBytes( msg, clientdllmd5, sizeof( clientdllmd5 )); MSG_ReadBytes( msg, clientdllmd5, sizeof( clientdllmd5 ), sizeof( clientdllmd5 ));
cl.maxclients = MSG_ReadByte( msg ); cl.maxclients = MSG_ReadByte( msg );
cl.playernum = MSG_ReadByte( msg ); cl.playernum = MSG_ReadByte( msg );
COM_UnMunge3((byte *)&cl.checksum, sizeof( cl.checksum ), ( 0xff - cl.playernum ) & 0xff ); COM_UnMunge3((byte *)&cl.checksum, sizeof( cl.checksum ), ( 0xff - cl.playernum ) & 0xff );
@@ -891,6 +861,15 @@ static void CL_ParseServerData( sizebuf_t *msg, connprotocol_t proto )
} }
} }
if( cl.playernum < 0 || cl.playernum >= MAX_CLIENTS || cl.maxclients <= 0 || cl.maxclients > MAX_CLIENTS )
{
Con_Printf( S_ERROR "%s: invalid playernum or maxclients (%d and %d must be less than %d)\n", __func__,
cl.playernum, cl.maxclients, MAX_CLIENTS );
CL_Disconnect_f();
Host_AbortCurrentFrame();
return;
}
Q_snprintf( mapfile, sizeof( mapfile ), "maps/%s.bsp", clgame.mapname ); Q_snprintf( mapfile, sizeof( mapfile ), "maps/%s.bsp", clgame.mapname );
if( CRC32_MapFile( &cl.worldmapCRC, mapfile, cl.maxclients > 1 )) if( CRC32_MapFile( &cl.worldmapCRC, mapfile, cl.maxclients > 1 ))
{ {
@@ -1238,12 +1217,10 @@ CL_ParseLightStyle
*/ */
static void CL_ParseLightStyle( sizebuf_t *msg, connprotocol_t proto ) static void CL_ParseLightStyle( sizebuf_t *msg, connprotocol_t proto )
{ {
int style; float f = cl.mtime[0];
const char *s;
float f = cl.mtime[0];
style = MSG_ReadByte( msg ); int style = MSG_ReadByte( msg );
s = MSG_ReadString( msg ); const char *s = MSG_ReadString( msg );
if( proto != PROTO_GOLDSRC && proto != PROTO_QUAKE ) if( proto != PROTO_GOLDSRC && proto != PROTO_QUAKE )
f = MSG_ReadFloat( msg ); f = MSG_ReadFloat( msg );
@@ -1271,10 +1248,7 @@ add the view angle yaw
*/ */
static void CL_ParseAddAngle( sizebuf_t *msg ) static void CL_ParseAddAngle( sizebuf_t *msg )
{ {
pred_viewangle_t *a; float delta_yaw = MSG_ReadBitAngle( msg, 16 );
float delta_yaw;
delta_yaw = MSG_ReadBitAngle( msg, 16 );
#if 0 #if 0
cl.viewangles[YAW] += delta_yaw; cl.viewangles[YAW] += delta_yaw;
return; return;
@@ -1284,7 +1258,7 @@ static void CL_ParseAddAngle( sizebuf_t *msg )
// select entry into circular buffer // select entry into circular buffer
cl.angle_position = (cl.angle_position + 1) & ANGLE_MASK; cl.angle_position = (cl.angle_position + 1) & ANGLE_MASK;
a = &cl.predicted_angle[cl.angle_position]; pred_viewangle_t *a = &cl.predicted_angle[cl.angle_position];
// record update // record update
a->starttime = cl.mtime[0]; a->starttime = cl.mtime[0];
@@ -1314,20 +1288,18 @@ reading decals, etc.
*/ */
static void CL_ParseRestore( sizebuf_t *msg ) static void CL_ParseRestore( sizebuf_t *msg )
{ {
string filename; string filename;
int i, mapCount;
char *pMapName;
// mapname.HL2 // mapname.HL2
Q_strncpy( filename, MSG_ReadString( msg ), sizeof( filename )); Q_strncpy( filename, MSG_ReadString( msg ), sizeof( filename ));
mapCount = MSG_ReadByte( msg ); int mapCount = MSG_ReadByte( msg );
// g-cont. acutally in Xash3D this does nothing. // g-cont. acutally in Xash3D this does nothing.
// decals already restored on a server, and correctly transferred through levels // decals already restored on a server, and correctly transferred through levels
// but i'm leave this message for backward compatibility // but i'm leave this message for backward compatibility
for( i = 0; i < mapCount; i++ ) for( int i = 0; i < mapCount; i++ )
{ {
pMapName = MSG_ReadString( msg ); char *pMapName = MSG_ReadString( msg );
Con_Printf( "Loading decals from %s\n", pMapName ); Con_Printf( "Loading decals from %s\n", pMapName );
} }
} }
@@ -1341,10 +1313,9 @@ register new user message or update existing
*/ */
static void CL_RegisterUserMessage( sizebuf_t *msg, connprotocol_t proto ) static void CL_RegisterUserMessage( sizebuf_t *msg, connprotocol_t proto )
{ {
char *pszName;
char szName[17]; char szName[17];
int size;
int svc_num = MSG_ReadByte( msg ); int svc_num = MSG_ReadByte( msg );
int size;
if( proto == PROTO_GOLDSRC ) if( proto == PROTO_GOLDSRC )
{ {
@@ -1359,9 +1330,10 @@ static void CL_RegisterUserMessage( sizebuf_t *msg, connprotocol_t proto )
size = -1; size = -1;
} }
char *pszName;
if( proto == PROTO_GOLDSRC ) if( proto == PROTO_GOLDSRC )
{ {
MSG_ReadBytes( msg, szName, sizeof( szName ) - 1 ); MSG_ReadBytes( msg, szName, sizeof( szName ), sizeof( szName ) - 1 );
szName[16] = 0; szName[16] = 0;
pszName = szName; pszName = szName;
} }
@@ -1379,9 +1351,8 @@ collect userinfo from all players
*/ */
static void CL_UpdateUserinfo( sizebuf_t *msg, connprotocol_t proto ) static void CL_UpdateUserinfo( sizebuf_t *msg, connprotocol_t proto )
{ {
int slot, id; int slot, id;
qboolean active; qboolean active;
player_info_t *player;
if( proto == PROTO_GOLDSRC ) if( proto == PROTO_GOLDSRC )
{ {
@@ -1399,7 +1370,7 @@ static void CL_UpdateUserinfo( sizebuf_t *msg, connprotocol_t proto )
if( slot >= MAX_CLIENTS ) if( slot >= MAX_CLIENTS )
Host_Error( "%s: svc_updateuserinfo >= MAX_CLIENTS\n", __func__ ); Host_Error( "%s: svc_updateuserinfo >= MAX_CLIENTS\n", __func__ );
player = &cl.players[slot]; player_info_t *player = &cl.players[slot];
if( active ) if( active )
{ {
@@ -1409,7 +1380,7 @@ static void CL_UpdateUserinfo( sizebuf_t *msg, connprotocol_t proto )
player->topcolor = Q_atoi( Info_ValueForKey( player->userinfo, "topcolor" )); player->topcolor = Q_atoi( Info_ValueForKey( player->userinfo, "topcolor" ));
player->bottomcolor = Q_atoi( Info_ValueForKey( player->userinfo, "bottomcolor" )); player->bottomcolor = Q_atoi( Info_ValueForKey( player->userinfo, "bottomcolor" ));
player->spectator = Q_atoi( Info_ValueForKey( player->userinfo, "*hltv" )); player->spectator = Q_atoi( Info_ValueForKey( player->userinfo, "*hltv" ));
MSG_ReadBytes( msg, player->hashedcdkey, sizeof( player->hashedcdkey )); MSG_ReadBytes( msg, player->hashedcdkey, sizeof( player->hashedcdkey ), sizeof( player->hashedcdkey ));
if( proto == PROTO_GOLDSRC && ( COM_StringEmpty( player->userinfo ) || COM_StringEmpty( player->name ))) if( proto == PROTO_GOLDSRC && ( COM_StringEmpty( player->userinfo ) || COM_StringEmpty( player->name )))
active = false; active = false;
@@ -1440,9 +1411,7 @@ downloading and precache resource in-game
*/ */
void CL_ParseResource( sizebuf_t *msg ) void CL_ParseResource( sizebuf_t *msg )
{ {
resource_t *pResource; resource_t *pResource = Mem_Calloc( cls.mempool, sizeof( resource_t ));
pResource = Mem_Calloc( cls.mempool, sizeof( resource_t ));
pResource->type = MSG_ReadUBitLong( msg, 4 ); pResource->type = MSG_ReadUBitLong( msg, 4 );
Q_strncpy( pResource->szFileName, MSG_ReadString( msg ), sizeof( pResource->szFileName )); Q_strncpy( pResource->szFileName, MSG_ReadString( msg ), sizeof( pResource->szFileName ));
@@ -1451,36 +1420,36 @@ void CL_ParseResource( sizebuf_t *msg )
pResource->ucFlags = MSG_ReadUBitLong( msg, 3 ) & ~RES_WASMISSING; pResource->ucFlags = MSG_ReadUBitLong( msg, 3 ) & ~RES_WASMISSING;
if( FBitSet( pResource->ucFlags, RES_CUSTOM )) if( FBitSet( pResource->ucFlags, RES_CUSTOM ))
MSG_ReadBytes( msg, pResource->rgucMD5_hash, sizeof( pResource->rgucMD5_hash )); MSG_ReadBytes( msg, pResource->rgucMD5_hash, sizeof( pResource->rgucMD5_hash ), sizeof( pResource->rgucMD5_hash ));
if( MSG_ReadOneBit( msg )) if( MSG_ReadOneBit( msg ))
MSG_ReadBytes( msg, pResource->rguc_reserved, sizeof( pResource->rguc_reserved )); MSG_ReadBytes( msg, pResource->rguc_reserved, sizeof( pResource->rguc_reserved ), sizeof( pResource->rguc_reserved ));
if( pResource->type == t_sound && pResource->nIndex > MAX_SOUNDS ) if( pResource->type == t_sound && pResource->nIndex >= MAX_SOUNDS )
{ {
Mem_Free( pResource ); Mem_Free( pResource );
Host_Error( "bad sound index\n" ); Host_Error( "bad sound index\n" );
} }
if( pResource->type == t_model && pResource->nIndex > MAX_MODELS ) if( pResource->type == t_model && pResource->nIndex >= MAX_MODELS )
{ {
Mem_Free( pResource ); Mem_Free( pResource );
Host_Error( "bad model index\n" ); Host_Error( "bad model index\n" );
} }
if( pResource->type == t_eventscript && pResource->nIndex > MAX_EVENTS ) if( pResource->type == t_eventscript && pResource->nIndex >= MAX_EVENTS )
{ {
Mem_Free( pResource ); Mem_Free( pResource );
Host_Error( "bad event index\n" ); Host_Error( "bad event index\n" );
} }
if( pResource->type == t_generic && pResource->nIndex > MAX_CUSTOM ) if( pResource->type == t_generic && pResource->nIndex >= MAX_CUSTOM )
{ {
Mem_Free( pResource ); Mem_Free( pResource );
Host_Error( "bad file index\n" ); Host_Error( "bad file index\n" );
} }
if( pResource->type == t_decal && pResource->nIndex > MAX_DECALS ) if( pResource->type == t_decal && pResource->nIndex >= MAX_DECALS )
{ {
Mem_Free( pResource ); Mem_Free( pResource );
Host_Error( "bad decal index\n" ); Host_Error( "bad decal index\n" );
@@ -1502,13 +1471,10 @@ void CL_UpdateUserPings( sizebuf_t *msg )
// because pings message always ends by null bit // because pings message always ends by null bit
while( 1 ) while( 1 )
{ {
int slot;
player_info_t *player;
if( !MSG_ReadOneBit( msg )) if( !MSG_ReadOneBit( msg ))
break; // end of message break; // end of message
slot = MSG_ReadUBitLong( msg, MAX_CLIENT_BITS ); int slot = MSG_ReadUBitLong( msg, MAX_CLIENT_BITS );
if( unlikely( slot >= MAX_CLIENTS )) if( unlikely( slot >= MAX_CLIENTS ))
{ {
@@ -1516,7 +1482,7 @@ void CL_UpdateUserPings( sizebuf_t *msg )
return; return;
} }
player = &cl.players[slot]; player_info_t *player = &cl.players[slot];
player->ping = MSG_ReadUBitLong( msg, 12 ); player->ping = MSG_ReadUBitLong( msg, 12 );
player->packet_loss = MSG_ReadUBitLong( msg, 7 ); player->packet_loss = MSG_ReadUBitLong( msg, 7 );
} }
@@ -1541,18 +1507,14 @@ static const char *CL_CheckTypeToString( int check_type )
static void CL_SendConsistencyInfo( sizebuf_t *msg, connprotocol_t proto ) static void CL_SendConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
{ {
qboolean user_changed_diskfile; byte md5[16] = { 0 };
vec3_t mins, maxs;
string filename;
byte md5[16] = { 0 };
int pos;
if( !cl.need_force_consistency_response ) if( !cl.need_force_consistency_response )
return; return;
cl.need_force_consistency_response = false; cl.need_force_consistency_response = false;
MSG_BeginClientCmd( msg, clc_fileconsistency ); MSG_BeginClientCmd( msg, clc_fileconsistency );
pos = MSG_GetNumBytesWritten( msg ); int pos = MSG_GetNumBytesWritten( msg );
if( proto == PROTO_GOLDSRC ) if( proto == PROTO_GOLDSRC )
{ {
MSG_WriteShort( msg, 0 ); MSG_WriteShort( msg, 0 );
@@ -1564,9 +1526,11 @@ static void CL_SendConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
for( int i = 0; i < cl.num_consistency; i++ ) for( int i = 0; i < cl.num_consistency; i++ )
{ {
qboolean have_file = true; qboolean have_file = true;
qboolean user_changed_diskfile = false;
vec3_t mins, maxs;
string filename;
consistency_t *pc = &cl.consistency_list[i]; consistency_t *pc = &cl.consistency_list[i];
user_changed_diskfile = false;
MSG_WriteOneBit( msg, 1 ); MSG_WriteOneBit( msg, 1 );
MSG_WriteUBitLong( msg, pc->orig_index, MAX_MODEL_BITS ); MSG_WriteUBitLong( msg, pc->orig_index, MAX_MODEL_BITS );
@@ -1645,10 +1609,9 @@ static void CL_SendConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
if( proto == PROTO_GOLDSRC ) if( proto == PROTO_GOLDSRC )
{ {
int len;
MSG_EndBitWriting( msg ); MSG_EndBitWriting( msg );
len = MSG_GetNumBytesWritten( msg ) - pos - 2; int len = MSG_GetNumBytesWritten( msg ) - pos - 2;
*(short *)&msg->pData[pos] = len; *(short *)&msg->pData[pos] = len;
COM_Munge( &msg->pData[pos + 2], len, cl.servercount ); COM_Munge( &msg->pData[pos + 2], len, cl.servercount );
@@ -1664,11 +1627,10 @@ static void CL_StartDark( void )
{ {
if( v_dark.value ) if( v_dark.value )
{ {
screenfade_t *sf = &clgame.fade; screenfade_t *sf = &clgame.fade;
float fadetime = 5.0f; float fadetime = 5.0f;
client_textmessage_t *title;
title = CL_TextMessageGet( "GAMETITLE" ); client_textmessage_t *title = CL_TextMessageGet( "GAMETITLE" );
if( Host_IsQuakeCompatible( )) if( Host_IsQuakeCompatible( ))
fadetime = 1.0f; fadetime = 1.0f;
@@ -1780,20 +1742,12 @@ void CL_RegisterResources( sizebuf_t *msg, connprotocol_t proto )
static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto ) static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
{ {
int lastcheck; byte nullbuffer[32];
int delta;
int i;
int isdelta;
resource_t *pResource;
resource_t *skip_crc_change;
int skip;
consistency_t *pc;
byte nullbuffer[32];
memset( nullbuffer, 0, 32 ); memset( nullbuffer, 0, 32 );
cl.need_force_consistency_response = MSG_ReadOneBit( msg ); cl.need_force_consistency_response = MSG_ReadOneBit( msg );
pResource = cl.resourcesneeded.pNext; resource_t *pResource = cl.resourcesneeded.pNext;
if( !cl.need_force_consistency_response ) if( !cl.need_force_consistency_response )
return; return;
@@ -1807,19 +1761,20 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
if( cl_trace_consistency.value ) if( cl_trace_consistency.value )
Con_Printf( "Server wants consistency of the following resources:\n" ); Con_Printf( "Server wants consistency of the following resources:\n" );
skip_crc_change = NULL; resource_t *skip_crc_change = NULL;
lastcheck = 0; int lastcheck = 0;
while( MSG_ReadOneBit( msg )) while( MSG_ReadOneBit( msg ))
{ {
isdelta = MSG_ReadOneBit( msg ); int isdelta = MSG_ReadOneBit( msg );
int delta;
if( isdelta ) delta = MSG_ReadUBitLong( msg, 5 ) + lastcheck; if( isdelta ) delta = MSG_ReadUBitLong( msg, 5 ) + lastcheck;
else delta = MSG_ReadUBitLong( msg, proto == PROTO_GOLDSRC ? MAX_GOLDSRC_MODEL_BITS : MAX_MODEL_BITS ); else delta = MSG_ReadUBitLong( msg, proto == PROTO_GOLDSRC ? MAX_GOLDSRC_MODEL_BITS : MAX_MODEL_BITS );
skip = delta - lastcheck; int skip = delta - lastcheck;
for( i = 0; i < skip; i++ ) for( int i = 0; i < skip; i++ )
{ {
if( pResource != skip_crc_change && Q_strstr( pResource->szFileName, "models/" )) if( pResource != skip_crc_change && Q_strstr( pResource->szFileName, "models/" ))
Mod_NeedCRC( pResource->szFileName, false ); Mod_NeedCRC( pResource->szFileName, false );
@@ -1835,7 +1790,7 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
if( cl.num_consistency >= MAX_MODELS ) if( cl.num_consistency >= MAX_MODELS )
Host_Error( "%s: MAX_MODELS limit exceeded (%d)\n", __func__, MAX_MODELS ); Host_Error( "%s: MAX_MODELS limit exceeded (%d)\n", __func__, MAX_MODELS );
pc = &cl.consistency_list[cl.num_consistency]; consistency_t *pc = &cl.consistency_list[cl.num_consistency];
cl.num_consistency++; cl.num_consistency++;
memset( pc, 0, sizeof( *pc )); memset( pc, 0, sizeof( *pc ));
@@ -1867,14 +1822,11 @@ CL_ParseResourceList
*/ */
void CL_ParseResourceList( sizebuf_t *msg, connprotocol_t proto ) void CL_ParseResourceList( sizebuf_t *msg, connprotocol_t proto )
{ {
resource_t *pResource; int total = MSG_ReadUBitLong( msg, proto == PROTO_GOLDSRC ? MAX_GOLDSRC_RESOURCE_BITS : MAX_RESOURCE_BITS );
int i, total;
total = MSG_ReadUBitLong( msg, proto == PROTO_GOLDSRC ? MAX_GOLDSRC_RESOURCE_BITS : MAX_RESOURCE_BITS ); for( int i = 0; i < total; i++ )
for( i = 0; i < total; i++ )
{ {
pResource = Mem_Calloc( cls.mempool, sizeof( resource_t )); resource_t *pResource = Mem_Calloc( cls.mempool, sizeof( resource_t ));
pResource->type = MSG_ReadUBitLong( msg, 4 ); pResource->type = MSG_ReadUBitLong( msg, 4 );
Q_strncpy( pResource->szFileName, MSG_ReadString( msg ), sizeof( pResource->szFileName )); Q_strncpy( pResource->szFileName, MSG_ReadString( msg ), sizeof( pResource->szFileName ));
@@ -1883,10 +1835,10 @@ void CL_ParseResourceList( sizebuf_t *msg, connprotocol_t proto )
pResource->ucFlags = MSG_ReadUBitLong( msg, 3 ) & ~RES_WASMISSING; pResource->ucFlags = MSG_ReadUBitLong( msg, 3 ) & ~RES_WASMISSING;
if( FBitSet( pResource->ucFlags, RES_CUSTOM )) if( FBitSet( pResource->ucFlags, RES_CUSTOM ))
MSG_ReadBytes( msg, pResource->rgucMD5_hash, sizeof( pResource->rgucMD5_hash )); MSG_ReadBytes( msg, pResource->rgucMD5_hash, sizeof( pResource->rgucMD5_hash ), sizeof( pResource->rgucMD5_hash ));
if( MSG_ReadOneBit( msg )) if( MSG_ReadOneBit( msg ))
MSG_ReadBytes( msg, pResource->rguc_reserved, sizeof( pResource->rguc_reserved )); MSG_ReadBytes( msg, pResource->rguc_reserved, sizeof( pResource->rguc_reserved ), sizeof( pResource->rguc_reserved ));
CL_AddToResourceList( pResource, &cl.resourcesneeded ); CL_AddToResourceList( pResource, &cl.resourcesneeded );
} }
@@ -1955,7 +1907,7 @@ static void CL_ParseVoiceData( sizebuf_t *msg, connprotocol_t proto )
if ( !size ) if ( !size )
return; return;
MSG_ReadBytes( msg, received, size ); MSG_ReadBytes( msg, received, sizeof( received ), size );
Voice_AddIncomingData( idx, received, size, frames ); Voice_AddIncomingData( idx, received, size, frames );
} }
@@ -2035,7 +1987,7 @@ static void CL_ParseDirector( sizebuf_t *msg )
byte pbuf[256]; byte pbuf[256];
// parse user message into buffer // parse user message into buffer
MSG_ReadBytes( msg, pbuf, iSize ); MSG_ReadBytes( msg, pbuf, sizeof( pbuf ), iSize );
clgame.dllFuncs.pfnDirectorMessage( iSize, pbuf ); clgame.dllFuncs.pfnDirectorMessage( iSize, pbuf );
} }
@@ -2071,14 +2023,12 @@ Set screen fade
*/ */
static void CL_ParseScreenFade( sizebuf_t *msg ) static void CL_ParseScreenFade( sizebuf_t *msg )
{ {
float duration, holdTime; screenfade_t *sf = &clgame.fade;
screenfade_t *sf = &clgame.fade;
float flScale;
duration = (float)MSG_ReadWord( msg ); float duration = (float)MSG_ReadWord( msg );
holdTime = (float)MSG_ReadWord( msg ); float holdTime = (float)MSG_ReadWord( msg );
sf->fadeFlags = MSG_ReadShort( msg ); sf->fadeFlags = MSG_ReadShort( msg );
flScale = FBitSet( sf->fadeFlags, FFADE_LONGFADE ) ? (1.0f / 256.0f) : (1.0f / 4096.0f); float flScale = FBitSet( sf->fadeFlags, FFADE_LONGFADE ) ? (1.0f / 256.0f) : (1.0f / 4096.0f);
sf->fader = MSG_ReadByte( msg ); sf->fader = MSG_ReadByte( msg );
sf->fadeg = MSG_ReadByte( msg ); sf->fadeg = MSG_ReadByte( msg );
@@ -2187,9 +2137,6 @@ Exec map/class specific configs
*/ */
static void CL_ParseExec( sizebuf_t *msg ) static void CL_ParseExec( sizebuf_t *msg )
{ {
qboolean is_class;
int class_idx;
string mapname;
const char *class_cfgs[] = { const char *class_cfgs[] = {
"", "",
"exec scout.cfg\n", "exec scout.cfg\n",
@@ -2205,17 +2152,18 @@ static void CL_ParseExec( sizebuf_t *msg )
"exec civilian.cfg\n" "exec civilian.cfg\n"
}; };
is_class = MSG_ReadByte( msg ); qboolean is_class = MSG_ReadByte( msg );
if( is_class ) if( is_class )
{ {
class_idx = MSG_ReadByte( msg ); int class_idx = MSG_ReadByte( msg );
if( class_idx >= 0 && class_idx <= 11 && !Q_stricmp( GI->gamefolder, "tfc" ) ) if( class_idx >= 0 && class_idx <= 11 && !Q_stricmp( GI->gamefolder, "tfc" ) )
Cbuf_AddText( class_cfgs[class_idx] ); Cbuf_AddText( class_cfgs[class_idx] );
} }
else if( !Q_stricmp( GI->gamefolder, "tfc" ) ) else if( !Q_stricmp( GI->gamefolder, "tfc" ) )
{ {
string mapname;
Cbuf_AddText( "exec mapdefault.cfg\n" ); Cbuf_AddText( "exec mapdefault.cfg\n" );
COM_FileBase( clgame.mapname, mapname, sizeof( mapname )); COM_FileBase( clgame.mapname, mapname, sizeof( mapname ));
@@ -2323,7 +2271,7 @@ void CL_ParseUserMessage( sizebuf_t *msg, int svc_num, connprotocol_t proto )
} }
// parse user message into buffer // parse user message into buffer
MSG_ReadBytes( msg, pbuf, iSize ); MSG_ReadBytes( msg, pbuf, sizeof( pbuf ), iSize );
if( cl_trace_messages.value ) if( cl_trace_messages.value )
{ {
@@ -2369,17 +2317,15 @@ show display finale or cutscene message
*/ */
static void CL_ParseFinaleCutscene( sizebuf_t *msg, int level ) static void CL_ParseFinaleCutscene( sizebuf_t *msg, int level )
{ {
static int msgindex = 0; static int msgindex = 0;
client_textmessage_t *text;
int channel;
cl.intermission = level; cl.intermission = level;
channel = msgindex; int channel = msgindex;
msgindex = (msgindex + 1) & (MAX_TEXTCHANNELS - 1); msgindex = (msgindex + 1) & (MAX_TEXTCHANNELS - 1);
// grab message channel // grab message channel
text = &cl_textmessage[channel]; client_textmessage_t *text = &cl_textmessage[channel];
// NOTE: svc_finale and svc_cutscene has a // NOTE: svc_finale and svc_cutscene has a
// predefined settings like Quake-style // predefined settings like Quake-style
@@ -2591,9 +2537,9 @@ dispatch messages
*/ */
void CL_ParseServerMessage( sizebuf_t *msg ) void CL_ParseServerMessage( sizebuf_t *msg )
{ {
size_t bufStart, playerbytes; size_t bufStart, playerbytes;
int cmd; int cmd;
int old_background; int old_background;
// parse the message // parse the message
while( 1 ) while( 1 )
+26 -32
View File
@@ -285,19 +285,17 @@ static void CL_CopyPacketEntity( frame_t *frame, int num, const entity_state_t *
static int CL_ParsePacketEntitiesGS( sizebuf_t *msg, qboolean delta ) static int CL_ParsePacketEntitiesGS( sizebuf_t *msg, qboolean delta )
{ {
frame_t *frame, *oldframe; frame_t *oldframe;
int oldindex, oldnum, numbase = 0; int numbase = 0;
entity_state_t *oldent;
int count;
int playerbytes = 0; int playerbytes = 0;
// save first uncompressed packet as timestamp // save first uncompressed packet as timestamp
if( cls.changelevel && !delta && cls.demorecording ) if( cls.changelevel && !delta && cls.demorecording )
CL_WriteDemoJumpTime(); CL_WriteDemoJumpTime();
count = MSG_ReadWord( msg ); int count = MSG_ReadWord( msg );
frame = &cl.frames[cl.parsecountmod]; frame_t *frame = &cl.frames[cl.parsecountmod];
memset( frame->flags, 0, sizeof( frame->flags )); memset( frame->flags, 0, sizeof( frame->flags ));
frame->first_entity = cls.next_client_entities; frame->first_entity = cls.next_client_entities;
frame->num_entities = 0; frame->num_entities = 0;
@@ -326,9 +324,9 @@ static int CL_ParsePacketEntitiesGS( sizebuf_t *msg, qboolean delta )
MSG_StartBitWriting( msg ); MSG_StartBitWriting( msg );
oldent = NULL; entity_state_t *oldent = NULL;
oldindex = 0; int oldindex = 0;
oldnum = CL_UpdateOldEntNum( oldindex, oldframe, &oldent ); int oldnum = CL_UpdateOldEntNum( oldindex, oldframe, &oldent );
// read it all but ignore it // read it all but ignore it
while( 1 ) while( 1 )
@@ -415,10 +413,9 @@ static int CL_ParsePacketEntitiesGS( sizebuf_t *msg, qboolean delta )
static float MSG_ReadGSBitCoord( sizebuf_t *sb ) static float MSG_ReadGSBitCoord( sizebuf_t *sb )
{ {
float value = 0; float value = 0;
int ival, fval;
ival = MSG_ReadOneBit( sb ); int ival = MSG_ReadOneBit( sb );
fval = MSG_ReadOneBit( sb ); int fval = MSG_ReadOneBit( sb );
if( ival || fval ) if( ival || fval )
{ {
@@ -439,13 +436,11 @@ static float MSG_ReadGSBitCoord( sizebuf_t *sb )
static void MSG_ReadGSBitVec3Coord( sizebuf_t *sb, vec3_t fa ) static void MSG_ReadGSBitVec3Coord( sizebuf_t *sb, vec3_t fa )
{ {
qboolean x, y, z;
VectorClear( fa ); VectorClear( fa );
x = MSG_ReadOneBit( sb ); qboolean x = MSG_ReadOneBit( sb );
y = MSG_ReadOneBit( sb ); qboolean y = MSG_ReadOneBit( sb );
z = MSG_ReadOneBit( sb ); qboolean z = MSG_ReadOneBit( sb );
if( x ) if( x )
fa[0] = MSG_ReadGSBitCoord( sb ); fa[0] = MSG_ReadGSBitCoord( sb );
if( y ) if( y )
@@ -456,31 +451,32 @@ static void MSG_ReadGSBitVec3Coord( sizebuf_t *sb, vec3_t fa )
static void CL_ParseSoundPacketGS( sizebuf_t *msg ) static void CL_ParseSoundPacketGS( sizebuf_t *msg )
{ {
vec3_t pos;
int chan, sound;
float volume, attn;
int flags, pitch, entnum;
sound_t handle = 0; sound_t handle = 0;
MSG_StartBitWriting( msg ); MSG_StartBitWriting( msg );
flags = MSG_ReadUBitLong( msg, 9 ); int flags = MSG_ReadUBitLong( msg, 9 );
float volume;
if( FBitSet( flags, SND_VOLUME )) if( FBitSet( flags, SND_VOLUME ))
volume = (float)MSG_ReadByte( msg ) / 255.0f; volume = (float)MSG_ReadByte( msg ) / 255.0f;
else volume = VOL_NORM; else volume = VOL_NORM;
float attn;
if( FBitSet( flags, SND_ATTENUATION )) if( FBitSet( flags, SND_ATTENUATION ))
attn = (float)MSG_ReadByte( msg ) / 64.0f; attn = (float)MSG_ReadByte( msg ) / 64.0f;
else attn = ATTN_NONE; else attn = ATTN_NONE;
chan = MSG_ReadUBitLong( msg, 3 ); int chan = MSG_ReadUBitLong( msg, 3 );
entnum = MSG_ReadUBitLong( msg, MAX_GOLDSRC_ENTITY_BITS ); int entnum = MSG_ReadUBitLong( msg, MAX_GOLDSRC_ENTITY_BITS );
int sound;
if( FBitSet( flags, SND_GOLDSRC_LARGE_INDEX )) if( FBitSet( flags, SND_GOLDSRC_LARGE_INDEX ))
sound = MSG_ReadWord( msg ); sound = MSG_ReadWord( msg );
else sound = MSG_ReadByte( msg ); else sound = MSG_ReadByte( msg );
vec3_t pos;
MSG_ReadGSBitVec3Coord( msg, pos ); MSG_ReadGSBitVec3Coord( msg, pos );
int pitch;
if( FBitSet( flags, SND_PITCH )) if( FBitSet( flags, SND_PITCH ))
pitch = MSG_ReadByte( msg ); pitch = MSG_ReadByte( msg );
else pitch = PITCH_NORM; else pitch = PITCH_NORM;
@@ -514,17 +510,15 @@ static void CL_ParseSoundPacketGS( sizebuf_t *msg )
static void CL_ParseSpawnStaticSound( sizebuf_t *msg ) static void CL_ParseSpawnStaticSound( sizebuf_t *msg )
{ {
vec3_t pos; vec3_t pos;
int sound, entnum, pitch, flags;
float volume, attn;
sound_t handle = 0; sound_t handle = 0;
MSG_ReadVec3Coord( msg, pos ); MSG_ReadVec3Coord( msg, pos );
sound = MSG_ReadShort( msg ); int sound = MSG_ReadShort( msg );
volume = MSG_ReadByte( msg ) * ( 1.0f / 255.0f ); float volume = MSG_ReadByte( msg ) * ( 1.0f / 255.0f );
attn = MSG_ReadByte( msg ) * ( 1.0f / 64.0f ); float attn = MSG_ReadByte( msg ) * ( 1.0f / 64.0f );
entnum = MSG_ReadShort( msg ); int entnum = MSG_ReadShort( msg );
pitch = MSG_ReadByte( msg ); int pitch = MSG_ReadByte( msg );
flags = MSG_ReadByte( msg ); int flags = MSG_ReadByte( msg );
if( FBitSet( flags, SND_SENTENCE )) if( FBitSet( flags, SND_SENTENCE ))
{ {
+45 -53
View File
@@ -80,14 +80,13 @@ we don't want interpolate this
*/ */
static qboolean CL_QuakeEntityTeleported( cl_entity_t *ent, entity_state_t *newstate ) static qboolean CL_QuakeEntityTeleported( cl_entity_t *ent, entity_state_t *newstate )
{ {
float len, maxlen; vec3_t delta;
vec3_t delta;
VectorSubtract( newstate->origin, ent->prevstate.origin, delta ); VectorSubtract( newstate->origin, ent->prevstate.origin, delta );
// compute potential max movement in units per frame and compare with entity movement // compute potential max movement in units per frame and compare with entity movement
maxlen = ( clgame.movevars.maxvelocity * ( 1.0f / GAME_FPS )); float maxlen = ( clgame.movevars.maxvelocity * ( 1.0f / GAME_FPS ));
len = VectorLength( delta ); float len = VectorLength( delta );
return (len > maxlen); return (len > maxlen);
} }
@@ -139,33 +138,30 @@ CL_ParseQuakeSound
*/ */
static void CL_ParseQuakeSound( sizebuf_t *msg ) static void CL_ParseQuakeSound( sizebuf_t *msg )
{ {
int channel, sound; int flags = MSG_ReadByte( msg );
int flags, entnum;
float volume, attn;
sound_t handle;
vec3_t pos;
flags = MSG_ReadByte( msg );
float volume;
if( FBitSet( flags, SND_VOLUME )) if( FBitSet( flags, SND_VOLUME ))
volume = (float)MSG_ReadByte( msg ) / 255.0f; volume = (float)MSG_ReadByte( msg ) / 255.0f;
else volume = VOL_NORM; else volume = VOL_NORM;
float attn;
if( FBitSet( flags, SND_ATTENUATION )) if( FBitSet( flags, SND_ATTENUATION ))
attn = (float)MSG_ReadByte( msg ) / 64.0f; attn = (float)MSG_ReadByte( msg ) / 64.0f;
else attn = ATTN_NONE; else attn = ATTN_NONE;
channel = MSG_ReadWord( msg ); int channel = MSG_ReadWord( msg );
sound = MSG_ReadByte( msg ); // Quake1 have max 255 precached sounds. erm int sound = MSG_ReadByte( msg ); // Quake1 have max 255 precached sounds. erm
// positioned in space // positioned in space
vec3_t pos;
MSG_ReadVec3Coord( msg, pos ); MSG_ReadVec3Coord( msg, pos );
entnum = channel >> 3; // entity reletive int entnum = channel >> 3; // entity reletive
channel &= 7; channel &= 7;
// see precached sound // see precached sound
handle = cl.sound_index[sound]; sound_t handle = cl.sound_index[sound];
if( !cl.audio_prepped ) if( !cl.audio_prepped )
return; // too early return; // too early
@@ -181,11 +177,6 @@ CL_ParseQuakeServerInfo
*/ */
static void CL_ParseQuakeServerInfo( sizebuf_t *msg ) static void CL_ParseQuakeServerInfo( sizebuf_t *msg )
{ {
resource_t *pResource;
const char *pResName;
int gametype;
int i;
Con_Reportf( "Serverdata packet received.\n" ); Con_Reportf( "Serverdata packet received.\n" );
cls.timestart = Platform_DoubleTime(); cls.timestart = Platform_DoubleTime();
@@ -198,7 +189,7 @@ static void CL_ParseQuakeServerInfo( sizebuf_t *msg )
cls.state = ca_connected; cls.state = ca_connected;
// parse protocol version number // parse protocol version number
i = MSG_ReadLong( msg ); int i = MSG_ReadLong( msg );
if( i != PROTOCOL_VERSION_QUAKE ) if( i != PROTOCOL_VERSION_QUAKE )
{ {
@@ -208,7 +199,7 @@ static void CL_ParseQuakeServerInfo( sizebuf_t *msg )
} }
cl.maxclients = MSG_ReadByte( msg ); cl.maxclients = MSG_ReadByte( msg );
gametype = MSG_ReadByte( msg ); int gametype = MSG_ReadByte( 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;
@@ -264,12 +255,12 @@ static void CL_ParseQuakeServerInfo( sizebuf_t *msg )
// Quake just have a large packet of initialization data // Quake just have a large packet of initialization data
for( i = 1; i < MAX_MODELS; i++ ) for( i = 1; i < MAX_MODELS; i++ )
{ {
pResName = MSG_ReadString( msg ); const char *pResName = MSG_ReadString( msg );
if( COM_StringEmptyOrNULL( pResName )) if( COM_StringEmptyOrNULL( pResName ))
break; // end of list break; // end of list
pResource = Mem_Calloc( cls.mempool, sizeof( resource_t )); resource_t *pResource = Mem_Calloc( cls.mempool, sizeof( resource_t ));
pResource->type = t_model; pResource->type = t_model;
Q_strncpy( pResource->szFileName, pResName, sizeof( pResource->szFileName )); Q_strncpy( pResource->szFileName, pResName, sizeof( pResource->szFileName ));
@@ -282,12 +273,12 @@ static void CL_ParseQuakeServerInfo( sizebuf_t *msg )
for( i = 1; i < MAX_SOUNDS; i++ ) for( i = 1; i < MAX_SOUNDS; i++ )
{ {
pResName = MSG_ReadString( msg ); const char *pResName = MSG_ReadString( msg );
if( COM_StringEmptyOrNULL( pResName )) if( COM_StringEmptyOrNULL( pResName ))
break; // end of list break; // end of list
pResource = Mem_Calloc( cls.mempool, sizeof( resource_t )); resource_t *pResource = Mem_Calloc( cls.mempool, sizeof( resource_t ));
pResource->type = t_sound; pResource->type = t_sound;
Q_strncpy( pResource->szFileName, pResName, sizeof( pResource->szFileName )); Q_strncpy( pResource->szFileName, pResName, sizeof( pResource->szFileName ));
@@ -340,15 +331,12 @@ CL_ParseQuakeClientData
*/ */
static void CL_ParseQuakeClientData( sizebuf_t *msg ) static void CL_ParseQuakeClientData( sizebuf_t *msg )
{ {
int i, bits = MSG_ReadWord( msg ); int bits = MSG_ReadWord( msg );
frame_t *frame;
// this is the frame update that this message corresponds to // this is the frame update that this message corresponds to
i = cls.netchan.incoming_sequence; cl.parsecount = cls.netchan.incoming_sequence; // ack'd incoming messages.
cl.parsecount = i; // ack'd incoming messages.
cl.parsecountmod = cl.parsecount & CL_UPDATE_MASK; // index into window. cl.parsecountmod = cl.parsecount & CL_UPDATE_MASK; // index into window.
frame = &cl.frames[cl.parsecountmod]; // frame at index. frame_t *frame = &cl.frames[cl.parsecountmod]; // frame at index.
frame->time = cl.mtime[0]; // mark network received time frame->time = cl.mtime[0]; // mark network received time
frame->receivedtime = host.realtime; // time now that we are parsing. frame->receivedtime = host.realtime; // time now that we are parsing.
memset( &frame->graphdata, 0, sizeof( netbandwidthgraph_t )); memset( &frame->graphdata, 0, sizeof( netbandwidthgraph_t ));
@@ -365,7 +353,7 @@ static void CL_ParseQuakeClientData( sizebuf_t *msg )
cl.local.idealpitch = MSG_ReadChar( msg ); cl.local.idealpitch = MSG_ReadChar( msg );
else cl.local.idealpitch = 0; else cl.local.idealpitch = 0;
for( i = 0; i < 3; i++ ) for( int i = 0; i < 3; i++ )
{ {
if( FBitSet( bits, SU_PUNCH1 << i )) if( FBitSet( bits, SU_PUNCH1 << i ))
frame->clientdata.punchangle[i] = (float)MSG_ReadChar( msg ); frame->clientdata.punchangle[i] = (float)MSG_ReadChar( msg );
@@ -568,15 +556,14 @@ CL_ParseQuakeParticles
*/ */
static void CL_ParseQuakeParticle( sizebuf_t *msg ) static void CL_ParseQuakeParticle( sizebuf_t *msg )
{ {
int count, color; vec3_t org, dir;
vec3_t org, dir;
MSG_ReadVec3Coord( msg, org ); MSG_ReadVec3Coord( msg, org );
dir[0] = MSG_ReadChar( msg ) * 0.0625f; dir[0] = MSG_ReadChar( msg ) * 0.0625f;
dir[1] = MSG_ReadChar( msg ) * 0.0625f; dir[1] = MSG_ReadChar( msg ) * 0.0625f;
dir[2] = MSG_ReadChar( msg ) * 0.0625f; dir[2] = MSG_ReadChar( msg ) * 0.0625f;
count = MSG_ReadByte( msg ); int count = MSG_ReadByte( msg );
color = MSG_ReadByte( msg ); int color = MSG_ReadByte( msg );
if( count == 255 ) count = 1024; if( count == 255 ) count = 1024;
R_RunParticleEffect( org, dir, color, count ); R_RunParticleEffect( org, dir, color, count );
@@ -590,14 +577,12 @@ CL_ParseQuakeStaticSound
*/ */
static void CL_ParseQuakeStaticSound( sizebuf_t *msg ) static void CL_ParseQuakeStaticSound( sizebuf_t *msg )
{ {
int sound_num; vec3_t org;
float vol, attn;
vec3_t org;
MSG_ReadVec3Coord( msg, org ); MSG_ReadVec3Coord( msg, org );
sound_num = MSG_ReadByte( msg ); int sound_num = MSG_ReadByte( msg );
vol = (float)MSG_ReadByte( msg ) / 255.0f; float vol = (float)MSG_ReadByte( msg ) / 255.0f;
attn = (float)MSG_ReadByte( msg ) / 64.0f; float attn = (float)MSG_ReadByte( msg ) / 64.0f;
S_StartSound( org, 0, CHAN_STATIC, cl.sound_index[sound_num], vol, attn, PITCH_NORM, 0 ); S_StartSound( org, 0, CHAN_STATIC, cl.sound_index[sound_num], vol, attn, PITCH_NORM, 0 );
} }
@@ -628,8 +613,6 @@ CL_ParseStaticEntity
static void CL_ParseQuakeStaticEntity( sizebuf_t *msg ) static void CL_ParseQuakeStaticEntity( sizebuf_t *msg )
{ {
entity_state_t state = { 0 }; entity_state_t state = { 0 };
cl_entity_t *ent;
int i;
if( !clgame.static_entities ) if( !clgame.static_entities )
clgame.static_entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES ); clgame.static_entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
@@ -645,14 +628,14 @@ static void CL_ParseQuakeStaticEntity( sizebuf_t *msg )
state.origin[2] = MSG_ReadCoord( msg ); state.origin[2] = MSG_ReadCoord( msg );
state.angles[2] = MSG_ReadAngle( msg ); state.angles[2] = MSG_ReadAngle( msg );
i = clgame.numStatics; int i = clgame.numStatics;
if( i >= MAX_STATIC_ENTITIES ) if( i >= MAX_STATIC_ENTITIES )
{ {
Con_Printf( S_ERROR "%s: static entities limit exceeded!\n", __func__ ); Con_Printf( S_ERROR "%s: static entities limit exceeded!\n", __func__ );
return; return;
} }
ent = &clgame.static_entities[i]; cl_entity_t *ent = &clgame.static_entities[i];
clgame.numStatics++; clgame.numStatics++;
ent->index = 0; // ??? ent->index = 0; // ???
@@ -692,16 +675,13 @@ CL_ParseQuakeBaseline
*/ */
static void CL_ParseQuakeBaseline( sizebuf_t *msg ) static void CL_ParseQuakeBaseline( sizebuf_t *msg )
{ {
entity_state_t state; int newnum = MSG_ReadWord( msg ); // entnum
cl_entity_t *ent;
int newnum;
newnum = MSG_ReadWord( msg ); // entnum
if( newnum >= clgame.maxEntities ) if( newnum >= clgame.maxEntities )
Host_Error( "%s: no free edicts\n", __func__ ); Host_Error( "%s: no free edicts\n", __func__ );
// parse baseline // parse baseline
entity_state_t state;
memset( &state, 0, sizeof( state )); memset( &state, 0, sizeof( state ));
state.modelindex = MSG_ReadByte( msg ); state.modelindex = MSG_ReadByte( msg );
state.frame = MSG_ReadByte( msg ); state.frame = MSG_ReadByte( msg );
@@ -714,7 +694,7 @@ static void CL_ParseQuakeBaseline( sizebuf_t *msg )
state.origin[2] = MSG_ReadCoord( msg ); state.origin[2] = MSG_ReadCoord( msg );
state.angles[2] = MSG_ReadAngle( msg ); state.angles[2] = MSG_ReadAngle( msg );
ent = CL_EDICT_NUM( newnum ); cl_entity_t *ent = CL_EDICT_NUM( newnum );
ent->index = newnum; ent->index = newnum;
ent->player = CL_IsPlayerIndex( newnum ); ent->player = CL_IsPlayerIndex( newnum );
ent->prevstate = ent->baseline = state; ent->prevstate = ent->baseline = state;
@@ -973,12 +953,21 @@ void CL_ParseQuakeMessage( sizebuf_t *msg )
break; break;
case svc_updatename: case svc_updatename:
param1 = MSG_ReadByte( msg ); param1 = MSG_ReadByte( msg );
if( param1 >= ARRAYSIZE( cl.players ))
{
MSG_ReadString( msg );
break;
}
Q_strncpy( cl.players[param1].name, MSG_ReadString( msg ), sizeof( cl.players[0].name )); Q_strncpy( cl.players[param1].name, MSG_ReadString( msg ), sizeof( cl.players[0].name ));
Q_strncpy( cl.players[param1].model, "player", sizeof( cl.players[0].name )); Q_strncpy( cl.players[param1].model, "player", sizeof( cl.players[0].name ));
break; break;
case svc_updatefrags: case svc_updatefrags:
param1 = MSG_ReadByte( msg ); param1 = MSG_ReadByte( msg );
param2 = MSG_ReadShort( msg ); param2 = MSG_ReadShort( msg );
if( param1 >= ARRAYSIZE( cl.players ))
break;
// HACKHACK: store frags into spectator // HACKHACK: store frags into spectator
cl.players[param1].spectator = param2; cl.players[param1].spectator = param2;
break; break;
@@ -994,6 +983,9 @@ void CL_ParseQuakeMessage( sizebuf_t *msg )
case svc_updatecolors: case svc_updatecolors:
param1 = MSG_ReadByte( msg ); param1 = MSG_ReadByte( msg );
param2 = MSG_ReadByte( msg ); param2 = MSG_ReadByte( msg );
if( param1 >= ARRAYSIZE( cl.players ) || param2 >= ARRAYSIZE( cl.players ))
break;
cl.players[param1].topcolor = param2 & 0xF; cl.players[param1].topcolor = param2 & 0xF;
cl.players[param1].bottomcolor = (param2 & 0xF0) >> 4; cl.players[param1].bottomcolor = (param2 & 0xF0) >> 4;
break; break;
+11 -12
View File
@@ -386,13 +386,14 @@ Do stereo processing
static void DLY_DoStereoDelay( portable_samplepair_t *paint, int count ) static void DLY_DoStereoDelay( portable_samplepair_t *paint, int count )
{ {
dly_t *dly = &stereodly; dly_t *dly = &stereodly;
int delay, samplexf;
if( !dly->lpdelayline ) if( !dly->lpdelayline )
return; // inactive return; // inactive
for( ; count; count--, paint++ ) for( ; count; count--, paint++ )
{ {
int delay;
if( dly->mod && --dly->modcur < 0 ) if( dly->mod && --dly->modcur < 0 )
dly->modcur = dly->mod; dly->modcur = dly->mod;
@@ -414,7 +415,7 @@ static void DLY_DoStereoDelay( portable_samplepair_t *paint, int count )
// modify delay, if crossfading // modify delay, if crossfading
if( dly->xfade ) if( dly->xfade )
{ {
samplexf = dly->lpdelayline[dly->idelayoutputxf] * (128 - dly->xfade) >> 7; int samplexf = dly->lpdelayline[dly->idelayoutputxf] * (128 - dly->xfade) >> 7;
delay = samplexf + ((delay * dly->xfade) >> 7); delay = samplexf + ((delay * dly->xfade) >> 7);
if( ++dly->idelayoutputxf >= dly->cdelaysamplesmax ) if( ++dly->idelayoutputxf >= dly->cdelaysamplesmax )
@@ -496,14 +497,13 @@ Do delay processing
static void DLY_DoDelay( portable_samplepair_t *paint, int count ) static void DLY_DoDelay( portable_samplepair_t *paint, int count )
{ {
dly_t *dly = &monodly; dly_t *dly = &monodly;
int delay;
if( !dly->lpdelayline || !count ) if( !dly->lpdelayline || !count )
return; // inactive return; // inactive
for( ; count; count--, paint++ ) for( ; count; count--, paint++ )
{ {
delay = dly->lpdelayline[dly->idelayoutput]; int delay = dly->lpdelayline[dly->idelayoutput];
// don't process if delay line and left/right samples are zero // don't process if delay line and left/right samples are zero
if( delay || paint->left || paint->right ) if( delay || paint->left || paint->right )
@@ -613,8 +613,6 @@ Do reverberation for one dly
static int RVB_DoReverbForOneDly( dly_t *dly, const int vlr, const portable_samplepair_t *samplepair ) static int RVB_DoReverbForOneDly( dly_t *dly, const int vlr, const portable_samplepair_t *samplepair )
{ {
int delay; int delay;
int samplexf;
int val, valt;
int voutm = 0; int voutm = 0;
if( --dly->modcur < 0 ) if( --dly->modcur < 0 )
@@ -624,6 +622,8 @@ static int RVB_DoReverbForOneDly( dly_t *dly, const int vlr, const portable_samp
if( dly->xfade || delay || samplepair->left || samplepair->right ) if( dly->xfade || delay || samplepair->left || samplepair->right )
{ {
int val, valt;
// modulate delay rate // modulate delay rate
if( !dly->mod ) if( !dly->mod )
{ {
@@ -636,7 +636,7 @@ static int RVB_DoReverbForOneDly( dly_t *dly, const int vlr, const portable_samp
if( dly->xfade ) if( dly->xfade )
{ {
samplexf = (dly->lpdelayline[dly->idelayoutputxf] * (REVERB_XFADE - dly->xfade)) / REVERB_XFADE; int samplexf = (dly->lpdelayline[dly->idelayoutputxf] * (REVERB_XFADE - dly->xfade)) / REVERB_XFADE;
delay = ((delay * dly->xfade) / REVERB_XFADE) + samplexf; delay = ((delay * dly->xfade) / REVERB_XFADE) + samplexf;
if( ++dly->idelayoutputxf >= dly->cdelaysamplesmax ) if( ++dly->idelayoutputxf >= dly->cdelaysamplesmax )
@@ -688,14 +688,14 @@ static void RVB_DoReverb( portable_samplepair_t *paint, int count )
{ {
dly_t *dly1 = &reverbdly[0]; dly_t *dly1 = &reverbdly[0];
dly_t *dly2 = &reverbdly[1]; dly_t *dly2 = &reverbdly[1];
int vlr, voutm;
if( !dly1->lpdelayline ) if( !dly1->lpdelayline )
return; return;
for( ; count; count--, paint++ ) for( ; count; count--, paint++ )
{ {
vlr = ( paint->left + paint->right ) >> 1; int vlr = ( paint->left + paint->right ) >> 1;
int voutm;
voutm = RVB_DoReverbForOneDly( dly1, vlr, paint ); voutm = RVB_DoReverbForOneDly( dly1, vlr, paint );
voutm += RVB_DoReverbForOneDly( dly2, vlr, paint ); voutm += RVB_DoReverbForOneDly( dly2, vlr, paint );
@@ -881,9 +881,8 @@ static void SX_Profiling_f( void )
portable_samplepair_t testbuffer[512]; portable_samplepair_t testbuffer[512];
float oldroom = room_type.value; float oldroom = room_type.value;
double start, end; double start, end;
int i, calls;
for( i = 0; i < ARRAYSIZE( testbuffer ); i++ ) for( int i = 0; i < ARRAYSIZE( testbuffer ); i++ )
{ {
testbuffer[i].left = COM_RandomLong( 0, 3000 ); testbuffer[i].left = COM_RandomLong( 0, 3000 );
testbuffer[i].right = COM_RandomLong( 0, 3000 ); testbuffer[i].right = COM_RandomLong( 0, 3000 );
@@ -899,7 +898,7 @@ static void SX_Profiling_f( void )
Con_Printf( "Profiling 10000 calls to DSP. Sample count is 512, room_type is %i\n", idsp_room ); Con_Printf( "Profiling 10000 calls to DSP. Sample count is 512, room_type is %i\n", idsp_room );
start = Platform_DoubleTime(); start = Platform_DoubleTime();
for( calls = 10000; calls; calls-- ) for( int calls = 10000; calls; calls-- )
{ {
SX_RoomFX( testbuffer, 512 ); SX_RoomFX( testbuffer, 512 );
} }
+10 -15
View File
@@ -39,17 +39,16 @@ S_SoundList_f
*/ */
void S_SoundList_f( void ) void S_SoundList_f( void )
{ {
sfx_t *sfx; sfx_t *sfx;
wavdata_t *sc; int i, totalSfx = 0;
int i, totalSfx = 0; int totalSize = 0;
int totalSize = 0;
for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ ) for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ )
{ {
if( !sfx->name[0] ) if( !sfx->name[0] )
continue; continue;
sc = sfx->cache; wavdata_t *sc = sfx->cache;
if( sc ) if( sc )
{ {
totalSize += sc->size; totalSize += sc->size;
@@ -149,7 +148,7 @@ S_FindName
sfx_t *S_FindName( const char *pname, qboolean *pfInCache ) sfx_t *S_FindName( const char *pname, qboolean *pfInCache )
{ {
sfx_t *sfx; sfx_t *sfx;
uint i, hash; uint i;
string name; string name;
if( COM_StringEmptyOrNULL( pname ) || !snd.initialized ) if( COM_StringEmptyOrNULL( pname ) || !snd.initialized )
@@ -162,7 +161,7 @@ sfx_t *S_FindName( const char *pname, qboolean *pfInCache )
COM_FixSlashes( name ); COM_FixSlashes( name );
// see if already loaded // see if already loaded
hash = COM_HashKey( name, MAX_SFX_HASH ); uint hash = COM_HashKey( name, MAX_SFX_HASH );
for( sfx = s_sfxHashList[hash]; sfx; sfx = sfx->hashNext ) for( sfx = s_sfxHashList[hash]; sfx; sfx = sfx->hashNext )
{ {
if( !Q_strcmp( sfx->name, name )) if( !Q_strcmp( sfx->name, name ))
@@ -210,17 +209,14 @@ S_FreeSound
*/ */
void S_FreeSound( sfx_t *sfx ) void S_FreeSound( sfx_t *sfx )
{ {
sfx_t *hashSfx;
sfx_t **prev;
if( !sfx || !sfx->name[0] ) if( !sfx || !sfx->name[0] )
return; return;
// de-link it from the hash tree // de-link it from the hash tree
prev = &s_sfxHashList[sfx->hashValue]; sfx_t **prev = &s_sfxHashList[sfx->hashValue];
while( 1 ) while( 1 )
{ {
hashSfx = *prev; sfx_t *hashSfx = *prev;
if( !hashSfx ) if( !hashSfx )
break; break;
@@ -251,12 +247,10 @@ S_BeginRegistration
*/ */
void S_BeginRegistration( void ) void S_BeginRegistration( void )
{ {
int i;
snd.have_ambient_sfx = false; snd.have_ambient_sfx = false;
// check for automatic ambient sounds // check for automatic ambient sounds
for( i = 0; i < NUM_AMBIENTS; i++ ) for( int i = 0; i < NUM_AMBIENTS; i++ )
{ {
if( !GI->ambientsound[i][0] ) if( !GI->ambientsound[i][0] )
continue; // empty slot continue; // empty slot
@@ -386,6 +380,7 @@ void S_FreeSounds( void )
for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ ) for( i = 0, sfx = s_knownSfx; i < s_numSfx; i++, sfx++ )
S_FreeSound( sfx ); S_FreeSound( sfx );
memset( s_knownSfx, 0, sizeof( s_knownSfx )); memset( s_knownSfx, 0, sizeof( s_knownSfx ));
memset( s_sfxHashList, 0, sizeof( s_sfxHashList )); memset( s_sfxHashList, 0, sizeof( s_sfxHashList ));
+49 -52
View File
@@ -290,8 +290,6 @@ static int SND_GetChannelTimeLeft( const channel_t *ch )
if( ch->words ) // sentences are special, count all remaining words if( ch->words ) // sentences are special, count all remaining words
{ {
int i;
if( FBitSet( ch->flags, FL_CHAN_SENTENCE_FINISHED ) ) if( FBitSet( ch->flags, FL_CHAN_SENTENCE_FINISHED ) )
return 0; return 0;
@@ -300,7 +298,7 @@ static int SND_GetChannelTimeLeft( const channel_t *ch )
// here we count all remaining words, stopping if no sfx or sound file is available // here we count all remaining words, stopping if no sfx or sound file is available
// see VOX_LoadWord // see VOX_LoadWord
for( i = ch->word_index + 1; i < CVOXWORDMAX; i++ ) for( int i = ch->word_index + 1; i < CVOXWORDMAX; i++ )
{ {
wavdata_t *sc; wavdata_t *sc;
int end; int end;
@@ -341,14 +339,9 @@ exceptions).
*/ */
channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx, qboolean *ignore ) channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx, qboolean *ignore )
{ {
int ch_idx; int first_to_die = -1;
int first_to_die; int life_left = 0x7fffffff;
int life_left;
int timeleft;
// check for replacement sound, or find the best one to replace
first_to_die = -1;
life_left = 0x7fffffff;
if( ignore ) *ignore = false; if( ignore ) *ignore = false;
if( channel == CHAN_STREAM && SND_FStreamIsPlaying( sfx )) if( channel == CHAN_STREAM && SND_FStreamIsPlaying( sfx ))
@@ -358,9 +351,10 @@ channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx, qboolean
return NULL; return NULL;
} }
for( ch_idx = NUM_AMBIENTS; ch_idx < MAX_DYNAMIC_CHANNELS; ch_idx++ ) for( int ch_idx = NUM_AMBIENTS; ch_idx < MAX_DYNAMIC_CHANNELS; ch_idx++ )
{ {
channel_t *ch = &snd.channels[ch_idx]; channel_t *ch = &snd.channels[ch_idx];
int timeleft;
// Never override a streaming sound that is currently playing or // Never override a streaming sound that is currently playing or
// voice over IP data that is playing or any sound on CHAN_VOICE( acting ) // voice over IP data that is playing or any sound on CHAN_VOICE( acting )
@@ -627,8 +621,8 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv
{ {
wavdata_t *pSource; wavdata_t *pSource;
sfx_t *sfx = NULL; sfx_t *sfx = NULL;
channel_t *target_chan, *check; channel_t *target_chan;
int vol, ch_idx; int vol;
qboolean bIgnore = false; qboolean bIgnore = false;
if( !snd.initialized ) return; if( !snd.initialized ) return;
@@ -746,7 +740,7 @@ S_RestoreSound
Restore a sound effect for the given entity on the given channel Restore a sound effect for the given entity on the given channel
==================== ====================
*/ */
void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float fvol, float attn, int pitch, int flags, double sample, double end, int wordIndex ) void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float fvol, float attn, int pitch, int flags, double sample, double end, uint wordIndex )
{ {
wavdata_t *pSource; wavdata_t *pSource;
sfx_t *sfx = NULL; sfx_t *sfx = NULL;
@@ -810,15 +804,30 @@ void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float
// not a first word in sentence! // not a first word in sentence!
if( wordIndex != 0 ) if( wordIndex != 0 )
{ {
VOX_FreeWord( target_chan ); // release first loaded word uint word_count = 0;
target_chan->word_index = wordIndex; // restore current word
VOX_LoadWord( target_chan );
if( !FBitSet( target_chan->flags, FL_CHAN_SENTENCE_FINISHED )) if( target_chan->words )
{ {
target_chan->sfx = target_chan->words[target_chan->word_index].sfx; while( word_count < CVOXWORDMAX && target_chan->words[word_count].sfx )
sfx = target_chan->sfx; word_count++;
pSource = sfx->cache; }
if( wordIndex >= word_count )
{
SetBits( target_chan->flags, FL_CHAN_SENTENCE_FINISHED );
}
else
{
VOX_FreeWord( target_chan ); // release first loaded word
target_chan->word_index = wordIndex; // restore current word
VOX_LoadWord( target_chan );
if( !FBitSet( target_chan->flags, FL_CHAN_SENTENCE_FINISHED ))
{
target_chan->sfx = target_chan->words[target_chan->word_index].sfx;
sfx = target_chan->sfx;
pSource = sfx->cache;
}
} }
} }
else else
@@ -874,7 +883,7 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa
channel_t *ch; channel_t *ch;
wavdata_t *pSource = NULL; wavdata_t *pSource = NULL;
sfx_t *sfx = NULL; sfx_t *sfx = NULL;
int vol, fvox = 0; int vol;
if( !snd.initialized ) return; if( !snd.initialized ) return;
sfx = S_GetSfxByHandle( handle ); sfx = S_GetSfxByHandle( handle );
@@ -911,7 +920,6 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa
Q_strncpy( ch->name, sfx->name, sizeof( ch->name )); Q_strncpy( ch->name, sfx->name, sizeof( ch->name ));
sfx = ch->sfx; sfx = ch->sfx;
if( sfx ) pSource = sfx->cache; if( sfx ) pSource = sfx->cache;
fvox = 1;
} }
else else
{ {
@@ -1020,14 +1028,14 @@ grab all static sounds playing at current channel
int S_GetCurrentDynamicSounds( soundlist_t *pout, int size ) int S_GetCurrentDynamicSounds( soundlist_t *pout, int size )
{ {
int sounds_left = size; int sounds_left = size;
int i, looped;
if( !snd.initialized ) if( !snd.initialized )
return 0; return 0;
for( i = 0; i < snd.max_channels && sounds_left; i++ ) for( int i = 0; i < snd.max_channels && sounds_left; i++ )
{ {
const channel_t *ch = &snd.channels[i]; const channel_t *ch = &snd.channels[i];
int looped;
if( !ch->sfx || !ch->sfx->name[0] || !Q_stricmp( ch->sfx->name, "*default" )) if( !ch->sfx || !ch->sfx->name[0] || !Q_stricmp( ch->sfx->name, "*default" ))
continue; // don't serialize default sounds continue; // don't serialize default sounds
@@ -1085,8 +1093,6 @@ S_UpdateAmbientSounds
*/ */
static void S_UpdateAmbientSounds( void ) static void S_UpdateAmbientSounds( void )
{ {
int ambient_channel;
if( !snd.have_ambient_sfx ) if( !snd.have_ambient_sfx )
return; return;
@@ -1117,7 +1123,7 @@ static void S_UpdateAmbientSounds( void )
continue; continue;
} }
float vol = s_ambient_level.value * leaf->ambient_sound_level[ambient_channel]; float vol = s_ambient_level.value * leaf->ambient_sound_level[i];
if( vol < 0.0f ) if( vol < 0.0f )
vol = 0.0f; vol = 0.0f;
@@ -1223,14 +1229,13 @@ S_RawSamplesStereo
*/ */
uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint max_samples, uint samples, uint rate, word width, word channels, const byte *data ) uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint max_samples, uint samples, uint rate, word width, word channels, const byte *data )
{ {
uint fracstep, samplefrac; uint src;
uint src, dst;
if( rawend < snd.paintedtime ) if( rawend < snd.paintedtime )
rawend = snd.paintedtime; rawend = snd.paintedtime;
fracstep = ((double) rate / (double)SOUND_DMA_SPEED) * (double)(1 << S_RAW_SAMPLES_PRECISION_BITS); uint fracstep = ((double) rate / (double)SOUND_DMA_SPEED) * (double)(1 << S_RAW_SAMPLES_PRECISION_BITS);
samplefrac = 0; uint samplefrac = 0;
if( width == 2 ) if( width == 2 )
{ {
@@ -1240,7 +1245,7 @@ uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint ma
{ {
for( src = 0; src < samples; samplefrac += fracstep, src = ( samplefrac >> S_RAW_SAMPLES_PRECISION_BITS )) for( src = 0; src < samples; samplefrac += fracstep, src = ( samplefrac >> S_RAW_SAMPLES_PRECISION_BITS ))
{ {
dst = rawend++ & ( max_samples - 1 ); uint dst = rawend++ & ( max_samples - 1 );
rawsamples[dst].left = in[src*2+0]; rawsamples[dst].left = in[src*2+0];
rawsamples[dst].right = in[src*2+1]; rawsamples[dst].right = in[src*2+1];
} }
@@ -1249,7 +1254,7 @@ uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint ma
{ {
for( src = 0; src < samples; samplefrac += fracstep, src = ( samplefrac >> S_RAW_SAMPLES_PRECISION_BITS )) for( src = 0; src < samples; samplefrac += fracstep, src = ( samplefrac >> S_RAW_SAMPLES_PRECISION_BITS ))
{ {
dst = rawend++ & ( max_samples - 1 ); uint dst = rawend++ & ( max_samples - 1 );
rawsamples[dst].left = in[src]; rawsamples[dst].left = in[src];
rawsamples[dst].right = in[src]; rawsamples[dst].right = in[src];
} }
@@ -1263,7 +1268,7 @@ uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint ma
for( src = 0; src < samples; samplefrac += fracstep, src = ( samplefrac >> S_RAW_SAMPLES_PRECISION_BITS )) for( src = 0; src < samples; samplefrac += fracstep, src = ( samplefrac >> S_RAW_SAMPLES_PRECISION_BITS ))
{ {
dst = rawend++ & ( max_samples - 1 ); uint dst = rawend++ & ( max_samples - 1 );
rawsamples[dst].left = in[src*2+0] << 8; rawsamples[dst].left = in[src*2+0] << 8;
rawsamples[dst].right = in[src*2+1] << 8; rawsamples[dst].right = in[src*2+1] << 8;
} }
@@ -1272,7 +1277,7 @@ uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint ma
{ {
for( src = 0; src < samples; samplefrac += fracstep, src = ( samplefrac >> S_RAW_SAMPLES_PRECISION_BITS )) for( src = 0; src < samples; samplefrac += fracstep, src = ( samplefrac >> S_RAW_SAMPLES_PRECISION_BITS ))
{ {
dst = rawend++ & ( max_samples - 1 ); uint dst = rawend++ & ( max_samples - 1 );
rawsamples[dst].left = ( data[src] - 128 ) << 8; rawsamples[dst].left = ( data[src] - 128 ) << 8;
rawsamples[dst].right = ( data[src] - 128 ) << 8; rawsamples[dst].right = ( data[src] - 128 ) << 8;
} }
@@ -1312,9 +1317,7 @@ Free raw channel that have been idling for too long.
*/ */
static void S_FreeIdleRawChannels( void ) static void S_FreeIdleRawChannels( void )
{ {
int i; for( int i = 0; i < snd.max_raw_channels; i++ )
for( i = 0; i < snd.max_raw_channels; i++ )
{ {
rawchan_t *ch = snd.raw_channels[i]; rawchan_t *ch = snd.raw_channels[i];
@@ -1347,9 +1350,7 @@ S_ClearRawChannels
*/ */
static void S_ClearRawChannels( void ) static void S_ClearRawChannels( void )
{ {
int i; for( int i = 0; i < snd.max_raw_channels; i++ )
for( i = 0; i < snd.max_raw_channels; i++ )
{ {
rawchan_t *ch = snd.raw_channels[i]; rawchan_t *ch = snd.raw_channels[i];
@@ -1467,12 +1468,10 @@ S_StopAllSounds
*/ */
void S_StopAllSounds( qboolean ambient ) void S_StopAllSounds( qboolean ambient )
{ {
int i;
if( !snd.initialized ) return; if( !snd.initialized ) return;
snd.total_channels = MAX_DYNAMIC_CHANNELS; // no statics snd.total_channels = MAX_DYNAMIC_CHANNELS; // no statics
for( i = 0; i < snd.max_channels; i++ ) for( int i = 0; i < snd.max_channels; i++ )
{ {
if( !snd.channels[i].sfx ) if( !snd.channels[i].sfx )
continue; continue;
@@ -1506,14 +1505,13 @@ update global soundtime
static int S_GetSoundtime( void ) static int S_GetSoundtime( void )
{ {
static int buffers, oldsamplepos; static int buffers, oldsamplepos;
int samplepos, fullsamples;
fullsamples = snd.samples / 2; int fullsamples = snd.samples / 2;
// it is possible to miscount buffers // it is possible to miscount buffers
// if it has wrapped twice between // if it has wrapped twice between
// calls to S_Update. Oh well. // calls to S_Update. Oh well.
samplepos = snd.samplepos; int samplepos = snd.samplepos;
if( samplepos < oldsamplepos ) if( samplepos < oldsamplepos )
{ {
@@ -1779,13 +1777,12 @@ static void S_Music_f( void )
{ {
string intro, main, track; string intro, main, track;
const char *ext[] = { "mp3", "wav" }; const char *ext[] = { "mp3", "wav" };
int i;
Q_strncpy( track, Cmd_Argv( 1 ), sizeof( track )); Q_strncpy( track, Cmd_Argv( 1 ), sizeof( track ));
Q_snprintf( intro, sizeof( intro ), "%s_intro", Cmd_Argv( 1 )); Q_snprintf( intro, sizeof( intro ), "%s_intro", Cmd_Argv( 1 ));
Q_snprintf( main, sizeof( main ), "%s_main", Cmd_Argv( 1 )); Q_snprintf( main, sizeof( main ), "%s_main", Cmd_Argv( 1 ));
for( i = 0; i < 2; i++ ) for( int i = 0; i < 2; i++ )
{ {
char intro_path[MAX_VA_STRING]; char intro_path[MAX_VA_STRING];
char main_path[MAX_VA_STRING]; char main_path[MAX_VA_STRING];
@@ -1863,8 +1860,8 @@ static void S_SoundFade_f( void )
int c = Cmd_Argc(); int c = Cmd_Argc();
int fade_percent; int fade_percent;
int hold_time; int hold_time;
int fade_out_seconds; int fade_out_seconds = 0;
int fade_in_seconds; int fade_in_seconds = 0;
if( c != 3 && c != 5 ) if( c != 3 && c != 5 )
{ {
+91 -74
View File
@@ -71,6 +71,39 @@ static portable_samplepair_t roombuffer[(PAINTBUFFER_SIZE+1)], paintbuffer[(PAIN
} \ } \
} \ } \
#define S_MakeMixMonoLerp( x ) \
static void S_MixMonoLerp ## x( portable_samplepair_t *pbuf, const int *volume, const void *buf, double offset_frac, double rate_scale, int num_samples ) \
{ \
const int##x##_t *data = buf; \
uint sample_idx = 0; \
for( int i = 0; i < num_samples; i++ ) \
{ \
int s = (int)( data[sample_idx] * ( 1.0 - offset_frac ) + data[sample_idx + 1] * offset_frac ); \
pbuf[i].left += ( s * volume[0] ) >> ( x - 8 ); \
pbuf[i].right += ( s * volume[1] ) >> ( x - 8 ); \
offset_frac += rate_scale; \
sample_idx += (uint)offset_frac; \
offset_frac -= (uint)offset_frac; \
} \
} \
#define S_MakeMixStereoLerp( x ) \
static void S_MixStereoLerp ## x( portable_samplepair_t *pbuf, const int *volume, const void *buf, double offset_frac, double rate_scale, int num_samples ) \
{ \
const int##x##_t *data = buf; \
uint sample_idx = 0; \
for( int i = 0; i < num_samples; i++ ) \
{ \
int sl = (int)( data[sample_idx + 0] * ( 1.0 - offset_frac ) + data[sample_idx + 2] * offset_frac ); \
int sr = (int)( data[sample_idx + 1] * ( 1.0 - offset_frac ) + data[sample_idx + 3] * offset_frac ); \
pbuf[i].left += ( sl * volume[0] ) >> ( x - 8 ); \
pbuf[i].right += ( sr * volume[1] ) >> ( x - 8 ); \
offset_frac += rate_scale; \
sample_idx += (uint)offset_frac << 1; \
offset_frac -= (uint)offset_frac; \
} \
} \
S_MakeMixMono( 8 ) S_MakeMixMono( 8 )
S_MakeMixMono( 16 ) S_MakeMixMono( 16 )
S_MakeMixStereo( 8 ) S_MakeMixStereo( 8 )
@@ -79,10 +112,14 @@ S_MakeMixMonoPitch( 8 )
S_MakeMixMonoPitch( 16 ) S_MakeMixMonoPitch( 16 )
S_MakeMixStereoPitch( 8 ) S_MakeMixStereoPitch( 8 )
S_MakeMixStereoPitch( 16 ) S_MakeMixStereoPitch( 16 )
S_MakeMixMonoLerp( 8 )
S_MakeMixMonoLerp( 16 )
S_MakeMixStereoLerp( 8 )
S_MakeMixStereoLerp( 16 )
static void S_MixAudio( portable_samplepair_t *pbuf, const int *pvol, const void *buf, int channels, int width, double offset_frac, double rate_scale, int num_samples ) static void S_MixAudio( portable_samplepair_t *pbuf, const int *pvol, const void *buf, int channels, int width, double offset_frac, double rate_scale, int num_samples, qboolean lerp )
{ {
if( Q_equal( rate_scale, 1.0 )) if( Q_equal( rate_scale, 1.0 ) && Q_equal( offset_frac, 0.0 ))
{ {
if( channels == 1 ) if( channels == 1 )
{ {
@@ -99,6 +136,23 @@ static void S_MixAudio( portable_samplepair_t *pbuf, const int *pvol, const void
S_MixStereo16( pbuf, pvol, buf, num_samples ); S_MixStereo16( pbuf, pvol, buf, num_samples );
} }
} }
else if( lerp )
{
if( channels == 1 )
{
if( width == 1 )
S_MixMonoLerp8( pbuf, pvol, buf, offset_frac, rate_scale, num_samples );
else
S_MixMonoLerp16( pbuf, pvol, buf, offset_frac, rate_scale, num_samples );
}
else
{
if( width == 1 )
S_MixStereoLerp8( pbuf, pvol, buf, offset_frac, rate_scale, num_samples );
else
S_MixStereoLerp16( pbuf, pvol, buf, offset_frac, rate_scale, num_samples );
}
}
else else
{ {
if( channels == 1 ) if( channels == 1 )
@@ -163,13 +217,16 @@ static int S_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan, i
if( num_samples == 0 ) if( num_samples == 0 )
return 0; return 0;
// linear interpolation needs one sample of lookahead beyond the last read position
const int lookahead = s_lerping.value ? 1 : 0;
while( num_samples > 0 ) while( num_samples > 0 )
{ {
// calculate the last sample position // calculate the last sample position
double end_sample = chan->sample + rate * num_samples * timecompress_rate; double end_sample = chan->sample + rate * num_samples * timecompress_rate;
// and get total amount of samples we want // and get total amount of samples we want, including lookahead for interpolation
int request_num_samples = (int)(ceil( end_sample ) - floor( chan->sample )); int request_num_samples = (int)(ceil( end_sample ) - floor( chan->sample )) + lookahead;
// get sample pointer and also amount of samples available // get sample pointer and also amount of samples available
const void *audio = NULL; const void *audio = NULL;
@@ -181,13 +238,30 @@ static int S_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan, i
double sample_frac = chan->sample - floor( chan->sample ); double sample_frac = chan->sample - floor( chan->sample );
// can interpolate only when at least two source samples are available
qboolean lerp = lookahead && available >= 2;
// this is how much data we output // this is how much data we output
int out_count = num_samples; int out_count = num_samples;
if( request_num_samples > available ) // but we can't write more than we have if( request_num_samples > available )
out_count = (int)ceil(( available - sample_frac ) / ( rate )); {
// lerp needs sample_idx + 1 to stay within available, so cap by available - 1
if( lerp )
out_count = (int)floor(( available - 1 - sample_frac ) / rate );
else
out_count = (int)ceil(( available - sample_frac ) / rate );
}
// near a buffer boundary (e.g. just before a loop wrap) lerp may yield zero;
// fall back to nearest for one sample to keep chan->sample advancing
if( out_count <= 0 )
{
lerp = false;
out_count = 1;
}
const wavdata_t *wav = chan->sfx->cache; const wavdata_t *wav = chan->sfx->cache;
S_MixAudio( pbuf + offset, pvol, audio, wav->channels, wav->width, sample_frac, rate, out_count ); S_MixAudio( pbuf + offset, pvol, audio, wav->channels, wav->width, sample_frac, rate, out_count, lerp );
chan->sample += out_count * rate * timecompress_rate; chan->sample += out_count * rate * timecompress_rate;
offset += out_count; offset += out_count;
@@ -231,11 +305,12 @@ static int VOX_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan,
return offset; return offset;
} }
static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate ) static int S_MixNormalChannelsToRoombuffer( portable_samplepair_t *dst, int end )
{ {
const qboolean sp = Host_IsSinglePlayerGame(); const qboolean sp = Host_IsSinglePlayerGame();
const qboolean ingame = CL_IsInGame(); const qboolean ingame = CL_IsInGame();
const int num_samples = ( end - snd.paintedtime ) / ( SOUND_DMA_SPEED / rate ); const int out_rate = snd.format.speed;
const int num_samples = end - snd.paintedtime;
// FWGS feature: make everybody sound like chipmunks when we're going fast // FWGS feature: make everybody sound like chipmunks when we're going fast
const float pitch_mult = ( sys_timescale.value + 1 ) / 2; const float pitch_mult = ( sys_timescale.value + 1 ) / 2;
@@ -298,19 +373,18 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate )
ch->inauduble_free_time = 0.0f; ch->inauduble_free_time = 0.0f;
if( rate != sc->rate )
continue;
if( ch->entchannel == CHAN_VOICE || ch->entchannel == CHAN_STREAM ) if( ch->entchannel == CHAN_VOICE || ch->entchannel == CHAN_STREAM )
{ {
cl_entity_t *ent = CL_GetEntityByIndex( ch->entnum ); cl_entity_t *ent = CL_GetEntityByIndex( ch->entnum );
if( ent != NULL ) if( ent != NULL )
{ {
int mouth_count = (int)( num_samples * (double)sc->rate / out_rate );
if( sc->width == 1 ) if( sc->width == 1 )
SND_MoveMouth8( &ent->mouth, ch->sample, sc, num_samples, FBitSet( ch->flags, FL_CHAN_USE_LOOP )); SND_MoveMouth8( &ent->mouth, ch->sample, sc, mouth_count, FBitSet( ch->flags, FL_CHAN_USE_LOOP ));
else else
SND_MoveMouth16( &ent->mouth, ch->sample, sc, num_samples, FBitSet( ch->flags, FL_CHAN_USE_LOOP )); SND_MoveMouth16( &ent->mouth, ch->sample, sc, mouth_count, FBitSet( ch->flags, FL_CHAN_USE_LOOP ));
} }
} }
@@ -320,14 +394,14 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate )
if( ch->words ) if( ch->words )
{ {
VOX_MixChannelToBuffer( dst, ch, num_samples, rate, pitch ); VOX_MixChannelToBuffer( dst, ch, num_samples, out_rate, pitch );
if( FBitSet( ch->flags, FL_CHAN_SENTENCE_FINISHED )) if( FBitSet( ch->flags, FL_CHAN_SENTENCE_FINISHED ))
S_FreeChannel( ch ); S_FreeChannel( ch );
} }
else else
{ {
S_MixChannelToBuffer( dst, ch, num_samples, rate, pitch, 0, 0 ); S_MixChannelToBuffer( dst, ch, num_samples, out_rate, pitch, 0, 0 );
if( FBitSet( ch->flags, FL_CHAN_FINISHED )) if( FBitSet( ch->flags, FL_CHAN_FINISHED ))
S_FreeChannel( ch ); S_FreeChannel( ch );
@@ -337,63 +411,6 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate )
return num_mixed_channels; return num_mixed_channels;
} }
static int S_AverageSample( int a, int b )
{
return ( a >> 1 ) + ( b >> 1 ) + ((( a & 1 ) + ( b & 1 )) >> 1 );
}
static void S_UpsampleBuffer( portable_samplepair_t *dst, size_t num_samples )
{
if( s_lerping.value )
{
// copy even positions and average odd
for( size_t i = num_samples - 1; i > 0; i-- )
{
dst[i * 2] = dst[i];
dst[i * 2 + 1].left = S_AverageSample( dst[i].left, dst[i - 1].left );
dst[i * 2 + 1].right = S_AverageSample( dst[i].right, dst[i - 1].right );
}
}
else
{
// copy into even and odd positions
for( size_t i = num_samples - 1; i > 0; i-- )
{
dst[i * 2] = dst[i];
dst[i * 2 + 1] = dst[i];
}
}
dst[1] = dst[0];
}
static int S_MixNormalChannelsToRoombuffer( int end, int count )
{
// for room buffer we only support CD rates like 11k, 22k, and 44k
// TODO: 48k output would require support from platform-specific backends first
// until there is no real usecase, let's keep it simple
int num_mixed_channels = S_MixNormalChannels( roombuffer, end, SOUND_11k );
if( snd.format.speed >= SOUND_22k )
{
if( num_mixed_channels > 0 )
S_UpsampleBuffer( roombuffer, count / ( SOUND_22k / SOUND_11k ));
num_mixed_channels += S_MixNormalChannels( roombuffer, end, SOUND_22k );
}
if( snd.format.speed >= SOUND_44k )
{
if( num_mixed_channels > 0 )
S_UpsampleBuffer( roombuffer, count / ( SOUND_44k / SOUND_22k ));
num_mixed_channels += S_MixNormalChannels( roombuffer, end, SOUND_44k );
}
return num_mixed_channels;
}
static int S_MixRawChannels( int end ) static int S_MixRawChannels( int end )
{ {
int num_room_channels = 0; int num_room_channels = 0;
@@ -537,7 +554,7 @@ void S_PaintChannels( int endtime )
S_ClearBuffers( num_samples ); S_ClearBuffers( num_samples );
int room_channels = S_MixNormalChannelsToRoombuffer( end, num_samples ); int room_channels = S_MixNormalChannelsToRoombuffer( roombuffer, end );
room_channels += S_MixRawChannels( end ); room_channels += S_MixRawChannels( end );
+14 -28
View File
@@ -36,20 +36,17 @@ static void SND_CommitMouthValue( mouth_t *mouth, int savg, int scount )
void SND_MoveMouth8( mouth_t *mouth, int pos, const wavdata_t *sc, int count, qboolean use_loop ) void SND_MoveMouth8( mouth_t *mouth, int pos, const wavdata_t *sc, int count, qboolean use_loop )
{ {
const int8_t *pdata = NULL; const int8_t *pdata = NULL;
int scount;
int savg, data;
uint i;
count = S_RetrieveAudioSamples( sc, (const void **)&pdata, pos, count, use_loop ); count = S_RetrieveAudioSamples( sc, (const void **)&pdata, pos, count, use_loop );
if( pdata == NULL ) return; if( pdata == NULL ) return;
i = 0; uint i = 0;
scount = mouth->sndcount; int scount = mouth->sndcount;
savg = 0; int savg = 0;
while( i < count && scount < CAVGSAMPLES ) while( i < count && scount < CAVGSAMPLES )
{ {
data = pdata[i]; int data = pdata[i];
savg += abs( data ); savg += abs( data );
i += 80 + ((byte)data & 0x1F); i += 80 + ((byte)data & 0x1F);
@@ -62,20 +59,17 @@ void SND_MoveMouth8( mouth_t *mouth, int pos, const wavdata_t *sc, int count, qb
void SND_MoveMouth16( mouth_t *mouth, int pos, const wavdata_t *sc, int count, qboolean use_loop ) void SND_MoveMouth16( mouth_t *mouth, int pos, const wavdata_t *sc, int count, qboolean use_loop )
{ {
const int16_t *pdata = NULL; const int16_t *pdata = NULL;
int savg, data;
int scount;
uint i;
count = S_RetrieveAudioSamples( sc, (const void **)&pdata, pos, count, use_loop ); count = S_RetrieveAudioSamples( sc, (const void **)&pdata, pos, count, use_loop );
if( pdata == NULL ) return; if( pdata == NULL ) return;
i = 0; uint i = 0;
scount = mouth->sndcount; int scount = mouth->sndcount;
savg = 0; int savg = 0;
while( i < count && scount < CAVGSAMPLES ) while( i < count && scount < CAVGSAMPLES )
{ {
data = pdata[i]; int data = pdata[i];
data = (bound( -32767, data, 0x7ffe ) >> 8); data = (bound( -32767, data, 0x7ffe ) >> 8);
savg += abs( data ); savg += abs( data );
@@ -88,9 +82,7 @@ void SND_MoveMouth16( mouth_t *mouth, int pos, const wavdata_t *sc, int count, q
void SND_ForceInitMouth( int entnum ) void SND_ForceInitMouth( int entnum )
{ {
cl_entity_t *clientEntity; cl_entity_t *clientEntity = CL_GetEntityByIndex( entnum );
clientEntity = CL_GetEntityByIndex( entnum );
if( clientEntity ) if( clientEntity )
{ {
@@ -102,9 +94,7 @@ void SND_ForceInitMouth( int entnum )
void SND_ForceCloseMouth( int entnum ) void SND_ForceCloseMouth( int entnum )
{ {
cl_entity_t *clientEntity; cl_entity_t *clientEntity = CL_GetEntityByIndex( entnum );
clientEntity = CL_GetEntityByIndex( entnum );
if( clientEntity ) if( clientEntity )
clientEntity->mouth.mouthopen = 0; clientEntity->mouth.mouthopen = 0;
@@ -112,17 +102,13 @@ void SND_ForceCloseMouth( int entnum )
void SND_MoveMouthRaw( mouth_t *mouth, const portable_samplepair_t *buf, int count ) void SND_MoveMouthRaw( mouth_t *mouth, const portable_samplepair_t *buf, int count )
{ {
int savg, data; uint i = 0;
int scount = 0; int scount = mouth->sndcount;
uint i; int savg = 0;
i = 0;
scount = mouth->sndcount;
savg = 0;
while ( i < count && scount < CAVGSAMPLES ) while ( i < count && scount < CAVGSAMPLES )
{ {
data = buf[i].left; // mono sound anyway int data = buf[i].left; // mono sound anyway
data = ( bound( -32767, data, 0x7ffe ) >> 8 ); data = ( bound( -32767, data, 0x7ffe ) >> 8 );
savg += abs( data ); savg += abs( data );
+7 -11
View File
@@ -66,14 +66,14 @@ S_GetMusicVolume
*/ */
float S_GetMusicVolume( void ) float S_GetMusicVolume( void )
{ {
float scale = 1.0f;
if( host.status == HOST_NOFOCUS && snd_mute_losefocus.value != 0.0f ) if( host.status == HOST_NOFOCUS && snd_mute_losefocus.value != 0.0f )
{ {
// we return zero volume to keep sounds running // we return zero volume to keep sounds running
return 0.0f; return 0.0f;
} }
float scale = 1.0f;
if( cls.key_dest != key_menu && musicfade.percent != 0 ) if( cls.key_dest != key_menu && musicfade.percent != 0 )
{ {
scale = bound( 0.0f, musicfade.percent / 100.0f, 1.0f ); scale = bound( 0.0f, musicfade.percent / 100.0f, 1.0f );
@@ -191,11 +191,7 @@ S_StreamBackgroundTrack
*/ */
void S_StreamBackgroundTrack( void ) void S_StreamBackgroundTrack( void )
{ {
int bufferSamples;
int fileSamples;
byte raw[MAX_RAW_SAMPLES]; byte raw[MAX_RAW_SAMPLES];
int r, fileBytes;
rawchan_t *ch = NULL;
if( !snd.initialized || !s_bgTrack.stream || snd.streaming ) if( !snd.initialized || !s_bgTrack.stream || snd.streaming )
return; return;
@@ -213,7 +209,7 @@ void S_StreamBackgroundTrack( void )
else if( cls.key_dest == key_console ) else if( cls.key_dest == key_console )
return; return;
ch = S_FindRawChannel( S_RAW_SOUND_BACKGROUNDTRACK, true ); rawchan_t *ch = S_FindRawChannel( S_RAW_SOUND_BACKGROUNDTRACK, true );
Assert( ch != NULL ); Assert( ch != NULL );
@@ -225,14 +221,14 @@ void S_StreamBackgroundTrack( void )
{ {
const stream_t *info = s_bgTrack.stream; const stream_t *info = s_bgTrack.stream;
bufferSamples = ch->max_samples - (ch->s_rawend - snd.soundtime); int bufferSamples = ch->max_samples - (ch->s_rawend - snd.soundtime);
// decide how much data needs to be read from the file // decide how much data needs to be read from the file
fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED ); int fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED );
if( fileSamples <= 1 ) return; // no more samples need if( fileSamples <= 1 ) return; // no more samples need
// our max buffer size // our max buffer size
fileBytes = fileSamples * ( info->width * info->channels ); int fileBytes = fileSamples * ( info->width * info->channels );
if( fileBytes > sizeof( raw )) if( fileBytes > sizeof( raw ))
{ {
@@ -241,7 +237,7 @@ void S_StreamBackgroundTrack( void )
} }
// read // read
r = FS_ReadStream( s_bgTrack.stream, fileBytes, raw ); int r = FS_ReadStream( s_bgTrack.stream, fileBytes, raw );
if( r < fileBytes ) if( r < fileBytes )
{ {
+19 -26
View File
@@ -52,7 +52,7 @@ static qboolean S_ShouldTrimSample16( const int16_t *buf, int channels )
static int S_TrimStart( const wavdata_t *wav, int start ) static int S_TrimStart( const wavdata_t *wav, int start )
{ {
size_t channels = wav->channels, width = wav->width, i; size_t channels = wav->channels, width = wav->width;
if( wav->type != WF_PCMDATA ) if( wav->type != WF_PCMDATA )
return start; return start;
@@ -61,7 +61,7 @@ static int S_TrimStart( const wavdata_t *wav, int start )
{ {
const int8_t *data = (const int8_t *)&wav->buffer[channels * width * start]; const int8_t *data = (const int8_t *)&wav->buffer[channels * width * start];
for( i = 0; i < TRIM_SCAN_MAX && start < wav->samples; i++ ) for( size_t i = 0; i < TRIM_SCAN_MAX && start < wav->samples; i++ )
{ {
if( !S_ShouldTrimSample8( data, wav->channels )) if( !S_ShouldTrimSample8( data, wav->channels ))
break; break;
@@ -74,7 +74,7 @@ static int S_TrimStart( const wavdata_t *wav, int start )
{ {
const int16_t *data = (const int16_t *)&wav->buffer[channels * width * start]; const int16_t *data = (const int16_t *)&wav->buffer[channels * width * start];
for( i = 0; i < TRIM_SCAN_MAX && start < wav->samples; i++ ) for( size_t i = 0; i < TRIM_SCAN_MAX && start < wav->samples; i++ )
{ {
if( !S_ShouldTrimSample16( data, wav->channels )) if( !S_ShouldTrimSample16( data, wav->channels ))
break; break;
@@ -89,7 +89,7 @@ static int S_TrimStart( const wavdata_t *wav, int start )
static int S_TrimEnd( const wavdata_t *wav, int end ) static int S_TrimEnd( const wavdata_t *wav, int end )
{ {
size_t channels = wav->channels, width = wav->width, i; size_t channels = wav->channels, width = wav->width;
if( wav->type != WF_PCMDATA ) if( wav->type != WF_PCMDATA )
return end; return end;
@@ -98,7 +98,7 @@ static int S_TrimEnd( const wavdata_t *wav, int end )
{ {
const int8_t *data = (const int8_t *)&wav->buffer[channels * width * ( end - 1 )]; const int8_t *data = (const int8_t *)&wav->buffer[channels * width * ( end - 1 )];
for( i = 0; i < TRIM_SCAN_MAX && end > 0; i++ ) for( size_t i = 0; i < TRIM_SCAN_MAX && end > 0; i++ )
{ {
if( !S_ShouldTrimSample8( data, wav->channels )) if( !S_ShouldTrimSample8( data, wav->channels ))
break; break;
@@ -111,7 +111,7 @@ static int S_TrimEnd( const wavdata_t *wav, int end )
{ {
const int16_t *data = (const int16_t *)&wav->buffer[channels * width * ( end - 1 )]; const int16_t *data = (const int16_t *)&wav->buffer[channels * width * ( end - 1 )];
for( i = 0; i < TRIM_SCAN_MAX && end > 0; i++ ) for( size_t i = 0; i < TRIM_SCAN_MAX && end > 0; i++ )
{ {
if( !S_ShouldTrimSample16( data, wav->channels )) if( !S_ShouldTrimSample16( data, wav->channels ))
break; break;
@@ -222,9 +222,6 @@ float VOX_ModifyPitch( channel_t *ch, float pitch )
static const char *VOX_GetDirectory( char *szpath, const char *psz, int nsize ) static const char *VOX_GetDirectory( char *szpath, const char *psz, int nsize )
{ {
const char *p;
int len;
// HACKHACK: some modders send strings like "/fvox/_period four" // HACKHACK: some modders send strings like "/fvox/_period four"
// which should get parsed as "_period four" said by fvox // which should get parsed as "_period four" said by fvox
// it might be incorrect but ignore first slash here for now // it might be incorrect but ignore first slash here for now
@@ -232,7 +229,7 @@ static const char *VOX_GetDirectory( char *szpath, const char *psz, int nsize )
psz++; psz++;
// search / backwards // search / backwards
p = Q_strrchr( psz, '/' ); const char *p = Q_strrchr( psz, '/' );
if( !p ) if( !p )
{ {
@@ -240,7 +237,7 @@ static const char *VOX_GetDirectory( char *szpath, const char *psz, int nsize )
return psz; return psz;
} }
len = p - psz + 1; int len = p - psz + 1;
if( len > nsize ) if( len > nsize )
{ {
@@ -256,8 +253,7 @@ static const char *VOX_GetDirectory( char *szpath, const char *psz, int nsize )
static const char *VOX_LookupString( const char *pszin ) static const char *VOX_LookupString( const char *pszin )
{ {
int i = -1, len; int i = -1;
const char *c;
// check if we are an immediate sentence // check if we are an immediate sentence
if( *pszin == '#' ) if( *pszin == '#' )
@@ -289,9 +285,9 @@ static const char *VOX_LookupString( const char *pszin )
if( i == cszrawsentences ) if( i == cszrawsentences )
return NULL; return NULL;
len = Q_strlen( rgpszrawsentence[i] ); int len = Q_strlen( rgpszrawsentence[i] );
c = &rgpszrawsentence[i][len + 1]; const char *c = &rgpszrawsentence[i][len + 1];
for( ; *c == ' ' || *c == '\t'; c++ ); for( ; *c == ' ' || *c == '\t'; c++ );
return c; return c;
@@ -362,12 +358,11 @@ static void VOX_MakeDefaultWordParams( voxword_t *voxword )
static qboolean VOX_ParseWordParams( char *psz, voxword_t *pvoxword, voxword_t *default_voxword ) static qboolean VOX_ParseWordParams( char *psz, voxword_t *pvoxword, voxword_t *default_voxword )
{ {
int len, i;
char sznum[8], *pszsave = psz; char sznum[8], *pszsave = psz;
*pvoxword = *default_voxword; *pvoxword = *default_voxword;
len = Q_strlen( psz ); int len = Q_strlen( psz );
if( len == 0 ) if( len == 0 )
return false; return false;
@@ -388,6 +383,7 @@ static qboolean VOX_ParseWordParams( char *psz, voxword_t *pvoxword, voxword_t *
for( ;; ) for( ;; )
{ {
char command; char command;
int i;
// find command // find command
for( ; *psz && for( ; *psz &&
@@ -446,7 +442,7 @@ void VOX_LoadSound( channel_t *ch, const char *pszin )
char buffer[512] = { 0 }, szpath[32] = { 0 }; char buffer[512] = { 0 }, szpath[32] = { 0 };
char *rgpparseword[CVOXWORDMAX] = { 0 }; char *rgpparseword[CVOXWORDMAX] = { 0 };
const char *psz; const char *psz;
int i, j; int j;
int num_words; int num_words;
voxword_t default_voxword; voxword_t default_voxword;
voxword_t words_buf[CVOXWORDMAX + 1]; // local scratch: parsed words + null terminator voxword_t words_buf[CVOXWORDMAX + 1]; // local scratch: parsed words + null terminator
@@ -490,7 +486,8 @@ void VOX_LoadSound( channel_t *ch, const char *pszin )
VOX_MakeDefaultWordParams( &default_voxword ); VOX_MakeDefaultWordParams( &default_voxword );
memset( words_buf, 0, sizeof( words_buf )); memset( words_buf, 0, sizeof( words_buf ));
for( i = 0, j = 0; i < num_words; i++ ) j = 0;
for( int i = 0; i < num_words; i++ )
{ {
char pathbuffer[MAX_SYSPATH]; char pathbuffer[MAX_SYSPATH];
@@ -589,9 +586,7 @@ void VOX_Init( void )
void VOX_Shutdown( void ) void VOX_Shutdown( void )
{ {
int i; for( int i = 0; i < cszrawsentences; i++ )
for( i = 0; i < cszrawsentences; i++ )
Mem_Free( rgpszrawsentence[i] ); Mem_Free( rgpszrawsentence[i] );
cszrawsentences = 0; cszrawsentences = 0;
@@ -609,9 +604,8 @@ static void Test_VOX_GetDirectory( void )
"barney/meow", "meow", "barney/", "barney/meow", "meow", "barney/",
"/fvox/_period", "_period", "fvox/", "/fvox/_period", "_period", "fvox/",
}; };
int i;
for( i = 0; i < sizeof( data ) / sizeof( data[0] ); i += 3 ) for( int i = 0; i < sizeof( data ) / sizeof( data[0] ); i += 3 )
{ {
string szpath; string szpath;
const char *p = VOX_GetDirectory( szpath, data[i+0], sizeof( szpath )); const char *p = VOX_GetDirectory( szpath, data[i+0], sizeof( szpath ));
@@ -623,7 +617,6 @@ static void Test_VOX_GetDirectory( void )
static void Test_VOX_LookupString( void ) static void Test_VOX_LookupString( void )
{ {
int i;
const char *p, *data[] = const char *p, *data[] =
{ {
"0", "123", "0", "123",
@@ -645,7 +638,7 @@ static void Test_VOX_LookupString( void )
rgpszrawsentence[cszrawsentences++] = (char*)"SentenceWithSpaces\0 SPAAACE"; rgpszrawsentence[cszrawsentences++] = (char*)"SentenceWithSpaces\0 SPAAACE";
rgpszrawsentence[cszrawsentences++] = (char*)"SentenceWithTabsAndSpaces\0\t \t\t MEOW"; rgpszrawsentence[cszrawsentences++] = (char*)"SentenceWithTabsAndSpaces\0\t \t\t MEOW";
for( i = 0; i < sizeof( data ) / sizeof( data[0] ); i += 2 ) for( int i = 0; i < sizeof( data ) / sizeof( data[0] ); i += 2 )
{ {
p = VOX_LookupString( data[i] ); p = VOX_LookupString( data[i] );
+29 -45
View File
@@ -381,18 +381,17 @@ Apply automatic gain control to voice samples
*/ */
static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale ) static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale )
{ {
float gain, modifiedMax; int blockOffset = 0;
int average, blockOffset = 0;
for( ;; ) for( ;; )
{ {
int i, localMax = 0, localSum = 0; int localMax = 0, localSum = 0;
int blockSize = Q_min( count - blockOffset, voice.autogain.block_size ); int blockSize = Q_min( count - blockOffset, voice.autogain.block_size );
if( blockSize < 1 ) if( blockSize < 1 )
break; break;
for( i = 0; i < blockSize; ++i ) for( int i = 0; i < blockSize; ++i )
{ {
int sample = samples[blockOffset + i]; int sample = samples[blockOffset + i];
int absSample = abs( sample ); int absSample = abs( sample );
@@ -401,14 +400,14 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale )
localMax = absSample; localMax = absSample;
localSum += absSample; localSum += absSample;
gain = voice.autogain.current_gain + i * voice.autogain.gain_multiplier; float gain = voice.autogain.current_gain + i * voice.autogain.gain_multiplier;
samples[blockOffset + i] = bound( SHRT_MIN, (int)( sample * gain ), SHRT_MAX ); samples[blockOffset + i] = bound( SHRT_MIN, (int)( sample * gain ), SHRT_MAX );
} }
if( blockOffset % voice.autogain.block_size == 0 ) if( blockOffset % voice.autogain.block_size == 0 )
{ {
average = localSum / blockSize; int average = localSum / blockSize;
modifiedMax = average + ( localMax - average ) * voice_avggain.value; float modifiedMax = average + ( localMax - average ) * voice_avggain.value;
voice.autogain.current_gain = voice.autogain.next_gain * scale; voice.autogain.current_gain = voice.autogain.next_gain * scale;
voice.autogain.next_gain = Q_min((float)SHRT_MAX / ( modifiedMax > 1 ? modifiedMax : 1 ), voice_maxgain.value ) * scale; voice.autogain.next_gain = Q_min((float)SHRT_MAX / ( modifiedMax > 1 ? modifiedMax : 1 ), voice_maxgain.value ) * scale;
@@ -435,13 +434,11 @@ static uint Voice_GetOpusCompressedData( byte *out, uint maxsize, uint *frames )
if( voice.input_file ) if( voice.input_file )
{ {
uint numbytes; double curtime = Platform_DoubleTime();
double updateInterval, curtime = Platform_DoubleTime(); double updateInterval = curtime - voice.start_time;
updateInterval = curtime - voice.start_time;
voice.start_time = curtime; voice.start_time = curtime;
numbytes = updateInterval * voice.samplerate * voice.width * VOICE_PCM_CHANNELS; uint numbytes = updateInterval * voice.samplerate * voice.width * VOICE_PCM_CHANNELS;
numbytes = Q_min( numbytes, voice.input_file->size - voice.input_file_pos ); numbytes = Q_min( numbytes, voice.input_file->size - voice.input_file_pos );
numbytes = Q_min( numbytes, sizeof( voice.input_buffer ) - voice.input_buffer_pos ); numbytes = Q_min( numbytes, sizeof( voice.input_buffer ) - voice.input_buffer_pos );
@@ -510,13 +507,11 @@ static uint Voice_GetGSCompressedData( byte *out, uint maxsize, uint *frames )
if( voice.input_file ) if( voice.input_file )
{ {
uint numbytes; double curtime = Platform_DoubleTime();
double updateInterval, curtime = Platform_DoubleTime(); double updateInterval = curtime - voice.start_time;
updateInterval = curtime - voice.start_time;
voice.start_time = curtime; voice.start_time = curtime;
numbytes = updateInterval * voice.samplerate * voice.width * VOICE_PCM_CHANNELS; uint numbytes = updateInterval * voice.samplerate * voice.width * VOICE_PCM_CHANNELS;
numbytes = Q_min( numbytes, voice.input_file->size - voice.input_file_pos ); numbytes = Q_min( numbytes, voice.input_file->size - voice.input_file_pos );
numbytes = Q_min( numbytes, sizeof( voice.input_buffer ) - voice.input_buffer_pos ); numbytes = Q_min( numbytes, sizeof( voice.input_buffer ) - voice.input_buffer_pos );
@@ -597,24 +592,15 @@ Process GoldSrc voice data and return number of samples
*/ */
static int Voice_ProcessGSData( int ent, const uint8_t *data, uint32_t size ) static int Voice_ProcessGSData( int ent, const uint8_t *data, uint32_t size )
{ {
uint32_t crc_in_packet;
uint32_t crc;
size_t offset;
size_t samples; size_t samples;
uint16_t sample_rate;
uint8_t vpc_type; uint8_t vpc_type;
uint16_t data_len; uint16_t data_len;
OpusDecoder *decoder;
size_t opus_offset;
int decoded;
size_t silence_samples;
uint16_t frame_size;
if( !data || ent <= 0 || ent > cl.maxclients ) if( !data || ent <= 0 || ent > cl.maxclients )
return 0; return 0;
crc_in_packet = LittleLong( *(uint32_t *)( data + size - sizeof( uint32_t ))); uint32_t crc_in_packet = LittleLong( *(uint32_t *)( data + size - sizeof( uint32_t )));
crc = CRC32_INIT_VALUE; uint32_t crc = CRC32_INIT_VALUE;
CRC32_ProcessBuffer( &crc, data, size - sizeof( uint32_t )); CRC32_ProcessBuffer( &crc, data, size - sizeof( uint32_t ));
crc = CRC32_Final( crc ); crc = CRC32_Final( crc );
@@ -624,7 +610,7 @@ static int Voice_ProcessGSData( int ent, const uint8_t *data, uint32_t size )
return 0; return 0;
} }
offset = sizeof( uint64_t ); size_t offset = sizeof( uint64_t );
samples = 0; samples = 0;
if( offset >= size - sizeof( uint32_t ) || data[offset] != GS_VPC_SETSAMPLERATE ) if( offset >= size - sizeof( uint32_t ) || data[offset] != GS_VPC_SETSAMPLERATE )
@@ -637,7 +623,6 @@ static int Voice_ProcessGSData( int ent, const uint8_t *data, uint32_t size )
if( offset + sizeof( uint32_t ) > size - sizeof( uint32_t )) if( offset + sizeof( uint32_t ) > size - sizeof( uint32_t ))
return 0; return 0;
sample_rate = LittleShort( *(uint16_t *)( data + offset ));
offset += sizeof( uint16_t ); offset += sizeof( uint16_t );
vpc_type = data[offset++]; vpc_type = data[offset++];
@@ -646,7 +631,9 @@ static int Voice_ProcessGSData( int ent, const uint8_t *data, uint32_t size )
if( vpc_type == GS_VPC_VDATA_OPUS_PLC ) if( vpc_type == GS_VPC_VDATA_OPUS_PLC )
{ {
decoder = voice.gs_decoders[ent - 1]; OpusDecoder *decoder = voice.gs_decoders[ent - 1];
size_t opus_offset;
if( !decoder ) if( !decoder )
{ {
Con_Printf( S_WARN "No decoder available for entity %d\n", ent ); Con_Printf( S_WARN "No decoder available for entity %d\n", ent );
@@ -655,7 +642,7 @@ static int Voice_ProcessGSData( int ent, const uint8_t *data, uint32_t size )
opus_offset = 0; opus_offset = 0;
while( opus_offset + sizeof( uint32_t ) <= data_len ) while( opus_offset + sizeof( uint32_t ) <= data_len )
{ {
frame_size = LittleShort( *(uint16_t *)( data + offset + opus_offset )); uint16_t frame_size = LittleShort( *(uint16_t *)( data + offset + opus_offset ));
opus_offset += sizeof( uint32_t ); opus_offset += sizeof( uint32_t );
// if frame size is 0, it means silence // if frame size is 0, it means silence
if( frame_size == 0 ) if( frame_size == 0 )
@@ -679,7 +666,7 @@ static int Voice_ProcessGSData( int ent, const uint8_t *data, uint32_t size )
Con_Printf( S_WARN "Opus frame size exceeds data length\n" ); Con_Printf( S_WARN "Opus frame size exceeds data length\n" );
return 0; return 0;
} }
decoded = opus_decode( decoder, data + offset + opus_offset, frame_size, int decoded = opus_decode( decoder, data + offset + opus_offset, frame_size,
( (int16_t *)voice.decompress_buffer ) + samples, voice.frame_size, 0 ); ( (int16_t *)voice.decompress_buffer ) + samples, voice.frame_size, 0 );
if( decoded < 0 ) if( decoded < 0 )
{ {
@@ -692,7 +679,7 @@ static int Voice_ProcessGSData( int ent, const uint8_t *data, uint32_t size )
} }
else if( vpc_type == GS_VPC_VDATA_SILENCE ) else if( vpc_type == GS_VPC_VDATA_SILENCE )
{ {
silence_samples = data_len / 2; size_t silence_samples = data_len / 2;
if( silence_samples > GS_MAX_DECOMPRESSED_SAMPLES ) if( silence_samples > GS_MAX_DECOMPRESSED_SAMPLES )
{ {
Con_Printf( S_WARN "Silence data too large\n" ); Con_Printf( S_WARN "Silence data too large\n" );
@@ -908,8 +895,6 @@ stop recording and notify user dlls
*/ */
void Voice_Disconnect( void ) void Voice_Disconnect( void )
{ {
int i;
Voice_RecordStop(); Voice_RecordStop();
if( voice.local.talking_ack ) if( voice.local.talking_ack )
@@ -918,7 +903,7 @@ void Voice_Disconnect( void )
voice.local.talking_ack = false; voice.local.talking_ack = false;
} }
for( i = 1; i <= MAX_CLIENTS; i++ ) for( int i = 1; i <= MAX_CLIENTS; i++ )
Voice_Status( i, false ); Voice_Status( i, false );
VoiceCapture_Shutdown(); VoiceCapture_Shutdown();
@@ -987,7 +972,6 @@ void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames )
const int playernum = ent - 1; const int playernum = ent - 1;
int samples = 0; int samples = 0;
int ofs = 0; int ofs = 0;
voice_status_t *status = NULL;
if( !voice.initialized || !voice_enable.value ) if( !voice.initialized || !voice_enable.value )
return; return;
@@ -1041,7 +1025,7 @@ Encode our voice data and send it to server
void CL_AddVoiceToDatagram( void ) void CL_AddVoiceToDatagram( void )
{ {
byte buffer[VOICE_MAX_DATA_SIZE]; byte buffer[VOICE_MAX_DATA_SIZE];
uint size, frames; uint size, frames = 0;
if( cls.state != ca_active || !voice.device_opened || !Voice_IsRecording()) if( cls.state != ca_active || !voice.device_opened || !Voice_IsRecording())
return; return;
@@ -1131,8 +1115,6 @@ Run timeout for clients
*/ */
void Voice_Idle( double frametime ) void Voice_Idle( double frametime )
{ {
int i;
if( FBitSet( voice_enable.flags, FCVAR_CHANGED )) if( FBitSet( voice_enable.flags, FCVAR_CHANGED ))
{ {
ClearBits( voice_enable.flags, FCVAR_CHANGED ); ClearBits( voice_enable.flags, FCVAR_CHANGED );
@@ -1203,10 +1185,12 @@ qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit )
voice_audio_info_t Voice_GetAudioInfo( void ) voice_audio_info_t Voice_GetAudioInfo( void )
{ {
voice_audio_info_t info; voice_audio_info_t info =
{
.width = voice.width,
.samplerate = voice.samplerate,
.frame_size = voice.frame_size,
};
info.width = voice.width;
info.samplerate = voice.samplerate;
info.frame_size = voice.frame_size;
return info; return info;
} }
+6 -9
View File
@@ -59,7 +59,6 @@ wavdata_t *FS_LoadSound( const char *filename, const byte *buffer, size_t size )
const char *ext = COM_FileExtension( filename ); const char *ext = COM_FileExtension( filename );
string loadname; string loadname;
qboolean anyformat = true; qboolean anyformat = true;
const loadwavfmt_t *format;
Sound_Reset(); // clear old sounddata Sound_Reset(); // clear old sounddata
Q_strncpy( loadname, filename, sizeof( loadname )); Q_strncpy( loadname, filename, sizeof( loadname ));
@@ -68,7 +67,7 @@ wavdata_t *FS_LoadSound( const char *filename, const byte *buffer, size_t size )
{ {
// we needs to compare file extension with list of supported formats // we needs to compare file extension with list of supported formats
// and be sure what is real extension, not a filename with dot // and be sure what is real extension, not a filename with dot
for( format = sound.loadformats; format && format->ext; format++ ) for( const loadwavfmt_t *format = sound.loadformats; format && format->ext; format++ )
{ {
if( !Q_stricmp( format->ext, ext )) if( !Q_stricmp( format->ext, ext ))
{ {
@@ -84,18 +83,17 @@ wavdata_t *FS_LoadSound( const char *filename, const byte *buffer, size_t size )
goto load_internal; goto load_internal;
// now try all the formats in the selected list // now try all the formats in the selected list
for( format = sound.loadformats; format && format->ext; format++) for( const loadwavfmt_t *format = sound.loadformats; format && format->ext; format++)
{ {
if( anyformat || !Q_stricmp( ext, format->ext )) if( anyformat || !Q_stricmp( ext, format->ext ))
{ {
qboolean success = false; qboolean success = false;
fs_offset_t filesize = 0; fs_offset_t filesize = 0;
byte *f;
string path; string path;
Q_snprintf( path, sizeof( path ), DEFAULT_SOUNDPATH "%s.%s", loadname, format->ext ); Q_snprintf( path, sizeof( path ), DEFAULT_SOUNDPATH "%s.%s", loadname, format->ext );
f = FS_LoadFile( path, &filesize, false ); byte *f = FS_LoadFile( path, &filesize, false );
if( f && filesize > 0 ) if( f && filesize > 0 )
{ {
success = format->loadfunc( path, f, filesize ); success = format->loadfunc( path, f, filesize );
@@ -119,7 +117,7 @@ wavdata_t *FS_LoadSound( const char *filename, const byte *buffer, size_t size )
} }
load_internal: load_internal:
for( format = sound.loadformats; format && format->ext; format++ ) for( const loadwavfmt_t *format = sound.loadformats; format && format->ext; format++ )
{ {
if( anyformat || !Q_stricmp( ext, format->ext )) if( anyformat || !Q_stricmp( ext, format->ext ))
{ {
@@ -162,7 +160,6 @@ stream_t *FS_OpenStream( const char *filename )
const char *ext = COM_FileExtension( filename ); const char *ext = COM_FileExtension( filename );
string loadname; string loadname;
qboolean anyformat = true; qboolean anyformat = true;
const streamfmt_t *format;
stream_t *stream = NULL; stream_t *stream = NULL;
Sound_Reset(); // clear old streaminfo Sound_Reset(); // clear old streaminfo
@@ -172,7 +169,7 @@ stream_t *FS_OpenStream( const char *filename )
{ {
// we needs to compare file extension with list of supported formats // we needs to compare file extension with list of supported formats
// and be sure what is real extension, not a filename with dot // and be sure what is real extension, not a filename with dot
for( format = sound.streamformat; format && format->ext; format++ ) for( const streamfmt_t *format = sound.streamformat; format && format->ext; format++ )
{ {
if( !Q_stricmp( format->ext, ext )) if( !Q_stricmp( format->ext, ext ))
{ {
@@ -184,7 +181,7 @@ stream_t *FS_OpenStream( const char *filename )
} }
// now try all the formats in the selected list // now try all the formats in the selected list
for( format = sound.streamformat; format && format->ext; format++) for( const streamfmt_t *format = sound.streamformat; format && format->ext; format++)
{ {
if( anyformat || !Q_stricmp( ext, format->ext )) if( anyformat || !Q_stricmp( ext, format->ext ))
{ {
+1 -3
View File
@@ -362,9 +362,7 @@ int Stream_ReadMPG( stream_t *stream, int needBytes, void *buffer )
{ {
// buffer handling // buffer handling
int bytesWritten = 0; int bytesWritten = 0;
void *mpg; void *mpg = stream->ptr;
mpg = stream->ptr;
while( 1 ) while( 1 )
{ {
+3 -4
View File
@@ -258,13 +258,12 @@ int Stream_ReadOggOpus( stream_t *stream, int needBytes, void *buffer )
while( 1 ) while( 1 )
{ {
int ret;
byte *data; byte *data;
int outsize; int outsize;
if( !stream->buffsize ) if( !stream->buffsize )
{ {
ret = op_read( ctx->of, (opus_int16 *)stream->temp, OUTBUF_SIZE / stream->width, NULL ); int ret = op_read( ctx->of, (opus_int16 *)stream->temp, OUTBUF_SIZE / stream->width, NULL );
if( ret == 0 ) if( ret == 0 )
break; // end of file break; // end of file
else if( ret < 0 ) else if( ret < 0 )
@@ -298,9 +297,9 @@ int Stream_ReadOggOpus( stream_t *stream, int needBytes, void *buffer )
int Stream_SetPosOggOpus( stream_t *stream, int newpos ) int Stream_SetPosOggOpus( stream_t *stream, int newpos )
{ {
int ret;
opus_streaming_ctx_t *ctx = (opus_streaming_ctx_t *)stream->ptr; opus_streaming_ctx_t *ctx = (opus_streaming_ctx_t *)stream->ptr;
if(( ret = op_raw_seek( ctx->of, newpos )) == 0 ) int ret = op_raw_seek( ctx->of, newpos );
if( ret == 0 )
{ {
stream->buffsize = 0; // flush any previous data stream->buffsize = 0; // flush any previous data
return true; return true;
+2 -2
View File
@@ -268,9 +268,9 @@ int Stream_ReadOggVorbis( stream_t *stream, int needBytes, void *buffer )
int Stream_SetPosOggVorbis( stream_t *stream, int newpos ) int Stream_SetPosOggVorbis( stream_t *stream, int newpos )
{ {
int ret;
vorbis_streaming_ctx_t *ctx = (vorbis_streaming_ctx_t *)stream->ptr; vorbis_streaming_ctx_t *ctx = (vorbis_streaming_ctx_t *)stream->ptr;
if(( ret = ov_raw_seek_lap( &ctx->vf, newpos )) == 0 ) int ret = ov_raw_seek_lap( &ctx->vf, newpos );
if( ret == 0 )
{ {
stream->buffsize = 0; // flush any previous data stream->buffsize = 0; // flush any previous data
return true; return true;
+31 -11
View File
@@ -176,7 +176,6 @@ Sound_LoadWAV
*/ */
qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesize ) qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesize )
{ {
int samples, fmt;
qboolean mpeg_stream = false; qboolean mpeg_stream = false;
if( !buffer || filesize <= 0 ) if( !buffer || filesize <= 0 )
@@ -205,7 +204,7 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
} }
iff_dataPtr += 8; iff_dataPtr += 8;
fmt = GetLittleShort(); int fmt = GetLittleShort();
if( fmt != 1 ) if( fmt != 1 )
{ {
@@ -276,7 +275,7 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
} }
iff_dataPtr += 4; iff_dataPtr += 4;
samples = GetLittleLong() / sound.width; int samples = GetLittleLong() / sound.width;
if( sound.samples ) if( sound.samples )
{ {
@@ -331,12 +330,11 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
// now convert 8-bit sounds to signed // now convert 8-bit sounds to signed
if( sound.width == 1 ) if( sound.width == 1 )
{ {
int i, j;
signed char *pData = (signed char *)sound.wav; signed char *pData = (signed char *)sound.wav;
for( i = 0; i < sound.samples; i++ ) for( int i = 0; i < sound.samples; i++ )
{ {
for( j = 0; j < sound.channels; j++ ) for( int j = 0; j < sound.channels; j++ )
{ {
*pData = (byte)((int)((byte)*pData) - 128 ); *pData = (byte)((int)((byte)*pData) - 128 );
pData++; pData++;
@@ -344,6 +342,31 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
} }
} }
// silence known-broken WAVs that contain stray non-zero samples masquerading as silence
if( Q_stristr( name, "null.wav" ) || Q_stristr( name, "_period.wav" ) || Q_stristr( name, "_comma.wav" ))
{
static const uint32_t broken_crcs[] =
{
0x14a36f29, // common/null.wav (HL1/Q1)
0x005a43ab, // vox/_period.wav (HL1)
0x7749ed15, // vox/_comma.wav (HL1)
};
uint32_t crc;
CRC32_Init( &crc );
CRC32_ProcessBuffer( &crc, buffer, filesize );
crc = CRC32_Final( crc );
for( size_t i = 0; i < ARRAYSIZE( broken_crcs ); i++ )
{
if( crc == broken_crcs[i] )
{
memset( sound.wav, 0, sound.size );
break;
}
}
}
return true; return true;
} }
@@ -357,7 +380,6 @@ stream_t *Stream_OpenWAV( const char *filename )
stream_t *stream; stream_t *stream;
int last_chunk = 0; int last_chunk = 0;
char chunkName[4]; char chunkName[4];
int iff_data;
file_t *file; file_t *file;
short t; short t;
@@ -393,7 +415,7 @@ stream_t *Stream_OpenWAV( const char *filename )
} }
// get "fmt " chunk // get "fmt " chunk
iff_data = FS_Tell( file ); int 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 ))
{ {
@@ -460,11 +482,9 @@ assume stream is valid
*/ */
int Stream_ReadWAV( stream_t *stream, int bytes, void *buffer ) int Stream_ReadWAV( stream_t *stream, int bytes, void *buffer )
{ {
int remaining;
if( !stream->file ) return 0; // invalid file if( !stream->file ) return 0; // invalid file
remaining = stream->size - stream->pos; int remaining = stream->size - stream->pos;
if( remaining <= 0 ) return 0; if( remaining <= 0 ) return 0;
if( bytes > remaining ) bytes = remaining; if( bytes > remaining ) bytes = remaining;
+2 -4
View File
@@ -219,8 +219,6 @@ client_textmessage_t *CL_TextMessageParse( poolhandle_t mempool, char *pfile, in
void Test_RunTitles( void ) void Test_RunTitles( void )
{ {
poolhandle_t mempool = Mem_AllocPool( __func__ ); poolhandle_t mempool = Mem_AllocPool( __func__ );
client_textmessage_t *tmessages;
client_textmessage_t *null;
int num_titles = 0, num_null_titles = 0; int num_titles = 0, num_null_titles = 0;
char titles[] = char titles[] =
"// this is a comment\n" "// this is a comment\n"
@@ -258,7 +256,7 @@ void Test_RunTitles( void )
char broken_titles[] = "}\n"; char broken_titles[] = "}\n";
char broken_titles2[] = "{\n{\n"; char broken_titles2[] = "{\n{\n";
null = CL_TextMessageParse( mempool, broken_titles, Q_strlen( broken_titles ), &num_null_titles ); client_textmessage_t *null = CL_TextMessageParse( mempool, broken_titles, Q_strlen( broken_titles ), &num_null_titles );
TASSERT_EQi( num_null_titles, 0 ); TASSERT_EQi( num_null_titles, 0 );
TASSERT_EQp( null, NULL ); TASSERT_EQp( null, NULL );
@@ -266,7 +264,7 @@ void Test_RunTitles( void )
TASSERT_EQi( num_null_titles, 0 ); TASSERT_EQi( num_null_titles, 0 );
TASSERT_EQp( null, NULL ); TASSERT_EQp( null, NULL );
tmessages = CL_TextMessageParse( mempool, titles, Q_strlen( titles ), &num_titles ); client_textmessage_t *tmessages = CL_TextMessageParse( mempool, titles, Q_strlen( titles ), &num_titles );
TASSERT_EQi( num_titles, 4 ); TASSERT_EQi( num_titles, 4 );
TASSERT_NEQp( tmessages, NULL ); TASSERT_NEQp( tmessages, NULL );
+10 -18
View File
@@ -73,9 +73,7 @@ static void GAME_EXPORT VGUI_DrawInit( void )
static void GAME_EXPORT VGUI_DrawShutdown( void ) static void GAME_EXPORT VGUI_DrawShutdown( void )
{ {
int i; for( int i = 1; i < vgui.texture_id; i++ )
for( i = 1; i < vgui.texture_id; i++ )
ref.dllFuncs.GL_FreeTexture( vgui.textures[i].gl_texturenum ); ref.dllFuncs.GL_FreeTexture( vgui.textures[i].gl_texturenum );
Mem_FreePool( &vgui.mempool ); Mem_FreePool( &vgui.mempool );
@@ -136,9 +134,7 @@ static void GAME_EXPORT VGUI_UploadTexture( int id, const char *buffer, int widt
// it's a new texture, try to find a copy // it's a new texture, try to find a copy
if( vgui.textures[id].gl_texturenum == 0 ) if( vgui.textures[id].gl_texturenum == 0 )
{ {
int i; for( int i = 1; i < vgui.texture_id; i++ )
for( i = 1; i < vgui.texture_id; i++ )
{ {
if( vgui.textures[i].gl_texturenum != 0 && !memcmp( vgui.textures[i].hash, hash, sizeof( hash ))) if( vgui.textures[i].gl_texturenum != 0 && !memcmp( vgui.textures[i].hash, hash, sizeof( hash )))
{ {
@@ -210,26 +206,22 @@ static void GAME_EXPORT VGUI_SetupDrawingText( int *pColor )
static void GAME_EXPORT VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr ) static void GAME_EXPORT VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr )
{ {
float x, y, w, h;
if( !ul || !lr ) if( !ul || !lr )
return; return;
x = ul->point[0]; float x = ul->point[0];
y = ul->point[1]; float y = ul->point[1];
w = lr->point[0] - x; float w = lr->point[0] - x;
h = lr->point[1] - y; float h = lr->point[1] - y;
SPR_AdjustSize( &x, &y, &w, &h ); SPR_AdjustSize( &x, &y, &w, &h );
if( vgui.enable_texture ) if( vgui.enable_texture )
{ {
float s1, s2, t1, t2; float s1 = ul->coord[0];
float t1 = ul->coord[1];
s1 = ul->coord[0]; float s2 = lr->coord[0];
t1 = ul->coord[1]; float t2 = lr->coord[1];
s2 = lr->coord[0];
t2 = lr->coord[1];
ref.dllFuncs.Color4ub( vgui.color[0], vgui.color[1], vgui.color[2], vgui.color[3] ); ref.dllFuncs.Color4ub( vgui.color[0], vgui.color[1], vgui.color[2], vgui.color[3] );
ref.dllFuncs.R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, vgui.textures[vgui.bound_texture].gl_texturenum ); ref.dllFuncs.R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, vgui.textures[vgui.bound_texture].gl_texturenum );
+3 -5
View File
@@ -91,11 +91,11 @@ VID_GetModeString
*/ */
const char *VID_GetModeString( int vid_mode ) const char *VID_GetModeString( int vid_mode )
{ {
vidmode_t *vidmode;
if( vid_mode < 0 || vid_mode >= R_MaxVideoModes() ) if( vid_mode < 0 || vid_mode >= R_MaxVideoModes() )
return NULL; return NULL;
if( !( vidmode = R_GetVideoMode( vid_mode ) ) ) vidmode_t *vidmode = R_GetVideoMode( vid_mode );
if( !vidmode )
return NULL; return NULL;
return vidmode->desc; return vidmode->desc;
@@ -176,9 +176,7 @@ static void VID_Mode_f( void )
{ {
case 2: case 2:
{ {
vidmode_t *vidmode; vidmode_t *vidmode = R_GetVideoMode( Q_atoi( Cmd_Argv( 1 )) );
vidmode = R_GetVideoMode( Q_atoi( Cmd_Argv( 1 )) );
if( !vidmode ) if( !vidmode )
{ {
Con_Printf( S_ERROR "unable to set mode, backend returned null\n" ); Con_Printf( S_ERROR "unable to set mode, backend returned null\n" );
+9 -19
View File
@@ -43,16 +43,12 @@ Find base command in bucket
*/ */
static base_command_hashmap_t *BaseCmd_FindInBucket( base_command_hashmap_t *bucket, base_command_type_e type, const char *name ) static base_command_hashmap_t *BaseCmd_FindInBucket( base_command_hashmap_t *bucket, base_command_type_e type, const char *name )
{ {
base_command_hashmap_t *i; for( base_command_hashmap_t *i = bucket; i != NULL; i = i->next )
for( i = bucket; i != NULL; i = i->next )
{ {
int cmp;
if( i->type != type ) if( i->type != type )
continue; continue;
cmp = Q_stricmp( i->name, name ); int cmp = Q_stricmp( i->name, name );
if( cmp < 0 ) if( cmp < 0 )
continue; continue;
@@ -147,16 +143,16 @@ Add new typed base command to hashmap
*/ */
void BaseCmd_Insert( base_command_type_e type, base_command_t *basecmd, const char *name ) void BaseCmd_Insert( base_command_type_e type, base_command_t *basecmd, const char *name )
{ {
base_command_hashmap_t *elem, *cur, *find;
uint hash = BaseCmd_HashKey( name ); uint hash = BaseCmd_HashKey( name );
size_t len = Q_strlen( name ); size_t len = Q_strlen( name );
base_command_hashmap_t *elem = Mem_Malloc( basecmd_pool, sizeof( base_command_hashmap_t ) + len + 1 );
elem = Mem_Malloc( basecmd_pool, sizeof( base_command_hashmap_t ) + len + 1 );
elem->basecmd = basecmd; elem->basecmd = basecmd;
elem->type = type; elem->type = type;
Q_strncpy( elem->name, name, len + 1 ); Q_strncpy( elem->name, name, len + 1 );
// link the variable in alphanumerical order // link the variable in alphanumerical order
base_command_hashmap_t *cur, *find;
for( cur = NULL, find = hashed_cmds[hash]; for( cur = NULL, find = hashed_cmds[hash];
find && Q_stricmp( find->name, elem->name ) < 0; find && Q_stricmp( find->name, elem->name ) < 0;
cur = find, find = find->next ); cur = find, find = find->next );
@@ -181,12 +177,10 @@ void BaseCmd_Remove( base_command_type_e type, const char *name )
for( prev = NULL, i = hashed_cmds[hash]; i != NULL; prev = i, i = i->next ) for( prev = NULL, i = hashed_cmds[hash]; i != NULL; prev = i, i = i->next )
{ {
int cmp;
if( i->type != type ) if( i->type != type )
continue; continue;
cmp = Q_stricmp( i->name, name ); int cmp = Q_stricmp( i->name, name );
if( cmp < 0 ) if( cmp < 0 )
continue; continue;
@@ -220,7 +214,7 @@ initialize base command hashmap system
*/ */
void BaseCmd_Init( void ) void BaseCmd_Init( void )
{ {
basecmd_pool = Mem_AllocPool( "BaseCmd" ); basecmd_pool = Mem_AllocPoolExt( "BaseCmd", MEM_SMALL_ALLOC_OPT );
memset( hashed_cmds, 0, sizeof( hashed_cmds ) ); memset( hashed_cmds, 0, sizeof( hashed_cmds ) );
} }
@@ -241,11 +235,10 @@ void BaseCmd_Stats_f( void )
for( int i = 0; i < HASH_SIZE; i++ ) for( int i = 0; i < HASH_SIZE; i++ )
{ {
base_command_hashmap_t *hm;
int len = 0; int len = 0;
// count bucket length // count bucket length
for( hm = hashed_cmds[i]; hm; hm = hm->next, len++ ); for( base_command_hashmap_t *hm = hashed_cmds[i]; hm; hm = hm->next, len++ );
if( len == 0 ) if( len == 0 )
{ {
@@ -300,11 +293,8 @@ void BaseCmd_Test_f( void )
for( int i = 0; i < 1000; i++ ) for( int i = 0; i < 1000; i++ )
{ {
cmdalias_t *a;
void *cmd;
// Cmd_LookupCmds don't allows to check alias, so just iterate // Cmd_LookupCmds don't allows to check alias, so just iterate
for( a = Cmd_AliasGetList(); a; a = a->next, stats.lookups++ ) for( cmdalias_t *a = Cmd_AliasGetList(); a; a = a->next, stats.lookups++ )
{ {
if( !BaseCmd_Find( HM_CMDALIAS, a->name )) if( !BaseCmd_Find( HM_CMDALIAS, a->name ))
{ {
@@ -313,7 +303,7 @@ void BaseCmd_Test_f( void )
} }
} }
for( cmd = Cmd_GetFirstFunctionHandle(); cmd; for( void *cmd = Cmd_GetFirstFunctionHandle(); cmd;
cmd = Cmd_GetNextFunctionHandle( cmd ), stats.lookups++ ) cmd = Cmd_GetNextFunctionHandle( cmd ), stats.lookups++ )
{ {
if( !BaseCmd_Find( HM_CMD, Cmd_GetName( cmd ))) if( !BaseCmd_Find( HM_CMD, Cmd_GetName( cmd )))
+6 -8
View File
@@ -77,9 +77,7 @@ Determine script variable type
*/ */
static cvartype_t CSCR_ParseType( parserstate_t *ps ) static cvartype_t CSCR_ParseType( parserstate_t *ps )
{ {
int i; for( int i = 1; i < T_COUNT; i++ )
for( i = 1; i < T_COUNT; i++ )
{ {
if( CSCR_ExpectString( ps, cvartypes[i], false, false )) if( CSCR_ExpectString( ps, cvartypes[i], false, false ))
return i; return i;
@@ -213,11 +211,11 @@ will callback on each scrvardef_t
static int CSCR_ParseFile( const char *scriptfilename, static int CSCR_ParseFile( const char *scriptfilename,
void (*callback)( scrvardef_t *var, void * ), void *userdata ) void (*callback)( scrvardef_t *var, void * ), void *userdata )
{ {
parserstate_t state = { 0 }; parserstate_t state = { 0 };
qboolean success = false; qboolean success = false;
int count = 0; int count = 0;
fs_offset_t length = 0; fs_offset_t length = 0;
char *start; char *start;
state.filename = scriptfilename; state.filename = scriptfilename;
state.buf = start = (char *)FS_LoadFile( scriptfilename, &length, true ); state.buf = start = (char *)FS_LoadFile( scriptfilename, &length, true );
+28 -56
View File
@@ -66,15 +66,13 @@ Cbuf_GetSpace
*/ */
static void *Cbuf_GetSpace( cmdbuf_t *buf, int length ) static void *Cbuf_GetSpace( cmdbuf_t *buf, int length )
{ {
void *data;
if(( buf->cursize + length ) >= sizeof( buf->data )) if(( buf->cursize + length ) >= sizeof( buf->data ))
{ {
buf->cursize = 0; buf->cursize = 0;
Host_Error( "%s: overflow\n", __func__ ); Host_Error( "%s: overflow\n", __func__ );
} }
data = buf->data + buf->cursize; void *data = buf->data + buf->cursize;
buf->cursize += length; buf->cursize += length;
return data; return data;
@@ -168,10 +166,8 @@ Cbuf_Execute
*/ */
static void Cbuf_ExecuteCommandsFromBuffer( cmdbuf_t *buf, qboolean isPrivileged, int cmdsToExecute ) static void Cbuf_ExecuteCommandsFromBuffer( cmdbuf_t *buf, qboolean isPrivileged, int cmdsToExecute )
{ {
char *text;
char line[MAX_CMD_LINE]; char line[MAX_CMD_LINE];
int i, quotes; int i;
char *comment;
while( buf->cursize ) while( buf->cursize )
{ {
@@ -189,10 +185,10 @@ static void Cbuf_ExecuteCommandsFromBuffer( cmdbuf_t *buf, qboolean isPrivileged
} }
// find a \n or ; line break // find a \n or ; line break
text = (char *)buf->data; char *text = (char *)buf->data;
quotes = false; int quotes = false;
comment = NULL; char *comment = NULL;
for( i = 0; i < buf->cursize; i++ ) for( i = 0; i < buf->cursize; i++ )
{ {
@@ -384,9 +380,7 @@ Just prints the rest of the line to the console
*/ */
static void Cmd_Echo_f( void ) static void Cmd_Echo_f( void )
{ {
int i; for( int i = 1; i < Cmd_Argc(); i++ )
for( i = 1; i < Cmd_Argc(); i++ )
Con_Printf( "%s ", Cmd_Argv( i )); Con_Printf( "%s ", Cmd_Argv( i ));
Con_Printf( "\n" ); Con_Printf( "\n" );
} }
@@ -402,8 +396,6 @@ static void Cmd_Alias_f( void )
{ {
cmdalias_t *a; cmdalias_t *a;
char cmd[MAX_CMD_LINE]; char cmd[MAX_CMD_LINE];
int i, c;
const char *s;
if( Cmd_Argc() == 1 ) if( Cmd_Argc() == 1 )
{ {
@@ -413,7 +405,7 @@ static void Cmd_Alias_f( void )
return; return;
} }
s = Cmd_Argv( 1 ); const char *s = Cmd_Argv( 1 );
if( Q_strlen( s ) >= MAX_ALIAS_NAME ) if( Q_strlen( s ) >= MAX_ALIAS_NAME )
{ {
@@ -452,9 +444,9 @@ static void Cmd_Alias_f( void )
// copy the rest of the command line // copy the rest of the command line
cmd[0] = 0; // start out with a null string cmd[0] = 0; // start out with a null string
c = Cmd_Argc(); int c = Cmd_Argc();
for( i = 2; i < c; i++ ) for( int i = 2; i < c; i++ )
{ {
if( i != 2 ) Q_strncat( cmd, " ", sizeof( cmd )); if( i != 2 ) Q_strncat( cmd, " ", sizeof( cmd ));
Q_strncat( cmd, Cmd_Argv( i ), sizeof( cmd )); Q_strncat( cmd, Cmd_Argv( i ), sizeof( cmd ));
@@ -473,20 +465,16 @@ Remove existing aliases.
*/ */
static void Cmd_UnAlias_f ( void ) static void Cmd_UnAlias_f ( void )
{ {
cmdalias_t *a, *p;
const char *s;
int i;
if( Cmd_Argc() == 1 ) if( Cmd_Argc() == 1 )
{ {
Con_Printf( S_USAGE "unalias alias1 [alias2 ...]\n" ); Con_Printf( S_USAGE "unalias alias1 [alias2 ...]\n" );
return; return;
} }
for( i = 1; i < Cmd_Argc(); i++ ) for( int i = 1; i < Cmd_Argc(); i++ )
{ {
s = Cmd_Argv( i ); const char *s = Cmd_Argv( i );
p = NULL; cmdalias_t *a, *p = NULL;
for( a = cmd_alias; a; p = a, a = a->next ) for( a = cmd_alias; a; p = a, a = a->next )
{ {
@@ -586,10 +574,9 @@ will point into this temporary buffer.
void Cmd_TokenizeString( const char *text ) void Cmd_TokenizeString( const char *text )
{ {
char cmd_token[MAX_CMD_BUFFER]; char cmd_token[MAX_CMD_BUFFER];
int i;
// clear the args from the last string // clear the args from the last string
for( i = 0; i < cmd_argc; i++ ) for( int i = 0; i < cmd_argc; i++ )
Mem_Free( cmd_argv[i] ); Mem_Free( cmd_argv[i] );
cmd_argc = 0; // clear previous args cmd_argc = 0; // clear previous args
@@ -709,15 +696,13 @@ Cmd_RemoveCommand
*/ */
void GAME_EXPORT Cmd_RemoveCommand( const char *cmd_name ) void GAME_EXPORT Cmd_RemoveCommand( const char *cmd_name )
{ {
cmd_t *cmd, **back;
if( !cmd_name || !*cmd_name ) if( !cmd_name || !*cmd_name )
return; return;
back = &cmd_functions; cmd_t **back = &cmd_functions;
while( 1 ) while( 1 )
{ {
cmd = *back; cmd_t *cmd = *back;
if( !cmd ) return; if( !cmd ) return;
if( !Q_strcmp( cmd_name, cmd->name )) if( !Q_strcmp( cmd_name, cmd->name ))
@@ -743,20 +728,17 @@ Cmd_LookupCmds
*/ */
void Cmd_LookupCmds( void *buffer, void *ptr, setpair_t callback ) void Cmd_LookupCmds( void *buffer, void *ptr, setpair_t callback )
{ {
cmd_t *cmd;
cmdalias_t *alias;
// nothing to process ? // nothing to process ?
if( !callback ) return; if( !callback ) return;
for( cmd = cmd_functions; cmd; cmd = cmd->next ) for( cmd_t *cmd = cmd_functions; cmd; cmd = cmd->next )
{ {
if( !buffer ) callback( cmd->name, (char *)cmd->function, cmd->desc, ptr ); if( !buffer ) callback( cmd->name, (char *)cmd->function, cmd->desc, ptr );
else callback( cmd->name, (char *)cmd->function, buffer, ptr ); else callback( cmd->name, (char *)cmd->function, buffer, ptr );
} }
// lookup an aliases too // lookup an aliases too
for( alias = cmd_alias; alias; alias = alias->next ) for( cmdalias_t *alias = cmd_alias; alias; alias = alias->next )
callback( alias->name, alias->value, buffer, ptr ); callback( alias->name, alias->value, buffer, ptr );
} }
@@ -846,14 +828,13 @@ 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_", "con_", "scr_" }; const char *prefixes[] = { "cl_", "gl_", "r_", "m_", "hud_", "joy_", "con_", "scr_" };
int i;
// always allow local commands // always allow local commands
if( isPrivileged ) if( isPrivileged )
return true; return true;
// never allow local only commands from remote // never allow local only commands from remote
if( FBitSet( cmd->flags, CMD_PRIVILEGED )) if( FBitSet( cmd->flags, CMD_PRIVILEGED ) || cmd->name[0] == '@' )
return false; return false;
// allow engine commands if user don't mind // allow engine commands if user don't mind
@@ -863,7 +844,7 @@ static qboolean Cmd_ShouldAllowCommand( cmd_t *cmd, qboolean isPrivileged )
if( FBitSet( cmd->flags, CMD_FILTERABLE )) if( FBitSet( cmd->flags, CMD_FILTERABLE ))
return false; return false;
for( i = 0; i < ARRAYSIZE( prefixes ); i++ ) for( int i = 0; i < ARRAYSIZE( prefixes ); i++ )
{ {
if( !Q_strnicmp( cmd->name, prefixes[i], Q_strlen( prefixes[i] ))) if( !Q_strnicmp( cmd->name, prefixes[i], Q_strlen( prefixes[i] )))
return false; return false;
@@ -1038,7 +1019,6 @@ Cmd_List_f
*/ */
static void Cmd_List_f( void ) static void Cmd_List_f( void )
{ {
cmd_t *cmd;
int i = 0; int i = 0;
size_t matchlen = 0; size_t matchlen = 0;
const char *match = NULL; const char *match = NULL;
@@ -1049,7 +1029,7 @@ static void Cmd_List_f( void )
matchlen = Q_strlen( match ); matchlen = Q_strlen( match );
} }
for( cmd = cmd_functions; cmd; cmd = cmd->next ) for( cmd_t *cmd = cmd_functions; cmd; cmd = cmd->next )
{ {
if( cmd->name[0] == '@' ) if( cmd->name[0] == '@' )
continue; // never show system cmds continue; // never show system cmds
@@ -1073,8 +1053,6 @@ unlink all commands with specified flag
*/ */
void Cmd_Unlink( int group ) void Cmd_Unlink( int group )
{ {
cmd_t *cmd;
cmd_t **prev;
int count = 0; int count = 0;
if( FBitSet( group, CMD_SERVERDLL ) && Cvar_VariableInteger( "host_gameloaded" )) if( FBitSet( group, CMD_SERVERDLL ) && Cvar_VariableInteger( "host_gameloaded" ))
@@ -1086,11 +1064,11 @@ void Cmd_Unlink( int group )
if( FBitSet( group, CMD_GAMEUIDLL ) && Cvar_VariableInteger( "host_gameuiloaded" )) if( FBitSet( group, CMD_GAMEUIDLL ) && Cvar_VariableInteger( "host_gameuiloaded" ))
return; return;
prev = &cmd_functions; cmd_t **prev = &cmd_functions;
while( 1 ) while( 1 )
{ {
cmd = *prev; cmd_t *cmd = *prev;
if( !cmd ) break; if( !cmd ) break;
// do filter by specified group // do filter by specified group
@@ -1115,10 +1093,6 @@ void Cmd_Unlink( int group )
static void Cmd_Apropos_f( void ) static void Cmd_Apropos_f( void )
{ {
cmd_t *cmd;
convar_t *var;
cmdalias_t *alias;
const char *partial;
int count = 0; int count = 0;
char buf[MAX_VA_STRING]; char buf[MAX_VA_STRING];
@@ -1128,7 +1102,7 @@ static void Cmd_Apropos_f( void )
return; return;
} }
partial = Cmd_Args(); const char *partial = Cmd_Args();
if( !Q_strpbrk( partial, "*?" )) if( !Q_strpbrk( partial, "*?" ))
{ {
@@ -1136,7 +1110,7 @@ static void Cmd_Apropos_f( void )
partial = buf; partial = buf;
} }
for( var = (convar_t*)Cvar_GetList(); var; var = var->next ) for( convar_t *var = (convar_t*)Cvar_GetList(); var; var = var->next )
{ {
if( !matchpattern_with_separator( var->name, partial, true, "", false ) ) if( !matchpattern_with_separator( var->name, partial, true, "", false ) )
{ {
@@ -1162,7 +1136,7 @@ static void Cmd_Apropos_f( void )
count++; count++;
} }
for( cmd = Cmd_GetFirstFunctionHandle(); cmd; cmd = Cmd_GetNextFunctionHandle( cmd ) ) for( cmd_t *cmd = Cmd_GetFirstFunctionHandle(); cmd; cmd = Cmd_GetNextFunctionHandle( cmd ) )
{ {
if( cmd->name[0] == '@' ) if( cmd->name[0] == '@' )
continue; // never show system cmds continue; // never show system cmds
@@ -1175,7 +1149,7 @@ static void Cmd_Apropos_f( void )
count++; count++;
} }
for( alias = Cmd_AliasGetList(); alias; alias = alias->next ) for( cmdalias_t *alias = Cmd_AliasGetList(); alias; alias = alias->next )
{ {
// proceed a bit differently here as an alias value always got a final \n // proceed a bit differently here as an alias value always got a final \n
if( !matchpattern_with_separator( alias->name, partial, true, "", false ) && if( !matchpattern_with_separator( alias->name, partial, true, "", false ) &&
@@ -1247,10 +1221,9 @@ Cmd_ExecScript
*/ */
static void Cmd_ExecScript( const char *filename ) static void Cmd_ExecScript( const char *filename )
{ {
byte *f;
fs_offset_t len; fs_offset_t len;
byte *f = FS_LoadFile( filename, &len, false );
f = FS_LoadFile( filename, &len, false );
if( !f ) if( !f )
{ {
Con_Reportf( "couldn't exec %s\n", filename ); Con_Reportf( "couldn't exec %s\n", filename );
@@ -1304,7 +1277,6 @@ static void Cmd_UnprivilegedExec_f( void )
"scout.cfg", "sniper.cfg", "soldier.cfg", "spy.cfg", "scout.cfg", "sniper.cfg", "soldier.cfg", "spy.cfg",
}; };
char mapcfg[MAX_VA_STRING]; char mapcfg[MAX_VA_STRING];
qboolean allow = false;
Q_snprintf( mapcfg, sizeof( mapcfg ), "%s.cfg", clgame.mapname ); Q_snprintf( mapcfg, sizeof( mapcfg ), "%s.cfg", clgame.mapname );
@@ -1454,7 +1426,7 @@ Cmd_Init
*/ */
void Cmd_Init( void ) void Cmd_Init( void )
{ {
cmd_pool = Mem_AllocPool( "Console Commands" ); cmd_pool = Mem_AllocPoolExt( "Console Commands", MEM_SMALL_ALLOC_OPT );
cmd_functions = NULL; cmd_functions = NULL;
cmd_condition = 0; cmd_condition = 0;
cmd_wait = 0; cmd_wait = 0;
+72 -112
View File
@@ -31,6 +31,8 @@ static const char *const file_exts[] =
// ban Windows code // ban Windows code
"exe", "vbs", "com", "bat", "exe", "vbs", "com", "bat",
"dll", "sys", "ps1", "dll", "sys", "ps1",
"lnk", "scr", "cpl", "msi",
"url", "jar",
// ban common unix code // ban common unix code
// NOTE: in unix anything can be executed as long it has access flag // NOTE: in unix anything can be executed as long it has access flag
@@ -66,19 +68,17 @@ static int idum = 0;
static int lran1( void ) static int lran1( void )
{ {
static int iy = 0; static int iy = 0;
static int iv[NTAB]; static int iv[NTAB];
int j;
int k;
if( idum <= 0 || !iy ) if( idum <= 0 || !iy )
{ {
if( -(idum) < 1 ) idum = 1; if( -(idum) < 1 ) idum = 1;
else idum = -(idum); else idum = -(idum);
for( j = NTAB + 7; j >= 0; j-- ) for( int j = NTAB + 7; j >= 0; j-- )
{ {
k = (idum) / IQ; int k = (idum) / IQ;
idum = IA * (idum - k * IQ) - IR * k; idum = IA * (idum - k * IQ) - IR * k;
if( idum < 0 ) idum += IM; if( idum < 0 ) idum += IM;
if( j < NTAB ) iv[j] = idum; if( j < NTAB ) iv[j] = idum;
@@ -87,10 +87,10 @@ static int lran1( void )
iy = iv[0]; iy = iv[0];
} }
k = (idum) / IQ; int k = (idum) / IQ;
idum = IA * (idum - k * IQ) - IR * k; idum = IA * (idum - k * IQ) - IR * k;
if( idum < 0 ) idum += IM; if( idum < 0 ) idum += IM;
j = iy / NDIV; int j = iy / NDIV;
iy = iv[j]; iy = iv[j];
iv[j] = idum; iv[j] = idum;
@@ -119,18 +119,15 @@ void GAME_EXPORT COM_SetRandomSeed( int lSeed )
float GAME_EXPORT COM_RandomFloat( float flLow, float flHigh ) float GAME_EXPORT COM_RandomFloat( float flLow, float flHigh )
{ {
float fl;
if( idum == 0 ) COM_SetRandomSeed( 0 ); if( idum == 0 ) COM_SetRandomSeed( 0 );
fl = fran1(); // float in [0,1] float fl = fran1(); // float in [0,1]
return (fl * (flHigh - flLow)) + flLow; // float in [low, high) return (fl * (flHigh - flLow)) + flLow; // float in [low, high)
} }
int GAME_EXPORT COM_RandomLong( int lLow, int lHigh ) int GAME_EXPORT COM_RandomLong( int lLow, int lHigh )
{ {
dword maxAcceptable; dword x = lHigh - lLow + 1;
dword n, x = lHigh - lLow + 1;
if( idum == 0 ) COM_SetRandomSeed( 0 ); if( idum == 0 ) COM_SetRandomSeed( 0 );
@@ -144,7 +141,8 @@ int GAME_EXPORT COM_RandomLong( int lLow, int lHigh )
// the average number of times through the loop is 2. For cases where x is // the average number of times through the loop is 2. For cases where x is
// much smaller than MAX_RANDOM_RANGE, the average number of times through the // much smaller than MAX_RANDOM_RANGE, the average number of times through the
// loop is very close to 1. // loop is very close to 1.
maxAcceptable = MAX_RANDOM_RANGE - ((MAX_RANDOM_RANGE + 1) % x ); dword maxAcceptable = MAX_RANDOM_RANGE - ((MAX_RANDOM_RANGE + 1) % x );
dword n;
do do
{ {
n = lran1(); n = lran1();
@@ -164,12 +162,13 @@ of all text functions.
*/ */
char *va( const char *format, ... ) char *va( const char *format, ... )
{ {
va_list argptr; static char string[16][MAX_VA_STRING], *s;
static char string[16][MAX_VA_STRING], *s; static int stringindex = 0;
static int stringindex = 0;
s = string[stringindex]; s = string[stringindex];
stringindex = (stringindex + 1) & 15; stringindex = (stringindex + 1) & 15;
va_list argptr;
va_start( argptr, format ); va_start( argptr, format );
Q_vsnprintf( s, sizeof( string[0] ), format, argptr ); Q_vsnprintf( s, sizeof( string[0] ), format, argptr );
va_end( argptr ); va_end( argptr );
@@ -220,12 +219,10 @@ typedef struct
qboolean LZSS_IsCompressed( const byte *source, size_t input_len ) qboolean LZSS_IsCompressed( const byte *source, size_t input_len )
{ {
const lzss_header_t *phdr;
if( input_len <= sizeof( lzss_header_t )) if( input_len <= sizeof( lzss_header_t ))
return 0; return 0;
phdr = (const lzss_header_t *)source; const lzss_header_t *phdr = (const lzss_header_t *)source;
if( phdr && phdr->id == LittleLong( LZSS_ID )) if( phdr && phdr->id == LittleLong( LZSS_ID ))
return true; return true;
@@ -234,12 +231,10 @@ qboolean LZSS_IsCompressed( const byte *source, size_t input_len )
uint LZSS_GetActualSize( const byte *source, size_t input_len ) uint LZSS_GetActualSize( const byte *source, size_t input_len )
{ {
const lzss_header_t *phdr;
if( input_len <= sizeof( lzss_header_t )) if( input_len <= sizeof( lzss_header_t ))
return 0; return 0;
phdr = (const lzss_header_t *)source; const lzss_header_t *phdr = (const lzss_header_t *)source;
if( phdr && phdr->id == LittleLong( LZSS_ID )) if( phdr && phdr->id == LittleLong( LZSS_ID ))
return LittleLong( phdr->size ); return LittleLong( phdr->size );
@@ -249,15 +244,12 @@ uint LZSS_GetActualSize( const byte *source, size_t input_len )
static void LZSS_BuildHash( lzss_state_t *state, const byte *source ) static void LZSS_BuildHash( lzss_state_t *state, const byte *source )
{ {
lzss_list_t *list; unsigned int targetindex = (uintptr_t)source & ( state->window_size - 1 );
lzss_node_t *node; lzss_node_t *node = &state->hash_node[targetindex];
unsigned int targetindex = (uintptr_t)source & ( state->window_size - 1 );
node = &state->hash_node[targetindex];
if( node->data ) if( node->data )
{ {
list = &state->hash_table[*node->data]; lzss_list_t *list = &state->hash_table[*node->data];
if( node->prev ) if( node->prev )
{ {
list->end = node->prev; list->end = node->prev;
@@ -270,7 +262,7 @@ static void LZSS_BuildHash( lzss_state_t *state, const byte *source )
} }
} }
list = &state->hash_table[*source]; lzss_list_t *list = &state->hash_table[*source];
node->data = source; node->data = source;
node->prev = NULL; node->prev = NULL;
node->next = list->start; node->next = list->start;
@@ -282,19 +274,19 @@ static void LZSS_BuildHash( lzss_state_t *state, const byte *source )
static byte *LZSS_CompressNoAlloc( lzss_state_t *state, byte *pInput, int input_length, byte *pOutputBuf, uint *pOutputSize ) static byte *LZSS_CompressNoAlloc( lzss_state_t *state, byte *pInput, int input_length, byte *pOutputBuf, uint *pOutputSize )
{ {
byte *pStart = pOutputBuf; // allocate the output buffer, compressed buffer is expected to be less, caller will free
byte *pEnd = pStart + input_length - sizeof( lzss_header_t ) - 8; // prevent compression failure
lzss_header_t *header = (lzss_header_t *)pStart;
byte *pOutput = pStart + sizeof( lzss_header_t );
const byte *pEncodedPosition = NULL;
byte *pLookAhead = pInput;
byte *pWindow = pInput;
int i, putCmdByte = 0;
byte *pCmdByte = NULL;
if( input_length <= sizeof( lzss_header_t ) + 8 ) if( input_length <= sizeof( lzss_header_t ) + 8 )
return NULL; return NULL;
byte *pStart = pOutputBuf; // allocate the output buffer, compressed buffer is expected to be less, caller will free
byte *pEnd = pStart + input_length - sizeof( lzss_header_t ) - 8; // prevent compression failure
lzss_header_t *header = (lzss_header_t *)pStart;
byte *pOutput = pStart + sizeof( lzss_header_t );
const byte *pEncodedPosition = NULL;
byte *pLookAhead = pInput;
byte *pWindow = pInput;
int putCmdByte = 0;
byte *pCmdByte = NULL;
// set LZSS header // set LZSS header
header->id = LittleLong( LZSS_ID ); header->id = LittleLong( LZSS_ID );
header->size = LittleLong( input_length ); header->size = LittleLong( input_length );
@@ -357,7 +349,7 @@ static byte *LZSS_CompressNoAlloc( lzss_state_t *state, byte *pInput, int input_
encoded_length = 1; encoded_length = 1;
} }
for( i = 0; i < encoded_length; i++ ) for( int i = 0; i < encoded_length; i++ )
{ {
LZSS_BuildHash( state, pLookAhead++ ); LZSS_BuildHash( state, pLookAhead++ );
} }
@@ -405,13 +397,12 @@ static byte *LZSS_CompressNoAlloc( lzss_state_t *state, byte *pInput, int input_
byte *LZSS_Compress( byte *pInput, int inputLength, uint *pOutputSize ) byte *LZSS_Compress( byte *pInput, int inputLength, uint *pOutputSize )
{ {
byte *pStart = (byte *)malloc( inputLength ); byte *pStart = (byte *)malloc( inputLength );
byte *pFinal = NULL;
lzss_state_t state = { .window_size = LZSS_WINDOW_SIZE };
if( !pStart ) if( !pStart )
return NULL; return NULL;
pFinal = LZSS_CompressNoAlloc( &state, pInput, inputLength, pStart, pOutputSize ); lzss_state_t state = { .window_size = LZSS_WINDOW_SIZE };
byte *pFinal = LZSS_CompressNoAlloc( &state, pInput, inputLength, pStart, pOutputSize );
if( !pFinal ) if( !pFinal )
{ {
@@ -424,21 +415,20 @@ byte *LZSS_Compress( byte *pInput, int inputLength, uint *pOutputSize )
uint LZSS_Decompress( const byte *pInput, byte *pOutput, size_t input_len, size_t output_len ) uint LZSS_Decompress( const byte *pInput, byte *pOutput, size_t input_len, size_t output_len )
{ {
uint totalBytes = 0;
int getCmdByte = 0;
int cmdByte = 0;
uint actualSize;
const byte *pInputEnd = pInput + input_len - 1; // thanks to nillerusr for the fix!
byte *pOrigOutput = pOutput;
if( input_len <= sizeof( lzss_header_t )) if( input_len <= sizeof( lzss_header_t ))
return 0; return 0;
actualSize = LZSS_GetActualSize( pInput, input_len ); uint actualSize = LZSS_GetActualSize( pInput, input_len );
if( !actualSize || actualSize > output_len ) if( !actualSize || actualSize > output_len )
return 0; return 0;
uint totalBytes = 0;
int getCmdByte = 0;
int cmdByte = 0;
const byte *pInputEnd = pInput + input_len - 1; // thanks to nillerusr for the fix!
byte *pOrigOutput = pOutput;
pInput += sizeof( lzss_header_t ); pInput += sizeof( lzss_header_t );
while( 1 ) while( 1 )
@@ -454,26 +444,22 @@ uint LZSS_Decompress( const byte *pInput, byte *pOutput, size_t input_len, size_
if( cmdByte & 0x01 ) if( cmdByte & 0x01 )
{ {
int position;
int i, count;
byte *pSource;
if( pInput > pInputEnd ) if( pInput > pInputEnd )
return 0; return 0;
position = *pInput++ << LZSS_LOOKSHIFT; int position = *pInput++ << LZSS_LOOKSHIFT;
position |= ( *pInput >> LZSS_LOOKSHIFT ); position |= ( *pInput >> LZSS_LOOKSHIFT );
count = ( *pInput++ & 0x0F ) + 1; int count = ( *pInput++ & 0x0F ) + 1;
if( count == 1 ) if( count == 1 )
break; break;
pSource = pOutput - position - 1; byte *pSource = pOutput - position - 1;
if( totalBytes + count > output_len || pSource < pOrigOutput ) if( totalBytes + count > output_len || pSource < pOrigOutput )
return 0; return 0;
for( i = 0; i < count; i++ ) for( int i = 0; i < count; i++ )
*pOutput++ = *pSource++; *pOutput++ = *pSource++;
totalBytes += count; totalBytes += count;
} }
@@ -504,16 +490,12 @@ COM_ParseVector
*/ */
qboolean COM_ParseVector( char **pfile, float *v, size_t size ) qboolean COM_ParseVector( char **pfile, float *v, size_t size )
{ {
string token;
qboolean bracket = false;
char *saved;
uint i;
if( v == NULL || size == 0 ) if( v == NULL || size == 0 )
return false; return false;
memset( v, 0, sizeof( *v ) * size ); memset( v, 0, sizeof( *v ) * size );
string token;
if( size == 1 ) if( size == 1 )
{ {
*pfile = COM_ParseFile( *pfile, token, sizeof( token )); *pfile = COM_ParseFile( *pfile, token, sizeof( token ));
@@ -521,16 +503,17 @@ qboolean COM_ParseVector( char **pfile, float *v, size_t size )
return true; return true;
} }
saved = *pfile; char *saved = *pfile;
if(( *pfile = COM_ParseFile( *pfile, token, sizeof( token ))) == NULL ) if(( *pfile = COM_ParseFile( *pfile, token, sizeof( token ))) == NULL )
return false; return false;
qboolean bracket = false;
if( token[0] == '(' ) if( token[0] == '(' )
bracket = true; bracket = true;
else *pfile = saved; // restore token to right get it again else *pfile = saved; // restore token to right get it again
for( i = 0; i < size; i++ ) for( uint i = 0; i < size; i++ )
{ {
*pfile = COM_ParseFile( *pfile, token, sizeof( token )); *pfile = COM_ParseFile( *pfile, token, sizeof( token ));
v[i] = Q_atof( token ); v[i] = Q_atof( token );
@@ -593,13 +576,11 @@ Converts pszInput Hex string to nInputLength/2 binary
*/ */
void COM_HexConvert( const char *pszInput, int nInputLength, byte *pOutput ) void COM_HexConvert( const char *pszInput, int nInputLength, byte *pOutput )
{ {
const char *pIn; byte *p = pOutput;
byte *p = pOutput;
int i;
for( i = 0; i < nInputLength; i += 2 ) for( int i = 0; i < nInputLength; i += 2 )
{ {
pIn = &pszInput[i]; const char *pIn = &pszInput[i];
*p = COM_Nibble( pIn[0] ) << 4 | COM_Nibble( pIn[1] ); *p = COM_Nibble( pIn[0] ) << 4 | COM_Nibble( pIn[1] );
p++; p++;
} }
@@ -613,10 +594,6 @@ COM_LoadFileForMe
*/ */
byte *GAME_EXPORT COM_LoadFileForMe( const char *filename, int *pLength ) byte *GAME_EXPORT COM_LoadFileForMe( const char *filename, int *pLength )
{ {
string name;
byte *pfile;
fs_offset_t iLength;
if( COM_StringEmptyOrNULL( filename )) if( COM_StringEmptyOrNULL( filename ))
{ {
if( pLength ) if( pLength )
@@ -624,10 +601,12 @@ byte *GAME_EXPORT COM_LoadFileForMe( const char *filename, int *pLength )
return NULL; return NULL;
} }
string name;
Q_strncpy( name, filename, sizeof( name )); Q_strncpy( name, filename, sizeof( name ));
COM_FixSlashes( name ); COM_FixSlashes( name );
pfile = g_fsapi.LoadFileMalloc( name, &iLength, false ); fs_offset_t iLength;
byte *pfile = g_fsapi.LoadFileMalloc( name, &iLength, false );
if( pLength ) *pLength = (int)iLength; if( pLength ) *pLength = (int)iLength;
return pfile; return pfile;
@@ -706,18 +685,6 @@ void GAME_EXPORT pfnGetModelBounds( model_t *mod, float *mins, float *maxs )
} }
} }
/*
=============
pfnCVarGetPointer
can return NULL
=============
*/
cvar_t *GAME_EXPORT pfnCVarGetPointer( const char *szVarName )
{
return (cvar_t *)Cvar_FindVar( szVarName );
}
/* /*
============= =============
pfnCompareFileTime pfnCompareFileTime
@@ -726,16 +693,17 @@ pfnCompareFileTime
*/ */
int GAME_EXPORT pfnCompareFileTime( const char *path1, const char *path2, int *retval ) int GAME_EXPORT pfnCompareFileTime( const char *path1, const char *path2, int *retval )
{ {
int t1, t2;
*retval = 0; *retval = 0;
if( !path1 || !path2 ) if( !path1 || !path2 )
return 0; return 0;
if(( t1 = g_fsapi.FileTime( path1, false )) == -1 ) int t1 = g_fsapi.FileTime( path1, false );
if( t1 == -1 )
return 0; return 0;
if(( t2 = g_fsapi.FileTime( path2, false )) == -1 ) int t2 = g_fsapi.FileTime( path2, false );
if( t2 == -1 )
return 0; return 0;
if( t1 < t2 ) if( t1 < t2 )
@@ -768,17 +736,11 @@ int GAME_EXPORT COM_CheckParm( char *parm, char **ppnext )
qboolean COM_IsSafeFileToDownload( const char *filename ) qboolean COM_IsSafeFileToDownload( const char *filename )
{ {
char lwrfilename[4096];
const char *last;
const char *ext;
size_t len;
int i;
if( COM_StringEmptyOrNULL( filename )) if( COM_StringEmptyOrNULL( filename ))
return false; return false;
ext = COM_FileExtension( filename ); const char *ext = COM_FileExtension( filename );
len = Q_strlen( filename ); size_t len = Q_strlen( filename );
// only allow extensionless files that start with !MD5 // only allow extensionless files that start with !MD5
if( !Q_strncmp( filename, "!MD5", 4 )) if( !Q_strncmp( filename, "!MD5", 4 ))
@@ -791,7 +753,7 @@ qboolean COM_IsSafeFileToDownload( const char *filename )
if( len != 36 ) if( len != 36 )
return false; return false;
for( i = 4; i < len; i++ ) for( int i = 4; i < len; i++ )
{ {
if(( filename[i] >= '0' && filename[i] <= '9' ) || if(( filename[i] >= '0' && filename[i] <= '9' ) ||
( filename[i] >= 'A' && filename[i] <= 'F' )) ( filename[i] >= 'A' && filename[i] <= 'F' ))
@@ -803,12 +765,13 @@ qboolean COM_IsSafeFileToDownload( const char *filename )
return true; return true;
} }
for( i = 0; i < len; i++ ) for( int i = 0; i < len; i++ )
{ {
if( !isprint( filename[i] )) if( !isprint( filename[i] ))
return false; return false;
} }
char lwrfilename[4096];
Q_strnlwr( filename, lwrfilename, sizeof( lwrfilename )); Q_strnlwr( filename, lwrfilename, sizeof( lwrfilename ));
ext = COM_FileExtension( lwrfilename ); ext = COM_FileExtension( lwrfilename );
@@ -818,7 +781,7 @@ qboolean COM_IsSafeFileToDownload( const char *filename )
if( lwrfilename[0] == '/' ) if( lwrfilename[0] == '/' )
return false; return false;
last = Q_strrchr( lwrfilename, '.' ); const char *last = Q_strrchr( lwrfilename, '.' );
if( last == NULL ) if( last == NULL )
return false; return false;
@@ -826,7 +789,7 @@ qboolean COM_IsSafeFileToDownload( const char *filename )
if( Q_strlen( last ) != 4 ) if( Q_strlen( last ) != 4 )
return false; return false;
for( i = 0; i < ARRAYSIZE( file_exts ); i++ ) for( int i = 0; i < ARRAYSIZE( file_exts ); i++ )
{ {
if( !Q_stricmp( ext, file_exts[i] )) if( !Q_stricmp( ext, file_exts[i] ))
return false; return false;
@@ -837,14 +800,11 @@ qboolean COM_IsSafeFileToDownload( const char *filename )
char *_copystring( poolhandle_t mempool, const char *s, const char *filename, int fileline ) char *_copystring( poolhandle_t mempool, const char *s, const char *filename, int fileline )
{ {
size_t size;
char *b;
if( !s ) return NULL; if( !s ) return NULL;
if( !mempool ) mempool = host.mempool; if( !mempool ) mempool = host.mempool;
size = Q_strlen( s ) + 1; size_t size = Q_strlen( s ) + 1;
b = _Mem_Alloc( mempool, size, false, filename, fileline ); char *b = _Mem_Alloc( mempool, size, false, filename, fileline );
Q_strncpy( b, s, size ); Q_strncpy( b, s, size );
return b; return b;
@@ -943,11 +903,11 @@ void GAME_EXPORT pfnResetTutorMessageDecayData( void )
static void Test_LZSS( void ) static void Test_LZSS( void )
{ {
char poison1[8192]; char poison1[8192] MAYBE_UNUSED;
byte in[256]; byte in[256];
char poison2[8192]; char poison2[8192] MAYBE_UNUSED;
byte out[256]; byte out[256];
char poison3[8192]; char poison3[8192] MAYBE_UNUSED;
lzss_header_t *hdr = (lzss_header_t *)in; lzss_header_t *hdr = (lzss_header_t *)in;
uint result; uint result;
+19 -3
View File
@@ -368,8 +368,12 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *memptr, size_t size, qboolean cl
ALLOC_CHECK( 3 ) WARN_UNUSED_RESULT; ALLOC_CHECK( 3 ) WARN_UNUSED_RESULT;
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline ) void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
ALLOC_CHECK( 2 ) MALLOC_LIKE( _Mem_Free, 1 ) WARN_UNUSED_RESULT; ALLOC_CHECK( 2 ) MALLOC_LIKE( _Mem_Free, 1 ) WARN_UNUSED_RESULT;
poolhandle_t _Mem_AllocPool( const char *name, const char *filename, int fileline ) poolhandle_t _Mem_AllocPool( const char *name, unsigned int flags, const char *filename, int fileline )
WARN_UNUSED_RESULT; WARN_UNUSED_RESULT;
// pool flags
#define MEM_SMALL_ALLOC_OPT (1U<<0) // use compact header for allocations <= 255 bytes (drops filename/fileline tracking)
void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline ); void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline );
void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline ); void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline );
void _Mem_Check( const char *filename, int fileline ); void _Mem_Check( const char *filename, int fileline );
@@ -385,7 +389,8 @@ void Mem_Stats_f( void );
_Mem_Free( *ptr, __FILE__, __LINE__ ); \ _Mem_Free( *ptr, __FILE__, __LINE__ ); \
*ptr = NULL; } *ptr = NULL; }
#define Mem_AllocPool( name ) _Mem_AllocPool( name, __FILE__, __LINE__ ) #define Mem_AllocPool( name ) _Mem_AllocPool( name, 0, __FILE__, __LINE__ )
#define Mem_AllocPoolExt( name, flags ) _Mem_AllocPool( name, flags, __FILE__, __LINE__ )
#define Mem_FreePool( pool ) _Mem_FreePool( pool, __FILE__, __LINE__ ) #define Mem_FreePool( pool ) _Mem_FreePool( pool, __FILE__, __LINE__ )
#define Mem_EmptyPool( pool ) _Mem_EmptyPool( pool, __FILE__, __LINE__ ) #define Mem_EmptyPool( pool ) _Mem_EmptyPool( pool, __FILE__, __LINE__ )
#define Mem_IsAllocated( mem ) Mem_IsAllocatedExt( NULL, mem ) #define Mem_IsAllocated( mem ) Mem_IsAllocatedExt( NULL, mem )
@@ -629,7 +634,6 @@ byte COM_Nibble( char c );
int COM_SaveFile( const char *filename, const void *data, int len ); int COM_SaveFile( const char *filename, const void *data, int len );
byte *COM_LoadFileForMe( const char *filename, int *pLength ) MALLOC_LIKE( free, 1 ); byte *COM_LoadFileForMe( const char *filename, int *pLength ) MALLOC_LIKE( free, 1 );
qboolean COM_IsSafeFileToDownload( const char *filename ); qboolean COM_IsSafeFileToDownload( const char *filename );
cvar_t *pfnCVarGetPointer( const char *szVarName );
int pfnDrawConsoleString( int x, int y, char *string ); int pfnDrawConsoleString( int x, int y, char *string );
void pfnDrawSetTextColor( float r, float g, float b ); void pfnDrawSetTextColor( float r, float g, float b );
void pfnDrawConsoleStringLen( const char *pText, int *length, int *height ); void pfnDrawConsoleStringLen( const char *pText, int *length, int *height );
@@ -740,6 +744,7 @@ qboolean CL_DisableVisibility( void );
qboolean CL_IsRecordDemo( void ); qboolean CL_IsRecordDemo( void );
qboolean CL_IsPlaybackDemo( void ); qboolean CL_IsPlaybackDemo( void );
qboolean UI_CreditsActive( void ); qboolean UI_CreditsActive( void );
void *UI_GetMenuFactory( void );
int CL_GetMaxClients( void ); int CL_GetMaxClients( void );
#else #else
static inline qboolean CL_Initialized( void ) { return false; } static inline qboolean CL_Initialized( void ) { return false; }
@@ -750,6 +755,7 @@ static inline qboolean CL_DisableVisibility( void ) { return false; }
static inline qboolean CL_IsRecordDemo( void ) { return false; } static inline qboolean CL_IsRecordDemo( void ) { return false; }
static inline qboolean CL_IsPlaybackDemo( void ) { return false; } static inline qboolean CL_IsPlaybackDemo( void ) { return false; }
static inline qboolean UI_CreditsActive( void ) { return false; } static inline qboolean UI_CreditsActive( void ) { return false; }
static inline void *UI_GetMenuFactory( void ) { return NULL; }
static inline int CL_GetMaxClients( void ) { return SV_GetMaxClients(); } static inline int CL_GetMaxClients( void ) { return SV_GetMaxClients(); }
#endif #endif
@@ -895,6 +901,7 @@ void NET_MasterClear( void );
void NET_MasterShutdown( void ); void NET_MasterShutdown( void );
qboolean NET_GetMaster( netadr_t from, uint *challenge, double *last_heartbeat ); qboolean NET_GetMaster( netadr_t from, uint *challenge, double *last_heartbeat );
qboolean NET_MasterQuery( uint32_t key, qboolean net, const char *filter ); qboolean NET_MasterQuery( uint32_t key, qboolean net, const char *filter );
void NET_QueryServerByAddress( netadr_t adr, connprotocol_t proto );
// //
// munge.c // munge.c
@@ -933,6 +940,15 @@ const char *SoundList_Get( soundlst_group_t group, int idx );
void SoundList_Init( void ); void SoundList_Init( void );
void SoundList_Shutdown( void ); void SoundList_Shutdown( void );
//
// xrcon.c
//
void XRcon_Init( void );
void XRcon_Shutdown( void );
void XRcon_Frame( void );
void XRcon_Print( const char *msg );
qboolean XRcon_IsActive( void );
#ifdef REF_DLL #ifdef REF_DLL
#error "common.h in ref_dll" #error "common.h in ref_dll"
#endif #endif
+97 -142
View File
@@ -54,11 +54,10 @@ Cmd_ListMaps
*/ */
int Cmd_ListMaps( search_t *t, char *lastmapname, size_t len, qboolean silent ) int Cmd_ListMaps( search_t *t, char *lastmapname, size_t len, qboolean silent )
{ {
file_t *f; int nummaps = 0;
int i, nummaps;
string mapname, message, compiler, generator; string mapname, message, compiler, generator;
for( i = 0, nummaps = 0; i < t->numfilenames; i++ ) for( int i = 0; i < t->numfilenames; i++ )
{ {
char entfilename[MAX_QPATH]; char entfilename[MAX_QPATH];
const char *ext = COM_FileExtension( t->filenames[i] ); const char *ext = COM_FileExtension( t->filenames[i] );
@@ -72,17 +71,14 @@ int Cmd_ListMaps( search_t *t, char *lastmapname, size_t len, qboolean silent )
compiler[0] = '\0'; compiler[0] = '\0';
generator[0] = '\0'; generator[0] = '\0';
f = FS_Open( t->filenames[i], "rb", con_gamemaps.value ); file_t *f = FS_Open( t->filenames[i], "rb", con_gamemaps.value );
if( f ) if( f )
{ {
dheader_t *header;
dextrahdr_t *hdrext;
dlump_t entities; dlump_t entities;
fs_offset_t filelen;
byte buf[MAX_SYSPATH] = { 0 }; // 1 kb byte buf[MAX_SYSPATH] = { 0 }; // 1 kb
filelen = FS_Read( f, buf, sizeof( buf )); fs_offset_t filelen = FS_Read( f, buf, sizeof( 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, filelen, silent, &entities )) if( !Mod_TestBmodelLumps( f, t->filenames[i], buf, filelen, silent, &entities ))
@@ -94,8 +90,8 @@ int Cmd_ListMaps( search_t *t, char *lastmapname, size_t len, qboolean silent )
lumpofs = entities.fileofs; lumpofs = entities.fileofs;
lumplen = entities.filelen; lumplen = entities.filelen;
header = (dheader_t *)buf; dheader_t *header = (dheader_t *)buf;
hdrext = (dextrahdr_t *)((byte *)buf + sizeof( dheader_t )); dextrahdr_t *hdrext = (dextrahdr_t *)((byte *)buf + sizeof( dheader_t ));
ver = header->version; ver = header->version;
if( hdrext->id == IDEXTRAHEADER ) version = hdrext->version; if( hdrext->id == IDEXTRAHEADER ) version = hdrext->version;
@@ -187,11 +183,9 @@ Prints or complete map filename
*/ */
static qboolean Cmd_GetMapList( const char *s, char *completedname, int length, qboolean print_suggestions ) static qboolean Cmd_GetMapList( const char *s, char *completedname, int length, qboolean print_suggestions )
{ {
search_t *t; string matchbuf;
string matchbuf;
int i, nummaps;
t = FS_Search( va( "maps/%s*.bsp", s ), true, con_gamemaps.value ); search_t *t = FS_Search( va( "maps/%s*.bsp", s ), true, con_gamemaps.value );
if( !t ) return false; if( !t ) return false;
COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf )); COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf ));
@@ -199,7 +193,7 @@ static qboolean Cmd_GetMapList( const char *s, char *completedname, int length,
Q_strncpy( completedname, matchbuf, length ); Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true; if( t->numfilenames == 1 ) return true;
nummaps = Cmd_ListMaps( t, matchbuf, sizeof( matchbuf ), !print_suggestions ); int nummaps = Cmd_ListMaps( t, matchbuf, sizeof( matchbuf ), !print_suggestions );
if( print_suggestions ) if( print_suggestions )
Con_Printf( "\n^3 %d maps found.\n", nummaps ); Con_Printf( "\n^3 %d maps found.\n", nummaps );
@@ -207,7 +201,7 @@ static qboolean Cmd_GetMapList( const char *s, char *completedname, int length,
Mem_Free( t ); Mem_Free( t );
// cut shortestMatch to the amount common with s // cut shortestMatch to the amount common with s
for( i = 0; matchbuf[i]; i++ ) for( int i = 0; matchbuf[i]; i++ )
{ {
if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] ))
completedname[i] = 0; completedname[i] = 0;
@@ -224,12 +218,10 @@ Prints or complete demo filename
*/ */
static qboolean Cmd_GetDemoList( const char *s, char *completedname, int length, qboolean print_suggestions ) static qboolean Cmd_GetDemoList( const char *s, char *completedname, int length, qboolean print_suggestions )
{ {
search_t *t; string matchbuf;
string matchbuf;
int i, numdems;
// lookup only in gamedir // lookup only in gamedir
t = FS_Search( va( "%s*.dem", s ), true, true ); search_t *t = FS_Search( va( "%s*.dem", s ), true, true );
if( !t ) return false; if( !t ) return false;
COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf )); COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf ));
@@ -237,7 +229,8 @@ static qboolean Cmd_GetDemoList( const char *s, char *completedname, int length,
Q_strncpy( completedname, matchbuf, length ); Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true; if( t->numfilenames == 1 ) return true;
for( i = 0, numdems = 0; i < t->numfilenames; i++ ) int numdems = 0;
for( int i = 0; i < t->numfilenames; i++ )
{ {
if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "dem" )) if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "dem" ))
continue; continue;
@@ -256,7 +249,7 @@ static qboolean Cmd_GetDemoList( const char *s, char *completedname, int length,
// cut shortestMatch to the amount common with s // cut shortestMatch to the amount common with s
if( completedname && length ) if( completedname && length )
{ {
for( i = 0; matchbuf[i]; i++ ) for( int i = 0; matchbuf[i]; i++ )
{ {
if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] ))
completedname[i] = 0; completedname[i] = 0;
@@ -274,11 +267,9 @@ Prints or complete movie filename
*/ */
static qboolean Cmd_GetMovieList( const char *s, char *completedname, int length, qboolean print_suggestions ) static qboolean Cmd_GetMovieList( const char *s, char *completedname, int length, qboolean print_suggestions )
{ {
search_t *t; string matchbuf;
string matchbuf;
int i, nummovies;
t = FS_Search( va( "media/%s*.avi", s ), true, false ); search_t *t = FS_Search( va( "media/%s*.avi", s ), true, false );
if( !t ) return false; if( !t ) return false;
COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf )); COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf ));
@@ -286,7 +277,8 @@ static qboolean Cmd_GetMovieList( const char *s, char *completedname, int length
Q_strncpy( completedname, matchbuf, length ); Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true; if( t->numfilenames == 1 ) return true;
for(i = 0, nummovies = 0; i < t->numfilenames; i++) int nummovies = 0;
for( int i = 0; i < t->numfilenames; i++ )
{ {
if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "avi" )) if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "avi" ))
continue; continue;
@@ -304,7 +296,7 @@ static qboolean Cmd_GetMovieList( const char *s, char *completedname, int length
// cut shortestMatch to the amount common with s // cut shortestMatch to the amount common with s
if( completedname && length ) if( completedname && length )
{ {
for( i = 0; matchbuf[i]; i++ ) for( int i = 0; matchbuf[i]; i++ )
{ {
if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] ))
completedname[i] = 0; completedname[i] = 0;
@@ -323,11 +315,9 @@ Prints or complete background track filename
*/ */
static qboolean Cmd_GetMusicList( const char *s, char *completedname, int length, qboolean print_suggestions ) static qboolean Cmd_GetMusicList( const char *s, char *completedname, int length, qboolean print_suggestions )
{ {
search_t *t; string matchbuf;
string matchbuf;
int i, numtracks;
t = FS_Search( va( "media/%s*.*", s ), true, false ); search_t *t = FS_Search( va( "media/%s*.*", s ), true, false );
if( !t ) return false; if( !t ) return false;
COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf )); COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf ));
@@ -335,7 +325,8 @@ static qboolean Cmd_GetMusicList( const char *s, char *completedname, int length
Q_strncpy( completedname, matchbuf, length ); Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true; if( t->numfilenames == 1 ) return true;
for(i = 0, numtracks = 0; i < t->numfilenames; i++) int numtracks = 0;
for( int i = 0; i < t->numfilenames; i++ )
{ {
const char *ext = COM_FileExtension( t->filenames[i] ); const char *ext = COM_FileExtension( t->filenames[i] );
@@ -355,7 +346,7 @@ static qboolean Cmd_GetMusicList( const char *s, char *completedname, int length
// cut shortestMatch to the amount common with s // cut shortestMatch to the amount common with s
if( completedname && length ) if( completedname && length )
{ {
for( i = 0; matchbuf[i]; i++ ) for( int i = 0; matchbuf[i]; i++ )
{ {
if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] ))
completedname[i] = 0; completedname[i] = 0;
@@ -373,11 +364,9 @@ Prints or complete savegame filename
*/ */
static qboolean Cmd_GetSavesList( const char *s, char *completedname, int length, qboolean print_suggestions ) static qboolean Cmd_GetSavesList( const char *s, char *completedname, int length, qboolean print_suggestions )
{ {
search_t *t; string matchbuf;
string matchbuf;
int i, numsaves;
t = FS_Search( va( DEFAULT_SAVE_DIRECTORY "%s*.sav", s ), true, true ); // lookup only in gamedir search_t *t = FS_Search( va( DEFAULT_SAVE_DIRECTORY "%s*.sav", s ), true, true ); // lookup only in gamedir
if( !t ) return false; if( !t ) return false;
COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf )); COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf ));
@@ -385,7 +374,8 @@ static qboolean Cmd_GetSavesList( const char *s, char *completedname, int length
Q_strncpy( completedname, matchbuf, length ); Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true; if( t->numfilenames == 1 ) return true;
for( i = 0, numsaves = 0; i < t->numfilenames; i++ ) int numsaves = 0;
for( int i = 0; i < t->numfilenames; i++ )
{ {
if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "sav" )) if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "sav" ))
continue; continue;
@@ -403,7 +393,7 @@ static qboolean Cmd_GetSavesList( const char *s, char *completedname, int length
// cut shortestMatch to the amount common with s // cut shortestMatch to the amount common with s
if( completedname && length ) if( completedname && length )
{ {
for( i = 0; matchbuf[i]; i++ ) for( int i = 0; matchbuf[i]; i++ )
{ {
if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] ))
completedname[i] = 0; completedname[i] = 0;
@@ -422,11 +412,9 @@ Prints or complete .cfg filename
*/ */
static qboolean Cmd_GetConfigList( const char *s, char *completedname, int length, qboolean print_suggestions ) static qboolean Cmd_GetConfigList( const char *s, char *completedname, int length, qboolean print_suggestions )
{ {
search_t *t; string matchbuf;
string matchbuf;
int i, numconfigs;
t = FS_Search( va( "%s*.cfg", s ), true, false ); search_t *t = FS_Search( va( "%s*.cfg", s ), true, false );
if( !t ) return false; if( !t ) return false;
COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf )); COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf ));
@@ -434,7 +422,8 @@ static qboolean Cmd_GetConfigList( const char *s, char *completedname, int lengt
Q_strncpy( completedname, matchbuf, length ); Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true; if( t->numfilenames == 1 ) return true;
for( i = 0, numconfigs = 0; i < t->numfilenames; i++ ) int numconfigs = 0;
for( int i = 0; i < t->numfilenames; i++ )
{ {
if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "cfg" )) if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "cfg" ))
continue; continue;
@@ -452,7 +441,7 @@ static qboolean Cmd_GetConfigList( const char *s, char *completedname, int lengt
// cut shortestMatch to the amount common with s // cut shortestMatch to the amount common with s
if( completedname && length ) if( completedname && length )
{ {
for( i = 0; matchbuf[i]; i++ ) for( int i = 0; matchbuf[i]; i++ )
{ {
if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] ))
completedname[i] = 0; completedname[i] = 0;
@@ -471,11 +460,9 @@ Prints or complete sound filename
*/ */
static qboolean Cmd_GetSoundList( const char *s, char *completedname, int length, qboolean print_suggestions ) static qboolean Cmd_GetSoundList( const char *s, char *completedname, int length, qboolean print_suggestions )
{ {
search_t *t; string matchbuf;
string matchbuf;
int i, numsounds;
t = FS_Search( va( "%s%s*.*", DEFAULT_SOUNDPATH, s ), true, false ); search_t *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, sizeof( matchbuf )); Q_strncpy( matchbuf, t->filenames[0] + sizeof( DEFAULT_SOUNDPATH ) - 1, sizeof( matchbuf ));
@@ -484,7 +471,8 @@ static qboolean Cmd_GetSoundList( const char *s, char *completedname, int length
Q_strncpy( completedname, matchbuf, length ); Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true; if( t->numfilenames == 1 ) return true;
for(i = 0, numsounds = 0; i < t->numfilenames; i++) int numsounds = 0;
for( int i = 0; i < t->numfilenames; i++ )
{ {
const char *ext = COM_FileExtension( t->filenames[i] ); const char *ext = COM_FileExtension( t->filenames[i] );
@@ -505,7 +493,7 @@ static qboolean Cmd_GetSoundList( const char *s, char *completedname, int length
// cut shortestMatch to the amount common with s // cut shortestMatch to the amount common with s
if( completedname && length ) if( completedname && length )
{ {
for( i = 0; matchbuf[i]; i++ ) for( int i = 0; matchbuf[i]; i++ )
{ {
if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] ))
completedname[i] = 0; completedname[i] = 0;
@@ -525,12 +513,10 @@ Prints or complete item classname (weapons only)
static qboolean Cmd_GetItemsList( const char *s, char *completedname, int length, qboolean print_suggestions ) static qboolean Cmd_GetItemsList( const char *s, char *completedname, int length, qboolean print_suggestions )
{ {
#if !XASH_DEDICATED #if !XASH_DEDICATED
search_t *t; string matchbuf;
string matchbuf;
int i, numitems;
if( !clgame.itemspath[0] ) return false; // not in game yet if( !clgame.itemspath[0] ) return false; // not in game yet
t = FS_Search( va( "%s/%s*.txt", clgame.itemspath, s ), true, false ); search_t *t = FS_Search( va( "%s/%s*.txt", clgame.itemspath, s ), true, false );
if( !t ) return false; if( !t ) return false;
COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf )); COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf ));
@@ -538,7 +524,8 @@ static qboolean Cmd_GetItemsList( const char *s, char *completedname, int length
Q_strncpy( completedname, matchbuf, length ); Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true; if( t->numfilenames == 1 ) return true;
for( i = 0, numitems = 0; i < t->numfilenames; i++ ) int numitems = 0;
for( int i = 0; i < t->numfilenames; i++ )
{ {
if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "txt" )) if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "txt" ))
continue; continue;
@@ -556,7 +543,7 @@ static qboolean Cmd_GetItemsList( const char *s, char *completedname, int length
// cut shortestMatch to the amount common with s // cut shortestMatch to the amount common with s
if( completedname && length ) if( completedname && length )
{ {
for( i = 0; matchbuf[i]; i++ ) for( int i = 0; matchbuf[i]; i++ )
{ {
if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] ))
completedname[i] = 0; completedname[i] = 0;
@@ -612,7 +599,6 @@ Autocomplete for bind command
*/ */
static qboolean Cmd_GetCommandsAndCvarsList( const char *s, char *completedname, int length, qboolean cmds, qboolean cvars, qboolean toggle, qboolean print_suggestions ) static qboolean Cmd_GetCommandsAndCvarsList( const char *s, char *completedname, int length, qboolean cmds, qboolean cvars, qboolean toggle, qboolean print_suggestions )
{ {
size_t i;
string matchbuf; string matchbuf;
con_autocomplete_t list = { 0 }; // local autocomplete list con_autocomplete_t list = { 0 }; // local autocomplete list
@@ -645,7 +631,7 @@ static qboolean Cmd_GetCommandsAndCvarsList( const char *s, char *completedname,
qsort( list.cmds, list.matchCount, sizeof( char* ), Con_SortCmds ); qsort( list.cmds, list.matchCount, sizeof( char* ), Con_SortCmds );
for( i = 0; i < list.matchCount; i++ ) for( size_t i = 0; i < list.matchCount; i++ )
{ {
Q_strncpy( matchbuf, list.cmds[i], sizeof( matchbuf )); Q_strncpy( matchbuf, list.cmds[i], sizeof( matchbuf ));
if( print_suggestions ) if( print_suggestions )
@@ -657,14 +643,14 @@ static qboolean Cmd_GetCommandsAndCvarsList( const char *s, char *completedname,
if( completedname && length ) if( completedname && length )
{ {
for( i = 0; matchbuf[i]; i++ ) for( size_t i = 0; matchbuf[i]; i++ )
{ {
if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] ))
completedname[i] = 0; completedname[i] = 0;
} }
} }
for( i = 0; i < list.matchCount; i++ ) for( size_t i = 0; i < list.matchCount; i++ )
{ {
if( list.cmds[i] != NULL ) if( list.cmds[i] != NULL )
{ {
@@ -709,11 +695,9 @@ Prints or complete .HPK filenames
*/ */
static qboolean Cmd_GetCustomList( const char *s, char *completedname, int length, qboolean print_suggestions ) static qboolean Cmd_GetCustomList( const char *s, char *completedname, int length, qboolean print_suggestions )
{ {
search_t *t; string matchbuf;
string matchbuf;
int i, numitems;
t = FS_Search( va( "%s*.hpk", s ), true, false ); search_t *t = FS_Search( va( "%s*.hpk", s ), true, false );
if( !t ) return false; if( !t ) return false;
COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf )); COM_FileBase( t->filenames[0], matchbuf, sizeof( matchbuf ));
@@ -721,7 +705,8 @@ static qboolean Cmd_GetCustomList( const char *s, char *completedname, int lengt
Q_strncpy( completedname, matchbuf, length ); Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true; if( t->numfilenames == 1 ) return true;
for(i = 0, numitems = 0; i < t->numfilenames; i++) int numitems = 0;
for( int i = 0; i < t->numfilenames; i++ )
{ {
if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "hpk" )) if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "hpk" ))
continue; continue;
@@ -739,7 +724,7 @@ static qboolean Cmd_GetCustomList( const char *s, char *completedname, int lengt
// cut shortestMatch to the amount common with s // cut shortestMatch to the amount common with s
if( completedname && length ) if( completedname && length )
{ {
for( i = 0; matchbuf[i]; i++ ) for( int i = 0; matchbuf[i]; i++ )
{ {
if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] ))
completedname[i] = 0; completedname[i] = 0;
@@ -757,15 +742,14 @@ Prints or complete gamedir name
*/ */
static qboolean Cmd_GetGamesList( const char *s, char *completedname, int length, qboolean print_suggestions ) static qboolean Cmd_GetGamesList( const char *s, char *completedname, int length, qboolean print_suggestions )
{ {
int i, numgamedirs; string gamedirs[MAX_MODS];
string gamedirs[MAX_MODS]; string matchbuf;
string matchbuf;
int len;
// compare gamelist with current keyword // compare gamelist with current keyword
len = Q_strlen( s ); int len = Q_strlen( s );
for( i = 0, numgamedirs = 0; i < FI->numgames; i++ ) int numgamedirs = 0;
for( int i = 0; i < FI->numgames; i++ )
{ {
if(( *s == '*' ) || !Q_strnicmp( FI->games[i]->gamefolder, s, len)) if(( *s == '*' ) || !Q_strnicmp( FI->games[i]->gamefolder, s, len))
Q_strncpy( gamedirs[numgamedirs++], FI->games[i]->gamefolder, sizeof( gamedirs[0] )); Q_strncpy( gamedirs[numgamedirs++], FI->games[i]->gamefolder, sizeof( gamedirs[0] ));
@@ -777,7 +761,7 @@ static qboolean Cmd_GetGamesList( const char *s, char *completedname, int 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( int i = 0; i < numgamedirs; i++ )
{ {
Q_strncpy( matchbuf, gamedirs[i], sizeof( matchbuf )); Q_strncpy( matchbuf, gamedirs[i], sizeof( matchbuf ));
if( print_suggestions ) if( print_suggestions )
@@ -790,7 +774,7 @@ static qboolean Cmd_GetGamesList( const char *s, char *completedname, int length
// cut shortestMatch to the amount common with s // cut shortestMatch to the amount common with s
if( completedname && length ) if( completedname && length )
{ {
for( i = 0; matchbuf[i]; i++ ) for( int i = 0; matchbuf[i]; i++ )
{ {
if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] ))
completedname[i] = 0; completedname[i] = 0;
@@ -808,10 +792,8 @@ Prints or complete CD command name
*/ */
static qboolean Cmd_GetCDList( const char *s, char *completedname, int length, qboolean print_suggestions ) static qboolean Cmd_GetCDList( const char *s, char *completedname, int length, qboolean print_suggestions )
{ {
int i, numcdcommands; string cdcommands[8];
string cdcommands[8]; string matchbuf;
string matchbuf;
int len;
const char *cd_command[] = const char *cd_command[] =
{ {
@@ -826,9 +808,10 @@ static qboolean Cmd_GetCDList( const char *s, char *completedname, int length, q
}; };
// compare CD command list with current keyword // compare CD command list with current keyword
len = Q_strlen( s ); int len = Q_strlen( s );
for( i = 0, numcdcommands = 0; i < 8; i++ ) int numcdcommands = 0;
for( int i = 0; i < 8; i++ )
{ {
if(( *s == '*' ) || !Q_strnicmp( cd_command[i], s, len)) if(( *s == '*' ) || !Q_strnicmp( cd_command[i], s, len))
Q_strncpy( cdcommands[numcdcommands++], cd_command[i], sizeof( cdcommands[0] )); Q_strncpy( cdcommands[numcdcommands++], cd_command[i], sizeof( cdcommands[0] ));
@@ -840,7 +823,7 @@ static qboolean Cmd_GetCDList( const char *s, char *completedname, int length, q
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( int i = 0; i < numcdcommands; i++ )
{ {
Q_strncpy( matchbuf, cdcommands[i], sizeof( matchbuf )); Q_strncpy( matchbuf, cdcommands[i], sizeof( matchbuf ));
if( print_suggestions ) if( print_suggestions )
@@ -853,7 +836,7 @@ static qboolean Cmd_GetCDList( const char *s, char *completedname, int length, q
// cut shortestMatch to the amount common with s // cut shortestMatch to the amount common with s
if( completedname && length ) if( completedname && length )
{ {
for( i = 0; matchbuf[i]; i++ ) for( int i = 0; matchbuf[i]; i++ )
{ {
if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] )) if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] ))
completedname[i] = 0; completedname[i] = 0;
@@ -864,21 +847,15 @@ static qboolean Cmd_GetCDList( const char *s, char *completedname, int length, q
static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir ) static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
{ {
qboolean use_filter = false; string mpfilter;
string mpfilter; string result;
char *buffer;
size_t buffersize;
string result;
int i, size;
search_t *t;
file_t *f;
if( FS_FileSize( "maps.lst", onlyingamedir ) > 0 && !fRefresh ) if( FS_FileSize( "maps.lst", onlyingamedir ) > 0 && !fRefresh )
return true; // exist return true; // exist
// setup mpfilter // setup mpfilter
Q_snprintf( mpfilter, sizeof( mpfilter ), "maps/%s", GI->mp_filter ); Q_snprintf( mpfilter, sizeof( mpfilter ), "maps/%s", GI->mp_filter );
t = FS_Search( "maps/*.bsp", false, onlyingamedir ); search_t *t = FS_Search( "maps/*.bsp", false, onlyingamedir );
if( !t ) if( !t )
{ {
@@ -890,11 +867,11 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
return false; return false;
} }
buffersize = t->numfilenames * 2 * sizeof( result ); size_t buffersize = t->numfilenames * 2 * sizeof( result );
buffer = Mem_Calloc( host.mempool, buffersize ); char *buffer = Mem_Calloc( host.mempool, buffersize );
use_filter = !COM_StringEmpty( GI->mp_filter ); qboolean use_filter = !COM_StringEmpty( GI->mp_filter );
for( i = 0; i < t->numfilenames; i++ ) for( int i = 0; i < t->numfilenames; i++ )
{ {
char *ents = NULL, *pfile; char *ents = NULL, *pfile;
int lumpofs = 0, lumplen = 0; int lumpofs = 0, lumplen = 0;
@@ -906,17 +883,16 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
if( use_filter && Q_stristr( t->filenames[i], mpfilter )) if( use_filter && Q_stristr( t->filenames[i], mpfilter ))
continue; continue;
f = FS_Open( t->filenames[i], "rb", onlyingamedir ); file_t *f = FS_Open( t->filenames[i], "rb", onlyingamedir );
COM_FileBase( t->filenames[i], mapname, sizeof( mapname )); COM_FileBase( t->filenames[i], mapname, sizeof( mapname ));
if( f ) if( f )
{ {
qboolean have_spawnpoints = false; qboolean have_spawnpoints = false;
dlump_t entities; dlump_t entities;
fs_offset_t filelen;
byte buf[MAX_SYSPATH] = { 0 }; byte buf[MAX_SYSPATH] = { 0 };
filelen = FS_Read( f, buf, MAX_SYSPATH ); fs_offset_t filelen = FS_Read( f, buf, MAX_SYSPATH );
// check all the lumps and some other errors // check all the lumps and some other errors
if( !Mod_TestBmodelLumps( f, t->filenames[i], buf, filelen, true, &entities )) if( !Mod_TestBmodelLumps( f, t->filenames[i], buf, filelen, true, &entities ))
@@ -999,7 +975,7 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
} }
if( t ) Mem_Free( t ); // free search result if( t ) Mem_Free( t ); // free search result
size = Q_strlen( buffer ); int size = Q_strlen( buffer );
if( !size ) if( !size )
{ {
@@ -1102,9 +1078,7 @@ for various cmds
*/ */
static qboolean Cmd_AutocompleteName( const char *source, int arg, char *buffer, size_t bufsize, qboolean print_suggestions ) static qboolean Cmd_AutocompleteName( const char *source, int arg, char *buffer, size_t bufsize, qboolean print_suggestions )
{ {
int i; for( int i = 0; i < ARRAYSIZE( cmd_list ); i++ )
for( i = 0; i < ARRAYSIZE( cmd_list ); i++ )
{ {
if( cmd_list[i].arg == arg && Cmd_CheckName( cmd_list[i].name )) if( cmd_list[i].arg == arg && Cmd_CheckName( cmd_list[i].name ))
return cmd_list[i].func( source, buffer, bufsize, print_suggestions ); return cmd_list[i].func( source, buffer, bufsize, print_suggestions );
@@ -1150,14 +1124,11 @@ Con_ConcatRemaining
*/ */
static void Con_ConcatRemaining( const char *src, const char *start ) static void Con_ConcatRemaining( const char *src, const char *start )
{ {
const char *arg; const char *arg = Q_strstr( src, start );
int i;
arg = Q_strstr( src, start );
if( !arg ) if( !arg )
{ {
for( i = 1; i < Cmd_Argc(); i++ ) for( int i = 1; i < Cmd_Argc(); i++ )
{ {
Q_strncat( con.completionField->buffer, " ", sizeof( con.completionField->buffer ) ); Q_strncat( con.completionField->buffer, " ", sizeof( con.completionField->buffer ) );
arg = Cmd_Argv( i ); arg = Cmd_Argv( i );
@@ -1190,11 +1161,7 @@ perform Tab expansion
*/ */
void Con_CompleteCommand( field_t *field, qboolean print_suggestions ) void Con_CompleteCommand( field_t *field, qboolean print_suggestions )
{ {
field_t temp;
string filename;
qboolean toggle = false; qboolean toggle = false;
qboolean nextcmd;
int i;
// setup the completion field // setup the completion field
con.completionField = field; con.completionField = field;
@@ -1205,7 +1172,7 @@ void Con_CompleteCommand( field_t *field, qboolean print_suggestions )
// only look at the first token for completion purposes // only look at the first token for completion purposes
Cmd_TokenizeString( con.completionField->buffer ); Cmd_TokenizeString( con.completionField->buffer );
nextcmd = (con.completionField->buffer[Q_strlen( con.completionField->buffer ) - 1] == ' ') ? true : false; qboolean nextcmd = (con.completionField->buffer[Q_strlen( con.completionField->buffer ) - 1] == ' ') ? true : false;
con.completionString = Cmd_Argv( 0 ); con.completionString = Cmd_Argv( 0 );
@@ -1217,7 +1184,7 @@ void Con_CompleteCommand( field_t *field, qboolean print_suggestions )
return; return;
// free the old autocomplete list // free the old autocomplete list
for( i = 0; i < con.matchCount; i++ ) for( int i = 0; i < con.matchCount; i++ )
{ {
if( con.cmds[i] != NULL ) if( con.cmds[i] != NULL )
{ {
@@ -1235,7 +1202,7 @@ void Con_CompleteCommand( field_t *field, qboolean print_suggestions )
if( !con.matchCount ) return; // no matches if( !con.matchCount ) return; // no matches
temp = *con.completionField; field_t temp = *con.completionField;
// autocomplete second arg // autocomplete second arg
if(( Cmd_Argc() >= 2 ) || ( Cmd_Argc() == 1 && nextcmd )) if(( Cmd_Argc() >= 2 ) || ( Cmd_Argc() == 1 && nextcmd ))
@@ -1249,11 +1216,12 @@ void Con_CompleteCommand( field_t *field, qboolean print_suggestions )
if( COM_StringEmpty( con.completionBuffer ) ) if( COM_StringEmpty( con.completionBuffer ) )
return; return;
string filename;
if( Cmd_AutocompleteName( con.completionBuffer, Cmd_Argc() - 1, filename, sizeof( filename ), print_suggestions )) if( Cmd_AutocompleteName( con.completionBuffer, Cmd_Argc() - 1, filename, sizeof( filename ), print_suggestions ))
{ {
con.completionField->buffer[0] = 0; con.completionField->buffer[0] = 0;
for( i = 0; i < Cmd_Argc() - 1; i++ ) for( int i = 0; i < Cmd_Argc() - 1; i++ )
{ {
Q_strncat( con.completionField->buffer, Cmd_Argv( i ), sizeof( con.completionField->buffer )); Q_strncat( con.completionField->buffer, Cmd_Argv( i ), sizeof( con.completionField->buffer ));
Q_strncat( con.completionField->buffer, " ", sizeof( con.completionField->buffer )); Q_strncat( con.completionField->buffer, " ", sizeof( con.completionField->buffer ));
@@ -1320,12 +1288,11 @@ NOTE: input string must be equal or longer than MAX_STRING
*/ */
void Cmd_AutoComplete( char *complete_string ) void Cmd_AutoComplete( char *complete_string )
{ {
field_t input;
if( !complete_string || !*complete_string ) if( !complete_string || !*complete_string )
return; return;
// setup input // setup input
field_t input;
Q_strncpy( input.buffer, complete_string, sizeof( input.buffer ) ); Q_strncpy( input.buffer, complete_string, sizeof( input.buffer ) );
input.cursor = input.scroll = 0; input.cursor = input.scroll = 0;
@@ -1345,10 +1312,8 @@ Cmd_AutoCompleteClear
*/ */
void Cmd_AutoCompleteClear( void ) void Cmd_AutoCompleteClear( void )
{ {
int i;
// free the old autocomplete list // free the old autocomplete list
for( i = 0; i < con.matchCount; i++ ) for( int i = 0; i < con.matchCount; i++ )
{ {
if( con.cmds[i] != NULL ) if( con.cmds[i] != NULL )
{ {
@@ -1377,15 +1342,13 @@ static void Cmd_WriteOpenGLCvar( const char *name, const char *string, const cha
static void Cmd_WriteHelp(const char *name, const char *unused, const char *desc, void *f ) static void Cmd_WriteHelp(const char *name, const char *unused, const char *desc, void *f )
{ {
int length;
if( COM_StringEmptyOrNULL( desc )) if( COM_StringEmptyOrNULL( desc ))
return; // ignore fantom cmds return; // ignore fantom cmds
if( name[0] == '+' || name[0] == '-' ) if( name[0] == '+' || name[0] == '-' )
return; // key bindings return; // key bindings
length = 3 - (Q_strlen( name ) / 10); // Asm_Ed default tab stop is 10 int length = 3 - (Q_strlen( name ) / 10); // Asm_Ed default tab stop is 10
if( length == 3 ) FS_Printf( f, "%s\t\t\t\"%s\"\n", name, desc ); if( length == 3 ) FS_Printf( f, "%s\t\t\t\"%s\"\n", name, desc );
if( length == 2 ) FS_Printf( f, "%s\t\t\"%s\"\n", name, desc ); if( length == 2 ) FS_Printf( f, "%s\t\t\"%s\"\n", name, desc );
@@ -1431,14 +1394,13 @@ Writes key bindings and archived cvars to config.cfg
*/ */
void Host_WriteConfig( void ) void Host_WriteConfig( void )
{ {
kbutton_t *mlook = NULL; kbutton_t *mlook = NULL;
kbutton_t *jlook = NULL; kbutton_t *jlook = NULL;
file_t *f;
if( !clgame.hInstance || Sys_CheckParm( "-nowriteconfig" ) ) return; if( !clgame.hInstance || Sys_CheckParm( "-nowriteconfig" ) ) return;
f = FS_Open( "config.cfg.new", "w", false ); file_t *f = FS_Open( "config.cfg.new", "w", false );
if( f ) if( f )
{ {
Con_Reportf( "%s()\n", __func__ ); Con_Reportf( "%s()\n", __func__ );
@@ -1479,11 +1441,11 @@ save serverinfo variables into server.cfg (using for dedicated server too)
*/ */
void GAME_EXPORT Host_WriteServerConfig( const char *name ) void GAME_EXPORT Host_WriteServerConfig( const char *name )
{ {
file_t *f;
string newconfigfile; string newconfigfile;
Q_snprintf( newconfigfile, MAX_STRING, "%s.new", name ); Q_snprintf( newconfigfile, MAX_STRING, "%s.new", name );
file_t *f;
if(( f = FS_Open( newconfigfile, "w", false )) != NULL ) if(( f = FS_Open( newconfigfile, "w", false )) != NULL )
{ {
Host_InitializeConfig( f, "game.cfg", "multiplayer server temporary config" ); Host_InitializeConfig( f, "game.cfg", "multiplayer server temporary config" );
@@ -1504,21 +1466,18 @@ save opengl variables into opengl.cfg
*/ */
void Host_WriteOpenGLConfig( void ) void Host_WriteOpenGLConfig( void )
{ {
const char *config_name;
string name;
file_t *f;
if( Sys_CheckParm( "-nowriteconfig" ) || !ref.dllFuncs.R_GetConfigName ) if( Sys_CheckParm( "-nowriteconfig" ) || !ref.dllFuncs.R_GetConfigName )
return; return;
config_name = ref.dllFuncs.R_GetConfigName(); const char *config_name = ref.dllFuncs.R_GetConfigName();
if( !config_name ) if( !config_name )
return; return;
string name;
Q_snprintf( name, sizeof( name ), "%s.cfg", config_name ); Q_snprintf( name, sizeof( name ), "%s.cfg", config_name );
f = FS_Open( va( "%s.new", name ), "w", false ); file_t *f = FS_Open( va( "%s.new", name ), "w", false );
if( f ) if( f )
{ {
Con_Reportf( "%s()\n", __func__ ); Con_Reportf( "%s()\n", __func__ );
@@ -1539,12 +1498,10 @@ save render variables into video.cfg
*/ */
void Host_WriteVideoConfig( void ) void Host_WriteVideoConfig( void )
{ {
file_t *f;
if( Sys_CheckParm( "-nowriteconfig" ) ) if( Sys_CheckParm( "-nowriteconfig" ) )
return; return;
f = FS_Open( "video.cfg.new", "w", false ); file_t *f = FS_Open( "video.cfg.new", "w", false );
if( f ) if( f )
{ {
Con_Reportf( "%s()\n", __func__ ); Con_Reportf( "%s()\n", __func__ );
@@ -1558,8 +1515,6 @@ void Host_WriteVideoConfig( void )
void Key_EnumCmds_f( void ) void Key_EnumCmds_f( void )
{ {
file_t *f;
FS_AllowDirectPaths( true ); FS_AllowDirectPaths( true );
if( FS_FileExists( "../help.txt", false )) if( FS_FileExists( "../help.txt", false ))
{ {
@@ -1568,7 +1523,7 @@ void Key_EnumCmds_f( void )
return; return;
} }
f = FS_Open( "../help.txt", "w", false ); file_t *f = FS_Open( "../help.txt", "w", false );
if( f ) if( f )
{ {
Host_InitializeConfig( f, "help.txt", "xash commands and console variables" ); Host_InitializeConfig( f, "help.txt", "xash commands and console variables" );
+4 -8
View File
@@ -51,10 +51,9 @@ static qboolean CustomDecal_Validate( const char *path, void *raw, int nFileSize
void COM_ClearCustomizationList( customization_t *pHead, qboolean bCleanDecals ) void COM_ClearCustomizationList( customization_t *pHead, qboolean bCleanDecals )
{ {
customization_t *pCurrent;
customization_t *pNext; customization_t *pNext;
for( pCurrent = pHead->pNext; pCurrent != NULL; pCurrent = pNext ) for( customization_t *pCurrent = pHead->pNext; pCurrent != NULL; pCurrent = pNext )
{ {
pNext = pCurrent->pNext; pNext = pCurrent->pNext;
@@ -82,12 +81,10 @@ void COM_ClearCustomizationList( customization_t *pHead, qboolean bCleanDecals )
qboolean COM_CreateCustomization( customization_t *pListHead, resource_t *pResource, int playernumber, int flags, customization_t **pOut, int *nLumps ) qboolean COM_CreateCustomization( customization_t *pListHead, resource_t *pResource, int playernumber, int flags, customization_t **pOut, int *nLumps )
{ {
qboolean bError = false; qboolean bError = false;
fs_offset_t checksize = 0;
customization_t *pCust;
if( pOut ) *pOut = NULL; if( pOut ) *pOut = NULL;
pCust = Z_Calloc( sizeof( customization_t )); customization_t *pCust = Z_Calloc( sizeof( customization_t ));
pCust->resource = *pResource; pCust->resource = *pResource;
if( pResource->nDownloadSize <= 0 ) if( pResource->nDownloadSize <= 0 )
@@ -102,7 +99,7 @@ qboolean COM_CreateCustomization( customization_t *pListHead, resource_t *pResou
} }
else else
{ {
fs_offset_t checksize = 0;
pCust->pBuffer = FS_LoadFile( pResource->szFileName, &checksize, true ); pCust->pBuffer = FS_LoadFile( pResource->szFileName, &checksize, true );
if( (int)checksize != pCust->resource.nDownloadSize ) if( (int)checksize != pCust->resource.nDownloadSize )
bError = true; bError = true;
@@ -158,11 +155,10 @@ CustomizationError:
int COM_SizeofResourceList( resource_t *pList, resourceinfo_t *ri ) int COM_SizeofResourceList( resource_t *pList, resourceinfo_t *ri )
{ {
int nSize = 0; int nSize = 0;
resource_t *p;
memset( ri, 0, sizeof( *ri )); memset( ri, 0, sizeof( *ri ));
for( p = pList->pNext; p != pList; p = p->pNext ) for( resource_t *p = pList->pNext; p != pList; p = p->pNext )
{ {
nSize += p->nDownloadSize; nSize += p->nDownloadSize;
+28 -63
View File
@@ -70,12 +70,10 @@ find the specified variable by name
*/ */
convar_t *Cvar_FindVar( const char *var_name ) convar_t *Cvar_FindVar( const char *var_name )
{ {
convar_t *var;
if( !var_name ) if( !var_name )
return NULL; return NULL;
var = BaseCmd_Find( HM_CVAR, var_name ); convar_t *var = BaseCmd_Find( HM_CVAR, var_name );
// HACKHACK: HL25 compatibility // HACKHACK: HL25 compatibility
if( !var && !Q_stricmp( var_name, "gl_widescreen_yfov" )) if( !var && !Q_stricmp( var_name, "gl_widescreen_yfov" ))
@@ -190,10 +188,9 @@ deal with userinfo etc
*/ */
static const char *Cvar_ValidateString( convar_t *var, const char *value ) static const char *Cvar_ValidateString( convar_t *var, const char *value )
{ {
const char *pszValue;
static char szNew[MAX_STRING]; static char szNew[MAX_STRING];
const char *pszValue = value;
pszValue = value;
szNew[0] = 0; szNew[0] = 0;
// this cvar's string must only contain printable characters. // this cvar's string must only contain printable characters.
@@ -283,14 +280,11 @@ unlink the variable
static int Cvar_UnlinkVar( const char *var_name, uint32_t group ) static int Cvar_UnlinkVar( const char *var_name, uint32_t group )
{ {
int count = 0; int count = 0;
convar_t **prev; convar_t **prev = &cvar_vars;
convar_t *var;
prev = &cvar_vars;
while( 1 ) while( 1 )
{ {
var = *prev; convar_t *var = *prev;
if( !var ) break; if( !var ) break;
// do filter by name // do filter by name
@@ -358,13 +352,11 @@ Cvar_LookupVars
*/ */
void Cvar_LookupVars( int checkbit, void *buffer, void *ptr, setpair_t callback ) void Cvar_LookupVars( int checkbit, void *buffer, void *ptr, setpair_t callback )
{ {
convar_t *var;
// nothing to process ? // nothing to process ?
if( !callback ) return; if( !callback ) return;
// force checkbit to 0 for lookup all cvars // force checkbit to 0 for lookup all cvars
for( var = cvar_vars; var; var = var->next ) for( convar_t *var = cvar_vars; var; var = var->next )
{ {
if( checkbit && !FBitSet( var->flags, checkbit )) if( checkbit && !FBitSet( var->flags, checkbit ))
continue; continue;
@@ -627,8 +619,6 @@ Cvar_Set2
*/ */
static convar_t *Cvar_Set2( const char *var_name, const char *value ) static convar_t *Cvar_Set2( const char *var_name, const char *value )
{ {
convar_t *var;
qboolean dll_variable = false;
qboolean force = false; qboolean force = false;
if( !Cvar_ValidateVarName( var_name, false )) if( !Cvar_ValidateVarName( var_name, false ))
@@ -637,7 +627,7 @@ static convar_t *Cvar_Set2( const char *var_name, const char *value )
return NULL; return NULL;
} }
var = Cvar_FindVar( var_name ); convar_t *var = Cvar_FindVar( var_name );
if( !var ) if( !var )
{ {
// if cvar not found, create it // if cvar not found, create it
@@ -663,7 +653,7 @@ static convar_t *Cvar_Set2( const char *var_name, const char *value )
// use this check to prevent acessing for unexisting fields // use this check to prevent acessing for unexisting fields
// for cvar_t: latched_string, description, etc // for cvar_t: latched_string, description, etc
dll_variable = FBitSet( var->flags, FCVAR_EXTDLL ); qboolean dll_variable = FBitSet( var->flags, FCVAR_EXTDLL );
// check value // check value
if( !value ) if( !value )
@@ -782,8 +772,6 @@ Cvar_Set
*/ */
void GAME_EXPORT Cvar_Set( const char *var_name, const char *value ) void GAME_EXPORT Cvar_Set( const char *var_name, const char *value )
{ {
convar_t *var;
if( !var_name ) if( !var_name )
{ {
// there is an error in C code if this happens // there is an error in C code if this happens
@@ -791,7 +779,7 @@ void GAME_EXPORT Cvar_Set( const char *var_name, const char *value )
return; return;
} }
var = Cvar_FindVar( var_name ); convar_t *var = Cvar_FindVar( var_name );
if( !var ) if( !var )
{ {
@@ -836,8 +824,6 @@ Cvar_VariableValue
*/ */
float GAME_EXPORT Cvar_VariableValue( const char *var_name ) float GAME_EXPORT Cvar_VariableValue( const char *var_name )
{ {
convar_t *var;
if( !var_name ) if( !var_name )
{ {
// there is an error in C code if this happens // there is an error in C code if this happens
@@ -845,7 +831,7 @@ float GAME_EXPORT Cvar_VariableValue( const char *var_name )
return 0.0f; return 0.0f;
} }
var = Cvar_FindVar( var_name ); convar_t *var = Cvar_FindVar( var_name );
if( !var ) return 0.0f; if( !var ) return 0.0f;
return Q_atof( var->string ); return Q_atof( var->string );
@@ -858,9 +844,7 @@ Cvar_VariableInteger
*/ */
int Cvar_VariableInteger( const char *var_name ) int Cvar_VariableInteger( const char *var_name )
{ {
convar_t *var; convar_t *var = Cvar_FindVar( var_name );
var = Cvar_FindVar( var_name );
if( !var ) return 0; if( !var ) return 0;
return Q_atoi( var->string ); return Q_atoi( var->string );
@@ -873,8 +857,6 @@ Cvar_VariableString
*/ */
const char *Cvar_VariableString( const char *var_name ) const char *Cvar_VariableString( const char *var_name )
{ {
convar_t *var;
if( !var_name ) if( !var_name )
{ {
// there is an error in C code if this happens // there is an error in C code if this happens
@@ -882,7 +864,7 @@ const char *Cvar_VariableString( const char *var_name )
return ""; return "";
} }
var = Cvar_FindVar( var_name ); convar_t *var = Cvar_FindVar( var_name );
if( !var ) return ""; if( !var ) return "";
return var->string; return var->string;
@@ -909,10 +891,8 @@ Any testing variables will be reset to the safe values
*/ */
void Cvar_SetCheatState( void ) void Cvar_SetCheatState( void )
{ {
convar_t *var;
// set all default vars to the safe value // set all default vars to the safe value
for( var = cvar_vars; var; var = var->next ) for( convar_t *var = cvar_vars; var; var = var->next )
{ {
// can't process dll cvars - missed def_string // can't process dll cvars - missed def_string
if( !FBitSet( var->flags, FCVAR_ALLOCATED|FCVAR_EXTENDED )) if( !FBitSet( var->flags, FCVAR_ALLOCATED|FCVAR_EXTENDED ))
@@ -959,12 +939,11 @@ static int ShouldSetCvar_splitstr_handler( char *prev, char *next, void *userdat
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_", "con_", "scr_" }; const char *prefixes[] = { "cl_", "gl_", "m_", "r_", "hud_", "joy_", "con_", "scr_" };
int i;
if( isPrivileged ) if( isPrivileged )
return true; return true;
if( FBitSet( v->flags, FCVAR_PRIVILEGED )) if( FBitSet( v->flags, FCVAR_PRIVILEGED ) || v->name[0] == '@' )
return false; return false;
if( cl_filterstuffcmd.value <= 0.0f ) if( cl_filterstuffcmd.value <= 0.0f )
@@ -981,7 +960,7 @@ static qboolean Cvar_ShouldSetCvar( convar_t *v, qboolean isPrivileged )
if( FBitSet( v->flags, FCVAR_FILTERABLE )) if( FBitSet( v->flags, FCVAR_FILTERABLE ))
return false; return false;
for( i = 0; i < ARRAYSIZE( prefixes ); i++ ) for( int i = 0; i < ARRAYSIZE( prefixes ); i++ )
{ {
if( !Q_strnicmp( v->name, prefixes[i], Q_strlen( prefixes[i] ))) if( !Q_strnicmp( v->name, prefixes[i], Q_strlen( prefixes[i] )))
return false; return false;
@@ -1046,9 +1025,7 @@ with the specified flag set to true.
*/ */
void Cvar_WriteVariables( file_t *f, int group ) void Cvar_WriteVariables( file_t *f, int group )
{ {
convar_t *var; for( convar_t *var = cvar_vars; var; var = var->next )
for( var = cvar_vars; var; var = var->next )
{ {
if( FBitSet( var->flags, group )) if( FBitSet( var->flags, group ))
FS_Printf( f, "%s \"%s\"\n", var->name, var->string ); FS_Printf( f, "%s \"%s\"\n", var->name, var->string );
@@ -1064,15 +1041,13 @@ Toggles a cvar for easy single key binding
*/ */
static void Cvar_Toggle_f( void ) static void Cvar_Toggle_f( void )
{ {
int v;
if( Cmd_Argc() != 2 ) if( Cmd_Argc() != 2 )
{ {
Con_Printf( S_USAGE "toggle <variable>\n" ); Con_Printf( S_USAGE "toggle <variable>\n" );
return; return;
} }
v = !Cvar_VariableInteger( Cmd_Argv( 1 )); int v = !Cvar_VariableInteger( Cmd_Argv( 1 ));
Cvar_Set( Cmd_Argv( 1 ), v ? "1" : "0" ); Cvar_Set( Cmd_Argv( 1 ), v ? "1" : "0" );
} }
@@ -1087,10 +1062,10 @@ weren't declared in C code.
*/ */
static void Cvar_Set_f( void ) static void Cvar_Set_f( void )
{ {
int i, c, l = 0, len;
char combined[MAX_CMD_TOKENS]; char combined[MAX_CMD_TOKENS];
int l = 0;
c = Cmd_Argc(); int c = Cmd_Argc();
if( c < 3 ) if( c < 3 )
{ {
Msg( S_USAGE "set <variable> <value>\n" ); Msg( S_USAGE "set <variable> <value>\n" );
@@ -1098,9 +1073,9 @@ static void Cvar_Set_f( void )
} }
combined[0] = 0; combined[0] = 0;
for( i = 2; i < c; i++ ) for( int i = 2; i < c; i++ )
{ {
len = Q_strlen( Cmd_Argv(i) + 1 ); int len = Q_strlen( Cmd_Argv(i) + 1 );
if( l + len >= MAX_CMD_TOKENS - 2 ) if( l + len >= MAX_CMD_TOKENS - 2 )
break; break;
Q_strncat( combined, Cmd_Argv( i ), sizeof( combined )); Q_strncat( combined, Cmd_Argv( i ), sizeof( combined ));
@@ -1134,7 +1109,6 @@ Cvar_List_f
*/ */
static void Cvar_List_f( void ) static void Cvar_List_f( void )
{ {
convar_t *var;
const char *match = NULL; const char *match = NULL;
int count = 0; int count = 0;
size_t matchlen = 0; size_t matchlen = 0;
@@ -1145,10 +1119,9 @@ static void Cvar_List_f( void )
matchlen = Q_strlen( match ); matchlen = Q_strlen( match );
} }
for( var = cvar_vars; var; var = var->next ) for( convar_t *var = cvar_vars; var; var = var->next )
{ {
char value[MAX_VA_STRING]; char value[MAX_VA_STRING];
char *p;
if( var->name[0] == '@' ) if( var->name[0] == '@' )
continue; // never shows system cvars continue; // never shows system cvars
@@ -1156,7 +1129,7 @@ static void Cvar_List_f( void )
if( match && !Q_strnicmpext( match, var->name, matchlen )) if( match && !Q_strnicmpext( match, var->name, matchlen ))
continue; continue;
p = Q_strchr( var->string, '^' ); char *p = Q_strchr( var->string, '^' );
if( IsColorString( p )) if( IsColorString( p ))
Q_snprintf( value, sizeof( value ), "\"%s\"", var->string ); Q_snprintf( value, sizeof( value ), "\"%s\"", var->string );
@@ -1195,12 +1168,10 @@ unlink all cvars with specified flag
*/ */
void Cvar_Unlink( uint32_t group ) void Cvar_Unlink( uint32_t group )
{ {
int count;
if( !Cvar_ValidateUnlinkGroup( group )) if( !Cvar_ValidateUnlinkGroup( group ))
return; return;
count = Cvar_UnlinkVar( NULL, group ); int count = Cvar_UnlinkVar( NULL, group );
Con_Reportf( "unlink %i cvars\n", count ); Con_Reportf( "unlink %i cvars\n", count );
} }
@@ -1208,18 +1179,14 @@ pending_cvar_t *Cvar_PrepareToUnlink( uint32_t group )
{ {
pending_cvar_t *list = NULL; pending_cvar_t *list = NULL;
pending_cvar_t *tail = NULL; pending_cvar_t *tail = NULL;
convar_t *cv;
for( cv = cvar_vars; cv != NULL; cv = cv->next ) for( convar_t *cv = cvar_vars; cv != NULL; cv = cv->next )
{ {
size_t namelen;
pending_cvar_t *p;
if( !FBitSet( cv->flags, group )) if( !FBitSet( cv->flags, group ))
continue; continue;
namelen = Q_strlen( cv->name ) + 1; size_t namelen = Q_strlen( cv->name ) + 1;
p = Mem_Malloc( cvar_pool, sizeof( *list ) + namelen ); pending_cvar_t *p = Mem_Malloc( cvar_pool, sizeof( *list ) + namelen );
p->next = NULL; p->next = NULL;
p->cv_cur = cv; p->cv_cur = cv;
p->cv_next = cv->next; p->cv_next = cv->next;
@@ -1295,7 +1262,7 @@ Reads in all archived cvars
*/ */
void Cvar_Init( void ) void Cvar_Init( void )
{ {
cvar_pool = Mem_AllocPool( "Console Variables" ); cvar_pool = Mem_AllocPoolExt( "Console Variables", MEM_SMALL_ALLOC_OPT );
cvar_vars = NULL; cvar_vars = NULL;
cvar_active_filter_quirks = NULL; cvar_active_filter_quirks = NULL;
Cvar_RegisterVariable( &cmd_scripting ); Cvar_RegisterVariable( &cmd_scripting );
@@ -1320,9 +1287,7 @@ Cvar_PostFSInit
*/ */
void Cvar_PostFSInit( void ) void Cvar_PostFSInit( void )
{ {
int i; for( int i = 0; i < ARRAYSIZE( cvar_filter_quirks ); i++ )
for( i = 0; i < ARRAYSIZE( cvar_filter_quirks ); i++ )
{ {
if( !Q_stricmp( cvar_filter_quirks[i].gamedir, GI->gamefolder )) if( !Q_stricmp( cvar_filter_quirks[i].gamedir, GI->gamefolder ))
{ {

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