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.
Doesn't fix the root cause of the problem, which is the mysterious setting of decal->pnext to decal which doesn't happen in GL, but does act as a blockade and a temporary fix
This is an annoying message that's caused by the game code. Decals, without
custom renderer, cannot be rendered on non-brush entities, and everybody knows
that anyway.
Previously, it would always return on the first one that had activity.
In practice, this meant that if IPv4 starts getting slammed, IPv6 reads
wouldn't happen.
* Use offsets into dbspmodel_t struct, get rid of srcmodel global variable.
* Allocate dbspmodel_t when it's required
* Make srclumps const, move Blue-Shift hack into lump loader's flag.
Mod_StudioComputeBounds incorrectly assumed that all models across all body parts were laid out contiguously in memory. This caused out-of-bounds reads or reading garbage data when loading complex models, leading to crashes.
Is this a mistake? This define effectively forces `--enable-ffmpeg-dlopen` at all times ignoring configuration (which in turn makes build to fail with ffmpeg 8.1).
In GoldSrc default branch interpreted as WALKMOVE_NORMAL, and there might be
some mods that expect this.
But Xash never did this, and if Xash-specific games rely on that behavior, we
better know about it.
AMD убрала в новых драйверах поддержку расширения GL_ATI_texture_compression_3dc, из-за чего сломалась загрузка ATI2 текстур. Формат RGTC включен в стандарт OpenGL 3.0, а единственные видеокарты с поддержкой 3DC, но без RGTC - это серия Radeon X1000 (2005г.). Можно было бы только ради Х1000 проверять поддерживаемые расширения и переключаться на 3DC, но без явной необходимости этого делать не хочется.
* readme: update README.md for android build instruction
* Update Android build instructions in README
Corrected instructions for running in Android Studio and added a new section for building on Android.
---------
Co-authored-by: a1batross <a1ba.omarov@gmail.com>
On GPUs where GL_ARB_shading_language_100 isn't available (i.e. all mobile GPUs
I believe) this function would return total amount of texture units available.
But ref_gl only tracks and uses MAX_TEXTURE_UNITS texture units, causing memory
corruption in functions that doesn't check the limit.
vfs.cfg executed before game directory is mounted, this way we can know which
folders must be mounted before engine initialization.
This commit also removes buggy hot reload of the addon folders.
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.
- 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.
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
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.
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.
check_frag(FRAGMENT_DL_ITERATE_PHDR % 'link.h', ' dl_iterate_phdr function in link.h', 'HAVE_DL_ITERATE_PHDR_LINK_H', 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_SYS_LINK_H', after_tests=['sys/link.h']),
* This project uses mixed Quake's and HLSDK's C/C++ code style convention.
* In short:
* Use spaces in parenthesis.
* Use spaces in parenthesis, but not when two parentheses are consecutive.
* Only tabs for indentation.
* Any brace must have it's own line.
* 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.
@@ -45,3 +46,8 @@
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.
## 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.
@@ -22,7 +22,7 @@ The other yet unsupported configuration is the big endian.
2) Open `public/build.h` file. Add appropriate checks for your operating system and/or CPU architecture. It shouldn't be hard.
Also, you'll need to build [Half-Life SDK](https://github.com/FWGS/hlsdk-xash3d/). It has same `public/build.h` so reflect changes into it. Note that to be compatible with HLSDK proprietary license, it's relicensed as public domain under [Unlicense](https://unlicense.org).
Also, you'll need to build [Half-Life SDK](https://github.com/FWGS/hlsdk-portable/). It has same `public/build.h` so reflect changes into it. Note that to be compatible with HLSDK proprietary license, it's relicensed as public domain under [Unlicense](https://unlicense.org).
We have a library naming scheme that allows us and game creators to distribute binaries for different platforms in one archive. Read `Documentation/extensions/library-naming.md` for more information.
Xash3D FWGS supports both GoldSource-style addon folders and has few own. Each directory can have it's own archives that will be mounted with lower priority than directory itself.
Below is the mounts map, in order of precedence from least important to most important.
|--------------------|------|
| Directory | Note |
|--------------------|------|
| `$game/downloaded` | Always added. Used to store server downloads.|
| `$game` | This is the game directory. |
| `$game/custom` | Always added. Used for user modifications content. |
| `$game_hd` | Added with `fs_mount_hd` set to non-zero value. Used for high definition content, similar to GoldSrc.. |
| `$game_addon` | Added with `fs_mount_addon` set to non-zero value. Used for user modifications content, similar to GoldSrc. |
| `$game_lv` | Added with `fs_mount_lv` set to non-zero value. Used for low-violence content, similar to GoldSrc. |
| `$game_$language` | Added with `fs_mount_l10n` set to non-zero value. Language is controlled with `ui_language` cvar or `-language` command line switch. Used for localization content, similar to GoldSrc. |
@@ -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.
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..
Xash3D FWGS supports lightmapped water, as an extension. It adds three new cvars and new worldspawn key values.
### For level designers:
If you're a level designer and intend to make your level to have lightmapped water, you can put these keyvalues to worldspawn entity description (always first entity in entities list):
| `_litwater` | integer | Set to any non-zero value to enable lightmapped water. Overrides `gl_litwater_force` cvar value. |
| `_litwater_minlight` | integer | Minimal lightmap value water surface will receive. Helps to avoid too dark areas when water isn't properly lit. If not set, defaults to zero. |
| `_litwater_scale` | float | Scales up lightmap value for water surfaces. If not set, defaults to 1.0. |
### For players:
Some of the maps already have computed lightmap for water surfaces and sometimes water has been properly lit but the support hasn't been declared by the level designer.
As a player, you can enable it in `Video options` menu or through console with `gl_litwater_force` cvar. There are also `gl_litwater_minlight` and `gl_litwater_scale` cvars that function similar to keys above. The default values has been set to `192` and `1.25` respectively to slightly avoid issues with maps that wasn't intended to have lightmapped water.
@@ -16,6 +16,7 @@ Only these objects are guaranteed to be available on all targets.
|-------------|-----------|
| `VFileSystem009` | Provides C++ interface to filesystem, binary-compatible with Valve's VFileSystem009. |
| `XashFileSystemXXX` | Provides C interface to filesystem. This interface is unstable and not recommended for generic use, outside of engine internals. For more info about current version look into `filesystem.h`. |
| `MenuFactory` | Returns a `CreateInterface` function pointer (`pfnCreateInterface_t`) for the currently loaded menu library. |
| Length | 2 bytes | uint16_t (LE) | Size of payload in bytes |
| Payload | N bytes | Binary | Command string or response data |
**Notes**:
- Header must be exactly `SBRK` (`53 42 52 4B` in hexadecimal form)
- Maximum frame size: soft limit is 4096 bytes, hard limit is 65535 bytes (due to uint16_t usage)
---
## Session Lifecycle
```
┌──────────────┐
│ IDLE │ ← Initial state, accepts new TCP connections
└──────────────┘
│ sb_gamedir
↓
┌──────────────┐
│ ACTIVE │ ← Session established, rejecting all of other TCP connections
└──────────────┘
│ sb_connect
↓
┌──────────────┐
│ ACTIVE │ ← Client getting auth ticket to connect to game server
└──────────────┘
│ sb_disconnect
↓
┌──────────────┐
│ ... │ ← Client announcing disconnect from game server, could connect somewhere again
└──────────────┘
│
↓
┌──────────────┐
│ ACTIVE │ ← Client shutting down game, terminating broker to reset Steam client state
└──────────────┘
│ sb_terminate
↓
┌──────────────┐
│ RESTARTING │
└──────────────┘
```
---
## Commands
All commands listed below are meant to be sent from client to broker as payload of a frame. The broker will parse the command string and respond accordingly.
XRCON is a TCP-based remote console protocol implemented as a server within the engine. It provides an alternative to the legacy RCON (which operates over UDP as out-of-band packets). XRCON uses a framed binary protocol over a single persistent TCP connection, accepting at most one client at a time.
Key characteristics:
- Based on TCP (stream-oriented, reliable)
- Default port is 27000
- Maximum only one concurrent client
- Binary framed protocol with a 12-byte header + variable-length payload
## Configuration
The XRCON server is controlled by two configuration variables, both restricted to privileged users:
| Variable | Default | Description |
|---|---|---|
| `xrcon_enable` | `0` (disabled) | Master switch; when enabled, the server starts listening for connections |
| `xrcon_address` | `127.0.0.1:27000` | Bind address and port; supports both IPv4 and IPv6. Changing this at runtime triggers a XRCON server restart (stop + rebind) |
By default, XRCON binds only to localhost (`127.0.0.1`), providing a degree of access control. The server will not start listening until explicitly enabled.
## Frame Format
All XRCON messages are encapsulated in a framed binary format. Each frame consists of a fixed 12-byte header followed by a variable-length payload.
### Header (12 bytes)
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 4 | Type | 4-character message type string (null-terminated, occupies 5 bytes in the structure but the 5th byte is padding) |
| 4 | 4 | Version | Protocol version (32-bit unsigned integer, network byte order) |
| 8 | 2 | Length | Total frame length in bytes, including the header (16-bit unsigned integer, network byte order) |
| 10 | 2 | Handle | Handle or sequence number (16-bit unsigned integer, network byte order; currently always zero) |
### Protocol Version
The current protocol version is `0x000000D4` (212 decimal). The server also accepts `0x00D40000` for compatibility with certain third-party clients (e.g., CS2RemoteConsole).
### Maximum Frame Size
- Maximum payload per frame: 4096 bytes
- Maximum total packet size (header + payload): approximately 4136 bytes
| Payload | Variable | Raw command string (null-terminated) |
The command string is injected into the engine's command buffer for execution. There is **no authentication** — any connected client may execute arbitrary commands.
### PRNT — Server Print
**Direction**: Server → Client
Sent by the server to stream console output to the connected client.
| Payload | 77 bytes | All zeros (placeholder / reserved for structured application information) |
This packet currently serves as a placeholder and contains no meaningful data. It may be extended in future versions to carry structured metadata about the server application.
### ADON — Additional Info
**Direction**: Server → Client
Sent by the server immediately after `AINF` during the connection handshake.
| Name Length | 2 bytes | Length of the name string (unsigned 16-bit integer) |
| Name | Variable | Server name / identifier string (e.g., `"HLDS"`) |
This packet carries the server application name, which is a short string identifying the server type (e.g., `"HLDS"` for Half-Life Dedicated Server).
## Security
XRCON has **no built-in authentication or encryption**. There is no password validation or transport-layer security. Any client that can establish a TCP connection to the XRCON port has full command execution access to the engine console.
The only security measures are:
1.**Default localhost binding**: The server binds to `127.0.0.1` by default, accepting connections only from the local machine.
2.**Disabled by default**: The `xrcon_enable` variable defaults to `0`, so the server does not listen unless explicitly enabled.
3.**Privileged variables**: Both configuration variables are restricted to privileged users and cannot be modified through unprivileged console commands or external access.
## Comparison with Legacy RCON
| Feature | XRCON | Legacy RCON |
|---|---|---|
| Transport | TCP (stream) | UDP (datagram, out-of-band) |
| Port | Configurable, default 27000 | Game port (default 27015) |
| Framing | Binary frame header | Plain text over UDP |
| Authentication | None | Password-based |
| Max clients | 1 | Multiple |
| Interaction format | Full console access | Request-response only for submitted command |
| Supported environments | Client and server | Server only |
This feature is still work-in-progress, but for now it's available for all users, and we appreciate any bug-reports and contributions around it.
For connecting to GoldSrc-based servers, use this command:
```
connect ip:port gs
```
But keep in mind, there are requirement for server to be able to accept connections from Xash3D-based clients: it should use Reunion or Dproto.
Without this requirement, you will just get "Steam validation rejected" error on connecting.
You need to use [Steam API broker](https://github.com/FWGS/steam-broker) and have purchased Half-Life 1 on your Steam account to be able to join GoldSrc servers.
That is because proper authorization with Steam API is not implemented in engine yet (but we have plans on it).
Broker will run on your PC and will be responsible for communicating with Steam client and obtaining auth tickets.
Also, make sure to set that broker as current ticket generator using console or edit `config.cfg` file manually:
```
cl_ticket_generator steam
```
Also, we encountered that some GoldSrc-based servers are recognizing Xash3D clients as "fake clients" and banning/kicking them. Maybe this problem will be
If you want to join GoldSrc servers from other device (Android/iOS or console), make sure to set proper broker IP address with `cl_steam_broker_addr` console variable. Default value assumed that broker is running on the same device as game client.
By the way, we encountered that some GoldSrc-based servers are recognizing Xash3D clients as "fake clients" and banning/kicking them. Maybe this problem will be
solved along with better compatibility with GoldSrc behavior, but may be not - we don't know logic behind this fake client checks.
|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 |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
|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
|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
|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
|Sven-Coop |5.0+ |Uses custom GoldSrc engine |
|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.
|Arrange Mod: Rebirth |v150 |No idea yet. |
|Blue Shift |The latest steam release |Uses vgui2 library which xash3d does not support. |Recreated source code here: https://github.com/FWGS/hlsdk-portable/tree/bshift.
|Counter Strike |Beta 6.5- |Uses an old WON HL 1.0.0.16- interface. |
| |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.
| |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-portable/tree/rebellion.
@@ -16,6 +16,9 @@ Mirrored on github - https://github.com/JoelTroch/am_src_rebirth
## Battle Grounds
Mirrored on github - https://github.com/nekonomicon/BattleGrounds
## Brain Bread
Official github repository - https://github.com/IronOak-Studios/BrainBread
## Bubblemod
Download page on official site(WM snapshot) - [http://www.bubblemod.org/dl_default.php](https://web.archive.org/web/20130717133158/http://www.bubblemod.org/dl_default.php)
@@ -32,18 +35,30 @@ Version 1.9 mirrored on github - https://github.com/solidi/hl-mods/tree/master/c
## Cold Ice Ressurection
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
## Deathmatch Classic
Available in Valve's Half-Life repository - https://github.com/ValveSoftware/halflife/tree/master/dmc
## Delta Particles
Available on ModDB - https://www.moddb.com/mods/half-life-delta/downloads/delta-particles-full-sources-maps-and-c-code
Xash3D FWGS currently supports four network protocols:
* Version 49, introduced in Xash3D in around 2018.
* Version 48, used in Xash3D FWGS 0.19 and earlier. Deprecated and to be removed in the future.
* GoldSrc version 48, used in current GoldSource version.
* Quake version 15, only used for demo playback for Quake Wrapper mod.
On the server side, we only support Xash3D 49 protocol, but bugcomp `gsmrf` mode can convert GoldSrc 48 messages into Xash3D 49 on the fly, for some mods that directly write engine internal messages.
In the following documents we will only cover version 49, as everything else is either not Xash3D specific or deprecated.
Connectionless protocol defines four common message sources and destinations, they can be:
*`S` for Server
*`C` for Client
*`M` for Master
*`A` for Anything else
All connectionless packets have `\xff\xff\xff\xff` (32-bit integer set to all ones) in it's header. Let's go through each of possible direction in this document.
<!--TOC-->
- [Any](#any)
- [Any to Any](#any-to-any)
- [`A2A_PING` and `A2A_GOLDSRC_PING`](#a2a_ping-and-a2a_goldsrc_ping)
- [`A2A_ACK` and `A2A_GOLDSRC_ACK`](#a2a_ack-and-a2a_goldsrc_ack)
- [Deprecated queries](#deprecated-queries)
- [`A2A_NETINFO`](#a2a_netinfo)
- [`A2A_INFO`](#a2a_info)
- [Any to Client](#any-to-client)
- [`A2C_PRINT` and `A2C_GOLDSRC_PRINT`](#a2c_print-and-a2c_goldsrc_print)
- [Any to Server and Server to Any](#any-to-server-and-server-to-any)
- [GoldSrc server queries](#goldsrc-server-queries)
- [`A2S_GOLDSRC_INFO`](#a2s_goldsrc_info)
- [`A2S_GOLDSRC_PLAYERS`](#a2s_goldsrc_players)
- [`A2S_GOLDSRC_RULES`](#a2s_goldsrc_rules)
- [Any to Master](#any-to-master)
- [`S2M_SCAN_REQUEST`](#s2m_scan_request)
- [Master to Any](#master-to-any)
- [`M2A_SERVERSLIST`](#m2a_serverslist)
- [Master and game server](#master-and-game-server)
- [Server to Master](#server-to-master)
- [`S2M_HEARTBEAT`](#s2m_heartbeat)
- [`S2M_SHUTDOWN`](#s2m_shutdown)
- [`S2M_INFO`](#s2m_info)
- [Master to Server](#master-to-server)
- [`M2S_CHALLENGE`](#m2s_challenge)
- [`M2S_NAT_CONNECT`](#m2s_nat_connect)
- [Client and game server](#client-and-game-server)
- [Client to Server](#client-to-server)
- [`C2S_BANDWIDTHTEST`](#c2s_bandwidthtest)
- [`C2S_GETCHALLENGE`](#c2s_getchallenge)
- [`C2S_CONNECT`](#c2s_connect)
- [Server to Client](#server-to-client)
- [`S2C_BANDWIDTHTEST`](#s2c_bandwidthtest)
- [`S2C_CHALLENGE`](#s2c_challenge)
- [`S2C_CONNECTION`](#s2c_connection)
- [`S2C_ERRORMSG`](#s2c_errormsg)
- [`S2C_REJECT`](#s2c_reject)
<!--TOC-->
## Any
### Any to Any
#### `A2A_PING` and `A2A_GOLDSRC_PING`
Simple ping message.
* Request, in ASCII: `ping` or `i` in GoldSrc format
* Response is always `A2A_ACK` or `A2A_GOLDSRC_ACK`
#### `A2A_ACK` and `A2A_GOLDSRC_ACK`
Simple ack message.
* Request, in ASCII: `ack` or `j` in GoldSrc format
* Response: none
#### Deprecated queries
These text-based Xash protocol queries are deprecated in favor of [GoldSrc server queries](#goldsrc-server-queries), which Xash3D FWGS servers implement as well. New implementations must not send them. The server still responds to `A2A_INFO` for compatibility with older clients, `A2A_NETINFO` is not handled anymore.
##### `A2A_NETINFO`
Used to implement Half-Life's NetAPI.
* Request message, in ASCII: `netinfo <version> <context> <request_id>`
-`version` must be 49, as text.
-`context` can be any 32-bit signed integer value, encoded as text.
-`request_id` see `common/net_api.h`
* Response message, in ASCII: `netinfo <context> <request_id> <response>`
-`context` same as in request.
-`request_id` same as in request.
-`response` is server's response, depending on request type. Always encoded as Quake info string.
Possible requests and response formats:
* Request ID `1` will make server respond with empty response string.
* Request ID `2` makes server respond with all server game rule cvars where the key is cvar name and the value is cvar value. One additional key `rules` with total amount of cvars is added.
* Request ID `3` makes server respond with players list, where:
-`p<id>name` is set to player's name
-`p<id>frags` is set to player's kill count
-`p<id>time` is set to player's total play time
-`players` is total player's list.
- Alternatively, it can respond with `neterror` set to `forbidden` if server does not wish to expose it's player list.
* Request ID `4` makes server to respond with common game details:
-`hostname` is server's name
-`gamedir` is game directory name
-`current` is total player count
-`max` is max players limit
-`map` is server's current level
* On any other server will respond with `neterror` set to `undefined`
* If protocol version doesn't match, server responds with `neterror` set to `protocol`
##### `A2A_INFO`
Used to request server's details.
* Request message, in ASCII: `info <version>`
-`version` must be 49, as text
* Response message, in ASCII: `info\n<response>`
-`response` is Quake info string, otherwise it's an error message.
* Response info string format:
-`p` is set to protocol version (FWGS extension)
-`map` is server's current level
-`dm` set to 1 if current game mode is deathmatch otherwise 0
-`team` set to 1 if current game mode includes teamplay otherwise 0
-`coop` set to 1 if current game mode is cooperative otherwise 0
-`numcl` is total player count
-`maxcl` is max players limit
-`gamedir` is game directory name
-`password` set to 1 if server is protected with password otherwise 0
-`host` is server's name
### Any to Client
#### `A2C_PRINT` and `A2C_GOLDSRC_PRINT`
Simple print message.
* Header: `\xff\xff\xff\xff`
* Request, in ASCII: `print <message>` or `l<message>` in GoldSrc format.
* Response: none
### Any to Server and Server to Any
#### GoldSrc server queries
These match Source Engine Query messages used in GoldSrc and Source engine and implemented for compatibility with existing server browsers and monitoring tools. The client uses them to query GoldSrc servers in the server browser, and as text-based Xash protocol queries are [deprecated](#deprecated-queries), it will use them to query Xash servers as well. Read documentation for them on VDC: https://developer.valvesoftware.com/wiki/Server_queries
Unlike other connectionless messages these are binary: integers are little-endian, floats are 32-bit IEEE 754 and strings are null-terminated.
`A2S_GOLDSRC_PLAYERS` and `A2S_GOLDSRC_RULES` requests carry a 32-bit challenge, `A2S_GOLDSRC_INFO` may have one appended after the query string. When no challenge is known yet, `\xff\xff\xff\xff` is sent in it's place. The server may answer with a challenge instead of the data: byte `A` (`0x41`) followed by a 32-bit challenge value, 9 bytes total with the header. The request is then repeated with the received challenge. Don't confuse this message with textual `S2C_GOLDSRC_CHALLENGE` used during connection, they only share the first byte.
Responses that don't fit into a single packet (usually rules) come from GoldSrc servers split into fragments. Such packets start with `\xfe\xff\xff\xff` instead of `\xff\xff\xff\xff`, followed by a 32-bit sequence number, same in all fragments of one response, and a byte with total fragment count in the lower 4 bits and this fragment's index in the upper 4 bits. Fragment payloads concatenated in index order form a normal `\xff\xff\xff\xff` message. Xash servers never split query responses and send them as single datagrams.
#### `A2S_GOLDSRC_INFO`
Used to request server's details.
* Request: `TSource Engine Query\0`, optionally followed by a 32-bit challenge. Xash servers ignore it.
* Response: byte `I` (`S2A_GOLDSRC_INFO`), followed by:
- byte: protocol version, 48 on GoldSrc, 49 on Xash3D FWGS
- string: server's name
- string: server's current level
- string: game directory name
- string: game description
- int16: Steam AppID, always 0 on Xash servers
- byte: total player count, bots included
- byte: max players limit
- byte: bot count
- byte: server type, `d` for dedicated or `l` for listen server
- byte: server's operating system, `w` for Windows, `l` for Linux, `m` for macOS
- byte: set to 1 if server is protected with password otherwise 0
- byte: set to 1 if server is VAC secured, Xash servers put the `secure` value from gameinfo here
- string: server's version
Same as the Source engine response format but without the extra data flag and its fields.
Legacy GoldSrc servers respond with the obsolete `m` format (`S2A_GOLDSRC_LEGACY_INFO`) instead, see VDC for its layout. Xash servers never send it but the client understands it and assumes protocol 48.
#### `A2S_GOLDSRC_PLAYERS`
Used to request server's player list.
* Request: byte `U` (`0x55`), then a 32-bit challenge.
* Response: byte `D` (`S2A_GOLDSRC_PLAYERS`), followed by a byte with total player count, then for each player:
- float: time in seconds the player is connected, -1.0 for bots on Xash servers
Xash server doesn't respond at all if the player list is empty, the server is protected with password or exposing the player list is disabled with `sv_expose_player_list` cvar.
#### `A2S_GOLDSRC_RULES`
Used to request server's game rules.
* Request: byte `V` (`0x56`), then a 32-bit challenge.
* Response: byte `E` (`S2A_GOLDSRC_RULES`), followed by an int16 with total rule count, then rule name and rule value strings for each.
Only server cvars (`FCVAR_SERVER`) are sent. Values of protected cvars (`FCVAR_PROTECTED`) are replaced with `1` if the value is set otherwise `0`. If there are no cvars to expose, server doesn't respond at all.
### Any to Master
#### `S2M_SCAN_REQUEST`
* Request: `1<region><IP:Port>\0<info>`
- Format of this message is loosely based on https://developer.valvesoftware.com/wiki/Master_Server_Query_Protocol
-`info` however adds few additional fields:
-`clver` set to engine's version
-`nat` set to 1 to filter only servers behind NAT and tell master to notify servers about scan
-`commit` set to engine's build commit hash
-`branch` set to engine's build branch
-`os` set to which operating system engine has been built
-`arch` set to which CPU architecture engine has been built
-`buildnum` set to engine's build number
-`key` set to random 32-bit value formatted as hex, used to validate master responses
* Response: `M2A_SERVERSLIST`
### Master to Any
#### `M2A_SERVERSLIST`
* Request: `f\xff<key><reserved><IP:Port>...`
-`key` is random 32-bit value set in `S2M_SCAN_REQUEST`
-`reserved` is single reserved 8-bit byte
- Following is list of IP addresses in binary form: 6-bytes for IPv4 address + port and 18-bytes for IPv6 address + port
- If port is 0, it means the end of list, otherwise it's the last IP used for pagination (not implemented in Xash3D)
* Response: client doesn't make response to master server but might request `A2S_GOLDSRC_INFO` from servers
## Master and game server
### Server to Master
#### `S2M_HEARTBEAT`
Used to update game server information on the master server.
* Request: `q\xff<heartbeat challenge>`
-`heartbeat challenge` is random 32-bit value, used to prevent faked/forged source IP addresses.
* Response: `M2S_CHALLENGE`
#### `S2M_SHUTDOWN`
Used to notify master server about server shutdown, but due to security reasons must be ignored by any master implementation.
* Request: `\x62\x0a`
* Response: none
#### `S2M_INFO`
Game server info response on `M2S_CHALLENGE`.
* Request: `0\n<info>`
-`info` is Quake info string containing server information passed to master server. It contains following fields:
-`protocol` is always 49
-`challenge` is master challenge
-`players` is total player count, without bots
-`max` is max players limits
-`bots` is total bot count
-`gamedir` is set to game directory
-`map` is server's current level
-`type` set to `d` for dedicated or `l` for listen server
-`password` set to `1` if server protected with password set otherwise `0`
-`os` always `w`
-`secure` always `0`
-`lan` always `0`
-`version` engine version
-`region` always `255`
-`product` same as `gamedir`
-`nat` set to `1` if server is behind NAT
* Response: none
### Master to Server
#### `M2S_CHALLENGE`
Master's respoonse on game server's heartbeat message.
-`master challenge` contains 32-bit value, used in server response to prevent faked/forged source IP addresses.
-`heartbat challenge` cotnains 32-bit value, used in heartbeat request to prevent faked/forged source IP addresses.
* Response: `S2M_INFO`.
#### `M2S_NAT_CONNECT`
Master server's message with client IP address and port, used in NAT punching.
* Request: `c <IP:Port>`
* Response: `S2C_INFO` to a specified client address.
## Client and game server
### Client to Server
#### `C2S_BANDWIDTHTEST`
Used to figure out network MTU. The message is optional and server might choose to not implement it or respond with challenge.
* Request, in ASCII: `bandwidth <version> <max_size>`
-`version` must be 49, as text.
-`max_size` is requested maximum packet size.
* Possible responses:
-`S2C_BANDWIDTHTEST`
-`S2C_CHALLENGE`
-`A2A_PRINT` followed by `S2C_REJECT`
-`S2C_ERRORMSG` (as FWGS extension) followed by `A2A_PRINT` and `S2C_REJECT`.
#### `C2S_GETCHALLENGE`
Used to validate client's address to prevent faked/forged source IP addresses.
* Header: `\xff\xff\xff\xff`
* Request, in ASCII: `getchallenge steam`
-`steam` argument is optional and can be ignored by the server, as it's only kept for compatibility with similar GoldSrc 48 message.
* Possible responses:
-`S2C_CHALLENGE`
#### `C2S_CONNECT`
Used to build a connection with the server.
* Header: `\xff\xff\xff\xff`
* Request, in ASCII: `connect <version> <challenge> "<protinfo>" "<userinfo>"`
-`version` must be 49, as text.
-`challenge` must be challenge value, as text.
-`protinfo` is a Quake info string, containing protocol extensions and other connection information.
-`uuid` is this client's unique ID (FWGS extension) hasheed with MD5.
-`qport` is random integer value from 1 to 65535, unique for this engine run.
-`ext` is an integer value OR'ed with requested protocol extensions. Currently only extension is `NET_EXT_SPLITSIZE` with the value of `1`, which tells server to split messages based on `cl_dlmax` value from `userinfo`.
-`userinfo` contains initial user info, encoded as Quake info string.
* Possible responses:
-`A2A_PRINT` followed by `S2C_REJECT`
-`S2C_ERRORMSG` (as FWGS extension) followed by `A2A_PRINT` and `S2C_REJECT`.
-`S2C_CONNECTION`
### Server to Client
#### `S2C_BANDWIDTHTEST`
* Request: `testpacket<crc><blob>`
-`crc` is 32-bit CRC of `blob`
-`blob` random data
* There is no required response to this message
Total message size doesn't exceed request max size.
#### `S2C_CHALLENGE`
* Request, in ASCII: `challenge <value>`
-`value` is challenge value that client must include in it's response
* Response: `C2S_CONNECT`
#### `S2C_CONNECTION`
* Request, in ASCII: `client_connect <protinfo>`
-`protinfo` is an optional Quake info string, contains following optional fields:
-`ext` is an integer value OR'ed with allowed protocol extension. Bit fields match requested in `ext` field in `C2S_CONNECT`
-`cheats` set to 1 if server allows cheats otherwise 0
* Response: there is no out of band from the client but client will proceed to building netchan and switch client-server interaction to it.
#### `S2C_ERRORMSG`
Show client error message. Doesn't mean connection reject, only used for UI.
* Request, in ASCII: `errormsg <message>`
-`message` contains error message
* Response: none
#### `S2C_REJECT`
Client has been rejected in connection.
* Request, in ASCII: `disconnect`
* Response: client can cope, get depressed or mentally tell server to fuck off.
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
ux0:tai/kubridge.skprx
```
3. Install `libshacccg.suprx` by following [this guide](https://cimmerian.gitbook.io/vita-troubleshooting-guide/shader-compiler/extract-libshacccg.suprx).
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!
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*

*Touch profiles window*

*Touch buttons parameters window*

## 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.
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.*

## 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*

* Example of adding a new button with a custom icon (the `lastinv` command is used - quick change between weapons)

*View of this button in layout editor*

## 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)
> **Only download Xash3D FWGS from official sources.** Third-party builds, "modded launchers", "optimized" repacks and random mirrors are frequently bundled with malware, miners, spyware and credential stealers. We cannot vouch for anything we did not build. Get official binaries only from the [releases page](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.
@@ -35,15 +39,22 @@ You still needed to copy `valve` directory as all game resources located there.
For additional info, run Xash3D with `-help` command line key.
## 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.
### 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.
## Reporting issues
* Issues are accepted in both English and Russian.
*Before sending a PR, check if you followed our contribution guide in CONTRIBUTING.md file.
*They are only accepted if you run legally acquired product (e.g. Half-Life in Steam).
## Contributing code
* Check the CONTRIBUTING.md file.
## 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/).
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
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,24 +76,43 @@ This repository contains our fork of HLSDK and restored source code for Half-Lif
* Only for 32-bit engine on 64-bit x86 operating system:
* Enable i386 on your system: `$ sudo dpkg --add-architecture i386`.
* Install build dependencies by running: `brew install python`.
* Clone the SDL2 repo `$ git clone --recursive https://github.com/libsdl-org/SDL.git -b SDL2` and compile the iOS framework by navigating to SDL/Xcode/SDL and opening the Xcode project.
* Clone this repository: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`.
### Building
#### Windows (Visual Studio)
0) Open command line.
@@ -99,3 +129,19 @@ 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).
To build you should clone [SDL](https://github.com/libsdl-org/SDL) from `SDL2` branch and [HLSDK-portable](https://github.com/FWGS/hlsdk-portable) `mobile-hacks` branch repositories to 3rdparty folder, after that you should be able to open the project in Android Studio from `android` directory or manually call Gradle to build the APK.
#### iOS/iPadOS (MacOS only)
0) (optional) Examine which build options are available: `./waf --help`.
1) Configure build: `./waf configure --ios --enable-bundled-deps --sdl2 (path/to/SDL2.framework)`, set `--ios-simulator` instead of `--ios` if you want to build for simulator.
2) Compile `./waf build`.
3) Navigate to `build` and copy your compiled SDL2.framework there, then add your game dylibs to `build/ios/libs/(gamedir)/(dlls/cl_dlls)`(You can also run `scripts/ios/buildhlsdk.sh` instead to automatically create an ipa with hlsdk dylibs)
4) Run `scripts/ios/createipa.sh` to create an installable ipa
### Running tests
Tests are enabled with `--enable-tests` passed to `./waf configure` and can be run with `./waf --alltests`.
This builds both standalone unit tests and a separate engine test binary (`xash3d_tests`) that embeds engine-level tests. The engine test binary requires no game assets.
Nomedia.kt - ensure that .nomedia file exists in directory
Copyright (C) 2025 Alibek Omarov
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
packagesu.xash.engine.util
importjava.io.File
objectNomedia{
funensureNomedia(directory:File):Boolean{
try{
// ensure paths exists
if(!directory.exists()&&!directory.mkdirs()){
returnfalse
}
// check if it's a directory
if(!directory.isDirectory){
returnfalse
}
valnomediaFile=File(directory,".nomedia")
// if the .nomedia is directory, remove it
if(nomediaFile.isDirectory){
// it should be empty to be deleted, but that's good
// because this way we're not deleting something important
// (who would stash important files in .nomedia directory though...)
if(!nomediaFile.delete()){
returnfalse
}
}
// it returns false if file already exists, which is fine for us
nomediaFile.createNewFile()
returntrue
}catch(e:Exception){
e.printStackTrace()
returnfalse
}
}
}
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.