Compare commits
2 Commits
continuous
...
continuous
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68f1a8bdc2 | ||
|
|
da1669ddf7 |
@@ -5,7 +5,6 @@ packages:
|
||||
- freetype-dev
|
||||
- fontconfig-dev
|
||||
- opus-dev
|
||||
- bzip2-dev
|
||||
sources:
|
||||
- https://git.sr.ht/~a1batross/xash3d-fwgs
|
||||
tasks:
|
||||
|
||||
@@ -7,7 +7,6 @@ packages:
|
||||
- libfreetype-dev
|
||||
- libfontconfig-dev
|
||||
- libopus-dev
|
||||
- libbz2-dev
|
||||
sources:
|
||||
- https://git.sr.ht/~a1batross/xash3d-fwgs
|
||||
tasks:
|
||||
|
||||
@@ -6,7 +6,6 @@ packages:
|
||||
- libfreetype-dev
|
||||
- libfontconfig-dev
|
||||
- libopus-dev
|
||||
- libbz2-dev
|
||||
sources:
|
||||
- https://git.sr.ht/~a1batross/xash3d-fwgs
|
||||
tasks:
|
||||
|
||||
@@ -6,7 +6,6 @@ packages:
|
||||
- print/freetype2
|
||||
- x11-fonts/fontconfig
|
||||
- audio/opus
|
||||
- archivers/bzip2
|
||||
sources:
|
||||
- https://git.sr.ht/~a1batross/xash3d-fwgs
|
||||
tasks:
|
||||
|
||||
@@ -6,7 +6,6 @@ packages:
|
||||
- fontconfig
|
||||
- libopus
|
||||
- pkgconf
|
||||
- bzip2
|
||||
sources:
|
||||
- https://git.sr.ht/~a1batross/xash3d-fwgs
|
||||
tasks:
|
||||
|
||||
@@ -3,7 +3,6 @@ packages:
|
||||
- python3
|
||||
- sdl2
|
||||
- opus
|
||||
- bzip2
|
||||
sources:
|
||||
- https://git.sr.ht/~a1batross/xash3d-fwgs
|
||||
tasks:
|
||||
|
||||
12
.cirrus.yml
@@ -1,13 +1,14 @@
|
||||
task:
|
||||
name: freebsd-14-amd64
|
||||
freebsd_instance:
|
||||
image_family: freebsd-14-2
|
||||
image_family: freebsd-14-0
|
||||
setup_script:
|
||||
- pkg update
|
||||
- pkg install -y pkgconf git sdl2 python fontconfig libvorbis opusfile bzip2 libbacktrace
|
||||
- pkg install -y pkgconf git sdl2 python fontconfig opus
|
||||
- git submodule update --init --recursive
|
||||
test_script:
|
||||
- ./scripts/cirrus/build_freebsd.sh
|
||||
- ./scripts/cirrus/build_freebsd.sh dedicated
|
||||
- ./scripts/cirrus/build_freebsd.sh full
|
||||
|
||||
task:
|
||||
name: freebsd-15-amd64
|
||||
@@ -15,7 +16,8 @@ task:
|
||||
image_family: freebsd-15-0-snap
|
||||
setup_script:
|
||||
- pkg update
|
||||
- pkg install -y pkgconf git sdl2 python fontconfig libvorbis opusfile bzip2 libbacktrace
|
||||
- pkg install -y pkgconf git sdl2 python fontconfig opus
|
||||
- git submodule update --init --recursive
|
||||
test_script:
|
||||
- ./scripts/cirrus/build_freebsd.sh
|
||||
- ./scripts/cirrus/build_freebsd.sh dedicated
|
||||
- ./scripts/cirrus/build_freebsd.sh full
|
||||
|
||||
47
.github/workflows/c-cpp.yml
vendored
@@ -15,39 +15,19 @@ jobs:
|
||||
include:
|
||||
# Linux build specifically want oldest Ubuntu as possible
|
||||
# to be crossdistribution compatible, otherwise use ubuntu-latest
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-20.04
|
||||
targetos: linux
|
||||
targetarch: amd64
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-20.04
|
||||
targetos: linux
|
||||
targetarch: i386
|
||||
- os: ubuntu-22.04
|
||||
targetos: linux
|
||||
targetarch: arm64
|
||||
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
|
||||
cross: true
|
||||
- os: ubuntu-22.04
|
||||
targetos: linux
|
||||
targetarch: ppc64el
|
||||
cross: true
|
||||
# - os: ubuntu-aarch64-22.04
|
||||
# - os: ubuntu-aarch64-20.04
|
||||
# targetos: linux
|
||||
# targetarch: aarch64
|
||||
# - os: ubuntu-latest
|
||||
# targetos: linux
|
||||
# targetarch: e2k-8c
|
||||
# cross: true
|
||||
- os: ubuntu-latest
|
||||
- os: ubuntu-20.04
|
||||
targetos: android
|
||||
targetarch: multiarch
|
||||
# - os: ubuntu-22.04
|
||||
# - os: ubuntu-20.04
|
||||
# targetos: motomagx
|
||||
# targetarch: armv6
|
||||
|
||||
@@ -60,21 +40,18 @@ jobs:
|
||||
- os: windows-latest
|
||||
targetos: win32
|
||||
targetarch: amd64
|
||||
- os: windows-2022 # always use the oldest possible for 32-bit because of older compilers, and better support of certain legacy OSes
|
||||
- os: windows-2019 # always use the oldest possible for 32-bit because of older compilers, and better support of certain legacy OSes
|
||||
targetos: win32
|
||||
targetarch: i386
|
||||
- os: macos-14 # arm64 as per github documentation
|
||||
- os: macos-14 # in GitHub documentation, it's an ARM64 machine
|
||||
targetos: apple
|
||||
targetarch: arm64
|
||||
- os: macos-13 # x86 as per github documentation (will they fix it before they deprecate this version?..)
|
||||
- os: macos-12 # in GitHub documentation, it's an x86 machine
|
||||
targetos: apple
|
||||
targetarch: amd64
|
||||
env:
|
||||
SDL_VERSION: 2.32.8
|
||||
FFMPEG_VERSION: 7.1
|
||||
SDL_VERSION: 2.30.3
|
||||
GH_CPU_ARCH: ${{ matrix.targetarch }}
|
||||
GH_CPU_OS: ${{ matrix.targetos }}
|
||||
GH_CROSSCOMPILING: ${{ matrix.cross }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -93,13 +70,12 @@ jobs:
|
||||
path: artifacts/*
|
||||
flatpak:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- app: su.xash.Engine.Compat.i386
|
||||
container:
|
||||
image: ghcr.io/flathub-infra/flatpak-github-actions:freedesktop-24.08
|
||||
image: bilelmoussaoui/flatpak-github-actions:freedesktop-23.08
|
||||
options: --privileged
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -107,7 +83,7 @@ jobs:
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build flatpak (Compat.i386)
|
||||
uses: FWGS/flatpak-github-actions/flatpak-builder@v6.5
|
||||
uses: FWGS/flatpak-github-actions/flatpak-builder@v6.3
|
||||
with:
|
||||
bundle: ${{ matrix.app }}.flatpak
|
||||
manifest-path: scripts/flatpak/${{ matrix.app }}.yml
|
||||
@@ -126,6 +102,7 @@ jobs:
|
||||
--yes \
|
||||
--cleanup-tag \
|
||||
--repo "$GITHUB_REPOSITORY" || true
|
||||
sleep 20s
|
||||
gh run download "$GITHUB_RUN_ID" \
|
||||
--dir artifacts/ \
|
||||
--repo "$GITHUB_REPOSITORY"
|
||||
|
||||
14
.gitignore
vendored
@@ -222,7 +222,7 @@ publish/
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
@@ -342,15 +342,3 @@ enc_temp_folder/
|
||||
|
||||
# KDevelop4
|
||||
*.kdev4
|
||||
|
||||
# ccls langauge server
|
||||
.ccls-*
|
||||
|
||||
# JetBrains
|
||||
.idea/
|
||||
cmake-build-*
|
||||
|
||||
# some Android-specific build stuff
|
||||
3rdparty/SDL
|
||||
3rdparty/hlsdk-portable
|
||||
!scripts/build-ninja.py
|
||||
|
||||
21
.gitmodules
vendored
@@ -19,24 +19,3 @@
|
||||
[submodule "3rdparty/xash-extras"]
|
||||
path = 3rdparty/extras/xash-extras
|
||||
url = https://github.com/FWGS/xash-extras
|
||||
[submodule "3rdparty/bzip2/bzip2"]
|
||||
path = 3rdparty/bzip2/bzip2
|
||||
url = https://gitlab.com/bzip2/bzip2
|
||||
[submodule "3rdparty/MultiEmulator"]
|
||||
path = 3rdparty/MultiEmulator
|
||||
url = https://github.com/FWGS/MultiEmulator
|
||||
[submodule "3rdparty/libogg/libogg"]
|
||||
path = 3rdparty/libogg/libogg
|
||||
url = https://github.com/xiph/ogg.git
|
||||
[submodule "3rdparty/vorbis/vorbis-src"]
|
||||
path = 3rdparty/vorbis/vorbis-src
|
||||
url = https://github.com/xiph/vorbis.git
|
||||
[submodule "3rdparty/opusfile/opusfile"]
|
||||
path = 3rdparty/opusfile/opusfile
|
||||
url = https://github.com/xiph/opusfile.git
|
||||
[submodule "3rdparty/libbacktrace/libbacktrace"]
|
||||
path = 3rdparty/libbacktrace/libbacktrace
|
||||
url = https://github.com/ianlancetaylor/libbacktrace
|
||||
[submodule "3rdparty/maintui"]
|
||||
path = 3rdparty/maintui
|
||||
url = https://github.com/numas13/xash3d-maintui.git
|
||||
|
||||
1
3rdparty/MultiEmulator
vendored
1
3rdparty/bzip2/bzip2
vendored
27
3rdparty/bzip2/wscript
vendored
@@ -1,27 +0,0 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
def options(opt):
|
||||
pass
|
||||
|
||||
def configure(conf):
|
||||
conf.define('_GNU_SOURCE', 1)
|
||||
conf.define('BZ_NO_STDIO', 1)
|
||||
|
||||
if conf.env.DEST_OS == 'win32':
|
||||
conf.define('BZ_LCCWIN32', 1)
|
||||
else:
|
||||
conf.define('BZ_UNIX', 1)
|
||||
|
||||
def build(bld):
|
||||
bld(features = 'subst', source = 'bzip2/bz_version.h.in', target = 'bzip2/bz_version.h', BZ_VERSION='1.1.0-fwgs', name = 'bz_version')
|
||||
|
||||
bz_sources = ['bzip2/blocksort.c', 'bzip2/huffman.c', 'bzip2/crctable.c', 'bzip2/randtable.c', 'bzip2/compress.c', 'bzip2/decompress.c', 'bzip2/bzlib.c']
|
||||
|
||||
bld.stlib(
|
||||
source = bz_sources,
|
||||
target = 'bzip2',
|
||||
use = 'bz_version',
|
||||
includes = 'bzip2/',
|
||||
export_includes = 'bzip2/'
|
||||
)
|
||||
1
3rdparty/extras/wscript
vendored
@@ -25,4 +25,5 @@ def build(bld):
|
||||
name = 'extras.pk3',
|
||||
files = srcdir.ant_glob('**/*'),
|
||||
relative_to = srcdir,
|
||||
compresslevel = 0,
|
||||
install_path = install_path)
|
||||
|
||||
2
3rdparty/extras/xash-extras
vendored
2
3rdparty/gl-wes-v2
vendored
2
3rdparty/gl4es/gl4es
vendored
8
3rdparty/gl4es/wscript
vendored
@@ -13,12 +13,12 @@ def configure(conf):
|
||||
|
||||
def build(bld):
|
||||
gl4es_srcdir = bld.path.find_node('gl4es/src')
|
||||
cflags = []
|
||||
if bld.env.COMPILER_CC != 'msvc':
|
||||
cflags += ['-w', '-fvisibility=hidden', '-std=gnu99']
|
||||
|
||||
bld.stlib(source = gl4es_srcdir.ant_glob(['gl/*.c', 'gl/*/*.c', 'glx/hardext.c']),
|
||||
target = 'gl4es',
|
||||
features = 'c',
|
||||
includes = ['gl4es/src', 'gl4es/src/gl', 'gl4es/src/glx', 'gl4es/include'],
|
||||
defines = ['NOX11', 'NO_GBM', 'NO_INIT_CONSTRUCTOR', 'DEFAULT_ES=2', 'NOEGL', 'NO_LOADER', 'STATICLIB'],
|
||||
cflags = cflags,
|
||||
cflags = ['-w', '-fvisibility=hidden', '-std=gnu99'],
|
||||
subsystem = bld.env.MSVC_SUBSYSTEM,
|
||||
export_includes = '.')
|
||||
|
||||
1
3rdparty/libbacktrace/libbacktrace
vendored
186
3rdparty/libbacktrace/wscript
vendored
@@ -1,186 +0,0 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
from waflib import TaskGen
|
||||
from waflib.Tools.c_config import DEFKEYS
|
||||
|
||||
FRAGMENT_ATOMIC='''int i;
|
||||
int main(void) {
|
||||
__atomic_load_n(&i, __ATOMIC_ACQUIRE);
|
||||
__atomic_store_n(&i, 1, __ATOMIC_RELEASE);
|
||||
return 0;
|
||||
}'''
|
||||
|
||||
FRAGMENT_SYNC='''int i;
|
||||
int main (void) {
|
||||
__sync_bool_compare_and_swap (&i, i, i);
|
||||
__sync_lock_test_and_set (&i, 1);
|
||||
__sync_lock_release (&i);
|
||||
return 0;
|
||||
}'''
|
||||
|
||||
FRAGMENT_GETPAGESIZE='''#include <unistd.h>
|
||||
int main(void) { return getpagesize() }'''
|
||||
|
||||
FRAGMENT_GETEXECNAME='''#include <stdlib.h>
|
||||
int main(void) { return getexecname() != 0 }'''
|
||||
|
||||
FRAGMENT_STRNLEN='''#include <string.h>
|
||||
int main(int argc, char **argv) { return (int)strnlen(argv[0], 10); }'''
|
||||
|
||||
FRAGMENT_DL_ITERATE_PHDR='''#include <%s>
|
||||
int main(void) { return dl_iterate_phdr(0, 0); }'''
|
||||
|
||||
FRAGMENT_FCNTL='''#include <fcntl.h>
|
||||
int main(void) { return fcntl(0, 0, 0); }'''
|
||||
|
||||
FRAGMENT_GETIPINFO='''#include "unwind.h"
|
||||
struct _Unwind_Context *context;
|
||||
int ip_before_insn = 0;
|
||||
int main(void) { return _Unwind_GetIPInfo(context, &ip_before_insn); }'''
|
||||
|
||||
FRAGMENT_LOADQUERY='''#include <sys/ldr.h>
|
||||
#include <sys/debug.h>
|
||||
int main(void) { return loadquery(0, 0, 0); }'''
|
||||
|
||||
FRAGMENT_KERN_PROC='''#include <sys/sysctl.h>
|
||||
#if !defined(%s) || !defined(KERN_PROC_PATHNAME)
|
||||
#error
|
||||
#endif
|
||||
int main(void) { return 0; }'''
|
||||
|
||||
FRAGMENT_LSTAT='''#include <sys/stat.h>
|
||||
struct stat st;
|
||||
int main(int argc, char **argv) { return lstat(argv[0], &st); }'''
|
||||
|
||||
FRAGMENT_READLINK='''#include <unistd.h>
|
||||
char buf[100];
|
||||
int main(int argc, char **argv) { return readlink(argv[0], buf, sizeof(buf)); }'''
|
||||
|
||||
def options(opt):
|
||||
pass
|
||||
|
||||
def configure(conf):
|
||||
# add unsupported platforms here
|
||||
if conf.env.DEST_OS in ['nswitch', 'psvita', 'dos']:
|
||||
conf.env.DISABLE_LIBBACKTRACE = True
|
||||
return
|
||||
|
||||
# win32 has it's own dbghelp-based backtrace, that's why we ship PDBs
|
||||
if conf.env.COMPILER_CC == 'msvc':
|
||||
conf.env.DISABLE_LIBBACKTRACE = True
|
||||
return
|
||||
|
||||
if not conf.path.find_dir('libbacktrace') or not conf.path.find_dir('libbacktrace/config'):
|
||||
conf.fatal('Can\'t find libbacktrace submodule. Run `git submodule update --init --recursive`.')
|
||||
return
|
||||
|
||||
conf.define('BACKTRACE_ELF_SIZE', 64 if conf.env.DEST_SIZEOF_VOID_P == 8 else 32)
|
||||
conf.define('BACKTRACE_XCOFF_SIZE', 64 if conf.env.DEST_SIZEOF_VOID_P == 8 else 32)
|
||||
conf.define('_ALL_SOURCE', 1)
|
||||
conf.define('_GNU_SOURCE', 1)
|
||||
conf.define('_POSIX_PTHREAD_SEMANTICS', 1)
|
||||
conf.define('_TANDEM_SOURCE', 1)
|
||||
conf.define('__EXTENSIONS__', 1)
|
||||
conf.define('_DARWIN_USE_64_BIT_INODE', 1)
|
||||
conf.define('_LARGE_FILES', 1)
|
||||
conf.check_large_file(compiler='c', execute=False, mandatory=False) # sets _FILE_OFFSET_BITS
|
||||
|
||||
conf.env.CFLAGS_EXTRAFLAGS = conf.filter_cflags(['-funwind-tables', '-g'], [])
|
||||
|
||||
if conf.filter_cflags(['-frandom-seed=test'], []):
|
||||
conf.env.HAVE_FRANDOM_SEED = True
|
||||
|
||||
def check_header(hdr):
|
||||
return {'header_name':hdr, 'msg':'... %s header' % hdr, 'mandatory':False, 'id':hdr, 'compiler': 'c'}
|
||||
|
||||
def check_frag(frag, msg, define, **kw):
|
||||
return dict({'fragment': frag, 'msg':'... %s' % msg, 'mandatory': False, 'compiler': 'c'}, **kw)
|
||||
|
||||
conf.multicheck(
|
||||
check_header('dlfcn.h'),
|
||||
check_header('inttypes.h'),
|
||||
check_header('link.h'),
|
||||
check_header('sys/link.h'),
|
||||
check_header('mach-o/dyld.h'),
|
||||
check_header('memory.h'),
|
||||
check_header('stdint.h'),
|
||||
check_header('stdlib.h'),
|
||||
check_header('strings.h'),
|
||||
check_header('string.h'),
|
||||
check_header('sys/ldr.h'),
|
||||
check_header('sys/mman.h'),
|
||||
check_header('sys/stat.h'),
|
||||
check_header('sys/types.h'),
|
||||
check_header('tlhelp32.h'),
|
||||
check_header('unistd.h'),
|
||||
check_header('windows.h'),
|
||||
|
||||
check_frag(FRAGMENT_ATOMIC, '__atomic extensions', 'HAVE_ATOMIC_FUNCTIONS'),
|
||||
check_frag(FRAGMENT_SYNC, ' __sync extensions', 'HAVE_SYNC_FUNCTIONS'),
|
||||
check_frag(FRAGMENT_GETPAGESIZE, ' getpagesize function', 'HAVE_DECL_GETPAGESIZE'),
|
||||
check_frag(FRAGMENT_STRNLEN, ' strnlen function', 'HAVE_DECL_STRNLEN'),
|
||||
check_frag(FRAGMENT_DL_ITERATE_PHDR % 'link.h', ' dl_iterate_phdr function in link.h', 'HAVE_DL_ITERATE_PHDR', after_tests=['link.h']),
|
||||
check_frag(FRAGMENT_DL_ITERATE_PHDR % 'sys/link.h', ' dl_iterate_phdr function in sys/link.h', 'HAVE_DL_ITERATE_PHDR', after_tests=['sys/link.h']),
|
||||
check_frag(FRAGMENT_FCNTL, 'fnctl function', 'HAVE_FCNTL'),
|
||||
check_frag(FRAGMENT_GETEXECNAME, 'getexecname function','HAVE_GETEXECNAME'),
|
||||
check_frag(FRAGMENT_GETIPINFO, '_Unwind_GetIPInfo function', 'HAVE_GETIPINFO'),
|
||||
check_frag(FRAGMENT_KERN_PROC % 'KERN_PROC', 'KERN_PROC and KERN_PROC_PATHNAME defines', 'HAVE_KERN_PROC'),
|
||||
check_frag(FRAGMENT_KERN_PROC % 'KERN_PROC_ARGS', 'KERN_PROC_ARGS and KERN_PROC_PATHNAME defines', 'HAVE_KERN_PROC_ARGS'),
|
||||
check_frag(FRAGMENT_LOADQUERY, 'loadquery function', 'HAVE_LOADQUERY'),
|
||||
check_frag(FRAGMENT_LSTAT, 'lstat function', 'HAVE_LSTAT'),
|
||||
check_frag(FRAGMENT_READLINK, 'readlink function', 'HAVE_READLINK'),
|
||||
|
||||
# {'lib':'lzma', 'define_name':'HAVE_LIBLZMA', 'uselib_store':'lzma', 'msg':'... lzma library', 'mandatory':False},
|
||||
# {'lib':'z', 'define_name':'HAVE_ZLIB', 'uselib_store':'z', 'msg':'... zlib library', 'mandatory':False},
|
||||
# {'lib':'zstd', 'define_name':'HAVE_ZSTD', 'uselib_store':'zstd', 'msg':'... zstd library', 'mandatory':False},
|
||||
msg='Checking for in parallel'
|
||||
)
|
||||
|
||||
conf.env[DEFKEYS].sort()
|
||||
|
||||
conf.write_config_header()
|
||||
|
||||
conf.define('BACKTRACE_SUPPORTED', 1)
|
||||
conf.define('BACKTRACE_USES_MALLOC', 0)
|
||||
conf.define('BACKTRACE_SUPPORTS_THREADS', 1)
|
||||
conf.define('BACKTRACE_SUPPORTS_DATA', conf.env.DEST_BINFMT in ['elf', 'mac-o'])
|
||||
|
||||
conf.write_config_header('backtrace-supported.h')
|
||||
|
||||
@TaskGen.feature('frandomseed')
|
||||
@TaskGen.after_method('propagate_uselib_vars')
|
||||
def process_frandom_seed(ctx):
|
||||
tasks = getattr(ctx, 'compiled_tasks', [])
|
||||
|
||||
for task in tasks:
|
||||
out = task.outputs[0]
|
||||
task.env.CFLAGS = list(task.env.CFLAGS) # need a copy
|
||||
task.env.CFLAGS += ['-frandom-seed=%s' % out.path_from(out.ctx.bldnode)]
|
||||
|
||||
def build(bld):
|
||||
if bld.env.DISABLE_LIBBACKTRACE:
|
||||
return
|
||||
|
||||
# we specifically only want mmap-based allocators because calling malloc is not safe from signal handlers
|
||||
sources = ['atomic.c', 'dwarf.c', 'fileline.c', 'posix.c', 'print.c', 'sort.c', 'state.c', 'backtrace.c', 'simple.c', 'mmap.c', 'mmapio.c']
|
||||
|
||||
if bld.env.DEST_BINFMT == 'pe':
|
||||
sources += ['pecoff.c']
|
||||
elif bld.env.DEST_BINFMT == 'mac-o':
|
||||
sources += ['macho.c']
|
||||
elif bld.env.DEST_BINFMT == 'elf':
|
||||
sources += ['elf.c']
|
||||
else:
|
||||
sources += ['unknown.c']
|
||||
|
||||
task = bld.stlib(
|
||||
source = ['libbacktrace/' + i for i in sources],
|
||||
target = 'backtrace',
|
||||
features = 'frandomseed' if bld.env.HAVE_FRANDOM_SEED else '',
|
||||
use = 'EXTRAFLAGS lzma z zstd',
|
||||
includes = '. libbacktrace/',
|
||||
export_defines = 'HAVE_LIBBACKTRACE=1',
|
||||
export_includes = 'libbacktrace/'
|
||||
)
|
||||
|
||||
1
3rdparty/libogg/libogg
vendored
50
3rdparty/libogg/wscript
vendored
@@ -1,50 +0,0 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
def options(opt):
|
||||
pass
|
||||
|
||||
def configure(conf):
|
||||
if not conf.path.find_dir('libogg') or not conf.path.find_dir('libogg/src'):
|
||||
conf.fatal('Can\'t find libogg submodule. Run `git submodule update --init --recursive`.')
|
||||
return
|
||||
|
||||
conf.env.INCLUDE_INTTYPES_H = 0
|
||||
conf.env.INCLUDE_SYS_TYPES_H = 0
|
||||
conf.env.INCLUDE_STDINT_H = 0
|
||||
|
||||
if conf.check_cc(header_name='inttypes.h', mandatory = False):
|
||||
conf.env.INCLUDE_INTTYPES_H = 1
|
||||
elif conf.check_cc(header_name='sys/types.h', mandatory = False):
|
||||
conf.env.INCLUDE_SYS_TYPES_H = 1
|
||||
elif conf.check_cc(header_name='stdint.h', mandatory = False):
|
||||
conf.env.INCLUDE_STDINT_H = 1
|
||||
|
||||
def build(bld):
|
||||
sources = bld.path.ant_glob([
|
||||
'libogg/src/*.c'
|
||||
])
|
||||
|
||||
bld(
|
||||
features = 'subst',
|
||||
name = 'libogg_config_types',
|
||||
source = 'libogg/include/ogg/config_types.h.in',
|
||||
target = 'libogg/include/ogg/config_types.h',
|
||||
INCLUDE_INTTYPES_H = bld.env.INCLUDE_INTTYPES_H,
|
||||
INCLUDE_SYS_TYPES_H = bld.env.INCLUDE_SYS_TYPES_H,
|
||||
INCLUDE_STDINT_H = bld.env.INCLUDE_STDINT_H,
|
||||
SIZE16 = 'int16_t',
|
||||
USIZE16 = 'uint16_t',
|
||||
SIZE32 = 'int32_t',
|
||||
USIZE32 = 'uint32_t',
|
||||
SIZE64 = 'int64_t',
|
||||
USIZE64 = 'uint64_t'
|
||||
)
|
||||
|
||||
bld.stlib(
|
||||
source = sources,
|
||||
target = 'ogg',
|
||||
use = 'libogg_config_types',
|
||||
includes = 'libogg/include/',
|
||||
export_includes = 'libogg/include/'
|
||||
)
|
||||
1
3rdparty/maintui
vendored
2
3rdparty/mainui
vendored
2
3rdparty/nanogl
vendored
2
3rdparty/opus/opus
vendored
106
3rdparty/opus/wscript
vendored
@@ -3,37 +3,6 @@
|
||||
|
||||
import os
|
||||
|
||||
FRAGMENT_VLA='''int main (int argc, char **argv) {
|
||||
char a[argc];
|
||||
a[sizeof( a ) - 1] = 0;
|
||||
int N;
|
||||
return a[0];
|
||||
}'''
|
||||
|
||||
FRAGMENT_ALLOCA_H='''#include <alloca.h>
|
||||
int main (void) {
|
||||
int foo=10;
|
||||
int * array = alloca(foo);
|
||||
}'''
|
||||
|
||||
FRAGMENT_STDLIB_H='''#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
int main (void) {
|
||||
int foo=10;
|
||||
int * array = alloca(foo);
|
||||
}'''
|
||||
|
||||
FRAGMENT_LRINT='''#include <math.h>
|
||||
#include <stdlib.h>
|
||||
int main (int argc, char **argv) {
|
||||
return lrint%s((%s)atof(argv[1]));
|
||||
}'''
|
||||
|
||||
# assuming MSVC always enables NEON
|
||||
FRAGMENT_NEON='''#if !defined __ARM_NEON__ && !defined _MSC_VER
|
||||
#error
|
||||
#endif'''
|
||||
|
||||
def options(opt):
|
||||
pass
|
||||
|
||||
@@ -42,61 +11,6 @@ def configure(conf):
|
||||
conf.fatal('Can\'t find opus submodule. Run `git submodule update --init --recursive`.')
|
||||
return
|
||||
|
||||
if conf.check_cc(fragment=FRAGMENT_LRINT % ('', 'double'), msg = 'Checking for C99 lrint', use = 'M', mandatory = False):
|
||||
conf.define('HAVE_LRINT', 1)
|
||||
|
||||
if conf.check_cc(fragment=FRAGMENT_LRINT % ('f', 'float'), msg = 'Checking for C99 lrintf', use = 'M', mandatory = False):
|
||||
conf.define('HAVE_LRINTF', 1)
|
||||
|
||||
# Check for C99 variable-size arrays, or alloca() as fallback
|
||||
if conf.check_cc(fragment=FRAGMENT_VLA, msg = 'Checking for C99 VLA support', mandatory = False):
|
||||
conf.define('VAR_ARRAYS', 1)
|
||||
elif conf.check_cc(fragment=FRAGMENT_ALLOCA_H, msg = 'Checking for alloca in alloca.h header', mandatory = False):
|
||||
conf.define('USE_ALLOCA', 1)
|
||||
conf.define('HAVE_ALLOCA_H', 1)
|
||||
elif conf.check_cc(fragment=FRAGMENT_STDLIB_H, msg = 'Checking for alloca.h in stdlib.h', mandatory = False):
|
||||
conf.define('USE_ALLOCA', 1)
|
||||
|
||||
if conf.env.DEST_CPU in ['thumb', 'arm']:
|
||||
if conf.check(header_name='arm_neon.h', mandatory = False):
|
||||
if conf.check(fragment=FRAGMENT_NEON, msg = 'Checking if compiler enabled NEON', mandatory = False):
|
||||
conf.env.HAVE_NEON = True
|
||||
conf.define('OPUS_ARM_MAY_HAVE_NEON_INTR', 1)
|
||||
conf.define('OPUS_ARM_PRESUME_NEON', 1)
|
||||
elif conf.env.DEST_CPU.startswith('x86'):
|
||||
if conf.check(header_name='xmmintrin.h', mandatory = False):
|
||||
if conf.env.COMPILER_CC != 'msvc':
|
||||
conf.env.CFLAGS += ['-msse']
|
||||
conf.define('OPUS_X86_MAY_HAVE_SSE', 1)
|
||||
if conf.env.DEST_SIZEOF_VOID_P > 4:
|
||||
conf.define('OPUS_X86_PRESUME_SSE', 1)
|
||||
|
||||
if conf.check(header_name='emmintrin.h', mandatory = False):
|
||||
if conf.env.COMPILER_CC != 'msvc':
|
||||
conf.env.CFLAGS += ['-msse2']
|
||||
conf.define('OPUS_X86_MAY_HAVE_SSE2', 1)
|
||||
if conf.env.DEST_SIZEOF_VOID_P > 4:
|
||||
conf.define('OPUS_X86_PRESUME_SSE2', 1)
|
||||
|
||||
# on x86_64 we enable both SSE and SSE2, so RTCD can be disabled (it's actually doesn't even build with RTCD enabled)
|
||||
if conf.env.DEST_SIZEOF_VOID_P == 4:
|
||||
if conf.check(header_name='cpuid.h', mandatory=False):
|
||||
conf.define('CPU_INFO_BY_C', 1)
|
||||
else:
|
||||
conf.define('CPU_INFO_BY_ASM', 1)
|
||||
|
||||
conf.define('OPUS_HAVE_RTCD', 1)
|
||||
|
||||
# if conf.check(header_name='smmintrin.h', mandatory = False):
|
||||
# if conf.env.COMPILER_CC != 'msvc':
|
||||
# conf.env.CFLAGS += ['-msse4.1']
|
||||
# conf.define('OPUS_X86_MAY_HAVE_SSE4_1', 1)
|
||||
|
||||
# if conf.check(header_name='immintrin.h', mandatory = False):
|
||||
# if conf.env.COMPILER_CC != 'msvc':
|
||||
# conf.env.CFLAGS += ['-mavx']
|
||||
# conf.define('OPUS_X86_MAY_HAVE_AVX', 1)
|
||||
|
||||
# TODO: ARM/x86 intrinsics detection
|
||||
# TODO: maybe call autotools/cmake/meson instead?
|
||||
|
||||
@@ -112,23 +26,8 @@ def build(bld):
|
||||
'opus/src/opus_compare.c',
|
||||
'opus/celt/opus_custom_demo.c'
|
||||
])
|
||||
|
||||
includes = ['opus', 'opus/include/', 'opus/celt/', 'opus/silk/', 'opus/silk/float/']
|
||||
|
||||
if bld.env.DEST_CPU in ['thumb', 'arm']:
|
||||
if bld.env.HAVE_NEON:
|
||||
sources += bld.path.ant_glob(['opus/silk/arm/*.c', 'opus/celt/arm/*.c'])
|
||||
includes += ['opus/silk/arm', 'opus/celt/arm']
|
||||
elif bld.env.DEST_CPU.startswith('x86'):
|
||||
sources += ['opus/silk/x86/x86_silk_map.c',
|
||||
'opus/celt/x86/pitch_sse.c',
|
||||
'opus/celt/x86/pitch_sse2.c',
|
||||
'opus/celt/x86/vq_sse2.c',
|
||||
'opus/celt/x86/x86_celt_map.c',
|
||||
'opus/celt/x86/x86cpu.c']
|
||||
includes += ['opus/silk/x86', 'opus/celt/x86']
|
||||
|
||||
defines = ['OPUS_BUILD', 'FLOAT_APPROX', 'PACKAGE_VERSION="1.4.0"', 'CUSTOM_MODES', 'ENABLE_HARDENING']
|
||||
includes = ['opus/include/', 'opus/celt/', 'opus/silk/', 'opus/silk/float/']
|
||||
defines = ['USE_ALLOCA', 'OPUS_BUILD', 'FLOAT_APPROX', 'PACKAGE_VERSION="1.3.1"', 'CUSTOM_MODES']
|
||||
|
||||
bld.stlib(
|
||||
source = sources,
|
||||
@@ -136,5 +35,6 @@ def build(bld):
|
||||
features = 'c',
|
||||
includes = includes,
|
||||
defines = defines,
|
||||
subsystem = bld.env.MSVC_SUBSYSTEM,
|
||||
export_includes = ['opus/include/']
|
||||
)
|
||||
|
||||
1
3rdparty/opusfile/opusfile
vendored
37
3rdparty/opusfile/wscript
vendored
@@ -1,37 +0,0 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
def options(opt):
|
||||
pass
|
||||
|
||||
def configure(conf):
|
||||
if not conf.path.find_dir('opusfile') or not conf.path.find_dir('opusfile/src'):
|
||||
conf.fatal('Can\'t find opusfile submodule. Run `git submodule update --init --recursive`.')
|
||||
return
|
||||
|
||||
if conf.env.COMPILER_CC == 'msvc':
|
||||
conf.define('_CRT_SECURE_NO_WARNINGS', 1)
|
||||
conf.define('_CRT_SECURE_NO_DEPRECATE', 1)
|
||||
conf.define('_CRT_NONSTDC_NO_DEPRECATE', 1)
|
||||
|
||||
if conf.env.DEST_OS == 'android':
|
||||
# HACKHACK: set it to 32 here because opusfile can't be built on Android SDK < 24
|
||||
# with _FILE_OFFSET_BITS 64 (which it sets automatically in src/internal.h)
|
||||
# we are not (????) relying on this part of the API, so it should be harmless
|
||||
conf.define('_FILE_OFFSET_BITS', 32)
|
||||
|
||||
def build(bld):
|
||||
sources = [
|
||||
'opusfile/src/info.c',
|
||||
'opusfile/src/internal.c',
|
||||
'opusfile/src/opusfile.c',
|
||||
'opusfile/src/stream.c'
|
||||
]
|
||||
|
||||
bld.stlib(
|
||||
source = sources,
|
||||
target = 'opusfile',
|
||||
includes = 'opusfile/include/',
|
||||
use = 'ogg opus',
|
||||
export_includes = 'opusfile/include/'
|
||||
)
|
||||
2
3rdparty/vgui_support
vendored
1
3rdparty/vorbis/vorbis-src
vendored
71
3rdparty/vorbis/wscript
vendored
@@ -1,71 +0,0 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
FRAGMENT_MEMORY_H='''#include <memory.h>
|
||||
int main (void) {
|
||||
return 0;
|
||||
}'''
|
||||
|
||||
FRAGMENT_ALLOCA_H='''#include <alloca.h>
|
||||
int main (void) {
|
||||
int foo=10;
|
||||
int * array = alloca(foo);
|
||||
}'''
|
||||
|
||||
def options(opt):
|
||||
pass
|
||||
|
||||
def configure(conf):
|
||||
if not conf.path.find_dir('vorbis-src') or not conf.path.find_dir('vorbis-src/lib'):
|
||||
conf.fatal('Can\'t find Vorbis submodule. Run `git submodule update --init --recursive`.')
|
||||
return
|
||||
|
||||
if conf.check_cc(fragment=FRAGMENT_MEMORY_H, msg = 'Checking for memory.h header', mandatory = False):
|
||||
conf.define('USE_MEMORY_H', 1)
|
||||
|
||||
conf.check_cc(fragment=FRAGMENT_ALLOCA_H, msg = 'Checking for alloca in alloca.h header', mandatory = False)
|
||||
|
||||
if conf.env.COMPILER_CC == 'msvc':
|
||||
conf.define('_CRT_SECURE_NO_WARNINGS', 1)
|
||||
conf.define('_CRT_SECURE_NO_DEPRECATE', 1)
|
||||
conf.define('_CRT_NONSTDC_NO_DEPRECATE', 1)
|
||||
|
||||
def build(bld):
|
||||
libvorbis_sources = [
|
||||
'vorbis-src/lib/mdct.c',
|
||||
'vorbis-src/lib/smallft.c',
|
||||
'vorbis-src/lib/block.c',
|
||||
'vorbis-src/lib/envelope.c',
|
||||
'vorbis-src/lib/window.c',
|
||||
'vorbis-src/lib/lsp.c',
|
||||
'vorbis-src/lib/lpc.c',
|
||||
'vorbis-src/lib/analysis.c',
|
||||
'vorbis-src/lib/synthesis.c',
|
||||
'vorbis-src/lib/psy.c',
|
||||
'vorbis-src/lib/info.c',
|
||||
'vorbis-src/lib/floor1.c',
|
||||
'vorbis-src/lib/floor0.c',
|
||||
'vorbis-src/lib/res0.c',
|
||||
'vorbis-src/lib/mapping0.c',
|
||||
'vorbis-src/lib/registry.c',
|
||||
'vorbis-src/lib/codebook.c',
|
||||
'vorbis-src/lib/sharedbook.c',
|
||||
'vorbis-src/lib/lookup.c',
|
||||
'vorbis-src/lib/bitrate.c'
|
||||
]
|
||||
|
||||
bld.stlib(
|
||||
source = libvorbis_sources,
|
||||
target = 'vorbis',
|
||||
includes = 'vorbis-src/include/',
|
||||
use = 'ogg',
|
||||
export_includes = 'vorbis-src/include/'
|
||||
)
|
||||
|
||||
bld.stlib(
|
||||
source = 'vorbis-src/lib/vorbisfile.c',
|
||||
target = 'vorbisfile',
|
||||
includes = 'vorbis-src/include/',
|
||||
use = 'vorbis',
|
||||
export_includes = 'vorbis-src/include/'
|
||||
)
|
||||
@@ -45,8 +45,3 @@
|
||||
Tags can be any: subsystem, simple feature name or even just a filename, without extension.
|
||||
Just keep them always same, it helps keep history clean and commit messages short.
|
||||
|
||||
## LLM-based tools usage.
|
||||
|
||||
While we wouldn't recommend using any LLM-based (also misleadingly called AI) tools, we understand that they are here to stay.
|
||||
|
||||
Whether you're reporting bug or contributing the code, you take complete authorship and responsibility over provided content and the same rules will apply to you as for everybody else, so validate the bug report or the patch before sending it.
|
||||
|
||||
@@ -13,6 +13,5 @@ When `-bugcomp` is specified with argument, it interpreted as flags separated wi
|
||||
| Flag | Description | Games that require this flag |
|
||||
| ------- | ----------- | ---------------------------- |
|
||||
| `peoei` | Reverts `pfnPEntityOfEntIndex` behavior to GoldSrc, where it returns NULL for last player due to incorrect player index comparison | * Counter-Strike: Condition Zero - Deleted Scenes |
|
||||
| `gsmrf` | Rewrites message at the moment when Game DLL attempts to write an internal engine message, usually specific to GoldSrc protocol.<br>Right now only supports `svc_spawnstaticsound`, more messages added by request. | * MetaMod/AMXModX based mods |
|
||||
| `gsmrf` | Rewrites message at the moment when Game DLL attempts to write an internal engine message, usually specific to GoldSrc protocol. Right now only supports `svc_spawnstaticsound`, more messages added by request. | * MetaMod/AMXModX based mods |
|
||||
| `sp_attn_none` | Makes sounds with attenuation zero spatialized, i.e. have a stereo effect. | Possibly, every game that was made for GoldSrc. |
|
||||
| `get_game_dir_full` | Makes server return full path in server's `pfnGetGameDir` API function | Mods targetting engine before HL 1.1.1.1, according to MetaMod [documentation](http://metamod.org/engine_notes.html#GetGameDir) |
|
||||
|
||||
@@ -5,10 +5,5 @@ This can be useful to test engine in Wine without using virtual machines or dual
|
||||
0. Clone and install https://github.com/mstorsjo/msvc-wine (you can skip CMake part)
|
||||
1. Set environment variable MSVC_WINE_PATH to the path to installed MSVC toolchain
|
||||
2. Pre-load wine: `wineserver -k; wineserver -p; wine64 wineboot`
|
||||
3. Run `PKGCONFIG=/bin/false ./waf configure -T <build-type> --enable-wine-msvc --sdl2=../SDL2_VC`. Configuration step will take more time than usual.
|
||||
3. Run `./waf configure -T <build-type> --enable-wine-msvc --sdl2=../SDL2_VC`. Configuration step will take more time than usual.
|
||||
4. .. other typical steps to build from console ...
|
||||
|
||||
> [!NOTE]
|
||||
> Notice the usage of PKGCONFIG=/bin/false here. We're disabling pkg-config so we don't accidentally pull
|
||||
> system-wide dependencies and force building them from source. In future builds we might set custom
|
||||
> directory to pull dependencies from, like ffmpeg...
|
||||
|
||||
@@ -2,27 +2,23 @@
|
||||
|
||||
On this page you can find links where you can support each developer individually, who has provided public sponsorship information.
|
||||
|
||||
## [a1batross](https://github.com/a1batross)
|
||||
### [a1batross](https://github.com/a1batross)
|
||||
|
||||
Initial Xash3D SDL2/Linux port author, Xash3D FWGS engine maintainer, creator of non-commercial Flying With Gauss organization.
|
||||
* Initial Xash3D SDL2/Linux port author, Xash3D FWGS engine maintainer, creator of non-commercial Flying With Gauss organization.
|
||||
* Boosty page: https://boosty.to/a1ba
|
||||
|
||||
* [Boosty page](https://boosty.to/a1ba)
|
||||
### [nekonomicon](https://github.com/nekonomicon)
|
||||
|
||||
## [nekonomicon](https://github.com/nekonomicon)
|
||||
* [hlsdk-portable](https://github.com/FWGS/hlsdk-portable), [mdldec](../utils/mdldec), [opensource-mods.md](opensource-mods.md) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=nekonomicon) (*BSD/clang port, PNG support, etc).
|
||||
* Boosty page: https://boosty.to/nekonomicon
|
||||
|
||||
[hlsdk-portable](https://github.com/FWGS/hlsdk-portable), [mdldec](../utils/mdldec), [opensource-mods.md](opensource-mods.md) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=nekonomicon) (*BSD/clang port, PNG support, etc).
|
||||
### [Velaron](https://github.com/Velaron)
|
||||
* [cs16-client](https://github.com/Velaron/cs16-client) & [tf15-client](https://github.com/Velaron/tf15-client) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=Velaron) (Android port, voice chat, etc).
|
||||
* BuyMeACoffee page: https://www.buymeacoffee.com/velaron
|
||||
|
||||
* [Boosty page](https://boosty.to/nekonomicon)
|
||||
|
||||
## [Velaron](https://github.com/Velaron)
|
||||
|
||||
[cs16-client](https://github.com/Velaron/cs16-client) & [tf15-client](https://github.com/Velaron/tf15-client) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=Velaron) (Android port, voice chat, etc).
|
||||
|
||||
* [Boosty page](https://boosty.to/velaron)
|
||||
|
||||
## [SNMetamorph](https://github.com/SNMetamorph)
|
||||
|
||||
[PrimeXT](https://github.com/SNMetamorph/PrimeXT) & [GoldSrc Monitor](https://github.com/SNMetamorph/goldsrc-monitor) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=SNMetamorph) (Windows port, voice chat, etc).
|
||||
|
||||
* [Boosty page](https://boosty.to/snmetamorph)
|
||||
* [Other donation methods](https://snmetamorph.github.io/donate)
|
||||
### [SNMetamorph](https://github.com/SNMetamorph)
|
||||
* [PrimeXT](https://github.com/SNMetamorph/PrimeXT) & [GoldSrc Monitor](https://github.com/SNMetamorph/goldsrc-monitor) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=SNMetamorph) (Windows port, voice chat, etc).
|
||||
* BTC: `16GAzK3qei5AwBW7sggXp3yNcFHBtdpxXj`
|
||||
* ETH (ERC20): `0xb580eeca9756e3881f9d6d026e28db28eb72a383`
|
||||
* USDT (ERC20): `0xb580eeca9756e3881f9d6d026e28db28eb72a383`
|
||||
* USDC (ERC20): `0xb580eeca9756e3881f9d6d026e28db28eb72a383`
|
||||
|
||||
150
Documentation/entity-tools.md
Normal file
@@ -0,0 +1,150 @@
|
||||
# There are few new commands availiable in xash3d fork:
|
||||
|
||||
## Commands:
|
||||
### ent_create
|
||||
Create entity with specified classname and key/values
|
||||
|
||||
`ent_create <classname> <key> <value> <key> <value> ...`
|
||||
|
||||
for example:
|
||||
|
||||
`ent_create monster_zombie targetname zomb1`
|
||||
|
||||
after creating entity, ent_last_xxx cvars are set to new entity and ent_last_cb called, look at ent_getvars description
|
||||
|
||||
### ent_fire
|
||||
|
||||
Make some actions on entity
|
||||
|
||||
`ent_fire <pattern> <command> <args>`
|
||||
Availiavle commands:
|
||||
* Set fields (Only set entity field, does not call any functions):
|
||||
* health
|
||||
* gravity
|
||||
* movetype
|
||||
* solid
|
||||
* rendermode
|
||||
* rendercolor (vector)
|
||||
* renderfx
|
||||
* renderamt
|
||||
* hullmin (vector)
|
||||
* hullmax (vector)
|
||||
* Actions
|
||||
* rename: set entity targetname
|
||||
* settarget: set entity target (only targetnames)
|
||||
* setmodel: set entity model (does not update)
|
||||
* set: set key/value by server library
|
||||
* See game FGD to get list.
|
||||
* command takes two arguments
|
||||
* touch: touch entity by current player.
|
||||
* use: use entity by current player.
|
||||
* movehere: place entity in player fov.
|
||||
* drop2floor: place entity to nearest floor surface
|
||||
* moveup: move entity to 25 units up
|
||||
* moveup (value): move by y axis relatively to specified value
|
||||
* Flags (Set/clear specified flag bit, arg is bit number):
|
||||
* setflag
|
||||
* clearflag
|
||||
* setspawnflag
|
||||
* clearspawnflag
|
||||
|
||||
### ent_info
|
||||
Print information about entity by identificator
|
||||
|
||||
`ent_info <identificator>`
|
||||
|
||||
### ent_getvars
|
||||
Set client cvars containing entity information (useful for [[Scripting]]) and call ent_last_cb
|
||||
|
||||
`ent_getvars <identificator>`
|
||||
|
||||
These cvars are set:
|
||||
```
|
||||
ent_last_name
|
||||
ent_last_num
|
||||
ent_last_inst
|
||||
ent_last_origin
|
||||
ent_last_class
|
||||
```
|
||||
|
||||
### ent_list
|
||||
Print short information about antities, filtered by pattern
|
||||
|
||||
`ent_list <pattern>`
|
||||
|
||||
## Syntax description
|
||||
|
||||
### \<identificator\>
|
||||
|
||||
* !cross: entity under aim
|
||||
* Instance code: !\<number\>_\<seria\l>
|
||||
* set by ent_getvars command
|
||||
* Entity index
|
||||
* targetname pattern
|
||||
|
||||
### \<pattern\>
|
||||
|
||||
Pattern is like identificator, but may filter many entities by classname
|
||||
|
||||
### (vector)
|
||||
|
||||
used by ent_fire command. vector means three float values, entered without quotes
|
||||
|
||||
### key/value
|
||||
|
||||
All entities parameters may be set by specifiing key and value strings.
|
||||
|
||||
Originally, this mechanizm is used in map/bsp format, but it can be used in enttools too.
|
||||
|
||||
Keys and values are passed to server library and processed by entity keyvalue function, setting edict and entity owns parameters.
|
||||
|
||||
If value contains spaces, it must be put in quotes:
|
||||
|
||||
`ent_fire !cross set origin "0 0 0"`
|
||||
|
||||
## Using with scripting
|
||||
|
||||
ent_create and ent_getvars commands are setting cvars on client
|
||||
|
||||
It can be used with ent_last_cb alias that is executed after setting cvars.
|
||||
|
||||
Simple example:
|
||||
|
||||
```
|
||||
ent_create weapon_c4
|
||||
alias ent_last_cb "ent_fire \$ent_last_inst use"
|
||||
```
|
||||
|
||||
Use weapon_c4 after creating it.
|
||||
|
||||
Note that you cannot use many dfferent callbacks at the same time.
|
||||
|
||||
You can set entity name by by pattern and create special script, contatning all callbacks.
|
||||
|
||||
Example:
|
||||
|
||||
example.cfg
|
||||
```
|
||||
alias ent_last_cb exec entity_cb.cfg
|
||||
ent create \<class\> targetname my_ent1_$name
|
||||
ent_create \<class\> targetname my_ent2_$name
|
||||
```
|
||||
entity_cb.cfg
|
||||
```
|
||||
if $ent_last_name == my_ent1_$name
|
||||
:(ent1 actions)
|
||||
if $ent_last_name == my_ent2_$name
|
||||
:(ent2 actions)
|
||||
```
|
||||
Note that scripting cannot be blocking. You cannot wait for server answer and continue. But you can use small scripts, connected with ent_last_cb command. The best usage is user interaction. You can add touch buttons to screen or call user command menu actions by callbacks.
|
||||
## Server side
|
||||
|
||||
To enable entity tools on server, set sv_enttools_enable to 1
|
||||
|
||||
To change maximum number of entities, touched by ent_fire, change sv_enttools_maxfire to required number.
|
||||
|
||||
To enable actions on players, set sv_enttools_players to 1.
|
||||
|
||||
To enable entity tools for player by nickname, set sv_enttools_godplayer to nickname. Useful to temporary enable from rcon.
|
||||
|
||||
To prevent crash on some actions, set host_mapdesign_fatal to 0
|
||||
@@ -1,152 +0,0 @@
|
||||
# Entity tools
|
||||
|
||||
For some features described below, you need to enable [console scripting](https://github.com/FWGS/xash3d-fwgs/blob/master/Documentation/extensions/console-scripting.md) with command `cmd_scripting 1` in console.
|
||||
To get more information about it, check another according page related to console scripting.
|
||||
|
||||
## Commands description
|
||||
|
||||
### ent_create
|
||||
Create entity with specified classname and key/values.
|
||||
|
||||
`ent_create <classname> <key> <value> <key> <value> ...`
|
||||
|
||||
For example:
|
||||
|
||||
`ent_create monster_zombie targetname zomb1`
|
||||
|
||||
After creating entity, ent_last_xxx cvars are set to new entity and ent_last_cb called, look at ent_getvars description.
|
||||
|
||||
### ent_fire
|
||||
|
||||
Makes some actions on entity.
|
||||
|
||||
`ent_fire <pattern> <command> <args>`
|
||||
|
||||
#### Available commands:
|
||||
|
||||
Set fields (only set entity field, does not call any functions)
|
||||
* health
|
||||
* gravity
|
||||
* movetype
|
||||
* solid
|
||||
* rendermode
|
||||
* rendercolor (vector)
|
||||
* renderfx
|
||||
* renderamt
|
||||
* hullmin (vector)
|
||||
* hullmax (vector)
|
||||
|
||||
Actions
|
||||
* rename: set entity targetname
|
||||
* settarget: set entity target (only targetnames)
|
||||
* setmodel: set entity model (does not update)
|
||||
* set: set key/value by server library
|
||||
* See game FGD to get list.
|
||||
* command takes two arguments
|
||||
* touch: touch entity by current player.
|
||||
* use: use entity by current player.
|
||||
* movehere: place entity in player fov.
|
||||
* drop2floor: place entity to nearest floor surface
|
||||
* moveup: move entity to 25 units up
|
||||
* moveup (value): move by y axis relatively to specified value
|
||||
|
||||
Flags (set/clear specified flag bit, arg is bit number):
|
||||
* setflag
|
||||
* clearflag
|
||||
* setspawnflag
|
||||
* clearspawnflag
|
||||
|
||||
### ent_info
|
||||
Print information about entity by identificator.
|
||||
|
||||
`ent_info <identificator>`
|
||||
|
||||
### ent_getvars
|
||||
Set client cvars containing entity information (useful for [scripting](extensions/console-scripting.md)) and then calls ent_last_cb.
|
||||
|
||||
`ent_getvars <identificator>`
|
||||
|
||||
These cvars are set:
|
||||
```
|
||||
ent_last_name
|
||||
ent_last_num
|
||||
ent_last_inst
|
||||
ent_last_origin
|
||||
ent_last_class
|
||||
```
|
||||
|
||||
### ent_list
|
||||
Print short information about antities, filtered by pattern.
|
||||
|
||||
`ent_list <pattern>`
|
||||
|
||||
## Syntax description
|
||||
|
||||
#### \<identificator\>
|
||||
* !cross: entity under aim
|
||||
* !\<number\>_\<serial\>: instance code
|
||||
* Set by ent_getvars command
|
||||
* Entity index
|
||||
* Targetname pattern
|
||||
|
||||
#### \<pattern\>
|
||||
|
||||
Pattern is like identificator, but may filter many entities by classname.
|
||||
|
||||
#### (vector)
|
||||
|
||||
Used by ent_fire command. vector means three float values, entered without quotes.
|
||||
|
||||
#### key/value
|
||||
|
||||
All entities parameters may be set by specifiing key and value strings.
|
||||
|
||||
Originally, this mechanizm is used in map/bsp format, but it can be used in enttools too.
|
||||
|
||||
Keys and values are passed to server library and processed by entity keyvalue function, setting edict and entity owns parameters.
|
||||
|
||||
If value contains spaces, it must be put in quotes:
|
||||
|
||||
`ent_fire !cross set origin "0 0 0"`
|
||||
|
||||
## Using with scripting
|
||||
|
||||
ent_create and ent_getvars commands are setting cvars on client
|
||||
|
||||
It can be used with ent_last_cb alias that is executed after setting cvars.
|
||||
|
||||
Simple example:
|
||||
|
||||
```
|
||||
ent_create weapon_c4
|
||||
alias ent_last_cb "ent_fire \$ent_last_inst use"
|
||||
```
|
||||
|
||||
Use weapon_c4 after creating it.
|
||||
|
||||
Note that you cannot use many different callbacks at the same time.
|
||||
|
||||
You can set entity name by by pattern and create special script, contatning all callbacks.
|
||||
|
||||
Example:
|
||||
|
||||
> example.cfg
|
||||
```
|
||||
alias ent_last_cb exec entity_cb.cfg
|
||||
ent create \<class\> targetname my_ent1_$name
|
||||
ent_create \<class\> targetname my_ent2_$name
|
||||
```
|
||||
> entity_cb.cfg
|
||||
```
|
||||
if $ent_last_name == my_ent1_$name
|
||||
:(ent1 actions)
|
||||
if $ent_last_name == my_ent2_$name
|
||||
:(ent2 actions)
|
||||
```
|
||||
Note that scripting cannot be blocking. You cannot wait for server answer and continue. But you can use small scripts, connected with ent_last_cb command. The best usage is user interaction. You can add touch buttons to screen or call user command menu actions by callbacks.
|
||||
|
||||
## Server side configuration
|
||||
|
||||
To enable entity tools on server, set sv_enttools_enable to 1
|
||||
|
||||
To change maximum number of entities, touched by ent_fire, change sv_enttools_maxfire to required number.
|
||||
@@ -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..
|
||||
|
||||
@@ -85,9 +85,6 @@ These strings are specific to Xash3D FWGS.
|
||||
As Xash3D accidentally supports GoldSrc games, it also supports parsing liblist.gam.\
|
||||
Xash3D will use this file if gameinfo.txt is absent, or if its modification timestamp is older than liblist.gam.
|
||||
|
||||
> [!NOTE]
|
||||
> Starting from January 2025, Xash3D FWGS doesn't automatically generate gameinfo.txt from liblist.gam. The key conversion table still remains but if you wish to use gameinfo.txt instead of liblist.gam, you can execute `fs_make_gameinfo` in console.
|
||||
|
||||
For game creators who plan supporting only Xash3D, using this file is not recommended.
|
||||
|
||||
The table below defines conversion rules from liblist.gam to gameinfo.txt. Some keys' interpretation does differ from `gameinfo.txt`, in this case a note will be left. If `liblist.gam` key isn't present in this table, it's ignored.
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# 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
|
||||
```
|
||||
|
||||
But keep in mind, there are requirement for server to be able to accept connections from Xash3D-based clients: it should use Reunion.
|
||||
Without this requirement, you will just get "Steam validation rejected" error on connecting.
|
||||
|
||||
That is because proper authorization with Steam API is not implemented in engine yet (but we have plans on it).
|
||||
|
||||
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.
|
||||
|
Before Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 212 KiB |
|
Before Width: | Height: | Size: 400 KiB |
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.1 MiB |
@@ -1,32 +0,0 @@
|
||||
# NAT bypass feature in Xash3D FWGS
|
||||
Since IPv6 not as widespread as we would like, NAT (Network Address Translation) still being actively used by many internet service providers in an attempts to
|
||||
mitigate IPv4 addresses exhaustion. In short, they uses one IPv4 address and doing some tricks with ports to represent many other users behind this address.
|
||||
|
||||
But this leads to a problem for users: they cannot accept direct
|
||||
incoming connections anymore. This means that if you are behind provider's NAT and will try to setup Xash3D FWGS server - nobody will be able to connect to it,
|
||||
and the server will not show up in servers public list.
|
||||
|
||||
## Is it possible to avoid this problem?
|
||||
In most cases, it is possible to bypass NAT with UDP hole punching, and Xash3D FWGS uses this method too. But this method is not 100% guaranteed to work - it depends
|
||||
on NAT configurations on both server and client side, and there is no way to control it.
|
||||
|
||||
First of all, server should not be behind symmetric NAT. You can check your NAT type on [this page](https://www.checkmynat.com/).
|
||||
If you get "Symmetric NAT" result in this test, that means you cannot setup publicly available server with internet connection that you are using.
|
||||
|
||||
Here is more detailed scheme of different NAT types compatibility, it explains are users with different NAT types can connect to each other or not.
|
||||
Client NAT type on rows, server NAT type on columns:
|
||||
|
||||
| *NAT Type* | Full Cone | Restricted Cone | Port Restricted Cone | Symmetric |
|
||||
| -------------------- | --------- | --------------- | -------------------- | --------- |
|
||||
| Full Cone | ✔️ | ✔️ | ✔️ | ✔️ |
|
||||
| Restricted Cone | ✔️ | ✔️ | ✔️ | ✔️ |
|
||||
| Port Restricted Cone | ✔️ | ✔️ | ✔️ | ❌ |
|
||||
| Symmetric | ✔️ | ✔️ | ❌ | ❌ |
|
||||
|
||||
## How to use NAT bypass feature?
|
||||
If you are starting server within the game, you need to enable option "*Use NAT Bypass instead of direct mode*" in bottom left corner of screen.
|
||||
|
||||
If you are starting dedicated server, you should add console variable `sv_nat 1` to server.cfg file, or add `+sv_nat 1` to server startup parameters.
|
||||
|
||||
If you need to connect to server behind NAT, there is separate tab named *NAT* for such servers in server browser. Note that it is useless to add NAT server to favorites,
|
||||
or somehow trying manually to store it, because it has changing address and port.
|
||||
@@ -2,19 +2,10 @@
|
||||
|
||||
|Name |Version |Why not working |What was made for that
|
||||
|---- |------- |--------------- |----------------------
|
||||
|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-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.
|
||||
| |1.6(The latest steam release) |Uses vgui2 library which xash3d does not support. |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface. Recreated Client Source Code here: https://github.com/Velaron/cs16-client.
|
||||
|Counter Strike: Condition Zero |The latest steam release |Uses vgui2 library which xash3d does not support. |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface. Recreated Client Source Code here: https://github.com/Velaron/cs16-client.
|
||||
|Counter Strike: Condition Zero - Deleted scenes |The latest steam release |Uses vgui2 library which xash3d does not support. Uses new sequences code on engine-side that was never used in any other mods before. |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface.
|
||||
|Day of Defeat |The latest steam release |Uses vgui2 library which xash3d does not support. |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface.
|
||||
|Half-Life: Extended |Day One demo |Uses many hooks to GoldSource engine and version check. |Just wait new version or use more old version.
|
||||
|Icon of Hell |Beta 0.99 |Uses outdated BSP31 map format and paranoia 2 libraries. |You can try [this tool](https://hlfx.ru/forum/showthread.php?threadid=5250) to convert maps and use Paranoia 2: The Savior 1.51 libraries but there no warranty if it works.
|
||||
|Paranoia 2: The Savior |All builds older 1.51 |Uses an old renderer interface and engine features. |
|
||||
|Rebellion |1.0 |Uses an old WON HL 1.0.0.16- interface. |Recreated source code here: https://github.com/FWGS/hlsdk-xash3d/tree/rebellion.
|
||||
|Sven-Coop |5.0+ |Uses custom GoldSrc engine. |
|
||||
|Time Shadows |Beta 0.1 |Uses Direct3D renderer. |
|
||||
|Blue Shift |The latest steam release |Uses vgui2 library which xash3d does not support |Recreated source code here: https://github.com/FWGS/hlsdk-xash3d/tree/bshift
|
||||
|Counter Strike |1.6(The latest steam release) |Uses vgui2 library which xash3d does not support |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface
|
||||
|Counter Strike: Condition Zero |The latest steam release |Uses vgui2 library which xash3d does not support |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface
|
||||
|Counter Strike: Condition Zero - Deleted scenes |The latest steam release |Uses vgui2 library which xash3d does not support |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface
|
||||
|Day of Defeat |The latest steam release |Uses vgui2 library which xash3d does not support |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface
|
||||
|Sven-Coop |5.0+ |Uses custom GoldSrc engine |
|
||||
|
||||
|
||||
@@ -32,21 +32,12 @@ Version 1.9 mirrored on github - https://github.com/solidi/hl-mods/tree/master/c
|
||||
## Cold Ice Ressurection
|
||||
Mirrored on github - https://github.com/solidi/hl-mods/tree/master/cir
|
||||
|
||||
## Counter-Life
|
||||
Available on ModDB - https://www.moddb.com/mods/counter-life/downloads/cl-version-1-source-code
|
||||
|
||||
## Cthulhu
|
||||
Uploaded to github by Oleg Cherkasky - https://github.com/gunrunners-paradise/Cthulhu-HLmod-SDK
|
||||
|
||||
## Deathmatch Classic
|
||||
Available in Valve's Half-Life repository - https://github.com/ValveSoftware/halflife/tree/master/dmc
|
||||
|
||||
## Delta Particles
|
||||
Available on ModDB - https://www.moddb.com/mods/half-life-delta/downloads/delta-particles-full-sources-maps-and-c-code
|
||||
|
||||
## Earth Special Forces
|
||||
Alpha 2.0 - https://www.gamers-desire.de/details/2830
|
||||
|
||||
## ESHQ
|
||||
Official github repository - https://github.com/adslbarxatov/xash3d-for-ESHQ
|
||||
|
||||
@@ -127,11 +118,6 @@ Mirrored on github - https://github.com/nekonomicon/HeartOfEvil
|
||||
## Ingram Chillin' Mod
|
||||
Official SourceForge repository - https://sourceforge.net/projects/icm-hl/
|
||||
|
||||
## Master Sword
|
||||
Official github repository of Master Sword Classic - https://github.com/BerntA/MasterSwordClassic
|
||||
|
||||
Official github repository of Master Sword Rebirth - https://github.com/MSRevive/MasterSwordRebirth
|
||||
|
||||
## MechMod
|
||||
Official github repository - https://github.com/vermagav/mechmod
|
||||
|
||||
@@ -210,7 +196,7 @@ Branch **redempt** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tr
|
||||
OpenAG by YaLTeR - https://github.com/YaLTeR/OpenAG
|
||||
|
||||
## Afraid of Monsters
|
||||
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-aom
|
||||
malortie's recreation - https://github.com/malortie/hl-aom
|
||||
|
||||
Branch **aom** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/aom
|
||||
|
||||
@@ -218,17 +204,17 @@ Branch **aom** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/a
|
||||
Reverse-engineered code: branch **aomdc** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/aomdc
|
||||
|
||||
## Azure Sheep
|
||||
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-asheep
|
||||
malortie's recreation - https://github.com/malortie/hl-asheep
|
||||
|
||||
Reverse-engineered code: branch **asheep** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/asheep
|
||||
|
||||
## Big Lolly
|
||||
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-biglolly
|
||||
malortie's recreation - https://github.com/malortie/hl-biglolly
|
||||
|
||||
Branch **biglolly** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/biglolly
|
||||
|
||||
## Black Ops
|
||||
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-blackops
|
||||
malortie's recreation - https://github.com/malortie/hl-blackops
|
||||
|
||||
Branch **blackops** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/blackops
|
||||
|
||||
@@ -257,7 +243,7 @@ Recreation by lostgamer aka nillerusr - https://github.com/LostGamerHL/crack_lif
|
||||
Reverse-engineered code: branch **clcampaign** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/clcampaign
|
||||
|
||||
## Escape from the Darkness
|
||||
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-eftd
|
||||
malortie's recreation - https://github.com/malortie/hl-eftd
|
||||
|
||||
Reverse-engineered code: branch **eftd** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/eftd
|
||||
|
||||
@@ -288,7 +274,7 @@ Reverse-engineered code: branch **rebellion** in hlsdk-portable - https://github
|
||||
Branch **hl_urbicide** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/hl_urbicide
|
||||
|
||||
## Half-Life: Visitors
|
||||
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-visitors
|
||||
malortie's recreation - https://github.com/malortie/hl-visitors
|
||||
|
||||
Reverse-engineered code: branch **visitors** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/visitors
|
||||
|
||||
@@ -296,17 +282,17 @@ Reverse-engineered code: branch **visitors** in hlsdk-portable - https://github.
|
||||
Branch **half-secret** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/half-secret
|
||||
|
||||
## Night at the Office
|
||||
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-nato
|
||||
malortie's recreation - https://github.com/malortie/hl-nato
|
||||
|
||||
Branch **noffice** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/noffice
|
||||
|
||||
## Poke 646
|
||||
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-poke646
|
||||
malortie's recreation - https://github.com/malortie/hl-poke646
|
||||
|
||||
Reverse-engineered code: branch **poke646** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/poke646
|
||||
|
||||
## Poke 646: Vendetta
|
||||
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-poke646-vendetta
|
||||
malortie's recreation - https://github.com/malortie/hl-poke646-vendetta
|
||||
|
||||
Reverse-engineered code: branch **poke646_vendetta** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/poke646_vendetta
|
||||
|
||||
@@ -323,19 +309,19 @@ Branch **sewer_beta** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable
|
||||
Reverse-engineered code by Velaron - https://github.com/Velaron/tf15-client
|
||||
|
||||
## The Gate
|
||||
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-thegate
|
||||
malortie's recreation - https://github.com/malortie/hl-thegate
|
||||
|
||||
Reverse-engineered code: branch **thegate** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/thegate
|
||||
|
||||
## They Hunger
|
||||
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-theyhunger
|
||||
malortie's recreation - https://github.com/malortie/hl-theyhunger
|
||||
|
||||
Reverse-engineered code: branch **theyhunger** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/theyhunger
|
||||
|
||||
They Hunger: Tactical - https://www.moddb.com/mods/they-hunger-tactical/downloads/tht-source-code-documentation
|
||||
|
||||
## Times of Troubles
|
||||
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-tot
|
||||
malortie's recreation - https://github.com/malortie/hl-tot
|
||||
|
||||
Branch **tot** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/tot
|
||||
|
||||
@@ -357,7 +343,7 @@ Branch **dmc** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/d
|
||||
Branch **echoes** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/echoes
|
||||
|
||||
## Half-Life: Invasion
|
||||
Port to HLSDK 2.4 by malortie - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-invasion
|
||||
Port to HLSDK 2.4 by malortie - https://github.com/malortie/hl-invasion
|
||||
|
||||
Port to Linux by fmoraw - https://github.com/fmoraw/hlinvasion
|
||||
|
||||
@@ -376,7 +362,7 @@ Port to Linux - https://github.com/fmoraw/NS
|
||||
Version 1.2: branch **sohl1.2** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/sohl1.2
|
||||
|
||||
## Swiss Cheese Halloween 2002
|
||||
Just more playable version by malortie - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-shall
|
||||
Just more playable version by malortie - https://github.com/malortie/hl-shall
|
||||
|
||||
Branch **halloween** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/halloween
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
Xash3D FWGS is intended to be easily portable for various platforms, however main issue is maintaining such ports.
|
||||
Xash3D FWGS is intended to be easily ported to specific platform, however main issue is maintaining such ports.
|
||||
|
||||
This page is about merged ports to main source tree and responsible for it developers.
|
||||
|
||||
For porting guidelines, read engine-porting-guide.md.
|
||||
For porting guidelines, look engine-porting-guide.md.
|
||||
|
||||
Status:
|
||||
* **Supported**: active, confirmed to be fully functional, gets built on CI.
|
||||
* **Orphaned**: some work was done but not finished or actively tested due to lack of human resources.
|
||||
* **Supported**: active, was confirmed to be fully functional.
|
||||
* **In progress**: active, under development.
|
||||
* **Old Engine**: port was for old engine fork.
|
||||
* **Deprecated**: not supported anymore.
|
||||
* **Old Engine**: port was for old engine fork
|
||||
* **Not maintained**: lack of human resources
|
||||
* **Deprecated**: not supported anymore
|
||||
|
||||
Table is sorted by status and platform.
|
||||
|
||||
@@ -17,22 +17,17 @@ Table is sorted by status and platform.
|
||||
| -------- | ------ | ---------- | ----
|
||||
| Android | Supported | @Velaron |
|
||||
| *BSD | Supported | @nekonomicon |
|
||||
| DOS4GW | Supported | @mittorn |
|
||||
| GNU/Linux | Supported | @a1batross, @mittorn |
|
||||
| Haiku | Supported | not maintained | Was added by #478 and #483
|
||||
| macOS | Supported | @sofakng |
|
||||
| MotoMAGX | Supported | @a1batross |
|
||||
| PSVita | Supported | @fgsfdsfgs |
|
||||
| Switch | Supported | @fgsfdsfgs |
|
||||
| Windows | Supported | @a1batross, @SNMetamorph |
|
||||
| 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
|
||||
| MotoMAGX | Orphaned | N/A | Should work but the compiler used for this platform is very unstable and easy to crash (it's GCC 3.4)
|
||||
| SerenityOS | Orphaned | N/A | Works but not throughly tested
|
||||
| Solaris | Orphaned | N/A | Works but not throughly tested
|
||||
| WebAssembly System Interface | Orphaned | N/A | Undone, WASI is missing a lot of APIs we want to use
|
||||
| Dreamcast | In progress | @maximqaxd | [GitHub Repository](https://github.com/maximqaxd/xash3d-fwgs_dc/)
|
||||
| PSP | In progress | @Crow_bar, @Velaron | [GitHub Repository](https://github.com/Crow-bar/xash3d-fwgs)
|
||||
| Wii | In progress | Collaborative effort | [GitHub Repository](https://github.com/saucesaft/xash3d-wii)
|
||||
| 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
|
||||
| Emscripten | Old Engine | not maintained |
|
||||
| 3DS | Old Engine fork | not maintained | [GitHub Repository](https://github.com/masterfeizz/Xash3DS)
|
||||
| Oculus Quest | Old Engine fork | @DrBeef | [GitHub Repository](https://github.com/DrBeef/Lambda1VR)
|
||||
| iOS | Deprecated | not maintained | See GitHub issue #61
|
||||
|
||||
@@ -2,14 +2,11 @@
|
||||
|
||||
### Prerequisites
|
||||
1. Make sure your PSVita is [set up to run homebrew applications](https://vita.hacks.guide/).
|
||||
2. Install [kubridge](https://github.com/TheOfficialFloW/kubridge/releases/). It is recommended to use kubridge version `0.1`, because other versions aren't tested, we don't know are they suitable or not.
|
||||
|
||||
Worth to notice, we got reports that automatic plugins management app EasyPlugin have issues with installing kubridge plugin, so it's better to install it manually: by copying `kubridge.suprx` to your taiHEN plugins folder (usually `ux0:/tai`, but could be `ur0:/tai`) and add it to your `config.txt`, for example:
|
||||
2. Install [kubridge](https://github.com/TheOfficialFloW/kubridge/releases/) by copying `kubridge.suprx` to your taiHEN plugins folder (usually `ux0:/tai`) and add it to your `config.txt`, for example:
|
||||
```
|
||||
*KERNEL
|
||||
ux0:tai/kubridge.skprx
|
||||
```
|
||||
|
||||
3. Install `libshacccg.suprx` by following [this guide](https://cimmerian.gitbook.io/vita-troubleshooting-guide/shader-compiler/extract-libshacccg.suprx).
|
||||
|
||||
### Installation
|
||||
|
||||
15
Documentation/public-servers-rules-and-recommendations.md
Normal file
@@ -0,0 +1,15 @@
|
||||
As online community is growing, we don't want to keep bad or invalid servers on the Internet Games list. It's a common rules for all Xash3D server owners who are using default master server.
|
||||
|
||||
1. Breaking master server or clients is prohibited in any way. If you found a serious bug, contact us at contact 'at' fwgs.ru or post an issue at GitHub.
|
||||
|
||||
2. Changing settings, exploiting vulnerabilities of clients is prohibited in any way. If you found a serious bug, contact us at contact 'at' fwgs.ru or post an issue at GitHub.
|
||||
|
||||
2. Agressive advertisement and spam on other servers is prohibited in any way.
|
||||
|
||||
3. If your server is require downloading custom content, it should be available for everyone. Recommended way to deliver custom content is FastDL.
|
||||
|
||||
4. It's recommended to keep your server is up-to-date. You may use our public Debian/Ubuntu/Arch Linux [repository](https://github.com/FWGS/xash3d/wiki/How-to-set-up-a-Xash3D-Dedicated-Server-on-Debian-or-Ubuntu) to simplify updating process.
|
||||
|
||||
Just follow these rules to not get banned on our master server. Good luck, have fun!
|
||||
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
# Touch controls configuring
|
||||
|
||||
## Introduction
|
||||
|
||||
Thanks to mittorn, we have the ability to fully customize the controls in Xash3D. The new config allows you to not only add and change control buttons, but also create custom menus. There is also a built-in visual editor available, which simplifies the customization process without the need for manual file editing.
|
||||
|
||||
## Editor mode usage
|
||||
|
||||
1. Launch Xash3D and start the game.
|
||||
2. To enter the edit mode, click on the gear icon (command `touch_enableedit`).
|
||||
3. In the edit mode, the grid is displayed. The number of cells can be changed with the command `touch_grid_count` (default is 50). The grid can be disabled with the command `touch_grid_enable 0`.
|
||||
|
||||
*Touch controls layout editor*
|
||||

|
||||
|
||||
*Touch profiles window*
|
||||

|
||||
|
||||
*Touch buttons parameters window*
|
||||

|
||||
|
||||
## Layout editor features
|
||||
|
||||
* **Moving buttons**: click on a button, drag it to the desired location, and release.
|
||||
* **Resizing buttons**: place your first finger on the top left corner of the button, and use your second finger to resize it.
|
||||
* **Hiding/showing buttons**: select the button (it will turn red), then use the menu:
|
||||
* **Close**: closes the editing mode (`touch_disableedit`).
|
||||
* **Reset**: resets the button to its default values.
|
||||
* **Hide/Show**: hides or shows the button (`touch_hide <name>` / `touch_show <name>`).
|
||||
|
||||
## Working with configuration files / console
|
||||
|
||||
All changes made in the visual editor are automatically saved to the touch profile file. The files are located in the `touch_profiles` folder inside game directory. The file name depends on the selected profile.
|
||||
|
||||
### Common commands in configuration files
|
||||
|
||||
```
|
||||
// Comment: lines starting with // are ignored.
|
||||
|
||||
// Swipe zones for movement. Specify how far you need to swipe to speed up.
|
||||
// The default values are set to be optimal for a small swipe to immediately walk quickly.
|
||||
touch_forwardzone "0.060000" ; touch_sidezone "0.060000"
|
||||
|
||||
// Sensitivity settings (pitch - horizontal, yaw - vertical).
|
||||
touch_pitch ; touch_yaw
|
||||
|
||||
// Grid settings (see above).
|
||||
touch_grid_count ; touch_grid_enable
|
||||
|
||||
// Draws a border around the button.
|
||||
touch_set_stroke <thickness> <c> <v> <e> <t>
|
||||
(<r> - red; <g> - green; <b> - blue; <a> - alpha/transparency)
|
||||
|
||||
// Show (1) or hide (0) client buttons.
|
||||
touch_setclientonly
|
||||
|
||||
// Removes all buttons from the screen.
|
||||
touch_removeall
|
||||
|
||||
// Shows all available buttons in the configuration file.
|
||||
touch_list
|
||||
|
||||
// Saves the config after editing. You can specify a new file name.
|
||||
touch_config_file command.cfg
|
||||
```
|
||||
|
||||
*The full list of buttons in the standard `touch.cfg` file, displayed in the console when using `touch_list`.*
|
||||

|
||||
|
||||
|
||||
## Adding new buttons
|
||||
|
||||
To add a new button, use the console command:
|
||||
|
||||
```
|
||||
touch_addbutton "digits" "touch/key_1.png" "toggle_digits" 0.340000 0.782222 0.400000 0.888889 255 255 255 100 0
|
||||
```
|
||||
|
||||
### Parameters of `touch_addbutton` command
|
||||
|
||||
| Parameter | Description |
|
||||
| --- | --- |
|
||||
| `"digits"` | Unique name of the button. |
|
||||
| `"touch/key_1.png"` | Path to the icon file (`.png` format). If the icon is not needed, leave `""`. |
|
||||
| `"toggle_digits"` | Command to execute after clicking (for example, `"buy"` for purchase). |
|
||||
| `0.340000` | X coordinate of the upper-left corner of the button. |
|
||||
| `0.782222` | Y coordinate of the upper-left corner of the button. |
|
||||
| `0.400000` | X coordinate of the lower-right corner of the button. |
|
||||
| `0.888889` | Y coordinate of the lower-right corner of the button. |
|
||||
| `255 255 255` | Button color in RGB format. |
|
||||
| `100` | Button transparency (0 - fully transparent, 255 - fully opaque). |
|
||||
| `0` | Flags (see next section). |
|
||||
|
||||
## List of flags
|
||||
|
||||
Flags define the behavior of the button. Their values are powers of two:
|
||||
|
||||
| Flag | Value | Description |
|
||||
| --- | --- | --- |
|
||||
| `TOUCH_FL_HIDE` | 1 | Hides the button (not displayed in the game, but visible in the editor). |
|
||||
| `TOUCH_FL_NOEDIT` | 2 | Disables editing of the button in the editor. |
|
||||
| `TOUCH_FL_CLIENT` | 4 | The button is client-side (not saved in the main control file). |
|
||||
| `TOUCH_FL_MP` | 8 | The button is displayed only in multiplayer. |
|
||||
| `TOUCH_FL_SP` | 16 | The button is displayed only in singleplayer. |
|
||||
| `TOUCH_FL_DEF_SHOW` | 32 | The button is always displayed on startup. |
|
||||
| `TOUCH_FL_DEF_HIDE` | 64 | The button is always hidden on startup. |
|
||||
| `TOUCH_FL_DRAW_ADDITIVE` | 128 | The button colors are added together in blend mode. |
|
||||
| `TOUCH_FL_STROKE` | 256 | Enables outline stroke around the button. |
|
||||
|
||||
Flags can be combined by adding their values together. For example, `5 = 1 + 4` is the combination of `TOUCH_FL_HIDE` and `TOUCH_FL_CLIENT` flags, which is a hidden client button.
|
||||
|
||||
*In the image below, the `spray`, `scores`, `messagemode` buttons are displayed simultaneously with the flag 8 and `loadquick`, `savequick` with the flag 16, and each is displayed in the corresponding game mode.*
|
||||

|
||||
|
||||
## Useful commands
|
||||
|
||||
* `touch_hide <pattern>`: hides buttons by pattern.
|
||||
* `touch_setcommand`: changes the command bound to a button.
|
||||
* `touch_settexture`: quickly changes the button image.
|
||||
* `touch_setcolor`: sets the button color.
|
||||
* `touch_exportconfig`: exports the current configuration, including aspect ratio.
|
||||
|
||||
## Usage examples
|
||||
|
||||
* `touch_hide menu*` hides all buttons with names starting with `menu`.
|
||||
* `touch_setcolor "attack" 255 160 0 128` changes the color of the primary fire button from opaque white to translucent orange, similar to the color of the HUD in Half-Life.
|
||||
|
||||
*Result of executing this command*
|
||||

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

|
||||
|
||||
*View of this button in layout editor*
|
||||

|
||||
|
||||
## Tips
|
||||
|
||||
* To prevent the `look` and `move` buttons from interfering with editing other elements, place them before the others in the configuration file.
|
||||
* And vice versa, to make a button appear on top of others, place it at the end of the configuration file.
|
||||
* You can assign commands to buttons that change other buttons, see the previous section "Usage examples".
|
||||
* After editing each parameter of each individual button in the Touch Buttons section, do not forget to press Save, otherwise the applied parameters will not be saved.
|
||||
* To create your own icon for the button, you can use any graphics editor (for Android, Photo Editor by iudesk is suitable). Saving conditions:
|
||||
* Image format - `.png` with transparency (e.g. alpha channel)
|
||||
* Aspect ratio / size - 1:1 / 256x256
|
||||
* Path to the icons location - `touch/gfx` inside game directory.
|
||||
|
||||
### Additional links
|
||||
* [Handy palette for selecting color in RGB format](https://www.rapidtables.com/web/color/RGB_Color.html)
|
||||
89
README.md
@@ -1,9 +1,8 @@
|
||||
# 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" />
|
||||
[](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml) [](https://cirrus-ci.com/github/FWGS/xash3d-fwgs) \
|
||||
[](http://fwgsdiscord.mentality.rip/) [](https://t.me/flyingwithgauss) \
|
||||
[](https://github.com/FWGS/xash3d-fwgs/releases/tag/continuous)
|
||||
[](https://builds.sr.ht/~a1batross/xash3d-fwgs?) [](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml) [](https://cirrus-ci.com/github/FWGS/xash3d-fwgs) [](http://fwgsdiscord.mentality.rip/) \
|
||||
[](https://github.com/FWGS/xash3d-fwgs/releases/latest) [](https://github.com/FWGS/xash3d-fwgs/releases/tag/continuous)
|
||||
|
||||
Xash3D ([pronounced](https://ipa-reader.com/?text=ks%C9%91%CA%82) `[ksɑʂ]`) FWGS is a game engine, aimed to provide compatibility with Half-Life Engine and extend it, as well as to give game developers well known workflow.
|
||||
Xash3D (pronounced `[ksɑʂ]`) FWGS is a game engine, aimed to provide compatibility with Half-Life Engine and extend it, as well as to give game developers well known workflow.
|
||||
|
||||
Xash3D FWGS is a heavily modified fork of an original [Xash3D Engine](https://www.moddb.com/engines/xash3d-engine) by Unkle Mike.
|
||||
|
||||
@@ -12,17 +11,16 @@ Xash3D FWGS is a heavily modified fork of an original [Xash3D Engine](https://ww
|
||||
If you like Xash3D FWGS, consider supporting individual engine maintainers. By supporting us, you help to continue developing this game engine further. The sponsorship links are available in [documentation](Documentation/donate.md).
|
||||
|
||||
## Fork features
|
||||
* Steam Half-Life (HLSDK 2.5) support.
|
||||
* Steam Half-Life (HLSDK 2.4) support.
|
||||
* Crossplatform and modern compilers support: supports Windows, Linux, BSD & Android on x86 & ARM and [many more](Documentation/ports.md).
|
||||
* Better multiplayer: multiple master servers, headless dedicated server, voice chat, [GoldSrc protocol support](Documentation/goldsrc-protocol-support.md) and IPv6 support.
|
||||
* Better multiplayer support: multiple master servers, headless dedicated server, voice chat and IPv6 support.
|
||||
* Multiple renderers support: OpenGL, GLESv1, GLESv2 and Software.
|
||||
* Advanced virtual filesystem: `.pk3` and `.pk3dir` support, compatibility with GoldSrc FS module, fast case-insensitivity emulation for crossplatform.
|
||||
* Mobility API: better game integration on mobile devices (vibration, touch controls).
|
||||
* Mobility API: better game integration on mobile devices (vibration, touch controls)
|
||||
* Different input methods: touch and gamepad in addition to mouse & keyboard.
|
||||
* TrueType font rendering, as a part of mainui_cpp.
|
||||
* External VGUI support module.
|
||||
* PNG & KTX2 image format support.
|
||||
* Ogg Vorbis (`.ogg`) & Ogg Opus (`.opus`) audio formats support.
|
||||
* [A set of small improvements](Documentation/), without broken compatibility.
|
||||
|
||||
## Installation & Running
|
||||
@@ -36,22 +34,18 @@ You still needed to copy `valve` directory as all game resources located there.
|
||||
|
||||
For additional info, run Xash3D with `-help` command line key.
|
||||
|
||||
### Android
|
||||
0) Install the APK file.
|
||||
1) Copy `valve` directory to a folder named `xash` in the Internal storage.
|
||||
2) Run games from within the app.
|
||||
|
||||
## Contributing
|
||||
* 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.
|
||||
* 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
|
||||
* 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/).
|
||||
We are using Waf build system. If you have some Waf-related questions, I recommend you to read https://waf.io/book/
|
||||
|
||||
**NOTE: NEVER USE GitHub's ZIP ARCHIVES. GitHub doesn't include external dependencies we're using!**
|
||||
NOTE: NEVER USE GitHub's ZIP ARCHIVES. GitHub doesn't include external dependencies we're using!
|
||||
|
||||
### Prerequisites
|
||||
|
||||
If your CPU is x86 compatible and you're on Windows or Linux, we are building 32-bit code by default. This was done to maintain compatibility with Steam releases of Half-Life and based on it's engine games.
|
||||
Even if Xash3D FWGS does support targetting 64-bit, you can't load games without recompiling them from source code!
|
||||
|
||||
@@ -68,52 +62,31 @@ This repository contains our fork of HLSDK and restored source code for Half-Lif
|
||||
|
||||
#### GNU/Linux
|
||||
##### Debian/Ubuntu
|
||||
* Only for 32-bit engine on 64-bit x86 operating system:
|
||||
* Enable i386 on your system: `$ sudo dpkg --add-architecture i386`.
|
||||
* Install `aptitude` ([why?](https://github.com/FWGS/xash3d-fwgs/issues/1828#issuecomment-2415131759)): `$ sudo apt update && sudo apt upgrade && sudo apt install aptitude`
|
||||
* Install development tools: `$ sudo aptitude --without-recommends install git build-essential gcc-multilib g++-multilib libsdl2-dev:i386 libfreetype-dev:i386 libopus-dev:i386 libbz2-dev:i386 libvorbis-dev:i386 libopusfile-dev:i386 libogg-dev:i386`.
|
||||
* Set PKG_CONFIG_PATH environment variable to point at 32-bit libraries: `$ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig`.
|
||||
* Enable i386 on your system, if you're compiling 32-bit engine on amd64. If not, skip this
|
||||
|
||||
* For 64-bit engine on 64-bit x86 and other non-x86 systems:
|
||||
* Install development tools: `$ sudo apt install git build-essential python libsdl2-dev libfreetype6-dev libopus-dev libbz2-dev libvorbis-dev libopusfile-dev libogg-dev`.
|
||||
|
||||
* Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`.
|
||||
|
||||
##### RedHat/Fedora
|
||||
* Only for 32-bit engine on 64-bit x86 operating system:
|
||||
* Install development tools: `$ sudo dnf install git gcc gcc-c++ glibc-devel.i686 SDL2-devel.i686 opus-devel.i686 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++ SDL2-devel opus-devel freetype-devel bzip2-devel libvorbis-devel opusfile-devel libogg-devel`.
|
||||
|
||||
* Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`.
|
||||
|
||||
#### Android (Windows/Linux/macOS)
|
||||
* Install [Android Studio](https://developer.android.com/studio) (or the command line tools).
|
||||
* Install [Python](https://python.org) (at least 2.7, latest is better).
|
||||
* Install [Git](https://git-scm.com/download/win).
|
||||
* Install [Ninja](https://ninja-build.org/).
|
||||
* Install [CMake](https://cmake.org/) (for some dependencies).
|
||||
|
||||
* Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`.
|
||||
`$ sudo dpkg --add-architecture i386`
|
||||
* Install development tools
|
||||
* For 32-bit engine on amd64: \
|
||||
`$ sudo apt install build-essential gcc-multilib g++-multilib python libsdl2-dev:i386 libfontconfig-dev:i386 libfreetype6-dev:i386`
|
||||
* For everything else: \
|
||||
`$ sudo apt install build-essential python libsdl2-dev libfontconfig-dev libfreetype6-dev`
|
||||
* Clone this repostory:
|
||||
`$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`
|
||||
|
||||
### Building
|
||||
#### Windows (Visual Studio)
|
||||
0) Open command line.
|
||||
0) Open command line
|
||||
1) Navigate to `xash3d-fwgs` directory.
|
||||
2) (optional) Examine which build options are available: `waf --help`.
|
||||
3) Configure build: `waf configure --sdl2=c:/path/to/SDL2`.
|
||||
4) Compile: `waf build`.
|
||||
5) Install: `waf install --destdir=c:/path/to/any/output/directory`.
|
||||
2) Carefully examine which build options are available: `waf --help`
|
||||
3) Configure build: `waf configure -T release --sdl2=c:/path/to/SDL2`
|
||||
4) Compile: `waf build`
|
||||
5) Install: `waf install --destdir=c:/path/to/any/output/directory`
|
||||
|
||||
#### Linux
|
||||
If compiling 32-bit on amd64, make sure `PKG_CONFIG_PATH` from the previous step is set correctly, prior to running configure.
|
||||
If compiling 32-bit on amd64, you may need to supply `export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig` prior to running configure.
|
||||
|
||||
0) (optional) Examine which build options are available: `./waf --help`.
|
||||
1) Configure build: `./waf configure` (you need to pass `-8` to compile 64-bit engine on 64-bit x86 processor).
|
||||
2) Compile: `./waf build`.
|
||||
3) Install: `./waf install --destdir=/path/to/any/output/directory`.
|
||||
|
||||
#### Android (Windows/Linux/macOS)
|
||||
You can just open the `android` folder in Android Studio and build from here, or use `gradlew` to build from command line.
|
||||
0) Examine which build options are available: `./waf --help`
|
||||
1) Configure build: `./waf configure -T release`
|
||||
(You need to pass `-8` to compile 64-bit engine on 64-bit x86 processor)
|
||||
2) Compile: `./waf build`
|
||||
3) Install(optional): `./waf install --destdir=/path/to/any/output/directory`
|
||||
|
||||
14
android/.gitignore
vendored
@@ -1,14 +0,0 @@
|
||||
.gradle/
|
||||
build/
|
||||
.externalNativeBuild
|
||||
.cxx/
|
||||
.idea/
|
||||
local.properties
|
||||
.project
|
||||
.classpath
|
||||
.gradle
|
||||
.settings
|
||||
release/
|
||||
*.hprof
|
||||
.vscode/
|
||||
*.bak
|
||||
@@ -1,140 +0,0 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import java.time.LocalDateTime
|
||||
import java.time.Month
|
||||
import java.time.temporal.ChronoUnit
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.android.application)
|
||||
alias(libs.plugins.kotlin.android)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "su.xash.engine"
|
||||
ndkVersion = "28.2.13676358"
|
||||
compileSdk = 35
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "su.xash.engine"
|
||||
versionName = "0.21-" + getGitHash()
|
||||
versionCode = getBuildNum()
|
||||
minSdk = 21
|
||||
targetSdk = 35
|
||||
|
||||
externalNativeBuild {
|
||||
val engineRoot = projectDir.parentFile.parent
|
||||
|
||||
experimentalProperties["ninja.abiFilters"] = setOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
|
||||
experimentalProperties["ninja.path"] = File(engineRoot, "wscript").path
|
||||
experimentalProperties["ninja.configure"] = "run-python"
|
||||
experimentalProperties["ninja.arguments"] = setOf(
|
||||
File(engineRoot, "scripts/configure-ninja.py").path,
|
||||
engineRoot,
|
||||
"--variant=\${ndk.variantName}",
|
||||
"--abi=\${ndk.abi}",
|
||||
"--configuration-dir=\${ndk.buildRoot}",
|
||||
"--ndk-version=\${ndk.moduleNdkVersion}",
|
||||
"--min-sdk-version=\${ndk.minPlatform}",
|
||||
"--ndk-root=${android.ndkDirectory}",
|
||||
// shut up, fake options
|
||||
"-p:Configuration=\${ndk.variantName}",
|
||||
"-p:Platform=\${ndk.abi}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
jvmTarget = JvmTarget.JVM_11
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
lint {
|
||||
abortOnError = false
|
||||
}
|
||||
|
||||
/*
|
||||
androidResources {
|
||||
noCompress += ""
|
||||
}
|
||||
*/
|
||||
|
||||
packaging {
|
||||
jniLibs {
|
||||
keepDebugSymbols.add("**/*.so")
|
||||
useLegacyPackaging = true
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
getByName("main") {
|
||||
assets.srcDirs("../../3rdparty/extras/xash-extras")
|
||||
java.srcDir("../../3rdparty/SDL/android-project/app/src/main/java")
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
isMinifyEnabled = false
|
||||
isShrinkResources = false
|
||||
isDebuggable = true
|
||||
applicationIdSuffix = ".test"
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
|
||||
register("asan") {
|
||||
initWith(getByName("debug"))
|
||||
}
|
||||
|
||||
register("continuous") {
|
||||
initWith(getByName("release"))
|
||||
applicationIdSuffix = ".test"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.material)
|
||||
|
||||
implementation(libs.appcompat)
|
||||
implementation(libs.navigation.runtime.ktx)
|
||||
implementation(libs.navigation.fragment.ktx)
|
||||
implementation(libs.navigation.ui.ktx)
|
||||
implementation(libs.preference.ktx)
|
||||
implementation(libs.swiperefreshlayout)
|
||||
|
||||
implementation(libs.acra.http)
|
||||
}
|
||||
|
||||
fun getBuildNum(): Int {
|
||||
val now = LocalDateTime.now()
|
||||
val releaseDate = LocalDateTime.of(2015, Month.APRIL, 1, 0, 0, 0)
|
||||
val qBuildNum = releaseDate.until(now, ChronoUnit.DAYS)
|
||||
val minuteOfDay = now.hour * 60 + now.minute
|
||||
return (qBuildNum * 10000 + minuteOfDay).toInt()
|
||||
}
|
||||
|
||||
fun getGitHash(): String {
|
||||
val process = ProcessBuilder("git", "rev-parse", "--short", "HEAD").directory(project.rootDir)
|
||||
.redirectErrorStream(true).start()
|
||||
return process.inputStream.bufferedReader().readText().trim()
|
||||
}
|
||||
116
android/app/proguard-rules.pro
vendored
@@ -1,116 +0,0 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
-keep class su.xash.engine.XashActivity {
|
||||
java.lang.String loadAndroidID();
|
||||
java.lang.String getAndroidID();
|
||||
void saveAndroidID(java.lang.String);
|
||||
java.lang.String getCallingPackage();
|
||||
java.lang.String[] getAssetsList(boolean, java.lang.String);
|
||||
android.content.res.AssetManager getAssets(boolean);
|
||||
}
|
||||
|
||||
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLInputConnection {
|
||||
void nativeCommitText(java.lang.String, int);
|
||||
void nativeGenerateScancodeForUnichar(char);
|
||||
}
|
||||
|
||||
-keep,includedescriptorclasses class org.libsdl.app.SDLActivity {
|
||||
# for some reason these aren't compatible with allowoptimization modifier
|
||||
boolean supportsRelativeMouse();
|
||||
void setWindowStyle(boolean);
|
||||
}
|
||||
|
||||
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLActivity {
|
||||
java.lang.String nativeGetHint(java.lang.String); # Java-side doesn't use this, so it gets minified, but C-side still tries to register it
|
||||
boolean onNativeSoftReturnKey();
|
||||
void onNativeKeyboardFocusLost();
|
||||
boolean isScreenKeyboardShown();
|
||||
android.util.DisplayMetrics getDisplayDPI();
|
||||
java.lang.String clipboardGetText();
|
||||
boolean clipboardHasText();
|
||||
void clipboardSetText(java.lang.String);
|
||||
int createCustomCursor(int[], int, int, int, int);
|
||||
void destroyCustomCursor(int);
|
||||
android.content.Context getContext();
|
||||
boolean getManifestEnvironmentVariables();
|
||||
android.view.Surface getNativeSurface();
|
||||
void initTouch();
|
||||
boolean isAndroidTV();
|
||||
boolean isChromebook();
|
||||
boolean isDeXMode();
|
||||
boolean isTablet();
|
||||
void manualBackButton();
|
||||
int messageboxShowMessageBox(int, java.lang.String, java.lang.String, int[], int[], java.lang.String[], int[]);
|
||||
void minimizeWindow();
|
||||
int openURL(java.lang.String);
|
||||
void requestPermission(java.lang.String, int);
|
||||
int showToast(java.lang.String, int, int, int, int);
|
||||
boolean sendMessage(int, int);
|
||||
boolean setActivityTitle(java.lang.String);
|
||||
boolean setCustomCursor(int);
|
||||
void setOrientation(int, int, boolean, java.lang.String);
|
||||
boolean setRelativeMouseEnabled(boolean);
|
||||
boolean setSystemCursor(int);
|
||||
boolean shouldMinimizeOnFocusLoss();
|
||||
boolean showTextInput(int, int, int, int);
|
||||
}
|
||||
|
||||
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.HIDDeviceManager {
|
||||
boolean initialize(boolean, boolean);
|
||||
boolean openDevice(int);
|
||||
int sendOutputReport(int, byte[]);
|
||||
int sendFeatureReport(int, byte[]);
|
||||
boolean getFeatureReport(int, byte[]);
|
||||
void closeDevice(int);
|
||||
}
|
||||
|
||||
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLAudioManager {
|
||||
int[] getAudioOutputDevices();
|
||||
int[] getAudioInputDevices();
|
||||
int[] audioOpen(int, int, int, int, int);
|
||||
void audioWriteFloatBuffer(float[]);
|
||||
void audioWriteShortBuffer(short[]);
|
||||
void audioWriteByteBuffer(byte[]);
|
||||
void audioClose();
|
||||
int[] captureOpen(int, int, int, int, int);
|
||||
int captureReadFloatBuffer(float[], boolean);
|
||||
int captureReadShortBuffer(short[], boolean);
|
||||
int captureReadByteBuffer(byte[], boolean);
|
||||
void captureClose();
|
||||
void audioSetThreadPriority(boolean, int);
|
||||
native int nativeSetupJNI();
|
||||
native void removeAudioDevice(boolean, int);
|
||||
native void addAudioDevice(boolean, int);
|
||||
}
|
||||
|
||||
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLControllerManager {
|
||||
void pollInputDevices();
|
||||
void pollHapticDevices();
|
||||
void hapticRun(int, float, int);
|
||||
void hapticStop(int);
|
||||
}
|
||||
|
||||
# Unexpected reference to missing service class: META-INF/services/javax.annotation.processing.Processor.
|
||||
-dontwarn javax.annotation.processing.Processor
|
||||
-dontwarn javax.annotation.processing.AbstractProcessor
|
||||
-dontwarn javax.annotation.processing.SupportedOptions
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
exec python $@
|
||||
@@ -1 +0,0 @@
|
||||
python %*
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name" translatable="false">Xash3D FWGS (Test)</string>
|
||||
<string name="authority" translatable="false">su.xash.engine.test.documents</string>
|
||||
</resources>
|
||||
@@ -1,26 +0,0 @@
|
||||
|
||||
#!/system/bin/sh
|
||||
HERE=$(cd "$(dirname "$0")" && pwd)
|
||||
cmd=$1
|
||||
shift
|
||||
# This must be called *before* `LD_PRELOAD` is set. Otherwise, if this is a 32-
|
||||
# bit app running on a 64-bit device, the 64-bit getprop will fail to load
|
||||
# because it will preload a 32-bit ASan runtime.
|
||||
# https://github.com/android/ndk/issues/1744
|
||||
os_version=$(getprop ro.build.version.sdk)
|
||||
if [ "$os_version" -eq "27" ]; then
|
||||
cmd="$cmd -Xrunjdwp:transport=dt_android_adb,suspend=n,server=y -Xcompiler-option --debuggable $@"
|
||||
elif [ "$os_version" -eq "28" ]; then
|
||||
cmd="$cmd -XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y -Xcompiler-option --debuggable $@"
|
||||
else
|
||||
cmd="$cmd -XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y $@"
|
||||
fi
|
||||
export ASAN_OPTIONS=log_to_syslog=false,allow_user_segv_handler=1
|
||||
ASAN_LIB=$(ls "$HERE"/libclang_rt.asan-*-android.so)
|
||||
if [ -f "$HERE/libc++_shared.so" ]; then
|
||||
# Workaround for https://github.com/android-ndk/ndk/issues/988.
|
||||
export LD_PRELOAD="$ASAN_LIB $HERE/libc++_shared.so"
|
||||
else
|
||||
export LD_PRELOAD="$ASAN_LIB"
|
||||
fi
|
||||
exec $cmd
|
||||
@@ -1,26 +0,0 @@
|
||||
|
||||
#!/system/bin/sh
|
||||
HERE=$(cd "$(dirname "$0")" && pwd)
|
||||
cmd=$1
|
||||
shift
|
||||
# This must be called *before* `LD_PRELOAD` is set. Otherwise, if this is a 32-
|
||||
# bit app running on a 64-bit device, the 64-bit getprop will fail to load
|
||||
# because it will preload a 32-bit ASan runtime.
|
||||
# https://github.com/android/ndk/issues/1744
|
||||
os_version=$(getprop ro.build.version.sdk)
|
||||
if [ "$os_version" -eq "27" ]; then
|
||||
cmd="$cmd -Xrunjdwp:transport=dt_android_adb,suspend=n,server=y -Xcompiler-option --debuggable $@"
|
||||
elif [ "$os_version" -eq "28" ]; then
|
||||
cmd="$cmd -XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y -Xcompiler-option --debuggable $@"
|
||||
else
|
||||
cmd="$cmd -XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y $@"
|
||||
fi
|
||||
export ASAN_OPTIONS=log_to_syslog=false,allow_user_segv_handler=1
|
||||
ASAN_LIB=$(ls "$HERE"/libclang_rt.asan-*-android.so)
|
||||
if [ -f "$HERE/libc++_shared.so" ]; then
|
||||
# Workaround for https://github.com/android-ndk/ndk/issues/988.
|
||||
export LD_PRELOAD="$ASAN_LIB $HERE/libc++_shared.so"
|
||||
else
|
||||
export LD_PRELOAD="$ASAN_LIB"
|
||||
fi
|
||||
exec $cmd
|
||||
@@ -1,26 +0,0 @@
|
||||
|
||||
#!/system/bin/sh
|
||||
HERE=$(cd "$(dirname "$0")" && pwd)
|
||||
cmd=$1
|
||||
shift
|
||||
# This must be called *before* `LD_PRELOAD` is set. Otherwise, if this is a 32-
|
||||
# bit app running on a 64-bit device, the 64-bit getprop will fail to load
|
||||
# because it will preload a 32-bit ASan runtime.
|
||||
# https://github.com/android/ndk/issues/1744
|
||||
os_version=$(getprop ro.build.version.sdk)
|
||||
if [ "$os_version" -eq "27" ]; then
|
||||
cmd="$cmd -Xrunjdwp:transport=dt_android_adb,suspend=n,server=y -Xcompiler-option --debuggable $@"
|
||||
elif [ "$os_version" -eq "28" ]; then
|
||||
cmd="$cmd -XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y -Xcompiler-option --debuggable $@"
|
||||
else
|
||||
cmd="$cmd -XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y $@"
|
||||
fi
|
||||
export ASAN_OPTIONS=log_to_syslog=false,allow_user_segv_handler=1
|
||||
ASAN_LIB=$(ls "$HERE"/libclang_rt.asan-*-android.so)
|
||||
if [ -f "$HERE/libc++_shared.so" ]; then
|
||||
# Workaround for https://github.com/android-ndk/ndk/issues/988.
|
||||
export LD_PRELOAD="$ASAN_LIB $HERE/libc++_shared.so"
|
||||
else
|
||||
export LD_PRELOAD="$ASAN_LIB"
|
||||
fi
|
||||
exec $cmd
|
||||
@@ -1,26 +0,0 @@
|
||||
|
||||
#!/system/bin/sh
|
||||
HERE=$(cd "$(dirname "$0")" && pwd)
|
||||
cmd=$1
|
||||
shift
|
||||
# This must be called *before* `LD_PRELOAD` is set. Otherwise, if this is a 32-
|
||||
# bit app running on a 64-bit device, the 64-bit getprop will fail to load
|
||||
# because it will preload a 32-bit ASan runtime.
|
||||
# https://github.com/android/ndk/issues/1744
|
||||
os_version=$(getprop ro.build.version.sdk)
|
||||
if [ "$os_version" -eq "27" ]; then
|
||||
cmd="$cmd -Xrunjdwp:transport=dt_android_adb,suspend=n,server=y -Xcompiler-option --debuggable $@"
|
||||
elif [ "$os_version" -eq "28" ]; then
|
||||
cmd="$cmd -XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y -Xcompiler-option --debuggable $@"
|
||||
else
|
||||
cmd="$cmd -XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y $@"
|
||||
fi
|
||||
export ASAN_OPTIONS=log_to_syslog=false,allow_user_segv_handler=1
|
||||
ASAN_LIB=$(ls "$HERE"/libclang_rt.asan-*-android.so)
|
||||
if [ -f "$HERE/libc++_shared.so" ]; then
|
||||
# Workaround for https://github.com/android-ndk/ndk/issues/988.
|
||||
export LD_PRELOAD="$ASAN_LIB $HERE/libc++_shared.so"
|
||||
else
|
||||
export LD_PRELOAD="$ASAN_LIB"
|
||||
fi
|
||||
exec $cmd
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name" translatable="false">Xash3D FWGS (Test)</string>
|
||||
<string name="authority" translatable="false">su.xash.engine.test.documents</string>
|
||||
</resources>
|
||||
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name" translatable="false">Xash3D FWGS (Test)</string>
|
||||
</resources>
|
||||
@@ -1,89 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:allowAudioPlaybackCapture="true"
|
||||
android:installLocation="preferExternal">
|
||||
<!-- OpenGL ES 1.1 -->
|
||||
<uses-feature android:glEsVersion="0x00010000" />
|
||||
<!-- Touchscreen support -->
|
||||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
android:required="false" />
|
||||
<!-- Game controller support -->
|
||||
<uses-feature
|
||||
android:name="android.hardware.bluetooth"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.gamepad"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.usb.host"
|
||||
android:required="false" />
|
||||
<!-- External mouse input events -->
|
||||
<uses-feature
|
||||
android:name="android.hardware.type.pc"
|
||||
android:required="false" />
|
||||
<!-- Audio recording support -->
|
||||
<uses-feature
|
||||
android:name="android.hardware.microphone"
|
||||
android:required="false" />
|
||||
<!-- Allow downloading to the external storage on Android 5.1 and older -->
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="22" />
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
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 -->
|
||||
<uses-permission
|
||||
android:name="android.permission.BLUETOOTH"
|
||||
android:maxSdkVersion="30" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<!-- Allow access to the vibrator -->
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<!-- Allow recording audio -->
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<!-- Allow internet access -->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<!-- Dedicated server -->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
android:allowBackup="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher"
|
||||
android:theme="@style/Theme.App"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:requestLegacyExternalStorage="true">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".XashActivity"
|
||||
android:alwaysRetainTaskState="true"
|
||||
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation|touchscreen"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:preferMinimalPostProcessing="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="su.xash.engine.MOD" />
|
||||
</intent>
|
||||
</queries>
|
||||
</manifest>
|
||||
@@ -1,3 +0,0 @@
|
||||
package su.xash.engine
|
||||
|
||||
class DedicatedActivity {}
|
||||
@@ -1,11 +0,0 @@
|
||||
package su.xash.engine
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
|
||||
class DedicatedService : Service() {
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package su.xash.engine
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.ui.AppBarConfiguration
|
||||
import androidx.navigation.ui.navigateUp
|
||||
import androidx.navigation.ui.setupActionBarWithNavController
|
||||
import su.xash.engine.databinding.ActivityMainBinding
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
private lateinit var appBarConfiguration: AppBarConfiguration
|
||||
private lateinit var navController: NavController
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
setSupportActionBar(binding.toolbar)
|
||||
|
||||
val navHostFragment =
|
||||
supportFragmentManager.findFragmentById(R.id.fragmentContainerView) as NavHostFragment
|
||||
navController = navHostFragment.navController
|
||||
appBarConfiguration = AppBarConfiguration(navController.graph)
|
||||
setupActionBarWithNavController(navController, appBarConfiguration)
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package su.xash.engine
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.os.StrictMode
|
||||
import org.acra.data.StringFormat
|
||||
import org.acra.ktx.initAcra
|
||||
|
||||
class MainApplication : Application() {
|
||||
override fun attachBaseContext(base: Context?) {
|
||||
super.attachBaseContext(base)
|
||||
|
||||
if (!BuildConfig.DEBUG) {
|
||||
initAcra {
|
||||
buildConfigClass = BuildConfig::class.java
|
||||
reportFormat = StringFormat.JSON
|
||||
|
||||
// httpSender {
|
||||
// uri = "http://bodis.pp.ua:5000/report"
|
||||
// }
|
||||
}
|
||||
} else {
|
||||
// enable strict mode to detect memory leaks etc.
|
||||
StrictMode.enableDefaults();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
package su.xash.engine;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.AssetManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.provider.Settings.Secure;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import org.libsdl.app.SDLActivity;
|
||||
|
||||
import su.xash.engine.util.AndroidBug5497Workaround;
|
||||
|
||||
public class XashActivity extends SDLActivity {
|
||||
private boolean mUseVolumeKeys;
|
||||
private String mPackageName;
|
||||
private static final String TAG = "XashActivity";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
//getWindow().addFlags(WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES);
|
||||
getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
|
||||
}
|
||||
|
||||
AndroidBug5497Workaround.assistActivity(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
// Now that we don't exit from native code, we need to exit here, resetting
|
||||
// application state (actually global variables that we don't cleanup on exit)
|
||||
//
|
||||
// When the issue with global variables will be resolved, remove that exit() call
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getLibraries() {
|
||||
return new String[]{"SDL2", "xash"};
|
||||
}
|
||||
|
||||
@SuppressLint("HardwareIds")
|
||||
private String getAndroidID() {
|
||||
return Secure.getString(getContentResolver(), Secure.ANDROID_ID);
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
private void saveAndroidID(String id) {
|
||||
getSharedPreferences("xash_preferences", MODE_PRIVATE).edit().putString("xash_id", id).commit();
|
||||
}
|
||||
|
||||
private String loadAndroidID() {
|
||||
return getSharedPreferences("xash_preferences", MODE_PRIVATE).getString("xash_id", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCallingPackage() {
|
||||
if (mPackageName != null) {
|
||||
return mPackageName;
|
||||
}
|
||||
|
||||
return super.getCallingPackage();
|
||||
}
|
||||
|
||||
private AssetManager getAssets(boolean isEngine) {
|
||||
AssetManager am = null;
|
||||
|
||||
if (isEngine) {
|
||||
am = getAssets();
|
||||
} else {
|
||||
try {
|
||||
am = getPackageManager().getResourcesForApplication(getCallingPackage()).getAssets();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Unable to load mod assets!");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return am;
|
||||
}
|
||||
|
||||
private String[] getAssetsList(boolean isEngine, String path) {
|
||||
AssetManager am = getAssets(isEngine);
|
||||
|
||||
try {
|
||||
return am.list(path);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return new String[]{};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (SDLActivity.mBrokenLibraries) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int keyCode = event.getKeyCode();
|
||||
if (!mUseVolumeKeys) {
|
||||
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_CAMERA || keyCode == KeyEvent.KEYCODE_ZOOM_IN || keyCode == KeyEvent.KEYCODE_ZOOM_OUT) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return getWindow().superDispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
// TODO: REMOVE LATER, temporary launchers support?
|
||||
@Override
|
||||
protected String[] getArguments() {
|
||||
String gamedir = getIntent().getStringExtra("gamedir");
|
||||
if (gamedir == null) gamedir = "valve";
|
||||
nativeSetenv("XASH3D_GAME", gamedir);
|
||||
|
||||
String gamelibdir = getIntent().getStringExtra("gamelibdir");
|
||||
if (gamelibdir != null) nativeSetenv("XASH3D_GAMELIBDIR", gamelibdir);
|
||||
|
||||
String pakfile = getIntent().getStringExtra("pakfile");
|
||||
if (pakfile != null) nativeSetenv("XASH3D_EXTRAS_PAK2", pakfile);
|
||||
|
||||
String basedir = getIntent().getStringExtra("basedir");
|
||||
if (basedir != null) {
|
||||
nativeSetenv("XASH3D_BASEDIR", basedir);
|
||||
} else {
|
||||
String rootPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/xash";
|
||||
nativeSetenv("XASH3D_BASEDIR", rootPath);
|
||||
}
|
||||
|
||||
mUseVolumeKeys = getIntent().getBooleanExtra("usevolume", false);
|
||||
mPackageName = getIntent().getStringExtra("package");
|
||||
|
||||
String[] env = getIntent().getStringArrayExtra("env");
|
||||
if (env != null) {
|
||||
for (int i = 0; i < env.length; i += 2)
|
||||
nativeSetenv(env[i], env[i + 1]);
|
||||
}
|
||||
|
||||
String argv = getIntent().getStringExtra("argv");
|
||||
if (argv == null) argv = "-console -log";
|
||||
return argv.split(" ");
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package su.xash.engine.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import su.xash.engine.R
|
||||
import su.xash.engine.databinding.CardGameBinding
|
||||
import su.xash.engine.model.Game
|
||||
import su.xash.engine.ui.library.LibraryViewModel
|
||||
|
||||
|
||||
class GameAdapter(private val libraryViewModel: LibraryViewModel) :
|
||||
ListAdapter<Game, GameAdapter.GameViewHolder>(DiffCallback()) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameAdapter.GameViewHolder {
|
||||
val binding = CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return GameViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: GameAdapter.GameViewHolder, position: Int) {
|
||||
return holder.bind(getItem(position))
|
||||
}
|
||||
|
||||
private class DiffCallback : DiffUtil.ItemCallback<Game>() {
|
||||
override fun areItemsTheSame(oldItem: Game, newItem: Game): Boolean {
|
||||
return oldItem.basedir.name == newItem.basedir.name
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean {
|
||||
return oldItem.basedir.name == newItem.basedir.name
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inner class GameViewHolder(val binding: CardGameBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
fun bind(game: Game) {
|
||||
binding.apply {
|
||||
gameTitle.text = game.title
|
||||
|
||||
if (game.icon != null) {
|
||||
gameIcon.setImageBitmap(game.icon)
|
||||
} else {
|
||||
gameIcon.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (game.cover != null) {
|
||||
gameCover.setImageBitmap(game.cover)
|
||||
} else {
|
||||
gameCover.visibility = View.GONE
|
||||
}
|
||||
|
||||
settingsButton.setOnClickListener {
|
||||
libraryViewModel.setSelectedGame(game)
|
||||
it.findNavController()
|
||||
.navigate(R.id.action_libraryFragment_to_gameSettingsFragment)
|
||||
}
|
||||
|
||||
root.setOnClickListener { libraryViewModel.startEngine(it.context, game) }
|
||||
launchButton.setOnClickListener {
|
||||
libraryViewModel.startEngine(it.context, game)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package su.xash.engine.model
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import su.xash.engine.util.TGAReader
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.util.Scanner
|
||||
|
||||
|
||||
object BackgroundBitmap {
|
||||
private const val BACKGROUND_ROWS = 3
|
||||
private const val BACKGROUND_COLUMNS = 4
|
||||
private const val BACKGROUND_WIDTH = 800
|
||||
private const val BACKGROUND_HEIGHT = 600
|
||||
|
||||
fun createBackground(file: File): Bitmap {
|
||||
var bitmap =
|
||||
Bitmap.createBitmap(BACKGROUND_WIDTH, BACKGROUND_HEIGHT, Bitmap.Config.ARGB_8888)
|
||||
var canvas = Canvas(bitmap)
|
||||
var x: Int
|
||||
var y = 0
|
||||
var width: Int
|
||||
var height = 0
|
||||
|
||||
val resourceFolder = File(file, "resource")
|
||||
var bgLayout = File(resourceFolder, "HD_BackgroundLayout.txt")
|
||||
if (!bgLayout.exists()) {
|
||||
bgLayout = File(resourceFolder, "BackgroundLayout.txt")
|
||||
}
|
||||
|
||||
if (!bgLayout.exists()) {
|
||||
val dir = File(resourceFolder, "background")
|
||||
for (i in 0 until BACKGROUND_ROWS) {
|
||||
x = 0
|
||||
for (j in 0 until BACKGROUND_COLUMNS) {
|
||||
val filename = "${BACKGROUND_WIDTH}_${i + 1}_${'a' + j}_loading.tga"
|
||||
val bmpFile = File(dir, filename)
|
||||
val bmpImage = loadTga(bmpFile)
|
||||
|
||||
canvas.drawBitmap(bmpImage, x.toFloat(), y.toFloat(), null)
|
||||
x += bmpImage.width
|
||||
height = bmpImage.height
|
||||
|
||||
}
|
||||
y += height
|
||||
}
|
||||
return bitmap
|
||||
}
|
||||
|
||||
FileInputStream(bgLayout).use { inputStream ->
|
||||
Scanner(inputStream).use { scanner ->
|
||||
while (scanner.hasNext()) {
|
||||
when (val str = scanner.next()) {
|
||||
"resolution" -> {
|
||||
width = scanner.nextInt()
|
||||
height = scanner.nextInt()
|
||||
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
|
||||
canvas = Canvas(bitmap)
|
||||
}
|
||||
|
||||
else -> {
|
||||
var bmpFile = file
|
||||
str.split("/").forEach { bmpFile = File(bmpFile, it) }
|
||||
//skip
|
||||
scanner.next()
|
||||
x = scanner.nextInt()
|
||||
y = scanner.nextInt()
|
||||
val bmp = loadTga(bmpFile)
|
||||
canvas.drawBitmap(bmp, x.toFloat(), y.toFloat(), null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bitmap
|
||||
}
|
||||
|
||||
private fun loadTga(file: File): Bitmap {
|
||||
FileInputStream(file).use {
|
||||
val buffer = it.readBytes()
|
||||
val pixels = TGAReader.read(buffer, TGAReader.ARGB)
|
||||
|
||||
val width = TGAReader.getWidth(buffer)
|
||||
val height = TGAReader.getHeight(buffer)
|
||||
|
||||
return Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_8888)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
package su.xash.engine.model
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
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) {
|
||||
private var iconName = "game.ico"
|
||||
var title = "Unknown Game"
|
||||
var icon: Bitmap? = null
|
||||
var cover: Bitmap? = null
|
||||
|
||||
private val pref = ctx.getSharedPreferences(basedir.name, Context.MODE_PRIVATE)
|
||||
|
||||
init {
|
||||
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()) {
|
||||
icon = BitmapFactory.decodeFile(iconFile.path)
|
||||
}
|
||||
|
||||
try {
|
||||
cover = BackgroundBitmap.createBackground(basedir)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun startEngine(ctx: Context) {
|
||||
ctx.startActivity(Intent(ctx, XashActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
putExtra("gamedir", basedir.name)
|
||||
putExtra("argv", pref.getString("arguments", "-console -log"))
|
||||
putExtra("usevolume", pref.getBoolean("use_volume_buttons", false))
|
||||
putExtra("basedir", basedir.parent)
|
||||
//.putExtra("gamelibdir", getGameLibDir(context))
|
||||
//.putExtra("package", getPackageName()) }
|
||||
})
|
||||
}
|
||||
|
||||
private fun parseGameInfo(file: File) {
|
||||
FileInputStream(file).use { inputStream ->
|
||||
inputStream.bufferedReader().use { reader ->
|
||||
reader.forEachLine {
|
||||
val tokens = it.split("\\s+".toRegex(), limit = 2)
|
||||
if (tokens.size >= 2) {
|
||||
val k = tokens[0]
|
||||
val v = tokens[1].trim('"')
|
||||
|
||||
if (k == "title" || k == "game") title = v
|
||||
if (k == "icon") iconName = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPackageName(): String? {
|
||||
// return if (mDbEntry != null) {
|
||||
// mDbEntry.getPackageName()
|
||||
// } else null
|
||||
return null
|
||||
}
|
||||
|
||||
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, file: File): List<Game> {
|
||||
val games = mutableListOf<Game>()
|
||||
|
||||
if (checkIfGamedir(file)) {
|
||||
games.add(Game(ctx, file))
|
||||
} else {
|
||||
file.listFiles()?.forEach {
|
||||
if (it.isDirectory) {
|
||||
if (checkIfGamedir(it)) {
|
||||
games.add(Game(ctx, it))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return games
|
||||
}
|
||||
|
||||
fun checkIfGamedir(file: File): Boolean {
|
||||
if (File(file, "liblist.gam").exists()) return true
|
||||
if (File(file, "gameinfo.txt").exists()) return true
|
||||
|
||||
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()));
|
||||
//}
|
||||
@@ -1,110 +0,0 @@
|
||||
package su.xash.engine.ui.library
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.provider.Settings
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.MenuProvider
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import su.xash.engine.BuildConfig
|
||||
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!!
|
||||
|
||||
private val libraryViewModel: LibraryViewModel by activityViewModels()
|
||||
|
||||
private val startActivityForResult =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
if (checkStoragePermissions()) {
|
||||
libraryViewModel.reloadGames(requireContext())
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkStoragePermissions(): Boolean {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) {
|
||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||
setTitle(R.string.file_access_required)
|
||||
setMessage(R.string.file_access_message)
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
startActivityForResult.launch(
|
||||
Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).setData(
|
||||
Uri.fromParts("package", BuildConfig.APPLICATION_ID, null)
|
||||
)
|
||||
)
|
||||
}
|
||||
setCancelable(false)
|
||||
show()
|
||||
}
|
||||
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentLibraryBinding.inflate(inflater, container, false)
|
||||
|
||||
val adapter = GameAdapter(libraryViewModel)
|
||||
binding.gamesList.adapter = adapter
|
||||
|
||||
requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED)
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
binding.swipeRefresh.setOnRefreshListener { libraryViewModel.reloadGames(requireContext()) }
|
||||
|
||||
libraryViewModel.isReloading.observe(viewLifecycleOwner) {
|
||||
binding.swipeRefresh.isRefreshing = it
|
||||
}
|
||||
|
||||
libraryViewModel.installedGames.observe(viewLifecycleOwner) {
|
||||
(binding.gamesList.adapter as GameAdapter).submitList(it)
|
||||
}
|
||||
|
||||
if (checkStoragePermissions()) {
|
||||
libraryViewModel.reloadGames(requireContext())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||
menuInflater.inflate(R.menu.menu_library, menu)
|
||||
}
|
||||
|
||||
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
||||
when (menuItem.itemId) {
|
||||
R.id.action_settings -> {
|
||||
findNavController().navigate(R.id.action_libraryFragment_to_appSettingsFragment)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package su.xash.engine.ui.library
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Environment
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import su.xash.engine.model.Game
|
||||
import java.io.File
|
||||
|
||||
class LibraryViewModel(application: Application) : AndroidViewModel(application) {
|
||||
val installedGames: LiveData<List<Game>> get() = _installedGames
|
||||
private val _installedGames = MutableLiveData(emptyList<Game>())
|
||||
|
||||
val isReloading: LiveData<Boolean> get() = _isReloading
|
||||
private val _isReloading = MutableLiveData(false)
|
||||
|
||||
val selectedItem: LiveData<Game> get() = _selectedItem
|
||||
private val _selectedItem = MutableLiveData<Game>()
|
||||
|
||||
private val appPreferences: SharedPreferences =
|
||||
application.getSharedPreferences("app_preferences", Context.MODE_PRIVATE)
|
||||
|
||||
fun reloadGames(ctx: Context) {
|
||||
if (isReloading.value == true) {
|
||||
return
|
||||
}
|
||||
_isReloading.value = true
|
||||
|
||||
viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
val rootPath = appPreferences.getString("game_path", null)
|
||||
?: (Environment.getExternalStorageDirectory().absolutePath + "/xash")
|
||||
val root = File(rootPath)
|
||||
|
||||
_installedGames.postValue(Game.getGames(ctx, root))
|
||||
_isReloading.postValue(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setSelectedGame(game: Game) {
|
||||
_selectedItem.value = game
|
||||
}
|
||||
|
||||
fun startEngine(ctx: Context, game: Game) {
|
||||
game.startEngine(ctx)
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package su.xash.engine.ui.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import su.xash.engine.databinding.FragmentAppSettingsBinding
|
||||
|
||||
class AppSettingsFragment : Fragment() {
|
||||
private var _binding: FragmentAppSettingsBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentAppSettingsBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
childFragmentManager.beginTransaction()
|
||||
.add(binding.settingsFragment.id, AppSettingsPreferenceFragment()).commit();
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package su.xash.engine.ui.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import su.xash.engine.R
|
||||
|
||||
class AppSettingsPreferenceFragment() : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
preferenceManager.sharedPreferencesName = "app_preferences";
|
||||
setPreferencesFromResource(R.xml.app_preferences, rootKey);
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package su.xash.engine.ui.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import su.xash.engine.databinding.FragmentGameSettingsBinding
|
||||
import su.xash.engine.ui.library.LibraryViewModel
|
||||
|
||||
class GameSettingsFragment : Fragment() {
|
||||
private var _binding: FragmentGameSettingsBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val libraryViewModel: LibraryViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentGameSettingsBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val game = libraryViewModel.selectedItem.value!!
|
||||
|
||||
binding.gameCard.apply {
|
||||
gameTitle.text = game.title
|
||||
|
||||
if (game.icon != null) {
|
||||
gameIcon.setImageBitmap(game.icon)
|
||||
} else {
|
||||
gameIcon.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (game.cover != null) {
|
||||
gameCover.setImageBitmap(game.cover)
|
||||
} else {
|
||||
gameCover.visibility = View.GONE
|
||||
}
|
||||
|
||||
buttonsContainer.visibility = View.GONE
|
||||
}
|
||||
|
||||
childFragmentManager.beginTransaction()
|
||||
.add(binding.settingsFragment.id, GameSettingsPreferenceFragment(game))
|
||||
.commit();
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package su.xash.engine.ui.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import su.xash.engine.R
|
||||
import su.xash.engine.model.Game
|
||||
|
||||
class GameSettingsPreferenceFragment(val game: Game) : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
preferenceManager.sharedPreferencesName = game.basedir.name;
|
||||
setPreferencesFromResource(R.xml.game_preferences, rootKey);
|
||||
|
||||
val packageList = findPreference<ListPreference>("package_name")!!
|
||||
packageList.entries = arrayOf(getString(R.string.app_name))
|
||||
packageList.entryValues = arrayOf(requireContext().packageName)
|
||||
|
||||
if (packageList.value == null) {
|
||||
packageList.setValueIndex(0);
|
||||
}
|
||||
|
||||
val separatePackages = findPreference<SwitchPreferenceCompat>("separate_libraries")!!
|
||||
val clientPackage = findPreference<ListPreference>("client_package")!!
|
||||
val serverPackage = findPreference<ListPreference>("server_package")!!
|
||||
separatePackages.setOnPreferenceChangeListener { _, newValue ->
|
||||
if (newValue == true) {
|
||||
packageList.isVisible = false
|
||||
clientPackage.isVisible = true
|
||||
serverPackage.isVisible = true
|
||||
} else {
|
||||
packageList.isVisible = true
|
||||
clientPackage.isVisible = false
|
||||
serverPackage.isVisible = false
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package su.xash.engine.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
public class AndroidBug5497Workaround {
|
||||
// For more information, see https://code.google.com/p/android/issues/detail?id=5497
|
||||
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
|
||||
|
||||
public static void assistActivity(Activity activity) {
|
||||
new AndroidBug5497Workaround(activity);
|
||||
}
|
||||
|
||||
private View mChildOfContent;
|
||||
private int usableHeightPrevious;
|
||||
private FrameLayout.LayoutParams frameLayoutParams;
|
||||
|
||||
private AndroidBug5497Workaround(Activity activity) {
|
||||
FrameLayout content = activity.findViewById(android.R.id.content);
|
||||
mChildOfContent = content.getChildAt(0);
|
||||
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(this::possiblyResizeChildOfContent);
|
||||
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
|
||||
}
|
||||
|
||||
private void possiblyResizeChildOfContent() {
|
||||
int usableHeightNow = computeUsableHeight();
|
||||
if (usableHeightNow != usableHeightPrevious) {
|
||||
int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
|
||||
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
|
||||
if (heightDifference > (usableHeightSansKeyboard / 4)) {
|
||||
// keyboard probably just became visible
|
||||
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
|
||||
} else {
|
||||
// keyboard probably just became hidden
|
||||
frameLayoutParams.height = usableHeightSansKeyboard;
|
||||
}
|
||||
mChildOfContent.requestLayout();
|
||||
usableHeightPrevious = usableHeightNow;
|
||||
}
|
||||
}
|
||||
|
||||
private int computeUsableHeight() {
|
||||
Rect r = new Rect();
|
||||
mChildOfContent.getWindowVisibleDisplayFrame(r);
|
||||
return (r.bottom - r.top);
|
||||
}
|
||||
}
|
||||
@@ -1,589 +0,0 @@
|
||||
/**
|
||||
* TGAReader.java
|
||||
* <p>
|
||||
* Copyright (c) 2014 Kenji Sasaki
|
||||
* Released under the MIT license.
|
||||
* https://github.com/npedotnet/TGAReader/blob/master/LICENSE
|
||||
* <p>
|
||||
* English document
|
||||
* https://github.com/npedotnet/TGAReader/blob/master/README.md
|
||||
* <p>
|
||||
* Japanese document
|
||||
* http://3dtech.jp/wiki/index.php?TGAReader
|
||||
*/
|
||||
|
||||
package su.xash.engine.util;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public final class TGAReader {
|
||||
|
||||
public static final Order ARGB = new Order(16, 8, 0, 24);
|
||||
public static final Order ABGR = new Order(0, 8, 16, 24);
|
||||
|
||||
public static int getWidth(byte[] buffer) {
|
||||
return (buffer[12] & 0xFF) | (buffer[13] & 0xFF) << 8;
|
||||
}
|
||||
|
||||
public static int getHeight(byte[] buffer) {
|
||||
return (buffer[14] & 0xFF) | (buffer[15] & 0xFF) << 8;
|
||||
}
|
||||
|
||||
public static int[] read(byte[] buffer, Order order) throws IOException {
|
||||
|
||||
// header
|
||||
// int idFieldLength = buffer[0] & 0xFF;
|
||||
// int colormapType = buffer[1] & 0xFF;
|
||||
int type = buffer[2] & 0xFF;
|
||||
int colormapOrigin = (buffer[3] & 0xFF) | (buffer[4] & 0xFF) << 8;
|
||||
int colormapLength = (buffer[5] & 0xFF) | (buffer[6] & 0xFF) << 8;
|
||||
int colormapDepth = buffer[7] & 0xFF;
|
||||
// int originX = (buffer[8] & 0xFF) | (buffer[9] & 0xFF) << 8; // unsupported
|
||||
// int originY = (buffer[10] & 0xFF) | (buffer[11] & 0xFF) << 8; // unsupported
|
||||
int width = getWidth(buffer);
|
||||
int height = getHeight(buffer);
|
||||
int depth = buffer[16] & 0xFF;
|
||||
int descriptor = buffer[17] & 0xFF;
|
||||
|
||||
int[] pixels;
|
||||
|
||||
// data
|
||||
switch (type) {
|
||||
case COLORMAP: {
|
||||
int imageDataOffset = 18 + (colormapDepth / 8) * colormapLength;
|
||||
pixels = createPixelsFromColormap(width, height, colormapDepth, buffer, imageDataOffset, buffer, colormapOrigin, descriptor, order);
|
||||
}
|
||||
break;
|
||||
case RGB:
|
||||
pixels = createPixelsFromRGB(width, height, depth, buffer, 18, descriptor, order);
|
||||
break;
|
||||
case GRAYSCALE:
|
||||
pixels = createPixelsFromGrayscale(width, height, depth, buffer, 18, descriptor, order);
|
||||
break;
|
||||
case COLORMAP_RLE: {
|
||||
int imageDataOffset = 18 + (colormapDepth / 8) * colormapLength;
|
||||
byte[] decodeBuffer = decodeRLE(width, height, depth, buffer, imageDataOffset);
|
||||
pixels = createPixelsFromColormap(width, height, colormapDepth, decodeBuffer, 0, buffer, colormapOrigin, descriptor, order);
|
||||
}
|
||||
break;
|
||||
case RGB_RLE: {
|
||||
byte[] decodeBuffer = decodeRLE(width, height, depth, buffer, 18);
|
||||
pixels = createPixelsFromRGB(width, height, depth, decodeBuffer, 0, descriptor, order);
|
||||
}
|
||||
break;
|
||||
case GRAYSCALE_RLE: {
|
||||
byte[] decodeBuffer = decodeRLE(width, height, depth, buffer, 18);
|
||||
pixels = createPixelsFromGrayscale(width, height, depth, decodeBuffer, 0, descriptor, order);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Unsupported image type: " + type);
|
||||
}
|
||||
|
||||
return pixels;
|
||||
|
||||
}
|
||||
|
||||
private static final int COLORMAP = 1;
|
||||
private static final int RGB = 2;
|
||||
private static final int GRAYSCALE = 3;
|
||||
private static final int COLORMAP_RLE = 9;
|
||||
private static final int RGB_RLE = 10;
|
||||
private static final int GRAYSCALE_RLE = 11;
|
||||
|
||||
private static final int RIGHT_ORIGIN = 0x10;
|
||||
private static final int UPPER_ORIGIN = 0x20;
|
||||
|
||||
private static byte[] decodeRLE(int width, int height, int depth, byte[] buffer, int offset) {
|
||||
int elementCount = depth / 8;
|
||||
byte[] elements = new byte[elementCount];
|
||||
int decodeBufferLength = elementCount * width * height;
|
||||
byte[] decodeBuffer = new byte[decodeBufferLength];
|
||||
int decoded = 0;
|
||||
while (decoded < decodeBufferLength) {
|
||||
int packet = buffer[offset++] & 0xFF;
|
||||
if ((packet & 0x80) != 0) { // RLE
|
||||
for (int i = 0; i < elementCount; i++) {
|
||||
elements[i] = buffer[offset++];
|
||||
}
|
||||
int count = (packet & 0x7F) + 1;
|
||||
for (int i = 0; i < count; i++) {
|
||||
for (int j = 0; j < elementCount; j++) {
|
||||
decodeBuffer[decoded++] = elements[j];
|
||||
}
|
||||
}
|
||||
} else { // RAW
|
||||
int count = (packet + 1) * elementCount;
|
||||
for (int i = 0; i < count; i++) {
|
||||
decodeBuffer[decoded++] = buffer[offset++];
|
||||
}
|
||||
}
|
||||
}
|
||||
return decodeBuffer;
|
||||
}
|
||||
|
||||
private static int[] createPixelsFromColormap(int width, int height, int depth, byte[] bytes, int offset, byte[] palette, int colormapOrigin, int descriptor, Order order) throws IOException {
|
||||
int[] pixels;
|
||||
int rs = order.redShift;
|
||||
int gs = order.greenShift;
|
||||
int bs = order.blueShift;
|
||||
int as = order.alphaShift;
|
||||
switch (depth) {
|
||||
case 24:
|
||||
pixels = new int[width * height];
|
||||
if ((descriptor & RIGHT_ORIGIN) != 0) {
|
||||
if ((descriptor & UPPER_ORIGIN) != 0) {
|
||||
// UpperRight
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int colormapIndex = bytes[offset + width * i + j] &
|
||||
0xFF - colormapOrigin;
|
||||
int color = 0xFFFFFFFF;
|
||||
if (colormapIndex >= 0) {
|
||||
int index = 3 * colormapIndex + 18;
|
||||
int b = palette[index] & 0xFF;
|
||||
int g = palette[index + 1] & 0xFF;
|
||||
int r = palette[index + 2] & 0xFF;
|
||||
int a = 0xFF;
|
||||
color = (r << rs) | (g << gs) | (b << bs) | (a << as);
|
||||
}
|
||||
pixels[width * i + (width - j - 1)] = color;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// LowerRight
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int colormapIndex = bytes[offset + width * i + j] &
|
||||
0xFF - colormapOrigin;
|
||||
int color = 0xFFFFFFFF;
|
||||
if (colormapIndex >= 0) {
|
||||
int index = 3 * colormapIndex + 18;
|
||||
int b = palette[index] & 0xFF;
|
||||
int g = palette[index + 1] & 0xFF;
|
||||
int r = palette[index + 2] & 0xFF;
|
||||
int a = 0xFF;
|
||||
color = (r << rs) | (g << gs) | (b << bs) | (a << as);
|
||||
}
|
||||
pixels[width * (height - i - 1) + (width - j - 1)] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((descriptor & UPPER_ORIGIN) != 0) {
|
||||
// UpperLeft
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int colormapIndex = bytes[offset + width * i + j] &
|
||||
0xFF - colormapOrigin;
|
||||
int color = 0xFFFFFFFF;
|
||||
if (colormapIndex >= 0) {
|
||||
int index = 3 * colormapIndex + 18;
|
||||
int b = palette[index] & 0xFF;
|
||||
int g = palette[index + 1] & 0xFF;
|
||||
int r = palette[index + 2] & 0xFF;
|
||||
int a = 0xFF;
|
||||
color = (r << rs) | (g << gs) | (b << bs) | (a << as);
|
||||
}
|
||||
pixels[width * i + j] = color;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// LowerLeft
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int colormapIndex = bytes[offset + width * i + j] &
|
||||
0xFF - colormapOrigin;
|
||||
int color = 0xFFFFFFFF;
|
||||
if (colormapIndex >= 0) {
|
||||
int index = 3 * colormapIndex + 18;
|
||||
int b = palette[index] & 0xFF;
|
||||
int g = palette[index + 1] & 0xFF;
|
||||
int r = palette[index + 2] & 0xFF;
|
||||
int a = 0xFF;
|
||||
color = (r << rs) | (g << gs) | (b << bs) | (a << as);
|
||||
}
|
||||
pixels[width * (height - i - 1) + j] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
pixels = new int[width * height];
|
||||
if ((descriptor & RIGHT_ORIGIN) != 0) {
|
||||
if ((descriptor & UPPER_ORIGIN) != 0) {
|
||||
// UpperRight
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int colormapIndex = bytes[offset + width * i + j] &
|
||||
0xFF - colormapOrigin;
|
||||
int color = 0xFFFFFFFF;
|
||||
if (colormapIndex >= 0) {
|
||||
int index = 4 * colormapIndex + 18;
|
||||
int b = palette[index] & 0xFF;
|
||||
int g = palette[index + 1] & 0xFF;
|
||||
int r = palette[index + 2] & 0xFF;
|
||||
int a = palette[index + 3] & 0xFF;
|
||||
color = (r << rs) | (g << gs) | (b << bs) | (a << as);
|
||||
}
|
||||
pixels[width * i + (width - j - 1)] = color;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// LowerRight
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int colormapIndex = bytes[offset + width * i + j] &
|
||||
0xFF - colormapOrigin;
|
||||
int color = 0xFFFFFFFF;
|
||||
if (colormapIndex >= 0) {
|
||||
int index = 4 * colormapIndex + 18;
|
||||
int b = palette[index] & 0xFF;
|
||||
int g = palette[index + 1] & 0xFF;
|
||||
int r = palette[index + 2] & 0xFF;
|
||||
int a = palette[index + 3] & 0xFF;
|
||||
color = (r << rs) | (g << gs) | (b << bs) | (a << as);
|
||||
}
|
||||
pixels[width * (height - i - 1) + (width - j - 1)] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((descriptor & UPPER_ORIGIN) != 0) {
|
||||
// UpperLeft
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int colormapIndex = bytes[offset + width * i + j] &
|
||||
0xFF - colormapOrigin;
|
||||
int color = 0xFFFFFFFF;
|
||||
if (colormapIndex >= 0) {
|
||||
int index = 4 * colormapIndex + 18;
|
||||
int b = palette[index] & 0xFF;
|
||||
int g = palette[index + 1] & 0xFF;
|
||||
int r = palette[index + 2] & 0xFF;
|
||||
int a = palette[index + 3] & 0xFF;
|
||||
color = (r << rs) | (g << gs) | (b << bs) | (a << as);
|
||||
}
|
||||
pixels[width * i + j] = color;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// LowerLeft
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int colormapIndex = bytes[offset + width * i + j] &
|
||||
0xFF - colormapOrigin;
|
||||
int color = 0xFFFFFFFF;
|
||||
if (colormapIndex >= 0) {
|
||||
int index = 4 * colormapIndex + 18;
|
||||
int b = palette[index] & 0xFF;
|
||||
int g = palette[index + 1] & 0xFF;
|
||||
int r = palette[index + 2] & 0xFF;
|
||||
int a = palette[index + 3] & 0xFF;
|
||||
color = (r << rs) | (g << gs) | (b << bs) | (a << as);
|
||||
}
|
||||
pixels[width * (height - i - 1) + j] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Unsupported depth:" + depth);
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private static int[] createPixelsFromRGB(int width, int height, int depth, byte[] bytes, int offset, int descriptor, Order order) throws IOException {
|
||||
int[] pixels;
|
||||
int rs = order.redShift;
|
||||
int gs = order.greenShift;
|
||||
int bs = order.blueShift;
|
||||
int as = order.alphaShift;
|
||||
switch (depth) {
|
||||
case 24:
|
||||
pixels = new int[width * height];
|
||||
if ((descriptor & RIGHT_ORIGIN) != 0) {
|
||||
if ((descriptor & UPPER_ORIGIN) != 0) {
|
||||
// UpperRight
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int index = offset + 3 * width * i + 3 * j;
|
||||
int b = bytes[index] & 0xFF;
|
||||
int g = bytes[index + 1] & 0xFF;
|
||||
int r = bytes[index + 2] & 0xFF;
|
||||
int a = 0xFF;
|
||||
pixels[width * i + (width - j - 1)] = (r << rs) |
|
||||
(g << gs) |
|
||||
(b << bs) |
|
||||
(a << as);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// LowerRight
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int index = offset + 3 * width * i + 3 * j;
|
||||
int b = bytes[index] & 0xFF;
|
||||
int g = bytes[index + 1] & 0xFF;
|
||||
int r = bytes[index + 2] & 0xFF;
|
||||
int a = 0xFF;
|
||||
pixels[width * (height - i - 1) + (width - j - 1)] = (r << rs) |
|
||||
(g << gs) |
|
||||
(b << bs) |
|
||||
(a << as);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((descriptor & UPPER_ORIGIN) != 0) {
|
||||
// UpperLeft
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int index = offset + 3 * width * i + 3 * j;
|
||||
int b = bytes[index] & 0xFF;
|
||||
int g = bytes[index + 1] & 0xFF;
|
||||
int r = bytes[index + 2] & 0xFF;
|
||||
int a = 0xFF;
|
||||
pixels[width * i + j] = (r << rs) |
|
||||
(g << gs) |
|
||||
(b << bs) |
|
||||
(a << as);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// LowerLeft
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int index = offset + 3 * width * i + 3 * j;
|
||||
int b = bytes[index] & 0xFF;
|
||||
int g = bytes[index + 1] & 0xFF;
|
||||
int r = bytes[index + 2] & 0xFF;
|
||||
int a = 0xFF;
|
||||
pixels[width * (height - i - 1) + j] = (r << rs) |
|
||||
(g << gs) |
|
||||
(b << bs) |
|
||||
(a << as);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
pixels = new int[width * height];
|
||||
if ((descriptor & RIGHT_ORIGIN) != 0) {
|
||||
if ((descriptor & UPPER_ORIGIN) != 0) {
|
||||
// UpperRight
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int index = offset + 4 * width * i + 4 * j;
|
||||
int b = bytes[index] & 0xFF;
|
||||
int g = bytes[index + 1] & 0xFF;
|
||||
int r = bytes[index + 2] & 0xFF;
|
||||
int a = bytes[index + 3] & 0xFF;
|
||||
pixels[width * i + (width - j - 1)] = (r << rs) |
|
||||
(g << gs) |
|
||||
(b << bs) |
|
||||
(a << as);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// LowerRight
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int index = offset + 4 * width * i + 4 * j;
|
||||
int b = bytes[index] & 0xFF;
|
||||
int g = bytes[index + 1] & 0xFF;
|
||||
int r = bytes[index + 2] & 0xFF;
|
||||
int a = bytes[index + 3] & 0xFF;
|
||||
pixels[width * (height - i - 1) + (width - j - 1)] = (r << rs) |
|
||||
(g << gs) |
|
||||
(b << bs) |
|
||||
(a << as);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((descriptor & UPPER_ORIGIN) != 0) {
|
||||
// UpperLeft
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int index = offset + 4 * width * i + 4 * j;
|
||||
int b = bytes[index] & 0xFF;
|
||||
int g = bytes[index + 1] & 0xFF;
|
||||
int r = bytes[index + 2] & 0xFF;
|
||||
int a = bytes[index + 3] & 0xFF;
|
||||
pixels[width * i + j] = (r << rs) |
|
||||
(g << gs) |
|
||||
(b << bs) |
|
||||
(a << as);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// LowerLeft
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int index = offset + 4 * width * i + 4 * j;
|
||||
int b = bytes[index] & 0xFF;
|
||||
int g = bytes[index + 1] & 0xFF;
|
||||
int r = bytes[index + 2] & 0xFF;
|
||||
int a = bytes[index + 3] & 0xFF;
|
||||
pixels[width * (height - i - 1) + j] = (r << rs) |
|
||||
(g << gs) |
|
||||
(b << bs) |
|
||||
(a << as);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Unsupported depth:" + depth);
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private static int[] createPixelsFromGrayscale(int width, int height, int depth, byte[] bytes, int offset, int descriptor, Order order) throws IOException {
|
||||
int[] pixels;
|
||||
int rs = order.redShift;
|
||||
int gs = order.greenShift;
|
||||
int bs = order.blueShift;
|
||||
int as = order.alphaShift;
|
||||
switch (depth) {
|
||||
case 8:
|
||||
pixels = new int[width * height];
|
||||
if ((descriptor & RIGHT_ORIGIN) != 0) {
|
||||
if ((descriptor & UPPER_ORIGIN) != 0) {
|
||||
// UpperRight
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int e = bytes[offset + width * i + j] & 0xFF;
|
||||
int a = 0xFF;
|
||||
pixels[width * i + (width - j - 1)] = (e << rs) |
|
||||
(e << gs) |
|
||||
(e << bs) |
|
||||
(a << as);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// LowerRight
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int e = bytes[offset + width * i + j] & 0xFF;
|
||||
int a = 0xFF;
|
||||
pixels[width * (height - i - 1) + (width - j - 1)] = (e << rs) |
|
||||
(e << gs) |
|
||||
(e << bs) |
|
||||
(a << as);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((descriptor & UPPER_ORIGIN) != 0) {
|
||||
// UpperLeft
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int e = bytes[offset + width * i + j] & 0xFF;
|
||||
int a = 0xFF;
|
||||
pixels[width * i + j] = (e << rs) |
|
||||
(e << gs) |
|
||||
(e << bs) |
|
||||
(a << as);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// LowerLeft
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int e = bytes[offset + width * i + j] & 0xFF;
|
||||
int a = 0xFF;
|
||||
pixels[width * (height - i - 1) + j] = (e << rs) |
|
||||
(e << gs) |
|
||||
(e << bs) |
|
||||
(a << as);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
pixels = new int[width * height];
|
||||
if ((descriptor & RIGHT_ORIGIN) != 0) {
|
||||
if ((descriptor & UPPER_ORIGIN) != 0) {
|
||||
// UpperRight
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int e = bytes[offset + 2 * width * i + 2 * j] & 0xFF;
|
||||
int a = bytes[offset + 2 * width * i + 2 * j + 1] & 0xFF;
|
||||
pixels[width * i + (width - j - 1)] = (e << rs) |
|
||||
(e << gs) |
|
||||
(e << bs) |
|
||||
(a << as);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// LowerRight
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int e = bytes[offset + 2 * width * i + 2 * j] & 0xFF;
|
||||
int a = bytes[offset + 2 * width * i + 2 * j + 1] & 0xFF;
|
||||
pixels[width * (height - i - 1) + (width - j - 1)] = (e << rs) |
|
||||
(e << gs) |
|
||||
(e << bs) |
|
||||
(a << as);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((descriptor & UPPER_ORIGIN) != 0) {
|
||||
// UpperLeft
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int e = bytes[offset + 2 * width * i + 2 * j] & 0xFF;
|
||||
int a = bytes[offset + 2 * width * i + 2 * j + 1] & 0xFF;
|
||||
pixels[width * i + j] = (e << rs) |
|
||||
(e << gs) |
|
||||
(e << bs) |
|
||||
(a << as);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// LowerLeft
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int e = bytes[offset + 2 * width * i + 2 * j] & 0xFF;
|
||||
int a = bytes[offset + 2 * width * i + 2 * j + 1] & 0xFF;
|
||||
pixels[width * (height - i - 1) + j] = (e << rs) |
|
||||
(e << gs) |
|
||||
(e << bs) |
|
||||
(a << as);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Unsupported depth:" + depth);
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private TGAReader() {
|
||||
}
|
||||
|
||||
public static final class Order {
|
||||
Order(int redShift, int greenShift, int blueShift, int alphaShift) {
|
||||
this.redShift = redShift;
|
||||
this.greenShift = greenShift;
|
||||
this.blueShift = blueShift;
|
||||
this.alphaShift = alphaShift;
|
||||
}
|
||||
|
||||
public int redShift;
|
||||
public int greenShift;
|
||||
public int blueShift;
|
||||
public int alphaShift;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
|
||||
</vector>
|
||||
@@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z" />
|
||||
</vector>
|
||||
@@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M20,6h-8l-2,-2L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,8c0,-1.1 -0.9,-2 -2,-2zM20,18L4,18L4,8h16v10z" />
|
||||
</vector>
|
||||
@@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#000000"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M8,5v14l11,-7z" />
|
||||
</vector>
|
||||
@@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z" />
|
||||
</vector>
|
||||
@@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M20,4H4C2.89,4 2,4.9 2,6v12c0,1.1 0.89,2 2,2h16c1.1,0 2,-0.9 2,-2V6C22,4.9 21.11,4 20,4zM20,18H4V8h16V18zM18,17h-6v-2h6V17zM7.5,17l-1.41,-1.41L8.67,13l-2.59,-2.59L7.5,9l4,4L7.5,17z" />
|
||||
</vector>
|
||||
@@ -1,36 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appBarLayout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/fragmentContainerView"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:defaultNavHost="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/appBarLayout"
|
||||
app:navGraph="@navigation/nav_graph"
|
||||
tools:layout="@layout/fragment_library" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,98 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/Widget.Material3.CardView.Filled"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="128dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/gameCover"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@android:mipmap/sym_def_app_icon" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
style="@style/Widget.Material3.CardView.Filled"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_margin="8dp"
|
||||
app:contentPadding="10dp"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/buttonsContainer"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toStartOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/gameIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginRight="8dp"
|
||||
android:adjustViewBounds="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/gameTitle"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@android:mipmap/sym_def_app_icon" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/gameTitle"
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:singleLine="true"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/gameIcon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Game Title" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/buttonsContainer"
|
||||
style="@style/Widget.Material3.CardView.Filled"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/launchButton"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
app:icon="@drawable/ic_baseline_play_arrow_24"
|
||||
app:layout_constraintEnd_toStartOf="@+id/settingsButton" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/settingsButton"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
app:icon="@drawable/ic_baseline_settings_24"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
@@ -1,45 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/Widget.Material3.CardView.Filled"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp">
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="EditText Preference" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/summary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@android:id/title"
|
||||
tools:text="Summary" />
|
||||
|
||||
<!-- <com.google.android.material.button.MaterialButton-->
|
||||
<!-- style="@style/Widget.Material3.Button.IconButton"-->
|
||||
<!-- android:layout_width="wrap_content"-->
|
||||
<!-- android:layout_height="wrap_content"-->
|
||||
<!-- app:icon="@drawable/baseline_edit_24"-->
|
||||
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
|
||||
<!-- app:layout_constraintEnd_toEndOf="parent"-->
|
||||
<!-- app:layout_constraintTop_toTopOf="parent" />-->
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||