Compare commits

..

20 Commits

Author SHA1 Message Date
Alibek Omarov
aa02f54536 engine: add a shortcut for loading custom DLLs that follow library naming scheme (like bots) 2025-08-03 04:35:10 +05:00
Alibek Omarov
ac162b33e9 scripts: build-ninja: add support for installing libraries with cmake, compared to yanking them out of build directory
Set up hlsdk-portable to install in APK style directory (omitting game and game library directories from path).
Minor refactoring.
2025-08-03 04:35:10 +05:00
Alibek Omarov
54091b0875 engine: platform: android: strip library path when loading libraries from APK 2025-08-03 04:35:10 +05:00
Bohdan Shulyar
0b65f87bb1 android: add some simple run instructions 2025-08-03 04:35:10 +05:00
Bohdan Shulyar
2553f376ae android: add some simple docs 2025-08-03 04:35:10 +05:00
Bohdan Shulyar
4e6babbd4d android: bump deps 2025-08-03 04:35:10 +05:00
Bohdan Shulyar
f7db736340 android: experimental ninja build 2025-08-03 04:35:10 +05:00
Bohdan Shulyar
d038162903 android: fix weird acra build error 2025-08-03 04:35:10 +05:00
Bohdan Shulyar
99f33fb406 android: don't generate x86 libraries for now 2025-08-03 04:35:10 +05:00
Bohdan Shulyar
27c851f071 android: bump gradle 2025-08-03 04:35:10 +05:00
Bohdan Shulyar
09f3998cda android: add a (not working yet) basedir option 2025-08-03 04:35:10 +05:00
Bohdan Shulyar
4c159015e4 android: update codebase to use java File API 2025-08-03 04:35:10 +05:00
Velaron
35b63ca647 android: reformat codebase 2025-08-03 04:35:10 +05:00
Velaron
4a4086e27c android: upgrade buildsystem 2025-08-03 04:35:10 +05:00
Velaron
b3c2e5568d android: remove DocumentsProvider 2025-08-03 04:35:10 +05:00
Velaron
232a3163ff android: remove currently unused or invalid resources 2025-08-03 04:35:10 +05:00
Alibek Omarov
aacdde1522 engine: platform: android: do not automatically prepend lib prefix 2025-08-03 04:35:10 +05:00
Alibek Omarov
54d737fe3e scripts: gha: temporarily switch hlsdk-portable branch to android_library_naming for testing 2025-08-03 04:35:10 +05:00
Alibek Omarov
b43105f13d filesystem: wscript: strip lib prefix on Android 2025-08-03 04:35:10 +05:00
Alibek Omarov
6661ec3090 defaults: disable INTERNAL_GAMELIBS for Android 2025-08-03 04:35:10 +05:00
419 changed files with 20827 additions and 21601 deletions

21
.cirrus.yml Normal file
View File

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

View File

@@ -21,12 +21,14 @@ jobs:
- os: ubuntu-22.04
targetos: linux
targetarch: i386
- os: ubuntu-22.04-arm
- os: ubuntu-22.04
targetos: linux
targetarch: arm64
- os: ubuntu-22.04-arm
cross: true
- os: ubuntu-22.04
targetos: linux
targetarch: armhf
cross: true
- os: ubuntu-24.04 # riscv64 would benefit from having latest compilers
targetos: linux
targetarch: riscv64
@@ -35,6 +37,9 @@ jobs:
targetos: linux
targetarch: ppc64el
cross: true
# - os: ubuntu-aarch64-22.04
# targetos: linux
# targetarch: aarch64
# - os: ubuntu-latest
# targetos: linux
# targetarch: e2k-8c
@@ -61,21 +66,18 @@ jobs:
- os: macos-14 # arm64 as per github documentation
targetos: apple
targetarch: arm64
- os: macos-latest
targetos: ios
targetarch: arm64
- os: macos-15-intel
- os: macos-13 # x86 as per github documentation (will they fix it before they deprecate this version?..)
targetos: apple
targetarch: amd64
env:
SDL_VERSION: 2.32.10
FFMPEG_VERSION: 8.1
SDL_VERSION: 2.32.8
FFMPEG_VERSION: 7.1
GH_CPU_ARCH: ${{ matrix.targetarch }}
GH_CPU_OS: ${{ matrix.targetos }}
GH_CROSSCOMPILING: ${{ matrix.cross }}
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies
@@ -85,7 +87,7 @@ jobs:
FWGS_PFX_PASSWORD: ${{ secrets.FWGS_PFX_PASSWORD }}
run: bash scripts/gha/build_${{ matrix.targetos }}.sh
- name: Upload engine (artifacts)
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: artifact-${{ matrix.targetos }}-${{ matrix.targetarch }}
path: artifacts/*
@@ -97,11 +99,11 @@ jobs:
include:
- app: su.xash.Engine.Compat.i386
container:
image: ghcr.io/flathub-infra/flatpak-github-actions:freedesktop-25.08
image: ghcr.io/flathub-infra/flatpak-github-actions:freedesktop-24.08
options: --privileged
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
submodules: recursive
- name: Build flatpak (Compat.i386)
@@ -115,10 +117,31 @@ jobs:
needs: [build, flatpak]
if: ${{ github.event_name == 'push' }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Remove old release, fetch artifacts, repackage binaries and upload new release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BASE_BUILDNUM_DATE: "2015-04-01"
run: bash scripts/gha/make_release.sh "Xash3D FWGS" "${{ github.ref_name }}"
RELEASE_TAG: ${{ github.ref_name == 'master' && 'continuous' || format('continuous-{0}', github.ref_name) }}
run: |
gh release delete "$RELEASE_TAG" \
--yes \
--cleanup-tag \
--repo "$GITHUB_REPOSITORY" || true
gh run download "$GITHUB_RUN_ID" \
--dir artifacts/ \
--repo "$GITHUB_REPOSITORY"
pushd artifacts/
echo "Found artifacts:"
ls
for i in $(find -mindepth 1 -maxdepth 1 -type d); do
mv "$i"/* .
rm -rf "$i"
done
echo "Repackaged artifacts:"
ls -R
popd
sleep 20s
gh release create "$RELEASE_TAG" artifacts/* \
--title "Xash3D FWGS Continuous ${{ github.ref_name }} Build" \
--target $GITHUB_SHA \
--repo "$GITHUB_REPOSITORY" \
--prerelease

7
.gitignore vendored
View File

@@ -318,12 +318,6 @@ build-*
*.includes
*.files
# ios
ios/cl_dlls/*
ios/dlls/*
ios/*.framework
scripts/ios/mod-build
# Waf
build_current
*waf-*/
@@ -345,7 +339,6 @@ __pycache__
.history/*
.cache/*
enc_temp_folder/
Taskfile.yml
# KDevelop4
*.kdev4

5
.gitmodules vendored
View File

@@ -39,7 +39,4 @@
url = https://github.com/ianlancetaylor/libbacktrace
[submodule "3rdparty/maintui"]
path = 3rdparty/maintui
url = https://github.com/FWGS/xash3d-maintui.git
[submodule "3rdparty/library_suffix"]
path = 3rdparty/library_suffix
url = https://github.com/FWGS/library-suffix.git
url = https://github.com/numas13/xash3d-maintui.git

View File

@@ -20,10 +20,10 @@ int main (void) {
}'''
FRAGMENT_GETPAGESIZE='''#include <unistd.h>
int main(void) { return getpagesize(); }'''
int main(void) { return getpagesize() }'''
FRAGMENT_GETEXECNAME='''#include <stdlib.h>
int main(void) { return getexecname() != 0; }'''
int main(void) { return getexecname() != 0 }'''
FRAGMENT_STRNLEN='''#include <string.h>
int main(int argc, char **argv) { return (int)strnlen(argv[0], 10); }'''
@@ -62,7 +62,7 @@ def options(opt):
def configure(conf):
# add unsupported platforms here
if conf.env.DEST_OS in ['nswitch', 'psvita', 'dos', 'irix']:
if conf.env.DEST_OS in ['nswitch', 'psvita', 'dos']:
conf.env.DISABLE_LIBBACKTRACE = True
return
@@ -95,7 +95,7 @@ def configure(conf):
return {'header_name':hdr, 'msg':'... %s header' % hdr, 'mandatory':False, 'id':hdr, 'compiler': 'c'}
def check_frag(frag, msg, define, **kw):
return dict({'fragment': frag, 'msg':'... %s' % msg, 'mandatory': False, 'define_name': define, 'compiler': 'c'}, **kw)
return dict({'fragment': frag, 'msg':'... %s' % msg, 'mandatory': False, 'compiler': 'c'}, **kw)
conf.multicheck(
check_header('dlfcn.h'),
@@ -120,8 +120,8 @@ def configure(conf):
check_frag(FRAGMENT_SYNC, ' __sync extensions', 'HAVE_SYNC_FUNCTIONS'),
check_frag(FRAGMENT_GETPAGESIZE, ' getpagesize function', 'HAVE_DECL_GETPAGESIZE'),
check_frag(FRAGMENT_STRNLEN, ' strnlen function', 'HAVE_DECL_STRNLEN'),
check_frag(FRAGMENT_DL_ITERATE_PHDR % 'link.h', ' dl_iterate_phdr function in link.h', 'HAVE_DL_ITERATE_PHDR_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']),
check_frag(FRAGMENT_DL_ITERATE_PHDR % 'link.h', ' dl_iterate_phdr function in link.h', 'HAVE_DL_ITERATE_PHDR', after_tests=['link.h']),
check_frag(FRAGMENT_DL_ITERATE_PHDR % 'sys/link.h', ' dl_iterate_phdr function in sys/link.h', 'HAVE_DL_ITERATE_PHDR', after_tests=['sys/link.h']),
check_frag(FRAGMENT_FCNTL, 'fnctl function', 'HAVE_FCNTL'),
check_frag(FRAGMENT_GETEXECNAME, 'getexecname function','HAVE_GETEXECNAME'),
check_frag(FRAGMENT_GETIPINFO, '_Unwind_GetIPInfo function', 'HAVE_GETIPINFO'),
@@ -137,9 +137,6 @@ def configure(conf):
msg='Checking for in parallel'
)
if conf.is_defined('HAVE_DL_ITERATE_PHDR_LINK_H') or conf.is_defined('HAVE_DL_ITERATE_PHDR_SYS_LINK_H'):
conf.define('HAVE_DL_ITERATE_PHDR', 1)
conf.env[DEFKEYS].sort()
conf.write_config_header()
@@ -165,13 +162,8 @@ def build(bld):
if bld.env.DISABLE_LIBBACKTRACE:
return
sources = ['atomic.c', 'dwarf.c', 'fileline.c', 'posix.c', 'print.c', 'sort.c', 'state.c', 'backtrace.c', 'simple.c']
if bld.env.DEST_OS == 'win32':
sources += ['read.c', 'alloc.c']
else:
# we specifically only want mmap-based allocators because calling malloc is not safe from signal handlers
sources += ['mmap.c', 'mmapio.c']
# we specifically only want mmap-based allocators because calling malloc is not safe from signal handlers
sources = ['atomic.c', 'dwarf.c', 'fileline.c', 'posix.c', 'print.c', 'sort.c', 'state.c', 'backtrace.c', 'simple.c', 'mmap.c', 'mmapio.c']
if bld.env.DEST_BINFMT == 'pe':
sources += ['pecoff.c']
@@ -184,8 +176,7 @@ def build(bld):
task = bld.stlib(
source = ['libbacktrace/' + i for i in sources],
# while we're using upstream libbacktrace, sometimes compiler picks up it's own version that isn't built with required options
target = 'backtrace_custom',
target = 'backtrace',
features = 'frandomseed' if bld.env.HAVE_FRANDOM_SEED else '',
use = 'EXTRAFLAGS lzma z zstd',
includes = '. libbacktrace/',

Submodule 3rdparty/library_suffix deleted from 2cb2a0e120

View File

@@ -29,11 +29,10 @@
* This project uses mixed Quake's and HLSDK's C/C++ code style convention.
* In short:
* Use spaces in parenthesis, but not when two parentheses are consecutive.
* Use spaces in parenthesis.
* 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.

View File

@@ -1,103 +0,0 @@
## Setting up Xash3D FWGS in Qt Creator
### Intro
Most versions of Qt Creator support using `compile_commands.json` as a project
file and Waf supports generating this file in a compliant format. In this
tutorial we will leverage that features.
The tutorial is written using Qt Creator 18.0, but I urge you to use whatever
latest Qt Creator version is available, as it's often has important bug fixes.
### Step 1. Configure the build.
`compile_commands.json` file, as it can be guessed from it's name, contains
every command used to invoke compiler during build. As the build process
depends on the build configuration, we have to configure it first. I'm not
going to get into details here, as basics of compiling Xash3D FWGS already
explained in `README.md`, located in repository root.
Save the configure step command somewhere, as it's going to be used later.
### Step 2. Generate `compile_commands.json` file.
Usually, this file is located in `build` directory after a successful build.
However, it's also possible to generate it manually by running follow command:
On *nix systems:
```
$ ./waf clangdb
```
Or on Windows:
```
> waf.bat clangdb
```
### Step 3. Load the project in Qt Creator.
To do this, you need to be sure that `Compilation Databases` plugin is enabled.
As it's considered experimental, it probably needs to be enabled manually. It
can be done in `Help` -> `About Plugins...`. Locate it in `Build Systems`
category, put the checkbox and press `OK`. The IDE will ask for restart, so do
this.
After IDE has been restarted, you can use `File` -> `Open File or Project...`.
Navigate to Xash3D FWGS directory, then to `build` directory and select
`compile_commands.json` file. If everything is done correctly, IDE will ask to
set up the project. Press `Configure Project` button, as most options there are
usually unapplicable to us.
Next IDE will show project tree, however you might not see any files. This is
happens as Qt Creator "thinks" our project root located in `build` directory.
Thankfully it provides a way to override this. To fix it, click with right
mouse button on the root of project tree (it's usually called something like
`build [master]`) and select `Change Root Directory`. In opened window choose
Xash3D FWGS repository root and press `OK`.
### Step 4. Tell IDE how to build this project.
Open `Projects` on the left menu and choose `Build Settings` tab. You should
see an empty configuration for build and clean steps. Press on `Add Build Step`
button and choose `Custom Process Step`.
In created step you should see `Command`, `Arguments` and `Working Directory`.
For the command, choose the Python executable. For arguments, use configure
command for Waf from the first step. Working directory is usually set by IDE
to `%{buildDir}`. You need to select the upper directory, where the `waf` is
located. To save some time, it can be specified as `%{buildDir}/../`.
Add another custom step, fill it with the same command and working directory.
For arguments use `waf build`.
Below you should see `Clean steps`. Create a clean step the same way, fill the
arguments and working directory as usual, for arguments use `waf clean`.
### Step 5. Tell IDE how to copy built binaries.
Now select `Deploy Settings` tab. Press `Add Deploy Step` -> `Custom Process
Step`. Again, same command and working directory. In arguments field type:
`waf install --destdir="<here put where Xash binaries should be copied to>"`.
### Step 6. Finally, set up Qt Creator to run the engine.
Select the `Run Settings` tab. Below you might see familiar text fields:
`Executable`, `Command line arguments` and `Working directory`.
For working directory click on `Browse...` button and select the folder where
Xash3D executable will be copied to, from previous step.
For executable type `./xash3d` if you're on *nix or `xash3d.exe` if you're on
Windows. The command line arguments are the same you use to run the engine. Can
be empty as well, but I personally use `-dev 2 -log` for extra verbosity.
### Outro
At this moment, you should be able to press `Run` button, wait until build
finishes and see running Xash3D FWGS. On Windows to use the debugger you might
need the `CDB` debugger and appropriate `qtcreatorcdbext` binary for debugging
32-bit applications and a separate for 64-bit, but that's left as an exercise
for the reader and a potential improvement for this document.

View File

@@ -26,12 +26,3 @@ Initial Xash3D SDL2/Linux port author, Xash3D FWGS engine maintainer, creator of
* [Boosty page](https://boosty.to/snmetamorph)
* [Other donation methods](https://snmetamorph.github.io/donate)
## [$_Vladislav](https://github.com/Vladislav4KZ)
[YaPB Project](https://github.com/yapb) member, [Xash3D FWGS](https://github.com/FWGS/xash3d-fwgs) tester,
editor of the [Official YaPB Documentation](https://github.com/yapb/docs) (in English and Russian), curator of the [YaPB Graph Database](https://github.com/yapb/graph) and author of [YaPB Waypoint/Graph Pack](https://gamebanana.com/mods/40087).
Also does the Russian localization of text, images (gfx/shell), as well as additional menu buttons in English used in Xash3D FWGS for various mods.
* [Boosty page](https://boosty.to/rasstaman1337)

View File

@@ -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-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).
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).
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.

View File

@@ -1,16 +0,0 @@
# Addon folders in Xash3D FWGS
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. |

View File

@@ -42,6 +42,3 @@ 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..

View File

@@ -1,19 +0,0 @@
## Lightmapped water
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):
| Key | Value | Description |
| ---------------------- | ------- | ----------- |
| `_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.

View File

@@ -1,139 +0,0 @@
# Steam API Broker Protocol Specification
## Overview
Due to proprietary nature of Steamworks SDK, it cannot be run on same amount
of platforms supported by Xash3D FWGS, neither we can link library directly due to
GNU GPLv3 license.
However, here comes the broker, by running it (in trusted
network, preferrably) on a machine that has Steam client installed, the
engine can communicate with it, acquiring needed information to log-in into
Steam protected multiplayer servers.
## Key Characteristics
Broker uses a simple TCP-based binary protocol with the following properties:
- Single active session per connection: once a session is activated, the broker will reject all other TCP connections until the session is terminated.
- All messages follow a consistent structure with a header, length, and payload: this is called a "frame".
- Stateful interactions: commands affect the session state, and certain commands are only valid in specific states.
- Numeric parameters are encoded in little-endian format for compatibility with majority of platforms.
---
## Frame Format
All communication uses a fixed frame structure:
| Field | Size | Type | Description |
|-------|------|------|-------------|
| Header | 4 bytes | ASCII | Frame start signature |
| 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.
### Session activation
Activates the session and signaling game startup.
**Format**: `sb_gamedir <gamedir>`
**Response**: None
---
### Authentication ticket request
Requests authentication ticket for a game server.
**Precondition**: Session must be active
**Format**: `sb_connect <ip:port> <server_steamid> <secure> <challenge>`
**Parameters**:
| Name | Description |
|------|------------------|
| `<ip:port>` | Game server address (e.g., `127.0.0.1:27015`) |
| `<server_steamid>` | Server SteamID |
| `<secure>` | 0 = insecure, 1 = secure |
| `<challenge>` | Random value for reply prevention |
**Response Format**:
| Field | Size | Type | Description |
|-------|------|------|-------------|
| Header | 11 bytes | string | `"sb_connect\n"` |
| Challenge | 4 bytes | int32_t (LE) | Echo of challenge from request |
| SteamID | 8 bytes | uint64_t (LE) | Client SteamID from configuration |
| Size | 4 bytes | uint32_t (LE) | Length of ticket in bytes |
| Ticket | N bytes | - | Authentication ticket data |
---
### Server disconnection announcement
Notifies broker of disconnection from game server.
**Precondition**: Session must be active
**Format**: `sb_disconnect <ip:port> <challenge>`
**Response**: None
---
### Session termination
Signaling game shutdown to broker and resetting Steam client state.
**Format**: `sb_terminate`
**Response**: None
---

View File

@@ -1,18 +1,15 @@
# Support for GoldSrc network protocol
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
```
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.
But keep in mind, there are requirement for server to be able to accept connections from Xash3D-based clients: it should use Reunion.
Without this requirement, you will just get "Steam validation rejected" error on connecting.
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
```
That is because proper authorization with Steam API is not implemented in engine yet (but we have plans on it).
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
Also, 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.

View File

@@ -4,7 +4,7 @@
|---- |------- |--------------- |----------------------
|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.
|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 |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.
@@ -15,6 +15,6 @@
|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.
|Rebellion |1.0 |Uses an old WON HL 1.0.0.16- interface. |Recreated source code here: https://github.com/FWGS/hlsdk-xash3d/tree/rebellion.
|Sven-Coop |5.0+ |Uses custom GoldSrc engine. |
|Time Shadows |Beta 0.1 |Uses Direct3D renderer. |

View File

@@ -16,9 +16,6 @@ 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)
@@ -53,9 +50,6 @@ Alpha 2.0 - https://www.gamers-desire.de/details/2830
## ESHQ
Official github repository - https://github.com/adslbarxatov/xash3d-for-ESHQ
## Feline
Available on ModDB - https://www.moddb.com/mods/feline-10/downloads/feline-sdk
## Flat-Life
Available on GamerLab - http://gamer-lab.com/eng/code_mods_goldsrc/Half-Life_2D_(Flat-Life)
@@ -70,9 +64,6 @@ Version 3.0, mirrored on github - https://github.com/nekonomicon/Go-mod30
## GT mod
Available on GamerLab - http://gamer-lab.com/eng/code_mods_goldsrc/GT_mod_(Polnie_ishodniki)
## Half-Force
Available on ModDB - https://www.moddb.com/mods/half-force/downloads/half-force-v20-sdk
## Half-Life: Advanced Deathmatch
Mirrored on github - https://github.com/solidi/hl-mods/tree/master/hla
@@ -85,9 +76,6 @@ 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: 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
@@ -109,9 +97,6 @@ Official github repository - https://github.com/Fograin/hl-subsmod-ex
## Half-Life: Rally
Official gitlab repository - https://gitlab.com/hlrally/src
## Half-Life: RXT
Available on ModDB - https://www.moddb.com/mods/half-life-rxt/downloads/rxt-source-code-v57
## Half-Life: Weapon Edition
Available on ModDB - https://www.moddb.com/mods/half-life-weapon-edition/downloads/half-life-weapon-edition-1508-alpha-open-src
@@ -133,17 +118,12 @@ Official github repository - https://github.com/HeathGames/half_rats_parasomnia_
## Half-Screwed
Official github repository - https://github.com/desukuran/half-screwed
## Halo: GoldSource
Available on ModDB - https://www.moddb.com/mods/halo-goldsrc/downloads/halo-gold-source-summer-2025-release-v10-sdk
## Headcrab Frenzy
Version 1.3 on ModDB - https://www.moddb.com/mods/headcrab-frenzy/downloads/headcrab-frenzy-13-beta-source-code
## Heart of Evil
Mirrored on github - https://github.com/nekonomicon/HeartOfEvil
Mirrored on github (Includes maps and models source files) - https://github.com/malortie/heart-of-evil-source-files
## Ingram Chillin' Mod
Official SourceForge repository - https://sourceforge.net/projects/icm-hl/
@@ -175,9 +155,6 @@ Prealpha, mirrored on github - https://github.com/a1batross/Paranoia2_ancient
Version 1.51, mirrored on github - https://github.com/a1batross/Paranoia2_original
## Public Enemy
Official github repository - https://github.com/IronOak-Studios/Public-Enemy
## Raven City
*Unfinished mod*
@@ -209,9 +186,6 @@ Mirrored on code.idtech.space - https://code.idtech.space/vera/halflife-wastelan
## Wizard Wars
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
## XashXT
Mirrored on github - https://github.com/a1batross/XashXT_original
@@ -277,9 +251,6 @@ Reverse-engineered code of server part by s1lentq - https://github.com/s1lentq/R
## Counter Strike Online
CSO-like Xash3D-based mod, CSMoE - https://github.com/MoeMod/CSMoE
## Crack-Life
Reverse-engineered code: branch **cracklife** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/cracklife
## Crack-Life: Campaign Mode
Recreation by lostgamer aka nillerusr - https://github.com/LostGamerHL/crack_life
@@ -382,9 +353,6 @@ Deathmatch Quaked - https://www.moddb.com/games/deathmatch-classic/downloads/dmq
Branch **dmc** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/dmc
## Delta Particles
Branch **delta_particles** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/delta_particles
## Half-Life: Echoes
Branch **echoes** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/echoes

View File

@@ -22,7 +22,6 @@ Table is sorted by status and platform.
| PSVita | Supported | @fgsfdsfgs |
| Switch | Supported | @fgsfdsfgs |
| Windows | Supported | @a1batross, @SNMetamorph |
| iOS | Supported | @ksagameng2 |
| DOS4GW | Orphaned | N/A | Haven't been confirmed to work for a very long time
| Haiku | Orphaned | N/A | Was added by #478 and #483
| IRIX | Orphaned | N/A | Undone, compiles but requires big endian port
@@ -36,3 +35,4 @@ Table is sorted by status and platform.
| Emscripten | Old Engine | N/A |
| 3DS | Old Engine fork | N/A | [GitHub Repository](https://github.com/masterfeizz/Xash3DS)
| Oculus Quest | Old Engine fork | N/A | [GitHub Repository](https://github.com/DrBeef/Lambda1VR)
| iOS | Deprecated | N/A | See GitHub issue #61

View File

@@ -1,11 +0,0 @@
# Xash3D FWGS protocol support
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.

View File

@@ -1,305 +0,0 @@
# Xash3D 49 connectionless protocol
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_NETINFO`](#a2a_netinfo)
- [`A2A_INFO`](#a2a_info)
- [`A2A_PING` and `A2A_GOLDSRC_PING`](#a2a_ping-and-a2a_goldsrc_ping)
- [`A2A_ACK` and `A2A_GOLDSRC_ACK`](#a2a_ack-and-a2a_goldsrc_ack)
- [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)
- [`A2S_GOLDSRC_INFO`, `A2S_GOLDSRC_RULES` and `A2S_GOLDSRC_PLAYERS` and their responses](#a2s_goldsrc_info-a2s_goldsrc_rules-and-a2s_goldsrc_players-and-their-responses)
- [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_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
#### `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
### 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
#### `A2S_GOLDSRC_INFO`, `A2S_GOLDSRC_RULES` and `A2S_GOLDSRC_PLAYERS` and their responses
These match Source Engine Query messages used in GoldSrc and Source engine and implemented for compatibility with existing tools. Read documentation for them on VDC: https://developer.valvesoftware.com/wiki/Server_queries
### 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_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.
* Request: `s<master challenge><heartbeat challenge>`
- `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.

View File

@@ -1,3 +0,0 @@
# Xash3D 49 netchan protocol
TBD...

View File

@@ -962,57 +962,53 @@ 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)**
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)**
15. **[Crack-Life: Campaign Mode](https://www.moddb.com/mods/crack-life)**
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/)**
16. **[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)**
17. **[Delta Particles](https://www.moddb.com/mods/half-life-delta)**
This mod already supports x86 Linux.
Support for other platforms may be available later.
19. **[Escape from the Darkness](https://www.moddb.com/mods/escape-from-the-darkness)**
18. **[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)**
19. **[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/)**
20. **[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)**
21. **[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)**
22. **[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)**
23. **[Half-Life: Field Intensity](https://www.moddb.com/mods/field-intensity)**
This mod already supports x86 Linux.
Support for other platforms may be available later.
25. **Half-Life: Gravgun** (unfinished) by *mittorn*, *a1batross* and *Solexid*
24. **Half-Life: Gravgun** (unfinished) by *mittorn*, *a1batross* and *Solexid*
*Support temporary abandoned*
@@ -1022,163 +1018,163 @@ 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)**
25. **[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)**
26. **[Half-Life: Invasion](https://www.moddb.com/mods/half-life-invasion)**
This mod supports x86 Linux.
Support for other platforms may be available later.
28. **[Half-Life: Intense Force](https://www.moddb.com/downloads/intense-force)**
27. **[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/)**
28. **[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/)**
29. **[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)**
30. **[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)**
31. **[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)**
32. **[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)**
33. **[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)**
34. **[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)**
35. **[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)**
36. **[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)**
37. **[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)**
38. **[Paranoia](https://www.moddb.com/mods/paranoia)**
*Support temporary abandoned*
[Source code](https://github.com/FWGS/paranoia_toolkit).
40. **[Poke646](https://poke646.com/)**
39. **[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/)**
40. **[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/)
41. [PrimeXT](https://snmetamorph.github.io/PrimeXT/)
[Source code](https://github.com/SNMetamorph/PrimeXT)
43. **[Quake Remake](https://www.moddb.com/games/quake-remake)**
42. **[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)**
43. **[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)**
44. **[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)**
45. **[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/)**
46. **[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)
47. [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)
48. [Spirit of Half-Life 1.2](https://www.moddb.com/mods/spirit-of-half-life)
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)**
49. **[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/)**
50. **[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)**
51. **[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)**
52. **[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)**
53. **[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)**
54. **[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/)
55. [XashXT](https://csm.dev/threads/xashxt-0-65-rev-4-release-stable.38319/)
*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)**
56. **[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)**
57. **[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)
58. [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

@@ -1,6 +1,6 @@
# Xash3D FWGS Engine <img align="right" width="128" height="128" src="https://github.com/FWGS/xash3d-fwgs/raw/master/game_launch/icon-xash-material.png" alt="Xash3D FWGS icon" />
[![GitHub Actions Status](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml/badge.svg)](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml) [![FreeBSD Build Status](https://img.shields.io/cirrus/github/FWGS/xash3d-fwgs?label=freebsd%20build)](https://cirrus-ci.com/github/FWGS/xash3d-fwgs) \
[![Discord Server](https://img.shields.io/discord/355697768582610945?logo=Discord&label=International%20Discord%20chat)](http://xash.su/discord/) [![Russian speakers Telegram Chat](https://img.shields.io/badge/Russian_speakers_Telegram_chat-gray?logo=Telegram)](https://t.me/flyingwithgauss) \
[![Discord Server](https://img.shields.io/discord/355697768582610945?logo=Discord&label=International%20Discord%20chat)](http://fwgsdiscord.mentality.rip/) [![Russian speakers Telegram Chat](https://img.shields.io/badge/Russian_speakers_Telegram_chat-gray?logo=Telegram)](https://t.me/flyingwithgauss) \
[![Download Daily Build](https://img.shields.io/badge/downloads-testing-orange)](https://github.com/FWGS/xash3d-fwgs/releases/tag/continuous)
Xash3D ([pronounced](https://ipa-reader.com/?text=ks%C9%91%CA%82) `[ksɑʂ]`) FWGS is a game engine, aimed to provide compatibility with Half-Life Engine and extend it, as well as to give game developers well known workflow.
@@ -41,12 +41,10 @@ For additional info, run Xash3D with `-help` command line key.
1) Copy `valve` directory to a folder named `xash` in the Internal storage.
2) Run games from within the app.
## Reporting issues
## 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.
* Issues are accepted in both English and Russian.
* They are only accepted if you run legally acquired product (e.g. Half-Life in Steam).
## Contributing code
* Check the CONTRIBUTING.md file.
* Before sending a PR, check if you followed our contribution guide in 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/).
@@ -83,11 +81,11 @@ This repository contains our fork of HLSDK and restored source code for Half-Lif
##### RedHat/Fedora
* Only for 32-bit engine on 64-bit x86 operating system:
* Install development tools: `$ sudo dnf install git gcc gcc-c++ glibc-devel.i686 SDL3-devel.i686 sdl2-compat-devel.i686 opus-devel.i686 freetype-devel.i686 bzip2-devel.i686 libvorbis-devel.i686 opusfile-devel.i686 libogg-devel.i686`.
* Install development tools: `$ sudo dnf install git gcc gcc-c++ glibc-devel.i686 SDL2-devel.i686 opus-devel.i686 freetype-devel.i686 bzip2-devel.i686 libvorbis-devel.i686 opusfile-devel.i686 libogg-devel.i686`.
* Set PKG_CONFIG_PATH environment variable to point at 32-bit libraries: `$ export PKG_CONFIG_PATH=/usr/lib/pkgconfig`.
* For 64-bit engine on 64-bit x86 and other non-x86 systems:
* Install development tools: `$ sudo dnf install git gcc gcc-c++ SDL3-devel sdl2-compat-devel opus-devel freetype-devel bzip2-devel libvorbis-devel opusfile-devel libogg-devel`.
* Install development tools: `$ sudo dnf install git gcc gcc-c++ SDL2-devel opus-devel freetype-devel bzip2-devel libvorbis-devel opusfile-devel libogg-devel`.
* Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`.
@@ -100,16 +98,6 @@ This repository contains our fork of HLSDK and restored source code for Half-Lif
* Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`.
#### iOS/iPadOS
* Install Xcode from the appstore.
* Install [Homebrew package manager](https://brew.sh).
* 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.
@@ -128,17 +116,4 @@ If compiling 32-bit on amd64, make sure `PKG_CONFIG_PATH` from the previous step
3) Install: `./waf install --destdir=/path/to/any/output/directory`.
#### Android (Windows/Linux/macOS)
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.
You can just open the `android` folder in Android Studio and build from here, or use `gradlew` to build from command line.

View File

@@ -1,18 +0,0 @@
# Xash3D FWGS Security Policy
## Supported versions
Because we don't have clear release cycle yet, support is only provided to the
latest engine versions from `master` branch. You can use `host_ver` command in
console to fetch detailed info about the engine build.
## Reporting a Vulnerability
If you discover a security vulnerability in this project, it can be reported
privately though `Security` tab on GitHub:
https://github.com/FWGS/xash3d-fwgs/security
Alternatively, you can report them publicly on the `Issues` tab:
https://github.com/FWGS/xash3d-fwgs/issues
In both cases, expect a reply within approximately a week.

View File

@@ -1,4 +1,3 @@
import com.android.build.api.dsl.ApplicationExtension
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import java.time.LocalDateTime
import java.time.Month
@@ -6,11 +5,12 @@ import java.time.temporal.ChronoUnit
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
}
extensions.configure<ApplicationExtension> {
android {
namespace = "su.xash.engine"
ndkVersion = "29.0.14206865"
ndkVersion = "28.2.13676358"
compileSdk = 35
defaultConfig {
@@ -23,7 +23,7 @@ extensions.configure<ApplicationExtension> {
externalNativeBuild {
val engineRoot = projectDir.parentFile.parent
experimentalProperties["ninja.abiFilters"] = setOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
experimentalProperties["ninja.abiFilters"] = setOf("armeabi-v7a", "arm64-v8a")
experimentalProperties["ninja.path"] = File(engineRoot, "wscript").path
experimentalProperties["ninja.configure"] = "run-python"
experimentalProperties["ninja.arguments"] = setOf(
@@ -34,7 +34,7 @@ extensions.configure<ApplicationExtension> {
"--configuration-dir=\${ndk.buildRoot}",
"--ndk-version=\${ndk.moduleNdkVersion}",
"--min-sdk-version=\${ndk.minPlatform}",
"--ndk-root=${androidComponents.sdkComponents.ndkDirectory.get()}",
"--ndk-root=${android.ndkDirectory}",
// shut up, fake options
"-p:Configuration=\${ndk.variantName}",
"-p:Platform=\${ndk.abi}"
@@ -62,23 +62,20 @@ extensions.configure<ApplicationExtension> {
abortOnError = false
}
/*
androidResources {
noCompress += ""
}
*/
packaging {
jniLibs {
keepDebugSymbols.add("**/*.so")
useLegacyPackaging = true
}
}
sourceSets {
getByName("main") {
assets.directories.add("../../3rdparty/extras/xash-extras")
java.directories.add("../../3rdparty/SDL/android-project/app/src/main/java")
assets.srcDirs("../../3rdparty/extras/xash-extras")
java.srcDir("../../3rdparty/SDL/android-project/app/src/main/java")
}
}

