Compare commits

...

214 Commits

Author SHA1 Message Date
Alibek Omarov
989958e185 scripts: cirrus: enable configure log temporarily 2025-02-09 17:50:21 +03:00
Alibek Omarov
43ea65fffc ci: upgrade freebsd tasks. 2025-02-09 17:41:01 +03:00
Alibek Omarov
a72d921c12 wscript: add system-wide libbacktrace detection 2025-02-09 17:41:01 +03:00
Alibek Omarov
99b7d71824 wscript: set DEST_SIZEOF_VOID_P with allow 64bit flag 2025-02-09 17:16:17 +03:00
Alibek Omarov
67c73bdcbe engine: server: remove impulse 204, it's not used anywhere
Thanks @tyabus for reminding me about this feature.
2025-02-09 17:16:05 +03:00
Alibek Omarov
8b1dbcf166 ci: remove extra 20s of wait before removing current release and downloading artifacts 2025-02-09 17:02:31 +03:00
Alibek Omarov
5f60095dc4 scripts: flatpak: disable separate debuginfo 2025-02-09 16:54:51 +03:00
Alibek Omarov
c7282b488b 3rdparty: libbacktrace: disable linking zlib, lzma and zstd for now, figure this out later 2025-02-09 16:49:43 +03:00
Alibek Omarov
afa829d996 3rdparty: libbacktrace: don't define POSIX_SOURCE, it breaks build on Mac 2025-02-09 16:41:26 +03:00
Alibek Omarov
c06ea8d915 engine: platform: posix: add printing backtrace to stderr and logfile for libbacktrace backend 2025-02-09 16:41:26 +03:00
Alibek Omarov
bf344282ec android: explicitly set Waf output directory so it doesn't mess with current configuration and places generated files where CMake expects them to be 2025-02-09 16:20:38 +03:00
Alibek Omarov
21f62910ac engine: platform: posix: fix build when glibc execinfo.h is not available, but libbacktrace is still used 2025-02-09 16:20:38 +03:00
Alibek Omarov
54552d93ef Documentation: goldsrc-protocol-support: I am not going to support Dproto 2025-02-09 16:18:21 +03:00
Alibek Omarov
97455e7fd4 engine: platform: sdl: fix build after last PR 2025-02-09 15:56:16 +03:00
Alibek Omarov
6087d43043 3rdparty: libbacktrace: properly disable it on win32, nswitch and psvita 2025-02-09 15:55:12 +03:00
Alibek Omarov
c1a96d3ff1 engine: platform: posix: fix build 2025-02-09 15:51:25 +03:00
Alibek Omarov
e27d20dfa3 android: enable debug symbols for native libraries 2025-02-09 15:49:28 +03:00
Alibek Omarov
890e12ec76 engine: platform: posix: flush stdout/stderr before everything, include build branch 2025-02-09 15:45:44 +03:00
Alibek Omarov
774d2ac28a engine: platform: posix: add libbacktrace support for crash handler 2025-02-09 15:42:28 +03:00
Alibek Omarov
960d724828 3rdparty: libbacktrace: add submodule 2025-02-09 15:40:07 +03:00
Alibek Omarov
32aa1f91bf engine: pass argv0 to crash handler setup, which is required for libbacktrace integration
Fix indentation in crash_posix.c
2025-02-09 15:36:49 +03:00
Alibek Omarov
bd3634c815 wscript: add sanity test for opusfile because some distros don't ship 32-bit binary 2025-02-09 15:34:30 +03:00
Oleg
eda0ac92cc engine: platform: sdl: change behavior when window position is not set 2025-02-09 08:54:31 +03:00
Oleg
546903ea05 engine: platform: sdl: write windows position changes even in fullscreen 2025-02-09 08:54:31 +03:00
Oleg
4975001795 engine: platform: sdl: enumerate video modes for display where window located is instead of display zero 2025-02-09 08:54:31 +03:00
Oleg
a078ad1f51 engine: platform: sdl: fix windows save position for multiple monitors 2025-02-09 08:54:31 +03:00
Oleg
8307f671d4 engine: platform: sdl: let platform decide where to put our fullscreen window 2025-02-09 08:54:31 +03:00
Alibek Omarov
241fab02b1 ref: gl: don't try to free luma and detail texture of water texture, as these fields used by r_ripple 2025-02-08 16:57:20 +03:00
Alibek Omarov
1bfee70477 engine: con_utils: add autocompletion for cvar commands like set, reset and toggle 2025-02-08 16:45:52 +03:00
Alibek Omarov
eb51d17cd2 engine: server: enable sv_zmax clamping back to avoid overflowing zmax value encoded in delta 2025-02-08 16:38:11 +03:00
Alibek Omarov
b5cb0b9f10 ref: gl: add r_dlight_virtual_radius. It potentially fixes ugly dlight cut off on largely scaled textures (or at least allows to tune it)
It also adds a fix found in JoeQuake (which traces back to FitzQuake, in which
it is attributed to LadyHavoc, Darkplaces author) to exactly calculate whether
the light hits the surface, so we don't wrongly enable lighting on a surface by
an increased radius.
2025-02-07 23:07:08 +03:00
Alibek Omarov
a955d1e957 ref: gl: make GL_BuildPolygonFromSurface static, remove one global variable usage (which is unused anyway) 2025-02-07 22:55:38 +03:00
Alibek Omarov
2b2c967e85 engine: add ms3.mentality.rip master server 2025-02-07 19:32:37 +03:00
Alibek Omarov
c48d93e3ce public: use last Git commit date (committer date, to be exact) as more predictable source for build num 2025-02-07 17:51:10 +03:00
Alibek Omarov
8f257cc331 public: add parsing build date from ISO-8601 alike format 2025-02-07 17:47:23 +03:00
Alibek Omarov
151e7fe37b public: crtlib: check for empty buffer in Q_vsnprintf 2025-02-06 21:19:10 +03:00
Alibek Omarov
add02dc6f9 engine: fix potential UB in netadr_t 2025-02-06 20:54:18 +03:00
Alibek Omarov
d4c34abd6e engine: enable writing log even if console hasn't been enabled at the engine startup (it might be enabled later, it might also contain crash data) 2025-02-06 20:03:07 +03:00
Alibek Omarov
1d81e611f0 scripts: gha: use N+1 job count when building PSVita dependencies 2025-02-06 00:32:42 +03:00
Alibek Omarov
6a0038e26a ref: gl: always set texture env mode to GL_MODULATE in TriAPI's RenderMode call
Not sure if this is correct, but it's generally a good idea to restore it to an
expected value.
2025-02-06 00:30:32 +03:00
Alibek Omarov
1d99f65e86 filesystem: when shutting down, clean up gameinfo pointers and total games count 2025-02-05 21:14:08 +03:00
Alibek Omarov
5e524bca60 engine: client: enable half-texel hack for nearest filtering too, if the scaling factor isn't an integer 2025-02-05 20:16:16 +03:00
Alibek Omarov
cf3e56e275 engine: client: add alternative mode for hud_scale, where it scales HUD down to selected resolution with preserving aspect ratio 2025-02-05 19:47:59 +03:00
Alibek Omarov
ade560c601 common: cvar: make auto descriptions private to cvar subsystem, use them when Cvar_Get is called with NULL description
It allows us to not lose engine-side description when client or gameui registers cvar with the same name. In case of
menu it's the only way to get cvar pointer.
2025-02-05 19:11:16 +03:00
Alibek Omarov
62e3ba2126 engine: add cvars to control mounting additional directories
Use existing ui_language cvar for mounting localization folders.
2025-02-05 18:54:28 +03:00
Alibek Omarov
674a4e5883 filesystem: add ability to mount HD, LV, addon and language folders by engine request 2025-02-05 18:24:36 +03:00
Alibek Omarov
f911210b81 public: simplify ctype.h is* functions wrappers for null-terminated strings, add Q_isalpha 2025-02-05 18:21:18 +03:00
Alibek Omarov
14eb07653c engine: client: fix incorrect format in error message in CL_SetLightStyle 2025-02-05 17:41:01 +03:00
Alibek Omarov
54b0cf9991 ref: gl: check OES NPOT texture extension in BigGL mode 2025-02-05 14:00:44 +03:00
Alibek Omarov
3ebcb08a97 ref: gl: add cvar r_large_lightmaps to enable larger lightmap sizes, opt-in, yields better performance with VBO renderer 2025-02-05 13:02:37 +03:00
Alibek Omarov
23940f8590 readme: remove fontconfig from dependencies list, we aren't using it anymore [skip ci] 2025-02-04 21:00:42 +03:00
Alibek Omarov
687fb0123f engine: implement basic gamepad gyroscope calibration
Called on game controller becoming active or by user request.
Exposes current calibration state by read-only console variable.
2025-02-03 13:14:51 +03:00
Alibek Omarov
6c91fdb0cd ref: gl: gl2_shim: fix int vs GLuint 2025-02-02 20:57:37 +03:00
Alibek Omarov
4832232fd6 ci: attempt to fix flatpak upload 2025-02-02 20:31:51 +03:00
Alibek Omarov
185bce0489 engine: common: remove unused D_ enum used for MsgDev in old engine. Make sure all enums and structs here are not anonymous 2025-02-02 20:26:07 +03:00
Alibek Omarov
f460aa63b0 engine: platform: posix: don't forget to print backtrace to stderr too 2025-02-02 19:20:54 +03:00
Alibek Omarov
22f8b6f9c3 engine: platform: enable crash handler for macOS 2025-02-02 18:30:41 +03:00
Alibek Omarov
0cb034afc2 engine: wscript: improve execinfo and GNU backtrace() check 2025-02-02 18:18:26 +03:00
Alibek Omarov
d0464ef602 engine: platform: posix: use glibc-based backtrace implementation for crash handling, if execinfo.h can be found 2025-02-02 18:06:18 +03:00
Alibek Omarov
c3ebb84b97 ci: bump SDL2 to 2.30.12 2025-02-02 08:14:24 +03:00
Alibek Omarov
11742efbc3 engine: fix player move on dedicated servers 2025-02-02 08:08:15 +03:00
Alibek Omarov
95af635ab4 engine: client: add command replaybufferdat to aid in debugging protocol errors by parsing buffer.dat 2025-02-02 05:22:46 +03:00
Alibek Omarov
1abec80191 engine: client: set codepage to 0 if con_charset value is unknown 2025-02-02 02:34:08 +03:00
Alibek Omarov
93ebddfba3 public: utflib: simplify Q_EncodeUTF8 2025-02-02 02:31:56 +03:00
Alibek Omarov
5378494199 wscript: enable main() function for Android port, which was forgotten after last refactoring 2025-02-01 18:26:20 +03:00
Alibek Omarov
1b44d7733e engine: platform: add improved Platform_Vibrate2 function, that allows to control vibration strength 2025-02-01 18:08:53 +03:00
Alibek Omarov
694c630b44 engine: zone: don't error when trying to free NULL pointer, like standard C free() and C++ delete 2025-02-01 17:51:02 +03:00
Alibek Omarov
7df1d4b9e2 engine: platform: sdl: remove useless for us game controller events 2025-01-31 19:48:33 +03:00
Alibek Omarov
b16037eabf engine: drop raw SDL joystick API, always use GameController instead. Implement actually working rumble, ensure we're freeing up all resources related to gamepads 2025-01-31 17:50:19 +03:00
Alibek Omarov
bff7299f9b gha: publish binaries even if flatpak fails 2025-01-31 10:37:41 +03:00
Alibek Omarov
de196b1c58 common: xash3d_types: avoid defining true and false in C23 2025-01-31 10:36:27 +03:00
Alibek Omarov
a0eec8b85d scripts: waifulib: add special_install_path for platform-specific executable formats that create post link stage (was nro_install_path) 2025-01-31 10:25:02 +03:00
Alibek Omarov
c7e8ea2ffa scripts: gha: linux: build smaller SDL2 (without 2D renderer) for Linux as well 2025-01-31 10:02:19 +03:00
Alibek Omarov
1c1cf3d646 scripts: waifulib: psvita: make sce_sys truly optional in apply_vpk 2025-01-31 10:02:19 +03:00
Alibek Omarov
9759b80b78 scripts: waifulib: psvita: set default title id and app name to just test 2025-01-31 09:10:39 +03:00
Alibek Omarov
94b2c0b443 scripts: gha: build render-less SDL2 for PSVita 2025-01-31 09:10:09 +03:00
Alibek Omarov
ff8d17a5a8 scripts: waifulib: psvita: add missing cprogram attributes 2025-01-31 09:04:40 +03:00
Alibek Omarov
aa23196a55 scripts: waifulib: support vpk and nro pass for pure C programs, just in case 2025-01-30 20:51:01 +03:00
Alibek Omarov
83b488c37e wscript: let building client and dedicated server in the same configuration 2025-01-30 20:23:12 +03:00
Alibek Omarov
77abf621d7 ref: gl: make GL_Support and GL_MaxTextureUnits functions inlined 2025-01-30 19:02:53 +03:00
Alibek Omarov
f9d4ac2771 ref: gl: fix ugly seam at the skybox, thanks Spoike for help 2025-01-30 18:53:31 +03:00
Alibek Omarov
f076d84975 engine: platform: android: move dlsym-weak hack from C++ to C 2025-01-30 18:07:35 +03:00
Alibek Omarov
faf0b32a94 ref: gl: fix massive frame drop caused by ripples code rendering same texture multiple times in the frame 2025-01-29 20:15:21 +03:00
Alibek Omarov
feb80e5997 engine: platform: sdl: read gamecontrollerdb.txt from extras.pk3 2025-01-29 13:43:10 +03:00
Alibek Omarov
578a77518f engine: client: fix clearing keyboard buttons caused by typical brain fart 2025-01-29 10:04:47 +03:00
Alibek Omarov
2457ecf226 filesystem: fix recursive basedir possible cyclic dependency when default game directory uses a basedir that's base directory is undefined
That could happen when default game directory depends on base directory that don't have gameinfo.txt.
Because all game directories with liblist.gam automatically have dependency on default game directory, it causes cyclic dependency.
2025-01-29 09:49:29 +03:00
Alibek Omarov
8cd99885f1 filesystem: clean added status for game folders when purging search paths 2025-01-29 09:46:18 +03:00
Alibek Omarov
684e229ac8 engine: client: get rid of absolutely useless bitfields 2025-01-26 23:34:04 +03:00
SNMetamorph
c0f1d8c647 engine: model: fixed incorrect check in Mod_LoadModel 2025-01-26 23:27:18 +03:00
SNMetamorph
c3b8696957 engine: platform: win32: disable initializing console in case of regular game startup 2025-01-26 23:02:24 +03:00
Tom Kidd
3ca413dbab Fixed path calc for extras on Mac 2025-01-26 22:25:08 +03:00
Alibek Omarov
92dc04ff3c engine: client: minor change, add forgotten newline in CL_DeltaEntityGS Host_Error call 2025-01-25 17:51:48 +03:00
Alibek Omarov
ad6db91285 engine: move xashid stuff onto client 2025-01-25 17:51:48 +03:00
David DeGraw
90a0f74087 undo change to mod link 2025-01-25 08:23:04 +03:00
David DeGraw
4f7f5288a1 more nits 2025-01-25 08:23:04 +03:00
David DeGraw
c23b4bfe61 nits 2025-01-25 08:23:04 +03:00
David DeGraw
4780f70ea2 Improve mod installation instructions
Also improved uplink setup and used a better source for mod files.
2025-01-25 08:23:04 +03:00
NightFox
98a04c7764 FIx Matrix*x4_LoadIdentity (xash3d_mathlib.h) 2025-01-25 08:21:21 +03:00
Alibek Omarov
7da9772143 engine: check for macOS bundle in SDL_GetBasePath, and fallback to SDL_GetPrefPath for our directory 2025-01-23 22:58:19 +03:00
Alibek Omarov
f0b29bac1b engine: client: add cl_trace_consistency used to print which resources server wants to check 2025-01-23 13:57:17 +03:00
Alibek Omarov
7b5ff606bd 3rdparty: extras: enable compression of extras.pk3 2025-01-23 13:08:53 +03:00
Alibek Omarov
3e22ee64ae scripts: waifulib: zip: add support for passing compression level on Python 3.7. Exclude PNG files from compression 2025-01-23 13:08:21 +03:00
Alibek Omarov
c86c45503f engine: replace few more Xash3D strings by XASH_ENGINE_NAME macro 2025-01-23 10:33:22 +03:00
Alibek Omarov
ef75a4c28d engine: rename pref path on Mac to Xash3D FWGS by allowing for custom branding through XASH_ENGINE_NAME macro 2025-01-23 10:24:55 +03:00
Alibek Omarov
bccd3f2271 engine: pass launcher's default game directory all the way down to Platform_Init, so we mount correct extras.pk3 on Mac 2025-01-23 10:22:53 +03:00
Tom Kidd
7bbc3e8238 Made modifications for Mac App Bundle
- Looks for game data in SDL pref path (Application Support)
- Sets XASH3D_EXTRAS_PAK1 to SDL base path (Resources dir in App Bundle
- Added option to force search for SDL dylib via pkgconfig on Darwin instead of Framework (option for Mac Source Ports build process)
2025-01-23 10:15:47 +03:00
Alibek Omarov
c34e0c66d9 engine: add fuzzing target for Mod_LoadModel 2025-01-23 10:12:32 +03:00
Alibek Omarov
e5d80878b8 scripts: waifulib: add asan-only build type 2025-01-23 10:11:56 +03:00
Alibek Omarov
1e075d25b7 engine: make LZSS compression optional for 49 protocol, disable it for local clients (singleplayer) 2025-01-22 21:18:19 +03:00
Alibek Omarov
d29e53481d engine: client: remove unused S_StreamAviSamples 2025-01-22 20:01:11 +03:00
Alibek Omarov
d23a2fd2df engine: client: stub AVI_StreamSound RenderAPI call, it is not used in ffmpeg-based video playback code 2025-01-22 20:00:50 +03:00
Alibek Omarov
f6f15cc204 engine: mod_studio: validate studio self-reported length before loading model 2025-01-22 20:00:13 +03:00
Alibek Omarov
4f2249ed8e ref: support loading sprites with truncated palette 2025-01-22 19:24:00 +03:00
Alibek Omarov
9f322df498 engine: imagelib: handle loading truncated palette files, by filling remaining bytes with zeros 2025-01-22 19:21:51 +03:00
Alibek Omarov
b554d7e215 ref: properly handle unloading sprites that aren't loaded completely 2025-01-22 19:20:20 +03:00
Alibek Omarov
719093c10b ref: properly return false to the engine if renderer refuses to load the model for some reason 2025-01-22 19:13:23 +03:00
Alibek Omarov
c2da140ccc engine: model: do not crash if renderer refused to load this model 2025-01-22 19:12:43 +03:00
Alibek Omarov
375998dffb Cleanup xash3d_types.h from engine-specific macros and types 2025-01-22 15:10:18 +03:00
Alibek Omarov
787444f63d engine: simplify sound fx allocation 2025-01-22 14:46:40 +03:00
Alibek Omarov
0c50076ff0 engine: zone: ensure poolcount is zero on Memory_Init 2025-01-22 13:49:51 +03:00
Alibek Omarov
8ce01c38c7 engine: http: ensure we don't write broken decompressed files 2025-01-22 13:49:24 +03:00
Alibek Omarov
cac6206984 engine: client: allocate everything related to sounds in the sound pool 2025-01-22 13:49:02 +03:00
Alibek Omarov
a5c88bdda9 engine: touch: allow smoother migration from old engine touch configs by stripping .tga extension 2025-01-22 13:40:47 +03:00
Alibek Omarov
fc017286a6 engine: base_cmd: slightly faster search based on assumption that list is always ordered 2025-01-22 05:41:52 +03:00
Alibek Omarov
20d4e3e719 engine: fix flexible array member usage in case of null terminated strings
(woops)
2025-01-22 05:41:52 +03:00
Alibek Omarov
4eaa32fc10 engine: whereami: sync with upstream 2025-01-21 20:03:20 +03:00
Alibek Omarov
b7c025b167 filesystem: android: request buffer for Android asset LoadFile implementation
Might be better than asking for random access and then only reading forward.
2025-01-21 19:50:14 +03:00
Alibek Omarov
f29c588e0f filesystem: take code from DarkPlaces to properly read compressed files 2025-01-21 18:47:42 +03:00
Alibek Omarov
2065ef143a engine: server: fix ent_create under PrimeXT 2025-01-21 16:09:56 +03:00
Alibek Omarov
a5c02c85f0 filesystem: wad: get rid of sentinel value at the end of wad_types array 2025-01-21 15:26:06 +03:00
Alibek Omarov
9a8761f1d8 engine: client: remove unused NetAPI_ValueForKey function 2025-01-21 15:17:03 +03:00
Alibek Omarov
273990d292 engine: cmd: store command description in flexible array member 2025-01-21 15:06:08 +03:00
Alibek Omarov
0e27d8717c ref: remove servercount from texture struct, Xash don't use it (and it's also harmful anyway) 2025-01-21 14:36:42 +03:00
Alibek Omarov
8a9b209db0 engine: zone: optimize memory usage a bit by compressing memheader_t better while keeping it efficient
It saves about 40 kilobytes of memory.
2025-01-21 14:04:33 +03:00
Alibek Omarov
232d1f8583 engine: make separate mempools for cmds, cvars and basecmd 2025-01-21 11:26:35 +03:00
Alibek Omarov
6cfa5877a4 engine: base_cmd: decrease base cmd hash size 2025-01-21 11:25:33 +03:00
Alibek Omarov
154df00f94 filesystem: don't create full path to rwdir, as cwd is always equal to rwdir
Fixes updating gameinfo.txt.
2025-01-20 19:53:04 +03:00
Alibek Omarov
c5649c94d5 engine: client: fix delta entity packet flush on GoldSrc protocol
Implement counting playerbytes for more accurate net_graph, even if we're
skipping this delta frame.
2025-01-20 19:38:44 +03:00
Alibek Omarov
a1da10fe38 filesystem: set default values for quick/autosave aged count 2025-01-20 16:06:57 +03:00
Andrey Akhmichin
17a71ffc96 ci: upgrade freebsd tasks. 2025-01-19 04:36:07 +03:00
Andrey Akhmichin
4609fbc0c5 Documentation: supported-mod-list.md: update links. 2025-01-19 04:35:17 +03:00
Andrey Akhmichin
d278d3bdd7 engine: common: fix clang build. 2025-01-19 04:33:06 +03:00
Alibek Omarov
7811b60292 engine: common: fix build for apple and freebsd-15 2025-01-18 10:40:12 +03:00
Alibek Omarov
870fad5606 public: tests: remove Q_colorstr tests 2025-01-18 10:36:11 +03:00
Alibek Omarov
3e93aa459d engine: net_buffer: turn bit write and read masks into predefined arrays, so we don't have to call InitMasks
In future, net_buffer might get moved to libpublic.

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

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

