Compare commits

...

362 Commits

Author SHA1 Message Date
Alibek Omarov
3baeea1253 engine: client: handle hud_utf8 in client.dll's draw character functions, rather than in engine's CL_DrawCharacter 2025-03-12 07:31:18 +03:00
Alibek Omarov
9ba7cc88d9 engine: client: move Con_UtfProcessChar to cl_gameui. It is now deprecated 2025-03-12 07:26:58 +03:00
Alibek Omarov
9ef7759e05 engine: client: rewrite touch control text drawing with utflib and cl_font 2025-03-12 07:26:58 +03:00
Alibek Omarov
232224f52d engine: client: OSK doesn't need unicode conversion, as it only supports basic latin anyway 2025-03-12 07:26:58 +03:00
Alibek Omarov
18d09d80cc engine: client: like GoldSrc, expect UTF-8 encoded strings in pfnDrawString/pfnDrawStringReverse 2025-03-12 06:15:27 +03:00
Alibek Omarov
67f91fc100 engine: client: decode utf-8 string in CL_DrawCenterPrint, as CL_DrawCharacter requires unicode codepoints now 2025-03-12 06:04:35 +03:00
Alibek Omarov
ca22c4123d engine: client: make CL_DrawCharacter accept unicode codepoints, as it was intended to do 2025-03-11 08:23:16 +03:00
Alibek Omarov
8af0e2c8b4 readme: add missing system dependencies on Linux systems [skip ci] 2025-03-08 02:42:28 +03:00
Alibek Omarov
a5191d8948 engine: client: console: simplify Field_DrawInputLine, try to make it safer 2025-03-08 02:35:32 +03:00
Alibek Omarov
b2d8239829 engine: common: net_http: fix decompression for compressed but not chunked files 2025-03-06 19:10:48 +03:00
Alibek Omarov
34322f025b engine: client: limit ticket generator choices to revemu2013 only 2025-03-06 12:35:32 +03:00
Alibek Omarov
3e6b434733 mainui: update 2025-03-05 22:36:41 +03:00
Alibek Omarov
8359cbe76c scripts: waifulib: add flag --enable-limited-debuginfo which enables -gline-tables-only on GCC and Clang compilers
This saves ~30mb of APK size on Android.
2025-03-05 02:19:39 +03:00
Alibek Omarov
0e90e6285e engine: host: use #if instead of #ifdef when checking for extended hl25 structs compile option 2025-03-03 22:59:44 +03:00
Alibek Omarov
2f5840f650 engine: host: add a cvar that indicates whether engine was built with --enable-hl25-extended-structs or not 2025-03-03 22:53:20 +03:00
Alibek Omarov
3b51a554dd mainui: update 2025-03-02 20:20:54 +03:00
Alibek Omarov
5f0880d4a2 engine: client: lower the bandwidth test fragment sizes to 1400 and less, as using 64k, 32k and more is unreliable 2025-03-02 20:20:40 +03:00
Bohdan Shulyar
884a3c66ac client: touch: fix minor typo that prevented editing touch buttons commands 2025-03-02 20:19:58 +03:00
Alibek Omarov
c76752cc5f engine: server: validate uuid in protinfo, it's an md5 string 2025-03-01 22:45:01 +03:00
Alibek Omarov
fc2888e107 engine: server: fix incorrect ID string generation, hashedcdkey is already an MD5 string 2025-03-01 22:27:22 +03:00
Alibek Omarov
674b4c1506 engine: server: reorder sv_client_t struct for better memory efficiency, remove unused fields 2025-03-01 22:07:05 +03:00
Alibek Omarov
cddd50f1e9 engine: server: completely erase sv_client_t on client connect, so we always start from scratch for every user 2025-03-01 22:07:05 +03:00
Alibek Omarov
6c9d5bc1fb engine: server: cleanup penalties and warns for new players 2025-03-01 16:03:39 +03:00
Alibek Omarov
ec23860238 gitmodules: use github mirrors instead of xiph.org's git
It's not really a good idea to hammer upstream git servers with cloning same
data over and over. Besides, it's down right now.
2025-03-01 15:28:55 +03:00
Alibek Omarov
14a2e34b7e mainui: update 2025-03-01 15:21:20 +03:00
Alibek Omarov
29c8818557 engine: server: do not continue processing command if the player was kicked during it (for example, by speedhack prevention) 2025-03-01 14:58:15 +03:00
Andrey Akhmichin
7222830b28 Documentation: supported-mod-list.md: a little remark. 2025-02-28 23:56:28 +03:00
Alibek Omarov
9b0ad7daf0 engine: common: register forgotten net_clockwindow cvar 2025-02-28 22:44:44 +03:00
Alibek Omarov
73729827f4 engine: platform: win32: add forgotten SDL.h include 2025-02-28 21:55:26 +03:00
Alibek Omarov
97fa395a3b engine: platform: win32: fix build by restoring previous win32 header inclusion order 2025-02-28 21:44:22 +03:00
Alibek Omarov
1cef8ea7af Revert "ref: gl: check OES NPOT texture extension in BigGL mode"
This breaks mipmaps on PSVita

This reverts commit 54b0cf9991.
2025-02-28 17:08:27 +03:00
Alibek Omarov
eda4e95607 engine: client: draw version at bottom right in menu, regardless if dev_overview or net_graph are enabled (those only used in-game) 2025-02-28 15:11:24 +03:00
Alibek Omarov
a5f0ca38f1 engine: remove inclusion of SDL headers globally, helps to cleanup code before SDL3 migration 2025-02-28 13:14:47 +03:00
Alibek Omarov
bbbd7711c1 engine: platform: cleanup remnants of disabling vsync while loading mechanism for linux fbdev and dos ports 2025-02-28 12:33:30 +03:00
Alibek Omarov
38e922557d engine: platform: sdl: remove disabling vsync while we're not in game, as this is something users have been complaining a lot
It's not a big deal if level loading will take a few milliseconds more.
2025-02-28 08:27:38 +03:00
Alibek Omarov
4dec1785ed engine: client: touch: fix inverted file extension check 2025-02-28 06:44:21 +03:00
Alibek Omarov
9f77b7dc46 scripts: waifulib: enable HLSDK -mtune only on GCC and Clang, and not on Android 2025-02-26 17:11:10 +03:00
Alibek Omarov
5061a29f86 scripts: waifulib: enable asynchronous-unwind-tables for better stacktraces 2025-02-26 17:10:30 +03:00
Alibek Omarov
cb5dffd554 engine: server: don't bother printing about unsupported connectionless packets if sv_log_outofband is set to 0 2025-02-26 17:06:33 +03:00
Alibek Omarov
4eaa8ab40f android: bump minimum CMake version, so disabling unneeded features in SDL actually works 2025-02-26 14:21:58 +03:00
Alibek Omarov
2a82d265d6 scripts: waifulib: xcompile: add support for Android NDK r27 as well 2025-02-26 12:40:22 +03:00
Alibek Omarov
f2392b5709 scripts: waifulib: xcompile: add support for building on Windows. Drop using shortcut target clang symlinks, as those don't work on Windows at all (they are wrapped into batch files, which can't be invoked like exes) 2025-02-26 12:40:22 +03:00
Alibek Omarov
5620e7ab4c android: fixup CMAKE_LIBRARY_OUTPUT_DIRECTORY on Win32, merge stdout and stderr for waf output 2025-02-26 12:40:22 +03:00
Alibek Omarov
a76236ac5a scripts: waifulib: xcompile: add support for NDK 28, remove setting up custom PREFIX to not mess up installation path 2025-02-26 12:40:22 +03:00
Alibek Omarov
d1c5862bab android: bump NDK version to 28 2025-02-26 12:40:22 +03:00
Alibek Omarov
81400d0b01 android: use xcompile.py's support for Android NDK, fix tabs 2025-02-26 12:40:22 +03:00
Alibek Omarov
a129f13e25 android: enable verbose output for CMake running from Gradle 2025-02-26 12:40:22 +03:00
Alibek Omarov
ec8b4c0a84 android: rework how engine is built, instead of generating CMakeLists, just use included in CMake ExternalProject feature 2025-02-26 12:40:22 +03:00
Alibek Omarov
f1f726822c engine: client: restore cl_cmdrate default value at 30. It wasn't an intentional change. 2025-02-25 19:52:48 +03:00
Alibek Omarov
8982d55392 engine: client: set default rate value to 25000
3500 is barely playable these days. Those who have worse than usual internet
connection, should set appropriate value themselves.
2025-02-25 17:36:43 +03:00
Alibek Omarov
f499286a87 engine: platform: sdl: don't call SDL_GL_SetSwapInterval each frame while we're not in game 2025-02-25 11:52:03 +03:00
Alibek Omarov
a3aaa87147 ref: gl: enable polygon offset for fullbright textures when rendering them in separate from VBO pass 2025-02-25 11:49:31 +03:00
Alibek Omarov
15a6971aca engine: platform: posix: strip path from filename in backtrace 2025-02-25 11:46:57 +03:00
Alibek Omarov
b1eb3390e3 engine: server: let server dll to register it's own showtriggers cvar 2025-02-24 06:41:11 +03:00
Alibek Omarov
74ad504377 engine: client: console: do not let color strings contribute to line length in console 2025-02-24 03:55:13 +03:00
Alibek Omarov
8a0c2577ed engine: platform: sdl: exclude fake game controller found on Android emulator 2025-02-24 03:42:03 +03:00
Alibek Omarov
a060d7aefd wscript: disable large file for 32-bit Android 2025-02-23 16:07:51 +03:00
Alibek Omarov
ccf342f4fe engine: client: fix inconsistent mouse state caused by mis-use of touch_emulate by cs16-client 2025-02-23 07:13:39 +03:00
Alibek Omarov
8b9a40ff1f engine: client: completely refactor touch code, protect button color, improve config output 2025-02-23 07:00:20 +03:00
Alibek Omarov
425cc61c4c engine: client: handle K_ESCAPE in Key_Console, remove special case for it in Key_Event 2025-02-23 06:47:44 +03:00
Alibek Omarov
fe1fd5b024 engine: client: make color array of DrawString functions const 2025-02-23 06:46:22 +03:00
Alibek Omarov
0c8da36a0b filesystem: disallow path traversal in FS_Delete and FS_Rename 2025-02-23 03:13:46 +03:00
Alibek Omarov
2c5030ab45 engine: client: do not save touch_emulate cvar 2025-02-23 02:04:33 +03:00
Alibek Omarov
9decba873b engine: platform: sdl: try to save and restore mouse position during showing or hiding cursor 2025-02-23 02:04:03 +03:00
Alibek Omarov
bda4c45504 engine: client: simplify CL_EDICT_NUM and it's sister, non throwing error, function CL_GetEntityByIndex 2025-02-23 01:51:05 +03:00
Alibek Omarov
f7aa8a0c90 ci: bump SDL2 to 2.32.0. This is the last major upgrade to SDL2 dependency, we should migrate to SDL3 (with sdl2-compat for GoldSrc mods) after that 2025-02-22 18:48:41 +03:00
Alibek Omarov
4c15cceb32 engine: client: deprecate custom id, it is not used meaningfully by anyone 2025-02-20 15:41:17 +03:00
Alibek Omarov
3e4c5beb25 ref: fix another typo made after R_StudioCalcBones refactor 2025-02-18 19:22:06 +03:00
Alibek Omarov
f84d865f4a engine: client: fix crash if server sends new movevars before entities were created
Nothing bad will happen if we skip wave height for world entity for now, but
we might need to handle this situation somehow in the future.
2025-02-17 13:02:21 +03:00
SNMetamorph
2465782a3e engine: platform: sys_win: fixed compiling error 2025-02-15 13:45:22 +03:00
Alibek Omarov
7ba2209124 engine: platform: sdl: set requested timer delay in units of 100ns according to the documentation 2025-02-15 13:08:05 +03:00
Alibek Omarov
af6b434b71 engine: platform: win32: implement nanosleep using waitable timers with high precision 2025-02-15 11:57:41 +03:00
Alibek Omarov
052ea6a8bd engine: platform: introduce for Platform_NanoSleep, to be used for better sleeping in between frames for lowering CPU usage 2025-02-15 10:11:17 +03:00
Alibek Omarov
448dc720ed engine: server: immediately exit from SV_GetChallenge on unknown type addresses 2025-02-15 09:31:20 +03:00
Alibek Omarov
75b15696f8 engine: zone: ensure memheader_t size is always expected 2025-02-15 09:31:20 +03:00
Andrey Akhmichin
7fb113f610 Documentation: opensource-mods.md: add "Delta Particles". 2025-02-15 08:02:44 +03:00
Andrey Akhmichin
0497e00ad2 Documentation: supported-mod-list.md: update. 2025-02-15 08:02:35 +03:00
Alibek Omarov
9c50288bbb engine: server: rewrite challenge generator to something more simple: salted MD5 of an IP address
The idea was taken from ReHLDS project.
2025-02-15 08:01:44 +03:00
Alibek Omarov
c5d4af802c engine: server: even if user set non-integer value for cl_updaterate, clamp it to sv_minupdaterate 2025-02-15 08:01:44 +03:00
Alibek Omarov
340a8b5e0c engine: server: fixes for userinfo change ratelimiting
* Add pentalty earlier
* Increase disallowed timewindow according to penality multiplier
* Allow first change even if it falls into ignore timewindow
2025-02-15 08:01:44 +03:00
Alibek Omarov
bc1b86c19c engine: server: refactor SV_ConnectClient, simplify LAN IP check 2025-02-15 08:01:44 +03:00
Alibek Omarov
b605cf603e common: xash3d_types: make it more compatible for inclusion in SDK 2025-02-15 08:01:44 +03:00
xiaodo
fdc2ed8093 engine: server: pfnClientCommand and pfnQueryClientCvarValue should execute on unspawned player 2025-02-14 20:52:45 +03:00
xiaodo
a27375d1f5 engine: server: cmds: fix kick command incorrect argc 2025-02-14 20:52:45 +03:00
Alibek Omarov
0e2abf9040 engine: platform: always create zeroed buffer for audio 2025-02-14 05:20:40 +03:00
Alibek Omarov
89430400d9 engine: sys_con: only allow names that start with either alphabetic or numerical character for a log file 2025-02-14 01:51:50 +03:00
Alibek Omarov
f1a9d408bf engine: sys_con: check if the next argument after -log starts with minus and ignore it if it does 2025-02-14 00:50:01 +03:00
Alibek Omarov
6529692244 engine: disable timestamps in log file by default, allow changing log file name with -log argument 2025-02-14 00:28:00 +03:00
Alibek Omarov
51d11f8e86 engine: platform: win32: remove unused log variables and checks from Win32 console, sys_con does the job 2025-02-14 00:28:00 +03:00
Alibek Omarov
c5397191e5 engine: client: touch: limit usage of touch_set_stroke and touch_setclientonly only for privileged mode 2025-02-13 20:55:49 +03:00
Alibek Omarov
44426709f7 engine: platform: posix: skip first stack frame when printing stack trace with libbacktrace 2025-02-13 20:43:32 +03:00
Alibek Omarov
2d8f747e84 wscript: disable using system-wide libbacktrace, as it might not support features we need 2025-02-13 19:21:07 +03:00
Alibek Omarov
0dd5a60410 3rdparty: gl4es: update submodule 2025-02-13 02:32:28 +03:00
Alibek Omarov
eec8129be4 3rdparty: extras: update submodule 2025-02-13 02:31:30 +03:00
Alibek Omarov
934c5e018d readme: clarify that chat is for russian speaking people [ci skip] 2025-02-12 18:08:10 +03:00
Alibek Omarov
d658d8cc78 readme: remove builds.sr.ht status, add Telegram chat link, remove stable build link (it's very outdated and not recommended to use) [skip ci] 2025-02-12 17:58:51 +03:00
Alibek Omarov
ca9a3f0491 engine: server: fix out of bounds write in SV_FindTouchedLeafs 2025-02-11 21:15:54 +03:00
Alibek Omarov
1510cb458f public: fix another typo 2025-02-11 21:12:50 +03:00
Andrey Akhmichin
30cabb8107 Documentation: supported-mod-list.md: fix branch name. 2025-02-11 21:10:59 +03:00
Alibek Omarov
64ee956618 engine: fix a typo 2025-02-11 20:06:15 +03:00
Alibek Omarov
39659644bf public: merge calc bone quaternion and position into single function
Expect that only adj and output quaternion can be NULL.
2025-02-11 18:57:08 +03:00
Alibek Omarov
eb09af0b08 ref: gl: avoid generating GL_INVALID_OPERATION if gl_vbo_dlightmode is set to 0 2025-02-11 18:57:08 +03:00
Andrey Akhmichin
91a4ace12c Documentation: supported-mod-list.md: update. 2025-02-11 16:28:40 +03:00
Alibek Omarov
2ad2e46b30 mainui: update 2025-02-10 13:18:59 +03:00
Alibek Omarov
627444279f Revert "common: cvar: make auto descriptions private to cvar subsystem, use them when Cvar_Get is called with NULL description"
This reverts commit ade560c601.
2025-02-10 12:49:05 +03:00
Alibek Omarov
3550bdb30d 3rdparty: mainui: update 2025-02-09 23:14:24 +03:00
Alibek Omarov
c201b895eb common: netadr: force cast uint16_t type to netadrtype_t
So it compiles in C++
2025-02-09 23:13:29 +03:00
Alibek Omarov
72f1ac3780 wscript: ensure system-wide libbacktrace supports threads 2025-02-09 18:29:02 +03:00
Alibek Omarov
d7dc3192de 3rdparty: libbacktrace: fix applying uselib 2025-02-09 18:25:40 +03:00
Alibek Omarov
43ea65fffc ci: upgrade freebsd tasks. 2025-02-09 17:41:01 +03:00
Alibek Omarov
a72d921c12 wscript: add system-wide libbacktrace detection 2025-02-09 17:41:01 +03:00
Alibek Omarov
99b7d71824 wscript: set DEST_SIZEOF_VOID_P with allow 64bit flag 2025-02-09 17:16:17 +03:00
Alibek Omarov
67c73bdcbe engine: server: remove impulse 204, it's not used anywhere
Thanks @tyabus for reminding me about this feature.
2025-02-09 17:16:05 +03:00
Alibek Omarov
8b1dbcf166 ci: remove extra 20s of wait before removing current release and downloading artifacts 2025-02-09 17:02:31 +03:00
Alibek Omarov
5f60095dc4 scripts: flatpak: disable separate debuginfo 2025-02-09 16:54:51 +03:00
Alibek Omarov
c7282b488b 3rdparty: libbacktrace: disable linking zlib, lzma and zstd for now, figure this out later 2025-02-09 16:49:43 +03:00
Alibek Omarov
afa829d996 3rdparty: libbacktrace: don't define POSIX_SOURCE, it breaks build on Mac 2025-02-09 16:41:26 +03:00
Alibek Omarov
c06ea8d915 engine: platform: posix: add printing backtrace to stderr and logfile for libbacktrace backend 2025-02-09 16:41:26 +03:00
Alibek Omarov
bf344282ec android: explicitly set Waf output directory so it doesn't mess with current configuration and places generated files where CMake expects them to be 2025-02-09 16:20:38 +03:00
Alibek Omarov
21f62910ac engine: platform: posix: fix build when glibc execinfo.h is not available, but libbacktrace is still used 2025-02-09 16:20:38 +03:00
Alibek Omarov
54552d93ef Documentation: goldsrc-protocol-support: I am not going to support Dproto 2025-02-09 16:18:21 +03:00
Alibek Omarov
97455e7fd4 engine: platform: sdl: fix build after last PR 2025-02-09 15:56:16 +03:00
Alibek Omarov
6087d43043 3rdparty: libbacktrace: properly disable it on win32, nswitch and psvita 2025-02-09 15:55:12 +03:00
Alibek Omarov
c1a96d3ff1 engine: platform: posix: fix build 2025-02-09 15:51:25 +03:00
Alibek Omarov
e27d20dfa3 android: enable debug symbols for native libraries 2025-02-09 15:49:28 +03:00
Alibek Omarov
890e12ec76 engine: platform: posix: flush stdout/stderr before everything, include build branch 2025-02-09 15:45:44 +03:00
Alibek Omarov
774d2ac28a engine: platform: posix: add libbacktrace support for crash handler 2025-02-09 15:42:28 +03:00
Alibek Omarov
960d724828 3rdparty: libbacktrace: add submodule 2025-02-09 15:40:07 +03:00
Alibek Omarov
32aa1f91bf engine: pass argv0 to crash handler setup, which is required for libbacktrace integration
Fix indentation in crash_posix.c
2025-02-09 15:36:49 +03:00
Alibek Omarov
bd3634c815 wscript: add sanity test for opusfile because some distros don't ship 32-bit binary 2025-02-09 15:34:30 +03:00
Oleg
eda0ac92cc engine: platform: sdl: change behavior when window position is not set 2025-02-09 08:54:31 +03:00
Oleg
546903ea05 engine: platform: sdl: write windows position changes even in fullscreen 2025-02-09 08:54:31 +03:00
Oleg
4975001795 engine: platform: sdl: enumerate video modes for display where window located is instead of display zero 2025-02-09 08:54:31 +03:00
Oleg
a078ad1f51 engine: platform: sdl: fix windows save position for multiple monitors 2025-02-09 08:54:31 +03:00
Oleg
8307f671d4 engine: platform: sdl: let platform decide where to put our fullscreen window 2025-02-09 08:54:31 +03:00
Alibek Omarov
241fab02b1 ref: gl: don't try to free luma and detail texture of water texture, as these fields used by r_ripple 2025-02-08 16:57:20 +03:00
Alibek Omarov
1bfee70477 engine: con_utils: add autocompletion for cvar commands like set, reset and toggle 2025-02-08 16:45:52 +03:00
Alibek Omarov
eb51d17cd2 engine: server: enable sv_zmax clamping back to avoid overflowing zmax value encoded in delta 2025-02-08 16:38:11 +03:00
Alibek Omarov
b5cb0b9f10 ref: gl: add r_dlight_virtual_radius. It potentially fixes ugly dlight cut off on largely scaled textures (or at least allows to tune it)
It also adds a fix found in JoeQuake (which traces back to FitzQuake, in which
it is attributed to LadyHavoc, Darkplaces author) to exactly calculate whether
the light hits the surface, so we don't wrongly enable lighting on a surface by
an increased radius.
2025-02-07 23:07:08 +03:00
Alibek Omarov
a955d1e957 ref: gl: make GL_BuildPolygonFromSurface static, remove one global variable usage (which is unused anyway) 2025-02-07 22:55:38 +03:00
Alibek Omarov
2b2c967e85 engine: add ms3.mentality.rip master server 2025-02-07 19:32:37 +03:00
Alibek Omarov
c48d93e3ce public: use last Git commit date (committer date, to be exact) as more predictable source for build num 2025-02-07 17:51:10 +03:00
Alibek Omarov
8f257cc331 public: add parsing build date from ISO-8601 alike format 2025-02-07 17:47:23 +03:00
Alibek Omarov
151e7fe37b public: crtlib: check for empty buffer in Q_vsnprintf 2025-02-06 21:19:10 +03:00
Alibek Omarov
add02dc6f9 engine: fix potential UB in netadr_t 2025-02-06 20:54:18 +03:00
Alibek Omarov
d4c34abd6e engine: enable writing log even if console hasn't been enabled at the engine startup (it might be enabled later, it might also contain crash data) 2025-02-06 20:03:07 +03:00
Alibek Omarov
1d81e611f0 scripts: gha: use N+1 job count when building PSVita dependencies 2025-02-06 00:32:42 +03:00
Alibek Omarov
6a0038e26a ref: gl: always set texture env mode to GL_MODULATE in TriAPI's RenderMode call
Not sure if this is correct, but it's generally a good idea to restore it to an
expected value.
2025-02-06 00:30:32 +03:00
Alibek Omarov
1d99f65e86 filesystem: when shutting down, clean up gameinfo pointers and total games count 2025-02-05 21:14:08 +03:00
Alibek Omarov
5e524bca60 engine: client: enable half-texel hack for nearest filtering too, if the scaling factor isn't an integer 2025-02-05 20:16:16 +03:00
Alibek Omarov
cf3e56e275 engine: client: add alternative mode for hud_scale, where it scales HUD down to selected resolution with preserving aspect ratio 2025-02-05 19:47:59 +03:00
Alibek Omarov
ade560c601 common: cvar: make auto descriptions private to cvar subsystem, use them when Cvar_Get is called with NULL description
It allows us to not lose engine-side description when client or gameui registers cvar with the same name. In case of
menu it's the only way to get cvar pointer.
2025-02-05 19:11:16 +03:00
Alibek Omarov
62e3ba2126 engine: add cvars to control mounting additional directories
Use existing ui_language cvar for mounting localization folders.
2025-02-05 18:54:28 +03:00
Alibek Omarov
674a4e5883 filesystem: add ability to mount HD, LV, addon and language folders by engine request 2025-02-05 18:24:36 +03:00
Alibek Omarov
f911210b81 public: simplify ctype.h is* functions wrappers for null-terminated strings, add Q_isalpha 2025-02-05 18:21:18 +03:00
Alibek Omarov
14eb07653c engine: client: fix incorrect format in error message in CL_SetLightStyle 2025-02-05 17:41:01 +03:00
Alibek Omarov
54b0cf9991 ref: gl: check OES NPOT texture extension in BigGL mode 2025-02-05 14:00:44 +03:00
Alibek Omarov
3ebcb08a97 ref: gl: add cvar r_large_lightmaps to enable larger lightmap sizes, opt-in, yields better performance with VBO renderer 2025-02-05 13:02:37 +03:00
Alibek Omarov
23940f8590 readme: remove fontconfig from dependencies list, we aren't using it anymore [skip ci] 2025-02-04 21:00:42 +03:00
Alibek Omarov
687fb0123f engine: implement basic gamepad gyroscope calibration
Called on game controller becoming active or by user request.
Exposes current calibration state by read-only console variable.
2025-02-03 13:14:51 +03:00
Alibek Omarov
6c91fdb0cd ref: gl: gl2_shim: fix int vs GLuint 2025-02-02 20:57:37 +03:00
Alibek Omarov
4832232fd6 ci: attempt to fix flatpak upload 2025-02-02 20:31:51 +03:00
Alibek Omarov
185bce0489 engine: common: remove unused D_ enum used for MsgDev in old engine. Make sure all enums and structs here are not anonymous 2025-02-02 20:26:07 +03:00
Alibek Omarov
f460aa63b0 engine: platform: posix: don't forget to print backtrace to stderr too 2025-02-02 19:20:54 +03:00
Alibek Omarov
22f8b6f9c3 engine: platform: enable crash handler for macOS 2025-02-02 18:30:41 +03:00
Alibek Omarov
0cb034afc2 engine: wscript: improve execinfo and GNU backtrace() check 2025-02-02 18:18:26 +03:00
Alibek Omarov
d0464ef602 engine: platform: posix: use glibc-based backtrace implementation for crash handling, if execinfo.h can be found 2025-02-02 18:06:18 +03:00
Alibek Omarov
c3ebb84b97 ci: bump SDL2 to 2.30.12 2025-02-02 08:14:24 +03:00
Alibek Omarov
11742efbc3 engine: fix player move on dedicated servers 2025-02-02 08:08:15 +03:00
Alibek Omarov
95af635ab4 engine: client: add command replaybufferdat to aid in debugging protocol errors by parsing buffer.dat 2025-02-02 05:22:46 +03:00
Alibek Omarov
1abec80191 engine: client: set codepage to 0 if con_charset value is unknown 2025-02-02 02:34:08 +03:00
Alibek Omarov
93ebddfba3 public: utflib: simplify Q_EncodeUTF8 2025-02-02 02:31:56 +03:00
Alibek Omarov
5378494199 wscript: enable main() function for Android port, which was forgotten after last refactoring 2025-02-01 18:26:20 +03:00
Alibek Omarov
1b44d7733e engine: platform: add improved Platform_Vibrate2 function, that allows to control vibration strength 2025-02-01 18:08:53 +03:00
Alibek Omarov
694c630b44 engine: zone: don't error when trying to free NULL pointer, like standard C free() and C++ delete 2025-02-01 17:51:02 +03:00
Alibek Omarov
7df1d4b9e2 engine: platform: sdl: remove useless for us game controller events 2025-01-31 19:48:33 +03:00
Alibek Omarov
b16037eabf engine: drop raw SDL joystick API, always use GameController instead. Implement actually working rumble, ensure we're freeing up all resources related to gamepads 2025-01-31 17:50:19 +03:00
Alibek Omarov
bff7299f9b gha: publish binaries even if flatpak fails 2025-01-31 10:37:41 +03:00
Alibek Omarov
de196b1c58 common: xash3d_types: avoid defining true and false in C23 2025-01-31 10:36:27 +03:00
Alibek Omarov
a0eec8b85d scripts: waifulib: add special_install_path for platform-specific executable formats that create post link stage (was nro_install_path) 2025-01-31 10:25:02 +03:00
Alibek Omarov
c7e8ea2ffa scripts: gha: linux: build smaller SDL2 (without 2D renderer) for Linux as well 2025-01-31 10:02:19 +03:00
Alibek Omarov
1c1cf3d646 scripts: waifulib: psvita: make sce_sys truly optional in apply_vpk 2025-01-31 10:02:19 +03:00
Alibek Omarov
9759b80b78 scripts: waifulib: psvita: set default title id and app name to just test 2025-01-31 09:10:39 +03:00
Alibek Omarov
94b2c0b443 scripts: gha: build render-less SDL2 for PSVita 2025-01-31 09:10:09 +03:00
Alibek Omarov
ff8d17a5a8 scripts: waifulib: psvita: add missing cprogram attributes 2025-01-31 09:04:40 +03:00
Alibek Omarov
aa23196a55 scripts: waifulib: support vpk and nro pass for pure C programs, just in case 2025-01-30 20:51:01 +03:00
Alibek Omarov
83b488c37e wscript: let building client and dedicated server in the same configuration 2025-01-30 20:23:12 +03:00
Alibek Omarov
77abf621d7 ref: gl: make GL_Support and GL_MaxTextureUnits functions inlined 2025-01-30 19:02:53 +03:00
Alibek Omarov
f9d4ac2771 ref: gl: fix ugly seam at the skybox, thanks Spoike for help 2025-01-30 18:53:31 +03:00
Alibek Omarov
f076d84975 engine: platform: android: move dlsym-weak hack from C++ to C 2025-01-30 18:07:35 +03:00
Alibek Omarov
faf0b32a94 ref: gl: fix massive frame drop caused by ripples code rendering same texture multiple times in the frame 2025-01-29 20:15:21 +03:00
Alibek Omarov
feb80e5997 engine: platform: sdl: read gamecontrollerdb.txt from extras.pk3 2025-01-29 13:43:10 +03:00
Alibek Omarov
578a77518f engine: client: fix clearing keyboard buttons caused by typical brain fart 2025-01-29 10:04:47 +03:00
Alibek Omarov
2457ecf226 filesystem: fix recursive basedir possible cyclic dependency when default game directory uses a basedir that's base directory is undefined
That could happen when default game directory depends on base directory that don't have gameinfo.txt.
Because all game directories with liblist.gam automatically have dependency on default game directory, it causes cyclic dependency.
2025-01-29 09:49:29 +03:00
Alibek Omarov
8cd99885f1 filesystem: clean added status for game folders when purging search paths 2025-01-29 09:46:18 +03:00
Alibek Omarov
684e229ac8 engine: client: get rid of absolutely useless bitfields 2025-01-26 23:34:04 +03:00
SNMetamorph
c0f1d8c647 engine: model: fixed incorrect check in Mod_LoadModel 2025-01-26 23:27:18 +03:00
SNMetamorph
c3b8696957 engine: platform: win32: disable initializing console in case of regular game startup 2025-01-26 23:02:24 +03:00
Tom Kidd
3ca413dbab Fixed path calc for extras on Mac 2025-01-26 22:25:08 +03:00
Alibek Omarov
92dc04ff3c engine: client: minor change, add forgotten newline in CL_DeltaEntityGS Host_Error call 2025-01-25 17:51:48 +03:00
Alibek Omarov
ad6db91285 engine: move xashid stuff onto client 2025-01-25 17:51:48 +03:00
David DeGraw
90a0f74087 undo change to mod link 2025-01-25 08:23:04 +03:00
David DeGraw
4f7f5288a1 more nits 2025-01-25 08:23:04 +03:00
David DeGraw
c23b4bfe61 nits 2025-01-25 08:23:04 +03:00
David DeGraw
4780f70ea2 Improve mod installation instructions
Also improved uplink setup and used a better source for mod files.
2025-01-25 08:23:04 +03:00
NightFox
98a04c7764 FIx Matrix*x4_LoadIdentity (xash3d_mathlib.h) 2025-01-25 08:21:21 +03:00
Alibek Omarov
7da9772143 engine: check for macOS bundle in SDL_GetBasePath, and fallback to SDL_GetPrefPath for our directory 2025-01-23 22:58:19 +03:00
Alibek Omarov
f0b29bac1b engine: client: add cl_trace_consistency used to print which resources server wants to check 2025-01-23 13:57:17 +03:00
Alibek Omarov
7b5ff606bd 3rdparty: extras: enable compression of extras.pk3 2025-01-23 13:08:53 +03:00
Alibek Omarov
3e22ee64ae scripts: waifulib: zip: add support for passing compression level on Python 3.7. Exclude PNG files from compression 2025-01-23 13:08:21 +03:00
Alibek Omarov
c86c45503f engine: replace few more Xash3D strings by XASH_ENGINE_NAME macro 2025-01-23 10:33:22 +03:00
Alibek Omarov
ef75a4c28d engine: rename pref path on Mac to Xash3D FWGS by allowing for custom branding through XASH_ENGINE_NAME macro 2025-01-23 10:24:55 +03:00
Alibek Omarov
bccd3f2271 engine: pass launcher's default game directory all the way down to Platform_Init, so we mount correct extras.pk3 on Mac 2025-01-23 10:22:53 +03:00
Tom Kidd
7bbc3e8238 Made modifications for Mac App Bundle
- Looks for game data in SDL pref path (Application Support)
- Sets XASH3D_EXTRAS_PAK1 to SDL base path (Resources dir in App Bundle
- Added option to force search for SDL dylib via pkgconfig on Darwin instead of Framework (option for Mac Source Ports build process)
2025-01-23 10:15:47 +03:00
Alibek Omarov
c34e0c66d9 engine: add fuzzing target for Mod_LoadModel 2025-01-23 10:12:32 +03:00
Alibek Omarov
e5d80878b8 scripts: waifulib: add asan-only build type 2025-01-23 10:11:56 +03:00
Alibek Omarov
1e075d25b7 engine: make LZSS compression optional for 49 protocol, disable it for local clients (singleplayer) 2025-01-22 21:18:19 +03:00
Alibek Omarov
d29e53481d engine: client: remove unused S_StreamAviSamples 2025-01-22 20:01:11 +03:00
Alibek Omarov
d23a2fd2df engine: client: stub AVI_StreamSound RenderAPI call, it is not used in ffmpeg-based video playback code 2025-01-22 20:00:50 +03:00
Alibek Omarov
f6f15cc204 engine: mod_studio: validate studio self-reported length before loading model 2025-01-22 20:00:13 +03:00
Alibek Omarov
4f2249ed8e ref: support loading sprites with truncated palette 2025-01-22 19:24:00 +03:00
Alibek Omarov
9f322df498 engine: imagelib: handle loading truncated palette files, by filling remaining bytes with zeros 2025-01-22 19:21:51 +03:00
Alibek Omarov
b554d7e215 ref: properly handle unloading sprites that aren't loaded completely 2025-01-22 19:20:20 +03:00
Alibek Omarov
719093c10b ref: properly return false to the engine if renderer refuses to load the model for some reason 2025-01-22 19:13:23 +03:00
Alibek Omarov
c2da140ccc engine: model: do not crash if renderer refused to load this model 2025-01-22 19:12:43 +03:00
Alibek Omarov
375998dffb Cleanup xash3d_types.h from engine-specific macros and types 2025-01-22 15:10:18 +03:00
Alibek Omarov
787444f63d engine: simplify sound fx allocation 2025-01-22 14:46:40 +03:00
Alibek Omarov
0c50076ff0 engine: zone: ensure poolcount is zero on Memory_Init 2025-01-22 13:49:51 +03:00
Alibek Omarov
8ce01c38c7 engine: http: ensure we don't write broken decompressed files 2025-01-22 13:49:24 +03:00
Alibek Omarov
cac6206984 engine: client: allocate everything related to sounds in the sound pool 2025-01-22 13:49:02 +03:00
Alibek Omarov
a5c88bdda9 engine: touch: allow smoother migration from old engine touch configs by stripping .tga extension 2025-01-22 13:40:47 +03:00
Alibek Omarov
fc017286a6 engine: base_cmd: slightly faster search based on assumption that list is always ordered 2025-01-22 05:41:52 +03:00
Alibek Omarov
20d4e3e719 engine: fix flexible array member usage in case of null terminated strings
(woops)
2025-01-22 05:41:52 +03:00
Alibek Omarov
4eaa32fc10 engine: whereami: sync with upstream 2025-01-21 20:03:20 +03:00
Alibek Omarov
b7c025b167 filesystem: android: request buffer for Android asset LoadFile implementation
Might be better than asking for random access and then only reading forward.
2025-01-21 19:50:14 +03:00
Alibek Omarov
f29c588e0f filesystem: take code from DarkPlaces to properly read compressed files 2025-01-21 18:47:42 +03:00
Alibek Omarov
2065ef143a engine: server: fix ent_create under PrimeXT 2025-01-21 16:09:56 +03:00
Alibek Omarov
a5c02c85f0 filesystem: wad: get rid of sentinel value at the end of wad_types array 2025-01-21 15:26:06 +03:00
Alibek Omarov
9a8761f1d8 engine: client: remove unused NetAPI_ValueForKey function 2025-01-21 15:17:03 +03:00
Alibek Omarov
273990d292 engine: cmd: store command description in flexible array member 2025-01-21 15:06:08 +03:00
Alibek Omarov
0e27d8717c ref: remove servercount from texture struct, Xash don't use it (and it's also harmful anyway) 2025-01-21 14:36:42 +03:00
Alibek Omarov
8a9b209db0 engine: zone: optimize memory usage a bit by compressing memheader_t better while keeping it efficient
It saves about 40 kilobytes of memory.
2025-01-21 14:04:33 +03:00
Alibek Omarov
232d1f8583 engine: make separate mempools for cmds, cvars and basecmd 2025-01-21 11:26:35 +03:00
Alibek Omarov
6cfa5877a4 engine: base_cmd: decrease base cmd hash size 2025-01-21 11:25:33 +03:00
Alibek Omarov
154df00f94 filesystem: don't create full path to rwdir, as cwd is always equal to rwdir
Fixes updating gameinfo.txt.
2025-01-20 19:53:04 +03:00
Alibek Omarov
c5649c94d5 engine: client: fix delta entity packet flush on GoldSrc protocol
Implement counting playerbytes for more accurate net_graph, even if we're
skipping this delta frame.
2025-01-20 19:38:44 +03:00
Alibek Omarov
a1da10fe38 filesystem: set default values for quick/autosave aged count 2025-01-20 16:06:57 +03:00
Andrey Akhmichin
17a71ffc96 ci: upgrade freebsd tasks. 2025-01-19 04:36:07 +03:00
Andrey Akhmichin
4609fbc0c5 Documentation: supported-mod-list.md: update links. 2025-01-19 04:35:17 +03:00
Andrey Akhmichin
d278d3bdd7 engine: common: fix clang build. 2025-01-19 04:33:06 +03:00
Alibek Omarov
7811b60292 engine: common: fix build for apple and freebsd-15 2025-01-18 10:40:12 +03:00
Alibek Omarov
870fad5606 public: tests: remove Q_colorstr tests 2025-01-18 10:36:11 +03:00
Alibek Omarov
3e93aa459d engine: net_buffer: turn bit write and read masks into predefined arrays, so we don't have to call InitMasks
In future, net_buffer might get moved to libpublic.

Also, get rid of 32-th bit write mask, it's only get used when we're trying to
write zero bits value which is nonsense.
2025-01-18 09:54:11 +03:00
Alibek Omarov
626c5e44f6 engine: client: use existing engine functions for some client API functions 2025-01-18 09:44:21 +03:00
Alibek Omarov
c906aa0106 ref: gl: make DrawGLPoly and R_TextureAnimation private to brush rendering code 2025-01-18 08:39:31 +03:00
Alibek Omarov
0a41b70e44 ref: gl: store ripple texture in texture's fb_texturenum as it's only used for water and water don't have luma 2025-01-18 08:38:43 +03:00
Alibek Omarov
ea338adc46 ref: gl: make GL_FrustumSetPlanme private to the frustum implementation 2025-01-18 08:34:25 +03:00
Alibek Omarov
5fa777578b ref: gl: fix detail texture leak, fix texture leak when texture have default texture set (in which case it still might have other textures set) 2025-01-18 08:33:20 +03:00
Alibek Omarov
5b9db5940b engine: mod_bmodel: don't try to load luma/fullbright texture for water, as no renderers support it anyway, and instead we will use that field for rippletexture 2025-01-18 08:30:59 +03:00
Alibek Omarov
4b1b3aa13c public: remove Q_colorstr, as it's completely useless and checking for color string is easy actually 2025-01-18 08:29:36 +03:00
Alibek Omarov
2d51d23d89 engine: client: don't send commands until ca_active on Xash protocol 2025-01-17 15:06:59 +03:00
Alibek Omarov
b5b6dad39c engine: fix a typo in scroll lock (missing L) 2025-01-15 23:49:13 +03:00
Alibek Omarov
a5619e9960 engine: take keydefs header from Quake-2 source code (client/keys.h) 2025-01-15 23:47:55 +03:00
Alibek Omarov
a75666a3cd engine: common: fix dedicated build by defining SV_GetMaxClients before CL_GetMaxClients stub (that redirects to it)
Also remove CL_Shutdown from dedicated stub lists.
2025-01-14 13:10:02 +03:00
Alibek Omarov
49426721d8 engine: use zero initializers instead of memset 2025-01-14 12:11:27 +03:00
Alibek Omarov
04125284a3 engine: dedicated: make some stubs inlined 2025-01-14 12:10:31 +03:00
Alibek Omarov
1d4f7b2f94 engine: server: slight refactoring, make SV_ModelHandle inlined, move PlayerIsFrozen to sv_client, fix packet loss data type 2025-01-14 12:09:23 +03:00
Alibek Omarov
38c82a3f76 engine: don't bother calculating crc32 for local clients for better performance (thanks @tyabus for the idea) 2025-01-14 11:55:28 +03:00
Alibek Omarov
785632a437 filesystem: minor refactoring in MD5_HashFile, use initializer instead of memset, limit buffer variable scope 2025-01-14 11:36:13 +03:00
Alibek Omarov
4be75af214 engine: client: always write buffer.dat so we will be able to request it from users. Append protocol number to it 2025-01-14 11:31:10 +03:00
Alibek Omarov
dcdca01e86 ref: gl: declare VBO globals static 2025-01-14 11:30:35 +03:00
Alibek Omarov
201d9c8f80 public: split VCS info to separate file for slightly better compilation speeds 2025-01-13 20:02:59 +03:00
Alibek Omarov
69341e36a3 public: expose commit and branch as global variables instead of functions 2025-01-13 20:02:59 +03:00
Alibek Omarov
3532a77643 public: move git commit and branch private to libpublic 2025-01-13 20:02:59 +03:00
Alibek Omarov
35dc072b26 filesystem: on Android, assume all paths are case-sensitive because doing Linux-specific ioctl check crashes FUSE driver and kills our app 2025-01-13 13:56:15 +03:00
Alibek Omarov
f92a3695b3 filesystem: fix fd leak in Platform_GetDirectoryCaseSensitivity 2025-01-13 13:54:42 +03:00
Alibek Omarov
a7b776f3b9 Revert "wscript: disable /showIncludes based msvcdeps for now, it causes issues with non-English locales"
Add option --enable-msvcdeps that we only enable on CI.

This reverts commit e58007aab3.
2025-01-10 21:48:43 +03:00
Alibek Omarov
f2fb668c9e android: now run exit() from Java side, as the next engine run is expected to be clean 2025-01-09 21:29:01 +03:00
Alibek Omarov
90e493fa3a engine: common: add Host_ExitInMain function that will force engine return from Host_Main() function, essentially making engine gracefully exit on Android
In future, this might be used everywhere, so users would be able to add custom
cleanup in some advanced game_launch implementation, on any platform.
2025-01-09 20:31:26 +03:00
Alibek Omarov
692bcc4073 engine: client: cl_tent: rewrite fizz effect, fix incorrect positoning along the way 2025-01-09 19:23:40 +03:00
Alibek Omarov
823642b10d readme: add link to ipa-reader.com for Xash word pronounciation [skip ci] 2025-01-09 17:13:56 +03:00
Alibek Omarov
07189ca2f5 engine: client: remove spammy message about not precached model on client side
Recently, mods (Brutal Half-Life v3 and MMod) started to call this function
every frame as a hacky way to detect presence of some model on the level. I
don't know why they do that, but users (who co-incidentally run engine with
-dev) has been complaining about console spam.

This is why we can't have things.
2025-01-09 17:10:54 +03:00
Alibek Omarov
0d55441830 engine: properly pass shutdown reason down to close log, helps to finally get rid of global finalmsg 2025-01-09 08:04:18 +03:00
Alibek Omarov
98ff33d9e2 engine: mod_bmodel: rewrite .lit file loader using normal stream io functions 2025-01-09 08:02:39 +03:00
Alibek Omarov
baa8fbaaec engine: mod_bmodel: fix misleading debug message telling about monochrome lighting when .lit file is used 2025-01-09 08:02:39 +03:00
Alibek Omarov
a0b46da04b engine: consolidate all box clipnodes used in studio models, pmove and server in a single place 2025-01-09 08:02:39 +03:00
Alibek Omarov
e70ba7ad64 engine: now, remove SUPPORT_BSP2_FORMAT macro, only prevent ref_soft from loading such maps 2025-01-09 08:02:39 +03:00
Alibek Omarov
8a41be9d47 engine: server: finally, make a union for large leaf indices in edict_t so we can run bsp2 maps without recompiling 2025-01-09 08:02:39 +03:00
Alibek Omarov
47aff9e30b engine: hack mnode_t struct so we can have 24-bit face and children indices to support BSP2 format in runtime 2025-01-09 08:02:39 +03:00
Alibek Omarov
ced8744ac9 engine: split edge struct into two with 16-bit indicies and 32-bit indicies to support BSP2 format in runtime 2025-01-08 14:46:07 +03:00
Alibek Omarov
734c07ddab engine: split clipnodes struct into two with 16-bit indicies and 32-bit indicies to support BSP2 format in runtime 2025-01-08 14:46:07 +03:00
Alibek Omarov
ceb603488a engine: platform: sdl: set up our custom log output function to catch all SDL errors in engine log file 2025-01-08 10:10:45 +03:00
Alibek Omarov
80bac157eb Update SDL to 2.30.11, use GitHub links for SDL, as it might be faster on Actions virtual machines 2025-01-08 09:42:53 +03:00
Alibek Omarov
b45581c630 Documentation: gameinfo: add a note about liblist.gam and gameinfo.txt changes 2025-01-08 01:22:23 +03:00
Alibek Omarov
d4fe3d6f8a filesystem: wscript: check d_type field in struct dirent, as this is an extension and some supported ports (like psvita) don't have it 2025-01-08 01:22:23 +03:00
Alibek Omarov
1907485895 filesystem: re-enable folder check for array returned by listdirectory with dirs_only set to true
According to glibc manual, not all filesystems support it and some might return DT_UNKNOWN.
2025-01-08 01:22:23 +03:00
Alibek Omarov
cfebb3e1d6 filesystem: massively rework how scanning game directories work
* No more conversion from liblist.gam to gameinfo.txt. We are using liblist.gam directly now.
  gameinfo.txt being native format to Xash3D not only remains, it takes priority over liblist.gam.
* Quake game directories now don't receive autogenerated gameinfo.txt.
* Empty directories don't get gameinfo.txt either, finally making it easier to support HD addon folders.
* If user still wishes to generate gameinfo.txt, there is now command fs_make_gameinfo that creates
  gameinfo.txt for currently running game.
* No more creating empty folders for RoDir. They are now created on demand.
2025-01-08 01:22:23 +03:00
Alibek Omarov
f9a0057c28 wscript: fix bsp2 build bruh 2025-01-08 01:22:23 +03:00
Alibek Omarov
ceb2b0c5e4 filesystem: add utility function FS_CheckForQuakePak that parses Quake PAK file and looks for specific files in it's root
Used to properly detect Quake game dirs.
2025-01-08 01:22:23 +03:00
Alibek Omarov
83b5edea88 engine: platform: sdl: clear key states on losing window focus 2025-01-06 16:38:16 +03:00
Alibek Omarov
9d2a85f11f engine: client: clear mouse state along with everything else in Key_ClearStates 2025-01-06 16:38:16 +03:00
Alibek Omarov
93d3df81ee engine: client: small refactoring and better explanation for char input handler for menus that don't query our extended API 2025-01-06 16:00:11 +03:00
Alibek Omarov
2a7f13151a engine: cmd: when command is already defined and has the same function pointer, show it as warning 2025-01-06 13:51:25 +03:00
Alibek Omarov
0c4f6ae61d engine: client: like GoldSrc, use cancelselect command for escape key. It is handled in client.dll and allows mods to override Esc key behavior 2025-01-06 13:51:25 +03:00
Andrey Akhmichin
b7150c3208 Documentation: opensource-mods.md: add "Earth Special Forces". 2025-01-02 05:35:33 +03:00
Alibek Omarov
d6ebff81e2 engine: client: vgui: track textures upload to avoid issues in buggy mods (that are probably will never get fixed) 2024-12-30 07:28:33 +03:00
Alibek Omarov
ce4148f351 engine: client: vgui: deprecate VGUI_CreateTexture and VGUI_UploadTextureBlock functions, as they never used by vgui_support module
* vgui_support used them in old engine for font cache, but we don't have that anymore.
2024-12-30 07:16:30 +03:00
Alibek Omarov
08c2632c14 engine: platform: nswitch: export _Unwind_GetIPInfo as required by cs16-client 2024-12-29 09:11:21 +03:00
Alibek Omarov
03eac904c1 public: make COM_FixSlashes inlined 2024-12-29 09:05:15 +03:00
Alibek Omarov
62f3354f4e mainui: update 2024-12-29 08:06:58 +03:00
Alibek Omarov
d5b6eff0c0 game_launch: fix --disable-menu-changegame by request 2024-12-29 08:06:50 +03:00
Alibek Omarov
c9ee844a24 scripts: gha: bundle SDL2 pdb file for better stacktraces on Windows 2024-12-29 02:08:05 +03:00
Alibek Omarov
687c9b004f engine: platform: sdl: set directsound as default audio driver on Windows, due to incompatibilities with mods 2024-12-29 02:01:23 +03:00
Alibek Omarov
14e79f04ac engine: prevent extra malloc in exec by checking if cfg already contains newline at EOL and appending it to cbuf if required 2024-12-28 16:03:49 +03:00
Alibek Omarov
5d6cf48687 engine: client: fix lightstyle timings on GoldSrc protocol, share the parser with Quake protocol handler 2024-12-28 01:40:59 +03:00
Alibek Omarov
88949a9ee6 engine: launcher: drop support for changing games from within internal launcher for platforms that do not have execv equivalent 2024-12-27 18:45:31 +03:00
Alibek Omarov
2d1e76199b engine: host: always print Host_Error text to log, even if console hasn't been enabled 2024-12-27 18:37:25 +03:00
Alibek Omarov
a5d78ecfd7 engine: be more verbose on why the engine is going to be shut down 2024-12-27 18:30:46 +03:00
Alibek Omarov
3576e474e6 engine: get rid of SendKeyEvents function, it only listened for WM_QUIT on Windows and we don't use that with SDL 2024-12-27 18:30:01 +03:00
Alibek Omarov
d50927f21f ref: gl: make r_ripple work with non-square non-pot textures, fix holes caused by unexpected transparency 2024-12-26 06:31:53 +03:00
Alibek Omarov
c6e3146290 ref: gl: fix broken water texture when it was discarded by R_UploadRipples 2024-12-26 03:49:12 +03:00
Alibek Omarov
9811988cce engine: server: set mapname globals field before making first call into DLL, as some mods tend to read it too early 2024-12-26 02:50:30 +03:00
Alibek Omarov
48bdd4238e engine: always include reason to server shutdown 2024-12-26 02:13:13 +03:00
Alibek Omarov
fd2b7e9197 engine: client: declare music command as overridable as the same command exists in HLU SDK 2024-12-26 01:16:48 +03:00
Alibek Omarov
0e42e5b9e3 engine: command: introduce new type of commands that can be overriden by a mod DLL for better compatibility 2024-12-26 01:15:32 +03:00
Alibek Omarov
65750f0cf3 engine: server: hack save fields that use types unsupported by Half-Life Unified SDK through array types 2024-12-26 00:36:28 +03:00
Alibek Omarov
6469b0a5f5 engine: common: shut up warn-unused-result on log write functions, only fetch system time for system logs when necessary 2024-12-24 11:27:34 +03:00
Alibek Omarov
4f98187e9a engine: move select-based stdin input function to platform/posix 2024-12-24 11:13:05 +03:00
Alibek Omarov
74c19a1557 engine: client: leave SDL2 client.dll detection for Windows only 2024-12-24 10:46:39 +03:00
Alibek Omarov
cfebee6ea8 engine: split crashhandler to win32 and posix versions 2024-12-24 10:37:49 +03:00
Alibek Omarov
bd0d6644e0 engine: move Sys_SendKeyEvents to platform/win32 2024-12-24 09:59:47 +03:00
Alibek Omarov
f41450127a Documentation: add note about pkg-config when compiling for Windows under Wine 2024-12-24 09:59:09 +03:00
Alibek Omarov
70897af362 public: add dll helpers to simplify basic interaction with exported functions lists 2024-12-23 04:43:15 +03:00
Alibek Omarov
f1d7101ad8 engine: client: get rid of NULL sentinels at the end of arrays 2024-12-22 07:43:26 +03:00
Alibek Omarov
ac9d960eef engine: common: get rid of NULL sentinels at the end of arrays 2024-12-22 07:22:10 +03:00
Alibek Omarov
0c471aecb1 engine: common: imagelib: get rid of NULL sentinels at the end of arrays 2024-12-22 07:21:06 +03:00
Alibek Omarov
72d0d70587 engine: server: get rid of NULL sentinels at the end of arrays 2024-12-22 07:12:32 +03:00
Alibek Omarov
bec526a77e utils: xar: fix xar build 2024-12-22 07:11:53 +03:00
Alibek Omarov
4d1119391a ref: gl: get rid of NULL sentinels at the end of arrays 2024-12-22 07:11:28 +03:00
Alibek Omarov
1dd622fcbb engine: client: keys: refactoring, remove NULL sentinels, make keys structs and few more functions private to keys.c file 2024-12-21 15:22:48 +03:00
Alibek Omarov
af4b64983a engine: fix a typo in Cmd_AddFilteredCommand flags passed to Cmd_AddCommandEx. Make them return Cmd_AddCommandEx value 2024-12-21 15:01:04 +03:00
Alibek Omarov
e751092555 engine: common: cmd: consider filtered buffer privileged when we're running local singleplayer game 2024-12-20 05:48:33 +03:00
Alibek Omarov
ce06b1d3d7 engine: client: allow CL_GetLocalPlayer to return NULL rather than halting whole server 2024-12-20 05:47:46 +03:00
Alibek Omarov
a834f4996f engine: move client adding functions to their appropriate subsystems and make them static. Make in-engine functions inlined. 2024-12-20 05:47:46 +03:00
Alibek Omarov
fdcf267fe3 engine: client: fix usermessage being removed because of case-sensitivity (message names are case-insensitive when transferred from server to client) 2024-12-20 03:05:14 +03:00
Alibek Omarov
7f2ebd1b5e engine: server: add command sv_list_messages to print all registered user messages 2024-12-20 02:37:38 +03:00
Alibek Omarov
68b2d9f269 engine: server: fix possible message number inconsistency if server requested it twice 2024-12-20 02:37:01 +03:00
Alibek Omarov
3f1eed9f59 engine: client: remove svc_goldsrc_* definitions for message that semantics matches Xash3D 49 protocol and instead use it's definitions 2024-12-20 01:51:24 +03:00
Alibek Omarov
0637dbaab1 engine: client: refactor and simplify CL_RegisterUserMessage 2024-12-20 01:51:24 +03:00
Alibek Omarov
85388e97c1 engine: client: add command cl_list_messages to print all registered user messages 2024-12-20 01:51:24 +03:00
Alibek Omarov
de961eb45e engine: client: use new extension for creating temporary files for demoheader 2024-12-19 07:10:02 +03:00
Alibek Omarov
3d60770b84 filesystem: add flag to open files in a RAM
On Linux, it uses memfd_create syscall that can be found on Linux 3.17 and
higher. By default memfds are executable, so we set MFD_NOEXEC_SEAL flag to
prevent execution at creation time.
2024-12-19 04:22:25 +03:00
Alibek Omarov
93c5853356 engine: server: merge SV_FindBestBaseline for normal entities and static entities into single function 2024-12-18 06:57:43 +03:00
Alibek Omarov
98e587285b engine: client: allocate static entities only when server sends static entity packet 2024-12-18 06:57:43 +03:00
Alibek Omarov
2aa13c8347 public: xash3d_mathlib: include string.h with memset definition 2024-12-17 21:58:42 +03:00
Alibek Omarov
53344771fd public: xash3d_mathlib: get rid of matrix identity global macros 2024-12-17 21:01:51 +03:00
Alibek Omarov
2373743920 public: mention FSF in copyright header, as some of the libc extensions callbacks were derived from glibc [skip ci] 2024-12-17 20:41:55 +03:00
Alibek Omarov
90a3497afe public: improve Q_strncat fallback implementation 2024-12-17 20:40:19 +03:00
Alibek Omarov
339aebb08c public: add Q_strnlen with fallback to memchr 2024-12-17 20:03:09 +03:00
Alibek Omarov
b4afe390d6 public: slight refactoring 2024-12-17 19:57:27 +03:00
Alibek Omarov
ca0c5f929a engine: slight refactoring of lightstyle handling functions 2024-12-17 17:04:26 +03:00
Alibek Omarov
48cc526c7e engine: client: fix possible svc_pings misparse by reading until null bit is encountered 2024-12-15 18:22:40 +03:00
203 changed files with 9324 additions and 7297 deletions

View File

@@ -1,10 +1,10 @@
task:
name: freebsd-14-amd64
freebsd_instance:
image_family: freebsd-14-0
image_family: freebsd-14-2
setup_script:
- pkg update
- pkg install -y pkgconf git sdl2 python fontconfig opus
- pkg install -y pkgconf git sdl2 python fontconfig libvorbis opusfile bzip2 libbacktrace
- git submodule update --init --recursive
test_script:
- ./scripts/cirrus/build_freebsd.sh dedicated
@@ -16,7 +16,7 @@ task:
image_family: freebsd-15-0-snap
setup_script:
- pkg update
- pkg install -y pkgconf git sdl2 python fontconfig opus
- pkg install -y pkgconf git sdl2 python fontconfig libvorbis opusfile bzip2 libbacktrace
- git submodule update --init --recursive
test_script:
- ./scripts/cirrus/build_freebsd.sh dedicated

View File

@@ -66,7 +66,7 @@ jobs:
targetos: apple
targetarch: amd64
env:
SDL_VERSION: 2.30.9
SDL_VERSION: 2.32.0
GH_CPU_ARCH: ${{ matrix.targetarch }}
GH_CROSSCOMPILING: ${{ matrix.cross }}
steps:
@@ -87,6 +87,7 @@ jobs:
path: artifacts/*
flatpak:
runs-on: ubuntu-latest
continue-on-error: true
strategy:
matrix:
include:
@@ -100,7 +101,7 @@ jobs:
with:
submodules: recursive
- name: Build flatpak (Compat.i386)
uses: FWGS/flatpak-github-actions/flatpak-builder@v6.3
uses: FWGS/flatpak-github-actions/flatpak-builder@v6.3-fix
with:
bundle: ${{ matrix.app }}.flatpak
manifest-path: scripts/flatpak/${{ matrix.app }}.yml
@@ -119,7 +120,6 @@ jobs:
--yes \
--cleanup-tag \
--repo "$GITHUB_REPOSITORY" || true
sleep 20s
gh run download "$GITHUB_RUN_ID" \
--dir artifacts/ \
--repo "$GITHUB_REPOSITORY"

9
.gitmodules vendored
View File

@@ -27,10 +27,13 @@
url = https://github.com/FWGS/MultiEmulator
[submodule "3rdparty/libogg/libogg"]
path = 3rdparty/libogg/libogg
url = https://gitlab.xiph.org/xiph/ogg.git
url = https://github.com/xiph/ogg.git
[submodule "3rdparty/vorbis/vorbis-src"]
path = 3rdparty/vorbis/vorbis-src
url = https://gitlab.xiph.org/xiph/vorbis.git
url = https://github.com/xiph/vorbis.git
[submodule "3rdparty/opusfile/opusfile"]
path = 3rdparty/opusfile/opusfile
url = https://gitlab.xiph.org/xiph/opusfile.git
url = https://github.com/xiph/opusfile.git
[submodule "3rdparty/libbacktrace/libbacktrace"]
path = 3rdparty/libbacktrace/libbacktrace
url = https://github.com/ianlancetaylor/libbacktrace

View File

@@ -25,5 +25,4 @@ def build(bld):
name = 'extras.pk3',
files = srcdir.ant_glob('**/*'),
relative_to = srcdir,
compresslevel = 0,
install_path = install_path)

185
3rdparty/libbacktrace/wscript vendored Normal file
View File

@@ -0,0 +1,185 @@
#! /usr/bin/env python
# encoding: utf-8
from waflib import TaskGen
FRAGMENT_ATOMIC='''int i;
int main(void) {
__atomic_load_n(&i, __ATOMIC_ACQUIRE);
__atomic_store_n(&i, 1, __ATOMIC_RELEASE);
return 0;
}'''
FRAGMENT_SYNC='''int i;
int main (void) {
__sync_bool_compare_and_swap (&i, i, i);
__sync_lock_test_and_set (&i, 1);
__sync_lock_release (&i);
return 0;
}'''
FRAGMENT_GETPAGESIZE='''#include <unistd.h>
int main(void) { return getpagesize() }'''
FRAGMENT_GETEXECNAME='''#include <stdlib.h>
int main(void) { return getexecname() != 0 }'''
FRAGMENT_STRNLEN='''#include <string.h>
int main(int argc, char **argv) { return (int)strnlen(argv[0], 10); }'''
FRAGMENT_DL_ITERATE_PHDR='''#include <%s>
int main(void) { return dl_iterate_phdr(0, 0); }'''
FRAGMENT_FCNTL='''#include <fcntl.h>
int main(void) { return fcntl(0, 0, 0); }'''
FRAGMENT_GETIPINFO='''#include "unwind.h"
struct _Unwind_Context *context;
int ip_before_insn = 0;
int main(void) { return _Unwind_GetIPInfo(context, &ip_before_insn); }'''
FRAGMENT_LOADQUERY='''#include <sys/ldr.h>
#include <sys/debug.h>
int main(void) { return loadquery(0, 0, 0); }'''
FRAGMENT_KERN_PROC='''#include <sys/sysctl.h>
#if !defined(%s) || !defined(KERN_PROC_PATHNAME)
#error
#endif
int main(void) { return 0; }'''
FRAGMENT_LSTAT='''#include <sys/stat.h>
struct stat st;
int main(int argc, char **argv) { return lstat(argv[0], &st); }'''
FRAGMENT_READLINK='''#include <unistd.h>
char buf[100];
int main(int argc, char **argv) { return readlink(argv[0], buf, sizeof(buf)); }'''
def options(opt):
pass
def configure(conf):
# add unsupported platforms here
if conf.env.DEST_OS in ['nswitch', 'psvita', 'dos']:
conf.env.DISABLE_LIBBACKTRACE = True
return
# win32 has it's own dbghelp-based backtrace, that's why we ship PDBs
if conf.env.COMPILER_CC == 'msvc':
conf.env.DISABLE_LIBBACKTRACE = True
return
if not conf.path.find_dir('libbacktrace') or not conf.path.find_dir('libbacktrace/config'):
conf.fatal('Can\'t find libbacktrace submodule. Run `git submodule update --init --recursive`.')
return
if conf.env.DEST_SIZEOF_VOID_P == 8:
conf.define('BACKTRACE_ELF_SIZE', 64)
conf.define('BACKTRACE_XCOFF_SIZE', 64)
else:
conf.define('BACKTRACE_ELF_SIZE', 32)
conf.define('BACKTRACE_XCOFF_SIZE', 32)
conf.define('_ALL_SOURCE', 1)
conf.define('_GNU_SOURCE', 1)
conf.define('_POSIX_PTHREAD_SEMANTICS', 1)
conf.define('_TANDEM_SOURCE', 1)
conf.define('__EXTENSIONS__', 1)
conf.define('_DARWIN_USE_64_BIT_INODE', 1)
conf.define('_LARGE_FILES', 1)
conf.check_large_file(compiler='c', execute=False, mandatory=False) # sets _FILE_OFFSET_BITS
conf.env.CFLAGS_EXTRAFLAGS = conf.filter_cflags(['-funwind-tables', '-g'], [])
if conf.filter_cflags(['-frandom-seed=test'], []):
conf.env.HAVE_FRANDOM_SEED = True
def check_header(hdr):
return {'header_name':hdr, 'msg':'... %s header' % hdr, 'mandatory':False, 'id':hdr}
conf.multicheck(
check_header('dlfcn.h'),
check_header('inttypes.h'),
check_header('link.h'),
check_header('sys/link.h'),
check_header('mach-o/dyld.h'),
check_header('memory.h'),
check_header('stdint.h'),
check_header('stdlib.h'),
check_header('strings.h'),
check_header('string.h'),
check_header('sys/ldr.h'),
check_header('sys/mman.h'),
check_header('sys/stat.h'),
check_header('sys/types.h'),
check_header('tlhelp32.h'),
check_header('unistd.h'),
check_header('windows.h'),
{'fragment':FRAGMENT_ATOMIC, 'msg':'... __atomic extensions', 'define_name':'HAVE_ATOMIC_FUNCTIONS', 'mandatory':False},
{'fragment':FRAGMENT_SYNC, 'msg':'... __sync extensions', 'define_name':'HAVE_SYNC_FUNCTIONS', 'mandatory':False},
{'fragment':FRAGMENT_GETPAGESIZE, 'msg':'... getpagesize function', 'define_name':'HAVE_DECL_GETPAGESIZE', 'mandatory':False},
{'fragment':FRAGMENT_STRNLEN, 'msg':'... strnlen function', 'define_name':'HAVE_DECL_STRNLEN', 'mandatory':False},
{'fragment':FRAGMENT_DL_ITERATE_PHDR % 'link.h', 'msg':'... dl_iterate_phdr function in link.h', 'define_name':'HAVE_DL_ITERATE_PHDR', 'after_tests': ['link.h'], 'mandatory':False},
{'fragment':FRAGMENT_DL_ITERATE_PHDR % 'sys/link.h', 'msg':'... dl_iterate_phdr function in sys/link.h', 'define_name':'HAVE_DL_ITERATE_PHDR', 'after_tests': ['sys/link.h'], 'mandatory':False},
{'fragment':FRAGMENT_FCNTL,'msg':'... fnctl function', 'define_name':'HAVE_FCNTL', 'mandatory':False},
{'fragment':FRAGMENT_GETEXECNAME,'msg':'... getexecname function','define_name':'HAVE_GETEXECNAME', 'mandatory':False},
{'fragment':FRAGMENT_GETIPINFO, 'msg':'... _Unwind_GetIPInfo function', 'define_name':'HAVE_GETIPINFO', 'mandatory':False},
{'fragment':FRAGMENT_KERN_PROC % 'KERN_PROC', 'msg': '... KERN_PROC and KERN_PROC_PATHNAME defines', 'define_name':'HAVE_KERN_PROC', 'mandatory':False},
{'fragment':FRAGMENT_KERN_PROC % 'KERN_PROC_ARGS', 'msg': '... KERN_PROC_ARGS and KERN_PROC_PATHNAME defines', 'define_name':'HAVE_KERN_PROC_ARGS', 'mandatory':False},
{'fragment':FRAGMENT_LOADQUERY, 'msg': '... loadquery function', 'define_name':'HAVE_LOADQUERY', 'mandatory':False},
{'fragment':FRAGMENT_LSTAT, 'msg': '... lstat function', 'define_name':'HAVE_LSTAT', 'mandatory':False},
{'fragment':FRAGMENT_READLINK, 'msg': '... readlink function', 'define_name':'HAVE_READLINK', 'mandatory':False},
# {'lib':'lzma', 'define_name':'HAVE_LIBLZMA', 'uselib_store':'lzma', 'msg':'... lzma library', 'mandatory':False},
# {'lib':'z', 'define_name':'HAVE_ZLIB', 'uselib_store':'z', 'msg':'... zlib library', 'mandatory':False},
# {'lib':'zstd', 'define_name':'HAVE_ZSTD', 'uselib_store':'zstd', 'msg':'... zstd library', 'mandatory':False},
msg='Checking for in parallel'
)
conf.write_config_header()
conf.define('BACKTRACE_SUPPORTED', 1)
conf.define('BACKTRACE_USES_MALLOC', 0)
conf.define('BACKTRACE_SUPPORTS_THREADS', 1)
conf.define('BACKTRACE_SUPPORTS_DATA', conf.env.DEST_BINFMT in ['elf', 'mac-o'])
conf.write_config_header('backtrace-supported.h')
@TaskGen.feature('frandomseed')
@TaskGen.after_method('propagate_uselib_vars')
def process_frandom_seed(ctx):
tasks = getattr(ctx, 'compiled_tasks', [])
for task in tasks:
out = task.outputs[0]
task.env.CFLAGS = list(task.env.CFLAGS) # need a copy
task.env.CFLAGS += ['-frandom-seed=%s' % out.path_from(out.ctx.bldnode)]
def build(bld):
if bld.env.DISABLE_LIBBACKTRACE:
return
# we specifically only want mmap-based allocators because calling malloc is not safe from signal handlers
sources = ['atomic.c', 'dwarf.c', 'fileline.c', 'posix.c', 'print.c', 'sort.c', 'state.c', 'backtrace.c', 'simple.c', 'mmap.c', 'mmapio.c']
if bld.env.DEST_BINFMT == 'pe':
sources += ['pecoff.c']
elif bld.env.DEST_BINFMT == 'mac-o':
sources += ['macho.c']
elif bld.env.DEST_BINFMT == 'elf':
sources += ['elf.c']
else:
sources += ['unknown.c']
task = bld.stlib(
source = ['libbacktrace/' + i for i in sources],
target = 'backtrace',
features = 'frandomseed' if bld.env.HAVE_FRANDOM_SEED else '',
use = 'EXTRAFLAGS lzma z zstd',
includes = '. libbacktrace/',
export_defines = 'HAVE_LIBBACKTRACE=1',
export_includes = 'libbacktrace/'
)

View File

@@ -5,5 +5,10 @@ This can be useful to test engine in Wine without using virtual machines or dual
0. Clone and install https://github.com/mstorsjo/msvc-wine (you can skip CMake part)
1. Set environment variable MSVC_WINE_PATH to the path to installed MSVC toolchain
2. Pre-load wine: `wineserver -k; wineserver -p; wine64 wineboot`
3. Run `./waf configure -T <build-type> --enable-wine-msvc --sdl2=../SDL2_VC`. Configuration step will take more time than usual.
3. Run `PKGCONFIG=/bin/false ./waf configure -T <build-type> --enable-wine-msvc --sdl2=../SDL2_VC`. Configuration step will take more time than usual.
4. .. other typical steps to build from console ...
> [!NOTE]
> Notice the usage of PKGCONFIG=/bin/false here. We're disabling pkg-config so we don't accidentally pull
> system-wide dependencies and force building them from source. In future builds we might set custom
> directory to pull dependencies from, like ffmpeg...

View File

@@ -85,6 +85,9 @@ These strings are specific to Xash3D FWGS.
As Xash3D accidentally supports GoldSrc games, it also supports parsing liblist.gam.\
Xash3D will use this file if gameinfo.txt is absent, or if its modification timestamp is older than liblist.gam.
> [!NOTE]
> Starting from January 2025, Xash3D FWGS doesn't automatically generate gameinfo.txt from liblist.gam. The key conversion table still remains but if you wish to use gameinfo.txt instead of liblist.gam, you can execute `fs_make_gameinfo` in console.
For game creators who plan supporting only Xash3D, using this file is not recommended.
The table below defines conversion rules from liblist.gam to gameinfo.txt. Some keys' interpretation does differ from `gameinfo.txt`, in this case a note will be left. If `liblist.gam` key isn't present in this table, it's ignored.

View File

@@ -6,7 +6,7 @@ For connecting to GoldSrc-based servers, use this command:
connect ip:port gs
```
But keep in mind, there are requirement for server to be able to accept connections from Xash3D-based clients: it should use Reunion or Dproto.
But keep in mind, there are requirement for server to be able to accept connections from Xash3D-based clients: it should use Reunion.
Without this requirement, you will just get "Steam validation rejected" error on connecting.
That is because proper authorization with Steam API is not implemented in engine yet (but we have plans on it).

View File

@@ -38,6 +38,12 @@ Uploaded to github by Oleg Cherkasky - https://github.com/gunrunners-paradise/Ct
## Deathmatch Classic
Available in Valve's Half-Life repository - https://github.com/ValveSoftware/halflife/tree/master/dmc
## Delta Particles
Available on ModDB - https://www.moddb.com/mods/half-life-delta/downloads/delta-particles-full-sources-maps-and-c-code
## Earth Special Forces
Alpha 2.0 - https://www.gamers-desire.de/details/2830
## ESHQ
Official github repository - https://github.com/adslbarxatov/xash3d-for-ESHQ

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,9 @@
# Xash3D FWGS Engine <img align="right" width="128" height="128" src="https://github.com/FWGS/xash3d-fwgs/raw/master/game_launch/icon-xash-material.png" alt="Xash3D FWGS icon" />
[![builds.sr.ht status](https://builds.sr.ht/~a1batross/xash3d-fwgs.svg)](https://builds.sr.ht/~a1batross/xash3d-fwgs?) [![GitHub Actions Status](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml/badge.svg)](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml) [![FreeBSD Build Status](https://img.shields.io/cirrus/github/FWGS/xash3d-fwgs?label=freebsd%20build)](https://cirrus-ci.com/github/FWGS/xash3d-fwgs) [![Discord Server](https://img.shields.io/discord/355697768582610945.svg)](http://fwgsdiscord.mentality.rip/) \
[![Download Stable](https://img.shields.io/badge/download-stable-yellow)](https://github.com/FWGS/xash3d-fwgs/releases/latest) [![Download Testing](https://img.shields.io/badge/downloads-testing-orange)](https://github.com/FWGS/xash3d-fwgs/releases/tag/continuous)
[![GitHub Actions Status](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml/badge.svg)](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml) [![FreeBSD Build Status](https://img.shields.io/cirrus/github/FWGS/xash3d-fwgs?label=freebsd%20build)](https://cirrus-ci.com/github/FWGS/xash3d-fwgs) \
[![Discord Server](https://img.shields.io/discord/355697768582610945?logo=Discord&label=International%20Discord%20chat)](http://fwgsdiscord.mentality.rip/) [![Russian speakers Telegram Chat](https://img.shields.io/badge/Russian_speakers_Telegram_chat-gray?logo=Telegram)](https://t.me/flyingwithgauss) \
[![Download Daily Build](https://img.shields.io/badge/downloads-testing-orange)](https://github.com/FWGS/xash3d-fwgs/releases/tag/continuous)
Xash3D (pronounced `[ksɑʂ]`) FWGS is a game engine, aimed to provide compatibility with Half-Life Engine and extend it, as well as to give game developers well known workflow.
Xash3D ([pronounced](https://ipa-reader.com/?text=ks%C9%91%CA%82) `[ksɑʂ]`) FWGS is a game engine, aimed to provide compatibility with Half-Life Engine and extend it, as well as to give game developers well known workflow.
Xash3D FWGS is a heavily modified fork of an original [Xash3D Engine](https://www.moddb.com/engines/xash3d-engine) by Unkle Mike.
@@ -65,21 +66,21 @@ This repository contains our fork of HLSDK and restored source code for Half-Lif
* Only for 32-bit engine on 64-bit x86 operating system:
* Enable i386 on your system: `$ sudo dpkg --add-architecture i386`.
* Install `aptitude` ([why?](https://github.com/FWGS/xash3d-fwgs/issues/1828#issuecomment-2415131759)): `$ sudo apt update && sudo apt upgrade && sudo apt install aptitude`
* Install development tools: `$ sudo aptitude --without-recommends install git build-essential gcc-multilib g++-multilib libsdl2-dev:i386 libfontconfig-dev:i386 libfreetype-dev:i386 libopus-dev:i386 libbz2-dev:i386`.
* Install development tools: `$ sudo aptitude --without-recommends install git build-essential gcc-multilib g++-multilib libsdl2-dev:i386 libfreetype-dev:i386 libopus-dev:i386 libbz2-dev:i386 libvorbis-dev:i386 libopusfile-dev:i386 libogg-dev:i386`.
* Set PKG_CONFIG_PATH environment variable to point at 32-bit libraries: `$ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig`.
* For 64-bit engine on 64-bit x86 and other non-x86 systems:
* Install development tools: `$ sudo apt install git build-essential python libsdl2-dev libfontconfig-dev libfreetype6-dev libopus-dev libbz2-dev`.
* Install development tools: `$ sudo apt install git build-essential python libsdl2-dev libfreetype6-dev libopus-dev libbz2-dev libvorbis-dev libopusfile-dev libogg-dev`.
* Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`.
##### RedHat/Fedora
* Only for 32-bit engine on 64-bit x86 operating system:
* Install development tools: `$ sudo dnf install git gcc gcc-c++ glibc-devel.i686 SDL2-devel.i686 opus-devel.i686 fontconfig-devel.i686 freetype-devel.i686 bzip2-devel.i686`.
* Install development tools: `$ sudo dnf install git gcc gcc-c++ glibc-devel.i686 SDL2-devel.i686 opus-devel.i686 freetype-devel.i686 bzip2-devel.i686 libvorbis-devel.i686 opusfile-devel.i686 libogg-devel.i686`.
* Set PKG_CONFIG_PATH environment variable to point at 32-bit libraries: `$ export PKG_CONFIG_PATH=/usr/lib/pkgconfig`.
* For 64-bit engine on 64-bit x86 and other non-x86 systems:
* Install development tools: `$ sudo dnf install git gcc gcc-c++ SDL2-devel opus-devel fontconfig-devel freetype-devel bzip2-devel`.
* Install development tools: `$ sudo dnf install git gcc gcc-c++ SDL2-devel opus-devel freetype-devel bzip2-devel libvorbis-devel opusfile-devel libogg-devel`.
* Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`.

View File

@@ -1,49 +1,39 @@
cmake_minimum_required(VERSION 3.6)
cmake_minimum_required(VERSION 3.22)
# Only used to build Android project
project(XASH_ANDROID)
# armeabi-v7a requires cpufeatures library
include(AndroidNdkModules)
android_ndk_import_module_cpufeatures()
if(ANDROID)
include_directories(${ANDROID_NDK}/sources/android/cpufeatures)
add_library(cpufeatures ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c)
target_link_libraries(cpufeatures dl)
endif()
find_package(PythonInterp 2.7 REQUIRED)
get_filename_component(C_COMPILER_ID ${CMAKE_C_COMPILER} NAME_WE)
get_filename_component(CXX_COMPILER_ID ${CMAKE_CXX_COMPILER} NAME_WE)
include(FindPython)
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
set(BUILD_TYPE "debug")
else()
set(BUILD_TYPE "release")
list(APPEND WAF_EXTRA_ARGS --enable-poly-opt --enable-lto)
list(APPEND WAF_EXTRA_ARGS --enable-poly-opt --enable-lto --enable-limited-debuginfo)
endif()
if(CMAKE_SIZEOF_VOID_P MATCHES "8")
set(64BIT ON CACHE BOOL "" FORCE)
list(APPEND WAF_EXTRA_ARGS -8) # only required for x86 when testing this cmakelist under linux
if(ANDROID_ABI STREQUAL "x86")
# HACKHACK: I don't know why but engine gets built as 64-bit binary here
list(APPEND WAF_EXTRA_ARGS -4)
endif()
set(CMAKE_VERBOSE_MAKEFILE ON)
set(WAF_CC "${CMAKE_C_COMPILER} --target=${CMAKE_C_COMPILER_TARGET}")
set(WAF_CXX "${CMAKE_CXX_COMPILER} --target=${CMAKE_CXX_COMPILER_TARGET}")
# not cleanest way to get upper directory
set(ENGINE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../")
execute_process(
COMMAND ${CMAKE_COMMAND} -E env
CC=${WAF_CC} CXX=${WAF_CXX}
AR=${CMAKE_AR} STRIP=${CMAKE_STRIP}
${PYTHON_EXECUTABLE} waf configure -T ${BUILD_TYPE} ${WAF_EXTRA_ARGS} cmake
--check-c-compiler=${C_COMPILER_ID} --check-cxx-compiler=${CXX_COMPILER_ID}
-s "${ENGINE_SOURCE_DIR}/SDL" --skip-sdl2-sanity-check --enable-bundled-deps
WORKING_DIRECTORY "${ENGINE_SOURCE_DIR}"
)
add_subdirectory("${ENGINE_SOURCE_DIR}/3rdparty/hlsdk-portable" hlsdk-portable)
set(WAF_CC "${CMAKE_C_COMPILER} --target=${CMAKE_C_COMPILER_TARGET}")
set(WAF_CXX "${CMAKE_CXX_COMPILER} --target=${CMAKE_CXX_COMPILER_TARGET}")
set(WAF ${Python_EXECUTABLE} ${ENGINE_SOURCE_DIR}waf -t ${ENGINE_SOURCE_DIR} -o ${CMAKE_CURRENT_BINARY_DIR}/xash3d-fwgs)
# try to build minimal SDL. Enable features as we're gonna use them
set(SDL_RENDER OFF)
@@ -56,5 +46,50 @@ set(SDL_VULKAN OFF)
set(SDL_OFFSCREEN OFF)
set(SDL_STATIC OFF)
add_subdirectory("${ENGINE_SOURCE_DIR}/3rdparty/SDL" SDL)
add_subdirectory("${ENGINE_SOURCE_DIR}/" xash3d-fwgs)
add_subdirectory("${ENGINE_SOURCE_DIR}/3rdparty/mainui" mainui)
include(ExternalProject)
# gradle passes backslashes to cmake, how does this even work for everybody else?
string(REPLACE "\\" "/" CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
ExternalProject_Add(
Xash3DFWGS
SOURCE_DIR ${ENGINE_SOURCE_DIR}
INSTALL_DIR ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
BUILD_IN_SOURCE TRUE
DEPENDS SDL2
BUILD_ALWAYS TRUE
LOG_CONFIGURE TRUE
LOG_BUILD TRUE
LOG_INSTALL TRUE
LOG_OUTPUT_ON_FAILURE TRUE
LOG_MERGED_STDOUTERR TRUE
# USES_TERMINAL_CONFIGURE TRUE
# USES_TERMINAL_BUILD TRUE
# USES_TERMINAL_INSTALL TRUE
# NOTE: setting up WAFLOCK is important to avoid possible race conditions
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env
ANDROID_NDK=${ANDROID_NDK}
BUILD_CMAKE_LIBRARY_OUTPUT_DIRECTORY=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
WAFLOCK=.lock-waf_android_${ANDROID_ABI}_build
${WAF} configure -T ${BUILD_TYPE} --android=${ANDROID_ABI},,${CMAKE_SYSTEM_VERSION}
-s "${ENGINE_SOURCE_DIR}/3rdparty/SDL" --enable-bundled-deps ${WAF_EXTRA_ARGS}
BUILD_COMMAND ${CMAKE_COMMAND} -E env
WAFLOCK=.lock-waf_android_${ANDROID_ABI}_build
${WAF} build -v
INSTALL_COMMAND ${CMAKE_COMMAND} -E env
WAFLOCK=.lock-waf_android_${ANDROID_ABI}_build
${WAF} install --destdir=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
)
add_subdirectory("${ENGINE_SOURCE_DIR}/3rdparty/hlsdk-portable" hlsdk-portable)
# a1ba: without this, xash3d target will be ignored as nothing depends on it
add_dependencies(client Xash3DFWGS)
add_dependencies(server Xash3DFWGS)

View File

@@ -9,7 +9,7 @@ plugins {
android {
namespace = "su.xash.engine"
ndkVersion = "27.2.12479018"
ndkVersion = "28.0.13004108"
defaultConfig {
applicationId = "su.xash"
@@ -96,6 +96,7 @@ android {
packaging {
jniLibs {
useLegacyPackaging = true
keepDebugSymbols.add("**/*.so")
}
}
}
@@ -112,7 +113,7 @@ dependencies {
implementation("androidx.preference:preference-ktx:1.2.1")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.work:work-runtime-ktx:2.9.0")
// implementation "androidx.legacy:legacy-support-v4:1.0.0"
// implementation "androidx.legacy:legacy-support-v4:1.0.0"
implementation("com.madgag.spongycastle:prov:1.58.0.0")
implementation("in.dragonbra:javasteam:1.2.0")

View File

@@ -30,6 +30,18 @@ public class XashActivity extends SDLActivity {
AndroidBug5497Workaround.assistActivity(this);
}
@Override
public void onDestroy()
{
super.onDestroy();
// Now that we don't exit from native code, we need to exit here, resetting
// application state (actually global variables that we don't cleanup on exit)
//
// When the issue with global variables will be resolved, remove that exit() call
System.exit(0);
}
@Override
protected String[] getLibraries() {
return new String[]{"SDL2", "xash"};

View File

@@ -20,4 +20,7 @@ kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
android.nonTransitiveRClass=true
# Enable verbose output for CMake
android.native.buildOutput=verbose

View File

@@ -16,8 +16,6 @@ GNU General Public License for more details.
#ifndef BSPFILE_H
#define BSPFILE_H
//#define SUPPORT_BSP2_FORMAT // allow to loading Darkplaces BSP2 maps (with broke binary compatibility)
/*
==============================================================================
@@ -65,7 +63,6 @@ BRUSH MODELS
#define MAX_MAP_CLIPNODES_BSP2 524288
// these limis not using by modelloader but only for displaying 'mapstats' correctly
#ifdef SUPPORT_BSP2_FORMAT
#define MAX_MAP_MODELS 2048 // embedded models
#define MAX_MAP_ENTSTRING 0x200000 // 2 Mb should be enough
#define MAX_MAP_PLANES 131072 // can be increased without problems
@@ -75,18 +72,6 @@ BRUSH MODELS
#define MAX_MAP_VERTS 524288 // can be increased without problems
#define MAX_MAP_FACES 262144 // can be increased without problems
#define MAX_MAP_MARKSURFACES 524288 // can be increased without problems
#else
// increased to match PrimeXT compilers
#define MAX_MAP_MODELS 1024 // embedded models
#define MAX_MAP_ENTSTRING 0x100000 // 1 Mb should be enough
#define MAX_MAP_PLANES 65536 // can be increased without problems
#define MAX_MAP_NODES 32767 // because negative shorts are leafs
#define MAX_MAP_CLIPNODES MAX_MAP_CLIPNODES_HLBSP // because negative shorts are contents
#define MAX_MAP_LEAFS 32767 // signed short limit
#define MAX_MAP_VERTS 65535 // unsigned short limit
#define MAX_MAP_FACES 65535 // unsigned short limit
#define MAX_MAP_MARKSURFACES 65535 // unsigned short limit
#endif
#define MAX_MAP_ENTITIES 8192 // network limit
#define MAX_MAP_TEXINFO MAX_MAP_FACES // in theory each face may have personal texinfo

View File

@@ -60,26 +60,29 @@ typedef struct
vec3_t position;
} mvertex_t;
typedef struct
typedef struct mclipnode32_s
{
int planenum;
#ifdef SUPPORT_BSP2_FORMAT
int children[2]; // negative numbers are contents
#else
short children[2]; // negative numbers are contents
#endif
} mclipnode_t;
int planenum;
int children[2]; // negative numbers are contents
} mclipnode32_t;
typedef struct mclipnode16_s
{
int planenum;
short children[2]; // negative numbers are contents
} mclipnode16_t;
// size is matched but representation is not
typedef struct
typedef struct medge32_s
{
#ifdef SUPPORT_BSP2_FORMAT
unsigned int v[2];
#else
} medge32_t;
typedef struct medge16_s
{
unsigned short v[2];
unsigned int cachededgeoffset;
#endif
} medge_t;
} medge16_t;
typedef struct texture_s
{
@@ -156,13 +159,31 @@ typedef struct mnode_s
// node specific
mplane_t *plane;
struct mnode_s *children[2];
#ifdef SUPPORT_BSP2_FORMAT
int firstsurface;
int numsurfaces;
#if !XASH_64BIT
union
{
struct mnode_s *children_[2];
struct
{
// the ordering is important
int child_0_leaf : 1;
int child_0_off : 23;
int firstsurface_1 : 8;
int child_1_leaf : 1;
int child_1_off : 23;
int numsurfaces_1 : 8;
};
};
unsigned short firstsurface_0;
unsigned short numsurfaces_0;
#else
unsigned short firstsurface;
unsigned short numsurfaces;
// in 64-bit ABI this struct has 4 more bytes of padding, let's use it!
struct mnode_s *children_[2];
unsigned short firstsurface_0;
unsigned short numsurfaces_0;
unsigned short firstsurface_1;
unsigned short numsurfaces_1;
#endif
} mnode_t;
@@ -203,7 +224,6 @@ typedef struct mleaf_s
int nummarksurfaces;
int cluster; // helper to acess to uncompressed visdata
byte ambient_sound_level[NUM_AMBIENTS];
} mleaf_t;
// surface extradata
@@ -291,7 +311,11 @@ struct msurface_s
typedef struct hull_s
{
mclipnode_t *clipnodes;
union
{
mclipnode16_t *clipnodes16;
mclipnode32_t *clipnodes32;
};
mplane_t *planes;
int firstclipnode;
int lastclipnode;
@@ -341,7 +365,12 @@ typedef struct model_s
mvertex_t *vertexes;
int numedges;
medge_t *edges;
union
{
medge16_t *edges16;
medge32_t *edges32;
};
int numnodes;
mnode_t *nodes;
@@ -356,7 +385,11 @@ typedef struct model_s
int *surfedges;
int numclipnodes;
mclipnode_t *clipnodes;
union
{
mclipnode16_t *clipnodes16;
mclipnode32_t *clipnodes32;
};
int nummarksurfaces;
msurface_t **marksurfaces;
@@ -550,16 +583,68 @@ typedef struct
#define ANIM_CYCLE 2
#define MOD_FRAMES 20
#define MAX_DEMOS 32
#define MAX_MOVIES 8
#define MAX_CDTRACKS 32
#define MAX_CLIENT_SPRITES 512 // SpriteTextures (0-256 hud, 256-512 client)
#define MAX_REQUESTS 64
STATIC_CHECK_SIZEOF( mnode_t, 52, 72 );
STATIC_CHECK_SIZEOF( mextrasurf_t, 324, 496 );
STATIC_CHECK_SIZEOF( decal_t, 60, 88 );
STATIC_CHECK_SIZEOF( mfaceinfo_t, 176, 304 );
// model flags (stored in model_t->flags)
#define MODEL_QBSP2 BIT( 28 ) // uses 32-bit types
// access functions
static inline mnode_t *node_child( const mnode_t *n, int side, const model_t *mod )
{
#if !XASH_64BIT
if( unlikely( mod->flags & MODEL_QBSP2 )) // MODEL_QBSP2
{
if( side == 0 )
{
if( n->child_0_leaf )
return (mnode_t *)(mod->leafs + n->child_0_off);
else
return (mnode_t *)(mod->nodes + n->child_0_off);
}
else
{
if( n->child_1_leaf )
return (mnode_t *)(mod->leafs + n->child_1_off);
else
return (mnode_t *)(mod->nodes + n->child_1_off);
}
}
return n->children_[side];
#else
return n->children_[side];
#endif
}
static inline void node_children( mnode_t *children[2], const mnode_t *n, const model_t *mod )
{
children[0] = node_child( n, 0, mod );
children[1] = node_child( n, 1, mod );
}
static inline int node_firstsurface( const mnode_t *n, const model_t *mod )
{
if( mod->flags & MODEL_QBSP2 )
return n->firstsurface_0 + ( n->firstsurface_1 << 16 );
else
return n->firstsurface_0;
}
static inline int node_numsurfaces( const mnode_t *n, const model_t *mod )
{
if( mod->flags & MODEL_QBSP2 )
return n->numsurfaces_0 + ( n->numsurfaces_1 << 16 );
else
return n->numsurfaces_0;
}
#endif//COM_MODEL_H

View File

@@ -28,7 +28,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define PORT_ANY -1
typedef enum {NA_LOOPBACK = 1, NA_BROADCAST, NA_IP, NA_IPX, NA_BROADCAST_IPX, NA_IP6, NA_MULTICAST_IP6} netadrtype_t;
typedef enum netadrtype_e
{
NA_UNDEFINED = 0,
NA_LOOPBACK,
NA_BROADCAST,
NA_IP,
NA_IPX,
NA_BROADCAST_IPX,
NA_IP6,
NA_MULTICAST_IP6
} netadrtype_t;
/*
Original Quake-2 structure:
@@ -46,29 +56,60 @@ typedef struct
#pragma pack( push, 1 )
typedef struct netadr_s
{
// the reason we do this evil thing, is that when this struct contains IPv6
// address the `type` is 2-byte wide, but when it doesn't `type` must 4-byte
// wide _and_ ip6_0 must be zeroed, to keep it binary compatible.
#if XASH_LITTLE_ENDIAN
uint16_t type;
uint8_t ip6_0[2];
#elif XASH_BIG_ENDIAN
uint8_t ip6_0[2];
uint16_t type;
#else
#error
#endif
union
{
// IPv6 struct
uint8_t ip6_1[14];
struct
{
uint16_t type6;
uint8_t ip6[16];
};
struct
{
uint32_t type; // must be netadrtype_t but will break with short enums
union
{
uint8_t ip[4];
uint32_t ip4; // for easier conversions
uint8_t ip[4];
uint32_t ip4; // for easier conversions
};
uint8_t ipx[10];
};
};
uint16_t port;
uint16_t port;
} netadr_t;
#pragma pack( pop )
static inline netadrtype_t NET_NetadrType( const netadr_t *a )
{
if( a->type == NA_IP6 || a->type == NA_MULTICAST_IP6 )
return (netadrtype_t)a->type;
if( a->ip6_0[0] || a->ip6_0[1] )
return NA_UNDEFINED;
return (netadrtype_t)a->type;
}
static inline void NET_NetadrSetType( netadr_t *a, netadrtype_t type )
{
if( type == NA_IP6 || type == NA_MULTICAST_IP6 )
{
a->type = type;
return;
}
a->ip6_0[0] = a->ip6_0[1] = 0;
a->type = type;
}
STATIC_CHECK_SIZEOF( netadr_t, 20, 20 );
#endif // NET_ADR_H

View File

@@ -86,8 +86,4 @@ GNU General Public License for more details.
#include <string.h>
#include <limits.h>
#if defined XASH_SDL && !defined REF_DLL
#include <SDL.h>
#endif
#endif // PORT_H

View File

@@ -13,47 +13,44 @@
#endif // _WIN32
#include <sys/types.h> // off_t
#ifdef STDINT_H
#include STDINT_H
#else // !STDINT_H
#include <stdint.h>
#endif // !STDINT_H
#include <assert.h>
typedef unsigned char byte;
typedef int sound_t;
typedef float vec_t;
typedef vec_t vec2_t[2];
typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4];
typedef vec_t quat_t[4];
typedef byte rgba_t[4]; // unsigned byte colorpack
typedef byte rgb_t[3]; // unsigned byte colorpack
typedef vec_t matrix3x4[3][4];
typedef vec_t matrix4x4[4][4];
typedef uint32_t poolhandle_t;
typedef uint8_t byte;
typedef float vec_t;
typedef vec_t vec2_t[2];
#ifndef vec3_t // SDK renames it to Vector
typedef vec_t vec3_t[3];
#endif
typedef vec_t vec4_t[4];
typedef vec_t quat_t[4];
typedef byte rgba_t[4]; // unsigned byte colorpack
typedef byte rgb_t[3]; // unsigned byte colorpack
typedef vec_t matrix3x4[3][4];
typedef vec_t matrix4x4[4][4];
typedef uint32_t poolhandle_t;
#undef true
#undef false
#ifndef __cplusplus
typedef enum { false, true } qboolean;
#else
typedef int qboolean;
// true and false are keywords in C++ and C23
#if !__cplusplus && __STDC_VERSION__ < 202311L
enum { false, true };
#endif
typedef int qboolean;
typedef uint64_t longtime_t;
#define MAX_STRING 256 // generic string
#define MAX_INFO_STRING 256 // infostrings are transmitted across network
#define MAX_SERVERINFO_STRING 512 // server handles too many settings. expand to 1024?
#define MAX_LOCALINFO_STRING 32768 // localinfo used on server and not sended to the clients
#define MAX_SYSPATH 1024 // system filepath
#define MAX_VA_STRING 1024 // string length returned by va()
#define MAX_PRINT_MSG 8192 // how many symbols can handle single call of Con_Printf or Con_DPrintf
#define MAX_TOKEN 2048 // parse token length
#define MAX_MODS 512 // environment games that engine can keep visible
#define MAX_USERMSG_LENGTH 2048 // don't modify it's relies on a client-side definitions
#define MAX_STRING 256 // generic string
#define MAX_VA_STRING 1024 // compatibility macro
#define MAX_SYSPATH 1024 // system filepath
#define MAX_MODS 512 // environment games that engine can keep visible
#define BIT( n ) ( 1U << ( n ))
#define BIT64( n ) ( 1ULL << ( n ))
#define SetBits( iBitVector, bits ) ((iBitVector) = (iBitVector) | (bits))
#define ClearBits( iBitVector, bits ) ((iBitVector) = (iBitVector) & ~(bits))
#define FBitSet( iBitVector, bit ) ((iBitVector) & (bit))
@@ -70,6 +67,8 @@ typedef uint64_t longtime_t;
#define IsColorString( p ) ( p && *( p ) == '^' && *(( p ) + 1) && *(( p ) + 1) >= '0' && *(( p ) + 1 ) <= '9' )
#define ColorIndex( c ) ((( c ) - '0' ) & 7 )
#undef EXPORT
#if defined( __GNUC__ )
#if defined( __i386__ )
#define EXPORT __attribute__(( visibility( "default" ), force_align_arg_pointer ))
@@ -209,34 +208,16 @@ _inline float LittleFloat( float f )
#endif
typedef unsigned int dword;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef char string[MAX_STRING];
typedef struct file_s file_t; // normal file
typedef struct stream_s stream_t; // sound stream for background music playing
typedef off_t fs_offset_t;
typedef unsigned int dword;
typedef unsigned int uint;
typedef char string[MAX_STRING];
typedef off_t fs_offset_t;
#if XASH_WIN32
typedef int fs_size_t; // return type of _read, _write funcs
typedef int fs_size_t; // return type of _read, _write funcs
#else /* !XASH_WIN32 */
typedef ssize_t fs_size_t;
typedef ssize_t fs_size_t;
#endif /* !XASH_WIN32 */
typedef struct dllfunc_s
{
const char *name;
void **func;
} dllfunc_t;
typedef struct dll_info_s
{
const char *name; // name of library
const dllfunc_t *fcts; // list of dll exports
qboolean crash; // crash if dll not found
void *link; // hinstance of loading library
} dll_info_t;
typedef void (*setpair_t)( const char *key, const void *value, const void *buffer, void *numpairs );
typedef void *(*pfnCreateInterface_t)( const char *, int * );
// config strings are a general means of communication from

View File

@@ -30,10 +30,9 @@ static dllfunc_t msvfw_funcs[] =
{ "DrawDibOpen", (void **) &pDrawDibOpen },
{ "DrawDibDraw", (void **) &pDrawDibDraw },
{ "DrawDibClose", (void **) &pDrawDibClose },
{ NULL, NULL }
};
dll_info_t msvfw_dll = { "msvfw32.dll", msvfw_funcs, false };
dll_info_t msvfw_dll = { "msvfw32.dll", msvfw_funcs, ARRAYSIZE( msvfw_funcs ), false };
// msacm32.dll exports
static MMRESULT (_stdcall *pacmStreamOpen)( LPHACMSTREAM, HACMDRIVER, LPWAVEFORMATEX, LPWAVEFORMATEX, LPWAVEFILTER, DWORD, DWORD, DWORD );
@@ -51,10 +50,9 @@ static dllfunc_t msacm_funcs[] =
{ "acmStreamConvert", (void **) &pacmStreamConvert },
{ "acmStreamSize", (void **) &pacmStreamSize },
{ "acmStreamClose", (void **) &pacmStreamClose },
{ NULL, NULL }
};
dll_info_t msacm_dll = { "msacm32.dll", msacm_funcs, false };
dll_info_t msacm_dll = { "msacm32.dll", msacm_funcs, ARRAYSIZE( msacm_funcs ), false };
// avifil32.dll exports
static int (_stdcall *pAVIStreamInfo)( PAVISTREAM pavi, AVISTREAMINFO *psi, LONG lSize );
@@ -88,10 +86,9 @@ static dllfunc_t avifile_funcs[] =
{ "AVIStreamRelease", (void **) &pAVIStreamRelease },
{ "AVIStreamStart", (void **) &pAVIStreamStart },
{ "AVIStreamTimeToSample", (void **) &pAVIStreamTimeToSample },
{ NULL, NULL }
};
dll_info_t avifile_dll = { "avifil32.dll", avifile_funcs, false };
dll_info_t avifile_dll = { "avifil32.dll", avifile_funcs, ARRAYSIZE( avifile_funcs ), false };
typedef struct movie_state_s
{

View File

@@ -153,6 +153,7 @@ static void CL_WriteErrorMessage( int current_count, sizebuf_t *msg )
FS_Write( fp, &cls.starting_count, sizeof( int ));
FS_Write( fp, &current_count, sizeof( int ));
FS_Write( fp, &cls.legacymode, sizeof( cls.legacymode ));
FS_Write( fp, MSG_GetData( msg ), MSG_GetMaxBytes( msg ));
FS_Close( fp );
@@ -168,7 +169,7 @@ list last 32 messages for debugging net troubleshooting
*/
void CL_WriteMessageHistory( void )
{
oldcmd_t *old, *failcommand;
oldcmd_t *old;
sizebuf_t *msg = &net_message;
int i, thecmd;
@@ -192,9 +193,49 @@ void CL_WriteMessageHistory( void )
thecmd++;
}
failcommand = &cls_message_debug.oldcmd[thecmd];
Con_Printf( "BAD: %3i:%s\n", MSG_GetNumBytesRead( msg ) - 1, CL_MsgInfo( failcommand->command ));
if( host_developer.value >= DEV_EXTENDED )
CL_WriteErrorMessage( MSG_GetNumBytesRead( msg ) - 1, msg );
old = &cls_message_debug.oldcmd[thecmd];
Con_Printf( S_RED "BAD: " S_DEFAULT "%i %04i %s\n", old->frame_number, old->starting_offset, CL_MsgInfo( old->command ));
CL_WriteErrorMessage( old->starting_offset, msg );
cls_message_debug.parsing = false;
}
void CL_ReplayBufferDat_f( void )
{
file_t *f = FS_Open( Cmd_Argv( 1 ), "rb", true );
sizebuf_t msg;
char buffer[NET_MAX_MESSAGE];
int starting_count, current_count, protocol;
fs_offset_t len;
if( !f )
return;
FS_Read( f, &starting_count, sizeof( starting_count ));
FS_Read( f, &current_count, sizeof( current_count ));
FS_Read( f, &protocol, sizeof( protocol ));
cls.legacymode = protocol;
len = FS_Read( f, buffer, sizeof( buffer ));
FS_Close( f );
MSG_Init( &msg, __func__, buffer, len );
Delta_Shutdown();
Delta_Init();
clgame.maxEntities = MAX_EDICTS;
clgame.entities = Mem_Calloc( clgame.mempool, sizeof( *clgame.entities ) * clgame.maxEntities );
// ad-hoc implement
#if 0
{
const int message_pos = 12; // put real number here
MSG_SeekToBit( &msg, ( message_pos - 12 + 1 ) << 3, SEEK_SET );
CL_ParseYourMom( &msg, protocol );
}
#endif
Sys_Quit( __func__ );
}

View File

@@ -157,7 +157,7 @@ void CL_StartupDemoHeader( void )
{
CL_CloseDemoHeader();
cls.demoheader = FS_Open( "demoheader.tmp", "w+b", true );
cls.demoheader = FS_Open( "demoheader.tmp", "w+bm", true );
if( !cls.demoheader )
{
@@ -373,7 +373,7 @@ CL_WriteDemoUserMessage
Dumps the user message (demoaction)
====================
*/
void CL_WriteDemoUserMessage( const byte *buffer, size_t size )
void GAME_EXPORT CL_WriteDemoUserMessage( int size, byte *buffer )
{
if( !cls.demorecording || cls.demowaiting )
return;
@@ -624,11 +624,10 @@ static void CL_ReadDemoUserCmd( qboolean discard )
if( !discard )
{
usercmd_t nullcmd;
const usercmd_t nullcmd = { 0 };
sizebuf_t buf;
demoangle_t *a;
memset( &nullcmd, 0, sizeof( nullcmd ));
MSG_Init( &buf, "UserCmd", data, sizeof( data ));
// a1ba: I have no proper explanation why
@@ -724,7 +723,7 @@ static void CL_DemoStartPlayback( int mode )
{
// NOTE: at this point demo is still valid
CL_Disconnect();
Host_ShutdownServer();
SV_Shutdown( "Server was killed due to demo playback start\n" );
Con_FastClose();
UI_SetActiveMenu( false );

View File

@@ -127,8 +127,10 @@ static void R_SplitEntityOnNode( mnode_t *node )
}
// recurse down the contacted sides
if( sides & 1 ) R_SplitEntityOnNode( node->children[0] );
if( sides & 2 ) R_SplitEntityOnNode( node->children[1] );
if( sides & 1 )
R_SplitEntityOnNode( node_child( node, 0, cl.worldmodel ));
if( sides & 2 )
R_SplitEntityOnNode( node_child( node, 1, cl.worldmodel ));
}
/*

View File

@@ -2229,4 +2229,3 @@ void CL_ThinkParticle( double frametime, particle_t *p )
break;
}
}

View File

@@ -13,10 +13,12 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include <ctype.h>
#include "common.h"
#include "filesystem.h"
#include "client.h"
#include "qfont.h"
#include "utflib.h"
qboolean CL_FixedFont( cl_font_t *font )
{
@@ -173,31 +175,27 @@ static int CL_CalcTabStop( const cl_font_t *font, int x )
return stop;
}
int CL_DrawCharacter( float x, float y, int number, rgba_t color, cl_font_t *font, int flags )
static int CL_DrawBitmapCharacter( float x, float y, uint32_t uc, const rgba_t color, const cl_font_t *font, int flags )
{
wrect_t *rc;
float w, h;
float s1, t1, s2, t2, half = 0.5f;
int texw, texh;
uint32_t number;
if( !font || !font->valid || y < -font->charHeight )
// bitmap fonts need conversion. Do this and validate the result
if( g_codepage == 1251 )
number = Q_UnicodeToCP1251( uc );
else if( g_codepage == 1252 )
number = Q_UnicodeToCP1252( uc );
else
number = uc;
if( !number || number >= ARRAYSIZE( font->charWidths ))
return 0;
// check if printable
if( number <= 32 )
{
if( number == ' ' )
return font->charWidths[' '];
else if( number == '\t' )
return CL_CalcTabStop( font, x );
return 0;
}
if( FBitSet( flags, FONT_DRAW_UTF8 ))
number = Con_UtfProcessChar( number & 255 );
else number &= 255;
if( !number || !font->charWidths[number])
// start rendering
if( !font->charWidths[number] )
return 0;
R_GetTextureParms( &texw, &texh, font->hFontTexture );
@@ -231,29 +229,60 @@ int CL_DrawCharacter( float x, float y, int number, rgba_t color, cl_font_t *fon
return font->charWidths[number];
}
int CL_DrawString( float x, float y, const char *s, rgba_t color, cl_font_t *font, int flags )
static int CL_DrawTrueTypeCharacter( float x, float y, uint32_t uc, const rgba_t color, cl_font_t *font, int flags )
{
// stub
return 0;
}
int CL_DrawCharacter( float x, float y, uint32_t uc, const rgba_t color, const cl_font_t *font, int flags )
{
if( !font || !font->valid || y < -font->charHeight )
return 0;
// check if printable
if( uc <= 32 )
{
if( uc == ' ' )
return font->charWidths[' '];
else if( uc == '\t' )
return CL_CalcTabStop( font, x );
return 0;
}
if( font->type == FONT_TRUETYPE )
return CL_DrawTrueTypeCharacter( x, y, uc, color, font, flags );
return CL_DrawBitmapCharacter( x, y, uc, color, font, flags );
}
int CL_DrawString( float x, float y, const char *s, const rgba_t color, const cl_font_t *font, int flags )
{
rgba_t current_color;
int draw_len = 0;
utfstate_t utfstate = { 0 };
if( !font || !font->valid )
return 0;
if( FBitSet( flags, FONT_DRAW_UTF8 ))
Con_UtfProcessChar( 0 ); // clear utf state
if( !FBitSet( flags, FONT_DRAW_NORENDERMODE ))
CL_SetFontRendermode( font );
Vector4Copy( color, current_color );
while( *s )
for( ; *s; s++ )
{
if( *s == '\n' )
{
s++;
uint32_t uc = (byte)*s;
if( !*s )
if( FBitSet( flags, FONT_DRAW_UTF8 ))
uc = Q_DecodeUTF8( &utfstate, uc );
if( !uc )
continue;
if( uc == '\n' )
{
if( !s[1] ) // ignore newline at end of string if next
break;
// some client functions ignore newlines
@@ -264,30 +293,29 @@ int CL_DrawString( float x, float y, const char *s, rgba_t color, cl_font_t *fon
}
if( FBitSet( flags, FONT_DRAW_RESETCOLORONLF ))
Vector4Copy( color, current_color );
Vector4Copy( color, current_color );
continue;
}
if( IsColorString( s ))
// check for colorstrings
if( uc == '^' && isdigit( s[1] ))
{
// don't copy alpha
if( !FBitSet( flags, FONT_DRAW_FORCECOL ))
VectorCopy( g_color_table[ColorIndex(*( s + 1 ))], current_color );
VectorCopy( g_color_table[ColorIndex( s[1] )], current_color );
s += 2;
s++;
continue;
}
// skip setting rendermode, it was changed for this string already
draw_len += CL_DrawCharacter( x + draw_len, y, (byte)*s, current_color, font, flags | FONT_DRAW_NORENDERMODE );
s++;
draw_len += CL_DrawCharacter( x + draw_len, y, uc, current_color, font, flags | FONT_DRAW_NORENDERMODE );
}
return draw_len;
}
int CL_DrawStringf( cl_font_t *font, float x, float y, rgba_t color, int flags, const char *fmt, ... )
int CL_DrawStringf( const cl_font_t *font, float x, float y, const rgba_t color, int flags, const char *fmt, ... )
{
va_list va;
char buf[MAX_VA_STRING];
@@ -299,20 +327,63 @@ int CL_DrawStringf( cl_font_t *font, float x, float y, rgba_t color, int flags,
return CL_DrawString( x, y, buf, color, font, flags );
}
void CL_DrawCharacterLen( cl_font_t *font, int number, int *width, int *height )
static int CL_DrawBitmapCharacterLen( const cl_font_t *font, uint32_t uc )
{
if( !font || !font->valid ) return;
if( width )
{
if( number == '\t' )
*width = CL_CalcTabStop( font, 0 ); // at least return max tabstop
else *width = font->charWidths[number & 255];
}
if( height ) *height = font->charHeight;
int number;
if( g_codepage == 1251 )
number = Q_UnicodeToCP1251( uc );
else if( g_codepage == 1252 )
number = Q_UnicodeToCP1252( uc );
else
number = uc;
if( !number || number >= ARRAYSIZE( font->charWidths ))
return 0;
return font->charWidths[number];
}
void CL_DrawStringLen( cl_font_t *font, const char *s, int *width, int *height, int flags )
static int CL_DrawTrueTypeCharacterLen( const cl_font_t *font, uint32_t uc )
{
// stub
return 0;
}
void CL_DrawCharacterLen( const cl_font_t *font, uint32_t uc, int *width, int *height )
{
if( !font || !font->valid )
return;
if( height )
*height = font->charHeight;
if( width )
{
// basically matches logic of CL_DrawCharacter
if( uc <= 32 )
{
if( uc == ' ' )
*width = font->charWidths[' '];
else if( uc == '\t' )
*width = CL_CalcTabStop( font, 0 ); // at least return max tabstop
else
*width = 0;
}
else if( font->type == FONT_TRUETYPE )
{
*width = CL_DrawTrueTypeCharacterLen( font, uc );
}
else
{
*width = CL_DrawBitmapCharacterLen( font, uc );
}
}
}
void CL_DrawStringLen( const cl_font_t *font, const char *s, int *width, int *height, int flags )
{
utfstate_t utfstate = { 0 };
int draw_len = 0;
if( !font || !font->valid )
@@ -327,54 +398,45 @@ void CL_DrawStringLen( cl_font_t *font, const char *s, int *width, int *height,
if( !COM_CheckString( s ))
return;
if( FBitSet( flags, FONT_DRAW_UTF8 ))
Con_UtfProcessChar( 0 ); // reset utf state
while( *s )
for( ; *s; s++ )
{
int number;
uint32_t uc = (byte)*s;
int char_width = 0;
if( *s == '\n' )
if( FBitSet( flags, FONT_DRAW_UTF8 ))
uc = Q_DecodeUTF8( &utfstate, uc );
if( !uc )
continue;
if( uc == '\n' )
{
// BUG: no check for end string here
// but high chances somebody's relying on this
s++;
draw_len = 0;
// some client functions ignore newlines
if( !FBitSet( flags, FONT_DRAW_NOLF ))
{
if( height )
*height += font->charHeight;
}
continue;
}
else if( *s == '\t' )
// check for colorstrings
if( uc == '^' && isdigit( s[1] ))
{
draw_len += CL_CalcTabStop( font, 0 ); // at least return max tabstop
s++;
continue;
}
if( IsColorString( s ))
CL_DrawCharacterLen( font, uc, &char_width, NULL );
draw_len += char_width;
if( width )
{
s += 2;
continue;
if( *width < draw_len )
*width = draw_len;
}
if( FBitSet( flags, FONT_DRAW_UTF8 ))
number = Con_UtfProcessChar( (byte)*s );
else number = (byte)*s;
if( number )
{
draw_len += font->charWidths[number];
if( width )
{
if( draw_len > *width )
*width = draw_len;
}
}
s++;
}
}

View File

@@ -13,6 +13,10 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#if XASH_SDL
#include <SDL.h> // SDL_GetWindowPosition
#endif // XASH_SDL
#include "common.h"
#include "client.h"
#include "const.h"
@@ -29,6 +33,7 @@ GNU General Public License for more details.
#include "vgui_draw.h"
#include "sound.h" // SND_STOP_LOOPING
#include "platform/platform.h"
#include "utflib.h"
#define MAX_LINELENGTH 80
#define MAX_TEXTCHANNELS 8 // must be power of two (GoldSrc uses 4 channels)
@@ -76,7 +81,6 @@ static const dllfunc_t cdll_exports[] =
{ "IN_ClearStates", (void **)&clgame.dllFuncs.IN_ClearStates },
{ "V_CalcRefdef", (void **)&clgame.dllFuncs.pfnCalcRefdef },
{ "KB_Find", (void **)&clgame.dllFuncs.KB_Find },
{ NULL, NULL }
};
// optional exports
@@ -91,7 +95,6 @@ static const dllfunc_t cdll_new_exports[] = // allowed only in SDK 2.3 and high
{ "IN_ClientTouchEvent", (void **)&clgame.dllFuncs.pfnTouchEvent}, // Xash3D FWGS ext
{ "IN_ClientMoveEvent", (void **)&clgame.dllFuncs.pfnMoveEvent}, // Xash3D FWGS ext
{ "IN_ClientLookEvent", (void **)&clgame.dllFuncs.pfnLookEvent}, // Xash3D FWGS ext
{ NULL, NULL }
};
static void pfnSPR_DrawHoles( int frame, int x, int y, const wrect_t *prc );
@@ -308,21 +311,22 @@ void SPR_AdjustSize( float *x, float *y, float *w, float *h )
static void SPR_AdjustTexCoords( int texnum, float width, float height, float *s1, float *t1, float *s2, float *t2 )
{
if( REF_GET_PARM( PARM_TEX_FILTERING, texnum ))
{
if( refState.width != clgame.scrInfo.iWidth )
{
// align to texel if scaling
*s1 += 0.5f;
*s2 -= 0.5f;
}
const qboolean filtering = REF_GET_PARM( PARM_TEX_FILTERING, texnum );
const int xremainder = refState.width % clgame.scrInfo.iWidth;
const int yremainder = refState.height % clgame.scrInfo.iHeight;
if( refState.height != clgame.scrInfo.iHeight )
{
// align to texel if scaling
*t1 += 0.5f;
*t2 -= 0.5f;
}
if(( filtering || xremainder ) && refState.width != clgame.scrInfo.iWidth )
{
// align to texel if scaling
*s1 += 0.5f;
*s2 -= 0.5f;
}
if(( filtering || yremainder ) && refState.height != clgame.scrInfo.iHeight )
{
// align to texel if scaling
*t1 += 0.5f;
*t2 -= 0.5f;
}
*s1 /= width;
@@ -405,8 +409,10 @@ void CL_DrawCenterPrint( void )
char *pText;
int i, j, x, y;
int width, lineLength;
byte *colorDefault, line[MAX_LINELENGTH];
byte *colorDefault;
uint32_t line[MAX_LINELENGTH];
int charWidth, charHeight;
utfstate_t utfstate = { 0 };
if( !clgame.centerPrint.time )
return;
@@ -429,14 +435,19 @@ void CL_DrawCenterPrint( void )
lineLength = 0;
width = 0;
while( *pText && *pText != '\n' && lineLength < MAX_LINELENGTH )
for( ; *pText && *pText != '\n' && lineLength < MAX_LINELENGTH; pText++ )
{
byte c = *pText;
line[lineLength] = c;
CL_DrawCharacterLen( font, c, &charWidth, NULL );
uint32_t uc = Q_DecodeUTF8( &utfstate, c );
if( !uc )
continue;
line[lineLength] = uc;
CL_DrawCharacterLen( font, uc, &charWidth, NULL );
width += charWidth;
lineLength++;
pText++;
}
if( lineLength == MAX_LINELENGTH )
@@ -450,7 +461,7 @@ void CL_DrawCenterPrint( void )
for( j = 0; j < lineLength; j++ )
{
if( x >= 0 && y >= 0 && x <= refState.width )
x += CL_DrawCharacter( x, y, line[j], colorDefault, font, FONT_DRAW_UTF8 | FONT_DRAW_HUD | FONT_DRAW_NORENDERMODE );
x += CL_DrawCharacter( x, y, line[j], colorDefault, font, FONT_DRAW_HUD | FONT_DRAW_NORENDERMODE );
}
y += charHeight;
}
@@ -558,7 +569,7 @@ static void CL_InitTitles( const char *filename )
Q_snprintf( name, sizeof( name ), TEXT_MSGNAME, i );
cl_textmessage[i].pName = _copystring( clgame.mempool, name, __FILE__, __LINE__ );
cl_textmessage[i].pName = copystringpool( clgame.mempool, name );
cl_textmessage[i].pMessage = cl_textbuffer[i];
}
@@ -976,7 +987,7 @@ static void CL_ClearUserMessage( char *pszName, int svc_num )
int i;
for( i = 0; i < MAX_USER_MESSAGES && clgame.msg[i].name[0]; i++ )
if( ( clgame.msg[i].number == svc_num ) && Q_strcmp( clgame.msg[i].name, pszName ) )
if( ( clgame.msg[i].number == svc_num ) && Q_stricmp( clgame.msg[i].name, pszName ) )
clgame.msg[i].number = 0;
}
@@ -1046,7 +1057,7 @@ void CL_InitEdicts( int maxclients )
cls.num_client_entities = CL_UPDATE_BACKUP * NUM_PACKET_ENTITIES;
cls.packet_entities = Mem_Realloc( clgame.mempool, cls.packet_entities, sizeof( entity_state_t ) * cls.num_client_entities );
clgame.entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * clgame.maxEntities );
clgame.static_entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
clgame.static_entities = NULL; // will be initialized later
clgame.numStatics = 0;
if(( clgame.maxRemapInfos - 1 ) != clgame.maxEntities )
@@ -1700,7 +1711,12 @@ int GAME_EXPORT CL_GetScreenInfo( SCREENINFO *pscrinfo )
clgame.scrInfo.iSize = sizeof( clgame.scrInfo );
clgame.scrInfo.iFlags = SCRINFO_SCREENFLASH;
if( scale_factor && scale_factor != 1.0f )
if( hud_scale.value >= 320.0f && hud_scale.value >= hud_scale_minimal_width.value )
{
scale_factor = refState.width / hud_scale.value;
apply_scale_factor = true;
}
else if( scale_factor && scale_factor != 1.0f )
{
float scaled_width = (float)refState.width / scale_factor;
if( scaled_width >= hud_scale_minimal_width.value )
@@ -1765,6 +1781,17 @@ static cvar_t *GAME_EXPORT pfnCvar_RegisterClientVariable( const char *szName, c
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_CLIENTDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_CLIENTDLL ));
}
static int GAME_EXPORT Cmd_AddClientCommand( const char *cmd_name, xcommand_t function )
{
int flags = CMD_CLIENTDLL;
// a1ba: try to mitigate outdated client.dll vulnerabilities
if( !Q_stricmp( cmd_name, "motd_write" ))
flags |= CMD_PRIVILEGED;
return Cmd_AddCommandEx( cmd_name, function, "client command", flags, __func__ );
}
/*
=============
pfnHookUserMsg
@@ -1970,7 +1997,13 @@ static int GAME_EXPORT pfnDrawCharacter( int x, int y, int number, int r, int g,
int flags = FONT_DRAW_HUD;
if( hud_utf8.value )
flags |= FONT_DRAW_UTF8;
{
static utfstate_t utfstate;
number = Q_DecodeUTF8( &utfstate, number );
if( !number )
return 0;
}
return CL_DrawCharacter( x, y, number, color, &cls.creditsFont, flags );
}
@@ -2399,9 +2432,8 @@ CL_FindModelIndex
*/
static int GAME_EXPORT CL_FindModelIndex( const char *m )
{
char filepath[MAX_QPATH];
static float lasttimewarn;
int i;
char filepath[MAX_QPATH];
int i;
if( !COM_CheckString( m ))
return 0;
@@ -2418,13 +2450,6 @@ static int GAME_EXPORT CL_FindModelIndex( const char *m )
return i+1;
}
if( lasttimewarn < host.realtime )
{
// tell user about problem (but don't spam console)
Con_DPrintf( S_ERROR "Could not find index for model %s: not precached\n", filepath );
lasttimewarn = host.realtime + 1.0f;
}
return 0;
}
@@ -2698,17 +2723,6 @@ static const char *pfnGetGameDirectory( void )
return szGetGameDir;
}
/*
=============
Key_LookupBinding
=============
*/
static const char *Key_LookupBinding( const char *pBinding )
{
return Key_KeynumToString( Key_GetKey( pBinding ));
}
/*
=============
pfnGetLevelName
@@ -3052,12 +3066,8 @@ pfnDrawString
*/
static int GAME_EXPORT pfnDrawString( int x, int y, const char *str, int r, int g, int b )
{
rgba_t color = { r, g, b, 255 };
int flags = FONT_DRAW_HUD | FONT_DRAW_NOLF;
if( hud_utf8.value )
SetBits( flags, FONT_DRAW_UTF8 );
const rgba_t color = { r, g, b, 255 };
int flags = FONT_DRAW_HUD | FONT_DRAW_NOLF | FONT_DRAW_UTF8;
return CL_DrawString( x, y, str, color, &cls.creditsFont, flags );
}
@@ -3069,13 +3079,10 @@ pfnDrawStringReverse
*/
static int GAME_EXPORT pfnDrawStringReverse( int x, int y, const char *str, int r, int g, int b )
{
rgba_t color = { r, g, b, 255 };
int flags = FONT_DRAW_HUD | FONT_DRAW_NOLF;
const rgba_t color = { r, g, b, 255 };
int flags = FONT_DRAW_HUD | FONT_DRAW_NOLF | FONT_DRAW_UTF8;
int width;
if( hud_utf8.value )
SetBits( flags, FONT_DRAW_UTF8 );
CL_DrawStringLen( &cls.creditsFont, str, &width, NULL, flags );
x -= width;
@@ -3358,28 +3365,6 @@ DemoApi implementation
=================
*/
/*
=================
Demo_IsRecording
=================
*/
static int GAME_EXPORT Demo_IsRecording( void )
{
return cls.demorecording;
}
/*
=================
Demo_IsPlayingback
=================
*/
static int GAME_EXPORT Demo_IsPlayingback( void )
{
return cls.demoplayback;
}
/*
=================
Demo_IsTimeDemo
@@ -3391,17 +3376,6 @@ static int GAME_EXPORT Demo_IsTimeDemo( void )
return cls.timedemo;
}
/*
=================
Demo_WriteBuffer
=================
*/
static void GAME_EXPORT Demo_WriteBuffer( int size, byte *buffer )
{
CL_WriteDemoUserMessage( buffer, size );
}
/*
=================
NetworkApi implementation
@@ -3464,7 +3438,7 @@ static void GAME_EXPORT NetAPI_SendRequest( int context, int request, int flags,
return;
}
if( remote_address->type == NA_IPX || remote_address->type == NA_BROADCAST_IPX )
if( NET_NetadrType( remote_address ) == NA_IPX || NET_NetadrType( remote_address ) == NA_BROADCAST_IPX )
return; // IPX no longer support
if( request == NETAPI_REQUEST_SERVERLIST )
@@ -3587,28 +3561,6 @@ static int GAME_EXPORT NetAPI_CompareAdr( netadr_t *a, netadr_t *b )
return NET_CompareAdr( *a, *b );
}
/*
=================
NetAPI_StringToAdr
=================
*/
static int GAME_EXPORT NetAPI_StringToAdr( char *s, netadr_t *a )
{
return NET_StringToAdr( s, a );
}
/*
=================
NetAPI_ValueForKey
=================
*/
static const char * GAME_EXPORT NetAPI_ValueForKey( const char *s, const char *key )
{
return Info_ValueForKey( s, key );
}
/*
=================
NetAPI_RemoveKey
@@ -3805,10 +3757,10 @@ static event_api_t gEventApi =
static demo_api_t gDemoApi =
{
Demo_IsRecording,
Demo_IsPlayingback,
(void *)CL_IsRecordDemo,
(void *)CL_IsPlaybackDemo,
Demo_IsTimeDemo,
Demo_WriteBuffer,
CL_WriteDemoUserMessage,
};
net_api_t gNetApi =
@@ -3820,8 +3772,8 @@ net_api_t gNetApi =
NetAPI_CancelAllRequests,
NetAPI_AdrToString,
NetAPI_CompareAdr,
NetAPI_StringToAdr,
NetAPI_ValueForKey,
(void *)NET_StringToAdr,
Info_ValueForKey,
NetAPI_RemoveKey,
NetAPI_SetValueForKey,
};
@@ -4007,9 +3959,10 @@ void CL_UnloadProgs( void )
qboolean CL_LoadProgs( const char *name )
{
static playermove_t gpMove;
const dllfunc_t *func;
CL_EXPORT_FUNCS GetClientAPI; // single export
qboolean critical_exports = true;
CL_EXPORT_FUNCS GetClientAPI; // single export
qboolean valid_single_export = false;
qboolean missed_exports = false;
int i;
if( clgame.hInstance ) CL_UnloadProgs();
@@ -4020,36 +3973,19 @@ qboolean CL_LoadProgs( const char *name )
clgame.mempool = Mem_AllocPool( "Client Edicts Zone" );
clgame.entities = NULL;
// a1ba: we need to check if client.dll has direct dependency on SDL2
// and if so, disable relative mouse mode
#if XASH_WIN32 && !XASH_64BIT
if( ( clgame.client_dll_uses_sdl = COM_CheckLibraryDirectDependency( name, OS_LIB_PREFIX "SDL2." OS_LIB_EXT, false ) ) )
{
Con_Printf( S_NOTE "%s uses SDL2 for mouse input\n", name );
}
else
{
Con_Printf( S_NOTE "%s uses Windows API for mouse input\n", name );
}
#else
// this doesn't mean other platforms uses SDL2 in any case
// it just helps input code to stay platform-independent
clgame.client_dll_uses_sdl = true;
clgame.client_dll_uses_sdl = COM_CheckLibraryDirectDependency( name, OS_LIB_PREFIX "SDL2." OS_LIB_EXT, false );
Con_Printf( S_NOTE "%s uses %s for mouse input\n", name, clgame.client_dll_uses_sdl ? "SDL2" : "Windows API" );
#endif
// NOTE: important stuff!
// vgui must startup BEFORE loading client.dll to avoid get error ERROR_NOACESS
// during LoadLibrary
// vgui must startup BEFORE loading client.dll to avoid get error ERROR_NOACESS during LoadLibrary
if( !GI->internal_vgui_support && VGui_LoadProgs( NULL ))
{
VGui_Startup( refState.width, refState.height );
}
else
{
// we failed to load vgui_support, but let's probe client.dll for support anyway
GI->internal_vgui_support = true;
}
GI->internal_vgui_support = true; // we failed to load vgui_support, but let's probe client.dll for support anyway
clgame.hInstance = COM_LoadLibrary( name, false, false );
@@ -4058,13 +3994,10 @@ qboolean CL_LoadProgs( const char *name )
// delayed vgui initialization for internal support
if( GI->internal_vgui_support && VGui_LoadProgs( clgame.hInstance ))
{
VGui_Startup( refState.width, refState.height );
}
// clear exports
for( func = cdll_exports; func && func->name; func++ )
*func->func = NULL;
ClearExports( cdll_exports, ARRAYSIZE( cdll_exports ));
// trying to get single export
if(( GetClientAPI = (void *)COM_GetProcAddress( clgame.hInstance, "GetClientAPI" )) != NULL )
@@ -4082,56 +4015,44 @@ qboolean CL_LoadProgs( const char *name )
CL_GetSecuredClientAPI( GetClientAPI );
}
if ( GetClientAPI != NULL )
{
// check critical functions again
for( func = cdll_exports; func && func->name; func++ )
{
if( func->func == NULL )
break; // BAH critical function was missed
}
if( GetClientAPI != NULL ) // check critical functions again
valid_single_export = ValidateExports( cdll_exports, ARRAYSIZE( cdll_exports ));
// because all the exports are loaded through function 'F"
if( !func || !func->name )
critical_exports = false;
}
for( func = cdll_exports; func && func->name != NULL; func++ )
for( i = 0; i < ARRAYSIZE( cdll_exports ); i++ )
{
if( *func->func != NULL )
continue; // already get through 'F'
if( *(cdll_exports[i].func) != NULL )
continue; // already gott through 'F' or 'GetClientAPI'
// functions are cleared before all the extensions are evaluated
if(( *func->func = (void *)COM_GetProcAddress( clgame.hInstance, func->name )) == NULL )
if(( *(cdll_exports[i].func) = (void *)COM_GetProcAddress( clgame.hInstance, cdll_exports[i].name )) == NULL )
{
Con_Reportf( "%s: failed to get address of %s proc\n", __func__, func->name );
Con_Reportf( S_ERROR "%s: failed to get address of %s proc\n", __func__, cdll_exports[i].name );
if( critical_exports )
{
COM_FreeLibrary( clgame.hInstance );
clgame.hInstance = NULL;
return false;
}
// print all not found exports at once, for debug
missed_exports = true;
}
}
if( missed_exports )
{
COM_FreeLibrary( clgame.hInstance );
clgame.hInstance = NULL;
return false;
}
// it may be loaded through 'GetClientAPI' so we don't need to clear them
if( critical_exports )
{
// clear new exports
for( func = cdll_new_exports; func && func->name; func++ )
*func->func = NULL;
}
if( !valid_single_export )
ClearExports( cdll_new_exports, ARRAYSIZE( cdll_new_exports ));
for( func = cdll_new_exports; func && func->name != NULL; func++ )
for( i = 0; i < ARRAYSIZE( cdll_new_exports ); i++ )
{
if( *func->func != NULL )
continue; // already get through 'F'
if( *(cdll_new_exports[i].func) != NULL )
continue; // already gott through 'F' or 'GetClientAPI'
// functions are cleared before all the extensions are evaluated
// NOTE: new exports can be missed without stop the engine
if(( *func->func = (void *)COM_GetProcAddress( clgame.hInstance, func->name )) == NULL )
Con_Reportf( "%s: failed to get address of %s proc\n", __func__, func->name );
if(( *(cdll_new_exports[i].func) = (void *)COM_GetProcAddress( clgame.hInstance, cdll_new_exports[i].name )) == NULL )
Con_Reportf( S_WARN "%s: failed to get address of %s proc\n", __func__, cdll_new_exports[i].name );
}
if( !clgame.dllFuncs.pfnInitialize( &gEngfuncs, CLDLL_INTERFACE_VERSION ))

View File

@@ -694,6 +694,11 @@ static cvar_t *GAME_EXPORT pfnCvar_RegisterGameUIVariable( const char *szName, c
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_GAMEUIDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_GAMEUIDLL ));
}
static int GAME_EXPORT Cmd_AddGameUICommand( const char *cmd_name, xcommand_t function )
{
return Cmd_AddCommandEx( cmd_name, function, "gameui command", CMD_GAMEUIDLL, __func__ );
}
/*
=============
pfnClientCmd
@@ -1109,7 +1114,7 @@ static void GAME_EXPORT UI_ShellExecute( const char *path, const char *parms, in
Platform_ShellExecute( path, parms );
if( shouldExit )
Sys_Quit();
Sys_Quit( __func__ );
}
/*
@@ -1319,10 +1324,21 @@ static int pfnIsCvarReadOnly( const char *name )
return FBitSet( cv->flags, FCVAR_READ_ONLY ) ? 1 : 0;
}
static int GAME_EXPORT pfnUtfProcessChar( int in )
{
// compatibility export, deprecated, do not use
if( !cls.accept_utf8 ) // incoming character is not a UTF-8 sequence
return in;
// otherwise, decode it and convert to selected codepage
return Con_UtfProcessCharForce( in );
}
static ui_extendedfuncs_t gExtendedfuncs =
{
pfnEnableTextInput,
Con_UtfProcessChar,
pfnUtfProcessChar,
Con_UtfMoveLeft,
Con_UtfMoveRight,
pfnGetRenderers,

View File

@@ -68,7 +68,7 @@ CVAR_DEFINE_AUTO( hud_scale_minimal_width, "640", FCVAR_ARCHIVE|FCVAR_LATCH, "if
CVAR_DEFINE_AUTO( cl_solid_players, "1", 0, "Make all players not solid (can't traceline them)" );
CVAR_DEFINE_AUTO( cl_updaterate, "20", FCVAR_USERINFO|FCVAR_ARCHIVE, "refresh rate of server messages" );
CVAR_DEFINE_AUTO( cl_showevents, "0", FCVAR_ARCHIVE, "show events playback" );
CVAR_DEFINE_AUTO( cl_cmdrate, "60", FCVAR_ARCHIVE, "Max number of command packets sent to server per second" );
CVAR_DEFINE_AUTO( cl_cmdrate, "30", FCVAR_ARCHIVE, "Max number of command packets sent to server per second" );
CVAR_DEFINE( cl_interp, "ex_interp", "0.1", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "Interpolate object positions starting this many seconds in past" );
CVAR_DEFINE_AUTO( cl_nointerp, "0", 0, "disable interpolation of entities and players" );
static CVAR_DEFINE_AUTO( cl_dlmax, "0", FCVAR_USERINFO|FCVAR_ARCHIVE, "max allowed outcoming fragment size" );
@@ -76,6 +76,7 @@ static CVAR_DEFINE_AUTO( cl_upmax, "1200", FCVAR_ARCHIVE, "max allowed incoming
CVAR_DEFINE_AUTO( cl_lw, "1", FCVAR_ARCHIVE|FCVAR_USERINFO, "enable client weapon predicting" );
CVAR_DEFINE_AUTO( cl_charset, "utf-8", FCVAR_ARCHIVE, "1-byte charset to use (iconv style)" );
CVAR_DEFINE_AUTO( cl_trace_consistency, "0", FCVAR_ARCHIVE, "enable consistency info tracing (good for developers)" );
CVAR_DEFINE_AUTO( cl_trace_stufftext, "0", FCVAR_ARCHIVE, "enable stufftext (server-to-client console commands) tracing (good for developers)" );
CVAR_DEFINE_AUTO( cl_trace_messages, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable message names tracing (good for developers)" );
CVAR_DEFINE_AUTO( cl_trace_events, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable events tracing (good for developers)" );
@@ -93,11 +94,10 @@ static CVAR_DEFINE_AUTO( name, username, FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_PRIN
static CVAR_DEFINE_AUTO( model, "", FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_FILTERABLE, "player model ('player' is a singleplayer model)" );
static CVAR_DEFINE_AUTO( topcolor, "0", FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_FILTERABLE, "player top color" );
static CVAR_DEFINE_AUTO( bottomcolor, "0", FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_FILTERABLE, "player bottom color" );
CVAR_DEFINE_AUTO( rate, "3500", FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_FILTERABLE, "player network rate" );
CVAR_DEFINE_AUTO( rate, "25000", FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_FILTERABLE, "player network rate" );
static CVAR_DEFINE_AUTO( cl_ticket_generator, "revemu2013", FCVAR_ARCHIVE, "you wouldn't steal a car" );
client_t cl;
client_static_t cls;
clgame_static_t clgame;
@@ -147,11 +147,6 @@ qboolean CL_IsRecordDemo( void )
return cls.demorecording;
}
qboolean CL_IsTimeDemo( void )
{
return cls.timedemo;
}
qboolean CL_DisableVisibility( void )
{
return cls.envshot_disable_vis;
@@ -598,7 +593,7 @@ CL_CreateCmd
*/
static void CL_CreateCmd( void )
{
usercmd_t nullcmd, *cmd;
usercmd_t nullcmd = { 0 }, *cmd;
runcmd_t *pcmd;
qboolean active;
double accurate_ms;
@@ -650,7 +645,6 @@ static void CL_CreateCmd( void )
}
else
{
memset( &nullcmd, 0, sizeof( nullcmd ));
cmd = &nullcmd;
}
@@ -723,11 +717,20 @@ static void CL_WritePacket( void )
int numbackup, maxbackup, maxcmds;
const connprotocol_t proto = cls.legacymode;
// FIXME: on Xash protocol we don't send move commands until ca_active
// to prevent outgoing_command outrun incoming_acknowledged
// which is fatal for some buggy mods like TFC
//
// ... but GoldSrc don't have (real) ca_validate state, so we consider
// ca_validate the same as ca_active, otherwise we don't pass validation
// of server-side mods like ReAuthCheck
const connstate_t min_state = proto == PROTO_GOLDSRC ? ca_validate : ca_active;
// don't send anything if playing back a demo
if( cls.demoplayback || cls.state < ca_connected || cls.state == ca_cinematic )
return;
if( cls.state <= ca_connected )
if( cls.state < min_state )
{
Netchan_TransmitBits( &cls.netchan, 0, "" );
return;
@@ -825,7 +828,7 @@ static void CL_WritePacket( void )
buf.pData[key] = CRC32_BlockSequence( &buf.pData[key + 1], size, cls.netchan.outgoing_sequence );
COM_Munge( &buf.pData[key + 1], Q_min( size, 255 ), cls.netchan.outgoing_sequence );
}
else
else if( !Host_IsLocalClient( ))
{
int size = MSG_GetRealBytesWritten( &buf ) - key - 1;
buf.pData[key] = CRC32_BlockSequence( &buf.pData[key + 1], size, cls.netchan.outgoing_sequence );
@@ -965,7 +968,7 @@ CL_Quit_f
void CL_Quit_f( void )
{
CL_Disconnect();
Sys_Quit();
Sys_Quit( "command" );
}
/*
@@ -1005,7 +1008,7 @@ static void CL_WriteSteamTicket( sizebuf_t *send )
const char *s;
uint32_t crc;
char buf[768] = { 0 }; // setti and steamemu return 768
size_t i = sizeof( buf );
int i = sizeof( buf );
if( !Q_strcmp( cl_ticket_generator.string, "null" ))
{
@@ -1024,24 +1027,7 @@ static void CL_WriteSteamTicket( sizebuf_t *send )
CRC32_Init( &crc );
CRC32_ProcessBuffer( &crc, s, Q_strlen( s ));
crc = CRC32_Final( crc );
if( !Q_stricmp( cl_ticket_generator.string, "revemu2013" ))
i = GenerateRevEmu2013( buf, crc );
else if( !Q_stricmp( cl_ticket_generator.string, "sc2009" ))
i = GenerateSC2009( buf, crc );
else if( !Q_stricmp( cl_ticket_generator.string, "oldrevemu" ))
i = GenerateOldRevEmu( buf, crc );
else if( !Q_stricmp( cl_ticket_generator.string, "steamemu" ))
i = GenerateSteamEmu( buf, crc );
else if( !Q_stricmp( cl_ticket_generator.string, "revemu" ))
i = GenerateRevEmu( buf, crc );
else if( !Q_stricmp( cl_ticket_generator.string, "setti" ))
i = GenerateSetti( buf );
else if( !Q_stricmp( cl_ticket_generator.string, "avsmp" ))
i = GenerateAVSMP( buf, crc, true );
else
Con_Printf( "%s: unknown generator %s, supported are: null, revemu2003, sc2009, oldrevemu, steamemu, revemu, setti, avsmp\n", __func__, cl_ticket_generator.string );
i = GenerateRevEmu2013( buf, s, crc );
MSG_WriteBytes( send, buf, i );
}
@@ -1059,6 +1045,7 @@ static void CL_SendConnectPacket( connprotocol_t proto, int challenge )
const char *key = ID_GetMD5();
netadr_t adr = { 0 };
int input_devices;
netadrtype_t adrtype;
protinfo[0] = 0;
@@ -1069,14 +1056,16 @@ static void CL_SendConnectPacket( connprotocol_t proto, int challenge )
return;
}
adrtype = NET_NetadrType( &adr );
if( adr.port == 0 ) adr.port = MSG_BigShort( PORT_SERVER );
input_devices = IN_CollectInputDevices();
IN_LockInputDevices( adr.type != NA_LOOPBACK ? true : false );
IN_LockInputDevices( adrtype != NA_LOOPBACK ? true : false );
// GoldSrc doesn't need sv_cheats set to 0, it's handled by svc_goldsrc_sendextrainfo
// it also doesn't need useragent string
if( adr.type != NA_LOOPBACK && proto != PROTO_GOLDSRC )
if( adrtype != NA_LOOPBACK && proto != PROTO_GOLDSRC )
{
Cvar_SetCheatState();
Cvar_FullSet( "sv_cheats", "0", FCVAR_READ_ONLY | FCVAR_SERVER );
@@ -1176,7 +1165,11 @@ Returns bandwidth test fragment size
*/
static int CL_GetTestFragmentSize( void )
{
const int fragmentSizes[CL_TEST_RETRIES] = { 64000, 32000, 10666, 5200, 1400 };
// const int fragmentSizes[CL_TEST_RETRIES] = { 64000, 32000, 10666, 5200, 1400 };
// it turns out, even if we pass the bandwidth test, it doesn't mean we can use such large fragments
// as a temporary solution, use smaller fragment sizes
const int fragmentSizes[CL_TEST_RETRIES] = { 1400, 1200, 1000, 800, 508 };
if( cls.connect_retry >= 0 && cls.connect_retry < CL_TEST_RETRIES )
return bound( FRAGMENT_MIN_SIZE, fragmentSizes[cls.connect_retry], FRAGMENT_MAX_SIZE );
else
@@ -1214,7 +1207,7 @@ static void CL_CheckForResend( void )
cls.signon = 0;
cls.state = ca_connecting;
Q_strncpy( cls.servername, "localhost", sizeof( cls.servername ));
cls.serveradr.type = NA_LOOPBACK;
NET_NetadrSetType( &cls.serveradr, NA_LOOPBACK );
cls.legacymode = PROTO_CURRENT;
// we don't need a challenge on the localhost
@@ -1401,7 +1394,8 @@ static void CL_Connect_f( void )
Q_strncpy( server, Cmd_Argv( 1 ), sizeof( server ));
// if running a local server, kill it and reissue
if( SV_Active( )) Host_ShutdownServer();
if( SV_Active( ))
SV_Shutdown( "Server was killed due to connection to remote server\n" );
NET_Config( true, !cl_nat.value ); // allow remote
Con_Printf( "server %s\n", server );
@@ -1549,8 +1543,8 @@ static void CL_SendDisconnectMessage( connprotocol_t proto )
MSG_WriteString( &buf, "dropclient\n" );
else MSG_WriteString( &buf, "disconnect" );
if( !cls.netchan.remote_address.type )
cls.netchan.remote_address.type = NA_LOOPBACK;
if( NET_NetadrType( &cls.netchan.remote_address ) == NA_UNDEFINED )
NET_NetadrSetType( &cls.netchan.remote_address, NA_LOOPBACK );
// make sure message will be delivered
Netchan_TransmitBits( &cls.netchan, MSG_GetNumBitsWritten( &buf ), MSG_GetData( &buf ));
@@ -1593,6 +1587,9 @@ void CL_SetupNetchanForProtocol( connprotocol_t proto )
}
break;
default:
if( !Host_IsLocalClient( ))
SetBits( flags, NETCHAN_USE_LZSS );
cls.extensions = Q_atoi( Info_ValueForKey( Cmd_Argv( 1 ), "ext" ));
if( FBitSet( cls.extensions, NET_EXT_SPLITSIZE ))
@@ -1716,19 +1713,17 @@ CL_LocalServers_f
*/
static void CL_LocalServers_f( void )
{
netadr_t adr;
memset( &adr, 0, sizeof( adr ));
netadr_t adr = { 0 };
Con_Printf( "Scanning for servers on the local network area...\n" );
NET_Config( true, true ); // allow remote
// send a broadcast packet
adr.type = NA_BROADCAST;
NET_NetadrSetType( &adr, NA_BROADCAST );
adr.port = MSG_BigShort( PORT_SERVER );
Netchan_OutOfBandPrint( NS_CLIENT, adr, A2A_INFO" %i", PROTOCOL_VERSION );
adr.type = NA_MULTICAST_IP6;
NET_NetadrSetType( &adr, NA_MULTICAST_IP6 );
Netchan_OutOfBandPrint( NS_CLIENT, adr, A2A_INFO" %i", PROTOCOL_VERSION );
}
@@ -1760,8 +1755,8 @@ static size_t NONNULL CL_BuildMasterServerScanRequest( char *buf, size_t size, u
// let master know about client version
Info_SetValueForKey( info, "clver", XASH_VERSION, remaining );
Info_SetValueForKey( info, "nat", nat ? "1" : "0", remaining );
Info_SetValueForKey( info, "commit", Q_buildcommit(), remaining );
Info_SetValueForKey( info, "branch", Q_buildbranch(), remaining );
Info_SetValueForKey( info, "commit", g_buildcommit, remaining );
Info_SetValueForKey( info, "branch", g_buildbranch, remaining );
Info_SetValueForKey( info, "os", Q_buildos(), remaining );
Info_SetValueForKey( info, "arch", Q_buildarch(), remaining );
@@ -2472,18 +2467,18 @@ static void CL_ServerList( netadr_t from, sizebuf_t *msg )
while( MSG_GetNumBitsLeft( msg ) > 8 )
{
uint8_t addr[16];
netadr_t servadr;
netadr_t servadr = { 0 };
if( from.type6 == 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 ));
NET_IP6BytesToNetadr( &servadr, addr );
servadr.type6 = NA_IP6;
NET_NetadrSetType( &servadr, NA_IP6 );
}
else
{
MSG_ReadBytes( msg, servadr.ip, sizeof( servadr.ip )); // 4 bytes for IP
servadr.type = NA_IP;
NET_NetadrSetType( &servadr, NA_IP );
}
servadr.port = MSG_ReadShort( msg ); // 2 bytes for Port
@@ -3131,6 +3126,9 @@ static qboolean CL_ShouldRescanFilesystem( void )
}
}
if( FBitSet( fs_mount_lv.flags|fs_mount_hd.flags|fs_mount_addon.flags|fs_mount_l10n.flags|ui_language.flags, FCVAR_CHANGED ))
retval = true;
return retval;
}
@@ -3140,7 +3138,7 @@ qboolean CL_PrecacheResources( void )
// if we downloaded new WAD files or any other archives they must be added to searchpath
if( CL_ShouldRescanFilesystem( ))
g_fsapi.Rescan();
FS_Rescan_f();
// NOTE: world need to be loaded as first model
for( pRes = cl.resourcesonhand.pNext; pRes && pRes != &cl.resourcesonhand; pRes = pRes->pNext )
@@ -3326,6 +3324,22 @@ static void CL_Escape_f( void )
else UI_SetActiveMenu( true );
}
static void CL_ListMessages_f( void )
{
int i;
Con_Printf( "num size name\n" );
for( i = 0; i < MAX_USER_MESSAGES; i++ )
{
if( !COM_CheckStringEmpty( clgame.msg[i].name ))
break;
Con_Printf( "%3d\t%3d\t%s\n", clgame.msg[i].number, clgame.msg[i].size, clgame.msg[i].name );
}
Con_Printf( "Total %i messages\n", i );
}
/*
=================
CL_InitLocal
@@ -3370,6 +3384,7 @@ static void CL_InitLocal( void )
Cvar_RegisterVariable( &rcon_address );
Cvar_RegisterVariable( &cl_trace_consistency );
Cvar_RegisterVariable( &cl_trace_stufftext );
Cvar_RegisterVariable( &cl_trace_messages );
Cvar_RegisterVariable( &cl_trace_events );
@@ -3464,6 +3479,8 @@ static void CL_InitLocal( void )
Cmd_AddCommand ("fullserverinfo", CL_FullServerinfo_f, "sent by server when serverinfo changes" );
Cmd_AddCommand ("upload", CL_BeginUpload_f, "uploading file to the server" );
Cmd_AddRestrictedCommand( "replaybufferdat", CL_ReplayBufferDat_f, "development and debugging tool" );
Cmd_AddRestrictedCommand ("quit", CL_Quit_f, "quit from game" );
Cmd_AddRestrictedCommand ("exit", CL_Quit_f, "quit from game" );
@@ -3483,6 +3500,7 @@ static void CL_InitLocal( void )
Cmd_AddCommand( "richpresence_gamemode", Cmd_Null_f, "compatibility command, does nothing" );
Cmd_AddCommand( "richpresence_update", Cmd_Null_f, "compatibility command, does nothing" );
Cmd_AddCommand( "cl_list_messages", CL_ListMessages_f, "list registered user messages" );
}
//============================================================================
@@ -3640,6 +3658,8 @@ void CL_Init( void )
if( !CL_LoadProgs( libpath ))
Host_Error( "can't initialize %s: %s\n", libpath, COM_GetLibraryError( ));
ID_Init();
cls.build_num = 0;
cls.initialized = true;
cl.maxclients = 1; // allow to drawing player in menu

View File

@@ -19,6 +19,7 @@ GNU General Public License for more details.
#include "library.h"
#include "input.h"
#include "platform/platform.h"
#include "utflib.h"
static CVAR_DEFINE_AUTO( vibration_length, "1.0", FCVAR_ARCHIVE | FCVAR_PRIVILEGED, "vibration length" );
static CVAR_DEFINE_AUTO( vibration_enable, "1", FCVAR_ARCHIVE | FCVAR_PRIVILEGED, "enable vibration" );
@@ -58,7 +59,13 @@ static int pfnDrawScaledCharacter( int x, int y, int number, int r, int g, int b
int flags = FONT_DRAW_HUD;
if( hud_utf8.value )
SetBits( flags, FONT_DRAW_UTF8 );
{
static utfstate_t utfstate;
number = Q_DecodeUTF8( &utfstate, number );
if( !number )
return 0;
}
if( fabs( g_font_scale - scale ) > 0.1f ||
g_scaled_font.hFontTexture != cls.creditsFont.hFontTexture )
@@ -92,6 +99,11 @@ static char *pfnParseFileSafe( char *data, char *buf, const int size, unsigned i
return COM_ParseFileSafe( data, buf, size, flags, len, NULL );
}
static void GAME_EXPORT pfnSetCustomClientID( const char *id )
{
// deprecated
}
static const mobile_engfuncs_t gMobileEngfuncs =
{
MOBILITY_API_VERSION,
@@ -106,7 +118,7 @@ static const mobile_engfuncs_t gMobileEngfuncs =
pfnDrawScaledCharacter,
Sys_Warn,
Sys_GetNativeObject,
ID_SetCustomClientID,
pfnSetCustomClientID,
pfnParseFileSafe
};

View File

@@ -311,10 +311,13 @@ static client entity
static void CL_ParseStaticEntity( sizebuf_t *msg )
{
int i, newnum;
entity_state_t from, to;
const entity_state_t from = { 0 };
entity_state_t to;
cl_entity_t *ent;
memset( &from, 0, sizeof( from ));
if( !clgame.static_entities )
clgame.static_entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
MSG_ReadDeltaEntity( msg, &from, &to, 0, DELTA_STATIC, cl.mtime[0] );
@@ -1322,11 +1325,11 @@ void CL_ParseLightStyle( sizebuf_t *msg, connprotocol_t proto )
{
int style;
const char *s;
float f = 0.0f;
float f = cl.mtime[0];
style = MSG_ReadByte( msg );
s = MSG_ReadString( msg );
if( proto != PROTO_GOLDSRC )
if( proto != PROTO_GOLDSRC && proto != PROTO_QUAKE )
f = MSG_ReadFloat( msg );
CL_SetLightstyle( style, s, f );
@@ -1424,37 +1427,31 @@ register new user message or update existing
void CL_RegisterUserMessage( sizebuf_t *msg, connprotocol_t proto )
{
char *pszName;
int svc_num, size, bits;
svc_num = MSG_ReadByte( msg );
char szName[17];
int size;
int svc_num = MSG_ReadByte( msg );
if( proto == PROTO_LEGACY || proto == PROTO_GOLDSRC )
{
size = MSG_ReadByte( msg );
bits = 8;
if( size == UINT8_MAX )
size = -1;
}
else
{
size = MSG_ReadWord( msg );
bits = 16;
if( size == UINT16_MAX )
size = -1;
}
if( proto == PROTO_GOLDSRC )
{
static char szName[17];
MSG_ReadBytes( msg, szName, sizeof( szName ) - 1 );
szName[16] = 0;
pszName = szName;
}
else pszName = MSG_ReadString( msg );
// important stuff
if( size == ( BIT( bits ) - 1 ) )
size = -1;
svc_num = bound( 0, svc_num, 255 );
CL_LinkUserMessage( pszName, svc_num, size );
}
@@ -1593,17 +1590,23 @@ collect pings and packet lossage from clients
*/
void CL_UpdateUserPings( sizebuf_t *msg )
{
int i, slot;
player_info_t *player;
for( i = 0; i < MAX_CLIENTS; i++ )
// a1ba: there was a MAX_PLAYERS check but it doesn't make sense
// because pings message always ends by null bit
while( 1 )
{
if( !MSG_ReadOneBit( msg )) break; // end of message
int slot;
player_info_t *player;
if( !MSG_ReadOneBit( msg ))
break; // end of message
slot = MSG_ReadUBitLong( msg, MAX_CLIENT_BITS );
if( slot >= MAX_CLIENTS )
if( unlikely( slot >= MAX_CLIENTS ))
{
Host_Error( "%s: svc_pings > MAX_CLIENTS\n", __func__ );
return;
}
player = &cl.players[slot];
player->ping = MSG_ReadUBitLong( msg, 12 );
@@ -1611,6 +1614,23 @@ void CL_UpdateUserPings( sizebuf_t *msg )
}
}
static const char *CL_CheckTypeToString( int check_type )
{
// renamed so they have same width and look better in console output
switch( check_type )
{
case force_exactfile:
return "exactfile";
case force_model_samebounds:
return "samebounds";
case force_model_specifybounds:
return "specbounds";
case force_model_specifybounds_if_avail:
return "specbounds2";
}
return "unknown";
}
static void CL_SendConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
{
qboolean user_changed_diskfile;
@@ -1876,6 +1896,9 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
return;
}
if( cl_trace_consistency.value )
Con_Printf( "Server wants consistency of the following resources:\n" );
skip_crc_change = NULL;
lastcheck = 0;
@@ -1907,7 +1930,7 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
pc = &cl.consistency_list[cl.num_consistency];
cl.num_consistency++;
memset( pc, 0, sizeof( consistency_t ));
memset( pc, 0, sizeof( *pc ));
pc->filename = pResource->szFileName;
pc->issound = (pResource->type == t_sound);
pc->orig_index = delta;
@@ -1920,6 +1943,9 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
pc->check_type = pResource->rguc_reserved[0];
}
if( cl_trace_consistency.value )
Con_Printf( "%s\t%s\t%s\n", COM_ResourceTypeFromIndex( pResource->type ), CL_CheckTypeToString( pc->check_type ), pc->filename );
skip_crc_change = pResource;
lastcheck = delta;
}

View File

@@ -33,10 +33,12 @@ static client entity
static void CL_LegacyParseStaticEntity( sizebuf_t *msg )
{
int i;
entity_state_t state;
entity_state_t state = { 0 };
cl_entity_t *ent;
memset( &state, 0, sizeof( state ));
if( !clgame.static_entities )
clgame.static_entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
state.modelindex = MSG_ReadShort( msg );
state.sequence = MSG_ReadByte( msg );
state.frame = MSG_ReadByte( msg );

View File

@@ -83,7 +83,10 @@ static void CL_ParseNewMovevars( sizebuf_t *msg )
R_SetupSky( clgame.movevars.skyName );
clgame.oldmovevars = clgame.movevars;
clgame.entities->curstate.scale = clgame.movevars.waveHeight;
// FIXME: set world wave height when entities will be allocated
if( clgame.entities )
clgame.entities->curstate.scale = clgame.movevars.waveHeight;
// keep features an actual!
clgame.oldmovevars.features = clgame.movevars.features = host.features;
@@ -91,11 +94,11 @@ static void CL_ParseNewMovevars( sizebuf_t *msg )
typedef struct delta_header_t
{
qboolean remove : 1;
qboolean custom : 1;
qboolean instanced : 1;
uint instanced_baseline_index : 6;
uint offset : 6;
qboolean remove;
qboolean custom;
qboolean instanced;
uint16_t instanced_baseline_index;
uint16_t offset;
} delta_header_t;
static int CL_ParseDeltaHeader( sizebuf_t *msg, qboolean delta, int oldnum, struct delta_header_t *hdr )
@@ -160,33 +163,47 @@ static int CL_GetEntityDelta( const struct delta_header_t *hdr, int entnum )
return DT_ENTITY_STATE_T;
}
static void CL_FlushEntityPacketGS( frame_t *frame, sizebuf_t *msg )
static int CL_FlushEntityPacketGS( frame_t *frame, sizebuf_t *msg )
{
int playerbytes = 0, numbase = 0;
frame->valid = false;
cl.validsequence = 0; // can't render a frame
// read it all but ignore it
while( 1 )
{
int num = 0;
int newnum, bufstart;
entity_state_t from = { 0 }, to;
delta_header_t hdr;
qboolean player;
if( MSG_ReadWord( msg ) != 0 )
{
MSG_SeekToBit( msg, -16, SEEK_CUR );
num = CL_ParseDeltaHeader( msg, false, num, &hdr );
numbase = newnum = CL_ParseDeltaHeader( msg, true, numbase, &hdr );
}
else break;
if( MSG_CheckOverflow( msg ))
Host_Error( "%s: overflow\n", __func__ );
player = CL_IsPlayerIndex( newnum );
bufstart = MSG_GetNumBytesRead( msg );
if( hdr.remove )
continue;
Delta_ReadGSFields( msg, CL_GetEntityDelta( &hdr, num ), &from, &to, cl.mtime[0] );
Delta_ReadGSFields( msg, CL_GetEntityDelta( &hdr, newnum ), &from, &to, cl.mtime[0] );
if( player )
playerbytes += MSG_GetNumBytesRead( msg ) - bufstart;
}
if( MSG_CheckOverflow( msg ))
Host_Error( "%s: overflow\n", __func__ );
return playerbytes;
}
static void CL_DeltaEntityGS( const delta_header_t *hdr, sizebuf_t *msg, frame_t *frame, int newnum, const entity_state_t *from )
@@ -203,7 +220,7 @@ static void CL_DeltaEntityGS( const delta_header_t *hdr, sizebuf_t *msg, frame_t
if(( newnum < 0 ) || ( newnum >= clgame.maxEntities ))
{
Con_DPrintf( S_ERROR "CL_DeltaEntity: invalid newnum: %d\n", newnum );
Host_Error( "%s: bad delta entity number: %i", __func__, newnum );
Host_Error( "%s: bad delta entity number: %i\n", __func__, newnum );
return;
}
@@ -267,7 +284,7 @@ static void CL_CopyPacketEntity( frame_t *frame, int num, const entity_state_t *
static int CL_ParsePacketEntitiesGS( sizebuf_t *msg, qboolean delta )
{
frame_t *frame, *oldframe;
int oldindex, newnum, oldnum, numbase = 0;
int oldindex, oldnum, numbase = 0;
entity_state_t *oldent;
int count;
int playerbytes = 0;
@@ -314,7 +331,7 @@ static int CL_ParsePacketEntitiesGS( sizebuf_t *msg, qboolean delta )
// read it all but ignore it
while( 1 )
{
int bufstart;
int bufstart, newnum;
qboolean player;
delta_header_t hdr;
int val = MSG_ReadWord( msg );
@@ -534,7 +551,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
{
if( MSG_CheckOverflow( msg ))
{
Host_Error( "CL_ParseServerMessage: overflow!\n" );
Host_Error( "%s: overflow!\n", __func__ );
return;
}
@@ -615,7 +632,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
case svc_setangle:
CL_ParseSetAngle( msg );
break;
case svc_goldsrc_serverinfo:
case svc_serverdata:
Cbuf_Execute(); // make sure any stuffed commands are done
CL_ParseServerData( msg, PROTO_GOLDSRC );
break;
@@ -625,7 +642,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
case svc_updateuserinfo:
CL_UpdateUserinfo( msg, PROTO_GOLDSRC );
break;
case svc_goldsrc_deltadescription:
case svc_deltatable:
Delta_ParseTableField_GS( msg );
break;
case svc_clientdata:
@@ -687,7 +704,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
case svc_addangle:
CL_ParseAddAngle( msg );
break;
case svc_goldsrc_newusermsg:
case svc_usermessage:
CL_RegisterUserMessage( msg, PROTO_GOLDSRC );
break;
case svc_packetentities:
@@ -709,7 +726,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
CL_ParseResourceList( msg, PROTO_GOLDSRC );
MSG_EndBitWriting( msg );
break;
case svc_goldsrc_newmovevars:
case svc_deltamovevars:
CL_ParseNewMovevars( msg );
break;
case svc_resourcerequest:
@@ -749,10 +766,10 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
Con_Reportf( S_ERROR "%s: svc_goldsrc_timescale: implement me!\n", __func__ );
MSG_ReadFloat( msg );
break;
case svc_goldsrc_sendcvarvalue:
case svc_querycvarvalue:
CL_ParseCvarValue( msg, false, PROTO_GOLDSRC );
break;
case svc_goldsrc_sendcvarvalue2:
case svc_querycvarvalue2:
CL_ParseCvarValue( msg, true, PROTO_GOLDSRC );
break;
case svc_exec:

View File

@@ -628,11 +628,12 @@ CL_ParseStaticEntity
*/
static void CL_ParseQuakeStaticEntity( sizebuf_t *msg )
{
entity_state_t state;
entity_state_t state = { 0 };
cl_entity_t *ent;
int i;
memset( &state, 0, sizeof( state ));
if( !clgame.static_entities )
clgame.static_entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
state.modelindex = MSG_ReadByte( msg );
state.frame = MSG_ReadByte( msg );
@@ -969,9 +970,7 @@ void CL_ParseQuakeMessage( sizebuf_t *msg )
CL_ParseQuakeServerInfo( msg );
break;
case svc_lightstyle:
param1 = MSG_ReadByte( msg );
str = MSG_ReadString( msg );
CL_SetLightstyle( param1, str, cl.mtime[0] );
CL_ParseLightStyle( msg, PROTO_QUAKE );
break;
case svc_updatename:
param1 = MSG_ReadByte( msg );

View File

@@ -138,10 +138,7 @@ intptr_t CL_RenderGetParm( const int parm, const int arg, const qboolean checkRe
switch( parm )
{
case PARM_BSP2_SUPPORTED:
#ifdef SUPPORT_BSP2_FORMAT
return 1;
#endif
return 0;
case PARAM_GAMEPAUSED:
return cl.paused;
case PARM_CLIENT_INGAME:
@@ -236,6 +233,11 @@ static intptr_t pfnRenderGetParm( int parm, int arg )
return CL_RenderGetParm( parm, arg, true );
}
static void pfnAVI_StreamSound( void *avi, int entnum, float fvol, float attn, float synctime )
{
return; // stub, use AVI_SetParm and AVI_Think to stream AVI sound
}
static render_api_t gRenderAPI =
{
pfnRenderGetParm, // GL_RenderGetParm,
@@ -268,7 +270,7 @@ static render_api_t gRenderAPI =
NULL, // R_UploadStretchRaw,
(void*)AVI_FreeVideo,
(void*)AVI_IsActive,
S_StreamAviSamples,
(void*)pfnAVI_StreamSound,
NULL,
NULL,
NULL, // GL_Bind,

View File

@@ -124,7 +124,7 @@ void SCR_DrawPos( void )
if( cls.state != ca_active || !cl_showpos.value || cl.background )
return;
ent = CL_EDICT_NUM( cl.playernum + 1 );
ent = CL_GetLocalPlayer();
speed = VectorLength( cl.simvel );
Q_snprintf( msg, MAX_SYSPATH,

View File

@@ -567,57 +567,54 @@ R_FizzEffect
Create a fizz effect
==============
*/
void GAME_EXPORT R_FizzEffect( cl_entity_t *pent, int modelIndex, int density )
void GAME_EXPORT R_FizzEffect( cl_entity_t *ent, int modelIndex, int density )
{
TEMPENTITY *pTemp;
int i, width, depth;
float angle, maxHeight, speed;
float xspeed, yspeed, zspeed;
vec3_t origin;
model_t *mod;
const float base_time = cl.time - 0.1f;
model_t *mod = CL_ModelHandle( modelIndex );
vec3_t volume, mins, maxs;
vec2_t speed;
int i;
if( !pent || !pent->model || !modelIndex )
if( !ent || !ent->model || !modelIndex || !mod )
return;
if(( mod = CL_ModelHandle( modelIndex )) == NULL )
return;
VectorCopy( ent->model->mins, mins );
VectorCopy( ent->model->maxs, maxs );
maxHeight = pent->model->maxs[2] - pent->model->mins[2];
width = pent->model->maxs[0] - pent->model->mins[0];
depth = pent->model->maxs[1] - pent->model->mins[1];
if( ent->angles[1] != 0.0f )
{
const float base_speed = ( ent->curstate.rendercolor.b ? -1.0f : 1.0f ) * ( ent->curstate.rendercolor.r * 256.0f + ent->curstate.rendercolor.g );
SinCos( DEG2RAD( ent->angles[1] ), &speed[1], &speed[0] );
speed[0] *= base_speed;
speed[1] *= base_speed;
}
else speed[0] = speed[1] = 0.0f;
speed = ( pent->curstate.rendercolor.r<<8 | pent->curstate.rendercolor.g );
if( pent->curstate.rendercolor.b )
speed = -speed;
angle = DEG2RAD( pent->angles[YAW] );
SinCos( angle, &yspeed, &xspeed );
xspeed *= speed;
yspeed *= speed;
VectorSubtract( maxs, mins, volume );
for( i = 0; i <= density; i++ )
{
origin[0] = mod->mins[0] + COM_RandomLong( 0, width - 1 );
origin[1] = mod->mins[1] + COM_RandomLong( 0, depth - 1 );
origin[2] = mod->mins[2];
pTemp = CL_TempEntAlloc( origin, mod );
TEMPENTITY *tent;
vec3_t origin;
if ( !pTemp ) return;
VectorCopy( mins, origin );
origin[0] += COM_RandomLong( 0, (int)volume[0] - 1 );
origin[1] += COM_RandomLong( 0, (int)volume[1] - 1 );
pTemp->flags |= FTENT_SINEWAVE;
if( !( tent = CL_TempEntAlloc( origin, mod )))
return;
pTemp->x = origin[0];
pTemp->y = origin[1];
tent->x = origin[0];
tent->y = origin[1];
tent->die = base_time;
tent->flags |= FTENT_SINEWAVE;
tent->entity.curstate.rendermode = kRenderTransAlpha;
Vector2Copy( speed, tent->entity.baseline.origin );
zspeed = COM_RandomLong( 80, 140 );
VectorSet( pTemp->entity.baseline.origin, xspeed, yspeed, zspeed );
pTemp->die = cl.time + ( maxHeight / zspeed ) - 0.1f;
pTemp->entity.curstate.frame = COM_RandomLong( 0, pTemp->frameMax );
// Set sprite scale
pTemp->entity.curstate.scale = 1.0f / COM_RandomFloat( 2.0f, 5.0f );
pTemp->entity.curstate.rendermode = kRenderTransAlpha;
pTemp->entity.curstate.renderamt = 255;
tent->entity.baseline.origin[2] = COM_RandomLong( 80, 140 );
tent->die += volume[2] / tent->entity.baseline.origin[2];
tent->entity.curstate.frame = COM_RandomLong( 0, tent->frameMax );
tent->entity.curstate.scale = 1.0f / COM_RandomFloat( 2.0f, 5.0f );
}
}
@@ -2427,18 +2424,18 @@ static void CL_ClearLightStyles( void )
void CL_SetLightstyle( int style, const char *s, float f )
{
int i, k;
lightstyle_t *ls;
float val1, val2;
int i;
lightstyle_t *ls;
Assert( s != NULL );
Assert( 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 );
return;
}
ls = &cl.lightstyles[style];
Q_strncpy( ls->pattern, s, sizeof( ls->pattern ));
ls->length = Q_strlen( s );
ls->length = Q_strncpy( ls->pattern, s, sizeof( ls->pattern ));
ls->time = f; // set local time
for( i = 0; i < ls->length; i++ )
@@ -2448,10 +2445,10 @@ void CL_SetLightstyle( int style, const char *s, float f )
// check for allow interpolate
// NOTE: fast flickering styles looks ugly when interpolation is running
for( k = 0; k < (ls->length - 1); k++ )
for( i = 0; i < ( ls->length - 1 ); i++ )
{
val1 = ls->map[(k+0) % ls->length];
val2 = ls->map[(k+1) % ls->length];
float val1 = ls->map[( i + 0 ) % ls->length];
float val2 = ls->map[( i + 1 ) % ls->length];
if( fabs( val1 - val2 ) > STYLE_LERPING_THRESHOLD )
{
@@ -2471,8 +2468,8 @@ DLIGHT MANAGEMENT
==============================================================
*/
dlight_t cl_dlights[MAX_DLIGHTS];
dlight_t cl_elights[MAX_ELIGHTS];
static dlight_t cl_dlights[MAX_DLIGHTS];
static dlight_t cl_elights[MAX_ELIGHTS];
/*
================

View File

@@ -466,8 +466,8 @@ static void R_ShowTree_r( mnode_t *node, float x, float y, float scale, int show
R_DrawNodeConnection( x, y, x + scale, y + scale );
}
R_ShowTree_r( node->children[1], x - scale, y + scale, downScale, shownodes, viewleaf );
R_ShowTree_r( node->children[0], x + scale, y + scale, downScale, shownodes, viewleaf );
R_ShowTree_r( node_child( node, 1, cl.worldmodel ), x - scale, y + scale, downScale, shownodes, viewleaf );
R_ShowTree_r( node_child( node, 0, cl.worldmodel ), x + scale, y + scale, downScale, shownodes, viewleaf );
world.recursion_level--;
}
@@ -482,7 +482,7 @@ static void R_ShowTree( void )
return;
world.recursion_level = 0;
viewleaf = Mod_PointInLeaf( refState.vieworg, cl.worldmodel->nodes );
viewleaf = Mod_PointInLeaf( refState.vieworg, cl.worldmodel->nodes, cl.worldmodel );
ref.dllFuncs.TriRenderMode( kRenderTransTexture );

View File

@@ -326,8 +326,12 @@ typedef struct
pfnEventHook func; // user-defined function
} cl_user_event_t;
#define FONT_FIXED 0
#define FONT_VARIABLE 1
enum
{
FONT_FIXED,
FONT_VARIABLE,
FONT_TRUETYPE
};
#define FONT_DRAW_HUD BIT( 0 ) // pass to drawing function to apply hud_scale
#define FONT_DRAW_UTF8 BIT( 1 ) // call UtfProcessChar
@@ -495,7 +499,9 @@ typedef struct
cl_entity_t viewent; // viewmodel
#if XASH_WIN32
qboolean client_dll_uses_sdl;
#endif
} clgame_static_t;
typedef struct
@@ -686,6 +692,7 @@ extern convar_t r_showtextures;
extern convar_t cl_bmodelinterp;
extern convar_t cl_lw; // local weapons
extern convar_t cl_charset;
extern convar_t cl_trace_consistency;
extern convar_t cl_trace_stufftext;
extern convar_t cl_trace_messages;
extern convar_t cl_trace_events;
@@ -734,6 +741,7 @@ void CL_ClearResourceLists( void );
//
// cl_debug.c
//
void CL_ReplayBufferDat_f( void );
void CL_Parse_Debug( qboolean enable );
void CL_Parse_RecordCommand( int cmd, int startoffset );
void CL_ResetFrame( frame_t *frame );
@@ -765,7 +773,7 @@ void CL_StartupDemoHeader( void );
void CL_DrawDemoRecording( void );
void CL_WriteDemoUserCmd( int cmdnumber );
void CL_WriteDemoMessage( qboolean startup, int start, sizebuf_t *msg );
void CL_WriteDemoUserMessage( const byte *buffer, size_t size );
void CL_WriteDemoUserMessage( int size, byte *buffer );
qboolean CL_DemoReadMessage( byte *buffer, size_t *length );
void CL_DemoInterpolateAngles( void );
void CL_CheckStartupDemos( void );
@@ -803,11 +811,12 @@ qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float sc
qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float scale, convar_t *rendermode, uint texFlags );
void CL_FreeFont( cl_font_t *font );
void CL_SetFontRendermode( cl_font_t *font );
int CL_DrawCharacter( float x, float y, int number, rgba_t color, cl_font_t *font, int flags );
int CL_DrawString( float x, float y, const char *s, rgba_t color, cl_font_t *font, int flags );
void CL_DrawCharacterLen( cl_font_t *font, int number, int *width, int *height );
void CL_DrawStringLen( cl_font_t *font, const char *s, int *width, int *height, int flags );
int CL_DrawStringf( cl_font_t *font, float x, float y, rgba_t color, int flags, const char *fmt, ... ) FORMAT_CHECK( 6 );
int CL_DrawCharacter( float x, float y, uint32_t uc, const rgba_t color, const cl_font_t *font, int flags );
void CL_DrawCharacterLen( const cl_font_t *font, uint32_t uc, int *width, int *height );
int CL_DrawString( float x, float y, const char *s, const rgba_t color, const cl_font_t *font, int flags );
int CL_DrawStringf( const cl_font_t *font, float x, float y, const rgba_t color, int flags, const char *fmt, ... ) FORMAT_CHECK( 6 );
void CL_DrawStringLen( const cl_font_t *font, const char *s, int *width, int *height, int flags );
//
@@ -840,19 +849,21 @@ void CL_EnableScissor( scissor_state_t *scissor, int x, int y, int width, int he
void CL_DisableScissor( scissor_state_t *scissor );
qboolean CL_Scissor( const scissor_state_t *scissor, float *x, float *y, float *width, float *height, float *u0, float *v0, float *u1, float *v1 );
static inline cl_entity_t *CL_EDICT_NUM( int n )
static inline cl_entity_t *CL_EDICT_NUM( int index )
{
if( !clgame.entities )
if( !clgame.entities ) // not in game yet
{
Host_Error( "%s: clgame.entities is NULL\n", __func__ );
return NULL;
}
if(( n >= 0 ) && ( n < clgame.maxEntities ))
return clgame.entities + n;
if( index < 0 || index >= clgame.maxEntities )
{
Host_Error( "%s: bad number %i\n", __func__, index );
return NULL;
}
Host_Error( "%s: bad number %i\n", __func__, n );
return NULL;
return clgame.entities + index;
}
static inline cl_entity_t *CL_GetEntityByIndex( int index )
@@ -863,10 +874,7 @@ static inline cl_entity_t *CL_GetEntityByIndex( int index )
if( index < 0 || index >= clgame.maxEntities )
return NULL;
if( index == 0 )
return clgame.entities;
return CL_EDICT_NUM( index );
return clgame.entities + index;
}
static inline model_t *CL_ModelHandle( int modelindex )
@@ -876,15 +884,17 @@ static inline model_t *CL_ModelHandle( int modelindex )
static inline qboolean CL_IsThirdPerson( void )
{
return clgame.dllFuncs.CL_IsThirdPerson() ? true : false;
return clgame.dllFuncs.CL_IsThirdPerson();
}
static inline cl_entity_t *CL_GetLocalPlayer( void )
{
cl_entity_t *player;
cl_entity_t *player = CL_GetEntityByIndex( cl.playernum + 1 );
player = CL_EDICT_NUM( cl.playernum + 1 );
Assert( player != NULL );
// HACKHACK: GoldSrc doesn't do this, but some mods actually check it for null pointer
// this is a lesser evil than changing semantics of HUD_VidInit and call it after entities are allocated
if( !player )
Con_Printf( S_WARN "%s: client entities are not initialized yet! Returning NULL...\n", __func__ );
return player;
}
@@ -1085,6 +1095,7 @@ void CL_ReadLineFile_f( void );
// console.c
//
extern convar_t con_fontsize;
extern int g_codepage;
int Con_Visible( void );
qboolean Con_FixedFont( void );
void Con_VidInit( void );
@@ -1095,14 +1106,13 @@ void Con_DrawDebug( void );
void Con_RunConsole( void );
void Con_DrawConsole( void );
void Con_DrawVersion( void );
int Con_UtfProcessChar( int in );
int Con_UtfProcessCharForce( int in );
int Con_UtfMoveLeft( char *str, int pos );
int Con_UtfMoveRight( char *str, int pos, int length );
void Con_DefaultColor( int r, int g, int b, qboolean gameui );
cl_font_t *Con_GetCurFont( void );
cl_font_t *Con_GetFont( int num );
int Con_DrawString( int x, int y, const char *string, rgba_t setColor ); // legacy, use cl_font.c
int Con_DrawString( int x, int y, const char *string, const rgba_t setColor ); // legacy, use cl_font.c
void GAME_EXPORT Con_DrawStringLen( const char *pText, int *length, int *height ); // legacy, use cl_font.c
void Con_CharEvent( int key );
void Key_Console( int key );
@@ -1115,7 +1125,7 @@ void Con_PageUp( int lines );
//
// s_main.c
//
void S_StreamAviSamples( void *Avi, int entnum, float fvol, float attn, float synctime );
typedef int sound_t;
void S_StartBackgroundTrack( const char *intro, const char *loop, int position, qboolean fullpath );
void S_StopBackgroundTrack( void );
void S_StreamSetPause( int pause );
@@ -1195,16 +1205,21 @@ void Key_Init( void );
void Key_WriteBindings( file_t *f );
const char *Key_GetBinding( int keynum );
void Key_SetBinding( int keynum, const char *binding );
const char *Key_LookupBinding( const char *pBinding );
void Key_ClearStates( void );
const char *Key_KeynumToString( int keynum );
int Key_StringToKeynum( const char *str );
int Key_GetKey( const char *binding );
void Key_EnumCmds_f( void );
void Key_SetKeyDest( int key_dest );
void Key_EnableTextInput( qboolean enable, qboolean force );
int Key_ToUpper( int key );
void OSK_Draw( void );
//
// identification.c
//
void ID_Init( void );
const char *ID_GetMD5( void );
extern rgba_t g_color_table[8];
extern triangleapi_t gTriApi;
extern net_api_t gNetApi;

View File

@@ -34,7 +34,7 @@ static CVAR_DEFINE_AUTO( con_color, "240 180 24", FCVAR_ARCHIVE, "set a custom c
static CVAR_DEFINE_AUTO( scr_drawversion, "1", FCVAR_ARCHIVE, "draw version in menu or screenshots, doesn't affect console" );
static CVAR_DEFINE_AUTO( con_oldfont, "0", 0, "use legacy font from gfx.wad, might be missing or broken" );
static int g_codepage = 0;
int g_codepage = 0;
static qboolean g_messagemode_privileged = true;
@@ -622,7 +622,7 @@ int Con_UtfProcessCharForce( int in )
// TODO: get rid of global state where possible
static utfstate_t state = { 0 };
int ch = Q_DecodeUTF8( &state, in );
uint32_t ch = Q_DecodeUTF8( &state, in );
if( g_codepage == 1251 )
return Q_UnicodeToCP1251( ch );
@@ -632,15 +632,6 @@ int Con_UtfProcessCharForce( int in )
return '?'; // not implemented yet
}
int GAME_EXPORT Con_UtfProcessChar( int in )
{
if( !cls.accept_utf8 ) // incoming character is not a UTF-8 sequence
return in;
// otherwise, decode it and convert to selected codepage
return Con_UtfProcessCharForce( in );
}
/*
=================
Con_UtfMoveLeft
@@ -759,7 +750,7 @@ Con_DrawString
client version of routine
====================
*/
int Con_DrawString( int x, int y, const char *string, rgba_t setColor )
int Con_DrawString( int x, int y, const char *string, const rgba_t setColor )
{
return CL_DrawString( x, y, string, setColor, con.curFont, FONT_DRAW_UTF8 );
}
@@ -843,11 +834,14 @@ If no console is visible, the notify window will pop up.
*/
void Con_Print( const char *txt )
{
static int cr_pending = 0;
static char buf[MAX_PRINT_MSG];
qboolean norefresh = false;
static int lastlength = 0;
static int bufpos = 0;
static qboolean cr_pending = false;
static qboolean colorstring = false;
static char buf[MAX_PRINT_MSG];
static int lastlength = 0;
static int bufpos = 0;
static int charpos = 0;
qboolean norefresh = false;
int c, mask = 0;
// client not running
@@ -873,7 +867,7 @@ void Con_Print( const char *txt )
if( cr_pending )
{
Con_DeleteLastLine();
cr_pending = 0;
cr_pending = false;
}
c = *txt;
@@ -886,23 +880,42 @@ void Con_Print( const char *txt )
{
Con_AddLine( buf, bufpos, true );
lastlength = CON_LINES_LAST().length;
cr_pending = 1;
cr_pending = true;
bufpos = 0;
charpos = 0;
}
break;
case '\n':
Con_AddLine( buf, bufpos, true );
lastlength = CON_LINES_LAST().length;
bufpos = 0;
charpos = 0;
break;
default:
buf[bufpos++] = c | mask;
if(( bufpos >= sizeof( buf ) - 1 ) || bufpos >= ( con.linewidth - 1 ))
if( IsColorString( txt ))
{
// first color string character
colorstring = true;
}
else if( colorstring )
{
// second color string character
colorstring = false;
}
else
{
// not a color string, move char counter
charpos++;
}
if(( bufpos >= sizeof( buf ) - 1 ) || charpos >= ( con.linewidth - 1 ))
{
Con_AddLine( buf, bufpos, true );
lastlength = CON_LINES_LAST().length;
bufpos = 0;
charpos = 0;
}
break;
}
@@ -918,6 +931,7 @@ void Con_Print( const char *txt )
Con_AddLine( buf, bufpos, lastlength != 0 );
lastlength = 0;
bufpos = 0;
charpos = 0;
}
// pump messages to avoid window hanging
@@ -1244,45 +1258,16 @@ static void Field_CharEvent( field_t *edit, int ch )
Field_DrawInputLine
==================
*/
static void Field_DrawInputLine( int x, int y, field_t *edit )
static void Field_DrawInputLine( int x, int y, const field_t *edit )
{
int len, cursorChar;
int drawLen;
int prestep, curPos;
char str[MAX_SYSPATH];
byte *colorDefault;
int curPos;
char str[MAX_SYSPATH];
const byte *colorDefault = g_color_table[ColorIndex( COLOR_DEFAULT )];
const int prestep = bound( 0, edit->scroll, sizeof( edit->buffer ) - 1 );
const int drawLen = bound( 0, edit->widthInChars, sizeof( str ));
const int cursorCharPos = bound( 0, edit->cursor - prestep, sizeof( str ));
drawLen = edit->widthInChars;
len = Q_strlen( edit->buffer ) + 1;
colorDefault = g_color_table[ColorIndex( COLOR_DEFAULT )];
// guarantee that cursor will be visible
if( len <= drawLen )
{
prestep = 0;
}
else
{
if( edit->scroll + drawLen > len )
{
edit->scroll = len - drawLen;
if( edit->scroll < 0 ) edit->scroll = 0;
}
prestep = edit->scroll;
}
if( prestep + drawLen > len )
drawLen = len - prestep;
// extract <drawLen> characters from the field at <prestep>
drawLen = Q_min( drawLen, MAX_SYSPATH - 1 );
memcpy( str, edit->buffer + prestep, drawLen );
str[drawLen] = 0;
// save char for overstrike
cursorChar = str[edit->cursor - prestep];
Q_strncpy( str, edit->buffer + prestep, drawLen );
// draw it
CL_DrawString( x, y, str, colorDefault, con.curFont, FONT_DRAW_UTF8 );
@@ -1291,7 +1276,7 @@ static void Field_DrawInputLine( int x, int y, field_t *edit )
if((int)( host.realtime * 4 ) & 1 ) return; // off blink
// calc cursor position
str[edit->cursor - prestep] = 0;
str[cursorCharPos] = 0;
CL_DrawStringLen( con.curFont, str, &curPos, NULL, FONT_DRAW_UTF8 );
if( host.key_overstrike )
@@ -1467,6 +1452,16 @@ Handles history and console scrollback
*/
void Key_Console( int key )
{
// exit the console by pressing MINUS on NSwitch
// or both Back(Select)/Start buttons for everyone else
if( key == K_BACK_BUTTON || key == K_START_BUTTON || key == K_ESCAPE )
{
if( cls.state == ca_active && !cl.background )
Key_SetKeyDest( key_game );
else UI_SetActiveMenu( true );
return;
}
// ctrl-L clears screen
if( key == 'l' && Key_IsDown( K_CTRL ))
{
@@ -1575,16 +1570,6 @@ void Key_Console( int key )
return;
}
// exit the console by pressing MINUS on NSwitch
// or both Back(Select)/Start buttons for everyone else
if( key == K_BACK_BUTTON || key == K_START_BUTTON )
{
if( cls.state == ca_active && !cl.background )
Key_SetKeyDest( key_game );
else UI_SetActiveMenu( true );
return;
}
// pass to the normal editline routine
Field_KeyDownEvent( &con.input, key );
}
@@ -2008,7 +1993,7 @@ void Con_DrawVersion( void )
int start, height = refState.height;
string curbuild;
if( !scr_drawversion.value || CL_IsDevOverviewMode() == 2 || net_graph.value )
if( !scr_drawversion.value )
return;
if( cls.key_dest == key_menu )
@@ -2020,6 +2005,9 @@ void Con_DrawVersion( void )
{
qboolean draw_version;
if( CL_IsDevOverviewMode() == 2 || net_graph.value )
return;
draw_version = cls.scrshot_action == scrshot_normal
|| cls.scrshot_action == scrshot_snapshot
|| host.force_draw_version_time > host.realtime;
@@ -2092,10 +2080,7 @@ void Con_RunConsole( void )
}
else
{
Con_Printf( S_WARN "Unknown charset %s, defaulting to cp1252", con_charset.string );
Cvar_DirectSet( &con_charset, "cp1252" );
g_codepage = 1252;
g_codepage = 0;
}
cls.accept_utf8 = !Q_stricmp( cl_charset.string, "utf-8" );

View File

@@ -19,8 +19,8 @@ GNU General Public License for more details.
#if !XASH_WIN32
#include <dirent.h>
#endif
static char id_md5[33];
static char id_customid[MAX_STRING];
/*
==========================================================
@@ -590,28 +590,12 @@ static void ID_Check( void )
const char *ID_GetMD5( void )
{
if( id_customid[0] )
return id_customid;
return id_md5;
}
/*
===============
ID_SetCustomClientID
===============
*/
void GAME_EXPORT ID_SetCustomClientID( const char *id )
{
if( !id )
return;
Q_strncpy( id_customid, id, sizeof( id_customid ) );
}
void ID_Init( void )
{
MD5Context_t hash = {0};
MD5Context_t hash = { 0 };
byte md5[16];
int i;
@@ -632,7 +616,7 @@ void ID_Init( void )
#elif XASH_WIN32
{
CHAR szBuf[MAX_PATH];
ID_GetKeyData( HKEY_CURRENT_USER, "Software\\Xash3D\\", "xash_id", szBuf, MAX_PATH );
ID_GetKeyData( HKEY_CURRENT_USER, "Software\\"XASH_ENGINE_NAME"\\", "xash_id", szBuf, MAX_PATH );
sscanf(szBuf, "%016"PRIX64, &id);
id ^= SYSTEM_XOR_MASK;
@@ -686,7 +670,7 @@ void ID_Init( void )
{
CHAR Buf[MAX_PATH];
sprintf( Buf, "%016"PRIX64, id^SYSTEM_XOR_MASK );
ID_SetKeyData( HKEY_CURRENT_USER, "Software\\Xash3D\\", REG_SZ, "xash_id", Buf, Q_strlen(Buf) );
ID_SetKeyData( HKEY_CURRENT_USER, "Software\\"XASH_ENGINE_NAME"\\", REG_SZ, "xash_id", Buf, Q_strlen(Buf) );
}
#else
{

View File

@@ -43,7 +43,6 @@ static struct joy_axis_s
short val;
short prevval;
} joyaxis[MAX_AXES] = { 0 };
static byte currentbinding; // add posibility to remap keys, to place it in joykeys[]
static qboolean joy_initialized;
static CVAR_DEFINE_AUTO( joy_pitch, "100.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "joystick pitch sensitivity" );
@@ -60,9 +59,9 @@ static CVAR_DEFINE_AUTO( joy_pitch_deadzone, DEFAULT_JOY_DEADZONE, FCVAR_ARCHIVE
static CVAR_DEFINE_AUTO( joy_yaw_deadzone, DEFAULT_JOY_DEADZONE, FCVAR_ARCHIVE | FCVAR_FILTERABLE, "yaw axis deadzone. Value from 0 to 32767" );
static CVAR_DEFINE_AUTO( joy_axis_binding, "sfpyrl", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "axis hardware id to engine inner axis binding, "
"s - side, f - forward, y - yaw, p - pitch, r - left trigger, l - right trigger" );
static CVAR_DEFINE_AUTO( joy_found, "0", FCVAR_READ_ONLY, "is joystick is connected" );
static CVAR_DEFINE_AUTO( joy_index, "0", FCVAR_READ_ONLY, "current active joystick" );
CVAR_DEFINE_AUTO( joy_enable, "1", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "enable joystick" );
static CVAR_DEFINE_AUTO( joy_have_gyro, "0", FCVAR_READ_ONLY, "tells whether current active gamepad has gyroscope or not" );
static CVAR_DEFINE_AUTO( joy_calibrated, "0", FCVAR_READ_ONLY, "tells whether current active gamepad gyroscope has been calibrated or not" );
/*
============
@@ -71,7 +70,30 @@ Joy_IsActive
*/
qboolean Joy_IsActive( void )
{
return joy_found.value && joy_enable.value;
return joy_enable.value;
}
/*
===========
Joy_SetCapabilities
===========
*/
void Joy_SetCapabilities( qboolean have_gyro )
{
Cvar_FullSet( joy_have_gyro.name, have_gyro ? "1" : "0", joy_have_gyro.flags );
}
/*
===========
Joy_SetCalibrationState
===========
*/
void Joy_SetCalibrationState( joy_calibration_state_t state )
{
if( (int)joy_calibrated.value == state )
return;
Cvar_FullSet( joy_calibrated.name, va( "%d", state ), joy_calibrated.flags );
}
/*
@@ -81,7 +103,7 @@ Joy_HatMotionEvent
DPad events
============
*/
void Joy_HatMotionEvent( byte hat, byte value )
static void Joy_HatMotionEvent( int value )
{
struct
{
@@ -96,9 +118,6 @@ void Joy_HatMotionEvent( byte hat, byte value )
};
int i;
if( !joy_found.value )
return;
for( i = 0; i < ARRAYSIZE( keys ); i++ )
{
if( value & keys[i].mask )
@@ -225,7 +244,7 @@ static void Joy_ProcessStick( const engineAxis_t engineAxis, short value )
val |= Joy_GetHatValueForAxis( JOY_AXIS_SIDE );
val |= Joy_GetHatValueForAxis( JOY_AXIS_FWD );
Joy_HatMotionEvent( 0, val );
Joy_HatMotionEvent( val );
}
}
@@ -236,23 +255,9 @@ Joy_AxisMotionEvent
Axis events
=============
*/
void Joy_AxisMotionEvent( byte axis, short value )
void Joy_AxisMotionEvent( engineAxis_t engineAxis, short value )
{
if( !joy_found.value )
return;
if( axis >= MAX_AXES )
{
Con_Reportf( "Only 6 axes is supported\n" );
return;
}
Joy_KnownAxisMotionEvent( joyaxesmap[axis], value );
}
void Joy_KnownAxisMotionEvent( engineAxis_t engineAxis, short value )
{
if( engineAxis == JOY_AXIS_NULL )
if( engineAxis >= JOY_AXIS_NULL )
return;
if( value == joyaxis[engineAxis].val )
@@ -266,66 +271,14 @@ void Joy_KnownAxisMotionEvent( engineAxis_t engineAxis, short value )
/*
=============
Joy_BallMotionEvent
Joy_GyroEvent
Trackball events. UNDONE
Gyroscope events
=============
*/
void Joy_BallMotionEvent( byte ball, short xrel, short yrel )
void Joy_GyroEvent( vec3_t data )
{
//if( !joy_found.value )
// return;
}
/*
=============
Joy_ButtonEvent
Button events
=============
*/
void Joy_ButtonEvent( byte button, byte down )
{
if( !joy_found.value )
return;
// generic game button code.
if( button > 32 )
{
int origbutton = button;
button = ( button & 31 ) + K_AUX1;
Con_Reportf( "Only 32 joybuttons is supported, converting %i button ID to %s\n", origbutton, Key_KeynumToString( button ) );
}
else button += K_AUX1;
Key_Event( button, down );
}
/*
=============
Joy_RemoveEvent
Called when joystick is removed. For future expansion
=============
*/
void Joy_RemoveEvent( void )
{
if( joy_found.value )
Cvar_FullSet( "joy_found", "0", FCVAR_READ_ONLY );
}
/*
=============
Joy_RemoveEvent
Called when joystick is removed. For future expansion
=============
*/
void Joy_AddEvent( void )
{
if( joy_enable.value && !joy_found.value )
Cvar_FullSet( "joy_found", "1", FCVAR_READ_ONLY );
}
/*
@@ -364,14 +317,19 @@ void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw )
*fw -= joy_forward.value * (float)joyaxis[JOY_AXIS_FWD ].val/(float)SHRT_MAX; // must be form -1.0 to 1.0
*side += joy_side.value * (float)joyaxis[JOY_AXIS_SIDE].val/(float)SHRT_MAX;
#if !defined(XASH_SDL)
*dpitch += joy_pitch.value * (float)joyaxis[JOY_AXIS_PITCH].val/(float)SHRT_MAX * host.realframetime; // abs axis rotate is frametime related
*dyaw -= joy_yaw.value * (float)joyaxis[JOY_AXIS_YAW ].val/(float)SHRT_MAX * host.realframetime;
#else
// HACKHACK: SDL have inverted look axis.
*dpitch -= joy_pitch.value * (float)joyaxis[JOY_AXIS_PITCH].val/(float)SHRT_MAX * host.realframetime;
*dyaw += joy_yaw.value * (float)joyaxis[JOY_AXIS_YAW ].val/(float)SHRT_MAX * host.realframetime;
#endif
}
static void Joy_CalibrateGyro_f( void )
{
if( !joy_have_gyro.value )
{
Con_Printf( "Current active gamepad doesn't have gyroscope\n" );
return;
}
Platform_CalibrateGamepadGyro();
}
/*
@@ -383,6 +341,8 @@ Main init procedure
*/
void Joy_Init( void )
{
Cmd_AddRestrictedCommand( "joy_calibrate_gyro", Joy_CalibrateGyro_f, "calibrate gamepad gyroscope. You must to put gamepad on stationary surface" );
Cvar_RegisterVariable( &joy_pitch );
Cvar_RegisterVariable( &joy_yaw );
Cvar_RegisterVariable( &joy_side );
@@ -402,11 +362,9 @@ void Joy_Init( void )
Cvar_RegisterVariable( &joy_yaw_deadzone );
Cvar_RegisterVariable( &joy_axis_binding );
Cvar_RegisterVariable( &joy_found );
// we doesn't loaded config.cfg yet, so this cvar is not archive.
// change by +set joy_index in cmdline
Cvar_RegisterVariable( &joy_index );
Cvar_RegisterVariable( &joy_have_gyro );
Cvar_RegisterVariable( &joy_calibrated );
Cvar_RegisterVariable( &joy_enable );
// renamed from -nojoy to -noenginejoy to not conflict with
@@ -417,7 +375,7 @@ void Joy_Init( void )
return;
}
Cvar_FullSet( "joy_found", va( "%d", Platform_JoyInit( joy_index.value )), FCVAR_READ_ONLY );
Platform_JoyInit();
joy_initialized = true;
}
@@ -431,8 +389,5 @@ Shutdown joystick code
*/
void Joy_Shutdown( void )
{
if( joy_initialized )
{
Cvar_FullSet( "joy_found", 0, FCVAR_READ_ONLY );
}
Platform_JoyShutdown();
}

File diff suppressed because it is too large Load Diff

View File

@@ -205,9 +205,10 @@ void IN_ToggleClientMouse( int newstate, int oldstate )
}
}
static void IN_SetRelativeMouseMode( qboolean set, qboolean verbose )
void IN_SetRelativeMouseMode( qboolean set )
{
static qboolean s_bRawInput;
qboolean verbose = m_grab_debug.value ? true : false;
if( set && !s_bRawInput )
{
@@ -231,9 +232,10 @@ static void IN_SetRelativeMouseMode( qboolean set, qboolean verbose )
}
}
static void IN_SetMouseGrab( qboolean set, qboolean verbose )
void IN_SetMouseGrab( qboolean set )
{
static qboolean s_bMouseGrab;
qboolean verbose = m_grab_debug.value ? true : false;
if( set && !s_bMouseGrab )
{
@@ -258,7 +260,7 @@ static void IN_SetMouseGrab( qboolean set, qboolean verbose )
static void IN_CheckMouseState( qboolean active )
{
qboolean use_raw_input, verbose;
qboolean use_raw_input;
#if XASH_WIN32
use_raw_input = ( m_rawinput.value && clgame.client_dll_uses_sdl ) || clgame.dllFuncs.pfnLookEvent != NULL;
@@ -266,20 +268,18 @@ static void IN_CheckMouseState( qboolean active )
use_raw_input = true; // always use SDL code
#endif
verbose = m_grab_debug.value ? true : false;
if( m_ignore.value )
active = false;
if( active && use_raw_input && !host.mouse_visible && cls.state == ca_active )
IN_SetRelativeMouseMode( true, verbose );
IN_SetRelativeMouseMode( true );
else
IN_SetRelativeMouseMode( false, verbose );
IN_SetRelativeMouseMode( false );
if( active && !host.mouse_visible && cls.state == ca_active )
IN_SetMouseGrab( true, verbose );
IN_SetMouseGrab( true );
else
IN_SetMouseGrab( false, verbose );
IN_SetMouseGrab( false );
}
/*
@@ -332,7 +332,7 @@ static void IN_MouseMove( void )
if( !in_mouseinitialized )
return;
if( Touch_Emulated( ))
if( Touch_WantVisibleCursor( ))
{
// touch emulation overrides all input
Touch_KeyEvent( 0, 0 );
@@ -363,7 +363,7 @@ void IN_MouseEvent( int key, int down )
else ClearBits( in_mstate, BIT( key ));
// touch emulation overrides all input
if( Touch_Emulated( ))
if( Touch_WantVisibleCursor( ))
{
Touch_KeyEvent( K_MOUSE1 + key, down );
}
@@ -633,8 +633,6 @@ Called every frame, even if not generating commands
*/
void Host_InputFrame( void )
{
Sys_SendKeyEvents ();
IN_Commands();
IN_MouseMove();

View File

@@ -46,6 +46,9 @@ uint IN_CollectInputDevices( void );
void IN_LockInputDevices( qboolean lock );
void IN_EngineAppendMove( float frametime, usercmd_t *cmd, qboolean active );
void IN_SetRelativeMouseMode( qboolean set );
void IN_SetMouseGrab( qboolean set );
extern convar_t m_yaw;
extern convar_t m_pitch;
//
@@ -74,7 +77,6 @@ void Touch_ResetDefaultButtons( void );
int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx, float dy );
void Touch_KeyEvent( int key, int down );
qboolean Touch_WantVisibleCursor( void );
qboolean Touch_Emulated( void );
void Touch_NotifyResize( void );
//
@@ -104,18 +106,21 @@ typedef enum engineAxis_e
JOY_AXIS_NULL
} engineAxis_t;
typedef enum joy_calibration_state_s
{
JOY_NOT_CALIBRATED = 0,
JOY_CALIBRATING,
JOY_FAILED_TO_CALIBRATE,
JOY_CALIBRATED
} joy_calibration_state_t;
qboolean Joy_IsActive( void );
void Joy_HatMotionEvent( byte hat, byte value );
void Joy_AxisMotionEvent( byte axis, short value );
void Joy_KnownAxisMotionEvent( engineAxis_t engineAxis, short value );
void Joy_BallMotionEvent( byte ball, short xrel, short yrel );
void Joy_ButtonEvent( byte button, byte down );
void Joy_AddEvent( void );
void Joy_RemoveEvent( void );
void Joy_SetCapabilities( qboolean have_gyro );
void Joy_SetCalibrationState( joy_calibration_state_t state );
void Joy_AxisMotionEvent( engineAxis_t engineAxis, short value );
void Joy_GyroEvent( vec3_t data );
void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw );
void Joy_Init( void );
void Joy_Shutdown( void );
void Joy_EnableTextInput(qboolean enable, qboolean force);
#endif//INPUT_H

View File

@@ -34,13 +34,13 @@ typedef struct keyname_s
const char *binding; // default bind
} keyname_t;
enginekey_t keys[256];
static enginekey_t keys[256];
keyname_t keynames[] =
static const keyname_t keynames[] =
{
{"TAB", K_TAB, "" },
{"ENTER", K_ENTER, "" },
{"ESCAPE", K_ESCAPE, "escape" }, // hardcoded
{"ESCAPE", K_ESCAPE, "cancelselect" }, // hardcoded
{"SPACE", K_SPACE, "+jump" },
{"BACKSPACE", K_BACKSPACE, "" },
{"UPARROW", K_UPARROW, "+forward" },
@@ -51,7 +51,7 @@ keyname_t keynames[] =
{"CTRL", K_CTRL, "+attack" },
{"SHIFT", K_SHIFT, "+speed" },
{"CAPSLOCK", K_CAPSLOCK, "" },
{"SCROLLOCK", K_SCROLLOCK, "" },
{"SCROLLOCK", K_SCROLLLOCK, "" },
{"F1", K_F1, "cmd help" },
{"F2", K_F2, "menu_savegame" },
{"F3", K_F3, "menu_loadgame" },
@@ -106,7 +106,7 @@ keyname_t keynames[] =
{"Y_BUTTON", K_Y_BUTTON, "impulse 100"}, // Flashlight
{"BACK", K_BACK_BUTTON, "pause"}, // Menu
{"MODE", K_MODE_BUTTON, ""},
{"START", K_START_BUTTON, "escape"},
{"START", K_START_BUTTON, "cancelselect"},
{"STICK1", K_LSTICK, "+speed"},
{"STICK2", K_RSTICK, "+duck"},
{"L1_BUTTON", K_L1_BUTTON, "+duck"},
@@ -139,7 +139,6 @@ keyname_t keynames[] =
// raw semicolon seperates commands
{"SEMICOLON", ';', "" },
{NULL, 0, NULL },
};
static void OSK_EnableTextInput( qboolean enable, qboolean force );
@@ -172,48 +171,25 @@ the K_* names are matched up.
to be configured even if they don't have defined names.
===================
*/
int Key_StringToKeynum( const char *str )
static int Key_StringToKeynum( const char *str )
{
keyname_t *kn;
int i;
if( !str || !str[0] ) return -1;
if( !str[1] ) return str[0];
if( !str || !str[0] )
return -1;
if( !str[1] )
return str[0];
// check for hex code
if( str[0] == '0' && str[1] == 'x' && Q_strlen( str ) == 4 )
{
int n1, n2;
n1 = str[2];
if( n1 >= '0' && n1 <= '9' )
{
n1 -= '0';
}
else if( n1 >= 'a' && n1 <= 'f' )
{
n1 = n1 - 'a' + 10;
}
else n1 = 0;
n2 = str[3];
if( n2 >= '0' && n2 <= '9' )
{
n2 -= '0';
}
else if( n2 >= 'a' && n2 <= 'f' )
{
n2 = n2 - 'a' + 10;
}
else n2 = 0;
return n1 * 16 + n2;
}
return COM_Nibble( str[2] ) << 4 | COM_Nibble( str[3] );
// scan for a text match
for( kn = keynames; kn->name; kn++ )
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
{
if( !Q_stricmp( str, kn->name ))
return kn->keynum;
if( !Q_stricmp( str, keynames[i].name ))
return keynames[i].keynum;
}
return -1;
@@ -229,15 +205,17 @@ given keynum.
*/
const char *Key_KeynumToString( int keynum )
{
keyname_t *kn;
static char tinystr[5];
int i, j;
if ( keynum == -1 ) return "<KEY NOT FOUND>";
if ( keynum < 0 || keynum > 255 ) return "<OUT OF RANGE>";
if( keynum == -1 )
return "<KEY NOT FOUND>";
if( keynum < 0 || keynum > 255 )
return "<OUT OF RANGE>";
// check for printable ascii (don't use quote)
if( keynum > 32 && keynum < 127 && keynum != '"' && keynum != ';' && keynum != K_SCROLLOCK )
if( keynum > 32 && keynum < 127 && keynum != '"' && keynum != ';' && keynum != K_SCROLLLOCK )
{
tinystr[0] = keynum;
tinystr[1] = 0;
@@ -245,10 +223,10 @@ const char *Key_KeynumToString( int keynum )
}
// check for a key string
for( kn = keynames; kn->name; kn++ )
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
{
if( keynum == kn->keynum )
return kn->name;
if( keynum == keynames[i].keynum )
return keynames[i].name;
}
// make a hex string
@@ -301,7 +279,7 @@ const char *Key_GetBinding( int keynum )
Key_GetKey
===================
*/
int Key_GetKey( const char *pBinding )
static int Key_GetKey( const char *pBinding )
{
int i, len;
const char *p;
@@ -327,6 +305,17 @@ int Key_GetKey( const char *pBinding )
return -1;
}
/*
=============
Key_LookupBinding
=============
*/
const char *Key_LookupBinding( const char *pBinding )
{
return Key_KeynumToString( Key_GetKey( pBinding ));
}
/*
===================
Key_Unbind_f
@@ -350,6 +339,12 @@ static void Key_Unbind_f( void )
return;
}
if( b == K_ESCAPE )
{
Con_Printf( "Can't unbind ESCAPE key\n" );
return;
}
Key_SetBinding( b, "" );
}
@@ -369,8 +364,8 @@ static void Key_Unbindall_f( void )
}
// set some defaults
Key_SetBinding( K_ESCAPE, "escape" );
Key_SetBinding( K_START_BUTTON, "escape" );
Key_SetBinding( K_ESCAPE, "cancelselect" );
Key_SetBinding( K_START_BUTTON, "cancelselect" );
}
/*
@@ -380,7 +375,6 @@ Key_Reset_f
*/
static void Key_Reset_f( void )
{
keyname_t *kn;
int i;
// clear all keys first
@@ -391,8 +385,8 @@ static void Key_Reset_f( void )
}
// apply default values
for( kn = keynames; kn->name; kn++ )
Key_SetBinding( kn->keynum, kn->binding );
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
Key_SetBinding( keynames[i].keynum, keynames[i].binding );
}
/*
@@ -500,7 +494,7 @@ Key_Init
*/
void Key_Init( void )
{
keyname_t *kn;
int i;
// register our functions
Cmd_AddRestrictedCommand( "bind", Key_Bind_f, "binds a command to the specified key in bindmap" );
@@ -511,7 +505,8 @@ void Key_Init( void )
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
for( kn = keynames; kn->name; kn++ ) Key_SetBinding( kn->keynum, kn->binding );
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
Key_SetBinding( keynames[i].keynum, keynames[i].binding );
Cvar_RegisterVariable( &osk_enable );
Cvar_RegisterVariable( &key_rotate );
@@ -731,35 +726,31 @@ void GAME_EXPORT Key_Event( int key, int down )
return; // handled in client.dll
}
break;
case key_message:
Key_Message( key );
return;
case key_console:
if( cls.state == ca_active && !cl.background )
Key_SetKeyDest( key_game );
else UI_SetActiveMenu( true );
return;
case key_menu:
UI_KeyEvent( key, true );
return;
default: return;
default:
break;
}
}
if( cls.key_dest == key_menu )
{
// only non printable keys passed
// classic Xash3D menus don't have an extension that tells engine
// to enable text input
if( !gameui.use_extended_api )
Key_EnableTextInput( true, false );
//pass printable chars for old menus
if( !gameui.use_extended_api && !host.textmode && down && ( key >= 32 ) && ( key <= 'z' ) )
{
if( Key_IsDown( K_SHIFT ) )
// we don't know if menu wants text input or not
// enable it unconditionally
Key_EnableTextInput( true, false );
// pass this key to the menu, if printable
if( !host.textmode && down && ( key >= 32 ) && ( key <= 'z' ))
{
key += 'A' - 'a';
if( Key_IsDown( K_SHIFT ))
key += 'A' - 'a';
UI_CharEvent( key );
}
UI_CharEvent( key );
}
UI_KeyEvent( key, down );
return;
}
@@ -855,11 +846,14 @@ void GAME_EXPORT Key_ClearStates( void )
int i;
// don't clear keys during changelevel
if( cls.changelevel ) return;
if( cls.changelevel )
return;
for( i = 0; i < 256; i++ )
{
if( keys[i].down )
if( i >= K_MOUSE1 && i <= K_MOUSE5 )
IN_MouseEvent( i - K_MOUSE1, false );
else
Key_Event( i, false );
keys[i].down = 0;
@@ -909,17 +903,16 @@ A helper function if platform input doesn't support text mode properly
*/
int Key_ToUpper( int keynum )
{
keynum = Q_toupper( keynum );
if( keynum == '-' )
keynum = '_';
return '_';
if( keynum == '=' )
keynum = '+';
return '+';
if( keynum == ';' )
keynum = ':';
return ':';
if( keynum == '\'' )
keynum = '"';
return '"';
return keynum;
return Q_toupper( keynum );
}
/* On-screen keyboard:
@@ -964,6 +957,7 @@ enum
OSK_ENTER,
OSK_SPECKEY_LAST
};
static const char *osk_keylayout[][4] =
{
{
@@ -980,7 +974,7 @@ static const char *osk_keylayout[][4] =
}
};
struct osk_s
static struct osk_s
{
qboolean enable;
int curlayout;
@@ -1014,7 +1008,6 @@ static qboolean OSK_KeyEvent( int key, int down )
return false;
}
switch ( key )
{
case K_ENTER:
@@ -1057,10 +1050,6 @@ static qboolean OSK_KeyEvent( int key, int down )
ch = (byte)osk.curbutton.val;
// do not pass UTF-8 sequence into the engine, convert it here
if( !cls.accept_utf8 )
ch = Con_UtfProcessCharForce( ch );
if( !ch )
break;
@@ -1104,7 +1093,7 @@ static qboolean OSK_KeyEvent( int key, int down )
/*
=============
Joy_EnableTextInput
OSK_EnableTextInput
Enables built-in IME
=============
@@ -1195,13 +1184,15 @@ void OSK_Draw( void )
X_STEP * MAX_OSK_ROWS * refState.width,
Y_STEP * MAX_OSK_LINES * refState.height, 100, 100, 100, 100 );
OSK_DrawSpecialButton( "-]", X_START, Y_START + Y_STEP * 2, X_STEP, Y_STEP );
OSK_DrawSpecialButton( "<-", X_START + X_STEP * 12, Y_START + Y_STEP * 2, X_STEP, Y_STEP );
OSK_DrawSpecialButton( "-]", X_START, Y_START + Y_STEP * 2, X_STEP, Y_STEP );
OSK_DrawSpecialButton( "<-", X_START + X_STEP * 12, Y_START + Y_STEP * 2, X_STEP, Y_STEP );
OSK_DrawSpecialButton( "sh", X_START, Y_START + Y_STEP * 3, X_STEP, Y_STEP );
OSK_DrawSpecialButton( "en", X_START + X_STEP * 12, Y_START + Y_STEP * 3, X_STEP, Y_STEP );
for( y = Y_START, j = 0; j < MAX_OSK_LINES; j++, y += Y_STEP )
for( y = Y_START, j = 0; j < MAX_OSK_LINES; j++, y += Y_STEP )
{
for( x = X_START, i = 0; i < MAX_OSK_ROWS; i++, x += X_STEP )
OSK_DrawSymbolButton( curlayout[j][i], x, y, X_STEP, Y_STEP );
}
}

View File

@@ -470,16 +470,16 @@ out_free:
* This is a stack of the clipnodes we have traversed
* "sides" indicates which side we went down each time
*/
static mclipnode_t *node_stack[MAX_CLIPNODE_DEPTH];
static int node_stack[MAX_CLIPNODE_DEPTH];
static int side_stack[MAX_CLIPNODE_DEPTH];
static uint node_stack_depth;
static void push_node( mclipnode_t *node, int side )
static void push_node( int nodenum, int side )
{
if( node_stack_depth == MAX_CLIPNODE_DEPTH )
Host_Error( "node stack overflow\n" );
node_stack[node_stack_depth] = node;
node_stack[node_stack_depth] = nodenum;
side_stack[node_stack_depth] = side;
node_stack_depth++;
}
@@ -502,22 +502,27 @@ static void free_hull_polys( hullnode_t *hull_polys )
}
}
static void hull_windings_r( hull_t *hull, mclipnode_t *node, hullnode_t *polys, hull_model_t *model );
static void hull_windings_r( hull_t *hull, int nodenum, hullnode_t *polys, hull_model_t *model );
static void do_hull_recursion( hull_t *hull, mclipnode_t *node, int side, hullnode_t *polys, hull_model_t *model )
static void do_hull_recursion( hull_t *hull, int nodenum, int side, hullnode_t *polys, hull_model_t *model )
{
winding_t *w, *next;
int childnum;
if( node->children[side] >= 0 )
if( world.version == QBSP2_VERSION )
childnum = hull->clipnodes32[nodenum].children[side];
else
childnum = hull->clipnodes16[nodenum].children[side];
if( childnum >= 0 )
{
mclipnode_t *child = hull->clipnodes + node->children[side];
push_node( node, side );
hull_windings_r( hull, child, polys, model );
push_node( nodenum, side );
hull_windings_r( hull, childnum, polys, model );
pop_node();
}
else
{
switch( node->children[side] )
switch( childnum )
{
case CONTENTS_EMPTY:
case CONTENTS_WATER:
@@ -542,20 +547,25 @@ static void do_hull_recursion( hull_t *hull, mclipnode_t *node, int side, hullno
}
break;
default:
Host_Error( "bad contents: %i\n", node->children[side] );
Host_Error( "bad contents: %i\n", childnum );
break;
}
}
}
static void hull_windings_r( hull_t *hull, mclipnode_t *node, hullnode_t *polys, hull_model_t *model )
static void hull_windings_r( hull_t *hull, int nodenum, hullnode_t *polys, hull_model_t *model )
{
mplane_t *plane = hull->planes + node->planenum;
mplane_t *plane;
hullnode_t frontlist = LIST_HEAD_INIT( frontlist );
hullnode_t backlist = LIST_HEAD_INIT( backlist );
winding_t *w, *next, *front, *back;
int i;
if( world.version == QBSP2_VERSION )
plane = hull->planes + hull->clipnodes32[nodenum].planenum;
else
plane = hull->planes + hull->clipnodes16[nodenum].planenum;
list_for_each_entry_safe( w, next, polys, chain )
{
// PARANIOA - PAIR CHECK
@@ -601,7 +611,13 @@ static void hull_windings_r( hull_t *hull, mclipnode_t *node, hullnode_t *polys,
for( i = 0; w && i < node_stack_depth; i++ )
{
mplane_t *p = hull->planes + node_stack[i]->planenum;
mplane_t *p;
if( world.version == QBSP2_VERSION )
p = hull->planes + hull->clipnodes32[node_stack[i]].planenum;
else
p = hull->planes + hull->clipnodes16[node_stack[i]].planenum;
w = winding_clip( w, p, false, side_stack[i], 0.00001 );
}
@@ -625,8 +641,8 @@ static void hull_windings_r( hull_t *hull, mclipnode_t *node, hullnode_t *polys,
Con_Printf( S_WARN "new winding was clipped away!\n" );
}
do_hull_recursion( hull, node, 0, &frontlist, model );
do_hull_recursion( hull, node, 1, &backlist, model );
do_hull_recursion( hull, nodenum, 0, &frontlist, model );
do_hull_recursion( hull, nodenum, 1, &backlist, model );
}
static void remove_paired_polys( hull_model_t *model )
@@ -655,7 +671,7 @@ static void make_hull_windings( hull_t *hull, hull_model_t *model )
if( hull->planes != NULL )
{
hull_windings_r( hull, hull->clipnodes + hull->firstclipnode, &head, model );
hull_windings_r( hull, hull->firstclipnode, &head, model );
remove_paired_polys( model );
}
Con_Reportf( "%i hull polys\n", model->num_polys );

View File

@@ -181,6 +181,11 @@ static void pfnCvar_FullSet( const char *var_name, const char *value, int flags
Cvar_FullSet( var_name, value, flags | FCVAR_REFDLL );
}
static int Cmd_AddRefCommand( const char *cmd_name, xcommand_t function, const char *description )
{
return Cmd_AddCommandEx( cmd_name, function, description, CMD_REFDLL, __func__ );
}
static void pfnStudioEvent( const mstudioevent_t *event, const cl_entity_t *e )
{
clgame.dllFuncs.pfnStudioEvent( event, e );
@@ -295,6 +300,12 @@ static qboolean R_Init_Video_( const int type )
return R_Init_Video( type );
}
static mleaf_t *pfnMod_PointInLeaf( const vec3_t p, mnode_t *node )
{
// FIXME: get rid of this on next RefAPI update
return Mod_PointInLeaf( p, node, cl.models[1] );
}
static const ref_api_t gEngfuncs =
{
pfnEngineGetParm,
@@ -335,7 +346,7 @@ static const ref_api_t gEngfuncs =
Mod_SampleSizeForFace,
Mod_BoxVisible,
Mod_PointInLeaf,
pfnMod_PointInLeaf,
R_DrawWorldHull,
R_DrawModelHull,

View File

@@ -312,7 +312,7 @@ static int DLY_Init( int idelay, float delay )
cur = &rgsxdly[idelay];
cur->cdelaysamplesmax = ((int)(delay * idsp_dma_speed) << sxhires) + 1;
cur->lpdelayline = (int *)Z_Calloc( cur->cdelaysamplesmax * sizeof( int ));
cur->lpdelayline = (int *)Mem_Calloc( sndpool, cur->cdelaysamplesmax * sizeof( int ));
cur->xfade = 0;
// init modulation

View File

@@ -107,17 +107,18 @@ S_CreateDefaultSound
*/
static wavdata_t *S_CreateDefaultSound( void )
{
wavdata_t *sc;
wavdata_t *sc;
uint samples = SOUND_DMA_SPEED;
uint channels = 1;
uint width = 2;
size_t size = samples * width * channels;
sc = Mem_Calloc( sndpool, sizeof( wavdata_t ));
sc->width = 2;
sc->channels = 1;
sc->loopStart = 0;
sc = Mem_Calloc( sndpool, sizeof( wavdata_t ) + size );
sc->width = width;
sc->channels = channels;
sc->rate = SOUND_DMA_SPEED;
sc->samples = SOUND_DMA_SPEED;
sc->size = sc->samples * sc->width * sc->channels;
sc->buffer = Mem_Calloc( sndpool, sc->size );
sc->samples = samples;
sc->size = size;
return sc;
}

View File

@@ -996,7 +996,7 @@ static void S_UpdateAmbientSounds( void )
// calc ambient sound levels
if( !cl.worldmodel ) return;
leaf = Mod_PointInLeaf( s_listener.origin, cl.worldmodel->nodes );
leaf = Mod_PointInLeaf( s_listener.origin, cl.worldmodel->nodes, cl.worldmodel );
if( !leaf || !s_ambient_level.value )
{
@@ -1207,86 +1207,6 @@ void S_RawSamples( uint samples, uint rate, word width, word channels, const byt
S_RawEntSamples( entnum, samples, rate, width, channels, data, snd_vol );
}
/*
===================
S_PositionedRawSamples
===================
*/
void S_StreamAviSamples( void *Avi, int entnum, float fvol, float attn, float synctime )
{
int bufferSamples;
int fileSamples;
byte raw[MAX_RAW_SAMPLES];
float duration = 0.0f;
int r, fileBytes;
rawchan_t *ch = NULL;
if( !dma.initialized || s_listener.paused || !CL_IsInGame( ))
return;
if( entnum < 0 || entnum >= GI->max_edicts )
return;
if( !( ch = S_FindRawChannel( entnum, true )))
return;
if( ch->sound_info.rate == 0 )
{
if( !AVI_GetAudioInfo( Avi, &ch->sound_info ))
return; // no audiotrack
}
ch->master_vol = bound( 0, fvol * 255, 255 );
ch->dist_mult = (attn / SND_CLIP_DISTANCE);
// see how many samples should be copied into the raw buffer
if( ch->s_rawend < soundtime )
ch->s_rawend = soundtime;
// position is changed, synchronization is lost etc
if( fabs( ch->oldtime - synctime ) > s_mixahead.value )
ch->sound_info.loopStart = AVI_TimeToSoundPosition( Avi, synctime * 1000 );
ch->oldtime = synctime; // keep actual time
while( ch->s_rawend < soundtime + ch->max_samples )
{
wavdata_t *info = &ch->sound_info;
bufferSamples = ch->max_samples - (ch->s_rawend - soundtime);
// decide how much data needs to be read from the file
fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED );
if( fileSamples <= 1 ) return; // no more samples need
// our max buffer size
fileBytes = fileSamples * ( info->width * info->channels );
if( fileBytes > sizeof( raw ))
{
fileBytes = sizeof( raw );
fileSamples = fileBytes / ( info->width * info->channels );
}
// read audio stream
r = AVI_GetAudioChunk( Avi, raw, info->loopStart, fileBytes );
info->loopStart += r; // advance play position
if( r < fileBytes )
{
fileBytes = r;
fileSamples = r / ( info->width * info->channels );
}
if( r > 0 )
{
// add to raw buffer
ch->s_rawend = S_RawSamplesStereo( ch->rawsamples, ch->s_rawend, ch->max_samples,
fileSamples, info->rate, info->width, info->channels, raw );
}
else break; // no more samples for this frame
}
}
/*
===================
S_FreeIdleRawChannels
@@ -1944,7 +1864,8 @@ qboolean S_Init( void )
Cmd_AddCommand( "play2", S_Play2_f, "playing a group of specified sound files" ); // nehahra stuff
Cmd_AddCommand( "playvol", S_PlayVol_f, "playing a specified sound file with specified volume" );
Cmd_AddCommand( "stopsound", S_StopSound_f, "stop all sounds" );
Cmd_AddCommand( "music", S_Music_f, "starting a background track" );
// HLU SDK have command with the same name
Cmd_AddCommandWithFlags( "music", S_Music_f, "starting a background track", CMD_OVERRIDABLE );
Cmd_AddCommand( "soundlist", S_SoundList_f, "display loaded sounds" );
Cmd_AddCommand( "s_info", S_SoundInfo_f, "print sound system information" );
Cmd_AddCommand( "s_fade", S_SoundFade_f, "fade all sounds then stop all" );
@@ -1953,14 +1874,15 @@ qboolean S_Init( void )
Cmd_AddCommand( "spk", S_SayReliable_f, "reliable play a specified sententce" );
Cmd_AddCommand( "speak", S_Say_f, "playing a specified sententce" );
sndpool = Mem_AllocPool( "Sound Zone" );
dma.backendName = "None";
if( !SNDDMA_Init( ) )
if( !SNDDMA_Init( ))
{
Con_Printf( "Audio: sound system can't be initialized\n" );
Mem_FreePool( &sndpool );
return false;
}
sndpool = Mem_AllocPool( "Sound Zone" );
soundtime = 0;
paintedtime = 0;
@@ -1987,7 +1909,8 @@ void S_Shutdown( void )
Cmd_RemoveCommand( "play" );
Cmd_RemoveCommand( "playvol" );
Cmd_RemoveCommand( "stopsound" );
Cmd_RemoveCommand( "music" );
if( Cmd_Exists( "music" ))
Cmd_RemoveCommand( "music" );
Cmd_RemoveCommand( "soundlist" );
Cmd_RemoveCommand( "s_info" );
Cmd_RemoveCommand( "s_fade" );

View File

@@ -16,6 +16,7 @@ GNU General Public License for more details.
#include "common.h"
#include "sound.h"
#include "client.h"
#include "soundlib.h"
static bg_track_t s_bgTrack;
static musicfade_t musicfade; // controlled by game dlls
@@ -212,7 +213,7 @@ void S_StreamBackgroundTrack( void )
while( ch->s_rawend < soundtime + ch->max_samples )
{
wavdata_t *info = FS_StreamInfo( s_bgTrack.stream );
const stream_t *info = s_bgTrack.stream;
bufferSamples = ch->max_samples - (ch->s_rawend - soundtime);

View File

@@ -557,7 +557,7 @@ static void VOX_ReadSentenceFile_( byte *buf, fs_offset_t size )
int index = cszrawsentences;
int size = strlen( name ) + strlen( value ) + 2;
rgpszrawsentence[index] = Mem_Malloc( host.mempool, size );
rgpszrawsentence[index] = Mem_Malloc( sndpool, size );
memcpy( rgpszrawsentence[index], name, size );
rgpszrawsentence[index][size - 1] = 0;
cszrawsentences++;

View File

@@ -114,7 +114,6 @@ typedef struct rawchan_s
vec3_t origin; // only use if fixed_origin is set
volatile uint s_rawend;
float oldtime; // catch time jumps
wavdata_t sound_info; // advance play position
size_t max_samples; // buffer length
portable_samplepair_t rawsamples[]; // variable sized
} rawchan_t;
@@ -171,6 +170,8 @@ typedef struct
int source; // may be game, menu, etc
} bg_track_t;
typedef int sound_t;
//====================================================================
#define MAX_DYNAMIC_CHANNELS (60 + NUM_AMBIENTS)

View File

@@ -29,17 +29,20 @@ static void Sound_Reset( void )
static MALLOC_LIKE( FS_FreeSound, 1 ) wavdata_t *SoundPack( void )
{
wavdata_t *pack = Mem_Calloc( host.soundpool, sizeof( wavdata_t ));
wavdata_t *pack = Mem_Malloc( host.soundpool, sizeof( *pack ) + sound.size );
pack->buffer = sound.wav;
pack->width = sound.width;
pack->rate = sound.rate;
pack->type = sound.type;
pack->size = sound.size;
pack->loopStart = sound.loopstart;
pack->samples = sound.samples;
pack->channels = sound.channels;
pack->type = sound.type;
pack->flags = sound.flags;
pack->rate = sound.rate;
pack->width = sound.width;
pack->channels = sound.channels;
memcpy( pack->buffer, sound.wav, sound.size );
Mem_Free( sound.wav );
sound.wav = NULL;
return pack;
}
@@ -132,7 +135,6 @@ free WAV buffer
void FS_FreeSound( wavdata_t *pack )
{
if( !pack ) return;
if( pack->buffer ) Mem_Free( pack->buffer );
Mem_Free( pack );
}
@@ -199,33 +201,6 @@ stream_t *FS_OpenStream( const char *filename )
return stream;
}
/*
================
FS_StreamInfo
get basic stream info
================
*/
wavdata_t *FS_StreamInfo( stream_t *stream )
{
static wavdata_t info;
if( !stream ) return NULL;
// fill structure
info.loopStart = 0;
info.rate = stream->rate;
info.width = stream->width;
info.channels = stream->channels;
info.flags = SOUND_STREAM;
info.size = stream->size;
info.buffer = NULL;
info.samples = 0; // not actual for streams
info.type = stream->type;
return &info;
}
/*
================
FS_ReadStream

View File

@@ -25,20 +25,29 @@ GNU General Public License for more details.
#define VGUI_MAX_TEXTURES 1024
typedef struct vgui_reusable_texture_s
{
int gl_texturenum;
byte hash[16];
} vgui_reusable_texture_t;
typedef struct vgui_static_s
{
qboolean initialized;
VGUI_DefaultCursor cursor;
vguiapi_t dllFuncs;
int textures[VGUI_MAX_TEXTURES];
vgui_reusable_texture_t *textures;
int texture_id;
int max_textures;
int bound_texture;
byte color[4];
qboolean enable_texture;
HINSTANCE hInstance;
poolhandle_t mempool;
enum VGUI_KeyCode virtualKeyTrans[256];
} vgui_static_t;
@@ -49,9 +58,16 @@ static CVAR_DEFINE_AUTO( vgui_utf8, "0", FCVAR_ARCHIVE, "enable utf-8 support fo
static void GAME_EXPORT VGUI_DrawInit( void )
{
memset( vgui.textures, 0, sizeof( vgui.textures ));
if( vgui.mempool )
Mem_EmptyPool( vgui.mempool );
else vgui.mempool = Mem_AllocPool( "VGui Support Pool" );
vgui.textures = NULL;
memset( vgui.color, 0, sizeof( vgui.color ));
vgui.texture_id = vgui.bound_texture = 0;
vgui.texture_id = 0;
vgui.bound_texture = 0;
vgui.max_textures = 0;
vgui.enable_texture = true;
}
@@ -60,28 +76,79 @@ static void GAME_EXPORT VGUI_DrawShutdown( void )
int i;
for( i = 1; i < vgui.texture_id; i++ )
ref.dllFuncs.GL_FreeTexture( vgui.textures[i] );
ref.dllFuncs.GL_FreeTexture( vgui.textures[i].gl_texturenum );
Mem_FreePool( &vgui.mempool );
vgui.textures = NULL;
memset( vgui.color, 0, sizeof( vgui.color ));
vgui.texture_id = 0;
vgui.bound_texture = 0;
vgui.max_textures = 0;
}
static int GAME_EXPORT VGUI_GenerateTexture( void )
{
if( ++vgui.texture_id >= VGUI_MAX_TEXTURES )
Host_Error( "%s: VGUI_MAX_TEXTURES limit exceeded\n", __func__ );
// allocate new
if( vgui.texture_id + 1 >= vgui.max_textures )
{
if( vgui.max_textures + VGUI_MAX_TEXTURES >= VGUI_MAX_TEXTURES * VGUI_MAX_TEXTURES )
{
// in theory it might look up texture that hasn't been bound for a while and
// reuse that but it will eventually overwrite some important textures anyway
Con_Printf( S_ERROR "%s: Refusing resizing VGUI textures array due to memory leak\n", __func__ );
return vgui.texture_id;
}
return vgui.texture_id;
vgui.max_textures += VGUI_MAX_TEXTURES;
// this potentially might leak memory if VGUI is used incorrectly!
// (like in Cry of Fear)
vgui.textures = Mem_Realloc( vgui.mempool, vgui.textures, sizeof( *vgui.textures ) * vgui.max_textures );
// warn mod developer
if( vgui.max_textures >= VGUI_MAX_TEXTURES * 4 )
Con_Printf( S_ERROR "%s: Potential memory leak in VGUI code is detected!\n", __func__ );
}
return ++vgui.texture_id;
}
static void GAME_EXPORT VGUI_UploadTexture( int id, const char *buffer, int width, int height )
{
rgbdata_t r_image = { 0 };
char texName[32];
MD5Context_t ctx;
byte hash[16];
if( id <= 0 || id >= VGUI_MAX_TEXTURES )
if( id <= 0 || id >= vgui.max_textures || width <= 0 || height <= 0 )
{
Con_DPrintf( S_ERROR "%s: bad texture %i. Ignored\n", __func__, id );
return;
}
// need to do this as some mods tend to upload same texture over and over
// exhausing engine-wide limit on textures and leaking vram
MD5Init( &ctx );
MD5Update( &ctx, buffer, width * height * 4 );
MD5Final( hash, &ctx );
// it's a new texture, try to find a copy
if( vgui.textures[id].gl_texturenum == 0 )
{
int i;
for( i = 1; i < vgui.texture_id; i++ )
{
if( vgui.textures[i].gl_texturenum != 0 && !memcmp( vgui.textures[i].hash, hash, sizeof( hash )))
{
// copy data to new texture id
vgui.textures[id] = vgui.textures[i];
return;
}
}
}
Q_snprintf( texName, sizeof( texName ), "*vgui%i", id );
r_image.width = width;
@@ -91,51 +158,29 @@ static void GAME_EXPORT VGUI_UploadTexture( int id, const char *buffer, int widt
r_image.flags = IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA;
r_image.buffer = (byte*)buffer;
vgui.textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE );
vgui.textures[id].gl_texturenum = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE );
memcpy( vgui.textures[id].hash, hash, sizeof( hash ));
}
static void GAME_EXPORT VGUI_CreateTexture( int id, int width, int height )
{
rgbdata_t r_image = { 0 };
char texName[32];
// nothing uses it, it can be removed
Host_Error( "%s: deprecated\n", __func__ );
if( id <= 0 || id >= VGUI_MAX_TEXTURES )
{
Con_DPrintf( S_ERROR "%s: bad texture %i. Ignored\n", __func__, id );
return;
}
Q_snprintf( texName, sizeof( texName ), "*vgui%i", id );
r_image.width = width;
r_image.height = height;
r_image.type = PF_RGBA_32;
r_image.size = width * height * 4;
r_image.flags = IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA;
r_image.buffer = NULL;
vgui.textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE );
vgui.bound_texture = id;
}
static void GAME_EXPORT VGUI_UploadTextureBlock( int id, int drawX, int drawY, const byte *rgba, int blockWidth, int blockHeight )
{
if( id <= 0 || id >= VGUI_MAX_TEXTURES || vgui.textures[id] == 0 )
{
Con_DPrintf( S_ERROR "%s: bad texture %i. Ignored\n", __func__, id );
return;
}
ref.dllFuncs.VGUI_UploadTextureBlock( drawX, drawY, rgba, blockWidth, blockHeight );
vgui.bound_texture = id;
// nothing uses it, it can be removed
Host_Error( "%s: deprecated\n", __func__ );
}
static void GAME_EXPORT VGUI_BindTexture( int id )
{
if( id <= 0 || id >= VGUI_MAX_TEXTURES || !vgui.textures[id] )
if( id <= 0 || id >= vgui.max_textures || !vgui.textures[id].gl_texturenum )
id = 1; // NOTE: same as bogus index 2700 in GoldSrc
ref.dllFuncs.GL_Bind( XASH_TEXTURE0, vgui.textures[id] );
ref.dllFuncs.GL_Bind( XASH_TEXTURE0, vgui.textures[id].gl_texturenum );
vgui.bound_texture = id;
}
@@ -144,7 +189,7 @@ static void GAME_EXPORT VGUI_GetTextureSizes( int *w, int *h )
int texnum;
if( vgui.bound_texture )
texnum = vgui.textures[vgui.bound_texture];
texnum = vgui.textures[vgui.bound_texture].gl_texturenum;
else
texnum = R_GetBuiltinTexture( REF_DEFAULT_TEXTURE );
@@ -187,7 +232,7 @@ static void GAME_EXPORT VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr )
t2 = lr->coord[1];
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] );
ref.dllFuncs.R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, vgui.textures[vgui.bound_texture].gl_texturenum );
}
else
{

View File

@@ -17,7 +17,7 @@ GNU General Public License for more details.
#include "base_cmd.h"
#include "cdll_int.h"
#define HASH_SIZE 128 // 128 * 4 * 4 == 2048 bytes
#define HASH_SIZE 64 // 64 * 4 * 4 == 1024 bytes
typedef struct base_command_hashmap_s base_command_hashmap_t;
@@ -26,10 +26,11 @@ struct base_command_hashmap_s
base_command_t *basecmd; // base command: cvar, alias or command
base_command_hashmap_t *next;
base_command_type_e type; // type for faster searching
char name[1]; // key for searching
char name[]; // key for searching
};
static base_command_hashmap_t *hashed_cmds[HASH_SIZE];
static poolhandle_t basecmd_pool;
#define BaseCmd_HashKey( x ) COM_HashKey( name, HASH_SIZE )
@@ -42,11 +43,27 @@ 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 )
{
base_command_hashmap_t *i = bucket;
for( ; i && ( i->type != type || Q_stricmp( name, i->name ) ); // filter out
i = i->next );
base_command_hashmap_t *i;
return i;
for( i = bucket; i != NULL; i = i->next )
{
int cmp;
if( i->type != type )
continue;
cmp = Q_stricmp( i->name, name );
if( cmp < 0 )
continue;
if( cmp > 0 )
break;
return i;
}
return NULL;
}
/*
@@ -90,27 +107,31 @@ void BaseCmd_FindAll( const char *name, base_command_t **cmd, base_command_t **a
base_command_hashmap_t *base = BaseCmd_GetBucket( name );
base_command_hashmap_t *i = base;
ASSERT( cmd && alias && cvar );
*cmd = *alias = *cvar = NULL;
for( ; i; i = i->next )
{
if( !Q_stricmp( i->name, name ) )
int cmp = Q_stricmp( i->name, name );
if( cmp < 0 )
continue;
if( cmp > 0 )
break;
switch( i->type )
{
switch( i->type )
{
case HM_CMD:
*cmd = i->basecmd;
break;
case HM_CMDALIAS:
*alias = i->basecmd;
break;
case HM_CVAR:
*cvar = i->basecmd;
break;
default: break;
}
case HM_CMD:
*cmd = i->basecmd;
break;
case HM_CMDALIAS:
*alias = i->basecmd;
break;
case HM_CVAR:
*cvar = i->basecmd;
break;
default:
break;
}
}
}
@@ -128,14 +149,14 @@ void BaseCmd_Insert( base_command_type_e type, base_command_t *basecmd, const ch
uint hash = BaseCmd_HashKey( name );
size_t len = Q_strlen( name );
elem = Z_Malloc( sizeof( base_command_hashmap_t ) + len );
elem = Mem_Malloc( basecmd_pool, sizeof( base_command_hashmap_t ) + len + 1 );
elem->basecmd = basecmd;
elem->type = type;
Q_strncpy( elem->name, name, len + 1 );
// link the variable in alphanumerical order
for( cur = NULL, find = hashed_cmds[hash];
find && Q_strcmp( find->name, elem->name ) < 0;
find && Q_stricmp( find->name, elem->name ) < 0;
cur = find, find = find->next );
if( cur ) cur->next = elem;
@@ -156,9 +177,23 @@ void BaseCmd_Remove( base_command_type_e type, const char *name )
uint hash = BaseCmd_HashKey( name );
base_command_hashmap_t *i, *prev;
for( prev = NULL, i = hashed_cmds[hash]; i &&
( Q_strcmp( i->name, name ) || i->type != type); // filter out
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 )
continue;
cmp = Q_stricmp( i->name, name );
if( cmp < 0 )
continue;
if( cmp > 0 )
i = NULL;
break;
}
if( !i )
{
@@ -183,9 +218,15 @@ initialize base command hashmap system
*/
void BaseCmd_Init( void )
{
basecmd_pool = Mem_AllocPool( "BaseCmd" );
memset( hashed_cmds, 0, sizeof( hashed_cmds ) );
}
void BaseCmd_Shutdown( void )
{
Mem_FreePool( &basecmd_pool );
}
/*
============
BaseCmd_Stats_f

View File

@@ -32,6 +32,7 @@ typedef enum base_command_type
typedef void base_command_t;
void BaseCmd_Init( void );
void BaseCmd_Shutdown( void );
base_command_t *BaseCmd_Find( base_command_type_e type, const char *name );
void BaseCmd_FindAll( const char *name,
base_command_t **cmd, base_command_t **alias, base_command_t **cvar );

View File

@@ -46,6 +46,7 @@ static cmdalias_t *cmd_alias;
static uint cmd_condition;
static int cmd_condlevel;
static qboolean cmd_currentCommandIsPrivileged;
static poolhandle_t cmd_pool;
static void Cmd_ExecuteStringWithPrivilegeCheck( const char *text, qboolean isPrivileged );
@@ -142,28 +143,33 @@ void Cbuf_AddFilteredText( const char *text )
Cbuf_InsertText
Adds command text immediately after the current command
Adds a \n to the text
============
*/
static void Cbuf_InsertTextToBuffer( cmdbuf_t *buf, const char *text )
static void Cbuf_InsertTextToBuffer( cmdbuf_t *buf, const char *text, size_t len, size_t requested_len )
{
int l = Q_strlen( text );
if(( buf->cursize + l ) >= buf->maxsize )
if(( buf->cursize + requested_len ) >= buf->maxsize )
{
Con_Reportf( S_WARN "%s: overflow\n", __func__ );
}
else
{
memmove( buf->data + l, buf->data, buf->cursize );
memcpy( buf->data, text, l );
buf->cursize += l;
memmove( buf->data + len, buf->data, buf->cursize );
memcpy( buf->data, text, len );
buf->cursize += len;
}
}
void Cbuf_InsertTextLen( const char *text, size_t len, size_t requested_len )
{
// sometimes we need to insert more data than we have
// but also prevent overflow
Cbuf_InsertTextToBuffer( &cmd_text, text, len, requested_len );
}
void Cbuf_InsertText( const char *text )
{
Cbuf_InsertTextToBuffer( &cmd_text, text );
size_t l = Q_strlen( text );
Cbuf_InsertTextToBuffer( &cmd_text, text, l, l );
}
/*
@@ -263,10 +269,16 @@ Cbuf_Execute
void Cbuf_Execute( void )
{
Cbuf_ExecuteCommandsFromBuffer( &cmd_text, true, -1 );
// a1ba: unlimited commands for filtered buffer per frame
// a1ba: goldsrc limits unprivileged commands per frame to 1 here
// I don't see any sense in restricting that at this moment
// but in future we may limit this
Cbuf_ExecuteCommandsFromBuffer( &filteredcmd_text, false, -1 );
// a1ba: there is little to no sense limit privileged commands in
// local game, as client runs server code anyway
// do this for singleplayer only though, to make it easier to catch
// possible bugs during local multiplayer testing
Cbuf_ExecuteCommandsFromBuffer( &filteredcmd_text, SV_Active() && SV_GetMaxClients() == 1, -1 );
}
/*
@@ -421,7 +433,7 @@ static void Cmd_Alias_f( void )
{
if( !Q_strcmp( s, a->name ))
{
Z_Free( a->value );
Mem_Free( a->value );
break;
}
}
@@ -430,7 +442,7 @@ static void Cmd_Alias_f( void )
{
cmdalias_t *cur, *prev;
a = Z_Malloc( sizeof( cmdalias_t ));
a = Mem_Malloc( cmd_pool, sizeof( cmdalias_t ));
Q_strncpy( a->name, s, sizeof( a->name ));
@@ -458,7 +470,7 @@ static void Cmd_Alias_f( void )
}
Q_strncat( cmd, "\n", sizeof( cmd ));
a->value = copystring( cmd );
a->value = copystringpool( cmd_pool, cmd );
}
/*
@@ -512,14 +524,14 @@ static void Cmd_UnAlias_f ( void )
=============================================================================
*/
typedef struct cmd_s
struct cmd_s
{
struct cmd_s *next;
char *name;
xcommand_t function;
int flags;
char *desc;
} cmd_t;
char desc[];
};
static int cmd_argc;
static const char *cmd_args = NULL;
@@ -625,7 +637,7 @@ void Cmd_TokenizeString( const char *text )
// clear the args from the last string
for( i = 0; i < cmd_argc; i++ )
Z_Free( cmd_argv[i] );
Mem_Free( cmd_argv[i] );
cmd_argc = 0; // clear previous args
cmd_args = NULL;
@@ -659,7 +671,7 @@ void Cmd_TokenizeString( const char *text )
if( cmd_argc < MAX_CMD_TOKENS )
{
cmd_argv[cmd_argc] = copystring( cmd_token );
cmd_argv[cmd_argc] = copystringpool( cmd_pool, cmd_token );
cmd_argc++;
}
}
@@ -670,10 +682,10 @@ void Cmd_TokenizeString( const char *text )
Cmd_AddCommandEx
============
*/
static int Cmd_AddCommandEx( const char *funcname, const char *cmd_name, xcommand_t function,
const char *cmd_desc, int iFlags )
int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd_desc, int iFlags, const char *funcname )
{
cmd_t *cmd, *cur, *prev;
cmd_t *cmd, *cur, *prev;
size_t desc_len;
if( !COM_CheckString( cmd_name ))
{
@@ -688,17 +700,35 @@ static int Cmd_AddCommandEx( const char *funcname, const char *cmd_name, xcomman
return 0;
}
// fail if the command already exists
if( Cmd_Exists( cmd_name ))
// fail if the command already exists and cannot be overriden
cmd = Cmd_Exists( cmd_name );
if( cmd )
{
Con_DPrintf( S_ERROR "%s: %s already defined\n", funcname, cmd_name );
return 0;
// some mods register commands that share the name with some engine's commands
// when they aren't critical to keep engine running, we can let mods to override them
// unfortunately, we lose original command this way
if( FBitSet( cmd->flags, CMD_OVERRIDABLE ))
{
desc_len = Q_strlen( cmd->desc ) + 1;
Q_strncpy( cmd->desc, cmd_desc, desc_len );
cmd->function = function;
cmd->flags = iFlags;
Con_DPrintf( S_WARN "%s: %s already defined but is allowed to be overriden\n", funcname, cmd_name );
return 1;
}
else
{
Con_DPrintf( "%s%s: %s already defined\n", cmd->function == function ? S_WARN : S_ERROR, funcname, cmd_name );
return 0;
}
}
// use a small malloc to avoid zone fragmentation
cmd = Z_Malloc( sizeof( cmd_t ) );
cmd->name = copystring( cmd_name );
cmd->desc = copystring( cmd_desc );
desc_len = Q_strlen( cmd_desc ) + 1;
cmd = Mem_Malloc( cmd_pool, sizeof( cmd_t ) + desc_len );
cmd->name = copystringpool( cmd_pool, cmd_name );
Q_strncpy( cmd->desc, cmd_desc, desc_len );
cmd->function = function;
cmd->flags = iFlags;
@@ -716,75 +746,6 @@ static int Cmd_AddCommandEx( const char *funcname, const char *cmd_name, xcomman
return 1;
}
/*
============
Cmd_AddCommand
============
*/
void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc )
{
Cmd_AddCommandEx( __func__, cmd_name, function, cmd_desc, 0 );
}
/*
============
Cmd_AddRestrictedCommand
============
*/
void Cmd_AddRestrictedCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc )
{
Cmd_AddCommandEx( __func__, cmd_name, function, cmd_desc, CMD_PRIVILEGED );
}
/*
============
Cmd_AddServerCommand
============
*/
void GAME_EXPORT Cmd_AddServerCommand( const char *cmd_name, xcommand_t function )
{
Cmd_AddCommandEx( __func__, cmd_name, function, "server command", CMD_SERVERDLL );
}
/*
============
Cmd_AddClientCommand
============
*/
int GAME_EXPORT Cmd_AddClientCommand( const char *cmd_name, xcommand_t function )
{
int flags = CMD_CLIENTDLL;
// a1ba: try to mitigate outdated client.dll vulnerabilities
if( !Q_stricmp( cmd_name, "motd_write" ))
{
flags |= CMD_PRIVILEGED;
}
return Cmd_AddCommandEx( __func__, cmd_name, function, "client command", flags );
}
/*
============
Cmd_AddGameUICommand
============
*/
int GAME_EXPORT Cmd_AddGameUICommand( const char *cmd_name, xcommand_t function )
{
return Cmd_AddCommandEx( __func__, cmd_name, function, "gameui command", CMD_GAMEUIDLL );
}
/*
============
Cmd_AddRefCommand
============
*/
int Cmd_AddRefCommand( const char *cmd_name, xcommand_t function, const char *description )
{
return Cmd_AddCommandEx( __func__, cmd_name, function, description, CMD_REFDLL );
}
/*
============
Cmd_RemoveCommand
@@ -814,9 +775,6 @@ void GAME_EXPORT Cmd_RemoveCommand( const char *cmd_name )
if( cmd->name )
Mem_Free( cmd->name );
if( cmd->desc )
Mem_Free( cmd->desc );
Mem_Free( cmd );
return;
}
@@ -853,19 +811,18 @@ void Cmd_LookupCmds( void *buffer, void *ptr, setpair_t callback )
Cmd_Exists
============
*/
qboolean Cmd_Exists( const char *cmd_name )
cmd_t *Cmd_Exists( const char *cmd_name )
{
#if defined(XASH_HASHED_VARS)
return BaseCmd_Find( HM_CMD, cmd_name ) != NULL;
return BaseCmd_Find( HM_CMD, cmd_name );
#else
cmd_t *cmd;
for( cmd = cmd_functions; cmd; cmd = cmd->next )
{
if( !Q_strcmp( cmd_name, cmd->name ))
return true;
return cmd;
}
return false;
return NULL;
#endif
}
@@ -1058,9 +1015,10 @@ static void Cmd_ExecuteStringWithPrivilegeCheck( const char *text, qboolean isPr
if( a )
{
size_t len = Q_strlen( a->value );
Cbuf_InsertTextToBuffer(
isPrivileged ? &cmd_text : &filteredcmd_text,
a->value );
a->value, len, len );
return;
}
}
@@ -1244,7 +1202,6 @@ void Cmd_Unlink( int group )
*prev = cmd->next;
if( cmd->name ) Mem_Free( cmd->name );
if( cmd->desc ) Mem_Free( cmd->desc );
Mem_Free( cmd );
count++;
@@ -1382,6 +1339,7 @@ Cmd_Init
*/
void Cmd_Init( void )
{
cmd_pool = Mem_AllocPool( "Console Commands" );
cmd_functions = NULL;
cmd_condition = 0;
cmd_alias = NULL;
@@ -1408,6 +1366,11 @@ void Cmd_Init( void )
#endif
}
void Cmd_Shutdown( void )
{
Mem_FreePool( &cmd_pool );
}
#if XASH_ENGINE_TESTS
#include "tests.h"

View File

@@ -72,8 +72,6 @@ GNU General Public License for more details.
#define CVAR_GLCONFIG_DESCRIPTION "enable or disable %s"
#define DEFAULT_BSP_BUILD_ERROR "%s can't be loaded in this build. Please rebuild engine with enabled SUPPORT_BSP2_FORMAT\n"
#define DEFAULT_UPDATE_PAGE "https://github.com/FWGS/xash3d-fwgs/releases/latest"
#define XASH_ENGINE_NAME "Xash3D FWGS"

View File

@@ -612,7 +612,7 @@ COM_Nibble
Returns the 4 bit nibble for a hex character
==================
*/
static byte COM_Nibble( char c )
byte COM_Nibble( char c )
{
if(( c >= '0' ) && ( c <= '9' ))
{

View File

@@ -76,23 +76,14 @@ XASH SPECIFIC - sort of hack that works only in Xash3D not in GoldSrc
#define HACKS_RELATED_HLMODS // some HL-mods works differently under Xash and can't be fixed without some hacks at least at current time
enum
enum dev_level_e
{
DEV_NONE = 0,
DEV_NORMAL,
DEV_EXTENDED
};
enum
{
D_INFO = 1, // "-dev 1", shows various system messages
D_WARN, // "-dev 2", shows not critical system warnings
D_ERROR, // "-dev 3", shows critical warnings
D_REPORT, // "-dev 4", special case for game reports
D_NOTE // "-dev 5", show system notifications for engine developers
};
typedef enum
typedef enum instance_e
{
HOST_NORMAL, // listen server, singleplayer
HOST_DEDICATED,
@@ -108,14 +99,14 @@ typedef enum
#include "com_model.h"
#include "com_strings.h"
#include "crtlib.h"
#include "cvar.h"
#include "con_nprint.h"
#include "crclib.h"
#include "ref_api.h"
#define FSCALLBACK_OVERRIDE_OPEN
#define FSCALLBACK_OVERRIDE_LOADFILE
#define FSCALLBACK_OVERRIDE_MALLOC_LIKE
#include "fscallback.h"
#include "cvar.h"
#include "con_nprint.h"
#include "crclib.h"
#include "ref_api.h"
// PERFORMANCE INFO
#define MIN_FPS 20.0f // host minimum fps value for maxfps.
@@ -146,6 +137,11 @@ typedef enum
#define MAX_STATIC_ENTITIES 32 // static entities that moved on the client when level is spawn
#endif
#define MAX_SERVERINFO_STRING 512 // server handles too many settings. expand to 1024?
#define MAX_PRINT_MSG 8192 // how many symbols can handle single call of Con_Printf or Con_DPrintf
#define MAX_TOKEN 2048 // parse token length
#define MAX_USERMSG_LENGTH 2048 // don't modify it's relies on a client-side definitions
#define GameState (&host.game)
#define FORCE_DRAW_VERSION_TIME 5.0 // draw version for 5 seconds
@@ -171,6 +167,11 @@ extern convar_t cl_filterstuffcmd;
extern convar_t rcon_password;
extern convar_t hpk_custom_file;
extern convar_t con_gamemaps;
extern convar_t fs_mount_lv;
extern convar_t fs_mount_hd;
extern convar_t fs_mount_addon;
extern convar_t fs_mount_l10n;
extern convar_t ui_language; // historically used for UI, but now controls mounted localization directory
#define Mod_AllowMaterials() ( host_allow_materials.value != 0.0f && !FBitSet( host.features, ENGINE_DISABLE_HDTEXTURES ))
@@ -189,7 +190,7 @@ GAMEINFO stuff
internal shared gameinfo structure (readonly for engine parts)
========================================================================
*/
typedef enum
typedef enum host_status_e
{
HOST_INIT = 0, // initalize operations
HOST_FRAME, // host running
@@ -200,7 +201,7 @@ typedef enum
HOST_CRASHED // an exception handler called
} host_status_t;
typedef enum
typedef enum host_state_e
{
STATE_RUNFRAME = 0,
STATE_LOAD_LEVEL,
@@ -209,7 +210,7 @@ typedef enum
STATE_GAME_SHUTDOWN,
} host_state_t;
typedef struct
typedef struct game_status_e
{
host_state_t curstate;
host_state_t nextstate;
@@ -220,7 +221,7 @@ typedef struct
qboolean newGame; // unload the server.dll before start a new map
} game_status_t;
typedef enum
typedef enum keydest_e
{
key_console = 0,
key_game,
@@ -228,7 +229,7 @@ typedef enum
key_message
} keydest_t;
typedef enum
typedef enum rdtype_e
{
RD_NONE = 0,
RD_CLIENT,
@@ -238,7 +239,7 @@ typedef enum
#include "net_ws.h"
// console field
typedef struct
typedef struct field_e
{
string buffer;
int cursor;
@@ -256,7 +257,7 @@ typedef struct host_redirect_s
int lines;
} host_redirect_t;
typedef struct
typedef struct soundlist_e
{
char name[MAX_QPATH];
short entnum;
@@ -297,11 +298,10 @@ typedef struct host_parm_s
host_status_t status; // global host state
game_status_t game; // game manager
uint type; // running at
instance_t type; // running at
poolhandle_t mempool; // static mempool for misc allocations
poolhandle_t imagepool; // imagelib mempool
poolhandle_t soundpool; // soundlib mempool
string finalmsg; // server shutdown final message
string downloadfile; // filename to be downloading
int downloadcount; // how many files remain to downloading
char deferred_cmd[128];// deferred commands
@@ -362,12 +362,13 @@ typedef struct host_parm_s
extern host_parm_t host;
#define CMD_SERVERDLL BIT( 0 ) // added by server.dll
#define CMD_CLIENTDLL BIT( 1 ) // added by client.dll
#define CMD_GAMEUIDLL BIT( 2 ) // added by GameUI.dll
#define CMD_PRIVILEGED BIT( 3 ) // only available in privileged mode
#define CMD_FILTERABLE BIT( 4 ) // filtered in unprivileged mode if cl_filterstuffcmd is 1
#define CMD_REFDLL BIT( 5 ) // added by ref.dll
#define CMD_SERVERDLL BIT( 0 ) // added by server.dll
#define CMD_CLIENTDLL BIT( 1 ) // added by client.dll
#define CMD_GAMEUIDLL BIT( 2 ) // added by GameUI.dll
#define CMD_PRIVILEGED BIT( 3 ) // only available in privileged mode
#define CMD_FILTERABLE BIT( 4 ) // filtered in unprivileged mode if cl_filterstuffcmd is 1
#define CMD_REFDLL BIT( 5 ) // added by ref.dll
#define CMD_OVERRIDABLE BIT( 6 ) // can be removed by DLLs if name matches
typedef void (*xcommand_t)( void );
@@ -414,15 +415,19 @@ byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamediro
MALLOC_LIKE( _Mem_Free, 1 ) WARN_UNUSED_RESULT;
byte *FS_LoadDirectFile( const char *path, fs_offset_t *filesizeptr )
MALLOC_LIKE( _Mem_Free, 1 ) WARN_UNUSED_RESULT;
void FS_Rescan_f( void );
void FS_CheckConfig( void );
//
// cmd.c
//
typedef struct cmd_s cmd_t;
void Cbuf_Clear( void );
void Cbuf_AddText( const char *text );
void Cbuf_AddTextf( const char *text, ... ) FORMAT_CHECK( 1 );
void Cbuf_AddFilteredText( const char *text );
void Cbuf_InsertText( const char *text );
void Cbuf_InsertTextLen( const char *text, size_t len, size_t requested_len );
void Cbuf_ExecStuffCmds( void );
void Cbuf_Execute (void);
qboolean Cmd_CurrentCommandIsPrivileged( void );
@@ -430,15 +435,27 @@ int Cmd_Argc( void );
const char *Cmd_Args( void ) RETURNS_NONNULL;
const char *Cmd_Argv( int arg ) RETURNS_NONNULL;
void Cmd_Init( void );
void Cmd_Shutdown( void );
void Cmd_Unlink( int group );
void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc );
void Cmd_AddRestrictedCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc );
void Cmd_AddServerCommand( const char *cmd_name, xcommand_t function );
int Cmd_AddClientCommand( const char *cmd_name, xcommand_t function );
int Cmd_AddGameUICommand( const char *cmd_name, xcommand_t function );
int Cmd_AddRefCommand( const char *cmd_name, xcommand_t function, const char *description );
int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd_desc, int flags, const char *funcname );
static inline int Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc )
{
return Cmd_AddCommandEx( cmd_name, function, cmd_desc, 0, __func__ );
}
static inline int Cmd_AddRestrictedCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc )
{
return Cmd_AddCommandEx( cmd_name, function, cmd_desc, CMD_PRIVILEGED, __func__ );
}
static inline int Cmd_AddCommandWithFlags( const char *cmd_name, xcommand_t function, const char *cmd_desc, int flags )
{
return Cmd_AddCommandEx( cmd_name, function, cmd_desc, flags, __func__ );
}
void Cmd_RemoveCommand( const char *cmd_name );
qboolean Cmd_Exists( const char *cmd_name );
cmd_t *Cmd_Exists( const char *cmd_name );
void Cmd_LookupCmds( void *buffer, void *ptr, setpair_t callback );
int Cmd_ListMaps( search_t *t , char *lastmapname, size_t len );
void Cmd_TokenizeString( const char *text );
@@ -477,7 +494,7 @@ internal sound format
typically expanded to wav buffer
========================================================================
*/
typedef enum
typedef enum sndformat_e
{
WF_UNKNOWN = 0,
WF_PCMDATA,
@@ -488,7 +505,7 @@ typedef enum
} sndformat_t;
// wavdata output flags
typedef enum
typedef enum sndFlags_e
{
// wavdata->flags
SOUND_LOOPED = BIT( 0 ), // this is looped sound (contain cue markers)
@@ -498,29 +515,29 @@ typedef enum
SOUND_RESAMPLE = BIT( 12 ), // resample sound to specified rate
} sndFlags_t;
typedef struct
typedef struct wavdata_s
{
word rate; // num samples per second (e.g. 11025 - 11 khz)
byte width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2)
byte channels; // num channels (1 - mono, 2 - stereo)
size_t size; // for bounds checking
uint loopStart; // offset at this point sound will be looping while playing more than only once
uint samples; // total samplecount in wav
uint type; // compression type
uint flags; // misc sound flags
byte *buffer; // sound buffer
size_t size; // for bounds checking
word rate; // num samples per second (e.g. 11025 - 11 khz)
byte width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2)
byte channels; // num channels (1 - mono, 2 - stereo)
byte buffer[]; // sound buffer
} wavdata_t;
//
// soundlib
//
typedef struct stream_s stream_t;
void Sound_Init( void );
void Sound_Shutdown( void );
void FS_FreeSound( wavdata_t *pack );
void FS_FreeStream( stream_t *stream );
wavdata_t *FS_LoadSound( const char *filename, const byte *buffer, size_t size ) MALLOC_LIKE( FS_FreeSound, 1 ) WARN_UNUSED_RESULT;
stream_t *FS_OpenStream( const char *filename ) MALLOC_LIKE( FS_FreeStream, 1 ) WARN_UNUSED_RESULT;
wavdata_t *FS_StreamInfo( stream_t *stream );
int FS_ReadStream( stream_t *stream, int bytes, void *buffer );
int FS_SetStreamPos( stream_t *stream, int newpos );
int FS_GetStreamPos( stream_t *stream );
@@ -534,7 +551,7 @@ qboolean Sound_SupportedFileFormat( const char *fileext );
typedef void( *pfnChangeGame )( const char *progname );
qboolean Host_IsQuakeCompatible( void );
void EXPORT Host_Shutdown( void );
void Host_ShutdownWithReason( const char *reason );
int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGame, pfnChangeGame func );
void Host_EndGame( qboolean abort, const char *message, ... ) FORMAT_CHECK( 2 );
void Host_AbortCurrentFrame( void ) NORETURN;
@@ -542,11 +559,11 @@ void Host_WriteServerConfig( const char *name );
void Host_WriteOpenGLConfig( void );
void Host_WriteVideoConfig( void );
void Host_WriteConfig( void );
void Host_ShutdownServer( void );
void Host_Error( const char *error, ... ) FORMAT_CHECK( 1 );
void Host_ValidateEngineFeatures( uint32_t mask, uint32_t features );
void Host_Frame( double time );
void Host_Credits( void );
void Host_ExitInMain( void );
//
// host_state.c
@@ -565,11 +582,19 @@ CLIENT / SERVER SYSTEMS
==============================================================
*/
#if !XASH_DEDICATED
void CL_Init( void );
void CL_Shutdown( void );
void Host_ClientBegin( void );
void Host_ClientFrame( void );
int CL_Active( void );
#else
static inline void CL_Init( void ) { }
static inline void CL_Shutdown( void ) { }
static inline void Host_ClientBegin( void ) { Cbuf_Execute(); }
static inline void Host_ClientFrame( void ) { }
static inline int CL_Active( void ) { return 0; }
#endif
void SV_Init( void );
void SV_Shutdown( const char *finalmsg );
@@ -586,6 +611,7 @@ qboolean SV_Active( void );
*/
char *COM_MemFgets( byte *pMemFile, int fileSize, int *filePos, char *pBuffer, int bufferSize );
void COM_HexConvert( const char *pszInput, int nInputLength, byte *pOutput );
byte COM_Nibble( char c );
int COM_SaveFile( const char *filename, const void *data, int len );
byte *COM_LoadFileForMe( const char *filename, int *pLength ) MALLOC_LIKE( free, 1 );
qboolean COM_IsSafeFileToDownload( const char *filename );
@@ -606,6 +632,7 @@ int pfnNumberOfEntities( void );
int pfnIsInGame( void );
float pfnTime( void );
#define copystring( s ) _copystring( host.mempool, s, __FILE__, __LINE__ )
#define copystringpool( pool, s ) _copystring( pool, s, __FILE__, __LINE__ )
#define SV_CopyString( s ) _copystring( svgame.stringspool, s, __FILE__, __LINE__ )
#define freestring( s ) if( s != NULL ) { Mem_Free( s ); s = NULL; }
char *_copystring( poolhandle_t mempool, const char *s, const char *filename, int fileline );
@@ -656,6 +683,7 @@ int CSCR_WriteGameCVars( file_t *cfg, const char *scriptfilename );
//
// hpak.c
//
const char *COM_ResourceTypeFromIndex( int index );
void HPAK_Init( void );
qboolean HPAK_GetDataPointer( const char *filename, struct resource_s *pRes, byte **buffer, int *size );
qboolean HPAK_ResourceForHash( const char *filename, byte *hash, struct resource_s *pRes );
@@ -689,13 +717,32 @@ typedef enum connprotocol_e
struct physent_s;
struct sv_client_s;
typedef struct sizebuf_s sizebuf_t;
int SV_GetMaxClients( void );
#if !XASH_DEDICATED
qboolean CL_Initialized( void );
qboolean CL_IsInGame( void );
qboolean CL_IsInConsole( void );
qboolean CL_IsIntermission( void );
qboolean CL_Initialized( void );
qboolean CL_DisableVisibility( void );
qboolean CL_IsRecordDemo( void );
qboolean CL_IsPlaybackDemo( void );
qboolean UI_CreditsActive( void );
int CL_GetMaxClients( void );
#else
static inline qboolean CL_Initialized( void ) { return false; }
static inline qboolean CL_IsInGame( void ) { return true; } // always true for dedicated
static inline qboolean CL_IsInConsole( void ) { return false; }
static inline qboolean CL_IsIntermission( void ) { return false; }
static inline qboolean CL_DisableVisibility( void ) { return false; }
static inline qboolean CL_IsRecordDemo( void ) { return false; }
static inline qboolean CL_IsPlaybackDemo( void ) { return false; }
static inline qboolean UI_CreditsActive( void ) { return false; }
static inline int CL_GetMaxClients( void ) { return SV_GetMaxClients(); }
#endif
char *CL_Userinfo( void );
void CL_CharEvent( int key );
qboolean CL_DisableVisibility( void );
byte *COM_LoadFile( const char *filename, int usehunk, int *pLength ) MALLOC_LIKE( free, 1 );
struct cmd_s *Cmd_GetFirstFunctionHandle( void );
struct cmd_s *Cmd_GetNextFunctionHandle( struct cmd_s *cmd );
@@ -713,13 +760,7 @@ const char *CL_MsgInfo( int cmd );
void SV_DrawDebugTriangles( void );
void SV_DrawOrthoTriangles( void );
double CL_GetDemoFramerate( void );
qboolean UI_CreditsActive( void );
void CL_StopPlayback( void );
int CL_GetMaxClients( void );
int SV_GetMaxClients( void );
qboolean CL_IsRecordDemo( void );
qboolean CL_IsTimeDemo( void );
qboolean CL_IsPlaybackDemo( void );
qboolean SV_Initialized( void );
void CL_ProcessFile( qboolean successfully_received, const char *filename );
int SV_GetSaveComment( const char *savename, char *comment );
@@ -832,13 +873,6 @@ void V_CheckGamma( void );
void V_CheckGammaEnd( void );
intptr_t V_GetGammaPtr( int parm );
//
// identification.c
//
void ID_Init( void );
const char *ID_GetMD5( void );
void GAME_EXPORT ID_SetCustomClientID( const char *id );
//
// masterlist.c
//

View File

@@ -498,7 +498,6 @@ static qboolean Cmd_GetSoundList( const char *s, char *completedname, int length
return true;
}
#if !XASH_DEDICATED
/*
=====================================
Cmd_GetItemsList
@@ -508,6 +507,7 @@ Prints or complete item classname (weapons only)
*/
static qboolean Cmd_GetItemsList( const char *s, char *completedname, int length )
{
#if !XASH_DEDICATED
search_t *t;
string matchbuf;
int i, numitems;
@@ -521,7 +521,7 @@ static qboolean Cmd_GetItemsList( const char *s, char *completedname, int length
Q_strncpy( completedname, matchbuf, length );
if( t->numfilenames == 1 ) return true;
for(i = 0, numitems = 0; i < t->numfilenames; i++)
for( i = 0, numitems = 0; i < t->numfilenames; i++ )
{
if( Q_stricmp( COM_FileExtension( t->filenames[i] ), "txt" ))
continue;
@@ -544,6 +544,8 @@ static qboolean Cmd_GetItemsList( const char *s, char *completedname, int length
}
}
return true;
#endif // !XASH_DEDICATED
return false;
}
/*
@@ -555,6 +557,7 @@ Autocomplete for bind command
*/
static qboolean Cmd_GetKeysList( const char *s, char *completedname, int length )
{
#if !XASH_DEDICATED
size_t i, numkeys;
string keys[256];
string matchbuf;
@@ -595,8 +598,9 @@ static qboolean Cmd_GetKeysList( const char *s, char *completedname, int length
}
return true;
#endif // !XASH_DEDICATED
return false;
}
#endif // XASH_DEDICATED
/*
===============
@@ -604,13 +608,20 @@ Con_AddCommandToList
===============
*/
static void Con_AddCommandToList( const char *s, const char *unused1, const char *unused2, void *_autocompleteList )
static void Con_AddCommandToList( const char *s, const char *value, const void *ptoggle, void *_autocompleteList )
{
con_autocomplete_t *list = (con_autocomplete_t*)_autocompleteList;
qboolean toggle = ptoggle != NULL && *(qboolean *)ptoggle;
if( *s == '@' ) return; // never show system cvars or cmds
if( list->matchCount >= CON_MAXCMDS ) return; // list is full
if( toggle )
{
if( Q_strcmp( value, "0" ) && Q_strcmp( value, "1" ))
return; // exclude non-toggable cvars
}
if( Q_strnicmp( s, list->completionString, Q_strlen( list->completionString ) ) )
return; // no match
@@ -634,13 +645,11 @@ Cmd_GetCommandsList
Autocomplete for bind command
=====================================
*/
static qboolean Cmd_GetCommandsList( const char *s, char *completedname, int length )
static qboolean Cmd_GetCommandsAndCvarsList( const char *s, char *completedname, int length, qboolean cmds, qboolean cvars, qboolean toggle )
{
size_t i;
string matchbuf;
con_autocomplete_t list; // local autocomplete list
memset( &list, 0, sizeof( list ));
con_autocomplete_t list = { 0 }; // local autocomplete list
list.completionString = s;
@@ -652,8 +661,16 @@ static qboolean Cmd_GetCommandsList( const char *s, char *completedname, int len
return false;
// find matching commands and variables
Cmd_LookupCmds( NULL, &list, (setpair_t)Con_AddCommandToList );
Cvar_LookupVars( 0, NULL, &list, (setpair_t)Con_AddCommandToList );
if( cvars )
{
Cvar_LookupVars( 0, &toggle, &list, (setpair_t)Con_AddCommandToList );
}
if( cmds )
{
toggle = false;
Cmd_LookupCmds( &toggle, &list, (setpair_t)Con_AddCommandToList );
}
if( !list.matchCount ) return false;
Q_strncpy( matchbuf, list.cmds[0], sizeof( matchbuf ));
@@ -669,7 +686,7 @@ static qboolean Cmd_GetCommandsList( const char *s, char *completedname, int len
Con_Printf( "%16s\n", matchbuf );
}
Con_Printf( "\n^3 %i commands found.\n", list.matchCount );
Con_Printf( "\n^3 %i %s found.\n", list.matchCount, cmds ? "commands" : "variables" );
if( completedname && length )
{
@@ -691,6 +708,30 @@ static qboolean Cmd_GetCommandsList( const char *s, char *completedname, int len
return true;
}
/*
=====================================
Cmd_GetCommandsList
Autocomplete for bind command
=====================================
*/
static qboolean Cmd_GetCommandsList( const char *s, char *completedname, int length )
{
return Cmd_GetCommandsAndCvarsList( s, completedname, length, true, true, false );
}
/*
=====================================
Cmd_GetCvarList
Autocomplete for bind command
=====================================
*/
static qboolean Cmd_GetCvarsList( const char *s, char *completedname, int length )
{
qboolean toggle = !Q_stricmp( Cmd_Argv( 0 ), "toggle" );
return Cmd_GetCommandsAndCvarsList( s, completedname, length, false, true, toggle );
}
/*
=====================================
@@ -1010,37 +1051,38 @@ int GAME_EXPORT Cmd_CheckMapsList( int fRefresh )
return Cmd_CheckMapsList_R( fRefresh, true );
}
// keep this sorted
static const autocomplete_list_t cmd_list[] =
{
{ "map_background", 1, Cmd_GetMapList },
{ "bind", 1, Cmd_GetKeysList },
{ "bind", 2, Cmd_GetCommandsList },
{ "cd", 1, Cmd_GetCDList },
{ "changelevel2", 1, Cmd_GetMapList },
{ "changelevel", 1, Cmd_GetMapList },
{ "playdemo", 1, Cmd_GetDemoList, },
{ "timedemo", 1, Cmd_GetDemoList, },
{ "listdemo", 1, Cmd_GetDemoList, },
{ "playvol", 1, Cmd_GetSoundList },
{ "hpkval", 1, Cmd_GetCustomList },
{ "hpklist", 1, Cmd_GetCustomList },
{ "hpkextract", 1, Cmd_GetCustomList },
{ "entpatch", 1, Cmd_GetMapList },
{ "music", 1, Cmd_GetMusicList, },
{ "movie", 1, Cmd_GetMovieList },
{ "exec", 1, Cmd_GetConfigList },
#if !XASH_DEDICATED
{ "give", 1, Cmd_GetItemsList },
{ "drop", 1, Cmd_GetItemsList },
{ "bind", 1, Cmd_GetKeysList },
{ "unbind", 1, Cmd_GetKeysList },
{ "bind", 2, Cmd_GetCommandsList },
#endif
{ "entpatch", 1, Cmd_GetMapList },
{ "exec", 1, Cmd_GetConfigList },
{ "game", 1, Cmd_GetGamesList },
{ "save", 1, Cmd_GetSavesList },
{ "give", 1, Cmd_GetItemsList },
{ "hpkextract", 1, Cmd_GetCustomList },
{ "hpklist", 1, Cmd_GetCustomList },
{ "hpkval", 1, Cmd_GetCustomList },
{ "listdemo", 1, Cmd_GetDemoList, },
{ "load", 1, Cmd_GetSavesList },
{ "play", 1, Cmd_GetSoundList },
{ "map", 1, Cmd_GetMapList },
{ "cd", 1, Cmd_GetCDList },
{ "map_background", 1, Cmd_GetMapList },
{ "movie", 1, Cmd_GetMovieList },
{ "mp3", 1, Cmd_GetCDList },
{ NULL }, // termiantor
{ "music", 1, Cmd_GetMusicList, },
{ "play", 1, Cmd_GetSoundList },
{ "playdemo", 1, Cmd_GetDemoList, },
{ "playvol", 1, Cmd_GetSoundList },
{ "reset", 1, Cmd_GetCvarsList },
{ "save", 1, Cmd_GetSavesList },
{ "set", 1, Cmd_GetCvarsList },
{ "timedemo", 1, Cmd_GetDemoList },
{ "toggle", 1, Cmd_GetCvarsList },
{ "unbind", 1, Cmd_GetKeysList },
};
/*
@@ -1073,12 +1115,12 @@ for various cmds
*/
static qboolean Cmd_AutocompleteName( const char *source, int arg, char *buffer, size_t bufsize )
{
const autocomplete_list_t *list;
int i;
for( list = cmd_list; list->name; list++ )
for( i = 0; i < ARRAYSIZE( cmd_list ); i++ )
{
if( list->arg == arg && Cmd_CheckName( list->name ))
return list->func( source, buffer, bufsize );
if( cmd_list[i].arg == arg && Cmd_CheckName( cmd_list[i].name ))
return cmd_list[i].func( source, buffer, bufsize );
}
return false;
@@ -1161,6 +1203,7 @@ void Con_CompleteCommand( field_t *field )
{
field_t temp;
string filename;
qboolean toggle = false;
qboolean nextcmd;
int i;
@@ -1195,8 +1238,8 @@ void Con_CompleteCommand( field_t *field )
con.shortestMatch[0] = 0;
// find matching commands and variables
Cmd_LookupCmds( NULL, &con, (setpair_t)Con_AddCommandToList );
Cvar_LookupVars( 0, NULL, &con, (setpair_t)Con_AddCommandToList );
Cmd_LookupCmds( &toggle, &con, (setpair_t)Con_AddCommandToList );
Cvar_LookupVars( 0, &toggle, &con, (setpair_t)Con_AddCommandToList );
if( !con.matchCount ) return; // no matches
@@ -1396,7 +1439,7 @@ void Host_WriteConfig( void )
{
Con_Reportf( "%s()\n", __func__ );
FS_Printf( f, "//=======================================================================\n");
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
FS_Printf( f, "//\t\tconfig.cfg - archive of cvars\n" );
FS_Printf( f, "//=======================================================================\n" );
Key_WriteBindings( f );
@@ -1444,7 +1487,7 @@ void GAME_EXPORT Host_WriteServerConfig( const char *name )
if(( f = FS_Open( newconfigfile, "w", false )) != NULL )
{
FS_Printf( f, "//=======================================================================\n" );
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
FS_Printf( f, "//\t\tgame.cfg - multiplayer server temporare config\n" );
FS_Printf( f, "//=======================================================================\n" );
@@ -1479,7 +1522,7 @@ void Host_WriteOpenGLConfig( void )
{
Con_Reportf( "%s()\n", __func__ );
FS_Printf( f, "//=======================================================================\n" );
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
FS_Printf( f, "//\t\t%s - archive of renderer implementation cvars\n", name );
FS_Printf( f, "//=======================================================================\n" );
FS_Printf( f, "\n" );
@@ -1509,7 +1552,7 @@ void Host_WriteVideoConfig( void )
{
Con_Reportf( "%s()\n", __func__ );
FS_Printf( f, "//=======================================================================\n" );
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
FS_Printf( f, "//\t\tvideo.cfg - archive of renderer variables\n");
FS_Printf( f, "//=======================================================================\n" );
Cvar_WriteVariables( f, FCVAR_RENDERINFO );
@@ -1535,7 +1578,7 @@ void Key_EnumCmds_f( void )
if( f )
{
FS_Printf( f, "//=======================================================================\n");
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
FS_Printf( f, "//\t\thelp.txt - xash commands and console variables\n");
FS_Printf( f, "//=======================================================================\n");

View File

@@ -1,558 +0,0 @@
/*
crashhandler.c - advanced crashhandler
Copyright (C) 2016 Mittorn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "common.h"
/*
================
Sys_Crash
Crash handler, called from system
================
*/
#if XASH_WIN32
#if DBGHELP
#pragma comment( lib, "dbghelp" )
#include <winnt.h>
#include <dbghelp.h>
#include <psapi.h>
#include <time.h>
#ifndef XASH_SDL
typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
#endif
static int Sys_ModuleName( HANDLE process, char *name, void *address, int len )
{
DWORD_PTR baseAddress = 0;
static HMODULE *moduleArray;
static unsigned int moduleCount;
LPBYTE moduleArrayBytes;
DWORD bytesRequired;
int i;
if( len < 3 )
return 0;
if( !moduleArray && EnumProcessModules( process, NULL, 0, &bytesRequired ) )
{
if ( bytesRequired )
{
moduleArrayBytes = (LPBYTE)LocalAlloc( LPTR, bytesRequired );
if( moduleArrayBytes && EnumProcessModules( process, (HMODULE *)moduleArrayBytes, bytesRequired, &bytesRequired ) )
{
moduleCount = bytesRequired / sizeof( HMODULE );
moduleArray = (HMODULE *)moduleArrayBytes;
}
}
}
for( i = 0; i < moduleCount; i++ )
{
MODULEINFO info;
GetModuleInformation( process, moduleArray[i], &info, sizeof(MODULEINFO) );
if( ( address > info.lpBaseOfDll ) &&
( (DWORD64)address < (DWORD64)info.lpBaseOfDll + (DWORD64)info.SizeOfImage ) )
return GetModuleBaseName( process, moduleArray[i], name, len );
}
return Q_snprintf( name, len, "???" );
}
static void Sys_StackTrace( PEXCEPTION_POINTERS pInfo )
{
char message[8192]; // match *nix Sys_Crash
int len = 0;
size_t i;
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
IMAGEHLP_LINE64 line;
DWORD dline = 0;
DWORD options;
CONTEXT context;
STACKFRAME64 stackframe;
DWORD image;
context = *pInfo->ContextRecord;
options = SymGetOptions();
options |= SYMOPT_DEBUG;
options |= SYMOPT_LOAD_LINES;
SymSetOptions( options );
SymInitialize( process, NULL, TRUE );
ZeroMemory( &stackframe, sizeof( STACKFRAME64 ));
#ifdef _M_IX86
image = IMAGE_FILE_MACHINE_I386;
stackframe.AddrPC.Offset = context.Eip;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Ebp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Esp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
image = IMAGE_FILE_MACHINE_AMD64;
stackframe.AddrPC.Offset = context.Rip;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Rsp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Rsp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
image = IMAGE_FILE_MACHINE_IA64;
stackframe.AddrPC.Offset = context.StIIP;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.IntSp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrBStore.Offset = context.RsBSP;
stackframe.AddrBStore.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.IntSp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_ARM
image = IMAGE_FILE_MACHINE_ARMNT;
stackframe.AddrPC.Offset = context.Pc;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.R11;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Sp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_ARM64
image = IMAGE_FILE_MACHINE_ARM64;
stackframe.AddrPC.Offset = context.Pc;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Fp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Sp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif
#error
#endif
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n",
Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch() );
len += Q_snprintf( message + len, 1024 - len, "Sys_Crash: address %p, code %p\n",
pInfo->ExceptionRecord->ExceptionAddress, (void*)pInfo->ExceptionRecord->ExceptionCode );
if( SymGetLineFromAddr64( process, (DWORD64)pInfo->ExceptionRecord->ExceptionAddress, &dline, &line ) )
{
len += Q_snprintf(message + len, 1024 - len, "Exception: %s:%d:%d\n",
(char*)line.FileName, (int)line.LineNumber, (int)dline);
}
if( SymGetLineFromAddr64( process, stackframe.AddrPC.Offset, &dline, &line ) )
{
len += Q_snprintf(message + len, 1024 - len,"PC: %s:%d:%d\n",
(char*)line.FileName, (int)line.LineNumber, (int)dline);
}
if( SymGetLineFromAddr64( process, stackframe.AddrFrame.Offset, &dline, &line ) )
{
len += Q_snprintf(message + len, 1024 - len,"Frame: %s:%d:%d\n",
(char*)line.FileName, (int)line.LineNumber, (int)dline);
}
for( i = 0; i < 25; i++ )
{
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
BOOL result = StackWalk64(
image, process, thread,
&stackframe, &context, NULL,
SymFunctionTableAccess64, SymGetModuleBase64, NULL);
DWORD64 displacement = 0;
if( !result )
break;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
len += Q_snprintf( message + len, 1024 - len, "% 2d %p",
i, (void*)stackframe.AddrPC.Offset );
if( SymFromAddr( process, stackframe.AddrPC.Offset, &displacement, symbol ) )
{
len += Q_snprintf( message + len, 1024 - len, " %s ", symbol->Name );
}
if( SymGetLineFromAddr64( process, stackframe.AddrPC.Offset, &dline, &line ) )
{
len += Q_snprintf(message + len, 1024 - len,"(%s:%d:%d) ",
(char*)line.FileName, (int)line.LineNumber, (int)dline);
}
len += Q_snprintf( message + len, 1024 - len, "(");
len += Sys_ModuleName( process, message + len, (void*)stackframe.AddrPC.Offset, 1024 - len );
len += Q_snprintf( message + len, 1024 - len, ")\n");
}
#if XASH_SDL == 2
if( host.type != HOST_DEDICATED ) // let system to restart server automaticly
SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR, "Sys_Crash", message, host.hWnd );
#endif
Sys_PrintLog( message );
SymCleanup( process );
}
static void Sys_GetProcessName( char *processName, size_t bufferSize )
{
char fullpath[MAX_PATH];
GetModuleBaseName( GetCurrentProcess(), NULL, fullpath, sizeof( fullpath ) - 1 );
COM_FileBase( fullpath, processName, bufferSize );
}
static void Sys_GetMinidumpFileName( const char *processName, char *mdmpFileName, size_t bufferSize )
{
time_t currentUtcTime = time( NULL );
struct tm *currentLocalTime = localtime( &currentUtcTime );
Q_snprintf( mdmpFileName, bufferSize, "%s_%s_crash_%d%.2d%.2d_%.2d%.2d%.2d.mdmp",
processName,
Q_buildcommit(),
currentLocalTime->tm_year + 1900,
currentLocalTime->tm_mon + 1,
currentLocalTime->tm_mday,
currentLocalTime->tm_hour,
currentLocalTime->tm_min,
currentLocalTime->tm_sec);
}
static qboolean Sys_WriteMinidump(PEXCEPTION_POINTERS exceptionInfo, MINIDUMP_TYPE minidumpType)
{
HRESULT errorCode;
string processName;
string mdmpFileName;
MINIDUMP_EXCEPTION_INFORMATION minidumpInfo;
Sys_GetProcessName( processName, sizeof( processName ));
Sys_GetMinidumpFileName( processName, mdmpFileName, sizeof( mdmpFileName ));
SetLastError( NOERROR );
HANDLE fileHandle = CreateFile(
mdmpFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
errorCode = HRESULT_FROM_WIN32( GetLastError( ));
if( !SUCCEEDED( errorCode )) {
CloseHandle( fileHandle );
return false;
}
minidumpInfo.ThreadId = GetCurrentThreadId();
minidumpInfo.ExceptionPointers = exceptionInfo;
minidumpInfo.ClientPointers = FALSE;
qboolean status = MiniDumpWriteDump(
GetCurrentProcess(), GetCurrentProcessId(), fileHandle,
minidumpType, &minidumpInfo, NULL, NULL);
CloseHandle( fileHandle );
return status;
}
#endif /* DBGHELP */
LPTOP_LEVEL_EXCEPTION_FILTER oldFilter;
static long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo )
{
// save config
if( host.status != HOST_CRASHED )
{
// check to avoid recursive call
host.crashed = true;
#ifdef XASH_SDL
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
#endif // XASH_SDL
#if DBGHELP
Sys_StackTrace( pInfo );
#else
Sys_Warn( "Sys_Crash: call %p at address %p", pInfo->ExceptionRecord->ExceptionAddress, pInfo->ExceptionRecord->ExceptionCode );
#endif
if( host.type == HOST_NORMAL )
CL_Crashed(); // tell client about crash
else host.status = HOST_CRASHED;
#if DBGHELP
if( Sys_CheckParm( "-minidumps" ))
{
int minidumpFlags = (
MiniDumpWithDataSegs |
MiniDumpWithCodeSegs |
MiniDumpWithHandleData |
MiniDumpWithFullMemory |
MiniDumpWithFullMemoryInfo |
MiniDumpWithIndirectlyReferencedMemory |
MiniDumpWithThreadInfo |
MiniDumpWithModuleHeaders);
if( !Sys_WriteMinidump( pInfo, (MINIDUMP_TYPE)minidumpFlags )) {
// fallback method, create minidump with minimal info in it
Sys_WriteMinidump( pInfo, MiniDumpWithDataSegs );
}
}
#endif
if( host_developer.value <= 0 )
{
// no reason to call debugger in release build - just exit
Sys_Quit();
return EXCEPTION_CONTINUE_EXECUTION;
}
// all other states keep unchanged to let debugger find bug
Sys_DestroyConsole();
}
if( oldFilter )
return oldFilter( pInfo );
return EXCEPTION_CONTINUE_EXECUTION;
}
void Sys_SetupCrashHandler( void )
{
SetErrorMode( SEM_FAILCRITICALERRORS ); // no abort/retry/fail errors
oldFilter = SetUnhandledExceptionFilter( Sys_Crash );
}
void Sys_RestoreCrashHandler( void )
{
// restore filter
if( oldFilter ) SetUnhandledExceptionFilter( oldFilter );
}
#elif XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX
// Posix signal handler
#ifndef XASH_OPENBSD
#include <ucontext.h>
#endif
#include <signal.h>
#include <sys/mman.h>
#include "library.h"
#define STACK_BACKTRACE_STR "Stack backtrace:\n"
#define STACK_DUMP_STR "Stack dump:\n"
#define STACK_BACKTRACE_STR_LEN ( sizeof( STACK_BACKTRACE_STR ) - 1 )
#define STACK_DUMP_STR_LEN ( sizeof( STACK_DUMP_STR ) - 1 )
#define ALIGN( x, y ) (((uintptr_t) ( x ) + (( y ) - 1 )) & ~(( y ) - 1 ))
static struct sigaction oldFilter;
static int Sys_PrintFrame( char *buf, int len, int i, void *addr )
{
Dl_info dlinfo;
if( len <= 0 )
return 0; // overflow
if( dladdr( addr, &dlinfo ))
{
if( dlinfo.dli_sname )
return Q_snprintf( buf, len, "%2d: %p <%s+%lu> (%s)\n", i, addr, dlinfo.dli_sname,
(unsigned long)addr - (unsigned long)dlinfo.dli_saddr, dlinfo.dli_fname ); // print symbol, module and address
return Q_snprintf( buf, len, "%2d: %p (%s)\n", i, addr, dlinfo.dli_fname ); // print module and address
}
return Q_snprintf( buf, len, "%2d: %p\n", i, addr ); // print only address
}
static void Sys_Crash( int signal, siginfo_t *si, void *context)
{
void *pc = NULL, **bp = NULL, **sp = NULL; // this must be set for every OS!
char message[8192];
int len, logfd, i = 0;
#if XASH_OPENBSD
struct sigcontext *ucontext = (struct sigcontext*)context;
#else
ucontext_t *ucontext = (ucontext_t*)context;
#endif
#if XASH_AMD64
#if XASH_FREEBSD
pc = (void*)ucontext->uc_mcontext.mc_rip;
bp = (void**)ucontext->uc_mcontext.mc_rbp;
sp = (void**)ucontext->uc_mcontext.mc_rsp;
#elif XASH_NETBSD
pc = (void*)ucontext->uc_mcontext.__gregs[_REG_RIP];
bp = (void**)ucontext->uc_mcontext.__gregs[_REG_RBP];
sp = (void**)ucontext->uc_mcontext.__gregs[_REG_RSP];
#elif XASH_OPENBSD
pc = (void*)ucontext->sc_rip;
bp = (void**)ucontext->sc_rbp;
sp = (void**)ucontext->sc_rsp;
#else
pc = (void*)ucontext->uc_mcontext.gregs[REG_RIP];
bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];
sp = (void**)ucontext->uc_mcontext.gregs[REG_RSP];
#endif
#elif XASH_X86
#if XASH_FREEBSD
pc = (void*)ucontext->uc_mcontext.mc_eip;
bp = (void**)ucontext->uc_mcontext.mc_ebp;
sp = (void**)ucontext->uc_mcontext.mc_esp;
#elif XASH_NETBSD
pc = (void*)ucontext->uc_mcontext.__gregs[_REG_EIP];
bp = (void**)ucontext->uc_mcontext.__gregs[_REG_EBP];
sp = (void**)ucontext->uc_mcontext.__gregs[_REG_ESP];
#elif XASH_OPENBSD
pc = (void*)ucontext->sc_eip;
bp = (void**)ucontext->sc_ebp;
sp = (void**)ucontext->sc_esp;
#else
pc = (void*)ucontext->uc_mcontext.gregs[REG_EIP];
bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];
sp = (void**)ucontext->uc_mcontext.gregs[REG_ESP];
#endif
#elif XASH_ARM && XASH_64BIT
pc = (void*)ucontext->uc_mcontext.pc;
bp = (void*)ucontext->uc_mcontext.regs[29];
sp = (void*)ucontext->uc_mcontext.sp;
#elif XASH_ARM
pc = (void*)ucontext->uc_mcontext.arm_pc;
bp = (void*)ucontext->uc_mcontext.arm_fp;
sp = (void*)ucontext->uc_mcontext.arm_sp;
#endif
// safe actions first, stack and memory may be corrupted
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n",
Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch() );
#if !XASH_FREEBSD && !XASH_NETBSD && !XASH_OPENBSD
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p %p\n", signal, si->si_errno, si->si_code, si->si_addr, si->si_ptr );
#else
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p\n", signal, si->si_errno, si->si_code, si->si_addr );
#endif
write( STDERR_FILENO, message, len );
// flush buffers before writing directly to descriptors
fflush( stdout );
fflush( stderr );
// now get log fd and write trace directly to log
logfd = Sys_LogFileNo();
write( logfd, message, len );
if( pc && bp && sp )
{
size_t pagesize = sysconf( _SC_PAGESIZE );
// try to print backtrace
write( STDERR_FILENO, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN );
write( logfd, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN );
Q_strncpy( message + len, STACK_BACKTRACE_STR, sizeof( message ) - len );
len += STACK_BACKTRACE_STR_LEN;
// false on success, true on failure
#define try_allow_read(pointer, pagesize) \
((mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_WRITE | PROT_EXEC ) == -1) && \
( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_EXEC ) == -1) && \
( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_WRITE ) == -1) && \
( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ ) == -1))
do
{
int line = Sys_PrintFrame( message + len, sizeof( message ) - len, ++i, pc);
write( STDERR_FILENO, message + len, line );
write( logfd, message + len, line );
len += line;
//if( !dladdr(bp,0) ) break; // only when bp is in module
if( try_allow_read( bp, pagesize ) )
break;
if( try_allow_read( bp[0], pagesize ) )
break;
pc = bp[1];
bp = (void**)bp[0];
}
while( bp && i < 128 );
// try to print stack
write( STDERR_FILENO, STACK_DUMP_STR, STACK_DUMP_STR_LEN );
write( logfd, STACK_DUMP_STR, STACK_DUMP_STR_LEN );
Q_strncpy( message + len, STACK_DUMP_STR, sizeof( message ) - len );
len += STACK_DUMP_STR_LEN;
if( !try_allow_read( sp, pagesize ) )
{
for( i = 0; i < 32; i++ )
{
int line = Sys_PrintFrame( message + len, sizeof( message ) - len, i, sp[i] );
write( STDERR_FILENO, message + len, line );
write( logfd, message + len, line );
len += line;
}
}
#undef try_allow_read
}
// put MessageBox as Sys_Error
Msg( "%s\n", message );
#ifdef XASH_SDL
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
#endif
host.crashed = true;
Platform_MessageBox( "Xash Error", message, false );
// log saved, now we can try to save configs and close log correctly, it may crash
if( host.type == HOST_NORMAL )
CL_Crashed();
host.status = HOST_CRASHED;
Sys_Quit();
}
void Sys_SetupCrashHandler( void )
{
struct sigaction act = { 0 };
act.sa_sigaction = Sys_Crash;
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
sigaction( SIGSEGV, &act, &oldFilter );
sigaction( SIGABRT, &act, &oldFilter );
sigaction( SIGBUS, &act, &oldFilter );
sigaction( SIGILL, &act, &oldFilter );
}
void Sys_RestoreCrashHandler( void )
{
sigaction( SIGSEGV, &oldFilter, NULL );
sigaction( SIGABRT, &oldFilter, NULL );
sigaction( SIGBUS, &oldFilter, NULL );
sigaction( SIGILL, &oldFilter, NULL );
}
#else
void Sys_SetupCrashHandler( void )
{
// stub
}
void Sys_RestoreCrashHandler( void )
{
// stub
}
#endif

View File

@@ -19,6 +19,7 @@ GNU General Public License for more details.
#include "eiface.h" // ARRAYSIZE
static convar_t *cvar_vars = NULL; // head of list
static poolhandle_t cvar_pool;
CVAR_DEFINE_AUTO( cmd_scripting, "0", FCVAR_ARCHIVE|FCVAR_PRIVILEGED, "enable simple condition checking and variable operations" );
typedef struct cvar_filter_quirks_s
@@ -432,7 +433,7 @@ convar_t *Cvar_Get( const char *name, const char *value, int flags, const char *
{
// directly set value
freestring( var->string );
var->string = copystring( value );
var->string = copystringpool( cvar_pool, value );
var->value = Q_atof( var->string );
SetBits( var->flags, flags );
@@ -452,18 +453,18 @@ convar_t *Cvar_Get( const char *name, const char *value, int flags, const char *
Con_Reportf( "%s change description from %s to %s\n", var->name, var->desc, var_desc );
// update description if needs
freestring( var->desc );
var->desc = copystring( var_desc );
var->desc = copystringpool( cvar_pool, var_desc );
}
return var;
}
// allocate a new cvar
var = Z_Malloc( sizeof( *var ));
var->name = copystring( name );
var->string = copystring( value );
var->def_string = copystring( value );
var->desc = copystring( var_desc );
var = Mem_Malloc( cvar_pool, sizeof( *var ));
var->name = copystringpool( cvar_pool, name );
var->string = copystringpool( cvar_pool, value );
var->def_string = copystringpool( cvar_pool, value );
var->desc = copystringpool( cvar_pool, var_desc );
var->value = Q_atof( var->string );
var->flags = flags|FCVAR_ALLOCATED;
@@ -549,7 +550,7 @@ void Cvar_RegisterVariable( convar_t *var )
if( FBitSet( var->flags, FCVAR_EXTENDED ))
var->def_string = var->string; // just swap pointers
var->string = copystring( var->string );
var->string = copystringpool( cvar_pool, var->string );
var->value = Q_atof( var->string );
// find the supposed position in chain (alphanumerical order)
@@ -679,7 +680,7 @@ static convar_t *Cvar_Set2( const char *var_name, const char *value )
// and finally changed the cvar itself
freestring( var->string );
var->string = copystring( pszValue );
var->string = copystringpool( cvar_pool, pszValue );
var->value = Q_atof( var->string );
// tell engine about changes
@@ -738,7 +739,7 @@ void GAME_EXPORT Cvar_DirectSet( convar_t *var, const char *value )
// and finally changed the cvar itself
freestring( var->string );
var->string = copystring( pszValue );
var->string = copystringpool( cvar_pool, pszValue );
var->value = Q_atof( var->string );
// tell engine about changes
@@ -781,7 +782,7 @@ void Cvar_FullSet( const char *var_name, const char *value, int flags )
}
freestring( var->string );
var->string = copystring( value );
var->string = copystringpool( cvar_pool, value );
var->value = Q_atof( var->string );
SetBits( var->flags, flags );
@@ -1189,6 +1190,7 @@ static void Cvar_List_f( void )
for( var = cvar_vars; var; var = var->next )
{
char value[MAX_VA_STRING];
char *p;
if( var->name[0] == '@' )
continue; // never shows system cvars
@@ -1196,7 +1198,9 @@ static void Cvar_List_f( void )
if( match && !Q_strnicmpext( match, var->name, matchlen ))
continue;
if( Q_colorstr( var->string ))
p = Q_strchr( var->string, '^' );
if( IsColorString( p ))
Q_snprintf( value, sizeof( value ), "\"%s\"", var->string );
else Q_snprintf( value, sizeof( value ), "\"^2%s^7\"", var->string );
@@ -1257,7 +1261,7 @@ pending_cvar_t *Cvar_PrepareToUnlink( int group )
continue;
namelen = Q_strlen( cv->name ) + 1;
p = Mem_Malloc( host.mempool, sizeof( *list ) + namelen );
p = Mem_Malloc( cvar_pool, sizeof( *list ) + namelen );
p->next = NULL;
p->cv_cur = cv;
p->cv_next = cv->next;
@@ -1333,6 +1337,7 @@ Reads in all archived cvars
*/
void Cvar_Init( void )
{
cvar_pool = Mem_AllocPool( "Console Variables" );
cvar_vars = NULL;
cvar_active_filter_quirks = NULL;
Cvar_RegisterVariable( &cmd_scripting );
@@ -1345,6 +1350,11 @@ void Cvar_Init( void )
Cmd_AddCommand( "cvarlist", Cvar_List_f, "display all console variables beginning with the specified prefix" );
}
void Cvar_Shutdown( void )
{
Mem_FreePool( &cvar_pool );
}
/*
============
Cvar_PostFSInit

View File

@@ -30,6 +30,8 @@ typedef struct pending_cvar_s
char cv_name[];
} pending_cvar_t;
typedef void (*setpair_t)( const char *key, const void *value, const void *buffer, void *numpairs );
cvar_t *Cvar_GetList( void );
#define Cvar_FindVar( name ) Cvar_FindVarExt( name, 0 )
convar_t *Cvar_FindVarExt( const char *var_name, int ignore_group );
@@ -52,6 +54,7 @@ void Cvar_Reset( const char *var_name );
void Cvar_SetCheatState( void );
qboolean Cvar_CommandWithPrivilegeCheck( convar_t *v, qboolean isPrivileged );
void Cvar_Init( void );
void Cvar_Shutdown( void );
void Cvar_PostFSInit( void );
void Cvar_Unlink( int group );

View File

@@ -49,52 +49,6 @@ const char *CL_MsgInfo( int cmd )
return sz;
}
int GAME_EXPORT CL_Active( void )
{
return false;
}
qboolean CL_Initialized( void )
{
return false;
}
qboolean CL_IsInGame( void )
{
return true; // always active for dedicated servers
}
qboolean CL_IsInConsole( void )
{
return false;
}
qboolean CL_IsIntermission( void )
{
return false;
}
qboolean CL_IsPlaybackDemo( void )
{
return false;
}
qboolean CL_IsRecordDemo( void )
{
return false;
}
qboolean CL_DisableVisibility( void )
{
return false;
}
void CL_Init( void )
{
}
void Key_Init( void )
{
@@ -130,16 +84,6 @@ void CL_WriteMessageHistory( void )
}
void Host_ClientBegin( void )
{
Cbuf_Execute();
}
void Host_ClientFrame( void )
{
}
void Host_InputFrame( void )
{
}
@@ -159,11 +103,6 @@ void GAME_EXPORT S_StopSound(int entnum, int channel, const char *soundname)
}
int GAME_EXPORT CL_GetMaxClients( void )
{
return 0;
}
void IN_TouchInitConfig( void )
{
@@ -174,11 +113,6 @@ void CL_Disconnect( void )
}
void CL_Shutdown( void )
{
}
void R_ClearStaticEntities( void )
{
@@ -189,11 +123,6 @@ void Host_Credits( void )
}
qboolean UI_CreditsActive( void )
{
return false;
}
void S_StopBackgroundTrack( void )
{
@@ -204,11 +133,6 @@ void SCR_BeginLoadingPlaque( qboolean is_background )
}
int S_GetCurrentDynamicSounds( soundlist_t *pout, int size )
{
return 0;
}
void S_StopAllSounds( qboolean ambient )
{

View File

@@ -1,4 +1,4 @@
/*
/*
filesystem.c - game filesystem based on DP fs
Copyright (C) 2003-2006 Mathieu Olivier
Copyright (C) 2000-2007 DarkPlaces contributors
@@ -16,11 +16,21 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#if XASH_SDL
#include <SDL.h> // SDL_GetBasePath
#endif
#include <errno.h>
#include "common.h"
#include "library.h"
#include "platform/platform.h"
CVAR_DEFINE_AUTO( fs_mount_hd, "0", FCVAR_ARCHIVE|FCVAR_PRIVILEGED|FCVAR_LATCH, "mount high definition content folder" );
CVAR_DEFINE_AUTO( fs_mount_lv, "0", FCVAR_ARCHIVE|FCVAR_PRIVILEGED|FCVAR_LATCH, "mount low violence models content folder" );
CVAR_DEFINE_AUTO( fs_mount_addon, "0", FCVAR_ARCHIVE|FCVAR_PRIVILEGED|FCVAR_LATCH, "mount addon content folder" );
CVAR_DEFINE_AUTO( fs_mount_l10n, "0", FCVAR_ARCHIVE|FCVAR_PRIVILEGED|FCVAR_LATCH, "mount localization content folder" );
CVAR_DEFINE_AUTO( ui_language, "english", FCVAR_ARCHIVE|FCVAR_PRIVILEGED|FCVAR_LATCH, "selected game language" );
fs_api_t g_fsapi;
fs_globals_t *FI;
@@ -69,9 +79,23 @@ void *FS_GetNativeObject( const char *obj )
return NULL;
}
static void FS_Rescan_f( void )
void FS_Rescan_f( void )
{
FS_Rescan();
uint32_t flags = 0;
// FIXME: VFS shouldn't care about this, allow engine to mount gamedirs
if( fs_mount_lv.value ) SetBits( flags, FS_MOUNT_LV );
if( fs_mount_hd.value ) SetBits( flags, FS_MOUNT_HD );
if( fs_mount_addon.value ) SetBits( flags, FS_MOUNT_ADDON );
if( fs_mount_l10n.value ) SetBits( flags, FS_MOUNT_L10N );
g_fsapi.Rescan( flags, ui_language.string );
ClearBits( fs_mount_lv.flags, FCVAR_CHANGED );
ClearBits( fs_mount_hd.flags, FCVAR_CHANGED );
ClearBits( fs_mount_addon.flags, FCVAR_CHANGED );
ClearBits( fs_mount_l10n.flags, FCVAR_CHANGED );
ClearBits( ui_language.flags, FCVAR_CHANGED );
}
static void FS_ClearPaths_f( void )
@@ -84,6 +108,11 @@ static void FS_Path_f_( void )
FS_Path_f();
}
static void FS_MakeGameInfo_f( void )
{
g_fsapi.MakeGameInfo();
}
static const fs_interface_t fs_memfuncs =
{
Con_Printf,
@@ -178,14 +207,23 @@ static qboolean FS_DetermineRootDirectory( char *out, size_t size )
#elif XASH_PSVITA
if( PSVita_GetBasePath( out, size ))
return true;
Sys_Error( "couldn't find Xash3D data directory" );
Sys_Error( "couldn't find %s data directory", XASH_ENGINE_NAME );
return false;
#elif ( XASH_SDL == 2 ) && !XASH_NSWITCH // GetBasePath not impl'd in switch-sdl2
path = SDL_GetBasePath();
#if XASH_APPLE
if( path != NULL && Q_stristr( path, ".app" ))
{
SDL_free((void *)path );
path = SDL_GetPrefPath( NULL, XASH_ENGINE_NAME );
}
#endif
if( path != NULL )
{
Q_strncpy( out, path, size );
SDL_free(( void *)path );
SDL_free((void *)path );
return true;
}
@@ -222,6 +260,12 @@ static qboolean FS_DetermineReadOnlyRootDirectory( char *out, size_t size )
return false;
}
void FS_CheckConfig( void )
{
if( fs_mount_lv.value || fs_mount_hd.value || fs_mount_addon.value || fs_mount_l10n.value )
FS_Rescan_f();
}
/*
================
FS_Init
@@ -272,6 +316,12 @@ void FS_Init( const char *basedir )
Cmd_AddRestrictedCommand( "fs_rescan", FS_Rescan_f, "rescan filesystem search pathes" );
Cmd_AddRestrictedCommand( "fs_path", FS_Path_f_, "show filesystem search pathes" );
Cmd_AddRestrictedCommand( "fs_clearpaths", FS_ClearPaths_f, "clear filesystem search pathes" );
Cmd_AddRestrictedCommand( "fs_make_gameinfo", FS_MakeGameInfo_f, "create gameinfo.txt for current running game" );
Cvar_RegisterVariable( &fs_mount_hd );
Cvar_RegisterVariable( &fs_mount_lv );
Cvar_RegisterVariable( &fs_mount_addon );
Cvar_RegisterVariable( &fs_mount_l10n );
if( !Sys_GetParmFromCmdLine( "-dll", host.gamedll ))
host.gamedll[0] = 0;

View File

@@ -43,6 +43,27 @@ GNU General Public License for more details.
static pfnChangeGame pChangeGame = NULL;
host_parm_t host; // host parms
#if XASH_ANDROID
static jmp_buf return_from_main_buf;
/*
===============
Host_ExitInMain
On some platforms (e.g. Android) we can't exit with exit(3) as calling it would
kill wrapper process (e.g. app_process) too early, before all resources would
be freed, contexts released, files closed, etc, etc...
To fix this, we create jmp_buf in Host_Main function, when jumping into with
non-zero value will immediately return from it with `error_on_exit`.
===============
*/
void Host_ExitInMain( void )
{
longjmp( return_from_main_buf, 1 );
}
#endif // XASH_ANDROID
#ifdef XASH_ENGINE_TESTS
struct tests_stats_s tests_stats;
#endif
@@ -119,7 +140,8 @@ static void Sys_PrintUsage( const char *exename )
"\nCommon options:\n"
O("-dev [level] ", "set log verbosity 0-2")
O("-log ", "write log to \"engine.log\"")
O("-log [file name] ", "write log to \"engine.log\" or [file name] if specified")
O("-logtime ", "enable writing timestamps to the log file")
O("-nowriteconfig ", "disable config save")
O("-noch ", "disable crashhandler")
#if XASH_WIN32 // !!!!
@@ -180,7 +202,6 @@ static void Sys_PrintUsage( const char *exename )
O("-daemonize ", "run engine as a daemon")
#endif
#if XASH_SDL == 2
O("-sdl_joy_old_api ","use SDL legacy joystick API")
O("-sdl_renderer <n> ","use alternative SDL_Renderer for software")
#endif // XASH_SDL
#if XASH_ANDROID && !XASH_SDL
@@ -209,7 +230,7 @@ static void Sys_PrintUsage( const char *exename )
fprintf( stderr, usage_str, exename );
#endif
Sys_Quit();
Sys_Quit( NULL );
}
static void Sys_PrintBugcompUsage( const char *exename )
@@ -234,12 +255,7 @@ static void Sys_PrintBugcompUsage( const char *exename )
fprintf( stderr, usage_str, exename );
#endif
Sys_Quit();
}
void Host_ShutdownServer( void )
{
SV_Shutdown( "Server was killed\n" );
Sys_Quit( NULL );
}
/*
@@ -367,9 +383,8 @@ static void Host_NewInstance( const char *name, const char *finalmsg )
if( !pChangeGame ) return;
host.change_game = true;
Q_strncpy( host.finalmsg, finalmsg, sizeof( host.finalmsg ));
if( !Sys_NewInstance( name ))
if( !Sys_NewInstance( name, finalmsg ))
pChangeGame( name ); // call from hl.exe
}
@@ -423,8 +438,7 @@ static void Host_Exec_f( void )
{
string cfgpath;
byte *f;
char *txt;
fs_offset_t len;
fs_offset_t len;
if( Cmd_Argc() != 2 )
{
@@ -479,20 +493,29 @@ static void Host_Exec_f( void )
return;
}
// len is fs_offset_t, which can be larger than size_t
if( len >= SIZE_MAX )
{
Con_Reportf( "%s: %s is too long\n", __func__, Cmd_Argv( 1 ));
return;
}
if( !Q_stricmp( "config.cfg", cfgpath ))
host.config_executed = true;
// adds \n\0 at end of the file
txt = Z_Calloc( len + 2 );
memcpy( txt, f, len );
txt[len] = '\n';
txt[len + 1] = '\0';
Mem_Free( f );
if( !host.apply_game_config )
Con_Printf( "execing %s\n", Cmd_Argv( 1 ));
Cbuf_InsertText( txt );
Mem_Free( txt );
// adds \n at end of the file
// FS_LoadFile always null terminates
if( f[len - 1] != '\n' )
{
Cbuf_InsertTextLen( f, len, len + 1 );
Cbuf_InsertTextLen( "\n", 1, 1 );
}
else Cbuf_InsertTextLen( f, len, len );
Mem_Free( f );
}
/*
@@ -595,7 +618,7 @@ static void Host_GetCommands( void )
{
char *cmd;
while( ( cmd = Sys_Input() ) )
while( ( cmd = Platform_Input() ) )
{
Cbuf_AddText( cmd );
Cbuf_Execute();
@@ -675,17 +698,17 @@ static qboolean Host_Autosleep( double dt, double scale )
static double timewindow; // allocate a time window for sleeps
static int counter; // for debug
static double realsleeptime;
const double sleeptime = sleep * 0.001;
const double sleeptime = sleep * 0.000001;
if( dt < targetframetime * scale )
{
// if we have allocated time window, try to sleep
if( timewindow > realsleeptime )
{
// Platform_Sleep isn't guaranteed to sleep an exact amount of milliseconds
// Platform_Sleep isn't guaranteed to sleep an exact amount of microseconds
// so we measure the real sleep time and use it to decrease the window
double t1 = Sys_DoubleTime(), t2;
Platform_Sleep( sleep ); // in msec!
Platform_NanoSleep( sleep * 1000 ); // in usec!
t2 = Sys_DoubleTime();
realsleeptime = t2 - t1;
@@ -814,11 +837,11 @@ void GAME_EXPORT Host_Error( const char *error, ... )
}
else
{
Con_Printf( "%s: %s", __func__, hosterror1 );
if( host.allow_console )
{
UI_SetActiveMenu( false );
Key_SetKeyDest( key_console );
Con_Printf( "%s: %s", __func__, hosterror1 );
}
else Platform_MessageBox( "Host Error", hosterror1, true );
}
@@ -835,13 +858,12 @@ void GAME_EXPORT Host_Error( const char *error, ... )
recursive = true;
Q_strncpy( hosterror2, hosterror1, sizeof( hosterror2 ));
host.errorframe = host.framecount; // to avoid multply calls per frame
Q_snprintf( host.finalmsg, sizeof( host.finalmsg ), "Server crashed: %s", hosterror1 );
// clearing cmd buffer to prevent execute any commands
COM_InitHostState();
Cbuf_Clear();
Host_ShutdownServer();
SV_Shutdown( "Server was killed due to an error\n" );
CL_Drop(); // drop clients
// recreate world if needs
@@ -920,7 +942,7 @@ static void Host_RunTests( int stage )
#endif
Msg( "Done! %d passed, %d failed\n", tests_stats.passed, tests_stats.failed );
error_on_exit = tests_stats.failed > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
Sys_Quit();
Sys_Quit( NULL );
}
}
#endif
@@ -1022,7 +1044,7 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
}
if( !Sys_CheckParm( "-noch" ))
Sys_SetupCrashHandler();
Sys_SetupCrashHandler( argv[0] );
#if XASH_DLL_LOADER
host.enabledll = !Sys_CheckParm( "-nodll" );
@@ -1109,7 +1131,7 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
#if XASH_DEDICATED
Platform_SetupSigtermHandling();
#endif
Platform_Init( Host_IsDedicated( ) || developer >= DEV_EXTENDED );
Platform_Init( Host_IsDedicated( ) || developer >= DEV_EXTENDED, basedir );
FS_Init( basedir );
Sys_InitLog();
@@ -1167,6 +1189,11 @@ static void Host_FreeCommon( void )
FS_Shutdown();
}
static void Sys_Quit_f( void )
{
Sys_Quit( "command" );
}
/*
=================
Host_Main
@@ -1206,9 +1233,17 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
Cvar_Getf( "buildnum", FCVAR_READ_ONLY, "returns a current build number", "%i", Q_buildnum_compat());
Cvar_Getf( "ver", FCVAR_READ_ONLY, "shows an engine version", "%i/%s (hw build %i)", PROTOCOL_VERSION, XASH_COMPAT_VERSION, Q_buildnum_compat());
Cvar_Getf( "host_ver", FCVAR_READ_ONLY, "detailed info about this build", "%i " XASH_VERSION " %s %s %s", Q_buildnum(), Q_buildos(), Q_buildarch(), Q_buildcommit());
Cvar_Getf( "host_ver", FCVAR_READ_ONLY, "detailed info about this build", "%i " XASH_VERSION " %s %s %s", Q_buildnum(), Q_buildos(), Q_buildarch(), g_buildcommit);
Cvar_Getf( "host_lowmemorymode", FCVAR_READ_ONLY, "indicates if engine compiled for low RAM consumption (0 - normal, 1 - low engine limits, 2 - low protocol limits)", "%i", XASH_LOW_MEMORY );
Cvar_Get( "host_hl25_extended_structs",
#if SUPPORT_HL25_EXTENDED_STRUCTS
"1",
#else
"0",
#endif
FCVAR_READ_ONLY, "indicates if engine was compiled with extended msurface_t struct" );
Mod_Init();
NET_Init();
NET_InitMasters();
@@ -1229,7 +1264,6 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
CL_Init();
HTTP_Init();
ID_Init();
SoundList_Init();
if( Host_IsDedicated( ))
@@ -1241,8 +1275,8 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
// disable texture replacements for dedicated
Cvar_FullSet( "host_allow_materials", "0", FCVAR_READ_ONLY );
Cmd_AddRestrictedCommand( "quit", Sys_Quit, "quit the game" );
Cmd_AddRestrictedCommand( "exit", Sys_Quit, "quit the game" );
Cmd_AddRestrictedCommand( "quit", Sys_Quit_f, "quit the game" );
Cmd_AddRestrictedCommand( "exit", Sys_Quit_f, "quit the game" );
}
else Cmd_AddRestrictedCommand( "minimize", Host_Minimize_f, "minimize main window to tray" );
@@ -1285,6 +1319,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
Cmd_RemoveCommand( "setgl" );
Cbuf_ExecStuffCmds(); // execute stuffcmds (commandline)
SCR_CheckStartupVids(); // must be last
FS_CheckConfig();
if( Sys_GetParmFromCmdLine( "-timedemo", demoname ))
Cbuf_AddTextf( "timedemo %s\n", demoname );
@@ -1313,6 +1348,11 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
// check after all configs were executed
HPAK_CheckIntegrity( hpk_custom_file.string );
#if XASH_ANDROID
if( setjmp( return_from_main_buf ))
return error_on_exit;
#endif // XASH_ANDROID
// main window message loop
while( !host.crashed )
{
@@ -1325,20 +1365,31 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
return 0;
}
void EXPORT Host_Shutdown( void );
void EXPORT Host_Shutdown( void )
{
Host_ShutdownWithReason( "launcher shutdown" );
}
/*
=================
Host_Shutdown
=================
*/
void EXPORT Host_Shutdown( void )
void Host_ShutdownWithReason( const char *reason )
{
qboolean error = host.status == HOST_ERR_FATAL;
if( host.shutdown_issued ) return;
if( host.shutdown_issued )
return;
host.shutdown_issued = true;
if( host.status != HOST_ERR_FATAL ) host.status = HOST_SHUTDOWN; // prepare host to normal shutdown
if( !host.change_game ) Q_strncpy( host.finalmsg, "Server shutdown", sizeof( host.finalmsg ));
if( reason != NULL )
Con_Printf( S_NOTE "Issuing host shutdown due to reason \"%s\"\n", reason );
if( host.status != HOST_ERR_FATAL )
host.status = HOST_SHUTDOWN; // prepare host to normal shutdown
#if !XASH_DEDICATED
if( host.type == HOST_NORMAL && !error )
@@ -1357,10 +1408,14 @@ void EXPORT Host_Shutdown( void )
Host_FreeCommon();
Platform_Shutdown();
BaseCmd_Shutdown();
Cmd_Shutdown();
Cvar_Shutdown();
// must be last, console uses this
Mem_FreePool( &host.mempool );
// restore filter
Sys_RestoreCrashHandler();
Sys_CloseLog();
Sys_CloseLog( reason );
}

View File

@@ -38,7 +38,7 @@ static void HPAK_MaxSize_f( void )
Con_Printf( S_ERROR "hpk_maxsize is deprecated, use hpk_max_size\n" );
}
static const char *HPAK_TypeFromIndex( int type )
const char *COM_ResourceTypeFromIndex( int type )
{
switch( type )
{
@@ -104,7 +104,7 @@ static void HPAK_CreatePak( const char *filename, resource_t *pResource, byte *p
string pakname;
byte md5[16];
file_t *fout;
MD5Context_t ctx;
MD5Context_t ctx = { 0 };
if( !COM_CheckString( filename ))
return;
@@ -125,7 +125,6 @@ static void HPAK_CreatePak( const char *filename, resource_t *pResource, byte *p
}
// let's hash it.
memset( &ctx, 0, sizeof( MD5Context_t ));
MD5Init( &ctx );
if( pData == NULL )
@@ -214,7 +213,7 @@ void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource,
file_t *file_src;
file_t *file_dst;
byte md5[16];
MD5Context_t ctx;
MD5Context_t ctx = { 0 };
if( pData == NULL && pFile == NULL )
return;
@@ -226,7 +225,6 @@ void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource,
}
// hash it
memset( &ctx, 0, sizeof( MD5Context_t ));
MD5Init( &ctx );
if( !pData )
@@ -463,7 +461,7 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet, qboolean de
if( !quiet )
{
Con_Printf( "%i: %s %s %s: ", i, HPAK_TypeFromIndex( pRes->type ),
Con_Printf( "%i: %s %s %s: ", i, COM_ResourceTypeFromIndex( pRes->type ),
Q_pretifymem( pRes->nDownloadSize, 2 ), pRes->szFileName );
}
@@ -944,7 +942,7 @@ static void HPAK_List_f( void )
{
entry = &directory.entries[nCurrent];
COM_FileBase( entry->resource.szFileName, lumpname, sizeof( lumpname ));
type = HPAK_TypeFromIndex( entry->resource.type );
type = COM_ResourceTypeFromIndex( entry->resource.type );
size = Q_memprint( entry->resource.nDownloadSize );
Con_Printf( "%i: %10s %s %s\n : %s\n", nCurrent + 1, type, size, lumpname, MD5_Print( entry->resource.rgucMD5_hash ));
@@ -1039,7 +1037,7 @@ static void HPAK_Extract_f( void )
continue;
COM_FileBase( entry->resource.szFileName, lumpname, sizeof( lumpname ) );
type = HPAK_TypeFromIndex( entry->resource.type );
type = COM_ResourceTypeFromIndex( entry->resource.type );
size = Q_memprint( entry->resource.nDownloadSize );
Con_Printf( "Extracting %i: %10s %s %s\n", nCurrent + 1, type, size, lumpname );

View File

@@ -15,6 +15,7 @@ GNU General Public License for more details.
#include <math.h>
#include "imagelib.h"
#include "eiface.h" // ARRAYSIZE
// global image variables
imglib_t image;
@@ -67,7 +68,6 @@ static const cubepack_t load_cubemap[] =
{ "3Ds Sky1", skybox_qv1 },
{ "3Ds Sky2", skybox_qv2 },
{ "3Ds Cube", cubemap_v1 },
{ NULL, NULL },
};
// soul of ImageLib - table of image format constants
@@ -297,9 +297,8 @@ rgbdata_t *FS_LoadImage( const char *filename, const byte *buffer, size_t size )
{
const char *ext = COM_FileExtension( filename );
string loadname;
int i;
int i, j;
const loadpixformat_t *extfmt;
const cubepack_t *cmap;
Q_strncpy( loadname, filename, sizeof( loadname ));
Image_Reset(); // clear old image
@@ -317,8 +316,10 @@ rgbdata_t *FS_LoadImage( const char *filename, const byte *buffer, size_t size )
return ImagePack();
// check all cubemap sides with package suffix
for( cmap = load_cubemap; cmap && cmap->type; cmap++ )
for( j = 0; j < ARRAYSIZE( load_cubemap ); j++ )
{
const cubepack_t *cmap = &load_cubemap[j];
for( i = 0; i < 6; i++ )
{
if( Image_ProbeLoad( extfmt, loadname, cmap->type[i].suf, cmap->type[i].hint ))

View File

@@ -28,12 +28,20 @@ Image_LoadPAL
qboolean Image_LoadPAL( const char *name, const byte *buffer, fs_offset_t filesize )
{
int rendermode = LUMP_NORMAL;
byte pal[768];
if( filesize != 768 )
if( filesize > sizeof( pal ))
{
Con_DPrintf( S_ERROR "%s: (%s) have invalid size (%li should be %d)\n", __func__, name, (long)filesize, 768 );
Con_DPrintf( S_ERROR "%s: (%s) have invalid size (%li should be less or equal than %d)\n", __func__, name, (long)filesize, sizeof( pal ));
return false;
}
else if( filesize < sizeof( pal ) && buffer != NULL )
{
// palette might be truncated, fill it with zeros
memset( pal, 0, sizeof( pal ));
memcpy( pal, buffer, filesize );
buffer = pal;
}
if( name[0] == '#' )
{

View File

@@ -37,11 +37,7 @@ static char **szArgv;
static void Sys_ChangeGame( const char *progname )
{
// a1ba: may never be called within engine
// if platform supports execv() function
Q_strncpy( szGameDir, progname, sizeof( szGameDir ));
Host_Shutdown( );
exit( Host_Main( szArgc, szArgv, szGameDir, 1, &Sys_ChangeGame ) );
// stub
}
static int Sys_Start( void )

View File

@@ -385,10 +385,7 @@ void NET_SaveMasters( void )
master_t *m;
if( !ml.modified )
{
Con_Reportf( "Master server list not changed\n" );
return;
}
f = FS_Open( "xashcomm.lst", "w", true );
@@ -422,14 +419,21 @@ void NET_InitMasters( void )
Cvar_RegisterVariable( &sv_verbose_heartbeats );
// keep main master always there
NET_AddMaster( MASTERSERVER_ADR, false, false );
NET_AddMaster( "mentality.rip:27011", false, false ); // testing server, might be offline
NET_AddMaster( "ms2.mentality.rip:27010", false, false ); // secondary master
{ // IPv4-only
NET_AddMaster( "mentality.rip:27010", false, false );
NET_AddMaster( "ms2.mentality.rip:27010", false, false );
NET_AddMaster( "ms3.mentality.rip:27010", false, false );
}
NET_AddMaster( "aaaa.mentality.rip:27010", false, true ); // IPv6-only
NET_AddMaster( "aaaa.mentality.rip:27011", false, true ); // IPv6-only, testing server, might be offline
NET_AddMaster( "aaaa.ms2.mentality.rip:27010", false, false ); // secondary IPv6-only master
{ // IPv6-only
NET_AddMaster( "aaaa.mentality.rip:27010", false, true );
NET_AddMaster( "aaaa.ms2.mentality.rip:27010", false, true );
}
{ // testing servers, might be offline
NET_AddMaster( "mentality.rip:27011", false, false );
NET_AddMaster( "aaaa.mentality.rip:27011", false, true );
}
NET_LoadMasters( );
}

View File

@@ -385,6 +385,35 @@ static const mlumpinfo_t extlumps[EXTRA_LUMPS] =
},
};
#define BOX_CLIPNODES_INITIALIZER \
{ \
.planenum = 0, \
.children = { CONTENTS_EMPTY, 1 }, \
}, \
{ \
.planenum = 1, \
.children = { 2, CONTENTS_EMPTY }, \
}, \
{ \
.planenum = 2, \
.children = { CONTENTS_EMPTY, 3 }, \
}, \
{ \
.planenum = 3, \
.children = { 4, CONTENTS_EMPTY }, \
}, \
{ \
.planenum = 4, \
.children = { CONTENTS_EMPTY, 5 }, \
}, \
{ \
.planenum = 5, \
.children = { CONTENTS_SOLID, CONTENTS_EMPTY }, \
}, \
const mclipnode16_t box_clipnodes16[6] = { BOX_CLIPNODES_INITIALIZER };
const mclipnode32_t box_clipnodes32[6] = { BOX_CLIPNODES_INITIALIZER };
/*
===============================================================================
@@ -453,7 +482,7 @@ static int Mod_LoadTextureFromWadList( wadlist_t *list, const char *name, rgbdat
return -1;
}
static fs_offset_t Mod_CalculateMipTexSize( mip_t *mt, qboolean palette )
static fs_offset_t Mod_CalculateMipTexSize( const mip_t *mt, qboolean palette )
{
if( !mt )
return 0;
@@ -856,7 +885,7 @@ Mod_PointInLeaf
==================
*/
mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node )
mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node, model_t *mod )
{
Assert( node != NULL );
@@ -864,7 +893,7 @@ mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node )
{
if( node->contents < 0 )
return (mleaf_t *)node;
node = node->children[PlaneDiff( p, node->plane ) <= 0];
node = node_child( node, PlaneDiff( p, node->plane ) <= 0, mod );
}
// never reached
@@ -885,7 +914,7 @@ byte *Mod_GetPVSForPoint( const vec3_t p )
ASSERT( worldmodel != NULL );
leaf = Mod_PointInLeaf( p, worldmodel->nodes );
leaf = Mod_PointInLeaf( p, worldmodel->nodes, worldmodel );
if( leaf && leaf->cluster >= 0 )
return Mod_DecompressPVS( leaf->compressed_vis, world.visbytes );
@@ -905,14 +934,14 @@ static void Mod_FatPVS_RecursiveBSPNode( const vec3_t org, float radius, byte *v
float d = PlaneDiff( org, node->plane );
if( d > radius )
node = node->children[0];
node = node_child( node, 0, worldmodel );
else if( d < -radius )
node = node->children[1];
node = node_child( node, 1, worldmodel );
else
{
// go down both sides
Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, visbytes, node->children[0], phs );
node = node->children[1];
Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, visbytes, node_child( node, 0, worldmodel ), phs );
node = node_child( node, 1, worldmodel );
}
}
@@ -950,7 +979,7 @@ int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, q
ASSERT( worldmodel != NULL );
leaf = Mod_PointInLeaf( org, worldmodel->nodes );
leaf = Mod_PointInLeaf( org, worldmodel->nodes, worldmodel );
bytes = Q_min( bytes, visbytes );
// enable full visibility for some reasons
@@ -1009,20 +1038,16 @@ static void Mod_BoxLeafnums_r( leaflist_t *ll, mnode_t *node )
sides = BOX_ON_PLANE_SIDE( ll->mins, ll->maxs, node->plane );
if( sides == 1 )
{
node = node->children[0];
}
node = node_child( node, 0, worldmodel );
else if( sides == 2 )
{
node = node->children[1];
}
node = node_child( node, 1, worldmodel );
else
{
// go down both
if( ll->topnode == -1 )
ll->topnode = node - worldmodel->nodes;
Mod_BoxLeafnums_r( ll, node->children[0] );
node = node->children[1];
Mod_BoxLeafnums_r( ll, node_child( node, 0, worldmodel ));
node = node_child( node, 1, worldmodel );
}
}
}
@@ -1079,35 +1104,6 @@ qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbi
return false;
}
/*
=============
Mod_HeadnodeVisible
=============
*/
qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, int *lastleaf )
{
if( !node || node->contents == CONTENTS_SOLID )
return false;
if( node->contents < 0 )
{
if( !CHECKVISBIT( visbits, ((mleaf_t *)node)->cluster ))
return false;
if( lastleaf )
*lastleaf = ((mleaf_t *)node)->cluster;
return true;
}
if( Mod_HeadnodeVisible( node->children[0], visbits, lastleaf ))
return true;
if( Mod_HeadnodeVisible( node->children[1], visbits, lastleaf ))
return true;
return false;
}
/*
=================
Mod_FindModelOrigin
@@ -1264,22 +1260,35 @@ Mod_GetFaceContents
determine face contents by name
==================
*/
static mvertex_t *Mod_GetVertexByNumber( model_t *mod, int surfedge )
static mvertex_t *Mod_GetVertexByNumber( model_t *mod, int surfedge, const dbspmodel_t *bmod )
{
int lindex;
medge_t *edge;
int lindex = mod->surfedges[surfedge];
lindex = mod->surfedges[surfedge];
if( lindex > 0 )
if( bmod->version == QBSP2_VERSION )
{
edge = &mod->edges[lindex];
return &mod->vertexes[edge->v[0]];
if( lindex > 0 )
{
medge32_t *edge = &mod->edges32[lindex];
return &mod->vertexes[edge->v[0]];
}
else
{
medge32_t *edge = &mod->edges32[-lindex];
return &mod->vertexes[edge->v[1]];
}
}
else
{
edge = &mod->edges[-lindex];
return &mod->vertexes[edge->v[1]];
if( lindex > 0 )
{
medge16_t *edge = &mod->edges16[lindex];
return &mod->vertexes[edge->v[0]];
}
else
{
medge16_t *edge = &mod->edges16[-lindex];
return &mod->vertexes[edge->v[1]];
}
}
}
@@ -1364,7 +1373,7 @@ Mod_CalcSurfaceExtents
Fills in surf->texturemins[] and surf->extents[]
=================
*/
static void Mod_CalcSurfaceExtents( model_t *mod, msurface_t *surf )
static void Mod_CalcSurfaceExtents( model_t *mod, msurface_t *surf, const dbspmodel_t *bmod )
{
// this place is VERY critical to precision
// keep it as float, don't use double, because it causes issues with lightmap
@@ -1391,8 +1400,16 @@ static void Mod_CalcSurfaceExtents( model_t *mod, msurface_t *surf )
if( e >= mod->numedges || e <= -mod->numedges )
Host_Error( "%s: bad edge\n", __func__ );
if( e >= 0 ) v = &mod->vertexes[mod->edges[e].v[0]];
else v = &mod->vertexes[mod->edges[-e].v[1]];
if( bmod->version == QBSP2_VERSION )
{
if( e >= 0 ) v = &mod->vertexes[mod->edges32[e].v[0]];
else v = &mod->vertexes[mod->edges32[-e].v[1]];
}
else
{
if( e >= 0 ) v = &mod->vertexes[mod->edges16[e].v[0]];
else v = &mod->vertexes[mod->edges16[-e].v[1]];
}
for( j = 0; j < 2; j++ )
{
@@ -1446,7 +1463,7 @@ Mod_CalcSurfaceBounds
fills in surf->mins and surf->maxs
=================
*/
static void Mod_CalcSurfaceBounds( model_t *mod, msurface_t *surf )
static void Mod_CalcSurfaceBounds( model_t *mod, msurface_t *surf, const dbspmodel_t *bmod )
{
int i, e;
mvertex_t *v;
@@ -1460,8 +1477,16 @@ static void Mod_CalcSurfaceBounds( model_t *mod, msurface_t *surf )
if( e >= mod->numedges || e <= -mod->numedges )
Host_Error( "%s: bad edge\n", __func__ );
if( e >= 0 ) v = &mod->vertexes[mod->edges[e].v[0]];
else v = &mod->vertexes[mod->edges[-e].v[1]];
if( bmod->version == QBSP2_VERSION )
{
if( e >= 0 ) v = &mod->vertexes[mod->edges32[e].v[0]];
else v = &mod->vertexes[mod->edges32[-e].v[1]];
}
else
{
if( e >= 0 ) v = &mod->vertexes[mod->edges16[e].v[0]];
else v = &mod->vertexes[mod->edges16[-e].v[1]];
}
AddPointToBounds( v->position, surf->info->mins, surf->info->maxs );
}
@@ -1473,7 +1498,7 @@ static void Mod_CalcSurfaceBounds( model_t *mod, msurface_t *surf )
Mod_CreateFaceBevels
=================
*/
static void Mod_CreateFaceBevels( model_t *mod, msurface_t *surf )
static void Mod_CreateFaceBevels( model_t *mod, msurface_t *surf, const dbspmodel_t *bmod )
{
vec3_t delta, edgevec;
byte *facebevel;
@@ -1506,8 +1531,8 @@ static void Mod_CreateFaceBevels( model_t *mod, msurface_t *surf )
{
mplane_t *dest = &fb->edges[i];
v0 = Mod_GetVertexByNumber( mod, surf->firstedge + i );
v1 = Mod_GetVertexByNumber( mod, surf->firstedge + (i + 1) % surf->numedges );
v0 = Mod_GetVertexByNumber( mod, surf->firstedge + i, bmod );
v1 = Mod_GetVertexByNumber( mod, surf->firstedge + (i + 1) % surf->numedges, bmod );
VectorSubtract( v1->position, v0->position, edgevec );
CrossProduct( faceNormal, edgevec, dest->normal );
VectorNormalize( dest->normal );
@@ -1521,7 +1546,7 @@ static void Mod_CreateFaceBevels( model_t *mod, msurface_t *surf )
// compute face radius
for( i = 0; i < surf->numedges; i++ )
{
v0 = Mod_GetVertexByNumber( mod, surf->firstedge + i );
v0 = Mod_GetVertexByNumber( mod, surf->firstedge + i, bmod );
VectorSubtract( v0->position, fb->origin, delta );
radius = DotProduct( delta, delta );
fb->radius = Q_max( radius, fb->radius );
@@ -1533,13 +1558,15 @@ static void Mod_CreateFaceBevels( model_t *mod, msurface_t *surf )
Mod_SetParent
=================
*/
static void Mod_SetParent( mnode_t *node, mnode_t *parent )
static void Mod_SetParent( model_t *mod, mnode_t *node, mnode_t *parent )
{
node->parent = parent;
if( node->contents < 0 ) return; // it's leaf
Mod_SetParent( node->children[0], node );
Mod_SetParent( node->children[1], node );
if( node->contents < 0 )
return; // it's leaf
Mod_SetParent( mod, node_child( node, 0, mod ), node );
Mod_SetParent( mod, node_child( node, 1, mod ), node );
}
/*
@@ -1547,7 +1574,7 @@ static void Mod_SetParent( mnode_t *node, mnode_t *parent )
CountClipNodes_r
==================
*/
static void CountClipNodes_r( mclipnode_t *src, hull_t *hull, int nodenum )
static void CountClipNodes16_r( mclipnode16_t *src, hull_t *hull, int nodenum )
{
// leaf?
if( nodenum < 0 ) return;
@@ -1556,16 +1583,11 @@ static void CountClipNodes_r( mclipnode_t *src, hull_t *hull, int nodenum )
Host_Error( "MAX_MAP_CLIPNODES limit exceeded\n" );
hull->lastclipnode++;
CountClipNodes_r( src, hull, src[nodenum].children[0] );
CountClipNodes_r( src, hull, src[nodenum].children[1] );
CountClipNodes16_r( src, hull, src[nodenum].children[0] );
CountClipNodes16_r( src, hull, src[nodenum].children[1] );
}
/*
==================
CountClipNodes32_r
==================
*/
static void CountClipNodes32_r( dclipnode32_t *src, hull_t *hull, int nodenum )
static void CountClipNodes32_r( mclipnode32_t *src, hull_t *hull, int nodenum )
{
// leaf?
if( nodenum < 0 ) return;
@@ -1578,15 +1600,27 @@ static void CountClipNodes32_r( dclipnode32_t *src, hull_t *hull, int nodenum )
CountClipNodes32_r( src, hull, src[nodenum].children[1] );
}
static void CountDClipNodes_r( dclipnode32_t *src, hull_t *hull, int nodenum )
{
// leaf?
if( nodenum < 0 ) return;
if( hull->lastclipnode == MAX_MAP_CLIPNODES )
Host_Error( "MAX_MAP_CLIPNODES limit exceeded\n" );
hull->lastclipnode++;
CountDClipNodes_r( src, hull, src[nodenum].children[0] );
CountDClipNodes_r( src, hull, src[nodenum].children[1] );
}
/*
==================
RemapClipNodes_r
==================
*/
static int RemapClipNodes_r( dclipnode32_t *srcnodes, hull_t *hull, int nodenum )
static int RemapClipNodes_r( dbspmodel_t *bmod, dclipnode32_t *srcnodes, hull_t *hull, int nodenum )
{
dclipnode32_t *src;
mclipnode_t *out;
dclipnode32_t *src;
int i, c;
// leaf?
@@ -1599,13 +1633,22 @@ static int RemapClipNodes_r( dclipnode32_t *srcnodes, hull_t *hull, int nodenum
src = srcnodes + nodenum;
c = hull->lastclipnode;
out = &hull->clipnodes[c];
hull->lastclipnode++;
out->planenum = src->planenum;
for( i = 0; i < 2; i++ )
out->children[i] = RemapClipNodes_r( srcnodes, hull, src->children[i] );
if( bmod->version == QBSP2_VERSION )
{
mclipnode32_t *out = &hull->clipnodes32[c];
out->planenum = src->planenum;
for( i = 0; i < 2; i++ )
out->children[i] = RemapClipNodes_r( bmod, srcnodes, hull, src->children[i] );
}
else
{
mclipnode16_t *out = &hull->clipnodes16[c];
out->planenum = src->planenum;
for( i = 0; i < 2; i++ )
out->children[i] = RemapClipNodes_r( bmod, srcnodes, hull, src->children[i] );
}
return c;
}
@@ -1617,34 +1660,64 @@ Mod_MakeHull0
Duplicate the drawing hull structure as a clipping hull
=================
*/
static void Mod_MakeHull0( model_t *mod )
static void Mod_MakeHull0( model_t *mod, const dbspmodel_t *bmod )
{
mnode_t *in, *child;
mclipnode_t *out;
hull_t *hull;
int i, j;
hull = &mod->hulls[0];
hull->clipnodes = out = Mem_Malloc( mod->mempool, mod->numnodes * sizeof( *out ));
in = mod->nodes;
hull_t *hull = &mod->hulls[0];
int i;
hull->firstclipnode = 0;
hull->lastclipnode = mod->numnodes - 1;
hull->planes = mod->planes;
for( i = 0; i < mod->numnodes; i++, out++, in++ )
if( bmod->version == QBSP2_VERSION )
{
out->planenum = in->plane - mod->planes;
mclipnode32_t *out;
mnode_t *in = mod->nodes;
for( j = 0; j < 2; j++ )
hull->clipnodes32 = out = Mem_Malloc( mod->mempool, mod->numnodes * sizeof( *hull->clipnodes32 ));
for( i = 0; i < mod->numnodes; i++, out++, in++ )
{
child = in->children[j];
int j;
if( child->contents < 0 )
out->children[j] = child->contents;
else out->children[j] = child - mod->nodes;
out->planenum = in->plane - mod->planes;
for( j = 0; j < 2; j++ )
{
mnode_t *child = node_child( in, j, mod );
if( child->contents < 0 )
out->children[j] = child->contents;
else
out->children[j] = child - mod->nodes;
}
}
}
else
{
mclipnode16_t *out;
mnode_t *in = mod->nodes;
hull->clipnodes16 = out = Mem_Malloc( mod->mempool, mod->numnodes * sizeof( *hull->clipnodes16 ));
for( i = 0; i < mod->numnodes; i++, out++, in++ )
{
int j;
out->planenum = in->plane - mod->planes;
for( j = 0; j < 2; j++ )
{
mnode_t *child = node_child( in, j, mod );
if( child->contents < 0 )
out->children[j] = child->contents;
else
out->children[j] = child - mod->nodes;
}
}
}
}
/*
@@ -1688,15 +1761,18 @@ static void Mod_SetupHull( dbspmodel_t *bmod, model_t *mod, poolhandle_t mempool
if( VectorIsNull( hull->clip_mins ) && VectorIsNull( hull->clip_maxs ))
return; // no hull specified
CountClipNodes32_r( bmod->clipnodes_out, hull, headnode );
CountDClipNodes_r( bmod->clipnodes_out, hull, headnode );
// fit array to real count
hull->clipnodes = (mclipnode_t *)Mem_Malloc( mempool, sizeof( mclipnode_t ) * hull->lastclipnode );
if( bmod->version == QBSP2_VERSION )
hull->clipnodes32 = Mem_Malloc( mempool, sizeof( *hull->clipnodes32 ) * hull->lastclipnode );
else
hull->clipnodes16 = Mem_Malloc( mempool, sizeof( *hull->clipnodes16 ) * hull->lastclipnode );
hull->planes = mod->planes; // share planes
hull->lastclipnode = 0; // restart counting
// remap clipnodes to 16-bit indexes
RemapClipNodes_r( bmod->clipnodes_out, hull, headnode );
RemapClipNodes_r( bmod, bmod->clipnodes_out, hull, headnode ); // remap clipnodes to 16-bit indexes
}
static qboolean Mod_LoadLitfile( model_t *mod, const char *ext, size_t expected_size, color24 **out, size_t *outsize )
@@ -1704,7 +1780,8 @@ static qboolean Mod_LoadLitfile( model_t *mod, const char *ext, size_t expected_
char modelname[64], path[64];
int iCompare;
fs_offset_t datasize;
byte *in;
file_t *f;
uint hdr[2];
COM_FileBase( mod->name, modelname, sizeof( modelname ));
Q_snprintf( path, sizeof( path ), "maps/%s.%s", modelname, ext );
@@ -1715,31 +1792,15 @@ static qboolean Mod_LoadLitfile( model_t *mod, const char *ext, size_t expected_
if( iCompare < 0 ) // this may happens if level-designer used -onlyents key for hlcsg
Con_Printf( S_WARN "%s probably is out of date\n", path );
in = FS_LoadFile( path, &datasize, false );
f = FS_Open( path, "rb", false );
if( !in )
if( !f )
{
Con_Printf( S_ERROR "couldn't load %s\n", path );
return false;
}
if( datasize <= 8 ) // header + version
{
Con_Printf( S_ERROR "%s is too short\n", path );
goto cleanup_and_error;
}
if( LittleLong( ((uint *)in)[0] ) != IDDELUXEMAPHEADER )
{
Con_Printf( S_ERROR "%s is corrupted\n", path );
goto cleanup_and_error;
}
if( LittleLong( ((uint *)in)[1] ) != DELUXEMAP_VERSION )
{
Con_Printf( S_ERROR "has %s mismatched version (%u should be %u)\n", path, LittleLong( ((uint *)in)[1] ), DELUXEMAP_VERSION );
goto cleanup_and_error;
}
datasize = FS_FileLength( f );
// skip header bytes
datasize -= 8;
@@ -1750,14 +1811,33 @@ static qboolean Mod_LoadLitfile( model_t *mod, const char *ext, size_t expected_
goto cleanup_and_error;
}
if( FS_Read( f, hdr, sizeof( hdr )) != sizeof( hdr ))
{
Con_Printf( S_ERROR "failed reading header from %s\n", path );
goto cleanup_and_error;
}
if( LittleLong( hdr[0] ) != IDDELUXEMAPHEADER )
{
Con_Printf( S_ERROR "%s is corrupted\n", path );
goto cleanup_and_error;
}
if( LittleLong( hdr[1] ) != DELUXEMAP_VERSION )
{
Con_Printf( S_ERROR "has %s mismatched version (%u should be %u)\n", path, LittleLong( hdr[1] ), DELUXEMAP_VERSION );
goto cleanup_and_error;
}
*out = Mem_Malloc( mod->mempool, datasize );
memcpy( *out, in + 8, datasize );
*outsize = datasize;
Mem_Free( in );
FS_Read( f, *out, datasize );
FS_Close( f );
return true;
cleanup_and_error:
Mem_Free( in );
FS_Close( f );
return false;
}
@@ -1772,6 +1852,7 @@ for embedded submodels
static void Mod_SetupSubmodels( model_t *mod, dbspmodel_t *bmod )
{
qboolean colored = false;
qboolean qbsp2 = false;
poolhandle_t mempool;
char *ents;
dmodel_t *bm;
@@ -1783,6 +1864,9 @@ static void Mod_SetupSubmodels( model_t *mod, dbspmodel_t *bmod )
if( FBitSet( mod->flags, MODEL_COLORED_LIGHTING ))
colored = true;
if( FBitSet( mod->flags, MODEL_QBSP2 ))
qbsp2 = true;
mod->numframes = 2; // regular and alternate animation
// set up the submodels
@@ -1795,7 +1879,10 @@ static void Mod_SetupSubmodels( model_t *mod, dbspmodel_t *bmod )
mod->hulls[0].lastclipnode = bm->headnode[0]; // need to be real count
// counting a real number of clipnodes per each submodel
CountClipNodes_r( mod->hulls[0].clipnodes, &mod->hulls[0], bm->headnode[0] );
if( bmod->version == QBSP2_VERSION )
CountClipNodes32_r( mod->hulls[0].clipnodes32, &mod->hulls[0], bm->headnode[0] );
else
CountClipNodes16_r( mod->hulls[0].clipnodes16, &mod->hulls[0], bm->headnode[0] );
// but hulls1-3 is build individually for a each given submodel
for( j = 1; j < MAX_MAP_HULLS; j++ )
@@ -1813,6 +1900,7 @@ static void Mod_SetupSubmodels( model_t *mod, dbspmodel_t *bmod )
// this bit will be shared between all the submodels include worldmodel
if( colored ) SetBits( mod->flags, MODEL_COLORED_LIGHTING );
if( qbsp2 ) SetBits( mod->flags, MODEL_QBSP2 );
if( i != 0 )
{
@@ -2135,15 +2223,15 @@ Mod_LoadEdges
*/
static void Mod_LoadEdges( model_t *mod, dbspmodel_t *bmod )
{
medge_t *out;
int i;
mod->edges = out = Mem_Malloc( mod->mempool, bmod->numedges * sizeof( medge_t ));
mod->numedges = bmod->numedges;
if( bmod->version == QBSP2_VERSION )
{
dedge32_t *in = (dedge32_t *)bmod->edges32;
dedge32_t *in = bmod->edges32;
medge32_t *out;
mod->edges32 = out = Mem_Malloc( mod->mempool, bmod->numedges * sizeof( *out ));
for( i = 0; i < bmod->numedges; i++, in++, out++ )
{
@@ -2153,7 +2241,9 @@ static void Mod_LoadEdges( model_t *mod, dbspmodel_t *bmod )
}
else
{
dedge_t *in = (dedge_t *)bmod->edges;
dedge_t *in = bmod->edges;
medge16_t *out;
mod->edges16 = out = Mem_Malloc( mod->mempool, bmod->numedges * sizeof( *out ));
for( i = 0; i < bmod->numedges; i++, in++, out++ )
{
@@ -2269,7 +2359,7 @@ static qboolean Mod_SearchForTextureReplacement( char *out, size_t size, const c
return false;
}
static void Mod_InitSkyClouds( model_t *mod, mip_t *mt, texture_t *tx, qboolean custom_palette )
static void Mod_InitSkyClouds( model_t *mod, const mip_t *mt, texture_t *tx, qboolean custom_palette )
{
#if !XASH_DEDICATED
rgbdata_t r_temp, *r_sky;
@@ -2426,9 +2516,6 @@ done:
static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureIndex )
{
texture_t *texture = NULL;
mip_t *mipTex = NULL;
qboolean usesCustomPalette = false;
uint32_t txFlags = 0;
char texpath[MAX_VA_STRING];
char safemtname[16]; // only for external textures
@@ -2436,12 +2523,10 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
// don't load texture data on dedicated server, as there is no renderer.
// but count the wadusage for automatic precache
//
// FIXME: for ENGINE_IMPROVED_LINETRACE we need to load textures on server too
// but there is no facility for this yet
texture = mod->textures[textureIndex];
mipTex = Mod_GetMipTexForTexture( bmod, textureIndex );
usesCustomPalette = Mod_CalcMipTexUsesCustomPalette( mod, bmod, textureIndex );
texture_t *texture = mod->textures[textureIndex];
const mip_t *mipTex = Mod_GetMipTexForTexture( bmod, textureIndex );
const qboolean usesCustomPalette = Mod_CalcMipTexUsesCustomPalette( mod, bmod, textureIndex );
const qboolean iswater = Mod_LooksLikeWaterTexture( mipTex->name );
// check for multi-layered sky texture (quake1 specific)
if( bmod->isworld && Q_strncmp( mipTex->name, "sky", 3 ) == 0 && ( mipTex->width / mipTex->height ) == 2 )
@@ -2450,11 +2535,13 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
return;
}
// FIXME: for ENGINE_IMPROVED_LINETRACE we need to load textures on server too
// but there is no facility for this yet
if( FBitSet( host.features, ENGINE_IMPROVED_LINETRACE ) && mipTex->name[0] == '{' )
SetBits( txFlags, TF_KEEP_SOURCE ); // Paranoia2 texture alpha-tracing
// check if this is water to keep the source texture and expand it to RGBA (so ripple effect works)
if( Mod_LooksLikeWaterTexture( mipTex->name ))
if( iswater )
SetBits( txFlags, TF_KEEP_SOURCE | TF_EXPAND_SOURCE );
// Texture loading order:
@@ -2519,8 +2606,13 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
texture->gl_texturenum = R_GetBuiltinTexture( REF_DEFAULT_TEXTURE );
}
// Check for luma texture
texture->fb_texturenum = 0;
// Check for luma texture
// a1ba: ignore for water because fb_texturenum will be used to store ripple texture
if( iswater )
return;
if( load_external ) // external textures will not have TF_HAS_LUMA flag because it set only from WAD images loader
{
if( Mod_SearchForTextureReplacement( texpath, sizeof( texpath ), mod->name, safemtname, "_luma" ))
@@ -2913,9 +3005,9 @@ static void Mod_LoadSurfaces( model_t *mod, dbspmodel_t *bmod )
if( FBitSet( out->texinfo->flags, TEX_SPECIAL ))
SetBits( out->flags, SURF_DRAWTILED );
Mod_CalcSurfaceBounds( mod, out );
Mod_CalcSurfaceExtents( mod, out );
Mod_CreateFaceBevels( mod, out );
Mod_CalcSurfaceBounds( mod, out, bmod );
Mod_CalcSurfaceExtents( mod, out, bmod );
Mod_CreateFaceBevels( mod, out, bmod );
// grab the second sample to detect colored lighting
if( test_lightsize > 0 && lightofs != -1 )
@@ -2962,7 +3054,6 @@ static void Mod_LoadSurfaces( model_t *mod, dbspmodel_t *bmod )
if( samples == 1 || samples == 3 )
{
bmod->lightmap_samples = (int)samples;
Con_Reportf( "lighting: %s\n", (bmod->lightmap_samples == 1) ? "monochrome" : "colored" );
bmod->lightmap_samples = Q_max( bmod->lightmap_samples, 1 ); // avoid division by zero
}
else Con_DPrintf( S_WARN "lighting invalid samplecount: %g, defaulting to %i\n", samples, bmod->lightmap_samples );
@@ -2994,16 +3085,62 @@ static void Mod_LoadNodes( model_t *mod, dbspmodel_t *bmod )
out->minmaxs[j+3] = in->maxs[j];
}
#if !XASH_64BIT
if( in->firstface >= BIT( 24 ))
{
Host_Error( "%s: face index limit exceeded on node %i\n", __func__, i );
return;
}
if( in->numfaces >= BIT( 24 ))
{
Host_Error( "%s: face count limit exceeded on node %i\n", __func__, i );
return;
}
#endif
p = in->planenum;
out->plane = mod->planes + p;
out->firstsurface = in->firstface;
out->numsurfaces = in->numfaces;
out->firstsurface_0 = in->firstface & 0xFFFF;
out->numsurfaces_0 = in->numfaces & 0xFFFF;
out->firstsurface_1 = in->firstface >> 16;
out->numsurfaces_1 = in->numfaces >> 16;
for( j = 0; j < 2; j++ )
{
p = in->children[j];
if( p >= 0 ) out->children[j] = mod->nodes + p;
else out->children[j] = (mnode_t *)(mod->leafs + ( -1 - p ));
#if XASH_64BIT
if( p >= 0 ) out->children_[j] = mod->nodes + p;
else out->children_[j] = (mnode_t *)(mod->leafs + ( -1 - p ));
#else
if( j == 0 )
{
if( p >= 0 )
{
out->child_0_leaf = 0;
out->child_0_off = p;
}
else
{
out->child_0_leaf = 1;
out->child_0_off = -1 - p;
}
}
else
{
if( p >= 0 )
{
out->child_1_leaf = 0;
out->child_1_off = p;
}
else
{
out->child_1_leaf = 1;
out->child_1_off = -1 - p;
}
}
#endif
}
}
else
@@ -3018,20 +3155,20 @@ static void Mod_LoadNodes( model_t *mod, dbspmodel_t *bmod )
p = in->planenum;
out->plane = mod->planes + p;
out->firstsurface = in->firstface;
out->numsurfaces = in->numfaces;
out->firstsurface_0 = in->firstface;
out->numsurfaces_0 = in->numfaces;
for( j = 0; j < 2; j++ )
{
p = in->children[j];
if( p >= 0 ) out->children[j] = mod->nodes + p;
else out->children[j] = (mnode_t *)(mod->leafs + ( -1 - p ));
if( p >= 0 ) out->children_[j] = mod->nodes + p;
else out->children_[j] = (mnode_t *)(mod->leafs + ( -1 - p ));
}
}
}
// sets nodes and leafs
Mod_SetParent( mod->nodes, NULL );
Mod_SetParent( mod, mod->nodes, NULL );
}
/*
@@ -3413,6 +3550,8 @@ static void Mod_LoadLighting( model_t *mod, dbspmodel_t *bmod )
break;
}
Con_Reportf( "lighting: %s\n", FBitSet( mod->flags, MODEL_COLORED_LIGHTING ) ? "colored" : "monochrome" );
// not supposed to be load ?
if( FBitSet( host.features, ENGINE_LOAD_DELUXEDATA ))
{
@@ -3491,13 +3630,6 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, const byte *mod_base, qboolea
Q_strncpy( loadstat.name, mod->name, sizeof( loadstat.name ));
wadvalue[0] = '\0';
#ifndef SUPPORT_BSP2_FORMAT
if( header->version == QBSP2_VERSION )
{
Con_Printf( S_ERROR DEFAULT_BSP_BUILD_ERROR, mod->name );
return false;
}
#endif
switch( header->version )
{
case HLBSP_VERSION:
@@ -3520,6 +3652,9 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, const byte *mod_base, qboolea
// everything else
srclumps[0].lumpnumber = LUMP_ENTITIES;
srclumps[1].lumpnumber = LUMP_PLANES;
if( header->version == QBSP2_VERSION )
SetBits( mod->flags, MODEL_QBSP2 );
break;
default:
Con_Printf( S_ERROR "%s has wrong version number (%i should be %i)\n", mod->name, header->version, HLBSP_VERSION );
@@ -3570,7 +3705,7 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, const byte *mod_base, qboolea
Mod_LoadClipnodes( mod, bmod );
// preform some post-initalization
Mod_MakeHull0( mod );
Mod_MakeHull0( mod, bmod );
Mod_SetupSubmodels( mod, bmod );
if( isworld )
@@ -3660,15 +3795,6 @@ qboolean Mod_TestBmodelLumps( file_t *f, const char *name, const byte *mod_base,
if( silent )
SetBits( flags, LUMP_SILENT );
#ifndef SUPPORT_BSP2_FORMAT
if( header->version == QBSP2_VERSION )
{
if( !FBitSet( flags, LUMP_SILENT ))
Con_Printf( S_ERROR DEFAULT_BSP_BUILD_ERROR, name );
return false;
}
#endif
switch( header->version )
{
case HLBSP_VERSION:

View File

@@ -135,6 +135,8 @@ extern poolhandle_t com_studiocache;
extern convar_t mod_studiocache;
extern convar_t r_wadtextures;
extern convar_t r_showhull;
extern const mclipnode16_t box_clipnodes16[6];
extern const mclipnode32_t box_clipnodes32[6];
//
// model.c
@@ -167,13 +169,12 @@ void Mod_LoadAliasModel( model_t *mod, const void *buffer, qboolean *loaded );
//
void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *loaded );
qboolean Mod_TestBmodelLumps( file_t *f, const char *name, const byte *mod_base, qboolean silent, dlump_t *entities );
qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, int *lastleaf );
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis, qboolean false );
qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbits );
int Mod_CheckLump( const char *filename, const int lump, int *lumpsize );
int Mod_ReadLump( const char *filename, const int lump, void **lumpdata, int *lumpsize );
int Mod_SaveLump( const char *filename, const int lump, void *lumpdata, int lumpsize );
mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node );
mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node, model_t *mod );
int Mod_SampleSizeForFace( const msurface_t *surf );
byte *Mod_GetPVSForPoint( const vec3_t p );
void Mod_UnloadBrushModel( model_t *mod );

View File

@@ -50,9 +50,8 @@ static matrix3x4 studio_bones[MAXSTUDIOBONES];
static uint studio_hull_hitgroup[MAXSTUDIOBONES];
static uint cache_hull_hitgroup[MAXSTUDIOBONES];
static mstudiocache_t cache_studio[STUDIO_CACHESIZE];
static mclipnode_t studio_clipnodes[6];
static mplane_t studio_planes[768];
static mplane_t cache_planes[768];
static mplane_t studio_planes[MAXSTUDIOBONES * 6];
static mplane_t cache_planes[MAXSTUDIOBONES * 6];
// current cache state
static int cache_current;
@@ -66,25 +65,14 @@ Mod_InitStudioHull
*/
void Mod_InitStudioHull( void )
{
int i, side;
int i;
if( studio_hull[0].planes != NULL )
return; // already initailized
for( i = 0; i < 6; i++ )
{
studio_clipnodes[i].planenum = i;
side = i & 1;
studio_clipnodes[i].children[side] = CONTENTS_EMPTY;
if( i != 5 ) studio_clipnodes[i].children[side^1] = i + 1;
else studio_clipnodes[i].children[side^1] = CONTENTS_SOLID;
}
for( i = 0; i < MAXSTUDIOBONES; i++ )
{
studio_hull[i].clipnodes = studio_clipnodes;
studio_hull[i].clipnodes16 = (mclipnode16_t *)box_clipnodes16;
studio_hull[i].planes = &studio_planes[i*6];
studio_hull[i].firstclipnode = 0;
studio_hull[i].lastclipnode = 5;
@@ -270,6 +258,11 @@ hull_t *Mod_HullForStudio( model_t *model, float frame, int sequence, vec3_t ang
for( i = j = 0; i < mod_studiohdr->numhitboxes; i++, j += 6 )
{
if( world.version == QBSP2_VERSION )
studio_hull[i].clipnodes32 = (mclipnode32_t *)box_clipnodes32;
else
studio_hull[i].clipnodes16 = (mclipnode16_t *)box_clipnodes16;
if( bSkipShield && i == 21 )
continue; // CS stuff
@@ -389,8 +382,7 @@ static void Mod_StudioCalcRotations( int boneused[], int numbones, const byte *p
for( j = numbones - 1; j >= 0; j-- )
{
i = boneused[j];
R_StudioCalcBoneQuaternion( frame, s, &pbone[i], &panim[i], adj, q[i] );
R_StudioCalcBonePosition( frame, s, &pbone[i], &panim[i], adj, pos[i] );
R_StudioCalcBones( frame, s, &pbone[i], &panim[i], adj, pos[i], q[i] );
}
if( pseqdesc->motiontype & STUDIO_X ) pos[pseqdesc->motionbone][0] = 0.0f;
@@ -731,7 +723,7 @@ void Mod_StudioComputeBounds( void *buffer, vec3_t mins, vec3_t maxs, qboolean i
{
for( k = 0; k < pseqdesc->numframes; k++ )
{
R_StudioCalcBonePosition( k, 0, &pbones[j], panim, NULL, pos );
R_StudioCalcBones( k, 0, &pbones[j], panim, NULL, pos, NULL );
Mod_StudioBoundVertex( vert_mins, vert_maxs, &bone_count, pos );
}
}
@@ -875,7 +867,7 @@ void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded )
mod->type = mod_studio;
phdr = R_StudioLoadHeader( mod, buffer );
if( !phdr )
if( !phdr || phdr->length < sizeof( studiohdr_t )) // garbage value in length
return; // bad model
#if !XASH_DEDICATED

View File

@@ -258,7 +258,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
{
char tempname[MAX_QPATH];
fs_offset_t length = 0;
qboolean loaded;
qboolean loaded, loaded2 = false;
byte *buf;
model_info_t *p;
@@ -279,7 +279,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
buf = FS_LoadFile( tempname, &length, false );
if( !buf )
if( !buf || length < sizeof( uint ))
{
memset( mod, 0, sizeof( model_t ));
@@ -329,11 +329,12 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
// let the server.dll load custom data
svgame.physFuncs.Mod_ProcessUserData( mod, true, buf );
}
loaded2 = true;
}
#if !XASH_DEDICATED
else
{
loaded = ref.dllFuncs.Mod_ProcessRenderData( mod, true, buf );
loaded2 = ref.dllFuncs.Mod_ProcessRenderData( mod, true, buf );
}
#endif
}
@@ -345,7 +346,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
hdr->pposeverts = NULL;
}
if( !loaded )
if( !loaded || !loaded2 )
{
Mod_FreeModel( mod );
Mem_Free( buf );
@@ -610,3 +611,41 @@ void Mod_NeedCRC( const char *name, qboolean needCRC )
if( needCRC ) SetBits( p->flags, FCRC_SHOULD_CHECKSUM );
else ClearBits( p->flags, FCRC_SHOULD_CHECKSUM );
}
#if XASH_ENGINE_TESTS
static const uint8_t *fuzz_data;
static size_t fuzz_size;
static byte *Fuzz_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
{
byte *buf = Mem_Malloc( host.mempool, fuzz_size );
memcpy( buf, fuzz_data, fuzz_size );
*filesizeptr = fuzz_size;
return buf;
}
int EXPORT Fuzz_Mod_LoadModel( const uint8_t *Data, size_t Size );
int EXPORT Fuzz_Mod_LoadModel( const uint8_t *Data, size_t Size )
{
model_t mod = { .name = "test", .needload = NL_NEEDS_LOADED };
Memory_Init();
host.type = HOST_DEDICATED;
host.mempool = Mem_AllocPool( "fuzzing pool" );
fuzz_data = Data;
fuzz_size = Size;
refState.draw_surfaces = NULL;
g_fsapi.LoadFile = Fuzz_LoadFile;
if( Mod_LoadModel( &mod, false ) && mod.mempool )
Mem_FreePool( &mod.mempool );
Mem_FreePool( &host.mempool );
return 0;
}
#endif // XASH_ENGINE_TESTS

View File

@@ -18,11 +18,177 @@ GNU General Public License for more details.
#include "net_buffer.h"
#include "xash3d_mathlib.h"
// precalculated bit masks for WriteUBitLong.
// Using these tables instead of doing the calculations
// gives a 33% speedup in WriteUBitLong.
static uint32_t BitWriteMasks[32][33];
static uint32_t ExtraMasks[32];
static const uint32_t BitWriteMasks[32][32] =
{ {
0xfffffffe, 0xfffffffc, 0xfffffff8, 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80, 0xffffff00,
0xfffffe00, 0xfffffc00, 0xfffff800, 0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000,
0xfffe0000, 0xfffc0000, 0xfff80000, 0xfff00000, 0xffe00000, 0xffc00000, 0xff800000, 0xff000000,
0xfe000000, 0xfc000000, 0xf8000000, 0xf0000000, 0xe0000000, 0xc0000000, 0x80000000, 0x00000000,
}, {
0xfffffffd, 0xfffffff9, 0xfffffff1, 0xffffffe1, 0xffffffc1, 0xffffff81, 0xffffff01, 0xfffffe01,
0xfffffc01, 0xfffff801, 0xfffff001, 0xffffe001, 0xffffc001, 0xffff8001, 0xffff0001, 0xfffe0001,
0xfffc0001, 0xfff80001, 0xfff00001, 0xffe00001, 0xffc00001, 0xff800001, 0xff000001, 0xfe000001,
0xfc000001, 0xf8000001, 0xf0000001, 0xe0000001, 0xc0000001, 0x80000001, 0x00000001, 0x00000001,
}, {
0xfffffffb, 0xfffffff3, 0xffffffe3, 0xffffffc3, 0xffffff83, 0xffffff03, 0xfffffe03, 0xfffffc03,
0xfffff803, 0xfffff003, 0xffffe003, 0xffffc003, 0xffff8003, 0xffff0003, 0xfffe0003, 0xfffc0003,
0xfff80003, 0xfff00003, 0xffe00003, 0xffc00003, 0xff800003, 0xff000003, 0xfe000003, 0xfc000003,
0xf8000003, 0xf0000003, 0xe0000003, 0xc0000003, 0x80000003, 0x00000003, 0x00000003, 0x00000003,
}, {
0xfffffff7, 0xffffffe7, 0xffffffc7, 0xffffff87, 0xffffff07, 0xfffffe07, 0xfffffc07, 0xfffff807,
0xfffff007, 0xffffe007, 0xffffc007, 0xffff8007, 0xffff0007, 0xfffe0007, 0xfffc0007, 0xfff80007,
0xfff00007, 0xffe00007, 0xffc00007, 0xff800007, 0xff000007, 0xfe000007, 0xfc000007, 0xf8000007,
0xf0000007, 0xe0000007, 0xc0000007, 0x80000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007,
}, {
0xffffffef, 0xffffffcf, 0xffffff8f, 0xffffff0f, 0xfffffe0f, 0xfffffc0f, 0xfffff80f, 0xfffff00f,
0xffffe00f, 0xffffc00f, 0xffff800f, 0xffff000f, 0xfffe000f, 0xfffc000f, 0xfff8000f, 0xfff0000f,
0xffe0000f, 0xffc0000f, 0xff80000f, 0xff00000f, 0xfe00000f, 0xfc00000f, 0xf800000f, 0xf000000f,
0xe000000f, 0xc000000f, 0x8000000f, 0x0000000f, 0x0000000f, 0x0000000f, 0x0000000f, 0x0000000f,
}, {
0xffffffdf, 0xffffff9f, 0xffffff1f, 0xfffffe1f, 0xfffffc1f, 0xfffff81f, 0xfffff01f, 0xffffe01f,
0xffffc01f, 0xffff801f, 0xffff001f, 0xfffe001f, 0xfffc001f, 0xfff8001f, 0xfff0001f, 0xffe0001f,
0xffc0001f, 0xff80001f, 0xff00001f, 0xfe00001f, 0xfc00001f, 0xf800001f, 0xf000001f, 0xe000001f,
0xc000001f, 0x8000001f, 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f,
}, {
0xffffffbf, 0xffffff3f, 0xfffffe3f, 0xfffffc3f, 0xfffff83f, 0xfffff03f, 0xffffe03f, 0xffffc03f,
0xffff803f, 0xffff003f, 0xfffe003f, 0xfffc003f, 0xfff8003f, 0xfff0003f, 0xffe0003f, 0xffc0003f,
0xff80003f, 0xff00003f, 0xfe00003f, 0xfc00003f, 0xf800003f, 0xf000003f, 0xe000003f, 0xc000003f,
0x8000003f, 0x0000003f, 0x0000003f, 0x0000003f, 0x0000003f, 0x0000003f, 0x0000003f, 0x0000003f,
}, {
0xffffff7f, 0xfffffe7f, 0xfffffc7f, 0xfffff87f, 0xfffff07f, 0xffffe07f, 0xffffc07f, 0xffff807f,
0xffff007f, 0xfffe007f, 0xfffc007f, 0xfff8007f, 0xfff0007f, 0xffe0007f, 0xffc0007f, 0xff80007f,
0xff00007f, 0xfe00007f, 0xfc00007f, 0xf800007f, 0xf000007f, 0xe000007f, 0xc000007f, 0x8000007f,
0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f,
}, {
0xfffffeff, 0xfffffcff, 0xfffff8ff, 0xfffff0ff, 0xffffe0ff, 0xffffc0ff, 0xffff80ff, 0xffff00ff,
0xfffe00ff, 0xfffc00ff, 0xfff800ff, 0xfff000ff, 0xffe000ff, 0xffc000ff, 0xff8000ff, 0xff0000ff,
0xfe0000ff, 0xfc0000ff, 0xf80000ff, 0xf00000ff, 0xe00000ff, 0xc00000ff, 0x800000ff, 0x000000ff,
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
}, {
0xfffffdff, 0xfffff9ff, 0xfffff1ff, 0xffffe1ff, 0xffffc1ff, 0xffff81ff, 0xffff01ff, 0xfffe01ff,
0xfffc01ff, 0xfff801ff, 0xfff001ff, 0xffe001ff, 0xffc001ff, 0xff8001ff, 0xff0001ff, 0xfe0001ff,
0xfc0001ff, 0xf80001ff, 0xf00001ff, 0xe00001ff, 0xc00001ff, 0x800001ff, 0x000001ff, 0x000001ff,
0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff,
}, {
0xfffffbff, 0xfffff3ff, 0xffffe3ff, 0xffffc3ff, 0xffff83ff, 0xffff03ff, 0xfffe03ff, 0xfffc03ff,
0xfff803ff, 0xfff003ff, 0xffe003ff, 0xffc003ff, 0xff8003ff, 0xff0003ff, 0xfe0003ff, 0xfc0003ff,
0xf80003ff, 0xf00003ff, 0xe00003ff, 0xc00003ff, 0x800003ff, 0x000003ff, 0x000003ff, 0x000003ff,
0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff,
}, {
0xfffff7ff, 0xffffe7ff, 0xffffc7ff, 0xffff87ff, 0xffff07ff, 0xfffe07ff, 0xfffc07ff, 0xfff807ff,
0xfff007ff, 0xffe007ff, 0xffc007ff, 0xff8007ff, 0xff0007ff, 0xfe0007ff, 0xfc0007ff, 0xf80007ff,
0xf00007ff, 0xe00007ff, 0xc00007ff, 0x800007ff, 0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff,
0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff,
}, {
0xffffefff, 0xffffcfff, 0xffff8fff, 0xffff0fff, 0xfffe0fff, 0xfffc0fff, 0xfff80fff, 0xfff00fff,
0xffe00fff, 0xffc00fff, 0xff800fff, 0xff000fff, 0xfe000fff, 0xfc000fff, 0xf8000fff, 0xf0000fff,
0xe0000fff, 0xc0000fff, 0x80000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff,
0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff,
}, {
0xffffdfff, 0xffff9fff, 0xffff1fff, 0xfffe1fff, 0xfffc1fff, 0xfff81fff, 0xfff01fff, 0xffe01fff,
0xffc01fff, 0xff801fff, 0xff001fff, 0xfe001fff, 0xfc001fff, 0xf8001fff, 0xf0001fff, 0xe0001fff,
0xc0001fff, 0x80001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff,
0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff,
}, {
0xffffbfff, 0xffff3fff, 0xfffe3fff, 0xfffc3fff, 0xfff83fff, 0xfff03fff, 0xffe03fff, 0xffc03fff,
0xff803fff, 0xff003fff, 0xfe003fff, 0xfc003fff, 0xf8003fff, 0xf0003fff, 0xe0003fff, 0xc0003fff,
0x80003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff,
0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff,
}, {
0xffff7fff, 0xfffe7fff, 0xfffc7fff, 0xfff87fff, 0xfff07fff, 0xffe07fff, 0xffc07fff, 0xff807fff,
0xff007fff, 0xfe007fff, 0xfc007fff, 0xf8007fff, 0xf0007fff, 0xe0007fff, 0xc0007fff, 0x80007fff,
0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff,
0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff,
}, {
0xfffeffff, 0xfffcffff, 0xfff8ffff, 0xfff0ffff, 0xffe0ffff, 0xffc0ffff, 0xff80ffff, 0xff00ffff,
0xfe00ffff, 0xfc00ffff, 0xf800ffff, 0xf000ffff, 0xe000ffff, 0xc000ffff, 0x8000ffff, 0x0000ffff,
0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff,
0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff,
}, {
0xfffdffff, 0xfff9ffff, 0xfff1ffff, 0xffe1ffff, 0xffc1ffff, 0xff81ffff, 0xff01ffff, 0xfe01ffff,
0xfc01ffff, 0xf801ffff, 0xf001ffff, 0xe001ffff, 0xc001ffff, 0x8001ffff, 0x0001ffff, 0x0001ffff,
0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff,
0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff,
}, {
0xfffbffff, 0xfff3ffff, 0xffe3ffff, 0xffc3ffff, 0xff83ffff, 0xff03ffff, 0xfe03ffff, 0xfc03ffff,
0xf803ffff, 0xf003ffff, 0xe003ffff, 0xc003ffff, 0x8003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff,
0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff,
0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff,
}, {
0xfff7ffff, 0xffe7ffff, 0xffc7ffff, 0xff87ffff, 0xff07ffff, 0xfe07ffff, 0xfc07ffff, 0xf807ffff,
0xf007ffff, 0xe007ffff, 0xc007ffff, 0x8007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff,
0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff,
0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff,
}, {
0xffefffff, 0xffcfffff, 0xff8fffff, 0xff0fffff, 0xfe0fffff, 0xfc0fffff, 0xf80fffff, 0xf00fffff,
0xe00fffff, 0xc00fffff, 0x800fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff,
0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff,
0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff,
}, {
0xffdfffff, 0xff9fffff, 0xff1fffff, 0xfe1fffff, 0xfc1fffff, 0xf81fffff, 0xf01fffff, 0xe01fffff,
0xc01fffff, 0x801fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff,
0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff,
0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff,
}, {
0xffbfffff, 0xff3fffff, 0xfe3fffff, 0xfc3fffff, 0xf83fffff, 0xf03fffff, 0xe03fffff, 0xc03fffff,
0x803fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff,
0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff,
0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff,
}, {
0xff7fffff, 0xfe7fffff, 0xfc7fffff, 0xf87fffff, 0xf07fffff, 0xe07fffff, 0xc07fffff, 0x807fffff,
0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff,
0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff,
0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff,
}, {
0xfeffffff, 0xfcffffff, 0xf8ffffff, 0xf0ffffff, 0xe0ffffff, 0xc0ffffff, 0x80ffffff, 0x00ffffff,
0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
}, {
0xfdffffff, 0xf9ffffff, 0xf1ffffff, 0xe1ffffff, 0xc1ffffff, 0x81ffffff, 0x01ffffff, 0x01ffffff,
0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
}, {
0xfbffffff, 0xf3ffffff, 0xe3ffffff, 0xc3ffffff, 0x83ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff,
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff,
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff,
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff,
}, {
0xf7ffffff, 0xe7ffffff, 0xc7ffffff, 0x87ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff,
0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff,
0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff,
0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff,
}, {
0xefffffff, 0xcfffffff, 0x8fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff,
0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff,
0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff,
0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff,
}, {
0xdfffffff, 0x9fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff,
0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff,
0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff,
0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff,
}, {
0xbfffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff,
0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff,
0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff,
0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff,
}, {
0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff,
0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff,
0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff,
0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff,
} };
static const uint32_t ExtraMasks[32] =
{
0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
};
const char *const svc_strings[svc_lastmsg+1] =
{
"svc_bad",
@@ -101,20 +267,14 @@ const char *const svc_legacy_strings[svc_lastmsg+1] =
const char *const svc_goldsrc_strings[svc_lastmsg+1] =
{
[svc_goldsrc_version] = "svc_goldsrc_version",
[svc_goldsrc_serverinfo] = "svc_goldsrc_serverinfo",
[svc_goldsrc_deltadescription] = "svc_goldsrc_deltadescription",
[svc_goldsrc_stopsound] = "svc_goldsrc_stopsound",
[svc_goldsrc_damage] = "svc_goldsrc_damage",
[svc_goldsrc_killedmonster] = "svc_goldsrc_killedmonster",
[svc_goldsrc_foundsecret] = "svc_goldsrc_foundsecret",
[svc_goldsrc_spawnstaticsound] = "svc_goldsrc_spawnstaticsound",
[svc_goldsrc_decalname] = "svc_goldsrc_decalname",
[svc_goldsrc_newusermsg] = "svc_goldsrc_newusermsg",
[svc_goldsrc_newmovevars] = "svc_goldsrc_newmovevars",
[svc_goldsrc_sendextrainfo] = "svc_goldsrc_sendextrainfo",
[svc_goldsrc_timescale] = "svc_goldsrc_timescale",
[svc_goldsrc_sendcvarvalue] = "svc_goldsrc_sendcvarvalue",
[svc_goldsrc_sendcvarvalue2] = "svc_goldsrc_sendcvarvalue2",
};
const char *const svc_quake_strings[svc_lastmsg+1] =
@@ -138,65 +298,41 @@ const char *const svc_quake_strings[svc_lastmsg+1] =
[svc_fog] = "svc_quake_fog",
};
void MSG_InitMasks( void )
{
uint startbit, endbit;
uint maskBit, nBitsLeft;
for( startbit = 0; startbit < 32; startbit++ )
{
for( nBitsLeft = 0; nBitsLeft < 33; nBitsLeft++ )
{
endbit = startbit + nBitsLeft;
BitWriteMasks[startbit][nBitsLeft] = (uint)BIT( startbit ) - 1;
if( endbit < 32 ) BitWriteMasks[startbit][nBitsLeft] |= ~((uint)BIT( endbit ) - 1 );
}
}
for( maskBit = 0; maskBit < 32; maskBit++ )
ExtraMasks[maskBit] = (uint)BIT( maskBit ) - 1;
}
void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits )
{
Assert( numbits >= 0 && numbits <= 32 );
int nBitsLeft = numbits;
int iCurBit = sb->iCurBit;
uint iDWord = iCurBit >> 5; // Mask in a dword.
uint32_t iCurBitMasked;
int nBitsWritten;
Assert( numbits >= 1 && numbits <= 32 );
// bounds checking..
if(( sb->iCurBit + numbits ) > sb->nDataBits )
if( MSG_Overflow( sb, numbits ))
{
sb->bOverflow = true;
sb->iCurBit = sb->nDataBits;
return;
}
else
{
int nBitsLeft = numbits;
int iCurBit = sb->iCurBit;
uint iDWord = iCurBit >> 5; // Mask in a dword.
uint32_t iCurBitMasked;
int nBitsWritten;
Assert(( iDWord * 4 + sizeof( int )) <= (uint)MSG_GetMaxBytes( sb ));
iCurBitMasked = iCurBit & 31;
((uint32_t *)sb->pData)[iDWord] &= BitWriteMasks[iCurBitMasked][nBitsLeft-1];
((uint32_t *)sb->pData)[iDWord] |= curData << iCurBitMasked;
// did it span a dword?
nBitsWritten = 32 - iCurBitMasked;
if( nBitsWritten < nBitsLeft )
{
nBitsLeft -= nBitsWritten;
iCurBit += nBitsWritten;
curData >>= nBitsWritten;
iCurBitMasked = iCurBit & 31;
((uint32_t *)sb->pData)[iDWord] &= BitWriteMasks[iCurBitMasked][nBitsLeft];
((uint32_t *)sb->pData)[iDWord] |= curData << iCurBitMasked;
// did it span a dword?
nBitsWritten = 32 - iCurBitMasked;
if( nBitsWritten < nBitsLeft )
{
nBitsLeft -= nBitsWritten;
iCurBit += nBitsWritten;
curData >>= nBitsWritten;
iCurBitMasked = iCurBit & 31;
((uint32_t *)sb->pData)[iDWord+1] &= BitWriteMasks[iCurBitMasked][nBitsLeft];
((uint32_t *)sb->pData)[iDWord+1] |= curData << iCurBitMasked;
}
sb->iCurBit += numbits;
((uint32_t *)sb->pData)[iDWord+1] &= BitWriteMasks[iCurBitMasked][nBitsLeft-1];
((uint32_t *)sb->pData)[iDWord+1] |= curData << iCurBitMasked;
}
sb->iCurBit += numbits;
}
/*
@@ -244,7 +380,7 @@ qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits )
int nBitsLeft = nBits;
// get output dword-aligned.
while((( uint32_t )pOut & 3 ) != 0 && nBitsLeft >= 8 )
while((( uintptr_t )pOut & 3 ) != 0 && nBitsLeft >= 8 )
{
MSG_WriteUBitLong( sb, *pOut, 8 );
@@ -281,16 +417,14 @@ qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits )
void MSG_WriteBitAngle( sizebuf_t *sb, float fAngle, int numbits )
{
uint mask, shift;
const uint shift = ( 1 << numbits );
const uint mask = shift - 1;
int d;
// clamp the angle before receiving
fAngle = fmod( fAngle, 360.0f );
if( fAngle < 0 ) fAngle += 360.0f;
shift = ( 1 << numbits );
mask = shift - 1;
d = (int)(( fAngle * shift ) / 360.0f );
d &= mask;
@@ -444,9 +578,8 @@ uint MSG_ReadUBitLong( sizebuf_t *sb, int numbits )
return 0; // end of message
}
if(( sb->iCurBit + numbits ) > sb->nDataBits )
if( MSG_Overflow( sb, numbits ))
{
sb->bOverflow = true;
sb->iCurBit = sb->nDataBits;
return 0;
}
@@ -519,13 +652,9 @@ qboolean MSG_ReadBits( sizebuf_t *sb, void *pOutData, int nBits )
float MSG_ReadBitAngle( sizebuf_t *sb, int numbits )
{
float fReturn, shift;
int i;
shift = (float)( 1 << numbits );
i = MSG_ReadUBitLong( sb, numbits );
fReturn = (float)i * ( 360.0f / shift );
float shift = (float)( 1 << numbits );
int i = MSG_ReadUBitLong( sb, numbits );
float fReturn = (float)i * ( 360.0f / shift );
// clamp the finale angle
if( fReturn < -180.0f ) fReturn += 360.0f;
@@ -537,11 +666,11 @@ float MSG_ReadBitAngle( sizebuf_t *sb, int numbits )
// Append numbits least significant bits from data to the current bit stream
int MSG_ReadSBitLong( sizebuf_t *sb, int numbits )
{
int r, sign;
int r;
if( sb->iAlternateSign )
{
sign = MSG_ReadOneBit( sb );
int sign = MSG_ReadOneBit( sb );
r = MSG_ReadUBitLong( sb, numbits - 1 );
if( sign )
@@ -550,9 +679,7 @@ int MSG_ReadSBitLong( sizebuf_t *sb, int numbits )
else
{
r = MSG_ReadUBitLong( sb, numbits - 1 );
sign = MSG_ReadOneBit( sb );
if( sign )
if( MSG_ReadOneBit( sb ))
r = -( BIT( numbits - 1 ) - r );
}
@@ -673,12 +800,12 @@ qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes )
static char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
{
static char string[4096];
int l = 0, c;
int l = 0;
do
{
// use MSG_ReadByte so -1 is out of bounds
c = MSG_ReadByte( sb );
int c = MSG_ReadByte( sb );
if( c == 0 ) break;
else if( bLine && c == '\n' )
@@ -871,8 +998,6 @@ static void Test_Buffer_ExciseBits( void )
void Test_RunBuffer( void )
{
MSG_InitMasks();
TRUN( Test_Buffer_BitByte( ));
TRUN( Test_Buffer_Write( ));
TRUN( Test_Buffer_Read( ));

View File

@@ -193,7 +193,6 @@ static inline void MSG_StartBitWriting( sizebuf_t *sb )
sb->iAlternateSign++;
}
void MSG_InitMasks( void ); // called once at startup engine
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
// Bit-write functions

View File

@@ -272,8 +272,6 @@ void Netchan_Init( void )
Cvar_FullSet( net_qport.name, buf, net_qport.flags );
net_mempool = Mem_AllocPool( "Network Pool" );
MSG_InitMasks(); // initialize bit-masks
}
void Netchan_Shutdown( void )
@@ -343,6 +341,7 @@ void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, voi
chan->split = FBitSet( flags, NETCHAN_USE_LEGACY_SPLIT ) ? true : false;
chan->use_munge = FBitSet( flags, NETCHAN_USE_MUNGE ) ? true : false;
chan->use_bz2 = FBitSet( flags, NETCHAN_USE_BZIP2 ) ? true : false;
chan->use_lzss = FBitSet( flags, NETCHAN_USE_LZSS ) ? true : false;
chan->gs_netchan = FBitSet( flags, NETCHAN_GOLDSRC ) ? true : false;
MSG_Init( &chan->message, "NetData", chan->message_buf, sizeof( chan->message_buf ));
@@ -768,7 +767,7 @@ static void Netchan_CreateFragments_( netchan_t *chan, sizebuf_t *msg )
Host_Error( "%s: BZ2 compression is not supported for server", __func__ );
#endif
}
else if( !chan->use_bz2 && !LZSS_IsCompressed( MSG_GetData( msg ), MSG_GetMaxBytes( msg )))
else if( chan->use_lzss && !LZSS_IsCompressed( MSG_GetData( msg ), MSG_GetMaxBytes( msg )))
{
uint uCompressedSize = 0;
uint uSourceSize = MSG_GetNumBytesWritten( msg );
@@ -1175,7 +1174,7 @@ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *l
p = n;
}
if( chan->use_bz2 && !memcmp( MSG_GetData( msg ), "BZ2", 4 ) )
if( chan->use_bz2 && !memcmp( MSG_GetData( msg ), "BZ2", 4 ))
{
#if !XASH_DEDICATED
byte buf[0x10000];
@@ -1196,7 +1195,7 @@ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *l
Host_Error( "%s: BZ2 compression is not supported for server\n", __func__ );
#endif
}
else if( !chan->use_bz2 && LZSS_IsCompressed( MSG_GetData( msg ), size ))
else if( chan->use_lzss && LZSS_IsCompressed( MSG_GetData( msg ), size ))
{
uint uDecompressedLen = LZSS_GetActualSize( MSG_GetData( msg ), size );
byte buf[NET_MAX_MESSAGE];
@@ -1347,7 +1346,7 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg )
Host_Error( "%s: BZ2 compression is not supported for server", __func__ );
#endif
}
else if( LZSS_IsCompressed( buffer, nsize + 1 ))
else if( chan->use_lzss && LZSS_IsCompressed( buffer, nsize + 1 ))
{
byte *uncompressedBuffer;

View File

@@ -39,8 +39,6 @@ GNU General Public License for more details.
#define DT_SIGNED BIT( 8 ) // sign modificator
#define DT_SIGNED_GS BIT( 31 ) // GoldSrc-specific sign modificator
#define NUM_FIELDS( x ) ((sizeof( x ) / sizeof( x[0] )) - 1)
// helper macroses
#define ENTS_DEF( x ) #x, offsetof( entity_state_t, x ), sizeof( ((entity_state_t *)0)->x )
#define UCMD_DEF( x ) #x, offsetof( usercmd_t, x ), sizeof( ((usercmd_t *)0)->x )
@@ -71,7 +69,6 @@ static const delta_field_t cmd_fields[] =
{ UCMD_DEF( impact_position[0] ) },
{ UCMD_DEF( impact_position[1] ) },
{ UCMD_DEF( impact_position[2] ) },
{ NULL },
};
static const delta_field_t pm_fields[] =
@@ -107,7 +104,6 @@ static const delta_field_t pm_fields[] =
{ PHYS_DEF( skydir_y ) },
{ PHYS_DEF( skydir_z ) },
{ PHYS_DEF( skyangle ) },
{ NULL },
};
static const delta_field_t ev_fields[] =
@@ -130,7 +126,6 @@ static const delta_field_t ev_fields[] =
{ EVNT_DEF( iparam2 ) },
{ EVNT_DEF( bparam1 ) },
{ EVNT_DEF( bparam2 ) },
{ NULL },
};
static const delta_field_t wd_fields[] =
@@ -157,7 +152,6 @@ static const delta_field_t wd_fields[] =
{ WPDT_DEF( fuser2 ) },
{ WPDT_DEF( fuser3 ) },
{ WPDT_DEF( fuser4 ) },
{ NULL },
};
static const delta_field_t cd_fields[] =
@@ -218,7 +212,6 @@ static const delta_field_t cd_fields[] =
{ CLDT_DEF( vuser4[0] ) },
{ CLDT_DEF( vuser4[1] ) },
{ CLDT_DEF( vuser4[2] ) },
{ NULL },
};
static const delta_field_t ent_fields[] =
@@ -314,7 +307,6 @@ static const delta_field_t ent_fields[] =
{ ENTS_DEF( vuser4[0] ) },
{ ENTS_DEF( vuser4[1] ) },
{ ENTS_DEF( vuser4[2] ) },
{ NULL },
};
static const delta_field_t meta_fields[] =
@@ -326,7 +318,6 @@ static const delta_field_t meta_fields[] =
{ DESC_DEF( significant_bits ), },
{ DESC_DEF( premultiply ), },
{ DESC_DEF( postmultiply ), },
{ NULL },
};
#if XASH_ENGINE_TESTS
@@ -362,24 +353,22 @@ static const delta_field_t test_fields[] =
{ TEST_DEF( dt_short_unsigned ) },
{ TEST_DEF( dt_byte_signed ) },
{ TEST_DEF( dt_byte_unsigned ) },
{ NULL },
};
#endif
static delta_info_t dt_info[] =
{
[DT_EVENT_T] = { "event_t", ev_fields, NUM_FIELDS( ev_fields ) },
[DT_MOVEVARS_T] = { "movevars_t", pm_fields, NUM_FIELDS( pm_fields ) },
[DT_USERCMD_T] = { "usercmd_t", cmd_fields, NUM_FIELDS( cmd_fields ) },
[DT_CLIENTDATA_T] = { "clientdata_t", cd_fields, NUM_FIELDS( cd_fields ) },
[DT_WEAPONDATA_T] = { "weapon_data_t", wd_fields, NUM_FIELDS( wd_fields ) },
[DT_ENTITY_STATE_T] = { "entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
[DT_ENTITY_STATE_PLAYER_T] = { "entity_state_player_t", ent_fields, NUM_FIELDS( ent_fields ) },
[DT_CUSTOM_ENTITY_STATE_T] = { "custom_entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
[DT_EVENT_T] = { "event_t", ev_fields, ARRAYSIZE( ev_fields ) },
[DT_MOVEVARS_T] = { "movevars_t", pm_fields, ARRAYSIZE( pm_fields ) },
[DT_USERCMD_T] = { "usercmd_t", cmd_fields, ARRAYSIZE( cmd_fields ) },
[DT_CLIENTDATA_T] = { "clientdata_t", cd_fields, ARRAYSIZE( cd_fields ) },
[DT_WEAPONDATA_T] = { "weapon_data_t", wd_fields, ARRAYSIZE( wd_fields ) },
[DT_ENTITY_STATE_T] = { "entity_state_t", ent_fields, ARRAYSIZE( ent_fields ) },
[DT_ENTITY_STATE_PLAYER_T] = { "entity_state_player_t", ent_fields, ARRAYSIZE( ent_fields ) },
[DT_CUSTOM_ENTITY_STATE_T] = { "custom_entity_state_t", ent_fields, ARRAYSIZE( ent_fields ) },
#if XASH_ENGINE_TESTS
[DT_DELTA_TEST_STRUCT_T] = { "delta_test_struct_t", test_fields, NUM_FIELDS( test_fields ) },
[DT_DELTA_TEST_STRUCT_T] = { "delta_test_struct_t", test_fields, ARRAYSIZE( test_fields ) },
#endif
[DT_STRUCT_COUNT] = { NULL },
};
// meta description is special, it cannot be overriden
@@ -387,9 +376,9 @@ static const delta_info_t dt_goldsrc_meta =
{
.pName = "goldsrc_delta_t",
.pInfo = meta_fields,
.maxFields = NUM_FIELDS( meta_fields ),
.numFields = NUM_FIELDS( meta_fields ),
.pFields = (delta_t[NUM_FIELDS( meta_fields )])
.maxFields = ARRAYSIZE( meta_fields ),
.numFields = ARRAYSIZE( meta_fields ),
.pFields = (delta_t[ARRAYSIZE( meta_fields )])
{
{
DESC_DEF( fieldType ),
@@ -451,7 +440,7 @@ static delta_info_t *Delta_FindStruct( const char *name )
if( !COM_CheckString( name ))
return NULL;
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
for( i = 0; i < ARRAYSIZE( dt_info ); i++ )
{
if( !Q_stricmp( dt_info[i].pName, name ))
return &dt_info[i];
@@ -465,7 +454,7 @@ static delta_info_t *Delta_FindStruct( const char *name )
static int Delta_NumTables( void )
{
return NUM_FIELDS( dt_info );
return ARRAYSIZE( dt_info );
}
static delta_info_t *Delta_FindStructByIndex( int index )
@@ -480,7 +469,7 @@ static delta_info_t *Delta_FindStructByEncoder( const char *encoderName )
if( !COM_CheckString( encoderName ) )
return NULL;
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
for( i = 0; i < ARRAYSIZE( dt_info ); i++ )
{
if( !Q_stricmp( dt_info[i].funcName, encoderName ))
return &dt_info[i];
@@ -495,7 +484,7 @@ static delta_info_t *Delta_FindStructByDelta( const delta_t *pFields )
if( !pFields ) return NULL;
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
for( i = 0; i < ARRAYSIZE( dt_info ); i++ )
{
if( dt_info[i].pFields == pFields )
return &dt_info[i];
@@ -518,29 +507,32 @@ static void Delta_CustomEncode( delta_info_t *dt, const void *from, const void *
dt->userCallback( dt->pFields, from, to );
}
static delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName )
static const delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName, int maxFields )
{
int i;
if( !fieldName || !*fieldName )
return NULL;
for( ; pInfo->name; pInfo++ )
for( i = 0; i < maxFields; i++ )
{
if( !Q_strcmp( pInfo->name, fieldName ))
return (delta_field_t *)pInfo;
if( !Q_strcmp( pInfo[i].name, fieldName ))
return &pInfo[i];
}
return NULL;
}
static int Delta_IndexForFieldInfo( const delta_field_t *pInfo, const char *fieldName )
static int Delta_IndexForFieldInfo( const delta_field_t *pInfo, const char *fieldName, int maxFields )
{
int i;
if( !fieldName || !*fieldName )
return -1;
for( i = 0; pInfo->name; i++, pInfo++ )
for( i = 0; i < maxFields; i++ )
{
if( !Q_strcmp( pInfo->name, fieldName ))
if( !Q_strcmp( pInfo[i].name, fieldName ))
return i;
}
return -1;
@@ -548,7 +540,7 @@ static int Delta_IndexForFieldInfo( const delta_field_t *pInfo, const char *fiel
static qboolean Delta_AddField( delta_info_t *dt, const char *pName, int flags, int bits, float mul, float post_mul )
{
delta_field_t *pFieldInfo;
const delta_field_t *pFieldInfo;
delta_t *pField;
int i;
@@ -567,7 +559,7 @@ static qboolean Delta_AddField( delta_info_t *dt, const char *pName, int flags,
}
// find field description
pFieldInfo = Delta_FindFieldInfo( dt->pInfo, pName );
pFieldInfo = Delta_FindFieldInfo( dt->pInfo, pName, dt->maxFields );
if( !pFieldInfo )
{
Con_DPrintf( S_ERROR "%s: couldn't find description for %s->%s\n", __func__, dt->pName, pName );
@@ -610,7 +602,7 @@ static void Delta_WriteTableField( sizebuf_t *msg, int tableIndex, const delta_t
dt = Delta_FindStructByIndex( tableIndex );
Assert( dt && dt->bInitialized );
nameIndex = Delta_IndexForFieldInfo( dt->pInfo, pField->name );
nameIndex = Delta_IndexForFieldInfo( dt->pInfo, pField->name, dt->maxFields );
Assert( nameIndex >= 0 && nameIndex < dt->maxFields );
MSG_BeginServerCmd( msg, svc_deltatable );
@@ -681,10 +673,10 @@ void Delta_ParseTableField( sizebuf_t *msg )
Delta_AddField( dt, pName, flags, bits, mul, post_mul );
}
static qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInfo, delta_t *pField, qboolean bPost )
static qboolean Delta_ParseField( char **delta_script, const delta_info_t *dt, delta_t *pField, qboolean bPost )
{
const delta_field_t *pFieldInfo;
string token;
delta_field_t *pFieldInfo;
char *oldpos;
*delta_script = COM_ParseFile( *delta_script, token, sizeof( token ));
@@ -701,7 +693,7 @@ static qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInf
return false;
}
pFieldInfo = Delta_FindFieldInfo( pInfo, token );
pFieldInfo = Delta_FindFieldInfo( dt->pInfo, token, dt->maxFields );
if( !pFieldInfo )
{
Con_DPrintf( S_ERROR "%s: unable to find field %s\n", __func__, token );
@@ -825,13 +817,11 @@ static void Delta_ParseTable( char **delta_script, delta_info_t *dt, const char
{
string token;
delta_t *pField;
const delta_field_t *pInfo;
// allocate the delta-structures
if( !dt->pFields ) dt->pFields = (delta_t *)Z_Calloc( dt->maxFields * sizeof( delta_t ));
pField = dt->pFields;
pInfo = dt->pInfo;
dt->numFields = 0;
// assume we have handled '{'
@@ -841,12 +831,12 @@ static void Delta_ParseTable( char **delta_script, delta_info_t *dt, const char
if( !Q_strcmp( token, "DEFINE_DELTA" ))
{
if( Delta_ParseField( delta_script, pInfo, &pField[dt->numFields], false ))
if( Delta_ParseField( delta_script, dt, &pField[dt->numFields], false ))
dt->numFields++;
}
else if( !Q_strcmp( token, "DEFINE_DELTA_POST" ))
{
if( Delta_ParseField( delta_script, pInfo, &pField[dt->numFields], true ))
if( Delta_ParseField( delta_script, dt, &pField[dt->numFields], true ))
dt->numFields++;
}
else if( token[0] == '}' )
@@ -963,7 +953,7 @@ void Delta_Init( void )
Delta_AddField( dt, "skyvec_z", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f );
Delta_AddField( dt, "wateralpha", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f );
Delta_AddField( dt, "fog_settings", DT_INTEGER, 32, 1.0f, 1.0f );
dt->numFields = NUM_FIELDS( pm_fields ) - 4;
dt->numFields = ARRAYSIZE( pm_fields ) - 4;
// now done
dt->bInitialized = true;
@@ -976,7 +966,7 @@ void Delta_InitClient( void )
// already initalized
if( delta_init ) return;
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
for( i = 0; i < ARRAYSIZE( dt_info ); i++ )
{
if( dt_info[i].numFields > 0 )
{
@@ -994,7 +984,7 @@ void Delta_Shutdown( void )
if( !delta_init ) return;
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
for( i = 0; i < ARRAYSIZE( dt_info ); i++ )
{
dt_info[i].numFields = 0;
dt_info[i].customEncode = CUSTOM_NONE;
@@ -2292,10 +2282,6 @@ void Test_RunDelta( void )
char buffer[4096] = { 0 };
const double timebase = 123.123;
// a1ba: netbuffer bitmasks are initialized in netchan for some reason
// initialize it ourselves just in case
MSG_InitMasks(); // initialize bit-masks
Delta_AddField( dt, "dt_string", DT_STRING, 1, 1.0f, 1.0f );
Delta_AddField( dt, "dt_timewindow_big", DT_TIMEWINDOW_BIG, 24, 1000.f, 1.0f );
Delta_AddField( dt, "dt_timewindow_8", DT_TIMEWINDOW_8, 8, 1.0f, 1.0f );

View File

@@ -46,7 +46,6 @@ enum
#if XASH_ENGINE_TESTS
DT_DELTA_TEST_STRUCT_T,
#endif
DT_STRUCT_COUNT
};
// struct info (filled by engine)

View File

@@ -326,7 +326,7 @@ static int HTTP_FileConnect( httpfile_t *file )
if( !COM_CheckStringEmpty( http_useragent.string ) || !Q_strcmp( http_useragent.string, "xash3d" ))
{
Q_snprintf( useragent, sizeof( useragent ), "%s/%s (%s-%s; build %d; %s)",
XASH_ENGINE_NAME, XASH_VERSION, Q_buildos( ), Q_buildarch( ), Q_buildnum( ), Q_buildcommit( ));
XASH_ENGINE_NAME, XASH_VERSION, Q_buildos( ), Q_buildarch( ), Q_buildnum( ), g_buildcommit );
}
else Q_strncpy( useragent, http_useragent.string, sizeof( useragent ));
@@ -505,11 +505,14 @@ static int HTTP_FileDecompress( httpfile_t *file )
if( zlib_result == Z_OK || zlib_result == Z_STREAM_END )
{
Mem_Free( data_in );
g_fsapi.WriteFile( name, data_out, decompressed_len );
HTTP_FreeFile( file, false );
}
else HTTP_FreeFile( file, true );
Mem_Free( data_in );
Mem_Free( data_out );
g_fsapi.WriteFile( name, data_out, decompressed_len );
HTTP_FreeFile( file, false );
return 1;
}
@@ -841,7 +844,16 @@ static int HTTP_FileProcessStream( httpfile_t *curfile )
if( curfile->downloaded >= curfile->size )
{
HTTP_FreeFile( curfile, false ); // success
// chunked files are finalized in FileSaveReceivedData
if( curfile->compressed && !curfile->chunked )
{
curfile->pfn_process = HTTP_FileDecompress;
curfile->success = true;
}
else
{
HTTP_FreeFile( curfile, false ); // success
}
return 0;
}
}

View File

@@ -151,17 +151,24 @@ static inline qboolean NET_IsSocketValid( int socket )
void NET_NetadrToIP6Bytes( uint8_t *ip6, const netadr_t *adr )
{
memcpy( ip6, adr->ip6, sizeof( adr->ip6 ));
memcpy( &ip6[0], adr->ip6_0, 2 );
memcpy( &ip6[2], adr->ip6_1, 14 );
}
void NET_IP6BytesToNetadr( netadr_t *adr, const uint8_t *ip6 )
{
memcpy( adr->ip6, ip6, sizeof( adr->ip6 ));
memcpy( adr->ip6_0, &ip6[0], 2 );
memcpy( adr->ip6_1, &ip6[2], 14 );
}
static int NET_NetadrIP6Compare( const netadr_t *a, const netadr_t *b )
{
return memcmp( a->ip6, b->ip6, sizeof( a->ip6 ));
uint8_t ip6_a[16], ip6_b[16];
NET_NetadrToIP6Bytes( ip6_a, a );
NET_NetadrToIP6Bytes( ip6_b, b );
return memcmp( ip6_a, ip6_b, sizeof( ip6_a ));
}
/*
@@ -171,27 +178,29 @@ NET_NetadrToSockadr
*/
static void NET_NetadrToSockadr( netadr_t *a, struct sockaddr_storage *s )
{
netadrtype_t type = NET_NetadrType( a );
memset( s, 0, sizeof( *s ));
if( a->type == NA_BROADCAST )
if( type == NA_BROADCAST )
{
s->ss_family = AF_INET;
((struct sockaddr_in *)s)->sin_port = a->port;
((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
}
else if( a->type == NA_IP )
else if( type == NA_IP )
{
s->ss_family = AF_INET;
((struct sockaddr_in *)s)->sin_port = a->port;
((struct sockaddr_in *)s)->sin_addr.s_addr = a->ip4;
}
else if( a->type6 == NA_IP6 )
else if( type == NA_IP6 )
{
s->ss_family = AF_INET6;
((struct sockaddr_in6 *)s)->sin6_port = a->port;
NET_NetadrToIP6Bytes(((struct sockaddr_in6 *)s)->sin6_addr.s6_addr, a );
}
else if( a->type6 == NA_MULTICAST_IP6 )
else if( type == NA_MULTICAST_IP6 )
{
s->ss_family = AF_INET6;
((struct sockaddr_in6 *)s)->sin6_port = a->port;
@@ -208,13 +217,13 @@ static void NET_SockadrToNetadr( const struct sockaddr_storage *s, netadr_t *a )
{
if( s->ss_family == AF_INET )
{
a->type = NA_IP;
NET_NetadrSetType( a, NA_IP );
a->ip4 = ((struct sockaddr_in *)s)->sin_addr.s_addr;
a->port = ((struct sockaddr_in *)s)->sin_port;
}
else if( s->ss_family == AF_INET6 )
{
a->type6 = NA_IP6;
NET_NetadrSetType( a, NA_IP6 );
NET_IP6BytesToNetadr( a, ((struct sockaddr_in6 *)s)->sin6_addr.s6_addr );
a->port = ((struct sockaddr_in6 *)s)->sin6_port;
}
@@ -549,8 +558,8 @@ qboolean NET_StringToFilterAdr( const char *s, netadr_t *adr, uint *prefixlen )
// try to parse as IPv6 first
if( ParseIPv6Addr( copy, ip6, NULL, NULL ))
{
NET_NetadrSetType( adr, NA_IP6 );
NET_IP6BytesToNetadr( adr, ip6 );
adr->type6 = NA_IP6;
if( !hasCIDR )
*prefixlen = 128;
@@ -620,7 +629,7 @@ qboolean NET_StringToFilterAdr( const char *s, netadr_t *adr, uint *prefixlen )
adr->ip4 = ntohl( mask );
}
adr->type = NA_IP;
NET_NetadrSetType( adr, NA_IP );
}
return true;
@@ -634,10 +643,11 @@ NET_AdrToString
const char *NET_AdrToString( const netadr_t a )
{
static char s[64];
netadrtype_t type = NET_NetadrType( &a );
if( a.type == NA_LOOPBACK )
if( type == NA_LOOPBACK )
return "loopback";
if( a.type6 == NA_IP6 || a.type6 == NA_MULTICAST_IP6 )
if( type == NA_IP6 || type == NA_MULTICAST_IP6 )
{
uint8_t ip6[16];
@@ -661,10 +671,11 @@ NET_BaseAdrToString
const char *NET_BaseAdrToString( const netadr_t a )
{
static char s[64];
netadrtype_t type = NET_NetadrType( &a );
if( a.type == NA_LOOPBACK )
if( type == NA_LOOPBACK )
return "loopback";
if( a.type6 == NA_IP6 || a.type6 == NA_MULTICAST_IP6 )
if( type == NA_IP6 || type == NA_MULTICAST_IP6 )
{
uint8_t ip6[16];
@@ -689,16 +700,19 @@ Compares without the port
*/
qboolean NET_CompareBaseAdr( const netadr_t a, const netadr_t b )
{
if( a.type6 != b.type6 )
netadrtype_t type_a = NET_NetadrType( &a );
netadrtype_t type_b = NET_NetadrType( &b );
if( type_a != type_b )
return false;
if( a.type == NA_LOOPBACK )
if( type_a == NA_LOOPBACK )
return true;
if( a.type == NA_IP )
if( type_a == NA_IP )
return a.ip4 == b.ip4;
if( a.type6 == NA_IP6 )
if( type_a == NA_IP6 )
{
if( !NET_NetadrIP6Compare( &a, &b ))
return true;
@@ -707,36 +721,6 @@ qboolean NET_CompareBaseAdr( const netadr_t a, const netadr_t b )
return false;
}
/*
====================
NET_CompareClassBAdr
Compare local masks
====================
*/
qboolean NET_CompareClassBAdr( const netadr_t a, const netadr_t b )
{
if( a.type6 != b.type6 )
return false;
if( a.type == NA_LOOPBACK )
return true;
if( a.type == NA_IP )
{
if( a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] )
return true;
}
// NOTE: we don't check for IPv6 here
// this check is very dumb and only used for LAN restriction
// Actual check is in IsReservedAdr
// for real mask compare use NET_CompareAdrByMask
return false;
}
/*
====================
NET_CompareAdrByMask
@@ -746,10 +730,13 @@ Checks if adr is a part of subnet
*/
qboolean NET_CompareAdrByMask( const netadr_t a, const netadr_t b, uint prefixlen )
{
if( a.type6 != b.type6 || a.type == NA_LOOPBACK )
netadrtype_t type_a = NET_NetadrType( &a );
netadrtype_t type_b = NET_NetadrType( &b );
if( type_a != type_b || type_a == NA_LOOPBACK )
return false;
if( a.type == NA_IP )
if( type_a == NA_IP )
{
uint32_t ipa = htonl( a.ip4 );
uint32_t ipb = htonl( b.ip4 );
@@ -757,7 +744,7 @@ qboolean NET_CompareAdrByMask( const netadr_t a, const netadr_t b, uint prefixle
if(( ipa & (( 0xFFFFFFFFU ) << ( 32 - prefixlen ))) == ipb )
return true;
}
else if( a.type6 == NA_IP6 )
else if( type_a == NA_IP6 )
{
uint16_t a_[8], b_[8];
size_t check = prefixlen / 16;
@@ -798,11 +785,13 @@ Check for reserved ip's
*/
qboolean NET_IsReservedAdr( netadr_t a )
{
if( a.type == NA_LOOPBACK )
netadrtype_t type_a = NET_NetadrType( &a );
if( type_a == NA_LOOPBACK )
return true;
// Following checks was imported from GameNetworkingSockets library
if( a.type == NA_IP )
if( type_a == NA_IP )
{
if(( a.ip[0] == 10 ) || // 10.x.x.x is reserved
( a.ip[0] == 127 ) || // 127.x.x.x
@@ -814,7 +803,7 @@ qboolean NET_IsReservedAdr( netadr_t a )
}
}
if( a.type6 == NA_IP6 )
if( type_a == NA_IP6 )
{
uint8_t ip6[16];
@@ -847,20 +836,23 @@ Compare full address
*/
qboolean NET_CompareAdr( const netadr_t a, const netadr_t b )
{
if( a.type6 != b.type6 )
netadrtype_t type_a = NET_NetadrType( &a );
netadrtype_t type_b = NET_NetadrType( &b );
if( type_a != type_b )
return false;
if( a.type == NA_LOOPBACK )
if( type_a == NA_LOOPBACK )
return true;
if( a.type == NA_IP )
if( type_a == NA_IP )
{
if( a.ip4 == b.ip4 && a.port == b.port )
return true;
return false;
}
if( a.type6 == NA_IP6 )
if( type_a == NA_IP6 )
{
if( a.port == b.port && !NET_NetadrIP6Compare( &a, &b ))
return true;
@@ -883,9 +875,13 @@ int NET_CompareAdrSort( const void *_a, const void *_b )
{
const netadr_t *a = _a, *b = _b;
int porta, portb, portdiff, addrdiff;
netadrtype_t type_a, type_b;
if( a->type6 != b->type6 )
return bound( -1, (int)a->type6 - (int)b->type6, 1 );
type_a = NET_NetadrType( a );
type_b = NET_NetadrType( b );
if( type_a != type_b )
return bound( -1, (int)type_a - (int)type_b, 1 );
porta = ntohs( a->port );
portb = ntohs( b->port );
@@ -896,7 +892,7 @@ int NET_CompareAdrSort( const void *_a, const void *_b )
else
portdiff = 0;
switch( a->type6 )
switch( type_a )
{
case NA_IP6:
if(( addrdiff = NET_NetadrIP6Compare( a, b )))
@@ -904,14 +900,7 @@ int NET_CompareAdrSort( const void *_a, const void *_b )
// fallthrough
case NA_MULTICAST_IP6:
return portdiff;
}
// don't check for full type earlier, as it's value depends on v6 address
if( a->type != b->type )
return bound( -1, (int)a->type - (int)b->type, 1 );
switch( a->type )
{
case NA_IP:
if(( addrdiff = memcmp( a->ip, b->ip, sizeof( a->ipx ))))
return addrdiff;
@@ -946,7 +935,7 @@ static qboolean NET_StringToAdrEx( const char *string, netadr_t *adr, int family
if( !Q_stricmp( string, "localhost" ) || !Q_stricmp( string, "loopback" ))
{
adr->type = NA_LOOPBACK;
NET_NetadrSetType( adr, NA_LOOPBACK );
return true;
}
@@ -971,7 +960,7 @@ net_gai_state_t NET_StringToAdrNB( const char *string, netadr_t *adr, qboolean v
if( !Q_stricmp( string, "localhost" ) || !Q_stricmp( string, "loopback" ))
{
adr->type = NA_LOOPBACK;
NET_NetadrSetType( adr, NA_LOOPBACK );
return NET_EAI_OK;
}
@@ -1017,7 +1006,7 @@ static qboolean NET_GetLoopPacket( netsrc_t sock, netadr_t *from, byte *data, si
*length = loop->msgs[i].datalen;
memset( from, 0, sizeof( *from ));
from->type = NA_LOOPBACK;
NET_NetadrSetType( from, NA_LOOPBACK );
return true;
}
@@ -1523,7 +1512,7 @@ static int NET_SendLong( netsrc_t sock, int net_socket, const char *buf, size_t
total_sent += size;
len -= size;
packet_number++;
Platform_Sleep( 1 );
Platform_NanoSleep( 100 * 1000 );
}
return total_sent;
@@ -1546,19 +1535,20 @@ void NET_SendPacketEx( netsrc_t sock, size_t length, const void *data, netadr_t
int ret;
struct sockaddr_storage addr = { 0 };
SOCKET net_socket = 0;
netadrtype_t type = NET_NetadrType( &to );
if( !net.initialized || to.type == NA_LOOPBACK )
if( !net.initialized || type == NA_LOOPBACK )
{
NET_SendLoopPacket( sock, length, data, to );
return;
}
else if( to.type == NA_BROADCAST || to.type == NA_IP )
else if( type == NA_BROADCAST || type == NA_IP )
{
net_socket = net.ip_sockets[sock];
if( !NET_IsSocketValid( net_socket ))
return;
}
else if( to.type6 == NA_MULTICAST_IP6 || to.type6 == NA_IP6 )
else if( type == NA_MULTICAST_IP6 || type == NA_IP6 )
{
net_socket = net.ip6_sockets[sock];
if( !NET_IsSocketValid( net_socket ))
@@ -1566,7 +1556,7 @@ void NET_SendPacketEx( netsrc_t sock, size_t length, const void *data, netadr_t
}
else
{
Host_Error( "%s: bad address type %i (%i)\n", __func__, to.type, to.type6 );
Host_Error( "%s: bad address type %i (%i, %i)\n", __func__, to.type, to.ip6_0[0], to.ip6_0[1] );
}
NET_NetadrToSockadr( &to, &addr );
@@ -1582,7 +1572,7 @@ void NET_SendPacketEx( netsrc_t sock, size_t length, const void *data, netadr_t
return;
// some PPP links don't allow broadcasts
if( err == WSAEADDRNOTAVAIL && ( to.type == NA_BROADCAST || to.type6 == NA_MULTICAST_IP6 ))
if( err == WSAEADDRNOTAVAIL && ( type == NA_BROADCAST || type == NA_MULTICAST_IP6 ))
return;
if( Host_IsDedicated( ))
@@ -2037,6 +2027,7 @@ void NET_Init( void )
Cvar_RegisterVariable( &net_fakelag );
Cvar_RegisterVariable( &net_fakeloss );
Cvar_RegisterVariable( &net_resolve_debug );
Cvar_RegisterVariable( &net_clockwindow );
Q_snprintf( cmd, sizeof( cmd ), "%i", PORT_SERVER );
Cvar_FullSet( "hostport", cmd, FCVAR_READ_ONLY );

View File

@@ -64,7 +64,6 @@ void NET_Config( qboolean net_enable, qboolean changeport );
const char *NET_AdrToString( const netadr_t a ) RETURNS_NONNULL;
const char *NET_BaseAdrToString( const netadr_t a ) RETURNS_NONNULL;
qboolean NET_IsReservedAdr( netadr_t a );
qboolean NET_CompareClassBAdr( const netadr_t a, const netadr_t b );
qboolean NET_StringToAdr( const char *string, netadr_t *adr );
qboolean NET_StringToFilterAdr( const char *s, netadr_t *adr, uint *prefixlen );
net_gai_state_t NET_StringToAdrNB( const char *string, netadr_t *adr, qboolean v6only );
@@ -80,7 +79,7 @@ void NET_NetadrToIP6Bytes( uint8_t *ip6, const netadr_t *adr );
static inline qboolean NET_IsLocalAddress( netadr_t adr )
{
return adr.type == NA_LOOPBACK ? true : false;
return NET_NetadrType( &adr ) == NA_LOOPBACK;
}
#if !XASH_DEDICATED

View File

@@ -69,7 +69,6 @@ GNU General Public License for more details.
// bytes will be stripped by the networking channel layer
#define NET_MAX_MESSAGE PAD_NUMBER(( NET_MAX_PAYLOAD + HEADER_BYTES ), 16 )
#define MASTERSERVER_ADR "mentality.rip:27010"
#define MS_SCAN_REQUEST "1\xFF" "0.0.0.0:0\0"
#define PORT_MASTER 27010
@@ -214,6 +213,7 @@ typedef enum netchan_flags_e
NETCHAN_USE_MUNGE = BIT( 1 ),
NETCHAN_USE_BZIP2 = BIT( 2 ),
NETCHAN_GOLDSRC = BIT( 3 ),
NETCHAN_USE_LZSS = BIT( 4 ), // mutually exclusive with bzip2
} netchan_flags_t;
// Network Connection Channel
@@ -285,6 +285,7 @@ typedef struct netchan_s
qboolean split;
qboolean use_munge;
qboolean use_bz2;
qboolean use_lzss;
qboolean gs_netchan;
} netchan_t;

View File

@@ -112,6 +112,9 @@ msurface_t *PM_RecursiveSurfCheck( model_t *mod, mnode_t *node, vec3_t p1, vec3_
int i, side;
msurface_t *surf;
vec3_t mid;
mnode_t *children[2];
int numsurfaces, firstsurface;
loc0:
if( node->contents < 0 )
return NULL;
@@ -119,15 +122,17 @@ loc0:
t1 = PlaneDiff( p1, node->plane );
t2 = PlaneDiff( p2, node->plane );
node_children( children, node, mod );
if( t1 >= -FRAC_EPSILON && t2 >= -FRAC_EPSILON )
{
node = node->children[0];
node = children[0];
goto loc0;
}
if( t1 < FRAC_EPSILON && t2 < FRAC_EPSILON )
{
node = node->children[1];
node = children[1];
goto loc0;
}
@@ -137,13 +142,15 @@ loc0:
VectorLerp( p1, frac, p2, mid );
if(( surf = PM_RecursiveSurfCheck( mod, node->children[side], p1, mid )) != NULL )
if(( surf = PM_RecursiveSurfCheck( mod, children[side], p1, mid )) != NULL )
return surf;
// walk through real faces
for( i = 0; i < node->numsurfaces; i++ )
numsurfaces = node_numsurfaces( node, mod );
firstsurface = node_firstsurface( node, mod );
for( i = 0; i < numsurfaces; i++ )
{
msurface_t *surf = &mod->surfaces[node->firstsurface + i];
msurface_t *surf = &mod->surfaces[firstsurface + i];
mextrasurf_t *info = surf->info;
mfacebevel_t *fb = info->bevel;
int j, contents;
@@ -172,7 +179,7 @@ loc0:
return NULL; // through the fence
}
return PM_RecursiveSurfCheck( mod, node->children[side^1], mid, p2 );
return PM_RecursiveSurfCheck( mod, children[side^1], mid, p2 );
}
/*
@@ -227,6 +234,9 @@ static int PM_TestLine_r( model_t *mod, mnode_t *node, vec_t p1f, vec_t p2f, con
float frac, midf;
int i, r, side;
vec3_t mid;
mnode_t *children[2];
int numsurfaces, firstsurface;
loc0:
if( node->contents < 0 )
{
@@ -242,15 +252,17 @@ loc0:
front = PlaneDiff( start, node->plane );
back = PlaneDiff( stop, node->plane );
node_children( children, node, mod );
if( front >= -FRAC_EPSILON && back >= -FRAC_EPSILON )
{
node = node->children[0];
node = children[0];
goto loc0;
}
if( front < FRAC_EPSILON && back < FRAC_EPSILON )
{
node = node->children[1];
node = children[1];
goto loc0;
}
@@ -261,7 +273,7 @@ loc0:
VectorLerp( start, frac, stop, mid );
midf = p1f + ( p2f - p1f ) * frac;
r = PM_TestLine_r( mod, node->children[side], p1f, midf, start, mid, trace );
r = PM_TestLine_r( mod, children[side], p1f, midf, start, mid, trace );
if( r != CONTENTS_EMPTY )
{
@@ -272,9 +284,11 @@ loc0:
}
// walk through real faces
for( i = 0; i < node->numsurfaces; i++ )
numsurfaces = node_numsurfaces( node, mod );
firstsurface = node_firstsurface( node, mod );
for( i = 0; i < numsurfaces; i++ )
{
msurface_t *surf = &mod->surfaces[node->firstsurface + i];
msurface_t *surf = &mod->surfaces[firstsurface + i];
mextrasurf_t *info = surf->info;
mfacebevel_t *fb = info->bevel;
int j, contents;
@@ -308,7 +322,7 @@ loc0:
return contents;
}
return PM_TestLine_r( mod, node->children[!side], midf, p2f, mid, stop, trace );
return PM_TestLine_r( mod, children[!side], midf, p2f, mid, stop, trace );
}
int PM_TestLineExt( playermove_t *pmove, physent_t *ents, int numents, const vec3_t start, const vec3_t end, int flags )

View File

@@ -25,8 +25,7 @@ GNU General Public License for more details.
#define PM_AllowHitBoxTrace( model, hull ) ( model && model->type == mod_studio && ( FBitSet( model->flags, STUDIO_TRACE_HITBOX ) || hull == 2 ))
static mplane_t pm_boxplanes[6];
static mclipnode_t pm_boxclipnodes[6];
static hull_t pm_boxhull;
static hull_t pm_boxhull;
// default hullmins
static const vec3_t pm_hullmins[MAX_MAP_HULLS] =
@@ -65,23 +64,15 @@ can just be stored out and get a proper hull_t structure.
*/
void PM_InitBoxHull( void )
{
int i, side;
int i;
pm_boxhull.clipnodes = pm_boxclipnodes;
pm_boxhull.clipnodes16 = (mclipnode16_t *)box_clipnodes16;
pm_boxhull.planes = pm_boxplanes;
pm_boxhull.firstclipnode = 0;
pm_boxhull.lastclipnode = 5;
for( i = 0; i < 6; i++ )
{
pm_boxclipnodes[i].planenum = i;
side = i & 1;
pm_boxclipnodes[i].children[side] = CONTENTS_EMPTY;
if( i != 5 ) pm_boxclipnodes[i].children[side^1] = i + 1;
else pm_boxclipnodes[i].children[side^1] = CONTENTS_SOLID;
pm_boxplanes[i].type = i>>1;
pm_boxplanes[i].normal[i>>1] = 1.0f;
pm_boxplanes[i].signbits = 0;
@@ -106,6 +97,11 @@ static hull_t *PM_HullForBox( const vec3_t mins, const vec3_t maxs )
pm_boxplanes[4].dist = maxs[2];
pm_boxplanes[5].dist = mins[2];
if( world.version == QBSP2_VERSION )
pm_boxhull.clipnodes32 = (mclipnode32_t *)box_clipnodes32;
else
pm_boxhull.clipnodes16 = (mclipnode16_t *)box_clipnodes16;
return &pm_boxhull;
}
@@ -122,10 +118,21 @@ int GAME_EXPORT PM_HullPointContents( hull_t *hull, int num, const vec3_t p )
if( !hull || !hull->planes ) // fantom bmodels?
return CONTENTS_NONE;
while( num >= 0 )
if( world.version == QBSP2_VERSION )
{
plane = &hull->planes[hull->clipnodes[num].planenum];
num = hull->clipnodes[num].children[PlaneDiff( p, plane ) < 0];
while( num >= 0 )
{
plane = &hull->planes[hull->clipnodes32[num].planenum];
num = hull->clipnodes32[num].children[PlaneDiff( p, plane ) < 0];
}
}
else
{
while( num >= 0 )
{
plane = &hull->planes[hull->clipnodes16[num].planenum];
num = hull->clipnodes16[num].children[PlaneDiff( p, plane ) < 0];
}
}
return num;
}
@@ -193,7 +200,7 @@ PM_RecursiveHullCheck
*/
qboolean PM_RecursiveHullCheck( hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, pmtrace_t *trace )
{
mclipnode_t *node;
int children[2];
mplane_t *plane;
float t1, t2;
float frac, midf;
@@ -226,21 +233,31 @@ loc0:
Host_Error( "%s: bad node number %i\n", __func__, num );
// find the point distances
node = hull->clipnodes + num;
plane = hull->planes + node->planenum;
if( world.version == QBSP2_VERSION )
{
children[0] = hull->clipnodes32[num].children[0];
children[1] = hull->clipnodes32[num].children[1];
plane = hull->planes + hull->clipnodes32[num].planenum;
}
else
{
children[0] = hull->clipnodes16[num].children[0];
children[1] = hull->clipnodes16[num].children[1];
plane = hull->planes + hull->clipnodes16[num].planenum;
}
t1 = PlaneDiff( p1, plane );
t2 = PlaneDiff( p2, plane );
if( t1 >= 0.0f && t2 >= 0.0f )
{
num = node->children[0];
num = children[0];
goto loc0;
}
if( t1 < 0.0f && t2 < 0.0f )
{
num = node->children[1];
num = children[1];
goto loc0;
}
@@ -257,14 +274,14 @@ loc0:
VectorLerp( p1, frac, p2, mid );
// move up to the node
if( !PM_RecursiveHullCheck( hull, node->children[side], p1f, midf, p1, mid, trace ))
if( !PM_RecursiveHullCheck( hull, children[side], p1f, midf, p1, mid, trace ))
return false;
// this recursion can not be optimized because mid would need to be duplicated on a stack
if( PM_HullPointContents( hull, node->children[side^1], mid ) != CONTENTS_SOLID )
if( PM_HullPointContents( hull, children[side^1], mid ) != CONTENTS_SOLID )
{
// go past the node
return PM_RecursiveHullCheck( hull, node->children[side^1], midf, p2f, mid, p2, trace );
return PM_RecursiveHullCheck( hull, children[side^1], midf, p2f, mid, p2, trace );
}
// never got out of the solid area

View File

@@ -324,20 +324,14 @@ extern const char *const clc_strings[clc_lastmsg+1];
#define PROTOCOL_GOLDSRC_VERSION 48
#define svc_goldsrc_version svc_changing
#define svc_goldsrc_serverinfo svc_serverdata
#define svc_goldsrc_deltadescription svc_deltatable
#define svc_goldsrc_stopsound svc_resource
#define svc_goldsrc_damage svc_restoresound
#define svc_goldsrc_killedmonster 27
#define svc_goldsrc_foundsecret 28
#define svc_goldsrc_spawnstaticsound 29
#define svc_goldsrc_decalname svc_bspdecal
#define svc_goldsrc_newusermsg svc_usermessage
#define svc_goldsrc_newmovevars svc_deltamovevars
#define svc_goldsrc_sendextrainfo 54
#define svc_goldsrc_timescale 55
#define svc_goldsrc_sendcvarvalue svc_querycvarvalue
#define svc_goldsrc_sendcvarvalue2 svc_querycvarvalue2
#define clc_goldsrc_hltv clc_requestcvarvalue // 9
#define clc_goldsrc_requestcvarvalue clc_requestcvarvalue2 // 10

View File

@@ -89,16 +89,6 @@ void Sound_Shutdown( void )
Mem_FreePool( &host.soundpool );
}
static byte *Sound_Copy( size_t size )
{
byte *out;
out = Mem_Realloc( host.soundpool, sound.tempbuffer, size );
sound.tempbuffer = NULL;
return out;
}
uint GAME_EXPORT Sound_GetApproxWavePlayLen( const char *filepath )
{
string name;
@@ -378,6 +368,7 @@ static qboolean Sound_ResampleInternal( wavdata_t *sc, int outrate, int outwidth
const int inwidth = sc->width;
const int inchannels = sc->channels;
const int incount = sc->samples;
const int insize = sc->size;
qboolean handled = false;
double stepscale;
double t1, t2;
@@ -431,22 +422,30 @@ static qboolean Sound_ResampleInternal( wavdata_t *sc, int outrate, int outwidth
else // upsample case, w/ interpolation
handled = Sound_ConvertUpsample( sc, inwidth, inchannels, incount, outwidth, outchannels, outcount, stepscale );
t2 = Sys_DoubleTime();
if( handled )
if( !handled )
{
if( t2 - t1 > 0.01f ) // critical, report to mod developer
Con_Printf( S_WARN "%s: from [%d bit %d Hz %dch] to [%d bit %d Hz %dch] (took %.3fs)\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels, t2 - t1 );
else
Con_Reportf( "%s: from [%d bit %d Hz %dch] to [%d bit %d Hz %dch] (took %.3fs)\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels, t2 - t1 );
}
else
// restore previously changed data
sc->rate = inrate;
sc->width = inwidth;
sc->channels = inchannels;
sc->samples = incount;
sc->size = insize;
Con_Printf( S_ERROR "%s: unsupported from [%d bit %d Hz %dch] to [%d bit %d Hz %dch]\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels );
return false;
}
t2 = Sys_DoubleTime();
sc->rate = outrate;
sc->width = outwidth;
return handled;
if( t2 - t1 > 0.01f ) // critical, report to mod developer
Con_Printf( S_WARN "%s: from [%d bit %d Hz %dch] to [%d bit %d Hz %dch] (took %.3fs)\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels, t2 - t1 );
else
Con_Reportf( "%s: from [%d bit %d Hz %dch] to [%d bit %d Hz %dch] (took %.3fs)\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels, t2 - t1 );
return true;
}
qboolean Sound_Process( wavdata_t **wav, int rate, int width, int channels, uint flags )
@@ -464,8 +463,11 @@ qboolean Sound_Process( wavdata_t **wav, int rate, int width, int channels, uint
if( result )
{
Mem_Free( snd->buffer ); // free original image buffer
snd->buffer = Sound_Copy( snd->size ); // unzone buffer
snd = Mem_Realloc( host.soundpool, snd, sizeof( *snd ) + snd->size );
memcpy( snd->buffer, sound.tempbuffer, snd->size );
Mem_Free( sound.tempbuffer );
sound.tempbuffer = NULL;
}
}

View File

@@ -14,10 +14,7 @@ GNU General Public License for more details.
*/
#include "common.h"
#if XASH_WIN32
#define STDOUT_FILENO 1
#include <io.h>
#elif XASH_ANDROID
#if XASH_ANDROID
#include <android/log.h>
#endif
#include <string.h>
@@ -25,66 +22,23 @@ GNU General Public License for more details.
#if XASH_IRIX
#include <sys/time.h>
#endif
#include "xash3d_mathlib.h"
// do not waste precious CPU cycles on mobiles or low memory devices
#if !XASH_WIN32 && !XASH_MOBILE_PLATFORM && !XASH_LOW_MEMORY
#define XASH_COLORIZE_CONSOLE true
// use with caution, running engine in Qt Creator may cause a freeze in read() call
// I have never encountered this bug anywhere else, so still enable by default
#define XASH_USE_SELECT 1
#define XASH_COLORIZE_CONSOLE 1
#else
#define XASH_COLORIZE_CONSOLE false
#define XASH_COLORIZE_CONSOLE 0
#endif
#if XASH_USE_SELECT
// non-blocking console input
#include <sys/select.h>
#endif
typedef struct {
char title[64];
qboolean log_active;
char log_path[MAX_SYSPATH];
FILE *logfile;
int logfileno;
} LogData;
static LogData s_ld;
char *Sys_Input( void )
{
#if XASH_USE_SELECT
if( Host_IsDedicated( ))
{
fd_set rfds;
static char line[1024];
static int len;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO( &rfds );
FD_SET( 0, &rfds); // stdin
while( select( 1, &rfds, NULL, NULL, &tv ) > 0 )
{
if( read( 0, &line[len], 1 ) != 1 )
break;
if( line[len] == '\n' || len > 1022 )
{
line[ ++len ] = 0;
len = 0;
return line;
}
len++;
tv.tv_sec = 0;
tv.tv_usec = 0;
}
}
#endif
#if XASH_WIN32
return Wcon_Input();
#endif
return NULL;
}
static struct logdata_s {
char title[64];
qboolean log_active;
qboolean log_time;
char log_path[MAX_SYSPATH];
FILE *logfile;
int logfileno;
} s_ld;
void Sys_DestroyConsole( void )
{
@@ -123,14 +77,19 @@ static void Sys_FlushLogfile( void )
void Sys_InitLog( void )
{
const char *mode;
const char *mode;
if( Sys_CheckParm( "-log" ) && host.allow_console != 0 )
if( Sys_CheckParm( "-log" ))
{
if( !Sys_GetParmFromCmdLine( "-log", s_ld.log_path ) || !isalnum( s_ld.log_path[0] ))
Q_strncpy( s_ld.log_path, "engine.log", sizeof( s_ld.log_path ));
COM_DefaultExtension( s_ld.log_path, ".log", sizeof( s_ld.log_path ));
s_ld.log_active = true;
Q_strncpy( s_ld.log_path, "engine.log", sizeof( s_ld.log_path ));
}
s_ld.log_time = Sys_CheckParm( "-logtime" );
if( host.change_game && host.type != HOST_DEDICATED )
mode = "a";
else mode = "w";
@@ -146,7 +105,7 @@ void Sys_InitLog( void )
if ( !s_ld.logfile )
{
Con_Reportf( S_ERROR "Sys_InitLog: can't create log file %s: %s\n", s_ld.log_path, strerror( errno ));
Con_Reportf( S_ERROR "%s: can't create log file %s: %s\n", __func__, s_ld.log_path, strerror( errno ));
return;
}
@@ -154,48 +113,48 @@ void Sys_InitLog( void )
// fit to 80 columns for easier read on standard terminal
fputs( "================================================================================\n", s_ld.logfile );
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
fprintf( s_ld.logfile, "Game started at %s\n", Q_timestamp( TIME_FULL ));
fputs( "================================================================================\n", s_ld.logfile );
fflush( s_ld.logfile );
}
}
void Sys_CloseLog( void )
void Sys_CloseLog( const char *finalmsg )
{
char event_name[64];
// continue logged
switch( host.status )
{
case HOST_CRASHED:
Q_strncpy( event_name, "crashed", sizeof( event_name ));
break;
case HOST_ERR_FATAL:
Q_strncpy( event_name, "stopped with error", sizeof( event_name ));
break;
default:
if( !host.change_game ) Q_strncpy( event_name, "stopped", sizeof( event_name ));
else Q_strncpy( event_name, host.finalmsg, sizeof( event_name ));
break;
}
Sys_FlushStdout(); // flush to stdout to ensure all data was written
if( s_ld.logfile )
if( !s_ld.logfile )
return;
// continue logged
if( !finalmsg )
{
fputc( '\n', s_ld.logfile );
fputs( "================================================================================\n", s_ld.logfile );
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
fprintf( s_ld.logfile, "Stopped with reason \"%s\" at %s\n", event_name, Q_timestamp( TIME_FULL ));
fputs( "================================================================================\n", s_ld.logfile );
fclose( s_ld.logfile );
s_ld.logfile = NULL;
switch( host.status )
{
case HOST_CRASHED:
finalmsg = "crashed";
break;
case HOST_ERR_FATAL:
finalmsg = "stopped with error";
break;
default:
finalmsg = "stopped";
break;
}
}
fputc( '\n', s_ld.logfile );
fputs( "================================================================================\n", s_ld.logfile );
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
fprintf( s_ld.logfile, "Stopped with reason \"%s\" at %s\n", finalmsg, Q_timestamp( TIME_FULL ));
fputs( "================================================================================\n", s_ld.logfile );
fclose( s_ld.logfile );
s_ld.logfile = NULL;
}
#if XASH_COLORIZE_CONSOLE == true
static void Sys_WriteEscapeSequenceForColorcode( int fd, int c )
#if XASH_COLORIZE_CONSOLE
static qboolean Sys_WriteEscapeSequenceForColorcode( int fd, int c )
{
static const char *q3ToAnsi[ 8 ] =
{
@@ -210,19 +169,26 @@ static void Sys_WriteEscapeSequenceForColorcode( int fd, int c )
};
const char *esc = q3ToAnsi[c];
if( c == 7 )
write( fd, esc, 4 );
else write( fd, esc, 7 );
return write( fd, esc, c == 7 ? 4 : 7 ) < 0 ? false : true;
}
#else
static void Sys_WriteEscapeSequenceForColorcode( int fd, int c ) {}
static qboolean Sys_WriteEscapeSequenceForColorcode( int fd, int c )
{
return true;
}
#endif
static void Sys_PrintLogfile( const int fd, const char *logtime, const char *msg, const qboolean colorize )
static void Sys_PrintLogfile( const int fd, const char *logtime, size_t logtime_len, const char *msg, const int colorize )
{
const char *p = msg;
write( fd, logtime, Q_strlen( logtime ) );
if( logtime_len != 0 )
{
if( write( fd, logtime, logtime_len ) < 0 )
{
// not critical for us
}
}
while( p && *p )
{
@@ -262,7 +228,7 @@ static void Sys_PrintLogfile( const int fd, const char *logtime, const char *msg
Sys_WriteEscapeSequenceForColorcode( fd, 7 );
}
static void Sys_PrintStdout( const char *logtime, const char *msg )
static void Sys_PrintStdout( const char *logtime, size_t logtime_len, const char *msg )
{
#if XASH_MOBILE_PLATFORM
static char buf[MAX_PRINT_MSG];
@@ -294,7 +260,7 @@ static void Sys_PrintStdout( const char *logtime, const char *msg )
#endif
#elif !XASH_WIN32 // Wcon does the job
Sys_PrintLogfile( STDOUT_FILENO, logtime, msg, XASH_COLORIZE_CONSOLE );
Sys_PrintLogfile( STDOUT_FILENO, logtime, logtime_len, msg, XASH_COLORIZE_CONSOLE );
Sys_FlushStdout();
#endif
}
@@ -305,34 +271,51 @@ void Sys_PrintLog( const char *pMsg )
const struct tm *crt_tm;
char logtime[32] = "";
static char lastchar;
size_t len;
qboolean print_time = true;
size_t len, logtime_len = 0;
time( &crt_time );
crt_tm = localtime( &crt_time );
if( !lastchar || lastchar == '\n' )
{
if( time( &crt_time ) >= 0 )
{
crt_tm = localtime( &crt_time );
if( crt_tm == NULL )
print_time = false;
}
}
else print_time = false;
if( !lastchar || lastchar == '\n')
strftime( logtime, sizeof( logtime ), "[%H:%M:%S] ", crt_tm ); //short time
if( print_time )
{
logtime_len = strftime( logtime, sizeof( logtime ), "[%H:%M:%S] ", crt_tm ); // short time
logtime_len = Q_min( logtime_len, sizeof( logtime ) - 1 ); // just in case
}
// spew to stdout
Sys_PrintStdout( logtime, pMsg );
Sys_PrintStdout( logtime, logtime_len, pMsg );
len = Q_strlen( pMsg );
if( !s_ld.logfile )
{
// save last char to detect when line was not ended
lastchar = len > 0 ? pMsg[len - 1] : 0;
return;
}
if( !lastchar || lastchar == '\n')
strftime( logtime, sizeof( logtime ), "[%Y:%m:%d|%H:%M:%S] ", crt_tm ); //full time
// save last char to detect when line was not ended
lastchar = len > 0 ? pMsg[len - 1] : 0;
Sys_PrintLogfile( s_ld.logfileno, logtime, pMsg, false );
Sys_FlushLogfile();
// spew to engine.log
if( s_ld.logfile )
{
if( s_ld.log_time && print_time )
{
logtime_len = strftime( logtime, sizeof( logtime ), "[%Y:%m:%d|%H:%M:%S] ", crt_tm ); //full time
logtime_len = Q_min( logtime_len, sizeof( logtime ) - 1 ); // just in case
}
else
{
logtime[0] = '\0';
logtime_len = 0;
}
Sys_PrintLogfile( s_ld.logfileno, logtime, logtime_len, pMsg, false );
Sys_FlushLogfile();
}
}
/*

View File

@@ -234,28 +234,12 @@ qboolean Sys_GetIntFromCmdLine( const char* argName, int *out )
return true;
}
void Sys_SendKeyEvents( void )
{
#if XASH_WIN32
MSG msg;
while( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ))
{
if( !GetMessage( &msg, NULL, 0, 0 ))
Sys_Quit ();
TranslateMessage( &msg );
DispatchMessage( &msg );
}
#endif
}
//=======================================================================
// DLL'S MANAGER SYSTEM
//=======================================================================
qboolean Sys_LoadLibrary( dll_info_t *dll )
{
const dllfunc_t *func;
size_t i;
string errorstring;
// check errors
@@ -267,12 +251,8 @@ qboolean Sys_LoadLibrary( dll_info_t *dll )
Con_Reportf( "%s: Loading %s", __func__, dll->name );
if( dll->fcts )
{
// lookup export table
for( func = dll->fcts; func && func->name != NULL; func++ )
*func->func = NULL;
}
if( dll->fcts ) // lookup export table
ClearExports( dll->fcts, dll->num_fcts );
if( !dll->link )
dll->link = COM_LoadLibrary( dll->name, false, true ); // environment pathes
@@ -285,9 +265,10 @@ qboolean Sys_LoadLibrary( dll_info_t *dll )
}
// Get the function adresses
for( func = dll->fcts; func && func->name != NULL; func++ )
for( i = 0; i < dll->num_fcts; i++ )
{
if( !( *func->func = Sys_GetProcAddress( dll, func->name )))
const dllfunc_t *func = &dll->fcts[i];
if( !( *func->func = COM_GetProcAddress( dll->link, func->name )))
{
Q_snprintf( errorstring, sizeof( errorstring ), "Sys_LoadLibrary: %s missing or invalid function (%s)\n", dll->name, func->name );
goto error;
@@ -300,19 +281,11 @@ error:
Con_Reportf( " - failed\n" );
Sys_FreeLibrary( dll ); // trying to free
if( dll->crash ) Sys_Error( "%s", errorstring );
else Con_Reportf( S_ERROR "%s", errorstring );
else Con_Reportf( S_ERROR "%s", errorstring );
return false;
}
void* Sys_GetProcAddress( dll_info_t *dll, const char* name )
{
if( !dll || !dll->link ) // invalid desc
return NULL;
return (void *)COM_GetProcAddress( dll->link, name );
}
qboolean Sys_FreeLibrary( dll_info_t *dll )
{
// invalid desc or alredy freed
@@ -330,6 +303,8 @@ qboolean Sys_FreeLibrary( dll_info_t *dll )
COM_FreeLibrary( dll->link );
dll->link = NULL;
ClearExports( dll->fcts, dll->num_fcts );
return true;
}
@@ -437,7 +412,7 @@ void Sys_Error( const char *error, ... )
Sys_WaitForQuit();
}
Sys_Quit();
Sys_Quit( "caught an error" );
}
#if XASH_EMSCRIPTEN
@@ -445,6 +420,12 @@ void Sys_Error( const char *error, ... )
_exit->_Exit->asm._exit->_exit
As we do not need atexit(), just throw hidden exception
*/
// Hey, you, making an Emscripten port!
// What if we're not supposed to use exit() on Emscripten and instead we should
// exit from the main() function? Would this fix this bug? Test this case, pls.
#error "Read the comment above"
#include <emscripten.h>
#define exit my_exit
void my_exit(int ret)
@@ -460,10 +441,14 @@ void my_exit(int ret)
Sys_Quit
================
*/
void Sys_Quit( void )
void Sys_Quit( const char *reason )
{
Host_Shutdown();
Host_ShutdownWithReason( reason );
#if XASH_ANDROID
Host_ExitInMain();
#else
exit( error_on_exit );
#endif
}
/*
@@ -554,7 +539,7 @@ but since engine will be unloaded during this call
it explicitly doesn't use internal allocation or string copy utils
==================
*/
qboolean Sys_NewInstance( const char *gamedir )
qboolean Sys_NewInstance( const char *gamedir, const char *finalmsg )
{
#if XASH_NSWITCH
char newargs[4096];
@@ -565,7 +550,7 @@ qboolean Sys_NewInstance( const char *gamedir )
// just restart the entire thing
printf( "envSetNextLoad exe: `%s`\n", exe );
printf( "envSetNextLoad argv:\n`%s`\n", newargs );
Host_Shutdown( );
Host_ShutdownWithReason( finalmsg );
envSetNextLoad( exe, newargs );
exit( 0 );
#else
@@ -603,7 +588,7 @@ qboolean Sys_NewInstance( const char *gamedir )
#if XASH_PSVITA
// under normal circumstances it's always going to be the same path
exe = strdup( "app0:/eboot.bin" );
Host_Shutdown( );
Host_ShutdownWithReason( finalmsg );
sceAppMgrLoadExec( exe, newargs, NULL );
#else
exelen = wai_getExecutablePath( NULL, 0, NULL );
@@ -611,7 +596,7 @@ qboolean Sys_NewInstance( const char *gamedir )
wai_getExecutablePath( exe, exelen, NULL );
exe[exelen] = 0;
Host_Shutdown();
Host_ShutdownWithReason( finalmsg );
execv( exe, newargs );
#endif

View File

@@ -41,6 +41,15 @@ NOTE: never change this structure because all dll descriptions in xash code
writes into struct by offsets not names
========================================================================
*/
typedef struct dll_info_s
{
const char *name; // name of library
const dllfunc_t *fcts; // list of dll exports
const size_t num_fcts;
qboolean crash; // crash if dll not found
void *link; // hinstance of loading library
} dll_info_t;
extern int error_on_exit;
double Sys_DoubleTime( void );
char *Sys_GetClipboardData( void );
@@ -49,22 +58,15 @@ int Sys_CheckParm( const char *parm );
void Sys_Warn( const char *format, ... ) FORMAT_CHECK( 1 );
void Sys_Error( const char *error, ... ) FORMAT_CHECK( 1 );
qboolean Sys_LoadLibrary( dll_info_t *dll );
void* Sys_GetProcAddress( dll_info_t *dll, const char* name );
qboolean Sys_FreeLibrary( dll_info_t *dll );
void Sys_ParseCommandLine( int argc, char **argv );
void Sys_SetupCrashHandler( void );
void Sys_RestoreCrashHandler( void );
void Sys_DebugBreak( void );
#define Sys_GetParmFromCmdLine( parm, out ) _Sys_GetParmFromCmdLine( parm, out, sizeof( out ))
qboolean _Sys_GetParmFromCmdLine( const char *parm, char *out, size_t size );
qboolean Sys_GetIntFromCmdLine( const char *parm, int *out );
void Sys_SendKeyEvents( void );
void Sys_Print( const char *pMsg );
void Sys_PrintLog( const char *pMsg );
void Sys_InitLog( void );
void Sys_CloseLog( void );
void Sys_Quit( void ) NORETURN;
qboolean Sys_NewInstance( const char *gamedir );
void Sys_Quit( const char *reason ) NORETURN;
qboolean Sys_NewInstance( const char *gamedir, const char *finalmsg );
void *Sys_GetNativeObject( const char *obj );
//
@@ -72,7 +74,7 @@ void *Sys_GetNativeObject( const char *obj );
//
char *Sys_Input( void );
void Sys_DestroyConsole( void );
void Sys_CloseLog( void );
void Sys_CloseLog( const char *finalmsg );
void Sys_InitLog( void );
void Sys_PrintLog( const char *pMsg );
int Sys_LogFileNo( void );

View File

@@ -68,7 +68,13 @@ extern "C" {
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#if (_MSC_VER >= 1900)
#include <stdbool.h>
#else
#define bool int
#define false 0
#define true 1
#endif
static int WAI_PREFIX(getModulePath_)(HMODULE module, char* out, int capacity, int* dirname_length)
{
@@ -243,6 +249,11 @@ int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
#endif
#endif
#if !defined(WAI_STRINGIZE)
#define WAI_STRINGIZE(s)
#define WAI_STRINGIZE_(s) #s
#endif
#if defined(__ANDROID__) || defined(ANDROID)
#include <fcntl.h>
#include <sys/mman.h>
@@ -265,20 +276,20 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
for (;;)
{
char buffer[PATH_MAX < 1024 ? 1024 : PATH_MAX];
uint64_t low, high;
char buffer[128 + PATH_MAX];
uintptr_t low, high;
char perms[5];
uint64_t offset;
uint32_t major, minor;
char path[PATH_MAX];
uint32_t inode;
uint32_t major, minor, inode;
char path[PATH_MAX + 1];
if (!fgets(buffer, sizeof(buffer), maps))
break;
if (sscanf(buffer, "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " %x:%x %u %s\n", &low, &high, perms, &offset, &major, &minor, &inode, path) == 8)
if (sscanf(buffer, "%" SCNxPTR "-%" SCNxPTR " %s %" SCNx64 " %x:%x %u %" WAI_STRINGIZE(PATH_MAX) "[^\n]\n", &low, &high, perms, &offset, &major, &minor, &inode, path) == 8)
{
uint64_t addr = (uintptr_t)WAI_RETURN_ADDRESS();
void* _addr = WAI_RETURN_ADDRESS();
uintptr_t addr = (uintptr_t)_addr;
if (low <= addr && addr <= high)
{
char* resolved;

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