View File

@@ -29,10 +29,10 @@
<!-- Allow downloading to the external storage on Android 5.1 and older -->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
android:maxSdkVersion="22" />
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<!-- Allow access to Bluetooth devices -->
<!-- Currently this is just for Steam Controller support and requires setting SDL_HINT_JOYSTICK_HIDAPI_STEAM -->
@@ -57,9 +57,7 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher"
android:theme="@style/Theme.App"
android:networkSecurityConfig="@xml/network_security_config"
android:usesCleartextTraffic="true"
android:requestLegacyExternalStorage="true">
android:usesCleartextTraffic="true">
<activity
android:name=".MainActivity"
android:exported="true">
@@ -69,15 +67,6 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
<activity
android:name=".XashActivity"
android:alwaysRetainTaskState="true"
@@ -91,9 +80,4 @@
</intent-filter>
</activity>
</application>
<queries>
<intent>
<action android:name="su.xash.engine.MOD" />
</intent>
</queries>
</manifest>

View File

@@ -1,7 +1,6 @@
package su.xash.engine
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
@@ -9,11 +8,6 @@ import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import su.xash.engine.databinding.ActivityMainBinding
import su.xash.engine.util.CrashReports
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
@@ -33,36 +27,9 @@ class MainActivity : AppCompatActivity() {
navController = navHostFragment.navController
appBarConfiguration = AppBarConfiguration(navController.graph)
setupActionBarWithNavController(navController, appBarConfiguration)
CrashReports.prune(this)
showPendingCrashReport()
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
private fun showPendingCrashReport() {
val pending = CrashReports.pendingFile(this)
if (!pending.exists() || pending.length() == 0L)
return
val historyDir = CrashReports.historyDir(this).apply { mkdirs() }
val ts = SimpleDateFormat("yyyyMMdd-HHmmss", Locale.US).format(Date())
val archived = File(historyDir, "crash-$ts.log")
if (!pending.renameTo(archived)) {
// fall back to in-place read if move failed; still consume the file
archived.writeText(pending.readText())
pending.delete()
}
val content = archived.readText()
AlertDialog.Builder(this)
.setTitle(R.string.crash_dialog_title)
.setView(CrashReports.buildContentView(this, content))
.setPositiveButton(R.string.crash_send_to_developers) { _, _ -> CrashReports.sendByEmail(this, content) }
.setNeutralButton(R.string.crash_share) { _, _ -> CrashReports.share(this, archived) }
.setNegativeButton(R.string.crash_dismiss, null)
.show()
}
}

View File

