Compare commits

...

22 Commits

Author SHA1 Message Date
Alibek Omarov
8c89579c35 3rdparty: nanogl: update 2026-08-04 21:58:54 +05:00
Alibek Omarov
18dddaf1a5 3rdparty: nanogl: update 2026-08-03 23:44:48 +05:00
Alibek Omarov
d3bcdc6c06 engine: imagelib: Image_SaveWAD refactoring 2026-08-03 21:55:03 +05:00
Andrey Akhmichin
c0a40f6e03 Documentation: opensource-mods.md: add Zombie Panic. 2026-08-03 18:43:59 +08:00
Andrey Akhmichin
e3e459bb67 Documentation: supported-mod-list.md: add Half-Life: Sum. 2026-08-02 18:12:30 +05:00
Andrey Akhmichin
badda6c585 Documentation: opensource-mods.md: add Half-Life: Sum. 2026-08-02 18:05:46 +05:00
Andrey Akhmichin
db68b7c6e7 Documentation: supported-mod-list.md: update. 2026-08-01 19:20:22 +05:00
Andrey Akhmichin
841b2bcf5a Documentation: opensource-mods.md: update. 2026-08-01 19:19:50 +05:00
Alibek Omarov
a5fb74eb8f engine: use XASH_OSX macro 2026-08-01 16:12:04 +05:00
Alibek Omarov
31d44f85a7 engine: implement reading hardware serial ID on Mac, implement reading MAC addresses on *BSDs, refactoring 2026-08-01 16:12:04 +05:00
Alibek Omarov
24f8525fad engine: server: refactoring. 2026-08-01 16:12:04 +05:00
SLB8910
04fbe1a356 CONTRIBUTING.md: fixed horrible grammer
made contributing.md actually readable
2026-07-30 20:55:09 +05:00
Andrey Akhmichin
ecda80fb9a Documentation: supported-mod-list.md: update. 2026-07-29 02:43:00 +05:00
Владислав Сухов
9f14c48787 3rdparty: mainui: update 2026-07-27 18:47:53 +04:00
Владислав Сухов
8b15bc9a96 3rdparty: mainui: update 2026-07-26 18:08:54 +05:00
Andrey Akhmichin
e6913c9ce2 Documentation: opensource-mods.md: update. 2026-07-26 08:24:34 +05:00
lewa_j
b4495238d9 3rdparty: gl4es: update from upstream, with msvc build fix 2026-07-25 17:33:13 +03:00
lewa_j
635b382c1d gl4es: msvc: suppress warning spam from CHECK_SHADER: warning C4098: 'void' function returning a value
Same flag is used in gl4es's CMakeLists
2026-07-25 15:26:25 +03:00
Terence Noone
7fbd461f83 engine: Format code
Ran uncrustify on each file
2026-07-24 14:23:39 +05:00
Terence Noone
eb0ff8e631 engine: Implement SDL3 resizing/mode switching
Adds the ability to switch to fullscreen, windowed, and borderless, as
well as changing fullscreen mode.
2026-07-24 14:23:39 +05:00
Terence Noone
f50e61403f engine: Fix SDL3 support
Gets SDL3 building again on macOS. The game is able to boot to the main
menu and play with hlsdk-portable and HL assets. Some bugs when changing
video modes.
2026-07-24 14:23:39 +05:00
Alibek Omarov
2cf8c63631 engine: server: fix a typo, we should set pmove frametime before calling server pmove, instead of server global pmove, like GoldSrc
Thanks to @dkenw for drawing attention to this issue.
2026-07-22 17:36:32 +05:00
24 changed files with 1081 additions and 426 deletions

View File