This is why we can't have things.
2025-01-09 17:10:54 +03:00
Alibek Omarov
0d55441830 engine: properly pass shutdown reason down to close log, helps to finally get rid of global finalmsg 2025-01-09 08:04:18 +03:00
Alibek Omarov
98ff33d9e2 engine: mod_bmodel: rewrite .lit file loader using normal stream io functions 2025-01-09 08:02:39 +03:00
Alibek Omarov
baa8fbaaec engine: mod_bmodel: fix misleading debug message telling about monochrome lighting when .lit file is used 2025-01-09 08:02:39 +03:00
Alibek Omarov
a0b46da04b engine: consolidate all box clipnodes used in studio models, pmove and server in a single place 2025-01-09 08:02:39 +03:00
Alibek Omarov
e70ba7ad64 engine: now, remove SUPPORT_BSP2_FORMAT macro, only prevent ref_soft from loading such maps 2025-01-09 08:02:39 +03:00
Alibek Omarov
8a41be9d47 engine: server: finally, make a union for large leaf indices in edict_t so we can run bsp2 maps without recompiling 2025-01-09 08:02:39 +03:00
Alibek Omarov
47aff9e30b engine: hack mnode_t struct so we can have 24-bit face and children indices to support BSP2 format in runtime 2025-01-09 08:02:39 +03:00
Alibek Omarov
ced8744ac9 engine: split edge struct into two with 16-bit indicies and 32-bit indicies to support BSP2 format in runtime 2025-01-08 14:46:07 +03:00
Alibek Omarov
734c07ddab engine: split clipnodes struct into two with 16-bit indicies and 32-bit indicies to support BSP2 format in runtime 2025-01-08 14:46:07 +03:00
Alibek Omarov
ceb603488a engine: platform: sdl: set up our custom log output function to catch all SDL errors in engine log file 2025-01-08 10:10:45 +03:00
Alibek Omarov
80bac157eb Update SDL to 2.30.11, use GitHub links for SDL, as it might be faster on Actions virtual machines 2025-01-08 09:42:53 +03:00
Alibek Omarov
b45581c630 Documentation: gameinfo: add a note about liblist.gam and gameinfo.txt changes 2025-01-08 01:22:23 +03:00
Alibek Omarov
d4fe3d6f8a filesystem: wscript: check d_type field in struct dirent, as this is an extension and some supported ports (like psvita) don't have it 2025-01-08 01:22:23 +03:00
Alibek Omarov
1907485895 filesystem: re-enable folder check for array returned by listdirectory with dirs_only set to true
According to glibc manual, not all filesystems support it and some might return DT_UNKNOWN.
2025-01-08 01:22:23 +03:00
Alibek Omarov
cfebb3e1d6 filesystem: massively rework how scanning game directories work
* No more conversion from liblist.gam to gameinfo.txt. We are using liblist.gam directly now.
  gameinfo.txt being native format to Xash3D not only remains, it takes priority over liblist.gam.
* Quake game directories now don't receive autogenerated gameinfo.txt.
* Empty directories don't get gameinfo.txt either, finally making it easier to support HD addon folders.
* If user still wishes to generate gameinfo.txt, there is now command fs_make_gameinfo that creates
  gameinfo.txt for currently running game.
* No more creating empty folders for RoDir. They are now created on demand.
2025-01-08 01:22:23 +03:00
Alibek Omarov
f9a0057c28 wscript: fix bsp2 build bruh 2025-01-08 01:22:23 +03:00
Alibek Omarov
ceb2b0c5e4 filesystem: add utility function FS_CheckForQuakePak that parses Quake PAK file and looks for specific files in it's root
Used to properly detect Quake game dirs.
2025-01-08 01:22:23 +03:00
Alibek Omarov
83b5edea88 engine: platform: sdl: clear key states on losing window focus 2025-01-06 16:38:16 +03:00
Alibek Omarov
9d2a85f11f engine: client: clear mouse state along with everything else in Key_ClearStates 2025-01-06 16:38:16 +03:00
Alibek Omarov
93d3df81ee engine: client: small refactoring and better explanation for char input handler for menus that don't query our extended API 2025-01-06 16:00:11 +03:00
Alibek Omarov
2a7f13151a engine: cmd: when command is already defined and has the same function pointer, show it as warning 2025-01-06 13:51:25 +03:00
Alibek Omarov
0c4f6ae61d engine: client: like GoldSrc, use cancelselect command for escape key. It is handled in client.dll and allows mods to override Esc key behavior 2025-01-06 13:51:25 +03:00
Andrey Akhmichin
b7150c3208 Documentation: opensource-mods.md: add "Earth Special Forces". 2025-01-02 05:35:33 +03:00
Alibek Omarov
d6ebff81e2 engine: client: vgui: track textures upload to avoid issues in buggy mods (that are probably will never get fixed) 2024-12-30 07:28:33 +03:00
Alibek Omarov
ce4148f351 engine: client: vgui: deprecate VGUI_CreateTexture and VGUI_UploadTextureBlock functions, as they never used by vgui_support module
* vgui_support used them in old engine for font cache, but we don't have that anymore.
2024-12-30 07:16:30 +03:00
Alibek Omarov
08c2632c14 engine: platform: nswitch: export _Unwind_GetIPInfo as required by cs16-client 2024-12-29 09:11:21 +03:00
Alibek Omarov
03eac904c1 public: make COM_FixSlashes inlined 2024-12-29 09:05:15 +03:00
Alibek Omarov
62f3354f4e mainui: update 2024-12-29 08:06:58 +03:00
Alibek Omarov
d5b6eff0c0 game_launch: fix --disable-menu-changegame by request 2024-12-29 08:06:50 +03:00
Alibek Omarov
c9ee844a24 scripts: gha: bundle SDL2 pdb file for better stacktraces on Windows 2024-12-29 02:08:05 +03:00
Alibek Omarov
687c9b004f engine: platform: sdl: set directsound as default audio driver on Windows, due to incompatibilities with mods 2024-12-29 02:01:23 +03:00
Alibek Omarov
14e79f04ac engine: prevent extra malloc in exec by checking if cfg already contains newline at EOL and appending it to cbuf if required 2024-12-28 16:03:49 +03:00
Alibek Omarov
5d6cf48687 engine: client: fix lightstyle timings on GoldSrc protocol, share the parser with Quake protocol handler 2024-12-28 01:40:59 +03:00
Alibek Omarov
88949a9ee6 engine: launcher: drop support for changing games from within internal launcher for platforms that do not have execv equivalent 2024-12-27 18:45:31 +03:00
Alibek Omarov
2d1e76199b engine: host: always print Host_Error text to log, even if console hasn't been enabled 2024-12-27 18:37:25 +03:00
Alibek Omarov
a5d78ecfd7 engine: be more verbose on why the engine is going to be shut down 2024-12-27 18:30:46 +03:00
Alibek Omarov
3576e474e6 engine: get rid of SendKeyEvents function, it only listened for WM_QUIT on Windows and we don't use that with SDL 2024-12-27 18:30:01 +03:00
Alibek Omarov
d50927f21f ref: gl: make r_ripple work with non-square non-pot textures, fix holes caused by unexpected transparency 2024-12-26 06:31:53 +03:00
Alibek Omarov
c6e3146290 ref: gl: fix broken water texture when it was discarded by R_UploadRipples 2024-12-26 03:49:12 +03:00
Alibek Omarov
9811988cce engine: server: set mapname globals field before making first call into DLL, as some mods tend to read it too early 2024-12-26 02:50:30 +03:00
179 changed files with 5612 additions and 3695 deletions

View File

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

View File

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

3
.gitmodules vendored
View File

@@ -34,3 +34,6 @@
[submodule "3rdparty/opusfile/opusfile"]
path = 3rdparty/opusfile/opusfile
url = https://gitlab.xiph.org/xiph/opusfile.git
[submodule "3rdparty/libbacktrace/libbacktrace"]
path = 3rdparty/libbacktrace/libbacktrace
url = https://github.com/ianlancetaylor/libbacktrace

View File

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

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

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

View File

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

View File

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

View File