@@ -15,10 +15,6 @@ import org.libsdl.app.SDLActivity;
import su.xash.engine.util.AndroidBug5497Workaround;
import java.io.File;
import java.util.Arrays;
import java.util.List;
public class XashActivity extends SDLActivity {
private boolean mUseVolumeKeys;
private String mPackageName;
@@ -124,10 +120,6 @@ public class XashActivity extends SDLActivity {
// TODO: REMOVE LATER, temporary launchers support?
@Override
protected String[] getArguments() {
File crashDir = new File(getFilesDir(), "crashes");
crashDir.mkdirs();
nativeSetenv("XASH3D_CRASH_DIR", crashDir.getAbsolutePath());
String gamedir = getIntent().getStringExtra("gamedir");
if (gamedir == null) gamedir = "valve";
nativeSetenv("XASH3D_GAME", gamedir);
@@ -135,14 +127,6 @@ public class XashActivity extends SDLActivity {
String gamelibdir = getIntent().getStringExtra("gamelibdir");
if (gamelibdir != null) nativeSetenv("XASH3D_GAMELIBDIR", gamelibdir);
String rodir = System.getenv("XASH3D_RODIR");
if (rodir == null) {
// FIXME: we are using rodir as a supplier for downloaded game libraries
rodir = getFilesDir().getAbsolutePath() + "/gamelibs";
nativeSetenv("XASH3D_RODIR", rodir);
}
Log.i(TAG, "XASH3D_RODIR = " + rodir);
String pakfile = getIntent().getStringExtra("pakfile");
if (pakfile != null) nativeSetenv("XASH3D_EXTRAS_PAK2", pakfile);
@@ -165,7 +149,6 @@ public class XashActivity extends SDLActivity {
String argv = getIntent().getStringExtra("argv");
if (argv == null) argv = "-console -log";
return argv.split(" ");
}
}

View File

@@ -6,41 +6,28 @@ import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.view.LayoutInflater
import android.widget.TextView
import androidx.core.net.toUri
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.progressindicator.LinearProgressIndicator
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import su.xash.engine.R
import android.net.Uri
import su.xash.engine.XashActivity
import java.io.File
import java.io.FileInputStream
class Game(val ctx: Context, val basedir: File, val gameInfoFile: File) {
class Game(val ctx: Context, val basedir: File) {
private var iconName = "game.ico"
var title = "Unknown Game"
var icon: Bitmap? = null
var cover: Bitmap? = null
val mobileHacksGames = arrayOf("aom", "bdlands", "biglolly", "bshift", "caseclosed",
"hl_urbicide", "induction", "redempt", "secret",
"sewer_beta", "tot", "valve", "vendetta")
// a1ba: follow the behavior of Xash3D's game_launch.
// for hl mods we put `valve` as game directory
// for any other game that's not hl this string must be replaced with your
// main game directory
// mods always use -game command line parameter
var defaultGameDir = "valve"
private val pref = ctx.getSharedPreferences(basedir.name, Context.MODE_PRIVATE)
init {
parseGameInfo(gameInfoFile)
val gameInfo = File(basedir, "gameinfo.txt")
if (gameInfo.exists()) {
parseGameInfo(gameInfo)
} else {
val libListGam = File(basedir, "liblist.gam")
if (libListGam.exists()) parseGameInfo(libListGam)
}
val iconFile = File(basedir, iconName)
if (iconFile.exists()) {
@@ -55,155 +42,14 @@ class Game(val ctx: Context, val basedir: File, val gameInfoFile: File) {
}
fun startEngine(ctx: Context) {
val packageNames = getPackageNamesForGameDir(basedir.name)
var externalGame = false
var commandLineArgs = ""
if (basedir.name != defaultGameDir)
commandLineArgs += "-game ${basedir.name} "
if (packageNames != null) {
if (packageNames.contains("su.xash.engine")) {
commandLineArgs += "-dll @hl "
} else if (packageNames.contains("su.xash.cs16client")) {
if (pref.getBoolean("enable_yapb_bots", true)) {
commandLineArgs += "-dll @yapb "
}
externalGame = true
}
}
commandLineArgs += pref.getString("arguments", "-console -log") ?: ""
if (externalGame && packageNames != null) {
var packageName: String? = null
var gameLibDir: String? = null
for (pn in packageNames) {
gameLibDir = try {
getGameLibDir(ctx, pn)
} catch (e: PackageManager.NameNotFoundException) {
null
} catch (e: Exception) {
e.printStackTrace()
null
}
if (gameLibDir != null) {
packageName = pn
break
}
}
if (gameLibDir == null) {
MaterialAlertDialogBuilder(ctx).apply {
setTitle(R.string.game_apk_required)
setMessage(R.string.game_apk_message)
setPositiveButton(R.string.game_apk_install) { _, _ ->
val intent = Intent(Intent.ACTION_VIEW,
getDownloadPageForGameDir(basedir.name).toUri())
ctx.startActivity(intent)
}
show()
}
return
}
launchEngine(ctx, commandLineArgs, packageName = packageName, gameLibDir = gameLibDir)
return
}
if (packageNames == null) {
// Unknown game — try to use downloaded libraries from hlsdk-mega-build
val downloader = GameLibDownloader(ctx)
val args = commandLineArgs
if (downloader.isDownloaded(basedir.name)) {
downloader.logExistingLibs(basedir.name)
launchEngine(ctx, args)
return
}
val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
scope.launch {
when (val r = downloader.lookupBuild(basedir.name)) {
is GameLibDownloader.Lookup.Available -> showDownloadDialog(ctx, downloader, args)
is GameLibDownloader.Lookup.NotInManifest -> launchEngine(ctx, args)
is GameLibDownloader.Lookup.Error -> showManifestErrorDialog(ctx, args, r.cause)
}
}
return
}
launchEngine(ctx, commandLineArgs)
}
private fun showDownloadDialog(ctx: Context, downloader: GameLibDownloader, commandLineArgs: String) {
val view = LayoutInflater.from(ctx).inflate(R.layout.dialog_download_progress, null)
val progressBar = view.findViewById<LinearProgressIndicator>(R.id.downloadProgress)
val statusText = view.findViewById<TextView>(R.id.downloadStatus)
val dialog = MaterialAlertDialogBuilder(ctx)
.setTitle(R.string.downloading_game_libs)
.setView(view)
.setCancelable(true)
.setNegativeButton(android.R.string.cancel) { d, _ -> d.dismiss() }
.create()
dialog.show()
val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
val job = scope.launch {
val result = downloader.download(basedir.name) { progress ->
progressBar.isIndeterminate = false
progressBar.progress = (progress * 100).toInt()
statusText.text = ctx.getString(R.string.download_progress, (progress * 100).toInt())
}
if (!dialog.isShowing) return@launch
dialog.dismiss()
if (result.isSuccess) {
launchEngine(ctx, commandLineArgs)
} else {
MaterialAlertDialogBuilder(ctx)
.setTitle(R.string.download_failed)
.setMessage(result.exceptionOrNull()?.message
?: ctx.getString(R.string.download_error))
.setPositiveButton(android.R.string.ok, null)
.show()
}
}
dialog.setOnDismissListener { job.cancel() }
}
private fun showManifestErrorDialog(ctx: Context, commandLineArgs: String, cause: Throwable) {
MaterialAlertDialogBuilder(ctx)
.setTitle(R.string.manifest_error_title)
.setMessage(ctx.getString(R.string.manifest_error_message, cause.message ?: cause.javaClass.simpleName))
.setPositiveButton(R.string.launch_anyway) { _, _ -> launchEngine(ctx, commandLineArgs) }
.setNegativeButton(android.R.string.cancel, null)
.show()
}
private fun launchEngine(
ctx: Context,
commandLineArgs: String,
packageName: String? = null,
gameLibDir: String? = null
) {
ctx.startActivity(Intent(ctx, XashActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
putExtra("gamedir", defaultGameDir)
putExtra("argv", commandLineArgs)
putExtra("gamedir", basedir.name)
putExtra("argv", pref.getString("arguments", "-console -log"))
putExtra("usevolume", pref.getBoolean("use_volume_buttons", false))
putExtra("basedir", basedir.parent)
if (gameLibDir != null) putExtra("gamelibdir", gameLibDir)
if (packageName != null) putExtra("package", packageName)
//.putExtra("gamelibdir", getGameLibDir(context))
//.putExtra("package", getPackageName()) }
})
}
@@ -224,47 +70,44 @@ class Game(val ctx: Context, val basedir: File, val gameInfoFile: File) {
}
}
private fun getPackageNamesForGameDir(gamedir: String): Array<String>? {
if (gamedir.equals("cstrike", ignoreCase = true)
|| gamedir.equals("czero", ignoreCase = true))
return arrayOf("su.xash.cs16client.test", "su.xash.cs16client")
if (gamedir.equals("tfc", ignoreCase = true))
return arrayOf("su.xash.tf15client.test", "su.xash.tf15client")
// mobile_hacks hlsdk-portable branch allows us to have few more mods out of the box
if (mobileHacksGames.any { it.equals(gamedir, ignoreCase = true) })
return arrayOf("su.xash.engine")
private fun getPackageName(): String? {
// return if (mDbEntry != null) {
// mDbEntry.getPackageName()
// } else null
return null
}
private fun getDownloadPageForGameDir(gamedir: String): String {
if (gamedir.equals("cstrike", ignoreCase = true)
|| gamedir.equals("czero", ignoreCase = true))
return "https://github.com/Velaron/cs16-client/releases/download/continuous/CS16Client-Android.apk"
if (gamedir.equals("tfc", ignoreCase = true))
return "https://github.com/Velaron/tf15-client/releases/download/continuous/TF15Client-Android.apk"
// just so we don't return null
return "https://github.com/FWGS/xash3d-fwgs/releases/download/continuous/xash3d-fwgs-android.apk"
}
private fun getGameLibDir(ctx: Context, packageName: String): String? {
val packageInfo: PackageInfo = ctx.packageManager.getPackageInfo(packageName, 0)
return packageInfo.applicationInfo?.nativeLibraryDir
private fun getGameLibDir(ctx: Context): String? {
val pkgName = getPackageName()
if (pkgName != null) {
val pkgInfo: PackageInfo = try {
ctx.packageManager.getPackageInfo(pkgName, 0)
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
ctx.startActivity(
Intent(
Intent.ACTION_VIEW, Uri.parse("market://details?id=$pkgName")
).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
)
return null
}
return pkgInfo.applicationInfo?.nativeLibraryDir
}
return ctx.applicationInfo.nativeLibraryDir
}
companion object {
fun getGames(ctx: Context, root: File): List<Game> {
fun getGames(ctx: Context, file: File): List<Game> {
val games = mutableListOf<Game>()
root.listFiles()?.forEach {
if (it.isDirectory) {
val subDirGameInfoFile = checkIfGamedir(it)
if (subDirGameInfoFile != null) {
games.add(Game(ctx, it, subDirGameInfoFile))
if (checkIfGamedir(file)) {
games.add(Game(ctx, file))
} else {
file.listFiles()?.forEach {
if (it.isDirectory) {
if (checkIfGamedir(it)) {
games.add(Game(ctx, it))
}
}
}
}
@@ -272,18 +115,24 @@ class Game(val ctx: Context, val basedir: File, val gameInfoFile: File) {
return games
}
fun checkIfGamedir(gamedir: File): File? {
gamedir.listFiles()?.forEach {
if (it.isFile) {
if (it.name.equals("liblist.gam", ignoreCase = true))
return it
fun checkIfGamedir(file: File): Boolean {
if (File(file, "liblist.gam").exists()) return true
if (File(file, "gameinfo.txt").exists()) return true
if (it.name.equals("gameinfo.txt", ignoreCase = true))
return it
}
}
return null
return false
}
}
}
// Intent intent = new Intent("su.xash.engine.MOD");
// for (ResolveInfo info : context.getPackageManager()
// .queryIntentActivities(intent, PackageManager.GET_META_DATA)) {
// String packageName = info.activityInfo.applicationInfo.packageName;
// String gameDir = info.activityInfo.applicationInfo.metaData.getString(
// "su.xash.engine.gamedir");
// Log.d(TAG, "package = " + packageName + " gamedir = " + gameDir);
// }
//public void startEngine(Context context) {
// context.startActivity(new Intent(context, XashActivity.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP).putExtra("gamedir", getGameDir()).putExtra("argv", getArguments()).putExtra("usevolume", getVolumeState()).putExtra("gamelibdir", getGameLibDir(context)).putExtra("package", getPackageName()));
//}

View File

@@ -1,373 +0,0 @@
package su.xash.engine.model
import android.content.Context
import android.os.Build
import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.withContext
import org.json.JSONObject
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.net.HttpURLConnection
import java.net.URL
import java.security.MessageDigest
import java.util.zip.ZipInputStream
import kotlin.coroutines.coroutineContext
class GameLibDownloader(private val context: Context) {
private val prefs get() = context.getSharedPreferences("gamelib_metadata", Context.MODE_PRIVATE)
// converts Android's ABI to library-suffix's arch names
fun getArch(): String? {
for (abi in Build.SUPPORTED_ABIS) {
when (abi) {
"arm64-v8a" -> return "arm64"
"armeabi-v7a" -> return "armv7l"
"x86_64" -> return "amd64"
"x86" -> return "i386"
}
}
return null
}
fun getLibsBaseDir(): File = File(context.filesDir, "gamelibs")
fun isDownloaded(gamedir: String): Boolean {
val dir = File(getLibsBaseDir(), gamedir)
if (dir.isDirectory && dir.list()?.isNotEmpty() == true)
return true
// zips extract to the case used in the manifest (e.g. "CAd"); the user's
// folder name might differ in case, so do a case-insensitive lookup too.
val base = getLibsBaseDir()
val match = base.listFiles()?.firstOrNull {
it.isDirectory && it.name.equals(gamedir, ignoreCase = true)
}
return match != null && (match.list()?.isNotEmpty() == true)
}
data class ManifestEntry(
val modKey: String,
val platformArch: String,
val filename: String,
val sha256: String,
val sourceJson: String?
)
data class SourceInfo(
val url: String?,
val branch: String?,
val commit: String?
)
private fun manifestCacheFile(): File = File(context.cacheDir, "hlsdk-manifest.json")
private suspend fun fetchManifest(): JSONObject? = fetchManifestOrError().first
private suspend fun fetchManifestOrError(): Pair<JSONObject?, Throwable?> {
val cacheFile = manifestCacheFile()
var connection: HttpURLConnection? = null
try {
connection = URL(MANIFEST_URL).openConnection() as HttpURLConnection
connection.connectTimeout = 10000
connection.readTimeout = 15000
connection.instanceFollowRedirects = true
connection.connect()
if (connection.responseCode != HttpURLConnection.HTTP_OK) {
val err = IOException("HTTP ${connection.responseCode} fetching manifest")
Log.w(TAG, "Manifest fetch failed: ${err.message}")
val cached = readCachedManifest(cacheFile)
return if (cached != null) cached to null else null to err
}
val text = connection.inputStream.bufferedReader().use { it.readText() }
val json = JSONObject(text)
val versionError = checkManifestVersion(json)
if (versionError != null) {
Log.w(TAG, "Manifest rejected: ${versionError.message}")
return null to versionError
}
cacheFile.writeText(text)
return json to null
} catch (e: Exception) {
Log.w(TAG, "Manifest fetch failed: ${e.message}")
val cached = readCachedManifest(cacheFile)
return if (cached != null) cached to null else null to e
} finally {
connection?.disconnect()
}
}
private fun readCachedManifest(cacheFile: File): JSONObject? {
if (!cacheFile.exists())
return null
val json = try {
JSONObject(cacheFile.readText())
} catch (_: Exception) {
return null
}
return if (checkManifestVersion(json) == null) json else null
}
private fun checkManifestVersion(json: JSONObject): IOException? {
if (!json.has("version"))
return IOException("Manifest missing 'version' field")
val v = json.opt("version")
if (v !is Int || v != MANIFEST_VERSION)
return IOException("Unsupported manifest version: $v (expected $MANIFEST_VERSION)")
return null
}
private fun lookupEntry(manifest: JSONObject, gamedir: String): ManifestEntry? {
val arch = getArch() ?: return null
val platformArch = "android-$arch"
val mods = manifest.optJSONObject("mods") ?: return null
// Find mod key case-insensitively
var modKey: String? = null
val keys = mods.keys()
while (keys.hasNext()) {
val k = keys.next()
if (k.equals(gamedir, ignoreCase = true)) {
modKey = k
break
}
}
if (modKey == null)
return null
val builds = mods.optJSONObject(modKey)?.optJSONObject("builds") ?: return null
val build = builds.optJSONObject(platformArch) ?: return null
val filename = build.optString("filename", "")
val sha256 = build.optString("sha256", "")
if (filename.isEmpty() || sha256.isEmpty())
return null
val sourceJson = build.optJSONObject("source")?.toString()
return ManifestEntry(modKey, platformArch, filename, sha256.lowercase(), sourceJson)
}
fun getSourceInfo(gamedir: String): SourceInfo? {
val raw = prefs.getString("${gamedir}_source", null) ?: return null
return try {
val o = JSONObject(raw)
SourceInfo(
url = o.optString("url").ifEmpty { null },
branch = o.optString("branch").ifEmpty { null },
commit = o.optString("commit").ifEmpty { null },
)
} catch (_: Exception) {
null
}
}
fun getDownloadTime(gamedir: String): Long =
prefs.getLong("${gamedir}_download_time", 0L)
sealed class Lookup {
data class Available(val entry: ManifestEntry) : Lookup()
object NotInManifest : Lookup()
data class Error(val cause: Throwable) : Lookup()
}
suspend fun lookupBuild(gamedir: String): Lookup {
return withContext(Dispatchers.IO) {
val (manifest, error) = fetchManifestOrError()
if (manifest == null)
return@withContext Lookup.Error(error ?: IOException("Failed to fetch manifest"))
val entry = lookupEntry(manifest, gamedir)
?: return@withContext Lookup.NotInManifest
Lookup.Available(entry)
}
}
suspend fun isUpdateAvailable(gamedir: String): Boolean {
return withContext(Dispatchers.IO) {
val manifest = fetchManifest() ?: return@withContext false
val entry = lookupEntry(manifest, gamedir) ?: return@withContext false
val storedSha = prefs.getString("${gamedir}_sha256", null)
storedSha == null || !storedSha.equals(entry.sha256, ignoreCase = true)
}
}
private fun urlForFilename(filename: String): String = "$RELEASE_BASE_URL/$filename"
private suspend fun tryDownload(
url: String,
dest: File,
onProgress: (Float) -> Unit
): Exception? {
var connection: HttpURLConnection? = null
try {
connection = URL(url).openConnection() as HttpURLConnection
connection.connectTimeout = 10000
connection.readTimeout = 30000
connection.instanceFollowRedirects = true
connection.connect()
val code = connection.responseCode
if (code !in 200..299)
return IOException("HTTP $code: $url")
val total = connection.contentLengthLong
var downloaded = 0L
connection.inputStream.use { input ->
FileOutputStream(dest).use { output ->
val buffer = ByteArray(65536)
while (true) {
coroutineContext.ensureActive()
val read = input.read(buffer)
if (read < 0)
break
output.write(buffer, 0, read)
downloaded += read
if (total > 0) {
val progress = downloaded.toFloat() / total
withContext(Dispatchers.Main) { onProgress(progress) }
}
}
}
}
return null
} catch (e: Exception) {
return e
} finally {
connection?.disconnect()
}
}
suspend fun download(gamedir: String, onProgress: (Float) -> Unit): Result<Unit> {
return withContext(Dispatchers.IO) {
val manifest = fetchManifest()
?: return@withContext Result.failure(IOException("Failed to fetch manifest"))
val entry = lookupEntry(manifest, gamedir)
?: return@withContext Result.failure(IOException("No build for '$gamedir' on ${getArch() ?: "this arch"}"))
val url = urlForFilename(entry.filename)
val tempFile = File(context.cacheDir, entry.filename)
try {
coroutineContext.ensureActive()
Log.i(TAG, "Downloading $url -> ${tempFile.absolutePath}")
val error = tryDownload(url, tempFile, onProgress)
if (error != null)
return@withContext Result.failure(error)
val actualSha = computeSHA256(tempFile)
Log.i(TAG, "Downloaded ${tempFile.length()} bytes, SHA-256: $actualSha (expected ${entry.sha256})")
if (!actualSha.equals(entry.sha256, ignoreCase = true))
return@withContext Result.failure(IOException("SHA-256 mismatch: expected ${entry.sha256}, got $actualSha"))
val destDir = getLibsBaseDir()
destDir.mkdirs()
val destCanon = destDir.canonicalPath
// Remove any prior install (possibly under a differently-cased dir) so we
// don't leave behind .so files from an older build.
destDir.listFiles()?.forEach {
if (it.isDirectory && it.name.equals(entry.modKey, ignoreCase = true))
it.deleteRecursively()
}
Log.i(TAG, "Extracting to ${destDir.absolutePath}")
val extractedFiles = mutableListOf<String>()
ZipInputStream(tempFile.inputStream()).use { zip ->
var zipEntry = zip.nextEntry
while (zipEntry != null) {
coroutineContext.ensureActive()
if (!zipEntry.isDirectory) {
val outFile = File(destDir, zipEntry.name)
if (!outFile.canonicalPath.startsWith(destCanon + File.separator))
throw SecurityException("Zip path traversal: ${zipEntry.name}")
outFile.parentFile?.mkdirs()
FileOutputStream(outFile).use { zip.copyTo(it) }
// ZipInputStream doesn't restore Unix permissions; shared libraries
// need the execute bit so dlopen can mmap them with PROT_EXEC
if (outFile.name.endsWith(".so"))
outFile.setExecutable(true, false)
extractedFiles.add(" ${outFile.absolutePath} (${outFile.length()} bytes, executable: ${outFile.canExecute()})")
}
zip.closeEntry()
zipEntry = zip.nextEntry
}
}
Log.i(TAG, "Extracted ${extractedFiles.size} files:")
extractedFiles.forEach { Log.i(TAG, it) }
prefs.edit()
.putString("${gamedir}_sha256", entry.sha256)
.putString("${gamedir}_filename", entry.filename)
.putString("${gamedir}_source", entry.sourceJson)
.putLong("${gamedir}_download_time", System.currentTimeMillis())
.apply()
Result.success(Unit)
} catch (e: Exception) {
// Best-effort: rewinding to a clean state on failure
File(getLibsBaseDir(), entry.modKey).deleteRecursively()
Result.failure(e)
} finally {
tempFile.delete()
}
}
}
fun logExistingLibs(gamedir: String) {
val gameDir = File(getLibsBaseDir(), gamedir)
val resolved = if (gameDir.exists()) {
gameDir
} else {
getLibsBaseDir().listFiles()?.firstOrNull {
it.isDirectory && it.name.equals(gamedir, ignoreCase = true)
}
}
if (resolved == null) {
Log.i(TAG, "Game libs dir does not exist for $gamedir")
return
}
Log.i(TAG, "Existing game libs under ${resolved.absolutePath}:")
resolved.walkTopDown().filter { it.isFile }.forEach {
Log.i(TAG, " ${it.absolutePath} (${it.length()} bytes)")
}
val storedSha = prefs.getString("${gamedir}_sha256", null)
val downloadTime = prefs.getLong("${gamedir}_download_time", 0L)
Log.i(TAG, "Archive SHA-256: $storedSha")
if (downloadTime > 0L)
Log.i(TAG, "Downloaded at: ${java.util.Date(downloadTime)}")
}
private fun computeSHA256(file: File): String {
val digest = MessageDigest.getInstance("SHA-256")
file.inputStream().use { input ->
val buffer = ByteArray(65536)
while (true) {
val read = input.read(buffer)
if (read < 0)
break
digest.update(buffer, 0, read)
}
}
return digest.digest().joinToString("") { "%02x".format(it) }
}
companion object {
private const val TAG = "GameLibDownloader"
private const val RELEASE_BASE_URL =
"https://github.com/FWGS/hlsdk-mega-build/releases/download/continuous"
private const val MANIFEST_URL =
"$RELEASE_BASE_URL/manifest.json"
private const val MANIFEST_VERSION = 1
}
}

View File

@@ -1,8 +1,6 @@
package su.xash.engine.ui.library
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
@@ -15,8 +13,7 @@ import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.appcompat.app.AlertDialog
import androidx.core.view.MenuProvider
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
@@ -28,7 +25,6 @@ import su.xash.engine.R
import su.xash.engine.adapters.GameAdapter
import su.xash.engine.databinding.FragmentLibraryBinding
class LibraryFragment : Fragment(), MenuProvider {
private var _binding: FragmentLibraryBinding? = null
private val binding get() = _binding!!
@@ -42,85 +38,23 @@ class LibraryFragment : Fragment(), MenuProvider {
}
}
private val requiredPermissions = arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
val granted = permissions.entries.all { it.value }
if (granted) {
libraryViewModel.reloadGames(requireContext())
} else {
checkStoragePermissions()
}
}
private fun checkStoragePermissions(): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (!Environment.isExternalStorageManager()) {
MaterialAlertDialogBuilder(requireContext()).apply {
setTitle(R.string.file_access_required)
setMessage(R.string.file_access_message)
setPositiveButton(R.string.open_settings) { _, _ ->
startActivityForResult.launch(
Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).setData(
Uri.fromParts("package", BuildConfig.APPLICATION_ID, null)
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) {
MaterialAlertDialogBuilder(requireContext()).apply {
setTitle(R.string.file_access_required)
setMessage(R.string.file_access_message)
setPositiveButton(android.R.string.ok) { _, _ ->
startActivityForResult.launch(
Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).setData(
Uri.fromParts("package", BuildConfig.APPLICATION_ID, null)
)
}
setNeutralButton(R.string.done_check_permissions) { dialog, _ ->
checkStoragePermissions()
}
setCancelable(false)
show()
return false
)
}
} else {
return true
setCancelable(false)
show()
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val permissionsNeeded = requiredPermissions.filter {
ContextCompat.checkSelfPermission(
requireContext(),
it
) != PackageManager.PERMISSION_GRANTED
}.toTypedArray()
if (!permissionsNeeded.isEmpty()) {
val showRationale = permissionsNeeded.any {
ActivityCompat.shouldShowRequestPermissionRationale(requireActivity(), it)
}
MaterialAlertDialogBuilder(requireContext()).apply {
setTitle(R.string.external_storage_required)
setMessage(R.string.external_storage_message)
setPositiveButton(R.string.open_settings) { _, _ ->
if (showRationale) {
requestPermissionLauncher.launch(permissionsNeeded)
} else {
val intent =
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data =
Uri.fromParts("package", requireContext().packageName, null)
}
startActivity(intent)
}
}
setNeutralButton(R.string.done_check_permissions) { _, _ ->
checkStoragePermissions()
}
setCancelable(false)
show()
}
return false
} else {
return true
}
return false
} else {
return true
}
@@ -173,12 +107,4 @@ class LibraryFragment : Fragment(), MenuProvider {
return false
}
override fun onResume() {
super.onResume()
if (checkStoragePermissions()) {
libraryViewModel.reloadGames(requireContext())
}
}
}

View File

@@ -12,7 +12,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import su.xash.engine.model.Game
import su.xash.engine.util.Nomedia
import java.io.File
class LibraryViewModel(application: Application) : AndroidViewModel(application) {
@@ -40,8 +39,6 @@ class LibraryViewModel(application: Application) : AndroidViewModel(application)
?: (Environment.getExternalStorageDirectory().absolutePath + "/xash")
val root = File(rootPath)
Nomedia.ensureNomedia(root)
_installedGames.postValue(Game.getGames(ctx, root))
_isReloading.postValue(false)
}

View File

@@ -1,8 +1,6 @@
package su.xash.engine.ui.settings
import android.os.Bundle
import androidx.navigation.fragment.findNavController
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import su.xash.engine.R
@@ -10,10 +8,5 @@ class AppSettingsPreferenceFragment() : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.sharedPreferencesName = "app_preferences";
setPreferencesFromResource(R.xml.app_preferences, rootKey);
findPreference<Preference>("crash_logs")?.setOnPreferenceClickListener {
findNavController().navigate(R.id.action_appSettingsFragment_to_crashLogsFragment)
true
}
}
}

View File

@@ -1,66 +0,0 @@
package su.xash.engine.ui.settings
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import su.xash.engine.R
import su.xash.engine.util.CrashReports
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
class CrashLogsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceScreen = preferenceManager.createPreferenceScreen(requireContext())
populate()
}
override fun onResume() {
super.onResume()
populate()
}
private fun populate() {
val ctx = requireContext()
preferenceScreen.removeAll()
val files = CrashReports.historyDir(ctx).listFiles()?.sortedByDescending { it.lastModified() } ?: emptyList()
if (files.isEmpty()) {
preferenceScreen.addPreference(Preference(ctx).apply {
setTitle(R.string.crash_logs_empty)
isSelectable = false
})
return
}
val fmt = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US)
files.forEach { file ->
preferenceScreen.addPreference(Preference(ctx).apply {
title = fmt.format(Date(file.lastModified()))
summary = file.name
setOnPreferenceClickListener {
showCrashLog(file)
true
}
})
}
}
private fun showCrashLog(file: File) {
val ctx = requireContext()
val content = file.readText()
AlertDialog.Builder(ctx)
.setTitle(file.name)
.setView(CrashReports.buildContentView(ctx, content))
.setPositiveButton(R.string.crash_send_to_developers) { _, _ -> CrashReports.sendByEmail(ctx, content) }
.setNeutralButton(R.string.crash_share) { _, _ -> CrashReports.share(ctx, file) }
.setNegativeButton(R.string.crash_log_delete) { _, _ ->
file.delete()
populate()
}
.show()
}
}

View File

@@ -1,17 +1,11 @@
package su.xash.engine.ui.settings
import android.content.Intent
import android.os.Bundle
import androidx.core.net.toUri
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreferenceCompat
import su.xash.engine.R
import su.xash.engine.model.Game
import su.xash.engine.model.GameLibDownloader
import java.text.DateFormat
import java.util.Date
class GameSettingsPreferenceFragment(val game: Game) : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
@@ -26,14 +20,6 @@ class GameSettingsPreferenceFragment(val game: Game) : PreferenceFragmentCompat(
packageList.setValueIndex(0);
}
if (game.basedir.name.equals("cstrike", ignoreCase = true)
|| game.basedir.name.equals("czero", ignoreCase = true)) {
val enableYaPBBots = findPreference<SwitchPreferenceCompat>("enable_yapb_bots")!!
enableYaPBBots.isVisible = true
}
populateDownloadedBuildInfo()
val separatePackages = findPreference<SwitchPreferenceCompat>("separate_libraries")!!
val clientPackage = findPreference<ListPreference>("client_package")!!
val serverPackage = findPreference<ListPreference>("server_package")!!
@@ -51,43 +37,4 @@ class GameSettingsPreferenceFragment(val game: Game) : PreferenceFragmentCompat(
true
}
}
private fun populateDownloadedBuildInfo() {
val downloader = GameLibDownloader(requireContext())
val source = downloader.getSourceInfo(game.basedir.name) ?: return
val downloadedAt = downloader.getDownloadTime(game.basedir.name)
val urlPref = findPreference<Preference>("source_url")!!
urlPref.isVisible = true
urlPref.summary = source.url ?: ""
urlPref.isEnabled = source.url != null
urlPref.setOnPreferenceClickListener {
source.url?.let {
startActivity(Intent(Intent.ACTION_VIEW, it.toUri()))
}
true
}
val branchPref = findPreference<Preference>("source_branch")!!
branchPref.isVisible = true
branchPref.summary = source.branch ?: ""
val commitPref = findPreference<Preference>("source_commit")!!
commitPref.isVisible = true
commitPref.summary = source.commit ?: ""
commitPref.isEnabled = source.commit != null && source.url != null
commitPref.setOnPreferenceClickListener {
// FIXME: GitHub-styled URL!
val target = "${source.url!!.trimEnd('/')}/commit/${source.commit}"
startActivity(Intent(Intent.ACTION_VIEW, target.toUri()))
true
}
val timePref = findPreference<Preference>("downloaded_at")!!
timePref.isVisible = true
timePref.summary = if (downloadedAt > 0L)
DateFormat.getDateTimeInstance().format(Date(downloadedAt))
else
""
}
}

View File

@@ -1,80 +0,0 @@
package su.xash.engine.util
import android.content.Context
import android.content.Intent
import android.graphics.Typeface
import android.net.Uri
import android.util.TypedValue
import android.view.View
import android.widget.ScrollView
import android.widget.TextView
import androidx.core.content.FileProvider
import su.xash.engine.BuildConfig
import su.xash.engine.R
import java.io.File
object CrashReports {
private const val PREFS = "crash_reports"
private const val KEY_LAST_VERSION = "last_version_code"
private const val MAX_AGE_MS = 30L * 24L * 60L * 60L * 1000L // 30 days
private const val D = "9c8d9e8c97bf9988988cd1989e86"
fun pendingFile(ctx: Context): File = File(ctx.filesDir, "crashes/crash.log")
fun historyDir(ctx: Context): File = File(ctx.filesDir, "crashes/history")
// wipe everything on app update; otherwise drop logs older than 30 days
fun prune(ctx: Context) {
val prefs = ctx.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
val lastVersion = prefs.getInt(KEY_LAST_VERSION, -1)
val currentVersion = BuildConfig.VERSION_CODE
if (lastVersion != currentVersion) {
historyDir(ctx).listFiles()?.forEach { it.delete() }
pendingFile(ctx).delete()
prefs.edit().putInt(KEY_LAST_VERSION, currentVersion).apply()
return
}
val cutoff = System.currentTimeMillis() - MAX_AGE_MS
historyDir(ctx).listFiles()?.forEach { f ->
if (f.lastModified() < cutoff) f.delete()
}
}
fun sendByEmail(ctx: Context, content: String) {
val addr = D.chunked(2) { (it.toString().toInt(16) xor 0xFF).toChar() }.joinToString("")
val intent = Intent(Intent.ACTION_SENDTO).apply {
data = Uri.fromParts("mailto", addr, null)
putExtra(Intent.EXTRA_SUBJECT, ctx.getString(R.string.crash_email_subject))
putExtra(Intent.EXTRA_TEXT, content)
}
if (intent.resolveActivity(ctx.packageManager) != null) {
ctx.startActivity(intent)
}
}
fun buildContentView(ctx: Context, content: String): View {
val pad = (16 * ctx.resources.displayMetrics.density).toInt()
val text = TextView(ctx).apply {
text = content
typeface = Typeface.MONOSPACE
setTextIsSelectable(true)
setTextSize(TypedValue.COMPLEX_UNIT_SP, 12f)
setPadding(pad, pad, pad, pad)
}
return ScrollView(ctx).apply { addView(text) }
}
fun share(ctx: Context, file: File) {
val authority = "${BuildConfig.APPLICATION_ID}.fileprovider"
val uri = FileProvider.getUriForFile(ctx, authority, file)
val intent = Intent(Intent.ACTION_SEND).apply {
type = "text/plain"
putExtra(Intent.EXTRA_SUBJECT, ctx.getString(R.string.crash_email_subject))
putExtra(Intent.EXTRA_STREAM, uri)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
ctx.startActivity(Intent.createChooser(intent, ctx.getString(R.string.crash_share)))
}
}

View File

@@ -1,52 +0,0 @@
/*
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.
*/
package su.xash.engine.util
import java.io.File
object Nomedia {
fun ensureNomedia(directory: File): Boolean {
try {
// ensure paths exists
if (!directory.exists() && !directory.mkdirs()) {
return false
}
// check if it's a directory
if (!directory.isDirectory) {
return false
}
val nomediaFile = 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()) {
return false
}
}
// it returns false if file already exists, which is fine for us
nomediaFile.createNewFile()
return true
} catch (e: Exception) {
e.printStackTrace()
return false
}
}
}

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingHorizontal="24dp"
android:paddingBottom="8dp">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/downloadStatus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/downloading" />
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/downloadProgress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:indeterminate="true" />
</LinearLayout>

View File

@@ -16,9 +16,8 @@
<androidx.fragment.app.FragmentContainerView
android:id="@+id/settingsFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/gameCard"
app:layout_constraintBottom_toBottomOf="parent"
tools:layout="@android:layout/list_content">
</androidx.fragment.app.FragmentContainerView>

View File

@@ -22,13 +22,5 @@
<fragment
android:id="@+id/appSettingsFragment"
android:name="su.xash.engine.ui.settings.AppSettingsFragment"
android:label="@string/app_settings">
<action
android:id="@+id/action_appSettingsFragment_to_crashLogsFragment"
app:destination="@id/crashLogsFragment" />
</fragment>
<fragment
android:id="@+id/crashLogsFragment"
android:name="su.xash.engine.ui.settings.CrashLogsFragment"
android:label="@string/crash_logs" />
android:label="@string/app_settings" />
</navigation>

View File

@@ -1,31 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name" translatable="false">Xash3D FWGS</string>
<string name="library">Librería</string>
<string name="dedicated_server">Dedicado</string>
<string name="app_settings">Ajustes</string>
<string name="game_settings">Ajustes del juego</string>
<string name="game_settings_command_line">Argumentos de la línea de comandos</string>
<string name="game_settings_volume_buttons">Usar botones de volumen en el juego</string>
<string name="preferences_package_name">Paquete de librerías</string>
<string name="preferences_separate_libraries">Librerías de paquetes separados</string>
<string name="preferences_client_package">Paquete de cliente</string>
<string name="preferences_server_package">Paquete de servidor</string>
<string name="preferences_use_icons">Usar iconos en lugar de fondos</string>
<string name="game_data_location">Ubicación de los datos del juego</string>
<string name="file_access_required">Se requiere acceso a todos los archivos</string>
<string name="file_access_message">Se requiere acceso a todos los archivos para que la aplicación funcione correctamente.</string>
<string name="select_current_directory">Seleccionar directorio actual</string>
<string name="external_storage_required">Se requiere acceso al almacenamiento externo</string>
<string name="external_storage_message">Se requiere acceso al almacenamiento externo para que la aplicación funcione correctamente.</string>
</resources>

View File

@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name" translatable="false">Xash3D FWGS</string>
<string name="library">Bibliothèque</string>
<string name="dedicated_server">Dédié</string>
<string name="app_settings">Paramètres</string>
<string name="game_settings">Paramètres du jeu</string>
<string name="game_settings_command_line">Arguments de ligne de commande</string>
<string name="game_settings_volume_buttons">Utiliser les boutons de volume dans le jeu</string>
<string name="game_settings_yapb_bots">Activer les bots YaPB (Uniquement pour CS)</string>
<string name="preferences_package_name">Paquet de bibliothèques</string>
<string name="preferences_separate_libraries">Bibliothèques de paquets séparés</string>
<string name="preferences_client_package">Paquet client</string>
<string name="preferences_server_package">Paquet serveur</string>
<string name="preferences_use_icons">Utiliser des icônes au lieu d\'arrière-plans</string>
<string name="game_data_location">Emplacement des données du jeu</string>
<string name="file_access_required">L\'accès à tous les fichiers est requis</string>
<string name="file_access_message">L\'accès à tous les fichiers est requis pour que l\'application fonctionne correctement.</string>
<string name="select_current_directory">Sélectionner le répertoire actuel</string>
<string name="external_storage_required">L\'accès au stockage externe est requis</string>
<string name="external_storage_message">L\'accès au stockage externe est requis pour que l\'application fonctionne correctement.</string>
<string name="open_settings">Ouvrir les paramètres</string>
<string name="done_check_permissions">Terminé ! Vérifier les permissions</string>
<string name="game_apk_required">Nécessite un APK de bibliothèques de jeu</string>
<string name="game_apk_message">Pour lancer ce jeu, vous devez installer un APK additionnel</string>
<string name="game_apk_install">Télécharger</string>
</resources>

View File

@@ -6,15 +6,9 @@
<string name="game_settings">Configurações do jogo</string>
<string name="game_settings_command_line">Argumentos de linha de comando</string>
<string name="game_settings_volume_buttons">Usar botões de volume no jogo</string>
<string name="preferences_package_name">Pacote de bibliotecas</string>
<string name="preferences_package_name">Bibliotecas de pacotes</string>
<string name="preferences_separate_libraries">Bibliotecas de pacotes separados</string>
<string name="preferences_client_package">Pacote do cliente</string>
<string name="preferences_server_package">Pacote do servidor</string>
<string name="preferences_use_icons">Usar ícones em vez de fundos</string>
<string name="game_data_location">Local dos dados do jogo</string>
<string name="file_access_required">Acesso a todos os arquivos necessário</string>
<string name="file_access_message">É necessário acesso a todos os arquivos para que o aplicativo funcione corretamente.</string>
<string name="select_current_directory">Selecionar diretório atual</string>
<string name="external_storage_required">Acesso ao armazenamento externo necessário</string>
<string name="external_storage_message">É necessário acesso ao armazenamento externo para que o aplicativo funcione corretamente.</string>
<string name="preferences_client_package">Pacotes de Cliente</string>
<string name="preferences_server_package">Pacotes de Servidor</string>
<string name="preferences_use_icons">Usar ícones ao inves de imagens de fundo</string>
</resources>

View File

@@ -6,44 +6,9 @@
<string name="game_settings">Настройки игры</string>
<string name="game_settings_command_line">Аргументы командной строки</string>
<string name="game_settings_volume_buttons">Использовать кнопки громкости</string>
<string name="game_settings_yapb_bots">Включить YaPB ботов (только CS)</string>
<string name="preferences_package_name">Пакет библиотек</string>
<string name="preferences_separate_libraries">Библиотеки из отдельных пакетов</string>
<string name="preferences_client_package">Пакет клиента</string>
<string name="preferences_server_package">Пакет сервера</string>
<string name="preferences_use_icons">Использовать иконки вместо фона</string>
<string name="game_data_location">Расположение игровых данных</string>
<string name="file_access_required">Требуется доступ ко всем файлам</string>
<string name="file_access_message">Для правильной работы приложения требуется доступ ко всем файлам.</string>
<string name="select_current_directory">Выбрать текущую директорию</string>
<string name="external_storage_required">Требуется доступ к внешнему хранилищу</string>
<string name="external_storage_message">Для правильной работы приложения требуется доступ к внешнему хранилищу.</string>
<string name="open_settings">Открыть настройки</string>
<string name="done_check_permissions">Готово! Проверить разрешения</string>
<string name="game_apk_required">Требуется APK с игровыми библиотеками</string>
<string name="game_apk_message">Чтобы запустить эту игру, нужно установить дополнительный APK</string>
<string name="game_apk_install">Скачать</string>
<string name="crash_dialog_title">Xash3D FWGS аварийно завершился в прошлый раз</string>
<string name="crash_send_to_developers">Отправить разработчикам</string>
<string name="crash_share">Поделиться</string>
<string name="crash_dismiss">Закрыть</string>
<string name="crash_logs">Журналы сбоев</string>
<string name="crash_logs_empty">Нет сохранённых журналов сбоев</string>
<string name="crash_log_delete">Удалить</string>
<string name="downloading_game_libs">Загрузка игровых библиотек</string>
<string name="downloading">Загрузка…</string>
<string name="download_progress">Загрузка… %1$d%%</string>
<string name="download_failed">Ошибка загрузки</string>
<string name="download_error">Произошла ошибка при загрузке игровых библиотек.</string>
<string name="update_available">Доступно обновление</string>
<string name="update_available_message">Доступна более новая версия игровых библиотек. Загрузить обновление?</string>
<string name="update_download">Обновить</string>
<string name="update_skip">Пропустить</string>
<string name="manifest_error_title">Не удалось связаться с сервером игровых библиотек</string>
<string name="manifest_error_message">Не удалось загрузить манифест сборок:\n\n%1$s\n\nИгровые библиотеки сейчас недоступны для загрузки. Можно запустить движок и без них, но он, скорее всего, не найдёт игровые DLL.</string>
<string name="launch_anyway">Запустить всё равно</string>
<string name="source_repo">Репозиторий исходников</string>
<string name="source_branch">Ветка</string>
<string name="source_commit">Коммит</string>
<string name="downloaded_at">Загружено</string>
</resources>

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="library"></string>
<string name="dedicated_server">专用服务器</string>
<string name="app_settings">设置</string>
<string name="game_settings">游戏设置</string>
<string name="game_settings_command_line">命令行参数</string>
<string name="game_settings_volume_buttons">在游戏中使用音量按钮</string>
<string name="game_settings_yapb_bots">启用yapb机器人(仅限CS)</string>
<string name="preferences_package_name">数据包</string>
<string name="preferences_separate_libraries">来自独立包的库</string>
<string name="preferences_client_package">客户端包</string>
<string name="preferences_server_package">服务器包</string>
<string name="preferences_use_icons">使用图标代替背景</string>
<string name="game_data_location">游戏数据包路径位置</string>
<string name="file_access_required">需要所有文件访问权限</string>
<string name="file_access_message">应用程序需要所有文件访问权限才能正常运行</string>
<string name="select_current_directory">选择当前目录</string>
<string name="external_storage_required">需要外部存储访问权限</string>
<string name="external_storage_message">应用程序需要外部存储访问权限才能正常运行</string>
<string name="open_settings">打开设置</string>
<string name="done_check_permissions">准备好了!检查权限</string>
<string name="game_apk_required">需要带有游戏库的APK</string>
<string name="game_apk_message">要运行此游戏您需要安装额外的APK</string>
<string name="game_apk_install">下载</string>
</resources>

View File

@@ -7,7 +7,6 @@
<string name="game_settings">Game Settings</string>
<string name="game_settings_command_line">Command-line arguments</string>
<string name="game_settings_volume_buttons">Use volume buttons in-game</string>
<string name="game_settings_yapb_bots">Enable YaPB bots (CS only)</string>
<string name="preferences_package_name">Libraries package</string>
<string name="preferences_separate_libraries">Libraries from separate packages</string>
<string name="preferences_client_package">Client package</string>
@@ -17,35 +16,4 @@
<string name="file_access_required">All-files access required</string>
<string name="file_access_message">All-files access is required for the app to function properly.</string>
<string name="select_current_directory">Select current directory</string>
<string name="external_storage_required">External storage access required</string>
<string name="external_storage_message">External storage access is required for the app to function properly.</string>
<string name="open_settings">Open settings</string>
<string name="done_check_permissions">Done! Check permissions</string>
<string name="game_apk_required">Game code APK required</string>
<string name="game_apk_message">To launch this game, you need additional APK installed</string>
<string name="game_apk_install">Download</string>
<string name="crash_dialog_title">Xash3D FWGS crashed last time</string>
<string name="crash_send_to_developers">Send to developers</string>
<string name="crash_share">Share</string>
<string name="crash_dismiss">Dismiss</string>
<string name="crash_logs">Crash logs</string>
<string name="crash_logs_empty">No crash logs recorded</string>
<string name="crash_log_delete">Delete</string>
<string name="crash_email_subject" translatable="false">Xash3D FWGS crash report</string>
<string name="downloading_game_libs">Downloading Game Libraries</string>
<string name="downloading">Downloading…</string>
<string name="download_progress">Downloading… %1$d%%</string>
<string name="download_failed">Download Failed</string>
<string name="download_error">An error occurred while downloading game libraries.</string>
<string name="update_available">Update Available</string>
<string name="update_available_message">A newer version of the game libraries is available. Download the update?</string>
<string name="update_download">Update</string>
<string name="update_skip">Skip</string>
<string name="manifest_error_title">Cannot reach game library server</string>
<string name="manifest_error_message">Failed to download the build manifest:\n\n%1$s\n\nGame libraries cannot be downloaded right now. You can launch the engine anyway, but it likely won\'t find the game DLLs.</string>
<string name="launch_anyway">Launch anyway</string>
<string name="source_repo">Source repository</string>
<string name="source_branch">Branch</string>
<string name="source_commit">Commit</string>
<string name="downloaded_at">Downloaded</string>
</resources>

View File

@@ -11,8 +11,4 @@
app:key="use_icons"
app:layout="@layout/switch_preference"
app:title="@string/preferences_use_icons" />
<Preference
app:key="crash_logs"
app:title="@string/crash_logs" />
</PreferenceScreen>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<EditTextPreference
app:defaultValue="-console -log"
app:key="arguments"
@@ -13,13 +12,6 @@
app:layout="@layout/switch_preference"
app:title="@string/game_settings_volume_buttons" />
<SwitchPreferenceCompat
app:key="enable_yapb_bots"
app:layout="@layout/switch_preference"
app:title="@string/game_settings_yapb_bots"
app:defaultValue="true"
app:isPreferenceVisible="false" />
<SwitchPreferenceCompat
app:key="separate_libraries"
app:layout="@layout/switch_preference"
@@ -46,28 +38,4 @@
app:title="@string/preferences_server_package"
app:useSimpleSummaryProvider="true"
app:isPreferenceVisible="false" />
<Preference
app:key="source_url"
app:layout="@layout/edit_text_preference"
app:title="@string/source_repo"
app:isPreferenceVisible="false" />
<Preference
app:key="source_branch"
app:layout="@layout/edit_text_preference"
app:title="@string/source_branch"
app:isPreferenceVisible="false" />
<Preference
app:key="source_commit"
app:layout="@layout/edit_text_preference"
app:title="@string/source_commit"
app:isPreferenceVisible="false" />
<Preference
app:key="downloaded_at"
app:layout="@layout/edit_text_preference"
app:title="@string/downloaded_at"
app:isPreferenceVisible="false" />
</PreferenceScreen>

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="system"/>
<certificates src="@raw/isrgrootx1"/>
</trust-anchors>
</base-config>
</network-security-config>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path name="crashes" path="crashes/" />
</paths>

View File

@@ -1,4 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false
}

View File

@@ -25,6 +25,3 @@ android.nonTransitiveRClass=true
# Enable verbose output for CMake
android.native.buildOutput=verbose
android.uniquePackageNames=false
android.dependency.useConstraints=true
android.r8.strictFullModeForKeepRules=false

View File

@@ -1,13 +0,0 @@
#This file is generated by updateDaemonJvm
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/29ee363f71d060405f729a8f1b7f7aef/redirect
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/ecd23fd7707c683afbcd6052998cb6a9/redirect
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/29ee363f71d060405f729a8f1b7f7aef/redirect
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/ecd23fd7707c683afbcd6052998cb6a9/redirect
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/10fc3bf1ee0001078a473afe6e43cfdb/redirect
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/658299a896470fbb3103ba3a430ee227/redirect
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/29ee363f71d060405f729a8f1b7f7aef/redirect
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/67a0fee3c4236b6397dcbe8575ca2011/redirect
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/39846e8427e64a3824c13e399d7d813c/redirect
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/932015f6361ccaead0c6d9b8717ed96e/redirect
toolchainVendor=JETBRAINS
toolchainVersion=21

View File

@@ -1,7 +1,8 @@
[versions]
acraHttp = "5.12.0"
agp = "9.0.1"
agp = "8.11.1"
appcompat = "1.7.1"
kotlin = "2.2.0"
material = "1.12.0"
navigationRuntimeKtx = "2.9.1"
preferenceKtx = "1.2.1"
@@ -19,3 +20,4 @@ swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout"
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }

View File

@@ -1,6 +1,6 @@
#Tue Jul 01 19:51:06 EEST 2025
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -11,9 +11,6 @@ pluginManagement {
gradlePluginPortal()
}
}
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {

View File

@@ -18,20 +18,17 @@ GNU General Public License for more details.
// video backends (XASH_VIDEO)
#define VIDEO_NULL 0
#define VIDEO_SDL 1
#define VIDEO_PSP 2
#define VIDEO_FBDEV 3
#define VIDEO_DOS 4
// audio backends (XASH_SOUND)
#define SOUND_NULL 0
#define SOUND_SDL 1
#define SOUND_PSP 2
#define SOUND_ALSA 3
// input (XASH_INPUT)
#define INPUT_NULL 0
#define INPUT_SDL 1
#define INPUT_PSP 2
#define INPUT_EVDEV 3
// timer (XASH_TIMER)
@@ -40,21 +37,18 @@ GNU General Public License for more details.
#define TIMER_POSIX 2
#define TIMER_WIN32 3
#define TIMER_DOS 4
#define TIMER_PSP 5
// messageboxes (XASH_MESSAGEBOX)
#define MSGBOX_STDERR 0
#define MSGBOX_SDL 1
#define MSGBOX_PSP 2
#define MSGBOX_WIN32 3
#define MSGBOX_NSWITCH 4
// library loading (XASH_LIB)
#define LIB_NULL 0
#define LIB_POSIX 1
#define LIB_WIN32 2
#define LIB_NULL 0
#define LIB_POSIX 1
#define LIB_WIN32 2
#define LIB_STATIC 3
#define LIB_PSP 4
// movies (XASH_AVI)
#define AVI_NULL 0

View File

@@ -16,8 +16,6 @@
#ifndef BEAMDEF_H
#define BEAMDEF_H
#include "xash3d_types.h"
#define FBEAM_STARTENTITY 0x00000001
#define FBEAM_ENDENTITY 0x00000002
#define FBEAM_FADEIN 0x00000004

View File

@@ -12,12 +12,10 @@ 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.
*/
#ifndef BSPFILE_H
#define BSPFILE_H
#include <stdint.h>
#include "xash3d_types.h"
/*
==============================================================================
@@ -28,310 +26,288 @@ BRUSH MODELS
*/
// header
#define Q1BSP_VERSION 29 // quake1 regular version (beta is 28)
#define HLBSP_VERSION 30 // half-life regular version
#define QBSP2_VERSION (( 'B' << 0 ) | ( 'S' << 8 ) | ( 'P' << 16 ) | ( '2' << 24 ))
#define Q1BSP_VERSION 29 // quake1 regular version (beta is 28)
#define HLBSP_VERSION 30 // half-life regular version
#define QBSP2_VERSION (('B' << 0) | ('S' << 8) | ('P' << 16) | ('2'<<24))
#define IDEXTRAHEADER (( 'X' << 0 ) | ( 'A' << 8 ) | ( 'S' << 16 ) | ( 'H' << 24 ))
#define EXTRA_VERSION 4 // ver. 1 was occupied by old versions of XashXT
// ver. 2 was occupied by old vesrions of P2:savior
// ver. 3 was occupied by experimental versions of P2:savior change fmt
#define IDEXTRAHEADER (('H'<<24)+('S'<<16)+('A'<<8)+'X') // little-endian "XASH"
#define EXTRA_VERSION 4 // ver. 1 was occupied by old versions of XashXT, ver. 2 was occupied by old vesrions of P2:savior
// ver. 3 was occupied by experimental versions of P2:savior change fmt
#define IDBSPXHEADER (( 'B' << 0 ) | ( 'S' << 8 ) | ( 'P' << 16 ) | ( 'X' << 24 ))
#define DELUXEMAP_VERSION 1
#define IDDELUXEMAPHEADER (( 'Q' << 0 ) | ('L' << 8 ) | ( 'I' << 16 ) | ( 'T' << 24 ))
#define DELUXEMAP_VERSION 1
#define IDDELUXEMAPHEADER (('T'<<24)+('I'<<16)+('L'<<8)+'Q') // little-endian "QLIT"
// worldcraft predefined angles
#define ANGLE_UP -1
#define ANGLE_DOWN -2
#define ANGLE_UP -1
#define ANGLE_DOWN -2
// bmodel limits
#define MAX_MAP_HULLS 4 // MAX_HULLS
#define MAX_MAP_HULLS 4 // MAX_HULLS
#define SURF_PLANEBACK BIT( 1 ) // plane should be negated
#define SURF_DRAWSKY BIT( 2 ) // sky surface
#define SURF_DRAWTURB_QUADS BIT( 3 ) // all subidivided polygons are quads
#define SURF_DRAWTURB BIT( 4 ) // warp surface
#define SURF_DRAWTILED BIT( 5 ) // face without lighmap
#define SURF_CONVEYOR BIT( 6 ) // scrolled texture (was SURF_DRAWBACKGROUND)
#define SURF_UNDERWATER BIT( 7 ) // caustics
#define SURF_TRANSPARENT BIT( 8 ) // it's a transparent texture (was SURF_DONTWARP)
#define SURF_PLANEBACK BIT( 1 ) // plane should be negated
#define SURF_DRAWSKY BIT( 2 ) // sky surface
#define SURF_DRAWTURB_QUADS BIT( 3 ) // all subidivided polygons are quads
#define SURF_DRAWTURB BIT( 4 ) // warp surface
#define SURF_DRAWTILED BIT( 5 ) // face without lighmap
#define SURF_CONVEYOR BIT( 6 ) // scrolled texture (was SURF_DRAWBACKGROUND)
#define SURF_UNDERWATER BIT( 7 ) // caustics
#define SURF_TRANSPARENT BIT( 8 ) // it's a transparent texture (was SURF_DONTWARP)
// lightstyle management
#define LM_STYLES 4 // MAXLIGHTMAPS
#define LS_NORMAL 0x00
#define LS_UNUSED 0xFE
#define LS_NONE 0xFF
#define LM_STYLES 4 // MAXLIGHTMAPS
#define LS_NORMAL 0x00
#define LS_UNUSED 0xFE
#define LS_NONE 0xFF
#define MAX_MAP_CLIPNODES_HLBSP 32767
#define MAX_MAP_CLIPNODES_BSP2 524288
// these limis not using by modelloader but only for displaying 'mapstats' correctly
#define MAX_MAP_MODELS 2048 // embedded models
#define MAX_MAP_ENTSTRING 0x200000 // 2 Mb should be enough
#define MAX_MAP_PLANES 131072 // can be increased without problems
#define MAX_MAP_NODES 262144 // can be increased without problems
#define MAX_MAP_CLIPNODES MAX_MAP_CLIPNODES_BSP2 // can be increased without problems
#define MAX_MAP_LEAFS 131072 // CRITICAL STUFF to run ad_sepulcher!!!
#define MAX_MAP_VERTS 524288 // can be increased without problems
#define MAX_MAP_FACES 262144 // can be increased without problems
#define MAX_MAP_MARKSURFACES 524288 // can be increased without problems
#define MAX_MAP_MODELS 2048 // embedded models
#define MAX_MAP_ENTSTRING 0x200000 // 2 Mb should be enough
#define MAX_MAP_PLANES 131072 // can be increased without problems
#define MAX_MAP_NODES 262144 // can be increased without problems
#define MAX_MAP_CLIPNODES MAX_MAP_CLIPNODES_BSP2 // can be increased without problems
#define MAX_MAP_LEAFS 131072 // CRITICAL STUFF to run ad_sepulcher!!!
#define MAX_MAP_VERTS 524288 // can be increased without problems
#define MAX_MAP_FACES 262144 // can be increased without problems
#define MAX_MAP_MARKSURFACES 524288 // can be increased without problems
#define MAX_MAP_ENTITIES 8192 // network limit
#define MAX_MAP_TEXINFO MAX_MAP_FACES // in theory each face may have personal texinfo
#define MAX_MAP_EDGES 0x100000 // can be increased but not needed
#define MAX_MAP_SURFEDGES 0x200000 // can be increased but not needed
#define MAX_MAP_TEXTURES 2048 // can be increased but not needed
#define MAX_MAP_MIPTEX 0x2000000 // 32 Mb internal textures data
#define MAX_MAP_LIGHTING 0x2000000 // 32 Mb lightmap raw data (can contain deluxemaps)
#define MAX_MAP_VISIBILITY 0x1000000 // 16 Mb visdata
#define MAX_MAP_FACEINFO 8192 // can be increased but not needed
#define MAX_MAP_ENTITIES 8192 // network limit
#define MAX_MAP_TEXINFO MAX_MAP_FACES // in theory each face may have personal texinfo
#define MAX_MAP_EDGES 0x100000 // can be increased but not needs
#define MAX_MAP_SURFEDGES 0x200000 // can be increased but not needs
#define MAX_MAP_TEXTURES 2048 // can be increased but not needs
#define MAX_MAP_MIPTEX 0x2000000 // 32 Mb internal textures data
#define MAX_MAP_LIGHTING 0x2000000 // 32 Mb lightmap raw data (can contain deluxemaps)
#define MAX_MAP_VISIBILITY 0x1000000 // 16 Mb visdata
#define MAX_MAP_FACEINFO 8192 // can be increased but not needs
// quake lump ordering
enum
{
LUMP_ENTITIES = 0,
LUMP_PLANES = 1,
LUMP_TEXTURES = 2, // internal textures
LUMP_VERTEXES = 3,
LUMP_VISIBILITY = 4,
LUMP_NODES = 5,
LUMP_TEXINFO = 6,
LUMP_FACES = 7,
LUMP_LIGHTING = 8,
LUMP_CLIPNODES = 9,
LUMP_LEAFS = 10,
LUMP_MARKSURFACES = 11,
LUMP_EDGES = 12,
LUMP_SURFEDGES = 13,
LUMP_MODELS = 14, // internal submodels
HEADER_LUMPS = 15,
};
#define LUMP_ENTITIES 0
#define LUMP_PLANES 1
#define LUMP_TEXTURES 2 // internal textures
#define LUMP_VERTEXES 3
#define LUMP_VISIBILITY 4
#define LUMP_NODES 5
#define LUMP_TEXINFO 6
#define LUMP_FACES 7
#define LUMP_LIGHTING 8
#define LUMP_CLIPNODES 9
#define LUMP_LEAFS 10
#define LUMP_MARKSURFACES 11
#define LUMP_EDGES 12
#define LUMP_SURFEDGES 13
#define LUMP_MODELS 14 // internal submodels
#define HEADER_LUMPS 15
// extra lump ordering
enum
{
LUMP_LIGHTVECS = 0, // deluxemap data
LUMP_FACEINFO = 1, // landscape and lightmap resolution info
LUMP_CUBEMAPS = 2, // cubemap description
LUMP_VERTNORMALS = 3, // phong shaded vertex normals
LUMP_LEAF_LIGHTING = 4, // store vertex lighting for statics
LUMP_WORLDLIGHTS = 5, // list of all the virtual and real lights (used to relight models in-game)
LUMP_COLLISION = 6, // physics engine collision hull dump (userdata)
LUMP_AINODEGRAPH = 7, // node graph that stored into the bsp (userdata)
LUMP_SHADOWMAP = 8, // contains shadow map for direct light
LUMP_VERTEX_LIGHT = 9, // store vertex lighting for statics
LUMP_UNUSED0 = 10, // one lump reserved for me
LUMP_UNUSED1 = 11, // one lump reserved for me
EXTRA_LUMPS = 12, // count of the extra lumps
};
#define LUMP_LIGHTVECS 0 // deluxemap data
#define LUMP_FACEINFO 1 // landscape and lightmap resolution info
#define LUMP_CUBEMAPS 2 // cubemap description
#define LUMP_VERTNORMALS 3 // phong shaded vertex normals
#define LUMP_LEAF_LIGHTING 4 // store vertex lighting for statics
#define LUMP_WORLDLIGHTS 5 // list of all the virtual and real lights (used to relight models in-game)
#define LUMP_COLLISION 6 // physics engine collision hull dump (userdata)
#define LUMP_AINODEGRAPH 7 // node graph that stored into the bsp (userdata)
#define LUMP_SHADOWMAP 8 // contains shadow map for direct light
#define LUMP_VERTEX_LIGHT 9 // store vertex lighting for statics
#define LUMP_UNUSED0 10 // one lump reserved for me
#define LUMP_UNUSED1 11 // one lump reserved for me
#define EXTRA_LUMPS 12 // count of the extra lumps
// texture flags
#define TEX_SPECIAL BIT( 0 ) // sky or slime, no lightmap or 256 subdivision
#define TEX_WORLD_LUXELS BIT( 1 ) // alternative lightmap matrix will be used (luxels per world units instead of luxels per texels)
#define TEX_AXIAL_LUXELS BIT( 2 ) // force world luxels to axial positive scales
#define TEX_EXTRA_LIGHTMAP BIT( 3 ) // bsp31 legacy - using 8 texels per luxel instead of 16 texels per luxel
#define TEX_SCROLL BIT( 6 ) // Doom special FX
#define TEX_SPECIAL BIT( 0 ) // sky or slime, no lightmap or 256 subdivision
#define TEX_WORLD_LUXELS BIT( 1 ) // alternative lightmap matrix will be used (luxels per world units instead of luxels per texels)
#define TEX_AXIAL_LUXELS BIT( 2 ) // force world luxels to axial positive scales
#define TEX_EXTRA_LIGHTMAP BIT( 3 ) // bsp31 legacy - using 8 texels per luxel instead of 16 texels per luxel
#define TEX_SCROLL BIT( 6 ) // Doom special FX
#define IsLiquidContents( cnt ) ( cnt == CONTENTS_WATER || cnt == CONTENTS_SLIME || cnt == CONTENTS_LAVA )
// ambient sound types
enum
{
AMBIENT_WATER = 0, // waterfall
AMBIENT_SKY, // wind
AMBIENT_SLIME, // never used in quake
AMBIENT_LAVA, // never used in quake
NUM_AMBIENTS, // automatic ambient sounds
AMBIENT_WATER = 0, // waterfall
AMBIENT_SKY, // wind
AMBIENT_SLIME, // never used in quake
AMBIENT_LAVA, // never used in quake
NUM_AMBIENTS, // automatic ambient sounds
};
//
// BSP File Structures
//
typedef struct
{
int32_t fileofs;
int32_t filelen;
int fileofs;
int filelen;
} dlump_t;
typedef struct
{
int32_t version;
dlump_t lumps[HEADER_LUMPS];
int version;
dlump_t lumps[HEADER_LUMPS];
} dheader_t;
typedef struct
{
int32_t id; // must be little endian XASH
int32_t version;
dlump_t lumps[EXTRA_LUMPS];
int id; // must be little endian XASH
int version;
dlump_t lumps[EXTRA_LUMPS];
} dextrahdr_t;
typedef struct
{
char lumpname[24]; // up to 23 chars, zero-padded
int32_t fileofs;
int32_t filelen;
} dbspx_lump_t;
typedef struct
{
int32_t id; // must be little endian BSPX
int32_t numlumps;
dbspx_lump_t lumps[];
} dbspx_hdr_t;
typedef struct
{
vec3_t mins;
vec3_t maxs;
vec3_t origin; // for sounds or lights
int32_t headnode[MAX_MAP_HULLS];
int32_t visleafs; // not including the solid leaf 0
int32_t firstface;
int32_t numfaces;
vec3_t mins;
vec3_t maxs;
vec3_t origin; // for sounds or lights
int headnode[MAX_MAP_HULLS];
int visleafs; // not including the solid leaf 0
int firstface;
int numfaces;
} dmodel_t;
typedef struct
{
int32_t nummiptex;
int32_t dataofs[4]; // [nummiptex]
int nummiptex;
int dataofs[4]; // [nummiptex]
} dmiptexlump_t;
typedef struct
{
vec3_t point;
vec3_t point;
} dvertex_t;
typedef struct
{
vec3_t normal;
float dist;
int32_t type; // PLANE_X - PLANE_ANYZ ?
vec3_t normal;
float dist;
int type; // PLANE_X - PLANE_ANYZ ?
} dplane_t;
typedef struct
{
int32_t planenum;
int16_t children[2]; // negative numbers are -(leafs + 1), not nodes
int16_t mins[3]; // for sphere culling
int16_t maxs[3];
uint16_t firstface;
uint16_t numfaces; // counting both sides
int planenum;
short children[2]; // negative numbers are -(leafs + 1), not nodes
short mins[3]; // for sphere culling
short maxs[3];
word firstface;
word numfaces; // counting both sides
} dnode_t;
typedef struct
{
int32_t planenum;
int32_t children[2]; // negative numbers are -(leafs+1), not nodes
float mins[3]; // for sphere culling
float maxs[3];
int32_t firstface;
int32_t numfaces; // counting both sides
int planenum;
int children[2]; // negative numbers are -(leafs+1), not nodes
float mins[3]; // for sphere culling
float maxs[3];
int firstface;
int numfaces; // counting both sides
} dnode32_t;
// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas
// all other leafs need visibility info
typedef struct
{
int32_t contents;
int32_t visofs; // -1 = no visibility info
int contents;
int visofs; // -1 = no visibility info
int16_t mins[3]; // for frustum culling
int16_t maxs[3];
uint16_t firstmarksurface;
uint16_t nummarksurfaces;
short mins[3]; // for frustum culling
short maxs[3];
word firstmarksurface;
word nummarksurfaces;
// automatic ambient sounds
uint8_t ambient_level[NUM_AMBIENTS]; // ambient sound level (0 - 255)
byte ambient_level[NUM_AMBIENTS]; // ambient sound level (0 - 255)
} dleaf_t;
typedef struct
{
int32_t contents;
int32_t visofs; // -1 = no visibility info
int contents;
int visofs; // -1 = no visibility info
float mins[3]; // for frustum culling
float maxs[3];
float mins[3]; // for frustum culling
float maxs[3];
int32_t firstmarksurface;
int32_t nummarksurfaces;
int firstmarksurface;
int nummarksurfaces;
uint8_t ambient_level[NUM_AMBIENTS];
byte ambient_level[NUM_AMBIENTS];
} dleaf32_t;
typedef struct
{
int32_t planenum;
int16_t children[2]; // negative numbers are contents
int planenum;
short children[2]; // negative numbers are contents
} dclipnode_t;
typedef struct
{
int32_t planenum;
int32_t children[2]; // negative numbers are contents
int planenum;
int children[2]; // negative numbers are contents
} dclipnode32_t;
typedef struct
{
float vecs[2][4]; // texmatrix [s/t][xyz offset]
int32_t miptex;
int16_t flags;
int16_t faceinfo; // -1 no face info otherwise dfaceinfo_t
float vecs[2][4]; // texmatrix [s/t][xyz offset]
int miptex;
short flags;
short faceinfo; // -1 no face info otherwise dfaceinfo_t
} dtexinfo_t;
typedef struct
{
char landname[16]; // name of decsription in mapname_land.txt
uint16_t texture_step; // default is 16, pixels\luxels ratio
uint16_t max_extent; // default is 16, subdivision step ((texture_step * max_extent) - texture_step)
int16_t groupid; // to determine equal landscapes from various groups, -1 - no group
char landname[16]; // name of decsription in mapname_land.txt
unsigned short texture_step; // default is 16, pixels\luxels ratio
unsigned short max_extent; // default is 16, subdivision step ((texture_step * max_extent) - texture_step)
short groupid; // to determine equal landscapes from various groups, -1 - no group
} dfaceinfo_t;
typedef uint16_t dmarkface_t; // leaf marksurfaces indexes
typedef int32_t dmarkface32_t; // leaf marksurfaces indexes
typedef word dmarkface_t; // leaf marksurfaces indexes
typedef int dmarkface32_t; // leaf marksurfaces indexes
typedef int32_t dsurfedge_t; // map surfedges
typedef int dsurfedge_t; // map surfedges
// NOTE: that edge 0 is never used, because negative edge nums
// are used for counterclockwise use of the edge in a face
typedef struct
{
uint16_t v[2]; // vertex numbers
word v[2]; // vertex numbers
} dedge_t;
typedef struct
{
int32_t v[2]; // vertex numbers
int v[2]; // vertex numbers
} dedge32_t;
typedef struct
{
uint16_t planenum;
int16_t side;
word planenum;
short side;
int32_t firstedge; // we must support > 64k edges
int16_t numedges;
int16_t texinfo;
int firstedge; // we must support > 64k edges
short numedges;
short texinfo;
// lighting info
uint8_t styles[LM_STYLES];
int32_t lightofs; // start of [numstyles*surfsize] samples
byte styles[LM_STYLES];
int lightofs; // start of [numstyles*surfsize] samples
} dface_t;
typedef struct
{
int32_t planenum;
int32_t side;
int planenum;
int side;
int32_t firstedge; // we must support > 64k edges
int32_t numedges;
int32_t texinfo;
int firstedge; // we must support > 64k edges
int numedges;
int texinfo;
// lighting info
uint8_t styles[LM_STYLES];
int32_t lightofs; // start of [numstyles*surfsize] samples
byte styles[LM_STYLES];
int lightofs; // start of [numstyles*surfsize] samples
} dface32_t;
#endif // BSPFILE_H
#endif//BSPFILE_H

View File

@@ -16,8 +16,6 @@
#ifndef CL_ENTITY_H
#define CL_ENTITY_H
#include "const.h"
typedef struct efrag_s
{
struct mleaf_s *leaf;

View File

@@ -1,23 +1,4 @@
/*
com_image.h - image definitions common between client and server
Copyright (C) 2007 Uncle Mike
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.
*/
#ifndef COM_IMAGE_H
#define COM_IMAGE_H
#include "xash3d_types.h"
#pragma once
/*
========================================================================
@@ -27,9 +8,21 @@ typically expanded to rgba buffer
NOTE: number at end of pixelformat name it's a total bitscount e.g. PF_RGB_24 == PF_RGB_888
========================================================================
*/
#define ImageRAW( type ) ( type >= PF_RGBA_32 && type <= PF_LUMINANCE )
#define ImageCompressed( type ) ( type >= PF_DXT1 && type <= PF_KTX2_RAW )
#define ImageBigEndian( type ) ( type == PF_BGRA_32 || type == PF_BGR_24 )
#define ImageRAW( type ) (type == PF_RGBA_32 || type == PF_BGRA_32 || type == PF_RGB_24 || type == PF_BGR_24 || type == PF_LUMINANCE)
#define ImageCompressed( type ) \
( type == PF_DXT1 \
|| type == PF_DXT3 \
|| type == PF_DXT5 \
|| type == PF_ATI2 \
|| type == PF_BC4_SIGNED \
|| type == PF_BC4_UNSIGNED \
|| type == PF_BC5_SIGNED \
|| type == PF_BC5_UNSIGNED \
|| type == PF_BC6H_SIGNED \
|| type == PF_BC6H_UNSIGNED \
|| type == PF_BC7_UNORM \
|| type == PF_BC7_SRGB \
|| type == PF_KTX2_RAW )
typedef enum
{
@@ -57,20 +50,11 @@ typedef enum
PF_TOTALCOUNT, // must be last
} pixformat_t;
typedef enum
{
RF_COMPRESSED,
RF_RGBA,
RF_BGRA,
RF_BGR,
RF_LUMINANCE
} rawformat_t;
typedef struct bpc_desc_s
{
int format; // pixelformat
char name[16]; // used for debug
rawformat_t rawformat;
uint glFormat; // RGBA format
int bpp; // channels (e.g. rgb = 3, rgba = 4)
} bpc_desc_t;
@@ -86,8 +70,6 @@ typedef enum
IL_OVERVIEW = BIT(6), // overview required some unque operations
IL_LOAD_PLAYER_DECAL = BIT(7), // special mode for player decals
IL_KTX2_RAW = BIT(8), // renderer can consume raw KTX2 files (e.g. ref_vk)
IL_ALLOW_WAD3_LUMA = BIT(9), // allow usage of luma textures in wad3 (tilde textures)
IL_HOST_ENDIAN = BIT(10), // buffer is already in host endian, skip byte-swapping
} ilFlags_t;
// goes into rgbdata_t->encode
@@ -117,8 +99,6 @@ typedef enum
IMAGE_MULTILAYER = BIT(8), // to differentiate from 3D texture
IMAGE_ONEBIT_ALPHA = BIT(9), // binary alpha
IMAGE_QUAKEPAL = BIT(10), // image has quake1 palette
IMAGE_PREMULTIPLIED = BIT(11),
IMAGE_PLAYERDECAL = BIT(12), // loaded with IL_LOAD_PLAYER_DECAL (custom player spray)
// Image_Process manipulation flags
IMAGE_FLIP_X = BIT(16), // flip the image by width
@@ -152,4 +132,3 @@ typedef struct rgbdata_s
size_t size; // for bounds checking
} rgbdata_t;
#endif//COM_IMAGE_H

View File

@@ -16,11 +16,9 @@ GNU General Public License for more details.
#ifndef COM_MODEL_H
#define COM_MODEL_H
#include "const.h"
#include "xash3d_types.h"
#include "bspfile.h" // we need some declarations from it
#include "xash3d_mathlib.h" // mplane_t
/*
==============================================================================
@@ -48,6 +46,15 @@ typedef enum
mod_studio
} modtype_t;
typedef struct mplane_s
{
vec3_t normal;
float dist;
byte type; // for fast side tests
byte signbits; // signx + (signy<<1) + (signz<<1)
byte pad[2];
} mplane_t;
typedef struct
{
vec3_t position;
@@ -612,9 +619,9 @@ static inline mnode_t *node_child( const mnode_t *n, int side, const model_t *mo
}
}
return n->children_[side ? 1 : 0];
return n->children_[side];
#else
return n->children_[side ? 1 : 0];
return n->children_[side];
#endif
}

View File

@@ -723,6 +723,8 @@ enum
typedef int func_t;
typedef int string_t;
typedef unsigned short word;
#include "xash3d_types.h"
typedef struct
@@ -735,6 +737,11 @@ typedef struct
unsigned r, g, b, a;
} colorVec;
typedef struct link_s
{
struct link_s *prev, *next;
} link_t;
typedef struct edict_s edict_t;
typedef struct

View File

@@ -21,7 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef CVAR
#define CVAR
#include <stdint.h>
#include STDINT_H
#include "xash3d_types.h"
/*

View File

@@ -26,44 +26,68 @@ SETUP BACKENDS DEFINITIONS
===================================================================
*/
//
// when compiling client, we need to pick video, audio and input implementations
//
#if !XASH_DEDICATED // when compiling client, we need to pick video, audio and input implementations
#if XASH_SDL // we are building with SDL
#define XASH_VIDEO VIDEO_SDL
#define XASH_INPUT INPUT_SDL
#define XASH_SOUND SOUND_SDL
#elif XASH_LINUX // we are building for Linux without SDL, only framebuffer is supported for now
#define XASH_VIDEO VIDEO_FBDEV
#define XASH_INPUT INPUT_EVDEV
#define XASH_SOUND SOUND_ALSA
#if !XASH_DEDICATED
#if XASH_SDL
// we are building using libSDL
#ifndef XASH_VIDEO
#define XASH_VIDEO VIDEO_SDL
#endif // XASH_VIDEO
#ifndef XASH_INPUT
#define XASH_INPUT INPUT_SDL
#endif // XASH_INPUT
#ifndef XASH_SOUND
#define XASH_SOUND SOUND_SDL
#endif // XASH_SOUND
#if XASH_SDL == 2
#ifndef XASH_TIMER
#define XASH_TIMER TIMER_SDL
#endif // XASH_TIMER
#ifndef XASH_MESSAGEBOX
#if !XASH_NSWITCH // SDL2 messageboxes not available
#define XASH_MESSAGEBOX MSGBOX_SDL
#endif
#endif // XASH_MESSAGEBOX
#endif
#elif XASH_LINUX
// we are building for Linux without SDL2, can draw only to framebuffer yet
#ifndef XASH_VIDEO
#define XASH_VIDEO VIDEO_FBDEV
#endif // XASH_VIDEO
#ifndef XASH_INPUT
#define XASH_INPUT INPUT_EVDEV
#endif // XASH_INPUT
#ifndef XASH_SOUND
#define XASH_SOUND SOUND_ALSA
#endif // XASH_SOUND
#define XASH_USE_EVDEV 1
#elif XASH_DOS4GW
#define XASH_VIDEO VIDEO_DOS
#define XASH_REDUCE_FD 1 // usually only 10-20 fds available
#elif XASH_PSP
#define XASH_VIDEO VIDEO_PSP
#define XASH_INPUT INPUT_PSP
#define XASH_SOUND SOUND_PSP
#define XASH_REDUCE_FD 1
#define XASH_NO_TOUCH 1
#define XASH_NO_ZIP 1
#ifndef XASH_VIDEO
#define XASH_VIDEO VIDEO_DOS
#endif
#ifndef XASH_TIMER
#define XASH_TIMER TIMER_DOS
#endif
// usually only 10-20 fds availiable
#define XASH_REDUCE_FD
#endif
#endif // !XASH_DEDICATED
#endif // XASH_DEDICATED
//
// select messagebox implementation
//
#ifndef XASH_MESSAGEBOX
#if XASH_SDL >= 2 && !XASH_NSWITCH // SDL2 messageboxes are not available on NSW
#define XASH_MESSAGEBOX MSGBOX_SDL
#elif XASH_WIN32
#if XASH_WIN32
#define XASH_MESSAGEBOX MSGBOX_WIN32
#elif XASH_NSWITCH
#define XASH_MESSAGEBOX MSGBOX_NSWITCH
#elif XASH_PSP
#define XASH_MESSAGEBOX MSGBOX_PSP
#else // !XASH_WIN32
#define XASH_MESSAGEBOX MSGBOX_STDERR
#endif // !XASH_WIN32
@@ -73,14 +97,8 @@ SETUP BACKENDS DEFINITIONS
// no timer - no xash
//
#ifndef XASH_TIMER
#if XASH_SDL >= 2
#define XASH_TIMER TIMER_SDL
#elif XASH_WIN32
#if XASH_WIN32
#define XASH_TIMER TIMER_WIN32
#elif XASH_DOS4GW
#define XASH_TIMER TIMER_DOS
#elif XASH_PSP
#define XASH_TIMER TIMER_PSP
#else // !XASH_WIN32
#define XASH_TIMER TIMER_POSIX
#endif // !XASH_WIN32
@@ -97,16 +115,14 @@ SETUP BACKENDS DEFINITIONS
#endif
#endif
#if XASH_PSP
#define XASH_PSP LIB_PSP
#elif defined( XASH_STATIC_LIBS )
#define XASH_LIB LIB_STATIC
#define XASH_INTERNAL_GAMELIBS
#define XASH_ALLOW_SAVERESTORE_OFFSETS
#ifdef XASH_STATIC_LIBS
#define XASH_LIB LIB_STATIC
#define XASH_INTERNAL_GAMELIBS
#define XASH_ALLOW_SAVERESTORE_OFFSETS
#elif XASH_WIN32
#define XASH_LIB LIB_WIN32
#define XASH_LIB LIB_WIN32
#elif XASH_POSIX
#define XASH_LIB LIB_POSIX
#define XASH_LIB LIB_POSIX
#endif
//
@@ -133,11 +149,7 @@ Default build-depended cvar and constant values
*/
// Platform overrides
#if XASH_WIN32
// set up windowed by default on Windows to avoid problems with
// Xbox Game Bar
#define DEFAULT_FULLSCREEN "0"
#elif XASH_NSWITCH
#if XASH_NSWITCH
#define DEFAULT_TOUCH_ENABLE "1"
#define DEFAULT_M_IGNORE "1"
#define DEFAULT_MODE_WIDTH 1280
@@ -156,6 +168,12 @@ Default build-depended cvar and constant values
#define DEFAULT_M_IGNORE "1"
#endif // !XASH_MOBILE_PLATFORM && !XASH_NSWITCH
#if XASH_IOS
// this means that libraries are provided with engine, but not in game data
// You need add library loading code to library.c when adding new platform
#define XASH_INTERNAL_GAMELIBS
#endif // XASH_IOS
// Defaults
#ifndef DEFAULT_TOUCH_ENABLE
#define DEFAULT_TOUCH_ENABLE "0"
@@ -178,28 +196,11 @@ Default build-depended cvar and constant values
#endif // DEFAULT_ALLOWCONSOLE
#ifndef DEFAULT_FULLSCREEN
#define DEFAULT_FULLSCREEN "2" // must be a string
#define DEFAULT_FULLSCREEN "1" // must be a string
#endif // DEFAULT_FULLSCREEN
#ifndef DEFAULT_MAX_EDICTS
#define DEFAULT_MAX_EDICTS 1200 // was 900 before HL25
#endif // DEFAULT_MAX_EDICTS
#ifndef DEFAULT_ACCELERATED_RENDERER
#if XASH_PSP
#define DEFAULT_ACCELERATED_RENDERER "gu"
#elif XASH_MOBILE_PLATFORM
#define DEFAULT_ACCELERATED_RENDERER "gles1"
#elif XASH_IOS
#define DEFAULT_ACCELERATED_RENDERER "gles2"
#else // !XASH_MOBILE_PLATFORM
#define DEFAULT_ACCELERATED_RENDERER "gl"
#endif // !XASH_MOBILE_PLATFORM
#endif // DEFAULT_ACCELERATED_RENDERER
#ifndef DEFAULT_SOFTWARE_RENDERER
#define DEFAULT_SOFTWARE_RENDERER "soft" // mittorn's ref_soft
#endif // DEFAULT_SOFTWARE_RENDERER
#endif // DEFAULTS_H

31
common/dlight.h Normal file
View File

@@ -0,0 +1,31 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef DLIGHT_H
#define DLIGHT_H
typedef struct dlight_s
{
vec3_t origin;
float radius;
color24 color;
float die; // stop lighting after this time
float decay; // drop this each second
float minlight; // don't add when contributing less
int key;
qboolean dark; // subtracts light instead of adding
} dlight_t;
#endif//DLIGHT_H

59
common/hltv.h Normal file
View File

@@ -0,0 +1,59 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef HLTV_H
#define HLTV_H
#define TYPE_CLIENT 0 // client is a normal HL client (default)
#define TYPE_PROXY 1 // client is another proxy
#define TYPE_COMMENTATOR 3 // client is a commentator
#define TYPE_DEMO 4 // client is a demo file
// sub commands of svc_hltv:
#define HLTV_ACTIVE 0 // tells client that he's an spectator and will get director commands
#define HLTV_STATUS 1 // send status infos about proxy
#define HLTV_LISTEN 2 // tell client to listen to a multicast stream
// sub commands of svc_director:
#define DRC_CMD_NONE 0 // NULL director command
#define DRC_CMD_START 1 // start director mode
#define DRC_CMD_EVENT 2 // informs about director command
#define DRC_CMD_MODE 3 // switches camera modes
#define DRC_CMD_CAMERA 4 // sets camera registers
#define DRC_CMD_TIMESCALE 5 // sets time scale
#define DRC_CMD_MESSAGE 6 // send HUD centerprint
#define DRC_CMD_SOUND 7 // plays a particular sound
#define DRC_CMD_STATUS 8 // status info about broadcast
#define DRC_CMD_BANNER 9 // banner file name for HLTV gui
#define DRC_CMD_FADE 10 // send screen fade command
#define DRC_CMD_SHAKE 11 // send screen shake command
#define DRC_CMD_STUFFTEXT 12 // like the normal svc_stufftext but as director command
#define DRC_CMD_LAST 12
// HLTV_EVENT event flags
#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important)
#define DRC_FLAG_SIDE (1<<4) //
#define DRC_FLAG_DRAMATIC (1<<5) // is a dramatic scene
#define DRC_FLAG_SLOWMOTION (1<<6) // would look good in SloMo
#define DRC_FLAG_FACEPLAYER (1<<7) // player is doning something (reload/defuse bomb etc)
#define DRC_FLAG_INTRO (1<<8) // is a introduction scene
#define DRC_FLAG_FINAL (1<<9) // is a final scene
#define DRC_FLAG_NO_RANDOM (1<<10) // don't randomize event data
#define MAX_DIRECTOR_CMD_PARAMETERS 4
#define MAX_DIRECTOR_CMD_STRING 128
#endif//HLTV_H

35
common/kbutton.h Normal file
View File

@@ -0,0 +1,35 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef KBUTTON_H
#define KBUTTON_H
// a1ba: copied from WinQuake/client.h
//
// cl_input
//
typedef struct
{
int down[2]; // key nums holding it down
int state; // low bit is down state
} kbutton_t;
STATIC_CHECK_SIZEOF( kbutton_t, 12, 12 );
#endif // KBUTTON_H

View File

@@ -16,8 +16,6 @@ GNU General Public License for more details.
#ifndef LIGHTSTYLE_H
#define LIGHTSTYLE_H
#include "xash3d_types.h"
typedef struct
{
char pattern[256];

95
common/mathlib.h Normal file
View File

@@ -0,0 +1,95 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
// mathlib.h
#include <math.h>
typedef float vec_t;
typedef vec_t vec2_t[2];
typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4]; // x,y,z,w
#ifndef M_PI
#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
#endif
struct mplane_s;
extern vec3_t vec3_origin;
extern int nanmask;
#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
#ifndef VECTOR_H
#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
#endif
#define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];}
#define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];}
#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];}
#define VectorClear(a) {(a)[0]=0.0;(a)[1]=0.0;(a)[2]=0.0;}
void VectorMA (const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc);
vec_t _DotProduct (vec3_t v1, vec3_t v2);
void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out);
void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out);
void _VectorCopy (vec3_t in, vec3_t out);
int VectorCompare (const vec3_t v1, const vec3_t v2);
float Length (const vec3_t v);
void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross);
float VectorNormalize (vec3_t v); // returns vector length
void VectorInverse (vec3_t v);
void VectorScale (const vec3_t in, vec_t scale, vec3_t out);
void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);
void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]);
void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
void AngleVectorsTranspose (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
#define AngleIVectors AngleVectorsTranspose
void AngleMatrix (const vec3_t angles, float (*matrix)[4] );
void AngleIMatrix (const vec3_t angles, float (*matrix)[4] );
void VectorTransform (const vec3_t in1, float in2[3][4], vec3_t out);
void NormalizeAngles( vec3_t angles );
void InterpolateAngles( vec3_t start, vec3_t end, vec3_t output, float frac );
float AngleBetweenVectors( const vec3_t v1, const vec3_t v2 );
void VectorMatrix( vec3_t forward, vec3_t right, vec3_t up);
void VectorAngles( const vec3_t forward, vec3_t angles );
int InvertMatrix( const float * m, float *out );
int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct mplane_s *plane);
float anglemod(float a);
#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \
(((p)->type < 3)? \
( \
((p)->dist <= (emins)[(p)->type])? \
1 \
: \
( \
((p)->dist >= (emaxs)[(p)->type])?\
2 \
: \
3 \
) \
) \
: \
BoxOnPlaneSide( (emins), (emaxs), (p)))