@@ -16,6 +16,8 @@ def build(bld):
cflags = []
if bld.env.COMPILER_CC != 'msvc':
cflags += ['-w', '-fvisibility=hidden', '-std=gnu99']
else:
cflags += ['-wd4098']
bld.stlib(source = gl4es_srcdir.ant_glob(['gl/*.c', 'gl/*/*.c', 'glx/hardext.c']),
target = 'gl4es',
includes = ['gl4es/src', 'gl4es/src/gl', 'gl4es/src/glx', 'gl4es/include'],

View File

@@ -1,53 +1,55 @@
## If you are reporting bugs
1. Check you are using latest version. You can build latest Xash3D FWGS for yourself, look to README.md.
2. Check open issues is your bug is already reported and closed issues if it reported and fixed. Don't send bug if it's already reported.
3. Re-run engine with `-dev 2 -log` arguments, reproduce bug and post engine.log which can be found in your working directory.
3. Describe steps to reproduce bug.
1. Check that you are using the latest version. To build the latest Xash3D FWGS, look at README.md.
2. Check the open issues to make sure your bug is not already reported and closed issues if it reported and fixed. Don't send a bug if it's already been reported.
3. Re-run engine with `-dev 2 -log` arguments, then reproduce the bug and post `engine.log` which can be found in your working directory.
3. Describe the steps to reproduce the bug.
4. Describe which OS and architecture you are using.
6. Attach screenshot if it will help clarify the situation.
6. Attach a screenshot if it will help clarify the situation.
## If you are contributing code
### Which branch?
* We recommend using `master` branch.
* We recommend using the `master` branch.
### Third-party libraries
* Philosophy of any Xash Project by Uncle Mike: don't be bloated. We follow it too.
* Adding new library is allowed only if there is a REAL reason to use it. It's will be nice, if you will leave a possibility to remove new dependency at build-time.
* Adding new dependencies for Waf Build System is not welcomed.
* The philosophy of any Xash Project by Uncle Mike: don't be bloated. We follow it too.
* Adding new libraries are allowed only if there is a REAL reason to use it. It will be nice, if you leave a possibility to remove the new dependency at build-time.
* Adding new dependencies for the Waf Build System is not welcomed.
### Portability level
* Xash3D have it's own crt library. It's recommended to use it. It most cases it's just a wrappers around standart C library.
* If your feature need platform-specific code, move it to `engine/platform` and try to implement to every supported OS and every supported compiler or at least leave a stubs.
* You must put it under appopriate macro. It's a rule: Xash3D FWGS must compile everywhere. For list of platforms we support, refer to public/build.h file.
* Xash3D has it's own crt library. It's recommended to use it. In most cases it's just a wrapper around the standard C library.
* If your feature needs platform-specific code, move it to `engine/platform` and try to implement every supported OS and every supported compiler or at least leave a stub.
* You must put it under the appropriate macro. It's a rule: Xash3D FWGS must compile everywhere. For list of platforms we support, refer to `public/build.h`.
### Code style
* This project uses mixed Quake's and HLSDK's C/C++ code style convention.
* This project uses a mix of Quake's and HLSDK's C/C++ code style convention.
* In short:
* Use spaces in parenthesis, but not when two parentheses are consecutive.
* Only tabs for indentation.
* Use only tabs for indentation.
* Any brace must have it's own line.
* Short blocks, if statements and loops on single line are allowed.
* Use short blocks, if statements and loops on single line are allowed.
* Prefer generic utilities from libpublic over rolling your own.
* Avoid magic numbers.
* While macros are powerful, it's better to avoid overusing them.
* If you unsure, try to mimic code style from anywhere else of engine source code.
* **ANY** commit message should start from declaring a tags, in format:
* If you are unsure, try to mimic the code style from anywhere else in the engine source code.
* **ANY** commit message should start from declaring tags, in the format:
`tag: added some bugs`
`tag: subtag: fixed some features`
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.
The tags can be a:
* subsystem
* simple feature name or even just a filename, without the extension.
Just always keep them the same because it helps keep the commit history clean and 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.
Whether you're reporting a bug or contributing to the code, you will take complete authorship and responsibility over the provided content, and the same rules will apply to you as for everybody else, so validate the bug report or the patch it before sending it.

View File

@@ -38,6 +38,9 @@ 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
## Crack-Life Anniversary Campaign
Available on ModDB - https://www.moddb.com/mods/crack-life/downloads/crack-life-anniversary-campaign-sdk
## Cthulhu
Uploaded to github by Oleg Cherkasky - https://github.com/gunrunners-paradise/Cthulhu-HLmod-SDK
@@ -62,11 +65,14 @@ Available on GamerLab - http://gamer-lab.com/eng/code_mods_goldsrc/Half-Life_2D_
## Gang Wars
Mirrored on github - https://github.com/nekonomicon/gw1.45src
## Go-mod
## Go-Mod
Versions 2.0 and 3.0, available in mod archives on ModDB - https://www.moddb.com/mods/go-mod/downloads
Version 3.0, mirrored on github - https://github.com/nekonomicon/Go-mod30
## Go-Mod: Reborn
Official github repository - https://github.com/LambdaLuke87/Go-Mod-Reborn-Lite-Build
## GT mod
Available on GamerLab - http://gamer-lab.com/eng/code_mods_goldsrc/GT_mod_(Polnie_ishodniki)
@@ -85,12 +91,21 @@ Available on ModDB - https://www.moddb.com/mods/half-life-echoes
## Half-Life: Expanded Arsenal
Available on ModDB - https://www.moddb.com/mods/half-life-expanded-arsenal
## Half-Life: Featureful
Branch **featureful** in halflife-featureful - https://github.com/FreeSlave/halflife-featureful
## Half-Life: Field Intensity
Branch **field_intensity_1.7** in halflife-featureful - https://github.com/FreeSlave/halflife-featureful/tree/field_intensity_1.7
## Half-Life: Gravgun mod
Branch **gravgun** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/gravgun
## Half-Life: Induction
Version 1.4: Branch **induction** in halflife-featureful - https://github.com/FreeSlave/halflife-featureful/tree/induction
## Half-Life: Insecure
Version 1.5 is available on ModDB - https://www.moddb.com/mods/half-life-insecure/downloads/half-life-insecure-map-tools-and-source-code-ver-15
## Half-Life: Invasion
Official github repository - https://github.com/jlecorre/hlinvasion
@@ -100,6 +115,13 @@ Mirrored on github - https://github.com/solidi/hl-mods/tree/master/pong
## Half-Life: Quest Mode
Available on cs-mapping.com.ua - https://old.cs-mapping.com.ua/forum/showthread.php?t=38030
## Half-Life: Sum
Original Version: Branch **sum_orig** in halflife-featureful - https://github.com/FreeSlave/halflife-featureful/tree/sum_orig
Version 2022: Branch **sum_2022** in halflife-featureful - https://github.com/FreeSlave/halflife-featureful/tree/sum_2022
Current Version: Branch **sum** in halflife-featureful - https://github.com/FreeSlave/halflife-featureful/tree/sum
## Half-Life: Top-Down
Official gitlab repository - https://gitlab.com/Sockman/hltopdown
@@ -109,6 +131,9 @@ Official github repository - https://github.com/Fograin/hl-subsmod-ex
## Half-Life: Rally
Official gitlab repository - https://gitlab.com/hlrally/src
## Half-Life: Reprocessing
Official github repository - https://github.com/EgorYak/ReprocessingSourceCode
## Half-Life: RXT
Available on ModDB - https://www.moddb.com/mods/half-life-rxt/downloads/rxt-source-code-v57
@@ -147,6 +172,9 @@ Mirrored on github (Includes maps and models source files) - https://github.com/
## Ingram Chillin' Mod
Official SourceForge repository - https://sourceforge.net/projects/icm-hl/
## Intense Force
Branch **intense_force** in halflife-featureful - https://github.com/FreeSlave/halflife-featureful/tree/intense_force
## Master Sword
Official github repository of Master Sword Classic - https://github.com/BerntA/MasterSwordClassic
@@ -189,6 +217,9 @@ Available in Valve's Half-Life repository - https://github.com/ValveSoftware/hal
## Spirit of Half-Life
[Logic&Trick's](https://github.com/LogicAndTrick) mirror - https://files.logic-and-trick.com/#/Half-Life/Mods/Spirit%20of%20Half-Life
## The Last Bullet
Official github repository - https://github.com/GT-Project-Cat/The-Last-Bullet-Updated-Code
## The Wastes
Version 1.5: mirrored on code.idtech.space - https://code.idtech.space/vera/halflife-thewastes-sdk
@@ -212,6 +243,19 @@ Download page on official site - http://www.thothie.com/ww/
## Wrong Door
Available on ModDB - https://www.moddb.com/mods/wrong-door/downloads/wrong-door-sdk
## XDM
*This mod is opensource but access to source code is always rebus*
How to get sources of version 3.0.4.3:
Download SFX-archive from ModDB - https://www.moddb.com/mods/xdm/downloads/xdm3043
Extract it.
Open client.dll in HEX-editor and patch header - change `Win!` to `Rar!`
Extract it using unrar - password `iamtheone`
## XashXT
Mirrored on github - https://github.com/a1batross/XashXT_original
@@ -220,6 +264,12 @@ Mirrored on github - https://github.com/a1batross/XashXT_original
[Logic&Trick's](https://github.com/LogicAndTrick) mirror - https://files.logic-and-trick.com/#/Half-Life/Mods/Spirit%20of%20Half-Life
## Yet another PS2 Half-Life port
Official github repository - https://github.com/supadupaplex/ya-ps2hl-dll
## Zombie Panic!
Official github repository - https://github.com/Monochrome-Inc/ZombiePanic-HL
## Zombie-X
Available in mod archive on ModDB - https://www.moddb.com/mods/zombie-x-10-final/downloads/zombie-x-10-dle-beta6-last-version
@@ -301,7 +351,7 @@ Unkle Mike's recreation - https://hlfx.ru/forum/showthread.php?s=&threadid=5253
Reverse-engineered code: branch **bshift** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/bshift
## Half-Life: Induction
Branch **induction** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/induction
Version 1.0-1.2: Branch **induction_1.2** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/induction_1.2
## Half-Life: Opposing Force
Recreation by lostgamer aka nillerusr - https://github.com/LostGamerHL/hlsdk-xash3d
@@ -375,6 +425,9 @@ Branch **aghl** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/
## Bubblemod
Branch **bubblemod** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/bubblemod
## Counter-Life
Branch **counter-life** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/counter-life
## Deathmatch Classic
Deathmatch Classic: Adrenaline Gamer Edition - https://github.com/martinwebrant/agmod/tree/master/src/dmc
@@ -388,6 +441,9 @@ Branch **delta_particles** in hlsdk-portable - https://github.com/FWGS/hlsdk-por
## Half-Life: Echoes
Branch **echoes** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/echoes
## Half-Life: Insecure
Branch **insecure** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/insecure
## Half-Life: Invasion
Port to HLSDK 2.4 by malortie - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-invasion
@@ -421,6 +477,8 @@ Branch **dmc** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/d
## Xen-Warrior
Branch **sohl1.2** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/sohl1.2
## Yet another PS2 Half-Life port
Branch **ps2hl** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/ps2hl
## Zombie-X
Branch **zombie-x** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/zombie-x

View File

@@ -892,6 +892,8 @@ Currently, fresh Xash3D FWGS builds for Android, PS Vita and Nintendo Switch use
## List of games and mods with custom gamedll
For mods from this category - first of all place mod folder beside **valve** folder.
NOTE: Precompiled libraries for some mods from this category may be already available for your platform in [hlsdk-mega-build](https://github.com/FWGS/hlsdk-mega-build) and this mods may be launch on Android out-of-the-box.
1. **[Absolute Redemption](https://www.moddb.com/mods/absolute-redemption)**
To run this mod on specific platforms you may be need to compile libraries from **redemption** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
@@ -950,7 +952,11 @@ This mod already supports x86 Linux.
Support for other platforms may be available later.
14. **[Counter Strike 1.6](https://store.steampowered.com/app/10/CounterStrike/)**
14. **[Counter-Life](https://www.moddb.com/mods/counter-life)**
To run this mod on specific platforms you may be need to compile libraries from **counter-life** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
15. **[Counter Strike 1.6](https://store.steampowered.com/app/10/CounterStrike/)**
On x86 you may be need to compile client part.
@@ -962,57 +968,65 @@ Client: https://github.com/Velaron/cs16-client/
Server: https://github.com/rehlds/ReGameDLL_CS
15. **[Crack-Life](https://www.moddb.com/mods/crack-life/downloads/crack-life)**
16. **[Crack-Life](https://www.moddb.com/mods/crack-life/downloads/crack-life)**
To run this mod on specific platforms you may be need to compile libraries from **cracklife** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
16. **[Crack-Life: Campaign Mode](https://www.moddb.com/mods/crack-life/downloads/crack-life-campaign-mode)**
17. **[Crack-Life: Campaign Mode](https://www.moddb.com/mods/crack-life/downloads/crack-life-campaign-mode)**
To run this mod on specific platforms you may be need to compile libraries from **clcampaign** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
17. **[Deathmatch Classic](https://store.steampowered.com/app/40/Deathmatch_Classic/)**
18. **[Deathmatch Classic](https://store.steampowered.com/app/40/Deathmatch_Classic/)**
Steam version already supports x86 Linux.
To run this mod on specific platforms you may be need to compile libraries from **dmc** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
18. **[Delta Particles](https://www.moddb.com/mods/half-life-delta)**
19. **[Delta Particles](https://www.moddb.com/mods/half-life-delta)**
This mod already supports x86 Linux.
Support for other platforms may be available later.
To run this mod on specific platforms you may be need to compile libraries from **delta_particles** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
19. **[Escape from the Darkness](https://www.moddb.com/mods/escape-from-the-darkness)**
20. **[Escape from the Darkness](https://www.moddb.com/mods/escape-from-the-darkness)**
To run this mod on specific platforms you may be need to compile libraries from **eftd** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
20. **[Gang Wars](https://www.moddb.com/mods/gangwars)**
21. **[Gang Wars](https://www.moddb.com/mods/gangwars)**
This mod already supports x86 Linux.
Support for other platforms may be available later.
21. **[Half-Life: Blue Shift](https://store.steampowered.com/app/130/HalfLife_Blue_Shift/)**
22. **[Half-Life: Blue Shift](https://store.steampowered.com/app/130/HalfLife_Blue_Shift/)**
To run this mod on specific platforms you may be need to compile libraries from **bshift** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
22. **[Half-Life: Decay](https://www.moddb.com/mods/half-life-decay)**
23. **[Half-Life: Decay](https://www.moddb.com/mods/half-life-decay)**
Currently, you can compile mod libraries for x86 Linux from **decay-pc** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
Support for other platforms may be available later.
23. **[Half-Life: Echoes](https://www.moddb.com/mods/half-life-echoes)**
24. **[Half-Life: Echoes](https://www.moddb.com/mods/half-life-echoes)**
To run this mod on specific platforms you may be need to compile libraries from **echoes** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
24. **[Half-Life: Field Intensity](https://www.moddb.com/mods/field-intensity)**
25. [Half-Life: Featureful](https://freeslave.github.io/halflife-featureful/)
*It's modding SDK*
This mod already supports x86 Linux.
Support for other platforms may be available later.
To run this mod on specific platforms you may be need to compile libraries from **featureful** branch of [halflife-featureful](https://github.com/FreeSlave/halflife-featureful).
25. **Half-Life: Gravgun** (unfinished) by *mittorn*, *a1batross* and *Solexid*
26. **[Half-Life: Field Intensity](https://www.moddb.com/mods/field-intensity)**
This mod already supports x86 Linux.
To run this mod on specific platforms you may be need to compile libraries from **field_intensity_1.7** branch of [halflife-featureful](https://github.com/FreeSlave/halflife-featureful).
27. **Half-Life: Gravgun** (unfinished) by *mittorn*, *a1batross* and *Solexid*
*Support temporary abandoned*
@@ -1022,163 +1036,197 @@ Currently, MSVC is not supported, use MinGW if you need build for Windows.
Mod files: [1](http://mittorn.fwgs.ru/coop-entpatches/), [2](http://mittorn.fwgs.ru/ggm/), [3](https://github.com/nillerusr/gravgun-extras).
26. **[Half-Life: Induction 1.2](https://www.moddb.com/mods/half-life-induction)**
28. **[Half-Life: Induction 1.2](https://www.moddb.com/mods/half-life-induction)**
To run this mod on specific platforms you may be need to compile libraries from **induction_1.2** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
27. **[Half-Life: Invasion](https://www.moddb.com/mods/half-life-invasion)**
29. **[Half-Life: Induction 1.4](https://www.moddb.com/mods/half-life-induction)**
This mod supports x86 Linux.
This mod already supports x86 Linux.
Support for other platforms may be available later.
To run this mod on specific platforms you may be need to compile libraries from **induction** branch of [halflife-featureful](https://github.com/FreeSlave/halflife-featureful).
28. **[Half-Life: Intense Force](https://www.moddb.com/downloads/intense-force)**
30. **[Half-Life: Insecure](https://www.moddb.com/mods/half-life-insecure)**
To run this mod on specific platforms you may be need to compile libraries from **insecure** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
31. **[Half-Life: Intense Force](https://www.moddb.com/downloads/intense-force)**
This mod already supports x86 Linux.
To run this mod on specific platforms you may be need to compile libraries from **intense_force** branch of [halflife-featureful](https://github.com/FreeSlave/halflife-featureful).
29. **[Half-Life: Opposing Force](https://store.steampowered.com/app/50/HalfLife_Opposing_Force/)**
32. **[Half-Life: Invasion](https://www.moddb.com/mods/half-life-invasion)**
This mod supports x86 Linux.
Support for other platforms may be available later.
33. **[Half-Life: Opposing Force](https://store.steampowered.com/app/50/HalfLife_Opposing_Force/)**
Steam version already supports x86 Linux.
To run this mod on specific platforms you may be need to compile libraries from **opfor** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
30. **[Half-Life: Quest mod](https://csm.dev/threads/half-life-the-quest-mod-isxodniki.38030/)**
34. **[Half-Life: Quest mod](https://csm.dev/threads/half-life-the-quest-mod-isxodniki.38030/)**
To run this mod on specific platforms you may be need to compile libraries from **sci** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
31. **[Half-Life: TopDown](https://www.moddb.com/mods/half-life-top-downs)**
35. **[Half-Life: Sum](https://www.moddb.com/mods/half-life-sum)**
This mod already supports x86 Linux.
To run this mod on specific platforms you may be need to compile libraries from **sum** branch of [halflife-featureful](https://github.com/FreeSlave/halflife-featureful).
36. **[Half-Life: TopDown](https://www.moddb.com/mods/half-life-top-downs)**
To run this mod on specific platforms you may be need to compile libraries from **topdown** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
32. **[Half-Life: Urbicide](https://www.moddb.com/mods/half-life-urbicide)**
37. **[Half-Life: Urbicide](https://www.moddb.com/mods/half-life-urbicide)**
To run this mod on specific platforms you may be need to compile libraries from **hl_urbicide** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
33. **[Half-Life: Visitors](https://www.moddb.com/mods/half-life-visitors)**
38. **[Half-Life: Visitors](https://www.moddb.com/mods/half-life-visitors)**
To run this mod on specific platforms you may be need to compile libraries from **visitors** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
34. **[Half-Rats: Parasomnia](https://www.moddb.com/mods/half-rats-parasomnia/downloads/half-rats-parasomnia-v10b-steamlinux)**
39. **[Half-Rats: Parasomnia](https://www.moddb.com/mods/half-rats-parasomnia/downloads/half-rats-parasomnia-v10b-steamlinux)**
This mod already supports x86 Linux.
Support for other platforms may be available later.
35. **[Half-Screwed: Death and Rebirth](https://www.moddb.com/mods/half-screwed)**
40. **[Half-Screwed: Death and Rebirth](https://www.moddb.com/mods/half-screwed)**
To run this mod on specific platforms you may be need to compile libraries from **half-screwed** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
36. **[Half-Secret](https://www.moddb.com/mods/half-secret)**
41. **[Half-Secret](https://www.moddb.com/mods/half-secret)**
To run this mod on specific platforms you may be need to compile libraries from **half-secret** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
37. **[Natural Selection](https://www.moddb.com/mods/natural-selection)**
42. **[Mortal Kombat](https://www.moddb.com/mods/hl-mortal-kombat)**
This mod already supports Android and x86 Linux.
43. **[Natural Selection](https://www.moddb.com/mods/natural-selection)**
This mod already supports x86 Linux.
Support for other platforms may be available later.
38. **[Night at the Office](https://www.moddb.com/mods/night-at-the-office)**
44. **[Night at the Office](https://www.moddb.com/mods/night-at-the-office)**
To run this mod on specific platforms you may be need to compile libraries from **noffice** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
39. **[Paranoia](https://www.moddb.com/mods/paranoia)**
45. **[Paranoia](https://www.moddb.com/mods/paranoia)**
*Support temporary abandoned*
[Source code](https://github.com/FWGS/paranoia_toolkit).
40. **[Poke646](https://poke646.com/)**
46. **[Poke646](https://poke646.com/)**
To run this mod on specific platforms you may be need to compile libraries from **poke646** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
41. **[Poke646: Vendetta](https://poke646.com/)**
47. **[Poke646: Vendetta](https://poke646.com/)**
To run this mod on specific platforms you may be need to compile libraries from **poke646_vendetta** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
42. [PrimeXT](https://snmetamorph.github.io/PrimeXT/)
48. [PrimeXT](https://snmetamorph.github.io/PrimeXT/)
*It's modding SDK*
[Source code](https://github.com/SNMetamorph/PrimeXT)
43. **[Quake Remake](https://www.moddb.com/games/quake-remake)**
49. **[Quake Remake](https://www.moddb.com/games/quake-remake)**
*Support was fully abandoned due Quake Wrapper release.*
[Actual source code](https://github.com/FWGS/quakeremake)
44. **[Rebellion](https://www.moddb.com/mods/rebellion1)**
50. **[Rebellion](https://www.moddb.com/mods/rebellion1)**
To run this mod on specific platforms you may be need to compile libraries from **rebellion** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
45. **[Residual Life](https://www.moddb.com/mods/hl-residual-life)**
51. **[Residual Life](https://www.moddb.com/mods/hl-residual-life)**
To run this mod on specific platforms you may be need to compile libraries from **residual_point** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
46. **[Residual Point](https://www.moddb.com/mods/hl-residual-point)**
52. **[Residual Point](https://www.moddb.com/mods/hl-residual-point)**
To run this mod on specific platforms you may be need to compile libraries from **residual_point** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
47. **[Ricochet](https://store.steampowered.com/app/60/Ricochet/)**
53. **[Ricochet](https://store.steampowered.com/app/60/Ricochet/)**
This mod already supports x86 Linux.
Support for other platforms may be available later.
48. [Sewer](https://www.moddb.com/games/half-life/addons/sewer-beta)
54. [Sewer](https://www.moddb.com/games/half-life/addons/sewer-beta)
To run this mod on specific platforms you may be need to compile libraries from **sewer_beta** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
49. [Spirit of Half-Life 1.2](https://www.moddb.com/mods/spirit-of-half-life)
55. [Spirit of Half-Life 1.2](https://www.moddb.com/mods/spirit-of-half-life)
*It's modding SDK*
To run this mod on specific platforms you may be need to compile libraries from **sohl1.2** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
50. **[Swiss Cheese Halloween](https://www.moddb.com/mods/half-life-halloween-mod)**
56. **[Swiss Cheese Halloween](https://www.moddb.com/mods/half-life-halloween-mod)**
To run this mod on specific platforms you may be need to compile libraries from **halloween** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
51. **[Team Fortress Classic](https://store.steampowered.com/app/20/Team_Fortress_Classic/)**
57. **[Team Fortress Classic](https://store.steampowered.com/app/20/Team_Fortress_Classic/)**
This mod already supports x86 Linux.
Currently, only source code of [client part](https://github.com/Velaron/tf15-client) is available.
52. **[The Gate](https://www.moddb.com/mods/the-gate)**
58. **[The Gate](https://www.moddb.com/mods/the-gate)**
To run this mod on specific platforms you may be need to compile libraries from **thegate** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
53. **[They Hunger: Trilogy](https://www.moddb.com/mods/they-hunger)**
59. **[The Last Bullet](https://www.moddb.com/mods/the-last-bullet-update)**
To run this mod on specific platforms you may be need to compile libraries from **fwgs** branch of [The-Last-Bullet-Updated-Code](https://github.com/GT-Project-Cat/The-Last-Bullet-Updated-Code).
60. **[They Hunger: Trilogy](https://www.moddb.com/mods/they-hunger)**
To run this mod on specific platforms you may be need to compile libraries from **theyhunger** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
54. **[ThreeWave CTF](https://www.moddb.com/games/deathmatch-classic/downloads/threewave-ctf)**
61. **[ThreeWave CTF](https://www.moddb.com/games/deathmatch-classic/downloads/threewave-ctf)**
To run this mod on specific platforms you may be need to compile libraries from **dmc** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
55. **[Times of Troubles](https://www.moddb.com/mods/times-of-troubles)**
62. **[Times of Troubles](https://www.moddb.com/mods/times-of-troubles)**
To run this mod on specific platforms you may be need to compile libraries from **tot** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
56. [XashXT](https://csm.dev/threads/xashxt-0-65-rev-4-release-stable.38319/)
63. [XashXT](https://csm.dev/threads/xashxt-0-65-rev-4-release-stable.38319/)
*It's modding SDK*
*Support was fully abandoned due PrimeXT development*
[Source code](https://github.com/FWGS/XashXT-FWGS/)
57. **[X-Half-Life DeathMatch](https://www.moddb.com/mods/xdm)**
64. **[X-Half-Life DeathMatch](https://www.moddb.com/mods/xdm)**
This mod already supports x86 Linux.
Support for other platforms may be available later.
58. **[Xen-Warrior](https://www.moddb.com/mods/xen-warrior)**
65. **[Xen-Warrior](https://www.moddb.com/mods/xen-warrior)**
To run this mod on specific platforms you may be need to compile libraries from **sohl1.2** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
Don't forget to enable XENWARRIOR build option!!!
59. [Zombie-X](https://www.moddb.com/mods/zombie-x-10-final)
66. **[Yet another PS2 Half-Life port](https://www.moddb.com/mods/yet-another-ps2-half-life-pc-port)**
To run this mod on specific platforms you may be need to compile libraries from **ps2hl** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).
67. [Zombie-X](https://www.moddb.com/mods/zombie-x-10-final)
To run this mod on specific platforms you may be need to compile libraries from **zombie-x** branch of [hlsdk-portable](https://github.com/FWGS/hlsdk-portable).

View File

@@ -15,14 +15,13 @@ GNU General Public License for more details.
#include "build.h"
#include <inttypes.h>
#if XASH_LINUX
#include <fcntl.h>
#if !XASH_WIN32
#include <dirent.h>
#else
#include <io.h>
#endif
#include "common.h"
#include "client.h"
#include "platform/platform.h"
/*
==========================================================
@@ -97,8 +96,6 @@ IDENTIFICATION
#define MAXBITS_GEN 30
#define MAXBITS_CHECK MAXBITS_GEN + 6
static qboolean ID_ProcessFile( bloomfilter_t *value, const char *path );
static void ID_BloomFilter_f( void )
{
bloomfilter_t value = 0;
@@ -203,84 +200,6 @@ static qboolean ID_ProcessCPUInfo( bloomfilter_t *value )
return true;
}
static qboolean ID_ValidateNetDevice( const char *dev )
{
const char *prefix = "/sys/class/net";
// These devices are fake, their mac address is generated each boot, while assign_type is 0
if( !Q_strnicmp( dev, "ccmni", sizeof( "ccmni" ) ) ||
!Q_strnicmp( dev, "ifb", sizeof( "ifb" ) ) )
return false;
byte *pfile = FS_LoadDirectFile( va( "%s/%s/addr_assign_type", prefix, dev ), NULL );
// if NULL, it may be old kernel
if( pfile )
{
int assignType = Q_atoi( (char*)pfile );
Mem_Free( pfile );
// check is MAC address is constant
if( assignType != 0 )
return false;
}
return true;
}
static int ID_ProcessNetDevices( bloomfilter_t *value )
{
const char *prefix = "/sys/class/net";
DIR *dir;
struct dirent *entry;
int count = 0;
if( !( dir = opendir( prefix ) ) )
return 0;
while( ( entry = readdir( dir ) ) && BloomFilter_Weight( *value ) < MAXBITS_GEN )
{
if( !Q_strcmp( entry->d_name, "." ) || !Q_strcmp( entry->d_name, ".." ) )
continue;
if( !ID_ValidateNetDevice( entry->d_name ) )
continue;
count += ID_ProcessFile( value, va( "%s/%s/address", prefix, entry->d_name ) );
}
closedir( dir );
return count;
}
static int ID_CheckNetDevices( bloomfilter_t value )
{
const char *prefix = "/sys/class/net";
DIR *dir;
struct dirent *entry;
int count = 0;
bloomfilter_t filter = 0;
if( !( dir = opendir( prefix ) ) )
return 0;
while( ( entry = readdir( dir ) ) )
{
if( !Q_strcmp( entry->d_name, "." ) || !Q_strcmp( entry->d_name, ".." ) )
continue;
if( !ID_ValidateNetDevice( entry->d_name ) )
continue;
if( ID_ProcessFile( &filter, va( "%s/%s/address", prefix, entry->d_name ) ) )
count += ( value & filter ) == filter, filter = 0;
}
closedir( dir );
return count;
}
static void ID_TestCPUInfo_f( void )
{
bloomfilter_t value = 0;
@@ -291,8 +210,6 @@ static void ID_TestCPUInfo_f( void )
Msg( "Could not get serial\n" );
}
#endif
static qboolean ID_ProcessFile( bloomfilter_t *value, const char *path )
{
int fd = open( path, O_RDONLY );
@@ -322,7 +239,6 @@ static qboolean ID_ProcessFile( bloomfilter_t *value, const char *path )
return true;
}
#if !XASH_WIN32
static int ID_ProcessFiles( bloomfilter_t *value, const char *prefix, const char *postfix )
{
DIR *dir;
@@ -365,7 +281,94 @@ static int ID_CheckFiles( bloomfilter_t value, const char *prefix, const char *p
closedir( dir );
return count;
}
#else
#endif // XASH_LINUX
#if XASH_POSIX
#define MAX_NETDEVICES 16
static qboolean ID_IsReservedMAC( uint64_t mac )
{
byte first = ( mac >> 40 ) & 0xff;
// no address at all
if( mac == 0 )
return true;
// group and local bits of the first octet, see https://www.rfc-editor.org/rfc/rfc9542#section-2.1.1
if( FBitSet( first, 0x01 ) || FBitSet( first, 0x02 ))
return true;
// IANA OUI, see https://www.iana.org/assignments/ethernet-numbers/ethernet-numbers.xhtml and https://www.rfc-editor.org/rfc/rfc9568#section-7.3
if(( mac >> 24 ) == 0x00005e )
return true;
return false;
}
static void ID_FormatMAC( char *out, size_t size, uint64_t mac )
{
// format exactly like /sys/class/net/ */address contents, so ids generated by older versions stay valid
Q_snprintf( out, size, "%02x:%02x:%02x:%02x:%02x:%02x\n",
(uint)(( mac >> 40 ) & 0xffu ),
(uint)(( mac >> 32 ) & 0xffu ),
(uint)(( mac >> 24 ) & 0xffu ),
(uint)(( mac >> 16 ) & 0xffu ),
(uint)(( mac >> 8 ) & 0xffu ),
(uint)( mac & 0xffu ));
}
static int ID_ProcessNetDevices( bloomfilter_t *value )
{
uint64_t macs[MAX_NETDEVICES];
int total = Posix_GetNetDeviceAddresses( macs, MAX_NETDEVICES );
int count = 0;
for( int i = 0; i < total && BloomFilter_Weight( *value ) < MAXBITS_GEN; i++ )
{
char buf[32];
if( ID_IsReservedMAC( macs[i] ))
continue;
ID_FormatMAC( buf, sizeof( buf ), macs[i] );
if( !ID_VerifyHEX( buf ))
continue;
*value |= BloomFilter_ProcessStr( buf );
count++;
}
return count;
}
static int ID_CheckNetDevices( bloomfilter_t value )
{
uint64_t macs[MAX_NETDEVICES];
int total = Posix_GetNetDeviceAddresses( macs, MAX_NETDEVICES );
int count = 0;
for( int i = 0; i < total; i++ )
{
char buf[32];
if( ID_IsReservedMAC( macs[i] ))
continue;
ID_FormatMAC( buf, sizeof( buf ), macs[i] );
if( !ID_VerifyHEX( buf ))
continue;
bloomfilter_t filter = BloomFilter_ProcessStr( buf );
count += ( value & filter ) == filter;
}
return count;
}
#endif // XASH_POSIX
#if XASH_WIN32
static int ID_GetKeyData( HKEY hRootKey, char *subKey, char *value, LPBYTE data, DWORD cbData )
{
HKEY hKey;
@@ -539,6 +542,17 @@ static bloomfilter_t ID_GenerateRawId( void )
count += ID_ProcessCPUInfo( &value );
count += ID_ProcessFiles( &value, "/sys/block", "device/cid" );
#endif
#if XASH_OSX
char buf[64];
if( Apple_GetSerialNumber( buf, sizeof( buf )))
{
value |= BloomFilter_ProcessStr( buf );
count++;
}
#endif
#if XASH_POSIX
count += ID_ProcessNetDevices( &value );
#endif
#if XASH_WIN32
@@ -587,12 +601,26 @@ static uint ID_CheckRawId( bloomfilter_t filter )
}
#endif // !XASH_ANDROID
count += ID_CheckNetDevices( filter );
count += ID_CheckFiles( filter, "/sys/block", "device/cid" );
if( ID_ProcessCPUInfo( &value ) )
count += (filter & value) == value;
#endif
#if XASH_OSX
char buf[64];
if( Apple_GetSerialNumber( buf, sizeof( buf )))
{
value = BloomFilter_ProcessStr( buf );
count += (filter & value) == value;
value = 0;
}
#endif
#if XASH_POSIX
count += ID_CheckNetDevices( filter );
#endif
#if XASH_WIN32
count += ID_CheckWMIC( filter, L"wmic path win32_physicalmedia get SerialNumber" );
count += ID_CheckWMIC( filter, L"wmic bios get serialnumber" );

View File

@@ -731,69 +731,77 @@ Image_SaveWAD
*/
qboolean Image_SaveWAD( const char *name, rgbdata_t *pix )
{
byte *mip1_data = NULL, *mip2_data = NULL, *mip3_data = NULL;
byte grad_palette[256 * 3];
file_t *f;
dwadinfo_t header =
{
.ident = IDWAD3HEADER,
.numlumps = 1,
};
mip_t miptex;
long infotableofs;
dlumpinfo_t lump;
fs_offset_t pad;
qboolean result = false;
int lump_type = ( pix->flags & IMAGE_GRADIENT_DECAL ) ? TYP_PALETTE : TYP_MIPTEX;
short palette_size = 256;
int infotableofs32 = 0;
if( !pix || !pix->buffer )
return false;
const byte *palette = pix->palette ? pix->palette : (const byte *)image.palette;
const int lump_type = ( pix->flags & IMAGE_GRADIENT_DECAL ) ? TYP_PALETTE : TYP_MIPTEX;
int m0size = pix->width * pix->height;
int m1size = m0size / 4;
int m2size = m0size / 16;
int m3size = m0size / 64;
mip1_data = (byte *)Mem_Malloc( host.imagepool, m1size );
mip2_data = (byte *)Mem_Malloc( host.imagepool, m2size );
mip3_data = (byte *)Mem_Malloc( host.imagepool, m3size );
if( !mip1_data || !mip2_data || !mip3_data )
goto cleanup;
byte *mip1_data = Mem_Malloc( host.imagepool, m1size );
byte *mip2_data = Mem_Malloc( host.imagepool, m2size );
byte *mip3_data = Mem_Malloc( host.imagepool, m3size );
if( !mip1_data || !mip2_data || !mip3_data ) // Mem_Malloc never returns NULL, but keep this check anyway
{
Mem_Free( mip1_data );
Mem_Free( mip2_data );
Mem_Free( mip3_data );
return false;
}
Image_GenerateMipmaps( pix->buffer, pix->width, pix->height, mip1_data, mip2_data, mip3_data );
memset( &miptex, 0, sizeof( mip_t ));
Q_strncpy( miptex.name, "{LOGO", sizeof( miptex.name ));
miptex.width = pix->width;
miptex.height = pix->height;
miptex.offsets[0] = sizeof( mip_t );
miptex.offsets[1] = miptex.offsets[0] + m0size;
miptex.offsets[2] = miptex.offsets[1] + m1size;
miptex.offsets[3] = miptex.offsets[2] + m2size;
f = FS_Open( name, "wb", false );
file_t *f = FS_Open( name, "wb", false );
if( !f )
goto cleanup;
{
Mem_Free( mip1_data );
Mem_Free( mip2_data );
Mem_Free( mip3_data );
return false;
}
le_struct_swap( dwadinfo_swap, &header );
FS_Write( f, &header, sizeof( header ));
{
dwadinfo_t header =
{
.ident = IDWAD3HEADER,
.numlumps = 1,
};
le_struct_swap( dwadinfo_swap, &header );
FS_Write( f, &header, sizeof( header ));
}
mip_t miptex = {
.name = "{LOGO",
.width = pix->width,
.height = pix->height,
.offsets[0] = sizeof( mip_t ),
.offsets[1] = sizeof( mip_t ) + m0size,
.offsets[2] = sizeof( mip_t ) + m0size + m1size,
.offsets[3] = sizeof( mip_t ) + m0size + m1size + m2size,
};
le_struct_swap( mip_swap, &miptex );
FS_Write( f, &miptex, sizeof( mip_t ));
le_struct_swap( mip_swap, &miptex );
FS_Write( f, pix->buffer, m0size );
FS_Write( f, mip1_data, m1size );
FS_Write( f, mip2_data, m2size );
FS_Write( f, mip3_data, m3size );
palette_size = LittleShort( palette_size );
FS_Write( f, &palette_size, sizeof( short ));
{
short palette_size = LittleShort( 256 );
FS_Write( f, &palette_size, sizeof( short ));
}
const byte *palette = pix->palette ? pix->palette : (const byte *)image.palette;
if( lump_type == TYP_PALETTE )
{
const byte *frontColorPtr = palette + 255 * 3;
byte grad_palette[256 * 3];
for( int i = 0; i < 256; ++i )
{
float t = i / 255.0f;
@@ -809,34 +817,37 @@ qboolean Image_SaveWAD( const char *name, rgbdata_t *pix )
}
// padding up to a multiple of 4
pad = (( FS_Tell( f ) + 3 ) & ~3 ) - FS_Tell( f );
fs_offset_t pad = (( FS_Tell( f ) + 3 ) & ~3 ) - FS_Tell( f );
for( int i = 0; i < pad; ++i )
FS_Write( f, (const void *)&(char){0}, 1 );
{
byte x = 0;
FS_Write( f, &x, 1 );
}
infotableofs = FS_Tell( f );
memset( &lump, 0, sizeof( lump ));
lump.filepos = sizeof( dwadinfo_t );
lump.disksize = (int)( miptex.offsets[3] + m3size + sizeof( short ) + 256 * 3 );
lump.size = lump.disksize;
lump.type = (char)lump_type;
lump.attribs = 0;
Q_strncpy( lump.name, "tempdecal", sizeof( lump.name ));
le_struct_swap( dlumpinfo_swap, &lump );
FS_Write( f, &lump, sizeof( lump ));
fs_offset_t infotableofs = FS_Tell( f );
{
dlumpinfo_t lump =
{
.filepos = sizeof( dwadinfo_t ),
.disksize = (int)( miptex.offsets[3] + m3size + sizeof( short ) + 256 * 3 ),
.size = (int)( miptex.offsets[3] + m3size + sizeof( short ) + 256 * 3 ),
.type = (char)lump_type,
.attribs = 0,
.name = "tempdecal",
};
le_struct_swap( dlumpinfo_swap, &lump );
FS_Write( f, &lump, sizeof( lump ));
}
FS_Seek( f, offsetof( dwadinfo_t, infotableofs ), SEEK_SET );
infotableofs32 = LittleLong((int)infotableofs );
int infotableofs32 = LittleLong((int)infotableofs );
FS_Write( f, &infotableofs32, sizeof( int ));
FS_Close( f );
result = true;
cleanup:
if( mip1_data )
Mem_Free( mip1_data );
if( mip2_data )
Mem_Free( mip2_data );
if( mip3_data )
Mem_Free( mip3_data );
return result;
Mem_Free( mip1_data );
Mem_Free( mip2_data );
Mem_Free( mip3_data );
return true;
}

View File

@@ -0,0 +1,50 @@
/*
id_apple.c - macOS hardware serial id source
Copyright (C) 2026 Xash3D FWGS Contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "platform/platform.h"
#include <AvailabilityMacros.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
// kIOMasterPortDefault was renamed to kIOMainPortDefault in macOS 12 SDK
#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000
#define kIOMainPortDefault kIOMasterPortDefault
#endif
static qboolean Apple_GetPlatformExpertProperty( CFStringRef key, char *out, size_t size )
{
io_service_t service = IOServiceGetMatchingService( kIOMainPortDefault, IOServiceMatching( "IOPlatformExpertDevice" ));
if( !service )
return false;
qboolean ret = false;
CFTypeRef prop = IORegistryEntryCreateCFProperty( service, key, kCFAllocatorDefault, 0 );
if( prop )
{
if( CFGetTypeID( prop ) == CFStringGetTypeID() && CFStringGetCString( (CFStringRef)prop, out, size, kCFStringEncodingUTF8 ))
ret = true;
CFRelease( prop );
}
IOObjectRelease( service );
return ret;
}
qboolean Apple_GetSerialNumber( char *out, size_t size )
{
return Apple_GetPlatformExpertProperty( CFSTR( "IOPlatformSerialNumber" ), out, size );
}

View File

@@ -69,6 +69,12 @@ void IOS_LaunchDialog( void );
void Posix_Daemonize( void );
void Posix_SetupSigtermHandling( void );
char *Posix_Input( void );
// returns the number of stable network device MAC addresses, each packed into low 48 bits
int Posix_GetNetDeviceAddresses( uint64_t *addresses, int max );
#endif
#if XASH_OSX
qboolean Apple_GetSerialNumber( char *out, size_t size );
#endif
#if XASH_SDL

View File

@@ -0,0 +1,141 @@
/*
id_posix.c - network device enumeration for unique id generation
Copyright (C) 2026 Xash3D FWGS contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "platform/platform.h"
#if XASH_LINUX
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
static qboolean Posix_ValidateNetDevice( const char *dev )
{
const char *prefix = "/sys/class/net";
// These devices are fake, their mac address is generated each boot, while assign_type is 0
if( !Q_strnicmp( dev, "ccmni", sizeof( "ccmni" ) - 1 ) || !Q_strnicmp( dev, "ifb", sizeof( "ifb" ) - 1 ))
return false;
byte *pfile = FS_LoadDirectFile( va( "%s/%s/addr_assign_type", prefix, dev ), NULL );
// if NULL, it may be old kernel
if( pfile )
{
int assignType = Q_atoi( (char*)pfile );
Mem_Free( pfile );
// check is MAC address is constant
if( assignType != 0 )
return false;
}
return true;
}
int Posix_GetNetDeviceAddresses( uint64_t *addresses, int max )
{
const char *prefix = "/sys/class/net";
DIR *dir = opendir( prefix );
struct dirent *entry;
int count = 0;
if( !dir )
return 0;
while(( entry = readdir( dir )) && count < max )
{
if( !Q_strcmp( entry->d_name, "." ) || !Q_strcmp( entry->d_name, ".." ))
continue;
if( !Posix_ValidateNetDevice( entry->d_name ))
continue;
int fd = open( va( "%s/%s/address", prefix, entry->d_name ), O_RDONLY );
if( fd < 0 )
continue;
char buffer[64];
int ret = read( fd, buffer, sizeof( buffer ) - 1 );
close( fd );
if( ret <= 0 )
continue;
buffer[ret] = 0;
uint mac[6];
char term = 0;
if( sscanf( buffer, "%02x:%02x:%02x:%02x:%02x:%02x%c", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5], &term ) < 6 )
continue;
// skip malformed or long address devices, we only need MAC addresses and they're always 48-bit
if( term != '\n' && term != '\0' )
continue;
addresses[count] = ((uint64_t)mac[0] << 40) | ((uint64_t)mac[1] << 32) | ((uint64_t)mac[2] << 24) | ((uint64_t)mac[3] << 16) | ((uint64_t)mac[4] << 8) | (uint64_t)mac[5];
count++;
}
closedir( dir );
return count;
}
#elif XASH_APPLE || XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <net/if_dl.h>
int Posix_GetNetDeviceAddresses( uint64_t *addresses, int max )
{
struct ifaddrs *ifaddr;
int count = 0;
if( getifaddrs( &ifaddr ) < 0 )
return 0;
for( struct ifaddrs *ifa = ifaddr; ifa != NULL && count < max; ifa = ifa->ifa_next )
{
if( !ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_LINK )
continue;
if( FBitSet( ifa->ifa_flags, IFF_LOOPBACK | IFF_POINTOPOINT ))
continue;
const struct sockaddr_dl *sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
if( sdl->sdl_alen != 6 )
continue;
const byte *mac = (const byte *)LLADDR( sdl );
addresses[count] = ((uint64_t)mac[0] << 40) | ((uint64_t)mac[1] << 32) | ((uint64_t)mac[2] << 24) | ((uint64_t)mac[3] << 16) | ((uint64_t)mac[4] << 8) | (uint64_t)mac[5];
count++;
}
freeifaddrs( ifaddr );
return count;
}
#else
int Posix_GetNetDeviceAddresses( uint64_t *addresses, int max )
{
Con_Reportf( S_WARN "%s: implement me!\n", __func__ );
return 0;
}
#endif

View File

@@ -28,4 +28,12 @@ GNU General Public License for more details.
void SDLash_InitCursors( void );
void SDLash_FreeCursors( void );
//
// sensor_sdl3.c
//
void SDLash_InitSensors( void );
void SDLash_ShutdownSensors( void );
qboolean SDLash_GyroIsAvailable( void );
void SDLash_SensorUpdate( SDL_SensorEvent sensor );
#endif // PLATFORM_SDL3_H

View File

@@ -0,0 +1,98 @@
/*
sensor_sdl3.c - SDL3 sensor handling
Copyright (C) 2026 Xash3D FWGS contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "common.h"
#include "input.h"
#include "platform_sdl3.h"
static SDL_SensorID g_system_gyro_id = -1;
static SDL_Sensor *g_system_gyro;
/*
==============
SDLash_InitSensors
==============
*/
void SDLash_InitSensors( void )
{
if( SDL_InitSubSystem( SDL_INIT_SENSOR ) == 0 )
{
int num_sensors;
SDL_SensorID *sensors = SDL_GetSensors( &num_sensors );
for( int i = 0; i < num_sensors; i++ )
{
if( SDL_GetSensorTypeForID( i ) == SDL_SENSOR_GYRO )
{
g_system_gyro = SDL_OpenSensor( i );
if( g_system_gyro )
{
g_system_gyro_id = sensors[i];
Con_Printf( "SDL: Opened built-in gyroscope: %s\n", SDL_GetSensorName( g_system_gyro ));
break;
}
}
}
SDL_free( sensors );
}
else
{
Con_Reportf( S_ERROR "Failed to init SDL Sensor subsystem: %s\n", SDL_GetError());
}
}
/*
==============
SDLash_ShutdownSensors
==============
*/
void SDLash_ShutdownSensors( void )
{
if( g_system_gyro )
{
SDL_CloseSensor( g_system_gyro );
g_system_gyro = NULL;
g_system_gyro_id = -1;
}
SDL_QuitSubSystem( SDL_INIT_SENSOR );
}
/*
==============
SDLash_GyroIsAvailable
==============
*/
qboolean SDLash_GyroIsAvailable( void )
{
return( g_system_gyro != NULL );
}
/*
==============
SDLash_SensorUpdate
==============
*/
void SDLash_SensorUpdate( SDL_SensorEvent sensor )
{
if( sensor.which == g_system_gyro_id )
{
IN_GyroEvent( sensor.data );
}
}

View File

@@ -38,6 +38,7 @@ void Platform_Sleep( int msec )
{
SDL_Delay( msec );
}
#endif // XASH_TIMER == TIMER_SDL
#if XASH_MESSAGEBOX == MSGBOX_SDL
@@ -45,6 +46,7 @@ void Platform_MessageBox( const char *title, const char *message, qboolean paren
{
SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR, title, message, parentMainWindow ? host.hWnd : NULL );
}
#endif
void SDLash_NanoSleep( int nsec )
@@ -90,10 +92,8 @@ static void SDLCALL SDLash_LogOutputFunction( void *userdata, int category, SDL_
}
}
void SDLash_Init( const char *basedir )
void SDLash_Init( void )
{
(void)basedir;
// TODO: initial state, to be filled from gameinfo!
SDL_SetAppMetadata( XASH_ENGINE_NAME, XASH_VERSION, "su.xash.engine" );
SDL_SetAppMetadataProperty( SDL_PROP_APP_METADATA_TYPE_STRING, "game" );

View File

@@ -19,6 +19,7 @@ GNU General Public License for more details.
#include "ref_common.h"
#include "xash3d_mathlib.h"
#include "common.h"
#include "wrect.h"
#include <SDL3/SDL_system.h>
static struct
@@ -92,8 +93,8 @@ static SDL_Window *VID_CreateWindowWithSafeGL( const char *title, SDL_Rect *rect
static void VID_SaveWindowSize( SDL_Window *hWnd, int width, int height )
{
qboolean maximized = FBitSet( SDL_GetWindowFlags( hWnd ), SDL_WINDOW_MAXIMIZED );
int render_w;
int render_h;
int render_w;
int render_h;
if( !SDL_GetWindowSizeInPixels( hWnd, &render_w, &render_h ))
{
@@ -110,7 +111,7 @@ static void VID_SaveWindowSize( SDL_Window *hWnd, int width, int height )
static qboolean VID_CreateWindow( const int input_width, const int input_height, window_mode_t window_mode )
{
SDL_Rect rect = { SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, input_width, input_height };
Uint32 flags = SDL_WINDOW_RESIZABLE;
Uint32 flags = SDL_WINDOW_RESIZABLE;
if( !glw_state.software )
SetBits( flags, SDL_WINDOW_OPENGL );
@@ -118,7 +119,7 @@ static qboolean VID_CreateWindow( const int input_width, const int input_height,
// probe true fullscreen first, if it fails, try borderless next
if( window_mode == WINDOW_MODE_FULLSCREEN )
{
SDL_DisplayID display = SDL_GetPrimaryDisplay();
SDL_DisplayID display = SDL_GetPrimaryDisplay();
SDL_DisplayMode dm;
if( SDL_GetClosestFullscreenDisplayMode( display, rect.w, rect.h, 0.0f, true, &dm ))
@@ -203,9 +204,44 @@ static qboolean VID_CreateWindow( const int input_width, const int input_height,
return true;
}
void VID_Info_f( void )
{
Uint32 flags = SDL_GetWindowFlags( host.hWnd );
int width, height;
int render_width, render_height;
int x, y;
SDL_GetWindowSize( host.hWnd, &width, &height );
SDL_GetWindowSizeInPixels( host.hWnd, &render_width, &render_height );
SDL_GetWindowPosition( host.hWnd, &x, &y );
Con_Printf( "Video: " S_GREEN "SDL3" S_DEFAULT "\n" );
Con_Printf( "Video driver: " S_GREEN "%s" S_DEFAULT "\n", SDL_GetCurrentVideoDriver( ));
Con_Printf( "Window size: " S_GREEN "%dx%d" S_DEFAULT " (" S_YELLOW "real %dx%d" S_DEFAULT ")\n", width, height, render_width, render_height );
Con_Printf( "Window position: " S_GREEN "%dx%d" S_DEFAULT "\n", x, y );
Con_Printf( "Window mode: %s" S_DEFAULT "\n",
FBitSet( flags, SDL_WINDOW_FULLSCREEN ) ? S_YELLOW "fullscreen"
: S_CYAN "windowed" );
Con_Printf( "Window bordered: %s" S_DEFAULT "\n", FBitSet( flags, SDL_WINDOW_BORDERLESS ) ? S_RED "false" : S_GREEN "true" );
Con_Printf( "Window resizable: %s" S_DEFAULT "\n", FBitSet( flags, SDL_WINDOW_RESIZABLE ) ? S_GREEN "true" : S_RED "false" );
Con_Printf( "Window maximized: %s" S_DEFAULT "\n", FBitSet( flags, SDL_WINDOW_MAXIMIZED ) ? S_GREEN "true" : S_RED "false" );
int display_index = SDL_GetDisplayForWindow( host.hWnd );
if( display_index >= 0 )
Con_Printf( "Window display index: " S_GREEN "%d" S_DEFAULT "\n", display_index );
else
Con_Printf( "Window display index: " S_RED "fail: " S_DEFAULT "%s\n", SDL_GetError( ));
const SDL_DisplayMode *dm = SDL_GetWindowFullscreenMode( host.hWnd );
if( dm )
Con_Printf( "Window display mode: " S_GREEN "%dx%d@%f" S_DEFAULT "\n", dm->w, dm->h, dm->refresh_rate );
else
Con_Printf( "Window display mode: " S_RED "fail: " S_DEFAULT "%s\n", SDL_GetError( ));
}
static void R_InitVideoModes( void )
{
SDL_DisplayID display = SDL_GetDisplayForWindow( host.hWnd );
SDL_DisplayID display = SDL_GetDisplayForWindow( host.hWnd );
int count;
SDL_DisplayMode **modes = SDL_GetFullscreenDisplayModes( display, &count );
@@ -257,6 +293,32 @@ void Platform_Minimize_f( void )
SDL_MinimizeWindow( host.hWnd );
}
platform_orientation_t Platform_GetDisplayOrientation( void )
{
if( host.hWnd )
{
int display_index = SDL_GetDisplayForWindow( host.hWnd );
if( display_index >= 0 )
{
switch( SDL_GetCurrentDisplayOrientation( display_index ))
{
case SDL_ORIENTATION_LANDSCAPE:
return ORIENTATION_LANDSCAPE;
case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
return ORIENTATION_LANDSCAPE_FLIPPED;
case SDL_ORIENTATION_PORTRAIT:
return ORIENTATION_PORTRAIT;
case SDL_ORIENTATION_PORTRAIT_FLIPPED:
return ORIENTATION_PORTRAIT_FLIPPED;
default:
return ORIENTATION_UNKNOWN;
}
}
}
return ORIENTATION_UNKNOWN;
}
void GL_UpdateSwapInterval( void )
{
if( FBitSet( gl_vsync.flags, FCVAR_CHANGED ))
@@ -307,6 +369,7 @@ qboolean R_Init_Video( ref_graphic_apis_t type )
switch( type )
{
case REF_SOFTWARE:
case REF_D3D:
break;
case REF_GL:
ref.dllFuncs.GL_InitExtensions();
@@ -341,26 +404,26 @@ int GL_SetAttribute( int attr, int val )
{
switch( attr )
{
#define MAP_REF_API_ATTRIBUTE_TO_SDL( name ) case REF_##name: return SDL_GL_SetAttribute( SDL_##name, val );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_RED_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_GREEN_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_BLUE_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_ALPHA_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_DOUBLEBUFFER );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_DEPTH_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_STENCIL_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_MULTISAMPLEBUFFERS );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_MULTISAMPLESAMPLES );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_ACCELERATED_VISUAL );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_MAJOR_VERSION );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_MINOR_VERSION );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_FLAGS );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_SHARE_WITH_CURRENT_CONTEXT );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_FRAMEBUFFER_SRGB_CAPABLE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_PROFILE_MASK );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_RELEASE_BEHAVIOR );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_RESET_NOTIFICATION );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_NO_ERROR );
#define MAP_REF_API_ATTRIBUTE_TO_SDL( name ) case REF_ ## name: return SDL_GL_SetAttribute( SDL_ ## name, val );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_RED_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_GREEN_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_BLUE_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_ALPHA_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_DOUBLEBUFFER );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_DEPTH_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_STENCIL_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_MULTISAMPLEBUFFERS );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_MULTISAMPLESAMPLES );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_ACCELERATED_VISUAL );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_MAJOR_VERSION );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_MINOR_VERSION );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_FLAGS );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_SHARE_WITH_CURRENT_CONTEXT );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_FRAMEBUFFER_SRGB_CAPABLE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_PROFILE_MASK );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_RELEASE_BEHAVIOR );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_RESET_NOTIFICATION );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_NO_ERROR );
#undef MAP_REF_API_ATTRIBUTE_TO_SDL
}
@@ -371,26 +434,26 @@ int GL_GetAttribute( int attr, int *val )
{
switch( attr )
{
#define MAP_REF_API_ATTRIBUTE_TO_SDL( name ) case REF_##name: return SDL_GL_GetAttribute( SDL_##name, val );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_RED_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_GREEN_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_BLUE_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_ALPHA_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_DOUBLEBUFFER );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_DEPTH_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_STENCIL_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_MULTISAMPLEBUFFERS );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_MULTISAMPLESAMPLES );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_ACCELERATED_VISUAL );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_MAJOR_VERSION );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_MINOR_VERSION );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_FLAGS );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_SHARE_WITH_CURRENT_CONTEXT );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_FRAMEBUFFER_SRGB_CAPABLE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_PROFILE_MASK );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_RELEASE_BEHAVIOR );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_RESET_NOTIFICATION );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_NO_ERROR );
#define MAP_REF_API_ATTRIBUTE_TO_SDL( name ) case REF_ ## name: return SDL_GL_GetAttribute( SDL_ ## name, val );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_RED_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_GREEN_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_BLUE_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_ALPHA_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_DOUBLEBUFFER );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_DEPTH_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_STENCIL_SIZE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_MULTISAMPLEBUFFERS );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_MULTISAMPLESAMPLES );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_ACCELERATED_VISUAL );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_MAJOR_VERSION );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_MINOR_VERSION );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_FLAGS );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_SHARE_WITH_CURRENT_CONTEXT );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_FRAMEBUFFER_SRGB_CAPABLE );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_PROFILE_MASK );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_RELEASE_BEHAVIOR );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_RESET_NOTIFICATION );
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_NO_ERROR );
#undef MAP_REF_API_ATTRIBUTE_TO_SDL
}
@@ -550,6 +613,9 @@ qboolean VID_SetMode( void )
case rserr_invalid_mode:
Sys_Warn( "%s: invalid mode, engine will run in %dx%d", __func__, vid_state.prev_width, vid_state.prev_height );
break;
default:
Sys_Warn( "%s: unknown error, engine will revert to %dx%d", __func__, vid_state.prev_width, vid_state.prev_height );
break;
}
// revert to last successful mode
@@ -563,8 +629,169 @@ qboolean VID_SetMode( void )
return true;
}
static qboolean VID_GetDisplayBounds( SDL_DisplayID display_id, SDL_Window *hWnd, SDL_Rect *rect )
{
if( SDL_GetDisplayUsableBounds( display_id, rect ) != 0 )
{
memset( rect, 0, sizeof( *rect ));
return false;
}
wrect_t wrc = { 0 };
if( hWnd )
{
SDL_GetWindowBordersSize( hWnd, &wrc.top, &wrc.left, &wrc.bottom, &wrc.right );
}
else
{
#if XASH_WIN32
wrc.left = GetSystemMetrics( SM_CYSIZEFRAME );
wrc.right = wrc.bottom = wrc.left;
wrc.top = GetSystemMetrics( SM_CYSMCAPTION ) + wrc.left;
#endif // XASH_WIN32
}
rect->x += wrc.left + wrc.right;
rect->y += wrc.top + wrc.bottom;
rect->w -= ( wrc.left + wrc.right ) * 2;
rect->h -= ( wrc.top + wrc.bottom ) * 2;
return true;
}
static rserr_t VID_SetScreenResolution( int width, int height, window_mode_t window_mode, window_mode_t prev_window_mode )
{
const SDL_DisplayID display_id = SDL_GetDisplayForWindow( host.hWnd );
int out_width, out_height;
switch( window_mode )
{
case WINDOW_MODE_BORDERLESS:
{
if( !SDL_SetWindowFullscreen( host.hWnd, false ))
{
Con_PrintSDLError( "SDL_SetWindowFullscreen" );
// there is no "invalid mode" for borderless fullscreen as there is
// no video mode change to begin with
return rserr_invalid_fullscreen;
}
if( !SDL_SetWindowBordered( host.hWnd, false ))
{
Con_PrintSDLError( "SDL_SetWindowBordered" );
return rserr_invalid_fullscreen;
}
break;
}
case WINDOW_MODE_FULLSCREEN:
{
const SDL_DisplayMode want = { .w = width, .h = height };
SDL_DisplayMode **modes;
const SDL_DisplayMode *got = 0;
int mode_count;
// return "invalid mode" if we are switching between video modes in fullscreen mode
// or "invalid fullscreen" if we are switching from windowed to fullscreen
const rserr_t appropriate_err = prev_window_mode == WINDOW_MODE_WINDOWED ? rserr_invalid_fullscreen : rserr_invalid_mode;
modes = SDL_GetFullscreenDisplayModes( display_id, &mode_count );
for( int i = 0; i < mode_count; i++ )
{
if( modes[i]->w == want.w && modes[i]->h == want.h )
{
got = modes[i];
break;
}
}
if( !got )
{
// Fallback to native
got = SDL_GetDesktopDisplayMode( display_id );
}
if( !SDL_SetWindowFullscreenMode( host.hWnd, got ))
{
Con_PrintSDLError( "SDL_SetWindowFullscreenMode" );
SDL_free( modes );
return appropriate_err;
}
if( !SDL_SetWindowFullscreen( host.hWnd, true ))
{
Con_PrintSDLError( "SDL_SetWindowFullscreen" );
SDL_free( modes );
return appropriate_err;
}
SDL_free( modes );
break;
}
case WINDOW_MODE_WINDOWED:
if( !SDL_SetWindowFullscreen( host.hWnd, false ))
{
Con_PrintSDLError( "SDL_SetWindowFullscreen" );
// TODO: appropriate error type when going back from fullscreen to windowed?
return rserr_unknown;
}
SDL_SetWindowResizable( host.hWnd, true );
SDL_SetWindowBordered( host.hWnd, true );
if( !FBitSet( SDL_GetWindowFlags( host.hWnd ), SDL_WINDOW_MAXIMIZED ))
{
const SDL_DisplayMode *dm;
qboolean center_window = false;
if( !( dm = SDL_GetDesktopDisplayMode( display_id )) && width >= dm->w && height >= dm->h )
{
SDL_SetWindowSize( host.hWnd, dm->w, dm->h );
// Con_Printf( "%s: activating fake fullscreen mode\n", __func__ );
center_window = true;
}
else
{
SDL_SetWindowSize( host.hWnd, width, height );
SDL_Rect r;
if( VID_GetDisplayBounds( display_id, host.hWnd, &r ) >= 0 )
{
int x, y;
SDL_GetWindowPosition( host.hWnd, &x, &y );
if( x <= r.x || y <= r.y )
center_window = true;
}
}
if( center_window )
SDL_SetWindowPosition( host.hWnd, SDL_WINDOWPOS_CENTERED_DISPLAY( display_id ), SDL_WINDOWPOS_CENTERED_DISPLAY( display_id ));
}
break;
default:
Con_Printf( S_WARN "%s: got invalid mode %d", __func__, window_mode );
}
SDL_GetWindowSize( host.hWnd, &out_width, &out_height );
Con_Printf( "%s: Setting video mode to %dx%d %s\n", __func__, out_width, out_height,
window_mode == WINDOW_MODE_BORDERLESS ? "borderless"
: window_mode == WINDOW_MODE_FULLSCREEN ? "fullscreen" : "windowed" );
VID_SaveWindowSize( host.hWnd, out_width, out_height );
// set icon that could've been lost after changing modes
VID_SetWindowIcon( host.hWnd );
return rserr_ok;
}
rserr_t R_ChangeDisplaySettings( int width, int height, window_mode_t window_mode )
{
rserr_t err;
if( !host.hWnd )
{
// create window if not exists
@@ -573,12 +800,13 @@ rserr_t R_ChangeDisplaySettings( int width, int height, window_mode_t window_mod
}
else
{
// TODO: change current window mode
return rserr_invalid_fullscreen;
err = VID_SetScreenResolution( width, height, window_mode, refState.window_mode );
if( err != rserr_ok )
return err;
}
refState.desktopBitsPixel = 24; // TODO: figure this out
refState.window_mode = window_mode;
refState.desktopBitsPixel = 24;
return rserr_ok;
}

View File

@@ -705,4 +705,23 @@ int SV_LightForEntity( edict_t *pEdict );
//
void SV_SourceQuery_HandleConnnectionlessPacket( const char *c, netadr_t from, sizebuf_t *msg );
static inline qboolean SV_CheckGroupOp( int op, int groupinfo, int mask )
{
if( op == GROUP_OP_AND && !FBitSet( groupinfo, mask ))
return false;
if( op == GROUP_OP_NAND && FBitSet( groupinfo, mask ))
return false;
return true;
}
static inline qboolean SV_CheckGroupTrace( const edict_t *e1, const edict_t *e2 )
{
if( e1->v.groupinfo && e2->v.groupinfo )
return SV_CheckGroupOp( svs.groupop, e1->v.groupinfo, e2->v.groupinfo );
return true;
}
#endif//SERVER_H

View File

@@ -435,14 +435,8 @@ static int SV_Multicast( int dest, const vec3_t origin, const edict_t *ent, qboo
if( filter && cl == sv.current_client && FBitSet( sv.current_client->flags, FCL_PREDICT_MOVEMENT ))
continue;
if( SV_IsValidEdict( ent ) && ent->v.groupinfo && cl->edict->v.groupinfo )
{
if( svs.groupop == GROUP_OP_AND && !FBitSet( cl->edict->v.groupinfo, ent->v.groupinfo ))
continue;
if( svs.groupop == GROUP_OP_NAND && FBitSet( cl->edict->v.groupinfo, ent->v.groupinfo ))
continue;
}
if( SV_IsValidEdict( ent ) && !SV_CheckGroupTrace( ent, cl->edict ))
continue;
if( !SV_CheckClientVisiblity( cl, mask ))
continue;
@@ -4123,14 +4117,8 @@ void GAME_EXPORT SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word
if( cl->state != cs_spawned || !cl->edict || FBitSet( cl->flags, FCL_FAKECLIENT ))
continue;
if( SV_IsValidEdict( pInvoker ) && pInvoker->v.groupinfo && cl->edict->v.groupinfo )
{
if( svs.groupop == GROUP_OP_AND && !FBitSet( cl->edict->v.groupinfo, pInvoker->v.groupinfo ))
continue;
if( svs.groupop == GROUP_OP_NAND && FBitSet( cl->edict->v.groupinfo, pInvoker->v.groupinfo ))
continue;
}
if( SV_IsValidEdict( pInvoker ) && !SV_CheckGroupTrace( pInvoker, cl->edict ))
continue;
if( SV_IsValidEdict( pInvoker ))
{

View File

@@ -60,6 +60,47 @@ Utility functions
===============================================================================
*/
/*
================
SV_CheckVelocity
================
*/
void SV_CheckVelocity( edict_t *ent )
{
float wishspd;
float maxspd;
// bound velocity
for( int i = 0; i < 3; i++ )
{
if( IS_NAN( ent->v.velocity[i] ))
{
if( sv_check_errors.value )
Con_Printf( "Got a NaN velocity on %s\n", SV_GetString( ent->v.classname ));
ent->v.velocity[i] = 0.0f;
}
if( IS_NAN( ent->v.origin[i] ))
{
if( sv_check_errors.value )
Con_Printf( "Got a NaN origin on %s\n", SV_GetString( ent->v.classname ));
ent->v.origin[i] = 0.0f;
}
}
wishspd = DotProduct( ent->v.velocity, ent->v.velocity );
maxspd = sv_maxvelocity.value * sv_maxvelocity.value * 1.73f; // half-diagonal
if( wishspd > maxspd )
{
wishspd = sqrt( wishspd );
if( sv_check_errors.value )
Con_Printf( "Got a velocity too high on %s ( %.2f > %.2f )\n", SV_GetString( ent->v.classname ), wishspd, sqrt( maxspd ));
wishspd = sv_maxvelocity.value / wishspd;
VectorScale( ent->v.velocity, wishspd, ent->v.velocity );
}
}
/*
================
SV_CheckAllEnts
@@ -110,47 +151,6 @@ static void SV_CheckAllEnts( void )
}
}
/*
================
SV_CheckVelocity
================
*/
void SV_CheckVelocity( edict_t *ent )
{
float wishspd;
float maxspd;
// bound velocity
for( int i = 0; i < 3; i++ )
{
if( IS_NAN( ent->v.velocity[i] ))
{
if( sv_check_errors.value )
Con_Printf( "Got a NaN velocity on %s\n", SV_GetString( ent->v.classname ));
ent->v.velocity[i] = 0.0f;
}
if( IS_NAN( ent->v.origin[i] ))
{
if( sv_check_errors.value )
Con_Printf( "Got a NaN origin on %s\n", SV_GetString( ent->v.classname ));
ent->v.origin[i] = 0.0f;
}
}
wishspd = DotProduct( ent->v.velocity, ent->v.velocity );
maxspd = sv_maxvelocity.value * sv_maxvelocity.value * 1.73f; // half-diagonal
if( wishspd > maxspd )
{
wishspd = sqrt( wishspd );
if( sv_check_errors.value )
Con_Printf( "Got a velocity too high on %s ( %.2f > %.2f )\n", SV_GetString( ent->v.classname ), wishspd, sqrt( maxspd ));
wishspd = sv_maxvelocity.value / wishspd;
VectorScale( ent->v.velocity, wishspd, ent->v.velocity );
}
}
/*
================
SV_UpdateBaseVelocity
@@ -158,26 +158,20 @@ SV_UpdateBaseVelocity
*/
void SV_UpdateBaseVelocity( edict_t *ent )
{
if( ent->v.flags & FL_ONGROUND )
{
edict_t *groundentity = ent->v.groundentity;
if( !FBitSet( ent->v.flags, FL_ONGROUND ))
return;
if( SV_IsValidEdict( groundentity ))
{
// On conveyor belt that's moving?
if( groundentity->v.flags & FL_CONVEYOR )
{
vec3_t new_basevel;
const edict_t *groundentity = ent->v.groundentity;
VectorScale( groundentity->v.movedir, groundentity->v.speed, new_basevel );
if( ent->v.flags & FL_BASEVELOCITY )
VectorAdd( new_basevel, ent->v.basevelocity, new_basevel );
if( !SV_IsValidEdict( groundentity ) || !FBitSet( groundentity->v.flags, FL_CONVEYOR ))
return;
ent->v.flags |= FL_BASEVELOCITY;
VectorCopy( new_basevel, ent->v.basevelocity );
}
}
}
if( FBitSet( ent->v.flags, FL_BASEVELOCITY ))
VectorMA( ent->v.basevelocity, groundentity->v.speed, groundentity->v.movedir, ent->v.basevelocity );
else
VectorScale( groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity );
ent->v.flags |= FL_BASEVELOCITY;
}
/*
@@ -189,18 +183,15 @@ returns true if the entity is in solid currently
*/
static qboolean SV_TestEntityPosition( edict_t *ent, edict_t *blocker )
{
qboolean monsterClip = FBitSet( ent->v.flags, FL_MONSTERCLIP ) ? true : false;
trace_t trace;
if( FBitSet( ent->v.flags, FL_CLIENT|FL_FAKECLIENT ))
{
// to avoid falling through tracktrain update client mins\maxs here
if( FBitSet( ent->v.flags, FL_DUCKING ))
SV_SetMinMaxSize( ent, host.player_mins[1], host.player_maxs[1], true );
else SV_SetMinMaxSize( ent, host.player_mins[0], host.player_maxs[0], true );
int hull = FBitSet( ent->v.flags, FL_DUCKING ) ? 1 : 0;
SV_SetMinMaxSize( ent, host.player_mins[hull], host.player_maxs[hull], true );
}
trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent, monsterClip );
qboolean monsterClip = FBitSet( ent->v.flags, FL_MONSTERCLIP ) ? true : false;
trace_t trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent, monsterClip );
if( SV_IsValidEdict( blocker ) && SV_IsValidEdict( trace.ent ))
{
@@ -212,6 +203,25 @@ static qboolean SV_TestEntityPosition( edict_t *ent, edict_t *blocker )
return trace.startsolid;
}
static qboolean SV_TryThink( edict_t *ent, double frametime, double time )
{
float thinktime = ent->v.nextthink;
if( thinktime <= 0.0f || thinktime > ( time + frametime ))
return false;
// don't let things stay in the past.
// it is possible to start that way
// by a trigger with a local time.
if( thinktime < time )
thinktime = time;
ent->v.nextthink = 0.0f;
svgame.globals->time = thinktime;
svgame.dllFuncs.pfnThink( ent );
return true;
}
/*
=============
SV_RunThink
@@ -224,21 +234,10 @@ Returns false if the entity removed itself.
*/
static qboolean SV_RunThink( edict_t *ent )
{
float thinktime;
if( !FBitSet( ent->v.flags, FL_KILLME ))
{
thinktime = ent->v.nextthink;
if( thinktime <= 0.0f || thinktime > (sv.time + sv.frametime))
if( !SV_TryThink( ent, sv.frametime, sv.time ))
return true;
if( thinktime < sv.time )
thinktime = sv.time; // don't let things stay in the past.
// it is possible to start that way
// by a trigger with a local time.
ent->v.nextthink = 0.0f;
svgame.globals->time = thinktime;
svgame.dllFuncs.pfnThink( ent );
}
if( FBitSet( ent->v.flags, FL_KILLME ))
@@ -259,25 +258,13 @@ Returns false if the entity removed itself.
*/
qboolean SV_PlayerRunThink( edict_t *ent, float frametime, double time )
{
float thinktime;
if( svgame.physFuncs.SV_PlayerThink )
return svgame.physFuncs.SV_PlayerThink( ent, frametime, time );
if( !FBitSet( ent->v.flags, FL_KILLME|FL_DORMANT ))
{
thinktime = ent->v.nextthink;
if( thinktime <= 0.0f || thinktime > (time + frametime))
if( !SV_TryThink( ent, frametime, time ))
return true;
if( thinktime < time )
thinktime = time; // don't let things stay in the past.
// it is possible to start that way
// by a trigger with a local time.
ent->v.nextthink = 0.0f;
svgame.globals->time = thinktime;
svgame.dllFuncs.pfnThink( ent );
}
if( FBitSet( ent->v.flags, FL_KILLME ))
@@ -297,17 +284,11 @@ void SV_Impact( edict_t *e1, edict_t *e2, trace_t *trace )
{
svgame.globals->time = sv.time;
if(( e1->v.flags|e2->v.flags ) & FL_KILLME )
if( FBitSet( e1->v.flags|e2->v.flags, FL_KILLME ))
return;
if( e1->v.groupinfo && e2->v.groupinfo )
{
if( svs.groupop == GROUP_OP_AND && !FBitSet( e1->v.groupinfo, e2->v.groupinfo ))
return;
if( svs.groupop == GROUP_OP_NAND && FBitSet( e1->v.groupinfo, e2->v.groupinfo ))
return;
}
if( !SV_CheckGroupTrace( e1, e2 ))
return;
if( e1->v.solid != SOLID_NOT )
{

View File

@@ -205,10 +205,7 @@ static void SV_AddLinksToPmove( areanode_t *node, const vec3_t pmove_mins, const
if( check->v.groupinfo != 0 )
{
if( svs.groupop == GROUP_OP_AND && !FBitSet( check->v.groupinfo, pl->v.groupinfo ))
continue;
if( svs.groupop == GROUP_OP_NAND && FBitSet( check->v.groupinfo, pl->v.groupinfo ))
if( !SV_CheckGroupOp( svs.groupop, check->v.groupinfo, pl->v.groupinfo ))
continue;
}
@@ -520,8 +517,7 @@ static void SV_SetupPMove( playermove_t *pmove, sv_client_t *cl, usercmd_t *ucmd
vec3_t absmin, absmax;
edict_t *clent = cl->edict;
svgame.globals->frametime = (ucmd->msec * 0.001f);
pmove->frametime = ucmd->msec * 0.001f;
pmove->player_index = NUM_FOR_EDICT( clent ) - 1;
pmove->multiplayer = (svs.maxclients > 1) ? true : false;
pmove->time = (float)(cl->timebase * 1000.0);
@@ -978,9 +974,9 @@ void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed )
// touch other objects
for( int i = 0; i < svgame.pmove->numtouch; i++ )
{
pmtrace_t *pmtrace = &svgame.pmove->touchindex[i];
edict_t *touch = SV_EdictNum( svgame.pmove->physents[pmtrace->ent].info );
trace_t trace;
pmtrace_t *pmtrace = &svgame.pmove->touchindex[i];
edict_t *touch = SV_EdictNum( svgame.pmove->physents[pmtrace->ent].info );
trace_t trace;
VectorCopy( pmtrace->deltavelocity, clent->v.velocity );
PM_ConvertTrace( &trace, pmtrace, touch );

View File

@@ -522,14 +522,8 @@ static void SV_TouchLinks( edict_t *ent, areanode_t *node )
if( touch == ent || touch->v.solid != SOLID_TRIGGER ) // disabled ?
continue;
if( touch->v.groupinfo && ent->v.groupinfo )
{
if( svs.groupop == GROUP_OP_AND && !FBitSet( touch->v.groupinfo, ent->v.groupinfo ))
continue;
if( svs.groupop == GROUP_OP_NAND && FBitSet( touch->v.groupinfo, ent->v.groupinfo ))
continue;
}
if( !SV_CheckGroupTrace( touch, ent ))
continue;
if( !BoundsIntersect( ent->v.absmin, ent->v.absmax, touch->v.absmin, touch->v.absmax ))
continue;
@@ -725,10 +719,7 @@ static void SV_WaterLinks( const vec3_t origin, int *pCont, areanode_t *node )
if( touch->v.groupinfo )
{
if( svs.groupop == GROUP_OP_AND && !FBitSet( touch->v.groupinfo, svs.groupmask ))
continue;
if( svs.groupop == GROUP_OP_NAND && FBitSet( touch->v.groupinfo, svs.groupmask ))
if( !SV_CheckGroupOp( svs.groupop, touch->v.groupinfo, svs.groupmask ))
continue;
}
@@ -1101,14 +1092,8 @@ static qboolean SV_ClipToEntity( edict_t *touch, moveclip_t *clip )
trace_t trace;
model_t *mod;
if( touch->v.groupinfo && SV_IsValidEdict( clip->passedict ) && clip->passedict->v.groupinfo != 0 )
{
if( svs.groupop == GROUP_OP_AND && !FBitSet( touch->v.groupinfo, clip->passedict->v.groupinfo ))
return true;
if( svs.groupop == GROUP_OP_NAND && FBitSet( touch->v.groupinfo, clip->passedict->v.groupinfo ))
return true;
}
if( SV_IsValidEdict( clip->passedict ) && !SV_CheckGroupTrace( touch, clip->passedict ))
return true;
if( touch == clip->passedict || touch->v.solid == SOLID_NOT )
return true;

View File

@@ -26,7 +26,12 @@ int main(int argc, char **argv)
}
'''
frameworks = ['Foundation', 'UIKit', 'QuartzCore', 'GameController', 'SystemConfiguration', 'CFNetwork', 'AVFoundation', 'CoreGraphics']
def get_frameworks(env):
if env.IOS:
return ['Foundation', 'UIKit', 'QuartzCore', 'GameController', 'SystemConfiguration', 'CFNetwork', 'AVFoundation', 'CoreGraphics']
if env.DEST_OS == 'darwin':
return ['IOKit', 'CoreFoundation']
return []
@TaskGen.extension('.m')
def m_hook(self, node):
@@ -124,9 +129,8 @@ def configure(conf):
if not conf.env.DEST_OS in ['win32', 'android']:
conf.check_pthreads(mode='c')
if conf.env.IOS:
for i in frameworks :
conf.check(features='c cprogram', framework=i, uselib_store=i, msg='Checking for %s framework' % i)
for i in get_frameworks(conf.env):
conf.check(features='c cprogram', framework=i, uselib_store=i, msg='Checking for %s framework' % i)
conf.define('ENGINE_DLL', 1)
@@ -179,6 +183,8 @@ def build(bld):
source += bld.path.ant_glob('platform/ios/*.c')
source += bld.path.ant_glob('platform/ios/*.m')
includes += bld.path.ant_glob('platform/ios')
elif bld.env.DEST_OS == 'darwin':
source += bld.path.ant_glob('platform/apple/*.c')
# include sources for optional features
if bld.get_define('XASH_CUSTOM_SWAP'):
@@ -206,6 +212,7 @@ def build(bld):
]
else: # POSIX
libs += ['M', 'RT', 'PTHREAD', 'ASOUND', 'HAIKU', 'MAGX', 'LOG', 'SOCKET']
libs += get_frameworks(bld.env)
if not bld.env.STATIC:
libs += ['DL']
@@ -274,7 +281,6 @@ def build(bld):
install_path = bld.env.LIBDIR
if bld.env.IOS:
libs += frameworks
defines += ['XASH_SDLMAIN=1']
if bld.env.DEST_OS in ['nswitch', 'psvita', 'emscripten']:

View File

@@ -365,6 +365,7 @@ def configure(conf):
'-Werror=duplicated-cond',
'-Werror=format=2',
'-Werror=free-nonheap-object',
'-Werror=init-self',
'-Werror=implicit-fallthrough=2',
'-Werror=logical-op',
'-Werror=nonnull',
@@ -385,7 +386,6 @@ def configure(conf):
# unstable diagnostics, may cause false positives
'-Walloc-zero',
'-Winit-self',
'-Wmisleading-indentation',
'-Wmismatched-dealloc',
'-Wstringop-overflow',