@@ -38,6 +38,9 @@ Uploaded to github by Oleg Cherkasky - https://github.com/gunrunners-paradise/Ct
## Deathmatch Classic
Available in Valve's Half-Life repository - https://github.com/ValveSoftware/halflife/tree/master/dmc
## Earth Special Forces
Alpha 2.0 - https://www.gamers-desire.de/details/2830
## ESHQ
Official github repository - https://github.com/adslbarxatov/xash3d-for-ESHQ

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -37,7 +37,7 @@ execute_process(
COMMAND ${CMAKE_COMMAND} -E env
CC=${WAF_CC} CXX=${WAF_CXX}
AR=${CMAKE_AR} STRIP=${CMAKE_STRIP}
${PYTHON_EXECUTABLE} waf configure -T ${BUILD_TYPE} ${WAF_EXTRA_ARGS} cmake
${PYTHON_EXECUTABLE} waf configure -T ${BUILD_TYPE} -o "${CMAKE_CURRENT_BINARY_DIR}/xash3d-fwgs" ${WAF_EXTRA_ARGS} cmake
--check-c-compiler=${C_COMPILER_ID} --check-cxx-compiler=${CXX_COMPILER_ID}
-s "${ENGINE_SOURCE_DIR}/SDL" --skip-sdl2-sanity-check --enable-bundled-deps
WORKING_DIRECTORY "${ENGINE_SOURCE_DIR}"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -373,7 +373,7 @@ CL_WriteDemoUserMessage
Dumps the user message (demoaction)
====================
*/
void CL_WriteDemoUserMessage( const byte *buffer, size_t size )
void GAME_EXPORT CL_WriteDemoUserMessage( int size, byte *buffer )
{
if( !cls.demorecording || cls.demowaiting )
return;
@@ -624,11 +624,10 @@ static void CL_ReadDemoUserCmd( qboolean discard )
if( !discard )
{
usercmd_t nullcmd;
const usercmd_t nullcmd = { 0 };
sizebuf_t buf;
demoangle_t *a;
memset( &nullcmd, 0, sizeof( nullcmd ));
MSG_Init( &buf, "UserCmd", data, sizeof( data ));
// a1ba: I have no proper explanation why

View File

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

View File

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

View File

@@ -306,21 +306,22 @@ void SPR_AdjustSize( float *x, float *y, float *w, float *h )
static void SPR_AdjustTexCoords( int texnum, float width, float height, float *s1, float *t1, float *s2, float *t2 )
{
if( REF_GET_PARM( PARM_TEX_FILTERING, texnum ))
{
if( refState.width != clgame.scrInfo.iWidth )
{
// align to texel if scaling
*s1 += 0.5f;
*s2 -= 0.5f;
}
const qboolean filtering = REF_GET_PARM( PARM_TEX_FILTERING, texnum );
const int xremainder = refState.width % clgame.scrInfo.iWidth;
const int yremainder = refState.height % clgame.scrInfo.iHeight;
if( refState.height != clgame.scrInfo.iHeight )
{
// align to texel if scaling
*t1 += 0.5f;
*t2 -= 0.5f;
}
if(( filtering || xremainder ) && refState.width != clgame.scrInfo.iWidth )
{
// align to texel if scaling
*s1 += 0.5f;
*s2 -= 0.5f;
}
if(( filtering || yremainder ) && refState.height != clgame.scrInfo.iHeight )
{
// align to texel if scaling
*t1 += 0.5f;
*t2 -= 0.5f;
}
*s1 /= width;
@@ -556,7 +557,7 @@ static void CL_InitTitles( const char *filename )
Q_snprintf( name, sizeof( name ), TEXT_MSGNAME, i );
cl_textmessage[i].pName = _copystring( clgame.mempool, name, __FILE__, __LINE__ );
cl_textmessage[i].pName = copystringpool( clgame.mempool, name );
cl_textmessage[i].pMessage = cl_textbuffer[i];
}
@@ -1698,7 +1699,12 @@ int GAME_EXPORT CL_GetScreenInfo( SCREENINFO *pscrinfo )
clgame.scrInfo.iSize = sizeof( clgame.scrInfo );
clgame.scrInfo.iFlags = SCRINFO_SCREENFLASH;
if( scale_factor && scale_factor != 1.0f )
if( hud_scale.value >= 320.0f && hud_scale.value >= hud_scale_minimal_width.value )
{
scale_factor = refState.width / hud_scale.value;
apply_scale_factor = true;
}
else if( scale_factor && scale_factor != 1.0f )
{
float scaled_width = (float)refState.width / scale_factor;
if( scaled_width >= hud_scale_minimal_width.value )
@@ -1760,7 +1766,7 @@ static cvar_t *GAME_EXPORT pfnCvar_RegisterClientVariable( const char *szName, c
|| !Q_stricmp( szName, "sensitivity" ))
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, NULL );
}
static int GAME_EXPORT Cmd_AddClientCommand( const char *cmd_name, xcommand_t function )
@@ -2408,9 +2414,8 @@ CL_FindModelIndex
*/
static int GAME_EXPORT CL_FindModelIndex( const char *m )
{
char filepath[MAX_QPATH];
static float lasttimewarn;
int i;
char filepath[MAX_QPATH];
int i;
if( !COM_CheckString( m ))
return 0;
@@ -2427,13 +2432,6 @@ static int GAME_EXPORT CL_FindModelIndex( const char *m )
return i+1;
}
if( lasttimewarn < host.realtime )
{
// tell user about problem (but don't spam console)
Con_DPrintf( S_ERROR "Could not find index for model %s: not precached\n", filepath );
lasttimewarn = host.realtime + 1.0f;
}
return 0;
}
@@ -3356,28 +3354,6 @@ DemoApi implementation
=================
*/
/*
=================
Demo_IsRecording
=================
*/
static int GAME_EXPORT Demo_IsRecording( void )
{
return cls.demorecording;
}
/*
=================
Demo_IsPlayingback
=================
*/
static int GAME_EXPORT Demo_IsPlayingback( void )
{
return cls.demoplayback;
}
/*
=================
Demo_IsTimeDemo
@@ -3389,17 +3365,6 @@ static int GAME_EXPORT Demo_IsTimeDemo( void )
return cls.timedemo;
}
/*
=================
Demo_WriteBuffer
=================
*/
static void GAME_EXPORT Demo_WriteBuffer( int size, byte *buffer )
{
CL_WriteDemoUserMessage( buffer, size );
}
/*
=================
NetworkApi implementation
@@ -3462,7 +3427,7 @@ static void GAME_EXPORT NetAPI_SendRequest( int context, int request, int flags,
return;
}
if( remote_address->type == NA_IPX || remote_address->type == NA_BROADCAST_IPX )
if( NET_NetadrType( remote_address ) == NA_IPX || NET_NetadrType( remote_address ) == NA_BROADCAST_IPX )
return; // IPX no longer support
if( request == NETAPI_REQUEST_SERVERLIST )
@@ -3585,28 +3550,6 @@ static int GAME_EXPORT NetAPI_CompareAdr( netadr_t *a, netadr_t *b )
return NET_CompareAdr( *a, *b );
}
/*
=================
NetAPI_StringToAdr
=================
*/
static int GAME_EXPORT NetAPI_StringToAdr( char *s, netadr_t *a )
{
return NET_StringToAdr( s, a );
}
/*
=================
NetAPI_ValueForKey
=================
*/
static const char * GAME_EXPORT NetAPI_ValueForKey( const char *s, const char *key )
{
return Info_ValueForKey( s, key );
}
/*
=================
NetAPI_RemoveKey
@@ -3803,10 +3746,10 @@ static event_api_t gEventApi =
static demo_api_t gDemoApi =
{
Demo_IsRecording,
Demo_IsPlayingback,
(void *)CL_IsRecordDemo,
(void *)CL_IsPlaybackDemo,
Demo_IsTimeDemo,
Demo_WriteBuffer,
CL_WriteDemoUserMessage,
};
net_api_t gNetApi =
@@ -3818,8 +3761,8 @@ net_api_t gNetApi =
NetAPI_CancelAllRequests,
NetAPI_AdrToString,
NetAPI_CompareAdr,
NetAPI_StringToAdr,
NetAPI_ValueForKey,
(void *)NET_StringToAdr,
Info_ValueForKey,
NetAPI_RemoveKey,
NetAPI_SetValueForKey,
};

View File

@@ -691,7 +691,7 @@ pfnCvar_RegisterVariable
*/
static cvar_t *GAME_EXPORT pfnCvar_RegisterGameUIVariable( const char *szName, const char *szValue, int flags )
{
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_GAMEUIDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_GAMEUIDLL ));
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_GAMEUIDLL, NULL );
}
static int GAME_EXPORT Cmd_AddGameUICommand( const char *cmd_name, xcommand_t function )
@@ -1114,7 +1114,7 @@ static void GAME_EXPORT UI_ShellExecute( const char *path, const char *parms, in
Platform_ShellExecute( path, parms );
if( shouldExit )
Sys_Quit();
Sys_Quit( __func__ );
}
/*

View File

@@ -76,6 +76,7 @@ static CVAR_DEFINE_AUTO( cl_upmax, "1200", FCVAR_ARCHIVE, "max allowed incoming
CVAR_DEFINE_AUTO( cl_lw, "1", FCVAR_ARCHIVE|FCVAR_USERINFO, "enable client weapon predicting" );
CVAR_DEFINE_AUTO( cl_charset, "utf-8", FCVAR_ARCHIVE, "1-byte charset to use (iconv style)" );
CVAR_DEFINE_AUTO( cl_trace_consistency, "0", FCVAR_ARCHIVE, "enable consistency info tracing (good for developers)" );
CVAR_DEFINE_AUTO( cl_trace_stufftext, "0", FCVAR_ARCHIVE, "enable stufftext (server-to-client console commands) tracing (good for developers)" );
CVAR_DEFINE_AUTO( cl_trace_messages, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable message names tracing (good for developers)" );
CVAR_DEFINE_AUTO( cl_trace_events, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable events tracing (good for developers)" );
@@ -147,11 +148,6 @@ qboolean CL_IsRecordDemo( void )
return cls.demorecording;
}
qboolean CL_IsTimeDemo( void )
{
return cls.timedemo;
}
qboolean CL_DisableVisibility( void )
{
return cls.envshot_disable_vis;
@@ -598,7 +594,7 @@ CL_CreateCmd
*/
static void CL_CreateCmd( void )
{
usercmd_t nullcmd, *cmd;
usercmd_t nullcmd = { 0 }, *cmd;
runcmd_t *pcmd;
qboolean active;
double accurate_ms;
@@ -650,7 +646,6 @@ static void CL_CreateCmd( void )
}
else
{
memset( &nullcmd, 0, sizeof( nullcmd ));
cmd = &nullcmd;
}
@@ -723,11 +718,20 @@ static void CL_WritePacket( void )
int numbackup, maxbackup, maxcmds;
const connprotocol_t proto = cls.legacymode;
// FIXME: on Xash protocol we don't send move commands until ca_active
// to prevent outgoing_command outrun incoming_acknowledged
// which is fatal for some buggy mods like TFC
//
// ... but GoldSrc don't have (real) ca_validate state, so we consider
// ca_validate the same as ca_active, otherwise we don't pass validation
// of server-side mods like ReAuthCheck
const connstate_t min_state = proto == PROTO_GOLDSRC ? ca_validate : ca_active;
// don't send anything if playing back a demo
if( cls.demoplayback || cls.state < ca_connected || cls.state == ca_cinematic )
return;
if( cls.state <= ca_connected )
if( cls.state < min_state )
{
Netchan_TransmitBits( &cls.netchan, 0, "" );
return;
@@ -825,7 +829,7 @@ static void CL_WritePacket( void )
buf.pData[key] = CRC32_BlockSequence( &buf.pData[key + 1], size, cls.netchan.outgoing_sequence );
COM_Munge( &buf.pData[key + 1], Q_min( size, 255 ), cls.netchan.outgoing_sequence );
}
else
else if( !Host_IsLocalClient( ))
{
int size = MSG_GetRealBytesWritten( &buf ) - key - 1;
buf.pData[key] = CRC32_BlockSequence( &buf.pData[key + 1], size, cls.netchan.outgoing_sequence );
@@ -965,7 +969,7 @@ CL_Quit_f
void CL_Quit_f( void )
{
CL_Disconnect();
Sys_Quit();
Sys_Quit( "command" );
}
/*
@@ -1059,6 +1063,7 @@ static void CL_SendConnectPacket( connprotocol_t proto, int challenge )
const char *key = ID_GetMD5();
netadr_t adr = { 0 };
int input_devices;
netadrtype_t adrtype;
protinfo[0] = 0;
@@ -1069,14 +1074,16 @@ static void CL_SendConnectPacket( connprotocol_t proto, int challenge )
return;
}
adrtype = NET_NetadrType( &adr );
if( adr.port == 0 ) adr.port = MSG_BigShort( PORT_SERVER );
input_devices = IN_CollectInputDevices();
IN_LockInputDevices( adr.type != NA_LOOPBACK ? true : false );
IN_LockInputDevices( adrtype != NA_LOOPBACK ? true : false );
// GoldSrc doesn't need sv_cheats set to 0, it's handled by svc_goldsrc_sendextrainfo
// it also doesn't need useragent string
if( adr.type != NA_LOOPBACK && proto != PROTO_GOLDSRC )
if( adrtype != NA_LOOPBACK && proto != PROTO_GOLDSRC )
{
Cvar_SetCheatState();
Cvar_FullSet( "sv_cheats", "0", FCVAR_READ_ONLY | FCVAR_SERVER );
@@ -1214,7 +1221,7 @@ static void CL_CheckForResend( void )
cls.signon = 0;
cls.state = ca_connecting;
Q_strncpy( cls.servername, "localhost", sizeof( cls.servername ));
cls.serveradr.type = NA_LOOPBACK;
NET_NetadrSetType( &cls.serveradr, NA_LOOPBACK );
cls.legacymode = PROTO_CURRENT;
// we don't need a challenge on the localhost
@@ -1550,8 +1557,8 @@ static void CL_SendDisconnectMessage( connprotocol_t proto )
MSG_WriteString( &buf, "dropclient\n" );
else MSG_WriteString( &buf, "disconnect" );
if( !cls.netchan.remote_address.type )
cls.netchan.remote_address.type = NA_LOOPBACK;
if( NET_NetadrType( &cls.netchan.remote_address ) == NA_UNDEFINED )
NET_NetadrSetType( &cls.netchan.remote_address, NA_LOOPBACK );
// make sure message will be delivered
Netchan_TransmitBits( &cls.netchan, MSG_GetNumBitsWritten( &buf ), MSG_GetData( &buf ));
@@ -1594,6 +1601,9 @@ void CL_SetupNetchanForProtocol( connprotocol_t proto )
}
break;
default:
if( !Host_IsLocalClient( ))
SetBits( flags, NETCHAN_USE_LZSS );
cls.extensions = Q_atoi( Info_ValueForKey( Cmd_Argv( 1 ), "ext" ));
if( FBitSet( cls.extensions, NET_EXT_SPLITSIZE ))
@@ -1717,19 +1727,17 @@ CL_LocalServers_f
*/
static void CL_LocalServers_f( void )
{
netadr_t adr;
memset( &adr, 0, sizeof( adr ));
netadr_t adr = { 0 };
Con_Printf( "Scanning for servers on the local network area...\n" );
NET_Config( true, true ); // allow remote
// send a broadcast packet
adr.type = NA_BROADCAST;
NET_NetadrSetType( &adr, NA_BROADCAST );
adr.port = MSG_BigShort( PORT_SERVER );
Netchan_OutOfBandPrint( NS_CLIENT, adr, A2A_INFO" %i", PROTOCOL_VERSION );
adr.type = NA_MULTICAST_IP6;
NET_NetadrSetType( &adr, NA_MULTICAST_IP6 );
Netchan_OutOfBandPrint( NS_CLIENT, adr, A2A_INFO" %i", PROTOCOL_VERSION );
}
@@ -1761,8 +1769,8 @@ static size_t NONNULL CL_BuildMasterServerScanRequest( char *buf, size_t size, u
// let master know about client version
Info_SetValueForKey( info, "clver", XASH_VERSION, remaining );
Info_SetValueForKey( info, "nat", nat ? "1" : "0", remaining );
Info_SetValueForKey( info, "commit", Q_buildcommit(), remaining );
Info_SetValueForKey( info, "branch", Q_buildbranch(), remaining );
Info_SetValueForKey( info, "commit", g_buildcommit, remaining );
Info_SetValueForKey( info, "branch", g_buildbranch, remaining );
Info_SetValueForKey( info, "os", Q_buildos(), remaining );
Info_SetValueForKey( info, "arch", Q_buildarch(), remaining );
@@ -2473,18 +2481,18 @@ static void CL_ServerList( netadr_t from, sizebuf_t *msg )
while( MSG_GetNumBitsLeft( msg ) > 8 )
{
uint8_t addr[16];
netadr_t servadr;
netadr_t servadr = { 0 };
if( from.type6 == NA_IP6 ) // IPv6 master server only sends IPv6 addresses
if( NET_NetadrType( &from ) == NA_IP6 ) // IPv6 master server only sends IPv6 addresses
{
MSG_ReadBytes( msg, addr, sizeof( addr ));
NET_IP6BytesToNetadr( &servadr, addr );
servadr.type6 = NA_IP6;
NET_NetadrSetType( &servadr, NA_IP6 );
}
else
{
MSG_ReadBytes( msg, servadr.ip, sizeof( servadr.ip )); // 4 bytes for IP
servadr.type = NA_IP;
NET_NetadrSetType( &servadr, NA_IP );
}
servadr.port = MSG_ReadShort( msg ); // 2 bytes for Port
@@ -3132,6 +3140,9 @@ static qboolean CL_ShouldRescanFilesystem( void )
}
}
if( FBitSet( fs_mount_lv.flags|fs_mount_hd.flags|fs_mount_addon.flags|fs_mount_l10n.flags|ui_language.flags, FCVAR_CHANGED ))
retval = true;
return retval;
}
@@ -3141,7 +3152,7 @@ qboolean CL_PrecacheResources( void )
// if we downloaded new WAD files or any other archives they must be added to searchpath
if( CL_ShouldRescanFilesystem( ))
g_fsapi.Rescan();
FS_Rescan_f();
// NOTE: world need to be loaded as first model
for( pRes = cl.resourcesonhand.pNext; pRes && pRes != &cl.resourcesonhand; pRes = pRes->pNext )
@@ -3387,6 +3398,7 @@ static void CL_InitLocal( void )
Cvar_RegisterVariable( &rcon_address );
Cvar_RegisterVariable( &cl_trace_consistency );
Cvar_RegisterVariable( &cl_trace_stufftext );
Cvar_RegisterVariable( &cl_trace_messages );
Cvar_RegisterVariable( &cl_trace_events );
@@ -3481,6 +3493,8 @@ static void CL_InitLocal( void )
Cmd_AddCommand ("fullserverinfo", CL_FullServerinfo_f, "sent by server when serverinfo changes" );
Cmd_AddCommand ("upload", CL_BeginUpload_f, "uploading file to the server" );
Cmd_AddRestrictedCommand( "replaybufferdat", CL_ReplayBufferDat_f, "development and debugging tool" );
Cmd_AddRestrictedCommand ("quit", CL_Quit_f, "quit from game" );
Cmd_AddRestrictedCommand ("exit", CL_Quit_f, "quit from game" );
@@ -3658,6 +3672,8 @@ void CL_Init( void )
if( !CL_LoadProgs( libpath ))
Host_Error( "can't initialize %s: %s\n", libpath, COM_GetLibraryError( ));
ID_Init();
cls.build_num = 0;
cls.initialized = true;
cl.maxclients = 1; // allow to drawing player in menu

View File

@@ -1325,11 +1325,11 @@ void CL_ParseLightStyle( sizebuf_t *msg, connprotocol_t proto )
{
int style;
const char *s;
float f = 0.0f;
float f = cl.mtime[0];
style = MSG_ReadByte( msg );
s = MSG_ReadString( msg );
if( proto != PROTO_GOLDSRC )
if( proto != PROTO_GOLDSRC && proto != PROTO_QUAKE )
f = MSG_ReadFloat( msg );
CL_SetLightstyle( style, s, f );
@@ -1614,6 +1614,23 @@ void CL_UpdateUserPings( sizebuf_t *msg )
}
}
static const char *CL_CheckTypeToString( int check_type )
{
// renamed so they have same width and look better in console output
switch( check_type )
{
case force_exactfile:
return "exactfile";
case force_model_samebounds:
return "samebounds";
case force_model_specifybounds:
return "specbounds";
case force_model_specifybounds_if_avail:
return "specbounds2";
}
return "unknown";
}
static void CL_SendConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
{
qboolean user_changed_diskfile;
@@ -1879,6 +1896,9 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
return;
}
if( cl_trace_consistency.value )
Con_Printf( "Server wants consistency of the following resources:\n" );
skip_crc_change = NULL;
lastcheck = 0;
@@ -1910,7 +1930,7 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
pc = &cl.consistency_list[cl.num_consistency];
cl.num_consistency++;
memset( pc, 0, sizeof( consistency_t ));
memset( pc, 0, sizeof( *pc ));
pc->filename = pResource->szFileName;
pc->issound = (pResource->type == t_sound);
pc->orig_index = delta;
@@ -1923,6 +1943,9 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
pc->check_type = pResource->rguc_reserved[0];
}
if( cl_trace_consistency.value )
Con_Printf( "%s\t%s\t%s\n", COM_ResourceTypeFromIndex( pResource->type ), CL_CheckTypeToString( pc->check_type ), pc->filename );
skip_crc_change = pResource;
lastcheck = delta;
}

View File