View File

@@ -27,7 +27,7 @@
// Set this flag for things like broadcast requests, etc. where the engine should not
// kill the request hook after receiving the first response
#define FNETAPI_MULTIPLE_RESPONSE ( 1<<0 )
// 1<<1 is reserved for deprecated xash3d-fwgs extension
#define FNETAPI_LEGACY_PROTOCOL ( 1<<1 ) // xash3d-fwgs extension
struct net_response_s;
typedef void (*net_api_response_func_t) ( struct net_response_s *response );

View File

@@ -21,7 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef NET_ADR_H
#define NET_ADR_H
#include <stdint.h>
#include STDINT_H
// net.h -- quake's interface to the networking layer
// a1ba: copied from Quake-2/qcommon/qcommon.h and modified to support IPv6

53
common/particledef.h Normal file
View File

@@ -0,0 +1,53 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef PARTICLEDEF_H
#define PARTICLEDEF_H
typedef enum
{
pt_static,
pt_grav,
pt_slowgrav,
pt_fire,
pt_explode,
pt_explode2,
pt_blob,
pt_blob2,
pt_vox_slowgrav,
pt_vox_grav,
pt_clientcustom // Must have callback function specified
} ptype_t;
typedef struct particle_s
{
vec3_t org;
short color;
short packedColor;
struct particle_s *next;
vec3_t vel;
float ramp;
float die;
ptype_t type;
void (*deathfunc)( struct particle_s *particle );
// for pt_clientcusttom, we'll call this function each frame
void (*callback)( struct particle_s *particle, float frametime );
// For deathfunc, etc.
unsigned char context;
} particle_t;
#endif//PARTICLEDEF_H

