Compare commits

..

593 Commits

Author SHA1 Message Date
Alibek Omarov
a656469f12 android: set requestLegacyExternalStorage specifically for Android 10 which didn't had MANAGE_EXTERNAL_STORAGE yet 2025-08-12 12:15:12 +05:00
Alibek Omarov
4f45df2293 engine: imagelib: add missing argument name, so it compilers with old C standards compliant compilers 2025-08-11 20:50:03 +05:00
Alibek Omarov
af0d77caf7 filesystem: android: more verbosity when mounting assets on Android fails 2025-08-11 18:49:26 +05:00
Alibek Omarov
3a6862f278 engine: when specifying server dll name with an @ (give that feature a name please), actually look for it in server dlls folder 2025-08-11 18:44:12 +05:00
Alibek Omarov
2ad482ee2f engine: platform: android: add some verbosity when successfully loading libraries on Android (hidden under -dev 2) 2025-08-11 18:36:44 +05:00
Alibek Omarov
be0d31f408 engine: imagelib: try to use FS_Search to bruteforce through supported image formats 2025-08-08 18:14:46 +05:00
Alibek Omarov
7c8e2a598f android: restore su.xash.engine.MOD action intent filter 2025-08-08 17:49:30 +05:00
Alibek Omarov
820a001ced engine: move prepending lib prefix on Android earlier, when the path is constructed 2025-08-08 17:03:56 +05:00
Alibek Omarov
a5b68c5ed9 public: remove unused global 2025-08-08 17:01:35 +05:00
Alibek Omarov
f37738f6f8 android: set useLegacyPackaging to true, disable noCompress 2025-08-08 16:16:35 +05:00
Alibek Omarov
4cc009ac3e engine: always prepend lib on Android, as it's part of library naming scheme now 2025-08-08 16:16:05 +05:00
Alibek Omarov
5100125fef Documentation: extensions: library-naming: add a note about distributing Android game libraries 2025-08-08 16:13:48 +05:00
Alibek Omarov
1c0d145874 filesystem: restore lib prefix on Android, otherwise Android won't unpack the libraries 2025-08-08 16:00:03 +05:00
Alibek Omarov
0e48f57247 3rdparty: mainui: update 2025-08-05 19:04:33 +05:00
Alibek Omarov
f9ec8f0b85 wscript: disable {gcc,msvc}deps with wafcache enabled 2025-08-05 19:03:53 +05:00
Alibek Omarov
a4614a00e9 engine: move android logging category from debug to info 2025-08-05 19:03:53 +05:00
Bohdan Shulyar
0ba45d343e host: common: switch host_writeconfig to direct function call 2025-08-05 01:31:21 +05:00
Bohdan Shulyar
2c26601bee engine: common: add a host_writeconfig console command 2025-08-05 01:31:21 +05:00
Alibek Omarov
10ada3c141 Revert "scripts: gha: temporarily switch hlsdk-portable branch to android_library_naming for testing"
This reverts commit c1c0c2761d.
2025-08-04 10:39:04 +05:00
Alibek Omarov
4912e84d46 android: enable x86 and x86_64 abis back 2025-08-04 10:38:59 +05:00
Alibek Omarov
81c7ef20eb filesystem: android: use commit date as android assets file time 2025-08-04 10:25:42 +05:00
Alibek Omarov
ac22de84bf public: remove Q_buildnum generated from __DATE__ macro, as we rely only on Git now 2025-08-04 10:25:42 +05:00
Alibek Omarov
70f6480a5f engine: add a shortcut for loading custom DLLs that follow library naming scheme (like bots) 2025-08-03 19:01:56 +05:00
Alibek Omarov
95bfb7cdf2 scripts: build-ninja: add support for installing libraries with cmake, compared to yanking them out of build directory
Set up hlsdk-portable to install in APK style directory (omitting game and game library directories from path).
Minor refactoring.
2025-08-03 19:01:56 +05:00
Alibek Omarov
b22186b2f1 engine: platform: android: strip library path when loading libraries from APK 2025-08-03 19:01:56 +05:00
Bohdan Shulyar
70e53f547b android: add some simple run instructions 2025-08-03 19:01:56 +05:00
Bohdan Shulyar
8047f8177b android: add some simple docs 2025-08-03 19:01:56 +05:00
Bohdan Shulyar
95bf2f03ad android: bump deps 2025-08-03 19:01:56 +05:00
Bohdan Shulyar
ca6de641a1 android: experimental ninja build 2025-08-03 19:01:56 +05:00
Bohdan Shulyar
bb811310d2 android: fix weird acra build error 2025-08-03 19:01:56 +05:00
Bohdan Shulyar
cd881c079b android: don't generate x86 libraries for now 2025-08-03 19:01:56 +05:00
Bohdan Shulyar
2319d4caf9 android: bump gradle 2025-08-03 19:01:56 +05:00
Bohdan Shulyar
ac412fc15e android: add a (not working yet) basedir option 2025-08-03 19:01:56 +05:00
Bohdan Shulyar
4f7a216191 android: update codebase to use java File API 2025-08-03 19:01:56 +05:00
Velaron
d87cdd7ff8 android: reformat codebase 2025-08-03 19:01:56 +05:00
Velaron
2c53cc7e70 android: upgrade buildsystem 2025-08-03 19:01:56 +05:00
Velaron
b7bb81fbe7 android: remove DocumentsProvider 2025-08-03 19:01:56 +05:00
Velaron
a767540a2b android: remove currently unused or invalid resources 2025-08-03 19:01:56 +05:00
Alibek Omarov
f1251e8767 engine: platform: android: do not automatically prepend lib prefix 2025-08-03 19:01:56 +05:00
Alibek Omarov
c1c0c2761d scripts: gha: temporarily switch hlsdk-portable branch to android_library_naming for testing 2025-08-03 19:01:56 +05:00
Alibek Omarov
c69a87fa89 filesystem: wscript: strip lib prefix on Android 2025-08-03 19:01:56 +05:00
Alibek Omarov
bf7f952d0e defaults: disable INTERNAL_GAMELIBS for Android 2025-08-03 19:01:56 +05:00
Alibek Omarov
6aecc45ce1 engine: platform: include errno.h globally, it's defined by the C standard, so should be available everywhere 2025-08-03 10:27:36 +05:00
Alibek Omarov
bfc10a732a engine: register forgotten ui_language cvar, so changing language actually works (thanks @Alivebyte on GitHub\!) 2025-08-03 10:23:31 +05:00
Alibek Omarov
67d1536127 public: rename rsqrt to Q_rsqrt due to weird collision with tgmath.h macro
It was reported on Discord with no additional information attached. But I guess
it might be better to prefix our math- and crtlib functions in general.
2025-08-03 10:20:52 +05:00
Alibek Omarov
56db9f73d8 engine: platform: ignore nanosleep EINTR error, otherwise sleeptime will never use nanosleep again 2025-08-03 10:18:29 +05:00
lewa_j
250d425b34 engine: platform: sdl2: use -egl to force EGL on windows, same as on other platforms 2025-08-03 08:21:14 +05:00
lewa_j
99140fc7df engine: platform: sdl2: Allow SDL to use wgl to create gles context, if it can 2025-08-03 08:21:14 +05:00
Alibek Omarov
2557d5acaa 3rdparty: opus: limit assembly to SSE and SSE2
Otherwise whole engine builds with SSE4.1 and AVX support with LTO enabled. =/
2025-08-03 04:34:46 +05:00
lewa_j
b14a1b664f engine: platform: sdl2: Fix uninitialized read introduces in 7fda58561f 2025-08-02 17:59:26 +03:00
Alibek Omarov
56361b52e7 3rdparty: opus: enable platform optimized code (x86 SSE/AVX with runtime detection and NEON on ARM)
Along that enable hardening and check for C99 lrintf (probably can do the same in the engine at some point).
2025-08-02 12:27:26 +05:00
Alibek Omarov
da1b9ad80d scripts: waifulib: xcompile: enable cross compilation automatically if CROSS_COMPILE environment variable is set 2025-07-31 03:17:39 +05:00
Alibek Omarov
aec1213319 scripts: waifulib: xcompile: fix NDK 28 minimal API version 2025-07-31 03:17:39 +05:00
Alibek Omarov
cb4540a877 engine: platform: android: call SDL_OpenURL only if XASH_SDL was defined during build. Remove version check, as Android always builds with latest SDL version. 2025-07-30 23:33:08 +05:00
Alibek Omarov
613768c3f9 wscript: add experimental option to enable wafcache [skip ci] 2025-07-30 21:07:45 +05:00
Alibek Omarov
234a16d611 scripts: waifulib: xcompile: add support for kbuild-style CROSS_COMPILE environment variable [skip ci] 2025-07-30 21:06:32 +05:00
Alibek Omarov
e468371394 3rdparty: libbacktrace: similarly, use C compiler for multicheck tests, as this is a C project 2025-07-29 21:42:40 +05:00
Alibek Omarov
671157ee20 public: wscript: set compiler for tests using compiler key instead of directly setting up features, otherwise it won't add uselib 2025-07-29 21:42:02 +05:00
Alibek Omarov
4398de1dab public: wscript: explicitly set language for libc tests in multicheck, as Waf chooses C++ by default
Compiling tgmath.h test with C++ compiler causes misdetection on PSVita which has broken tgmath.h support.
2025-07-29 20:41:59 +05:00
Alibek Omarov
dc09cf0c39 public: fix incorrect logic where libc extension defines were exported without an actual check 2025-07-29 11:31:45 +05:00
Alibek Omarov
f4854dbcde public: wscript: parallelize libc extension checks for faster reconfigure 2025-07-29 08:57:57 +05:00
Alibek Omarov
25e206f5ae engine: platform: posix: remove old crashhandler as libbacktrace supports much more targets, remove duplicated code around execinfo and libbacktrace-based crashhandlers
Update copyright headers.
2025-07-29 08:14:06 +05:00
Andrey Akhmichin
b3d3a15c3d utils: mdldec: bump version to 1.2.1. 2025-07-27 22:02:59 +05:00
Andrey Akhmichin
92faa25670 utils: mdldec: add support for absolute paths on *nix. 2025-07-27 22:02:59 +05:00
lewa_j
3eed2769d5 ref: wscript: gl4es fix typo 2025-07-27 16:27:55 +05:00
lewa_j
6302553ee4 ref: update nanogl and wes submodules 2025-07-27 16:27:55 +05:00
lewa_j
ae2808dff7 ref: gles3compat: Fix crashes on stubs under windows, probably due to signature missmatch 2025-07-27 16:27:55 +05:00
lewa_j
af69df15e1 ref: Fix gl4es build under windows. Static gl functions declared with APIENTRY even without mangling. 2025-07-27 16:27:55 +05:00
lewa_j
98e4aae6bb ref: wscript: Fix gl4es invalid build flags under msvc 2025-07-27 16:27:55 +05:00
Sergey Degtyar
3e921c829f engine: client: fix CL_DrawCenterPrint aligment for cyrillic text 2025-07-26 19:57:23 +05:00
Sergey Degtyar
e994cc0c8b engine: client: adjust SPRAY_ALPHA_THRESHOLD 2025-07-25 02:32:40 +05:00
Alibek Omarov
cd26b1f279 engine: imagelib: img_quant: reduce used colors from 256 to 255, so last color in palette can be reserved for custom usage (like transparency in player decals) 2025-07-25 01:39:59 +05:00
Alibek Omarov
24f05e3fc5 engine: client: refactor spray logo, get rid of unneeded bmp checks 2025-07-25 01:34:46 +05:00
Alibek Omarov
2bdeb05153 engine: client: oops, fix including non-existent file 2025-07-25 00:24:45 +05:00
Alibek Omarov
de4b635b19 engine: client: move cl_spray.c only external function declaration to client.h, move other definitions to cl_spray.c 2025-07-24 23:59:15 +05:00
SNMetamorph
ab744a8baf engine: client: fixed critical bugs in GoldSrc spray generating code, removed useless hacks 2025-07-24 20:49:05 +05:00
SNMetamorph
0aca03d343 engine: client: refactored GoldSrc sprays code, removed magic numbers 2025-07-24 20:49:05 +05:00
Alibek Omarov
eeca965b5d 3rdparty: update libbacktrace and mainui submodules 2025-07-18 19:00:39 +05:00
Alibek Omarov
eb27dc639e Documentation: remove public server rules and recommendation (it might be back after reworking it) 2025-07-18 19:00:39 +05:00
Bohdan Shulyar
af5c6d1196 donate: update url 2025-07-18 03:47:09 +05:00
Sergey Degtyar
0cce014c01 engine: client: fix spray support for 24-bit BMP (save as miptex, not decal) 2025-07-17 02:20:36 +05:00
Sergey Degtyar
6111df486e engine: client: GoldSrc spray support 2025-07-16 23:54:56 +05:00
Sergey Degtyar
7dc88f9417 filesystem: common: move wad structures to wadfile.h 2025-07-16 23:54:56 +05:00
Sergey Degtyar
e36486b73a engine: imagelib: handling wad extension to save and load image properly 2025-07-16 23:54:56 +05:00
Sergey Degtyar
000304ddde engine: net_chan: added bz2 compression for file fragments 2025-07-16 23:54:56 +05:00
Alibek Omarov
4c9b69af5f engine: mod_bmodel: allow firstclipnode index to be negative, as maps compiled with it rely on this trick by encoding whole hull as empty contents 2025-07-16 23:42:49 +05:00
SNMetamorph
599b1b48ec engine: voice: added wrapper for players voice status array to avoid mess with off-by-one errors 2025-07-15 18:54:01 +05:00
Alibek Omarov
4e23012950 ci: disable build for e2k-8c for now (probably will compile natively on e2k-4c instead) 2025-07-13 04:43:34 +05:00
Alibek Omarov
6e69e1d67b scripts: gha: build engine for Linux and Windows with FFmpeg linked in runtime by default, thus allowing for smaller distribution size for game developers 2025-07-13 04:39:44 +05:00
Alibek Omarov
7564e3c61f engine: client: add support for building with FFmpeg linked in runtime 2025-07-13 04:39:44 +05:00
Alibek Omarov
0543b861ca ci: upgrade win32-i386 build runner to windows-2022 (which probably will break XP support... or it might not) 2025-07-09 19:31:12 +05:00
Alibek Omarov
0d403a7117 engine: client: console: make con history remember modifications to old lines 2025-07-09 19:23:17 +05:00
Alibek Omarov
928ce9d754 engine: client: console: simplify history handling by defining a separate type for console lines saved in history
Thus we don't need to save linewidth for them anymore.
2025-07-09 19:22:29 +05:00
Alibek Omarov
6cc3bed60a engine: client: console: fix uninitialized variable 2025-07-09 19:04:59 +05:00
Alibek Omarov
40dfd2e711 engine: client: voice: fix off by one errors (as suggested by @SNMetamorph) 2025-07-09 18:29:36 +05:00
Alibek Omarov
c554eef3b9 engine: client: add ability to disable prepending [Xash3D] tag to the nickname when connecting to GoldSrc servers 2025-07-09 17:44:13 +05:00
Alibek Omarov
dc0648e812 engine: net_http: validate file size against reported by server, when downloading chunked files 2025-07-09 17:35:25 +05:00
Alibek Omarov
3d762802ab Merge remote-tracking branch 'pwd491/gsvoice' 2025-07-09 16:43:14 +05:00
Sergey Degtyar
21b0516724 engine: client: move voice reset to Voice_Shutdown 2025-07-03 16:25:24 +03:00
Sergey Degtyar
cca1732245 engine: client: refactored voice.c
- reformatted code.
- changed function declarations to static.
- ensured consistent use of defined constants for buffer sizes.
2025-07-03 13:50:57 +03:00
Sergey Degtyar
fddf0200db engine: client: replaced hardcoded buffer sizes with defined constants for voice data 2025-07-03 13:36:25 +03:00
Sergey Degtyar
6bb7bcd378 engine: client: GoldSrc voice chat support
- Added support for GoldSrc voice mode, including initialization and shutdown functions.
- Implemented data size verification for the GoldSrc voice package.
- Creation and processing of voice packets, CRC verification of data integrity.
- Added a Steam ID field to the client_static_t structure
- Automatic gain control has been introduced for voice samples.
- The voice status structure has been updated.
- Refactored voice data handling for better type consistency and maintainability.
- Fixed ISO C90 compliance issues for better portability.
- Fixed decoder index usage.
2025-07-01 16:09:09 +03:00
Sergey Degtyar
f37bbec78e engine: sound: voice buffer isolation and correct MP3 volume handling 2025-06-26 06:57:50 +03:00
Sergey Degtyar
50a8f23b43 engine: sdl: always reset device descriptors on shutdown 2025-06-26 06:57:37 +03:00
Marc-Antoine Lortie
f9fc26239b Update reimplementations and ports links. 2025-06-24 21:41:39 +03:00
Marc-Antoine Lortie
9f797ef705 Fix repository spelling. 2025-06-24 21:40:40 +03:00
Alibek Omarov
a7671a8ac1 3rdparty: update UI submodules 2025-06-19 16:43:08 +05:00
Alibek Omarov
c807faf5b9 engine: client: rename queryserver to ui_queryserver (so q<tab> will always result in quit command, by users request) 2025-06-19 16:43:08 +05:00
Alibek Omarov
45dd15b064 wscript: remove unused --enable-emscripten 2025-06-19 15:48:50 +05:00
Alibek Omarov
7e50026100 engine: server: fix restoring player view entity after save restore (fixes trigger_camera usage) 2025-06-19 15:22:54 +05:00
Alibek Omarov
05a258a5b4 engine: client: respect intro videos aspect ratio 2025-06-19 14:29:34 +05:00
Alibek Omarov
902fa52cbd Revert "scripts: gha: fix ffmpeg build flavor (the one we're using for now don't have minimal flavor)"
This reverts commit 2267b2e4e6.
2025-06-16 06:24:39 +05:00
Alibek Omarov
cc528d407d Revert "scripts: gha: use full ffmpeg builds, as ours are not finalized yet"
This reverts commit 7f5e62d03a.
2025-06-16 06:24:35 +05:00
Alibek Omarov
2267b2e4e6 scripts: gha: fix ffmpeg build flavor (the one we're using for now don't have minimal flavor) 2025-06-16 06:21:17 +05:00
Alibek Omarov
7f5e62d03a scripts: gha: use full ffmpeg builds, as ours are not finalized yet 2025-06-15 16:01:23 +05:00
Alibek Omarov
e3bfdf4127 engine: wscript: remove duplicated --enable-ffmpeg option 2025-06-15 14:25:28 +05:00
Alibek Omarov
bf186b8178 github: set correct flatpak github action version 2025-06-15 13:18:34 +05:00
Alibek Omarov
907e02da8d Merge ffmpeg support 2025-06-15 13:15:17 +05:00
yohimik
2234f91c38 ref: gl: add stubs for WebGL 2025-06-15 13:01:13 +05:00
Alibek Omarov
582fe9a2fc common: defaults: Emscripten doesn't use INTERNAL_GAMELIBS anymore 2025-06-15 13:01:13 +05:00
Alibek Omarov
fa92a5fa0c engine: common: disable colored stdout for Emscripten 2025-06-15 13:01:13 +05:00
Alibek Omarov
342aa56144 engine: wscript: increase default memory size for Emscripten port, include game files from rodir folder in source tree root 2025-06-15 13:01:13 +05:00
Alibek Omarov
e9440a8612 filesystem: fix folder exists check in RoDir 2025-06-15 13:01:13 +05:00
Alibek Omarov
3e396bb55a engine: host: allow console if DEFAULT_DEV is set to larger than 0 value 2025-06-15 13:01:13 +05:00
Alibek Omarov
72b8182af0 public: comment out XASH_JS define to avoid arch misdetection on modern Emscripten versions 2025-06-15 13:01:13 +05:00
Alibek Omarov
6022865cae engine: filesystem_engine: set default root directory on Emscripten 2025-06-15 13:01:13 +05:00
Alibek Omarov
1559b1b331 engine: system: exit from Emscripten with force_exit call 2025-06-15 13:01:13 +05:00
Alibek Omarov
5db150e565 engine: launcher: get rid of Emscripten load library hacks, mount IDBFS into /rwdir 2025-06-15 13:01:13 +05:00
Alibek Omarov
e823ba050a engine: whereami: add stub for Emscripten 2025-06-15 13:01:13 +05:00
Alibek Omarov
6f545f178e engine: host: move main loop contents into separate function 2025-06-15 13:01:13 +05:00
Alibek Omarov
b598daf049 engine: wscript: disable default install for Emscripten, we need to rename main program into index.html and also install additional outputs 2025-06-15 12:51:57 +05:00
Alibek Omarov
3f5ca210a0 common: port: set .wasm as libraries extension on Emscripten 2025-06-15 12:51:57 +05:00
Alibek Omarov
f1e665b5b3 engine: wscript: disable async ns resolve for Emscripten for now 2025-06-15 12:51:57 +05:00
Alibek Omarov
eb84efd260 wscript: set Emscripten defaults 2025-06-15 12:51:57 +05:00
Alibek Omarov
90884a2d09 scripts: waifulib: sdl2: use Emscripten's SDL port 2025-06-15 12:51:57 +05:00
Alibek Omarov
69e38c963d engine: platform: remove Emscripten-specific library loading, it's not needed anymore 2025-06-15 12:51:57 +05:00
Alibek Omarov
d7f4b21db7 3rdparty: mainui: update 2025-06-15 12:51:57 +05:00
Alibek Omarov
6aa281bc59 public: define Emscripten as POSIX-compatible 2025-06-15 12:51:57 +05:00
Alibek Omarov
e22dadc36f scripts: waifulib: add tool for building with Emscripten's Clang wrapper 2025-06-15 12:51:57 +05:00
Alibek Omarov
1bf5909023 wscript: don't forget to recurse into ref/gl with only gles3compat enabled 2025-06-15 09:13:39 +05:00
Andrey Akhmichin
ba71f114d9 Documentation: opensource-mods.md: add "Master Sword". 2025-06-15 07:12:45 +03:00
Alibek Omarov
c90d110096 engine: platform: sdl2: assign K_AUX32 and K_AUX31 to volume buttons to match old engine behavior on Android 2025-06-07 11:21:32 +05:00
Alibek Omarov
05edde050d engine: always remap clipnodes for bsp30ext 2025-05-27 22:54:06 +03:00
Alibek Omarov
1c29490889 Reapply "engine: disable clipnodes remapping for non-extended formats and QBSP2"
This reverts commit 2e748c4aea.
2025-05-27 22:44:53 +03:00
Alibek Omarov
210f51d38c ci: use flatpak github action fork again because I forgot that github has weird limitations 2025-05-27 22:38:13 +03:00
Alibek Omarov
2e748c4aea Revert "engine: disable clipnodes remapping for non-extended formats and QBSP2"
This reverts commit f2ecdad5bb.
2025-05-27 22:23:44 +03:00
Alibek Omarov
375ff6296b ci: try to upgrade flatpak action 2025-05-27 22:21:23 +03:00
Alibek Omarov
026435865a wscript: cleanup defaults, now that we don't need to specify most options from here 2025-05-27 21:54:22 +03:00
Alibek Omarov
216e680965 wscript: detect threading ability by platform
On client, it's handled by SDL{2,3}. On server we rely on pthreads (and some platforms don't have pthreads).
2025-05-27 21:40:07 +03:00
Alibek Omarov
3fe77ec86c wscript: remove msdev.py generator (Visual Studio project still can be generated using msvs.py) 2025-05-27 20:59:47 +03:00
Alibek Omarov
a88fea6ab3 wscript: remove cmake.py generator 2025-05-27 20:57:47 +03:00
Alibek Omarov
78ef00a269 wscript: remove hacky logic determening valid target when crosscompiling to 32-bit x86 2025-05-27 20:50:08 +03:00
Alibek Omarov
f9a9aedea5 engine: set fps_override to 0 by default, it's still experimental and breaks multiplayer
Was probably set to 1 by mistake.
2025-05-26 20:10:45 +05:00
Alibek Omarov
53e59c2e73 ref: load sprites textures with texgamma applied (like GoldSrc) 2025-05-26 19:09:28 +05:00
Alibek Omarov
fc3b8ae45d engine: imagelib: allow installing texgamma processed palette before loading sprites 2025-05-26 19:09:28 +05:00
Alibek Omarov
911b83a9d8 engine: imagelib: load studio model textures with texgamma applied (like GoldSrc) 2025-05-26 19:09:28 +05:00
Alibek Omarov
5276e46dc0 contributing: add a note about usage of LLM-based tools [skip ci] 2025-05-26 03:28:58 +05:00
Alibek Omarov
9fbd47bb4c engine: server: move unexpected master server query packets and failed challenges to more verbose loglevel 2025-05-25 21:05:37 +05:00
Alibek Omarov
b8ead38573 engine: server: prevent flood about unreliable datagram overflow on frozen players 2025-05-25 20:37:06 +05:00
Alibek Omarov
6a318d5000 engine: server: check for master servers addresses in connectionless packet handler, and it it matches, only reply to M2S messages 2025-05-25 20:29:16 +05:00
Alibek Omarov
71040c7ed5 engine: net_http: fix missing newline 2025-05-25 19:21:23 +05:00
Alibek Omarov
c3531b6499 engine: expect that base_cmd is consistent, as for many years no cases of broken basecmd were found 2025-05-25 16:48:31 +05:00
Alibek Omarov
9c6f12f31c engine: make command argc/argv functions inline 2025-05-25 16:47:45 +05:00
Alibek Omarov
913d0eb693 engine: add command to make other commands or variables privileged 2025-05-25 16:33:11 +05:00
Alibek Omarov
7bff848592 engine: base_cmd: simplify FindAll 2025-05-25 16:33:11 +05:00
Alibek Omarov
72485da491 engine: client: make demo recording and demo removing command privileged 2025-05-25 03:22:19 +05:00
Alibek Omarov
694472f4c1 engine: platform: allow querying window type through R_GetWindowHandle 2025-05-24 22:03:43 +05:00
TheEVolk
735f4e2bcb ref_api: make handle as argument and use type request input 2025-05-24 20:47:28 +05:00
TheEVolk
9ebeb520fa engine: platform: refactor R_GetWindowHandle to return a struct instead of a pointer 2025-05-24 20:47:28 +05:00
TheEVolk
dd52840a97 ref_api: update REF_API_VERSION to 10 and document R_GetWindowHandle addition 2025-05-24 20:47:28 +05:00
TheEVolk
4ce03662d9 ref_api: R_GetWindowHandle method 2025-05-24 20:47:28 +05:00
Andrey Akhmichin
20320d8dfa Documentation: not-supported-mod-list-and-reasons-why.md: update. 2025-05-24 20:45:28 +05:00
Alibek Omarov
f2ecdad5bb engine: disable clipnodes remapping for non-extended formats and QBSP2 2025-05-24 20:43:44 +05:00
Alibek Omarov
298842be32 engine: fix clipnodes limit check based on BSP version 2025-05-24 17:43:01 +05:00
Alibek Omarov
15544cde26 engine: common: fix typo in aguirRe nickname [skip ci] 2025-05-21 17:43:05 +05:00
Alibek Omarov
a4ad537e59 engine: server: minor refactoring 2025-05-20 20:24:42 +05:00
Alibek Omarov
7ba48e00bc 3rdparty: libbacktrace: sort entries in config.h to keep it the same between reconfigurations
Multicheck parallel nature caused config.h entries to be sorted randomly and
libbacktrace recompiled on every occasion.
2025-05-20 15:25:39 +05:00
Alibek Omarov
bb620d1265 engine: client: set cl_upmax to 508 by default 2025-05-20 14:35:29 +05:00
SNMetamorph
32e6f37c7e engine: server: fixed incorrect printing of IPv6 address in "status" command 2025-05-12 14:11:09 +03:00
Alibek Omarov
8f95535390 engine: server: fix a typo that prevented "status" command from executing by spawned player 2025-05-12 11:37:11 +03:00
Alibek Omarov
b2444f2480 engine: restore SDL2 include path 2025-05-11 18:01:17 +03:00
Alibek Omarov
37d6d75e69 engine: platform: sdl3: add system and input SDL3 platform implementation 2025-05-11 17:35:13 +03:00
Alibek Omarov
97bdd9dba0 engine: port occasional SDL2 calls to SDL3, no platform yet 2025-05-11 16:18:10 +03:00
Alibek Omarov
ffc8bf30d7 engine: platform: make most input platform functions optional, patch fbdev/evdev to compile 2025-05-11 16:14:36 +03:00
Alibek Omarov
8209a8a681 engine: platform: move mouse grab enabling and querying functions to SDL platform code 2025-05-11 16:09:57 +03:00
Alibek Omarov
34beb9666b engine: soundlib: drop SDL-based resampler 2025-05-11 15:27:50 +03:00
Alibek Omarov
6ccafbe297 engine: platform: move Host_Minimize_f into platform code 2025-05-11 15:24:52 +03:00
Andrey Akhmichin
a479099804 utils: mdldec: write all GoldSource-compatible motion-types with "-m" option. 2025-05-11 03:40:57 +03:00
Alibek Omarov
94791d3cb6 engine: allow downloading files that have multiple dots in filename. Also disallow everything that has nonprintable characters. 2025-05-06 21:16:06 +03:00
Alibek Omarov
6555562e78 engine: common: fix building tests 2025-05-06 21:15:28 +03:00
Alibek Omarov
de790d6f59 Revert "engine: server: increased sv_connect_timeout to a half a minute"
This reverts commit 3fca1bb4d5.
2025-05-06 20:22:20 +03:00
Alibek Omarov
cff0df60a9 engine: server: also bump timeouts for connected clients during changelevel in server activation 2025-05-06 20:19:17 +03:00
Alibek Omarov
c8b8e19ed3 engine: server: fix time out on change level 2025-05-06 20:11:41 +03:00
Alibek Omarov
2106556dec engine: server: limit status and build info commands only to spawned clients 2025-05-06 19:50:51 +03:00
Alibek Omarov
7221bd6049 engine: server: small refactoring 2025-05-06 19:50:26 +03:00
Alibek Omarov
ded38020d3 engine: server: add new client state cs_spawning, to ensure that client cannot spawn before it has an entity 2025-05-06 19:37:54 +03:00
Alibek Omarov
c6251174df engine: server: don't let unspawned player execute ent tools commands or send voice data 2025-05-06 19:02:32 +03:00
Alibek Omarov
177c132969 engine: common: fix incorrect argument name, which also fixes build with compilers that enforce C23 2025-05-06 19:00:18 +03:00
Alibek Omarov
3fca1bb4d5 engine: server: increased sv_connect_timeout to a half a minute 2025-05-06 16:28:29 +03:00
Alibek Omarov
321e28c810 scripts: waifulib: sdl2: fix SDL3 sanity test 2025-05-05 18:51:01 +03:00
Alibek Omarov
7fda58561f engine: platform: sdl2: remove SDL1.2 code, as it's now moved into it's own separate directory 2025-05-05 05:56:23 +03:00
Alibek Omarov
0cbb62b329 engine: platform: try to restore SDL1.2 support (only ref_soft is tested, ref_gl doesn't work) 2025-05-05 05:44:31 +03:00
Alibek Omarov
aa2e5eb3cc engine: platform: move SDL2 support code into sdl2 subdirectory. Change XASH_SDL macro value from 12 to 1 for SDL1.2 2025-05-05 05:15:10 +03:00
Alibek Omarov
3d26ba1ed8 engine: client: always pass a valid pointer to usercmd_t in ref_params_t to prevent crassh when client.dll reads them during demo playback 2025-05-05 03:40:18 +03:00
Alibek Omarov
47c4844024 engine: platform: sdl: enable building with SDL as old as 2.0.8, it should satisfy everybody masturbating to old software 2025-04-30 17:45:05 +03:00
Alibek Omarov
d457d7d093 filesystem: archive mounting refactoring 2025-04-28 22:28:30 +03:00
Vladimir
43364ec2e9 defaults: enable touch for psvita & nswitch (#2143) 2025-04-27 14:39:58 +03:00
Alibek Omarov
14127c26f5 scripts: gha: don't put dedicated binary in full client tarballs 2025-04-24 23:41:26 +03:00
Alibek Omarov
291f24a611 scripts: cirrus: build dedicated server alongside full client for slightly faster builds 2025-04-24 23:33:59 +03:00
Alibek Omarov
1abb16638f scripts: gha: build dedicated server alongside full client for slightly faster builds 2025-04-24 23:33:59 +03:00
Alibek Omarov
3e41e389c5 engine: lib_common: do not take generic GNU/Linux rules for library naming on Android 2025-04-24 21:53:03 +03:00
Alibek Omarov
5aca143eba engine: disable Android-specific library loader under Termux 2025-04-24 21:46:43 +03:00
Alibek Omarov
60fa855d47 filesystem: wscript: strip lib prefix on Termux too 2025-04-24 21:42:20 +03:00
Alibek Omarov
22661fd446 public: define XASH_TERMUX if __TERMUX__ is defined. Do not enable XASH_MOBILE_PLATFORM for it 2025-04-24 21:40:35 +03:00
Alibek Omarov
61d8d5e12b wscript: detect if we're compiling from Termux 2025-04-24 21:39:46 +03:00
Alibek Omarov
a7f3c04baa engine: platform: android: hide SDL calls under XASH_SDL macro 2025-04-24 21:39:46 +03:00
Alibek Omarov
296e642f09 wscript: look for libm when compiling for Android on Android device itself (e.g. Termux) 2025-04-24 20:52:55 +03:00
Alibek Omarov
75eb1f1e8b filesystem: android: make failing to find JNI env non-fatal 2025-04-24 20:52:18 +03:00
Alibek Omarov
8f4a45baaa engine: platform: win32: set IMAGEHLP_LINE64 structure size as required in dbghelp docs on MSDN 2025-04-21 20:33:30 +03:00
Alibek Omarov
18aac5fd3d readme: update 2025-04-21 20:12:55 +03:00
Alibek Omarov
ca6ca8450b engine: platform: sdl: load .ico file with wide function allowing for icons to be loaded from non-latin game directory 2025-04-21 20:09:39 +03:00
Alibek Omarov
6ecaea3102 engine: system: convert Windows username to utf8 2025-04-21 19:56:49 +03:00
Alibek Omarov
fa47ca0d2d engine: system: make a copy of pw_name just in case 2025-04-21 19:56:23 +03:00
Alibek Omarov
8ce3b4ac93 engine: client: identification: use wide CreateProcess call, ensure that process terminated and it's handles are closed 2025-04-21 19:38:10 +03:00
Alibek Omarov
a7ba705277 engine: platform: win32: make output similar to libbacktrace-based crashhandler, general improvements and refactoring 2025-04-21 18:54:39 +03:00
Alibek Omarov
85a4d296f5 Documentation: not-supported-mod-list-and-reasons-why: clarify that we don't know why Arrange Mod doesn't work on Xash yet [skip ci] 2025-04-21 17:06:11 +03:00
Andrey Akhmichin
4dd8d89459 Documentation: not-supported-mod-list-and-reasons-why.md: update [skip ci] 2025-04-21 17:04:19 +03:00
Alibek Omarov
c564cc96c7 engine: get rid of host.crashed field, as it's a complete duplicate of host.status 2025-04-21 16:59:44 +03:00
Alibek Omarov
0e54200f34 engine: platform: win32: move saving minidumps before showing stacktrace messagebox 2025-04-21 16:58:43 +03:00
Alibek Omarov
fa75c33390 engine: platform: win32: do not set parent window for stacktrace print window 2025-04-21 16:57:27 +03:00
Alibek Omarov
36cb3b2d89 engine: fix incompatible int size when casting pointer to int 2025-04-21 15:54:32 +03:00
Andrey Akhmichin
2f3b03d27a Documentation: opensource-mods.md: add "Counter-Life". 2025-04-20 10:23:53 +03:00
SNMetamorph
f0deac206b Documentation: added initial revision of touch controls configuring guide
Thanks to VladislavKZ and archer for helping with information gathering.
2025-04-18 17:24:44 +03:00
Alibek Omarov
5d0e473cf1 3rdparty: maintui: update 2025-04-16 14:52:46 +03:00
Alibek Omarov
2174fe6d21 ci: update to ubuntu-22.04 2025-04-15 21:04:48 +03:00
Alibek Omarov
5d1e207337 3rdparty: maintui: update 2025-04-15 21:00:38 +03:00
Alibek Omarov
87c209f1f9 engine: server: drop clients that do not continue connecting after smaller timeout 2025-04-15 20:54:27 +03:00
SNMetamorph
ed5ea002d7 Documentation: donate: updated details, changed layout 2025-04-15 18:07:59 +03:00
Alibek Omarov
149593fea5 engine: server: hide Cmd_ForwardToServer call under XASH_DEDICATED just in case, fixes build with debug 2025-04-11 00:34:10 +03:00
Alibek Omarov
8c0f1d65ba 3rdparty: maintui: update 2025-04-10 23:56:55 +03:00
Alibek Omarov
bbf6f1c7b8 scripts: gha: fix generating sources.list on different ubuntu version 2025-04-10 23:37:36 +03:00
Alibek Omarov
3b61e0bbd6 ci: thanks github, ubuntu-latest isn't actually latest 2025-04-10 23:07:39 +03:00
Alibek Omarov
8d2986bc74 3rdparty: maintui: update 2025-04-10 23:02:48 +03:00
Alibek Omarov
27a8adad22 ci: compile risc-v port on ubuntu-latest for newer compilers 2025-04-10 22:48:41 +03:00
Alibek Omarov
64e774377b scripts: gha: fix ppc64el rust target 2025-04-10 22:48:17 +03:00
Alibek Omarov
8ff469d466 3rdparty: maintui: update 2025-04-10 22:26:13 +03:00
Alibek Omarov
a20e961892 scripts: gha: install i686-pc-windows-msvc rust target for cross-compiling 32-bit maintui 2025-04-10 22:02:13 +03:00
Alibek Omarov
8ba30a1c09 scripts: gha: add Rust target for crosscompiling 2025-04-10 20:01:03 +03:00
Alibek Omarov
d570d6d6da scripts: gha: enable building maintui on supported platforms (win32, linux and apple) 2025-04-10 19:21:09 +03:00
Alibek Omarov
882b573e70 wscript: build maintui alongside mainui_cpp, so both could be used and shipped 2025-04-10 19:21:09 +03:00
Andrey Akhmichin
54657c149b utils: mdldec: use separate options for sequences and textures. 2025-04-10 14:57:11 +05:00
Alibek Omarov
9054b11ebd engine: client: let loading custom menu dll with -menulib command line switch 2025-04-09 17:35:36 +03:00
Alibek Omarov
71d31330f9 filesystem: dir: fix possible null dereference 2025-04-05 14:03:24 +05:00
SNMetamorph
ea29699633 scripts: gha: psvita: pinned cmake version to 3.28.3 2025-04-05 12:45:45 +05:00
Andrey Akhmichin
ccb8d611c6 public: add getopt implementation from NetBSD libc. 2025-04-02 12:07:41 +03:00
Andrey Akhmichin
f4d98c056e utils: mdldec: handle unknown options. 2025-04-02 12:07:41 +03:00
Andrey Akhmichin
779adcd838 utils: mdldec: bump version to 1.2. 2025-04-02 12:07:41 +03:00
Andrey Akhmichin
16e2ce0aeb utils: mdldec: avoid brackets. 2025-04-02 12:07:41 +03:00
Andrey Akhmichin
7bfcd4cef0 utils: mdldec: add options to:
- disable log output.
 - use separate directories for smd and texture files.
 - avoid to write paranoia 2 motion types.
 - ignore filesize checks.
 - enable UV coords shifting.
 - show decompiler version.
 - show help.
2025-04-02 12:07:41 +03:00
Andrey Akhmichin
c298635728 utils: mdldec: Makefile: update. 2025-04-02 12:07:41 +03:00
Andrey Akhmichin
92e976952e utils: mdldec: fix UV coords shifting yet again. 2025-04-02 12:07:41 +03:00
Denis Drakhnia
a85bd0c864 maintui: first blood 2025-04-01 14:46:27 +03:00
Alibek Omarov
0a5f175431 mainui: update 2025-03-31 19:18:39 +03:00
Alibek Omarov
da6402ccc2 common: xash3d_types: disable PFN_RETURNS_NONNULL attribute for MCST lcc 2025-03-31 19:14:22 +03:00
Alibek Omarov
9d1b03d119 scripts: gha: build for e2k-8c on GitHub Actions machines 2025-03-31 19:07:47 +03:00
Alibek Omarov
6cf0d7a871 scripts: gha: linux: fix enabling stb_truetype in mainui_cpp 2025-03-31 18:20:23 +03:00
SNMetamorph
d5a6a7ae60 scripts: gha: made voice chat enabled by default for PS Vita platform 2025-03-30 20:24:38 +03:00
SNMetamorph
185374f99f engine: platform: psvita: explicitly exported symbol rintf
This is required for cs16client port for PS Vita.
2025-03-30 20:24:38 +03:00
SNMetamorph
b9072e4642 Documentation: slightly updated PS Vita port installation instructions 2025-03-30 20:24:38 +03:00
yumirak
06e5895d7a engine: client: fix TE_BLOODSPRITE behaviour to GoldSrc 2025-03-26 22:00:10 +03:00
Alibek Omarov
ac5be8156b Revert "wscript: force -Wuninitialized to error"
This reverts commit e615ff0e7f.
2025-03-25 19:10:13 +03:00
Alibek Omarov
8c12a8baed mainui: update 2025-03-25 19:02:00 +03:00
Alibek Omarov
e615ff0e7f wscript: force -Wuninitialized to error 2025-03-25 17:11:51 +03:00
Alibek Omarov
2e8fa60e96 engine: client: don't allow downscaling HUD when using hud_scale's fixed resolution mode 2025-03-25 17:07:05 +03:00
Alibek Omarov
a8ba9124dd engine: server: fix -Wmaybe-uninitialized 2025-03-25 17:07:05 +03:00
Alibek Omarov
f6e8a68b22 engine: imagelib: img_png: fix -Wmaybe-uninitialized 2025-03-25 17:07:05 +03:00
Alibek Omarov
706cc16a86 ref: fix -Wmaybe-uninitialized 2025-03-25 17:06:59 +03:00
Alibek Omarov
a9fd508e47 engine: common: fix reading maybe uninitialized crt_tm variable 2025-03-25 17:04:35 +03:00
Alibek Omarov
90bd72d481 ref: gl: disable blend after we're done drawing sprite "lightmap"
Fixes translucent brush model on renderfx2.bsp (https://twhl.info/vault/view/6933)
which so happened to draw after agrunt sprite, that has "lightmap" enabled
2025-03-25 00:52:11 +03:00
Alibek Omarov
a2a3978de7 engine: server: fix erasing physinfo on client connect, when it was already set by game logic on save restore
Fixes issue when player loses long-jump in Half-Life on save load or level transition.
2025-03-24 23:22:19 +03:00
Andrey Akhmichin
ea70989fd2 utils: mdldec: Fix resource names validity checks. 2025-03-24 01:24:31 +03:00
Andrey Akhmichin
091228bcb3 Documentation: supported-mod-list.md: update. 2025-03-24 01:24:25 +03:00
Alibek Omarov
9c49253388 filesystem: allow symlinks when using listdirectory with dirs_only = true
Should fix special setups when game directories are actually symlinks
2025-03-20 20:31:44 +03:00
Alibek Omarov
eea804a4bf engine: server: improve server op status command output 2025-03-20 05:47:24 +03:00
Alibek Omarov
ecbfdb82f4 engine: server: add requested server command status. Only expose client input devices for now, as everything else might be considered sensitive information 2025-03-20 05:46:49 +03:00
Alibek Omarov
a1950ec7b0 engine: server: tiny refactoring, make SV_CalcPing pointer to client const 2025-03-20 05:44:23 +03:00
Alibek Omarov
6b56e13b60 engine: make local ipv4 address private to net_ws, acquire local addresses with GetLocalAddress function 2025-03-20 05:39:02 +03:00
Alibek Omarov
d93bee0cbc engine: minor refactoring, rename ref_state_t fields to snake case, rename readable names to shorter (no pun intended) long names 2025-03-20 03:11:17 +03:00
Alibek Omarov
5009db6aac engine: client: make renderer loading failure less scary for the user 2025-03-20 03:06:05 +03:00
Alibek Omarov
c389736c2f android: do not crash on Browse button if activity wasn't found 2025-03-20 02:44:37 +03:00
Alibek Omarov
66bdca63ee ref: gl: upload skybox texture object with >= 5800 name only with GL compatibility context, it's not needed on GLES 2025-03-17 08:32:06 +03:00
SNMetamorph
d3f455649e engine: client: implemented xashid for PS Vita platform 2025-03-16 21:34:32 +03:00
SNMetamorph
17ff80d85d engine: platform: psvita: implemented function for getting PSID 2025-03-16 21:34:32 +03:00
SNMetamorph
407d0aa291 engine: wscript: enabled linking library SceLibKernel_stub on PS Vita 2025-03-16 21:34:32 +03:00
Alibek Omarov
d13429a287 game_launch: explicitly call wide or ascii Win32 API function calls 2025-03-16 20:41:57 +03:00
Alibek Omarov
a84204fc75 engine: partial fix to explicitly call ascii or wide Win32 API function calls 2025-03-16 20:41:57 +03:00
SNMetamorph
292ace2d26 engine: client: fixed SQB in CL_ParseEvent & CL_ParseReliableEvent 2025-03-16 20:31:14 +03:00
Alibek Omarov
68a1fbdc2b engine: platform: win32: use widechar versions of LoadLibrary, which fixes loading engine if path contains non-latin characters 2025-03-16 03:16:02 +03:00
Alibek Omarov
d68f29737a public: crtlib: use Q_rint instead of round in Q_pretifymem, so we don't have to link libm when we don't need it 2025-03-16 01:01:13 +03:00
Alibek Omarov
a34edbd8e8 wscript: ok, let's disable format-nonliteral for now 2025-03-15 20:01:47 +03:00
Alibek Omarov
71e2d4ecd4 engine: client: fix another case of format-nonliteral 2025-03-15 19:52:24 +03:00
Alibek Omarov
25656b532a engine: platform: posix: fix a typo 2025-03-15 19:52:00 +03:00
Alibek Omarov
1a791e8556 engine: soundlib: get rid of useless formatstring, which is always the same for all types 2025-03-15 19:36:34 +03:00
Alibek Omarov
ccd31c6b27 engine: imagelib: get rid of useless formatstring, which is always the same for all types 2025-03-15 19:29:11 +03:00
Alibek Omarov
6aeedf201c ref: gl: update dlight texture in case if BLOCK_SIZE changes between maps (going from QBSP to BSP2 or toggling r_large_lightmaps cvar) 2025-03-15 19:23:49 +03:00
Alibek Omarov
c9f8bdfcb0 ref: gl: allow updating texture with NULL data by calling TexImage instead of TexSubImage 2025-03-15 19:20:36 +03:00
Alibek Omarov
3cf4901ad2 engine: fix another case of format-nonliteral 2025-03-15 18:23:38 +03:00
Alibek Omarov
92de3ebc58 wscript: disable format-nonliteral for Clang, it's buggy there 2025-03-15 14:20:11 +03:00
Alibek Omarov
7aa9f23590 public: crtlib: fix Q_pretifymem so it compiles with -Wformat-nonliteral 2025-03-15 14:19:47 +03:00
Alibek Omarov
3d999269eb engine: net_ws: make net6_local global static, as it's not used outside of this translation unit 2025-03-15 01:24:59 +03:00
Alibek Omarov
1e8e4825fa engine: fix remaining -Wformat=2 and force it to -Werror 2025-03-15 01:24:59 +03:00
Alibek Omarov
91bc372811 mainui: update 2025-03-15 01:24:59 +03:00
Alibek Omarov
f9df96d70e engine: server: fix server strings deduplication on 64-bit systems 2025-03-15 01:24:59 +03:00
Alibek Omarov
8af0e2c8b4 readme: add missing system dependencies on Linux systems [skip ci] 2025-03-08 02:42:28 +03:00
Alibek Omarov
a5191d8948 engine: client: console: simplify Field_DrawInputLine, try to make it safer 2025-03-08 02:35:32 +03:00
Alibek Omarov
b2d8239829 engine: common: net_http: fix decompression for compressed but not chunked files 2025-03-06 19:10:48 +03:00
Alibek Omarov
34322f025b engine: client: limit ticket generator choices to revemu2013 only 2025-03-06 12:35:32 +03:00
Alibek Omarov
3e6b434733 mainui: update 2025-03-05 22:36:41 +03:00
Alibek Omarov
8359cbe76c scripts: waifulib: add flag --enable-limited-debuginfo which enables -gline-tables-only on GCC and Clang compilers
This saves ~30mb of APK size on Android.
2025-03-05 02:19:39 +03:00
Alibek Omarov
0e90e6285e engine: host: use #if instead of #ifdef when checking for extended hl25 structs compile option 2025-03-03 22:59:44 +03:00
Alibek Omarov
2f5840f650 engine: host: add a cvar that indicates whether engine was built with --enable-hl25-extended-structs or not 2025-03-03 22:53:20 +03:00
Alibek Omarov
3b51a554dd mainui: update 2025-03-02 20:20:54 +03:00
Alibek Omarov
5f0880d4a2 engine: client: lower the bandwidth test fragment sizes to 1400 and less, as using 64k, 32k and more is unreliable 2025-03-02 20:20:40 +03:00
Bohdan Shulyar
884a3c66ac client: touch: fix minor typo that prevented editing touch buttons commands 2025-03-02 20:19:58 +03:00
Alibek Omarov
c76752cc5f engine: server: validate uuid in protinfo, it's an md5 string 2025-03-01 22:45:01 +03:00
Alibek Omarov
fc2888e107 engine: server: fix incorrect ID string generation, hashedcdkey is already an MD5 string 2025-03-01 22:27:22 +03:00
Alibek Omarov
674b4c1506 engine: server: reorder sv_client_t struct for better memory efficiency, remove unused fields 2025-03-01 22:07:05 +03:00
Alibek Omarov
cddd50f1e9 engine: server: completely erase sv_client_t on client connect, so we always start from scratch for every user 2025-03-01 22:07:05 +03:00
Alibek Omarov
6c9d5bc1fb engine: server: cleanup penalties and warns for new players 2025-03-01 16:03:39 +03:00
Alibek Omarov
ec23860238 gitmodules: use github mirrors instead of xiph.org's git
It's not really a good idea to hammer upstream git servers with cloning same
data over and over. Besides, it's down right now.
2025-03-01 15:28:55 +03:00
Alibek Omarov
14a2e34b7e mainui: update 2025-03-01 15:21:20 +03:00
Alibek Omarov
29c8818557 engine: server: do not continue processing command if the player was kicked during it (for example, by speedhack prevention) 2025-03-01 14:58:15 +03:00
Andrey Akhmichin
7222830b28 Documentation: supported-mod-list.md: a little remark. 2025-02-28 23:56:28 +03:00
Alibek Omarov
9b0ad7daf0 engine: common: register forgotten net_clockwindow cvar 2025-02-28 22:44:44 +03:00
Alibek Omarov
73729827f4 engine: platform: win32: add forgotten SDL.h include 2025-02-28 21:55:26 +03:00
Alibek Omarov
97fa395a3b engine: platform: win32: fix build by restoring previous win32 header inclusion order 2025-02-28 21:44:22 +03:00
Alibek Omarov
1cef8ea7af Revert "ref: gl: check OES NPOT texture extension in BigGL mode"
This breaks mipmaps on PSVita

This reverts commit 54b0cf9991.
2025-02-28 17:08:27 +03:00
Alibek Omarov
eda4e95607 engine: client: draw version at bottom right in menu, regardless if dev_overview or net_graph are enabled (those only used in-game) 2025-02-28 15:11:24 +03:00
Alibek Omarov
a5f0ca38f1 engine: remove inclusion of SDL headers globally, helps to cleanup code before SDL3 migration 2025-02-28 13:14:47 +03:00
Alibek Omarov
bbbd7711c1 engine: platform: cleanup remnants of disabling vsync while loading mechanism for linux fbdev and dos ports 2025-02-28 12:33:30 +03:00
Alibek Omarov
38e922557d engine: platform: sdl: remove disabling vsync while we're not in game, as this is something users have been complaining a lot
It's not a big deal if level loading will take a few milliseconds more.
2025-02-28 08:27:38 +03:00
Alibek Omarov
4dec1785ed engine: client: touch: fix inverted file extension check 2025-02-28 06:44:21 +03:00
Alibek Omarov
9f77b7dc46 scripts: waifulib: enable HLSDK -mtune only on GCC and Clang, and not on Android 2025-02-26 17:11:10 +03:00
Alibek Omarov
5061a29f86 scripts: waifulib: enable asynchronous-unwind-tables for better stacktraces 2025-02-26 17:10:30 +03:00
Alibek Omarov
cb5dffd554 engine: server: don't bother printing about unsupported connectionless packets if sv_log_outofband is set to 0 2025-02-26 17:06:33 +03:00
Alibek Omarov
4eaa8ab40f android: bump minimum CMake version, so disabling unneeded features in SDL actually works 2025-02-26 14:21:58 +03:00
Alibek Omarov
2a82d265d6 scripts: waifulib: xcompile: add support for Android NDK r27 as well 2025-02-26 12:40:22 +03:00
Alibek Omarov
f2392b5709 scripts: waifulib: xcompile: add support for building on Windows. Drop using shortcut target clang symlinks, as those don't work on Windows at all (they are wrapped into batch files, which can't be invoked like exes) 2025-02-26 12:40:22 +03:00
Alibek Omarov
5620e7ab4c android: fixup CMAKE_LIBRARY_OUTPUT_DIRECTORY on Win32, merge stdout and stderr for waf output 2025-02-26 12:40:22 +03:00
Alibek Omarov
a76236ac5a scripts: waifulib: xcompile: add support for NDK 28, remove setting up custom PREFIX to not mess up installation path 2025-02-26 12:40:22 +03:00
Alibek Omarov
d1c5862bab android: bump NDK version to 28 2025-02-26 12:40:22 +03:00
Alibek Omarov
81400d0b01 android: use xcompile.py's support for Android NDK, fix tabs 2025-02-26 12:40:22 +03:00
Alibek Omarov
a129f13e25 android: enable verbose output for CMake running from Gradle 2025-02-26 12:40:22 +03:00
Alibek Omarov
ec8b4c0a84 android: rework how engine is built, instead of generating CMakeLists, just use included in CMake ExternalProject feature 2025-02-26 12:40:22 +03:00
Alibek Omarov
f1f726822c engine: client: restore cl_cmdrate default value at 30. It wasn't an intentional change. 2025-02-25 19:52:48 +03:00
Alibek Omarov
8982d55392 engine: client: set default rate value to 25000
3500 is barely playable these days. Those who have worse than usual internet
connection, should set appropriate value themselves.
2025-02-25 17:36:43 +03:00
Alibek Omarov
f499286a87 engine: platform: sdl: don't call SDL_GL_SetSwapInterval each frame while we're not in game 2025-02-25 11:52:03 +03:00
Alibek Omarov
a3aaa87147 ref: gl: enable polygon offset for fullbright textures when rendering them in separate from VBO pass 2025-02-25 11:49:31 +03:00
Alibek Omarov
15a6971aca engine: platform: posix: strip path from filename in backtrace 2025-02-25 11:46:57 +03:00
Alibek Omarov
b1eb3390e3 engine: server: let server dll to register it's own showtriggers cvar 2025-02-24 06:41:11 +03:00
Alibek Omarov
74ad504377 engine: client: console: do not let color strings contribute to line length in console 2025-02-24 03:55:13 +03:00
Alibek Omarov
8a0c2577ed engine: platform: sdl: exclude fake game controller found on Android emulator 2025-02-24 03:42:03 +03:00
Alibek Omarov
a060d7aefd wscript: disable large file for 32-bit Android 2025-02-23 16:07:51 +03:00
Alibek Omarov
ccf342f4fe engine: client: fix inconsistent mouse state caused by mis-use of touch_emulate by cs16-client 2025-02-23 07:13:39 +03:00
Alibek Omarov
8b9a40ff1f engine: client: completely refactor touch code, protect button color, improve config output 2025-02-23 07:00:20 +03:00
Alibek Omarov
425cc61c4c engine: client: handle K_ESCAPE in Key_Console, remove special case for it in Key_Event 2025-02-23 06:47:44 +03:00
Alibek Omarov
fe1fd5b024 engine: client: make color array of DrawString functions const 2025-02-23 06:46:22 +03:00
Alibek Omarov
0c8da36a0b filesystem: disallow path traversal in FS_Delete and FS_Rename 2025-02-23 03:13:46 +03:00
Alibek Omarov
2c5030ab45 engine: client: do not save touch_emulate cvar 2025-02-23 02:04:33 +03:00
Alibek Omarov
9decba873b engine: platform: sdl: try to save and restore mouse position during showing or hiding cursor 2025-02-23 02:04:03 +03:00
Alibek Omarov
bda4c45504 engine: client: simplify CL_EDICT_NUM and it's sister, non throwing error, function CL_GetEntityByIndex 2025-02-23 01:51:05 +03:00
Alibek Omarov
f7aa8a0c90 ci: bump SDL2 to 2.32.0. This is the last major upgrade to SDL2 dependency, we should migrate to SDL3 (with sdl2-compat for GoldSrc mods) after that 2025-02-22 18:48:41 +03:00
Alibek Omarov
4c15cceb32 engine: client: deprecate custom id, it is not used meaningfully by anyone 2025-02-20 15:41:17 +03:00
Alibek Omarov
3e4c5beb25 ref: fix another typo made after R_StudioCalcBones refactor 2025-02-18 19:22:06 +03:00
Alibek Omarov
f84d865f4a engine: client: fix crash if server sends new movevars before entities were created
Nothing bad will happen if we skip wave height for world entity for now, but
we might need to handle this situation somehow in the future.
2025-02-17 13:02:21 +03:00
SNMetamorph
2465782a3e engine: platform: sys_win: fixed compiling error 2025-02-15 13:45:22 +03:00
Alibek Omarov
7ba2209124 engine: platform: sdl: set requested timer delay in units of 100ns according to the documentation 2025-02-15 13:08:05 +03:00
Alibek Omarov
af6b434b71 engine: platform: win32: implement nanosleep using waitable timers with high precision 2025-02-15 11:57:41 +03:00
Alibek Omarov
052ea6a8bd engine: platform: introduce for Platform_NanoSleep, to be used for better sleeping in between frames for lowering CPU usage 2025-02-15 10:11:17 +03:00
Alibek Omarov
448dc720ed engine: server: immediately exit from SV_GetChallenge on unknown type addresses 2025-02-15 09:31:20 +03:00
Alibek Omarov
75b15696f8 engine: zone: ensure memheader_t size is always expected 2025-02-15 09:31:20 +03:00
Andrey Akhmichin
7fb113f610 Documentation: opensource-mods.md: add "Delta Particles". 2025-02-15 08:02:44 +03:00
Andrey Akhmichin
0497e00ad2 Documentation: supported-mod-list.md: update. 2025-02-15 08:02:35 +03:00
Alibek Omarov
9c50288bbb engine: server: rewrite challenge generator to something more simple: salted MD5 of an IP address
The idea was taken from ReHLDS project.
2025-02-15 08:01:44 +03:00
Alibek Omarov
c5d4af802c engine: server: even if user set non-integer value for cl_updaterate, clamp it to sv_minupdaterate 2025-02-15 08:01:44 +03:00
Alibek Omarov
340a8b5e0c engine: server: fixes for userinfo change ratelimiting
* Add pentalty earlier
* Increase disallowed timewindow according to penality multiplier
* Allow first change even if it falls into ignore timewindow
2025-02-15 08:01:44 +03:00
Alibek Omarov
bc1b86c19c engine: server: refactor SV_ConnectClient, simplify LAN IP check 2025-02-15 08:01:44 +03:00
Alibek Omarov
b605cf603e common: xash3d_types: make it more compatible for inclusion in SDK 2025-02-15 08:01:44 +03:00
xiaodo
fdc2ed8093 engine: server: pfnClientCommand and pfnQueryClientCvarValue should execute on unspawned player 2025-02-14 20:52:45 +03:00
xiaodo
a27375d1f5 engine: server: cmds: fix kick command incorrect argc 2025-02-14 20:52:45 +03:00
Alibek Omarov
0e2abf9040 engine: platform: always create zeroed buffer for audio 2025-02-14 05:20:40 +03:00
Alibek Omarov
89430400d9 engine: sys_con: only allow names that start with either alphabetic or numerical character for a log file 2025-02-14 01:51:50 +03:00
Alibek Omarov
f1a9d408bf engine: sys_con: check if the next argument after -log starts with minus and ignore it if it does 2025-02-14 00:50:01 +03:00
Alibek Omarov
6529692244 engine: disable timestamps in log file by default, allow changing log file name with -log argument 2025-02-14 00:28:00 +03:00
Alibek Omarov
51d11f8e86 engine: platform: win32: remove unused log variables and checks from Win32 console, sys_con does the job 2025-02-14 00:28:00 +03:00
Alibek Omarov
c5397191e5 engine: client: touch: limit usage of touch_set_stroke and touch_setclientonly only for privileged mode 2025-02-13 20:55:49 +03:00
Alibek Omarov
44426709f7 engine: platform: posix: skip first stack frame when printing stack trace with libbacktrace 2025-02-13 20:43:32 +03:00
Alibek Omarov
2d8f747e84 wscript: disable using system-wide libbacktrace, as it might not support features we need 2025-02-13 19:21:07 +03:00
Alibek Omarov
0dd5a60410 3rdparty: gl4es: update submodule 2025-02-13 02:32:28 +03:00
Alibek Omarov
eec8129be4 3rdparty: extras: update submodule 2025-02-13 02:31:30 +03:00
Alibek Omarov
934c5e018d readme: clarify that chat is for russian speaking people [ci skip] 2025-02-12 18:08:10 +03:00
Alibek Omarov
d658d8cc78 readme: remove builds.sr.ht status, add Telegram chat link, remove stable build link (it's very outdated and not recommended to use) [skip ci] 2025-02-12 17:58:51 +03:00
Alibek Omarov
ca9a3f0491 engine: server: fix out of bounds write in SV_FindTouchedLeafs 2025-02-11 21:15:54 +03:00
Alibek Omarov
1510cb458f public: fix another typo 2025-02-11 21:12:50 +03:00
Andrey Akhmichin
30cabb8107 Documentation: supported-mod-list.md: fix branch name. 2025-02-11 21:10:59 +03:00
Alibek Omarov
64ee956618 engine: fix a typo 2025-02-11 20:06:15 +03:00
Alibek Omarov
39659644bf public: merge calc bone quaternion and position into single function
Expect that only adj and output quaternion can be NULL.
2025-02-11 18:57:08 +03:00
Alibek Omarov
eb09af0b08 ref: gl: avoid generating GL_INVALID_OPERATION if gl_vbo_dlightmode is set to 0 2025-02-11 18:57:08 +03:00
Andrey Akhmichin
91a4ace12c Documentation: supported-mod-list.md: update. 2025-02-11 16:28:40 +03:00
Alibek Omarov
2ad2e46b30 mainui: update 2025-02-10 13:18:59 +03:00
Alibek Omarov
627444279f Revert "common: cvar: make auto descriptions private to cvar subsystem, use them when Cvar_Get is called with NULL description"
This reverts commit ade560c601.
2025-02-10 12:49:05 +03:00
Alibek Omarov
3550bdb30d 3rdparty: mainui: update 2025-02-09 23:14:24 +03:00
Alibek Omarov
c201b895eb common: netadr: force cast uint16_t type to netadrtype_t
So it compiles in C++
2025-02-09 23:13:29 +03:00
Alibek Omarov
72f1ac3780 wscript: ensure system-wide libbacktrace supports threads 2025-02-09 18:29:02 +03:00
Alibek Omarov
d7dc3192de 3rdparty: libbacktrace: fix applying uselib 2025-02-09 18:25:40 +03:00
Alibek Omarov
43ea65fffc ci: upgrade freebsd tasks. 2025-02-09 17:41:01 +03:00
Alibek Omarov
a72d921c12 wscript: add system-wide libbacktrace detection 2025-02-09 17:41:01 +03:00
Alibek Omarov
99b7d71824 wscript: set DEST_SIZEOF_VOID_P with allow 64bit flag 2025-02-09 17:16:17 +03:00
Alibek Omarov
67c73bdcbe engine: server: remove impulse 204, it's not used anywhere
Thanks @tyabus for reminding me about this feature.
2025-02-09 17:16:05 +03:00
Alibek Omarov
8b1dbcf166 ci: remove extra 20s of wait before removing current release and downloading artifacts 2025-02-09 17:02:31 +03:00
Alibek Omarov
5f60095dc4 scripts: flatpak: disable separate debuginfo 2025-02-09 16:54:51 +03:00
Alibek Omarov
c7282b488b 3rdparty: libbacktrace: disable linking zlib, lzma and zstd for now, figure this out later 2025-02-09 16:49:43 +03:00
Alibek Omarov
afa829d996 3rdparty: libbacktrace: don't define POSIX_SOURCE, it breaks build on Mac 2025-02-09 16:41:26 +03:00
Alibek Omarov
c06ea8d915 engine: platform: posix: add printing backtrace to stderr and logfile for libbacktrace backend 2025-02-09 16:41:26 +03:00
Alibek Omarov
bf344282ec android: explicitly set Waf output directory so it doesn't mess with current configuration and places generated files where CMake expects them to be 2025-02-09 16:20:38 +03:00
Alibek Omarov
21f62910ac engine: platform: posix: fix build when glibc execinfo.h is not available, but libbacktrace is still used 2025-02-09 16:20:38 +03:00
Alibek Omarov
54552d93ef Documentation: goldsrc-protocol-support: I am not going to support Dproto 2025-02-09 16:18:21 +03:00
Alibek Omarov
97455e7fd4 engine: platform: sdl: fix build after last PR 2025-02-09 15:56:16 +03:00
Alibek Omarov
6087d43043 3rdparty: libbacktrace: properly disable it on win32, nswitch and psvita 2025-02-09 15:55:12 +03:00
Alibek Omarov
c1a96d3ff1 engine: platform: posix: fix build 2025-02-09 15:51:25 +03:00
Alibek Omarov
e27d20dfa3 android: enable debug symbols for native libraries 2025-02-09 15:49:28 +03:00
Alibek Omarov
890e12ec76 engine: platform: posix: flush stdout/stderr before everything, include build branch 2025-02-09 15:45:44 +03:00
Alibek Omarov
774d2ac28a engine: platform: posix: add libbacktrace support for crash handler 2025-02-09 15:42:28 +03:00
Alibek Omarov
960d724828 3rdparty: libbacktrace: add submodule 2025-02-09 15:40:07 +03:00
Alibek Omarov
32aa1f91bf engine: pass argv0 to crash handler setup, which is required for libbacktrace integration
Fix indentation in crash_posix.c
2025-02-09 15:36:49 +03:00
Alibek Omarov
bd3634c815 wscript: add sanity test for opusfile because some distros don't ship 32-bit binary 2025-02-09 15:34:30 +03:00
Oleg
eda0ac92cc engine: platform: sdl: change behavior when window position is not set 2025-02-09 08:54:31 +03:00
Oleg
546903ea05 engine: platform: sdl: write windows position changes even in fullscreen 2025-02-09 08:54:31 +03:00
Oleg
4975001795 engine: platform: sdl: enumerate video modes for display where window located is instead of display zero 2025-02-09 08:54:31 +03:00
Oleg
a078ad1f51 engine: platform: sdl: fix windows save position for multiple monitors 2025-02-09 08:54:31 +03:00
Oleg
8307f671d4 engine: platform: sdl: let platform decide where to put our fullscreen window 2025-02-09 08:54:31 +03:00
Alibek Omarov
241fab02b1 ref: gl: don't try to free luma and detail texture of water texture, as these fields used by r_ripple 2025-02-08 16:57:20 +03:00
Alibek Omarov
1bfee70477 engine: con_utils: add autocompletion for cvar commands like set, reset and toggle 2025-02-08 16:45:52 +03:00
Alibek Omarov
eb51d17cd2 engine: server: enable sv_zmax clamping back to avoid overflowing zmax value encoded in delta 2025-02-08 16:38:11 +03:00
Alibek Omarov
b5cb0b9f10 ref: gl: add r_dlight_virtual_radius. It potentially fixes ugly dlight cut off on largely scaled textures (or at least allows to tune it)
It also adds a fix found in JoeQuake (which traces back to FitzQuake, in which
it is attributed to LadyHavoc, Darkplaces author) to exactly calculate whether
the light hits the surface, so we don't wrongly enable lighting on a surface by
an increased radius.
2025-02-07 23:07:08 +03:00
Alibek Omarov
a955d1e957 ref: gl: make GL_BuildPolygonFromSurface static, remove one global variable usage (which is unused anyway) 2025-02-07 22:55:38 +03:00
Alibek Omarov
2b2c967e85 engine: add ms3.mentality.rip master server 2025-02-07 19:32:37 +03:00
Alibek Omarov
c48d93e3ce public: use last Git commit date (committer date, to be exact) as more predictable source for build num 2025-02-07 17:51:10 +03:00
Alibek Omarov
8f257cc331 public: add parsing build date from ISO-8601 alike format 2025-02-07 17:47:23 +03:00
Alibek Omarov
151e7fe37b public: crtlib: check for empty buffer in Q_vsnprintf 2025-02-06 21:19:10 +03:00
Alibek Omarov
add02dc6f9 engine: fix potential UB in netadr_t 2025-02-06 20:54:18 +03:00
Alibek Omarov
d4c34abd6e engine: enable writing log even if console hasn't been enabled at the engine startup (it might be enabled later, it might also contain crash data) 2025-02-06 20:03:07 +03:00
Alibek Omarov
1d81e611f0 scripts: gha: use N+1 job count when building PSVita dependencies 2025-02-06 00:32:42 +03:00
Alibek Omarov
6a0038e26a ref: gl: always set texture env mode to GL_MODULATE in TriAPI's RenderMode call
Not sure if this is correct, but it's generally a good idea to restore it to an
expected value.
2025-02-06 00:30:32 +03:00
Alibek Omarov
1d99f65e86 filesystem: when shutting down, clean up gameinfo pointers and total games count 2025-02-05 21:14:08 +03:00
Alibek Omarov
5e524bca60 engine: client: enable half-texel hack for nearest filtering too, if the scaling factor isn't an integer 2025-02-05 20:16:16 +03:00
Alibek Omarov
cf3e56e275 engine: client: add alternative mode for hud_scale, where it scales HUD down to selected resolution with preserving aspect ratio 2025-02-05 19:47:59 +03:00
Alibek Omarov
ade560c601 common: cvar: make auto descriptions private to cvar subsystem, use them when Cvar_Get is called with NULL description
It allows us to not lose engine-side description when client or gameui registers cvar with the same name. In case of
menu it's the only way to get cvar pointer.
2025-02-05 19:11:16 +03:00
Alibek Omarov
62e3ba2126 engine: add cvars to control mounting additional directories
Use existing ui_language cvar for mounting localization folders.
2025-02-05 18:54:28 +03:00
Alibek Omarov
674a4e5883 filesystem: add ability to mount HD, LV, addon and language folders by engine request 2025-02-05 18:24:36 +03:00
Alibek Omarov
f911210b81 public: simplify ctype.h is* functions wrappers for null-terminated strings, add Q_isalpha 2025-02-05 18:21:18 +03:00
Alibek Omarov
14eb07653c engine: client: fix incorrect format in error message in CL_SetLightStyle 2025-02-05 17:41:01 +03:00
Alibek Omarov
54b0cf9991 ref: gl: check OES NPOT texture extension in BigGL mode 2025-02-05 14:00:44 +03:00
Alibek Omarov
3ebcb08a97 ref: gl: add cvar r_large_lightmaps to enable larger lightmap sizes, opt-in, yields better performance with VBO renderer 2025-02-05 13:02:37 +03:00
Alibek Omarov
23940f8590 readme: remove fontconfig from dependencies list, we aren't using it anymore [skip ci] 2025-02-04 21:00:42 +03:00
Alibek Omarov
687fb0123f engine: implement basic gamepad gyroscope calibration
Called on game controller becoming active or by user request.
Exposes current calibration state by read-only console variable.
2025-02-03 13:14:51 +03:00
Alibek Omarov
6c91fdb0cd ref: gl: gl2_shim: fix int vs GLuint 2025-02-02 20:57:37 +03:00
Alibek Omarov
4832232fd6 ci: attempt to fix flatpak upload 2025-02-02 20:31:51 +03:00
Alibek Omarov
185bce0489 engine: common: remove unused D_ enum used for MsgDev in old engine. Make sure all enums and structs here are not anonymous 2025-02-02 20:26:07 +03:00
Alibek Omarov
f460aa63b0 engine: platform: posix: don't forget to print backtrace to stderr too 2025-02-02 19:20:54 +03:00
Alibek Omarov
22f8b6f9c3 engine: platform: enable crash handler for macOS 2025-02-02 18:30:41 +03:00
Alibek Omarov
0cb034afc2 engine: wscript: improve execinfo and GNU backtrace() check 2025-02-02 18:18:26 +03:00
Alibek Omarov
d0464ef602 engine: platform: posix: use glibc-based backtrace implementation for crash handling, if execinfo.h can be found 2025-02-02 18:06:18 +03:00
Alibek Omarov
c3ebb84b97 ci: bump SDL2 to 2.30.12 2025-02-02 08:14:24 +03:00
Alibek Omarov
11742efbc3 engine: fix player move on dedicated servers 2025-02-02 08:08:15 +03:00
Alibek Omarov
95af635ab4 engine: client: add command replaybufferdat to aid in debugging protocol errors by parsing buffer.dat 2025-02-02 05:22:46 +03:00
Alibek Omarov
1abec80191 engine: client: set codepage to 0 if con_charset value is unknown 2025-02-02 02:34:08 +03:00
Alibek Omarov
93ebddfba3 public: utflib: simplify Q_EncodeUTF8 2025-02-02 02:31:56 +03:00
Alibek Omarov
5378494199 wscript: enable main() function for Android port, which was forgotten after last refactoring 2025-02-01 18:26:20 +03:00
Alibek Omarov
1b44d7733e engine: platform: add improved Platform_Vibrate2 function, that allows to control vibration strength 2025-02-01 18:08:53 +03:00
Alibek Omarov
694c630b44 engine: zone: don't error when trying to free NULL pointer, like standard C free() and C++ delete 2025-02-01 17:51:02 +03:00
Alibek Omarov
7df1d4b9e2 engine: platform: sdl: remove useless for us game controller events 2025-01-31 19:48:33 +03:00
Alibek Omarov
b16037eabf engine: drop raw SDL joystick API, always use GameController instead. Implement actually working rumble, ensure we're freeing up all resources related to gamepads 2025-01-31 17:50:19 +03:00
Alibek Omarov
bff7299f9b gha: publish binaries even if flatpak fails 2025-01-31 10:37:41 +03:00
Alibek Omarov
de196b1c58 common: xash3d_types: avoid defining true and false in C23 2025-01-31 10:36:27 +03:00
Alibek Omarov
a0eec8b85d scripts: waifulib: add special_install_path for platform-specific executable formats that create post link stage (was nro_install_path) 2025-01-31 10:25:02 +03:00
Alibek Omarov
c7e8ea2ffa scripts: gha: linux: build smaller SDL2 (without 2D renderer) for Linux as well 2025-01-31 10:02:19 +03:00
Alibek Omarov
1c1cf3d646 scripts: waifulib: psvita: make sce_sys truly optional in apply_vpk 2025-01-31 10:02:19 +03:00
Alibek Omarov
9759b80b78 scripts: waifulib: psvita: set default title id and app name to just test 2025-01-31 09:10:39 +03:00
Alibek Omarov
94b2c0b443 scripts: gha: build render-less SDL2 for PSVita 2025-01-31 09:10:09 +03:00
Alibek Omarov
ff8d17a5a8 scripts: waifulib: psvita: add missing cprogram attributes 2025-01-31 09:04:40 +03:00
Alibek Omarov
aa23196a55 scripts: waifulib: support vpk and nro pass for pure C programs, just in case 2025-01-30 20:51:01 +03:00
Alibek Omarov
83b488c37e wscript: let building client and dedicated server in the same configuration 2025-01-30 20:23:12 +03:00
Alibek Omarov
77abf621d7 ref: gl: make GL_Support and GL_MaxTextureUnits functions inlined 2025-01-30 19:02:53 +03:00
Alibek Omarov
f9d4ac2771 ref: gl: fix ugly seam at the skybox, thanks Spoike for help 2025-01-30 18:53:31 +03:00
Alibek Omarov
f076d84975 engine: platform: android: move dlsym-weak hack from C++ to C 2025-01-30 18:07:35 +03:00
Alibek Omarov
faf0b32a94 ref: gl: fix massive frame drop caused by ripples code rendering same texture multiple times in the frame 2025-01-29 20:15:21 +03:00
Alibek Omarov
feb80e5997 engine: platform: sdl: read gamecontrollerdb.txt from extras.pk3 2025-01-29 13:43:10 +03:00
Alibek Omarov
004af02e99 engine: avi: comment out debug messages 2025-01-29 11:13:29 +03:00
Alibek Omarov
8ad56eb085 Merge branch 'master' into avi 2025-01-29 11:12:38 +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
32def35408 engine: avi: remove stub file 2025-01-23 18:56:44 +03:00
Alibek Omarov
952ccb1247 engine: avi: very dumb pause 2025-01-23 18:55:48 +03:00
Alibek Omarov
6f0fb594e7 Merge branch 'master' 2025-01-23 18:42:00 +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
8b4b0479c8 ci: enable ffmpeg by default for Windows and Linux x86 targets 2024-12-13 03:04:32 +03:00
Alibek Omarov
c8bf7e5630 engine: avi: get rid of stubs file, temporarily put these stubs into avi_ffmpeg.c 2024-12-13 03:04:32 +03:00
Alibek Omarov
4987080e1e engine: client: remove unused S_RawSamples wrapper function 2024-12-13 03:04:32 +03:00
Alibek Omarov
1d78e400ff engine: sound: increase MAX_RAW_SAMPLES to 16384 to fit an audio track coming from the movies 2024-12-13 03:04:32 +03:00
Alibek Omarov
2d1a885954 common: render_api: use movie_state_s in AVI functions for easier type checking 2024-12-13 03:04:32 +03:00
Alibek Omarov
43ba2e747b engine: avi: mention SDL3 and FTEQW developers which ffmpeg integrations in their projects helped me to understand the ffmpeg API 2024-12-13 03:04:32 +03:00
Alibek Omarov
eefb823ee2 engine: client: remove legacy movie audio track streaming functions 2024-12-13 03:04:32 +03:00
Alibek Omarov
a3c33e0fa9 engine: client: sound: make S_RawSampleStereo public to other parts of engine 2024-12-13 03:04:32 +03:00
Alibek Omarov
16fe6b1b1a engine: client: avi: remove VFW-based player 2024-12-13 03:04:32 +03:00
Alibek Omarov
4275829bd5 engine: client: partially rework how AVI playback works in Xash. Add ffmpeg-based player.
This intentionally will not build without --enable-ffmpeg for now.

We add new functions to the RenderAPI called AVI_Think and AVI_SetParm. Game
developer is supposed to call AVI_Think each frame and set video playback
parameters through AVI_SetParm function.

What's tested:
* Intro cinematics.
* Looping videos.
* Playing back an hour long video.
* API extension (PrimeXT's avi branch at https://github.com/a1batross/PrimeXT).

What's broken:
* There is no way to seek a video file, only rewind to the start.
2024-12-13 03:04:32 +03:00
Alibek Omarov
1884f0a3ce engine: client: avi: add new macro XASH_AVI and corresponding backend select macros (AVI_NULL and AVI_FFMPEG) 2024-12-09 00:27:40 +03:00
344 changed files with 16177 additions and 11555 deletions

View File

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

View File

@@ -6,21 +6,8 @@ jobs:
# steps: # steps:
# - name: Cleanup # - name: Cleanup
# run: rm -rf .* || true # run: rm -rf .* || true
get_prev_runid:
runs-on: ubuntu-latest
outputs:
value: ${{ steps.do.outputs.value }}
steps:
- id: do
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
value=$(gh run -R ${{ github.repository }} list -b${{ github.ref_name }} -ssuccess -L1 --json databaseId -q'.[0].databaseId')
echo "Last run ID is $value"
echo "value=$value" >> "$GITHUB_OUTPUT"
build: build:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
needs: get_prev_runid
continue-on-error: true continue-on-error: true
strategy: strategy:
fail-fast: false fail-fast: false
@@ -28,35 +15,39 @@ jobs:
include: include:
# Linux build specifically want oldest Ubuntu as possible # Linux build specifically want oldest Ubuntu as possible
# to be crossdistribution compatible, otherwise use ubuntu-latest # to be crossdistribution compatible, otherwise use ubuntu-latest
- os: ubuntu-20.04 - os: ubuntu-22.04
targetos: linux targetos: linux
targetarch: amd64 targetarch: amd64
- os: ubuntu-20.04 - os: ubuntu-22.04
targetos: linux targetos: linux
targetarch: i386 targetarch: i386
- os: ubuntu-20.04 - os: ubuntu-22.04
targetos: linux targetos: linux
targetarch: arm64 targetarch: arm64
cross: true cross: true
- os: ubuntu-20.04 - os: ubuntu-22.04
targetos: linux targetos: linux
targetarch: armhf targetarch: armhf
cross: true cross: true
- os: ubuntu-20.04 - os: ubuntu-24.04 # riscv64 would benefit from having latest compilers
targetos: linux targetos: linux
targetarch: riscv64 targetarch: riscv64
cross: true cross: true
- os: ubuntu-20.04 - os: ubuntu-22.04
targetos: linux targetos: linux
targetarch: ppc64el targetarch: ppc64el
cross: true cross: true
# - os: ubuntu-aarch64-20.04 # - os: ubuntu-aarch64-22.04
# targetos: linux # targetos: linux
# targetarch: aarch64 # targetarch: aarch64
- os: ubuntu-20.04 # - os: ubuntu-latest
# targetos: linux
# targetarch: e2k-8c
# cross: true
- os: ubuntu-latest
targetos: android targetos: android
targetarch: multiarch targetarch: multiarch
# - os: ubuntu-20.04 # - os: ubuntu-22.04
# targetos: motomagx # targetos: motomagx
# targetarch: armv6 # targetarch: armv6
@@ -69,7 +60,7 @@ jobs:
- os: windows-latest - os: windows-latest
targetos: win32 targetos: win32
targetarch: amd64 targetarch: amd64
- os: windows-2019 # always use the oldest possible for 32-bit because of older compilers, and better support of certain legacy OSes - os: windows-2022 # always use the oldest possible for 32-bit because of older compilers, and better support of certain legacy OSes
targetos: win32 targetos: win32
targetarch: i386 targetarch: i386
- os: macos-14 # arm64 as per github documentation - os: macos-14 # arm64 as per github documentation
@@ -79,22 +70,16 @@ jobs:
targetos: apple targetos: apple
targetarch: amd64 targetarch: amd64
env: env:
SDL_VERSION: 2.30.11 SDL_VERSION: 2.32.8
FFMPEG_VERSION: 7.1
GH_CPU_ARCH: ${{ matrix.targetarch }} GH_CPU_ARCH: ${{ matrix.targetarch }}
GH_CPU_OS: ${{ matrix.targetos }}
GH_CROSSCOMPILING: ${{ matrix.cross }} GH_CROSSCOMPILING: ${{ matrix.cross }}
WAFCACHE: ${{ github.workspace }}/wafcache/
WAFCACHE_EVICT_MAX_BYTES: 1000000 # github only gives 10gb for the whole repository
WAFCACHE_STATS: 1 # enable statistics in build log
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
- name: Restore cache
uses: actions/cache/restore@v4
with:
key: ${{ runner.os }}-${{ matrix.targetos }}-${{ matrix.targetarch }}-${{ needs.get_prev_runid.outputs.value }}
path: ${{ github.workspace }}/wafcache/
- name: Install dependencies - name: Install dependencies
run: bash scripts/gha/deps_${{ matrix.targetos }}.sh run: bash scripts/gha/deps_${{ matrix.targetos }}.sh
- name: Build engine - name: Build engine
@@ -106,20 +91,15 @@ jobs:
with: with:
name: artifact-${{ matrix.targetos }}-${{ matrix.targetarch }} name: artifact-${{ matrix.targetos }}-${{ matrix.targetarch }}
path: artifacts/* path: artifacts/*
- name: Save cache
uses: actions/cache/save@v4
with:
path: ${{ github.workspace }}/wafcache/
key: ${{ runner.os }}-${{ matrix.targetos }}-${{ matrix.targetarch }}-${{ github.run_id }}
flatpak: flatpak:
runs-on: ubuntu-latest runs-on: ubuntu-latest
continue-on-error: true
strategy: strategy:
matrix: matrix:
include: include:
- app: su.xash.Engine.Compat.i386 - app: su.xash.Engine.Compat.i386
container: container:
image: bilelmoussaoui/flatpak-github-actions:freedesktop-24.08 image: ghcr.io/flathub-infra/flatpak-github-actions:freedesktop-24.08
options: --privileged options: --privileged
steps: steps:
- name: Checkout - name: Checkout
@@ -127,7 +107,7 @@ jobs:
with: with:
submodules: recursive submodules: recursive
- name: Build flatpak (Compat.i386) - name: Build flatpak (Compat.i386)
uses: FWGS/flatpak-github-actions/flatpak-builder@v6.3 uses: FWGS/flatpak-github-actions/flatpak-builder@v6.5
with: with:
bundle: ${{ matrix.app }}.flatpak bundle: ${{ matrix.app }}.flatpak
manifest-path: scripts/flatpak/${{ matrix.app }}.yml manifest-path: scripts/flatpak/${{ matrix.app }}.yml
@@ -146,7 +126,6 @@ jobs:
--yes \ --yes \
--cleanup-tag \ --cleanup-tag \
--repo "$GITHUB_REPOSITORY" || true --repo "$GITHUB_REPOSITORY" || true
sleep 20s
gh run download "$GITHUB_RUN_ID" \ gh run download "$GITHUB_RUN_ID" \
--dir artifacts/ \ --dir artifacts/ \
--repo "$GITHUB_REPOSITORY" --repo "$GITHUB_REPOSITORY"

11
.gitignore vendored
View File

@@ -222,7 +222,7 @@ publish/
# Publish Web Output # Publish Web Output
*.[Pp]ublish.xml *.[Pp]ublish.xml
*.azurePubxml *.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings # TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted # but database connection strings (with potential passwords) will be unencrypted
*.pubxml *.pubxml
*.publishproj *.publishproj
@@ -345,3 +345,12 @@ enc_temp_folder/
# ccls langauge server # ccls langauge server
.ccls-* .ccls-*
# JetBrains
.idea/
cmake-build-*
# some Android-specific build stuff
3rdparty/SDL
3rdparty/hlsdk-portable
!scripts/build-ninja.py

12
.gitmodules vendored
View File

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

View File

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

View File

@@ -13,10 +13,12 @@ def configure(conf):
def build(bld): def build(bld):
gl4es_srcdir = bld.path.find_node('gl4es/src') gl4es_srcdir = bld.path.find_node('gl4es/src')
cflags = []
if bld.env.COMPILER_CC != 'msvc':
cflags += ['-w', '-fvisibility=hidden', '-std=gnu99']
bld.stlib(source = gl4es_srcdir.ant_glob(['gl/*.c', 'gl/*/*.c', 'glx/hardext.c']), bld.stlib(source = gl4es_srcdir.ant_glob(['gl/*.c', 'gl/*/*.c', 'glx/hardext.c']),
target = 'gl4es', target = 'gl4es',
includes = ['gl4es/src', 'gl4es/src/gl', 'gl4es/src/glx', 'gl4es/include'], includes = ['gl4es/src', 'gl4es/src/gl', 'gl4es/src/glx', 'gl4es/include'],
defines = ['NOX11', 'NO_GBM', 'NO_INIT_CONSTRUCTOR', 'DEFAULT_ES=2', 'NOEGL', 'NO_LOADER', 'STATICLIB'], defines = ['NOX11', 'NO_GBM', 'NO_INIT_CONSTRUCTOR', 'DEFAULT_ES=2', 'NOEGL', 'NO_LOADER', 'STATICLIB'],
cflags = ['-w', '-fvisibility=hidden', '-std=gnu99'], cflags = cflags,
export_includes = '.') export_includes = '.')

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

@@ -0,0 +1,186 @@
#! /usr/bin/env python
# encoding: utf-8
from waflib import TaskGen
from waflib.Tools.c_config import DEFKEYS
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
conf.define('BACKTRACE_ELF_SIZE', 64 if conf.env.DEST_SIZEOF_VOID_P == 8 else 32)
conf.define('BACKTRACE_XCOFF_SIZE', 64 if conf.env.DEST_SIZEOF_VOID_P == 8 else 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, 'compiler': 'c'}
def check_frag(frag, msg, define, **kw):
return dict({'fragment': frag, 'msg':'... %s' % msg, 'mandatory': False, 'compiler': 'c'}, **kw)
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'),
check_frag(FRAGMENT_ATOMIC, '__atomic extensions', 'HAVE_ATOMIC_FUNCTIONS'),
check_frag(FRAGMENT_SYNC, ' __sync extensions', 'HAVE_SYNC_FUNCTIONS'),
check_frag(FRAGMENT_GETPAGESIZE, ' getpagesize function', 'HAVE_DECL_GETPAGESIZE'),
check_frag(FRAGMENT_STRNLEN, ' strnlen function', 'HAVE_DECL_STRNLEN'),
check_frag(FRAGMENT_DL_ITERATE_PHDR % 'link.h', ' dl_iterate_phdr function in link.h', 'HAVE_DL_ITERATE_PHDR', after_tests=['link.h']),
check_frag(FRAGMENT_DL_ITERATE_PHDR % 'sys/link.h', ' dl_iterate_phdr function in sys/link.h', 'HAVE_DL_ITERATE_PHDR', after_tests=['sys/link.h']),
check_frag(FRAGMENT_FCNTL, 'fnctl function', 'HAVE_FCNTL'),
check_frag(FRAGMENT_GETEXECNAME, 'getexecname function','HAVE_GETEXECNAME'),
check_frag(FRAGMENT_GETIPINFO, '_Unwind_GetIPInfo function', 'HAVE_GETIPINFO'),
check_frag(FRAGMENT_KERN_PROC % 'KERN_PROC', 'KERN_PROC and KERN_PROC_PATHNAME defines', 'HAVE_KERN_PROC'),
check_frag(FRAGMENT_KERN_PROC % 'KERN_PROC_ARGS', 'KERN_PROC_ARGS and KERN_PROC_PATHNAME defines', 'HAVE_KERN_PROC_ARGS'),
check_frag(FRAGMENT_LOADQUERY, 'loadquery function', 'HAVE_LOADQUERY'),
check_frag(FRAGMENT_LSTAT, 'lstat function', 'HAVE_LSTAT'),
check_frag(FRAGMENT_READLINK, 'readlink function', 'HAVE_READLINK'),
# {'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.env[DEFKEYS].sort()
conf.write_config_header()
conf.define('BACKTRACE_SUPPORTED', 1)
conf.define('BACKTRACE_USES_MALLOC', 0)
conf.define('BACKTRACE_SUPPORTS_THREADS', 1)
conf.define('BACKTRACE_SUPPORTS_DATA', conf.env.DEST_BINFMT in ['elf', 'mac-o'])
conf.write_config_header('backtrace-supported.h')
@TaskGen.feature('frandomseed')
@TaskGen.after_method('propagate_uselib_vars')
def process_frandom_seed(ctx):
tasks = getattr(ctx, 'compiled_tasks', [])
for task in tasks:
out = task.outputs[0]
task.env.CFLAGS = list(task.env.CFLAGS) # need a copy
task.env.CFLAGS += ['-frandom-seed=%s' % out.path_from(out.ctx.bldnode)]
def build(bld):
if bld.env.DISABLE_LIBBACKTRACE:
return
# we specifically only want mmap-based allocators because calling malloc is not safe from signal handlers
sources = ['atomic.c', 'dwarf.c', 'fileline.c', 'posix.c', 'print.c', 'sort.c', 'state.c', 'backtrace.c', 'simple.c', 'mmap.c', 'mmapio.c']
if bld.env.DEST_BINFMT == 'pe':
sources += ['pecoff.c']
elif bld.env.DEST_BINFMT == 'mac-o':
sources += ['macho.c']
elif bld.env.DEST_BINFMT == 'elf':
sources += ['elf.c']
else:
sources += ['unknown.c']
task = bld.stlib(
source = ['libbacktrace/' + i for i in sources],
target = 'backtrace',
features = 'frandomseed' if bld.env.HAVE_FRANDOM_SEED else '',
use = 'EXTRAFLAGS lzma z zstd',
includes = '. libbacktrace/',
export_defines = 'HAVE_LIBBACKTRACE=1',
export_includes = 'libbacktrace/'
)

1
3rdparty/maintui vendored Submodule

Submodule 3rdparty/maintui added at eba8d49880

78
3rdparty/opus/wscript vendored
View File

@@ -23,6 +23,17 @@ int main (void) {
int * array = alloca(foo); int * array = alloca(foo);
}''' }'''
FRAGMENT_LRINT='''#include <math.h>
#include <stdlib.h>
int main (int argc, char **argv) {
return lrint%s((%s)atof(argv[1]));
}'''
# assuming MSVC always enables NEON
FRAGMENT_NEON='''#if !defined __ARM_NEON__ && !defined _MSC_VER
#error
#endif'''
def options(opt): def options(opt):
pass pass
@@ -31,15 +42,61 @@ def configure(conf):
conf.fatal('Can\'t find opus submodule. Run `git submodule update --init --recursive`.') conf.fatal('Can\'t find opus submodule. Run `git submodule update --init --recursive`.')
return return
if conf.check_cc(fragment=FRAGMENT_LRINT % ('', 'double'), msg = 'Checking for C99 lrint', use = 'M', mandatory = False):
conf.define('HAVE_LRINT', 1)
if conf.check_cc(fragment=FRAGMENT_LRINT % ('f', 'float'), msg = 'Checking for C99 lrintf', use = 'M', mandatory = False):
conf.define('HAVE_LRINTF', 1)
# Check for C99 variable-size arrays, or alloca() as fallback # Check for C99 variable-size arrays, or alloca() as fallback
if conf.check_cc(fragment=FRAGMENT_VLA, msg = 'Checking for C99 VLA support', mandatory = False): if conf.check_cc(fragment=FRAGMENT_VLA, msg = 'Checking for C99 VLA support', mandatory = False):
conf.define('VAR_ARRAYS', 1) conf.define('VAR_ARRAYS', 1)
elif conf.check_cc(fragment=FRAGMENT_ALLOCA_H, msg = 'Checking for alloca in alloca.h header', mandatory = False): elif conf.check_cc(fragment=FRAGMENT_ALLOCA_H, msg = 'Checking for alloca in alloca.h header', mandatory = False):
conf.define('USE_ALLOCA', 1) conf.define('USE_ALLOCA', 1)
conf.define('HAVE_ALLOCA_H', 1) conf.define('HAVE_ALLOCA_H', 1)
elif conf.check_cc(fragmenmt=FRAGMENT_STDLIB_H, msg = 'Checking for alloca.h in stdlib.h', mandatory = False): elif conf.check_cc(fragment=FRAGMENT_STDLIB_H, msg = 'Checking for alloca.h in stdlib.h', mandatory = False):
conf.define('USE_ALLOCA', 1) conf.define('USE_ALLOCA', 1)
if conf.env.DEST_CPU in ['thumb', 'arm']:
if conf.check(header_name='arm_neon.h', mandatory = False):
if conf.check(fragment=FRAGMENT_NEON, msg = 'Checking if compiler enabled NEON', mandatory = False):
conf.env.HAVE_NEON = True
conf.define('OPUS_ARM_MAY_HAVE_NEON_INTR', 1)
conf.define('OPUS_ARM_PRESUME_NEON', 1)
elif conf.env.DEST_CPU.startswith('x86'):
if conf.check(header_name='xmmintrin.h', mandatory = False):
if conf.env.COMPILER_CC != 'msvc':
conf.env.CFLAGS += ['-msse']
conf.define('OPUS_X86_MAY_HAVE_SSE', 1)
if conf.env.DEST_SIZEOF_VOID_P > 4:
conf.define('OPUS_X86_PRESUME_SSE', 1)
if conf.check(header_name='emmintrin.h', mandatory = False):
if conf.env.COMPILER_CC != 'msvc':
conf.env.CFLAGS += ['-msse2']
conf.define('OPUS_X86_MAY_HAVE_SSE2', 1)
if conf.env.DEST_SIZEOF_VOID_P > 4:
conf.define('OPUS_X86_PRESUME_SSE2', 1)
# on x86_64 we enable both SSE and SSE2, so RTCD can be disabled (it's actually doesn't even build with RTCD enabled)
if conf.env.DEST_SIZEOF_VOID_P == 4:
if conf.check(header_name='cpuid.h', mandatory=False):
conf.define('CPU_INFO_BY_C', 1)
else:
conf.define('CPU_INFO_BY_ASM', 1)
conf.define('OPUS_HAVE_RTCD', 1)
# if conf.check(header_name='smmintrin.h', mandatory = False):
# if conf.env.COMPILER_CC != 'msvc':
# conf.env.CFLAGS += ['-msse4.1']
# conf.define('OPUS_X86_MAY_HAVE_SSE4_1', 1)
# if conf.check(header_name='immintrin.h', mandatory = False):
# if conf.env.COMPILER_CC != 'msvc':
# conf.env.CFLAGS += ['-mavx']
# conf.define('OPUS_X86_MAY_HAVE_AVX', 1)
# TODO: ARM/x86 intrinsics detection # TODO: ARM/x86 intrinsics detection
# TODO: maybe call autotools/cmake/meson instead? # TODO: maybe call autotools/cmake/meson instead?
@@ -55,8 +112,23 @@ def build(bld):
'opus/src/opus_compare.c', 'opus/src/opus_compare.c',
'opus/celt/opus_custom_demo.c' 'opus/celt/opus_custom_demo.c'
]) ])
includes = ['opus/include/', 'opus/celt/', 'opus/silk/', 'opus/silk/float/']
defines = ['OPUS_BUILD', 'FLOAT_APPROX', 'PACKAGE_VERSION="1.4.0"', 'CUSTOM_MODES'] includes = ['opus', 'opus/include/', 'opus/celt/', 'opus/silk/', 'opus/silk/float/']
if bld.env.DEST_CPU in ['thumb', 'arm']:
if bld.env.HAVE_NEON:
sources += bld.path.ant_glob(['opus/silk/arm/*.c', 'opus/celt/arm/*.c'])
includes += ['opus/silk/arm', 'opus/celt/arm']
elif bld.env.DEST_CPU.startswith('x86'):
sources += ['opus/silk/x86/x86_silk_map.c',
'opus/celt/x86/pitch_sse.c',
'opus/celt/x86/pitch_sse2.c',
'opus/celt/x86/vq_sse2.c',
'opus/celt/x86/x86_celt_map.c',
'opus/celt/x86/x86cpu.c']
includes += ['opus/silk/x86', 'opus/celt/x86']
defines = ['OPUS_BUILD', 'FLOAT_APPROX', 'PACKAGE_VERSION="1.4.0"', 'CUSTOM_MODES', 'ENABLE_HARDENING']
bld.stlib( bld.stlib(
source = sources, source = sources,

View File

@@ -45,3 +45,8 @@
Tags can be any: subsystem, simple feature name or even just a filename, without extension. Tags can be any: subsystem, simple feature name or even just a filename, without extension.
Just keep them always same, it helps keep history clean and commit messages short. Just keep them always same, it helps keep history clean and commit messages short.
## LLM-based tools usage.
While we wouldn't recommend using any LLM-based (also misleadingly called AI) tools, we understand that they are here to stay.
Whether you're reporting bug or contributing the code, you take complete authorship and responsibility over provided content and the same rules will apply to you as for everybody else, so validate the bug report or the patch before sending it.

View File

@@ -2,23 +2,27 @@
On this page you can find links where you can support each developer individually, who has provided public sponsorship information. On this page you can find links where you can support each developer individually, who has provided public sponsorship information.
### [a1batross](https://github.com/a1batross) ## [a1batross](https://github.com/a1batross)
* Initial Xash3D SDL2/Linux port author, Xash3D FWGS engine maintainer, creator of non-commercial Flying With Gauss organization. Initial Xash3D SDL2/Linux port author, Xash3D FWGS engine maintainer, creator of non-commercial Flying With Gauss organization.
* Boosty page: https://boosty.to/a1ba
### [nekonomicon](https://github.com/nekonomicon) * [Boosty page](https://boosty.to/a1ba)
* [hlsdk-portable](https://github.com/FWGS/hlsdk-portable), [mdldec](../utils/mdldec), [opensource-mods.md](opensource-mods.md) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=nekonomicon) (*BSD/clang port, PNG support, etc). ## [nekonomicon](https://github.com/nekonomicon)
* Boosty page: https://boosty.to/nekonomicon
### [Velaron](https://github.com/Velaron) [hlsdk-portable](https://github.com/FWGS/hlsdk-portable), [mdldec](../utils/mdldec), [opensource-mods.md](opensource-mods.md) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=nekonomicon) (*BSD/clang port, PNG support, etc).
* [cs16-client](https://github.com/Velaron/cs16-client) & [tf15-client](https://github.com/Velaron/tf15-client) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=Velaron) (Android port, voice chat, etc).
* BuyMeACoffee page: https://www.buymeacoffee.com/velaron
### [SNMetamorph](https://github.com/SNMetamorph) * [Boosty page](https://boosty.to/nekonomicon)
* [PrimeXT](https://github.com/SNMetamorph/PrimeXT) & [GoldSrc Monitor](https://github.com/SNMetamorph/goldsrc-monitor) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=SNMetamorph) (Windows port, voice chat, etc).
* BTC: `16GAzK3qei5AwBW7sggXp3yNcFHBtdpxXj` ## [Velaron](https://github.com/Velaron)
* ETH (ERC20): `0xb580eeca9756e3881f9d6d026e28db28eb72a383`
* USDT (ERC20): `0xb580eeca9756e3881f9d6d026e28db28eb72a383` [cs16-client](https://github.com/Velaron/cs16-client) & [tf15-client](https://github.com/Velaron/tf15-client) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=Velaron) (Android port, voice chat, etc).
* USDC (ERC20): `0xb580eeca9756e3881f9d6d026e28db28eb72a383`
* [Boosty page](https://boosty.to/velaron)
## [SNMetamorph](https://github.com/SNMetamorph)
[PrimeXT](https://github.com/SNMetamorph/PrimeXT) & [GoldSrc Monitor](https://github.com/SNMetamorph/goldsrc-monitor) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=SNMetamorph) (Windows port, voice chat, etc).
* [Boosty page](https://boosty.to/snmetamorph)
* [Other donation methods](https://snmetamorph.github.io/donate)

View File

@@ -42,3 +42,6 @@ Issue #3: Some mods (like The Specialists, Tyrian, ...) already apply suffixes _
Resolution: On x86 on **Win/Lin/Mac**, don't change anything. Otherwise, strip the _i?86 part and follow the usual scheme. Resolution: On x86 on **Win/Lin/Mac**, don't change anything. Otherwise, strip the _i?86 part and follow the usual scheme.
See discussion: https://github.com/FWGS/xash3d-fwgs/issues/39 See discussion: https://github.com/FWGS/xash3d-fwgs/issues/39
Issue #4: When distributing game libraries on Android inside an APK, they couldn't be loaded.
Resolution: Enable `useLegacyPackaging` option in build.gradle, when distributing games in APK. Always force game libraries to have `lib` prefix on Android, regardless if they are packaged in APK or not..

View File

@@ -6,7 +6,7 @@ For connecting to GoldSrc-based servers, use this command:
connect ip:port gs 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. 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). That is because proper authorization with Steam API is not implemented in engine yet (but we have plans on it).

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@@ -2,10 +2,19 @@
|Name |Version |Why not working |What was made for that |Name |Version |Why not working |What was made for that
|---- |------- |--------------- |---------------------- |---- |------- |--------------- |----------------------
|Blue Shift |The latest steam release |Uses vgui2 library which xash3d does not support |Recreated source code here: https://github.com/FWGS/hlsdk-xash3d/tree/bshift |Area 51 |Update 1 |Uses outdated BSP31 map format and custom HLFX SDK libraries. |You can try [this tool](https://hlfx.ru/forum/showthread.php?threadid=5250) to convert maps but there no warranty if it works.
|Counter Strike |1.6(The latest steam release) |Uses vgui2 library which xash3d does not support |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface |Arrange Mod: Rebirth |v150 |No idea yet. |
|Counter Strike: Condition Zero |The latest steam release |Uses vgui2 library which xash3d does not support |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface |Blue Shift |The latest steam release |Uses vgui2 library which xash3d does not support. |Recreated source code here: https://github.com/FWGS/hlsdk-xash3d/tree/bshift.
|Counter Strike: Condition Zero - Deleted scenes |The latest steam release |Uses vgui2 library which xash3d does not support |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface |Counter Strike |Beta 6.5- |Uses an old WON HL 1.0.0.16- interface. |
|Day of Defeat |The latest steam release |Uses vgui2 library which xash3d does not support |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface | |1.4 |Has encrypted blob instead of normal client.dll. |You can try [this tool](https://aluigi.altervista.org/papers/hldlldec.zip) to decrypt client.dll but there no warranty if it works.
|Sven-Coop |5.0+ |Uses custom GoldSrc engine | | |1.5 |Has encrypted blob instead of normal client.dll. |Decrypted blob here: https://csm.dev/threads/cs-1-5-client-dll-decrypted-patched-for-usage.38845.
| |1.6(The latest steam release) |Uses vgui2 library which xash3d does not support. |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface. Recreated Client Source Code here: https://github.com/Velaron/cs16-client.
|Counter Strike: Condition Zero |The latest steam release |Uses vgui2 library which xash3d does not support. |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface. Recreated Client Source Code here: https://github.com/Velaron/cs16-client.
|Counter Strike: Condition Zero - Deleted scenes |The latest steam release |Uses vgui2 library which xash3d does not support. Uses new sequences code on engine-side that was never used in any other mods before. |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface.
|Day of Defeat |The latest steam release |Uses vgui2 library which xash3d does not support. |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface.
|Half-Life: Extended |Day One demo |Uses many hooks to GoldSource engine and version check. |Just wait new version or use more old version.
|Icon of Hell |Beta 0.99 |Uses outdated BSP31 map format and paranoia 2 libraries. |You can try [this tool](https://hlfx.ru/forum/showthread.php?threadid=5250) to convert maps and use Paranoia 2: The Savior 1.51 libraries but there no warranty if it works.
|Paranoia 2: The Savior |All builds older 1.51 |Uses an old renderer interface and engine features. |
|Rebellion |1.0 |Uses an old WON HL 1.0.0.16- interface. |Recreated source code here: https://github.com/FWGS/hlsdk-xash3d/tree/rebellion.
|Sven-Coop |5.0+ |Uses custom GoldSrc engine. |
|Time Shadows |Beta 0.1 |Uses Direct3D renderer. |

View File

@@ -32,12 +32,18 @@ Version 1.9 mirrored on github - https://github.com/solidi/hl-mods/tree/master/c
## Cold Ice Ressurection ## Cold Ice Ressurection
Mirrored on github - https://github.com/solidi/hl-mods/tree/master/cir Mirrored on github - https://github.com/solidi/hl-mods/tree/master/cir
## Counter-Life
Available on ModDB - https://www.moddb.com/mods/counter-life/downloads/cl-version-1-source-code
## Cthulhu ## Cthulhu
Uploaded to github by Oleg Cherkasky - https://github.com/gunrunners-paradise/Cthulhu-HLmod-SDK Uploaded to github by Oleg Cherkasky - https://github.com/gunrunners-paradise/Cthulhu-HLmod-SDK
## Deathmatch Classic ## Deathmatch Classic
Available in Valve's Half-Life repository - https://github.com/ValveSoftware/halflife/tree/master/dmc Available in Valve's Half-Life repository - https://github.com/ValveSoftware/halflife/tree/master/dmc
## Delta Particles
Available on ModDB - https://www.moddb.com/mods/half-life-delta/downloads/delta-particles-full-sources-maps-and-c-code
## Earth Special Forces ## Earth Special Forces
Alpha 2.0 - https://www.gamers-desire.de/details/2830 Alpha 2.0 - https://www.gamers-desire.de/details/2830
@@ -121,6 +127,11 @@ Mirrored on github - https://github.com/nekonomicon/HeartOfEvil
## Ingram Chillin' Mod ## Ingram Chillin' Mod
Official SourceForge repository - https://sourceforge.net/projects/icm-hl/ Official SourceForge repository - https://sourceforge.net/projects/icm-hl/
## Master Sword
Official github repository of Master Sword Classic - https://github.com/BerntA/MasterSwordClassic
Official github repository of Master Sword Rebirth - https://github.com/MSRevive/MasterSwordRebirth
## MechMod ## MechMod
Official github repository - https://github.com/vermagav/mechmod Official github repository - https://github.com/vermagav/mechmod
@@ -199,7 +210,7 @@ Branch **redempt** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tr
OpenAG by YaLTeR - https://github.com/YaLTeR/OpenAG OpenAG by YaLTeR - https://github.com/YaLTeR/OpenAG
## Afraid of Monsters ## Afraid of Monsters
malortie's recreation - https://github.com/malortie/hl-aom malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-aom
Branch **aom** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/aom Branch **aom** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/aom
@@ -207,17 +218,17 @@ Branch **aom** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/a
Reverse-engineered code: branch **aomdc** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/aomdc Reverse-engineered code: branch **aomdc** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/aomdc
## Azure Sheep ## Azure Sheep
malortie's recreation - https://github.com/malortie/hl-asheep malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-asheep
Reverse-engineered code: branch **asheep** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/asheep Reverse-engineered code: branch **asheep** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/asheep
## Big Lolly ## Big Lolly
malortie's recreation - https://github.com/malortie/hl-biglolly malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-biglolly
Branch **biglolly** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/biglolly Branch **biglolly** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/biglolly
## Black Ops ## Black Ops
malortie's recreation - https://github.com/malortie/hl-blackops malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-blackops
Branch **blackops** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/blackops Branch **blackops** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/blackops
@@ -246,7 +257,7 @@ Recreation by lostgamer aka nillerusr - https://github.com/LostGamerHL/crack_lif
Reverse-engineered code: branch **clcampaign** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/clcampaign Reverse-engineered code: branch **clcampaign** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/clcampaign
## Escape from the Darkness ## Escape from the Darkness
malortie's recreation - https://github.com/malortie/hl-eftd malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-eftd
Reverse-engineered code: branch **eftd** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/eftd Reverse-engineered code: branch **eftd** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/eftd
@@ -277,7 +288,7 @@ Reverse-engineered code: branch **rebellion** in hlsdk-portable - https://github
Branch **hl_urbicide** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/hl_urbicide Branch **hl_urbicide** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/hl_urbicide
## Half-Life: Visitors ## Half-Life: Visitors
malortie's recreation - https://github.com/malortie/hl-visitors malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-visitors
Reverse-engineered code: branch **visitors** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/visitors Reverse-engineered code: branch **visitors** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/visitors
@@ -285,17 +296,17 @@ Reverse-engineered code: branch **visitors** in hlsdk-portable - https://github.
Branch **half-secret** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/half-secret Branch **half-secret** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/half-secret
## Night at the Office ## Night at the Office
malortie's recreation - https://github.com/malortie/hl-nato malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-nato
Branch **noffice** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/noffice Branch **noffice** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/noffice
## Poke 646 ## Poke 646
malortie's recreation - https://github.com/malortie/hl-poke646 malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-poke646
Reverse-engineered code: branch **poke646** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/poke646 Reverse-engineered code: branch **poke646** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/poke646
## Poke 646: Vendetta ## Poke 646: Vendetta
malortie's recreation - https://github.com/malortie/hl-poke646-vendetta malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-poke646-vendetta
Reverse-engineered code: branch **poke646_vendetta** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/poke646_vendetta Reverse-engineered code: branch **poke646_vendetta** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/poke646_vendetta
@@ -312,19 +323,19 @@ Branch **sewer_beta** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable
Reverse-engineered code by Velaron - https://github.com/Velaron/tf15-client Reverse-engineered code by Velaron - https://github.com/Velaron/tf15-client
## The Gate ## The Gate
malortie's recreation - https://github.com/malortie/hl-thegate malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-thegate
Reverse-engineered code: branch **thegate** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/thegate Reverse-engineered code: branch **thegate** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/thegate
## They Hunger ## They Hunger
malortie's recreation - https://github.com/malortie/hl-theyhunger malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-theyhunger
Reverse-engineered code: branch **theyhunger** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/theyhunger Reverse-engineered code: branch **theyhunger** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/theyhunger
They Hunger: Tactical - https://www.moddb.com/mods/they-hunger-tactical/downloads/tht-source-code-documentation They Hunger: Tactical - https://www.moddb.com/mods/they-hunger-tactical/downloads/tht-source-code-documentation
## Times of Troubles ## Times of Troubles
malortie's recreation - https://github.com/malortie/hl-tot malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-tot
Branch **tot** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/tot Branch **tot** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/tot
@@ -346,7 +357,7 @@ Branch **dmc** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/d
Branch **echoes** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/echoes Branch **echoes** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/echoes
## Half-Life: Invasion ## Half-Life: Invasion
Port to HLSDK 2.4 by malortie - https://github.com/malortie/hl-invasion Port to HLSDK 2.4 by malortie - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-invasion
Port to Linux by fmoraw - https://github.com/fmoraw/hlinvasion Port to Linux by fmoraw - https://github.com/fmoraw/hlinvasion
@@ -365,7 +376,7 @@ Port to Linux - https://github.com/fmoraw/NS
Version 1.2: branch **sohl1.2** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/sohl1.2 Version 1.2: branch **sohl1.2** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/sohl1.2
## Swiss Cheese Halloween 2002 ## Swiss Cheese Halloween 2002
Just more playable version by malortie - https://github.com/malortie/hl-shall Just more playable version by malortie - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-shall
Branch **halloween** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/halloween Branch **halloween** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/halloween

View File

@@ -2,11 +2,14 @@
### Prerequisites ### Prerequisites
1. Make sure your PSVita is [set up to run homebrew applications](https://vita.hacks.guide/). 1. Make sure your PSVita is [set up to run homebrew applications](https://vita.hacks.guide/).
2. Install [kubridge](https://github.com/TheOfficialFloW/kubridge/releases/) by copying `kubridge.suprx` to your taiHEN plugins folder (usually `ux0:/tai`) and add it to your `config.txt`, for example: 2. Install [kubridge](https://github.com/TheOfficialFloW/kubridge/releases/). It is recommended to use kubridge version `0.1`, because other versions aren't tested, we don't know are they suitable or not.
Worth to notice, we got reports that automatic plugins management app EasyPlugin have issues with installing kubridge plugin, so it's better to install it manually: by copying `kubridge.suprx` to your taiHEN plugins folder (usually `ux0:/tai`, but could be `ur0:/tai`) and add it to your `config.txt`, for example:
``` ```
*KERNEL *KERNEL
ux0:tai/kubridge.skprx ux0:tai/kubridge.skprx
``` ```
3. Install `libshacccg.suprx` by following [this guide](https://cimmerian.gitbook.io/vita-troubleshooting-guide/shader-compiler/extract-libshacccg.suprx). 3. Install `libshacccg.suprx` by following [this guide](https://cimmerian.gitbook.io/vita-troubleshooting-guide/shader-compiler/extract-libshacccg.suprx).
### Installation ### Installation

View File

@@ -1,15 +0,0 @@
As online community is growing, we don't want to keep bad or invalid servers on the Internet Games list. It's a common rules for all Xash3D server owners who are using default master server.
1. Breaking master server or clients is prohibited in any way. If you found a serious bug, contact us at contact 'at' fwgs.ru or post an issue at GitHub.
2. Changing settings, exploiting vulnerabilities of clients is prohibited in any way. If you found a serious bug, contact us at contact 'at' fwgs.ru or post an issue at GitHub.
2. Agressive advertisement and spam on other servers is prohibited in any way.
3. If your server is require downloading custom content, it should be available for everyone. Recommended way to deliver custom content is FastDL.
4. It's recommended to keep your server is up-to-date. You may use our public Debian/Ubuntu/Arch Linux [repository](https://github.com/FWGS/xash3d/wiki/How-to-set-up-a-Xash3D-Dedicated-Server-on-Debian-or-Ubuntu) to simplify updating process.
Just follow these rules to not get banned on our master server. Good luck, have fun!

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,149 @@
# Touch controls configuring
## Introduction
Thanks to mittorn, we have the ability to fully customize the controls in Xash3D. The new config allows you to not only add and change control buttons, but also create custom menus. There is also a built-in visual editor available, which simplifies the customization process without the need for manual file editing.
## Editor mode usage
1. Launch Xash3D and start the game.
2. To enter the edit mode, click on the gear icon (command `touch_enableedit`).
3. In the edit mode, the grid is displayed. The number of cells can be changed with the command `touch_grid_count` (default is 50). The grid can be disabled with the command `touch_grid_enable 0`.
*Touch controls layout editor*
![](images/editor.jpg)
*Touch profiles window*
![](images/touch-profiles.jpg)
*Touch buttons parameters window*
![](images/touch-buttons.jpg)
## Layout editor features
* **Moving buttons**: click on a button, drag it to the desired location, and release.
* **Resizing buttons**: place your first finger on the top left corner of the button, and use your second finger to resize it.
* **Hiding/showing buttons**: select the button (it will turn red), then use the menu:
* **Close**: closes the editing mode (`touch_disableedit`).
* **Reset**: resets the button to its default values.
* **Hide/Show**: hides or shows the button (`touch_hide <name>` / `touch_show <name>`).
## Working with configuration files / console
All changes made in the visual editor are automatically saved to the touch profile file. The files are located in the `touch_profiles` folder inside game directory. The file name depends on the selected profile.
### Common commands in configuration files
```
// Comment: lines starting with // are ignored.
// Swipe zones for movement. Specify how far you need to swipe to speed up.
// The default values are set to be optimal for a small swipe to immediately walk quickly.
touch_forwardzone "0.060000" ; touch_sidezone "0.060000"
// Sensitivity settings (pitch - horizontal, yaw - vertical).
touch_pitch ; touch_yaw
// Grid settings (see above).
touch_grid_count ; touch_grid_enable
// Draws a border around the button.
touch_set_stroke <thickness> <c> <v> <e> <t>
(<r> - red; <g> - green; <b> - blue; <a> - alpha/transparency)
// Show (1) or hide (0) client buttons.
touch_setclientonly
// Removes all buttons from the screen.
touch_removeall
// Shows all available buttons in the configuration file.
touch_list
// Saves the config after editing. You can specify a new file name.
touch_config_file command.cfg
```
*The full list of buttons in the standard `touch.cfg` file, displayed in the console when using `touch_list`.*
![](images/example2.jpg)
## Adding new buttons
To add a new button, use the console command:
```
touch_addbutton "digits" "touch/key_1.png" "toggle_digits" 0.340000 0.782222 0.400000 0.888889 255 255 255 100 0
```
### Parameters of `touch_addbutton` command
| Parameter | Description |
| --- | --- |
| `"digits"` | Unique name of the button. |
| `"touch/key_1.png"` | Path to the icon file (`.png` format). If the icon is not needed, leave `""`. |
| `"toggle_digits"` | Command to execute after clicking (for example, `"buy"` for purchase). |
| `0.340000` | X coordinate of the upper-left corner of the button. |
| `0.782222` | Y coordinate of the upper-left corner of the button. |
| `0.400000` | X coordinate of the lower-right corner of the button. |
| `0.888889` | Y coordinate of the lower-right corner of the button. |
| `255 255 255` | Button color in RGB format. |
| `100` | Button transparency (0 - fully transparent, 255 - fully opaque). |
| `0` | Flags (see next section). |
## List of flags
Flags define the behavior of the button. Their values are powers of two:
| Flag | Value | Description |
| --- | --- | --- |
| `TOUCH_FL_HIDE` | 1 | Hides the button (not displayed in the game, but visible in the editor). |
| `TOUCH_FL_NOEDIT` | 2 | Disables editing of the button in the editor. |
| `TOUCH_FL_CLIENT` | 4 | The button is client-side (not saved in the main control file). |
| `TOUCH_FL_MP` | 8 | The button is displayed only in multiplayer. |
| `TOUCH_FL_SP` | 16 | The button is displayed only in singleplayer. |
| `TOUCH_FL_DEF_SHOW` | 32 | The button is always displayed on startup. |
| `TOUCH_FL_DEF_HIDE` | 64 | The button is always hidden on startup. |
| `TOUCH_FL_DRAW_ADDITIVE` | 128 | The button colors are added together in blend mode. |
| `TOUCH_FL_STROKE` | 256 | Enables outline stroke around the button. |
Flags can be combined by adding their values together. For example, `5 = 1 + 4` is the combination of `TOUCH_FL_HIDE` and `TOUCH_FL_CLIENT` flags, which is a hidden client button.
*In the image below, the `spray`, `scores`, `messagemode` buttons are displayed simultaneously with the flag 8 and `loadquick`, `savequick` with the flag 16, and each is displayed in the corresponding game mode.*
![](images/example1.jpg)
## Useful commands
* `touch_hide <pattern>`: hides buttons by pattern.
* `touch_setcommand`: changes the command bound to a button.
* `touch_settexture`: quickly changes the button image.
* `touch_setcolor`: sets the button color.
* `touch_exportconfig`: exports the current configuration, including aspect ratio.
## Usage examples
* `touch_hide menu*` hides all buttons with names starting with `menu`.
* `touch_setcolor "attack" 255 160 0 128` changes the color of the primary fire button from opaque white to translucent orange, similar to the color of the HUD in Half-Life.
*Result of executing this command*
![](images/example3.jpg)
* Example of adding a new button with a custom icon (the `lastinv` command is used - quick change between weapons)
![](images/example4.jpg)
*View of this button in layout editor*
![](images/example5.jpg)
## Tips
* To prevent the `look` and `move` buttons from interfering with editing other elements, place them before the others in the configuration file.
* And vice versa, to make a button appear on top of others, place it at the end of the configuration file.
* You can assign commands to buttons that change other buttons, see the previous section "Usage examples".
* After editing each parameter of each individual button in the Touch Buttons section, do not forget to press Save, otherwise the applied parameters will not be saved.
* To create your own icon for the button, you can use any graphics editor (for Android, Photo Editor by iudesk is suitable). Saving conditions:
* Image format - `.png` with transparency (e.g. alpha channel)
* Aspect ratio / size - 1:1 / 256x256
* Path to the icons location - `touch/gfx` inside game directory.
### Additional links
* [Handy palette for selecting color in RGB format](https://www.rapidtables.com/web/color/RGB_Color.html)

View File

@@ -1,6 +1,7 @@
# Xash3D FWGS Engine <img align="right" width="128" height="128" src="https://github.com/FWGS/xash3d-fwgs/raw/master/game_launch/icon-xash-material.png" alt="Xash3D FWGS icon" /> # Xash3D FWGS Engine <img align="right" width="128" height="128" src="https://github.com/FWGS/xash3d-fwgs/raw/master/game_launch/icon-xash-material.png" alt="Xash3D FWGS icon" />
[![builds.sr.ht status](https://builds.sr.ht/~a1batross/xash3d-fwgs.svg)](https://builds.sr.ht/~a1batross/xash3d-fwgs?) [![GitHub Actions Status](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml/badge.svg)](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml) [![FreeBSD Build Status](https://img.shields.io/cirrus/github/FWGS/xash3d-fwgs?label=freebsd%20build)](https://cirrus-ci.com/github/FWGS/xash3d-fwgs) [![Discord Server](https://img.shields.io/discord/355697768582610945.svg)](http://fwgsdiscord.mentality.rip/) \ [![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) \
[![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) [![Discord Server](https://img.shields.io/discord/355697768582610945?logo=Discord&label=International%20Discord%20chat)](http://fwgsdiscord.mentality.rip/) [![Russian speakers Telegram Chat](https://img.shields.io/badge/Russian_speakers_Telegram_chat-gray?logo=Telegram)](https://t.me/flyingwithgauss) \
[![Download Daily Build](https://img.shields.io/badge/downloads-testing-orange)](https://github.com/FWGS/xash3d-fwgs/releases/tag/continuous)
Xash3D ([pronounced](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 ([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.
@@ -35,6 +36,11 @@ You still needed to copy `valve` directory as all game resources located there.
For additional info, run Xash3D with `-help` command line key. For additional info, run Xash3D with `-help` command line key.
### Android
0) Install the APK file.
1) Copy `valve` directory to a folder named `xash` in the Internal storage.
2) Run games from within the app.
## Contributing ## Contributing
* Before sending an issue, check if someone already reported your issue. Make sure you're following "How To Ask Questions The Smart Way" guide by Eric Steven Raymond. Read more: http://www.catb.org/~esr/faqs/smart-questions.html. * Before sending an issue, check if someone already reported your issue. Make sure you're following "How To Ask Questions The Smart Way" guide by Eric Steven Raymond. Read more: http://www.catb.org/~esr/faqs/smart-questions.html.
* Issues are accepted in both English and Russian. * Issues are accepted in both English and Russian.
@@ -43,7 +49,7 @@ For additional info, run Xash3D with `-help` command line key.
## Build instructions ## Build instructions
We are using Waf build system. If you have some Waf-related questions, I recommend you to read [Waf Book](https://waf.io/book/). We are using Waf build system. If you have some Waf-related questions, I recommend you to read [Waf Book](https://waf.io/book/).
NOTE: NEVER USE GitHub's ZIP ARCHIVES. GitHub doesn't include external dependencies we're using! **NOTE: NEVER USE GitHub's ZIP ARCHIVES. GitHub doesn't include external dependencies we're using!**
### Prerequisites ### Prerequisites
If your CPU is x86 compatible and you're on Windows or Linux, we are building 32-bit code by default. This was done to maintain compatibility with Steam releases of Half-Life and based on it's engine games. If your CPU is x86 compatible and you're on Windows or Linux, we are building 32-bit code by default. This was done to maintain compatibility with Steam releases of Half-Life and based on it's engine games.
@@ -65,21 +71,30 @@ 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: * Only for 32-bit engine on 64-bit x86 operating system:
* Enable i386 on your system: `$ sudo dpkg --add-architecture i386`. * 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 `aptitude` ([why?](https://github.com/FWGS/xash3d-fwgs/issues/1828#issuecomment-2415131759)): `$ sudo apt update && sudo apt upgrade && sudo apt install aptitude`
* Install development tools: `$ sudo aptitude --without-recommends install git build-essential gcc-multilib g++-multilib libsdl2-dev:i386 libfontconfig-dev:i386 libfreetype-dev:i386 libopus-dev:i386 libbz2-dev:i386`. * Install development tools: `$ sudo aptitude --without-recommends install git build-essential gcc-multilib g++-multilib libsdl2-dev:i386 libfreetype-dev:i386 libopus-dev:i386 libbz2-dev:i386 libvorbis-dev:i386 libopusfile-dev:i386 libogg-dev:i386`.
* Set PKG_CONFIG_PATH environment variable to point at 32-bit libraries: `$ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig`. * 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: * For 64-bit engine on 64-bit x86 and other non-x86 systems:
* Install development tools: `$ sudo apt install git build-essential python libsdl2-dev libfontconfig-dev libfreetype6-dev libopus-dev libbz2-dev`. * Install development tools: `$ sudo apt install git build-essential python libsdl2-dev libfreetype6-dev libopus-dev libbz2-dev libvorbis-dev libopusfile-dev libogg-dev`.
* Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`. * Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`.
##### RedHat/Fedora ##### RedHat/Fedora
* Only for 32-bit engine on 64-bit x86 operating system: * Only for 32-bit engine on 64-bit x86 operating system:
* Install development tools: `$ sudo dnf install git gcc gcc-c++ glibc-devel.i686 SDL2-devel.i686 opus-devel.i686 fontconfig-devel.i686 freetype-devel.i686 bzip2-devel.i686`. * Install development tools: `$ sudo dnf install git gcc gcc-c++ glibc-devel.i686 SDL2-devel.i686 opus-devel.i686 freetype-devel.i686 bzip2-devel.i686 libvorbis-devel.i686 opusfile-devel.i686 libogg-devel.i686`.
* Set PKG_CONFIG_PATH environment variable to point at 32-bit libraries: `$ export PKG_CONFIG_PATH=/usr/lib/pkgconfig`. * 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: * For 64-bit engine on 64-bit x86 and other non-x86 systems:
* Install development tools: `$ sudo dnf install git gcc gcc-c++ SDL2-devel opus-devel fontconfig-devel freetype-devel bzip2-devel`. * Install development tools: `$ sudo dnf install git gcc gcc-c++ SDL2-devel opus-devel freetype-devel bzip2-devel libvorbis-devel opusfile-devel libogg-devel`.
* Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`.
#### Android (Windows/Linux/macOS)
* Install [Android Studio](https://developer.android.com/studio) (or the command line tools).
* Install [Python](https://python.org) (at least 2.7, latest is better).
* Install [Git](https://git-scm.com/download/win).
* Install [Ninja](https://ninja-build.org/).
* Install [CMake](https://cmake.org/) (for some dependencies).
* Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`. * Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`.
@@ -99,3 +114,6 @@ If compiling 32-bit on amd64, make sure `PKG_CONFIG_PATH` from the previous step
1) Configure build: `./waf configure` (you need to pass `-8` to compile 64-bit engine on 64-bit x86 processor). 1) Configure build: `./waf configure` (you need to pass `-8` to compile 64-bit engine on 64-bit x86 processor).
2) Compile: `./waf build`. 2) Compile: `./waf build`.
3) Install: `./waf install --destdir=/path/to/any/output/directory`. 3) Install: `./waf install --destdir=/path/to/any/output/directory`.
#### Android (Windows/Linux/macOS)
You can just open the `android` folder in Android Studio and build from here, or use `gradlew` to build from command line.

View File

@@ -1,60 +0,0 @@
cmake_minimum_required(VERSION 3.6)
# Only used to build Android project
project(XASH_ANDROID)
# armeabi-v7a requires cpufeatures library
include(AndroidNdkModules)
android_ndk_import_module_cpufeatures()
find_package(PythonInterp 2.7 REQUIRED)
get_filename_component(C_COMPILER_ID ${CMAKE_C_COMPILER} NAME_WE)
get_filename_component(CXX_COMPILER_ID ${CMAKE_CXX_COMPILER} NAME_WE)
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
set(BUILD_TYPE "debug")
else()
set(BUILD_TYPE "release")
list(APPEND WAF_EXTRA_ARGS --enable-poly-opt --enable-lto)
endif()
if(CMAKE_SIZEOF_VOID_P MATCHES "8")
set(64BIT ON CACHE BOOL "" FORCE)
list(APPEND WAF_EXTRA_ARGS -8) # only required for x86 when testing this cmakelist under linux
endif()
set(CMAKE_VERBOSE_MAKEFILE ON)
set(WAF_CC "${CMAKE_C_COMPILER} --target=${CMAKE_C_COMPILER_TARGET}")
set(WAF_CXX "${CMAKE_CXX_COMPILER} --target=${CMAKE_CXX_COMPILER_TARGET}")
# not cleanest way to get upper directory
set(ENGINE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../")
execute_process(
COMMAND ${CMAKE_COMMAND} -E env
CC=${WAF_CC} CXX=${WAF_CXX}
AR=${CMAKE_AR} STRIP=${CMAKE_STRIP}
${PYTHON_EXECUTABLE} waf configure -T ${BUILD_TYPE} ${WAF_EXTRA_ARGS} cmake
--check-c-compiler=${C_COMPILER_ID} --check-cxx-compiler=${CXX_COMPILER_ID}
-s "${ENGINE_SOURCE_DIR}/SDL" --skip-sdl2-sanity-check --enable-bundled-deps
WORKING_DIRECTORY "${ENGINE_SOURCE_DIR}"
)
add_subdirectory("${ENGINE_SOURCE_DIR}/3rdparty/hlsdk-portable" hlsdk-portable)
# try to build minimal SDL. Enable features as we're gonna use them
set(SDL_RENDER OFF)
set(SDL_POWER OFF)
set(SDL_VULKAN OFF)
set(SDL_DISKAUDIO OFF)
set(SDL_DUMMYAUDIO OFF)
set(SDL_DUMMYVIDEO OFF)
set(SDL_VULKAN OFF)
set(SDL_OFFSCREEN OFF)
set(SDL_STATIC OFF)
add_subdirectory("${ENGINE_SOURCE_DIR}/3rdparty/SDL" SDL)
add_subdirectory("${ENGINE_SOURCE_DIR}/" xash3d-fwgs)
add_subdirectory("${ENGINE_SOURCE_DIR}/3rdparty/mainui" mainui)

View File

@@ -1,129 +1,140 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.Month import java.time.Month
import java.time.temporal.ChronoUnit import java.time.temporal.ChronoUnit
plugins { plugins {
id("com.android.application") alias(libs.plugins.android.application)
id("org.jetbrains.kotlin.android") alias(libs.plugins.kotlin.android)
} }
android { android {
namespace = "su.xash.engine" namespace = "su.xash.engine"
ndkVersion = "27.2.12479018" ndkVersion = "28.2.13676358"
compileSdk = 35
defaultConfig { defaultConfig {
applicationId = "su.xash" applicationId = "su.xash.engine"
applicationIdSuffix = "engine" versionName = "0.21-" + getGitHash()
versionName = "0.21" versionCode = getBuildNum()
versionCode = getBuildNum() minSdk = 21
minSdk = 21 targetSdk = 35
targetSdk = 34
compileSdk = 34
externalNativeBuild { externalNativeBuild {
cmake { val engineRoot = projectDir.parentFile.parent
abiFilters("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
arguments("-DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF")
}
}
}
externalNativeBuild { experimentalProperties["ninja.abiFilters"] = setOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
cmake { experimentalProperties["ninja.path"] = File(engineRoot, "wscript").path
version = "3.22.1" experimentalProperties["ninja.configure"] = "run-python"
path = file("CMakeLists.txt") experimentalProperties["ninja.arguments"] = setOf(
} File(engineRoot, "scripts/configure-ninja.py").path,
} engineRoot,
"--variant=\${ndk.variantName}",
"--abi=\${ndk.abi}",
"--configuration-dir=\${ndk.buildRoot}",
"--ndk-version=\${ndk.moduleNdkVersion}",
"--min-sdk-version=\${ndk.minPlatform}",
"--ndk-root=${android.ndkDirectory}",
// shut up, fake options
"-p:Configuration=\${ndk.variantName}",
"-p:Platform=\${ndk.abi}"
)
}
}
compileOptions { compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_11
} }
kotlinOptions { kotlin {
jvmTarget = "1.8" compilerOptions {
} jvmTarget = JvmTarget.JVM_11
}
}
buildTypes { buildFeatures {
debug { viewBinding = true
isMinifyEnabled = false buildConfig = true
isShrinkResources = false }
isDebuggable = true
applicationIdSuffix = ".test"
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
)
}
release { lint {
isMinifyEnabled = true abortOnError = false
isShrinkResources = true }
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
)
}
register("asan") { /*
initWith(getByName("debug")) androidResources {
} noCompress += ""
}
*/
register("continuous") { packaging {
initWith(getByName("release")) jniLibs {
applicationIdSuffix = ".test" keepDebugSymbols.add("**/*.so")
} useLegacyPackaging = true
} }
}
sourceSets { sourceSets {
getByName("main") { getByName("main") {
assets.srcDirs("../../3rdparty/extras/xash-extras", "../moddb") assets.srcDirs("../../3rdparty/extras/xash-extras")
java.srcDir("../../3rdparty/SDL/android-project/app/src/main/java") java.srcDir("../../3rdparty/SDL/android-project/app/src/main/java")
} }
} }
lint { buildTypes {
abortOnError = false debug {
} isMinifyEnabled = false
isShrinkResources = false
isDebuggable = true
applicationIdSuffix = ".test"
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
)
}
buildFeatures { release {
viewBinding = true isMinifyEnabled = true
buildConfig = true isShrinkResources = true
} proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
)
}
androidResources { register("asan") {
noCompress += "" initWith(getByName("debug"))
} }
packaging { register("continuous") {
jniLibs { initWith(getByName("release"))
useLegacyPackaging = true applicationIdSuffix = ".test"
} }
} }
} }
dependencies { dependencies {
implementation("com.google.android.material:material:1.11.0") implementation(libs.material)
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.navigation:navigation-fragment-ktx:2.7.7")
implementation("androidx.navigation:navigation-ui-ktx:2.7.7")
implementation("androidx.cardview:cardview:1.0.0")
implementation("androidx.annotation:annotation:1.7.1")
implementation("androidx.fragment:fragment-ktx:1.6.2")
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("com.madgag.spongycastle:prov:1.58.0.0") implementation(libs.appcompat)
implementation("in.dragonbra:javasteam:1.2.0") implementation(libs.navigation.runtime.ktx)
implementation(libs.navigation.fragment.ktx)
implementation(libs.navigation.ui.ktx)
implementation(libs.preference.ktx)
implementation(libs.swiperefreshlayout)
implementation("ch.acra:acra-http:5.11.2") implementation(libs.acra.http)
} }
fun getBuildNum(): Int { fun getBuildNum(): Int {
val now = LocalDateTime.now() val now = LocalDateTime.now()
val releaseDate = LocalDateTime.of(2015, Month.APRIL, 1, 0, 0, 0) val releaseDate = LocalDateTime.of(2015, Month.APRIL, 1, 0, 0, 0)
val qBuildNum = releaseDate.until(now, ChronoUnit.DAYS) val qBuildNum = releaseDate.until(now, ChronoUnit.DAYS)
val minuteOfDay = now.hour * 60 + now.minute val minuteOfDay = now.hour * 60 + now.minute
return (qBuildNum * 10000 + minuteOfDay).toInt() return (qBuildNum * 10000 + minuteOfDay).toInt()
}
fun getGitHash(): String {
val process = ProcessBuilder("git", "rev-parse", "--short", "HEAD").directory(project.rootDir)
.redirectErrorStream(true).start()
return process.inputStream.bufferedReader().readText().trim()
} }

View File

@@ -1,3 +1,25 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-keep class su.xash.engine.XashActivity { -keep class su.xash.engine.XashActivity {
java.lang.String loadAndroidID(); java.lang.String loadAndroidID();
java.lang.String getAndroidID(); java.lang.String getAndroidID();
@@ -87,3 +109,8 @@
void hapticRun(int, float, int); void hapticRun(int, float, int);
void hapticStop(int); void hapticStop(int);
} }
# Unexpected reference to missing service class: META-INF/services/javax.annotation.processing.Processor.
-dontwarn javax.annotation.processing.Processor
-dontwarn javax.annotation.processing.AbstractProcessor
-dontwarn javax.annotation.processing.SupportedOptions

3
android/app/run-python Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
exec python $@

View File

@@ -0,0 +1 @@
python %*

View File

@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name" translatable="false">Xash3D FWGS (Test)</string> <string name="app_name" translatable="false">Xash3D FWGS (Test)</string>
<string name="authority" translatable="false">su.xash.engine.test.documents</string> </resources>
</resources>

View File

@@ -1,101 +1,89 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:allowAudioPlaybackCapture="true"
android:allowAudioPlaybackCapture="true" android:installLocation="preferExternal">
android:installLocation="preferExternal" <!-- OpenGL ES 1.1 -->
tools:targetApi="q"> <uses-feature android:glEsVersion="0x00010000" />
<!-- OpenGL ES 1.1 --> <!-- Touchscreen support -->
<uses-feature android:glEsVersion="0x00010000" /> <uses-feature
<!-- Touchscreen support --> android:name="android.hardware.touchscreen"
<uses-feature android:required="false" />
android:name="android.hardware.touchscreen" <!-- Game controller support -->
android:required="false" /> <uses-feature
<!-- Game controller support --> android:name="android.hardware.bluetooth"
<uses-feature android:required="false" />
android:name="android.hardware.bluetooth" <uses-feature
android:required="false" /> android:name="android.hardware.gamepad"
<uses-feature android:required="false" />
android:name="android.hardware.gamepad" <uses-feature
android:required="false" /> android:name="android.hardware.usb.host"
<uses-feature android:required="false" />
android:name="android.hardware.usb.host" <!-- External mouse input events -->
android:required="false" /> <uses-feature
<!-- External mouse input events --> android:name="android.hardware.type.pc"
<uses-feature android:required="false" />
android:name="android.hardware.type.pc" <!-- Audio recording support -->
android:required="false" /> <uses-feature
<!-- Audio recording support --> android:name="android.hardware.microphone"
<uses-feature android:required="false" />
android:name="android.hardware.microphone" <!-- Allow downloading to the external storage on Android 5.1 and older -->
android:required="false" /> <uses-permission
<!-- Allow downloading to the external storage on Android 5.1 and older --> android:name="android.permission.WRITE_EXTERNAL_STORAGE"
<uses-permission android:maxSdkVersion="22" />
android:name="android.permission.WRITE_EXTERNAL_STORAGE" <uses-permission
android:maxSdkVersion="22" /> android:name="android.permission.READ_EXTERNAL_STORAGE"
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
android:maxSdkVersion="32" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<!-- Allow access to Bluetooth devices --> <!-- Allow access to Bluetooth devices -->
<!-- Currently this is just for Steam Controller support and requires setting SDL_HINT_JOYSTICK_HIDAPI_STEAM --> <!-- Currently this is just for Steam Controller support and requires setting SDL_HINT_JOYSTICK_HIDAPI_STEAM -->
<uses-permission <uses-permission
android:name="android.permission.BLUETOOTH" android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" /> android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- Allow access to the vibrator --> <!-- Allow access to the vibrator -->
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<!-- Allow recording audio --> <!-- Allow recording audio -->
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- Allow internet access --> <!-- Allow internet access -->
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<!-- Dedicated server --> <!-- Dedicated server -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application <application
android:name=".MainApplication" android:name=".MainApplication"
android:allowBackup="true" android:allowBackup="true"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher"
android:theme="@style/Theme.App" android:theme="@style/Theme.App"
android:usesCleartextTraffic="true"> android:usesCleartextTraffic="true"
<activity android:requestLegacyExternalStorage="true">
android:name=".MainActivity" <activity
android:exported="true"> android:name=".MainActivity"
<intent-filter> android:exported="true">
<action android:name="android.intent.action.MAIN" /> <intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".XashActivity" android:name=".XashActivity"
android:alwaysRetainTaskState="true" android:alwaysRetainTaskState="true"
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation|touchscreen" android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation|touchscreen"
android:exported="true" android:exported="true"
android:launchMode="singleTask" android:launchMode="singleTask"
android:preferMinimalPostProcessing="true" android:preferMinimalPostProcessing="true"
android:windowSoftInputMode="adjustResize" android:windowSoftInputMode="adjustResize">
tools:targetApi="r"> <intent-filter>
<intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> </intent-filter>
</intent-filter> </activity>
</activity> </application>
<queries>
<provider <intent>
android:name=".XashDocumentsProvider" <action android:name="su.xash.engine.MOD" />
android:authorities="@string/authority" </intent>
android:exported="true" </queries>
android:grantUriPermissions="true" </manifest>
android:permission="android.permission.MANAGE_DOCUMENTS">
<intent-filter>
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
</intent-filter>
</provider>
</application>
<queries>
<intent>
<action android:name="su.xash.engine.MOD" />
</intent>
</queries>
</manifest>

View File

@@ -1,49 +0,0 @@
package su.xash.engine;
import android.app.Activity;
import android.graphics.Rect;
import android.view.View;
import android.widget.FrameLayout;
public class AndroidBug5497Workaround {
// For more information, see https://code.google.com/p/android/issues/detail?id=5497
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
public static void assistActivity(Activity activity) {
new AndroidBug5497Workaround(activity);
}
private View mChildOfContent;
private int usableHeightPrevious;
private FrameLayout.LayoutParams frameLayoutParams;
private AndroidBug5497Workaround(Activity activity) {
FrameLayout content = activity.findViewById(android.R.id.content);
mChildOfContent = content.getChildAt(0);
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(this::possiblyResizeChildOfContent);
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
}
private void possiblyResizeChildOfContent() {
int usableHeightNow = computeUsableHeight();
if (usableHeightNow != usableHeightPrevious) {
int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
if (heightDifference > (usableHeightSansKeyboard / 4)) {
// keyboard probably just became visible
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
} else {
// keyboard probably just became hidden
frameLayoutParams.height = usableHeightSansKeyboard;
}
mChildOfContent.requestLayout();
usableHeightPrevious = usableHeightNow;
}
}
private int computeUsableHeight() {
Rect r = new Rect();
mChildOfContent.getWindowVisibleDisplayFrame(r);
return (r.bottom - r.top);
}
}

View File

@@ -1,4 +1,3 @@
package su.xash.engine package su.xash.engine
class DedicatedActivity { class DedicatedActivity {}
}

View File

@@ -4,8 +4,8 @@ import android.app.Service
import android.content.Intent import android.content.Intent
import android.os.IBinder import android.os.IBinder
class DedicatedService: Service() { class DedicatedService : Service() {
override fun onBind(intent: Intent?): IBinder? { override fun onBind(intent: Intent?): IBinder? {
TODO("Not yet implemented") TODO("Not yet implemented")
} }
} }

View File

@@ -10,26 +10,26 @@ import androidx.navigation.ui.setupActionBarWithNavController
import su.xash.engine.databinding.ActivityMainBinding import su.xash.engine.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding private lateinit var binding: ActivityMainBinding
private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var navController: NavController private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater) binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
setSupportActionBar(binding.toolbar) setSupportActionBar(binding.toolbar)
val navHostFragment = val navHostFragment =
supportFragmentManager.findFragmentById(R.id.fragmentContainerView) as NavHostFragment supportFragmentManager.findFragmentById(R.id.fragmentContainerView) as NavHostFragment
navController = navHostFragment.navController navController = navHostFragment.navController
appBarConfiguration = AppBarConfiguration(navController.graph) appBarConfiguration = AppBarConfiguration(navController.graph)
setupActionBarWithNavController(navController, appBarConfiguration) setupActionBarWithNavController(navController, appBarConfiguration)
} }
override fun onSupportNavigateUp(): Boolean { override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
} }
} }

View File

@@ -3,26 +3,25 @@ package su.xash.engine
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
import android.os.StrictMode import android.os.StrictMode
import org.acra.config.httpSender
import org.acra.data.StringFormat import org.acra.data.StringFormat
import org.acra.ktx.initAcra import org.acra.ktx.initAcra
class MainApplication : Application() { class MainApplication : Application() {
override fun attachBaseContext(base: Context?) { override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base) super.attachBaseContext(base)
if (!BuildConfig.DEBUG) { if (!BuildConfig.DEBUG) {
initAcra { initAcra {
buildConfigClass = BuildConfig::class.java buildConfigClass = BuildConfig::class.java
reportFormat = StringFormat.JSON reportFormat = StringFormat.JSON
httpSender { // httpSender {
uri = "http://bodis.pp.ua:5000/report" // uri = "http://bodis.pp.ua:5000/report"
} // }
} }
} else { } else {
// enable strict mode to detect memory leaks etc. // enable strict mode to detect memory leaks etc.
StrictMode.enableDefaults(); StrictMode.enableDefaults();
} }
} }
} }

View File

@@ -5,6 +5,7 @@ import android.content.pm.ActivityInfo;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings.Secure; import android.provider.Settings.Secure;
import android.util.Log; import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
@@ -12,137 +13,142 @@ import android.view.WindowManager;
import org.libsdl.app.SDLActivity; import org.libsdl.app.SDLActivity;
import su.xash.engine.util.AndroidBug5497Workaround;
public class XashActivity extends SDLActivity { public class XashActivity extends SDLActivity {
private boolean mUseVolumeKeys; private boolean mUseVolumeKeys;
private String mPackageName; private String mPackageName;
private static final String TAG = "XashActivity"; private static final String TAG = "XashActivity";
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
//getWindow().addFlags(WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES); //getWindow().addFlags(WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES);
getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
} }
AndroidBug5497Workaround.assistActivity(this); AndroidBug5497Workaround.assistActivity(this);
} }
@Override @Override
public void onDestroy() public void onDestroy() {
{ super.onDestroy();
super.onDestroy();
// Now that we don't exit from native code, we need to exit here, resetting // 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) // 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 // When the issue with global variables will be resolved, remove that exit() call
System.exit(0); System.exit(0);
} }
@Override @Override
protected String[] getLibraries() { protected String[] getLibraries() {
return new String[]{"SDL2", "xash"}; return new String[]{"SDL2", "xash"};
} }
@SuppressLint("HardwareIds") @SuppressLint("HardwareIds")
private String getAndroidID() { private String getAndroidID() {
return Secure.getString(getContentResolver(), Secure.ANDROID_ID); return Secure.getString(getContentResolver(), Secure.ANDROID_ID);
} }
@SuppressLint("ApplySharedPref") @SuppressLint("ApplySharedPref")
private void saveAndroidID(String id) { private void saveAndroidID(String id) {
getSharedPreferences("xash_preferences", MODE_PRIVATE).edit().putString("xash_id", id).commit(); getSharedPreferences("xash_preferences", MODE_PRIVATE).edit().putString("xash_id", id).commit();
} }
private String loadAndroidID() { private String loadAndroidID() {
return getSharedPreferences("xash_preferences", MODE_PRIVATE).getString("xash_id", ""); return getSharedPreferences("xash_preferences", MODE_PRIVATE).getString("xash_id", "");
} }
@Override @Override
public String getCallingPackage() { public String getCallingPackage() {
if (mPackageName != null) { if (mPackageName != null) {
return mPackageName; return mPackageName;
} }
return super.getCallingPackage(); return super.getCallingPackage();
} }
private AssetManager getAssets(boolean isEngine) { private AssetManager getAssets(boolean isEngine) {
AssetManager am = null; AssetManager am = null;
if (isEngine) { if (isEngine) {
am = getAssets(); am = getAssets();
} else { } else {
try { try {
am = getPackageManager().getResourcesForApplication(getCallingPackage()).getAssets(); am = getPackageManager().getResourcesForApplication(getCallingPackage()).getAssets();
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Unable to load mod assets!"); Log.e(TAG, "Unable to load mod assets!");
e.printStackTrace(); e.printStackTrace();
} }
} }
return am; return am;
} }
private String[] getAssetsList(boolean isEngine, String path) { private String[] getAssetsList(boolean isEngine, String path) {
AssetManager am = getAssets(isEngine); AssetManager am = getAssets(isEngine);
try { try {
return am.list(path); return am.list(path);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
return new String[]{}; return new String[]{};
} }
@Override @Override
public boolean dispatchKeyEvent(KeyEvent event) { public boolean dispatchKeyEvent(KeyEvent event) {
if (SDLActivity.mBrokenLibraries) { if (SDLActivity.mBrokenLibraries) {
return false; return false;
} }
int keyCode = event.getKeyCode(); int keyCode = event.getKeyCode();
if (!mUseVolumeKeys) { if (!mUseVolumeKeys) {
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_CAMERA || keyCode == KeyEvent.KEYCODE_ZOOM_IN || keyCode == KeyEvent.KEYCODE_ZOOM_OUT) {
keyCode == KeyEvent.KEYCODE_VOLUME_UP || return false;
keyCode == KeyEvent.KEYCODE_CAMERA || }
keyCode == KeyEvent.KEYCODE_ZOOM_IN || }
keyCode == KeyEvent.KEYCODE_ZOOM_OUT) {
return false;
}
}
return getWindow().superDispatchKeyEvent(event); return getWindow().superDispatchKeyEvent(event);
} }
// TODO: REMOVE LATER, temporary launchers support? // TODO: REMOVE LATER, temporary launchers support?
@Override @Override
protected String[] getArguments() { protected String[] getArguments() {
String gamedir = getIntent().getStringExtra("gamedir"); String gamedir = getIntent().getStringExtra("gamedir");
if (gamedir == null) gamedir = "valve"; if (gamedir == null) gamedir = "valve";
nativeSetenv("XASH3D_GAME", gamedir); nativeSetenv("XASH3D_GAME", gamedir);
String gamelibdir = getIntent().getStringExtra("gamelibdir"); String gamelibdir = getIntent().getStringExtra("gamelibdir");
if (gamelibdir != null) nativeSetenv("XASH3D_GAMELIBDIR", gamelibdir); if (gamelibdir != null) nativeSetenv("XASH3D_GAMELIBDIR", gamelibdir);
String pakfile = getIntent().getStringExtra("pakfile"); String pakfile = getIntent().getStringExtra("pakfile");
if (pakfile != null) nativeSetenv("XASH3D_EXTRAS_PAK2", pakfile); if (pakfile != null) nativeSetenv("XASH3D_EXTRAS_PAK2", pakfile);
mUseVolumeKeys = getIntent().getBooleanExtra("usevolume", false); String basedir = getIntent().getStringExtra("basedir");
mPackageName = getIntent().getStringExtra("package"); if (basedir != null) {
nativeSetenv("XASH3D_BASEDIR", basedir);
} else {
String rootPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/xash";
nativeSetenv("XASH3D_BASEDIR", rootPath);
}
String[] env = getIntent().getStringArrayExtra("env"); mUseVolumeKeys = getIntent().getBooleanExtra("usevolume", false);
if (env != null) { mPackageName = getIntent().getStringExtra("package");
for (int i = 0; i < env.length; i += 2)
nativeSetenv(env[i], env[i + 1]);
}
String argv = getIntent().getStringExtra("argv"); String[] env = getIntent().getStringArrayExtra("env");
if (argv == null) argv = "-console -log"; if (env != null) {
return argv.split(" "); for (int i = 0; i < env.length; i += 2)
} nativeSetenv(env[i], env[i + 1]);
}
String argv = getIntent().getStringExtra("argv");
if (argv == null) argv = "-console -log";
return argv.split(" ");
}
} }

View File

@@ -1,253 +0,0 @@
package su.xash.engine;
import android.annotation.TargetApi;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.graphics.Point;
import android.os.Build;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
import android.provider.DocumentsProvider;
import android.webkit.MimeTypeMap;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@TargetApi(Build.VERSION_CODES.KITKAT)
public class XashDocumentsProvider extends DocumentsProvider {
private static final String ALL_MIME_TYPES = "*/*";
private File mRootDir;
private static final String TAG = "XashDocumentsProvider";
@Override
public boolean onCreate() {
mRootDir = getContext().getExternalFilesDir(null);
return true;
}
private static final String[] DEFAULT_ROOT_PROJECTION = new String[]{Root.COLUMN_ROOT_ID,
Root.COLUMN_MIME_TYPES,
Root.COLUMN_FLAGS,
Root.COLUMN_ICON,
Root.COLUMN_TITLE,
Root.COLUMN_SUMMARY,
Root.COLUMN_DOCUMENT_ID,
Root.COLUMN_AVAILABLE_BYTES};
private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[]{Document.COLUMN_DOCUMENT_ID,
Document.COLUMN_MIME_TYPE,
Document.COLUMN_DISPLAY_NAME,
Document.COLUMN_LAST_MODIFIED,
Document.COLUMN_FLAGS,
Document.COLUMN_SIZE};
@Override
public Cursor queryRoots(String[] projection) {
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_ROOT_PROJECTION);
final String appName = getContext().getString(R.string.app_name);
final String docId = getDocIdForFile(mRootDir);
int flags;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_SEARCH;
} else {
flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD;
}
final MatrixCursor.RowBuilder row = result.newRow();
row.add(Root.COLUMN_ROOT_ID, docId);
row.add(Root.COLUMN_DOCUMENT_ID, docId);
row.add(Root.COLUMN_SUMMARY, null);
row.add(Root.COLUMN_FLAGS, flags);
row.add(Root.COLUMN_TITLE, appName);
row.add(Root.COLUMN_MIME_TYPES, ALL_MIME_TYPES);
row.add(Root.COLUMN_AVAILABLE_BYTES, mRootDir.getFreeSpace());
row.add(Root.COLUMN_ICON, R.mipmap.ic_launcher);
return result;
}
@Override
public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException {
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
includeFile(result, documentId, null);
return result;
}
@Override
public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException {
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
final File parent = getFileForDocId(parentDocumentId);
final File[] filesList = parent.listFiles();
if (filesList != null) {
for (File file : filesList) {
includeFile(result, null, file);
}
}
return result;
}
@Override
public ParcelFileDescriptor openDocument(final String documentId, String mode, CancellationSignal signal) throws FileNotFoundException {
final File file = getFileForDocId(documentId);
final int accessMode = ParcelFileDescriptor.parseMode(mode);
return ParcelFileDescriptor.open(file, accessMode);
}
@Override
public AssetFileDescriptor openDocumentThumbnail(String documentId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException {
final File file = getFileForDocId(documentId);
final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
return new AssetFileDescriptor(pfd, 0, file.length());
}
@Override
public String createDocument(String parentDocumentId, String mimeType, String displayName) throws FileNotFoundException {
File newFile = new File(parentDocumentId, displayName);
int noConflictId = 1;
while (newFile.exists()) {
newFile = new File(parentDocumentId, displayName + " (" + noConflictId++ + ")");
}
try {
boolean succeeded;
if (Document.MIME_TYPE_DIR.equals(mimeType)) {
succeeded = newFile.mkdir();
} else {
succeeded = newFile.createNewFile();
}
if (!succeeded) {
throw new FileNotFoundException("Failed to create document with id " + newFile.getPath());
}
} catch (IOException e) {
throw new FileNotFoundException("Failed to create document with id " + newFile.getPath());
}
return newFile.getPath();
}
@Override
public void deleteDocument(String documentId) throws FileNotFoundException {
File file = getFileForDocId(documentId);
if (file.isDirectory()) {
if (!deleteDirectory(file)) {
throw new FileNotFoundException("Failed to delete document with id " + documentId);
}
} else if (!file.delete()) {
throw new FileNotFoundException("Failed to delete document with id " + documentId);
}
}
@Override
public String getDocumentType(String documentId) throws FileNotFoundException {
File file = getFileForDocId(documentId);
return getMimeType(file);
}
@Override
public boolean isChildDocument(String parentDocumentId, String documentId) {
return documentId.startsWith(parentDocumentId);
}
private static File getFileForDocId(String docId) throws FileNotFoundException {
final File f = new File(docId);
if (!f.exists()) throw new FileNotFoundException(f.getAbsolutePath() + " not found");
return f;
}
private static String getDocIdForFile(File file) {
return file.getAbsolutePath();
}
private static String getMimeType(File file) {
if (file.isDirectory()) {
return Document.MIME_TYPE_DIR;
} else {
final String name = file.getName();
final int lastDot = name.lastIndexOf('.');
if (lastDot >= 0) {
final String extension = name.substring(lastDot + 1).toLowerCase();
final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
if (mime != null) return mime;
}
return "application/octet-stream";
}
}
private static boolean deleteDirectory(File dir) {
final File[] allContents = dir.listFiles();
if (allContents != null) {
for (File file : allContents) {
deleteDirectory(file);
}
}
return dir.delete();
}
private void includeFile(MatrixCursor result, String docId, File file) throws FileNotFoundException {
if (docId == null) {
docId = getDocIdForFile(file);
} else {
file = getFileForDocId(docId);
}
int flags = 0;
if (file.isDirectory()) {
if (file.canWrite()) {
flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
}
} else if (file.canWrite()) {
flags |= Document.FLAG_SUPPORTS_WRITE;
}
File parentFile = file.getParentFile();
if (parentFile != null && parentFile.canWrite()) {
flags |= Document.FLAG_SUPPORTS_DELETE;
}
final String displayName = file.getName();
final String mimeType = getMimeType(file);
if (mimeType.startsWith("image/")) {
flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
}
final MatrixCursor.RowBuilder row = result.newRow();
row.add(Document.COLUMN_DOCUMENT_ID, docId);
row.add(Document.COLUMN_DISPLAY_NAME, displayName);
row.add(Document.COLUMN_SIZE, file.length());
row.add(Document.COLUMN_MIME_TYPE, mimeType);
row.add(Document.COLUMN_LAST_MODIFIED, file.lastModified());
row.add(Document.COLUMN_FLAGS, flags);
row.add(Document.COLUMN_ICON, R.mipmap.ic_launcher);
}
}

View File

@@ -14,64 +14,57 @@ import su.xash.engine.ui.library.LibraryViewModel
class GameAdapter(private val libraryViewModel: LibraryViewModel) : class GameAdapter(private val libraryViewModel: LibraryViewModel) :
ListAdapter<Game, GameAdapter.GameViewHolder>(DiffCallback()) { ListAdapter<Game, GameAdapter.GameViewHolder>(DiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameAdapter.GameViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameAdapter.GameViewHolder {
val binding = CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false) val binding = CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return GameViewHolder(binding) return GameViewHolder(binding)
} }
override fun onBindViewHolder(holder: GameAdapter.GameViewHolder, position: Int) { override fun onBindViewHolder(holder: GameAdapter.GameViewHolder, position: Int) {
return holder.bind(getItem(position)) return holder.bind(getItem(position))
} }
private class DiffCallback : DiffUtil.ItemCallback<Game>() { private class DiffCallback : DiffUtil.ItemCallback<Game>() {
override fun areItemsTheSame(oldItem: Game, newItem: Game): Boolean { override fun areItemsTheSame(oldItem: Game, newItem: Game): Boolean {
return oldItem.basedir.name == newItem.basedir.name return oldItem.basedir.name == newItem.basedir.name
} }
override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean { override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean {
return oldItem.basedir.name == newItem.basedir.name && oldItem.installed == newItem.installed return oldItem.basedir.name == newItem.basedir.name
} }
} }
inner class GameViewHolder(val binding: CardGameBinding) : inner class GameViewHolder(val binding: CardGameBinding) :
RecyclerView.ViewHolder(binding.root) { RecyclerView.ViewHolder(binding.root) {
fun bind(game: Game) { fun bind(game: Game) {
binding.apply { binding.apply {
gameTitle.text = game.title gameTitle.text = game.title
if (game.icon != null) { if (game.icon != null) {
gameIcon.setImageBitmap(game.icon) gameIcon.setImageBitmap(game.icon)
} else { } else {
gameIcon.visibility = View.GONE gameIcon.visibility = View.GONE
} }
if (game.cover != null) { if (game.cover != null) {
gameCover.setImageBitmap(game.cover) gameCover.setImageBitmap(game.cover)
} else { } else {
gameCover.visibility = View.GONE gameCover.visibility = View.GONE
} }
if (!game.installed) { settingsButton.setOnClickListener {
launchButton.visibility = View.GONE libraryViewModel.setSelectedGame(game)
settingsButton.visibility = View.GONE it.findNavController()
progressIndicator.visibility = View.VISIBLE .navigate(R.id.action_libraryFragment_to_gameSettingsFragment)
return }
}
settingsButton.setOnClickListener { root.setOnClickListener { libraryViewModel.startEngine(it.context, game) }
libraryViewModel.setSelectedGame(game) launchButton.setOnClickListener {
it.findNavController() libraryViewModel.startEngine(it.context, game)
.navigate(R.id.action_libraryFragment_to_gameSettingsFragment) }
} }
}
root.setOnClickListener { libraryViewModel.startEngine(it.context, game) } }
launchButton.setOnClickListener { }
libraryViewModel.startEngine(it.context, game)
}
}
}
}
}

View File

@@ -1,89 +1,90 @@
package su.xash.engine.model package su.xash.engine.model
import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Canvas import android.graphics.Canvas
import androidx.documentfile.provider.DocumentFile
import su.xash.engine.util.TGAReader import su.xash.engine.util.TGAReader
import java.io.File
import java.io.FileInputStream
import java.util.Scanner import java.util.Scanner
object BackgroundBitmap { object BackgroundBitmap {
private const val BACKGROUND_ROWS = 3 private const val BACKGROUND_ROWS = 3
private const val BACKGROUND_COLUMNS = 4 private const val BACKGROUND_COLUMNS = 4
private const val BACKGROUND_WIDTH = 800 private const val BACKGROUND_WIDTH = 800
private const val BACKGROUND_HEIGHT = 600 private const val BACKGROUND_HEIGHT = 600
fun createBackground(ctx: Context, file: DocumentFile): Bitmap { fun createBackground(file: File): Bitmap {
var bitmap = var bitmap =
Bitmap.createBitmap(BACKGROUND_WIDTH, BACKGROUND_HEIGHT, Bitmap.Config.ARGB_8888) Bitmap.createBitmap(BACKGROUND_WIDTH, BACKGROUND_HEIGHT, Bitmap.Config.ARGB_8888)
var canvas = Canvas(bitmap) var canvas = Canvas(bitmap)
var x: Int var x: Int
var y = 0 var y = 0
var width: Int var width: Int
var height = 0 var height = 0
var bgLayout = file.findFile("resource")?.findFile("HD_BackgroundLayout.txt") val resourceFolder = File(file, "resource")
if (bgLayout == null) { var bgLayout = File(resourceFolder, "HD_BackgroundLayout.txt")
bgLayout = file.findFile("resource")?.findFile("BackgroundLayout.txt") if (!bgLayout.exists()) {
} bgLayout = File(resourceFolder, "BackgroundLayout.txt")
}
if (bgLayout == null) { if (!bgLayout.exists()) {
val dir = file.findFile("resource")?.findFile("background") val dir = File(resourceFolder, "background")
for (i in 0 until BACKGROUND_ROWS) { for (i in 0 until BACKGROUND_ROWS) {
x = 0 x = 0
for (j in 0 until BACKGROUND_COLUMNS) { for (j in 0 until BACKGROUND_COLUMNS) {
val filename = "${BACKGROUND_WIDTH}_${i + 1}_${'a' + j}_loading.tga" val filename = "${BACKGROUND_WIDTH}_${i + 1}_${'a' + j}_loading.tga"
val bmpFile = dir?.findFile(filename) val bmpFile = File(dir, filename)
val bmpImage = loadTga(ctx, bmpFile!!) val bmpImage = loadTga(bmpFile)
canvas.drawBitmap(bmpImage, x.toFloat(), y.toFloat(), null) canvas.drawBitmap(bmpImage, x.toFloat(), y.toFloat(), null)
x += bmpImage.width x += bmpImage.width
height = bmpImage.height height = bmpImage.height
} }
y += height y += height
} }
return bitmap return bitmap
} }
ctx.contentResolver.openInputStream(bgLayout.uri).use { inputStream -> FileInputStream(bgLayout).use { inputStream ->
Scanner(inputStream).use { scanner -> Scanner(inputStream).use { scanner ->
while (scanner.hasNext()) { while (scanner.hasNext()) {
when (val str = scanner.next()) { when (val str = scanner.next()) {
"resolution" -> { "resolution" -> {
width = scanner.nextInt() width = scanner.nextInt()
height = scanner.nextInt() height = scanner.nextInt()
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
canvas = Canvas(bitmap) canvas = Canvas(bitmap)
} }
else -> { else -> {
var bmpFile = file var bmpFile = file
str.split("/").forEach { bmpFile = bmpFile.findFile(it)!! } str.split("/").forEach { bmpFile = File(bmpFile, it) }
//skip //skip
scanner.next() scanner.next()
x = scanner.nextInt() x = scanner.nextInt()
y = scanner.nextInt() y = scanner.nextInt()
val bmp = loadTga(ctx, bmpFile) val bmp = loadTga(bmpFile)
canvas.drawBitmap(bmp, x.toFloat(), y.toFloat(), null) canvas.drawBitmap(bmp, x.toFloat(), y.toFloat(), null)
} }
} }
} }
} }
} }
return bitmap return bitmap
} }
private fun loadTga(ctx: Context, file: DocumentFile): Bitmap { private fun loadTga(file: File): Bitmap {
ctx.contentResolver.openInputStream(file.uri).use { FileInputStream(file).use {
val buffer = it?.readBytes() val buffer = it.readBytes()
val pixels = TGAReader.read(buffer, TGAReader.ARGB) val pixels = TGAReader.read(buffer, TGAReader.ARGB)
val width = TGAReader.getWidth(buffer) val width = TGAReader.getWidth(buffer)
val height = TGAReader.getHeight(buffer) val height = TGAReader.getHeight(buffer)
return Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_8888) return Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_8888)
} }
} }
} }

View File

@@ -5,118 +5,123 @@ import android.content.Intent
import android.content.pm.PackageInfo import android.content.pm.PackageInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import android.provider.MediaStore
import androidx.documentfile.provider.DocumentFile
import su.xash.engine.XashActivity import su.xash.engine.XashActivity
import java.io.File
import java.io.FileInputStream
class Game(val ctx: Context, val basedir: DocumentFile, var installed: Boolean = true) { class Game(val ctx: Context, val basedir: File) {
private var iconName = "game.ico" private var iconName = "game.ico"
var title = "Unknown Game" var title = "Unknown Game"
var icon: Bitmap? = null var icon: Bitmap? = null
var cover: Bitmap? = null var cover: Bitmap? = null
private val pref = ctx.getSharedPreferences(basedir.name, Context.MODE_PRIVATE) private val pref = ctx.getSharedPreferences(basedir.name, Context.MODE_PRIVATE)
init { init {
basedir.findFile("gameinfo.txt")?.let { val gameInfo = File(basedir, "gameinfo.txt")
parseGameInfo(it) if (gameInfo.exists()) {
} ?: basedir.findFile("liblist.gam")?.let { parseGameInfo(it) } parseGameInfo(gameInfo)
} else {
val libListGam = File(basedir, "liblist.gam")
if (libListGam.exists()) parseGameInfo(libListGam)
}
basedir.findFile(iconName) val iconFile = File(basedir, iconName)
?.let { icon = MediaStore.Images.Media.getBitmap(ctx.contentResolver, it.uri) } if (iconFile.exists()) {
icon = BitmapFactory.decodeFile(iconFile.path)
}
try { try {
cover = BackgroundBitmap.createBackground(ctx, basedir) cover = BackgroundBitmap.createBackground(basedir)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
} }
fun startEngine(ctx: Context) { fun startEngine(ctx: Context) {
ctx.startActivity(Intent(ctx, XashActivity::class.java).apply { ctx.startActivity(Intent(ctx, XashActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
putExtra("gamedir", basedir.name) putExtra("gamedir", basedir.name)
putExtra("argv", pref.getString("arguments", "-console -log")) putExtra("argv", pref.getString("arguments", "-console -log"))
putExtra("usevolume", pref.getBoolean("use_volume_buttons", false)) putExtra("usevolume", pref.getBoolean("use_volume_buttons", false))
//.putExtra("gamelibdir", getGameLibDir(context)) putExtra("basedir", basedir.parent)
//.putExtra("package", getPackageName()) } //.putExtra("gamelibdir", getGameLibDir(context))
}) //.putExtra("package", getPackageName()) }
} })
}
private fun parseGameInfo(file: DocumentFile) { private fun parseGameInfo(file: File) {
ctx.contentResolver.openInputStream(file.uri).use { inputStream -> FileInputStream(file).use { inputStream ->
inputStream?.bufferedReader().use { reader -> inputStream.bufferedReader().use { reader ->
reader?.forEachLine { reader.forEachLine {
val tokens = it.split("\\s+".toRegex(), limit = 2) val tokens = it.split("\\s+".toRegex(), limit = 2)
if (tokens.size >= 2) { if (tokens.size >= 2) {
val k = tokens[0] val k = tokens[0]
val v = tokens[1].trim('"') val v = tokens[1].trim('"')
if (k == "title" || k == "game") title = v if (k == "title" || k == "game") title = v
if (k == "icon") iconName = v if (k == "icon") iconName = v
} }
} }
} }
} }
} }
private fun getPackageName(): String? { private fun getPackageName(): String? {
// return if (mDbEntry != null) { // return if (mDbEntry != null) {
// mDbEntry.getPackageName() // mDbEntry.getPackageName()
// } else null // } else null
return null return null
} }
private fun getGameLibDir(ctx: Context): String? { private fun getGameLibDir(ctx: Context): String? {
val pkgName = getPackageName() val pkgName = getPackageName()
if (pkgName != null) { if (pkgName != null) {
val pkgInfo: PackageInfo = try { val pkgInfo: PackageInfo = try {
ctx.packageManager.getPackageInfo(pkgName, 0) ctx.packageManager.getPackageInfo(pkgName, 0)
} catch (e: PackageManager.NameNotFoundException) { } catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace() e.printStackTrace()
ctx.startActivity( ctx.startActivity(
Intent( Intent(
Intent.ACTION_VIEW, Uri.parse("market://details?id=$pkgName") Intent.ACTION_VIEW, Uri.parse("market://details?id=$pkgName")
).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) ).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
) )
return null return null
} }
return pkgInfo.applicationInfo.nativeLibraryDir return pkgInfo.applicationInfo?.nativeLibraryDir
} }
return ctx.applicationInfo.nativeLibraryDir return ctx.applicationInfo.nativeLibraryDir
} }
companion object { companion object {
fun getGames(ctx: Context, file: DocumentFile): List<Game> { fun getGames(ctx: Context, file: File): List<Game> {
val games = mutableListOf<Game>() val games = mutableListOf<Game>()
if (checkIfGamedir(file)) { if (checkIfGamedir(file)) {
games.add(Game(ctx, file)) games.add(Game(ctx, file))
} else { } else {
file.listFiles().forEach { file.listFiles()?.forEach {
if (it.isDirectory) { if (it.isDirectory) {
if (checkIfGamedir(it)) { if (checkIfGamedir(it)) {
games.add(Game(ctx, it)) games.add(Game(ctx, it))
} }
} }
} }
} }
return games return games
} }
fun checkIfGamedir(file: DocumentFile): Boolean { fun checkIfGamedir(file: File): Boolean {
// exclude unfinished downloads if (File(file, "liblist.gam").exists()) return true
if (file.name?.startsWith('.') == true) if (File(file, "gameinfo.txt").exists()) return true
return false
file.findFile("liblist.gam")?.let { return true } return false
file.findFile("gameinfo.txt")?.let { return true } }
return false }
}
}
} }
// Intent intent = new Intent("su.xash.engine.MOD"); // Intent intent = new Intent("su.xash.engine.MOD");

View File

@@ -1,59 +0,0 @@
package su.xash.engine.model
import org.json.JSONArray
import org.json.JSONObject
import java.io.InputStream
class ModDatabase(inputStream: InputStream) {
val entries = mutableListOf<Entry>()
companion object {
const val VERSION = 1
fun getFilename(): String {
return "v${VERSION}.json"
}
}
init {
inputStream.bufferedReader().use {
val jsonArray = JSONArray(it.readText())
for (i in 0..<jsonArray.length()) {
entries.add(Entry(jsonArray.getJSONObject(i)))
}
}
}
fun getByGameDir(gamedir: String): Entry? {
return entries.filter { it.gamedir.equals(gamedir) }.firstOrNull()
}
inner class Entry(jsonObject: JSONObject) {
var name: String? = null
var appid: Int? = null
var gamedir: String? = null
// TODO Depots
var pkgname: String? = null
init {
if (jsonObject.has("name")) {
name = jsonObject.getString("name");
}
if (jsonObject.has("app_id")) {
appid = jsonObject.getInt("app_id");
}
if (jsonObject.has("gamedir")) {
gamedir = jsonObject.getString("gamedir");
}
if (jsonObject.has("package_name")) {
pkgname = jsonObject.getString("package_name");
}
}
}
}

View File

@@ -1,94 +1,110 @@
package su.xash.engine.ui.library package su.xash.engine.ui.library
import android.annotation.SuppressLint
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.os.Environment
import android.provider.Settings
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.Menu import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.core.view.MenuProvider import androidx.core.view.MenuProvider
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import kotlinx.coroutines.launch import com.google.android.material.dialog.MaterialAlertDialogBuilder
import su.xash.engine.BuildConfig
import su.xash.engine.R import su.xash.engine.R
import su.xash.engine.adapters.GameAdapter import su.xash.engine.adapters.GameAdapter
import su.xash.engine.databinding.FragmentLibraryBinding import su.xash.engine.databinding.FragmentLibraryBinding
class LibraryFragment : Fragment(), MenuProvider { class LibraryFragment : Fragment(), MenuProvider {
private var _binding: FragmentLibraryBinding? = null private var _binding: FragmentLibraryBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private val libraryViewModel: LibraryViewModel by activityViewModels() private val libraryViewModel: LibraryViewModel by activityViewModels()
override fun onCreateView( private val startActivityForResult =
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
): View? { if (checkStoragePermissions()) {
_binding = FragmentLibraryBinding.inflate(inflater, container, false) libraryViewModel.reloadGames(requireContext())
}
}
val adapter = GameAdapter(libraryViewModel) private fun checkStoragePermissions(): Boolean {
binding.gamesList.adapter = adapter if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) {
MaterialAlertDialogBuilder(requireContext()).apply {
setTitle(R.string.file_access_required)
setMessage(R.string.file_access_message)
setPositiveButton(android.R.string.ok) { _, _ ->
startActivityForResult.launch(
Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).setData(
Uri.fromParts("package", BuildConfig.APPLICATION_ID, null)
)
)
}
setCancelable(false)
show()
}
requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) return false
} else {
return true
}
}
return binding.root override fun onCreateView(
} inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
_binding = FragmentLibraryBinding.inflate(inflater, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val adapter = GameAdapter(libraryViewModel)
binding.swipeRefresh.setOnRefreshListener { libraryViewModel.reloadGames(requireContext()) } binding.gamesList.adapter = adapter
libraryViewModel.isReloading.observe(viewLifecycleOwner) { requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED)
binding.swipeRefresh.isRefreshing = it
}
libraryViewModel.installedGames.observe(viewLifecycleOwner) { return binding.root
(binding.gamesList.adapter as GameAdapter).submitList(it) }
}
libraryViewModel.workInfos.observe(viewLifecycleOwner) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
libraryViewModel.refreshDownloads(requireContext()) binding.swipeRefresh.setOnRefreshListener { libraryViewModel.reloadGames(requireContext()) }
}
libraryViewModel.downloads.observe(viewLifecycleOwner) { libraryViewModel.isReloading.observe(viewLifecycleOwner) {
libraryViewModel.reloadGames(requireContext()) binding.swipeRefresh.isRefreshing = it
} }
}
override fun onDestroyView() { libraryViewModel.installedGames.observe(viewLifecycleOwner) {
super.onDestroyView() (binding.gamesList.adapter as GameAdapter).submitList(it)
_binding = null }
}
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { if (checkStoragePermissions()) {
menuInflater.inflate(R.menu.menu_library, menu) libraryViewModel.reloadGames(requireContext())
} }
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean { override fun onDestroyView() {
when (menuItem.itemId) { super.onDestroyView()
R.id.action_browse -> { _binding = null
startActivity( }
Intent(Intent.ACTION_VIEW).setDataAndType(
null, "vnd.android.document/directory"
)
)
}
R.id.action_install -> { override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
findNavController().navigate(R.id.action_libraryFragment_to_setupFragment) menuInflater.inflate(R.menu.menu_library, menu)
} }
R.id.action_settings -> { override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
findNavController().navigate(R.id.action_libraryFragment_to_appSettingsFragment) when (menuItem.itemId) {
} R.id.action_settings -> {
} findNavController().navigate(R.id.action_libraryFragment_to_appSettingsFragment)
}
}
return false return false
} }
} }

View File

@@ -3,125 +3,53 @@ package su.xash.engine.ui.library
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.net.Uri import android.os.Environment
import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.preference.PreferenceManager
import androidx.work.Data
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.OutOfQuotaPolicy
import androidx.work.WorkInfo
import androidx.work.WorkManager
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import su.xash.engine.model.Game import su.xash.engine.model.Game
import su.xash.engine.model.ModDatabase import java.io.File
import su.xash.engine.workers.FileCopyWorker
import su.xash.engine.workers.KEY_FILE_URI
import java.util.Locale
const val TAG_INSTALL = "TAG_INSTALL"
class LibraryViewModel(application: Application) : AndroidViewModel(application) { class LibraryViewModel(application: Application) : AndroidViewModel(application) {
val installedGames: LiveData<List<Game>> get() = _installedGames val installedGames: LiveData<List<Game>> get() = _installedGames
private val _installedGames = MutableLiveData(emptyList<Game>()) private val _installedGames = MutableLiveData(emptyList<Game>())
val downloads: LiveData<List<Game>> get() = _downloads val isReloading: LiveData<Boolean> get() = _isReloading
private val _downloads = MutableLiveData(emptyList<Game>()) private val _isReloading = MutableLiveData(false)
val isReloading: LiveData<Boolean> get() = _isReloading val selectedItem: LiveData<Game> get() = _selectedItem
private val _isReloading = MutableLiveData(false) private val _selectedItem = MutableLiveData<Game>()
private val workManager = WorkManager.getInstance(application.applicationContext) private val appPreferences: SharedPreferences =
val workInfos: LiveData<List<WorkInfo>> = workManager.getWorkInfosByTagLiveData(TAG_INSTALL) application.getSharedPreferences("app_preferences", Context.MODE_PRIVATE)
val selectedItem: LiveData<Game> get() = _selectedItem fun reloadGames(ctx: Context) {
private val _selectedItem = MutableLiveData<Game>() if (isReloading.value == true) {
return
}
_isReloading.value = true
val appPreferences = application.getSharedPreferences("app_preferences", Context.MODE_PRIVATE) viewModelScope.launch {
val modDb: ModDatabase withContext(Dispatchers.IO) {
val rootPath = appPreferences.getString("game_path", null)
?: (Environment.getExternalStorageDirectory().absolutePath + "/xash")
val root = File(rootPath)
init { _installedGames.postValue(Game.getGames(ctx, root))
modDb = application.assets.open(ModDatabase.getFilename()).use { ModDatabase(it) } _isReloading.postValue(false)
reloadGames(application.applicationContext) }
} }
}
fun reloadGames(ctx: Context) { fun setSelectedGame(game: Game) {
if (isReloading.value == true) { _selectedItem.value = game
return }
}
_isReloading.value = true
viewModelScope.launch { fun startEngine(ctx: Context, game: Game) {
withContext(Dispatchers.IO) { game.startEngine(ctx)
val games = mutableListOf<Game>() }
val root = DocumentFile.fromFile(ctx.getExternalFilesDir(null)!!) }
val installedGames = Game.getGames(ctx, root)
.filter { p -> _downloads.value?.any { p.basedir.name == it.basedir.name } == false }
games.addAll(installedGames)
downloads.value?.let { games.addAll(it) }
_installedGames.postValue(games)
_isReloading.postValue(false)
}
}
}
fun refreshDownloads(ctx: Context) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
val games = mutableListOf<Game>()
workInfos.value?.filter {
it.state == WorkInfo.State.RUNNING && !it.progress.getString(FileCopyWorker.Input)
.isNullOrEmpty()
}?.forEach {
val uri = Uri.parse(it.progress.getString(FileCopyWorker.Input))
val file = DocumentFile.fromTreeUri(ctx, uri)
games.addAll(Game.getGames(ctx, file!!))
games.forEach { g -> g.installed = false }
}
_downloads.postValue(games)
}
}
}
fun installGame(uri: Uri) {
val data = Data.Builder().putString(KEY_FILE_URI, uri.toString()).build()
val request = OneTimeWorkRequestBuilder<FileCopyWorker>().run {
setInputData(data)
addTag(TAG_INSTALL)
build()
}
workManager.enqueue(request)
}
fun setSelectedGame(game: Game) {
_selectedItem.value = game
}
fun uninstallGame(game: Game) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
game.installed = false
game.basedir.delete()
_installedGames.postValue(_installedGames.value)
}
}
}
fun startEngine(ctx: Context, game: Game) {
game.startEngine(ctx)
}
}

View File

@@ -8,24 +8,24 @@ import androidx.fragment.app.Fragment
import su.xash.engine.databinding.FragmentAppSettingsBinding import su.xash.engine.databinding.FragmentAppSettingsBinding
class AppSettingsFragment : Fragment() { class AppSettingsFragment : Fragment() {
private var _binding: FragmentAppSettingsBinding? = null private var _binding: FragmentAppSettingsBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? { ): View {
_binding = FragmentAppSettingsBinding.inflate(inflater, container, false) _binding = FragmentAppSettingsBinding.inflate(inflater, container, false)
return binding.root return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
childFragmentManager.beginTransaction() childFragmentManager.beginTransaction()
.add(binding.settingsFragment.id, AppSettingsPreferenceFragment()).commit(); .add(binding.settingsFragment.id, AppSettingsPreferenceFragment()).commit();
} }
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
_binding = null _binding = null
} }
} }

View File

@@ -5,8 +5,8 @@ import androidx.preference.PreferenceFragmentCompat
import su.xash.engine.R import su.xash.engine.R
class AppSettingsPreferenceFragment() : PreferenceFragmentCompat() { class AppSettingsPreferenceFragment() : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.sharedPreferencesName = "app_preferences"; preferenceManager.sharedPreferencesName = "app_preferences";
setPreferencesFromResource(R.xml.app_preferences, rootKey); setPreferencesFromResource(R.xml.app_preferences, rootKey);
} }
} }

View File

@@ -6,59 +6,52 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import su.xash.engine.R
import su.xash.engine.databinding.FragmentGameSettingsBinding import su.xash.engine.databinding.FragmentGameSettingsBinding
import su.xash.engine.ui.library.LibraryViewModel import su.xash.engine.ui.library.LibraryViewModel
class GameSettingsFragment : Fragment() { class GameSettingsFragment : Fragment() {
private var _binding: FragmentGameSettingsBinding? = null private var _binding: FragmentGameSettingsBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private val libraryViewModel: LibraryViewModel by activityViewModels() private val libraryViewModel: LibraryViewModel by activityViewModels()
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? { ): View {
_binding = FragmentGameSettingsBinding.inflate(inflater, container, false) _binding = FragmentGameSettingsBinding.inflate(inflater, container, false)
return binding.root return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val game = libraryViewModel.selectedItem.value!! val game = libraryViewModel.selectedItem.value!!
binding.gameCard.apply { binding.gameCard.apply {
gameTitle.text = game.title gameTitle.text = game.title
if (game.icon != null) { if (game.icon != null) {
gameIcon.setImageBitmap(game.icon) gameIcon.setImageBitmap(game.icon)
} else { } else {
gameIcon.visibility = View.GONE gameIcon.visibility = View.GONE
} }
if (game.cover != null) { if (game.cover != null) {
gameCover.setImageBitmap(game.cover) gameCover.setImageBitmap(game.cover)
} else { } else {
gameCover.visibility = View.GONE gameCover.visibility = View.GONE
} }
buttonsContainer.visibility = View.GONE buttonsContainer.visibility = View.GONE
} }
childFragmentManager.beginTransaction() childFragmentManager.beginTransaction()
.add(binding.settingsFragment.id, GameSettingsPreferenceFragment(game)) .add(binding.settingsFragment.id, GameSettingsPreferenceFragment(game))
.commit(); .commit();
}
binding.bottomNavigation.menu.findItem(R.id.action_uninstall).setOnMenuItemClickListener { override fun onDestroyView() {
libraryViewModel.uninstallGame(game) super.onDestroyView()
findNavController().popBackStack() _binding = null
} }
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
} }

View File

@@ -8,33 +8,33 @@ import su.xash.engine.R
import su.xash.engine.model.Game import su.xash.engine.model.Game
class GameSettingsPreferenceFragment(val game: Game) : PreferenceFragmentCompat() { class GameSettingsPreferenceFragment(val game: Game) : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.sharedPreferencesName = game.basedir.name; preferenceManager.sharedPreferencesName = game.basedir.name;
setPreferencesFromResource(R.xml.game_preferences, rootKey); setPreferencesFromResource(R.xml.game_preferences, rootKey);
val packageList = findPreference<ListPreference>("package_name")!! val packageList = findPreference<ListPreference>("package_name")!!
packageList.entries = arrayOf(getString(R.string.app_name)) packageList.entries = arrayOf(getString(R.string.app_name))
packageList.entryValues = arrayOf(requireContext().packageName) packageList.entryValues = arrayOf(requireContext().packageName)
if (packageList.value == null) { if (packageList.value == null) {
packageList.setValueIndex(0); packageList.setValueIndex(0);
} }
val separatePackages = findPreference<SwitchPreferenceCompat>("separate_libraries")!! val separatePackages = findPreference<SwitchPreferenceCompat>("separate_libraries")!!
val clientPackage = findPreference<ListPreference>("client_package")!! val clientPackage = findPreference<ListPreference>("client_package")!!
val serverPackage = findPreference<ListPreference>("server_package")!! val serverPackage = findPreference<ListPreference>("server_package")!!
separatePackages.setOnPreferenceChangeListener { _, newValue -> separatePackages.setOnPreferenceChangeListener { _, newValue ->
if (newValue == true) { if (newValue == true) {
packageList.isVisible = false packageList.isVisible = false
clientPackage.isVisible = true clientPackage.isVisible = true
serverPackage.isVisible = true serverPackage.isVisible = true
} else { } else {
packageList.isVisible = true packageList.isVisible = true
clientPackage.isVisible = false clientPackage.isVisible = false
serverPackage.isVisible = false serverPackage.isVisible = false
} }
true true
} }
} }
} }

View File

@@ -1,48 +0,0 @@
package su.xash.engine.ui.setup
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.viewpager2.adapter.FragmentStateAdapter
import su.xash.engine.databinding.FragmentSetupBinding
import su.xash.engine.ui.setup.pages.LocationPageFragment
import su.xash.engine.ui.setup.pages.WelcomePageFragment
class SetupFragment : Fragment() {
private var _binding: FragmentSetupBinding? = null
private val binding get() = _binding!!
private val setupViewModel: SetupViewModel by activityViewModels()
private lateinit var setupPageAdapter: SetupPageAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
_binding = FragmentSetupBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
setupPageAdapter = SetupPageAdapter(this)
binding.viewPager.isUserInputEnabled = false
binding.viewPager.adapter = setupPageAdapter
setupViewModel.pageNumber.observe(viewLifecycleOwner) {
binding.viewPager.setCurrentItem(it, true)
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
class SetupPageAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
val pages = listOf(WelcomePageFragment(), LocationPageFragment())
override fun getItemCount(): Int = 2
override fun createFragment(position: Int): Fragment = pages[position]
}

View File

@@ -1,25 +0,0 @@
package su.xash.engine.ui.setup
import android.app.Application
import android.net.Uri
import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import su.xash.engine.MainApplication
import su.xash.engine.model.Game
class SetupViewModel(application: Application) : AndroidViewModel(application) {
val pageNumber: LiveData<Int> get() = _pageNumber
private val _pageNumber = MutableLiveData(0)
fun checkIfGameDir(uri: Uri): Boolean {
val ctx = getApplication<MainApplication>().applicationContext
val file = DocumentFile.fromTreeUri(ctx, uri)!!
return Game.checkIfGamedir(file)
}
fun setPageNumber(pos: Int) {
_pageNumber.value = pos
}
}

View File

@@ -1,59 +0,0 @@
package su.xash.engine.ui.setup.pages
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import su.xash.engine.R
import su.xash.engine.databinding.PageLocationBinding
import su.xash.engine.ui.library.LibraryViewModel
import su.xash.engine.ui.setup.SetupViewModel
class LocationPageFragment : Fragment() {
private var _binding: PageLocationBinding? = null
private val binding get() = _binding!!
private val setupViewModel: SetupViewModel by activityViewModels()
private val libraryViewModel: LibraryViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
_binding = PageLocationBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.pageButton.setOnClickListener {
getGamesDirectory.launch(null)
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
private val getGamesDirectory =
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) {
it?.let {
if (!setupViewModel.checkIfGameDir(it)) {
MaterialAlertDialogBuilder(requireContext()).apply {
setTitle(R.string.error)
setMessage(R.string.setup_location_empty)
setPositiveButton(R.string.ok) { dialog, _ -> dialog.dismiss() }
show()
}
} else {
requireContext().contentResolver.takePersistableUriPermission(it, Intent.FLAG_GRANT_READ_URI_PERMISSION)
libraryViewModel.installGame(it)
findNavController().navigate(R.id.action_setupFragment_to_libraryFragment)
}
}
}
}

View File

@@ -1,35 +0,0 @@
package su.xash.engine.ui.setup.pages
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import su.xash.engine.databinding.PageWelcomeBinding
import su.xash.engine.ui.setup.SetupViewModel
class WelcomePageFragment : Fragment() {
private var _binding: PageWelcomeBinding? = null
private val binding get() = _binding!!
private val setupViewModel: SetupViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
_binding = PageWelcomeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.pageButton.setOnClickListener {
setupViewModel.setPageNumber(1)
}
setupViewModel.setPageNumber(0)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View File

@@ -0,0 +1,49 @@
package su.xash.engine.util;
import android.app.Activity;
import android.graphics.Rect;
import android.view.View;
import android.widget.FrameLayout;
public class AndroidBug5497Workaround {
// For more information, see https://code.google.com/p/android/issues/detail?id=5497
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
public static void assistActivity(Activity activity) {
new AndroidBug5497Workaround(activity);
}
private View mChildOfContent;
private int usableHeightPrevious;
private FrameLayout.LayoutParams frameLayoutParams;
private AndroidBug5497Workaround(Activity activity) {
FrameLayout content = activity.findViewById(android.R.id.content);
mChildOfContent = content.getChildAt(0);
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(this::possiblyResizeChildOfContent);
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
}
private void possiblyResizeChildOfContent() {
int usableHeightNow = computeUsableHeight();
if (usableHeightNow != usableHeightPrevious) {
int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
if (heightDifference > (usableHeightSansKeyboard / 4)) {
// keyboard probably just became visible
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
} else {
// keyboard probably just became hidden
frameLayoutParams.height = usableHeightSansKeyboard;
}
mChildOfContent.requestLayout();
usableHeightPrevious = usableHeightNow;
}
}
private int computeUsableHeight() {
Rect r = new Rect();
mChildOfContent.getWindowVisibleDisplayFrame(r);
return (r.bottom - r.top);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,97 +0,0 @@
package su.xash.engine.workers
import android.content.Context
import android.net.Uri
import androidx.documentfile.provider.DocumentFile
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
const val KEY_FILE_URI = "KEY_FILE_URI"
class FileCopyWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx, params) {
companion object {
const val Input = "Input"
const val Progress = "Progress"
}
private var fileCount = 0
private var fileCopied = 0
override suspend fun doWork(): Result {
withContext(Dispatchers.IO) {
val fileUri = inputData.getString(KEY_FILE_URI)
setProgress(workDataOf(Input to fileUri))
val uri = Uri.parse(fileUri)
val source = DocumentFile.fromTreeUri(applicationContext, uri)
fileCount = source?.countDirFiles() ?: return@withContext Result.failure()
setProgress(workDataOf(Progress to 0f))
val gamedir = source.name!!
val externalFilesDir = DocumentFile.fromFile(applicationContext.getExternalFilesDir(null)!!)
// create a directory to store staged files
val target = externalFilesDir.createDirectory(".$gamedir")!!
source.copyDirTo(applicationContext, this@FileCopyWorker, target)
target.renameTo(gamedir)
setProgress(workDataOf(Progress to 1f))
}
return Result.success()
}
suspend fun fileCopied(count: Int) {
if(count == 0)
return
fileCopied += count
val percentage: Float = fileCopied.toFloat() / fileCount.toFloat();
setProgress(workDataOf(Progress to percentage))
}
}
fun DocumentFile.countDirFiles(): Int {
var count: Int = 0
listFiles().forEach {
if (it.isDirectory)
count += it.countDirFiles()
else
count++
}
return count
}
fun DocumentFile.copyFileTo(ctx: Context, file: DocumentFile) {
val outFile = file.createFile("application", name!!)!!
ctx.contentResolver.openOutputStream(outFile.uri).use { os ->
ctx.contentResolver.openInputStream(uri).use {
it?.copyTo(os!!)
}
}
}
suspend fun DocumentFile.copyDirTo(ctx: Context, worker: FileCopyWorker, dir: DocumentFile) {
var count: Int = 0
listFiles().forEach {
if (it.isDirectory) {
val outDir = dir.createDirectory(it.name!!)!!
it.copyDirTo(ctx, worker, outDir)
} else {
it.copyFileTo(ctx, dir)
count++
}
}
worker.fileCopied(count)
}

View File

@@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M21,10h-8.35C11.83,7.67 9.61,6 7,6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6c2.61,0 4.83,-1.67 5.65,-4H13l2,2l2,-2l2,2l4,-4.04L21,10zM7,15c-1.65,0 -3,-1.35 -3,-3c0,-1.65 1.35,-3 3,-3s3,1.35 3,3C10,13.65 8.65,15 7,15z"/>
</vector>

View File

@@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>

View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true">
<shape android:shape="rectangle">
<gradient android:endColor="#2D73FF" android:startColor="#06BFFF" />
<corners android:radius="4dp" />
</shape>
</item>
<item android:state_enabled="false">
<shape android:shape="rectangle">
<gradient android:endColor="#6D6D6D" android:startColor="#8F8F8F" />
<corners android:radius="4dp" />
</shape>
</item>
</selector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M12.004,2c-5.25,0 -9.556,4.05 -9.964,9.197l5.36,2.216c0.454,-0.31 1.002,-0.492 1.593,-0.492 0.053,0 0.104,0.003 0.157,0.005l2.384,-3.452v-0.049c0,-2.08 1.69,-3.77 3.77,-3.77 2.079,0 3.77,1.692 3.77,3.772s-1.692,3.771 -3.77,3.771h-0.087l-3.397,2.426c0,0.043 0.003,0.088 0.003,0.133 0,1.562 -1.262,2.83 -2.825,2.83 -1.362,0 -2.513,-0.978 -2.775,-2.273l-3.838,-1.589C3.573,18.922 7.427,22 12.005,22c5.522,0 9.998,-4.477 9.998,-10 0,-5.522 -4.477,-10 -9.999,-10zM7.078,16.667c0.218,0.452 0.595,0.832 1.094,1.041 1.081,0.45 2.328,-0.063 2.777,-1.145 0.22,-0.525 0.22,-1.1 0.004,-1.625 -0.215,-0.525 -0.625,-0.934 -1.147,-1.152 -0.52,-0.217 -1.075,-0.208 -1.565,-0.025l1.269,0.525c0.797,0.333 1.174,1.25 0.84,2.046 -0.33,0.797 -1.247,1.175 -2.044,0.843l-1.228,-0.508zM17.818,9.422c0,-1.385 -1.128,-2.512 -2.513,-2.512 -1.387,0 -2.512,1.127 -2.512,2.512 0,1.388 1.125,2.513 2.512,2.513 1.386,0 2.512,-1.125 2.512,-2.513zM15.31,7.53c1.04,0 1.888,0.845 1.888,1.888s-0.847,1.888 -1.888,1.888c-1.044,0 -1.888,-0.845 -1.888,-1.888s0.845,-1.888 1.888,-1.888z"/>
</vector>

View File

@@ -1,33 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="295.46dp"
android:height="90.47dp"
android:viewportWidth="295.46"
android:viewportHeight="90.47">
<path
android:fillColor="#FF000000"
android:pathData="m45.08,1c-23.24,0 -42.28,17.92 -44.08,40.69l23.71,9.8c2.01,-1.37 4.44,-2.18 7.05,-2.18 0.23,0 0.47,0.01 0.7,0.02l10.54,-15.28c0,-0.07 0,-0.14 0,-0.22 0,-9.2 7.48,-16.68 16.68,-16.68 9.2,0 16.68,7.48 16.68,16.68s-7.48,16.68 -16.68,16.68c-0.13,0 -0.25,0 -0.38,-0.01l-15.04,10.73c0.01,0.19 0.01,0.39 0.01,0.59 0,6.91 -5.62,12.52 -12.52,12.52 -6.06,0 -11.13,-4.33 -12.28,-10.06l-16.96,-7.01c5.25,18.57 22.31,32.18 42.56,32.18 24.43,0 44.24,-19.81 44.24,-44.24 0,-24.43 -19.81,-44.24 -44.24,-44.24"/>
<path
android:fillColor="#FF000000"
android:pathData="m28.72,68.12 l-5.43,-2.24c0.96,2.01 2.63,3.68 4.84,4.61 4.78,1.99 10.3,-0.28 12.29,-5.06 0.96,-2.31 0.97,-4.87 0.01,-7.19 -0.95,-2.32 -2.76,-4.13 -5.07,-5.1 -2.3,-0.96 -4.76,-0.92 -6.93,-0.1l5.61,2.32c3.53,1.47 5.2,5.52 3.72,9.05 -1.47,3.53 -5.52,5.2 -9.05,3.72"/>
<path
android:fillColor="#FF000000"
android:pathData="m70.8,33.83c0,-6.13 -4.99,-11.12 -11.12,-11.12 -6.13,0 -11.12,4.99 -11.12,11.12 0,6.13 4.99,11.11 11.12,11.11 6.13,0 11.12,-4.99 11.12,-11.11m-19.45,-0.02c0,-4.61 3.74,-8.35 8.35,-8.35s8.35,3.74 8.35,8.35 -3.74,8.35 -8.35,8.35 -8.35,-3.74 -8.35,-8.35"/>
<path
android:fillColor="#FF000000"
android:pathData="m136.56,31.27 l-2.96,5.21c-2.28,-1.6 -5.38,-2.56 -8.08,-2.56 -3.09,0 -5,1.28 -5,3.57 0,2.78 3.39,3.43 8.44,5.24 5.42,1.92 8.54,4.17 8.54,9.14 0,6.79 -5.34,10.61 -13.02,10.61 -3.74,0 -8.26,-0.97 -11.73,-3.08l2.16,-5.78c2.82,1.49 6.19,2.37 9.2,2.37 4.05,0 5.98,-1.5 5.98,-3.7 0,-2.53 -2.94,-3.29 -7.68,-4.86 -5.4,-1.8 -9.15,-4.17 -9.15,-9.67 0,-6.2 4.96,-9.76 12.1,-9.76 4.98,0 8.98,1.58 11.2,3.26"/>
<path
android:fillColor="#FF000000"
android:pathData="m152.76,61.9v-27.34h-10.13v-5.99h27.21v5.99h-10.1v27.34z"/>
<path
android:fillColor="#FF000000"
android:pathData="m197.9,42.05v5.99h-13.36v7.82h15.5v6.04h-22.47v-33.33h22.47v5.97h-15.5v7.51z"/>
<path
android:fillColor="#FF000000"
android:pathData="m215.62,55.43 l-2.21,6.47h-7.32l12.49,-33.33h7.03l12.85,33.32h-7.56l-2.25,-6.47h-13.03zM222.07,36.52 L217.51,49.87h9.2z"/>
<path
android:fillColor="#FF000000"
android:pathData="m261.22,60.93 l-8.97,-19.3v20.27h-6.68v-33.33h6.67l11.2,24.06 10.8,-24.06h6.73v33.33h-6.68v-20.44l-9.12,19.47z"/>
<path
android:fillColor="#FF000000"
android:pathData="m294.46,32.78c0,2.86 -2.15,4.65 -4.61,4.65 -2.47,0 -4.62,-1.78 -4.62,-4.65 0,-2.86 2.15,-4.64 4.62,-4.64 2.46,0 4.61,1.77 4.61,4.64m-8.46,0c0,2.4 1.73,3.9 3.85,3.9 2.11,0 3.83,-1.5 3.83,-3.9 0,-2.4 -1.72,-3.88 -3.83,-3.88 -2.12,0 -3.85,1.5 -3.85,3.88m3.91,-2.37c1.2,0 1.6,0.63 1.6,1.32 0,0.63 -0.37,1.05 -0.82,1.26l1.07,2.01h-0.88l-0.9,-1.78h-0.93v1.78h-0.73v-4.58zM289.05,32.54h0.81c0.53,0 0.84,-0.33 0.84,-0.75 0,-0.42 -0.22,-0.69 -0.84,-0.69h-0.81v1.44z"/>
</vector>

View File

@@ -1,35 +1,36 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" xmlns:tools="http://schemas.android.com/tools"
android:layout_height="match_parent" android:layout_width="match_parent"
xmlns:tools="http://schemas.android.com/tools"> android:layout_height="match_parent"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout" android:id="@+id/appBarLayout"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar" android:id="@+id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView <androidx.fragment.app.FragmentContainerView
android:id="@+id/fragmentContainerView" android:id="@+id/fragmentContainerView"
android:name="androidx.navigation.fragment.NavHostFragment" android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
app:defaultNavHost="true" app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/appBarLayout" app:layout_constraintTop_toBottomOf="@id/appBarLayout"
app:navGraph="@navigation/nav_graph" app:navGraph="@navigation/nav_graph"
tools:layout="@layout/fragment_library"/> tools:layout="@layout/fragment_library" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,111 +1,98 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android" <com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
style="@style/Widget.Material3.CardView.Filled" style="@style/Widget.Material3.CardView.Filled"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp"> android:layout_marginTop="8dp">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="128dp"> android:layout_height="128dp">
<ImageView <ImageView
android:id="@+id/gameCover" android:id="@+id/gameCover"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:scaleType="centerCrop" android:scaleType="centerCrop"
tools:src="@android:mipmap/sym_def_app_icon" /> tools:src="@android:mipmap/sym_def_app_icon" />
<com.google.android.material.card.MaterialCardView <com.google.android.material.card.MaterialCardView
style="@style/Widget.Material3.CardView.Filled" style="@style/Widget.Material3.CardView.Filled"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_margin="8dp" android:layout_margin="8dp"
app:contentPadding="10dp" app:contentPadding="10dp"
app:layout_constrainedWidth="true" app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/buttonsContainer" app:layout_constraintEnd_toStartOf="@id/buttonsContainer"
app:layout_constraintHorizontal_bias="0" app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"> app:layout_constraintStart_toStartOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent"> android:layout_height="match_parent">
<ImageView <ImageView
android:id="@+id/gameIcon" android:id="@+id/gameIcon"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginRight="8dp" android:layout_marginRight="8dp"
android:adjustViewBounds="true" android:adjustViewBounds="true"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/gameTitle" app:layout_constraintEnd_toStartOf="@id/gameTitle"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:src="@android:mipmap/sym_def_app_icon" /> tools:src="@android:mipmap/sym_def_app_icon" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:id="@+id/gameTitle" android:id="@+id/gameTitle"
style="@style/TextAppearance.Material3.TitleMedium" style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:gravity="center" android:gravity="center"
android:singleLine="true" android:singleLine="true"
app:layout_constrainedWidth="true" app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/gameIcon" app:layout_constraintStart_toEndOf="@id/gameIcon"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:text="Game Title" /> tools:text="Game Title" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView <com.google.android.material.card.MaterialCardView
android:id="@+id/buttonsContainer" android:id="@+id/buttonsContainer"
style="@style/Widget.Material3.CardView.Filled" style="@style/Widget.Material3.CardView.Filled"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"> app:layout_constraintEnd_toEndOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<com.google.android.material.progressindicator.CircularProgressIndicator <com.google.android.material.button.MaterialButton
android:id="@+id/progressIndicator" android:id="@+id/launchButton"
android:layout_width="wrap_content" style="@style/Widget.Material3.Button.IconButton"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:indeterminate="true" android:layout_height="match_parent"
android:padding="10dp" app:icon="@drawable/ic_baseline_play_arrow_24"
android:visibility="gone" app:layout_constraintEnd_toStartOf="@+id/settingsButton" />
app:indicatorSize="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/launchButton" android:id="@+id/settingsButton"
style="@style/Widget.Material3.Button.IconButton" style="@style/Widget.Material3.Button.IconButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
app:icon="@drawable/ic_baseline_play_arrow_24" app:icon="@drawable/ic_baseline_settings_24"
app:layout_constraintEnd_toStartOf="@+id/settingsButton" /> app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.button.MaterialButton </com.google.android.material.card.MaterialCardView>
android:id="@+id/settingsButton" </androidx.constraintlayout.widget.ConstraintLayout>
style="@style/Widget.Material3.Button.IconButton" </com.google.android.material.card.MaterialCardView>
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:icon="@drawable/ic_baseline_settings_24"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>

View File

@@ -1,30 +1,45 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content"> style="@style/Widget.Material3.CardView.Filled"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent">
<!-- <com.google.android.material.textfield.TextInputLayout--> <androidx.constraintlayout.widget.ConstraintLayout
<!-- android:layout_width="match_parent"--> android:layout_width="match_parent"
<!-- android:layout_height="wrap_content"--> android:layout_height="wrap_content"
<!-- app:layout_constraintTop_toTopOf="parent"--> android:padding="10dp">
<!-- app:layout_constraintBottom_toBottomOf="parent">-->
<!-- <com.google.android.material.textfield.TextInputEditText--> <TextView
<!-- android:layout_width="match_parent"--> android:id="@android:id/title"
<!-- android:layout_height="wrap_content" />--> android:layout_width="match_parent"
<!-- </com.google.android.material.textfield.TextInputLayout>--> android:layout_height="wrap_content"
<TextView android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
android:id="@android:id/title" app:layout_constraintTop_toTopOf="parent"
android:layout_width="match_parent" tools:text="EditText Preference" />
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent" <TextView
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"/> android:id="@android:id/summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@android:id/title"
tools:text="Summary" />
<!-- <com.google.android.material.button.MaterialButton-->
<!-- style="@style/Widget.Material3.Button.IconButton"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- app:icon="@drawable/baseline_edit_24"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent" />-->
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<TextView
android:id="@android:id/summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@android:id/title"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,14 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_width="match_parent" android:layout_height="match_parent">
android:layout_height="match_parent"
android:paddingHorizontal="8dp">
<androidx.fragment.app.FragmentContainerView <androidx.fragment.app.FragmentContainerView
android:id="@+id/settingsFragment" android:id="@+id/settingsFragment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:layout="@android:layout/list_content" /> tools:layout="@android:layout/list_content" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,39 +1,32 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<include <include
android:id="@+id/gameCard" android:id="@+id/gameCard"
layout="@layout/card_game" layout="@layout/card_game"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="8dp" android:layout_margin="8dp"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.card.MaterialCardView <androidx.fragment.app.FragmentContainerView
style="@style/Widget.Material3.CardView.Filled" android:id="@+id/settingsFragment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="8dp" app:layout_constraintTop_toBottomOf="@id/gameCard"
app:contentPadding="16dp" tools:layout="@android:layout/list_content">
app:layout_constraintTop_toBottomOf="@id/gameCard">
<androidx.fragment.app.FragmentContainerView </androidx.fragment.app.FragmentContainerView>
android:id="@+id/settingsFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:layout="@android:layout/list_content" />
</com.google.android.material.card.MaterialCardView> <!-- <com.google.android.material.bottomnavigation.BottomNavigationView-->
<!-- android:id="@+id/bottomNavigation"-->
<com.google.android.material.bottomnavigation.BottomNavigationView <!-- style="@style/Widget.MaterialComponents.BottomNavigationView.Colored"-->
android:id="@+id/bottomNavigation" <!-- android:layout_width="match_parent"-->
style="@style/Widget.MaterialComponents.BottomNavigationView.Colored" <!-- android:layout_height="wrap_content"-->
android:layout_width="match_parent" <!-- app:layout_constraintBottom_toBottomOf="parent"-->
android:layout_height="wrap_content" <!-- app:menu="@menu/menu_game_settings" />-->
app:layout_constraintBottom_toBottomOf="parent" </androidx.constraintlayout.widget.ConstraintLayout>
app:menu="@menu/menu_game_settings" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,23 +1,23 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:id="@+id/swipeRefresh"
android:layout_height="match_parent" android:layout_width="match_parent"
android:id="@+id/swipeRefresh"> android:layout_height="match_parent">
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/gamesList" android:id="@+id/gamesList"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:layoutManager="LinearLayoutManager" android:clipToPadding="false"
android:clipToPadding="false" android:paddingHorizontal="8dp"
android:paddingHorizontal="8dp" app:layoutManager="LinearLayoutManager"
tools:listitem="@layout/card_game" /> tools:listitem="@layout/card_game" />
</RelativeLayout> </RelativeLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,58 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/steam_background"
android:gravity="center_vertical"
android:orientation="vertical"
tools:context=".fragment.SteamLoginFragment">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/steam_logo"
app:tint="#C5C3C0" />
<com.google.android.material.textfield.TextInputLayout
android:layout_width="320dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"
app:startIconDrawable="@drawable/ic_baseline_person_24">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/steamLogin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/username"
android:inputType="textEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="320dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"
app:startIconDrawable="@drawable/ic_baseline_key_24">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/steamPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/password"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/loginButton"
style="@style/App.Theme.SteamButton"
android:layout_width="240dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"
android:text="@string/login" />
</LinearLayout>

View File

@@ -1,19 +1,20 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<TextView
android:id="@android:id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"/>
<TextView <TextView
android:id="@android:id/summary" android:id="@android:id/title"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@android:id/title" android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"/> app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@android:id/summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
app:layout_constraintTop_toBottomOf="@android:id/title" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools">
<ImageView
android:id="@+id/pagePic"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="64dp"
android:layout_marginBottom="32dp"
android:src="@drawable/ic_baseline_folder_open_24"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/pageTitle"/>
<TextView
android:id="@+id/pageTitle"
style="@style/TextAppearance.Material3.TitleLarge"
android:layout_width="match_parent"
android:layout_height="0dp"
android:gravity="center"
android:paddingHorizontal="16dp"
android:text="@string/setup_location_title"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@id/pageMessage"
app:layout_constraintTop_toBottomOf="@id/pagePic" />
<TextView
android:id="@+id/pageMessage"
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent"
android:layout_height="0dp"
android:gravity="center"
android:paddingHorizontal="16dp"
android:text="@string/setup_location_message"
app:layout_constraintBottom_toTopOf="@id/pageButton"
app:layout_constraintTop_toBottomOf="@id/pageTitle" />
<Button
android:id="@+id/pageButton"
android:layout_width="240dp"
android:layout_marginBottom="128dp"
android:layout_height="wrap_content"
android:text="@string/ok"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/pageMessage" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools">
<ImageView
android:id="@+id/pagePic"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="64dp"
android:layout_marginBottom="32dp"
android:src="@mipmap/ic_launcher"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/pageTitle"/>
<TextView
android:id="@+id/pageTitle"
style="@style/TextAppearance.Material3.TitleLarge"
android:layout_width="match_parent"
android:layout_height="0dp"
android:gravity="center"
android:textStyle="bold"
android:paddingHorizontal="16dp"
android:text="@string/setup_welcome_title"
app:layout_constraintBottom_toTopOf="@id/pageMessage"
app:layout_constraintTop_toBottomOf="@id/pagePic" />
<TextView
android:id="@+id/pageMessage"
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent"
android:layout_height="0dp"
android:gravity="center"
android:paddingHorizontal="16dp"
android:text="@string/setup_welcome_message"
app:layout_constraintBottom_toTopOf="@id/pageButton"
app:layout_constraintTop_toBottomOf="@id/pageTitle" />
<Button
android:id="@+id/pageButton"
android:layout_width="240dp"
android:layout_marginBottom="128dp"
android:layout_height="wrap_content"
android:text="@string/next"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/pageMessage" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="32dp">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/steam_guard_code"
android:textAppearance="@style/TextAppearance.Material3.TitleLarge"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textInputLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/steamCode"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/steam_guard_code" />
</com.google.android.material.textfield.TextInputLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,23 +1,37 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content"> style="@style/Widget.Material3.CardView.Filled"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView <androidx.constraintlayout.widget.ConstraintLayout
android:id="@android:id/title" android:layout_width="match_parent"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:padding="10dp">
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" <TextView
app:layout_constraintBottom_toBottomOf="parent" android:id="@android:id/title"
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"/> android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Switch preference" />
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/switchWidget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/switchWidget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,14 +1,9 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<item <item
android:id="@+id/action_dedicated" android:id="@+id/action_dedicated"
android:icon="@drawable/ic_baseline_terminal_24" android:icon="@drawable/ic_baseline_terminal_24"
android:title="@string/dedicated_server" android:title="@string/dedicated_server"
app:showAsAction="always|withText" android:visible="false"
android:visible="false"/> app:showAsAction="always|withText" />
<item </menu>
android:id="@+id/action_uninstall"
android:icon="@drawable/ic_baseline_delete_24"
android:title="@string/uninstall"
app:showAsAction="always|withText" />
</menu>

View File

@@ -1,19 +1,8 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<item <item
android:id="@+id/action_browse" android:id="@+id/action_settings"
android:icon="@drawable/ic_baseline_folder_open_24" android:icon="@drawable/ic_baseline_settings_24"
android:title="@string/browse" android:title="@string/app_settings"
app:showAsAction="always|withText" /> app:showAsAction="always|withText" />
<item </menu>
android:id="@+id/action_install"
android:icon="@drawable/ic_baseline_add_24"
android:title="@string/install"
app:showAsAction="always|withText" />
<item
android:id="@+id/action_settings"
android:icon="@drawable/ic_baseline_settings_24"
android:title="@string/app_settings"
app:showAsAction="always|withText"
android:visible="false"/>
</menu>

View File

@@ -1,38 +1,26 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android" <navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/nav_graph"
android:id="@+id/nav_graph" android:label="@string/library"
android:label="@string/library" app:startDestination="@id/libraryFragment">
app:startDestination="@id/libraryFragment"> <fragment
<fragment android:id="@+id/libraryFragment"
android:id="@+id/libraryFragment" android:name="su.xash.engine.ui.library.LibraryFragment"
android:name="su.xash.engine.ui.library.LibraryFragment" android:label="@string/library">
android:label="@string/library"> <action
<action android:id="@+id/action_libraryFragment_to_gameSettingsFragment"
android:id="@+id/action_libraryFragment_to_setupFragment" app:destination="@id/gameSettingsFragment" />
app:destination="@id/setupFragment" /> <action
<action android:id="@+id/action_libraryFragment_to_appSettingsFragment"
android:id="@+id/action_libraryFragment_to_gameSettingsFragment" app:destination="@id/appSettingsFragment" />
app:destination="@id/gameSettingsFragment" /> </fragment>
<action <fragment
android:id="@+id/action_libraryFragment_to_appSettingsFragment" android:id="@+id/gameSettingsFragment"
app:destination="@id/appSettingsFragment" /> android:name="su.xash.engine.ui.settings.GameSettingsFragment"
</fragment> android:label="@string/game_settings" />
<fragment <fragment
android:id="@+id/setupFragment" android:id="@+id/appSettingsFragment"
android:name="su.xash.engine.ui.setup.SetupFragment" android:name="su.xash.engine.ui.settings.AppSettingsFragment"
android:label="@string/setup" > android:label="@string/app_settings" />
<action </navigation>
android:id="@+id/action_setupFragment_to_libraryFragment"
app:destination="@id/libraryFragment" />
</fragment>
<fragment
android:id="@+id/gameSettingsFragment"
android:name="su.xash.engine.ui.settings.GameSettingsFragment"
android:label="@string/game_settings" />
<fragment
android:id="@+id/appSettingsFragment"
android:name="su.xash.engine.ui.settings.AppSettingsFragment"
android:label="@string/app_settings" />
</navigation>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="ok">Ok</string>
<string name="cancel">Cancelar</string>
</resources>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="cancel">Annulla</string>
<string name="ok">Ok</string>
</resources>

View File

@@ -1,33 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="ok">Ok</string> <string name="library">Biblioteca</string>
<string name="cancel">Cancelar</string> <string name="dedicated_server">Dedicado</string>
<string name="next">Próximo</string> <string name="app_settings">Configurações</string>
<string name="browse">Navegar</string> <string name="game_settings">Configurações do jogo</string>
<string name="install">Instalar</string> <string name="game_settings_command_line">Argumentos de linha de comando</string>
<string name="library">Biblioteca</string> <string name="game_settings_volume_buttons">Usar botões de volume no jogo</string>
<string name="steam_guard_code">Código do Steam Guard</string> <string name="preferences_package_name">Bibliotecas de pacotes</string>
<string name="steam_login">Logar com Steam</string> <string name="preferences_separate_libraries">Bibliotecas de pacotes separados</string>
<string name="login">Logar</string> <string name="preferences_client_package">Pacotes de Cliente</string>
<string name="username">Usuário</string> <string name="preferences_server_package">Pacotes de Servidor</string>
<string name="password">Senha</string> <string name="preferences_use_icons">Usar ícones ao inves de imagens de fundo</string>
<string name="uninstall">Desinstalar</string>
<string name="dedicated_server">Dedicado</string>
<string name="error">Erro!</string>
<string name="setup">Configurar</string>
<string name="app_settings">Configurações</string>
<string name="game_settings">Configurações do jogo</string>
<string name="game_settings_command_line">Argumentos de linha de comando</string>
<string name="game_settings_volume_buttons">Usar botões de volume no jogo</string>
<string name="setup_welcome_title">Bem vindo ao Xash3D FWGS!</string>
<string name="setup_welcome_message">Agora, nós vamos guiá-lo durante o processo de instalação.</string>
<string name="setup_location_title">Jogos</string>
<string name="setup_location_message">Selecione a pasta onde seus jogos estão localizados.</string>
<string name="setup_location_empty">A pasta selecionada não contem nenhum jogo.</string>
<string name="setup_location_invalid">A pasta selecionada é invalida.</string>
<string name="preferences_package_name">Bibliotecas de pacotes</string>
<string name="preferences_separate_libraries">Bibliotecas de pacotes separados</string>
<string name="preferences_client_package">Pacotes de Cliente</string>
<string name="preferences_server_package">Pacotes de Servidor</string>
<string name="preferences_use_icons">Usar ícones ao inves de imagens de fundo</string>
</resources> </resources>

View File

@@ -1,33 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="cancel">Отмена</string> <string name="library">Библиотека</string>
<string name="ok">ОК</string> <string name="dedicated_server">Выделенный</string>
<string name="next">Далее</string> <string name="app_settings">Настройки</string>
<string name="browse">Обзор</string> <string name="game_settings">Настройки игры</string>
<string name="install">Установить</string> <string name="game_settings_command_line">Аргументы командной строки</string>
<string name="library">Библиотека</string> <string name="game_settings_volume_buttons">Использовать кнопки громкости</string>
<string name="steam_guard_code">Код Steam Guard</string> <string name="preferences_package_name">Пакет библиотек</string>
<string name="steam_login">Логин Steam</string> <string name="preferences_separate_libraries">Библиотеки из отдельных пакетов</string>
<string name="login">Логин</string> <string name="preferences_client_package">Пакет клиента</string>
<string name="username">Имя пользователя</string> <string name="preferences_server_package">Пакет сервера</string>
<string name="password">Пароль</string> <string name="preferences_use_icons">Использовать иконки вместо фона</string>
<string name="uninstall">Удалить</string> </resources>
<string name="dedicated_server">Выделенный</string>
<string name="error">Ошибка!</string>
<string name="setup">Установка</string>
<string name="app_settings">Настройки</string>
<string name="game_settings">Настройки игры</string>
<string name="game_settings_command_line">Аргументы командной строки</string>
<string name="game_settings_volume_buttons">Использовать кнопки громкости</string>
<string name="setup_welcome_title">Добро пожаловать в Xash3D FWGS!</string>
<string name="setup_welcome_message">Теперь мы ознакомим вас с процессом установки.</string>
<string name="setup_location_title">Игры</string>
<string name="setup_location_message">Выберите папку, в которой находятся ваши игры.</string>
<string name="setup_location_empty">Выбранный каталог не содержит ни одной игры.</string>
<string name="setup_location_invalid">Выбранный каталог недопустим.</string>
<string name="preferences_package_name">Пакет библиотек</string>
<string name="preferences_separate_libraries">Библиотеки из отдельных пакетов</string>
<string name="preferences_client_package">Пакет клиента</string>
<string name="preferences_server_package">Пакет сервера</string>
<string name="preferences_use_icons">Использовать иконки вместо фона</string>
</resources>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="ok">Tamam</string>
<string name="cancel">İptal</string>
</resources>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="ok">Ок</string>
<string name="cancel">Скасувати</string>
</resources>

View File

@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="valve_red">#F74843</color> <color name="valve_red">#F74843</color>
<color name="steam_grey">#C5C3C0</color> <color name="hl_orange">#FB7E14</color>
<color name="steam_background">#181A21</color> <color name="black">#000000</color>
<color name="steam_dark_grey">#32353C</color> <color name="hl_dark_grey">#151515</color>
<color name="hl_orange">#FB7E14</color> <color name="hl_grey">#292929</color>
<color name="black">#000000</color>
<color name="hl_dark_grey">#151515</color>
<color name="hl_grey">#292929</color>
</resources> </resources>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="ic_launcher_background">#F74843</color> <color name="ic_launcher_background">#F74843</color>
</resources> </resources>

View File

@@ -1,36 +1,19 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name" translatable="false">Xash3D FWGS</string> <string name="app_name" translatable="false">Xash3D FWGS</string>
<string name="authority" translatable="false">su.xash.engine.documents</string> <string name="library">Library</string>
<string name="cancel">Cancel</string> <string name="dedicated_server">Dedicated</string>
<string name="ok">OK</string> <string name="app_settings">Settings</string>
<string name="next">Next</string> <string name="game_settings">Game Settings</string>
<string name="browse">Browse</string> <string name="game_settings_command_line">Command-line arguments</string>
<string name="install">Install</string> <string name="game_settings_volume_buttons">Use volume buttons in-game</string>
<string name="library">Library</string> <string name="preferences_package_name">Libraries package</string>
<string name="steam_guard_code">Steam Guard Code</string> <string name="preferences_separate_libraries">Libraries from separate packages</string>
<string name="steam_login">Steam Login</string> <string name="preferences_client_package">Client package</string>
<string name="login">Login</string> <string name="preferences_server_package">Server package</string>
<string name="username">Username</string> <string name="preferences_use_icons">Use icons instead of backgrounds</string>
<string name="password">Password</string> <string name="game_data_location">Game data location</string>
<string name="steam" translatable="false">Steam</string> <string name="file_access_required">All-files access required</string>
<string name="uninstall">Uninstall</string> <string name="file_access_message">All-files access is required for the app to function properly.</string>
<string name="dedicated_server">Dedicated</string> <string name="select_current_directory">Select current directory</string>
<string name="error">Error!</string> </resources>
<string name="setup">Setup</string>
<string name="app_settings">Settings</string>
<string name="game_settings">Game Settings</string>
<string name="game_settings_command_line">Command-line arguments</string>
<string name="game_settings_volume_buttons">Use volume buttons in-game</string>
<string name="setup_welcome_title">Welcome to Xash3D FWGS!</string>
<string name="setup_welcome_message">Now, we will guide you through the installation process.</string>
<string name="setup_location_title">Games</string>
<string name="setup_location_message">Select the folder, where your games are located.</string>
<string name="setup_location_empty">Selected directory doesn\'t contain any games.</string>
<string name="setup_location_invalid">Selected directory is invalid.</string>
<string name="preferences_package_name">Libraries package</string>
<string name="preferences_separate_libraries">Libraries from separate packages</string>
<string name="preferences_client_package">Client package</string>
<string name="preferences_server_package">Server package</string>
<string name="preferences_use_icons">Use icons instead of backgrounds</string>
</resources>

View File

@@ -1,14 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="App.Theme.SteamButton" parent="@style/Widget.Material3.Button"> <style name="ShapeAppearance.App.MediumComponent" parent="ShapeAppearance.Material3.MediumComponent">
<item name="android:background">@drawable/steam_button_gradient</item> <item name="cornerSize">4dp</item>
<item name="backgroundTint">@null</item> </style>
<item name="android:textColor">#FFFFFF</item>
</style>
<style name="ShapeAppearance.App.MediumComponent" parent="ShapeAppearance.Material3.MediumComponent">
<item name="cornerSize">4dp</item>
</style>
</resources> </resources>

View File

@@ -1,17 +1,18 @@
<resources> <resources>
<style name="Theme.App" parent="Theme.Material3.Dark.NoActionBar">
<item name="colorPrimary">@color/hl_orange</item>
<item name="colorPrimaryDark">@color/hl_dark_grey</item>
<!-- <item name="colorPrimaryContainer">@color/valve_red</item>-->
<item name="colorSurface">@color/hl_grey</item>
<item name="colorSurfaceVariant">@color/hl_grey</item>
<item name="android:colorBackground">@color/hl_dark_grey</item>
<item name="colorControlNormal">@color/hl_orange</item>
<item name="colorOnPrimary">@color/hl_dark_grey</item>
<!-- <item name="colorOnPrimaryContainer">@android:color/white</item>-->
<!-- <item name="colorOnSurface">@android:color/white</item>-->
<!-- <item name="colorOnSurfaceVariant">@android:color/white</item>-->
<!-- <item name="shapeAppearanceMediumComponent">@style/ShapeAppearance.App.MediumComponent</item>--> <style name="Theme.App" parent="Theme.Material3.Dark.NoActionBar">
</style> <item name="colorPrimary">@color/hl_orange</item>
</resources> <item name="colorPrimaryDark">@color/hl_dark_grey</item>
<!-- <item name="colorPrimaryContainer">@color/valve_red</item>-->
<item name="colorSurface">@color/hl_grey</item>
<item name="colorSurfaceVariant">@color/hl_grey</item>
<item name="android:colorBackground">@color/hl_dark_grey</item>
<item name="colorControlNormal">@color/hl_orange</item>
<item name="colorOnPrimary">@color/hl_dark_grey</item>
<!-- <item name="colorOnPrimaryContainer">@android:color/white</item>-->
<!-- <item name="colorOnSurface">@android:color/white</item>-->
<!-- <item name="colorOnSurfaceVariant">@android:color/white</item>-->
<!-- <item name="shapeAppearanceMediumComponent">@style/ShapeAppearance.App.MediumComponent</item>-->
</style>
</resources>

View File

@@ -1,8 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<SwitchPreferenceCompat <Preference
app:key="use_icons" app:key="game_path"
app:layout="@layout/switch_preference" app:layout="@layout/edit_text_preference"
app:title="@string/preferences_use_icons" /> app:title="@string/game_data_location"
</PreferenceScreen> android:summary="/storage/emulated/0/xash" />
<SwitchPreferenceCompat
app:key="use_icons"
app:layout="@layout/switch_preference"
app:title="@string/preferences_use_icons" />
</PreferenceScreen>

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