@@ -91,11 +91,11 @@ static void CL_ParseNewMovevars( sizebuf_t *msg )
typedef struct delta_header_t
{
qboolean remove : 1;
qboolean custom : 1;
qboolean instanced : 1;
uint instanced_baseline_index : 6;
uint offset : 6;
qboolean remove;
qboolean custom;
qboolean instanced;
uint16_t instanced_baseline_index;
uint16_t offset;
} delta_header_t;
static int CL_ParseDeltaHeader( sizebuf_t *msg, qboolean delta, int oldnum, struct delta_header_t *hdr )
@@ -160,33 +160,47 @@ static int CL_GetEntityDelta( const struct delta_header_t *hdr, int entnum )
return DT_ENTITY_STATE_T;
}
static void CL_FlushEntityPacketGS( frame_t *frame, sizebuf_t *msg )
static int CL_FlushEntityPacketGS( frame_t *frame, sizebuf_t *msg )
{
int playerbytes = 0, numbase = 0;
frame->valid = false;
cl.validsequence = 0; // can't render a frame
// read it all but ignore it
while( 1 )
{
int num = 0;
int newnum, bufstart;
entity_state_t from = { 0 }, to;
delta_header_t hdr;
qboolean player;
if( MSG_ReadWord( msg ) != 0 )
{
MSG_SeekToBit( msg, -16, SEEK_CUR );
num = CL_ParseDeltaHeader( msg, false, num, &hdr );
numbase = newnum = CL_ParseDeltaHeader( msg, true, numbase, &hdr );
}
else break;
if( MSG_CheckOverflow( msg ))
Host_Error( "%s: overflow\n", __func__ );
player = CL_IsPlayerIndex( newnum );
bufstart = MSG_GetNumBytesRead( msg );
if( hdr.remove )
continue;
Delta_ReadGSFields( msg, CL_GetEntityDelta( &hdr, num ), &from, &to, cl.mtime[0] );
Delta_ReadGSFields( msg, CL_GetEntityDelta( &hdr, newnum ), &from, &to, cl.mtime[0] );
if( player )
playerbytes += MSG_GetNumBytesRead( msg ) - bufstart;
}
if( MSG_CheckOverflow( msg ))
Host_Error( "%s: overflow\n", __func__ );
return playerbytes;
}
static void CL_DeltaEntityGS( const delta_header_t *hdr, sizebuf_t *msg, frame_t *frame, int newnum, const entity_state_t *from )
@@ -203,7 +217,7 @@ static void CL_DeltaEntityGS( const delta_header_t *hdr, sizebuf_t *msg, frame_t
if(( newnum < 0 ) || ( newnum >= clgame.maxEntities ))
{
Con_DPrintf( S_ERROR "CL_DeltaEntity: invalid newnum: %d\n", newnum );
Host_Error( "%s: bad delta entity number: %i", __func__, newnum );
Host_Error( "%s: bad delta entity number: %i\n", __func__, newnum );
return;
}
@@ -267,7 +281,7 @@ static void CL_CopyPacketEntity( frame_t *frame, int num, const entity_state_t *
static int CL_ParsePacketEntitiesGS( sizebuf_t *msg, qboolean delta )
{
frame_t *frame, *oldframe;
int oldindex, newnum, oldnum, numbase = 0;
int oldindex, oldnum, numbase = 0;
entity_state_t *oldent;
int count;
int playerbytes = 0;
@@ -314,7 +328,7 @@ static int CL_ParsePacketEntitiesGS( sizebuf_t *msg, qboolean delta )
// read it all but ignore it
while( 1 )
{
int bufstart;
int bufstart, newnum;
qboolean player;
delta_header_t hdr;
int val = MSG_ReadWord( msg );
@@ -534,7 +548,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
{
if( MSG_CheckOverflow( msg ))
{
Host_Error( "CL_ParseServerMessage: overflow!\n" );
Host_Error( "%s: overflow!\n", __func__ );
return;
}

View File

@@ -970,9 +970,7 @@ void CL_ParseQuakeMessage( sizebuf_t *msg )
CL_ParseQuakeServerInfo( msg );
break;
case svc_lightstyle:
param1 = MSG_ReadByte( msg );
str = MSG_ReadString( msg );
CL_SetLightstyle( param1, str, cl.mtime[0] );
CL_ParseLightStyle( msg, PROTO_QUAKE );
break;
case svc_updatename:
param1 = MSG_ReadByte( msg );

View File

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

View File

@@ -567,57 +567,54 @@ R_FizzEffect
Create a fizz effect
==============
*/
void GAME_EXPORT R_FizzEffect( cl_entity_t *pent, int modelIndex, int density )
void GAME_EXPORT R_FizzEffect( cl_entity_t *ent, int modelIndex, int density )
{
TEMPENTITY *pTemp;
int i, width, depth;
float angle, maxHeight, speed;
float xspeed, yspeed, zspeed;
vec3_t origin;
model_t *mod;
const float base_time = cl.time - 0.1f;
model_t *mod = CL_ModelHandle( modelIndex );
vec3_t volume, mins, maxs;
vec2_t speed;
int i;
if( !pent || !pent->model || !modelIndex )
if( !ent || !ent->model || !modelIndex || !mod )
return;
if(( mod = CL_ModelHandle( modelIndex )) == NULL )
return;
VectorCopy( ent->model->mins, mins );
VectorCopy( ent->model->maxs, maxs );
maxHeight = pent->model->maxs[2] - pent->model->mins[2];
width = pent->model->maxs[0] - pent->model->mins[0];
depth = pent->model->maxs[1] - pent->model->mins[1];
if( ent->angles[1] != 0.0f )
{
const float base_speed = ( ent->curstate.rendercolor.b ? -1.0f : 1.0f ) * ( ent->curstate.rendercolor.r * 256.0f + ent->curstate.rendercolor.g );
SinCos( DEG2RAD( ent->angles[1] ), &speed[1], &speed[0] );
speed[0] *= base_speed;
speed[1] *= base_speed;
}
else speed[0] = speed[1] = 0.0f;
speed = ( pent->curstate.rendercolor.r<<8 | pent->curstate.rendercolor.g );
if( pent->curstate.rendercolor.b )
speed = -speed;
angle = DEG2RAD( pent->angles[YAW] );
SinCos( angle, &yspeed, &xspeed );
xspeed *= speed;
yspeed *= speed;
VectorSubtract( maxs, mins, volume );
for( i = 0; i <= density; i++ )
{
origin[0] = mod->mins[0] + COM_RandomLong( 0, width - 1 );
origin[1] = mod->mins[1] + COM_RandomLong( 0, depth - 1 );
origin[2] = mod->mins[2];
pTemp = CL_TempEntAlloc( origin, mod );
TEMPENTITY *tent;
vec3_t origin;
if ( !pTemp ) return;
VectorCopy( mins, origin );
origin[0] += COM_RandomLong( 0, (int)volume[0] - 1 );
origin[1] += COM_RandomLong( 0, (int)volume[1] - 1 );
pTemp->flags |= FTENT_SINEWAVE;
if( !( tent = CL_TempEntAlloc( origin, mod )))
return;
pTemp->x = origin[0];
pTemp->y = origin[1];
tent->x = origin[0];
tent->y = origin[1];
tent->die = base_time;
tent->flags |= FTENT_SINEWAVE;
tent->entity.curstate.rendermode = kRenderTransAlpha;
Vector2Copy( speed, tent->entity.baseline.origin );
zspeed = COM_RandomLong( 80, 140 );
VectorSet( pTemp->entity.baseline.origin, xspeed, yspeed, zspeed );
pTemp->die = cl.time + ( maxHeight / zspeed ) - 0.1f;
pTemp->entity.curstate.frame = COM_RandomLong( 0, pTemp->frameMax );
// Set sprite scale
pTemp->entity.curstate.scale = 1.0f / COM_RandomFloat( 2.0f, 5.0f );
pTemp->entity.curstate.rendermode = kRenderTransAlpha;
pTemp->entity.curstate.renderamt = 255;
tent->entity.baseline.origin[2] = COM_RandomLong( 80, 140 );
tent->die += volume[2] / tent->entity.baseline.origin[2];
tent->entity.curstate.frame = COM_RandomLong( 0, tent->frameMax );
tent->entity.curstate.scale = 1.0f / COM_RandomFloat( 2.0f, 5.0f );
}
}
@@ -2432,7 +2429,7 @@ void CL_SetLightstyle( int style, const char *s, float f )
if( unlikely( style < 0 || style >= MAX_LIGHTSTYLES ))
{
Con_Printf( S_WARN "%s: ignored invalid lightstyle id %d\n", style );
Con_Printf( S_WARN "%s: ignored invalid lightstyle id %d\n", __func__, style );
return;
}

View File

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

View File

@@ -688,6 +688,7 @@ extern convar_t r_showtextures;
extern convar_t cl_bmodelinterp;
extern convar_t cl_lw; // local weapons
extern convar_t cl_charset;
extern convar_t cl_trace_consistency;
extern convar_t cl_trace_stufftext;
extern convar_t cl_trace_messages;
extern convar_t cl_trace_events;
@@ -736,6 +737,7 @@ void CL_ClearResourceLists( void );
//
// cl_debug.c
//
void CL_ReplayBufferDat_f( void );
void CL_Parse_Debug( qboolean enable );
void CL_Parse_RecordCommand( int cmd, int startoffset );
void CL_ResetFrame( frame_t *frame );
@@ -767,7 +769,7 @@ void CL_StartupDemoHeader( void );
void CL_DrawDemoRecording( void );
void CL_WriteDemoUserCmd( int cmdnumber );
void CL_WriteDemoMessage( qboolean startup, int start, sizebuf_t *msg );
void CL_WriteDemoUserMessage( const byte *buffer, size_t size );
void CL_WriteDemoUserMessage( int size, byte *buffer );
qboolean CL_DemoReadMessage( byte *buffer, size_t *length );
void CL_DemoInterpolateAngles( void );
void CL_CheckStartupDemos( void );
@@ -1119,7 +1121,7 @@ void Con_PageUp( int lines );
//
// s_main.c
//
void S_StreamAviSamples( void *Avi, int entnum, float fvol, float attn, float synctime );
typedef int sound_t;
void S_StartBackgroundTrack( const char *intro, const char *loop, int position, qboolean fullpath );
void S_StopBackgroundTrack( void );
void S_StreamSetPause( int pause );
@@ -1208,6 +1210,13 @@ void Key_EnableTextInput( qboolean enable, qboolean force );
int Key_ToUpper( int key );
void OSK_Draw( void );
//
// identification.c
//
void ID_Init( void );
const char *ID_GetMD5( void );
void GAME_EXPORT ID_SetCustomClientID( const char *id );
extern rgba_t g_color_table[8];
extern triangleapi_t gTriApi;
extern net_api_t gNetApi;

View File

@@ -622,7 +622,7 @@ int Con_UtfProcessCharForce( int in )
// TODO: get rid of global state where possible
static utfstate_t state = { 0 };
int ch = Q_DecodeUTF8( &state, in );
uint32_t ch = Q_DecodeUTF8( &state, in );
if( g_codepage == 1251 )
return Q_UnicodeToCP1251( ch );
@@ -2092,10 +2092,7 @@ void Con_RunConsole( void )
}
else
{
Con_Printf( S_WARN "Unknown charset %s, defaulting to cp1252", con_charset.string );
Cvar_DirectSet( &con_charset, "cp1252" );
g_codepage = 1252;
g_codepage = 0;
}
cls.accept_utf8 = !Q_stricmp( cl_charset.string, "utf-8" );

View File

@@ -611,7 +611,7 @@ void GAME_EXPORT ID_SetCustomClientID( const char *id )
void ID_Init( void )
{
MD5Context_t hash = {0};
MD5Context_t hash = { 0 };
byte md5[16];
int i;
@@ -632,7 +632,7 @@ void ID_Init( void )
#elif XASH_WIN32
{
CHAR szBuf[MAX_PATH];
ID_GetKeyData( HKEY_CURRENT_USER, "Software\\Xash3D\\", "xash_id", szBuf, MAX_PATH );
ID_GetKeyData( HKEY_CURRENT_USER, "Software\\"XASH_ENGINE_NAME"\\", "xash_id", szBuf, MAX_PATH );
sscanf(szBuf, "%016"PRIX64, &id);
id ^= SYSTEM_XOR_MASK;
@@ -686,7 +686,7 @@ void ID_Init( void )
{
CHAR Buf[MAX_PATH];
sprintf( Buf, "%016"PRIX64, id^SYSTEM_XOR_MASK );
ID_SetKeyData( HKEY_CURRENT_USER, "Software\\Xash3D\\", REG_SZ, "xash_id", Buf, Q_strlen(Buf) );
ID_SetKeyData( HKEY_CURRENT_USER, "Software\\"XASH_ENGINE_NAME"\\", REG_SZ, "xash_id", Buf, Q_strlen(Buf) );
}
#else
{

View File

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

View File

@@ -266,7 +266,7 @@ static qboolean Touch_DumpConfig( const char *name, const char *profilename )
}
FS_Printf( f, "//=======================================================================\n");
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
FS_Printf( f, "//\t\t\ttouchscreen config\n" );
FS_Printf( f, "//=======================================================================\n" );
FS_Printf( f, "\ntouch_config_file \"%s\"\n", profilename );
@@ -902,9 +902,10 @@ static void Touch_AddButton_f( void )
rgba_t color;
int argc = Cmd_Argc( );
touch_button_t *button = NULL;
const char *name, *texture, *command;
const char *name, *command;
float x1, y1, x2, y2;
qboolean privileged = Cmd_CurrentCommandIsPrivileged();
string texture;
if( argc < 4 )
{
@@ -913,9 +914,18 @@ static void Touch_AddButton_f( void )
}
name = Cmd_Argv( 1 );
texture = Cmd_Argv( 2 );
Q_strncpy( texture, Cmd_Argv( 2 ), sizeof( texture ));
command = Cmd_Argv( 3 );
// HACKHACK: old engine specifically used .tga for touch buttons
// and because new engine extras.pk3 don't have .tga textures
// (which instead were converted to .png) strip extension to let
// to let imagelib choose better format
//
// Remove this when old engine migration would be done
if( Q_stricmp( COM_FileExtension( texture ), "tga" ))
COM_StripExtension( texture );
if( argc < 8 )
{
x1 = y1 = 0.4f;
@@ -1101,7 +1111,7 @@ void Touch_Init( void )
Touch_AddDefaultButton( "duck", "touch_default/crouch", "+duck", 0.880000, 0.757428, 1.000000, 0.984656, color, 2, 1, 0 );
Touch_AddDefaultButton( "tduck", "touch_default/tduck", ";+duck", 0.560000, 0.833171, 0.620000, 0.946785, color, 2, 1, 0 );
Touch_AddDefaultButton( "edit", "touch_default/settings", "touch_enableedit", 0.420000, 0.000000, 0.500000, 0.151486, color, 2, 1, 32 );
Touch_AddDefaultButton( "menu", "touch_default/menu", "escape", 0.000000, 0.833171, 0.080000, 0.984656, color, 2, 1, 0 );
Touch_AddDefaultButton( "menu", "touch_default/menu", "cancelselect", 0.000000, 0.833171, 0.080000, 0.984656, color, 2, 1, 0 );
Touch_AddDefaultButton( "spray", "touch_default/spray", "impulse 201", 0.680000, 0.000000, 0.760000, 0.142222, color, 2, 1, 8 );
Touch_AddDefaultButton( "voicechat", "touch_default/microphone", "+voicerecord", 0.780000, 0.817778, 0.860000, 0.960000, color, 2, 1, 8 );

View File

@@ -633,8 +633,6 @@ Called every frame, even if not generating commands
*/
void Host_InputFrame( void )
{
Platform_SendKeyEvents();
IN_Commands();
IN_MouseMove();

View File

@@ -104,18 +104,21 @@ typedef enum engineAxis_e
JOY_AXIS_NULL
} engineAxis_t;
typedef enum joy_calibration_state_s
{
JOY_NOT_CALIBRATED = 0,
JOY_CALIBRATING,
JOY_FAILED_TO_CALIBRATE,
JOY_CALIBRATED
} joy_calibration_state_t;
qboolean Joy_IsActive( void );
void Joy_HatMotionEvent( byte hat, byte value );
void Joy_AxisMotionEvent( byte axis, short value );
void Joy_KnownAxisMotionEvent( engineAxis_t engineAxis, short value );
void Joy_BallMotionEvent( byte ball, short xrel, short yrel );
void Joy_ButtonEvent( byte button, byte down );
void Joy_AddEvent( void );
void Joy_RemoveEvent( void );
void Joy_SetCapabilities( qboolean have_gyro );
void Joy_SetCalibrationState( joy_calibration_state_t state );
void Joy_AxisMotionEvent( engineAxis_t engineAxis, short value );
void Joy_GyroEvent( vec3_t data );
void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw );
void Joy_Init( void );
void Joy_Shutdown( void );
void Joy_EnableTextInput(qboolean enable, qboolean force);
#endif//INPUT_H

View File

@@ -40,7 +40,7 @@ static const keyname_t keynames[] =
{
{"TAB", K_TAB, "" },
{"ENTER", K_ENTER, "" },
{"ESCAPE", K_ESCAPE, "escape" }, // hardcoded
{"ESCAPE", K_ESCAPE, "cancelselect" }, // hardcoded
{"SPACE", K_SPACE, "+jump" },
{"BACKSPACE", K_BACKSPACE, "" },
{"UPARROW", K_UPARROW, "+forward" },
@@ -51,7 +51,7 @@ static const keyname_t keynames[] =
{"CTRL", K_CTRL, "+attack" },
{"SHIFT", K_SHIFT, "+speed" },
{"CAPSLOCK", K_CAPSLOCK, "" },
{"SCROLLOCK", K_SCROLLOCK, "" },
{"SCROLLOCK", K_SCROLLLOCK, "" },
{"F1", K_F1, "cmd help" },
{"F2", K_F2, "menu_savegame" },
{"F3", K_F3, "menu_loadgame" },
@@ -106,7 +106,7 @@ static const keyname_t keynames[] =
{"Y_BUTTON", K_Y_BUTTON, "impulse 100"}, // Flashlight
{"BACK", K_BACK_BUTTON, "pause"}, // Menu
{"MODE", K_MODE_BUTTON, ""},
{"START", K_START_BUTTON, "escape"},
{"START", K_START_BUTTON, "cancelselect"},
{"STICK1", K_LSTICK, "+speed"},
{"STICK2", K_RSTICK, "+duck"},
{"L1_BUTTON", K_L1_BUTTON, "+duck"},
@@ -215,7 +215,7 @@ const char *Key_KeynumToString( int keynum )
return "<OUT OF RANGE>";
// check for printable ascii (don't use quote)
if( keynum > 32 && keynum < 127 && keynum != '"' && keynum != ';' && keynum != K_SCROLLOCK )
if( keynum > 32 && keynum < 127 && keynum != '"' && keynum != ';' && keynum != K_SCROLLLOCK )
{
tinystr[0] = keynum;
tinystr[1] = 0;
@@ -339,6 +339,12 @@ static void Key_Unbind_f( void )
return;
}
if( b == K_ESCAPE )
{
Con_Printf( "Can't unbind ESCAPE key\n" );
return;
}
Key_SetBinding( b, "" );
}
@@ -358,8 +364,8 @@ static void Key_Unbindall_f( void )
}
// set some defaults
Key_SetBinding( K_ESCAPE, "escape" );
Key_SetBinding( K_START_BUTTON, "escape" );
Key_SetBinding( K_ESCAPE, "cancelselect" );
Key_SetBinding( K_START_BUTTON, "cancelselect" );
}
/*
@@ -737,18 +743,24 @@ void GAME_EXPORT Key_Event( int key, int down )
if( cls.key_dest == key_menu )
{
// only non printable keys passed
// classic Xash3D menus don't have an extension that tells engine
// to enable text input
if( !gameui.use_extended_api )
Key_EnableTextInput( true, false );
//pass printable chars for old menus
if( !gameui.use_extended_api && !host.textmode && down && ( key >= 32 ) && ( key <= 'z' ) )
{
if( Key_IsDown( K_SHIFT ) )
// we don't know if menu wants text input or not
// enable it unconditionally
Key_EnableTextInput( true, false );
// pass this key to the menu, if printable
if( !host.textmode && down && ( key >= 32 ) && ( key <= 'z' ))
{
key += 'A' - 'a';
if( Key_IsDown( K_SHIFT ))
key += 'A' - 'a';
UI_CharEvent( key );
}
UI_CharEvent( key );
}
UI_KeyEvent( key, down );
return;
}
@@ -844,11 +856,14 @@ void GAME_EXPORT Key_ClearStates( void )
int i;
// don't clear keys during changelevel
if( cls.changelevel ) return;
if( cls.changelevel )
return;
for( i = 0; i < 256; i++ )
{
if( keys[i].down )
if( i >= K_MOUSE1 && i <= K_MOUSE5 )
IN_MouseEvent( i - K_MOUSE1, false );
else
Key_Event( i, false );
keys[i].down = 0;
@@ -1092,7 +1107,7 @@ static qboolean OSK_KeyEvent( int key, int down )
/*
=============
Joy_EnableTextInput
OSK_EnableTextInput
Enables built-in IME
=============

View File

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

View File

@@ -300,6 +300,12 @@ static qboolean R_Init_Video_( const int type )
return R_Init_Video( type );
}
static mleaf_t *pfnMod_PointInLeaf( const vec3_t p, mnode_t *node )
{
// FIXME: get rid of this on next RefAPI update
return Mod_PointInLeaf( p, node, cl.models[1] );
}
static const ref_api_t gEngfuncs =
{
pfnEngineGetParm,
@@ -340,7 +346,7 @@ static const ref_api_t gEngfuncs =
Mod_SampleSizeForFace,
Mod_BoxVisible,
Mod_PointInLeaf,
pfnMod_PointInLeaf,
R_DrawWorldHull,
R_DrawModelHull,

View File

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

View File

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

View File

@@ -996,7 +996,7 @@ static void S_UpdateAmbientSounds( void )
// calc ambient sound levels
if( !cl.worldmodel ) return;
leaf = Mod_PointInLeaf( s_listener.origin, cl.worldmodel->nodes );
leaf = Mod_PointInLeaf( s_listener.origin, cl.worldmodel->nodes, cl.worldmodel );
if( !leaf || !s_ambient_level.value )
{
@@ -1207,86 +1207,6 @@ void S_RawSamples( uint samples, uint rate, word width, word channels, const byt
S_RawEntSamples( entnum, samples, rate, width, channels, data, snd_vol );
}
/*
===================
S_PositionedRawSamples
===================
*/
void S_StreamAviSamples( void *Avi, int entnum, float fvol, float attn, float synctime )
{
int bufferSamples;
int fileSamples;
byte raw[MAX_RAW_SAMPLES];
float duration = 0.0f;
int r, fileBytes;
rawchan_t *ch = NULL;
if( !dma.initialized || s_listener.paused || !CL_IsInGame( ))
return;
if( entnum < 0 || entnum >= GI->max_edicts )
return;
if( !( ch = S_FindRawChannel( entnum, true )))
return;
if( ch->sound_info.rate == 0 )
{
if( !AVI_GetAudioInfo( Avi, &ch->sound_info ))
return; // no audiotrack
}
ch->master_vol = bound( 0, fvol * 255, 255 );
ch->dist_mult = (attn / SND_CLIP_DISTANCE);
// see how many samples should be copied into the raw buffer
if( ch->s_rawend < soundtime )
ch->s_rawend = soundtime;
// position is changed, synchronization is lost etc
if( fabs( ch->oldtime - synctime ) > s_mixahead.value )
ch->sound_info.loopStart = AVI_TimeToSoundPosition( Avi, synctime * 1000 );
ch->oldtime = synctime; // keep actual time
while( ch->s_rawend < soundtime + ch->max_samples )
{
wavdata_t *info = &ch->sound_info;
bufferSamples = ch->max_samples - (ch->s_rawend - soundtime);
// decide how much data needs to be read from the file
fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED );
if( fileSamples <= 1 ) return; // no more samples need
// our max buffer size
fileBytes = fileSamples * ( info->width * info->channels );
if( fileBytes > sizeof( raw ))
{
fileBytes = sizeof( raw );
fileSamples = fileBytes / ( info->width * info->channels );
}
// read audio stream
r = AVI_GetAudioChunk( Avi, raw, info->loopStart, fileBytes );
info->loopStart += r; // advance play position
if( r < fileBytes )
{
fileBytes = r;
fileSamples = r / ( info->width * info->channels );
}
if( r > 0 )
{
// add to raw buffer
ch->s_rawend = S_RawSamplesStereo( ch->rawsamples, ch->s_rawend, ch->max_samples,
fileSamples, info->rate, info->width, info->channels, raw );
}
else break; // no more samples for this frame
}
}
/*
===================
S_FreeIdleRawChannels
@@ -1954,14 +1874,15 @@ qboolean S_Init( void )
Cmd_AddCommand( "spk", S_SayReliable_f, "reliable play a specified sententce" );
Cmd_AddCommand( "speak", S_Say_f, "playing a specified sententce" );
sndpool = Mem_AllocPool( "Sound Zone" );
dma.backendName = "None";
if( !SNDDMA_Init( ) )
if( !SNDDMA_Init( ))
{
Con_Printf( "Audio: sound system can't be initialized\n" );
Mem_FreePool( &sndpool );
return false;
}
sndpool = Mem_AllocPool( "Sound Zone" );
soundtime = 0;
paintedtime = 0;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -46,6 +46,7 @@ static cmdalias_t *cmd_alias;
static uint cmd_condition;
static int cmd_condlevel;
static qboolean cmd_currentCommandIsPrivileged;
static poolhandle_t cmd_pool;
static void Cmd_ExecuteStringWithPrivilegeCheck( const char *text, qboolean isPrivileged );
@@ -142,28 +143,33 @@ void Cbuf_AddFilteredText( const char *text )
Cbuf_InsertText
Adds command text immediately after the current command
Adds a \n to the text
============
*/
static void Cbuf_InsertTextToBuffer( cmdbuf_t *buf, const char *text )
static void Cbuf_InsertTextToBuffer( cmdbuf_t *buf, const char *text, size_t len, size_t requested_len )
{
int l = Q_strlen( text );
if(( buf->cursize + l ) >= buf->maxsize )
if(( buf->cursize + requested_len ) >= buf->maxsize )
{
Con_Reportf( S_WARN "%s: overflow\n", __func__ );
}
else
{
memmove( buf->data + l, buf->data, buf->cursize );
memcpy( buf->data, text, l );
buf->cursize += l;
memmove( buf->data + len, buf->data, buf->cursize );
memcpy( buf->data, text, len );
buf->cursize += len;
}
}
void Cbuf_InsertTextLen( const char *text, size_t len, size_t requested_len )
{
// sometimes we need to insert more data than we have
// but also prevent overflow
Cbuf_InsertTextToBuffer( &cmd_text, text, len, requested_len );
}
void Cbuf_InsertText( const char *text )
{
Cbuf_InsertTextToBuffer( &cmd_text, text );
size_t l = Q_strlen( text );
Cbuf_InsertTextToBuffer( &cmd_text, text, l, l );
}
/*
@@ -427,7 +433,7 @@ static void Cmd_Alias_f( void )
{
if( !Q_strcmp( s, a->name ))
{
Z_Free( a->value );
Mem_Free( a->value );
break;
}
}
@@ -436,7 +442,7 @@ static void Cmd_Alias_f( void )
{
cmdalias_t *cur, *prev;
a = Z_Malloc( sizeof( cmdalias_t ));
a = Mem_Malloc( cmd_pool, sizeof( cmdalias_t ));
Q_strncpy( a->name, s, sizeof( a->name ));
@@ -464,7 +470,7 @@ static void Cmd_Alias_f( void )
}
Q_strncat( cmd, "\n", sizeof( cmd ));
a->value = copystring( cmd );
a->value = copystringpool( cmd_pool, cmd );
}
/*
@@ -524,7 +530,7 @@ struct cmd_s
char *name;
xcommand_t function;
int flags;
char *desc;
char desc[];
};
static int cmd_argc;
@@ -631,7 +637,7 @@ void Cmd_TokenizeString( const char *text )
// clear the args from the last string
for( i = 0; i < cmd_argc; i++ )
Z_Free( cmd_argv[i] );
Mem_Free( cmd_argv[i] );
cmd_argc = 0; // clear previous args
cmd_args = NULL;
@@ -665,7 +671,7 @@ void Cmd_TokenizeString( const char *text )
if( cmd_argc < MAX_CMD_TOKENS )
{
cmd_argv[cmd_argc] = copystring( cmd_token );
cmd_argv[cmd_argc] = copystringpool( cmd_pool, cmd_token );
cmd_argc++;
}
}
@@ -678,7 +684,8 @@ Cmd_AddCommandEx
*/
int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd_desc, int iFlags, const char *funcname )
{
cmd_t *cmd, *cur, *prev;
cmd_t *cmd, *cur, *prev;
size_t desc_len;
if( !COM_CheckString( cmd_name ))
{
@@ -702,8 +709,8 @@ int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd
// unfortunately, we lose original command this way
if( FBitSet( cmd->flags, CMD_OVERRIDABLE ))
{
Mem_Free( cmd->desc );
cmd->desc = copystring( cmd_desc );
desc_len = Q_strlen( cmd->desc ) + 1;
Q_strncpy( cmd->desc, cmd_desc, desc_len );
cmd->function = function;
cmd->flags = iFlags;
@@ -712,15 +719,16 @@ int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd
}
else
{
Con_DPrintf( S_ERROR "%s: %s already defined\n", funcname, cmd_name );
Con_DPrintf( "%s%s: %s already defined\n", cmd->function == function ? S_WARN : S_ERROR, funcname, cmd_name );
return 0;
}
}
// use a small malloc to avoid zone fragmentation
cmd = Z_Malloc( sizeof( cmd_t ) );
cmd->name = copystring( cmd_name );
cmd->desc = copystring( cmd_desc );
desc_len = Q_strlen( cmd_desc ) + 1;
cmd = Mem_Malloc( cmd_pool, sizeof( cmd_t ) + desc_len );
cmd->name = copystringpool( cmd_pool, cmd_name );
Q_strncpy( cmd->desc, cmd_desc, desc_len );
cmd->function = function;
cmd->flags = iFlags;
@@ -767,9 +775,6 @@ void GAME_EXPORT Cmd_RemoveCommand( const char *cmd_name )
if( cmd->name )
Mem_Free( cmd->name );
if( cmd->desc )
Mem_Free( cmd->desc );
Mem_Free( cmd );
return;
}
@@ -1010,9 +1015,10 @@ static void Cmd_ExecuteStringWithPrivilegeCheck( const char *text, qboolean isPr
if( a )
{
size_t len = Q_strlen( a->value );
Cbuf_InsertTextToBuffer(
isPrivileged ? &cmd_text : &filteredcmd_text,
a->value );
a->value, len, len );
return;
}
}
@@ -1196,7 +1202,6 @@ void Cmd_Unlink( int group )
*prev = cmd->next;
if( cmd->name ) Mem_Free( cmd->name );
if( cmd->desc ) Mem_Free( cmd->desc );
Mem_Free( cmd );
count++;
@@ -1334,6 +1339,7 @@ Cmd_Init
*/
void Cmd_Init( void )
{
cmd_pool = Mem_AllocPool( "Console Commands" );
cmd_functions = NULL;
cmd_condition = 0;
cmd_alias = NULL;
@@ -1360,6 +1366,11 @@ void Cmd_Init( void )
#endif
}
void Cmd_Shutdown( void )
{
Mem_FreePool( &cmd_pool );
}
#if XASH_ENGINE_TESTS
#include "tests.h"

View File

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

View File

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

View File

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

View File

@@ -19,6 +19,7 @@ GNU General Public License for more details.
#include "eiface.h" // ARRAYSIZE
static convar_t *cvar_vars = NULL; // head of list
static poolhandle_t cvar_pool;
CVAR_DEFINE_AUTO( cmd_scripting, "0", FCVAR_ARCHIVE|FCVAR_PRIVILEGED, "enable simple condition checking and variable operations" );
typedef struct cvar_filter_quirks_s
@@ -102,16 +103,10 @@ Cvar_BuildAutoDescription
build cvar auto description that based on the setup flags
============
*/
const char *Cvar_BuildAutoDescription( const char *szName, int flags )
static const char *Cvar_BuildAutoDescription( int flags )
{
static char desc[256];
if( FBitSet( flags, FCVAR_GLCONFIG ))
{
Q_snprintf( desc, sizeof( desc ), CVAR_GLCONFIG_DESCRIPTION, szName );
return desc;
}
desc[0] = '\0';
if( FBitSet( flags, FCVAR_EXTDLL ))
@@ -432,7 +427,7 @@ convar_t *Cvar_Get( const char *name, const char *value, int flags, const char *
{
// directly set value
freestring( var->string );
var->string = copystring( value );
var->string = copystringpool( cvar_pool, value );
var->value = Q_atof( var->string );
SetBits( var->flags, flags );
@@ -446,24 +441,28 @@ convar_t *Cvar_Get( const char *name, const char *value, int flags, const char *
Cvar_DirectSet( var, value );
}
if( FBitSet( var->flags, FCVAR_ALLOCATED ) && Q_strcmp( var_desc, var->desc ))
if( FBitSet( var->flags, FCVAR_ALLOCATED ) && var_desc != NULL && Q_strcmp( var_desc, var->desc ))
{
if( !FBitSet( flags, FCVAR_GLCONFIG ))
Con_Reportf( "%s change description from %s to %s\n", var->name, var->desc, var_desc );
// update description if needs
freestring( var->desc );
var->desc = copystring( var_desc );
var->desc = copystringpool( cvar_pool, var_desc );
}
return var;
}
// allocate a new cvar
var = Z_Malloc( sizeof( *var ));
var->name = copystring( name );
var->string = copystring( value );
var->def_string = copystring( value );
var->desc = copystring( var_desc );
if( !var_desc )
var_desc = Cvar_BuildAutoDescription( flags );
var = Mem_Malloc( cvar_pool, sizeof( *var ));
var->name = copystringpool( cvar_pool, name );
var->string = copystringpool( cvar_pool, value );
var->def_string = copystringpool( cvar_pool, value );
var->desc = copystringpool( cvar_pool, var_desc );
var->value = Q_atof( var->string );
var->flags = flags|FCVAR_ALLOCATED;
@@ -549,7 +548,7 @@ void Cvar_RegisterVariable( convar_t *var )
if( FBitSet( var->flags, FCVAR_EXTENDED ))
var->def_string = var->string; // just swap pointers
var->string = copystring( var->string );
var->string = copystringpool( cvar_pool, var->string );
var->value = Q_atof( var->string );
// find the supposed position in chain (alphanumerical order)
@@ -679,7 +678,7 @@ static convar_t *Cvar_Set2( const char *var_name, const char *value )
// and finally changed the cvar itself
freestring( var->string );
var->string = copystring( pszValue );
var->string = copystringpool( cvar_pool, pszValue );
var->value = Q_atof( var->string );
// tell engine about changes
@@ -738,7 +737,7 @@ void GAME_EXPORT Cvar_DirectSet( convar_t *var, const char *value )
// and finally changed the cvar itself
freestring( var->string );
var->string = copystring( pszValue );
var->string = copystringpool( cvar_pool, pszValue );
var->value = Q_atof( var->string );
// tell engine about changes
@@ -781,7 +780,7 @@ void Cvar_FullSet( const char *var_name, const char *value, int flags )
}
freestring( var->string );
var->string = copystring( value );
var->string = copystringpool( cvar_pool, value );
var->value = Q_atof( var->string );
SetBits( var->flags, flags );
@@ -1189,6 +1188,7 @@ static void Cvar_List_f( void )
for( var = cvar_vars; var; var = var->next )
{
char value[MAX_VA_STRING];
char *p;
if( var->name[0] == '@' )
continue; // never shows system cvars
@@ -1196,13 +1196,15 @@ static void Cvar_List_f( void )
if( match && !Q_strnicmpext( match, var->name, matchlen ))
continue;
if( Q_colorstr( var->string ))
p = Q_strchr( var->string, '^' );
if( IsColorString( p ))
Q_snprintf( value, sizeof( value ), "\"%s\"", var->string );
else Q_snprintf( value, sizeof( value ), "\"^2%s^7\"", var->string );
if( FBitSet( var->flags, FCVAR_EXTENDED|FCVAR_ALLOCATED ))
Con_Printf( " %-*s %s ^3%s^7\n", 32, var->name, value, var->desc );
else Con_Printf( " %-*s %s ^3%s^7\n", 32, var->name, value, Cvar_BuildAutoDescription( var->name, var->flags ));
else Con_Printf( " %-*s %s ^3%s^7\n", 32, var->name, value, Cvar_BuildAutoDescription( var->flags ));
count++;
}
@@ -1257,7 +1259,7 @@ pending_cvar_t *Cvar_PrepareToUnlink( int group )
continue;
namelen = Q_strlen( cv->name ) + 1;
p = Mem_Malloc( host.mempool, sizeof( *list ) + namelen );
p = Mem_Malloc( cvar_pool, sizeof( *list ) + namelen );
p->next = NULL;
p->cv_cur = cv;
p->cv_next = cv->next;
@@ -1333,6 +1335,7 @@ Reads in all archived cvars
*/
void Cvar_Init( void )
{
cvar_pool = Mem_AllocPool( "Console Variables" );
cvar_vars = NULL;
cvar_active_filter_quirks = NULL;
Cvar_RegisterVariable( &cmd_scripting );
@@ -1345,6 +1348,11 @@ void Cvar_Init( void )
Cmd_AddCommand( "cvarlist", Cvar_List_f, "display all console variables beginning with the specified prefix" );
}
void Cvar_Shutdown( void )
{
Mem_FreePool( &cvar_pool );
}
/*
============
Cvar_PostFSInit

View File

@@ -30,6 +30,8 @@ typedef struct pending_cvar_s
char cv_name[];
} pending_cvar_t;
typedef void (*setpair_t)( const char *key, const void *value, const void *buffer, void *numpairs );
cvar_t *Cvar_GetList( void );
#define Cvar_FindVar( name ) Cvar_FindVarExt( name, 0 )
convar_t *Cvar_FindVarExt( const char *var_name, int ignore_group );
@@ -42,7 +44,6 @@ void Cvar_DirectSet( convar_t *var, const char *value );
void Cvar_DirectSetValue( convar_t *var, float value );
void Cvar_Set( const char *var_name, const char *value );
void Cvar_SetValue( const char *var_name, float value );
const char *Cvar_BuildAutoDescription( const char *szName, int flags ) RETURNS_NONNULL;
float Cvar_VariableValue( const char *var_name );
int Cvar_VariableInteger( const char *var_name );
const char *Cvar_VariableString( const char *var_name ) RETURNS_NONNULL;
@@ -52,6 +53,7 @@ void Cvar_Reset( const char *var_name );
void Cvar_SetCheatState( void );
qboolean Cvar_CommandWithPrivilegeCheck( convar_t *v, qboolean isPrivileged );
void Cvar_Init( void );
void Cvar_Shutdown( void );
void Cvar_PostFSInit( void );
void Cvar_Unlink( int group );

View File

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

View File

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

View File

@@ -43,6 +43,27 @@ GNU General Public License for more details.
static pfnChangeGame pChangeGame = NULL;
host_parm_t host; // host parms
#if XASH_ANDROID
static jmp_buf return_from_main_buf;
/*
===============
Host_ExitInMain
On some platforms (e.g. Android) we can't exit with exit(3) as calling it would
kill wrapper process (e.g. app_process) too early, before all resources would
be freed, contexts released, files closed, etc, etc...
To fix this, we create jmp_buf in Host_Main function, when jumping into with
non-zero value will immediately return from it with `error_on_exit`.
===============
*/
void Host_ExitInMain( void )
{
longjmp( return_from_main_buf, 1 );
}
#endif // XASH_ANDROID
#ifdef XASH_ENGINE_TESTS
struct tests_stats_s tests_stats;
#endif
@@ -180,7 +201,6 @@ static void Sys_PrintUsage( const char *exename )
O("-daemonize ", "run engine as a daemon")
#endif
#if XASH_SDL == 2
O("-sdl_joy_old_api ","use SDL legacy joystick API")
O("-sdl_renderer <n> ","use alternative SDL_Renderer for software")
#endif // XASH_SDL
#if XASH_ANDROID && !XASH_SDL
@@ -209,7 +229,7 @@ static void Sys_PrintUsage( const char *exename )
fprintf( stderr, usage_str, exename );
#endif
Sys_Quit();
Sys_Quit( NULL );
}
static void Sys_PrintBugcompUsage( const char *exename )
@@ -234,7 +254,7 @@ static void Sys_PrintBugcompUsage( const char *exename )
fprintf( stderr, usage_str, exename );
#endif
Sys_Quit();
Sys_Quit( NULL );
}
/*
@@ -362,9 +382,8 @@ static void Host_NewInstance( const char *name, const char *finalmsg )
if( !pChangeGame ) return;
host.change_game = true;
Q_strncpy( host.finalmsg, finalmsg, sizeof( host.finalmsg ));
if( !Sys_NewInstance( name ))
if( !Sys_NewInstance( name, finalmsg ))
pChangeGame( name ); // call from hl.exe
}
@@ -418,8 +437,7 @@ static void Host_Exec_f( void )
{
string cfgpath;
byte *f;
char *txt;
fs_offset_t len;
fs_offset_t len;
if( Cmd_Argc() != 2 )
{
@@ -474,20 +492,29 @@ static void Host_Exec_f( void )
return;
}
// len is fs_offset_t, which can be larger than size_t
if( len >= SIZE_MAX )
{
Con_Reportf( "%s: %s is too long\n", __func__, Cmd_Argv( 1 ));
return;
}
if( !Q_stricmp( "config.cfg", cfgpath ))
host.config_executed = true;
// adds \n\0 at end of the file
txt = Z_Calloc( len + 2 );
memcpy( txt, f, len );
txt[len] = '\n';
txt[len + 1] = '\0';
Mem_Free( f );
if( !host.apply_game_config )
Con_Printf( "execing %s\n", Cmd_Argv( 1 ));
Cbuf_InsertText( txt );
Mem_Free( txt );
// adds \n at end of the file
// FS_LoadFile always null terminates
if( f[len - 1] != '\n' )
{
Cbuf_InsertTextLen( f, len, len + 1 );
Cbuf_InsertTextLen( "\n", 1, 1 );
}
else Cbuf_InsertTextLen( f, len, len );
Mem_Free( f );
}
/*
@@ -809,11 +836,11 @@ void GAME_EXPORT Host_Error( const char *error, ... )
}
else
{
Con_Printf( "%s: %s", __func__, hosterror1 );
if( host.allow_console )
{
UI_SetActiveMenu( false );
Key_SetKeyDest( key_console );
Con_Printf( "%s: %s", __func__, hosterror1 );
}
else Platform_MessageBox( "Host Error", hosterror1, true );
}
@@ -830,7 +857,6 @@ void GAME_EXPORT Host_Error( const char *error, ... )
recursive = true;
Q_strncpy( hosterror2, hosterror1, sizeof( hosterror2 ));
host.errorframe = host.framecount; // to avoid multply calls per frame
Q_snprintf( host.finalmsg, sizeof( host.finalmsg ), "Server crashed: %s", hosterror1 );
// clearing cmd buffer to prevent execute any commands
COM_InitHostState();
@@ -915,7 +941,7 @@ static void Host_RunTests( int stage )
#endif
Msg( "Done! %d passed, %d failed\n", tests_stats.passed, tests_stats.failed );
error_on_exit = tests_stats.failed > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
Sys_Quit();
Sys_Quit( NULL );
}
}
#endif
@@ -1017,7 +1043,7 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
}
if( !Sys_CheckParm( "-noch" ))
Sys_SetupCrashHandler();
Sys_SetupCrashHandler( argv[0] );
#if XASH_DLL_LOADER
host.enabledll = !Sys_CheckParm( "-nodll" );
@@ -1104,7 +1130,7 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
#if XASH_DEDICATED
Platform_SetupSigtermHandling();
#endif
Platform_Init( Host_IsDedicated( ) || developer >= DEV_EXTENDED );
Platform_Init( Host_IsDedicated( ) || developer >= DEV_EXTENDED, basedir );
FS_Init( basedir );
Sys_InitLog();
@@ -1162,6 +1188,11 @@ static void Host_FreeCommon( void )
FS_Shutdown();
}
static void Sys_Quit_f( void )
{
Sys_Quit( "command" );
}
/*
=================
Host_Main
@@ -1201,7 +1232,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
Cvar_Getf( "buildnum", FCVAR_READ_ONLY, "returns a current build number", "%i", Q_buildnum_compat());
Cvar_Getf( "ver", FCVAR_READ_ONLY, "shows an engine version", "%i/%s (hw build %i)", PROTOCOL_VERSION, XASH_COMPAT_VERSION, Q_buildnum_compat());
Cvar_Getf( "host_ver", FCVAR_READ_ONLY, "detailed info about this build", "%i " XASH_VERSION " %s %s %s", Q_buildnum(), Q_buildos(), Q_buildarch(), Q_buildcommit());
Cvar_Getf( "host_ver", FCVAR_READ_ONLY, "detailed info about this build", "%i " XASH_VERSION " %s %s %s", Q_buildnum(), Q_buildos(), Q_buildarch(), g_buildcommit);
Cvar_Getf( "host_lowmemorymode", FCVAR_READ_ONLY, "indicates if engine compiled for low RAM consumption (0 - normal, 1 - low engine limits, 2 - low protocol limits)", "%i", XASH_LOW_MEMORY );
Mod_Init();
@@ -1224,7 +1255,6 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
CL_Init();
HTTP_Init();
ID_Init();
SoundList_Init();
if( Host_IsDedicated( ))
@@ -1236,8 +1266,8 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
// disable texture replacements for dedicated
Cvar_FullSet( "host_allow_materials", "0", FCVAR_READ_ONLY );
Cmd_AddRestrictedCommand( "quit", Sys_Quit, "quit the game" );
Cmd_AddRestrictedCommand( "exit", Sys_Quit, "quit the game" );
Cmd_AddRestrictedCommand( "quit", Sys_Quit_f, "quit the game" );
Cmd_AddRestrictedCommand( "exit", Sys_Quit_f, "quit the game" );
}
else Cmd_AddRestrictedCommand( "minimize", Host_Minimize_f, "minimize main window to tray" );
@@ -1280,6 +1310,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
Cmd_RemoveCommand( "setgl" );
Cbuf_ExecStuffCmds(); // execute stuffcmds (commandline)
SCR_CheckStartupVids(); // must be last
FS_CheckConfig();
if( Sys_GetParmFromCmdLine( "-timedemo", demoname ))
Cbuf_AddTextf( "timedemo %s\n", demoname );
@@ -1308,6 +1339,11 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
// check after all configs were executed
HPAK_CheckIntegrity( hpk_custom_file.string );
#if XASH_ANDROID
if( setjmp( return_from_main_buf ))
return error_on_exit;
#endif // XASH_ANDROID
// main window message loop
while( !host.crashed )
{
@@ -1320,20 +1356,31 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
return 0;
}
void EXPORT Host_Shutdown( void );
void EXPORT Host_Shutdown( void )
{
Host_ShutdownWithReason( "launcher shutdown" );
}
/*
=================
Host_Shutdown
=================
*/
void EXPORT Host_Shutdown( void )
void Host_ShutdownWithReason( const char *reason )
{
qboolean error = host.status == HOST_ERR_FATAL;
if( host.shutdown_issued ) return;
if( host.shutdown_issued )
return;
host.shutdown_issued = true;
if( host.status != HOST_ERR_FATAL ) host.status = HOST_SHUTDOWN; // prepare host to normal shutdown
if( !host.change_game ) Q_strncpy( host.finalmsg, "Server shutdown", sizeof( host.finalmsg ));
if( reason != NULL )
Con_Printf( S_NOTE "Issuing host shutdown due to reason \"%s\"\n", reason );
if( host.status != HOST_ERR_FATAL )
host.status = HOST_SHUTDOWN; // prepare host to normal shutdown
#if !XASH_DEDICATED
if( host.type == HOST_NORMAL && !error )
@@ -1352,10 +1399,14 @@ void EXPORT Host_Shutdown( void )
Host_FreeCommon();
Platform_Shutdown();
BaseCmd_Shutdown();
Cmd_Shutdown();
Cvar_Shutdown();
// must be last, console uses this
Mem_FreePool( &host.mempool );
// restore filter
Sys_RestoreCrashHandler();
Sys_CloseLog();
Sys_CloseLog( reason );
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -50,9 +50,8 @@ static matrix3x4 studio_bones[MAXSTUDIOBONES];
static uint studio_hull_hitgroup[MAXSTUDIOBONES];
static uint cache_hull_hitgroup[MAXSTUDIOBONES];
static mstudiocache_t cache_studio[STUDIO_CACHESIZE];
static mclipnode_t studio_clipnodes[6];
static mplane_t studio_planes[768];
static mplane_t cache_planes[768];
static mplane_t studio_planes[MAXSTUDIOBONES * 6];
static mplane_t cache_planes[MAXSTUDIOBONES * 6];
// current cache state
static int cache_current;
@@ -66,25 +65,14 @@ Mod_InitStudioHull
*/
void Mod_InitStudioHull( void )
{
int i, side;
int i;
if( studio_hull[0].planes != NULL )
return; // already initailized
for( i = 0; i < 6; i++ )
{
studio_clipnodes[i].planenum = i;
side = i & 1;
studio_clipnodes[i].children[side] = CONTENTS_EMPTY;
if( i != 5 ) studio_clipnodes[i].children[side^1] = i + 1;
else studio_clipnodes[i].children[side^1] = CONTENTS_SOLID;
}
for( i = 0; i < MAXSTUDIOBONES; i++ )
{
studio_hull[i].clipnodes = studio_clipnodes;
studio_hull[i].clipnodes16 = (mclipnode16_t *)box_clipnodes16;
studio_hull[i].planes = &studio_planes[i*6];
studio_hull[i].firstclipnode = 0;
studio_hull[i].lastclipnode = 5;
@@ -270,6 +258,11 @@ hull_t *Mod_HullForStudio( model_t *model, float frame, int sequence, vec3_t ang
for( i = j = 0; i < mod_studiohdr->numhitboxes; i++, j += 6 )
{
if( world.version == QBSP2_VERSION )
studio_hull[i].clipnodes32 = (mclipnode32_t *)box_clipnodes32;
else
studio_hull[i].clipnodes16 = (mclipnode16_t *)box_clipnodes16;
if( bSkipShield && i == 21 )
continue; // CS stuff
@@ -875,7 +868,7 @@ void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded )
mod->type = mod_studio;
phdr = R_StudioLoadHeader( mod, buffer );
if( !phdr )
if( !phdr || phdr->length < sizeof( studiohdr_t )) // garbage value in length
return; // bad model
#if !XASH_DEDICATED

View File

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

View File

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

View File

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

View File

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

View File

@@ -2282,10 +2282,6 @@ void Test_RunDelta( void )
char buffer[4096] = { 0 };
const double timebase = 123.123;
// a1ba: netbuffer bitmasks are initialized in netchan for some reason
// initialize it ourselves just in case
MSG_InitMasks(); // initialize bit-masks
Delta_AddField( dt, "dt_string", DT_STRING, 1, 1.0f, 1.0f );
Delta_AddField( dt, "dt_timewindow_big", DT_TIMEWINDOW_BIG, 24, 1000.f, 1.0f );
Delta_AddField( dt, "dt_timewindow_8", DT_TIMEWINDOW_8, 8, 1.0f, 1.0f );

View File

@@ -326,7 +326,7 @@ static int HTTP_FileConnect( httpfile_t *file )
if( !COM_CheckStringEmpty( http_useragent.string ) || !Q_strcmp( http_useragent.string, "xash3d" ))
{
Q_snprintf( useragent, sizeof( useragent ), "%s/%s (%s-%s; build %d; %s)",
XASH_ENGINE_NAME, XASH_VERSION, Q_buildos( ), Q_buildarch( ), Q_buildnum( ), Q_buildcommit( ));
XASH_ENGINE_NAME, XASH_VERSION, Q_buildos( ), Q_buildarch( ), Q_buildnum( ), g_buildcommit );
}
else Q_strncpy( useragent, http_useragent.string, sizeof( useragent ));
@@ -505,11 +505,14 @@ static int HTTP_FileDecompress( httpfile_t *file )
if( zlib_result == Z_OK || zlib_result == Z_STREAM_END )
{
Mem_Free( data_in );
g_fsapi.WriteFile( name, data_out, decompressed_len );
HTTP_FreeFile( file, false );
}
else HTTP_FreeFile( file, true );
Mem_Free( data_in );
Mem_Free( data_out );
g_fsapi.WriteFile( name, data_out, decompressed_len );
HTTP_FreeFile( file, false );
return 1;
}

View File

@@ -151,17 +151,24 @@ static inline qboolean NET_IsSocketValid( int socket )
void NET_NetadrToIP6Bytes( uint8_t *ip6, const netadr_t *adr )
{
memcpy( ip6, adr->ip6, sizeof( adr->ip6 ));
memcpy( &ip6[0], adr->ip6_0, 2 );
memcpy( &ip6[2], adr->ip6_1, 14 );
}
void NET_IP6BytesToNetadr( netadr_t *adr, const uint8_t *ip6 )
{
memcpy( adr->ip6, ip6, sizeof( adr->ip6 ));
memcpy( adr->ip6_0, &ip6[0], 2 );
memcpy( adr->ip6_1, &ip6[2], 14 );
}
static int NET_NetadrIP6Compare( const netadr_t *a, const netadr_t *b )
{
return memcmp( a->ip6, b->ip6, sizeof( a->ip6 ));
uint8_t ip6_a[16], ip6_b[16];
NET_NetadrToIP6Bytes( ip6_a, a );
NET_NetadrToIP6Bytes( ip6_b, b );
return memcmp( ip6_a, ip6_b, sizeof( ip6_a ));
}
/*
@@ -171,27 +178,29 @@ NET_NetadrToSockadr
*/
static void NET_NetadrToSockadr( netadr_t *a, struct sockaddr_storage *s )
{
netadrtype_t type = NET_NetadrType( a );
memset( s, 0, sizeof( *s ));
if( a->type == NA_BROADCAST )
if( type == NA_BROADCAST )
{
s->ss_family = AF_INET;
((struct sockaddr_in *)s)->sin_port = a->port;
((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
}
else if( a->type == NA_IP )
else if( type == NA_IP )
{
s->ss_family = AF_INET;
((struct sockaddr_in *)s)->sin_port = a->port;
((struct sockaddr_in *)s)->sin_addr.s_addr = a->ip4;
}
else if( a->type6 == NA_IP6 )
else if( type == NA_IP6 )
{
s->ss_family = AF_INET6;
((struct sockaddr_in6 *)s)->sin6_port = a->port;
NET_NetadrToIP6Bytes(((struct sockaddr_in6 *)s)->sin6_addr.s6_addr, a );
}
else if( a->type6 == NA_MULTICAST_IP6 )
else if( type == NA_MULTICAST_IP6 )
{
s->ss_family = AF_INET6;
((struct sockaddr_in6 *)s)->sin6_port = a->port;
@@ -208,13 +217,13 @@ static void NET_SockadrToNetadr( const struct sockaddr_storage *s, netadr_t *a )
{
if( s->ss_family == AF_INET )
{
a->type = NA_IP;
NET_NetadrSetType( a, NA_IP );
a->ip4 = ((struct sockaddr_in *)s)->sin_addr.s_addr;
a->port = ((struct sockaddr_in *)s)->sin_port;
}
else if( s->ss_family == AF_INET6 )
{
a->type6 = NA_IP6;
NET_NetadrSetType( a, NA_IP6 );
NET_IP6BytesToNetadr( a, ((struct sockaddr_in6 *)s)->sin6_addr.s6_addr );
a->port = ((struct sockaddr_in6 *)s)->sin6_port;
}
@@ -549,8 +558,8 @@ qboolean NET_StringToFilterAdr( const char *s, netadr_t *adr, uint *prefixlen )
// try to parse as IPv6 first
if( ParseIPv6Addr( copy, ip6, NULL, NULL ))
{
NET_NetadrSetType( adr, NA_IP6 );
NET_IP6BytesToNetadr( adr, ip6 );
adr->type6 = NA_IP6;
if( !hasCIDR )
*prefixlen = 128;
@@ -620,7 +629,7 @@ qboolean NET_StringToFilterAdr( const char *s, netadr_t *adr, uint *prefixlen )
adr->ip4 = ntohl( mask );
}
adr->type = NA_IP;
NET_NetadrSetType( adr, NA_IP );
}
return true;
@@ -634,10 +643,11 @@ NET_AdrToString
const char *NET_AdrToString( const netadr_t a )
{
static char s[64];
netadrtype_t type = NET_NetadrType( &a );
if( a.type == NA_LOOPBACK )
if( type == NA_LOOPBACK )
return "loopback";
if( a.type6 == NA_IP6 || a.type6 == NA_MULTICAST_IP6 )
if( type == NA_IP6 || type == NA_MULTICAST_IP6 )
{
uint8_t ip6[16];
@@ -661,10 +671,11 @@ NET_BaseAdrToString
const char *NET_BaseAdrToString( const netadr_t a )
{
static char s[64];
netadrtype_t type = NET_NetadrType( &a );
if( a.type == NA_LOOPBACK )
if( type == NA_LOOPBACK )
return "loopback";
if( a.type6 == NA_IP6 || a.type6 == NA_MULTICAST_IP6 )
if( type == NA_IP6 || type == NA_MULTICAST_IP6 )
{
uint8_t ip6[16];
@@ -689,16 +700,19 @@ Compares without the port
*/
qboolean NET_CompareBaseAdr( const netadr_t a, const netadr_t b )
{
if( a.type6 != b.type6 )
netadrtype_t type_a = NET_NetadrType( &a );
netadrtype_t type_b = NET_NetadrType( &b );
if( type_a != type_b )
return false;
if( a.type == NA_LOOPBACK )
if( type_a == NA_LOOPBACK )
return true;
if( a.type == NA_IP )
if( type_a == NA_IP )
return a.ip4 == b.ip4;
if( a.type6 == NA_IP6 )
if( type_a == NA_IP6 )
{
if( !NET_NetadrIP6Compare( &a, &b ))
return true;
@@ -716,13 +730,16 @@ Compare local masks
*/
qboolean NET_CompareClassBAdr( const netadr_t a, const netadr_t b )
{
if( a.type6 != b.type6 )
netadrtype_t type_a = NET_NetadrType( &a );
netadrtype_t type_b = NET_NetadrType( &b );
if( type_a != type_b )
return false;
if( a.type == NA_LOOPBACK )
if( type_a == NA_LOOPBACK )
return true;
if( a.type == NA_IP )
if( type_a == NA_IP )
{
if( a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] )
return true;
@@ -746,10 +763,13 @@ Checks if adr is a part of subnet
*/
qboolean NET_CompareAdrByMask( const netadr_t a, const netadr_t b, uint prefixlen )
{
if( a.type6 != b.type6 || a.type == NA_LOOPBACK )
netadrtype_t type_a = NET_NetadrType( &a );
netadrtype_t type_b = NET_NetadrType( &b );
if( type_a != type_b || type_a == NA_LOOPBACK )
return false;
if( a.type == NA_IP )
if( type_a == NA_IP )
{
uint32_t ipa = htonl( a.ip4 );
uint32_t ipb = htonl( b.ip4 );
@@ -757,7 +777,7 @@ qboolean NET_CompareAdrByMask( const netadr_t a, const netadr_t b, uint prefixle
if(( ipa & (( 0xFFFFFFFFU ) << ( 32 - prefixlen ))) == ipb )
return true;
}
else if( a.type6 == NA_IP6 )
else if( type_a == NA_IP6 )
{
uint16_t a_[8], b_[8];
size_t check = prefixlen / 16;
@@ -798,11 +818,13 @@ Check for reserved ip's
*/
qboolean NET_IsReservedAdr( netadr_t a )
{
if( a.type == NA_LOOPBACK )
netadrtype_t type_a = NET_NetadrType( &a );
if( type_a == NA_LOOPBACK )
return true;
// Following checks was imported from GameNetworkingSockets library
if( a.type == NA_IP )
if( type_a == NA_IP )
{
if(( a.ip[0] == 10 ) || // 10.x.x.x is reserved
( a.ip[0] == 127 ) || // 127.x.x.x
@@ -814,7 +836,7 @@ qboolean NET_IsReservedAdr( netadr_t a )
}
}
if( a.type6 == NA_IP6 )
if( type_a == NA_IP6 )
{
uint8_t ip6[16];
@@ -847,20 +869,23 @@ Compare full address
*/
qboolean NET_CompareAdr( const netadr_t a, const netadr_t b )
{
if( a.type6 != b.type6 )
netadrtype_t type_a = NET_NetadrType( &a );
netadrtype_t type_b = NET_NetadrType( &b );
if( type_a != type_b )
return false;
if( a.type == NA_LOOPBACK )
if( type_a == NA_LOOPBACK )
return true;
if( a.type == NA_IP )
if( type_a == NA_IP )
{
if( a.ip4 == b.ip4 && a.port == b.port )
return true;
return false;
}
if( a.type6 == NA_IP6 )
if( type_a == NA_IP6 )
{
if( a.port == b.port && !NET_NetadrIP6Compare( &a, &b ))
return true;
@@ -883,9 +908,13 @@ int NET_CompareAdrSort( const void *_a, const void *_b )
{
const netadr_t *a = _a, *b = _b;
int porta, portb, portdiff, addrdiff;
netadrtype_t type_a, type_b;
if( a->type6 != b->type6 )
return bound( -1, (int)a->type6 - (int)b->type6, 1 );
type_a = NET_NetadrType( a );
type_b = NET_NetadrType( b );
if( type_a != type_b )
return bound( -1, (int)type_a - (int)type_b, 1 );
porta = ntohs( a->port );
portb = ntohs( b->port );
@@ -896,7 +925,7 @@ int NET_CompareAdrSort( const void *_a, const void *_b )
else
portdiff = 0;
switch( a->type6 )
switch( type_a )
{
case NA_IP6:
if(( addrdiff = NET_NetadrIP6Compare( a, b )))
@@ -904,14 +933,7 @@ int NET_CompareAdrSort( const void *_a, const void *_b )
// fallthrough
case NA_MULTICAST_IP6:
return portdiff;
}
// don't check for full type earlier, as it's value depends on v6 address
if( a->type != b->type )
return bound( -1, (int)a->type - (int)b->type, 1 );
switch( a->type )
{
case NA_IP:
if(( addrdiff = memcmp( a->ip, b->ip, sizeof( a->ipx ))))
return addrdiff;
@@ -946,7 +968,7 @@ static qboolean NET_StringToAdrEx( const char *string, netadr_t *adr, int family
if( !Q_stricmp( string, "localhost" ) || !Q_stricmp( string, "loopback" ))
{
adr->type = NA_LOOPBACK;
NET_NetadrSetType( adr, NA_LOOPBACK );
return true;
}
@@ -971,7 +993,7 @@ net_gai_state_t NET_StringToAdrNB( const char *string, netadr_t *adr, qboolean v
if( !Q_stricmp( string, "localhost" ) || !Q_stricmp( string, "loopback" ))
{
adr->type = NA_LOOPBACK;
NET_NetadrSetType( adr, NA_LOOPBACK );
return NET_EAI_OK;
}
@@ -1017,7 +1039,7 @@ static qboolean NET_GetLoopPacket( netsrc_t sock, netadr_t *from, byte *data, si
*length = loop->msgs[i].datalen;
memset( from, 0, sizeof( *from ));
from->type = NA_LOOPBACK;
NET_NetadrSetType( from, NA_LOOPBACK );
return true;
}
@@ -1546,19 +1568,20 @@ void NET_SendPacketEx( netsrc_t sock, size_t length, const void *data, netadr_t
int ret;
struct sockaddr_storage addr = { 0 };
SOCKET net_socket = 0;
netadrtype_t type = NET_NetadrType( &to );
if( !net.initialized || to.type == NA_LOOPBACK )
if( !net.initialized || type == NA_LOOPBACK )
{
NET_SendLoopPacket( sock, length, data, to );
return;
}
else if( to.type == NA_BROADCAST || to.type == NA_IP )
else if( type == NA_BROADCAST || type == NA_IP )
{
net_socket = net.ip_sockets[sock];
if( !NET_IsSocketValid( net_socket ))
return;
}
else if( to.type6 == NA_MULTICAST_IP6 || to.type6 == NA_IP6 )
else if( type == NA_MULTICAST_IP6 || type == NA_IP6 )
{
net_socket = net.ip6_sockets[sock];
if( !NET_IsSocketValid( net_socket ))
@@ -1566,7 +1589,7 @@ void NET_SendPacketEx( netsrc_t sock, size_t length, const void *data, netadr_t
}
else
{
Host_Error( "%s: bad address type %i (%i)\n", __func__, to.type, to.type6 );
Host_Error( "%s: bad address type %i (%i, %i)\n", __func__, to.type, to.ip6_0[0], to.ip6_0[1] );
}
NET_NetadrToSockadr( &to, &addr );
@@ -1582,7 +1605,7 @@ void NET_SendPacketEx( netsrc_t sock, size_t length, const void *data, netadr_t
return;
// some PPP links don't allow broadcasts
if( err == WSAEADDRNOTAVAIL && ( to.type == NA_BROADCAST || to.type6 == NA_MULTICAST_IP6 ))
if( err == WSAEADDRNOTAVAIL && ( type == NA_BROADCAST || type == NA_MULTICAST_IP6 ))
return;
if( Host_IsDedicated( ))

View File

@@ -80,7 +80,7 @@ void NET_NetadrToIP6Bytes( uint8_t *ip6, const netadr_t *adr );
static inline qboolean NET_IsLocalAddress( netadr_t adr )
{
return adr.type == NA_LOOPBACK ? true : false;
return NET_NetadrType( &adr ) == NA_LOOPBACK;
}
#if !XASH_DEDICATED

View File

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

View File

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

View File

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

View File

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

View File

@@ -80,7 +80,7 @@ void Sys_InitLog( void )
{
const char *mode;
if( Sys_CheckParm( "-log" ) && host.allow_console != 0 )
if( Sys_CheckParm( "-log" ))
{
s_ld.log_active = true;
Q_strncpy( s_ld.log_path, "engine.log", sizeof( s_ld.log_path ));
@@ -109,44 +109,44 @@ void Sys_InitLog( void )
// fit to 80 columns for easier read on standard terminal
fputs( "================================================================================\n", s_ld.logfile );
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
fprintf( s_ld.logfile, "Game started at %s\n", Q_timestamp( TIME_FULL ));
fputs( "================================================================================\n", s_ld.logfile );
fflush( s_ld.logfile );
}
}
void Sys_CloseLog( void )
void Sys_CloseLog( const char *finalmsg )
{
char event_name[64];
// continue logged
switch( host.status )
{
case HOST_CRASHED:
Q_strncpy( event_name, "crashed", sizeof( event_name ));
break;
case HOST_ERR_FATAL:
Q_strncpy( event_name, "stopped with error", sizeof( event_name ));
break;
default:
if( !host.change_game ) Q_strncpy( event_name, "stopped", sizeof( event_name ));
else Q_strncpy( event_name, host.finalmsg, sizeof( event_name ));
break;
}
Sys_FlushStdout(); // flush to stdout to ensure all data was written
if( s_ld.logfile )
if( !s_ld.logfile )
return;
// continue logged
if( !finalmsg )
{
fputc( '\n', s_ld.logfile );
fputs( "================================================================================\n", s_ld.logfile );
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
fprintf( s_ld.logfile, "Stopped with reason \"%s\" at %s\n", event_name, Q_timestamp( TIME_FULL ));
fputs( "================================================================================\n", s_ld.logfile );
fclose( s_ld.logfile );
s_ld.logfile = NULL;
switch( host.status )
{
case HOST_CRASHED:
finalmsg = "crashed";
break;
case HOST_ERR_FATAL:
finalmsg = "stopped with error";
break;
default:
finalmsg = "stopped";
break;
}
}
fputc( '\n', s_ld.logfile );
fputs( "================================================================================\n", s_ld.logfile );
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
fprintf( s_ld.logfile, "Stopped with reason \"%s\" at %s\n", finalmsg, Q_timestamp( TIME_FULL ));
fputs( "================================================================================\n", s_ld.logfile );
fclose( s_ld.logfile );
s_ld.logfile = NULL;
}
#if XASH_COLORIZE_CONSOLE

View File

@@ -412,7 +412,7 @@ void Sys_Error( const char *error, ... )
Sys_WaitForQuit();
}
Sys_Quit();
Sys_Quit( "caught an error" );
}
#if XASH_EMSCRIPTEN
@@ -420,6 +420,12 @@ void Sys_Error( const char *error, ... )
_exit->_Exit->asm._exit->_exit
As we do not need atexit(), just throw hidden exception
*/
// Hey, you, making an Emscripten port!
// What if we're not supposed to use exit() on Emscripten and instead we should
// exit from the main() function? Would this fix this bug? Test this case, pls.
#error "Read the comment above"
#include <emscripten.h>
#define exit my_exit
void my_exit(int ret)
@@ -435,10 +441,14 @@ void my_exit(int ret)
Sys_Quit
================
*/
void Sys_Quit( void )
void Sys_Quit( const char *reason )
{
Host_Shutdown();
Host_ShutdownWithReason( reason );
#if XASH_ANDROID
Host_ExitInMain();
#else
exit( error_on_exit );
#endif
}
/*
@@ -529,7 +539,7 @@ but since engine will be unloaded during this call
it explicitly doesn't use internal allocation or string copy utils
==================
*/
qboolean Sys_NewInstance( const char *gamedir )
qboolean Sys_NewInstance( const char *gamedir, const char *finalmsg )
{
#if XASH_NSWITCH
char newargs[4096];
@@ -540,7 +550,7 @@ qboolean Sys_NewInstance( const char *gamedir )
// just restart the entire thing
printf( "envSetNextLoad exe: `%s`\n", exe );
printf( "envSetNextLoad argv:\n`%s`\n", newargs );
Host_Shutdown( );
Host_ShutdownWithReason( finalmsg );
envSetNextLoad( exe, newargs );
exit( 0 );
#else
@@ -578,7 +588,7 @@ qboolean Sys_NewInstance( const char *gamedir )
#if XASH_PSVITA
// under normal circumstances it's always going to be the same path
exe = strdup( "app0:/eboot.bin" );
Host_Shutdown( );
Host_ShutdownWithReason( finalmsg );
sceAppMgrLoadExec( exe, newargs, NULL );
#else
exelen = wai_getExecutablePath( NULL, 0, NULL );
@@ -586,7 +596,7 @@ qboolean Sys_NewInstance( const char *gamedir )
wai_getExecutablePath( exe, exelen, NULL );
exe[exelen] = 0;
Host_Shutdown();
Host_ShutdownWithReason( finalmsg );
execv( exe, newargs );
#endif

View File

@@ -41,6 +41,15 @@ NOTE: never change this structure because all dll descriptions in xash code
writes into struct by offsets not names
========================================================================
*/
typedef struct dll_info_s
{
const char *name; // name of library
const dllfunc_t *fcts; // list of dll exports
const size_t num_fcts;
qboolean crash; // crash if dll not found
void *link; // hinstance of loading library
} dll_info_t;
extern int error_on_exit;
double Sys_DoubleTime( void );
char *Sys_GetClipboardData( void );
@@ -55,13 +64,9 @@ void Sys_DebugBreak( void );
#define Sys_GetParmFromCmdLine( parm, out ) _Sys_GetParmFromCmdLine( parm, out, sizeof( out ))
qboolean _Sys_GetParmFromCmdLine( const char *parm, char *out, size_t size );
qboolean Sys_GetIntFromCmdLine( const char *parm, int *out );
void Sys_SendKeyEvents( void );
void Sys_Print( const char *pMsg );
void Sys_PrintLog( const char *pMsg );
void Sys_InitLog( void );
void Sys_CloseLog( void );
void Sys_Quit( void ) NORETURN;
qboolean Sys_NewInstance( const char *gamedir );
void Sys_Quit( const char *reason ) NORETURN;
qboolean Sys_NewInstance( const char *gamedir, const char *finalmsg );
void *Sys_GetNativeObject( const char *obj );
//
@@ -69,7 +74,7 @@ void *Sys_GetNativeObject( const char *obj );
//
char *Sys_Input( void );
void Sys_DestroyConsole( void );
void Sys_CloseLog( void );
void Sys_CloseLog( const char *finalmsg );
void Sys_InitLog( void );
void Sys_PrintLog( const char *pMsg );
int Sys_LogFileNo( void );

View File

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

View File

@@ -31,7 +31,8 @@ extern "C" {
* @param out destination buffer, optional
* @param capacity destination buffer capacity
* @param dirname_length optional recipient for the length of the dirname part
* of the path.
* of the path. Available only when `capacity` is large enough to retrieve the
* path.
*
* @return the length of the executable path on success (without a terminal NUL
* character), otherwise `-1`
@@ -52,7 +53,8 @@ int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length);
* @param out destination buffer, optional
* @param capacity destination buffer capacity
* @param dirname_length optional recipient for the length of the dirname part
* of the path.
* of the path. Available only when `capacity` is large enough to retrieve the
* path.
*
* @return the length of the module path on success (without a terminal NUL
* character), otherwise `-1`

View File

@@ -18,7 +18,7 @@ GNU General Public License for more details.
#include "common.h"
#define MEMHEADER_SENTINEL1 0xDEADF00DU
#define MEMHEADER_SENTINEL1 0xA1BAU
#define MEMHEADER_SENTINEL2 0xDFU
#ifdef XASH_CUSTOM_SWAP
@@ -51,31 +51,29 @@ static void *Q_realloc( void *mem, size_t size )
#define Q_realloc realloc
#endif
// keep this structure as compact as possible while keeping it aligned
// on ILP32 it's 24 bytes, which is aligned to 8 byte boundary
// on LP64 it's 40 bytes, which is also aligned to 8 byte boundary
typedef struct memheader_s
{
struct memheader_s *next; // next and previous memheaders in chain belonging to pool
struct memheader_s *prev;
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;
#if !XASH_64BIT
uint32_t pad0; // doesn't have value, only to make Mem_Alloc return aligned addresses on ILP32
#endif
uint32_t sentinel1; // should always be MEMHEADER_SENTINEL1
struct memheader_s *next, *prev; // next and previous memheaders in chain belonging to pool
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
uint16_t fileline;
uint16_t sentinel1; // must be equal to MEMHEADER_SENTINEL1
// immediately followed by data, which is followed by a MEMHEADER_SENTINEL2 byte
} memheader_t;
typedef struct mempool_s
{
struct memheader_s *chain; // chain of individual memory allocations
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 lastchecksize; // updated each time the pool is displayed by memlist
const char *filename; // file name and line where Mem_AllocPool was called
int fileline;
char name[64]; // name of the pool
struct memheader_s *chain; // chain of individual memory allocations
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 lastchecksize; // updated each time the pool is displayed by memlist
const char *filename; // file name and line where Mem_AllocPool was called
int fileline;
char name[64]; // name of the pool
} mempool_t;
static mempool_t *poolchain = NULL; // critical stuff
@@ -233,10 +231,7 @@ static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline
void _Mem_Free( void *data, const char *filename, int fileline )
{
if( data == NULL )
{
Sys_Error( "%s: data == NULL (called at %s:%i)\n", __func__, filename, fileline );
return;
}
Mem_FreeBlock((memheader_t *)((byte *)data - sizeof( memheader_t )), filename, fileline );
}
@@ -521,4 +516,5 @@ Memory_Init
void Memory_Init( void )
{
poolchain = NULL; // init mem chain
poolcount = 0;
}

View File

@@ -16,11 +16,8 @@
#ifndef EDICT_H
#define EDICT_H
#ifdef SUPPORT_BSP2_FORMAT
#define MAX_ENT_LEAFS 24 // Orignally was 16
#else
#define MAX_ENT_LEAFS 48
#endif
#define MAX_ENT_LEAFS_32 24 // Orignally was 16
#define MAX_ENT_LEAFS_16 48
#include "progdefs.h"
@@ -33,11 +30,12 @@ struct edict_s
int headnode; // -1 to use normal leaf check
int num_leafs;
#ifdef SUPPORT_BSP2_FORMAT
int leafnums[MAX_ENT_LEAFS];
#else
short leafnums[MAX_ENT_LEAFS];
#endif
union
{
int leafnums32[MAX_ENT_LEAFS_32];
short leafnums16[MAX_ENT_LEAFS_16];
};
float freetime; // sv.time when the object was freed
void* pvPrivateData; // Alloced and freed by engine, used by DLLs

View File

@@ -1,186 +1,164 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
/*
Copyright (C) 1997-2001 Id Software, Inc.
#ifndef KEYDEFS_H
#define KEYDEFS_H
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// taken from Quake-2 source code and modified for GoldSrc compatibility
//
// these are the key numbers that should be passed to Key_Event
//
#define K_TAB 9
#define K_ENTER 13
#define K_ESCAPE 27
#define K_SPACE 32
#define K_SCROLLOCK 70
// normal keys should be passed as lowercased ascii
//
#define K_TAB 9
#define K_ENTER 13
#define K_ESCAPE 27
#define K_SPACE 32
#define K_SCROLLLOCK 70
#define K_BACKSPACE 127
#define K_UPARROW 128
#define K_DOWNARROW 129
#define K_LEFTARROW 130
#define K_RIGHTARROW 131
#define K_ALT 132
#define K_CTRL 133
#define K_SHIFT 134
#define K_F1 135
#define K_F2 136
#define K_F3 137
#define K_F4 138
#define K_F5 139
#define K_F6 140
#define K_F7 141
#define K_F8 142
#define K_F9 143
#define K_F10 144
#define K_F11 145
#define K_F12 146
#define K_INS 147
#define K_DEL 148
#define K_PGDN 149
#define K_PGUP 150
#define K_HOME 151
#define K_END 152
#define K_BACKSPACE 127
#define K_UPARROW 128
#define K_DOWNARROW 129
#define K_LEFTARROW 130
#define K_RIGHTARROW 131
#define K_ALT 132
#define K_CTRL 133
#define K_SHIFT 134
#define K_F1 135
#define K_F2 136
#define K_F3 137
#define K_F4 138
#define K_F5 139
#define K_F6 140
#define K_F7 141
#define K_F8 142
#define K_F9 143
#define K_F10 144
#define K_F11 145
#define K_F12 146
#define K_INS 147
#define K_DEL 148
#define K_PGDN 149
#define K_PGUP 150
#define K_HOME 151
#define K_END 152
#define K_KP_HOME 160
#define K_KP_UPARROW 161
#define K_KP_PGUP 162
#define K_KP_LEFTARROW 163
#define K_KP_5 164
#define K_KP_HOME 160
#define K_KP_UPARROW 161
#define K_KP_PGUP 162
#define K_KP_LEFTARROW 163
#define K_KP_5 164
#define K_KP_RIGHTARROW 165
#define K_KP_END 166
#define K_KP_DOWNARROW 167
#define K_KP_PGDN 168
#define K_KP_ENTER 169
#define K_KP_INS 170
#define K_KP_DEL 171
#define K_KP_SLASH 172
#define K_KP_MINUS 173
#define K_KP_PLUS 174
#define K_CAPSLOCK 175
#define K_KP_MUL 176
#define K_WIN 177
#define K_KP_NUMLOCK 178
#define K_KP_END 166
#define K_KP_DOWNARROW 167
#define K_KP_PGDN 168
#define K_KP_ENTER 169
#define K_KP_INS 170
#define K_KP_DEL 171
#define K_KP_SLASH 172
#define K_KP_MINUS 173
#define K_KP_PLUS 174
#define K_CAPSLOCK 175
#define K_KP_MUL 176
#define K_WIN 177
#define K_KP_NUMLOCK 178
//
// joystick buttons
//
#define K_JOY1 203 // LTRIGGER (L2)
#define K_JOY2 204 // RTRIGGER (R2)
#define K_JOY3 205
#define K_JOY4 206
#define K_JOY1 203
#define K_JOY2 204
#define K_JOY3 205
#define K_JOY4 206
//
// aux keys are for multi-buttoned joysticks to generate so they can use
// the normal binding process
//
#define K_AUX1 207
#define K_A_BUTTON K_AUX1
#define K_AUX1 207
#define K_AUX2 208
#define K_AUX3 209
#define K_AUX4 210
#define K_AUX5 211
#define K_AUX6 212
#define K_AUX7 213
#define K_AUX8 214
#define K_AUX9 215
#define K_AUX10 216
#define K_AUX11 217
#define K_AUX12 218
#define K_AUX13 219
#define K_AUX14 220
#define K_AUX15 221
#define K_AUX16 222
#define K_AUX17 223
#define K_AUX18 224
#define K_AUX19 225
#define K_AUX20 226
#define K_AUX21 227
#define K_AUX22 228
#define K_AUX23 229
#define K_AUX24 230
#define K_AUX25 231
#define K_AUX26 232
#define K_AUX27 233
#define K_AUX28 234
#define K_AUX29 235
#define K_AUX30 236
#define K_AUX31 237
#define K_AUX32 238
#define K_AUX2 208
#define K_B_BUTTON K_AUX2
#define K_AUX3 209
#define K_X_BUTTON K_AUX3
#define K_AUX4 210
#define K_Y_BUTTON K_AUX4
#define K_AUX5 211
#define K_L1_BUTTON K_AUX5
#define K_AUX6 212
#define K_R1_BUTTON K_AUX6
#define K_AUX7 213
#define K_BACK_BUTTON K_AUX7
#define K_AUX8 214
#define K_MODE_BUTTON K_AUX8
#define K_AUX9 215
#define K_START_BUTTON K_AUX9
#define K_AUX10 216
#define K_LSTICK K_AUX10
#define K_AUX11 217
#define K_RSTICK K_AUX11
#define K_AUX12 218
#define K_L2_BUTTON K_AUX12
#define K_AUX13 219
#define K_R2_BUTTON K_AUX13
#define K_AUX14 220
#define K_C_BUTTON K_AUX14
#define K_AUX15 221
#define K_Z_BUTTON K_AUX15
#define K_AUX16 222
#define K_DPAD_UP K_AUX16
#define K_AUX17 223
#define K_DPAD_DOWN K_AUX17
#define K_AUX18 224
#define K_DPAD_LEFT K_AUX18
#define K_AUX19 225
#define K_DPAD_RIGHT K_AUX19
#define K_AUX20 226
#define K_MISC_BUTTON K_AUX20 // Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button
#define K_AUX21 227
#define K_PADDLE1_BUTTON K_AUX21 // Xbox Elite paddle P1-P4
#define K_AUX22 228
//
// button names for game pads
//
#define K_A_BUTTON K_AUX1
#define K_B_BUTTON K_AUX2
#define K_X_BUTTON K_AUX3
#define K_Y_BUTTON K_AUX4
#define K_L1_BUTTON K_AUX5
#define K_R1_BUTTON K_AUX6
#define K_BACK_BUTTON K_AUX7
#define K_MODE_BUTTON K_AUX8
#define K_START_BUTTON K_AUX9
#define K_LSTICK K_AUX10
#define K_RSTICK K_AUX11
#define K_L2_BUTTON K_AUX12
#define K_R2_BUTTON K_AUX13
#define K_C_BUTTON K_AUX14
#define K_Z_BUTTON K_AUX15
#define K_DPAD_UP K_AUX16
#define K_DPAD_DOWN K_AUX17
#define K_DPAD_LEFT K_AUX18
#define K_DPAD_RIGHT K_AUX19
#define K_MISC_BUTTON K_AUX20
#define K_PADDLE1_BUTTON K_AUX21
#define K_PADDLE2_BUTTON K_AUX22
#define K_AUX23 229
#define K_PADDLE3_BUTTON K_AUX23
#define K_AUX24 230
#define K_PADDLE4_BUTTON K_AUX24
#define K_AUX25 231
#define K_TOUCHPAD K_AUX25 // PS4/PS5 touchpad button
#define K_AUX26 232
#define K_AUX27 233
#define K_AUX28 234
#define K_AUX29 235
#define K_AUX30 236
#define K_AUX31 237
#define K_AUX32 238
#define K_MWHEELDOWN 239
#define K_MWHEELUP 240
#define K_PAUSE 255
#define K_TOUCHPAD K_AUX25
//
// mouse buttons generate virtual keys
//
#define K_MOUSE1 241
#define K_MOUSE2 242
#define K_MOUSE3 243
#define K_MOUSE4 244
#define K_MOUSE5 245
#define K_MWHEELDOWN 239
#define K_MWHEELUP 240
#define K_MOUSE1 241
#define K_MOUSE2 242
#define K_MOUSE3 243
#define K_MOUSE4 244
#define K_MOUSE5 245
#endif//KEYDEFS_H
#define K_PAUSE 255

View File

@@ -32,7 +32,7 @@
#include <android/log.h>
#include "linker.h"
static const Elf_Sym *soinfo_elf_lookup( const soinfo *si, unsigned hash, const char *name )
static const Elf_Sym *soinfo_elf_lookup( const struct soinfo *si, unsigned hash, const char *name )
{
const Elf_Sym *symtab = si->symtab;
const char *strtab = si->strtab;
@@ -87,14 +87,14 @@ static unsigned elfhash( const unsigned char *name )
Binary Interface) where in Chapter 5 it discuss resolving "Shared
Object Dependencies" in breadth first search order.
*/
static const Elf_Sym *dlsym_handle_lookup( const soinfo *si, const char *name )
static const Elf_Sym *dlsym_handle_lookup( const struct soinfo *si, const char *name )
{
return soinfo_elf_lookup( si, elfhash((const unsigned char *)name ), name );
}
extern "C" void *dlsym_weak( void *handle, const char *symbol )
void *dlsym_weak( void *handle, const char *symbol )
{
const soinfo *found = (soinfo *)handle;
const struct soinfo *found = (struct soinfo *)handle;
const Elf_Sym *sym = dlsym_handle_lookup( found, symbol );
if( sym != NULL )

View File

@@ -31,10 +31,8 @@
#include <unistd.h>
#include <sys/types.h>
// #include <elf.h>
#include <stdbool.h>
#include <linux/elf.h>
// #include <sys/exec_elf.h>
// #include <link.h>
// a1ba: we don't really need custom linker on Android 64, because
// it's only intended to workaround bug which persist on Android < 4.4
@@ -69,8 +67,8 @@ struct link_map_t {
uintptr_t l_addr;
char *l_name;
uintptr_t l_ld;
link_map_t *l_next;
link_map_t *l_prev;
struct link_map_t *l_next;
struct link_map_t *l_prev;
};
// Values for r_debug->state
@@ -85,7 +83,7 @@ enum {
#define SOINFO_NAME_LEN 128
typedef void (*linker_function_t)();
typedef void (*linker_function_t)( void );
// Android uses REL for 32-bit but only uses RELA for 64-bit.
#if defined( __LP64__ )
@@ -93,7 +91,6 @@ typedef void (*linker_function_t)();
#endif
struct soinfo {
public:
char name[SOINFO_NAME_LEN];
const Elf_Phdr *phdr;
size_t phnum;
@@ -112,7 +109,7 @@ public:
uint32_t unused3; // DO NOT USE, maintained for compatibility
#endif
soinfo *next;
struct soinfo *next;
unsigned flags;
const char *strtab;
@@ -164,8 +161,8 @@ public:
unsigned mips_gotsym;
#endif
size_t ref_count;
link_map_t link_map;
size_t ref_count;
struct link_map_t link_map;
bool constructors_called;
@@ -177,14 +174,6 @@ public:
bool has_text_relocations;
#endif
bool has_DT_SYMBOLIC;
void CallConstructors();
void CallDestructors();
void CallPreInitConstructors();
private:
void CallArray( const char *array_name, linker_function_t *functions, size_t count, bool reverse );
void CallFunction( const char *function_name, linker_function_t function );
};
#endif

View File

@@ -91,11 +91,6 @@ void GAME_EXPORT Platform_SetMousePos(int x, int y)
}
int Platform_JoyInit( int numjoy )
{
return 0;
}
void Platform_EnableTextInput( qboolean enable )
{
keystate.chars = enable;

View File

@@ -184,7 +184,7 @@ qboolean SNDDMA_Init( void )
return false;
}
dma.buffer = Z_Malloc( samples * 2 ); //allocate pcm frame buffer
dma.buffer = Mem_Malloc( sndpool, samples * 2 ); //allocate pcm frame buffer
dma.samplepos = 0;
dma.samples = samples;
dma.format.width = 2;

View File

@@ -281,13 +281,8 @@ void GAME_EXPORT Platform_SetMousePos(int x, int y)
}
void Platform_Vibrate(float life, char flags)
void Platform_Vibrate( float life, char flags )
{
}
int Platform_JoyInit( int numjoy )
{
return 0;
}
#endif

View File

@@ -34,6 +34,7 @@ long pathconf( const char *path, int name ) { return -1; }
// part of libunwind; required by any dynamic lib that uses C++ exceptions
extern void *_Unwind_Resume;
extern void *_Unwind_GetIPInfo;
// these are macros in our libc, so we need to wrap them
static int tolower_fn( int c ) { return tolower( c ); }
@@ -55,6 +56,7 @@ static const solder_export_t aux_exports[] =
SOLDER_EXPORT_SYMBOL( strchrnul ),
SOLDER_EXPORT_SYMBOL( stpcpy ),
SOLDER_EXPORT_SYMBOL( _Unwind_Resume ),
SOLDER_EXPORT_SYMBOL( _Unwind_GetIPInfo ),
};
const solder_export_t *__solder_aux_exports = aux_exports;

View File

@@ -55,7 +55,7 @@ char *Posix_Input( void );
#endif
#if XASH_SDL
void SDLash_Init( void );
void SDLash_Init( const char *basedir );
void SDLash_Shutdown( void );
#endif
@@ -104,7 +104,7 @@ void Linux_SetTimer( float time );
int Linux_GetProcessID( void );
#endif
static inline void Platform_Init( qboolean con_showalways )
static inline void Platform_Init( qboolean con_showalways, const char *basedir )
{
#if XASH_POSIX
// daemonize as early as possible, because we need to close our file descriptors
@@ -112,7 +112,7 @@ static inline void Platform_Init( qboolean con_showalways )
#endif
#if XASH_SDL
SDLash_Init( );
SDLash_Init( basedir );
#endif
#if XASH_ANDROID
@@ -178,11 +178,11 @@ static inline void Platform_Sleep( int msec )
#endif
}
#if XASH_WIN32 || XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX
void Sys_SetupCrashHandler( void );
#if XASH_WIN32 || XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX || XASH_APPLE
void Sys_SetupCrashHandler( const char *argv0 );
void Sys_RestoreCrashHandler( void );
#else
static inline void Sys_SetupCrashHandler( void )
static inline void Sys_SetupCrashHandler( const char *argv0 )
{
}
@@ -199,7 +199,8 @@ static inline void Sys_RestoreCrashHandler( void )
==============================================================================
*/
void Platform_Vibrate( float life, char flags );
void Platform_Vibrate( float life, char flags ); // left for compatibility
void Platform_Vibrate2( float time, int low_freq, int high_freq, uint flags );
/*
==============================================================================
@@ -209,7 +210,27 @@ void Platform_Vibrate( float life, char flags );
==============================================================================
*/
// Gamepad support
int Platform_JoyInit( int numjoy ); // returns number of connected gamepads, negative if error
#if XASH_SDL
int Platform_JoyInit( void ); // returns number of connected gamepads, negative if error
void Platform_JoyShutdown( void );
void Platform_CalibrateGamepadGyro( void );
#else
static inline int Platform_JoyInit( void )
{
return 0;
}
static inline void Platform_JoyShutdown( void )
{
}
static inline void Platform_CalibrateGamepadGyro( void )
{
}
#endif
// Text input
void Platform_EnableTextInput( qboolean enable );
key_modifier_t Platform_GetKeyModifiers( void );
@@ -253,14 +274,6 @@ static inline char *Platform_Input( void )
#endif
}
#if XASH_WIN32
void Platform_SendKeyEvents( void );
#else
static inline void Platform_SendKeyEvents( void )
{
}
#endif
/*
==============================================================================

View File

@@ -0,0 +1,87 @@
/*
crashhandler.c - advanced crashhandler
Copyright (C) 2016 Mittorn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
// on Glibc (which potentially might not be only Linux) systems we
// have backtrace() and backtrace_symbols() calls, which replace for us
// platform-specific code
#if HAVE_EXECINFO
#include "common.h"
#include <execinfo.h>
#include <signal.h>
void Sys_Crash( int signal, siginfo_t *si, void *context )
{
char message[8192];
int len, logfd, i = 0;
int size;
void *addrs[16];
char **syms;
(void)context;
// flush buffers before writing directly to descriptors
fflush( stdout );
fflush( stderr );
// safe actions first, stack and memory may be corrupted
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s-%s, %s-%s)\n",
Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch() );
#if !XASH_FREEBSD && !XASH_NETBSD && !XASH_OPENBSD && !XASH_APPLE // they don't have si_ptr
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p %p\n", signal, si->si_errno, si->si_code, si->si_addr, si->si_ptr );
#else
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p\n", signal, si->si_errno, si->si_code, si->si_addr );
#endif
write( STDERR_FILENO, message, len );
// now get log fd and write trace directly to log
logfd = Sys_LogFileNo();
write( logfd, message, len );
size = backtrace( addrs, sizeof( addrs ) / sizeof( addrs[0] ));
syms = backtrace_symbols( addrs, size );
for( i = 0; i < size && syms; i++ )
{
size_t symlen = Q_strlen( syms[i] );
char ch = '\n';
write( logfd, syms[i], symlen );
write( logfd, &ch, 1 );
write( STDERR_FILENO, syms[i], symlen );
write( STDERR_FILENO, &ch, 1 );
len += Q_snprintf( message + len, sizeof( message ) - len, "%2d: %s\n", i, syms[i] );
}
// put MessageBox as Sys_Error
Msg( "%s\n", message );
#ifdef XASH_SDL
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
#endif
host.crashed = true;
Platform_MessageBox( "Xash Error", message, false );
// log saved, now we can try to save configs and close log correctly, it may crash
if( host.type == HOST_NORMAL )
CL_Crashed();
host.status = HOST_CRASHED;
Sys_Quit( "crashed" );
}
#endif // HAVE_EXECINFO

View File

@@ -0,0 +1,187 @@
/*
crashhandler.c - advanced crashhandler
Copyright (C) 2016 Mittorn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#if HAVE_LIBBACKTRACE
#include <signal.h>
#include "common.h"
#include "backtrace.h"
static struct backtrace_state *g_bt_state;
static qboolean enable_libbacktrace;
static void Sys_BacktraceError( void *data, const char *msg, int errnum )
{
if( errnum < 0 )
{
Con_Printf( S_ERROR "no symbol info, no libbacktrace\n" );
return;
}
Con_Printf( S_ERROR "libbacktrace error: %s (%d)\n", msg, errnum );
enable_libbacktrace = false;
}
struct print_data
{
char *message;
size_t message_size;
int len;
int idx;
int logfd;
};
static void Sys_AppendPrint( struct print_data *pd, const char *fmt, ... )
{
va_list va;
int len;
va_start( va, fmt );
len = Q_vsnprintf( pd->message, pd->message_size, fmt, va );
va_end( va );
if( len > 0 )
{
char ch = '\n';
write( pd->logfd, pd->message, len );
write( pd->logfd, &ch, 1 );
write( STDERR_FILENO, pd->message, len );
write( STDERR_FILENO, &ch, 1 );
pd->message += len;
pd->len += len;
pd->message_size -= len;
}
}
static void Sys_BacktracePrintError( void *data, const char *msg, int errnum )
{
struct print_data *pd = data;
Sys_AppendPrint( pd, "%2d: error: %s (%d)\n", pd->idx++, msg, errnum );
}
static void Sys_BacktracePrintSyminfo( void *data, uintptr_t pc, const char *symname, uintptr_t symval, uintptr_t symsize )
{
struct print_data *pd = data;
Dl_info dlinfo = { 0 };
const char *module_name;
if( dladdr((void *)pc, &dlinfo ))
module_name = dlinfo.dli_fname;
else module_name = NULL;
if( symname )
{
if( module_name )
Sys_AppendPrint( pd, "%2d: <%s+%d> (%s)\n", pd->idx++, symname, pc - symval, module_name );
else
Sys_AppendPrint( pd, "%2d: <%s+%d>\n", pd->idx++, symname, pc - symval );
}
else
{
if( module_name )
Sys_AppendPrint( pd, "%2d: %p (%s)\n", pd->idx++, pc, module_name );
else
Sys_AppendPrint( pd, "%2d: %p\n", pd->idx++, pc );
}
}
static int Sys_BacktracePrintFull( void *data, uintptr_t pc, const char *filename, int lineno, const char *function )
{
struct print_data *pd = data;
Dl_info dlinfo = { 0 };
const char *module_name;
if( dladdr((void *)pc, &dlinfo ))
module_name = dlinfo.dli_fname;
else module_name = NULL;
if( filename && lineno && function )
{
if( module_name )
Sys_AppendPrint( pd, "%2d: %s (%s:%d) (%s)\n", pd->idx++, function, filename, lineno, module_name );
else
Sys_AppendPrint( pd, "%2d: %s (%s:%d)\n", pd->idx++, function, filename, lineno );
}
else
{
backtrace_syminfo( g_bt_state, pc, Sys_BacktracePrintSyminfo, Sys_BacktraceError, data );
}
return 0;
}
void Sys_CrashLibbacktrace( int signal, siginfo_t *si, void *context )
{
char message[8192];
int len, logfd;
struct print_data pd = { .idx = 0 };
(void)context;
// flush buffers before writing directly to descriptors
fflush( stdout );
fflush( stderr );
// safe actions first, stack and memory may be corrupted
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s-%s, %s-%s)\n",
Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch() );
#if !XASH_FREEBSD && !XASH_NETBSD && !XASH_OPENBSD && !XASH_APPLE // they don't have si_ptr
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p %p\n", signal, si->si_errno, si->si_code, si->si_addr, si->si_ptr );
#else
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p\n", signal, si->si_errno, si->si_code, si->si_addr );
#endif
write( STDERR_FILENO, message, len );
// now get log fd and write trace directly to log
pd.logfd = logfd = Sys_LogFileNo();
write( logfd, message, len );
pd.message = message + len;
pd.message_size = sizeof( message ) - len;
pd.len = 0;
if( g_bt_state )
backtrace_full( g_bt_state, 0, Sys_BacktracePrintFull, Sys_BacktracePrintError, &pd );
// put MessageBox as Sys_Error
Msg( "%s\n", message );
#ifdef XASH_SDL
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
#endif
host.crashed = true;
Platform_MessageBox( "Xash Error", message, false );
// log saved, now we can try to save configs and close log correctly, it may crash
if( host.type == HOST_NORMAL )
CL_Crashed();
host.status = HOST_CRASHED;
Sys_Quit( "crashed" );
}
qboolean Sys_SetupLibbacktrace( const char *argv0 )
{
enable_libbacktrace = true;
g_bt_state = backtrace_create_state( argv0, true, Sys_BacktraceError, NULL );
return g_bt_state != NULL && enable_libbacktrace;
}
#endif // HAVE_EXECINFO

View File

@@ -18,7 +18,8 @@ GNU General Public License for more details.
// while this is mostly POSIX-compatible functions
// the contents of ucontext_t is platform-dependent
// before adding new OS here, check platform.h
#if XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX
#define _XOPEN_SOURCE 1 // required for ucontext
#if XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX || XASH_APPLE
#ifndef XASH_OPENBSD
#include <ucontext.h>
#endif
@@ -26,6 +27,13 @@ GNU General Public License for more details.
#include <sys/mman.h>
#include "library.h"
void Sys_Crash( int signal, siginfo_t *si, void *context );
void Sys_CrashLibbacktrace( int signal, siginfo_t *si, void *context );
qboolean Sys_SetupLibbacktrace( const char *argv0 );
static struct sigaction oldFilter;
#if !HAVE_EXECINFO
#define STACK_BACKTRACE_STR "Stack backtrace:\n"
#define STACK_DUMP_STR "Stack dump:\n"
@@ -33,27 +41,25 @@ GNU General Public License for more details.
#define STACK_DUMP_STR_LEN ( sizeof( STACK_DUMP_STR ) - 1 )
#define ALIGN( x, y ) (((uintptr_t) ( x ) + (( y ) - 1 )) & ~(( y ) - 1 ))
static struct sigaction oldFilter;
static int Sys_PrintFrame( char *buf, int len, int i, void *addr )
{
Dl_info dlinfo;
if( len <= 0 )
return 0; // overflow
if( dladdr( addr, &dlinfo ))
{
if( dlinfo.dli_sname )
return Q_snprintf( buf, len, "%2d: %p <%s+%lu> (%s)\n", i, addr, dlinfo.dli_sname,
(unsigned long)addr - (unsigned long)dlinfo.dli_saddr, dlinfo.dli_fname ); // print symbol, module and address
if( dladdr( addr, &dlinfo ))
{
if( dlinfo.dli_sname )
return Q_snprintf( buf, len, "%2d: %p <%s+%lu> (%s)\n", i, addr, dlinfo.dli_sname,
(unsigned long)addr - (unsigned long)dlinfo.dli_saddr, dlinfo.dli_fname ); // print symbol, module and address
return Q_snprintf( buf, len, "%2d: %p (%s)\n", i, addr, dlinfo.dli_fname ); // print module and address
}
return Q_snprintf( buf, len, "%2d: %p (%s)\n", i, addr, dlinfo.dli_fname ); // print module and address
}
return Q_snprintf( buf, len, "%2d: %p\n", i, addr ); // print only address
return Q_snprintf( buf, len, "%2d: %p\n", i, addr ); // print only address
}
static void Sys_Crash( int signal, siginfo_t *si, void *context)
void Sys_Crash( int signal, siginfo_t *si, void *context )
{
void *pc = NULL, **bp = NULL, **sp = NULL; // this must be set for every OS!
char message[8192];
@@ -65,6 +71,10 @@ static void Sys_Crash( int signal, siginfo_t *si, void *context)
ucontext_t *ucontext = (ucontext_t*)context;
#endif
// flush buffers before writing directly to descriptors
fflush( stdout );
fflush( stderr );
#if XASH_AMD64
#if XASH_FREEBSD
pc = (void*)ucontext->uc_mcontext.mc_rip;
@@ -112,10 +122,10 @@ static void Sys_Crash( int signal, siginfo_t *si, void *context)
#endif
// safe actions first, stack and memory may be corrupted
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n",
Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch() );
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s-%s, %s-%s)\n",
Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch() );
#if !XASH_FREEBSD && !XASH_NETBSD && !XASH_OPENBSD
#if !XASH_FREEBSD && !XASH_NETBSD && !XASH_OPENBSD && !XASH_APPLE
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p %p\n", signal, si->si_errno, si->si_code, si->si_addr, si->si_ptr );
#else
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p\n", signal, si->si_errno, si->si_code, si->si_addr );
@@ -123,10 +133,6 @@ static void Sys_Crash( int signal, siginfo_t *si, void *context)
write( STDERR_FILENO, message, len );
// flush buffers before writing directly to descriptors
fflush( stdout );
fflush( stderr );
// now get log fd and write trace directly to log
logfd = Sys_LogFileNo();
write( logfd, message, len );
@@ -197,19 +203,30 @@ static void Sys_Crash( int signal, siginfo_t *si, void *context)
CL_Crashed();
host.status = HOST_CRASHED;
Sys_Quit();
Sys_Quit( "crashed" );
}
void Sys_SetupCrashHandler( void )
#endif // !HAVE_EXECINFO
void Sys_SetupCrashHandler( const char *argv0 )
{
struct sigaction act = { 0 };
act.sa_sigaction = Sys_Crash;
#if HAVE_LIBBACKTRACE
if( Sys_SetupLibbacktrace( argv0 ))
{
act.sa_sigaction = Sys_CrashLibbacktrace;
}
else
#endif
{
act.sa_sigaction = Sys_Crash;
}
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
sigaction( SIGSEGV, &act, &oldFilter );
sigaction( SIGABRT, &act, &oldFilter );
sigaction( SIGBUS, &act, &oldFilter );
sigaction( SIGILL, &act, &oldFilter );
}
void Sys_RestoreCrashHandler( void )

View File

@@ -148,7 +148,9 @@ void Posix_Daemonize( void )
static void Posix_SigtermCallback( int signal )
{
Sys_Quit();
string reason;
Con_Printf( reason, sizeof( reason ), "caught signal %d", signal );
Sys_Quit( reason );
}
void Posix_SetupSigtermHandling( void )

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