View File

@@ -1,86 +0,0 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef QW_PMOVE_H
#define QW_PMOVE_H
// a1ba: from QW's client/pmove.h
// and modified to keep binary compatibility with
// goldsrc base structs and xash extensions
typedef struct pmplane_s
{
vec3_t normal;
float dist;
} pmplane_t;
STATIC_CHECK_SIZEOF( pmplane_t, 16, 16 );
typedef struct pmtrace_s
{
qboolean allsolid; // if true, plane is not valid
qboolean startsolid; // if true, the initial point was in a solid area
qboolean inopen, inwater;
float fraction; // time completed, 1.0 = didn't hit anything
vec3_t endpos; // final position
pmplane_t plane; // surface normal at impact
int ent; // entity the surface is on
vec3_t deltavelocity;
int hitgroup;
} pmtrace_t;
STATIC_CHECK_SIZEOF( pmtrace_t, 68, 68 );
typedef struct movevars_s
{
float gravity;
float stopspeed;
float maxspeed;
float spectatormaxspeed;
float accelerate;
float airaccelerate;
float wateraccelerate;
float friction;
float edgefriction; // goldsrc binary compat
float waterfriction;
float entgravity;
// goldsrc additions
float bounce;
float stepsize;
float maxvelocity;
float zmax;
float waveHeight;
qboolean footsteps;
char skyName[32];
float rollangle;
float rollspeed;
vec3_t skycolor;
vec3_t skyvec;
// xash extensions
int features;
int fog_settings;
float wateralpha;
vec3_t skydir; // unused
float skyangle; // unused
} movevars_t;
STATIC_CHECK_SIZEOF( movevars_t, 160, 160 );
#endif // QW_PMOVE_H

