Compare commits

...

160 Commits

Author SHA1 Message Date
Alibek Omarov
de21d845ec engine: don't forget to put newline at the end of overflowed console message 2024-04-21 20:21:17 +03:00
Alibek Omarov
320f8466e6 engine: hpak: don't print error about missing custom.hpak in quiet mode 2024-04-21 20:05:37 +03:00
Alibek Omarov
f3208e95b2 engine: server: remove misleading message about interface version in case when GetEntityAPI2 has failed
Add message when GetEntityAPI was used instead
2024-04-21 20:05:34 +03:00
Alibek Omarov
ea34bc8652 engine: turn bugcomp into flags that can be enabled/disabled separately 2024-04-21 16:52:15 +03:00
Alibek Omarov
3daf014af8 wscript: always enable -Werror=implicit-function-declaration 2024-04-20 20:48:01 +03:00
Alibek Omarov
ca9d3d262a engine: common: net_encode: directly call MSG_ReadSBitLong for DT_TIMEWINDOW_*, don't do the multiplier check for DT_TIMEWINDOW_BIG 2024-04-20 20:48:01 +03:00
Alibek Omarov
a08f5e439d engine: common: net_encode: fix comparing DT_TIMEWINDOW_* fields
Fixes: 35783bcec2 ("engine: common: net_encode: fix inaccuracy in DT_TIMEWINDOW_* encoding")
2024-04-19 01:51:25 +03:00
Alibek Omarov
8f6771dff4 engine: common: zone: check that Mem_FindPool might return NULL (it can if Sys_Error was called inside of a Sys_Error) 2024-04-19 00:14:26 +03:00
Alibek Omarov
cd47c6b5b3 engine: common: zone: disallow migrating allocations from one pool to another, as this isn't practically used anywhere 2024-04-19 00:14:26 +03:00
Alibek Omarov
1f4f3d7fda engine: common: zone: remove mempool sentinels as pools aren't subject to buffer overflow or double free anymore 2024-04-19 00:14:26 +03:00
Alibek Omarov
e81b5144b3 engine: common: zone: use realloc for managing mem pools
rearrange data in memheader_s to avoid unnecessary paddings
2024-04-19 00:14:26 +03:00
Alibek Omarov
9ec1caed53 engine: common: zone: implement dummy Q_realloc for XASH_CUSTOM_SWAP 2024-04-19 00:14:26 +03:00
Alibek Omarov
ca3b4a9d7f engine: host: oops 2024-04-18 16:48:41 +03:00
Alibek Omarov
87ac217887 engine: common: net_encode: add bitmask operation to delta tests 2024-04-18 16:44:15 +03:00
Alibek Omarov
213650db8f engine: exit with non-zero return code if engine tests are failed 2024-04-18 16:36:18 +03:00
Alibek Omarov
ac46164a6e engine: common: net_encode: implement basic delta tests 2024-04-17 20:27:22 +03:00
Alibek Omarov
6d12d84e94 engine: common: net_encode: apply post_multiplier to integer fields, like GoldSrc does 2024-04-17 06:23:22 +03:00
Alibek Omarov
2a18cde60c engine: common: net_encode: fix applying integer clamp before multiplier
Without this fix, data still might overflow after applying multiplier
and potentially send incorrect data.
2024-04-17 06:16:44 +03:00
Alibek Omarov
35783bcec2 engine: common: net_encode: fix inaccuracy in DT_TIMEWINDOW_* encoding
By avoiding double rounding, we get more accurate time on client when timebase
gets rounded down and target time gets rounded up:

```
>>> round(123.1) - round(124.51)
-2
>>> round(123.1 - 124.51)
-1
```
2024-04-17 06:09:52 +03:00
Alibek Omarov
1677835b45 engine: common: simplify bit buffer operations
Yields a small performance boost
2024-04-08 07:24:53 +03:00
Alibek Omarov
2f2780cb1b ref: null: fix crashes 2024-04-08 07:23:56 +03:00
Alibek Omarov
95b134b5a6 ci: fix cirrus CI configuration file 2024-04-06 06:58:15 +03:00
Alibek Omarov
f60e856f35 engine: server: replace useless call to SV_Serverinfo to a direct access 2024-04-06 06:58:15 +03:00
Alibek Omarov
2ec0d25d85 Documentation: add note about environment variables 2024-04-05 20:15:38 +03:00
Alibek Omarov
fcd0982524 engine: server: free 64-bit string pool last when unloading library 2024-04-05 19:45:24 +03:00
Alibek Omarov
6881ee742d engine: server: fix incorrect NULL check in pfnCvar_RegisterServerVariable 2024-04-05 18:45:15 +03:00
Alibek Omarov
f070bbef3c engine: server: make EDICT_NUM inlined 2024-04-04 20:42:25 +03:00
Alibek Omarov
dd8c66d90e engine: common: fix possible NULL dereference in LZSS_Compress 2024-04-04 20:42:25 +03:00
Alibek Omarov
f995d055b5 filesystem: fix possible NULL dereference 2024-04-04 20:42:25 +03:00
Alibek Omarov
fed65dd497 engine: imagelib: fix possible NULL dereference 2024-04-04 20:42:25 +03:00
Alibek Omarov
c896425ad9 engine: server: make changelevel commands compatible with GoldSrc 2024-04-04 00:21:28 +03:00
Alibek Omarov
4107bd4e0f engine: common: quickly assume that map is valid when generating maps.lst if mpfilter is set or game is multiplayer only 2024-04-03 06:13:43 +03:00
Alibek Omarov
156b2b2b10 engine: server: remove MAP_HAS_SPAWNPOINT checks 2024-04-03 05:52:42 +03:00
Alibek Omarov
13a063bf7d mainui: update 2024-04-02 04:05:49 +03:00
Alibek Omarov
ef786b7d79 engine: client: fix sprites transparency in Night at the Office 2024-04-02 02:18:49 +03:00
Alibek Omarov
5c0c1b1226 ref: gl: make g_posenum in alias renderer static 2024-03-30 03:52:50 +03:00
Alibek Omarov
d041b2aa27 engine: fix error_on_exit data type 2024-03-26 17:15:34 +03:00
Alibek Omarov
f6d489e038 engine: server: register str64stats command that prints string pool usage statistics 2024-03-26 17:15:15 +03:00
Alibek Omarov
d34fedea69 engine: server: cleanup unused variables 2024-03-25 05:50:04 +03:00
Alibek Omarov
80b3f90091 engine: server: more accurate SV_ParseEdict
* Add removing trailing spaces, like GoldSrc does
* Pass classname first to allow game to override it
* Remove FL_CUSTOMENTITY flag usage, GoldSrc doesn't set this flag for "custom"
  export entities
* Fix possible memory leak
2024-03-25 05:49:59 +03:00
SNMetamorph
2a4fafc3f9 engine: voice: added voice_transmit_scale cvar to configure outcoming voice audio volume 2024-03-23 23:37:03 +03:00
SNMetamorph
9b3ccf5f04 engine: voice: output_buffer renamed to compress_buffer 2024-03-23 23:37:03 +03:00
SNMetamorph
f59ac2360a engine: voice: made voice_scale to influence incoming voice audio volume 2024-03-23 23:37:03 +03:00
Alibek Omarov
ff21fb42e6 engine: client: create separate Opus decoders for each player
Turns out, we can't re-use same decoder for different streams.
2024-03-20 18:41:52 +03:00
Alibek Omarov
288cac69de public: add small utility library for unicode stuff 2024-03-19 21:34:18 +03:00
Alibek Omarov
2640b6d869 engine: host: remove misleading message about TAB-autocompletion in dedicated mode 2024-03-19 21:24:21 +03:00
Alibek Omarov
d8910b0e38 engine: platform: linux: do not search sd_notify if NOTIFY_SOCKET isn't set 2024-03-19 21:23:53 +03:00
Alibek Omarov
049bed555e engine: host: fit -help into 80 columns terminal 2024-03-19 21:13:28 +03:00
Alibek Omarov
fe5944720b engine: use common strings to name the engine, makes branding easier for custom forks 2024-03-19 21:11:10 +03:00
Alibek Omarov
665c46b281 filesystem: minor logging opened archives change 2024-03-19 20:42:10 +03:00
Alibek Omarov
975ab6785e engine: make log starting and ending messages shorter, so it fits into standard 80 columns term 2024-03-19 20:41:46 +03:00
Alibek Omarov
6fa4dbfba2 public: build: use XASH_BUILD_BRANCH define set by Waf. Expect XASH_BUILD_{BRANCH,COMMIT} to be always set. 2024-03-19 19:34:30 +03:00
SNMetamorph
0506a1dfce engine: sys_con: added VCS branch name printing to log file header 2024-03-19 19:31:54 +03:00
SNMetamorph
908a9930e6 public: added Q_buildbranch function, needed for better logging 2024-03-19 19:31:54 +03:00
SNMetamorph
7d7e72196b engine: host: enabled printing current developer level 2024-03-19 19:31:54 +03:00
SNMetamorph
7cc67157e5 engine: sys_con: fixed incorrect logging init messages order 2024-03-19 19:31:54 +03:00
SNMetamorph
b7ff9c7a24 engine: sys_con: added missing title for log messages 2024-03-19 19:31:54 +03:00
Alibek Omarov
aab1fa1ba2 wscript: move gitversion load to libpublic, define XASH_BUILD_BRANCH, use unknown-{commit,branch} if detecting git version was failed 2024-03-19 19:30:52 +03:00
Alibek Omarov
effeba2f44 waf: upgrade to waifu 1.2.0 2024-03-19 19:24:49 +03:00
Alibek Omarov
e039ef35c0 filesystem: don't check for SDL whether we can load Android assets, because filesystem doesn't know anything about SDL
Replace it with runtime check instead.
2024-03-11 23:25:10 +03:00
Alibek Omarov
599a1f026e engine: client: fix missing comma 2024-03-11 22:56:52 +03:00
Alibek Omarov
39cba17f01 filesystem: android: try to fix compiling-in AAsset mounting code 2024-03-11 21:49:33 +03:00
SNMetamorph
17e106f96d ref: gl: invalidate texture units state cache when texture deletes 2024-03-09 22:12:35 +03:00
Alibek Omarov
081cf9132b engine: client: read console_history.txt as binary, skip empty and repeating lines, reimplement it through FS_Gets for fun 2024-03-08 15:25:36 +03:00
Alibek Omarov
6a7e027248 engine: common: add joy_ prefix to automatically filterable cvars 2024-03-08 15:25:36 +03:00
Alibek Omarov
27100e7751 engine: client: hook sensitivity cvar registration and make it priveleged cvar 2024-03-08 15:25:36 +03:00
Alibek Omarov
75d9ed341a Create FUNDING.yml 2024-03-07 09:41:18 +03:00
Alibek Omarov
1a0867523d engine: system: parent messagebox to main window when dealing with Sys_Error 2024-03-05 17:12:51 +03:00
Alibek Omarov
7584bbe47e engine: client: fix sound mute when losing focus 2024-03-03 19:00:50 +03:00
Andrey Akhmichin
505b6cc264 utils: mdldec: boneweights fix. 2024-03-01 20:26:18 +03:00
Alibek Omarov
24f23908be engine: platform: stub Sys_DebuggerPresent on unsupported platforms 2024-02-27 05:17:01 +03:00
Alibek Omarov
43bd73f37b engine: platform: that's why commit --amend and/or rebase --interactive your fixes in your patches before proposing them 2024-02-27 04:59:54 +03:00
mittorn
bb2753cbfc engine/system: add asm-based raise implementation for arm and aarch64, making Sys_DebugBreak more relevant, use tgkill instead of kill 2024-02-27 04:54:55 +03:00
mittorn
5568eccc8a ref/r_sprite: move dframetype to inner block 2024-02-27 04:17:21 +03:00
mittorn
c3b2cc4423 waifulib/compiler_optimizations: disable no-semantic-interposition for gcc4 in release builds too 2024-02-27 04:16:14 +03:00
mittorn
d84130219f crashhandler: set host.crashed before messagebox to allow platform code handle crashed state in different way 2024-02-27 04:14:37 +03:00
mittorn
d97d4d6c42 filesystem: add XASH_ANDROID_ASSETS macro for aassets switch 2024-02-27 04:04:54 +03:00
mittorn
15798aaf52 ref/r_sprite: move dframetype to inner block 2024-02-27 04:04:54 +03:00
mittorn
e53892e827 ref_gl: fix loop scope in ripple code 2024-02-27 04:04:54 +03:00
mittorn
cb12af69ed gl2shim: add SOFTFP_LINK support for gles3compat 2024-02-27 04:04:54 +03:00
mittorn
e82050a4bc gl2shim: fix gcc 4.9 build 2024-02-27 04:04:54 +03:00
mittorn
e4edd2da45 platform/posix: check for non-zero dladdr ret 2024-02-27 04:04:54 +03:00
mittorn
4f80922358 waf/compiler_optimizations: remove no-semantic-interposition for gcc4 2024-02-27 04:04:54 +03:00
mittorn
ae7ed03376 ref_soft: fix crash when y < -height 2024-02-27 04:04:54 +03:00
mittorn
c082e46662 imagelib: fix for loop scope 2024-02-27 04:04:54 +03:00
mittorn
b0bbcab6b4 ref_soft,ref_gl: fix unaligned read in sprite code 2024-02-27 04:04:54 +03:00
SNMetamorph
0fc83080ec engine: server: allowed bandwidth test on listen servers 2024-02-26 19:41:32 +03:00
SNMetamorph
73883b504f engine: client: improved bandwidth test logic 2024-02-26 19:41:32 +03:00
SNMetamorph
8efc9d74e8 engine: server: fixed test packet buffer was not being created 2024-02-26 19:41:32 +03:00
mittorn
373321ff00 ref/gl: do not set type on 1D textures on GLES (will fallback to 2D) 2024-02-26 16:08:37 +03:00
Alibek Omarov
a508467aac engine: client: silently ignore if server didn't sent local player info in delta at spawn
The bug happens somewhere in server, not sure where or how. Remove Host_Error so mods
can be played again.
2024-02-26 11:48:46 +03:00
Alibek Omarov
abbe993e80 3rdparty: gl4es: update 2024-02-26 11:20:04 +03:00
Alibek Omarov
c644e4d569 3rdparty: nanogl: update, fix link error with missing glTexEnvfv 2024-02-26 11:06:09 +03:00
Alibek Omarov
c200e008f1 wscript: disable gl-wes-v2 renderer from Android builds 2024-02-26 10:55:42 +03:00
Alibek Omarov
e95a2da6d0 engine: platform: sdl: slightly rework previous patch to not call SDL each frame and check for NULL pointers 2024-02-23 20:55:32 +03:00
Alibek Omarov
8afca1a79c engine: server: allow starting game from custom map 2024-02-23 20:54:32 +03:00
Alibek Omarov
827c9ca857 filesystem: restore original Xash behavior with unreferenced keys in gameinfo.txt/liblist.gam 2024-02-23 20:54:32 +03:00
Alibek Omarov
2416635ba3 common: validate extended surfaces size 2024-02-23 20:54:32 +03:00
Alibek Omarov
39eec89580 engine: increase elights limit up to 128 2024-02-23 20:54:32 +03:00
Sheridan Kane Rathbun
98d88266a6 engine: platform: sdl: fix incorrect mouse cursor positioning on high-dpi displays (#1623)
Signed-off-by: SheridanR <sheridan.rathbun@gmail.com>
2024-02-23 20:54:17 +03:00
mittorn
0f3359fc05 ref_gl: do not apply overbright color if lightscale correction used 2024-02-22 21:02:34 +03:00
mittorn
6c77608c34 ref_gl: implement color-modulate overbrigths with gl_vbo using texture GL_COMBINE 2024-02-22 21:02:34 +03:00
Alibek Omarov
abdff6eff6 mainui: update 2024-02-22 15:43:49 +03:00
Alibek Omarov
95a75465c9 common: remove FORCEINLINE and NOINLINE macros, we don't use them in engine 2024-02-22 15:43:37 +03:00
Alibek Omarov
119926805f mainui: update 2024-02-21 03:39:11 +03:00
Alibek Omarov
f749b5cb4b 3rdparty: nanogl: update 2024-02-21 02:57:18 +03:00
Alibek Omarov
c29ad6b598 scripts: waifulib: compiler_optimizations: add option to use profiling 2024-02-21 02:57:07 +03:00
Alibek Omarov
4c5dfb963e engine: zone: few more tunings for realloc 2024-02-21 00:59:02 +03:00
Alibek Omarov
e11f9e05d4 engine: server: add GetNativeObject to server's PhysicsAPI 2024-02-19 17:49:37 +03:00
Alibek Omarov
5c8b5b3511 Documentation: extensions: add doc about native-object 2024-02-19 17:49:37 +03:00
Alibek Omarov
2ea7162287 engine: gameui: add GetNativeObject to extended menu API 2024-02-19 17:49:37 +03:00
Alibek Omarov
e62ab51842 engine: platforms: android: platforms aren't expected to get NULL or zero sized native object names anymore 2024-02-19 17:49:37 +03:00
Bohdan Shulyar
f1bc9b87b1 platform: android: port to SDL 2024-02-19 17:47:40 +03:00
Alibek Omarov
a9bddaac64 engine: platform: win32: do not call filesystem functions if filesystem_stdio was failed to load 2024-02-19 06:27:24 +03:00
Alibek Omarov
6cef6f6a75 engine: zone: refactoring 2024-02-19 06:13:54 +03:00
Alibek Omarov
25ea6ed500 scripts: waifulib: don't use relative path while creating ZIP file (so cwd might not be equal to sources path) 2024-02-19 05:00:12 +03:00
Alibek Omarov
3d5173f257 engine: zone: implement Mem_Realloc through standard realloc 2024-02-19 04:22:16 +03:00
Alibek Omarov
05ff0d6020 engine: cmd: remove unused global variable 2024-02-17 22:17:22 +03:00
Alibek Omarov
3cea12627e engine: client: add cl_trace_stufftext from old engine 2024-02-17 22:16:39 +03:00
Alibek Omarov
b59b7c1a8d engine: server: better error message for missing spawn functions 2024-02-17 22:15:41 +03:00
Alibek Omarov
dd2c369df3 engine: imagelib: fix integer overflow on huge images when calculating reflectivity 2024-02-17 22:14:27 +03:00
Andrey Akhmichin
8b79e49a0f engine: server: execute maps/<mapname>_unload.cfg on server deactivation. 2024-02-16 17:57:26 +03:00
Andrey Akhmichin
4ea6eba8f2 engine: server: execute maps/<mapname>_load.cfg before entities precaching. 2024-02-16 17:57:26 +03:00
Andrey Akhmichin
f649076bc3 engine: server: execute map change config file before entities precaching. 2024-02-16 17:57:26 +03:00
Andrey Akhmichin
8ecffa4663 engine: server: define new "disconcfgfile" cvar. 2024-02-16 17:57:26 +03:00
Andrey Akhmichin
e90b83849a engine: server: execute map change config file in singleplayer. 2024-02-16 17:57:26 +03:00
Andrey Akhmichin
d517b9717a engine: server: define new "_sv_override_scientist_mdl" cvar for Uplink's scientist model. 2024-02-16 17:57:26 +03:00
Alibek Omarov
2c0d6e06be engine: server: return NULL in SV_ClientBy{Id,Name} if client array isn't allocated 2024-02-15 13:56:47 +03:00
Alibek Omarov
dec71850a1 engine: console: allow changing background filtering 2024-02-13 15:34:33 +03:00
Alibek Omarov
b1860972c6 engine: font: fix inverted check, fix potential division by zero 2024-02-13 15:33:51 +03:00
Alibek Omarov
1f4c9b67da engine: server: don't init or send voice chat in singleplayer 2024-02-13 15:09:26 +03:00
Alibek Omarov
c2da125358 engine: client: as an experiment, let users override default font rendermode through hud_fontrender and con_fontrender cvars 2024-02-09 07:25:47 +03:00
Alibek Omarov
31fa990d44 engine: gamma: fix gamma changes not caught if gamma cvar was set during frame 2024-02-09 06:29:30 +03:00
Alibek Omarov
d3e60c7d84 engine: gamma: higher brightness limit for compatibility 2024-02-09 06:28:31 +03:00
Alibek Omarov
e2424b4303 engine: server: clean up userinfo and fullupdate throttle on client connect 2024-02-07 23:27:02 +03:00
Alibek Omarov
240563cd1b engine: client: set r_lighting_modulate to 0.6 and save it to config for old Xash mods that use it internally 2024-02-07 23:22:27 +03:00
Alibek Omarov
d708cd58fb mainui: update 2024-02-07 23:22:27 +03:00
Alibek Omarov
491b503f96 engine: common: optimize COM_LoadFile/COM_LoadFileForMe removing double allocation 2024-02-07 23:22:27 +03:00
Alibek Omarov
636a2228f6 filesystem: add new API function LoadFileMalloc that returns a pointer that can be freed using standard free() 2024-02-07 23:22:27 +03:00
Alibek Omarov
bb03e2597c filesystem: allow to pass custom allocation functions to LoadFile 2024-02-07 23:22:27 +03:00
Alibek Omarov
21c828ee40 engine: sounds: remove extra logging 2024-02-05 15:57:59 +03:00
Alibek Omarov
132c9de142 engine: host: add the most important command line flag help string 2024-02-05 15:28:18 +03:00
Alibek Omarov
9d9507d77f engine: change mobility API license to Unlicense, as with build.h
See GitHub issue: https://github.com/FWGS/hlsdk-portable/issues/259

Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2024-02-05 15:01:03 +03:00
Alibek Omarov
7daa6c3451 engine: server: use soundlist to acquire random sounds for physics 2024-02-05 12:49:31 +03:00
Alibek Omarov
c8e1ffe0dd engine: client: use soundlist to acquire random sounds for temp entities 2024-02-05 12:49:31 +03:00
Alibek Omarov
b5f02324a6 engine: add basic sounds.lst implementation 2024-02-05 12:49:27 +03:00
Alibek Omarov
47f5dfdcfd common: define macros for color codes for easier access 2024-02-05 12:49:27 +03:00
Alibek Omarov
33da68b013 engine: client: move reseting gamma changed flag to the end of the frame for custom renderers 2024-02-05 03:41:15 +03:00
Alibek Omarov
618ec83c9d engine: client: don't trigger CheckGamma if there is no screenshot action 2024-02-05 03:40:14 +03:00
Alibek Omarov
85de61ebc8 engine: client: fix userid not being written to player info on userinfo change 2024-02-05 02:58:46 +03:00
Alibek Omarov
2feaae59f7 engine: client: bring back r_lighting_modulate, as a compatibility cvar 2024-02-02 13:52:17 +03:00
Alibek Omarov
2550d7fbd3 public: tests: remove linuxunkabi remnants 2024-02-01 02:54:22 +03:00
Alibek Omarov
565f717804 ref: add ref_null renderer that does nothing
This was sitting in my git stash for months. Let's publish it now.
2024-02-01 02:45:19 +03:00
Alibek Omarov
b56c83a2f9 Documentation: add a note about musl 2024-01-31 23:59:28 +03:00
Alibek Omarov
bf17996f72 public: remove linuxunkabi 2024-01-31 23:59:28 +03:00
Alibek Omarov
a3acb1c85b engine: gamma: validate gamma cvars in local games too 2024-01-30 17:55:36 +03:00
Alibek Omarov
d4d63301e0 mainui: update 2024-01-30 17:50:31 +03:00
Alibek Omarov
e9af0c9810 ref: gl: wscript: remove all libs dependencies from gles3compat, added by mistake 2024-01-30 17:40:59 +03:00
Alibek Omarov
131ad9c790 3rdparty: update submodules 2024-01-30 17:28:12 +03:00
Alibek Omarov
bfcaba54dc wscript: move werror flags into uselib 2024-01-30 17:24:17 +03:00
134 changed files with 3445 additions and 1227 deletions

View File

@@ -1,16 +1,3 @@
task:
# Seems packages for it were removed from the mirrors
# name: freebsd-12-amd64
# freebsd_instance:
# image_family: freebsd-12-4
# setup_script:
# - pkg update
# - pkg install -y pkgconf git sdl2 python fontconfig opus
# - git submodule update --init --recursive
# test_script:
# - ./scripts/cirrus/build_freebsd.sh dedicated
# - ./scripts/cirrus/build_freebsd.sh full
task: task:
name: freebsd-13-amd64 name: freebsd-13-amd64
freebsd_instance: freebsd_instance:
@@ -26,7 +13,7 @@ task:
task: task:
name: freebsd-14-amd64 name: freebsd-14-amd64
freebsd_instance: freebsd_instance:
image_family: freebsd-14-0-snap image_family: freebsd-14-0
setup_script: setup_script:
- pkg update - pkg update
- pkg install -y pkgconf git sdl2 python fontconfig opus - pkg install -y pkgconf git sdl2 python fontconfig opus

1
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
custom: https://github.com/FWGS/xash3d-fwgs/blob/master/Documentation/donate.md

View File

@@ -24,14 +24,9 @@ jobs:
# - os: ubuntu-aarch64-20.04 # - os: ubuntu-aarch64-20.04
# targetos: linux # targetos: linux
# targetarch: aarch64 # targetarch: aarch64
- os: ubuntu-20.04
# - os: ubuntu-20.04 targetos: android
# targetos: android targetarch: multiarch
# targetarch: 32
# - os: ubuntu-20.04
# targetos: android
# targetarch: 64
# - os: ubuntu-20.04 # - os: ubuntu-20.04
# targetos: motomagx # targetos: motomagx
# targetarch: armv6 # targetarch: armv6
@@ -51,7 +46,6 @@ jobs:
env: env:
SDL_VERSION: 2.28.5 SDL_VERSION: 2.28.5
GH_CPU_ARCH: ${{ matrix.targetarch }} GH_CPU_ARCH: ${{ matrix.targetarch }}
ANDROID_SDK_TOOLS_VER: 4333796
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3

5
.gitignore vendored
View File

@@ -54,6 +54,11 @@ CMakeFiles
Makefile Makefile
cmake_install.cmake cmake_install.cmake
install_manifest.txt install_manifest.txt
CMakeLists.txt*
CMakeScripts
Testing
compile_commands.json
_deps
# makedepend # makedepend
Makefile.dep Makefile.dep
*.bak *.bak

View File

@@ -1,17 +1,15 @@
# Bug-compatibility in Xash3D FWGS # Bug-compatibility in Xash3D FWGS
Xash3D FWGS has special mode for games that rely on original engine bugs. Xash3D FWGS has special mode for games that rely on original engine bugs. In this mode, we emulate the behaviour of selected functions that may help running mods relying on engine bugs, but enabling them by default may break majority of other games.
In this mode, we emulate the behaviour of selected functions that may help running mods relying on engine bugs, but enabling them by default may break majority of other games.
At this time, we only have implemented GoldSrc bug-compatibility. It can be enabled with `-bugcomp` command line switch. At this time, we only have implemented GoldSrc bug-compatibility. It can be enabled with `-bugcomp` command line switch.
When `-bugcomp` is specified without argument, it enables everything. This behavior might be changed or removed in future versions.
When `-bugcomp` is specified with argument, it interpreted as flags separated with `+`. This way it's possible to combine multiple levels of bug-compatibility.
## GoldSrc bug-compatibility ## GoldSrc bug-compatibility
### Emulated bugs | Flag | Description | Games that require this flag |
| ------- | ----------- | ---------------------------- |
* `pfnPEntityOfEntIndex` in GoldSrc returns NULL for last player due to incorrect player index comparison | `peoei` | Reverts `pfnPEntityOfEntIndex` behavior to GoldSrc, where it returns NULL for last player due to incorrect player index comparison | * Counter-Strike: Condition Zero - Deleted Scenes |
### Games and mods that require this
* Counter-Strike: Condition Zero - Deleted Scenes

View File

@@ -0,0 +1,21 @@
## Environment variables
#### Xash3D FWGS
The engine respects these environment variables:
| Variable | Type | Description |
| --------------------- | ---------- | ----------- |
| `XASH3D_GAME` | _string_ | Overrides default game directory. Ignored if `-game` command line argument is set |
| `XASH3D_BASEDIR` | _string_ | Sets path to base (root) directory, instead of current working directory |
| `XASH3D_RODIR` | _string_ | Sets path to read-only base (root) directory. Ignored if `-rodir` command line argument is set |
| `XASH3D_EXTRAS_PAK1` | _string_ | Archive file from specified path will be added to virtual filesystem search path in the lowest possible priority |
| `XASH3D_EXTRAS_PAK2` | _string_ | Similar to `XASH3D_EXTRAS_PAK1` but next to it in priority list |
Environment variables NOT listed in the table above are used internally, and aren't considered as stable interface.
#### mdldec
| Variable | Type | Description |
| --------------------- | ---------- | ----------- |
| `MDLDEC_ACT_PATH` | _string_ | If set, will read activities list from this path |

View File

@@ -0,0 +1,25 @@
# GetNativeObject API
To be able to use platform-specific features or get optional engine interfaces, we've added a simple call to MobilityAPI on client DLL and PhysicsAPI for server DLL and extended MenuAPI for menu DLL.
It's defined like this:
```
void *pfnGetNativeObject( const char *name );
```
#### Cross-platform objects
Only these objects are guaranteed to be available on all targets.
| Object name | Interface |
|-------------|-----------|
| `VFileSystem009` | Provides C++ interface to filesystem, binary-compatible with Valve's VFileSystem009. |
| `XashFileSystemXXX` | Provides C interface to filesystem. This interface is unstable and not recommended for generic use, outside of engine internals. For more info about current version look into `filesystem.h`. |
#### Android-specific objects
| Object name | Interface |
|-------------|-----------|
| `JNIEnv` | Allows interfacing with Java Native Interface. |
| `ActivityClass` | Returns JNI object for engine Android activity class. |

View File

@@ -0,0 +1,65 @@
# sounds.lst.md
Using sounds.lst located in scripts folder, modder can override some of the hardcoded sounds in temp entities and server physics.
File format:
```
<group name>
{
<path1>
<path2>
<path3>
}
<group2 name> <path with %d> <min number> <max number>
```
* Sounds can use any supported sound format (WAV or MP3).
* The path must be relative to the sounds/ folder in the game or base directory root, addon folder, or archive root.
* Groups can be empty or omitted from the file to load no sound.
* Groups can either list a set of files or specify a format string and a range.
* Anything after // will be considered a comment and ignored.
* Behavior is undefined if the group was listed multiple times.
Currently supported groups are:
|Group name|Usage|
|----------|-----|
|`BouncePlayerShell`|Used for BOUNCE_SHELL tempentity hitsound|
|`BounceWeaponShell`|Used for BOUCNE_SHOTSHELL tempentity hitsound|
|`BounceConcrete`|Used for BOUNCE_CONCRETE tempentity hitsound|
|`BounceGlass`|Used for BOUCNE_GLASS|
|`BounceMetal`|Used for BOUNCE_METAL|
|`BounceFlesh`|Used for BOUNCE_FLESH|
|`BounceWood`|Used for BOUNCE_WOOD|
|`Ricochet`|Used for BOUNCE_SHRAP and ricochet tempentities|
|`Explode`|Used for tempentity explosions|
|`EntityWaterEnter`|Used for entity entering water|
|`EntityWaterExit`|Used for entity exiting water|
|`PlayerWaterEnter`|Used for player entering water|
|`PlayerWaterExit`|Used for player exiting water|
## Example
This example is based on defaults sounds used in Half-Life:
```
BouncePlayerShell "player/pl_shell%d.wav" 1 3
BounceWeaponShell "weapons/sshell%d.wav" 1 3
BounceConcrete "debris/concrete%d.wav" 1 3
BounceGlass "debris/glass%d.wav" 1 4
BounceMetal "debris/metal%d.wav" 1 6
BounceFlesh "debris/flesh%d.wav" 1 7
BounceWood "debris/wood%d.wav" 1 4
Ricochet "weapons/ric%d.wav" 1 5
Explode "weapons/explode%d.wav" 3 5
EntityWaterEnter "player/pl_wade%d.wav" 1 4
EntityWaterExit "player/pl_wade%d.wav" 1 4
PlayerWaterEnter
{
"player/pl_wade1.wav"
}
PlayerWaterExit
{
"player/pl_wade2.wav"
}
```

15
Documentation/musl.md Normal file
View File

@@ -0,0 +1,15 @@
# Xash3D FWGS on `musl`
Xash3D FWGS works on `musl` out of the box. However, the engine doesn't try to differentiate glibc and musl anymore. If you see error similar to:
```
Host_InitError: can't initialize cl_dlls/client.so: Error relocating valve/cl_dlls/client.so: __sprintf_chk: symbol not found
```
... or you know that the game you're running is linked against glibc, you can try using `libgcompat`, like this:
```
$ LD_PRELOAD=/lib/libgcompat.so.0 ./xash3d ...
```
It will automatically add the missing symbols that glibc binaries usually need. In the future we might automatically link engine against `libgcompat` for better compatibility with prebuilt or closed-source games, if there will be any use for this.

View File

@@ -534,5 +534,14 @@ typedef struct
#define MAX_EFRAGS 8192 // Arcane Dimensions required #define MAX_EFRAGS 8192 // Arcane Dimensions required
#define MAX_REQUESTS 64 #define MAX_REQUESTS 64
#if ! XASH_64BIT
STATIC_ASSERT( sizeof( mextrasurf_t ) == 324, "mextrasurf_t unexpected size" );
STATIC_ASSERT( sizeof( decal_t ) == 60, "decal_t unexpected size");
STATIC_ASSERT( sizeof( mfaceinfo_t ) == 176, "mfaceinfo_t unexpected size");
#else
STATIC_ASSERT( sizeof( mextrasurf_t) == 496, "mextrasurf_t unexpected size");
STATIC_ASSERT( sizeof( decal_t ) == 88, "decal_t unexpected size");
STATIC_ASSERT( sizeof( mfaceinfo_t ) == 304, "mfaceinfo_t unexpected size");
#endif
#endif//COM_MODEL_H #endif//COM_MODEL_H

View File

@@ -28,11 +28,7 @@ typedef byte rgb_t[3]; // unsigned byte colorpack
typedef vec_t matrix3x4[3][4]; typedef vec_t matrix3x4[3][4];
typedef vec_t matrix4x4[4][4]; typedef vec_t matrix4x4[4][4];
#if XASH_64BIT
typedef uint32_t poolhandle_t; typedef uint32_t poolhandle_t;
#else
typedef void* poolhandle_t;
#endif
#undef true #undef true
#undef false #undef false
@@ -86,8 +82,6 @@ typedef uint64_t longtime_t;
#define NORETURN __attribute__((noreturn)) #define NORETURN __attribute__((noreturn))
#define NONNULL __attribute__((nonnull)) #define NONNULL __attribute__((nonnull))
#define ALLOC_CHECK(x) __attribute__((alloc_size(x))) #define ALLOC_CHECK(x) __attribute__((alloc_size(x)))
#define FORCEINLINE inline __attribute__((always_inline))
#define NOINLINE __attribute__((noinline))
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#define EXPORT __declspec( dllexport ) #define EXPORT __declspec( dllexport )
#define GAME_EXPORT #define GAME_EXPORT
@@ -95,8 +89,6 @@ typedef uint64_t longtime_t;
#define NORETURN #define NORETURN
#define NONNULL #define NONNULL
#define ALLOC_CHECK(x) #define ALLOC_CHECK(x)
#define FORCEINLINE __forceinline
#define NOINLINE __declspec( noinline )
#else #else
#define EXPORT #define EXPORT
#define GAME_EXPORT #define GAME_EXPORT
@@ -104,8 +96,6 @@ typedef uint64_t longtime_t;
#define NORETURN #define NORETURN
#define NONNULL #define NONNULL
#define ALLOC_CHECK(x) #define ALLOC_CHECK(x)
#define FORCEINLINE
#define NOINLINE
#endif #endif
#if ( __GNUC__ >= 3 ) #if ( __GNUC__ >= 3 )

View File

@@ -46,10 +46,35 @@ static int CL_LoadFontTexture( const char *fontname, uint texFlags, int *width )
return tex; return tex;
} }
qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags ) static int CL_FontRenderMode( convar_t *fontrender )
{
switch((int)fontrender->value )
{
case 0:
return kRenderTransAdd;
case 1:
return kRenderTransAlpha;
case 2:
return kRenderTransTexture;
default:
Cvar_DirectSet( fontrender, fontrender->def_string );
}
return kRenderTransTexture;
}
void CL_SetFontRendermode( cl_font_t *font )
{
ref.dllFuncs.GL_SetRenderMode( CL_FontRenderMode( font->rendermode ));
}
qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, convar_t *rendermode, uint texFlags )
{ {
int font_width, i; int font_width, i;
if( !rendermode )
return false;
if( font->valid ) if( font->valid )
return true; // already loaded return true; // already loaded
@@ -76,13 +101,16 @@ qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float sc
return true; return true;
} }
qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags ) qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float scale, convar_t *rendermode, uint texFlags )
{ {
fs_offset_t length; fs_offset_t length;
qfont_t src; qfont_t src;
byte *pfile; byte *pfile;
int font_width, i; int font_width, i;
if( !rendermode )
return false;
if( font->valid ) if( font->valid )
return true; return true;
@@ -105,7 +133,7 @@ qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float
font->type = FONT_VARIABLE; font->type = FONT_VARIABLE;
font->valid = true; font->valid = true;
font->scale = scale; font->scale = scale ? scale : 1.0f;
font->rendermode = rendermode; font->rendermode = rendermode;
font->charHeight = Q_rint( src.rowheight * scale ); font->charHeight = Q_rint( src.rowheight * scale );
@@ -177,7 +205,8 @@ int CL_DrawCharacter( float x, float y, int number, rgba_t color, cl_font_t *fon
return font->charWidths[number]; return font->charWidths[number];
rc = &font->fontRc[number]; rc = &font->fontRc[number];
if( font->scale <= 1.0f || REF_GET_PARM( PARM_TEX_FILTERING, font->hFontTexture ))
if( font->scale <= 1.f || !REF_GET_PARM( PARM_TEX_FILTERING, font->hFontTexture ))
half = 0; half = 0;
s1 = ((float)rc->left + half ) / texw; s1 = ((float)rc->left + half ) / texw;
@@ -191,7 +220,7 @@ int CL_DrawCharacter( float x, float y, int number, rgba_t color, cl_font_t *fon
SPR_AdjustSize( &x, &y, &w, &h ); SPR_AdjustSize( &x, &y, &w, &h );
if( !FBitSet( flags, FONT_DRAW_NORENDERMODE )) if( !FBitSet( flags, FONT_DRAW_NORENDERMODE ))
ref.dllFuncs.GL_SetRenderMode( font->rendermode ); CL_SetFontRendermode( font );
// don't apply color to fixed fonts it's already colored // don't apply color to fixed fonts it's already colored
if( font->type != FONT_FIXED || REF_GET_PARM( PARM_TEX_GLFORMAT, font->hFontTexture ) == 0x8045 ) // GL_LUMINANCE8_ALPHA8 if( font->type != FONT_FIXED || REF_GET_PARM( PARM_TEX_GLFORMAT, font->hFontTexture ) == 0x8045 ) // GL_LUMINANCE8_ALPHA8
@@ -214,7 +243,7 @@ int CL_DrawString( float x, float y, const char *s, rgba_t color, cl_font_t *fon
Con_UtfProcessChar( 0 ); // clear utf state Con_UtfProcessChar( 0 ); // clear utf state
if( !FBitSet( flags, FONT_DRAW_NORENDERMODE )) if( !FBitSet( flags, FONT_DRAW_NORENDERMODE ))
ref.dllFuncs.GL_SetRenderMode( font->rendermode ); CL_SetFontRendermode( font );
Vector4Copy( color, current_color ); Vector4Copy( color, current_color );

View File

@@ -474,8 +474,7 @@ void CL_DrawCenterPrint( void )
pText = clgame.centerPrint.message; pText = clgame.centerPrint.message;
CL_DrawCharacterLen( font, 0, NULL, &charHeight ); CL_DrawCharacterLen( font, 0, NULL, &charHeight );
CL_SetFontRendermode( font );
ref.dllFuncs.GL_SetRenderMode( font->rendermode );
for( i = 0; i < clgame.centerPrint.lines; i++ ) for( i = 0; i < clgame.centerPrint.lines; i++ )
{ {
lineLength = 0; lineLength = 0;
@@ -1449,7 +1448,7 @@ pfnSPR_Draw
*/ */
static void GAME_EXPORT pfnSPR_Draw( int frame, int x, int y, const wrect_t *prc ) static void GAME_EXPORT pfnSPR_Draw( int frame, int x, int y, const wrect_t *prc )
{ {
ref.dllFuncs.GL_SetRenderMode( kRenderNormal ); ref.dllFuncs.GL_SetRenderMode( kRenderTransAlpha );
SPR_DrawGeneric( frame, x, y, -1, -1, prc ); SPR_DrawGeneric( frame, x, y, -1, -1, prc );
} }
@@ -1714,7 +1713,8 @@ pfnCvar_RegisterVariable
static cvar_t *GAME_EXPORT pfnCvar_RegisterClientVariable( const char *szName, const char *szValue, int flags ) static cvar_t *GAME_EXPORT pfnCvar_RegisterClientVariable( const char *szName, const char *szValue, int flags )
{ {
// a1ba: try to mitigate outdated client.dll vulnerabilities // a1ba: try to mitigate outdated client.dll vulnerabilities
if( !Q_stricmp( szName, "motdfile" )) if( !Q_stricmp( szName, "motdfile" )
|| !Q_stricmp( szName, "sensitivity" ))
flags |= FCVAR_PRIVILEGED; flags |= FCVAR_PRIVILEGED;
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_CLIENTDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_CLIENTDLL )); return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_CLIENTDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_CLIENTDLL ));

View File

@@ -1220,6 +1220,7 @@ static ui_extendedfuncs_t gExtendedfuncs =
pfnParseFileSafe, pfnParseFileSafe,
NET_AdrToString, NET_AdrToString,
NET_CompareAdrSort, NET_CompareAdrSort,
Sys_GetNativeObject,
}; };
void UI_UnloadProgs( void ) void UI_UnloadProgs( void )

View File

@@ -28,7 +28,6 @@ GNU General Public License for more details.
#define MAX_CMD_BUFFER 8000 #define MAX_CMD_BUFFER 8000
#define CONNECTION_PROBLEM_TIME 15.0 // 15 seconds #define CONNECTION_PROBLEM_TIME 15.0 // 15 seconds
#define CL_CONNECTION_RETRIES 10 #define CL_CONNECTION_RETRIES 10
#define CL_TEST_RETRIES_NORESPONCE 3
#define CL_TEST_RETRIES 5 #define CL_TEST_RETRIES 5
CVAR_DEFINE_AUTO( mp_decals, "300", FCVAR_ARCHIVE, "decals limit in multiplayer" ); CVAR_DEFINE_AUTO( mp_decals, "300", FCVAR_ARCHIVE, "decals limit in multiplayer" );
@@ -61,6 +60,7 @@ CVAR_DEFINE_AUTO( cl_smoothtime, "0.1", FCVAR_ARCHIVE, "time to smooth up" );
CVAR_DEFINE_AUTO( cl_clockreset, "0.1", FCVAR_ARCHIVE, "frametime delta maximum value before reset" ); CVAR_DEFINE_AUTO( cl_clockreset, "0.1", FCVAR_ARCHIVE, "frametime delta maximum value before reset" );
CVAR_DEFINE_AUTO( cl_fixtimerate, "7.5", FCVAR_ARCHIVE, "time in msec to client clock adjusting" ); CVAR_DEFINE_AUTO( cl_fixtimerate, "7.5", FCVAR_ARCHIVE, "time in msec to client clock adjusting" );
CVAR_DEFINE_AUTO( hud_fontscale, "1.0", FCVAR_ARCHIVE|FCVAR_LATCH, "scale hud font texture" ); CVAR_DEFINE_AUTO( hud_fontscale, "1.0", FCVAR_ARCHIVE|FCVAR_LATCH, "scale hud font texture" );
CVAR_DEFINE_AUTO( hud_fontrender, "0", FCVAR_ARCHIVE, "hud font render mode (0: additive, 1: holes, 2: trans)" );
CVAR_DEFINE_AUTO( hud_scale, "0", FCVAR_ARCHIVE|FCVAR_LATCH, "scale hud at current resolution" ); CVAR_DEFINE_AUTO( hud_scale, "0", FCVAR_ARCHIVE|FCVAR_LATCH, "scale hud at current resolution" );
CVAR_DEFINE_AUTO( hud_scale_minimal_width, "640", FCVAR_ARCHIVE|FCVAR_LATCH, "if hud_scale results in a HUD virtual screen smaller than this value, it won't be applied" ); CVAR_DEFINE_AUTO( hud_scale_minimal_width, "640", FCVAR_ARCHIVE|FCVAR_LATCH, "if hud_scale results in a HUD virtual screen smaller than this value, it won't be applied" );
CVAR_DEFINE_AUTO( cl_solid_players, "1", 0, "Make all players not solid (can't traceline them)" ); CVAR_DEFINE_AUTO( cl_solid_players, "1", 0, "Make all players not solid (can't traceline them)" );
@@ -74,8 +74,9 @@ 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_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_charset, "utf-8", FCVAR_ARCHIVE, "1-byte charset to use (iconv style)" );
CVAR_DEFINE_AUTO( cl_trace_messages, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable message names tracing (good for developers)"); CVAR_DEFINE_AUTO( cl_trace_stufftext, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable stufftext (server-to-client console commands) tracing (good for developers)" );
CVAR_DEFINE_AUTO( cl_trace_events, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable events 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)" );
static CVAR_DEFINE_AUTO( cl_nat, "0", 0, "show servers running under NAT" ); static CVAR_DEFINE_AUTO( cl_nat, "0", 0, "show servers running under NAT" );
CVAR_DEFINE_AUTO( hud_utf8, "0", FCVAR_ARCHIVE, "Use utf-8 encoding for hud text" ); CVAR_DEFINE_AUTO( hud_utf8, "0", FCVAR_ARCHIVE, "Use utf-8 encoding for hud text" );
CVAR_DEFINE_AUTO( ui_renderworld, "0", FCVAR_ARCHIVE, "render world when UI is visible" ); CVAR_DEFINE_AUTO( ui_renderworld, "0", FCVAR_ARCHIVE, "render world when UI is visible" );
@@ -1070,6 +1071,22 @@ static void CL_SendConnectPacket( void )
cls.timestart = Sys_DoubleTime(); cls.timestart = Sys_DoubleTime();
} }
/*
=================
CL_GetTestFragmentSize
Returns bandwidth test fragment size
=================
*/
static int CL_GetTestFragmentSize( void )
{
const int fragmentSizes[CL_TEST_RETRIES] = { 64000, 32000, 10666, 5200, 1400 };
if( cls.connect_retry >= 0 && cls.connect_retry < CL_TEST_RETRIES )
return bound( FRAGMENT_MIN_SIZE, fragmentSizes[cls.connect_retry], FRAGMENT_MAX_SIZE );
else
return FRAGMENT_MIN_SIZE;
}
/* /*
================= =================
CL_CheckForResend CL_CheckForResend
@@ -1081,8 +1098,9 @@ static void CL_CheckForResend( void )
{ {
netadr_t adr; netadr_t adr;
net_gai_state_t res; net_gai_state_t res;
float resendTime;
qboolean bandwidthTest; qboolean bandwidthTest;
if( cls.internetservers_wait ) if( cls.internetservers_wait )
CL_SendMasterServerScanRequest(); CL_SendMasterServerScanRequest();
@@ -1108,7 +1126,10 @@ static void CL_CheckForResend( void )
else if( cl_resend.value > CL_MAX_RESEND_TIME ) else if( cl_resend.value > CL_MAX_RESEND_TIME )
Cvar_SetValue( "cl_resend", CL_MAX_RESEND_TIME ); Cvar_SetValue( "cl_resend", CL_MAX_RESEND_TIME );
if(( host.realtime - cls.connect_time ) < cl_resend.value ) bandwidthTest = !cls.legacymode && cl_test_bandwidth.value && cls.connect_retry <= CL_TEST_RETRIES;
resendTime = bandwidthTest ? 1.0f : cl_resend.value;
if(( host.realtime - cls.connect_time ) < resendTime )
return; return;
res = NET_StringToAdrNB( cls.servername, &adr ); res = NET_StringToAdrNB( cls.servername, &adr );
@@ -1135,10 +1156,11 @@ static void CL_CheckForResend( void )
if( adr.port == 0 ) adr.port = MSG_BigShort( PORT_SERVER ); if( adr.port == 0 ) adr.port = MSG_BigShort( PORT_SERVER );
if( cls.connect_retry == CL_TEST_RETRIES_NORESPONCE ) if( cls.connect_retry == CL_TEST_RETRIES )
{ {
// too many fails use default connection method // too many fails use default connection method
Con_Printf( "hi-speed connection is failed, use default method\n" ); Con_Printf( "Bandwidth test failed, fallback to default connecting method\n" );
Con_Printf( "Connecting to %s... (retry #%i)\n", cls.servername, cls.connect_retry + 1 );
Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" ); Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" );
Cvar_SetValue( "cl_dlmax", FRAGMENT_MIN_SIZE ); Cvar_SetValue( "cl_dlmax", FRAGMENT_MIN_SIZE );
cls.connect_time = host.realtime; cls.connect_time = host.realtime;
@@ -1146,16 +1168,15 @@ static void CL_CheckForResend( void )
return; return;
} }
bandwidthTest = !cls.legacymode && cl_test_bandwidth.value;
cls.serveradr = adr; cls.serveradr = adr;
cls.max_fragment_size = Q_min( FRAGMENT_MAX_SIZE, cls.max_fragment_size / (cls.connect_retry + 1)); cls.max_fragment_size = CL_GetTestFragmentSize();
cls.connect_time = host.realtime; // for retransmit requests cls.connect_time = host.realtime; // for retransmit requests
cls.connect_retry++; cls.connect_retry++;
if( bandwidthTest ) if( bandwidthTest )
Con_Printf( "Connecting to %s... [retry #%i, max fragment size %i]\n", cls.servername, cls.connect_retry, cls.max_fragment_size ); Con_Printf( "Connecting to %s... (retry #%i, fragment size %i)\n", cls.servername, cls.connect_retry, cls.max_fragment_size );
else else
Con_Printf( "Connecting to %s... [retry #%i]\n", cls.servername, cls.connect_retry ); Con_Printf( "Connecting to %s... (retry #%i)\n", cls.servername, cls.connect_retry );
if( bandwidthTest ) if( bandwidthTest )
Netchan_OutOfBandPrint( NS_CLIENT, adr, "bandwidth %i %i\n", PROTOCOL_VERSION, cls.max_fragment_size ); Netchan_OutOfBandPrint( NS_CLIENT, adr, "bandwidth %i %i\n", PROTOCOL_VERSION, cls.max_fragment_size );
@@ -2891,6 +2912,7 @@ static void CL_InitLocal( void )
Cvar_RegisterVariable( &rcon_address ); Cvar_RegisterVariable( &rcon_address );
Cvar_RegisterVariable( &cl_trace_stufftext );
Cvar_RegisterVariable( &cl_trace_messages ); Cvar_RegisterVariable( &cl_trace_messages );
Cvar_RegisterVariable( &cl_trace_events ); Cvar_RegisterVariable( &cl_trace_events );
@@ -2926,6 +2948,7 @@ static void CL_InitLocal( void )
Cvar_RegisterVariable( &cl_clockreset ); Cvar_RegisterVariable( &cl_clockreset );
Cvar_RegisterVariable( &cl_fixtimerate ); Cvar_RegisterVariable( &cl_fixtimerate );
Cvar_RegisterVariable( &hud_fontscale ); Cvar_RegisterVariable( &hud_fontscale );
Cvar_RegisterVariable( &hud_fontrender );
Cvar_RegisterVariable( &hud_scale ); Cvar_RegisterVariable( &hud_scale );
Cvar_RegisterVariable( &hud_scale_minimal_width ); Cvar_RegisterVariable( &hud_scale_minimal_width );
Cvar_Get( "cl_background", "0", FCVAR_READ_ONLY, "indicate what background map is running" ); Cvar_Get( "cl_background", "0", FCVAR_READ_ONLY, "indicate what background map is running" );

View File

@@ -387,7 +387,7 @@ static void NetGraph_DrawTextFields( int x, int y, int w, wrect_t rect, int coun
// move rolling average // move rolling average
framerate = FRAMERATE_AVG_FRAC * host.frametime + ( 1.0f - FRAMERATE_AVG_FRAC ) * framerate; framerate = FRAMERATE_AVG_FRAC * host.frametime + ( 1.0f - FRAMERATE_AVG_FRAC ) * framerate;
ref.dllFuncs.GL_SetRenderMode( font->rendermode ); CL_SetFontRendermode( font );
if( framerate > 0.0f ) if( framerate > 0.0f )
{ {

View File

@@ -1382,9 +1382,13 @@ void CL_UpdateUserinfo( sizebuf_t *msg, qboolean legacy )
if( slot >= MAX_CLIENTS ) if( slot >= MAX_CLIENTS )
Host_Error( "CL_ParseServerMessage: svc_updateuserinfo >= MAX_CLIENTS\n" ); Host_Error( "CL_ParseServerMessage: svc_updateuserinfo >= MAX_CLIENTS\n" );
player = &cl.players[slot];
if( !legacy ) if( !legacy )
id = MSG_ReadLong( msg ); // unique user ID id = MSG_ReadLong( msg ); // unique user ID
player = &cl.players[slot]; else
id = 0; // bogus
active = MSG_ReadOneBit( msg ) ? true : false; active = MSG_ReadOneBit( msg ) ? true : false;
if( active ) if( active )
@@ -1406,6 +1410,10 @@ void CL_UpdateUserinfo( sizebuf_t *msg, qboolean legacy )
memset( player, 0, sizeof( *player )); memset( player, 0, sizeof( *player ));
} }
// in GoldSrc userinfo might be empty but userid is always sent as separate value
// thus avoids clean up even after client disconnect
player->userid = id;
} }
/* /*
@@ -2321,11 +2329,18 @@ void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message )
break; break;
case svc_stufftext: case svc_stufftext:
s = MSG_ReadString( msg ); s = MSG_ReadString( msg );
if( cl_trace_stufftext.value )
{
size_t len = Q_strlen( s );
Con_Printf( "Stufftext: %s%c", s, len && s[len-1] == '\n' ? '\0' : '\n' );
}
#ifdef HACKS_RELATED_HLMODS #ifdef HACKS_RELATED_HLMODS
// disable Cry Of Fear antisave protection // disable Cry Of Fear antisave protection
if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS ) if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS )
break; // too early break; // too early
#endif #endif
Cbuf_AddFilteredText( s ); Cbuf_AddFilteredText( s );
break; break;
case svc_setangle: case svc_setangle:

View File

@@ -443,13 +443,17 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message )
break; break;
case svc_stufftext: case svc_stufftext:
s = MSG_ReadString( msg ); s = MSG_ReadString( msg );
if( cl_trace_stufftext.value )
{
size_t len = Q_strlen( s );
Con_Printf( "Stufftext: %s%c", s, len && s[len-1] == '\n' ? '\0' : '\n' );
}
#ifdef HACKS_RELATED_HLMODS #ifdef HACKS_RELATED_HLMODS
// disable Cry Of Fear antisave protection // disable Cry Of Fear antisave protection
if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS ) if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS )
break; // too early break; // too early
#endif #endif
Con_Reportf( "Stufftext: %s", s );
Cbuf_AddFilteredText( s ); Cbuf_AddFilteredText( s );
break; break;
case svc_setangle: case svc_setangle:

View File

@@ -795,25 +795,14 @@ static void CL_SetupPMove( playermove_t *pmove, const local_state_t *from, const
pmove->player_index = ps->number - 1; pmove->player_index = ps->number - 1;
// a1ba: workaround bug on old protocol where the server refuse to send // a1ba: workaround bug where the server refuse to send our local player in delta
// our local player in delta. cl.playernum, in theory, must be equal // cl.playernum, in theory, must be equal to our local player index anyway
// to our local player index anyway //
// this might not be a real solution, since everything else will be bogus // this might not be a real solution, since everything else will be bogus
// but we need to properly run prediction and avoid potential memory // but we need to properly run prediction and avoid potential memory
// corruption // corruption
// either debug this, or remove when old protocol will be dropped!!!
if( pmove->player_index < 0 ) if( pmove->player_index < 0 )
{ pmove->player_index = bound( 0, cl.playernum, cl.maxclients - 1 );
if( cls.legacymode )
{
pmove->player_index = bound( 0, cl.playernum, cl.maxclients - 1 );
}
else
{
// if this happens, record a demo and send it to a1ba
Host_Error( "%s: ps->number == %d\n", __func__, ps->number );
}
}
pmove->multiplayer = (cl.maxclients > 1); pmove->multiplayer = (cl.maxclients > 1);
pmove->runfuncs = runfuncs; pmove->runfuncs = runfuncs;

View File

@@ -288,6 +288,9 @@ void SCR_MakeScreenShot( void )
qboolean iRet = false; qboolean iRet = false;
int viewsize; int viewsize;
if( cls.scrshot_action == scrshot_inactive )
return;
if( cls.envshot_viewsize > 0 ) if( cls.envshot_viewsize > 0 )
viewsize = cls.envshot_viewsize; viewsize = cls.envshot_viewsize;
else viewsize = cl_envshot_size.value; else viewsize = cl_envshot_size.value;
@@ -319,8 +322,6 @@ void SCR_MakeScreenShot( void )
if( iRet ) if( iRet )
VID_WriteOverviewScript(); // store overview script too VID_WriteOverviewScript(); // store overview script too
break; break;
case scrshot_inactive:
return;
} }
// report // report
@@ -572,15 +573,15 @@ void SCR_LoadCreditsFont( void )
"creditsfont_%s.fnt", Cvar_VariableString( "con_charset" )) > 0 ) "creditsfont_%s.fnt", Cvar_VariableString( "con_charset" )) > 0 )
{ {
if( FS_FileExists( charsetFnt, false )) if( FS_FileExists( charsetFnt, false ))
success = Con_LoadVariableWidthFont( charsetFnt, font, scale, kRenderTransAdd, TF_FONT ); success = Con_LoadVariableWidthFont( charsetFnt, font, scale, &hud_fontrender, TF_FONT );
} }
} }
if( !success ) if( !success )
success = Con_LoadVariableWidthFont( "gfx/creditsfont.fnt", font, scale, kRenderTransAdd, TF_FONT ); success = Con_LoadVariableWidthFont( "gfx/creditsfont.fnt", font, scale, &hud_fontrender, TF_FONT );
if( !success ) if( !success )
success = Con_LoadFixedWidthFont( "gfx/conchars", font, scale, kRenderTransAdd, TF_FONT ); success = Con_LoadFixedWidthFont( "gfx/conchars", font, scale, &hud_fontrender, TF_FONT );
// copy font size for client.dll // copy font size for client.dll
if( success ) if( success )

View File

@@ -57,36 +57,6 @@ const char *cl_default_sprites[] =
"sprites/shellchrome.spr", "sprites/shellchrome.spr",
}; };
const char *cl_player_shell_sounds[] =
{
"player/pl_shell1.wav",
"player/pl_shell2.wav",
"player/pl_shell3.wav",
};
const char *cl_weapon_shell_sounds[] =
{
"weapons/sshell1.wav",
"weapons/sshell2.wav",
"weapons/sshell3.wav",
};
const char *cl_ricochet_sounds[] =
{
"weapons/ric1.wav",
"weapons/ric2.wav",
"weapons/ric3.wav",
"weapons/ric4.wav",
"weapons/ric5.wav",
};
const char *cl_explode_sounds[] =
{
"weapons/explode3.wav",
"weapons/explode4.wav",
"weapons/explode5.wav",
};
static void CL_PlayerDecal( int playerIndex, int textureIndex, int entityIndex, float *pos ); static void CL_PlayerDecal( int playerIndex, int textureIndex, int entityIndex, float *pos );
/* /*
@@ -148,6 +118,7 @@ client resources not precached by server
*/ */
void CL_AddClientResources( void ) void CL_AddClientResources( void )
{ {
const char *snd;
char filepath[MAX_QPATH]; char filepath[MAX_QPATH];
int i; int i;
@@ -163,37 +134,37 @@ void CL_AddClientResources( void )
} }
// then check sounds // then check sounds
for( i = 0; i < ARRAYSIZE( cl_player_shell_sounds ); i++ ) for( i = 0; ( snd = SoundList_Get( BouncePlayerShell, i )); i++ )
{ {
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", cl_player_shell_sounds[i] ); Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
if( !FS_FileExists( filepath, false )) if( !FS_FileExists( filepath, false ))
CL_AddClientResource( cl_player_shell_sounds[i], t_sound ); CL_AddClientResource( snd, t_sound );
} }
for( i = 0; i < ARRAYSIZE( cl_weapon_shell_sounds ); i++ ) for( i = 0; ( snd = SoundList_Get( BounceWeaponShell, i )); i++ )
{ {
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", cl_weapon_shell_sounds[i] ); Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
if( !FS_FileExists( filepath, false )) if( !FS_FileExists( filepath, false ))
CL_AddClientResource( cl_weapon_shell_sounds[i], t_sound ); CL_AddClientResource( snd, t_sound );
} }
for( i = 0; i < ARRAYSIZE( cl_explode_sounds ); i++ ) for( i = 0; ( snd = SoundList_Get( Explode, i )); i++ )
{ {
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", cl_explode_sounds[i] ); Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
if( !FS_FileExists( filepath, false )) if( !FS_FileExists( filepath, false ))
CL_AddClientResource( cl_explode_sounds[i], t_sound ); CL_AddClientResource( snd, t_sound );
} }
#if 0 // ric sounds was precached by server-side #if 0 // ric sounds was precached by server-side
for( i = 0; i < ARRAYSIZE( cl_ricochet_sounds ); i++ ) for( i = 0; ( snd = SoundList_Get( Ricochet, i )); i++ )
{ {
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", cl_ricochet_sounds[i] ); Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
if( !FS_FileExists( filepath, false )) if( !FS_FileExists( filepath, false ))
CL_AddClientResource( cl_ricochet_sounds[i], t_sound ); CL_AddClientResource( snd, t_sound );
} }
#endif #endif
} }
@@ -301,7 +272,7 @@ play collide sound
static void CL_TempEntPlaySound( TEMPENTITY *pTemp, float damp ) static void CL_TempEntPlaySound( TEMPENTITY *pTemp, float damp )
{ {
float fvol; float fvol;
char soundname[32]; const char *soundname = NULL;
qboolean isshellcasing = false; qboolean isshellcasing = false;
int zvel; int zvel;
@@ -312,36 +283,39 @@ static void CL_TempEntPlaySound( TEMPENTITY *pTemp, float damp )
switch( pTemp->hitSound ) switch( pTemp->hitSound )
{ {
case BOUNCE_GLASS: case BOUNCE_GLASS:
Q_snprintf( soundname, sizeof( soundname ), "debris/glass%i.wav", COM_RandomLong( 1, 4 )); soundname = SoundList_GetRandom( BounceGlass );
break; break;
case BOUNCE_METAL: case BOUNCE_METAL:
Q_snprintf( soundname, sizeof( soundname ), "debris/metal%i.wav", COM_RandomLong( 1, 6 )); soundname = SoundList_GetRandom( BounceMetal );
break; break;
case BOUNCE_FLESH: case BOUNCE_FLESH:
Q_snprintf( soundname, sizeof( soundname ), "debris/flesh%i.wav", COM_RandomLong( 1, 7 )); soundname = SoundList_GetRandom( BounceFlesh );
break; break;
case BOUNCE_WOOD: case BOUNCE_WOOD:
Q_snprintf( soundname, sizeof( soundname ), "debris/wood%i.wav", COM_RandomLong( 1, 4 )); soundname = SoundList_GetRandom( BounceWood );
break; break;
case BOUNCE_SHRAP: case BOUNCE_SHRAP:
Q_strncpy( soundname, cl_ricochet_sounds[COM_RandomLong( 0, 4 )], sizeof( soundname ) ); soundname = SoundList_GetRandom( Ricochet );
break; break;
case BOUNCE_SHOTSHELL: case BOUNCE_SHOTSHELL:
Q_strncpy( soundname, cl_weapon_shell_sounds[COM_RandomLong( 0, 2 )], sizeof( soundname ) ); soundname = SoundList_GetRandom( BounceWeaponShell );
isshellcasing = true; // shell casings have different playback parameters isshellcasing = true; // shell casings have different playback parameters
fvol = 0.5f; fvol = 0.5f;
break; break;
case BOUNCE_SHELL: case BOUNCE_SHELL:
Q_strncpy( soundname, cl_player_shell_sounds[COM_RandomLong( 0, 2 )], sizeof( soundname ) ); soundname = SoundList_GetRandom( BouncePlayerShell );
isshellcasing = true; // shell casings have different playback parameters isshellcasing = true; // shell casings have different playback parameters
break; break;
case BOUNCE_CONCRETE: case BOUNCE_CONCRETE:
Q_snprintf( soundname, sizeof( soundname ), "debris/concrete%i.wav", COM_RandomLong( 1, 3 )); soundname = SoundList_GetRandom( BounceConcrete );
break; break;
default: // null sound default: // null sound
return; return;
} }
if( !soundname )
return;
zvel = abs( pTemp->entity.baseline.origin[2] ); zvel = abs( pTemp->entity.baseline.origin[2] );
// only play one out of every n // only play one out of every n
@@ -1491,7 +1465,7 @@ void GAME_EXPORT R_FunnelSprite( const vec3_t org, int modelIndex, int reverse )
=============== ===============
R_SparkEffect R_SparkEffect
Create a streaks + richochet sprite Create a streaks + ricochet sprite
=============== ===============
*/ */
void GAME_EXPORT R_SparkEffect( const vec3_t pos, int count, int velocityMin, int velocityMax ) void GAME_EXPORT R_SparkEffect( const vec3_t pos, int count, int velocityMin, int velocityMax )
@@ -1507,18 +1481,25 @@ R_RicochetSound
Make a random ricochet sound Make a random ricochet sound
============== ==============
*/ */
static void R_RicochetSound_( const vec3_t pos, int sound ) static void R_RicochetSoundByName( const vec3_t pos, const char *name )
{ {
sound_t handle; sound_t handle;
handle = S_RegisterSound( name );
handle = S_RegisterSound( cl_ricochet_sounds[sound] );
S_StartSound( pos, 0, CHAN_AUTO, handle, VOL_NORM, 1.0, 100, 0 ); S_StartSound( pos, 0, CHAN_AUTO, handle, VOL_NORM, 1.0, 100, 0 );
} }
static void R_RicochetSoundByIndex( const vec3_t pos, int idx )
{
const char *name = SoundList_Get( Ricochet, idx );
if( name )
R_RicochetSoundByName( pos, name );
}
void GAME_EXPORT R_RicochetSound( const vec3_t pos ) void GAME_EXPORT R_RicochetSound( const vec3_t pos )
{ {
R_RicochetSound_( pos, COM_RandomLong( 0, 4 )); const char *name = SoundList_GetRandom( Ricochet );
if( name )
R_RicochetSoundByName( pos, name );
} }
/* /*
@@ -1665,8 +1646,12 @@ void GAME_EXPORT R_Explosion( vec3_t pos, int model, float scale, float framerat
if( !FBitSet( flags, TE_EXPLFLAG_NOSOUND )) if( !FBitSet( flags, TE_EXPLFLAG_NOSOUND ))
{ {
hSound = S_RegisterSound( cl_explode_sounds[COM_RandomLong( 0, 2 )] ); const char *name = SoundList_GetRandom( Explode );
S_StartSound( pos, 0, CHAN_STATIC, hSound, VOL_NORM, 0.3f, PITCH_NORM, 0 ); if( name )
{
hSound = S_RegisterSound( name );
S_StartSound( pos, 0, CHAN_STATIC, hSound, VOL_NORM, 0.3f, PITCH_NORM, 0 );
}
} }
} }
@@ -1909,6 +1894,7 @@ void CL_ParseTempEntity( sizebuf_t *msg )
cl_entity_t *pEnt; cl_entity_t *pEnt;
dlight_t *dl; dlight_t *dl;
sound_t hSound; sound_t hSound;
const char *name;
if( cls.legacymode ) if( cls.legacymode )
iSize = MSG_ReadByte( msg ); iSize = MSG_ReadByte( msg );
@@ -1968,8 +1954,11 @@ void CL_ParseTempEntity( sizebuf_t *msg )
pos[2] = MSG_ReadCoord( &buf ); pos[2] = MSG_ReadCoord( &buf );
R_BlobExplosion( pos ); R_BlobExplosion( pos );
hSound = S_RegisterSound( cl_explode_sounds[0] ); if(( name = SoundList_Get( Explode, 0 )))
S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 1.0f, PITCH_NORM, 0 ); {
hSound = S_RegisterSound( name );
S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 1.0f, PITCH_NORM, 0 );
}
break; break;
case TE_SMOKE: case TE_SMOKE:
pos[0] = MSG_ReadCoord( &buf ); pos[0] = MSG_ReadCoord( &buf );
@@ -2022,8 +2011,11 @@ void CL_ParseTempEntity( sizebuf_t *msg )
dl->die = cl.time + 0.5; dl->die = cl.time + 0.5;
dl->decay = 300; dl->decay = 300;
hSound = S_RegisterSound( cl_explode_sounds[0] ); if(( name = SoundList_Get( Explode, 0 )))
S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 0.6f, PITCH_NORM, 0 ); {
hSound = S_RegisterSound( name );
S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 1.0f, PITCH_NORM, 0 );
}
break; break;
case TE_BSPDECAL: case TE_BSPDECAL:
case TE_DECAL: case TE_DECAL:
@@ -2251,8 +2243,8 @@ void CL_ParseTempEntity( sizebuf_t *msg )
CL_DecalShoot( CL_DecalIndex( decalIndex ), entityIndex, 0, pos, 0 ); CL_DecalShoot( CL_DecalIndex( decalIndex ), entityIndex, 0, pos, 0 );
R_BulletImpactParticles( pos ); R_BulletImpactParticles( pos );
flags = COM_RandomLong( 0, 0x7fff ); flags = COM_RandomLong( 0, 0x7fff );
if( flags < 0x3fff ) if( flags < 0x3fff && ( count = SoundList_Count( Ricochet )))
R_RicochetSound_( pos, flags % 5 ); R_RicochetSoundByIndex( pos, flags % count );
break; break;
case TE_SPRAY: case TE_SPRAY:
case TE_SPRITE_SPRAY: case TE_SPRITE_SPRAY:

View File

@@ -553,4 +553,6 @@ void V_PostRender( void )
ref.dllFuncs.R_AllowFog( true ); ref.dllFuncs.R_AllowFog( true );
Platform_SetTimer( 0.0f ); Platform_SetTimer( 0.0f );
ref.dllFuncs.R_EndFrame(); ref.dllFuncs.R_EndFrame();
V_CheckGammaEnd();
} }

View File

@@ -342,7 +342,7 @@ typedef struct
byte charWidths[256]; // scaled widths byte charWidths[256]; // scaled widths
int charHeight; // scaled height int charHeight; // scaled height
int type; // fixed width font or variable int type; // fixed width font or variable
int rendermode; // default rendermode convar_t *rendermode; // user-defined default rendermode
qboolean valid; // all rectangles are valid qboolean valid; // all rectangles are valid
} cl_font_t; } cl_font_t;
@@ -681,12 +681,14 @@ extern convar_t cl_draw_beams;
extern convar_t cl_clockreset; extern convar_t cl_clockreset;
extern convar_t cl_fixtimerate; extern convar_t cl_fixtimerate;
extern convar_t hud_fontscale; extern convar_t hud_fontscale;
extern convar_t hud_fontrender;
extern convar_t hud_scale; extern convar_t hud_scale;
extern convar_t hud_scale_minimal_width; extern convar_t hud_scale_minimal_width;
extern convar_t r_showtextures; extern convar_t r_showtextures;
extern convar_t cl_bmodelinterp; extern convar_t cl_bmodelinterp;
extern convar_t cl_lw; // local weapons extern convar_t cl_lw; // local weapons
extern convar_t cl_charset; extern convar_t cl_charset;
extern convar_t cl_trace_stufftext;
extern convar_t cl_trace_messages; extern convar_t cl_trace_messages;
extern convar_t cl_trace_events; extern convar_t cl_trace_events;
extern convar_t hud_utf8; extern convar_t hud_utf8;
@@ -798,9 +800,10 @@ void CL_FireEvents( void );
// cl_font.c // cl_font.c
// //
qboolean CL_FixedFont( cl_font_t *font ); qboolean CL_FixedFont( cl_font_t *font );
qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags ); qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, convar_t *rendermode, uint texFlags );
qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags ); 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_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_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 ); 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_DrawCharacterLen( cl_font_t *font, int number, int *width, int *height );

View File

@@ -25,6 +25,7 @@ GNU General Public License for more details.
static CVAR_DEFINE_AUTO( scr_conspeed, "600", FCVAR_ARCHIVE, "console moving speed" ); static CVAR_DEFINE_AUTO( scr_conspeed, "600", FCVAR_ARCHIVE, "console moving speed" );
static CVAR_DEFINE_AUTO( con_notifytime, "3", FCVAR_ARCHIVE, "notify time to live" ); static CVAR_DEFINE_AUTO( con_notifytime, "3", FCVAR_ARCHIVE, "notify time to live" );
CVAR_DEFINE_AUTO( con_fontsize, "1", FCVAR_ARCHIVE, "console font number (0, 1 or 2)" ); CVAR_DEFINE_AUTO( con_fontsize, "1", FCVAR_ARCHIVE, "console font number (0, 1 or 2)" );
static CVAR_DEFINE_AUTO( con_fontrender, "2", FCVAR_ARCHIVE, "console font render mode (0: additive, 1: holes, 2: trans)" );
static CVAR_DEFINE_AUTO( con_charset, "cp1251", FCVAR_ARCHIVE, "console font charset (only cp1251 supported now)" ); static CVAR_DEFINE_AUTO( con_charset, "cp1251", FCVAR_ARCHIVE, "console font charset (only cp1251 supported now)" );
static CVAR_DEFINE_AUTO( con_fontscale, "1.0", FCVAR_ARCHIVE, "scale font texture" ); static CVAR_DEFINE_AUTO( con_fontscale, "1.0", FCVAR_ARCHIVE, "scale font texture" );
static CVAR_DEFINE_AUTO( con_fontnum, "-1", FCVAR_ARCHIVE, "console font number (0, 1 or 2), -1 for autoselect" ); static CVAR_DEFINE_AUTO( con_fontnum, "-1", FCVAR_ARCHIVE, "console font number (0, 1 or 2), -1 for autoselect" );
@@ -547,7 +548,7 @@ static void Con_LoadConsoleFont( int fontNumber, cl_font_t *font )
if( con_oldfont.value ) if( con_oldfont.value )
{ {
success = Con_LoadVariableWidthFont( "gfx/conchars.fnt", font, scale, kRenderTransTexture, TF_FONT|TF_NEAREST ); success = Con_LoadVariableWidthFont( "gfx/conchars.fnt", font, scale, &con_fontrender, TF_FONT|TF_NEAREST );
} }
else else
{ {
@@ -560,14 +561,14 @@ static void Con_LoadConsoleFont( int fontNumber, cl_font_t *font )
if( Q_snprintf( path, sizeof( path ), if( Q_snprintf( path, sizeof( path ),
"font%i_%s.fnt", fontNumber, Cvar_VariableString( "con_charset" )) > 0 ) "font%i_%s.fnt", fontNumber, Cvar_VariableString( "con_charset" )) > 0 )
{ {
success = Con_LoadVariableWidthFont( path, font, scale, kRenderTransTexture, TF_FONT|TF_NEAREST ); success = Con_LoadVariableWidthFont( path, font, scale, &con_fontrender, TF_FONT|TF_NEAREST );
} }
} }
if( !success ) if( !success )
{ {
Q_snprintf( path, sizeof( path ), "fonts/font%i", fontNumber ); Q_snprintf( path, sizeof( path ), "fonts/font%i", fontNumber );
success = Con_LoadVariableWidthFont( path, font, scale, kRenderTransTexture, TF_FONT|TF_NEAREST ); success = Con_LoadVariableWidthFont( path, font, scale, &con_fontrender, TF_FONT|TF_NEAREST );
} }
} }
@@ -575,7 +576,7 @@ static void Con_LoadConsoleFont( int fontNumber, cl_font_t *font )
{ {
// quake fixed font as fallback // quake fixed font as fallback
// keep source to print directly into conback image // keep source to print directly into conback image
if( !Con_LoadFixedWidthFont( "gfx/conchars", font, scale, kRenderTransTexture, TF_FONT|TF_NEAREST|TF_KEEP_SOURCE )) if( !Con_LoadFixedWidthFont( "gfx/conchars", font, scale, &con_fontrender, TF_FONT|TF_NEAREST|TF_KEEP_SOURCE ))
Con_DPrintf( S_ERROR "failed to load console font\n" ); Con_DPrintf( S_ERROR "failed to load console font\n" );
} }
} }
@@ -840,6 +841,7 @@ void Con_Init( void )
Cvar_RegisterVariable( &con_fontsize ); Cvar_RegisterVariable( &con_fontsize );
Cvar_RegisterVariable( &con_charset ); Cvar_RegisterVariable( &con_charset );
Cvar_RegisterVariable( &con_fontscale ); Cvar_RegisterVariable( &con_fontscale );
Cvar_RegisterVariable( &con_fontrender );
Cvar_RegisterVariable( &con_fontnum ); Cvar_RegisterVariable( &con_fontnum );
Cvar_RegisterVariable( &con_color ); Cvar_RegisterVariable( &con_color );
Cvar_RegisterVariable( &scr_drawversion ); Cvar_RegisterVariable( &scr_drawversion );
@@ -1123,7 +1125,7 @@ Con_ClearField
*/ */
static void Con_ClearField( field_t *edit ) static void Con_ClearField( field_t *edit )
{ {
memset( edit->buffer, 0, MAX_STRING ); memset( edit->buffer, 0, sizeof( edit->buffer ));
edit->cursor = 0; edit->cursor = 0;
edit->scroll = 0; edit->scroll = 0;
} }
@@ -1442,36 +1444,49 @@ static void Con_HistoryAppend( con_history_t *self, field_t *from )
static void Con_LoadHistory( con_history_t *self ) static void Con_LoadHistory( con_history_t *self )
{ {
const byte *aFile = FS_LoadFile( "console_history.txt", NULL, true );
const char *pLine, *pFile;
int i, len;
field_t *f; field_t *f;
file_t *fd;
int i;
if( !aFile ) fd = FS_Open( "console_history.txt", "rb", true );
if( !fd )
return; return;
for( pFile = pLine = (char *)aFile; *pFile; pFile++ ) while( !FS_Eof( fd ))
{ {
if( *pFile != '\n' ) f = &self->lines[self->next % CON_HISTORY];
Con_ClearField( f );
f->widthInChars = con.linewidth;
FS_Gets( fd, f->buffer, sizeof( f->buffer ));
f->cursor = Q_strlen( f->buffer );
// skip empty lines
if( f->cursor == 0 )
continue; continue;
Con_ClearField( &self->lines[self->next] ); // skip repeating lines
if( self->next > 0 )
len = Q_min( pFile - pLine + 1, sizeof( f->buffer )); {
f = &self->lines[self->next % CON_HISTORY]; field_t *prev;
f->widthInChars = con.linewidth; prev = &self->lines[(self->next - 1) % CON_HISTORY];
f->cursor = len - 1; if( !Q_stricmp( prev->buffer, f->buffer ))
Q_strncpy( f->buffer, pLine, len); continue;
}
self->next++; self->next++;
pLine = pFile + 1;
} }
FS_Close( fd );
for( i = self->next; i < CON_HISTORY; i++ ) for( i = self->next; i < CON_HISTORY; i++ )
{ {
Con_ClearField( &self->lines[i] ); f = &self->lines[i];
self->lines[i].widthInChars = con.linewidth;
Con_ClearField( f );
f->widthInChars = con.linewidth;
} }
self->line = self->next; self->line = self->next;
@@ -1489,7 +1504,7 @@ static void Con_SaveHistory( con_history_t *self )
if( historyStart < 0 ) if( historyStart < 0 )
historyStart = 0; historyStart = 0;
f = FS_Open( "console_history.txt", "w", true ); f = FS_Open( "console_history.txt", "wb", true );
for( i = historyStart; i < self->next; i++ ) for( i = historyStart; i < self->next; i++ )
FS_Printf( f, "%s\n", self->lines[i % CON_HISTORY].buffer ); FS_Printf( f, "%s\n", self->lines[i % CON_HISTORY].buffer );
@@ -2098,9 +2113,13 @@ void Con_RunConsole( void )
// decide on the destination height of the console // decide on the destination height of the console
if( host.allow_console && cls.key_dest == key_console ) if( host.allow_console && cls.key_dest == key_console )
{ {
#if XASH_MOBILE_PLATFORM
con.showlines = refState.height; // always full screen on mobile devices
#else
if( cls.state < ca_active || cl.first_frame ) if( cls.state < ca_active || cl.first_frame )
con.showlines = refState.height; // full screen con.showlines = refState.height; // full screen
else con.showlines = (refState.height >> 1); // half screen else con.showlines = (refState.height >> 1); // half screen
#endif
} }
else con.showlines = 0; // none visible else con.showlines = 0; // none visible
@@ -2185,6 +2204,8 @@ INTERNAL RESOURCE
*/ */
void Con_VidInit( void ) void Con_VidInit( void )
{ {
const uint flags = TF_IMAGE|TF_ALLOW_NEAREST;
if( !con.historyLoaded ) if( !con.historyLoaded )
{ {
Con_LoadHistory( &con.history ); Con_LoadHistory( &con.history );
@@ -2204,28 +2225,28 @@ void Con_VidInit( void )
{ {
// trying to load truecolor image first // trying to load truecolor image first
if( FS_FileExists( "gfx/shell/conback.bmp", false ) || FS_FileExists( "gfx/shell/conback.tga", false )) if( FS_FileExists( "gfx/shell/conback.bmp", false ) || FS_FileExists( "gfx/shell/conback.tga", false ))
con.background = ref.dllFuncs.GL_LoadTexture( "gfx/shell/conback", NULL, 0, TF_IMAGE ); con.background = ref.dllFuncs.GL_LoadTexture( "gfx/shell/conback", NULL, 0, flags );
if( !con.background ) if( !con.background )
{ {
if( FS_FileExists( "cached/conback640", false )) if( FS_FileExists( "cached/conback640", false ))
con.background = ref.dllFuncs.GL_LoadTexture( "cached/conback640", NULL, 0, TF_IMAGE ); con.background = ref.dllFuncs.GL_LoadTexture( "cached/conback640", NULL, 0, flags );
else if( FS_FileExists( "cached/conback", false )) else if( FS_FileExists( "cached/conback", false ))
con.background = ref.dllFuncs.GL_LoadTexture( "cached/conback", NULL, 0, TF_IMAGE ); con.background = ref.dllFuncs.GL_LoadTexture( "cached/conback", NULL, 0, flags );
} }
} }
else else
{ {
// trying to load truecolor image first // trying to load truecolor image first
if( FS_FileExists( "gfx/shell/loading.bmp", false ) || FS_FileExists( "gfx/shell/loading.tga", false )) if( FS_FileExists( "gfx/shell/loading.bmp", false ) || FS_FileExists( "gfx/shell/loading.tga", false ))
con.background = ref.dllFuncs.GL_LoadTexture( "gfx/shell/loading", NULL, 0, TF_IMAGE ); con.background = ref.dllFuncs.GL_LoadTexture( "gfx/shell/loading", NULL, 0, flags );
if( !con.background ) if( !con.background )
{ {
if( FS_FileExists( "cached/loading640", false )) if( FS_FileExists( "cached/loading640", false ))
con.background = ref.dllFuncs.GL_LoadTexture( "cached/loading640", NULL, 0, TF_IMAGE ); con.background = ref.dllFuncs.GL_LoadTexture( "cached/loading640", NULL, 0, flags );
else if( FS_FileExists( "cached/loading", false )) else if( FS_FileExists( "cached/loading", false ))
con.background = ref.dllFuncs.GL_LoadTexture( "cached/loading", NULL, 0, TF_IMAGE ); con.background = ref.dllFuncs.GL_LoadTexture( "cached/loading", NULL, 0, flags );
} }
} }

View File

@@ -21,6 +21,7 @@ GNU General Public License for more details.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Gamma conversion support // Gamma conversion support
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static qboolean gamma_rebuilt;
static byte texgammatable[256]; static byte texgammatable[256];
static uint lightgammatable[1024]; static uint lightgammatable[1024];
static uint lineargammatable[1024]; static uint lineargammatable[1024];
@@ -82,9 +83,6 @@ static void BuildGammaTable( const float gamma, const float brightness, const fl
static void V_ValidateGammaCvars( void ) static void V_ValidateGammaCvars( void )
{ {
if( Host_IsLocalGame( ))
return;
if( v_gamma.value < 1.8f ) if( v_gamma.value < 1.8f )
Cvar_DirectSet( &v_gamma, "1.8" ); Cvar_DirectSet( &v_gamma, "1.8" );
else if( v_gamma.value > 3.0f ) else if( v_gamma.value > 3.0f )
@@ -102,14 +100,13 @@ static void V_ValidateGammaCvars( void )
if( v_brightness.value < 0.0f ) if( v_brightness.value < 0.0f )
Cvar_DirectSet( &v_brightness, "0" ); Cvar_DirectSet( &v_brightness, "0" );
else if( v_brightness.value > 2.0f ) else if( v_brightness.value > 3.0f )
Cvar_DirectSet( &v_brightness, "2" ); Cvar_DirectSet( &v_brightness, "3" );
} }
void V_CheckGamma( void ) void V_CheckGamma( void )
{ {
static qboolean dirty = false; static qboolean dirty = false;
qboolean notify_refdll = false;
// because these cvars were defined as archive // because these cvars were defined as archive
// but wasn't doing anything useful // but wasn't doing anything useful
@@ -135,20 +132,33 @@ void V_CheckGamma( void )
V_ValidateGammaCvars(); V_ValidateGammaCvars();
dirty = false; dirty = false;
gamma_rebuilt = true;
BuildGammaTable( v_gamma.value, v_brightness.value, v_texgamma.value, v_lightgamma.value ); BuildGammaTable( v_gamma.value, v_brightness.value, v_texgamma.value, v_lightgamma.value );
// force refdll to recalculate lightmaps // force refdll to recalculate lightmaps
notify_refdll = true; if( ref.initialized )
ref.dllFuncs.R_GammaChanged( false );
}
}
// unfortunately, recalculating textures isn't possible yet void V_CheckGammaEnd( void )
{
// don't reset changed flag if it was set during frame
// keep it for next frame
if( !gamma_rebuilt )
return;
gamma_rebuilt = false;
// keep the flags until the end of frame so client.dll will catch these changes
if( FBitSet( v_texgamma.flags|v_lightgamma.flags|v_brightness.flags|v_gamma.flags, FCVAR_CHANGED ))
{
ClearBits( v_texgamma.flags, FCVAR_CHANGED ); ClearBits( v_texgamma.flags, FCVAR_CHANGED );
ClearBits( v_lightgamma.flags, FCVAR_CHANGED ); ClearBits( v_lightgamma.flags, FCVAR_CHANGED );
ClearBits( v_brightness.flags, FCVAR_CHANGED ); ClearBits( v_brightness.flags, FCVAR_CHANGED );
ClearBits( v_gamma.flags, FCVAR_CHANGED ); ClearBits( v_gamma.flags, FCVAR_CHANGED );
} }
if( notify_refdll && ref.initialized )
ref.dllFuncs.R_GammaChanged( false );
} }
void V_Init( void ) void V_Init( void )

View File

@@ -2029,10 +2029,18 @@ int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx
{ {
touch.move_finger = touch.resize_finger = touch.look_finger = -1; touch.move_finger = touch.resize_finger = touch.look_finger = -1;
// Hack for keyboard, hope it help // Hack for keyboard, hope it help
// a1ba: this is absolutely horrible
if( cls.key_dest == key_console || cls.key_dest == key_message ) if( cls.key_dest == key_console || cls.key_dest == key_message )
{ {
if ( type == event_down ) // don't pop it again on event_up static float x1 = 0.0f;
x1 += dx;
if( type == event_up ) // don't show keyboard on every tap
{
Key_EnableTextInput( true, true ); Key_EnableTextInput( true, true );
x1 = 0.0f;
}
if( cls.key_dest == key_console ) if( cls.key_dest == key_console )
{ {
static float y1 = 0; static float y1 = 0;
@@ -2054,6 +2062,13 @@ int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx
// exit of console area // exit of console area
if( type == event_down && x < 0.1f && y > 0.9f ) if( type == event_down && x < 0.1f && y > 0.9f )
Cbuf_AddText( "escape\n" ); Cbuf_AddText( "escape\n" );
// swipe from edge to exit console/chat
if(( x > 0.8f && x1 < -0.1f ) || ( x < 0.2f && x1 > 0.1f ))
{
Cbuf_AddText( "escape\n" );
x1 = 0.0f;
}
} }
UI_MouseMove( TO_SCRN_X(x), TO_SCRN_Y(y) ); UI_MouseMove( TO_SCRN_X(x), TO_SCRN_Y(y) );
//MsgDev( D_NOTE, "touch %d %d\n", TO_SCRN_X(x), TO_SCRN_Y(y) ); //MsgDev( D_NOTE, "touch %d %d\n", TO_SCRN_X(x), TO_SCRN_Y(y) );

View File

@@ -565,7 +565,7 @@ static void R_CollectRendererNames( void )
"GL4ES", "GL4ES",
#endif #endif
#if XASH_REF_GLES3COMPAT_ENABLED #if XASH_REF_GLES3COMPAT_ENABLED
"GLES3 (gl2_shim)" "GLES3 (gl2_shim)",
#endif #endif
#if XASH_REF_SOFT_ENABLED #if XASH_REF_SOFT_ENABLED
"Software", "Software",
@@ -611,6 +611,7 @@ qboolean R_Init( void )
// cvars that are expected to exist by client.dll // cvars that are expected to exist by client.dll
// refdll should just get pointer to them // refdll should just get pointer to them
Cvar_Get( "r_lighting_modulate", "0.6", FCVAR_ARCHIVE, "compatibility cvar, does nothing" );
Cvar_Get( "r_drawentities", "1", FCVAR_CHEAT, "render entities" ); Cvar_Get( "r_drawentities", "1", FCVAR_CHEAT, "render entities" );
Cvar_Get( "cl_himodels", "1", FCVAR_ARCHIVE, "draw high-resolution player models in multiplayer" ); Cvar_Get( "cl_himodels", "1", FCVAR_ARCHIVE, "draw high-resolution player models in multiplayer" );

View File

@@ -43,7 +43,7 @@ CVAR_DEFINE_AUTO( s_lerping, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "apply interpo
static CVAR_DEFINE( s_ambient_level, "ambient_level", "0.3", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "volume of environment noises (water and wind)" ); static CVAR_DEFINE( s_ambient_level, "ambient_level", "0.3", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "volume of environment noises (water and wind)" );
static CVAR_DEFINE( s_ambient_fade, "ambient_fade", "1000", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "rate of volume fading when client is moving" ); static CVAR_DEFINE( s_ambient_fade, "ambient_fade", "1000", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "rate of volume fading when client is moving" );
static CVAR_DEFINE_AUTO( s_combine_sounds, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "combine channels with same sounds" ); static CVAR_DEFINE_AUTO( s_combine_sounds, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "combine channels with same sounds" );
CVAR_DEFINE_AUTO( snd_mute_losefocus, "1", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "silence the audio when game window loses focus" ); static CVAR_DEFINE_AUTO( snd_mute_losefocus, "1", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "silence the audio when game window loses focus" );
CVAR_DEFINE_AUTO( s_test, "0", 0, "engine developer cvar for quick testing new features" ); CVAR_DEFINE_AUTO( s_test, "0", 0, "engine developer cvar for quick testing new features" );
CVAR_DEFINE_AUTO( s_samplecount, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "sample count (0 for default value)" ); CVAR_DEFINE_AUTO( s_samplecount, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "sample count (0 for default value)" );
CVAR_DEFINE_AUTO( s_warn_late_precache, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "warn about late precached sounds on client-side" ); CVAR_DEFINE_AUTO( s_warn_late_precache, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "warn about late precached sounds on client-side" );
@@ -64,6 +64,12 @@ float S_GetMasterVolume( void )
{ {
float scale = 1.0f; float scale = 1.0f;
if( host.status == HOST_NOFOCUS && snd_mute_losefocus.value != 0.0f )
{
// we return zero volume to keep sounds running
return 0.0f;
}
if( !s_listener.inmenu && soundfade.percent != 0 ) if( !s_listener.inmenu && soundfade.percent != 0 )
{ {
scale = bound( 0.0f, soundfade.percent / 100.0f, 1.0f ); scale = bound( 0.0f, soundfade.percent / 100.0f, 1.0f );

View File

@@ -221,7 +221,6 @@ extern convar_t s_musicvolume;
extern convar_t s_lerping; extern convar_t s_lerping;
extern convar_t s_test; // cvar to testify new effects extern convar_t s_test; // cvar to testify new effects
extern convar_t s_samplecount; extern convar_t s_samplecount;
extern convar_t snd_mute_losefocus;
extern convar_t s_warn_late_precache; extern convar_t s_warn_late_precache;
void S_InitScaletable( void ); void S_InitScaletable( void );

View File

@@ -20,8 +20,6 @@ GNU General Public License for more details.
#include "vid_common.h" #include "vid_common.h"
#include "platform/platform.h" #include "platform/platform.h"
static CVAR_DEFINE( window_width, "width", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen width" );
static CVAR_DEFINE( window_height, "height", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen height" );
static CVAR_DEFINE_AUTO( vid_mode, "0", FCVAR_RENDERINFO, "current video mode index (used only for storage)" ); static CVAR_DEFINE_AUTO( vid_mode, "0", FCVAR_RENDERINFO, "current video mode index (used only for storage)" );
static CVAR_DEFINE_AUTO( vid_rotate, "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen rotation (0-3)" ); static CVAR_DEFINE_AUTO( vid_rotate, "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen rotation (0-3)" );
static CVAR_DEFINE_AUTO( vid_scale, "1.0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "pixel scale" ); static CVAR_DEFINE_AUTO( vid_scale, "1.0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "pixel scale" );
@@ -29,6 +27,8 @@ static CVAR_DEFINE_AUTO( vid_scale, "1.0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "p
CVAR_DEFINE_AUTO( vid_highdpi, "1", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "enable High-DPI mode" ); CVAR_DEFINE_AUTO( vid_highdpi, "1", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "enable High-DPI mode" );
CVAR_DEFINE_AUTO( vid_maximized, "0", FCVAR_RENDERINFO, "window maximized state, read-only" ); CVAR_DEFINE_AUTO( vid_maximized, "0", FCVAR_RENDERINFO, "window maximized state, read-only" );
CVAR_DEFINE( vid_fullscreen, "fullscreen", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "fullscreen state (0 windowed, 1 fullscreen, 2 borderless)" ); CVAR_DEFINE( vid_fullscreen, "fullscreen", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "fullscreen state (0 windowed, 1 fullscreen, 2 borderless)" );
CVAR_DEFINE( window_width, "width", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen width" );
CVAR_DEFINE( window_height, "height", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen height" );
CVAR_DEFINE( window_xpos, "_window_xpos", "-1", FCVAR_RENDERINFO, "window position by horizontal" ); CVAR_DEFINE( window_xpos, "_window_xpos", "-1", FCVAR_RENDERINFO, "window position by horizontal" );
CVAR_DEFINE( window_ypos, "_window_ypos", "-1", FCVAR_RENDERINFO, "window position by vertical" ); CVAR_DEFINE( window_ypos, "_window_ypos", "-1", FCVAR_RENDERINFO, "window position by vertical" );

View File

@@ -38,6 +38,8 @@ extern glwstate_t glw_state;
extern convar_t vid_fullscreen; extern convar_t vid_fullscreen;
extern convar_t vid_maximized; extern convar_t vid_maximized;
extern convar_t vid_highdpi; extern convar_t vid_highdpi;
extern convar_t window_width;
extern convar_t window_height;
extern convar_t window_xpos; extern convar_t window_xpos;
extern convar_t window_ypos; extern convar_t window_ypos;
extern convar_t gl_msaa_samples; extern convar_t gl_msaa_samples;

View File

@@ -25,11 +25,12 @@ voice_state_t voice = { 0 };
CVAR_DEFINE_AUTO( voice_enable, "1", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "enable voice chat" ); CVAR_DEFINE_AUTO( voice_enable, "1", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "enable voice chat" );
CVAR_DEFINE_AUTO( voice_loopback, "0", FCVAR_PRIVILEGED, "loopback voice back to the speaker" ); CVAR_DEFINE_AUTO( voice_loopback, "0", FCVAR_PRIVILEGED, "loopback voice back to the speaker" );
CVAR_DEFINE_AUTO( voice_scale, "1.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "incoming voice volume scale" ); CVAR_DEFINE_AUTO( voice_scale, "1.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "incoming voice volume scale" );
CVAR_DEFINE_AUTO( voice_transmit_scale, "1.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "outcoming voice volume scale" );
CVAR_DEFINE_AUTO( voice_avggain, "0.5", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "automatic voice gain control (average)" ); CVAR_DEFINE_AUTO( voice_avggain, "0.5", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "automatic voice gain control (average)" );
CVAR_DEFINE_AUTO( voice_maxgain, "5.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "automatic voice gain control (maximum)" ); CVAR_DEFINE_AUTO( voice_maxgain, "5.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "automatic voice gain control (maximum)" );
CVAR_DEFINE_AUTO( voice_inputfromfile, "0", FCVAR_PRIVILEGED, "input voice from voice_input.wav" ); CVAR_DEFINE_AUTO( voice_inputfromfile, "0", FCVAR_PRIVILEGED, "input voice from voice_input.wav" );
static void Voice_ApplyGainAdjust( int16_t *samples, int count ); static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale );
/* /*
=============================================================================== ===============================================================================
@@ -39,6 +40,25 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count );
=============================================================================== ===============================================================================
*/ */
static qboolean Voice_InitCustomMode( void )
{
int err = 0;
voice.width = sizeof( opus_int16 );
voice.samplerate = VOICE_OPUS_CUSTOM_SAMPLERATE;
voice.frame_size = VOICE_OPUS_CUSTOM_FRAME_SIZE;
voice.custom_mode = opus_custom_mode_create( SOUND_44k, voice.frame_size, &err );
if( !voice.custom_mode )
{
Con_Printf( S_ERROR "Can't create Opus Custom mode: %s\n", opus_strerror( err ));
return false;
}
return true;
}
/* /*
========================= =========================
Voice_InitOpusDecoder Voice_InitOpusDecoder
@@ -47,24 +67,17 @@ Voice_InitOpusDecoder
*/ */
static qboolean Voice_InitOpusDecoder( void ) static qboolean Voice_InitOpusDecoder( void )
{ {
int err; int err = 0;
voice.width = sizeof( opus_int16 ); for( int i = 0; i < cl.maxclients; i++ )
voice.samplerate = VOICE_OPUS_CUSTOM_SAMPLERATE;
voice.frame_size = VOICE_OPUS_CUSTOM_FRAME_SIZE;
voice.custom_mode = opus_custom_mode_create( SOUND_44k, voice.frame_size, &err );
if( !voice.custom_mode )
{ {
Con_Printf( S_ERROR "Can't create Opus Custom mode: %s\n", opus_strerror( err )); voice.decoders[i] = opus_custom_decoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
return false;
}
voice.decoder = opus_custom_decoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err ); if( !voice.decoders[i] )
if( !voice.decoder ) {
{ Con_Printf( S_ERROR "Can't create Opus decoder for %i: %s\n", i, opus_strerror( err ));
Con_Printf( S_ERROR "Can't create Opus encoder: %s\n", opus_strerror( err )); return false;
return false; }
} }
return true; return true;
@@ -78,7 +91,7 @@ Voice_InitOpusEncoder
*/ */
static qboolean Voice_InitOpusEncoder( int quality ) static qboolean Voice_InitOpusEncoder( int quality )
{ {
int err; int err = 0;
voice.encoder = opus_custom_encoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err ); voice.encoder = opus_custom_encoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
if( !voice.encoder ) if( !voice.encoder )
@@ -117,10 +130,13 @@ Voice_ShutdownOpusDecoder
*/ */
static void Voice_ShutdownOpusDecoder( void ) static void Voice_ShutdownOpusDecoder( void )
{ {
if( voice.decoder ) for( int i = 0; i < MAX_CLIENTS; i++ )
{ {
opus_custom_decoder_destroy( voice.decoder ); if( !voice.decoders[i] )
voice.decoder = NULL; continue;
opus_custom_decoder_destroy( voice.decoders[i] );
voice.decoders[i] = NULL;
} }
} }
@@ -137,7 +153,10 @@ static void Voice_ShutdownOpusEncoder( void )
opus_custom_encoder_destroy( voice.encoder ); opus_custom_encoder_destroy( voice.encoder );
voice.encoder = NULL; voice.encoder = NULL;
} }
}
static void Voice_ShutdownCustomMode( void )
{
if( voice.custom_mode ) if( voice.custom_mode )
{ {
opus_custom_mode_destroy( voice.custom_mode ); opus_custom_mode_destroy( voice.custom_mode );
@@ -184,7 +203,7 @@ static uint Voice_GetOpusCompressedData( byte *out, uint maxsize, uint *frames )
if( !voice.input_file ) if( !voice.input_file )
{ {
// adjust gain before encoding, but only for input from voice // adjust gain before encoding, but only for input from voice
Voice_ApplyGainAdjust((opus_int16*)(voice.input_buffer + ofs), voice.frame_size); Voice_ApplyGainAdjust((opus_int16*)(voice.input_buffer + ofs), voice.frame_size, voice_transmit_scale.value);
} }
#endif #endif
@@ -238,10 +257,10 @@ Voice_ApplyGainAdjust
========================= =========================
*/ */
static void Voice_ApplyGainAdjust( int16_t *samples, int count ) static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale )
{ {
float gain, modifiedMax; float gain, modifiedMax;
int average, adjustedSample, blockOffset = 0; int average, blockOffset = 0;
for( ;; ) for( ;; )
{ {
@@ -260,10 +279,8 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count )
localMax = absSample; localMax = absSample;
localSum += absSample; localSum += absSample;
gain = voice.autogain.current_gain + i * voice.autogain.gain_multiplier; gain = voice.autogain.current_gain + i * voice.autogain.gain_multiplier;
adjustedSample = Q_min( SHRT_MAX, Q_max(( int )( sample * gain ), SHRT_MIN )); samples[blockOffset + i] = bound( SHRT_MIN, (int)( sample * gain ), SHRT_MAX );
samples[blockOffset + i] = adjustedSample;
} }
if( blockOffset % voice.autogain.block_size == 0 ) if( blockOffset % voice.autogain.block_size == 0 )
@@ -271,9 +288,9 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count )
average = localSum / blockSize; average = localSum / blockSize;
modifiedMax = average + ( localMax - average ) * voice_avggain.value; modifiedMax = average + ( localMax - average ) * voice_avggain.value;
voice.autogain.current_gain = voice.autogain.next_gain * voice_scale.value; voice.autogain.current_gain = voice.autogain.next_gain * scale;
voice.autogain.next_gain = Q_min( (float)SHRT_MAX / modifiedMax, voice_maxgain.value ) * voice_scale.value; voice.autogain.next_gain = Q_min( (float)SHRT_MAX / modifiedMax, voice_maxgain.value ) * scale;
voice.autogain.gain_multiplier = ( voice.autogain.next_gain - voice.autogain.current_gain ) / ( voice.autogain.block_size - 1 ); voice.autogain.gain_multiplier = ( voice.autogain.next_gain - voice.autogain.current_gain ) / ( blockSize - 1 );
} }
blockOffset += blockSize; blockOffset += blockSize;
} }
@@ -443,7 +460,7 @@ Feed the decoded data to engine sound subsystem
static void Voice_StartChannel( uint samples, byte *data, int entnum ) static void Voice_StartChannel( uint samples, byte *data, int entnum )
{ {
SND_ForceInitMouth( entnum ); SND_ForceInitMouth( entnum );
S_RawEntSamples( entnum, samples, voice.samplerate, voice.width, VOICE_PCM_CHANNELS, data, 255 ); S_RawEntSamples( entnum, samples, voice.samplerate, voice.width, VOICE_PCM_CHANNELS, data, bound( 0, 255 * voice_scale.value, 255 ));
} }
/* /*
@@ -455,10 +472,11 @@ Received encoded voice data, decode it
*/ */
void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames ) void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames )
{ {
const int playernum = ent - 1;
int samples = 0; int samples = 0;
int ofs = 0; int ofs = 0;
if( !voice.decoder ) if( playernum < 0 || playernum >= cl.maxclients || !voice.decoders[playernum] )
return; return;
// decode frame by frame // decode frame by frame
@@ -478,7 +496,7 @@ void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames )
if( ofs + compressed_size > size ) if( ofs + compressed_size > size )
break; break;
frame_samples = opus_custom_decode( voice.decoder, data + ofs, compressed_size, frame_samples = opus_custom_decode( voice.decoders[playernum], data + ofs, compressed_size,
(opus_int16*)voice.decompress_buffer + samples, voice.frame_size ); (opus_int16*)voice.decompress_buffer + samples, voice.frame_size );
ofs += compressed_size; ofs += compressed_size;
@@ -502,8 +520,8 @@ void CL_AddVoiceToDatagram( void )
if( cls.state != ca_active || !Voice_IsRecording() || !voice.encoder ) if( cls.state != ca_active || !Voice_IsRecording() || !voice.encoder )
return; return;
size = Voice_GetOpusCompressedData( voice.output_buffer, sizeof( voice.output_buffer ), &frames ); size = Voice_GetOpusCompressedData( voice.compress_buffer, sizeof( voice.compress_buffer ), &frames );
if( size > 0 && MSG_GetNumBytesLeft( &cls.datagram ) >= size + 32 ) if( size > 0 && MSG_GetNumBytesLeft( &cls.datagram ) >= size + 32 )
{ {
@@ -511,7 +529,7 @@ void CL_AddVoiceToDatagram( void )
MSG_WriteByte( &cls.datagram, voice_loopback.value != 0 ); MSG_WriteByte( &cls.datagram, voice_loopback.value != 0 );
MSG_WriteByte( &cls.datagram, frames ); MSG_WriteByte( &cls.datagram, frames );
MSG_WriteShort( &cls.datagram, size ); MSG_WriteShort( &cls.datagram, size );
MSG_WriteBytes( &cls.datagram, voice.output_buffer, size ); MSG_WriteBytes( &cls.datagram, voice.compress_buffer, size );
} }
} }
@@ -527,6 +545,7 @@ void Voice_RegisterCvars( void )
Cvar_RegisterVariable( &voice_enable ); Cvar_RegisterVariable( &voice_enable );
Cvar_RegisterVariable( &voice_loopback ); Cvar_RegisterVariable( &voice_loopback );
Cvar_RegisterVariable( &voice_scale ); Cvar_RegisterVariable( &voice_scale );
Cvar_RegisterVariable( &voice_transmit_scale );
Cvar_RegisterVariable( &voice_avggain ); Cvar_RegisterVariable( &voice_avggain );
Cvar_RegisterVariable( &voice_maxgain ); Cvar_RegisterVariable( &voice_maxgain );
Cvar_RegisterVariable( &voice_inputfromfile ); Cvar_RegisterVariable( &voice_inputfromfile );
@@ -544,8 +563,9 @@ static void Voice_Shutdown( void )
int i; int i;
Voice_RecordStop(); Voice_RecordStop();
Voice_ShutdownOpusEncoder();
Voice_ShutdownOpusDecoder(); Voice_ShutdownOpusDecoder();
Voice_ShutdownOpusEncoder();
Voice_ShutdownCustomMode();
VoiceCapture_Shutdown(); VoiceCapture_Shutdown();
if( voice.local.talking_ack ) if( voice.local.talking_ack )
@@ -609,11 +629,10 @@ qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit )
voice.autogain.block_size = 128; voice.autogain.block_size = 128;
if( !Voice_InitOpusDecoder( )) if( !Voice_InitCustomMode( ))
{ {
// no reason to init encoder and open audio device // no reason to init encoder and open audio device
// if we can't hear other players // if we can't hear other players
Con_Printf( S_ERROR "Voice chat disabled.\n" );
Voice_Shutdown(); Voice_Shutdown();
return false; return false;
} }
@@ -633,6 +652,16 @@ qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit )
if( !preinit ) if( !preinit )
{ {
Voice_ShutdownOpusDecoder();
if( !Voice_InitOpusDecoder())
{
// no reason to init encoder and open audio device
// if we can't hear other players
Con_Printf( S_ERROR "Can't create decoders, voice chat is disabled.\n" );
Voice_Shutdown();
return false;
}
voice.device_opened = VoiceCapture_Init(); voice.device_opened = VoiceCapture_Init();
if( !voice.device_opened ) if( !voice.device_opened )

View File

@@ -62,7 +62,7 @@ typedef struct voice_state_s
// opus stuff // opus stuff
OpusCustomMode *custom_mode; OpusCustomMode *custom_mode;
OpusCustomEncoder *encoder; OpusCustomEncoder *encoder;
OpusCustomDecoder *decoder; OpusCustomDecoder *decoders[MAX_CLIENTS];
// audio info // audio info
uint width; uint width;
@@ -71,7 +71,7 @@ typedef struct voice_state_s
// buffers // buffers
byte input_buffer[MAX_RAW_SAMPLES]; byte input_buffer[MAX_RAW_SAMPLES];
byte output_buffer[MAX_RAW_SAMPLES]; byte compress_buffer[MAX_RAW_SAMPLES];
byte decompress_buffer[MAX_RAW_SAMPLES]; byte decompress_buffer[MAX_RAW_SAMPLES];
fs_offset_t input_buffer_pos; // in bytes fs_offset_t input_buffer_pos; // in bytes

View File

@@ -529,7 +529,6 @@ typedef struct cmd_s
static int cmd_argc; static int cmd_argc;
static const char *cmd_args = NULL; static const char *cmd_args = NULL;
static char *cmd_argv[MAX_CMD_TOKENS]; static char *cmd_argv[MAX_CMD_TOKENS];
static char cmd_tokenized[MAX_CMD_BUFFER]; // will have 0 bytes inserted
static cmd_t *cmd_functions; // possible commands to execute static cmd_t *cmd_functions; // possible commands to execute
/* /*
@@ -950,7 +949,7 @@ static void Cmd_Else_f( void )
static qboolean Cmd_ShouldAllowCommand( cmd_t *cmd, qboolean isPrivileged ) static qboolean Cmd_ShouldAllowCommand( cmd_t *cmd, qboolean isPrivileged )
{ {
const char *prefixes[] = { "cl_", "gl_", "r_", "m_", "hud_" }; const char *prefixes[] = { "cl_", "gl_", "r_", "m_", "hud_", "joy_" };
int i; int i;
// always allow local commands // always allow local commands

View File

@@ -17,15 +17,24 @@ GNU General Public License for more details.
#define COM_STRINGS_H #define COM_STRINGS_H
// default colored message headers // default colored message headers
#define S_NOTE "^2Note:^7 " #define S_BLACK "^0"
#define S_WARN "^3Warning:^7 " #define S_RED "^1"
#define S_ERROR "^1Error:^7 " #define S_GREEN "^2"
#define S_USAGE "Usage: " #define S_YELLOW "^3"
#define S_USAGE_INDENT " " #define S_BLUE "^4"
#define S_CYAN "^5"
#define S_MAGENTA "^6"
#define S_DEFAULT "^7"
#define S_OPENGL_NOTE "^2OpenGL Note:^7 " #define S_NOTE S_GREEN "Note: " S_DEFAULT
#define S_OPENGL_WARN "^3OpenGL Warning:^7 " #define S_WARN S_YELLOW "Warning: " S_DEFAULT
#define S_OPENGL_ERROR "^3OpenGL Error:^7 " #define S_ERROR S_RED "Error: " S_DEFAULT
#define S_USAGE "Usage: "
#define S_USAGE_INDENT "\t"
#define S_OPENGL_NOTE S_GREEN "OpenGL Note: " S_DEFAULT
#define S_OPENGL_WARN S_YELLOW "OpenGL Warning: " S_DEFAULT
#define S_OPENGL_ERROR S_RED "OpenGL Error: " S_DEFAULT
// end game final default message // end game final default message
#define DEFAULT_ENDGAME_MESSAGE "The End" #define DEFAULT_ENDGAME_MESSAGE "The End"
@@ -65,6 +74,7 @@ GNU General Public License for more details.
#define DEFAULT_UPDATE_PAGE "https://github.com/FWGS/xash3d-fwgs/releases/latest" #define DEFAULT_UPDATE_PAGE "https://github.com/FWGS/xash3d-fwgs/releases/latest"
#define XASH_ENGINE_NAME "Xash3D FWGS" #define XASH_ENGINE_NAME "Xash3D FWGS"
#define XASH_DEDICATED_SERVER_NAME "XashDS"
#define XASH_VERSION "0.20" // engine current version #define XASH_VERSION "0.20" // engine current version
#define XASH_COMPAT_VERSION "0.99" // version we are based on #define XASH_COMPAT_VERSION "0.99" // version we are based on

View File

@@ -390,6 +390,9 @@ byte *LZSS_Compress( byte *pInput, int inputLength, uint *pOutputSize )
byte *pFinal = NULL; byte *pFinal = NULL;
lzss_state_t state; lzss_state_t state;
if( !pStart )
return NULL;
memset( &state, 0, sizeof( state )); memset( &state, 0, sizeof( state ));
state.window_size = LZSS_WINDOW_SIZE; state.window_size = LZSS_WINDOW_SIZE;
@@ -693,7 +696,7 @@ COM_LoadFileForMe
byte *GAME_EXPORT COM_LoadFileForMe( const char *filename, int *pLength ) byte *GAME_EXPORT COM_LoadFileForMe( const char *filename, int *pLength )
{ {
string name; string name;
byte *file, *pfile; byte *pfile;
fs_offset_t iLength; fs_offset_t iLength;
if( !COM_CheckString( filename )) if( !COM_CheckString( filename ))
@@ -706,21 +709,9 @@ byte *GAME_EXPORT COM_LoadFileForMe( const char *filename, int *pLength )
Q_strncpy( name, filename, sizeof( name )); Q_strncpy( name, filename, sizeof( name ));
COM_FixSlashes( name ); COM_FixSlashes( name );
pfile = FS_LoadFile( name, &iLength, false ); pfile = g_fsapi.LoadFileMalloc( name, &iLength, false );
if( pLength ) *pLength = (int)iLength; if( pLength ) *pLength = (int)iLength;
if( pfile )
{
file = malloc( iLength + 1 );
if( file != NULL )
{
memcpy( file, pfile, iLength );
file[iLength] = '\0';
}
Mem_Free( pfile );
pfile = file;
}
return pfile; return pfile;
} }

View File

@@ -273,12 +273,8 @@ typedef struct
typedef enum bugcomp_e typedef enum bugcomp_e
{ {
// default mode, we assume that user dlls are not relying on engine bugs // reverts fix for pfnPEntityOfEntIndex for bug compatibility with GoldSrc
BUGCOMP_OFF, BUGCOMP_PENTITYOFENTINDEX_FLAG = BIT( 0 ),
// GoldSrc mode, user dlls are relying on GoldSrc specific bugs
// but fixing them may break regular Xash games
BUGCOMP_GOLDSRC,
} bugcomp_t; } bugcomp_t;
typedef struct host_parm_s typedef struct host_parm_s
@@ -356,7 +352,7 @@ typedef struct host_parm_s
int numdecals; int numdecals;
// bug compatibility level, for very "special" games // bug compatibility level, for very "special" games
bugcomp_t bugcomp; uint32_t bugcomp;
// measure time to first frame // measure time to first frame
double starttime; double starttime;
@@ -795,6 +791,7 @@ uint ScreenGammaTable( uint );
uint LinearGammaTable( uint ); uint LinearGammaTable( uint );
void V_Init( void ); void V_Init( void );
void V_CheckGamma( void ); void V_CheckGamma( void );
void V_CheckGammaEnd( void );
// //
// identification.c // identification.c
@@ -815,6 +812,34 @@ void NET_MasterClear( void );
void NET_MasterShutdown( void ); void NET_MasterShutdown( void );
qboolean NET_GetMaster( netadr_t from, uint *challenge, double *last_heartbeat ); qboolean NET_GetMaster( netadr_t from, uint *challenge, double *last_heartbeat );
//
// sounds.c
//
typedef enum soundlst_group_e
{
BouncePlayerShell = 0,
BounceWeaponShell,
BounceConcrete,
BounceGlass,
BounceMetal,
BounceFlesh,
BounceWood,
Ricochet,
Explode,
PlayerWaterEnter,
PlayerWaterExit,
EntityWaterEnter,
EntityWaterExit,
SoundList_Groups // must be last
} soundlst_group_t;
int SoundList_Count( soundlst_group_t group );
const char *SoundList_GetRandom( soundlst_group_t group );
const char *SoundList_Get( soundlst_group_t group, int idx );
void SoundList_Init( void );
void SoundList_Shutdown( void );
#ifdef REF_DLL #ifdef REF_DLL
#error "common.h in ref_dll" #error "common.h in ref_dll"
#endif #endif

View File

@@ -866,7 +866,7 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
return true; // exist return true; // exist
// setup mpfilter // setup mpfilter
size = Q_snprintf( mpfilter, sizeof( mpfilter ), "maps/%s", GI->mp_filter ); Q_snprintf( mpfilter, sizeof( mpfilter ), "maps/%s", GI->mp_filter );
t = FS_Search( "maps/*.bsp", false, onlyingamedir ); t = FS_Search( "maps/*.bsp", false, onlyingamedir );
if( !t ) if( !t )
@@ -900,9 +900,9 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
if( f ) if( f )
{ {
int num_spawnpoints = 0; qboolean have_spawnpoints = false;
dheader_t *header; dheader_t *header;
dlump_t entities; dlump_t entities;
memset( buf, 0, MAX_SYSPATH ); memset( buf, 0, MAX_SYSPATH );
FS_Read( f, buf, MAX_SYSPATH ); FS_Read( f, buf, MAX_SYSPATH );
@@ -943,7 +943,18 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL ) while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
{ {
if( token[0] == '}' && worldspawn ) if( token[0] == '}' && worldspawn )
{
worldspawn = false; worldspawn = false;
// if mod has mp_filter set up, then it's a mod that
// might not have valid mp_entity set in GI
// if mod is multiplayer only, assume all maps are valid
if( use_filter || GI->gamemode == GAME_MULTIPLAYER_ONLY )
{
have_spawnpoints = true;
break;
}
}
else if( !Q_strcmp( token, "message" ) && worldspawn ) else if( !Q_strcmp( token, "message" ) && worldspawn )
{ {
// get the message contents // get the message contents
@@ -952,17 +963,23 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
else if( !Q_strcmp( token, "classname" )) else if( !Q_strcmp( token, "classname" ))
{ {
pfile = COM_ParseFile( pfile, token, sizeof( token )); pfile = COM_ParseFile( pfile, token, sizeof( token ));
if( !Q_strcmp( token, GI->mp_entity ) || use_filter )
num_spawnpoints++; if( !Q_strcmp( token, GI->mp_entity ))
{
have_spawnpoints = true;
break;
}
} }
if( num_spawnpoints ) break; // valid map
if( have_spawnpoints )
break; // valid map
} }
Mem_Free( ents ); Mem_Free( ents );
} }
if( f ) FS_Close( f ); if( f ) FS_Close( f );
if( num_spawnpoints ) if( have_spawnpoints )
{ {
// format: mapname "maptitle"\n // format: mapname "maptitle"\n
Q_snprintf( result, sizeof( result ), "%s \"%s\"\n", mapname, message ); Q_snprintf( result, sizeof( result ), "%s \"%s\"\n", mapname, message );

View File

@@ -490,13 +490,14 @@ static void Sys_Crash( int signal, siginfo_t *si, void *context)
#ifdef XASH_SDL #ifdef XASH_SDL
SDL_SetWindowGrab( host.hWnd, SDL_FALSE ); SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
#endif #endif
host.crashed = true;
Platform_MessageBox( "Xash Error", message, false ); Platform_MessageBox( "Xash Error", message, false );
// log saved, now we can try to save configs and close log correctly, it may crash // log saved, now we can try to save configs and close log correctly, it may crash
if( host.type == HOST_NORMAL ) if( host.type == HOST_NORMAL )
CL_Crashed(); CL_Crashed();
host.status = HOST_CRASHED; host.status = HOST_CRASHED;
host.crashed = true;
Sys_Quit(); Sys_Quit();
} }

View File

@@ -152,8 +152,10 @@ static qboolean Cvar_UpdateInfo( convar_t *var, const char *value, qboolean noti
if ( Host_IsDedicated() ) if ( Host_IsDedicated() )
{ {
// g-cont. this is a very strange behavior... // g-cont. this is a very strange behavior...
Info_SetValueForKey( SV_Serverinfo(), var->name, value, MAX_SERVERINFO_STRING ), char *info = SV_Serverinfo();
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", SV_Serverinfo( ));
Info_SetValueForKey( info, var->name, value, MAX_SERVERINFO_STRING ),
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", info );
} }
#if !XASH_DEDICATED #if !XASH_DEDICATED
else else
@@ -953,7 +955,7 @@ static void Cvar_SetGL( const char *name, const char *value )
static qboolean Cvar_ShouldSetCvar( convar_t *v, qboolean isPrivileged ) static qboolean Cvar_ShouldSetCvar( convar_t *v, qboolean isPrivileged )
{ {
const char *prefixes[] = { "cl_", "gl_", "m_", "r_", "hud_" }; const char *prefixes[] = { "cl_", "gl_", "m_", "r_", "hud_", "joy_" };
int i; int i;
if( isPrivileged ) if( isPrivileged )

View File

@@ -65,6 +65,32 @@ static CVAR_DEFINE( host_sleeptime, "sleeptime", "1", FCVAR_ARCHIVE|FCVAR_FILTER
static CVAR_DEFINE_AUTO( host_sleeptime_debug, "0", 0, "print sleeps between frames" ); static CVAR_DEFINE_AUTO( host_sleeptime_debug, "0", 0, "print sleeps between frames" );
CVAR_DEFINE( con_gamemaps, "con_mapfilter", "1", FCVAR_ARCHIVE, "when true show only maps in game folder" ); CVAR_DEFINE( con_gamemaps, "con_mapfilter", "1", FCVAR_ARCHIVE, "when true show only maps in game folder" );
typedef struct feature_message_s
{
uint32_t mask;
const char *msg;
const char *arg;
} feature_message_t;
static feature_message_t bugcomp_features[] =
{
{ BUGCOMP_PENTITYOFENTINDEX_FLAG, "pfnPEntityOfEntIndex bugfix revert", "peoei" },
};
static feature_message_t engine_features[] =
{
{ ENGINE_WRITE_LARGE_COORD, "Big World Support" },
{ ENGINE_QUAKE_COMPATIBLE, "Quake Compatibility" },
{ ENGINE_LOAD_DELUXEDATA, "Deluxemap Support" },
{ ENGINE_PHYSICS_PUSHER_EXT, "Improved MOVETYPE_PUSH" },
{ ENGINE_LARGE_LIGHTMAPS, "Large Lightmaps" },
{ ENGINE_COMPENSATE_QUAKE_BUG, "Stupid Quake Bug Compensation" },
{ ENGINE_IMPROVED_LINETRACE, "Improved Trace Line" },
{ ENGINE_COMPUTE_STUDIO_LERP, "Studio MOVETYPE_STEP Lerping" },
{ ENGINE_LINEAR_GAMMA_SPACE, "Linear Gamma Space" },
{ ENGINE_STEP_POSHISTORY_LERP, "MOVETYPE_STEP Position History Based Lerping" },
};
static void Sys_PrintUsage( void ) static void Sys_PrintUsage( void )
{ {
string version_str; string version_str;
@@ -92,8 +118,9 @@ static void Sys_PrintUsage( void )
O("-minidumps ", "enable writing minidumps when game is crashed") O("-minidumps ", "enable writing minidumps when game is crashed")
#endif #endif
O("-rodir <path> ", "set read-only base directory") O("-rodir <path> ", "set read-only base directory")
O("-bugcomp ", "enable precise bug compatibility. Will break games that don't require it") O("-bugcomp [opts] ", "enable precise bug compatibility")
O(" ", "Refer to engine documentation for more info") O(" ", "will break games that don't require it")
O(" ", "refer to engine documentation for more info")
O("-disablehelp ", "disable this message") O("-disablehelp ", "disable this message")
#if !XASH_DEDICATED #if !XASH_DEDICATED
O("-dedicated ", "run engine in dedicated mode") O("-dedicated ", "run engine in dedicated mode")
@@ -106,9 +133,11 @@ static void Sys_PrintUsage( void )
O("-noip6 ", "disable IPv6") O("-noip6 ", "disable IPv6")
O("-ip6 <ip> ", "set IPv6 address") O("-ip6 <ip> ", "set IPv6 address")
O("-port6 <port> ", "set IPv6 port") O("-port6 <port> ", "set IPv6 port")
O("-clockwindow <cw>", "adjust clockwindow used to ignore client commands to prevent speed hacks") O("-clockwindow <cw>", "adjust clockwindow used to ignore client commands")
O(" ", "to prevent speed hacks")
"\nGame options:\n" "\nGame options:\n"
O("-game <directory>", "set game directory to start engine with")
O("-dll <path> ", "override server DLL path") O("-dll <path> ", "override server DLL path")
#if !XASH_DEDICATED #if !XASH_DEDICATED
O("-clientlib <path>", "override client DLL path") O("-clientlib <path>", "override client DLL path")
@@ -190,31 +219,14 @@ void Host_ShutdownServer( void )
Host_PrintEngineFeatures Host_PrintEngineFeatures
================ ================
*/ */
static void Host_PrintEngineFeatures( int features ) static void Host_PrintFeatures( uint32_t flags, const char *s, feature_message_t *features, size_t size )
{ {
struct size_t i;
{
uint32_t mask;
const char *msg;
} features_str[] =
{
{ ENGINE_WRITE_LARGE_COORD, "Big World Support" },
{ ENGINE_QUAKE_COMPATIBLE, "Quake Compatibility" },
{ ENGINE_LOAD_DELUXEDATA, "Deluxemap Support" },
{ ENGINE_PHYSICS_PUSHER_EXT, "Improved MOVETYPE_PUSH" },
{ ENGINE_LARGE_LIGHTMAPS, "Large Lightmaps" },
{ ENGINE_COMPENSATE_QUAKE_BUG, "Stupid Quake Bug Compensation" },
{ ENGINE_IMPROVED_LINETRACE, "Improved Trace Line" },
{ ENGINE_COMPUTE_STUDIO_LERP, "Studio MOVETYPE_STEP Lerping" },
{ ENGINE_LINEAR_GAMMA_SPACE, "Linear Gamma Space" },
{ ENGINE_STEP_POSHISTORY_LERP, "MOVETYPE_STEP Position History Based Lerping" },
};
int i;
for( i = 0; i < ARRAYSIZE( features_str ); i++ ) for( i = 0; i < size; i++ )
{ {
if( FBitSet( features, features_str[i].mask )) if( FBitSet( flags, features[i].mask ))
Con_Reportf( "^3EXT:^7 %s is enabled\n", features_str[i].msg ); Con_Printf( "^3%s:^7 %s is enabled\n", s, features[i].msg );
} }
} }
@@ -242,7 +254,7 @@ void Host_ValidateEngineFeatures( uint32_t features )
SetBits( features, ENGINE_STEP_POSHISTORY_LERP ); SetBits( features, ENGINE_STEP_POSHISTORY_LERP );
// print requested first // print requested first
Host_PrintEngineFeatures( features ); Host_PrintFeatures( features, "EXT", engine_features, ARRAYSIZE( engine_features ));
// now warn about incompatible bits // now warn about incompatible bits
if( FBitSet( features, ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ) == ( ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP )) if( FBitSet( features, ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ) == ( ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ))
@@ -938,11 +950,59 @@ static void Host_RunTests( int stage )
TEST_LIST_1_CLIENT; TEST_LIST_1_CLIENT;
#endif #endif
Msg( "Done! %d passed, %d failed\n", tests_stats.passed, tests_stats.failed ); 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();
} }
} }
#endif #endif
static uint32_t Host_CheckBugcomp( void )
{
uint32_t flags = 0;
string args, arg;
char *prev, *next;
size_t i;
if( !Sys_CheckParm( "-bugcomp" ))
return 0;
if( Sys_GetParmFromCmdLine( "-bugcomp", args ) && args[0] != '-' )
{
for( prev = args, next = Q_strchrnul( prev, '+' ); ; prev = next + 1, next = Q_strchrnul( prev, '+' ))
{
Q_strncpy( arg, prev, next - prev + 1 );
for( i = 0; i < ARRAYSIZE( bugcomp_features ); i++ )
{
if( !Q_stricmp( bugcomp_features[i].arg, arg ))
{
SetBits( flags, bugcomp_features[i].mask );
break;
}
}
if( i == ARRAYSIZE( bugcomp_features ))
{
Con_Printf( S_ERROR "Unknown bugcomp flag %s\n", arg );
Con_Printf( "Valid flags are:\n" );
for( i = 0; i < ARRAYSIZE( bugcomp_features ); i++ )
Con_Printf( "\t%s: %s\n", bugcomp_features[i].arg, bugcomp_features[i].msg );
}
if( !*next )
break;
}
}
else
{
// no argument specified -bugcomp just enables everything
flags = -1;
}
Host_PrintFeatures( flags, "BUGCOMP", bugcomp_features, ARRAYSIZE( bugcomp_features ));
return flags;
}
/* /*
================= =================
Host_InitCommon Host_InitCommon
@@ -1047,13 +1107,6 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
// member console allowing // member console allowing
host.allow_console_init = host.allow_console; host.allow_console_init = host.allow_console;
if( Sys_CheckParm( "-bugcomp" ))
{
// add argument check here when we add other levels
// of bugcompatibility
host.bugcomp = BUGCOMP_GOLDSRC;
}
// timeBeginPeriod( 1 ); // a1ba: Do we need this? // timeBeginPeriod( 1 ); // a1ba: Do we need this?
// NOTE: this message couldn't be passed into game console but it doesn't matter // NOTE: this message couldn't be passed into game console but it doesn't matter
@@ -1180,11 +1233,11 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
Sys_InitLog(); Sys_InitLog();
// print bugcompatibility level here, after log was initialized // print current developer level to simplify processing users feedback
if( host.bugcomp == BUGCOMP_GOLDSRC ) if( developer > 0 )
{ Con_Printf( "Developer level: ^3%i\n", developer );
Con_Printf( "^3BUGCOMP^7: GoldSrc bug-compatibility enabled\n" );
} host.bugcomp = Host_CheckBugcomp();
Cmd_AddCommand( "exec", Host_Exec_f, "execute a script file" ); Cmd_AddCommand( "exec", Host_Exec_f, "execute a script file" );
Cmd_AddCommand( "memlist", Host_MemStats_f, "prints memory pool information" ); Cmd_AddCommand( "memlist", Host_MemStats_f, "prints memory pool information" );
@@ -1310,6 +1363,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
HTTP_Init(); HTTP_Init();
ID_Init(); ID_Init();
SoundList_Init();
if( Host_IsDedicated() ) if( Host_IsDedicated() )
{ {
@@ -1367,7 +1421,11 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
host.status = HOST_FRAME; host.status = HOST_FRAME;
if( GameState->nextstate == STATE_RUNFRAME ) if( GameState->nextstate == STATE_RUNFRAME )
#if XASH_WIN32 // FIXME: implement autocomplete on *nix
Con_Printf( "Type 'map <mapname>' to start game... (TAB-autocomplete is working too)\n" ); Con_Printf( "Type 'map <mapname>' to start game... (TAB-autocomplete is working too)\n" );
#else // !XASH_WIN32
Con_Printf( "Type 'map <mapname>' to start game...\n" );
#endif // !XASH_WIN32
// execute server.cfg after commandline // execute server.cfg after commandline
// so we have a chance to set servercfgfile // so we have a chance to set servercfgfile
@@ -1412,6 +1470,7 @@ void EXPORT Host_Shutdown( void )
SV_ShutdownFilter(); SV_ShutdownFilter();
CL_Shutdown(); CL_Shutdown();
SoundList_Shutdown();
Mod_Shutdown(); Mod_Shutdown();
NET_Shutdown(); NET_Shutdown();
HTTP_Shutdown(); HTTP_Shutdown();

View File

@@ -400,7 +400,8 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet, qboolean de
f = FS_Open( pakname, "rb", true ); f = FS_Open( pakname, "rb", true );
if( !f ) if( !f )
{ {
Con_DPrintf( S_ERROR "Couldn't find %s.\n", pakname ); if( !quiet )
Con_DPrintf( S_ERROR "Couldn't find %s.\n", pakname );
return true; return true;
} }

View File

@@ -28,7 +28,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, fs_offset_t filesi
rgba_t palette[256] = { 0 }; rgba_t palette[256] = { 0 };
int i, columns, column, rows, row, bpp = 1; int i, columns, column, rows, row, bpp = 1;
int cbPalBytes = 0, padSize = 0, bps = 0; int cbPalBytes = 0, padSize = 0, bps = 0;
int reflectivity[3] = { 0, 0, 0 }; uint reflectivity[3] = { 0, 0, 0 };
qboolean load_qfont = false; qboolean load_qfont = false;
bmp_t bhdr; bmp_t bhdr;
fs_offset_t estimatedSize; fs_offset_t estimatedSize;

View File

@@ -70,6 +70,7 @@ static qboolean Image_KTX2Parse( const ktx2_header_t *header, const byte *buffer
ktx2_index_t index; ktx2_index_t index;
size_t total_size = 0; size_t total_size = 0;
size_t max_offset = 0; size_t max_offset = 0;
int mip, cursor;
const byte *const levels_begin = buffer + KTX2_LEVELS_OFFSET; const byte *const levels_begin = buffer + KTX2_LEVELS_OFFSET;
// Sets image.type and image.flags // Sets image.type and image.flags
@@ -125,7 +126,7 @@ static qboolean Image_KTX2Parse( const ktx2_header_t *header, const byte *buffer
memcpy( &index, buffer + KTX2_IDENTIFIER_SIZE + sizeof( ktx2_header_t ), sizeof( index )); memcpy( &index, buffer + KTX2_IDENTIFIER_SIZE + sizeof( ktx2_header_t ), sizeof( index ));
for( int mip = 0; mip < header->levelCount; ++mip ) for( mip = 0; mip < header->levelCount; ++mip )
{ {
const uint32_t width = Q_max( 1, ( header->pixelWidth >> mip )); const uint32_t width = Q_max( 1, ( header->pixelWidth >> mip ));
const uint32_t height = Q_max( 1, ( header->pixelHeight >> mip )); const uint32_t height = Q_max( 1, ( header->pixelHeight >> mip ));
@@ -154,7 +155,7 @@ static qboolean Image_KTX2Parse( const ktx2_header_t *header, const byte *buffer
image.rgba = Mem_Malloc( host.imagepool, image.size ); image.rgba = Mem_Malloc( host.imagepool, image.size );
memcpy( image.rgba, buffer, image.size ); memcpy( image.rgba, buffer, image.size );
for( int mip = 0, cursor = 0; mip < header->levelCount; ++mip ) for( mip = 0, cursor = 0; mip < header->levelCount; ++mip )
{ {
ktx2_level_t level; ktx2_level_t level;
memcpy( &level, levels_begin + mip * sizeof( level ), sizeof( level )); memcpy( &level, levels_begin + mip * sizeof( level ), sizeof( level ));

View File

@@ -29,7 +29,7 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi
rgba_t palette[256]; rgba_t palette[256];
byte red = 0, green = 0, blue = 0, alpha = 0; byte red = 0, green = 0, blue = 0, alpha = 0;
int readpixelcount, pixelcount; int readpixelcount, pixelcount;
int reflectivity[3] = { 0, 0, 0 }; uint reflectivity[3] = { 0, 0, 0 };
qboolean compressed; qboolean compressed;
tga_t targa_header; tga_t targa_header;

View File

@@ -360,7 +360,7 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
byte *fin, *pal; byte *fin, *pal;
int ofs[4], rendermode; int ofs[4], rendermode;
int i, pixels, numcolors; int i, pixels, numcolors;
int reflectivity[3] = { 0, 0, 0 }; uint reflectivity[3] = { 0, 0, 0 };
if( filesize < sizeof( mip )) if( filesize < sizeof( mip ))
return false; return false;
@@ -390,7 +390,7 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
if( Q_strrchr( name, '{' )) if( Q_strrchr( name, '{' ))
{ {
// NOTE: decals with 'blue base' can be interpret as colored decals // NOTE: decals with 'blue base' can be interpret as colored decals
if( !Image_CheckFlag( IL_LOAD_DECAL ) || ( pal[765] == 0 && pal[766] == 0 && pal[767] == 255 )) if( !Image_CheckFlag( IL_LOAD_DECAL ) || ( pal && pal[765] == 0 && pal[766] == 0 && pal[767] == 255 ))
{ {
SetBits( image.flags, IMAGE_ONEBIT_ALPHA ); SetBits( image.flags, IMAGE_ONEBIT_ALPHA );
rendermode = LUMP_MASKED; rendermode = LUMP_MASKED;
@@ -488,37 +488,40 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
} }
// check for half-life water texture // check for half-life water texture
if( hl_texture && ( mip.name[0] == '!' || !Q_strnicmp( mip.name, "water", 5 ))) if( pal != NULL )
{ {
// grab the fog color if( hl_texture && ( mip.name[0] == '!' || !Q_strnicmp( mip.name, "water", 5 )))
image.fogParams[0] = pal[3*3+0];
image.fogParams[1] = pal[3*3+1];
image.fogParams[2] = pal[3*3+2];
// grab the fog density
image.fogParams[3] = pal[4*3+0];
}
else if( hl_texture && ( rendermode == LUMP_GRADIENT ))
{
// grab the decal color
image.fogParams[0] = pal[255*3+0];
image.fogParams[1] = pal[255*3+1];
image.fogParams[2] = pal[255*3+2];
// calc the decal reflectivity
image.fogParams[3] = VectorAvg( image.fogParams );
}
else if( pal != NULL )
{
// calc texture reflectivity
for( i = 0; i < 256; i++ )
{ {
reflectivity[0] += pal[i*3+0]; // grab the fog color
reflectivity[1] += pal[i*3+1]; image.fogParams[0] = pal[3*3+0];
reflectivity[2] += pal[i*3+2]; image.fogParams[1] = pal[3*3+1];
} image.fogParams[2] = pal[3*3+2];
VectorDivide( reflectivity, 256, image.fogParams ); // grab the fog density
image.fogParams[3] = pal[4*3+0];
}
else if( hl_texture && ( rendermode == LUMP_GRADIENT ))
{
// grab the decal color
image.fogParams[0] = pal[255*3+0];
image.fogParams[1] = pal[255*3+1];
image.fogParams[2] = pal[255*3+2];
// calc the decal reflectivity
image.fogParams[3] = VectorAvg( image.fogParams );
}
else
{
// calc texture reflectivity
for( i = 0; i < 256; i++ )
{
reflectivity[0] += pal[i*3+0];
reflectivity[1] += pal[i*3+1];
reflectivity[2] += pal[i*3+2];
}
VectorDivide( reflectivity, 256, image.fogParams );
}
} }
image.type = PF_INDEXED_32; // 32-bit palete image.type = PF_INDEXED_32; // 32-bit palete

View File

@@ -118,7 +118,7 @@ static void NET_AnnounceToMaster( master_t *m )
MSG_WriteBytes( &msg, "q\xFF", 2 ); MSG_WriteBytes( &msg, "q\xFF", 2 );
MSG_WriteDword( &msg, m->heartbeat_challenge ); MSG_WriteDword( &msg, m->heartbeat_challenge );
NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &msg ), MSG_GetBuf( &msg ), m->adr ); NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &msg ), MSG_GetData( &msg ), m->adr );
if( sv_verbose_heartbeats.value ) if( sv_verbose_heartbeats.value )
{ {

View File

@@ -109,85 +109,6 @@ void MSG_InitMasks( void )
ExtraMasks[maskBit] = (uint)BIT( maskBit ) - 1; ExtraMasks[maskBit] = (uint)BIT( maskBit ) - 1;
} }
void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits )
{
MSG_StartWriting( sb, pData, nBytes, 0, nMaxBits );
sb->pDebugName = pDebugName;
}
void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits )
{
// make sure it's dword aligned and padded.
Assert(((uint32_t)pData & 3 ) == 0 );
sb->pDebugName = "Unnamed";
sb->pData = (byte *)pData;
if( nBits == -1 )
{
sb->nDataBits = nBytes << 3;
}
else
{
Assert( nBits <= nBytes * 8 );
sb->nDataBits = nBits;
}
sb->iCurBit = iStartBit;
sb->bOverflow = false;
}
/*
=======================
MSG_Clear
for clearing overflowed buffer
=======================
*/
void MSG_Clear( sizebuf_t *sb )
{
sb->iCurBit = 0;
sb->bOverflow = false;
}
static qboolean MSG_Overflow( sizebuf_t *sb, int nBits )
{
if( sb->iCurBit + nBits > sb->nDataBits )
sb->bOverflow = true;
return sb->bOverflow;
}
qboolean MSG_CheckOverflow( sizebuf_t *sb )
{
return MSG_Overflow( sb, 0 );
}
int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence )
{
// compute the file offset
switch( whence )
{
case SEEK_CUR:
bitPos += sb->iCurBit;
break;
case SEEK_SET:
break;
case SEEK_END:
bitPos += sb->nDataBits;
break;
default:
return -1;
}
if( bitPos < 0 || bitPos > sb->nDataBits )
return -1;
sb->iCurBit = bitPos;
return 0;
}
void MSG_WriteOneBit( sizebuf_t *sb, int nValue ) void MSG_WriteOneBit( sizebuf_t *sb, int nValue )
{ {
if( !MSG_Overflow( sb, 1 )) if( !MSG_Overflow( sb, 1 ))
@@ -669,7 +590,7 @@ qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes )
return MSG_ReadBits( sb, pOut, nBytes << 3 ); return MSG_ReadBits( sb, pOut, nBytes << 3 );
} }
char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine ) static char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
{ {
static char string[4096]; static char string[4096];
int l = 0, c; int l = 0, c;
@@ -695,6 +616,16 @@ char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
return string; return string;
} }
char *MSG_ReadString( sizebuf_t *sb )
{
return MSG_ReadStringExt( sb, false );
}
char *MSG_ReadStringLine( sizebuf_t *sb )
{
return MSG_ReadStringExt( sb, true );
}
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove ) void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove )
{ {
int i, endbit = startbit + bitstoremove; int i, endbit = startbit + bitstoremove;

View File

@@ -30,39 +30,128 @@ GNU General Public License for more details.
// So PAD_NUMBER(0,4) is 0 and PAD_NUMBER(1,4) is 4 // So PAD_NUMBER(0,4) is 0 and PAD_NUMBER(1,4) is 4
#define PAD_NUMBER( num, boundary ) ((( num ) + (( boundary ) - 1 )) / ( boundary )) * ( boundary ) #define PAD_NUMBER( num, boundary ) ((( num ) + (( boundary ) - 1 )) / ( boundary )) * ( boundary )
_inline int BitByte( int bits ) static inline int BitByte( int bits )
{ {
return PAD_NUMBER( bits, 8 ) >> 3; return PAD_NUMBER( bits, 8 ) >> 3;
} }
struct sizebuf_s struct sizebuf_s
{ {
qboolean bOverflow; // overflow reading or writing byte *pData;
const char *pDebugName; // buffer name (pointer to const name) qboolean bOverflow; // overflow reading or writing
int iCurBit;
byte *pData; int nDataBits;
int iCurBit; const char *pDebugName; // buffer name (pointer to const name)
int nDataBits;
}; };
#define MSG_StartReading MSG_StartWriting #define MSG_StartReading MSG_StartWriting
#define MSG_GetNumBytesRead MSG_GetNumBytesWritten #define MSG_GetNumBytesRead MSG_GetNumBytesWritten
#define MSG_GetRealBytesRead MSG_GetRealBytesWritten #define MSG_GetRealBytesRead MSG_GetRealBytesWritten
#define MSG_GetNumBitsRead MSG_GetNumBitsWritten #define MSG_GetNumBitsRead MSG_GetNumBitsWritten
#define MSG_ReadBitAngles MSG_ReadBitVec3Coord #define MSG_ReadBitAngles MSG_ReadBitVec3Coord
#define MSG_ReadString( sb ) MSG_ReadStringExt( sb, false ) #define MSG_ReadAngle( sb ) (float)( MSG_ReadChar( sb ) * ( 360.0f / 256.0f ))
#define MSG_ReadStringLine( sb ) MSG_ReadStringExt( sb, true ) #define MSG_Init( sb, name, data, bytes ) MSG_InitExt( sb, name, data, bytes, -1 )
#define MSG_ReadAngle( sb ) (float)(MSG_ReadChar( sb ) * ( 360.0f / 256.0f )) #define MSG_CheckOverflow( sb ) MSG_Overflow( sb, 0 )
#define MSG_Init( sb, name, data, bytes ) MSG_InitExt( sb, name, data, bytes, -1 )
// common functions // common functions
void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits ); static inline void MSG_Clear( sizebuf_t *sb )
void MSG_InitMasks( void ); // called once at startup engine {
int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence ); sb->bOverflow = false;
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove ); sb->iCurBit = 0;
_inline int MSG_TellBit( sizebuf_t *sb ) { return sb->iCurBit; } }
_inline const char *MSG_GetName( sizebuf_t *sb ) { return sb->pDebugName; }
qboolean MSG_CheckOverflow( sizebuf_t *sb ); static inline void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nBits )
{
sb->pData = pData;
MSG_Clear( sb );
if( nBits < 0 )
sb->nDataBits = nBytes << 3;
else
sb->nDataBits = nBits;
sb->pDebugName = pDebugName;
}
static inline void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits )
{
MSG_InitExt( sb, "Unnamed", pData, nBytes, nBits );
sb->iCurBit = iStartBit;
}
static inline int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence )
{
// compute the file offset
switch( whence )
{
case SEEK_CUR:
bitPos += sb->iCurBit;
break;
case SEEK_SET:
break;
case SEEK_END:
bitPos += sb->nDataBits;
break;
default:
return -1;
}
if( unlikely( bitPos < 0 || bitPos > sb->nDataBits ))
return -1;
sb->iCurBit = bitPos;
return 0;
}
static inline int MSG_TellBit( sizebuf_t *sb )
{
return sb->iCurBit;
}
static inline const char *MSG_GetName( sizebuf_t *sb )
{
return sb->pDebugName;
}
static inline int MSG_GetNumBytesWritten( sizebuf_t *sb )
{
return BitByte( sb->iCurBit );
}
static inline int MSG_GetRealBytesWritten( sizebuf_t *sb )
{
return sb->iCurBit >> 3; // unpadded
}
static inline int MSG_GetNumBitsWritten( sizebuf_t *sb )
{
return sb->iCurBit;
}
static inline int MSG_GetMaxBits( sizebuf_t *sb )
{
return sb->nDataBits;
}
static inline int MSG_GetMaxBytes( sizebuf_t *sb )
{
return sb->nDataBits >> 3;
}
static inline int MSG_GetNumBitsLeft( sizebuf_t *sb )
{
return sb->nDataBits - sb->iCurBit;
}
static inline int MSG_GetNumBytesLeft( sizebuf_t *sb )
{
return MSG_GetNumBitsLeft( sb ) >> 3;
}
static inline byte *MSG_GetData( sizebuf_t *sb )
{
return sb->pData;
}
#if XASH_BIG_ENDIAN #if XASH_BIG_ENDIAN
#define MSG_BigShort( x ) ( x ) #define MSG_BigShort( x ) ( x )
@@ -73,9 +162,15 @@ static inline uint16_t MSG_BigShort( const uint16_t x )
} }
#endif #endif
// init writing static inline qboolean MSG_Overflow( sizebuf_t *sb, int nBits )
void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits ); {
void MSG_Clear( sizebuf_t *sb ); if( sb->iCurBit + nBits > sb->nDataBits )
sb->bOverflow = true;
return sb->bOverflow;
}
void MSG_InitMasks( void ); // called once at startup engine
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
// Bit-write functions // Bit-write functions
void MSG_WriteOneBit( sizebuf_t *sb, int nValue ); void MSG_WriteOneBit( sizebuf_t *sb, int nValue );
@@ -99,20 +194,11 @@ void MSG_WriteCoord( sizebuf_t *sb, float val );
void MSG_WriteFloat( sizebuf_t *sb, float val ); void MSG_WriteFloat( sizebuf_t *sb, float val );
void MSG_WriteVec3Coord( sizebuf_t *sb, const float *fa ); void MSG_WriteVec3Coord( sizebuf_t *sb, const float *fa );
void MSG_WriteVec3Angles( sizebuf_t *sb, const float *fa ); void MSG_WriteVec3Angles( sizebuf_t *sb, const float *fa );
qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes ); // same as MSG_WriteData
qboolean MSG_WriteString( sizebuf_t *sb, const char *pStr ); // returns false if it overflows the buffer. qboolean MSG_WriteString( sizebuf_t *sb, const char *pStr ); // returns false if it overflows the buffer.
qboolean MSG_WriteStringf( sizebuf_t *sb, const char *format, ... ) _format( 2 ); qboolean MSG_WriteStringf( sizebuf_t *sb, const char *format, ... ) _format( 2 );
qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes );
// helper functions // helper functions
_inline int MSG_GetNumBytesWritten( sizebuf_t *sb ) { return BitByte( sb->iCurBit ); }
_inline int MSG_GetRealBytesWritten( sizebuf_t *sb ) { return sb->iCurBit >> 3; } // unpadded
_inline int MSG_GetNumBitsWritten( sizebuf_t *sb ) { return sb->iCurBit; }
_inline int MSG_GetMaxBits( sizebuf_t *sb ) { return sb->nDataBits; }
_inline int MSG_GetMaxBytes( sizebuf_t *sb ) { return sb->nDataBits >> 3; }
_inline int MSG_GetNumBitsLeft( sizebuf_t *sb ) { return sb->nDataBits - sb->iCurBit; }
_inline int MSG_GetNumBytesLeft( sizebuf_t *sb ) { return MSG_GetNumBitsLeft( sb ) >> 3; }
_inline byte *MSG_GetData( sizebuf_t *sb ) { return sb->pData; }
_inline byte *MSG_GetBuf( sizebuf_t *sb ) { return sb->pData; } // just an alias
// Bit-read functions // Bit-read functions
int MSG_ReadOneBit( sizebuf_t *sb ); int MSG_ReadOneBit( sizebuf_t *sb );
@@ -136,7 +222,8 @@ float MSG_ReadCoord( sizebuf_t *sb );
float MSG_ReadFloat( sizebuf_t *sb ); float MSG_ReadFloat( sizebuf_t *sb );
void MSG_ReadVec3Coord( sizebuf_t *sb, vec3_t fa ); void MSG_ReadVec3Coord( sizebuf_t *sb, vec3_t fa );
void MSG_ReadVec3Angles( sizebuf_t *sb, vec3_t fa ); void MSG_ReadVec3Angles( sizebuf_t *sb, vec3_t fa );
char *MSG_ReadString( sizebuf_t *sb );
char *MSG_ReadStringLine( sizebuf_t *sb );
qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes ); qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes );
char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine );
#endif//NET_BUFFER_H #endif//NET_BUFFER_H

View File

@@ -315,6 +315,43 @@ static const delta_field_t ent_fields[] =
{ NULL }, { NULL },
}; };
#if XASH_ENGINE_TESTS
typedef struct delta_test_struct_t
{
char dt_string[128]; // always signed
float dt_timewindow_big; // always signed
float dt_timewindow_8; // always signed
float dt_angle; // always_signed
float dt_float_signed;
float dt_float_unsigned;
int32_t dt_integer_signed;
uint32_t dt_integer_unsigned;
int16_t dt_short_signed;
uint16_t dt_short_unsigned;
int8_t dt_byte_signed;
uint8_t dt_byte_unsigned;
} delta_test_struct_t;
#define TEST_DEF( x ) #x, offsetof( delta_test_struct_t, x ), sizeof( ((delta_test_struct_t *)0)->x )
static const delta_field_t test_fields[] =
{
{ TEST_DEF( dt_string ) },
{ TEST_DEF( dt_timewindow_big )},
{ TEST_DEF( dt_timewindow_8 )},
{ TEST_DEF( dt_angle ) },
{ TEST_DEF( dt_float_signed ) },
{ TEST_DEF( dt_float_unsigned ) },
{ TEST_DEF( dt_integer_signed ) },
{ TEST_DEF( dt_integer_unsigned ) },
{ TEST_DEF( dt_short_signed ) },
{ TEST_DEF( dt_short_unsigned ) },
{ TEST_DEF( dt_byte_signed ) },
{ TEST_DEF( dt_byte_unsigned ) },
{ NULL },
};
#endif
enum enum
{ {
DT_EVENT_T = 0, DT_EVENT_T = 0,
@@ -325,6 +362,10 @@ enum
DT_ENTITY_STATE_T, DT_ENTITY_STATE_T,
DT_ENTITY_STATE_PLAYER_T, DT_ENTITY_STATE_PLAYER_T,
DT_CUSTOM_ENTITY_STATE_T, DT_CUSTOM_ENTITY_STATE_T,
#if XASH_ENGINE_TESTS
DT_DELTA_TEST_STRUCT_T,
#endif
DT_STRUCT_COUNT
}; };
static delta_info_t dt_info[] = static delta_info_t dt_info[] =
@@ -337,7 +378,10 @@ static delta_info_t dt_info[] =
[DT_ENTITY_STATE_T] = { "entity_state_t", ent_fields, NUM_FIELDS( ent_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_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_CUSTOM_ENTITY_STATE_T] = { "custom_entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
{ NULL }, #if XASH_ENGINE_TESTS
[DT_DELTA_TEST_STRUCT_T] = { "delta_test_struct_t", test_fields, NUM_FIELDS( test_fields ) },
#endif
[DT_STRUCT_COUNT] = { NULL },
}; };
static delta_info_t *Delta_FindStruct( const char *name ) static delta_info_t *Delta_FindStruct( const char *name )
@@ -411,9 +455,7 @@ static void Delta_CustomEncode( delta_info_t *dt, const void *from, const void *
dt->pFields[i].bInactive = false; dt->pFields[i].bInactive = false;
if( dt->userCallback ) if( dt->userCallback )
{
dt->userCallback( dt->pFields, from, to ); dt->userCallback( dt->pFields, from, to );
}
} }
static delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName ) static delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName )
@@ -974,14 +1016,14 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
toF = *(uint8_t *)((int8_t *)to + pField->offset ); toF = *(uint8_t *)((int8_t *)to + pField->offset );
} }
if( !Q_equal(pField->multiplier, 1.0f ))
{
fromF *= pField->multiplier;
toF *= pField->multiplier;
}
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits ); fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits ); toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
if( !Q_equal(pField->multiplier, 1.0f ))
fromF *= pField->multiplier;
if( !Q_equal( pField->multiplier, 1.0f ))
toF *= pField->multiplier;
} }
else if( pField->flags & DT_SHORT ) else if( pField->flags & DT_SHORT )
{ {
@@ -996,14 +1038,14 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
toF = *(uint16_t *)((int8_t *)to + pField->offset ); toF = *(uint16_t *)((int8_t *)to + pField->offset );
} }
if( !Q_equal(pField->multiplier, 1.0f ))
{
fromF *= pField->multiplier;
toF *= pField->multiplier;
}
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits ); fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits ); toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
if( !Q_equal(pField->multiplier, 1.0f ))
fromF *= pField->multiplier;
if( !Q_equal( pField->multiplier, 1.0f ))
toF *= pField->multiplier;
} }
else if( pField->flags & DT_INTEGER ) else if( pField->flags & DT_INTEGER )
{ {
@@ -1017,14 +1059,15 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
fromF = *(uint32_t *)((int8_t *)from + pField->offset ); fromF = *(uint32_t *)((int8_t *)from + pField->offset );
toF = *(uint32_t *)((int8_t *)to + pField->offset ); toF = *(uint32_t *)((int8_t *)to + pField->offset );
} }
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
if( !Q_equal(pField->multiplier, 1.0f )) if( !Q_equal(pField->multiplier, 1.0f ))
{
fromF *= pField->multiplier; fromF *= pField->multiplier;
if( !Q_equal( pField->multiplier, 1.0f ))
toF *= pField->multiplier; toF *= pField->multiplier;
}
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
} }
else if( pField->flags & ( DT_ANGLE|DT_FLOAT )) else if( pField->flags & ( DT_ANGLE|DT_FLOAT ))
{ {
@@ -1034,33 +1077,17 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
} }
else if( pField->flags & DT_TIMEWINDOW_8 ) else if( pField->flags & DT_TIMEWINDOW_8 )
{ {
val_a = Q_rint((*(float *)((byte *)from + pField->offset )) * 100.0f ); val_a = *(float *)((byte *)from + pField->offset );
val_b = Q_rint((*(float *)((byte *)to + pField->offset )) * 100.0f ); val_b = *(float *)((byte *)to + pField->offset );
val_a -= Q_rint(timebase * 100.0); fromF = Q_rint( val_a * 100.0 );
val_b -= Q_rint(timebase * 100.0); toF = Q_rint( val_b * 100.0 );
fromF = FloatAsInt( val_a );
toF = FloatAsInt( val_b );
} }
else if( pField->flags & DT_TIMEWINDOW_BIG ) else if( pField->flags & DT_TIMEWINDOW_BIG )
{ {
val_a = (*(float *)((byte *)from + pField->offset )); val_a = *(float *)((byte *)from + pField->offset );
val_b = (*(float *)((byte *)to + pField->offset )); val_b = *(float *)((byte *)to + pField->offset );
fromF = Q_rint( val_a * pField->multiplier );
if( !Q_equal( pField->multiplier, 1.0f )) toF = Q_rint( val_b * pField->multiplier );
{
val_a *= pField->multiplier;
val_b *= pField->multiplier;
val_a = (timebase * pField->multiplier) - val_a;
val_b = (timebase * pField->multiplier) - val_b;
}
else
{
val_a = timebase - val_a;
val_b = timebase - val_b;
}
fromF = FloatAsInt( val_a );
toF = FloatAsInt( val_b );
} }
else if( pField->flags & DT_STRING ) else if( pField->flags & DT_STRING )
{ {
@@ -1144,6 +1171,7 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
int signbit = FBitSet( pField->flags, DT_SIGNED ) ? 1 : 0; int signbit = FBitSet( pField->flags, DT_SIGNED ) ? 1 : 0;
float flValue, flAngle; float flValue, flAngle;
uint iValue; uint iValue;
int dt;
const char *pStr; const char *pStr;
if( Delta_CompareField( pField, from, to, timebase )) if( Delta_CompareField( pField, from, to, timebase ))
@@ -1160,11 +1188,11 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
iValue = *(int8_t *)((int8_t *)to + pField->offset ); iValue = *(int8_t *)((int8_t *)to + pField->offset );
else else
iValue = *(uint8_t *)((int8_t *)to + pField->offset ); iValue = *(uint8_t *)((int8_t *)to + pField->offset );
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
if( !Q_equal( pField->multiplier, 1.0 ) ) if( !Q_equal( pField->multiplier, 1.0 ))
iValue *= pField->multiplier; iValue *= pField->multiplier;
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
MSG_WriteBitLong( msg, iValue, pField->bits, signbit ); MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
} }
else if( pField->flags & DT_SHORT ) else if( pField->flags & DT_SHORT )
@@ -1173,11 +1201,11 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
iValue = *(int16_t *)((int8_t *)to + pField->offset ); iValue = *(int16_t *)((int8_t *)to + pField->offset );
else else
iValue = *(uint16_t *)((int8_t *)to + pField->offset ); iValue = *(uint16_t *)((int8_t *)to + pField->offset );
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
if( !Q_equal( pField->multiplier, 1.0 ) ) if( !Q_equal( pField->multiplier, 1.0 ))
iValue *= pField->multiplier; iValue *= pField->multiplier;
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
MSG_WriteBitLong( msg, iValue, pField->bits, signbit ); MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
} }
else if( pField->flags & DT_INTEGER ) else if( pField->flags & DT_INTEGER )
@@ -1186,11 +1214,11 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
iValue = *(int32_t *)((int8_t *)to + pField->offset ); iValue = *(int32_t *)((int8_t *)to + pField->offset );
else else
iValue = *(uint32_t *)((int8_t *)to + pField->offset ); iValue = *(uint32_t *)((int8_t *)to + pField->offset );
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
if( !Q_equal( pField->multiplier, 1.0 ) ) if( !Q_equal( pField->multiplier, 1.0 ))
iValue *= pField->multiplier; iValue *= pField->multiplier;
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
MSG_WriteBitLong( msg, iValue, pField->bits, signbit ); MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
} }
else if( pField->flags & DT_FLOAT ) else if( pField->flags & DT_FLOAT )
@@ -1210,19 +1238,17 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
} }
else if( pField->flags & DT_TIMEWINDOW_8 ) else if( pField->flags & DT_TIMEWINDOW_8 )
{ {
signbit = 1; // timewindow is always signed
flValue = *(float *)((byte *)to + pField->offset ); flValue = *(float *)((byte *)to + pField->offset );
iValue = (int)Q_rint( timebase * 100.0 ) - (int)Q_rint( flValue * 100.0 ); dt = Q_rint(( timebase - flValue ) * 100.0 );
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits ); dt = Delta_ClampIntegerField( pField, dt, 1, pField->bits );
MSG_WriteBitLong( msg, iValue, pField->bits, signbit ); MSG_WriteSBitLong( msg, dt, pField->bits );
} }
else if( pField->flags & DT_TIMEWINDOW_BIG ) else if( pField->flags & DT_TIMEWINDOW_BIG )
{ {
signbit = 1; // timewindow is always signed
flValue = *(float *)((byte *)to + pField->offset ); flValue = *(float *)((byte *)to + pField->offset );
iValue = (int)Q_rint( timebase * pField->multiplier ) - (int)Q_rint( flValue * pField->multiplier ); dt = Q_rint(( timebase - flValue ) * pField->multiplier );
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits ); dt = Delta_ClampIntegerField( pField, dt, 1, pField->bits );
MSG_WriteBitLong( msg, iValue, pField->bits, signbit ); MSG_WriteSBitLong( msg, dt, pField->bits );
} }
else if( pField->flags & DT_STRING ) else if( pField->flags & DT_STRING )
{ {
@@ -1306,9 +1332,12 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
if( pField->flags & DT_BYTE ) if( pField->flags & DT_BYTE )
{ {
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned ); iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
if( !Q_equal( pField->multiplier, 1.0 ) ) if( !Q_equal( pField->multiplier, 1.0 ))
iValue /= pField->multiplier; iValue /= pField->multiplier;
if( !Q_equal( pField->post_multiplier, 1.0 ))
iValue *= pField->post_multiplier;
if( bSigned ) if( bSigned )
*(int8_t *)((uint8_t *)to + pField->offset ) = iValue; *(int8_t *)((uint8_t *)to + pField->offset ) = iValue;
else else
@@ -1317,9 +1346,12 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
else if( pField->flags & DT_SHORT ) else if( pField->flags & DT_SHORT )
{ {
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned ); iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
if( !Q_equal( pField->multiplier, 1.0 ) ) if( !Q_equal( pField->multiplier, 1.0 ))
iValue /= pField->multiplier; iValue /= pField->multiplier;
if( !Q_equal( pField->post_multiplier, 1.0 ))
iValue *= pField->post_multiplier;
if( bSigned ) if( bSigned )
*(int16_t *)((uint8_t *)to + pField->offset ) = iValue; *(int16_t *)((uint8_t *)to + pField->offset ) = iValue;
else else
@@ -1328,9 +1360,12 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
else if( pField->flags & DT_INTEGER ) else if( pField->flags & DT_INTEGER )
{ {
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned ); iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
if( !Q_equal( pField->multiplier, 1.0 ) ) if( !Q_equal( pField->multiplier, 1.0 ))
iValue /= pField->multiplier; iValue /= pField->multiplier;
if( !Q_equal( pField->post_multiplier, 1.0 ))
iValue *= pField->post_multiplier;
if( bSigned ) if( bSigned )
*(int32_t *)((uint8_t *)to + pField->offset ) = iValue; *(int32_t *)((uint8_t *)to + pField->offset ) = iValue;
else else
@@ -1344,11 +1379,11 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
else else
flValue = iValue; flValue = iValue;
if( !Q_equal( pField->multiplier, 1.0 ) ) if( !Q_equal( pField->multiplier, 1.0 ))
flValue = flValue / pField->multiplier; flValue /= pField->multiplier;
if( !Q_equal( pField->post_multiplier, 1.0 ) ) if( !Q_equal( pField->post_multiplier, 1.0 ))
flValue = flValue * pField->post_multiplier; flValue *= pField->post_multiplier;
*(float *)((byte *)to + pField->offset ) = flValue; *(float *)((byte *)to + pField->offset ) = flValue;
} }
@@ -1359,22 +1394,14 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
} }
else if( pField->flags & DT_TIMEWINDOW_8 ) else if( pField->flags & DT_TIMEWINDOW_8 )
{ {
bSigned = true; // timewindow is always signed iValue = MSG_ReadSBitLong( msg, pField->bits );
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned ); flTime = ( timebase * 100.0 - (int)iValue ) / 100.0;
flTime = (timebase * 100.0 - (int)iValue) / 100.0;
*(float *)((byte *)to + pField->offset ) = flTime; *(float *)((byte *)to + pField->offset ) = flTime;
} }
else if( pField->flags & DT_TIMEWINDOW_BIG ) else if( pField->flags & DT_TIMEWINDOW_BIG )
{ {
bSigned = true; // timewindow is always signed iValue = MSG_ReadSBitLong( msg, pField->bits );
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned ); flTime = ( timebase * pField->multiplier - (int)iValue ) / pField->multiplier;
if( !Q_equal( pField->multiplier, 1.0 ) )
flTime = ( timebase * pField->multiplier - (int)iValue ) / pField->multiplier;
else
flTime = timebase - (int)iValue;
*(float *)((byte *)to + pField->offset ) = flTime; *(float *)((byte *)to + pField->offset ) = flTime;
} }
else if( pField->flags & DT_STRING ) else if( pField->flags & DT_STRING )
@@ -2069,3 +2096,103 @@ void GAME_EXPORT Delta_UnsetFieldByIndex( delta_t *pFields, int fieldNumber )
dt->pFields[fieldNumber].bInactive = true; dt->pFields[fieldNumber].bInactive = true;
} }
#if XASH_ENGINE_TESTS
#include "tests.h"
void Test_RunDelta( void )
{
delta_info_t *dt = &dt_info[DT_DELTA_TEST_STRUCT_T];
delta_test_struct_t from, to = { 0 };
delta_test_struct_t null = { 0 };
sizebuf_t msg;
int i;
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 );
Delta_AddField( dt, "dt_angle", DT_ANGLE, 16, 1.0f, 1.0f );
Delta_AddField( dt, "dt_float_signed", DT_FLOAT | DT_SIGNED, 22, 100.0f, 1.0f );
Delta_AddField( dt, "dt_float_unsigned", DT_FLOAT, 24, 10000.0f, 0.1f );
Delta_AddField( dt, "dt_integer_signed", DT_INTEGER | DT_SIGNED, 24, 1.0f, 1.0f );
Delta_AddField( dt, "dt_integer_unsigned", DT_INTEGER, 24, 1.0f, 1.0f );
Delta_AddField( dt, "dt_short_signed", DT_SHORT | DT_SIGNED, 16, 1.0f, 1.0f );
Delta_AddField( dt, "dt_short_unsigned", DT_SHORT, 15, 0.125f, 1.0f );
Delta_AddField( dt, "dt_byte_signed", DT_BYTE | DT_SIGNED, 6, 1.0f, 1.0f );
Delta_AddField( dt, "dt_byte_unsigned", DT_BYTE, 8, 1.0f, 1.0f );
Q_strncpy( from.dt_string, "test data check it's the same", sizeof( from.dt_string ));
from.dt_timewindow_big = timebase + 2.3456;
from.dt_timewindow_8 = timebase + 0.0234;
from.dt_angle = 160.245f;
from.dt_float_signed = -15.123f;
from.dt_float_unsigned = 1235.321f;
from.dt_integer_signed = -412784;
from.dt_integer_unsigned = 123453;
from.dt_short_signed = -12343;
from.dt_short_unsigned = 32131;
from.dt_byte_signed = 16;
from.dt_byte_unsigned = 218;
MSG_Init( &msg, "test message", buffer, sizeof( buffer ));
for( i = 0; i < dt->numFields; i++ )
Delta_WriteField( &msg, &dt->pFields[i], &null, &from, timebase );
MSG_SeekToBit( &msg, 0, SEEK_SET );
for( i = 0; i < dt->numFields; i++ )
Delta_ReadField( &msg, &dt->pFields[i], &null, &to, timebase );
Con_Printf( "struct as encoded to delta:\n" );
TASSERT_STR( from.dt_string, to.dt_string );
// the epsilon value is derived from multiplier value
TASSERT( Q_equal_e( from.dt_timewindow_big, to.dt_timewindow_big, 0.001f ));
// dt_timewindow_8 type has multiplier locked at 100.0f
TASSERT( Q_equal_e( from.dt_timewindow_8, to.dt_timewindow_8, 0.01f ));
TASSERT( Q_equal_e( from.dt_angle, to.dt_angle, 0.1f ));
TASSERT( Q_equal_e( from.dt_float_signed, to.dt_float_signed, 0.01f ));
// dt_float_unsigned has post-multiplier that doesn't affect network data
// and therefore should be reverted back when comparing
TASSERT( Q_equal_e( from.dt_float_unsigned, to.dt_float_unsigned * 10.f , 0.01f ));
TASSERT_EQi( from.dt_integer_signed, to.dt_integer_signed );
TASSERT_EQi( from.dt_integer_unsigned, to.dt_integer_unsigned );
TASSERT_EQi( from.dt_short_signed, to.dt_short_signed );
TASSERT(( from.dt_short_unsigned & ( 0xffff << 3 )) == to.dt_short_unsigned );
TASSERT_EQi( from.dt_byte_signed, to.dt_byte_signed );
TASSERT_EQi( from.dt_byte_unsigned, to.dt_byte_unsigned );
Con_Printf( "from.dt_timewindow_big = %f\n", from.dt_timewindow_big );
Con_Printf( "to.dt_timewindow_big = %f\n", to.dt_timewindow_big );
Con_Printf( "from.dt_timewindow_8 = %f\n", from.dt_timewindow_8 );
Con_Printf( "to.dt_timewindow_8 = %f\n", to.dt_timewindow_8 );
Con_Printf( "from.dt_angle = %f\n", from.dt_angle );
Con_Printf( "to.dt_angle = %f\n", to.dt_angle );
Con_Printf( "from.dt_float_signed = %f\n", from.dt_float_signed );
Con_Printf( "to.dt_float_signed = %f\n", to.dt_float_signed );
Con_Printf( "from.dt_float_unsigned = %f\n", from.dt_float_unsigned );
Con_Printf( "to.dt_float_unsigned = %f\n", to.dt_float_unsigned );
Con_Printf( "from.dt_integer_signed = %i\n", from.dt_integer_signed );
Con_Printf( "to.dt_integer_signed = %i\n", to.dt_integer_signed );
Con_Printf( "from.dt_integer_unsigned = %i\n", from.dt_integer_unsigned );
Con_Printf( "to.dt_integer_unsigned = %i\n", to.dt_integer_unsigned );
Con_Printf( "from.dt_short_signed = %i\n", from.dt_short_signed );
Con_Printf( "to.dt_short_signed = %i\n", to.dt_short_signed );
Con_Printf( "from.dt_short_unsigned = %i\n", from.dt_short_unsigned );
Con_Printf( "to.dt_short_unsigned = %i\n", to.dt_short_unsigned );
Con_Printf( "from.dt_byte_signed = %i\n", from.dt_byte_signed );
Con_Printf( "to.dt_byte_signed = %i\n", to.dt_byte_signed );
Con_Printf( "from.dt_byte_unsigned = %i\n", from.dt_byte_unsigned );
Con_Printf( "to.dt_byte_unsigned = %i\n", to.dt_byte_unsigned );
}
#endif // XASH_ENGINE_TESTS

View File

@@ -127,7 +127,7 @@ GNU General Public License for more details.
#define MAX_CUSTOM (1<<MAX_CUSTOM_BITS)// 10 bits == 1024 generic file #define MAX_CUSTOM (1<<MAX_CUSTOM_BITS)// 10 bits == 1024 generic file
#define MAX_USER_MESSAGES 197 // another 58 messages reserved for engine routines #define MAX_USER_MESSAGES 197 // another 58 messages reserved for engine routines
#define MAX_DLIGHTS 32 // dynamic lights (rendered per one frame) #define MAX_DLIGHTS 32 // dynamic lights (rendered per one frame)
#define MAX_ELIGHTS 64 // entity only point lights #define MAX_ELIGHTS 128 // a1ba: increased from 64 to 128, entity only point lights
#define MAX_LIGHTSTYLES 256 // a1ba: increased from 64 to 256, protocol limit #define MAX_LIGHTSTYLES 256 // a1ba: increased from 64 to 256, protocol limit
#define MAX_RENDER_DECALS 4096 // max rendering decals per a level #define MAX_RENDER_DECALS 4096 // max rendering decals per a level

362
engine/common/sounds.c Normal file
View File

@@ -0,0 +1,362 @@
/*
sounds.c - sounds.lst parser
Copyright (C) 2024 Alibek Omarov
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.
*/
#include "common.h"
enum soundlst_type_e
{
SoundList_None,
SoundList_Range,
SoundList_List
};
static const char *soundlst_groups[SoundList_Groups] =
{
"BouncePlayerShell",
"BounceWeaponShell",
"BounceConcrete",
"BounceGlass",
"BounceMetal",
"BounceFlesh",
"BounceWood",
"Ricochet",
"Explode",
"PlayerWaterEnter",
"PlayerWaterExit",
"EntityWaterEnter",
"EntityWaterExit",
};
typedef struct soundlst_s
{
enum soundlst_type_e type;
char *snd;
int min; // the string length if type is group
int max; // the string count if type is group
} soundlst_t;
soundlst_t soundlst[SoundList_Groups];
static void SoundList_Print_f( void );
static void SoundList_Free( soundlst_t *lst )
{
if( lst->snd )
Mem_Free( lst->snd );
memset( lst, 0, sizeof( *lst ));
}
void SoundList_Shutdown( void )
{
int i;
for( i = 0; i < SoundList_Groups; i++ )
SoundList_Free( &soundlst[i] );
}
int SoundList_Count( enum soundlst_group_e group )
{
soundlst_t *lst = &soundlst[group];
switch( lst->type )
{
case SoundList_Range:
return lst->max - lst->min + 1;
case SoundList_List:
return lst->max;
}
return 0;
}
const char *SoundList_Get( enum soundlst_group_e group, int i )
{
static string temp;
soundlst_t *lst = &soundlst[group];
if( i < 0 || i >= SoundList_Count( group ))
return NULL;
switch( lst->type )
{
case SoundList_Range:
Q_snprintf( temp, sizeof( temp ), lst->snd, lst->min + i );
return temp;
case SoundList_List:
return &lst->snd[i * lst->min];
}
return NULL;
}
const char *SoundList_GetRandom( enum soundlst_group_e group )
{
int count = SoundList_Count( group );
int idx = COM_RandomLong( 0, count - 1 );
// Con_Printf( "%s: %s %d %d\n", __func__, soundlst_groups[group], count, idx );
return SoundList_Get( group, idx );
}
static qboolean SoundList_ParseGroup( soundlst_t *lst, char **file )
{
string token;
int count = 0, slen = 0, i;
char *p;
p = *file;
while(( p = COM_ParseFile( p, token, sizeof( token ))))
{
int len;
if( !Q_strcmp( token, "}" ))
break;
if( !Q_strcmp( token, "{" ))
{
Con_Printf( "%s: expected '}' but got '{' during group list parse\n", __func__ );
return false;
}
else if( !COM_CheckStringEmpty( token ))
{
Con_Printf( "%s: expected '}' but got EOF during group list parse\n", __func__ );
return false;
}
len = Q_strlen( token ) + 1;
if( slen < len )
slen = len;
count++;
}
if( count == 0 ) // deactivate group
{
lst->type = SoundList_None;
lst->snd = NULL;
lst->min = lst->max = 0;
return true;
}
lst->type = SoundList_List;
lst->min = slen;
lst->max = count;
lst->snd = Mem_Malloc( host.mempool, count * slen ); // allocate single buffer for the whole group
for( i = 0; i < count; i++ )
{
*file = COM_ParseFile( *file, token, sizeof( token ));
Q_strncpy( &lst->snd[i * slen], token, slen );
}
return true;
}
static qboolean SoundList_ParseRange( soundlst_t *lst, char **file )
{
string token, snd;
char *p;
int i = 0;
lst->type = SoundList_Range;
*file = COM_ParseFile( *file, snd, sizeof( snd ));
// validate format string, count all % characters
p = snd;
i = 0;
while(( p = Q_strchr( p, '%' )))
{
// only decimal
if( p[1] != 'd' && p[1] != 'i' && p[1] != 'u' )
{
Con_Printf( "%s: invalid range string %s, only decimal numbers are allowed", __func__, snd );
return false;
}
i++;
p++;
}
// if more than one %, then it's an invalid format string
if( i != 1 )
{
Con_Printf( "%s: invalid range string %s, only single specifier is allowed\n", __func__, snd );
return false;
}
*file = COM_ParseFile( *file, token, sizeof( token ));
if( !Q_isdigit( token ))
{
Con_Printf( "%s: %s must be a digit\n", __func__, token );
return false;
}
lst->min = Q_atoi( token );
*file = COM_ParseFile( *file, token, sizeof( token ));
if( !Q_isdigit( token ))
{
Con_Printf( "%s: %s must be a digit\n", __func__, token );
return false;
}
lst->max = Q_atoi( token );
lst->snd = copystring( snd );
return true;
}
static qboolean SoundList_Parse( char *file )
{
string token;
int i;
while(( file = COM_ParseFile( file, token, sizeof( token ))))
{
soundlst_t *lst = NULL;
char *p;
for( i = 0; i < SoundList_Groups; i++ )
{
if( !Q_strcmp( token, soundlst_groups[i] ))
{
lst = &soundlst[i];
break;
}
}
if( !lst )
{
Con_Printf( "%s: unexpected token %s, must be group name\n", __func__, token );
goto cleanup;
}
p = COM_ParseFile( file, token, sizeof( token ));
// group is a range
if( !Q_strcmp( token, "{" ))
{
file = p; // advance pointer
if( !SoundList_ParseGroup( lst, &file ))
goto cleanup;
file = COM_ParseFile( file, token, sizeof( token ));
if( Q_strcmp( token, "}" ))
{
Con_Printf( "%s: unexpected token %s, must be }\n", __func__, token );
goto cleanup;
}
}
else
{
// ranges are more simple, but need to rewind pointer for them
if( !SoundList_ParseRange( lst, &file ))
goto cleanup;
}
}
if( host_developer.value >= 2 )
SoundList_Print_f();
return true;
cleanup:
SoundList_Shutdown();
return false;
}
static void SoundList_Print_f( void )
{
int i;
for( i = 0; i < SoundList_Groups; i++ )
{
soundlst_t *lst = &soundlst[i];
switch( lst->type )
{
case SoundList_Range:
Con_Reportf( "%-16s\t" S_CYAN "Range" S_DEFAULT " %s [%d; %d]\n",
soundlst_groups[i], lst->snd, lst->min, lst->max );
break;
case SoundList_List:
{
int j;
Con_Reportf( "%-16s\t" S_MAGENTA "List" S_DEFAULT " [", soundlst_groups[i] );
for( j = 0; j < lst->max; j++ )
Con_Reportf( "%s%s", &lst->snd[j * lst->min], j + 1 == lst->max ? "" : ", " );
Con_Reportf( "]\n" );
break;
}
default:
Con_Reportf( "%-16s\t" S_RED "inactive" S_DEFAULT "\n", soundlst_groups[i] );
break;
}
}
}
// I wish we had #embed already
static const char default_sounds_lst[] =
"BouncePlayerShell \"player/pl_shell%d.wav\" 1 3\n"
"BounceWeaponShell \"weapons/sshell%d.wav\" 1 3\n"
"BounceConcrete \"debris/concrete%d.wav\" 1 3\n"
"BounceGlass \"debris/glass%d.wav\" 1 4\n"
"BounceMetal \"debris/metal%d.wav\" 1 6\n"
"BounceFlesh \"debris/flesh%d.wav\" 1 7\n"
"BounceWood \"debris/wood%d.wav\" 1 4\n"
"Ricochet \"weapons/ric%d.wav\" 1 5\n"
"Explode \"weapons/explode%d.wav\" 3 5\n"
"EntityWaterEnter \"player/pl_wade%d.wav\" 1 4\n"
"EntityWaterExit \"player/pl_wade%d.wav\" 1 4\n"
"PlayerWaterEnter\n"
"{\n"
" \"player/pl_wade1.wav\"\n"
"}\n"
"\n"
"PlayerWaterExit\n"
"{\n"
" \"player/pl_wade2.wav\"\n"
"}\n";
static void SoundList_Reload_f( void )
{
qboolean load_internal = false;
char *pfile = FS_LoadFile( "scripts/sounds.lst", NULL, false );
if( pfile )
{
if( !SoundList_Parse( pfile ))
{
Con_Printf( S_ERROR "can't parse sounds.lst file, loading internal...\n" );
load_internal = true;
}
Mem_Free( pfile );
}
else load_internal = true;
if( load_internal )
SoundList_Parse( (char *)default_sounds_lst );
}
void SoundList_Init( void )
{
Cmd_AddRestrictedCommand( "host_soundlist_print", SoundList_Print_f, "print current sound list" );
Cmd_AddRestrictedCommand( "host_soundlist_reload", SoundList_Reload_f, "reload sound list" );
SoundList_Reload_f ();
}

View File

@@ -135,6 +135,10 @@ void Sys_InitLog( void )
mode = "a"; mode = "a";
else mode = "w"; else mode = "w";
if( Host_IsDedicated( ))
Q_strncpy( s_ld.title, XASH_DEDICATED_SERVER_NAME " " XASH_VERSION, sizeof( s_ld.title ));
else Q_strncpy( s_ld.title, XASH_ENGINE_NAME " " XASH_VERSION, sizeof( s_ld.title ));
// create log if needed // create log if needed
if( s_ld.log_active ) if( s_ld.log_active )
{ {
@@ -142,15 +146,18 @@ void Sys_InitLog( void )
if ( !s_ld.logfile ) 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 "Sys_InitLog: can't create log file %s: %s\n", s_ld.log_path, strerror( errno ));
return; return;
} }
s_ld.logfileno = fileno( s_ld.logfile ); s_ld.logfileno = fileno( s_ld.logfile );
fprintf( s_ld.logfile, "=================================================================================\n" ); // fit to 80 columns for easier read on standard terminal
fprintf( s_ld.logfile, "\t%s (build %i commit %s (%s-%s)) started at %s\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch(), Q_timestamp( TIME_FULL ) ); fputs( "================================================================================\n", s_ld.logfile );
fprintf( s_ld.logfile, "=================================================================================\n" ); 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, "Game started at %s\n", Q_timestamp( TIME_FULL ));
fputs( "================================================================================\n", s_ld.logfile );
fflush( s_ld.logfile );
} }
} }
@@ -177,12 +184,11 @@ void Sys_CloseLog( void )
if( s_ld.logfile ) if( s_ld.logfile )
{ {
fprintf( s_ld.logfile, "\n"); fputc( '\n', s_ld.logfile );
fprintf( s_ld.logfile, "================================================================================="); fputs( "================================================================================\n", s_ld.logfile );
if( host.change_game ) fprintf( s_ld.logfile, "\n\t%s (build %i) %s\n", s_ld.title, Q_buildnum(), event_name ); fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
else fprintf( s_ld.logfile, "\n\t%s (build %i) %s at %s\n", s_ld.title, Q_buildnum(), event_name, Q_timestamp( TIME_FULL )); fprintf( s_ld.logfile, "Stopped with reason \"%s\" at %s\n", event_name, Q_timestamp( TIME_FULL ));
fprintf( s_ld.logfile, "=================================================================================\n"); fputs( "================================================================================\n", s_ld.logfile );
fclose( s_ld.logfile ); fclose( s_ld.logfile );
s_ld.logfile = NULL; s_ld.logfile = NULL;
} }
@@ -335,15 +341,18 @@ void GAME_EXPORT Con_Printf( const char *szFmt, ... )
{ {
static char buffer[MAX_PRINT_MSG]; static char buffer[MAX_PRINT_MSG];
va_list args; va_list args;
qboolean add_newline;
if( !host.allow_console ) if( !host.allow_console )
return; return;
va_start( args, szFmt ); va_start( args, szFmt );
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ); add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
va_end( args ); va_end( args );
Sys_Print( buffer ); Sys_Print( buffer );
if( add_newline )
Sys_Print( "\n" );
} }
/* /*
@@ -356,18 +365,21 @@ void GAME_EXPORT Con_DPrintf( const char *szFmt, ... )
{ {
static char buffer[MAX_PRINT_MSG]; static char buffer[MAX_PRINT_MSG];
va_list args; va_list args;
qboolean add_newline;
if( host_developer.value < DEV_NORMAL ) if( host_developer.value < DEV_NORMAL )
return; return;
va_start( args, szFmt ); va_start( args, szFmt );
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ); add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
va_end( args ); va_end( args );
if( buffer[0] == '0' && buffer[1] == '\n' && buffer[2] == '\0' ) if( buffer[0] == '0' && buffer[1] == '\n' && buffer[2] == '\0' )
return; // hlrally spam return; // hlrally spam
Sys_Print( buffer ); Sys_Print( buffer );
if( add_newline )
Sys_Print( "\n" );
} }
/* /*
@@ -380,15 +392,18 @@ void Con_Reportf( const char *szFmt, ... )
{ {
static char buffer[MAX_PRINT_MSG]; static char buffer[MAX_PRINT_MSG];
va_list args; va_list args;
qboolean add_newline;
if( host_developer.value < DEV_EXTENDED ) if( host_developer.value < DEV_EXTENDED )
return; return;
va_start( args, szFmt ); va_start( args, szFmt );
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ); add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
va_end( args ); va_end( args );
Sys_Print( buffer ); Sys_Print( buffer );
if( add_newline )
Sys_Print( "\n" );
} }

View File

@@ -19,6 +19,10 @@ GNU General Public License for more details.
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
#if _MSC_VER
#include <intrin.h>
#endif
#ifdef XASH_SDL #ifdef XASH_SDL
#include <SDL.h> #include <SDL.h>
#endif #endif
@@ -49,7 +53,7 @@ GNU General Public License for more details.
#include "library.h" #include "library.h"
#include "whereami.h" #include "whereami.h"
qboolean error_on_exit = false; // arg for exit(); int error_on_exit = 0; // arg for exit();
/* /*
================ ================
@@ -68,17 +72,15 @@ Sys_DebugBreak
*/ */
void Sys_DebugBreak( void ) void Sys_DebugBreak( void )
{ {
#if XASH_LINUX || ( XASH_WIN32 && !XASH_64BIT )
#if _MSC_VER #if _MSC_VER
if( Sys_DebuggerPresent() ) if( Sys_DebuggerPresent( ))
_asm { int 3 } __debugbreak();
#elif XASH_X86 #else // !_MSC_VER
if( Sys_DebuggerPresent() ) if( Sys_DebuggerPresent( ))
asm volatile( "int $3;" ); {
#else INLINE_RAISE( SIGINT );
if( Sys_DebuggerPresent() ) INLINE_NANOSLEEP1(); // sometimes signal comes with delay, let it interrupt nanosleep
raise( SIGINT ); }
#endif
#endif #endif
} }
@@ -402,7 +404,7 @@ void Sys_Warn( const char *format, ... )
Msg( "Sys_Warn: %s\n", text ); Msg( "Sys_Warn: %s\n", text );
if( !Host_IsDedicated() ) // dedicated server should not hang on messagebox if( !Host_IsDedicated() ) // dedicated server should not hang on messagebox
Platform_MessageBox( "Xash Warning", text, false ); Platform_MessageBox( "Xash Warning", text, true );
} }
/* /*
@@ -428,7 +430,7 @@ void Sys_Error( const char *error, ... )
// make sure that console received last message // make sure that console received last message
if( host.change_game ) Sys_Sleep( 200 ); if( host.change_game ) Sys_Sleep( 200 );
error_on_exit = true; error_on_exit = 1;
host.status = HOST_ERR_FATAL; host.status = HOST_ERR_FATAL;
va_start( argptr, error ); va_start( argptr, error );
Q_vsnprintf( text, MAX_PRINT_MSG, error, argptr ); Q_vsnprintf( text, MAX_PRINT_MSG, error, argptr );
@@ -447,7 +449,7 @@ void Sys_Error( const char *error, ... )
Wcon_ShowConsole( false ); Wcon_ShowConsole( false );
#endif #endif
Sys_Print( text ); Sys_Print( text );
Platform_MessageBox( "Xash Error", text, false ); Platform_MessageBox( "Xash Error", text, true );
} }
else else
{ {

View File

@@ -41,7 +41,7 @@ NOTE: never change this structure because all dll descriptions in xash code
writes into struct by offsets not names writes into struct by offsets not names
======================================================================== ========================================================================
*/ */
extern int error_on_exit;
void Sys_Sleep( int msec ); void Sys_Sleep( int msec );
double Sys_DoubleTime( void ); double Sys_DoubleTime( void );
char *Sys_GetClipboardData( void ); char *Sys_GetClipboardData( void );

View File

@@ -39,13 +39,15 @@ void Test_RunCon( void );
void Test_RunVOX( void ); void Test_RunVOX( void );
void Test_RunIPFilter( void ); void Test_RunIPFilter( void );
void Test_RunGamma( void ); void Test_RunGamma( void );
void Test_RunDelta( void );
#define TEST_LIST_0 \ #define TEST_LIST_0 \
Test_RunLibCommon(); \ Test_RunLibCommon(); \
Test_RunCommon(); \ Test_RunCommon(); \
Test_RunCmd(); \ Test_RunCmd(); \
Test_RunCvar(); \ Test_RunCvar(); \
Test_RunIPFilter(); Test_RunIPFilter(); \
Test_RunDelta();
#define TEST_LIST_0_CLIENT \ #define TEST_LIST_0_CLIENT \
Test_RunCon(); \ Test_RunCon(); \

View File

@@ -25,18 +25,39 @@ GNU General Public License for more details.
#include "platform/swap/swap.h" #include "platform/swap/swap.h"
#define Q_malloc SWAP_Malloc #define Q_malloc SWAP_Malloc
#define Q_free SWAP_Free #define Q_free SWAP_Free
static void *Q_realloc( void *mem, size_t size )
{
void *newmem;
if( mem && size == 0 )
{
Q_free( mem );
return NULL;
}
newmem = Q_malloc( size );
if( mem && newmem )
{
memcpy( newmem, mem, size );
Q_free( mem );
}
return newmem;
}
#else #else
#define Q_malloc malloc #define Q_malloc malloc
#define Q_free free #define Q_free free
#define Q_realloc realloc
#endif #endif
typedef struct memheader_s typedef struct memheader_s
{ {
struct memheader_s *next; // next and previous memheaders in chain belonging to pool struct memheader_s *next; // next and previous memheaders in chain belonging to pool
struct memheader_s *prev; struct memheader_s *prev;
struct mempool_s *pool; // pool this memheader belongs to
size_t size; // size of the memory after the header (excluding header and sentinel2)
const char *filename; // file name and line where Mem_Alloc was called const char *filename; // file name and line where Mem_Alloc was called
size_t size; // size of the memory after the header (excluding header and sentinel2)
poolhandle_t poolptr; // pool this memheader belongs to
int fileline; int fileline;
#if !XASH_64BIT #if !XASH_64BIT
uint32_t pad0; // doesn't have value, only to make Mem_Alloc return aligned addresses on ILP32 uint32_t pad0; // doesn't have value, only to make Mem_Alloc return aligned addresses on ILP32
@@ -48,232 +69,321 @@ typedef struct memheader_s
typedef struct mempool_s typedef struct mempool_s
{ {
uint32_t sentinel1; // should always be MEMHEADER_SENTINEL1
struct memheader_s *chain; // chain of individual memory allocations struct memheader_s *chain; // chain of individual memory allocations
size_t totalsize; // total memory allocated in this pool (inside memheaders) size_t totalsize; // total memory allocated in this pool (inside memheaders)
size_t realsize; // total memory allocated in this pool (actual malloc total) size_t realsize; // total memory allocated in this pool (actual malloc total)
size_t lastchecksize; // updated each time the pool is displayed by memlist size_t lastchecksize; // updated each time the pool is displayed by memlist
struct mempool_s *next; // linked into global mempool list
const char *filename; // file name and line where Mem_AllocPool was called const char *filename; // file name and line where Mem_AllocPool was called
int fileline; int fileline;
#if XASH_64BIT
poolhandle_t idx;
#endif
char name[64]; // name of the pool char name[64]; // name of the pool
uint32_t sentinel2; // should always be MEMHEADER_SENTINEL1
} mempool_t; } mempool_t;
static mempool_t *poolchain = NULL; // critical stuff static mempool_t *poolchain = NULL; // critical stuff
static size_t poolcount = 0;
#if XASH_64BIT
// a1ba: due to mempool being passed with the model through reused 32-bit field // a1ba: due to mempool being passed with the model through reused 32-bit field
// which makes engine incompatible with 64-bit pointers I changed mempool type // which makes engine incompatible with 64-bit pointers I changed mempool type
// from pointer to 32-bit handle, thankfully mempool structure is private // from pointer to 32-bit handle, thankfully mempool structure is private
// But! Mempools are handled through linked list so we can't index them safely
static poolhandle_t lastidx = 0;
static mempool_t *Mem_FindPool( poolhandle_t poolptr ) static mempool_t *Mem_FindPool( poolhandle_t poolptr )
{ {
mempool_t *pool; if( likely( poolptr > 0 && poolptr <= poolcount ))
return &poolchain[poolptr - 1];
for( pool = poolchain; pool; pool = pool->next )
{
if( pool->idx == poolptr )
return pool;
}
Sys_Error( "%s: not allocated or double freed pool %d", __FUNCTION__, poolptr ); Sys_Error( "%s: not allocated or double freed pool %d", __FUNCTION__, poolptr );
return NULL; return NULL;
} }
#else
static mempool_t *Mem_FindPool( poolhandle_t poolptr ) static poolhandle_t Mem_PoolIndex( mempool_t *mempool )
{ {
return (mempool_t *)poolptr; return (poolhandle_t)(mempool - poolchain) + 1;
}
static inline void Mem_PoolAdd( mempool_t *pool, size_t size )
{
pool->totalsize += size;
pool->realsize += sizeof( memheader_t ) + size + sizeof( byte );
}
static inline void Mem_PoolSubtract( mempool_t *pool, size_t size )
{
pool->totalsize -= size;
pool->realsize -= sizeof( memheader_t ) + size + sizeof( byte );
}
static inline void Mem_PoolLinkAlloc( mempool_t *pool, memheader_t *mem )
{
mem->next = pool->chain;
if( mem->next ) mem->next->prev = mem;
pool->chain = mem;
mem->prev = NULL;
mem->poolptr = Mem_PoolIndex( pool );
}
static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
{
if( mem->next ) mem->next->prev = mem->prev;
if( mem->prev ) mem->prev->next = mem->next;
else pool->chain = mem->next;
mem->poolptr = 0;
}
static inline void Mem_InitAlloc( memheader_t *mem, size_t size, const char *filename, int fileline )
{
mem->size = size;
mem->filename = filename;
mem->fileline = fileline;
mem->sentinel1 = MEMHEADER_SENTINEL1;
*((byte *)mem + sizeof( memheader_t ) + mem->size ) = MEMHEADER_SENTINEL2;
}
static const char *Mem_CheckFilename( const char *filename )
{
static const char *dummy = "<corrupted>\0";
if( !COM_CheckString( filename ))
return dummy;
if( memchr( filename, '\0', MAX_OSPATH ) != NULL )
return filename;
return dummy;
}
static qboolean Mem_CheckAllocHeader( const char *func, const memheader_t *mem, const char *filename, int fileline )
{
const char *memfilename;
if( mem->sentinel1 != MEMHEADER_SENTINEL1 )
{
memfilename = Mem_CheckFilename( mem->filename );
Sys_Error( "%s: trashed header sentinel 1 (alloc at %s:%i, check at %s:%i)\n", func, memfilename, mem->fileline, filename, fileline );
return false;
}
if( *((byte *)mem + sizeof( memheader_t ) + mem->size ) != MEMHEADER_SENTINEL2 )
{
memfilename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
Sys_Error( "%s: trashed header sentinel 2 (alloc at %s:%i, check at %s:%i)\n", func, memfilename, mem->fileline, filename, fileline );
return false;
}
return true;
} }
#endif
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline ) void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
{ {
memheader_t *mem; memheader_t *mem;
mempool_t *pool; mempool_t *pool;
if( size <= 0 ) return NULL; if( size <= 0 )
if( !poolptr ) Sys_Error( "Mem_Alloc: pool == NULL (alloc at %s:%i)\n", filename, fileline ); return NULL;
if( unlikely( !poolptr ))
{
Sys_Error( "%s: pool == NULL (alloc at %s:%i)\n", __func__, filename, fileline );
return NULL;
}
pool = Mem_FindPool( poolptr ); pool = Mem_FindPool( poolptr );
if( !pool )
return NULL;
pool->totalsize += size; mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( byte ));
if( mem == NULL )
{
Sys_Error( "%s: out of memory (alloc size %s at %s:%i)\n", __func__, Q_memprint( size ), filename, fileline );
return NULL;
}
// big allocations are not clumped Mem_InitAlloc( mem, size, filename, fileline );
pool->realsize += sizeof( memheader_t ) + size + sizeof( size_t );
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( size_t )); Mem_PoolAdd( pool, size );
if( mem == NULL ) Sys_Error( "Mem_Alloc: out of memory (alloc at %s:%i)\n", filename, fileline ); Mem_PoolLinkAlloc( pool, mem );
mem->filename = filename;
mem->fileline = fileline;
mem->size = size;
mem->pool = pool;
mem->sentinel1 = MEMHEADER_SENTINEL1;
// we have to use only a single byte for this sentinel, because it may not be aligned
// and some platforms can't use unaligned accesses
*((byte *)mem + sizeof( memheader_t ) + mem->size ) = MEMHEADER_SENTINEL2;
// append to head of list
mem->next = pool->chain;
mem->prev = NULL;
pool->chain = mem;
if( mem->next ) mem->next->prev = mem;
if( clear ) if( clear )
memset((void *)((byte *)mem + sizeof( memheader_t )), 0, mem->size ); memset((void *)((byte *)mem + sizeof( memheader_t )), 0, mem->size );
return (void *)((byte *)mem + sizeof( memheader_t )); return (void *)((byte *)mem + sizeof( memheader_t ));
} }
static const char *Mem_CheckFilename( const char *filename )
{
static const char *dummy = "<corrupted>\0";
const char *out = filename;
int i;
if( !COM_CheckString( out ))
return dummy;
for( i = 0; i < MAX_OSPATH; i++, out++ )
{
if( *out == '\0' )
return filename; // valid name
}
return dummy;
}
static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline ) static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline )
{ {
mempool_t *pool; mempool_t *pool;
if( mem->sentinel1 != MEMHEADER_SENTINEL1 ) if( !Mem_CheckAllocHeader( __func__, mem, filename, fileline ))
{ return;
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
Sys_Error( "Mem_Free: trashed header sentinel 1 (alloc at %s:%i, free at %s:%i)\n", mem->filename, mem->fileline, filename, fileline );
}
if( *((byte *)mem + sizeof( memheader_t ) + mem->size ) != MEMHEADER_SENTINEL2 ) pool = Mem_FindPool( mem->poolptr );
{ if( !pool )
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args return;
Sys_Error( "Mem_Free: trashed header sentinel 2 (alloc at %s:%i, free at %s:%i)\n", mem->filename, mem->fileline, filename, fileline );
}
pool = mem->pool;
// unlink memheader from doubly linked list // unlink memheader from doubly linked list
if(( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem )) if(( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem ))
Sys_Error( "Mem_Free: not allocated or double freed (free at %s:%i)\n", filename, fileline ); {
Sys_Error( "%s: not allocated or double freed (free at %s:%i)\n", __func__, filename, fileline );
return;
}
if( mem->prev ) mem->prev->next = mem->next; Mem_PoolSubtract( pool, mem->size );
else pool->chain = mem->next; Mem_PoolUnlinkAlloc( pool, mem );
if( mem->next )
mem->next->prev = mem->prev;
// memheader has been unlinked, do the actual free now
pool->totalsize -= mem->size;
pool->realsize -= sizeof( memheader_t ) + mem->size + sizeof( size_t );
Q_free( mem ); Q_free( mem );
} }
void _Mem_Free( void *data, const char *filename, int fileline ) void _Mem_Free( void *data, const char *filename, int fileline )
{ {
if( data == NULL ) Sys_Error( "Mem_Free: data == NULL (called at %s:%i)\n", filename, fileline ); if( data == NULL )
{
Sys_Error( "Mem_Free: data == NULL (called at %s:%i)\n", filename, fileline );
return;
}
Mem_FreeBlock((memheader_t *)((byte *)data - sizeof( memheader_t )), filename, fileline ); Mem_FreeBlock((memheader_t *)((byte *)data - sizeof( memheader_t )), filename, fileline );
} }
void *_Mem_Realloc( poolhandle_t poolptr, void *memptr, size_t size, qboolean clear, const char *filename, int fileline ) void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clear, const char *filename, int fileline )
{ {
memheader_t *memhdr = NULL; memheader_t *mem;
char *nb; uintptr_t oldmem;
mempool_t *pool;
size_t oldsize;
if( size <= 0 ) return memptr; // no need to reallocate if( size <= 0 )
return data; // no need to reallocate
if( memptr ) if( unlikely( !poolptr ))
{ {
memhdr = (memheader_t *)((byte *)memptr - sizeof( memheader_t )); Sys_Error( "Mem_Realloc: pool == NULL (alloc at %s:%i)\n", filename, fileline );
if( size == memhdr->size ) return memptr; return NULL;
} }
nb = _Mem_Alloc( poolptr, size, clear, filename, fileline ); if( !data )
return _Mem_Alloc( poolptr, size, clear, filename, fileline );
if( memptr ) // first allocate? mem = (memheader_t *)((byte *)data - sizeof( memheader_t ));
if( !Mem_CheckAllocHeader( "Mem_Realloc", mem, filename, fileline ))
return NULL;
if( unlikely( mem->poolptr != poolptr ))
{ {
size_t newsize = memhdr->size < size ? memhdr->size : size; // upper data can be trucnated! Sys_Error( "Mem_Realloc: pool migration is not allowed (alloc at %s:%i, realloc at %s:%i)\n",
memcpy( nb, memptr, newsize ); Mem_CheckFilename( mem->filename ), mem->fileline, filename, fileline );
_Mem_Free( memptr, filename, fileline ); // free unused old block return NULL;
} }
return (void *)nb; oldsize = mem->size;
if( size == oldsize )
return data;
pool = Mem_FindPool( poolptr );
oldmem = (uintptr_t)mem;
mem = Q_realloc( mem, sizeof( memheader_t ) + size + sizeof( byte ));
if( mem == NULL )
{
Sys_Error( "Mem_Realloc: out of memory (alloc size %s at %s:%i)\n", Q_memprint( size ), filename, fileline );
return NULL;
}
// Con_Printf( S_NOTE "%s: mem %s oldmem, size before %zu now %zu (alloc at %s:%i)\n",
// __func__, (uintptr_t)mem != oldmem ? "!=" : "==", oldsize, size, filename, fileline );
Mem_InitAlloc( mem, size, filename, fileline );
if( size > oldsize )
{
Mem_PoolAdd( pool, size - oldsize );
if( clear )
memset((byte *)mem + sizeof( memheader_t ) + oldsize, 0, size - oldsize );
}
else Mem_PoolSubtract( pool, oldsize - size );
if( oldmem != (uintptr_t)mem ) // just relink pointers
{
if( mem->next ) mem->next->prev = mem;
if( mem->prev ) mem->prev->next = mem;
else pool->chain = mem;
}
return (void *)((byte *)mem + sizeof( memheader_t ));
}
static poolhandle_t Mem_InitPool( mempool_t *pool, const char *name, const char *filename, int fileline )
{
memset( pool, 0, sizeof( *pool ));
// fill header
pool->filename = filename;
pool->fileline = fileline;
pool->realsize = sizeof( mempool_t );
Q_strncpy( pool->name, name, sizeof( pool->name ));
return Mem_PoolIndex( pool );
} }
poolhandle_t _Mem_AllocPool( const char *name, const char *filename, int fileline ) poolhandle_t _Mem_AllocPool( const char *name, const char *filename, int fileline )
{ {
mempool_t *pool; mempool_t *pool;
size_t i;
pool = (mempool_t *)Q_malloc( sizeof( mempool_t )); for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
{
if( pool->filename == NULL )
return Mem_InitPool( pool, name, filename, fileline );
}
pool = (mempool_t *)Q_realloc( poolchain, sizeof( *poolchain ) * ( poolcount + 1 ));
if( pool == NULL ) if( pool == NULL )
{ {
Sys_Error( "Mem_AllocPool: out of memory (allocpool at %s:%i)\n", filename, fileline ); Sys_Error( "Mem_AllocPool: out of memory (allocpool at %s:%i)\n", filename, fileline );
return 0; return 0;
} }
memset( pool, 0, sizeof( mempool_t ));
// fill header
pool->sentinel1 = MEMHEADER_SENTINEL1;
pool->sentinel2 = MEMHEADER_SENTINEL1;
pool->filename = filename;
pool->fileline = fileline;
pool->chain = NULL;
pool->totalsize = 0;
pool->realsize = sizeof( mempool_t );
Q_strncpy( pool->name, name, sizeof( pool->name ));
pool->next = poolchain;
poolchain = pool; poolchain = pool;
pool = &poolchain[poolcount++];
#if XASH_64BIT return Mem_InitPool( pool, name, filename, fileline );
pool->idx = ++lastidx;
return pool->idx;
#else
return (poolhandle_t)pool;
#endif
} }
void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline ) void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline )
{ {
mempool_t *pool; mempool_t *pool;
mempool_t **chainaddress;
if( *poolptr && ( pool = Mem_FindPool( *poolptr ))) if( *poolptr && ( pool = Mem_FindPool( *poolptr )))
{ {
// unlink pool from chain if( !pool->filename )
for( chainaddress = &poolchain; *chainaddress && *chainaddress != pool; chainaddress = &((*chainaddress)->next)); {
if( *chainaddress != pool ) Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline ); Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
if( pool->sentinel1 != MEMHEADER_SENTINEL1 ) Sys_Error( "Mem_FreePool: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)\n", pool->filename, pool->fileline, filename, fileline ); *poolptr = 0;
if( pool->sentinel2 != MEMHEADER_SENTINEL1 ) Sys_Error( "Mem_FreePool: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)\n", pool->filename, pool->fileline, filename, fileline ); return;
*chainaddress = pool->next; }
// free memory owned by the pool // free memory owned by the pool
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline ); while( pool->chain )
Mem_FreeBlock( pool->chain, filename, fileline );
// free the pool itself // free the pool itself
memset( pool, 0xBF, sizeof( mempool_t )); memset( pool, 0xBF, sizeof( mempool_t ));
Q_free( pool ); pool->chain = NULL;
pool->filename = NULL; // mark as reusable
*poolptr = 0; *poolptr = 0;
} }
} }
void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline ) void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline )
{ {
mempool_t *pool = Mem_FindPool( poolptr ); mempool_t *pool;
if( !poolptr ) Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline ); if( unlikely( !poolptr ))
{
Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
return;
}
if( pool->sentinel1 != MEMHEADER_SENTINEL1 ) Sys_Error( "Mem_EmptyPool: trashed pool sentinel 1 (allocpool at %s:%i, emptypool at %s:%i)\n", pool->filename, pool->fileline, filename, fileline ); pool = Mem_FindPool( poolptr );
if( pool->sentinel2 != MEMHEADER_SENTINEL1 ) Sys_Error( "Mem_EmptyPool: trashed pool sentinel 2 (allocpool at %s:%i, emptypool at %s:%i)\n", pool->filename, pool->fileline, filename, fileline ); if( !pool )
return;
// free memory owned by the pool // free memory owned by the pool
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline ); while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
@@ -288,14 +398,20 @@ static qboolean Mem_CheckAlloc( mempool_t *pool, void *data )
// search only one pool // search only one pool
target = (memheader_t *)((byte *)data - sizeof( memheader_t )); target = (memheader_t *)((byte *)data - sizeof( memheader_t ));
for( header = pool->chain; header; header = header->next ) for( header = pool->chain; header; header = header->next )
if( header == target ) return true; {
if( header == target )
return true;
}
} }
else else
{ {
// search all pools // search all pools
for( pool = poolchain; pool; pool = pool->next ) size_t i;
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
{
if( Mem_CheckAlloc( pool, data )) if( Mem_CheckAlloc( pool, data ))
return true; return true;
}
} }
return false; return false;
} }
@@ -308,59 +424,35 @@ Check pointer for memory
qboolean Mem_IsAllocatedExt( poolhandle_t poolptr, void *data ) qboolean Mem_IsAllocatedExt( poolhandle_t poolptr, void *data )
{ {
mempool_t *pool = NULL; mempool_t *pool = NULL;
if( poolptr ) pool = Mem_FindPool( poolptr );
if( poolptr )
pool = Mem_FindPool( poolptr );
return Mem_CheckAlloc( pool, data ); return Mem_CheckAlloc( pool, data );
} }
static void Mem_CheckHeaderSentinels( void *data, const char *filename, int fileline )
{
memheader_t *mem;
if( data == NULL )
Sys_Error( "Mem_CheckSentinels: data == NULL (sentinel check at %s:%i)\n", filename, fileline );
mem = (memheader_t *)((byte *) data - sizeof(memheader_t));
if( mem->sentinel1 != MEMHEADER_SENTINEL1 )
{
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
Sys_Error( "Mem_CheckSentinels: trashed header sentinel 1 (block allocated at %s:%i, sentinel check at %s:%i)\n", mem->filename, mem->fileline, filename, fileline );
}
if( *((byte *)mem + sizeof(memheader_t) + mem->size) != MEMHEADER_SENTINEL2 )
{
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
Sys_Error( "Mem_CheckSentinels: trashed header sentinel 2 (block allocated at %s:%i, sentinel check at %s:%i)\n", mem->filename, mem->fileline, filename, fileline );
}
}
void _Mem_Check( const char *filename, int fileline ) void _Mem_Check( const char *filename, int fileline )
{ {
memheader_t *mem; memheader_t *mem;
mempool_t *pool; mempool_t *pool;
size_t i;
for( pool = poolchain; pool; pool = pool->next ) for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
{
if( pool->sentinel1 != MEMHEADER_SENTINEL1 )
Sys_Error( "Mem_CheckSentinelsGlobal: trashed pool sentinel 1 (allocpool at %s:%i, sentinel check at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
if( pool->sentinel2 != MEMHEADER_SENTINEL1 )
Sys_Error( "Mem_CheckSentinelsGlobal: trashed pool sentinel 2 (allocpool at %s:%i, sentinel check at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
}
for( pool = poolchain; pool; pool = pool->next )
for( mem = pool->chain; mem; mem = mem->next ) for( mem = pool->chain; mem; mem = mem->next )
Mem_CheckHeaderSentinels((void *)((byte *) mem + sizeof(memheader_t)), filename, fileline ); Mem_CheckAllocHeader( "Mem_CheckSentinels", mem, filename, fileline );
} }
void Mem_PrintStats( void ) void Mem_PrintStats( void )
{ {
size_t count = 0, size = 0, realsize = 0; size_t count = 0, size = 0, realsize = 0, i;
mempool_t *pool; mempool_t *pool;
Mem_Check(); Mem_Check();
for( pool = poolchain; pool; pool = pool->next ) for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
{ {
if( !pool->filename )
continue;
count++; count++;
size += pool->totalsize; size += pool->totalsize;
realsize += pool->realsize; realsize += pool->realsize;
@@ -374,31 +466,38 @@ void Mem_PrintList( size_t minallocationsize )
{ {
mempool_t *pool; mempool_t *pool;
memheader_t *mem; memheader_t *mem;
size_t i;
Mem_Check(); Mem_Check();
Con_Printf( "memory pool list:\n"" ^3size name\n"); Con_Printf( "memory pool list:\n" );
for( pool = poolchain; pool; pool = pool->next ) Con_Printf( "\t^3size\t\t\t\tname\n");
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
{ {
long changed_size = (long)pool->totalsize - (long)pool->lastchecksize; long changed_size = (long)pool->totalsize - (long)pool->lastchecksize;
if( !pool->filename )
continue;
// poolnames can contain color symbols, make sure what color is reset // poolnames can contain color symbols, make sure what color is reset
if( changed_size != 0 ) if( pool->lastchecksize != 0 && changed_size != 0 )
{ {
char sign = (changed_size < 0) ? '-' : '+'; char sign = (changed_size < 0) ? '-' : '+';
Con_Printf( "%10s (%10s actual) %s (^7%c%s change)\n", Q_memprint( pool->totalsize ), Q_memprint( pool->realsize ), Con_Printf( "%10s (%10s real)\t%s (^7%c%s change)\n", Q_memprint( pool->totalsize ), Q_memprint( pool->realsize ),
pool->name, sign, Q_memprint( abs( changed_size ))); pool->name, sign, Q_memprint( abs( changed_size )));
} }
else else
{ {
Con_Printf( "%5s (%5s actual) %s\n", Q_memprint( pool->totalsize ), Q_memprint( pool->realsize ), pool->name ); Con_Printf( "%10s (%10s real)\t%s\n", Q_memprint( pool->totalsize ), Q_memprint( pool->realsize ), pool->name );
} }
pool->lastchecksize = pool->totalsize; pool->lastchecksize = pool->totalsize;
for( mem = pool->chain; mem; mem = mem->next ) for( mem = pool->chain; mem; mem = mem->next )
{
if( mem->size >= minallocationsize ) if( mem->size >= minallocationsize )
Con_Printf( "%10s allocated at %s:%i\n", Q_memprint( mem->size ), mem->filename, mem->fileline ); Con_Printf( "%10s allocated at %s:%i\n", Q_memprint( mem->size ), mem->filename, mem->fileline );
}
} }
} }

View File

@@ -215,6 +215,7 @@ typedef struct ui_extendedfuncs_s {
// network address funcs // network address funcs
const char *(*pfnAdrToString)( const struct netadr_s a ); const char *(*pfnAdrToString)( const struct netadr_s a );
int (*pfnCompareAdr)( const void *a, const void *b ); // netadr_t int (*pfnCompareAdr)( const void *a, const void *b ); // netadr_t
void *(*pfnGetNativeObject)( const char *name );
} ui_extendedfuncs_t; } ui_extendedfuncs_t;
// deprecated export from old engine // deprecated export from old engine

View File

@@ -2,15 +2,30 @@
mobility_int.h - interface between engine and client for mobile platforms mobility_int.h - interface between engine and client for mobile platforms
Copyright (C) 2015 a1batross Copyright (C) 2015 a1batross
This program is free software: you can redistribute it and/or modify This is free and unencumbered software released into the public domain.
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, Anyone is free to copy, modify, publish, use, compile, sell, or
but WITHOUT ANY WARRANTY; without even the implied warranty of distribute this software, either in source code form or as a compiled
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the binary, for any purpose, commercial or non-commercial, and by any
GNU General Public License for more details. means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
*/ */
#pragma once #pragma once

View File

@@ -107,7 +107,10 @@ typedef struct server_physics_api_s
int (*pfnSaveFile)( const char *filename, const void *data, int len ); int (*pfnSaveFile)( const char *filename, const void *data, int len );
const byte *(*pfnLoadImagePixels)( const char *filename, int *width, int *height ); const byte *(*pfnLoadImagePixels)( const char *filename, int *width, int *height );
const char* (*pfnGetModelName)( int modelindex ); const char *(*pfnGetModelName)( int modelindex );
// FWGS extension
void *(*pfnGetNativeObject)( const char *object );
} server_physics_api_t; } server_physics_api_t;
// physic callbacks // physic callbacks

View File

@@ -61,23 +61,16 @@ Android_GetNativeObject
void *Android_GetNativeObject( const char *name ) void *Android_GetNativeObject( const char *name )
{ {
static const char *availObjects[] = { "JNIEnv", "ActivityClass", NULL }; if( !strcasecmp( name, "JNIEnv" ) )
void *object = NULL;
if( !name )
{ {
object = (void *)availObjects; return (void *)jni.env;
}
else if( !strcasecmp( name, "JNIEnv" ) )
{
object = (void *)jni.env;
} }
else if( !strcasecmp( name, "ActivityClass" ) ) else if( !strcasecmp( name, "ActivityClass" ) )
{ {
object = (void *)jni.actcls; return (void *)jni.actcls;
} }
return object; return NULL;
} }
/* /*

View File

@@ -52,7 +52,7 @@ static pid_t gettid( void )
static void *g_hsystemd; static void *g_hsystemd;
static int (*g_pfn_sd_notify)( int unset_environment, const char *state ); static int (*g_pfn_sd_notify)( int unset_environment, const char *state );
qboolean Sys_DebuggerPresent( void ) qboolean Platform_DebuggerPresent( void )
{ {
char buf[4096]; char buf[4096];
ssize_t num_read; ssize_t num_read;
@@ -111,6 +111,11 @@ void Linux_Init( void )
if( !Host_IsDedicated( )) if( !Host_IsDedicated( ))
return; return;
// manpage says sd_notify will send messages to socket in NOTIFY_SOCKET
// environment variable. Check if it's available.
if( getenv( "NOTIFY_SOCKET" ) == NULL )
return;
if(( g_hsystemd = dlopen( "libsystemd.so.0", RTLD_LAZY )) == NULL ) if(( g_hsystemd = dlopen( "libsystemd.so.0", RTLD_LAZY )) == NULL )
return; return;

View File

@@ -34,8 +34,8 @@ double Platform_DoubleTime( void );
void Platform_Sleep( int msec ); void Platform_Sleep( int msec );
void Platform_ShellExecute( const char *path, const char *parms ); void Platform_ShellExecute( const char *path, const char *parms );
void Platform_MessageBox( const char *title, const char *message, qboolean parentMainWindow ); void Platform_MessageBox( const char *title, const char *message, qboolean parentMainWindow );
qboolean Sys_DebuggerPresent( void ); // optional, see Sys_DebugBreak
void Platform_SetStatus( const char *status ); void Platform_SetStatus( const char *status );
qboolean Platform_DebuggerPresent( void );
// legacy iOS port functions // legacy iOS port functions
#if TARGET_OS_IOS #if TARGET_OS_IOS
@@ -64,6 +64,8 @@ const char *Android_LoadID( void );
void Android_SaveID( const char *id ); void Android_SaveID( const char *id );
void Android_Init( void ); void Android_Init( void );
void *Android_GetNativeObject( const char *name ); void *Android_GetNativeObject( const char *name );
int Android_GetKeyboardHeight( void );
void Android_Shutdown( void );
#endif #endif
#if XASH_WIN32 #if XASH_WIN32
@@ -140,6 +142,15 @@ static inline void Platform_Shutdown( void )
#endif #endif
} }
static inline qboolean Sys_DebuggerPresent( void )
{
#if XASH_LINUX || XASH_WIN32
return Platform_DebuggerPresent();
#else
return false;
#endif
}
/* /*
============================================================================== ==============================================================================
@@ -256,4 +267,89 @@ void VoiceCapture_Shutdown( void );
qboolean VoiceCapture_Activate( qboolean activate ); qboolean VoiceCapture_Activate( qboolean activate );
qboolean VoiceCapture_Lock( qboolean lock ); qboolean VoiceCapture_Lock( qboolean lock );
// this allows to make break in current line, without entering libc code
// libc built with -fomit-frame-pointer may just eat stack frame (hello, glibc), making entering libc even more useless
// calling syscalls directly allows to make break like if it was asm("int $3") on x86
#if XASH_LINUX && XASH_X86
#define INLINE_RAISE(x) asm volatile( "int $3;" );
#define INLINE_NANOSLEEP1() // nothing!
#elif XASH_LINUX && XASH_ARM && !XASH_64BIT
#define INLINE_RAISE(x) do \
{ \
int raise_pid = getpid(); \
int raise_tid = gettid(); \
int raise_sig = (x); \
__asm__ volatile ( \
"mov r7,#268\n\t" \
"mov r0,%0\n\t" \
"mov r1,%1\n\t" \
"mov r2,%2\n\t" \
"svc 0\n\t" \
: \
: "r"(raise_pid), "r"(raise_tid), "r"(raise_sig) \
: "r0", "r1", "r2", "r7", "memory" \
); \
} while( 0 )
#define INLINE_NANOSLEEP1() do \
{ \
struct timespec ns_t1 = {1, 0}; \
struct timespec ns_t2 = {0, 0}; \
__asm__ volatile ( \
"mov r7,#162\n\t" \
"mov r0,%0\n\t" \
"mov r1,%1\n\t" \
"svc 0\n\t" \
: \
: "r"(&ns_t1), "r"(&ns_t2) \
: "r0", "r1", "r7", "memory" \
); \
} while( 0 )
#elif XASH_LINUX && XASH_ARM && XASH_64BIT
#define INLINE_RAISE(x) do \
{ \
int raise_pid = getpid(); \
int raise_tid = gettid(); \
int raise_sig = (x); \
__asm__ volatile ( \
"mov x8,#131\n\t" \
"mov x0,%0\n\t" \
"mov x1,%1\n\t" \
"mov x2,%2\n\t" \
"svc 0\n\t" \
: \
: "r"(raise_pid), "r"(raise_tid), "r"(raise_sig) \
: "x0", "x1", "x2", "x8", "memory", "cc" \
); \
} while( 0 )
#define INLINE_NANOSLEEP1() do \
{ \
struct timespec ns_t1 = {1, 0}; \
struct timespec ns_t2 = {0, 0}; \
__asm__ volatile ( \
"mov x8,#101\n\t" \
"mov x0,%0\n\t" \
"mov x1,%1\n\t" \
"svc 0\n\t" \
: \
: "r"(&ns_t1), "r"(&ns_t2) \
: "x0", "x1", "x8", "memory", "cc" \
); \
} while( 0 )
#elif XASH_LINUX
#ifdef __NR_tgkill
#define INLINE_RAISE(x) syscall( __NR_tgkill, getpid(), gettid(), x )
#else // __NR_tgkill
#define INLINE_RAISE(x) raise(x)
#endif // __NR_tgkill
#define INLINE_NANOSLEEP1() do \
{ \
struct timespec ns_t1 = {1, 0}; \
struct timespec ns_t2 = {0, 0}; \
nanosleep( &ns_t1, &ns_t2 ); \
} while( 0 )
#else // generic
#define INLINE_RAISE(x) raise(x)
#define INLINE_NANOSLEEP1() sleep(1)
#endif // generic
#endif // PLATFORM_H #endif // PLATFORM_H

View File

@@ -212,8 +212,8 @@ const char *COM_NameForFunction( void *hInstance, void *function )
// NOTE: dladdr() is a glibc extension // NOTE: dladdr() is a glibc extension
{ {
Dl_info info = {0}; Dl_info info = {0};
dladdr( (void*)function, &info ); int ret = dladdr( (void*)function, &info );
if( info.dli_sname ) if( ret && info.dli_sname )
return COM_GetPlatformNeutralName( info.dli_sname ); return COM_GetPlatformNeutralName( info.dli_sname );
} }
#ifdef XASH_ALLOW_SAVERESTORE_OFFSETS #ifdef XASH_ALLOW_SAVERESTORE_OFFSETS

View File

@@ -374,14 +374,8 @@ static void SDLash_ActiveEvent( int gain )
{ {
host.status = HOST_FRAME; host.status = HOST_FRAME;
if( cls.key_dest == key_game ) if( cls.key_dest == key_game )
{
IN_ActivateMouse( ); IN_ActivateMouse( );
}
if( dma.initialized && snd_mute_losefocus.value )
{
SNDDMA_Activate( true );
}
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME; host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
if( vid_fullscreen.value == WINDOW_MODE_FULLSCREEN ) if( vid_fullscreen.value == WINDOW_MODE_FULLSCREEN )
VID_SetMode(); VID_SetMode();
@@ -397,14 +391,8 @@ static void SDLash_ActiveEvent( int gain )
#endif #endif
host.status = HOST_NOFOCUS; host.status = HOST_NOFOCUS;
if( cls.key_dest == key_game ) if( cls.key_dest == key_game )
{
IN_DeactivateMouse(); IN_DeactivateMouse();
}
if( dma.initialized && snd_mute_losefocus.value )
{
SNDDMA_Activate( false );
}
host.force_draw_version_time = host.realtime + 2.0; host.force_draw_version_time = host.realtime + 2.0;
VID_RestoreScreenResolution(); VID_RestoreScreenResolution();
} }
@@ -654,7 +642,9 @@ static void SDLash_EventFilter( SDL_Event *event )
SDLash_ActiveEvent( false ); SDLash_ActiveEvent( false );
break; break;
case SDL_WINDOWEVENT_RESIZED: case SDL_WINDOWEVENT_RESIZED:
#if !XASH_MOBILE_PLATFORM
if( vid_fullscreen.value == WINDOW_MODE_WINDOWED ) if( vid_fullscreen.value == WINDOW_MODE_WINDOWED )
#endif
{ {
SDL_Window *wnd = SDL_GetWindowFromID( event->window.windowID ); SDL_Window *wnd = SDL_GetWindowFromID( event->window.windowID );
VID_SaveWindowSize( event->window.data1, event->window.data2, VID_SaveWindowSize( event->window.data1, event->window.data2,

View File

@@ -44,6 +44,18 @@ Platform_GetMousePos
void GAME_EXPORT Platform_GetMousePos( int *x, int *y ) void GAME_EXPORT Platform_GetMousePos( int *x, int *y )
{ {
SDL_GetMouseState( x, y ); SDL_GetMouseState( x, y );
if( x && window_width.value && window_width.value != refState.width )
{
float factor = refState.width / window_width.value;
*x = *x * factor;
}
if( y && window_height.value && window_height.value != refState.height )
{
float factor = refState.height / window_height.value;
*y = *y * factor;
}
} }
/* /*

View File

@@ -576,10 +576,8 @@ static qboolean VID_SetScreenResolution( int width, int height, window_mode_t wi
SDL_DisplayMode got; SDL_DisplayMode got;
Uint32 wndFlags = 0; Uint32 wndFlags = 0;
#if !XASH_APPLE
if( vid_highdpi.value ) if( vid_highdpi.value )
SetBits( wndFlags, SDL_WINDOW_ALLOW_HIGHDPI ); SetBits( wndFlags, SDL_WINDOW_ALLOW_HIGHDPI );
#endif
SDL_SetWindowBordered( host.hWnd, SDL_FALSE ); SDL_SetWindowBordered( host.hWnd, SDL_FALSE );
@@ -744,7 +742,6 @@ qboolean VID_CreateWindow( int width, int height, window_mode_t window_mode )
if( !glw_state.software ) if( !glw_state.software )
SetBits( wndFlags, SDL_WINDOW_OPENGL ); SetBits( wndFlags, SDL_WINDOW_OPENGL );
#if !XASH_MOBILE_PLATFORM
if( window_mode == WINDOW_MODE_WINDOWED ) if( window_mode == WINDOW_MODE_WINDOWED )
{ {
SDL_Rect r; SDL_Rect r;
@@ -787,10 +784,6 @@ qboolean VID_CreateWindow( int width, int height, window_mode_t window_mode )
SetBits( wndFlags, SDL_WINDOW_BORDERLESS ); SetBits( wndFlags, SDL_WINDOW_BORDERLESS );
xpos = ypos = 0; xpos = ypos = 0;
} }
#else
SetBits( wndFlags, SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_INPUT_GRABBED );
xpos = ypos = SDL_WINDOWPOS_UNDEFINED;
#endif
if( !VID_CreateWindowWithSafeGL( wndname, xpos, ypos, width, height, wndFlags )) if( !VID_CreateWindowWithSafeGL( wndname, xpos, ypos, width, height, wndFlags ))
return false; return false;
@@ -799,14 +792,12 @@ qboolean VID_CreateWindow( int width, int height, window_mode_t window_mode )
if( FBitSet( SDL_GetWindowFlags( host.hWnd ), SDL_WINDOW_MAXIMIZED|SDL_WINDOW_FULLSCREEN_DESKTOP ) != 0 ) if( FBitSet( SDL_GetWindowFlags( host.hWnd ), SDL_WINDOW_MAXIMIZED|SDL_WINDOW_FULLSCREEN_DESKTOP ) != 0 )
SDL_GetWindowSize( host.hWnd, &width, &height ); SDL_GetWindowSize( host.hWnd, &width, &height );
#if !XASH_MOBILE_PLATFORM
if( window_mode != WINDOW_MODE_WINDOWED ) if( window_mode != WINDOW_MODE_WINDOWED )
{ {
if( !VID_SetScreenResolution( width, height, window_mode )) if( !VID_SetScreenResolution( width, height, window_mode ))
return false; return false;
} }
else VID_RestoreScreenResolution(); else VID_RestoreScreenResolution();
#endif
VID_SetWindowIcon( host.hWnd ); VID_SetWindowIcon( host.hWnd );
SDL_ShowWindow( host.hWnd ); SDL_ShowWindow( host.hWnd );
@@ -1175,6 +1166,14 @@ qboolean VID_SetMode( void )
#endif // SDL_VERSION_ATLEAST( 2, 0, 0 ) #endif // SDL_VERSION_ATLEAST( 2, 0, 0 )
} }
#if XASH_MOBILE_PLATFORM
if( Q_strcmp( vid_fullscreen.string, DEFAULT_FULLSCREEN ))
{
Cvar_DirectSet( &vid_fullscreen, DEFAULT_FULLSCREEN );
Con_Reportf( S_ERROR "VID_SetMode: windowed unavailable on this platform\n" );
}
#endif
if( !FBitSet( vid_fullscreen.flags, FCVAR_CHANGED )) if( !FBitSet( vid_fullscreen.flags, FCVAR_CHANGED ))
Cvar_DirectSet( &vid_fullscreen, DEFAULT_FULLSCREEN ); Cvar_DirectSet( &vid_fullscreen, DEFAULT_FULLSCREEN );
else else

View File

@@ -504,12 +504,12 @@ void Wcon_CreateConsole( void )
if( host.type == HOST_NORMAL ) if( host.type == HOST_NORMAL )
{ {
Q_strncpy( s_wcd.title, "Xash3D " XASH_VERSION, sizeof( s_wcd.title )); Q_strncpy( s_wcd.title, XASH_ENGINE_NAME " " XASH_VERSION, sizeof( s_wcd.title ));
Q_strncpy( s_wcd.log_path, "engine.log", sizeof( s_wcd.log_path )); Q_strncpy( s_wcd.log_path, "engine.log", sizeof( s_wcd.log_path ));
} }
else // dedicated console else // dedicated console
{ {
Q_strncpy( s_wcd.title, "XashDS " XASH_VERSION, sizeof( s_wcd.title )); Q_strncpy( s_wcd.title, XASH_DEDICATED_SERVER_NAME " " XASH_VERSION, sizeof( s_wcd.title ));
Q_strncpy( s_wcd.log_path, "dedicated.log", sizeof( s_wcd.log_path )); Q_strncpy( s_wcd.log_path, "dedicated.log", sizeof( s_wcd.log_path ));
s_wcd.log_active = true; // always make log s_wcd.log_active = true; // always make log
} }

View File

@@ -356,13 +356,13 @@ static void ListMissingModules( dll_user_t *hInst )
byte *data; byte *data;
char buf[MAX_VA_STRING]; char buf[MAX_VA_STRING];
if ( !hInst ) return; if( !hInst || !g_fsapi.LoadFile ) return;
data = FS_LoadFile( hInst->dllName, NULL, false ); data = g_fsapi.LoadFile( hInst->dllName, NULL, false );
if ( !data ) return; if( !data ) return;
importDesc = GetImportDescriptor( hInst->dllName, data, &peHeader ); importDesc = GetImportDescriptor( hInst->dllName, data, &peHeader );
if ( !importDesc ) if( !importDesc )
{ {
Mem_Free( data ); Mem_Free( data );
return; return;

View File

@@ -41,7 +41,7 @@ void Platform_Sleep( int msec )
} }
#endif // XASH_TIMER == TIMER_WIN32 #endif // XASH_TIMER == TIMER_WIN32
qboolean Sys_DebuggerPresent( void ) qboolean Platform_DebuggerPresent( void )
{ {
return IsDebuggerPresent(); return IsDebuggerPresent();
} }

View File

@@ -43,10 +43,9 @@ extern int SV_UPDATE_BACKUP;
#define SVF_MERGE_VISIBILITY BIT( 1 ) // we are do portal pass #define SVF_MERGE_VISIBILITY BIT( 1 ) // we are do portal pass
// mapvalid flags // mapvalid flags
#define MAP_IS_EXIST BIT( 0 ) #define MAP_IS_EXIST BIT( 0 )
#define MAP_HAS_SPAWNPOINT BIT( 1 ) #define MAP_HAS_LANDMARK BIT( 2 )
#define MAP_HAS_LANDMARK BIT( 2 ) #define MAP_INVALID_VERSION BIT( 3 )
#define MAP_INVALID_VERSION BIT( 3 )
#define SV_SPAWN_TIME 0.1 #define SV_SPAWN_TIME 0.1
@@ -613,11 +612,9 @@ string_t SV_MakeString( const char *szValue );
const char *SV_GetString( string_t iString ); const char *SV_GetString( string_t iString );
void SV_SetStringArrayMode( qboolean dynamic ); void SV_SetStringArrayMode( qboolean dynamic );
void SV_EmptyStringPool( void ); void SV_EmptyStringPool( void );
#ifdef XASH_64BIT
void SV_PrintStr64Stats_f( void ); void SV_PrintStr64Stats_f( void );
#endif
sv_client_t *SV_ClientFromEdict( const edict_t *pEdict, qboolean spawned_only ); sv_client_t *SV_ClientFromEdict( const edict_t *pEdict, qboolean spawned_only );
uint SV_MapIsValid( const char *filename, const char *spawn_entity, const char *landmark_name ); uint SV_MapIsValid( const char *filename, const char *landmark_name );
void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch ); void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch );
edict_t *SV_FindGlobalEntity( string_t classname, string_t globalname ); edict_t *SV_FindGlobalEntity( string_t classname, string_t globalname );
qboolean SV_CreateStaticEntity( struct sizebuf_s *msg, int index ); qboolean SV_CreateStaticEntity( struct sizebuf_s *msg, int index );
@@ -628,12 +625,18 @@ void SV_RestartAmbientSounds( void );
void SV_RestartDecals( void ); void SV_RestartDecals( void );
void SV_RestartStaticEnts( void ); void SV_RestartStaticEnts( void );
int pfnDropToFloor( edict_t* e ); int pfnDropToFloor( edict_t* e );
edict_t *SV_EdictNum( int n );
void SV_SetModel( edict_t *ent, const char *name ); void SV_SetModel( edict_t *ent, const char *name );
int pfnDecalIndex( const char *m ); int pfnDecalIndex( const char *m );
void SV_CreateDecal( sizebuf_t *msg, const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags, float scale ); void SV_CreateDecal( sizebuf_t *msg, const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags, float scale );
qboolean SV_RestoreCustomDecal( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent ); qboolean SV_RestoreCustomDecal( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent );
static inline edict_t *SV_EdictNum( int n )
{
if( likely( n >= 0 && n < GI->max_edicts ))
return &svgame.edicts[n];
return NULL;
}
// //
// sv_log.c // sv_log.c
// //

View File

@@ -453,6 +453,11 @@ static void SV_ConnectClient( netadr_t from )
// parse some info from the info strings (this can override cl_updaterate) // parse some info from the info strings (this can override cl_updaterate)
Q_strncpy( newcl->userinfo, userinfo, sizeof( newcl->userinfo )); Q_strncpy( newcl->userinfo, userinfo, sizeof( newcl->userinfo ));
newcl->fullupdate_next_calltime = 0;
newcl->userinfo_next_changetime = 0;
newcl->userinfo_penalty = 0;
newcl->userinfo_change_attempts = 0;
SV_UserinfoChanged( newcl ); SV_UserinfoChanged( newcl );
SV_ClearResourceLists( newcl ); SV_ClearResourceLists( newcl );
#if 0 #if 0
@@ -794,7 +799,7 @@ sv_client_t *SV_ClientById( int id )
ASSERT( id >= 0 ); ASSERT( id >= 0 );
for( i = 0, cl = svs.clients; i < svgame.globals->maxClients; i++, cl++ ) for( i = 0, cl = svs.clients; cl && i < svgame.globals->maxClients; i++, cl++ )
{ {
if( !cl->state ) if( !cl->state )
continue; continue;
@@ -814,7 +819,7 @@ sv_client_t *SV_ClientByName( const char *name )
if( !COM_CheckString( name )) if( !COM_CheckString( name ))
return NULL; return NULL;
for( i = 0, cl = svs.clients; i < svgame.globals->maxClients; i++, cl++ ) for( i = 0, cl = svs.clients; cl && i < svgame.globals->maxClients; i++, cl++ )
{ {
if( !cl->state ) if( !cl->state )
continue; continue;
@@ -1685,7 +1690,7 @@ static qboolean SV_New_f( sv_client_t *cl )
// server info string // server info string
MSG_BeginServerCmd( &msg, svc_stufftext ); MSG_BeginServerCmd( &msg, svc_stufftext );
MSG_WriteStringf( &msg, "fullserverinfo \"%s\"\n", SV_Serverinfo( )); MSG_WriteStringf( &msg, "fullserverinfo \"%s\"\n", svs.serverinfo );
// collect the info about all the players and send to me // collect the info about all the players and send to me
for( i = 0, cur = svs.clients; i < svs.maxclients; i++, cur++ ) for( i = 0, cur = svs.clients; i < svs.maxclients; i++, cur++ )
@@ -3453,7 +3458,7 @@ static void SV_ParseVoiceData( sv_client_t *cl, sizebuf_t *msg )
MSG_ReadBytes( msg, received, size ); MSG_ReadBytes( msg, received, size );
if( !sv_voiceenable.value ) if( !sv_voiceenable.value || svs.maxclients <= 1 )
return; return;
for( i = 0, cur = svs.clients; i < svs.maxclients; i++, cur++ ) for( i = 0, cur = svs.clients; i < svs.maxclients; i++, cur++ )

View File

@@ -169,17 +169,11 @@ SV_ValidateMap
check map for typically errors check map for typically errors
================== ==================
*/ */
static qboolean SV_ValidateMap( const char *pMapName, qboolean check_spawn ) static qboolean SV_ValidateMap( const char *pMapName )
{ {
char *spawn_entity;
int flags; int flags;
// determine spawn entity classname flags = SV_MapIsValid( pMapName, NULL );
if( !check_spawn || (int)sv_maxclients.value <= 1 )
spawn_entity = GI->sp_entity;
else spawn_entity = GI->mp_entity;
flags = SV_MapIsValid( pMapName, spawn_entity, NULL );
if( FBitSet( flags, MAP_INVALID_VERSION )) if( FBitSet( flags, MAP_INVALID_VERSION ))
{ {
@@ -193,12 +187,6 @@ static qboolean SV_ValidateMap( const char *pMapName, qboolean check_spawn )
return false; return false;
} }
if( check_spawn && !FBitSet( flags, MAP_HAS_SPAWNPOINT ))
{
Con_Printf( S_ERROR "map %s doesn't have a valid spawnpoint\n", pMapName );
return false;
}
return true; return true;
} }
@@ -224,7 +212,7 @@ static void SV_Map_f( void )
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname )); Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
COM_StripExtension( mapname ); COM_StripExtension( mapname );
if( !SV_ValidateMap( mapname, true )) if( !SV_ValidateMap( mapname ))
return; return;
Cvar_DirectSet( &sv_hostmap, mapname ); Cvar_DirectSet( &sv_hostmap, mapname );
@@ -296,7 +284,7 @@ static void SV_MapBackground_f( void )
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname )); Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
COM_StripExtension( mapname ); COM_StripExtension( mapname );
if( !SV_ValidateMap( mapname, false )) if( !SV_ValidateMap( mapname ))
return; return;
// background map is always run as singleplayer // background map is always run as singleplayer
@@ -346,7 +334,7 @@ static void SV_NextMap_f( void )
Cvar_DirectSet( &sv_hostmap, nextmap ); Cvar_DirectSet( &sv_hostmap, nextmap );
// found current point, check for valid // found current point, check for valid
if( SV_ValidateMap( nextmap, true )) if( SV_ValidateMap( nextmap ))
{ {
// found and valid // found and valid
COM_LoadLevel( nextmap, false ); COM_LoadLevel( nextmap, false );
@@ -368,13 +356,12 @@ SV_NewGame_f
*/ */
static void SV_NewGame_f( void ) static void SV_NewGame_f( void )
{ {
if( Cmd_Argc() != 1 ) if( Cmd_Argc() == 1 )
{ COM_NewGame( GI->startmap );
else if( Cmd_Argc() == 2 )
COM_NewGame( Cmd_Argv( 1 ));
else
Con_Printf( S_USAGE "newgame\n" ); Con_Printf( S_USAGE "newgame\n" );
return;
}
COM_NewGame( GI->startmap );
} }
/* /*
@@ -547,7 +534,7 @@ classic change level
*/ */
static void SV_ChangeLevel_f( void ) static void SV_ChangeLevel_f( void )
{ {
if( Cmd_Argc() != 2 ) if( Cmd_Argc() < 2 ) // allow extra arguments, for compatibility
{ {
Con_Printf( S_USAGE "changelevel <mapname>\n" ); Con_Printf( S_USAGE "changelevel <mapname>\n" );
return; return;
@@ -565,13 +552,15 @@ smooth change level
*/ */
static void SV_ChangeLevel2_f( void ) static void SV_ChangeLevel2_f( void )
{ {
if( Cmd_Argc() != 3 ) if( Cmd_Argc() < 2 ) // allow extra arguments, for compatibility
{ {
Con_Printf( S_USAGE "changelevel2 <mapname> <landmark>\n" ); Con_Printf( S_USAGE "changelevel2 <mapname> [landmark]\n" );
return; return;
} }
SV_QueueChangeLevel( Cmd_Argv( 1 ), Cmd_Argv( 2 )); if( Cmd_Argc() == 2 ) // with single argument, behaves like usual changelevel
SV_QueueChangeLevel( Cmd_Argv( 1 ), NULL );
else SV_QueueChangeLevel( Cmd_Argv( 1 ), Cmd_Argv( 2 ));
} }
/* /*
@@ -764,7 +753,7 @@ static void SV_ServerInfo_f( void )
} }
Info_SetValueForStarKey( svs.serverinfo, Cmd_Argv( 1 ), Cmd_Argv( 2 ), MAX_SERVERINFO_STRING ); Info_SetValueForStarKey( svs.serverinfo, Cmd_Argv( 1 ), Cmd_Argv( 2 ), MAX_SERVERINFO_STRING );
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", SV_Serverinfo( )); SV_BroadcastCommand( "fullserverinfo \"%s\"\n", svs.serverinfo );
} }
/* /*
@@ -1018,6 +1007,7 @@ void SV_InitOperatorCommands( void )
Cmd_AddCommand( "redirect", Rcon_Redirect_f, "force enable rcon redirection" ); Cmd_AddCommand( "redirect", Rcon_Redirect_f, "force enable rcon redirection" );
Cmd_AddCommand( "logaddress", SV_SetLogAddress_f, "sets address and port for remote logging host" ); Cmd_AddCommand( "logaddress", SV_SetLogAddress_f, "sets address and port for remote logging host" );
Cmd_AddCommand( "log", SV_ServerLog_f, "enables logging to file" ); Cmd_AddCommand( "log", SV_ServerLog_f, "enables logging to file" );
Cmd_AddCommand( "str64stats", SV_PrintStr64Stats_f, "print engine pool string statistics" );
if( host.type == HOST_NORMAL ) if( host.type == HOST_NORMAL )
{ {
@@ -1056,6 +1046,7 @@ void SV_KillOperatorCommands( void )
Cmd_RemoveCommand( "redirect" ); Cmd_RemoveCommand( "redirect" );
Cmd_RemoveCommand( "logaddress" ); Cmd_RemoveCommand( "logaddress" );
Cmd_RemoveCommand( "log" ); Cmd_RemoveCommand( "log" );
Cmd_RemoveCommand( "str64stats" );
if( host.type == HOST_NORMAL ) if( host.type == HOST_NORMAL )
{ {

View File

@@ -811,17 +811,17 @@ static void SV_UpdateToReliableMessages( void )
continue; // reliables go to all connected or spawned continue; // reliables go to all connected or spawned
if( MSG_GetNumBytesWritten( &sv.reliable_datagram ) < MSG_GetNumBytesLeft( &cl->netchan.message )) if( MSG_GetNumBytesWritten( &sv.reliable_datagram ) < MSG_GetNumBytesLeft( &cl->netchan.message ))
MSG_WriteBits( &cl->netchan.message, MSG_GetBuf( &sv.reliable_datagram ), MSG_GetNumBitsWritten( &sv.reliable_datagram )); MSG_WriteBits( &cl->netchan.message, MSG_GetData( &sv.reliable_datagram ), MSG_GetNumBitsWritten( &sv.reliable_datagram ));
else Netchan_CreateFragments( &cl->netchan, &sv.reliable_datagram ); else Netchan_CreateFragments( &cl->netchan, &sv.reliable_datagram );
if( MSG_GetNumBytesWritten( &sv.datagram ) < MSG_GetNumBytesLeft( &cl->datagram )) if( MSG_GetNumBytesWritten( &sv.datagram ) < MSG_GetNumBytesLeft( &cl->datagram ))
MSG_WriteBits( &cl->datagram, MSG_GetBuf( &sv.datagram ), MSG_GetNumBitsWritten( &sv.datagram )); MSG_WriteBits( &cl->datagram, MSG_GetData( &sv.datagram ), MSG_GetNumBitsWritten( &sv.datagram ));
else Con_DPrintf( S_WARN "Ignoring unreliable datagram for %s, would overflow\n", cl->name ); else Con_DPrintf( S_WARN "Ignoring unreliable datagram for %s, would overflow\n", cl->name );
if( FBitSet( cl->flags, FCL_HLTV_PROXY )) if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
{ {
if( MSG_GetNumBytesWritten( &sv.spec_datagram ) < MSG_GetNumBytesLeft( &cl->datagram )) if( MSG_GetNumBytesWritten( &sv.spec_datagram ) < MSG_GetNumBytesLeft( &cl->datagram ))
MSG_WriteBits( &cl->datagram, MSG_GetBuf( &sv.spec_datagram ), MSG_GetNumBitsWritten( &sv.spec_datagram )); MSG_WriteBits( &cl->datagram, MSG_GetData( &sv.spec_datagram ), MSG_GetNumBitsWritten( &sv.spec_datagram ));
else Con_DPrintf( S_WARN "Ignoring spectator datagram for %s, would overflow\n", cl->name ); else Con_DPrintf( S_WARN "Ignoring spectator datagram for %s, would overflow\n", cl->name );
} }
} }

View File

@@ -39,13 +39,6 @@ static vec3_t viewPoint[MAX_CLIENTS];
typedef void (__cdecl *LINK_ENTITY_FUNC)( entvars_t *pev ); typedef void (__cdecl *LINK_ENTITY_FUNC)( entvars_t *pev );
typedef void (__stdcall *GIVEFNPTRSTODLL)( enginefuncs_t* engfuncs, globalvars_t *pGlobals ); typedef void (__stdcall *GIVEFNPTRSTODLL)( enginefuncs_t* engfuncs, globalvars_t *pGlobals );
edict_t *SV_EdictNum( int n )
{
if(( n >= 0 ) && ( n < GI->max_edicts ))
return svgame.edicts + n;
return NULL;
}
#ifndef NDEBUG #ifndef NDEBUG
qboolean SV_CheckEdict( const edict_t *e, const char *file, const int line ) qboolean SV_CheckEdict( const edict_t *e, const char *file, const int line )
{ {
@@ -150,18 +143,6 @@ char *SV_Serverinfo( void )
return svs.serverinfo; return svs.serverinfo;
} }
/*
=============
SV_LocalInfo
get local infostring
=============
*/
static char *SV_Localinfo( void )
{
return svs.localinfo;
}
/* /*
============= =============
SV_AngleMod SV_AngleMod
@@ -268,7 +249,6 @@ SV_SetModel
void GAME_EXPORT SV_SetModel( edict_t *ent, const char *modelname ) void GAME_EXPORT SV_SetModel( edict_t *ent, const char *modelname )
{ {
char name[MAX_QPATH]; char name[MAX_QPATH];
qboolean found = false;
model_t *mod; model_t *mod;
int i = 1; int i = 1;
@@ -778,7 +758,6 @@ void SV_QueueChangeLevel( const char *level, const char *landname )
{ {
uint flags, smooth = false; uint flags, smooth = false;
char mapname[MAX_QPATH]; char mapname[MAX_QPATH];
char *spawn_entity;
// hold mapname to other place // hold mapname to other place
Q_strncpy( mapname, level, sizeof( mapname )); Q_strncpy( mapname, level, sizeof( mapname ));
@@ -787,12 +766,7 @@ void SV_QueueChangeLevel( const char *level, const char *landname )
if( COM_CheckString( landname )) if( COM_CheckString( landname ))
smooth = true; smooth = true;
// determine spawn entity classname flags = SV_MapIsValid( mapname, landname );
if( svs.maxclients == 1 )
spawn_entity = GI->sp_entity;
else spawn_entity = GI->mp_entity;
flags = SV_MapIsValid( mapname, spawn_entity, landname );
if( FBitSet( flags, MAP_INVALID_VERSION )) if( FBitSet( flags, MAP_INVALID_VERSION ))
{ {
@@ -826,15 +800,6 @@ void SV_QueueChangeLevel( const char *level, const char *landname )
return; return;
} }
if( !smooth && !FBitSet( flags, MAP_HAS_SPAWNPOINT ))
{
if( sv_validate_changelevel.value )
{
Con_Printf( S_ERROR "changelevel: %s doesn't have a valid spawnpoint. Ignored.\n", mapname );
return;
}
}
// bad changelevel position invoke enables in one-way transition // bad changelevel position invoke enables in one-way transition
if( sv.framecount < 15 ) if( sv.framecount < 15 )
{ {
@@ -864,7 +829,6 @@ void SV_WriteEntityPatch( const char *filename )
int lumpofs = 0, lumplen = 0; int lumpofs = 0, lumplen = 0;
byte buf[MAX_TOKEN]; // 1 kb byte buf[MAX_TOKEN]; // 1 kb
string bspfilename; string bspfilename;
dheader_t *header;
dlump_t entities; dlump_t entities;
file_t *f; file_t *f;
@@ -875,7 +839,6 @@ void SV_WriteEntityPatch( const char *filename )
memset( buf, 0, MAX_TOKEN ); memset( buf, 0, MAX_TOKEN );
FS_Read( f, buf, MAX_TOKEN ); FS_Read( f, buf, MAX_TOKEN );
header = (dheader_t *)buf;
// check all the lumps and some other errors // check all the lumps and some other errors
if( !Mod_TestBmodelLumps( f, bspfilename, buf, true, &entities )) if( !Mod_TestBmodelLumps( f, bspfilename, buf, true, &entities ))
@@ -915,7 +878,6 @@ static char *SV_ReadEntityScript( const char *filename, int *flags )
int lumpofs = 0, lumplen = 0; int lumpofs = 0, lumplen = 0;
byte buf[MAX_TOKEN]; byte buf[MAX_TOKEN];
char *ents = NULL; char *ents = NULL;
dheader_t *header;
dlump_t entities; dlump_t entities;
size_t ft1, ft2; size_t ft1, ft2;
file_t *f; file_t *f;
@@ -930,7 +892,6 @@ static char *SV_ReadEntityScript( const char *filename, int *flags )
SetBits( *flags, MAP_IS_EXIST ); SetBits( *flags, MAP_IS_EXIST );
memset( buf, 0, MAX_TOKEN ); memset( buf, 0, MAX_TOKEN );
FS_Read( f, buf, MAX_TOKEN ); FS_Read( f, buf, MAX_TOKEN );
header = (dheader_t *)buf;
// check all the lumps and some other errors // check all the lumps and some other errors
if( !Mod_TestBmodelLumps( f, bspfilename, buf, (host_developer.value) ? false : true, &entities )) if( !Mod_TestBmodelLumps( f, bspfilename, buf, (host_developer.value) ? false : true, &entities ))
@@ -977,7 +938,7 @@ SV_MapIsValid
Validate map Validate map
============== ==============
*/ */
uint SV_MapIsValid( const char *filename, const char *spawn_entity, const char *landmark_name ) uint SV_MapIsValid( const char *filename, const char *landmark_name )
{ {
uint flags = 0; uint flags = 0;
char *pfile; char *pfile;
@@ -993,45 +954,27 @@ uint SV_MapIsValid( const char *filename, const char *spawn_entity, const char *
need_landmark = COM_CheckString( landmark_name ); need_landmark = COM_CheckString( landmark_name );
// g-cont. in-dev mode we can entering on map even without "info_player_start" if( !need_landmark )
if( !need_landmark && host_developer.value )
{ {
// not transition
Mem_Free( ents ); Mem_Free( ents );
// skip spawnpoint checks in devmode return flags;
return (flags|MAP_HAS_SPAWNPOINT);
} }
pfile = ents; pfile = ents;
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL ) while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
{ {
if( !Q_strcmp( token, "classname" )) if( !Q_strcmp( token, "targetname" ))
{
// check classname for spawn entity
pfile = COM_ParseFile( pfile, check_name, sizeof( check_name ));
if( !Q_strcmp( spawn_entity, check_name ))
{
SetBits( flags, MAP_HAS_SPAWNPOINT );
// we already find landmark, stop the parsing
if( need_landmark && FBitSet( flags, MAP_HAS_LANDMARK ))
break;
}
}
else if( need_landmark && !Q_strcmp( token, "targetname" ))
{ {
// check targetname for landmark entity // check targetname for landmark entity
pfile = COM_ParseFile( pfile, check_name, sizeof( check_name )); pfile = COM_ParseFile( pfile, check_name, sizeof( check_name ));
if( !Q_strcmp( landmark_name, check_name )) if( !Q_strcmp( landmark_name, check_name ))
{ {
// we found landmark, stop the parsing
SetBits( flags, MAP_HAS_LANDMARK ); SetBits( flags, MAP_HAS_LANDMARK );
break;
// we already find spawnpoint, stop the parsing
if( FBitSet( flags, MAP_HAS_SPAWNPOINT ))
break;
} }
} }
} }
@@ -1174,15 +1117,22 @@ static LINK_ENTITY_FUNC SV_GetEntityClass( const char *pszClassName )
SV_AllocPrivateData SV_AllocPrivateData
allocate private data for a given edict allocate private data for a given edict
if customentity is NULL, no "custom" entity EXPORT is being done
if customentity is not NULL, will be set to true if "custom" export
was used to create this entity
============== ==============
*/ */
static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className ) static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className, qboolean *customentity )
{ {
const char *pszClassName; const char *pszClassName;
LINK_ENTITY_FUNC SpawnEdict; LINK_ENTITY_FUNC SpawnEdict;
pszClassName = STRING( className ); pszClassName = STRING( className );
if( customentity )
*customentity = false;
if( !ent ) if( !ent )
{ {
// allocate a new one // allocate a new one
@@ -1205,19 +1155,21 @@ static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className )
if( svgame.physFuncs.SV_CreateEntity && svgame.physFuncs.SV_CreateEntity( ent, pszClassName ) != -1 ) if( svgame.physFuncs.SV_CreateEntity && svgame.physFuncs.SV_CreateEntity( ent, pszClassName ) != -1 )
return ent; return ent;
SpawnEdict = SV_GetEntityClass( "custom" ); if( customentity )
{
SpawnEdict = SV_GetEntityClass( "custom" );
*customentity = SpawnEdict != NULL;
}
if( !SpawnEdict ) if( !SpawnEdict )
{ {
Con_Printf( S_ERROR "No spawn function for %s\n", STRING( className )); Con_Printf( S_ERROR "No spawn function for \"%s\"\n", pszClassName );
// free entity immediately // free entity immediately
SV_FreeEdict( ent ); SV_FreeEdict( ent );
return NULL; return NULL;
} }
SetBits( ent->v.flags, FL_CUSTOMENTITY ); // it's a custom entity but not a beam!
} }
SpawnEdict( &ent->v ); SpawnEdict( &ent->v );
@@ -1234,12 +1186,7 @@ create specified entity, alloc private data
*/ */
edict_t* SV_CreateNamedEntity( edict_t *ent, string_t className ) edict_t* SV_CreateNamedEntity( edict_t *ent, string_t className )
{ {
edict_t *ed = SV_AllocPrivateData( ent, className ); return SV_AllocPrivateData( ent, className, NULL );
// for some reasons this flag should be immediately cleared
if( ed ) ClearBits( ed->v.flags, FL_CUSTOMENTITY );
return ed;
} }
/* /*
@@ -2851,8 +2798,10 @@ standard path to register game variable
static void GAME_EXPORT pfnCvar_RegisterServerVariable( cvar_t *variable ) static void GAME_EXPORT pfnCvar_RegisterServerVariable( cvar_t *variable )
{ {
if( variable != NULL ) if( variable != NULL )
{
SetBits( variable->flags, FCVAR_EXTDLL ); SetBits( variable->flags, FCVAR_EXTDLL );
Cvar_RegisterVariable( (convar_t *)variable ); Cvar_RegisterVariable( (convar_t *)variable );
}
} }
/* /*
@@ -3218,7 +3167,9 @@ string_t GAME_EXPORT SV_AllocString( const char *szValue )
{ {
char *newString = NULL; char *newString = NULL;
uint len; uint len;
#ifdef XASH_64BIT
int cmp; int cmp;
#endif
if( svgame.physFuncs.pfnAllocString != NULL ) if( svgame.physFuncs.pfnAllocString != NULL )
{ {
@@ -3281,19 +3232,21 @@ string_t GAME_EXPORT SV_AllocString( const char *szValue )
#endif #endif
} }
#ifdef XASH_64BIT
void SV_PrintStr64Stats_f( void ) void SV_PrintStr64Stats_f( void )
{ {
Msg( "====================\n" ); #ifdef XASH_64BIT
Msg( "64 bit string pool statistics\n" ); Con_Printf( "====================\n" );
Msg( "====================\n" ); Con_Printf( "64 bit string pool statistics\n" );
Msg( "string array size: %lu\n", str64.maxstringarray ); Con_Printf( "====================\n" );
Msg( "total alloc %lu\n", str64.totalalloc ); Con_Printf( "string array size: %lu\n", str64.maxstringarray );
Msg( "maximum array usage: %lu\n", str64.maxalloc ); Con_Printf( "total alloc %lu\n", str64.totalalloc );
Msg( "overflow counter: %lu\n", str64.numoverflows ); Con_Printf( "maximum array usage: %lu\n", str64.maxalloc );
Msg( "dup string counter: %lu\n", str64.numdups ); Con_Printf( "overflow counter: %lu\n", str64.numoverflows );
} Con_Printf( "dup string counter: %lu\n", str64.numdups );
#else
Con_Printf( "Not implemented\n" );
#endif #endif
}
/* /*
============= =============
@@ -3391,12 +3344,10 @@ pfnPEntityOfEntIndex
============= =============
*/ */
static edict_t *pfnPEntityOfEntIndex( int iEntIndex ) static edict_t *pfnPEntityOfEntIndexBroken( int iEntIndex )
{ {
// have to be bug-compatible with GoldSrc in this function // have to be bug-compatible with GoldSrc in this function
if( host.bugcomp == BUGCOMP_GOLDSRC ) return SV_PEntityOfEntIndex( iEntIndex, false );
return SV_PEntityOfEntIndex( iEntIndex, false );
return SV_PEntityOfEntIndex( iEntIndex, true );
} }
/* /*
@@ -3737,9 +3688,9 @@ vaild map must contain one info_player_deatchmatch
*/ */
int GAME_EXPORT pfnIsMapValid( char *filename ) int GAME_EXPORT pfnIsMapValid( char *filename )
{ {
uint flags = SV_MapIsValid( filename, GI->mp_entity, NULL ); uint flags = SV_MapIsValid( filename, NULL );
if( FBitSet( flags, MAP_IS_EXIST ) && FBitSet( flags, MAP_HAS_SPAWNPOINT )) if( FBitSet( flags, MAP_IS_EXIST ))
return true; return true;
return false; return false;
} }
@@ -3873,11 +3824,11 @@ static char *GAME_EXPORT pfnGetInfoKeyBuffer( edict_t *e )
// NULL passes localinfo // NULL passes localinfo
if( !SV_IsValidEdict( e )) if( !SV_IsValidEdict( e ))
return SV_Localinfo(); return svs.localinfo;
// world passes serverinfo // world passes serverinfo
if( e == svgame.edicts ) if( e == svgame.edicts )
return SV_Serverinfo(); return svs.serverinfo;
// userinfo for specified edict // userinfo for specified edict
if(( cl = SV_ClientFromEdict( e, false )) != NULL ) if(( cl = SV_ClientFromEdict( e, false )) != NULL )
@@ -4731,7 +4682,7 @@ static enginefuncs_t gEngfuncs =
pfnPEntityOfEntOffset, pfnPEntityOfEntOffset,
pfnEntOffsetOfPEntity, pfnEntOffsetOfPEntity,
pfnIndexOfEdict, pfnIndexOfEdict,
pfnPEntityOfEntIndex, pfnPEntityOfEntIndexAllEntities,
pfnFindEntityByVars, pfnFindEntityByVars,
pfnGetModelPtr, pfnGetModelPtr,
pfnRegUserMsg, pfnRegUserMsg,
@@ -4820,6 +4771,15 @@ static enginefuncs_t gEngfuncs =
pfnPEntityOfEntIndexAllEntities, pfnPEntityOfEntIndexAllEntities,
}; };
static void SV_FreeKeyValueStrings( KeyValueData *kvd, int numpairs )
{
for( int i = 0; i < numpairs; i++ )
{
Mem_Free( kvd[i].szKeyName );
Mem_Free( kvd[i].szValue );
}
}
/* /*
==================== ====================
SV_ParseEdict SV_ParseEdict
@@ -4831,36 +4791,34 @@ ed should be a properly initialized empty edict.
static qboolean SV_ParseEdict( char **pfile, edict_t *ent ) static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
{ {
KeyValueData pkvd[256]; // per one entity KeyValueData pkvd[256]; // per one entity
qboolean adjust_origin = false; qboolean adjust_origin = false, customentity;
int i, numpairs = 0; int i, numpairs = 0;
char *classname = NULL; const char *classname = NULL;
char token[2048];
vec3_t origin;
// go through all the dictionary pairs // go through all the dictionary pairs
while( 1 ) while( 1 )
{ {
string keyname; string keyname;
char value[2048];
int len;
// parse key // parse key
if(( *pfile = COM_ParseFile( *pfile, token, sizeof( token ))) == NULL ) if(( *pfile = COM_ParseFile( *pfile, keyname, sizeof( keyname ))) == NULL )
Host_Error( "ED_ParseEdict: EOF without closing brace\n" ); Host_Error( "ED_ParseEdict: EOF without closing brace\n" );
if( token[0] == '}' ) break; // end of desc
Q_strncpy( keyname, token, sizeof( keyname )); if( keyname[0] == '}' )
break; // end of desc
// parse value // parse value
if(( *pfile = COM_ParseFile( *pfile, token, sizeof( token ))) == NULL ) if(( *pfile = COM_ParseFile( *pfile, value, sizeof( value ))) == NULL )
Host_Error( "ED_ParseEdict: EOF without closing brace\n" ); Host_Error( "ED_ParseEdict: EOF without closing brace\n" );
if( token[0] == '}' ) if( value[0] == '}' )
Host_Error( "ED_ParseEdict: closing brace without data\n" ); Host_Error( "ED_ParseEdict: closing brace without data\n" );
// ignore attempts to set key "" // ignore attempts to set empty key or value
if( !keyname[0] ) continue;
// "wad" field is already handled // "wad" field is already handled
if( !Q_strcmp( keyname, "wad" )) if( !keyname[0] || !value[0] || !Q_strcmp( keyname, "wad" ))
continue; continue;
// keynames with a leading underscore are used for // keynames with a leading underscore are used for
@@ -4868,57 +4826,83 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
if( FBitSet( world.flags, FWORLD_SKYSPHERE ) && keyname[0] == '_' ) if( FBitSet( world.flags, FWORLD_SKYSPHERE ) && keyname[0] == '_' )
continue; continue;
// ignore attempts to set value "" // classname must be first
if( !token[0] ) continue; if( !Q_strcmp( keyname, "classname" ))
{
KeyValueData kvd = {
.szClassName = NULL,
.szKeyName = keyname,
.szValue = value,
.fHandled = false
};
// don't allow double classnames
if( classname != NULL )
continue;
svgame.dllFuncs.pfnKeyValue( ent, &kvd );
// ideally, all game dlls should handle classname.
// throw an error for now, improve the logic if it causes
// compatibility issues with Xash-based games
if( !kvd.fHandled )
Host_Error( "%s: game didn't handled \"%s\" classname\n", __func__, value );
// this lets game dll override custom entity classname
// to something bogus that's exported in game dll
classname = STRING( ent->v.classname );
continue;
}
// GoldSrc removes trailing spaces
// but does this after sucking out classname
// which doesn't have similar check
for( len = Q_strlen( keyname ); len > 0 && keyname[len - 1] == ' '; len-- )
keyname[len - 1] = '\0';
// create keyvalue strings // create keyvalue strings
pkvd[numpairs].szClassName = (char*)""; // unknown at this moment pkvd[numpairs].szClassName = (char*)""; // unknown at this moment
pkvd[numpairs].szKeyName = copystring( keyname ); pkvd[numpairs].szKeyName = copystring( keyname );
pkvd[numpairs].szValue = copystring( token ); pkvd[numpairs].szValue = copystring( value );
pkvd[numpairs].fHandled = false; pkvd[numpairs].fHandled = false;
numpairs++;
if( !Q_strcmp( keyname, "classname" ) && classname == NULL ) if( numpairs > ARRAYSIZE( pkvd ))
classname = copystring( pkvd[numpairs].szValue ); {
if( ++numpairs >= 256 ) break; if( classname )
Con_Printf( S_ERROR "%s: too many keyvalue pairs for %s!\n", __func__, classname );
else Con_Printf( S_ERROR "%s: too many keyvalue pairs!\n", __func__ );
break;
}
} }
if( classname == NULL ) if( classname == NULL )
{ {
// release allocated strings // release allocated strings
for( i = 0; i < numpairs; i++ ) SV_FreeKeyValueStrings( pkvd, numpairs );
{
Mem_Free( pkvd[i].szKeyName );
Mem_Free( pkvd[i].szValue );
}
return false; return false;
} }
ent = SV_AllocPrivateData( ent, ALLOC_STRING( classname )); ent = SV_AllocPrivateData( ent, ent->v.classname, &customentity );
if( !SV_IsValidEdict( ent ) || FBitSet( ent->v.flags, FL_KILLME )) if( !SV_IsValidEdict( ent ) || FBitSet( ent->v.flags, FL_KILLME ))
{ {
// release allocated strings // release allocated strings
for( i = 0; i < numpairs; i++ ) SV_FreeKeyValueStrings( pkvd, numpairs );
{
Mem_Free( pkvd[i].szKeyName );
Mem_Free( pkvd[i].szValue );
}
return false; return false;
} }
if( FBitSet( ent->v.flags, FL_CUSTOMENTITY )) if( customentity )
{ {
if( numpairs < 256 ) KeyValueData kvd = {
{ .szClassName = (char *)"custom",
pkvd[numpairs].szClassName = (char*)"custom"; .szKeyName = (char *)"customclass",
pkvd[numpairs].szKeyName = (char*)"customclass"; .szValue = (char *)classname,
pkvd[numpairs].szValue = classname; .fHandled = false
pkvd[numpairs].fHandled = false; };
numpairs++;
}
// clear it now - no longer used svgame.dllFuncs.pfnKeyValue( ent, &kvd );
ClearBits( ent->v.flags, FL_CUSTOMENTITY ); // no fHandled check, GoldSrc behavior
} }
#ifdef HACKS_RELATED_HLMODS #ifdef HACKS_RELATED_HLMODS
@@ -4932,6 +4916,14 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
for( i = 0; i < numpairs; i++ ) for( i = 0; i < numpairs; i++ )
{ {
char *keyname, *value;
char temp[MAX_VA_STRING];
#if 0 // this is stupid bug in GoldSrc, disable
if( !Q_strcmp( pkvd[i].szValue, classname ))
continue;
#endif
if( !Q_strcmp( pkvd[i].szKeyName, "angle" )) if( !Q_strcmp( pkvd[i].szKeyName, "angle" ))
{ {
float flYawAngle = Q_atof( pkvd[i].szValue ); float flYawAngle = Q_atof( pkvd[i].szValue );
@@ -4942,8 +4934,6 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
if( flYawAngle >= 0.0f ) if( flYawAngle >= 0.0f )
{ {
char temp[MAX_VA_STRING];
Q_snprintf( temp, sizeof( temp ), "%g %g %g", ent->v.angles[0], flYawAngle, ent->v.angles[2] ); Q_snprintf( temp, sizeof( temp ), "%g %g %g", ent->v.angles[0], flYawAngle, ent->v.angles[2] );
pkvd[i].szValue = copystring( temp ); pkvd[i].szValue = copystring( temp );
} }
@@ -4954,11 +4944,10 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
else pkvd[i].szValue = copystring( "0 0 0" ); // technically an error else pkvd[i].szValue = copystring( "0 0 0" ); // technically an error
} }
#ifdef HACKS_RELATED_HLMODS
if( adjust_origin && !Q_strcmp( pkvd[i].szKeyName, "origin" )) if( adjust_origin && !Q_strcmp( pkvd[i].szKeyName, "origin" ))
{ {
char temp[MAX_VA_STRING]; char *pstart = pkvd[i].szValue;
char *pstart = pkvd[i].szValue; vec3_t origin;
COM_ParseVector( &pstart, origin, 3 ); COM_ParseVector( &pstart, origin, 3 );
Mem_Free( pkvd[i].szValue ); // release old value, so we don't need these Mem_Free( pkvd[i].szValue ); // release old value, so we don't need these
@@ -4966,24 +4955,18 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
Q_snprintf( temp, sizeof( temp ), "%g %g %g", origin[0], origin[1], origin[2] - 16.0f ); Q_snprintf( temp, sizeof( temp ), "%g %g %g", origin[0], origin[1], origin[2] - 16.0f );
pkvd[i].szValue = copystring( temp ); pkvd[i].szValue = copystring( temp );
} }
#endif
if( !pkvd[i].fHandled )
{
pkvd[i].szClassName = classname;
svgame.dllFuncs.pfnKeyValue( ent, &pkvd[i] );
}
// no reason to keep this data // do not leak memory if game overwritten these pointers
if( Mem_IsAllocatedExt( host.mempool, pkvd[i].szKeyName )) keyname = pkvd[i].szKeyName;
Mem_Free( pkvd[i].szKeyName ); value = pkvd[i].szValue;
if( Mem_IsAllocatedExt( host.mempool, pkvd[i].szValue )) pkvd[i].szClassName = (char *)classname;
Mem_Free( pkvd[i].szValue ); svgame.dllFuncs.pfnKeyValue( ent, &pkvd[i] );
Mem_Free( keyname );
Mem_Free( value );
} }
if( Mem_IsAllocatedExt( host.mempool, classname ))
Mem_Free( classname );
return true; return true;
} }
@@ -5102,8 +5085,6 @@ void SV_UnloadProgs( void )
/// SV_UnloadProgs will be disabled /// SV_UnloadProgs will be disabled
//Mod_ClearUserData (); //Mod_ClearUserData ();
SV_FreeStringPool();
if( svgame.dllFuncs2.pfnGameShutdown != NULL ) if( svgame.dllFuncs2.pfnGameShutdown != NULL )
svgame.dllFuncs2.pfnGameShutdown (); svgame.dllFuncs2.pfnGameShutdown ();
@@ -5124,6 +5105,8 @@ void SV_UnloadProgs( void )
Cvar_Unlink( FCVAR_EXTDLL ); Cvar_Unlink( FCVAR_EXTDLL );
Cmd_Unlink( CMD_SERVERDLL ); Cmd_Unlink( CMD_SERVERDLL );
SV_FreeStringPool();
Mod_ResetStudioAPI (); Mod_ResetStudioAPI ();
COM_FreeLibrary( svgame.hInstance ); COM_FreeLibrary( svgame.hInstance );
@@ -5170,6 +5153,11 @@ qboolean SV_LoadProgs( const char *name )
// make sure what physic functions is cleared // make sure what physic functions is cleared
memset( &svgame.physFuncs, 0, sizeof( svgame.physFuncs )); memset( &svgame.physFuncs, 0, sizeof( svgame.physFuncs ));
// revert fix for pfnPEntityOfEntIndex to be compatible with GoldSrc
// games that rely on this bug
if( FBitSet( host.bugcomp, BUGCOMP_PENTITYOFENTINDEX_FLAG ))
gEngfuncs.pfnPEntityOfEntIndex = pfnPEntityOfEntIndexBroken;
// make local copy of engfuncs to prevent overwrite it with bots.dll // make local copy of engfuncs to prevent overwrite it with bots.dll
memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs )); memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs ));
@@ -5182,7 +5170,7 @@ qboolean SV_LoadProgs( const char *name )
COM_FreeLibrary( svgame.hInstance ); COM_FreeLibrary( svgame.hInstance );
Con_Printf( S_ERROR "SV_LoadProgs: failed to get address of GetEntityAPI proc\n" ); Con_Printf( S_ERROR "SV_LoadProgs: failed to get address of GetEntityAPI proc\n" );
svgame.hInstance = NULL; svgame.hInstance = NULL;
Mem_FreePool(&svgame.mempool); Mem_FreePool( &svgame.mempool );
return false; return false;
} }
@@ -5193,7 +5181,7 @@ qboolean SV_LoadProgs( const char *name )
COM_FreeLibrary( svgame.hInstance ); COM_FreeLibrary( svgame.hInstance );
Con_Printf( S_ERROR "SV_LoadProgs: failed to get address of GiveFnptrsToDll proc\n" ); Con_Printf( S_ERROR "SV_LoadProgs: failed to get address of GiveFnptrsToDll proc\n" );
svgame.hInstance = NULL; svgame.hInstance = NULL;
Mem_FreePool(&svgame.mempool); Mem_FreePool( &svgame.mempool );
return false; return false;
} }
@@ -5218,7 +5206,8 @@ qboolean SV_LoadProgs( const char *name )
{ {
if( !GetEntityAPI2( &svgame.dllFuncs, &version )) if( !GetEntityAPI2( &svgame.dllFuncs, &version ))
{ {
Con_Printf( S_WARN "SV_LoadProgs: interface version %i should be %i\n", INTERFACE_VERSION, version ); if( INTERFACE_VERSION != version )
Con_Printf( S_WARN "SV_LoadProgs: interface version %i should be %i\n", INTERFACE_VERSION, version );
// fallback to old API // fallback to old API
if( !GetEntityAPI( &svgame.dllFuncs, version )) if( !GetEntityAPI( &svgame.dllFuncs, version ))
@@ -5226,9 +5215,10 @@ qboolean SV_LoadProgs( const char *name )
COM_FreeLibrary( svgame.hInstance ); COM_FreeLibrary( svgame.hInstance );
Con_Printf( S_ERROR "SV_LoadProgs: couldn't get entity API\n" ); Con_Printf( S_ERROR "SV_LoadProgs: couldn't get entity API\n" );
svgame.hInstance = NULL; svgame.hInstance = NULL;
Mem_FreePool(&svgame.mempool); Mem_FreePool( &svgame.mempool );
return false; return false;
} }
else Con_Reportf( "SV_LoadProgs: ^2initailized legacy EntityAPI ^7ver. %i\n", version );
} }
else Con_Reportf( "SV_LoadProgs: ^2initailized extended EntityAPI ^7ver. %i\n", version ); else Con_Reportf( "SV_LoadProgs: ^2initailized extended EntityAPI ^7ver. %i\n", version );
} }
@@ -5237,9 +5227,10 @@ qboolean SV_LoadProgs( const char *name )
COM_FreeLibrary( svgame.hInstance ); COM_FreeLibrary( svgame.hInstance );
Con_Printf( S_ERROR "SV_LoadProgs: couldn't get entity API\n" ); Con_Printf( S_ERROR "SV_LoadProgs: couldn't get entity API\n" );
svgame.hInstance = NULL; svgame.hInstance = NULL;
Mem_FreePool(&svgame.mempool); Mem_FreePool( &svgame.mempool );
return false; return false;
} }
else Con_Reportf( "SV_LoadProgs: ^2initailized legacy EntityAPI ^7ver. %i\n", version );
SV_InitOperatorCommands(); SV_InitOperatorCommands();
Mod_InitStudioAPI(); Mod_InitStudioAPI();

View File

@@ -469,7 +469,8 @@ static void SV_CreateBaseline( void )
int delta_type; int delta_type;
int entnum; int entnum;
SV_WriteVoiceCodec( &sv.signon ); if( svs.maxclients > 1 )
SV_WriteVoiceCodec( &sv.signon );
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE )) if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
playermodel = SV_ModelIndex( DEFAULT_PLAYER_PATH_QUAKE ); playermodel = SV_ModelIndex( DEFAULT_PLAYER_PATH_QUAKE );
@@ -672,14 +673,6 @@ void SV_ActivateServer( int runPhysics )
if( sv.ignored_world_decals ) if( sv.ignored_world_decals )
Con_Printf( S_WARN "%i static decals was rejected due buffer overflow\n", sv.ignored_world_decals ); Con_Printf( S_WARN "%i static decals was rejected due buffer overflow\n", sv.ignored_world_decals );
if( svs.maxclients > 1 )
{
const char *cycle = Cvar_VariableString( "mapchangecfgfile" );
if( COM_CheckString( cycle ))
Cbuf_AddTextf( "exec %s\n", cycle );
}
} }
/* /*
@@ -692,6 +685,13 @@ deactivate server, free edicts, strings etc
void SV_DeactivateServer( void ) void SV_DeactivateServer( void )
{ {
int i; int i;
const char *cycle = Cvar_VariableString( "disconcfgfile" );
if( COM_CheckString( cycle ))
Cbuf_AddTextf( "exec %s\n", cycle );
if( COM_CheckStringEmpty( sv.name ))
Cbuf_AddTextf( "exec maps/%s_unload.cfg\n", sv.name );
if( !svs.initialized || sv.state == ss_dead ) if( !svs.initialized || sv.state == ss_dead )
return; return;
@@ -922,11 +922,11 @@ static void SV_GenerateTestPacket( void )
// testpacket already generated once, exit // testpacket already generated once, exit
// testpacket and lookup table takes ~300k of memory // testpacket and lookup table takes ~300k of memory
// disable for low memory mode // disable for low memory mode
if( svs.testpacket_buf || XASH_LOW_MEMORY >= 0 ) if( svs.testpacket_buf || XASH_LOW_MEMORY > 0 )
return; return;
// don't need in singleplayer with full client // don't need in singleplayer with full client
if( svs.maxclients <= 1 && !Host_IsDedicated( )) if( svs.maxclients <= 1 )
return; return;
file = FS_Open( "gfx.wad", "rb", false ); file = FS_Open( "gfx.wad", "rb", false );
@@ -987,8 +987,9 @@ clients along with it.
*/ */
qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean background ) qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean background )
{ {
int i, current_skill; int i, current_skill;
edict_t *ent; edict_t *ent;
const char *cycle;
SV_SetupClients(); SV_SetupClients();
@@ -1006,6 +1007,13 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean ba
svs.timestart = Sys_DoubleTime(); svs.timestart = Sys_DoubleTime();
svs.spawncount++; // any partially connected client will be restarted svs.spawncount++; // any partially connected client will be restarted
cycle = Cvar_VariableString( "mapchangecfgfile" );
if( COM_CheckString( cycle ))
Cbuf_AddTextf( "exec %s\n", cycle );
Cbuf_AddTextf( "exec maps/%s_load.cfg\n", mapname );
// let's not have any servers with no name // let's not have any servers with no name
if( !COM_CheckString( hostname.string )) if( !COM_CheckString( hostname.string ))
Cvar_Set( "hostname", svgame.dllFuncs.pfnGetGameDescription ? svgame.dllFuncs.pfnGetGameDescription() : FS_Title( )); Cvar_Set( "hostname", svgame.dllFuncs.pfnGetGameDescription ? svgame.dllFuncs.pfnGetGameDescription() : FS_Title( ));

View File

@@ -77,7 +77,7 @@ void Log_Open( void )
if( fp ) svs.log.file = fp; if( fp ) svs.log.file = fp;
Log_Printf( "Log file started (file \"%s\") (game \"%s\") (version \"%i/" XASH_VERSION "/%d\")\n", Log_Printf( "Log file started (file \"%s\") (game \"%s\") (version \"%i/" XASH_VERSION "/%d\")\n",
szTestFile, Info_ValueForKey( SV_Serverinfo(), "*gamedir" ), PROTOCOL_VERSION, Q_buildnum() ); szTestFile, Info_ValueForKey( svs.serverinfo, "*gamedir" ), PROTOCOL_VERSION, Q_buildnum() );
} }
void Log_Close( void ) void Log_Close( void )

View File

@@ -75,6 +75,8 @@ CVAR_DEFINE_AUTO( skill, "1", 0, "skill level in singleplayer game" );
CVAR_DEFINE_AUTO( temp1, "0", 0, "temporary cvar that used by some mods" ); CVAR_DEFINE_AUTO( temp1, "0", 0, "temporary cvar that used by some mods" );
CVAR_DEFINE_AUTO( listipcfgfile, "listip.cfg", 0, "name of listip.cfg file" ); CVAR_DEFINE_AUTO( listipcfgfile, "listip.cfg", 0, "name of listip.cfg file" );
CVAR_DEFINE_AUTO( mapchangecfgfile, "", 0, "name of map change configuration file" ); CVAR_DEFINE_AUTO( mapchangecfgfile, "", 0, "name of map change configuration file" );
CVAR_DEFINE_AUTO( disconcfgfile, "", 0, "name of disconnect configuration file" );
CVAR_DEFINE_AUTO( _sv_override_scientist_mdl, "", 0, "override default scientist model name (specially for HL25 Uplink maps)" );
// physic-related variables // physic-related variables
CVAR_DEFINE_AUTO( sv_gravity, "800", FCVAR_MOVEVARS, "world gravity value" ); CVAR_DEFINE_AUTO( sv_gravity, "800", FCVAR_MOVEVARS, "world gravity value" );
@@ -948,6 +950,8 @@ void SV_Init( void )
Cvar_RegisterVariable( &bannedcfgfile ); Cvar_RegisterVariable( &bannedcfgfile );
Cvar_RegisterVariable( &listipcfgfile ); Cvar_RegisterVariable( &listipcfgfile );
Cvar_RegisterVariable( &mapchangecfgfile ); Cvar_RegisterVariable( &mapchangecfgfile );
Cvar_RegisterVariable( &disconcfgfile );
Cvar_RegisterVariable( &_sv_override_scientist_mdl );
Cvar_RegisterVariable( &sv_voiceenable ); Cvar_RegisterVariable( &sv_voiceenable );
Cvar_RegisterVariable( &sv_voicequality ); Cvar_RegisterVariable( &sv_voicequality );

View File

@@ -150,21 +150,9 @@ void SV_WaterMove( edict_t *ent )
if( flags & FL_INWATER ) if( flags & FL_INWATER )
{ {
// leave the water. // leave the water.
switch( COM_RandomLong( 0, 3 )) const char *snd = SoundList_GetRandom( EntityWaterExit );
{ if( snd )
case 0: SV_StartSound( ent, CHAN_BODY, snd, 1.0f, ATTN_NORM, 0, 100 );
SV_StartSound( ent, CHAN_BODY, "player/pl_wade1.wav", 1.0f, ATTN_NORM, 0, 100 );
break;
case 1:
SV_StartSound( ent, CHAN_BODY, "player/pl_wade2.wav", 1.0f, ATTN_NORM, 0, 100 );
break;
case 2:
SV_StartSound( ent, CHAN_BODY, "player/pl_wade3.wav", 1.0f, ATTN_NORM, 0, 100 );
break;
case 3:
SV_StartSound( ent, CHAN_BODY, "player/pl_wade4.wav", 1.0f, ATTN_NORM, 0, 100 );
break;
}
ent->v.flags = flags & ~FL_INWATER; ent->v.flags = flags & ~FL_INWATER;
} }
@@ -197,21 +185,9 @@ void SV_WaterMove( edict_t *ent )
if( watertype == CONTENTS_WATER ) if( watertype == CONTENTS_WATER )
{ {
// entering the water // entering the water
switch( COM_RandomLong( 0, 3 )) const char *snd = SoundList_GetRandom( EntityWaterEnter );
{ if( snd )
case 0: SV_StartSound( ent, CHAN_BODY, snd, 1.0f, ATTN_NORM, 0, 100 );
SV_StartSound( ent, CHAN_BODY, "player/pl_wade1.wav", 1.0f, ATTN_NORM, 0, 100 );
break;
case 1:
SV_StartSound( ent, CHAN_BODY, "player/pl_wade2.wav", 1.0f, ATTN_NORM, 0, 100 );
break;
case 2:
SV_StartSound( ent, CHAN_BODY, "player/pl_wade3.wav", 1.0f, ATTN_NORM, 0, 100 );
break;
case 3:
SV_StartSound( ent, CHAN_BODY, "player/pl_wade4.wav", 1.0f, ATTN_NORM, 0, 100 );
break;
}
} }
ent->v.flags = flags | FL_INWATER; ent->v.flags = flags | FL_INWATER;

View File

@@ -1384,7 +1384,9 @@ static void SV_CheckWaterTransition( edict_t *ent )
if( ent->v.watertype == CONTENTS_EMPTY ) if( ent->v.watertype == CONTENTS_EMPTY )
{ {
// just crossed into water // just crossed into water
SV_StartSound( ent, CHAN_AUTO, "player/pl_wade1.wav", 1.0f, ATTN_NORM, 0, 100 ); const char *snd = SoundList_GetRandom( PlayerWaterEnter );
if( snd )
SV_StartSound( ent, CHAN_AUTO, snd, 1.0f, ATTN_NORM, 0, 100 );
ent->v.velocity[2] *= 0.5f; ent->v.velocity[2] *= 0.5f;
} }
@@ -1418,7 +1420,9 @@ static void SV_CheckWaterTransition( edict_t *ent )
if( ent->v.watertype != CONTENTS_EMPTY ) if( ent->v.watertype != CONTENTS_EMPTY )
{ {
// just crossed into water // just crossed into water
SV_StartSound( ent, CHAN_AUTO, "player/pl_wade2.wav", 1.0f, ATTN_NORM, 0, 100 ); const char *snd = SoundList_GetRandom( PlayerWaterExit );
if( snd )
SV_StartSound( ent, CHAN_AUTO, snd, 1.0f, ATTN_NORM, 0, 100 );
} }
ent->v.watertype = CONTENTS_EMPTY; ent->v.watertype = CONTENTS_EMPTY;
ent->v.waterlevel = 0; ent->v.waterlevel = 0;
@@ -2118,6 +2122,7 @@ static server_physics_api_t gPhysicsAPI =
COM_SaveFile, COM_SaveFile,
pfnLoadImagePixels, pfnLoadImagePixels,
pfnGetModelName, pfnGetModelName,
Sys_GetNativeObject
}; };
/* /*

View File

@@ -2110,7 +2110,7 @@ qboolean SV_LoadGame( const char *pPath )
if( validload ) if( validload )
{ {
// now check for map problems // now check for map problems
flags = SV_MapIsValid( gameHeader.mapName, GI->sp_entity, NULL ); flags = SV_MapIsValid( gameHeader.mapName, NULL );
if( FBitSet( flags, MAP_INVALID_VERSION )) if( FBitSet( flags, MAP_INVALID_VERSION ))
{ {
@@ -2386,7 +2386,7 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment )
uint flags; uint flags;
// now check for map problems // now check for map problems
flags = SV_MapIsValid( mapName, GI->sp_entity, NULL ); flags = SV_MapIsValid( mapName, NULL );
if( FBitSet( flags, MAP_INVALID_VERSION )) if( FBitSet( flags, MAP_INVALID_VERSION ))
{ {

View File

@@ -125,7 +125,7 @@ def build(bld):
bld(name = 'engine_includes', export_includes = '. common common/imagelib', use = 'filesystem_includes') bld(name = 'engine_includes', export_includes = '. common common/imagelib', use = 'filesystem_includes')
is_cxx_link = False is_cxx_link = False
libs = [ 'engine_includes', 'public', 'dllemu' ] libs = [ 'engine_includes', 'public', 'dllemu', 'werror' ]
# basic build: dedicated only # basic build: dedicated only
source = bld.path.ant_glob([ source = bld.path.ant_glob([
@@ -237,7 +237,8 @@ def build(bld):
app_name = 'xash3d-fwgs' app_name = 'xash3d-fwgs'
) )
else: else:
if bld.env.DISABLE_LAUNCHER: # always build as shared library on Android
if bld.env.DISABLE_LAUNCHER and bld.env.DEST_OS != "android":
install_path = bld.env.BINDIR install_path = bld.env.BINDIR
program = 'cxxprogram' if is_cxx_link else 'cprogram' program = 'cxxprogram' if is_cxx_link else 'cprogram'
if bld.env.STATIC: if bld.env.STATIC:

View File

@@ -320,6 +320,12 @@ public:
return nullptr; return nullptr;
state = new CSearchState( &searchHead, search ); state = new CSearchState( &searchHead, search );
if( !state )
{
Mem_Free( search );
return nullptr;
}
*handle = state->handle; *handle = state->handle;
return state->search->filenames[0]; return state->search->filenames[0];
} }

View File

@@ -233,7 +233,7 @@ static file_t *FS_OpenFile_AndroidAssets( searchpath_t *search, const char *file
return file; return file;
} }
static byte *FS_LoadAndroidAssetsFile( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *filesize ) static byte *FS_LoadAndroidAssetsFile( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *filesize, void *( *pfnAlloc )( size_t ), void ( *pfnFree )( void * ))
{ {
byte *buf; byte *buf;
off_t size; off_t size;
@@ -247,18 +247,24 @@ static byte *FS_LoadAndroidAssetsFile( searchpath_t *search, const char *path, i
size = AAsset_getLength( asset ); size = AAsset_getLength( asset );
buf = (byte *)Mem_Malloc( fs_mempool, size + 1 ); buf = (byte *)pfnAlloc( size + 1 );
if( unlikely( !buf ))
{
Con_Reportf( "%s: can't alloc %d bytes, no free memory\n", __func__, size + 1 );
AAsset_close( asset );
return NULL;
}
buf[size] = '\0'; buf[size] = '\0';
if( AAsset_read( asset, buf, size ) < 0 ) if( AAsset_read( asset, buf, size ) < 0 )
{ {
Mem_Free( buf ); pfnFree( buf );
AAsset_close( asset ); AAsset_close( asset );
return NULL; return NULL;
} }
AAsset_close( asset ); AAsset_close( asset );
if( filesize ) *filesize = size; if( filesize ) *filesize = size;
return buf; return buf;
@@ -270,6 +276,9 @@ searchpath_t *FS_AddAndroidAssets_Fullpath( const char *path, int flags )
android_assets_t *assets = NULL; android_assets_t *assets = NULL;
qboolean engine = true; qboolean engine = true;
if( !jni.getPackageName || !jni.getCallingPackage || !jni.getAssetsList || !jni.getAssets )
return NULL;
if( FBitSet( flags, FS_STATIC_PATH | FS_CUSTOM_PATH )) if( FBitSet( flags, FS_STATIC_PATH | FS_CUSTOM_PATH ))
return NULL; return NULL;
@@ -280,7 +289,7 @@ searchpath_t *FS_AddAndroidAssets_Fullpath( const char *path, int flags )
if( !assets ) if( !assets )
{ {
Con_Reportf( S_ERROR "%s: unable to load Android assets \"%s\"\n", __FUNCTION__, Android_GetPackageName( engine )); Con_Reportf( S_ERROR "%s: unable to load Android assets \"%s\"\n", __func__, Android_GetPackageName( engine ));
return NULL; return NULL;
} }
@@ -320,6 +329,9 @@ void FS_InitAndroid( void )
jni.getCallingPackage = (*jni.env)->GetMethodID( jni.env, jni.activity_class, "getCallingPackage", "()Ljava/lang/String;" ); jni.getCallingPackage = (*jni.env)->GetMethodID( jni.env, jni.activity_class, "getCallingPackage", "()Ljava/lang/String;" );
jni.getAssetsList = (*jni.env)->GetMethodID( jni.env, jni.activity_class, "getAssetsList", "(ZLjava/lang/String;)[Ljava/lang/String;" ); jni.getAssetsList = (*jni.env)->GetMethodID( jni.env, jni.activity_class, "getAssetsList", "(ZLjava/lang/String;)[Ljava/lang/String;" );
jni.getAssets = (*jni.env)->GetMethodID( jni.env, jni.activity_class, "getAssets", "(Z)Landroid/content/res/AssetManager;" ); jni.getAssets = (*jni.env)->GetMethodID( jni.env, jni.activity_class, "getAssets", "(Z)Landroid/content/res/AssetManager;" );
if( !jni.getPackageName || !jni.getCallingPackage || !jni.getAssetsList || !jni.getAssets )
Con_Reportf( S_WARN "%s: unable to find required JNI interface to load Android assets\n", __func__ );
} }
#endif // XASH_ANDROID #endif // XASH_ANDROID

View File

@@ -72,7 +72,7 @@ const fs_archive_t g_archives[] =
static const fs_archive_t g_directory_archive = static const fs_archive_t g_directory_archive =
{ NULL, SEARCHPATH_PLAIN, FS_AddDir_Fullpath, false }; { NULL, SEARCHPATH_PLAIN, FS_AddDir_Fullpath, false };
#ifdef XASH_ANDROID #if XASH_ANDROID
static const fs_archive_t g_android_archive = static const fs_archive_t g_android_archive =
{ NULL, SEARCHPATH_ANDROID_ASSETS, FS_AddAndroidAssets_Fullpath, false }; { NULL, SEARCHPATH_ANDROID_ASSETS, FS_AddAndroidAssets_Fullpath, false };
#endif #endif
@@ -406,7 +406,7 @@ void FS_AddGameDirectory( const char *dir, uint flags )
stringlistfreecontents( &list ); stringlistfreecontents( &list );
#ifdef XASH_ANDROID #if XASH_ANDROID
FS_AddArchive_Fullpath( &g_android_archive, dir, flags ); FS_AddArchive_Fullpath( &g_android_archive, dir, flags );
#endif #endif
@@ -632,30 +632,23 @@ static void FS_InitGameInfo( gameinfo_t *GameInfo, const char *gamedir )
memset( GameInfo, 0, sizeof( *GameInfo )); memset( GameInfo, 0, sizeof( *GameInfo ));
// filesystem info // filesystem info
Q_strncpy( GameInfo->gamefolder, gamedir, sizeof( GameInfo->gamefolder ));
Q_strncpy( GameInfo->basedir, "valve", sizeof( GameInfo->basedir ));
GameInfo->falldir[0] = 0;
Q_strncpy( GameInfo->startmap, "c0a0", sizeof( GameInfo->startmap ));
Q_strncpy( GameInfo->trainmap, "t0a0", sizeof( GameInfo->trainmap ));
Q_strncpy( GameInfo->title, "New Game", sizeof( GameInfo->title )); Q_strncpy( GameInfo->title, "New Game", sizeof( GameInfo->title ));
GameInfo->version = 1.0f; Q_strncpy( GameInfo->gamefolder, gamedir, sizeof( GameInfo->gamefolder ));
Q_strncpy( GameInfo->basedir, fs_basedir, sizeof( GameInfo->basedir ));
// .dll pathes Q_strncpy( GameInfo->sp_entity, "info_player_start", sizeof( GameInfo->sp_entity ));
Q_strncpy( GameInfo->mp_entity, "info_player_deathmatch", sizeof( GameInfo->mp_entity ));
Q_strncpy( GameInfo->startmap, "newmap", sizeof( GameInfo->startmap ));
Q_strncpy( GameInfo->dll_path, "cl_dlls", sizeof( GameInfo->dll_path )); Q_strncpy( GameInfo->dll_path, "cl_dlls", sizeof( GameInfo->dll_path ));
Q_strncpy( GameInfo->game_dll, "dlls/hl.dll", sizeof( GameInfo->game_dll )); Q_strncpy( GameInfo->game_dll, "dlls/hl.dll", sizeof( GameInfo->game_dll ));
Q_strncpy( GameInfo->game_dll_linux, "dlls/hl.so", sizeof( GameInfo->game_dll_linux )); Q_strncpy( GameInfo->game_dll_linux, "dlls/hl.so", sizeof( GameInfo->game_dll_linux ));
Q_strncpy( GameInfo->game_dll_osx, "dlls/hl.dylib", sizeof( GameInfo->game_dll_osx )); Q_strncpy( GameInfo->game_dll_osx, "dlls/hl.dylib", sizeof( GameInfo->game_dll_osx ));
// .ico path
Q_strncpy( GameInfo->iconpath, "game.ico", sizeof( GameInfo->iconpath )); Q_strncpy( GameInfo->iconpath, "game.ico", sizeof( GameInfo->iconpath ));
Q_strncpy( GameInfo->sp_entity, "info_player_start", sizeof( GameInfo->sp_entity ));
Q_strncpy( GameInfo->mp_entity, "info_player_deathmatch", sizeof( GameInfo->mp_entity ));
GameInfo->max_edicts = DEFAULT_MAX_EDICTS; // default value if not specified GameInfo->max_edicts = DEFAULT_MAX_EDICTS; // default value if not specified
GameInfo->max_tents = 500; GameInfo->max_tents = 500;
GameInfo->max_beams = 128; GameInfo->max_beams = 128;
GameInfo->max_particles = 4096; GameInfo->max_particles = 4096;
GameInfo->version = 1.0f;
} }
static void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qboolean isGameInfo ) static void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qboolean isGameInfo )
@@ -1468,7 +1461,7 @@ qboolean FS_InitStdio( qboolean unused_set_to_true, const char *rootdir, const c
FS_InitMemory(); FS_InitMemory();
#ifdef XASH_ANDROID #if XASH_ANDROID
FS_InitAndroid(); FS_InitAndroid();
#endif #endif
@@ -2419,6 +2412,16 @@ static void FS_Purge( file_t *file )
file->ungetc = EOF; file->ungetc = EOF;
} }
static void *FS_CustomAlloc( size_t size )
{
return Mem_Malloc( fs_mempool, size );
}
static void FS_CustomFree( void *data )
{
return Mem_Free( data );
}
/* /*
============ ============
FS_LoadFile FS_LoadFile
@@ -2427,12 +2430,16 @@ Filename are relative to the xash directory.
Always appends a 0 byte. Always appends a 0 byte.
============ ============
*/ */
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly ) static byte *FS_LoadFile_( const char *path, fs_offset_t *filesizeptr, const qboolean gamedironly, const qboolean custom_alloc )
{ {
searchpath_t *search; searchpath_t *search;
fs_offset_t filesize;
file_t *file; file_t *file;
byte *buf;
char netpath[MAX_SYSPATH]; char netpath[MAX_SYSPATH];
int pack_ind; int pack_ind;
void *( *pfnAlloc )( size_t ) = custom_alloc ? FS_CustomAlloc : malloc;
void ( *pfnFree )( void * ) = custom_alloc ? FS_CustomFree : free;
// some mappers used leading '/' or '\' in path to models or sounds // some mappers used leading '/' or '\' in path to models or sounds
if( path[0] == '/' || path[0] == '\\' ) if( path[0] == '/' || path[0] == '\\' )
@@ -2451,27 +2458,39 @@ byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamediro
// custom load file function for compressed files // custom load file function for compressed files
if( search->pfnLoadFile ) if( search->pfnLoadFile )
return search->pfnLoadFile( search, netpath, pack_ind, filesizeptr ); return search->pfnLoadFile( search, netpath, pack_ind, filesizeptr, pfnAlloc, pfnFree );
file = search->pfnOpenFile( search, netpath, "rb", pack_ind ); file = search->pfnOpenFile( search, netpath, "rb", pack_ind );
if( file ) if( !file ) // TODO: indicate errors
return NULL;
filesize = file->real_length;
buf = (byte *)pfnAlloc( filesize + 1 );
if( unlikely( !buf )) // TODO: indicate errors
{ {
fs_offset_t filesize = file->real_length; Con_Reportf( "%s: can't alloc %d bytes, no free memory\n", __func__, filesize + 1 );
byte *buf;
buf = (byte *)Mem_Malloc( fs_mempool, filesize + 1 );
buf[filesize] = '\0';
FS_Read( file, buf, filesize );
FS_Close( file ); FS_Close( file );
return NULL;
if( filesizeptr )
*filesizeptr = filesize;
return buf;
} }
return NULL; buf[filesize] = '\0';
FS_Read( file, buf, filesize );
FS_Close( file );
if( filesizeptr ) *filesizeptr = filesize;
return buf;
}
byte *FS_LoadFileMalloc( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
{
return FS_LoadFile_( path, filesizeptr, gamedironly, false );
}
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
{
return FS_LoadFile_( path, filesizeptr, gamedironly, g_engfuncs._Mem_Alloc != _Mem_Alloc );
} }
qboolean CRC32_File( dword *crcvalue, const char *filename ) qboolean CRC32_File( dword *crcvalue, const char *filename )
@@ -3020,6 +3039,7 @@ fs_api_t g_api =
(void *)FS_MountArchive_Fullpath, (void *)FS_MountArchive_Fullpath,
FS_GetFullDiskPath, FS_GetFullDiskPath,
FS_LoadFileMalloc,
}; };
int EXPORT GetFSAPI( int version, fs_api_t *api, fs_globals_t **globals, fs_interface_t *engfuncs ); int EXPORT GetFSAPI( int version, fs_api_t *api, fs_globals_t **globals, fs_interface_t *engfuncs );

View File

@@ -196,6 +196,9 @@ typedef struct fs_api_t
void *(*MountArchive_Fullpath)( const char *path, int flags ); void *(*MountArchive_Fullpath)( const char *path, int flags );
qboolean (*GetFullDiskPath)( char *buffer, size_t size, const char *name, qboolean gamedironly ); qboolean (*GetFullDiskPath)( char *buffer, size_t size, const char *name, qboolean gamedironly );
// like LoadFile but returns pointer that can be free'd using standard library function
byte *(*LoadFileMalloc)( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
} fs_api_t; } fs_api_t;
typedef struct fs_interface_t typedef struct fs_interface_t

View File

@@ -103,7 +103,7 @@ typedef struct searchpath_s
int (*pfnFileTime)( struct searchpath_s *search, const char *filename ); int (*pfnFileTime)( struct searchpath_s *search, const char *filename );
int (*pfnFindFile)( struct searchpath_s *search, const char *path, char *fixedname, size_t len ); int (*pfnFindFile)( struct searchpath_s *search, const char *path, char *fixedname, size_t len );
void (*pfnSearch)( struct searchpath_s *search, stringlist_t *list, const char *pattern, int caseinsensitive ); void (*pfnSearch)( struct searchpath_s *search, stringlist_t *list, const char *pattern, int caseinsensitive );
byte *(*pfnLoadFile)( struct searchpath_s *search, const char *path, int pack_ind, fs_offset_t *filesize ); byte *(*pfnLoadFile)( struct searchpath_s *search, const char *path, int pack_ind, fs_offset_t *filesize, void *( *pfnAlloc )( size_t ), void ( *pfnFree )( void * ));
} searchpath_t; } searchpath_t;
typedef searchpath_t *(*FS_ADDARCHIVE_FULLPATH)( const char *path, int flags ); typedef searchpath_t *(*FS_ADDARCHIVE_FULLPATH)( const char *path, int flags );
@@ -181,6 +181,7 @@ qboolean FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize );
// file buffer ops // file buffer ops
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly ); byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
byte *FS_LoadFileMalloc( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
byte *FS_LoadDirectFile( const char *path, fs_offset_t *filesizeptr ); byte *FS_LoadDirectFile( const char *path, fs_offset_t *filesizeptr );
qboolean FS_WriteFile( const char *filename, const void *data, fs_offset_t len ); qboolean FS_WriteFile( const char *filename, const void *data, fs_offset_t len );

View File

@@ -358,7 +358,7 @@ searchpath_t *FS_AddPak_Fullpath( const char *pakfile, int flags )
search->pfnFindFile = FS_FindFile_PAK; search->pfnFindFile = FS_FindFile_PAK;
search->pfnSearch = FS_Search_PAK; search->pfnSearch = FS_Search_PAK;
Con_Reportf( "Adding pakfile: %s (%i files)\n", pakfile, pak->numfiles ); Con_Reportf( "Adding PAK: %s (%i files)\n", pakfile, pak->numfiles );
return search; return search;
} }

View File

@@ -591,7 +591,7 @@ W_ReadLump
reading lump into temp buffer reading lump into temp buffer
=========== ===========
*/ */
static byte *W_ReadLump( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *lumpsizeptr ) static byte *W_ReadLump( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *lumpsizeptr, void *( *pfnAlloc )( size_t ), void ( *pfnFree )( void * ))
{ {
const wfile_t *wad = search->wad; const wfile_t *wad = search->wad;
const dlumpinfo_t *lump = &wad->lumps[pack_ind]; const dlumpinfo_t *lump = &wad->lumps[pack_ind];
@@ -613,19 +613,25 @@ static byte *W_ReadLump( searchpath_t *search, const char *path, int pack_ind, f
return NULL; return NULL;
} }
buf = (byte *)Mem_Malloc( wad->mempool, lump->disksize ); buf = (byte *)pfnAlloc( lump->disksize );
if( unlikely( !buf ))
{
Con_Reportf( S_ERROR "%s: can't alloc %d bytes, no free memory\n", __func__, lump->disksize );
FS_Seek( wad->handle, oldpos, SEEK_SET );
return NULL;
}
size = FS_Read( wad->handle, buf, lump->disksize ); size = FS_Read( wad->handle, buf, lump->disksize );
FS_Seek( wad->handle, oldpos, SEEK_SET );
if( size < lump->disksize ) if( size < lump->disksize )
{ {
Con_Reportf( S_WARN "W_ReadLump: %s is probably corrupted\n", lump->name ); Con_Reportf( S_WARN "W_ReadLump: %s is probably corrupted\n", lump->name );
FS_Seek( wad->handle, oldpos, SEEK_SET ); pfnFree( buf );
Mem_Free( buf );
return NULL; return NULL;
} }
if( lumpsizeptr ) *lumpsizeptr = lump->disksize; if( lumpsizeptr ) *lumpsizeptr = lump->disksize;
FS_Seek( wad->handle, oldpos, SEEK_SET );
return buf; return buf;
} }
@@ -664,6 +670,6 @@ searchpath_t *FS_AddWad_Fullpath( const char *wadfile, int flags )
search->pfnSearch = FS_Search_WAD; search->pfnSearch = FS_Search_WAD;
search->pfnLoadFile = W_ReadLump; search->pfnLoadFile = W_ReadLump;
Con_Reportf( "Adding wadfile: %s (%i files)\n", wadfile, wad->numlumps ); Con_Reportf( "Adding WAD: %s (%i files)\n", wadfile, wad->numlumps );
return search; return search;
} }

View File

@@ -18,7 +18,7 @@ def configure(conf):
def build(bld): def build(bld):
bld(name = 'filesystem_includes', export_includes = '.') bld(name = 'filesystem_includes', export_includes = '.')
libs = [ 'filesystem_includes', 'sdk_includes' ] libs = [ 'filesystem_includes', 'sdk_includes', 'werror' ]
# on PSVita do not link any libraries that are already in the main executable, but add the includes target # on PSVita do not link any libraries that are already in the main executable, but add the includes target
if bld.env.DEST_OS != 'psvita': if bld.env.DEST_OS != 'psvita':

View File

@@ -422,7 +422,7 @@ FS_LoadZIPFile
=========== ===========
*/ */
static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *sizeptr ) static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *sizeptr, void *( *pfnAlloc )( size_t ), void ( *pfnFree )( void * ))
{ {
zipfile_t *file; zipfile_t *file;
byte *compressed_buffer = NULL, *decompressed_buffer = NULL; byte *compressed_buffer = NULL, *decompressed_buffer = NULL;
@@ -451,11 +451,16 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
return NULL; return NULL;
}*/ }*/
decompressed_buffer = pfnAlloc( file->size + 1 );
if( unlikely( !decompressed_buffer ))
{
Con_Reportf( S_ERROR "%s: can't alloc %d bytes, no free memory\n", __func__, file->size + 1 );
return NULL;
}
decompressed_buffer[file->size] = '\0';
if( file->flags == ZIP_COMPRESSION_NO_COMPRESSION ) if( file->flags == ZIP_COMPRESSION_NO_COMPRESSION )
{ {
decompressed_buffer = Mem_Malloc( fs_mempool, file->size + 1 );
decompressed_buffer[file->size] = '\0';
c = read( search->zip->handle, decompressed_buffer, file->size ); c = read( search->zip->handle, decompressed_buffer, file->size );
if( c != file->size ) if( c != file->size )
{ {
@@ -472,7 +477,7 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
if( final_crc != file->crc32 ) if( final_crc != file->crc32 )
{ {
Con_Reportf( S_ERROR "Zip_LoadFile: %s file crc32 mismatch\n", file->name ); Con_Reportf( S_ERROR "Zip_LoadFile: %s file crc32 mismatch\n", file->name );
Mem_Free( decompressed_buffer ); pfnFree( decompressed_buffer );
return NULL; return NULL;
} }
#endif // ENABLE_CRC_CHECK #endif // ENABLE_CRC_CHECK
@@ -485,8 +490,6 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
else if( file->flags == ZIP_COMPRESSION_DEFLATED ) else if( file->flags == ZIP_COMPRESSION_DEFLATED )
{ {
compressed_buffer = Mem_Malloc( fs_mempool, file->compressed_size + 1 ); compressed_buffer = Mem_Malloc( fs_mempool, file->compressed_size + 1 );
decompressed_buffer = Mem_Malloc( fs_mempool, file->size + 1 );
decompressed_buffer[file->size] = '\0';
c = read( search->zip->handle, compressed_buffer, file->compressed_size ); c = read( search->zip->handle, compressed_buffer, file->compressed_size );
if( c != file->compressed_size ) if( c != file->compressed_size )
@@ -529,7 +532,7 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
if( final_crc != file->crc32 ) if( final_crc != file->crc32 )
{ {
Con_Reportf( S_ERROR "Zip_LoadFile: %s file crc32 mismatch\n", file->name ); Con_Reportf( S_ERROR "Zip_LoadFile: %s file crc32 mismatch\n", file->name );
Mem_Free( decompressed_buffer ); pfnFree( decompressed_buffer );
return NULL; return NULL;
} }
#endif #endif
@@ -542,7 +545,7 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
{ {
Con_Reportf( S_ERROR "Zip_LoadFile: %s : error while file decompressing. Zlib return code %d.\n", file->name, zlib_result ); Con_Reportf( S_ERROR "Zip_LoadFile: %s : error while file decompressing. Zlib return code %d.\n", file->name, zlib_result );
Mem_Free( compressed_buffer ); Mem_Free( compressed_buffer );
Mem_Free( decompressed_buffer ); pfnFree( decompressed_buffer );
return NULL; return NULL;
} }
@@ -550,6 +553,7 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
else else
{ {
Con_Reportf( S_ERROR "Zip_LoadFile: %s : file compressed with unknown algorithm.\n", file->name ); Con_Reportf( S_ERROR "Zip_LoadFile: %s : file compressed with unknown algorithm.\n", file->name );
pfnFree( decompressed_buffer );
return NULL; return NULL;
} }
@@ -697,7 +701,7 @@ searchpath_t *FS_AddZip_Fullpath( const char *zipfile, int flags )
search->pfnSearch = FS_Search_ZIP; search->pfnSearch = FS_Search_ZIP;
search->pfnLoadFile = FS_LoadZIPFile; search->pfnLoadFile = FS_LoadZIPFile;
Con_Reportf( "Adding zipfile: %s (%i files)\n", zipfile, zip->numfiles ); Con_Reportf( "Adding ZIP: %s (%i files)\n", zipfile, zip->numfiles );
return search; return search;
} }

View File

@@ -33,7 +33,7 @@ def build(bld):
bld(source = source, bld(source = source,
target = 'xash3d', # hl.exe target = 'xash3d', # hl.exe
features = 'c cxx cxxprogram', features = 'c cxx cxxprogram',
use = 'sdk_includes DL USER32 SHELL32', use = 'sdk_includes DL USER32 SHELL32 werror',
rpath = bld.env.DEFAULT_RPATH, rpath = bld.env.DEFAULT_RPATH,
install_path = bld.env.BINDIR, install_path = bld.env.BINDIR,
subsystem = bld.env.MSVC_SUBSYSTEM subsystem = bld.env.MSVC_SUBSYSTEM

View File

@@ -95,8 +95,6 @@ const char *Q_PlatformStringByID( const int platform )
return "win32"; return "win32";
case PLATFORM_ANDROID: case PLATFORM_ANDROID:
return "android"; return "android";
case PLATFORM_LINUX_UNKNOWN:
return "linuxunkabi";
case PLATFORM_LINUX: case PLATFORM_LINUX:
return "linux"; return "linux";
case PLATFORM_APPLE: case PLATFORM_APPLE:
@@ -239,19 +237,25 @@ const char *Q_buildarch( void )
============= =============
Q_buildcommit Q_buildcommit
Returns a short hash of current commit in VCS as string. Returns a short hash of current commit in VCS as string
XASH_BUILD_COMMIT must be passed in quotes XASH_BUILD_COMMIT must be passed in quotes
if XASH_BUILD_COMMIT is not defined,
Q_buildcommit will identify this build as "notset"
============= =============
*/ */
const char *Q_buildcommit( void ) const char *Q_buildcommit( void )
{ {
#ifdef XASH_BUILD_COMMIT
return XASH_BUILD_COMMIT; return XASH_BUILD_COMMIT;
#else }
return "notset";
#endif /*
=============
Q_buildbranch
Returns current branch name in VCS as string
XASH_BUILD_BRANCH must be passed in quotes
=============
*/
const char *Q_buildbranch( void )
{
return XASH_BUILD_BRANCH;
} }

View File

@@ -69,7 +69,6 @@ Then you can use another oneliner to query all variables:
#undef XASH_IRIX #undef XASH_IRIX
#undef XASH_JS #undef XASH_JS
#undef XASH_LINUX #undef XASH_LINUX
#undef XASH_LINUX_UNKNOWN
#undef XASH_LITTLE_ENDIAN #undef XASH_LITTLE_ENDIAN
#undef XASH_MIPS #undef XASH_MIPS
#undef XASH_MOBILE_PLATFORM #undef XASH_MOBILE_PLATFORM
@@ -103,13 +102,6 @@ Then you can use another oneliner to query all variables:
#if defined __linux__ #if defined __linux__
#if defined __ANDROID__ #if defined __ANDROID__
#define XASH_ANDROID 1 #define XASH_ANDROID 1
#else
#include <features.h>
// if our system libc has features.h header
// try to detect it to not confuse other libcs with built with glibc game libraries
#if !defined __GLIBC__
#define XASH_LINUX_UNKNOWN 1
#endif
#endif #endif
#define XASH_LINUX 1 #define XASH_LINUX 1
#elif defined __FreeBSD__ #elif defined __FreeBSD__

View File

@@ -41,14 +41,11 @@ GNU General Public License for more details.
#define PLATFORM_IRIX 12 #define PLATFORM_IRIX 12
#define PLATFORM_NSWITCH 13 #define PLATFORM_NSWITCH 13
#define PLATFORM_PSVITA 14 #define PLATFORM_PSVITA 14
#define PLATFORM_LINUX_UNKNOWN 15
#if XASH_WIN32 #if XASH_WIN32
#define XASH_PLATFORM PLATFORM_WIN32 #define XASH_PLATFORM PLATFORM_WIN32
#elif XASH_ANDROID #elif XASH_ANDROID
#define XASH_PLATFORM PLATFORM_ANDROID #define XASH_PLATFORM PLATFORM_ANDROID
#elif XASH_LINUX_UNKNOWN
#define XASH_PLATFORM PLATFORM_LINUX_UNKNOWN
#elif XASH_LINUX #elif XASH_LINUX
#define XASH_PLATFORM PLATFORM_LINUX #define XASH_PLATFORM PLATFORM_LINUX
#elif XASH_APPLE #elif XASH_APPLE

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