41
common/pmtrace.h Normal file
View File

@@ -0,0 +1,41 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef PM_TRACE_H
#define PM_TRACE_H
typedef struct
{
vec3_t normal;
float dist;
} pmplane_t;
typedef struct pmtrace_s pmtrace_t;
struct pmtrace_s
{
qboolean allsolid; // if true, plane is not valid
qboolean startsolid; // if true, the initial point was in a solid area
qboolean inopen, inwater; // End point is in empty space or in water
float fraction; // time completed, 1.0 = didn't hit anything
vec3_t endpos; // final position
pmplane_t plane; // surface normal at impact
int ent; // entity at impact
vec3_t deltavelocity; // Change in player's velocity caused by impact.
// Only run on server.
int hitgroup;
};
#endif//PM_TRACE_H

View File

@@ -17,54 +17,76 @@ GNU General Public License for more details.
#ifndef PORT_H
#define PORT_H
#include "build.h"
#if !XASH_WIN32
#if XASH_APPLE
#include <sys/syslimits.h>
#define OS_LIB_EXT "dylib"
#define OPEN_COMMAND "open"
#elif XASH_EMSCRIPTEN
#define OS_LIB_EXT "wasm"
#define OPEN_COMMAND "???"
#else
#define OS_LIB_EXT "so"
#define OPEN_COMMAND "xdg-open"
#endif
#define OS_LIB_PREFIX "lib"
#define VGUI_SUPPORT_DLL "libvgui_support." OS_LIB_EXT
// Windows-specific
#define __cdecl
#define __stdcall
#define _inline static inline
#if XASH_POSIX
#include <unistd.h>
#if XASH_NSWITCH
#define SOLDER_LIBDL_COMPAT
#include <solder.h>
#elif XASH_PSVITA
#define VRTLD_LIBDL_COMPAT
#include <vrtld.h>
#define O_BINARY 0
#else
#include <dlfcn.h>
#define HAVE_DUP
#define O_BINARY 0
#endif
#define O_TEXT 0
#define _mkdir( x ) mkdir( x, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH )
#endif
typedef void* HANDLE;
typedef void* HINSTANCE;
typedef struct tagPOINT
{
int x, y;
} POINT;
#else // WIN32
#define open _open
#define read _read
#define alloca _alloca
#define HSPRITE WINAPI_HSPRITE
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <windows.h>
#undef HSPRITE
#define OS_LIB_PREFIX ""
#define OS_LIB_EXT "dll"
#define VGUI_SUPPORT_DLL "../vgui_support." OS_LIB_EXT
#define HAVE_DUP
#endif //WIN32
#ifndef XASH_LOW_MEMORY
#define XASH_LOW_MEMORY 0
#endif
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "build.h"
#if XASH_POSIX
#include <unistd.h>
#define OS_LIB_PREFIX "lib"
#endif
#if XASH_APPLE
#include <sys/syslimits.h>
#define OS_LIB_EXT "dylib"
#define OPEN_COMMAND "open"
#elif XASH_POSIX
#define OS_LIB_EXT "so"
#define OPEN_COMMAND "xdg-open"
#elif XASH_WIN32
#define HSPRITE WINAPI_HSPRITE
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#ifndef NOMINMAX
#define NOMINMAX
#endif // NOMINMAX
#include <windows.h>
#undef HSPRITE
#define open _open
#define read _read
#ifndef alloca
#define alloca _alloca
#endif // alloca
#define OS_LIB_PREFIX ""
#define OS_LIB_EXT "dll"
#define OPEN_COMMAND "open"
#elif XASH_PSP
#define OS_LIB_EXT "prx"
#endif
#if !XASH_WIN32
typedef void *HINSTANCE;
typedef struct tagPOINT { int x, y; } POINT; // one nasty function in cdll_int.h needs it
#endif // !XASH_WIN32
#ifndef XASH_LOW_MEMORY
#define XASH_LOW_MEMORY 0
#endif
#endif // PORT_H

View File

@@ -1,118 +0,0 @@
/*
Copyright (C) 1997-2001 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// client.h -- primary header for client
#ifndef QUAKE_CLIENT_H
#define QUAKE_CLIENT_H
#include <stdint.h>
#include "xash3d_types.h"
// Definitions originally taken from Quake, modified for binary compatibility
typedef struct usercmd_s
{
int16_t lerp_msec; // added in HL
int8_t msec; // added in QW
uint8_t pad1;
vec3_t viewangles;
// intended velocities
float forwardmove;
float sidemove;
float upmove;
uint8_t lightlevel;
uint8_t pad2;
uint16_t buttons; // added in QW
uint8_t impulse;
// added in HL
uint8_t weaponselect;
uint8_t pad3[2];
// unused HL impact stuff, left for modders
// TODO: document how to use them in delta encoding
int32_t reserved[4];
} usercmd_t;
STATIC_CHECK_SIZEOF( usercmd_t, 52, 52 );
typedef struct dlight_s
{
vec3_t origin;
float radius;
struct
{
uint8_t r, g, b;
} color;
float die; // stop lighting after this time
float decay; // drop this each second
float minlight; // don't add when contributing less
int key; // so entities can reuse same entry
qboolean dark; // subtracts light instead of adding
} dlight_t;
STATIC_CHECK_SIZEOF( dlight_t, 40, 40 );
//
// cl_input
//
typedef struct
{
int down[2]; // key nums holding it down
int state; // low bit is down state
} kbutton_t;
STATIC_CHECK_SIZEOF( kbutton_t, 12, 12 );
typedef enum {
// Quake defined types
pt_static, pt_grav, pt_slowgrav, pt_fire, pt_explode, pt_explode2, pt_blob, pt_blob2,
// added in HL
pt_4x_slowgrav, // 4 times faster than pt_slowgrav
pt_8x_slowgrav, // 8 times faster than pt_slowgrav
pt_custom, // will call think function from particle
} ptype_t;
// !!! if this is changed, it must be changed in d_ifacea.h too !!!
typedef struct particle_s
{
// driver-usable fields
vec3_t org;
short color; // in HL color is defnied by palette
short unused; // not used in hw
// drivers never touch the following fields
struct particle_s *next;
vec3_t vel;
float ramp;
float die;
ptype_t type;
// HL added fields
void (*on_die)( struct particle_s *p );
void (*think)( struct particle_s *p, float frametime );
unsigned char userdata;
} particle_t;
STATIC_CHECK_SIZEOF( particle_t, 56, 72 );
#endif // QUAKE_CLIENT_H

View File

@@ -16,13 +16,23 @@
#ifndef R_EFX_H
#define R_EFX_H
// particle_t
#if !defined( PARTICLEDEFH )
#include "particledef.h"
#endif
// BEAM
#if !defined( BEAMDEF_H )
#if !defined( BEAMDEFH )
#include "beamdef.h"
#endif
// dlight_t
#if !defined ( DLIGHTH )
#include "dlight.h"
#endif
// cl_entity_t
#if !defined( CL_ENTITY_H )
#if !defined( CL_ENTITYH )
#include "cl_entity.h"
#endif
@@ -104,9 +114,7 @@ typedef struct tempent_s
// baseline.angles - angle velocity
} TEMPENTITY;
typedef struct particle_s particle_t;
typedef struct efx_api_s efx_api_t;
struct dlight_s;
struct efx_api_s
{
@@ -174,8 +182,8 @@ struct efx_api_s
BEAM *(*R_BeamLightning)( float *start, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed );
BEAM *(*R_BeamPoints)( float *start, float *end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b );
BEAM *(*R_BeamRing)( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b );
struct dlight_s *(*CL_AllocDlight)( int key );
struct dlight_s *(*CL_AllocElight)( int key );
dlight_t *(*CL_AllocDlight)( int key );
dlight_t *(*CL_AllocElight)( int key );
TEMPENTITY *(*CL_TempEntAlloc)( const float *org, struct model_s *model );
TEMPENTITY *(*CL_TempEntAllocNoModel)( const float *org );
TEMPENTITY *(*CL_TempEntAllocHigh)( const float *org, struct model_s *model );

View File

@@ -16,8 +16,6 @@
#ifndef REF_PARAMS_H
#define REF_PARAMS_H
#include "xash3d_types.h"
typedef struct ref_params_s
{
// output

View File

@@ -16,8 +16,8 @@ GNU General Public License for more details.
#ifndef RENDER_API_H
#define RENDER_API_H
#include <stdint.h>
#include "lightstyle.h"
#include "dlight.h"
#define CL_RENDER_INTERFACE_VERSION 37 // Xash3D 1.0
#define MAX_STUDIO_DECALS 4096 // + unused space of BSP decals
@@ -101,7 +101,7 @@ typedef enum
TF_TEXTURE_3D = (1<<20), // this is GL_TEXTURE_3D
TF_ATLAS_PAGE = (1<<21), // bit who indicate lightmap page or deluxemap page
TF_ALPHACONTRAST = (1<<22), // special texture mode for A2C
TF_PREMULTIPLIED = (1<<23), // RGBA was stored premultiplied (HL gradient / indexalpha)
// reserved
// reserved
TF_IMG_UPLOADED = (1<<25), // this is set for first time when called glTexImage, otherwise it will be call glTexSubImage
TF_ARB_FLOAT = (1<<26), // float textures
@@ -175,7 +175,6 @@ enum movie_parms_e
struct movie_state_s;
struct ref_viewpass_s;
struct dlight_s;
typedef struct render_api_s
{
@@ -184,8 +183,8 @@ typedef struct render_api_s
void (*GetDetailScaleForTexture)( int texture, float *xScale, float *yScale );
void (*GetExtraParmsForTexture)( int texture, byte *red, byte *green, byte *blue, byte *alpha );
lightstyle_t* (*GetLightStyle)( int number );
struct dlight_s* (*GetDynamicLight)( int number );
struct dlight_s* (*GetEntityLight)( int number );
dlight_t* (*GetDynamicLight)( int number );
dlight_t* (*GetEntityLight)( int number );
byte (*LightToTexGamma)( byte color ); // software gamma support
float (*GetFrameTime)( void );

View File

@@ -1,196 +0,0 @@
/*
sound_api.h - Xash3D extension for client sound interface
Copyright (C) 2026 Xash3D FWGS Developers
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
*/
#ifndef SOUND_API_H
#define SOUND_API_H
#include "xash3d_types.h"
// Experimental implementation, backward compatibility is not guaranteed.
#define CL_SOUND_INTERFACE_VERSION 1
#define FL_VOXWORD_IN_CACHE BIT( 0 ) // if set, it was loaded prior and shouldn't be freed
#define FL_CHAN_USE_LOOP BIT( 0 ) // don't loop default and local sounds
#define FL_CHAN_STATIC_SOUND BIT( 1 ) // use origin instead of fetching entnum's origin
#define FL_CHAN_LOCAL_SOUND BIT( 2 ) // it's a local menu sound (not looped, not paused)
#define FL_CHAN_SENTENCE_FINISHED BIT( 4 ) // if set, finished playing sentence
#define FL_CHAN_FINISHED BIT( 5 ) // if set, finished playing single word
typedef int sound_t;
typedef struct portable_samplepair_s
{
int left;
int right;
} portable_samplepair_t;
typedef struct sfx_s
{
char name[MAX_QPATH];
wavdata_t *cache;
int servercount;
uint hashValue;
struct sfx_s *hashNext;
} sfx_t;
typedef struct voxword_s
{
sfx_t *sfx;
uint16_t volume; // volume percent
uint16_t pitch; // pitch shift percent (keep large for extra chipmunk fun)
uint8_t timecompress; // percent of skipped data (speeds up playback without pitch shift)
uint8_t start; // percent at which playback starts
uint8_t end; // percent at which playback ends
uint8_t flags;
} voxword_t;
typedef struct channel_s
{
char name[16]; // keep sentence name
sfx_t *sfx; // sfx number
vec3_t origin; // only use if fixed_origin is set
float dist_mult; // distance multiplier (attenuation/clipK)
int entchannel; // sound channel (CHAN_STREAM, CHAN_VOICE, etc.)
uint flags;
short entnum; // entity soundsource
short master_vol; // 0-255 master volume
short leftvol; // 0-255 left volume
short rightvol; // 0-255 right volume
short basePitch; // base pitch percent (100% is normal pitch playback)
byte word_index;
// HACKHACK: count when this channel became inaudible
// to not free it when it could be respatialized soon
#define MAX_CHANNEL_INAUDIBLE_TIME 0.1f
float inauduble_free_time;
double sample;
double forced_end;
wavdata_t *data;
voxword_t *words; // dynamically allocated, (num_words + 1) entries, null sfx terminates
uintptr_t engine_reserved[8]; // only for engine developers
uintptr_t game_reserved[8]; // free space for game developers
} channel_t;
typedef struct rawchan_s
{
short entnum;
short master_vol;
short leftvol; // 0-255 left volume
short rightvol; // 0-255 right volume
float dist_mult; // distance multiplier (attenuation/clipK)
vec3_t origin; // only use if fixed_origin is set
volatile uint s_rawend;
float oldtime; // catch time jumps
uintptr_t engine_reserved[8]; // only for engine developers
uintptr_t game_reserved[8]; // free space for game developers
size_t max_samples; // buffer length
portable_samplepair_t rawsamples[]; // variable sized
} rawchan_t;
typedef struct snd_format_s
{
uint speed;
byte width;
byte channels;
} snd_format_t;
typedef struct snd_globals_s
{
// dma
const char *backend_name;
byte *buffer;
snd_format_t format;
qboolean initialized; // sound engine is active
int samples; // mono samples in buffer
int samplepos; // in mono samples
int paintedtime; // total samples that have been mixed at speed
int soundtime; // total samples that have been played out to hardware at dma speed
// listener (client, camera, etc)
vec3_t origin;
vec3_t forward, right, up;
int entnum;
qboolean streaming; // playing AVI-file
qboolean stream_paused; // pause only background track
// SoundAPI shared pointers
channel_t *const channels;
int max_channels;
int total_channels;
rawchan_t **const raw_channels;
int max_raw_channels;
sound_t ambient_sfx[NUM_AMBIENTS];
qboolean have_ambient_sfx;
} snd_globals_t;
typedef struct voice_audio_info_s
{
uint width;
uint samplerate;
uint frame_size; // in samples
} voice_audio_info_t;
// API from engine to client (client calls these)
typedef struct sound_api_s
{
qboolean (*CL_GetEntitySpatialization)( channel_t *ch );
sfx_t* (*S_GetSfxByHandle)( sound_t handle );
// Voice extensions
void (*pfnS_RawEntSamples)( int entnum, uint samples, uint rate, word width, word channels, const byte *data, int snd_vol, float attn );
void (*pfnSND_ForceInitMouth)( int entnum );
voice_audio_info_t (*pfnVoice_GetAudioInfo)( void );
} sound_api_t;
// Callbacks from client to engine (engine calls these when custom sound is active)
typedef struct sound_interface_s
{
int version;
qboolean (*pfnS_Init)( snd_globals_t *globals );
void (*pfnS_Shutdown)( void );
void (*pfnS_UpdateSound)( void );
/* Full paint: endtime (sample pairs), dma buffer, paintedtime in/out. Client does mix + transfer to dma.buffer. */
void (*pfnS_PaintChannels)( int endtime );
void (*pfnS_UpdateChannel)( int ch_idx, const channel_t *ch, sound_t handle ); // ch=NULL -> channel freed
void (*pfnS_UpdateRawChannel)( int raw_idx, rawchan_t *ch ); // ch=NULL -> channel freed
void (*pfnS_Spatialize)( channel_t *ch );
void (*pfnS_FreeSound)( sfx_t *sfx, sound_t handle );
} sound_interface_t;
#endif // SOUND_API_H

39
common/usercmd.h Normal file
View File

@@ -0,0 +1,39 @@
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#ifndef USERCMD_H
#define USERCMD_H
typedef struct usercmd_s
{
short lerp_msec; // Interpolation time on client
byte msec; // Duration in ms of command
vec3_t viewangles; // Command view angles
// intended velocities
float forwardmove; // Forward velocity
float sidemove; // Sideways velocity
float upmove; // Upward velocity
byte lightlevel; // Light level at spot where we are standing.
unsigned short buttons; // Attack and move buttons
byte impulse; // Impulse command issued
byte weaponselect; // Current weapon id
// Experimental player impact stuff.
int impact_index;
vec3_t impact_position;
} usercmd_t;
#endif//USERCMD_H

View File

@@ -2,28 +2,23 @@
#ifndef XASH_TYPES_H
#define XASH_TYPES_H
#include <wchar.h> // off_t
#include <sys/types.h> // off_t
#include <stdint.h>
#include <assert.h>
#include "build.h"
#include "port.h"
#define MAX_STRING 256 // generic string
#define MAX_VA_STRING 1024 // compatibility macro
#define MAX_SYSPATH 1024 // system filepath
#define MAX_OSPATH 260 // max length of a filesystem pathname
#define CS_SIZE 64 // size of one config string
#define CS_TIME 16 // size of time string
// platform-specific alignment for types, to not break ABI
#if XASH_PSP
#define MAYBE_ALIGNED( x ) __attribute__(( aligned( 16 )))
#if XASH_IRIX
#include <port.h>
#endif
#if !defined( MAYBE_ALIGNED )
#define MAYBE_ALIGNED( x )
#endif // !defined( MAYBE_ALIGNED )
#if XASH_WIN32
#include <wchar.h> // off_t
#endif // _WIN32
#include <sys/types.h> // off_t
#ifdef STDINT_H
#include STDINT_H
#else // !STDINT_H
#include <stdint.h>
#endif // !STDINT_H
#include <assert.h>
typedef uint8_t byte;
typedef float vec_t;
@@ -31,30 +26,13 @@ typedef vec_t vec2_t[2];
#ifndef vec3_t // SDK renames it to Vector
typedef vec_t vec3_t[3];
#endif
typedef vec_t vec4_t[4] MAYBE_ALIGNED( 16 );
typedef vec_t quat_t[4] MAYBE_ALIGNED( 16 );
typedef byte rgba_t[4]; // unsigned byte colorpack
typedef byte rgb_t[3]; // unsigned byte colorpack
typedef vec_t matrix3x4[3][4] MAYBE_ALIGNED( 16 );
typedef vec_t matrix4x4[4][4] MAYBE_ALIGNED( 16 );
typedef vec_t vec4_t[4];
typedef vec_t quat_t[4];
typedef byte rgba_t[4]; // unsigned byte colorpack
typedef byte rgb_t[3]; // unsigned byte colorpack
typedef vec_t matrix3x4[3][4];
typedef vec_t matrix4x4[4][4];
typedef uint32_t poolhandle_t;
typedef uint16_t word;
typedef uint32_t dword;
typedef char string[MAX_STRING];
typedef off_t fs_offset_t;
#if XASH_WIN32
typedef int fs_size_t; // return type of _read, _write funcs
#else // !XASH_WIN32
typedef ssize_t fs_size_t;
#endif // !XASH_WIN32
typedef unsigned int uint;
typedef void *(*pfnCreateInterface_t)( const char *, int * );
// Quake definition
typedef struct link_s
{
struct link_s *prev, *next;
} link_t;
#undef true
#undef false
@@ -65,77 +43,95 @@ enum { false, true };
#endif
typedef int qboolean;
#if XASH_LOW_MEMORY == 1 || XASH_PSP
#define MAX_QPATH 48
#define MAX_MODS 16
#elif XASH_LOW_MEMORY == 2
#define MAX_QPATH 32 // should be enough for singleplayer
#define MAX_MODS 4
#else // !XASH_LOW_MEMORY
#define MAX_QPATH 64
#define MAX_MODS 512
#endif // !XASH_LOW_MEMORY
#define MAX_STRING 256 // generic string
#define MAX_VA_STRING 1024 // compatibility macro
#define MAX_SYSPATH 1024 // system filepath
#define MAX_MODS 512 // environment games that engine can keep visible
#define BIT( n ) ( 1U << ( n ))
#define BIT64( n ) ( 1ULL << ( n ))
#define BIT( n ) ( 1U << ( n ))
#define BIT64( n ) ( 1ULL << ( n ))
#define SetBits( bit_vector, bits ) (( bit_vector ) |= ( bits ))
#define ClearBits( bit_vector, bits ) (( bit_vector ) &= ~( bits ))
#define FBitSet( bit_vector, bits ) (( bit_vector ) & ( bits ))
#define SetBits( iBitVector, bits ) ((iBitVector) = (iBitVector) | (bits))
#define ClearBits( iBitVector, bits ) ((iBitVector) = (iBitVector) & ~(bits))
#define FBitSet( iBitVector, bit ) ((iBitVector) & (bit))
#ifndef __cplusplus
#ifdef NULL
#undef NULL
#endif
#define NULL ((void *)0)
#endif
// color strings
#define IsColorString( p ) (( p ) && *( p ) == '^' && *(( p ) + 1) && *(( p ) + 1) >= '0' && *(( p ) + 1 ) <= '9' )
#define ColorIndex( c ) ((( c ) - '0' ) & 7 )
#define IsColorString( p ) ( p && *( p ) == '^' && *(( p ) + 1) && *(( p ) + 1) >= '0' && *(( p ) + 1 ) <= '9' )
#define ColorIndex( c ) ((( c ) - '0' ) & 7 )
#undef EXPORT
#if defined( __GNUC__ )
#if defined( __i386__ )
#define EXPORT __attribute__(( visibility( "default" ), force_align_arg_pointer ))
#define GAME_EXPORT __attribute__(( force_align_arg_pointer ))
#else // !defined( __i386__ )
#define EXPORT __attribute__(( visibility ( "default" )))
#endif // !defined( __i386__ )
#else
#define EXPORT __attribute__(( visibility ( "default" )))
#define GAME_EXPORT
#endif
#define MALLOC __attribute__(( malloc ))
// added in GCC 11
#if __GNUC__ >= 11
// might want to set noclone due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116893
// but it's easier to not force mismatched-dealloc to error yet
#define MALLOC_LIKE( x, y ) __attribute__(( malloc( x, y )))
#else
#define MALLOC_LIKE( x, y ) __attribute__(( malloc ))
#endif
#define RETURNS_NONNULL __attribute__(( returns_nonnull ))
#if !__clang__ && !__MCST__
// clang has bugged returns_nonnull for functions pointers, it's ignored and generates a warning about objective-c? O_o
// lcc doesn't support it at all
#define PFN_RETURNS_NONNULL RETURNS_NONNULL
#define MALLOC_LIKE( x, y ) MALLOC
#endif
#define NORETURN __attribute__(( noreturn ))
#define NONNULL __attribute__(( nonnull ))
#define RETURNS_NONNULL __attribute__(( returns_nonnull ))
#if __clang__ || __MCST__
// clang has bugged returns_nonnull for functions pointers, it's ignored and generates a warning about objective-c? O_o
// lcc doesn't support it at all
#define PFN_RETURNS_NONNULL
#else
#define PFN_RETURNS_NONNULL RETURNS_NONNULL
#endif
#define FORMAT_CHECK( x ) __attribute__(( format( printf, x, x + 1 )))
#define ALLOC_CHECK( x ) __attribute__(( alloc_size( x )))
#define NO_ASAN __attribute__(( no_sanitize( "address" )))
#define WARN_UNUSED_RESULT __attribute__(( warn_unused_result ))
#define RENAME_SYMBOL( x ) asm( x )
#if !defined( offsetof )
#define offsetof( s, m ) __builtin_offsetof( s, m )
#endif // !defined( offsetof )
#elif defined( _MSC_VER )
#define EXPORT __declspec( dllexport )
#else
#if defined( _MSC_VER )
#define EXPORT __declspec( dllexport )
#define NO_ASAN __declspec( no_sanitize_address )
#else
#define EXPORT
#define NO_ASAN
#endif
#define GAME_EXPORT
#define NORETURN
#define NONNULL
#define RETURNS_NONNULL
#define PFN_RETURNS_NONNULL
#define FORMAT_CHECK( x )
#define ALLOC_CHECK( x )
#define RENAME_SYMBOL( x )
#define MALLOC
#define MALLOC_LIKE( x, y )
#define WARN_UNUSED_RESULT
#endif
#ifdef ARRAYSIZE
#undef ARRAYSIZE
#endif // ARRAYSIZE
#if defined( __has_feature )
#if __has_feature( address_sanitizer )
#define USE_ASAN 1
#endif // __has_feature
#endif // defined( __has_feature )
#define ARRAYSIZE( p ) ( sizeof(( p ))/ sizeof(( p )[0] ))
#if defined( __SANITIZE_ADDRESS__ )
#define USE_ASAN 1
#if defined( __GNUC__ )
#define NO_ASAN __attribute__(( no_sanitize( "address" )))
#elif defined( _MSC_VER )
#define NO_ASAN __declspec( no_sanitize_address )
#endif
#if !defined( USE_ASAN ) && defined( __SANITIZE_ADDRESS__ )
#define USE_ASAN 1
#endif
#if __GNUC__ >= 3
@@ -148,73 +144,11 @@ typedef int qboolean;
#endif
#endif
#if !defined( __cplusplus ) && __STDC_VERSION__ >= 199101L // not C++ and C99 or newer
#define XASH_RESTRICT restrict
#elif _MSC_VER || __GNUC__ || __clang__ // compiler-specific extensions
#define XASH_RESTRICT __restrict
#endif
#if !defined( EXPORT )
#define EXPORT
#endif // !defined( EXPORT )
#if !defined( GAME_EXPORT )
#define GAME_EXPORT
#endif // !defined( GAME_EXPORT )
#if !defined( MALLOC_LIKE )
#define MALLOC_LIKE( x, y )
#endif // !defined MALLOC_LIKE
#if !defined( NO_ASAN )
#define NO_ASAN
#endif // !defined( NO_ASAN )
#if !defined( RETURNS_NONNULL )
#define RETURNS_NONNULL
#endif // !defined( RETURNS_NONNULL )
#if !defined( PFN_RETURNS_NONNULL )
#define PFN_RETURNS_NONNULL
#endif // !defined( PFN_RETURNS_NONNULL )
#if !defined( NORETURN )
#define NORETURN
#endif // !defined( NORETURN )
#if !defined( NONNULL )
#define NONNULL
#endif // !defined( NONNULL )
#if !defined( FORMAT_CHECK )
#define FORMAT_CHECK( x )
#endif // !defined( FORMAT_CHECK )
#if !defined( ALLOC_CHECK )
#define ALLOC_CHECK( x )
#endif // !defined( ALLOC_CHECK )
#if !defined( WARN_UNUSED_RESULT )
#define WARN_UNUSED_RESULT
#endif // !defined( WARN_UNUSED_RESULT )
#if !defined( RENAME_SYMBOL )
#define RENAME_SYMBOL( x )
#endif // !defined( RENAME_SYMBOL )
#if !defined( unlikely ) || !defined( likely )
#define unlikely( x ) ( x )
#define likely( x ) ( x )
#endif // !defined( unlikely ) || !defined( likely )
#if !defined( XASH_RESTRICT )
#define XASH_RESTRICT
#endif
#if !defined( offsetof )
#define offsetof( s, m ) (size_t)&(((s *)0)->m )
#endif // !defined( offsetof )
#if __STDC_VERSION__ >= 202311L || __cplusplus >= 201103L // C23 or C++ static_assert is a keyword
#define STATIC_ASSERT_( ignore, x, y ) static_assert( x, y )
#define STATIC_ASSERT static_assert
@@ -231,41 +165,75 @@ typedef int qboolean;
// at least, statically check size of some public structures
#if XASH_64BIT
#define STATIC_CHECK_SIZEOF( type, size32, size64 ) \
STATIC_ASSERT( sizeof( type ) == size64, #type " unexpected size" )
#define STATIC_CHECK_SIZEOF( type, size32, size64 ) \
STATIC_ASSERT( sizeof( type ) == size64, #type " unexpected size" )
#else
#define STATIC_CHECK_SIZEOF( type, size32, size64 ) \
STATIC_ASSERT( sizeof( type ) == size32, #type " unexpected size" )
#define STATIC_CHECK_SIZEOF( type, size32, size64 ) \
STATIC_ASSERT( sizeof( type ) == size32, #type " unexpected size" )
#endif
#define Swap32( x ) (((uint32_t)((( x ) & 255 ) << 24 )) + ((uint32_t)(((( x ) >> 8 ) & 255 ) << 16 )) + ((uint32_t)((( x ) >> 16 ) & 255 ) << 8 ) + ((( x ) >> 24 ) & 255 ))
#define Swap16( x ) ((uint16_t)((((uint16_t)( x ) >> 8 ) & 255 ) + (((uint16_t)( x ) & 255 ) << 8 )))
#define Swap32Store( x ) ( x = Swap32( x ))
#define Swap16Store( x ) ( x = Swap16( x ))
#define LittleFourCC( a, b, c, d ) (((uint32_t)( d ) << 24 ) | ((uint32_t)( c ) << 16 ) | ((uint32_t)( b ) << 8 ) | (uint32_t)( a ))
#define BigFourCC( a, b, c, d ) (((uint32_t)( a ) << 24 ) | ((uint32_t)( b ) << 16 ) | ((uint32_t)( c ) << 8 ) | (uint32_t)( d ))
#if XASH_BIG_ENDIAN
#define LittleLong( x ) Swap32( x )
#define LittleShort( x ) Swap16( x )
#define LittleLongSW( x ) Swap32Store( x )
#define LittleShortSW( x ) Swap16Store( x )
#define LittleFloat( x ) SwapFloat( x )
#define BigLong( x ) ( x )
#define BigShort( x ) ( x )
#define BigFloat( x ) ( x )
#define HostFourCC( a, b, c, d ) BigFourCC( a, b, c, d )
#if !defined( __cplusplus ) && __STDC_VERSION__ >= 199101L // not C++ and C99 or newer
#define XASH_RESTRICT restrict
#elif _MSC_VER || __GNUC__ || __clang__ // compiler-specific extensions
#define XASH_RESTRICT __restrict
#else
#define LittleLong( x ) ( x )
#define LittleShort( x ) ( x )
#define LittleFloat( x ) ( x )
#define LittleLongSW( x )
#define LittleShortSW( x )
#define BigLong( x ) Swap32( x )
#define BigShort( x ) Swap16( x )
#define BigFloat( x ) SwapFloat( x )
#define HostFourCC( a, b, c, d ) LittleFourCC( a, b, c, d )
#define XASH_RESTRICT // nothing
#endif
#ifdef XASH_BIG_ENDIAN
#define LittleLong(x) (((int)(((x)&255)<<24)) + ((int)((((x)>>8)&255)<<16)) + ((int)(((x)>>16)&255)<<8) + (((x) >> 24)&255))
#define LittleLongSW(x) (x = LittleLong(x) )
#define LittleShort(x) ((short)( (((short)(x) >> 8) & 255) + (((short)(x) & 255) << 8)))
#define LittleShortSW(x) (x = LittleShort(x) )
_inline float LittleFloat( float f )
{
union
{
float f;
unsigned char b[4];
} dat1, dat2;
dat1.f = f;
dat2.b[0] = dat1.b[3];
dat2.b[1] = dat1.b[2];
dat2.b[2] = dat1.b[1];
dat2.b[3] = dat1.b[0];
return dat2.f;
}
#else
#define LittleLong(x) (x)
#define LittleLongSW(x)
#define LittleShort(x) (x)
#define LittleShortSW(x)
#define LittleFloat(x) (x)
#endif
typedef unsigned int dword;
typedef unsigned int uint;
typedef char string[MAX_STRING];
typedef off_t fs_offset_t;
#if XASH_WIN32
typedef int fs_size_t; // return type of _read, _write funcs
#else /* !XASH_WIN32 */
typedef ssize_t fs_size_t;
#endif /* !XASH_WIN32 */
typedef void *(*pfnCreateInterface_t)( const char *, int * );
// config strings are a general means of communication from
// the server to all connected clients.
// each config string can be at most CS_SIZE characters.
#if XASH_LOW_MEMORY == 0
#define MAX_QPATH 64 // max length of a game pathname
#elif XASH_LOW_MEMORY == 2
#define MAX_QPATH 32 // should be enough for singleplayer
#elif XASH_LOW_MEMORY == 1
#define MAX_QPATH 48
#endif
#define MAX_OSPATH 260 // max length of a filesystem pathname
#define CS_SIZE 64 // size of one config string
#define CS_TIME 16 // size of time string
#endif // XASH_TYPES_H

View File

@@ -17,10 +17,8 @@
#define ALIAS_H
#include "build.h"
#include <stdint.h>
#include STDINT_H
#include "synctype.h"
#include "xash3d_types.h"
#include "com_model.h"
/*
==============================================================================

View File

@@ -23,12 +23,6 @@ struct mstudioevent_s;
struct engine_studio_api_s;
struct r_studio_interface_s;
struct sound_api_s;
struct sound_interface_s;
typedef struct sound_api_s sound_api_t;
typedef struct sound_interface_s sound_interface_t;
// NOTE: ordering is important!
typedef struct cldll_func_s
{
@@ -80,9 +74,6 @@ typedef struct cldll_func_s
int (*pfnTouchEvent)( int type, int fingerID, float x, float y, float dx, float dy );
void (*pfnMoveEvent)( float forwardmove, float sidemove );
void (*pfnLookEvent)( float relyaw, float relpitch );
// Sound API
int (*pfnGetSoundInterface)( int version, const sound_api_t *api, sound_interface_t *callback );
int (*pfnVoice_StartChannel)( int samples, byte *data, int entnum );
} cldll_func_t;
#endif//CDLL_EXP_H

View File

@@ -25,6 +25,7 @@ qboolean AVI_GetVideoInfo( movie_state_t *Avi, int *xres, int *yres, float *dura
qboolean AVI_HaveAudioTrack( const movie_state_t *Avi );
void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, int quiet );
movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio );
int AVI_TimeToSoundPosition( movie_state_t *Avi, int time );
void AVI_CloseVideo( movie_state_t *Avi );
qboolean AVI_IsActive( movie_state_t *Avi );
void AVI_FreeVideo( movie_state_t *Avi );

View File

@@ -23,6 +23,7 @@ static qboolean avi_initialized;
static poolhandle_t avi_mempool;
#if XASH_AVI == AVI_FFMPEG
#define XASH_FFMPEG_DLOPEN 1
#include "avi_ffmpeg.h"
struct movie_state_s
@@ -221,6 +222,11 @@ int AVI_GetVideoFrameNumber( movie_state_t *Avi, float time )
return 0;
}
int AVI_TimeToSoundPosition( movie_state_t *Avi, int time )
{
return 0;
}
qboolean AVI_GetVideoInfo( movie_state_t *Avi, int *xres, int *yres, float *duration )
{
if( !Avi->active )
@@ -255,9 +261,9 @@ static void AVI_StreamAudio( movie_state_t *Avi )
rawchan_t *ch = NULL;
// keep the same semantics, when S_RAW_SOUND_SOUNDTRACK doesn't play if S_StartStreaming wasn't enabled
qboolean disable_stream = Avi->entnum == S_RAW_SOUND_SOUNDTRACK ? !snd.streaming : false;
qboolean disable_stream = Avi->entnum == S_RAW_SOUND_SOUNDTRACK ? !s_listener.streaming : false;
if( !snd.initialized || disable_stream || cl.paused || !Avi->cached_audio )
if( !dma.initialized || disable_stream || s_listener.paused || !Avi->cached_audio )
return;
ch = S_FindRawChannel( Avi->entnum, true );
@@ -268,14 +274,14 @@ static void AVI_StreamAudio( movie_state_t *Avi )
ch->master_vol = Avi->volume;
ch->dist_mult = (Avi->attn / SND_CLIP_DISTANCE);
if( ch->s_rawend < snd.soundtime )
ch->s_rawend = snd.soundtime;
if( ch->s_rawend < soundtime )
ch->s_rawend = soundtime;
while( ch->s_rawend < snd.soundtime + ch->max_samples )
while( ch->s_rawend < soundtime + ch->max_samples )
{
size_t copy;
buffer_samples = ch->max_samples - (ch->s_rawend - snd.soundtime);
buffer_samples = ch->max_samples - (ch->s_rawend - soundtime);
file_samples = buffer_samples * ((float)Avi->rate / SOUND_DMA_SPEED);
if( file_samples <= 1 ) return; // no more samples need
@@ -349,10 +355,6 @@ qboolean AVI_Think( movie_state_t *Avi )
qboolean decoded = false;
qboolean flushing = false;
qboolean redraw = false;
if( !Avi->video_ctx )
return false;
const double timebase = (double)Avi->video_ctx->pkt_timebase.den / Avi->video_ctx->pkt_timebase.num;
int64_t curtime = round( Platform_DoubleTime() * timebase );
@@ -382,7 +384,7 @@ qboolean AVI_Think( movie_state_t *Avi )
if(( res = pav_read_frame( Avi->fmt_ctx, Avi->pkt )) >= 0 )
{
if( Avi->pkt->stream_index == Avi->audio_stream && Avi->audio_ctx )
if( Avi->pkt->stream_index == Avi->audio_stream )
{
res = pavcodec_send_packet( Avi->audio_ctx, Avi->pkt );
if( res < 0 )
@@ -444,16 +446,13 @@ qboolean AVI_Think( movie_state_t *Avi )
if( Avi->texture == 0 )
{
int cinTexture = SCR_GetCinematicTexture();
int w = Avi->w >= 0 ? Avi->w : refState.width;
int h = Avi->h >= 0 ? Avi->h : refState.height;
if( redraw )
ref.dllFuncs.GL_UpdateTexture( cinTexture, Avi->xres, Avi->yres, Avi->xres, Avi->yres, Avi->dst, PF_BGRA_32 );
ref.dllFuncs.R_DrawStretchPic( Avi->x, Avi->y, w, h, 0, 0, 1, 1, cinTexture );
ref.dllFuncs.R_DrawStretchRaw( Avi->x, Avi->y, w, h, Avi->xres, Avi->yres, Avi->dst, redraw );
}
else if( redraw && Avi->texture > 0 )
ref.dllFuncs.GL_UpdateTexture( Avi->texture, Avi->xres, Avi->yres, Avi->w, Avi->h, Avi->dst, PF_BGRA_32 );
ref.dllFuncs.AVI_UploadRawFrame( Avi->texture, Avi->xres, Avi->yres, Avi->w, Avi->h, Avi->dst );
if( flushing && !decoded )
return false; // probably hit an EOF
@@ -843,6 +842,11 @@ void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audi
;
}
int AVI_TimeToSoundPosition( movie_state_t *Avi, int time )
{
return 0;
}
void AVI_CloseVideo( movie_state_t *Avi )
{
;

View File

@@ -26,101 +26,35 @@ GNU General Public License for more details.
#if XASH_FFMPEG_DLOPEN
// using typeof gives more resilience to function declaration changes
// but it's only available in GCC and standardized in C23
#if defined(__GNUC__) || __STDC_VERSION__ >= 202311L
#define SUPPORTED_AVU_VERSION_MAJOR LIBAVUTIL_VERSION_MAJOR
#define SUPPORTED_AVF_VERSION_MAJOR LIBAVFORMAT_VERSION_MAJOR
#define SUPPORTED_AVC_VERSION_MAJOR LIBAVCODEC_VERSION_MAJOR
#define SUPPORTED_SWR_VERSION_MAJOR LIBSWRESAMPLE_VERSION_MAJOR
#define SUPPORTED_SWS_VERSION_MAJOR LIBSWSCALE_VERSION_MAJOR
#define F( func ) \
typedef typeof( func ) func##_t; \
func##_t *p##func
// libavutil
F( avutil_version );
F( av_frame_alloc );
F( av_frame_free );
F( av_frame_ref );
F( av_frame_unref );
F( av_strerror );
F( av_free );
F( av_get_bytes_per_sample );
F( av_get_media_type_string );
F( av_image_alloc );
// libavformat
F( avformat_version );
F( av_find_best_stream );
F( av_read_frame );
F( av_seek_frame );
F( avformat_close_input );
F( avformat_find_stream_info );
F( avformat_open_input );
// libavcodec
F( avcodec_version );
F( av_packet_alloc );
F( av_packet_free );
F( av_packet_unref );
F( avcodec_alloc_context3 );
F( avcodec_find_decoder );
F( avcodec_flush_buffers );
F( avcodec_free_context );
F( avcodec_open2 );
F( avcodec_parameters_to_context );
F( avcodec_receive_frame );
F( avcodec_send_packet );
// libswresample
F( swresample_version );
F( swr_alloc_set_opts2 );
F( swr_convert );
F( swr_free );
F( swr_init );
// libswscale
F( swscale_version );
F( sws_freeContext );
F( sws_getContext );
F( sws_scale );
#undef F
#else // !defined(__GNUC__) && __STDC_VERSION__ < 202311L
// the following symbols were taken from ffmpeg public headers
// on each major ffmpeg uprgade, they must be validated
// ffmpeg guarantees API and ABI compatibility between major versions
// so complain if this gets compiled against unsupported yet version
// the same check will be done in runtime to ensure compatibility
#define SUPPORTED_AVU_VERSION_MAJOR 60
#define SUPPORTED_AVF_VERSION_MAJOR 62
#define SUPPORTED_AVC_VERSION_MAJOR 62
#define SUPPORTED_SWR_VERSION_MAJOR 6
#define SUPPORTED_SWS_VERSION_MAJOR 9
#define SUPPORTED_AVU_VERSION_MAJOR 59
#define SUPPORTED_AVF_VERSION_MAJOR 61
#define SUPPORTED_AVC_VERSION_MAJOR 61
#define SUPPORTED_SWR_VERSION_MAJOR 5
#define SUPPORTED_SWS_VERSION_MAJOR 8
#if SUPPORTED_AVU_VERSION_MAJOR != LIBAVUTIL_VERSION_MAJOR
#error "unsupported libavutil version"
#error
#endif
#if SUPPORTED_AVF_VERSION_MAJOR != LIBAVFORMAT_VERSION_MAJOR
#error "unsupported libavformat version"
#error
#endif
#if SUPPORTED_AVC_VERSION_MAJOR != LIBAVCODEC_VERSION_MAJOR
#error "unsupported libavcodec version"
#error
#endif
#if SUPPORTED_SWR_VERSION_MAJOR != LIBSWRESAMPLE_VERSION_MAJOR
#error "unsupported libswresample version"
#error
#endif
#if SUPPORTED_SWS_VERSION_MAJOR != LIBSWSCALE_VERSION_MAJOR
#error "unsupported libswscale version"
#error
#endif
// libavutil
@@ -171,8 +105,6 @@ void (*psws_freeContext)( struct SwsContext *swsContext );
struct SwsContext *(*psws_getContext)( int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, enum AVPixelFormat dstFormat, int flags, SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param );
int (*psws_scale)( struct SwsContext *c, const uint8_t *const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[], const int dstStride[] );
#endif // defined(__GNUC__) || __STDC_VERSION__ >= 202311L
#else // !XASH_FFMPEG_DLOPEN
#define SUPPORTED_AVU_VERSION_MAJOR LIBAVUTIL_VERSION_MAJOR
@@ -184,9 +116,8 @@ int (*psws_scale)( struct SwsContext *c, const uint8_t *const srcS
// libavutil
#define pavutil_version avutil_version
#define pav_frame_alloc av_frame_alloc
#define pav_frame_free av_frame_free
#define pav_frame_ref av_frame_ref
#define pav_frame_unref av_frame_unref
#define pav_frame_unref av_Frame_unref
#define pav_strerror av_strerror
#define pav_free av_free
#define pav_get_bytes_per_sample av_get_bytes_per_sample

View File

@@ -97,17 +97,7 @@ void CL_PlayCDTrack_f( void )
if( Q_isdigit( pszTrack ))
{
track = bound( 1, Q_atoi( Cmd_Argv( 2 )), MAX_CDTRACKS );
// a1ba: some maps contain cd track set in worldspawn
// forcibly stopping music on changelevel
//
// server notifies us about this in sv_client.c SV_PutClientInServer
// through "cd loop" command
//
// however, it could be set to a track that doesn't contain music data (in CD terms)
// so we catch it here and music will carry over changelevels
if( !COM_StringEmpty( clgame.cdtracks[track-1] ))
S_StartBackgroundTrack( clgame.cdtracks[track-1], clgame.cdtracks[track-1], 0, false );
S_StartBackgroundTrack( clgame.cdtracks[track-1], clgame.cdtracks[track-1], 0, false );
}
else S_StartBackgroundTrack( pszTrack, pszTrack, 0, true );
paused = false;
@@ -146,13 +136,10 @@ void CL_PlayCDTrack_f( void )
}
else if( !Q_stricmp( command, "info" ))
{
int maxTrack = 0;
int i, maxTrack;
for( int i = 0; i < MAX_CDTRACKS; i++ )
{
if( !COM_StringEmpty( clgame.cdtracks[i] ) )
maxTrack++;
}
for( maxTrack = i = 0; i < MAX_CDTRACKS; i++ )
if( COM_CheckStringEmpty( clgame.cdtracks[i] ) ) maxTrack++;
Con_Printf( "%u tracks\n", maxTrack );
if( track )

View File

@@ -16,8 +16,10 @@ GNU General Public License for more details.
#include "common.h"
#include "client.h"
#include "net_encode.h"
#include "particledef.h"
#include "cl_tent.h"
#include "shake.h"
#include "hltv.h"
#include "input.h"
#define MSG_COUNT 32 // last 32 messages parsed
@@ -55,6 +57,9 @@ const char *CL_MsgInfo( int cmd )
case PROTO_CURRENT:
svc_string = svc_strings[cmd];
break;
case PROTO_LEGACY:
svc_string = svc_legacy_strings[cmd];
break;
case PROTO_QUAKE:
svc_string = svc_quake_strings[cmd];
break;
@@ -144,11 +149,7 @@ static void CL_WriteErrorMessage( int current_count, sizebuf_t *msg )
file_t *fp;
fp = FS_Open( buffer_file, "wb", false );
if( !fp )
{
Con_Printf( S_ERROR "%s: can't open %s for write\n", __func__, buffer_file );
return;
}
if( !fp ) return;
FS_Write( fp, &cls.starting_count, sizeof( int ));
FS_Write( fp, &current_count, sizeof( int ));

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