mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-05 11:35:05 +08:00
Compare commits
1 Commits
inotify
...
dll-leak-d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c395acad63 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -331,5 +331,4 @@ __pycache__
|
||||
.vscode/*
|
||||
*.code-workspace
|
||||
.history/*
|
||||
.cache/*
|
||||
enc_temp_folder/
|
||||
.cache/*
|
||||
17
.gitmodules
vendored
17
.gitmodules
vendored
@@ -1,18 +1,15 @@
|
||||
[submodule "mainui"]
|
||||
path = 3rdparty/mainui
|
||||
path = mainui
|
||||
url = https://github.com/FWGS/mainui_cpp
|
||||
[submodule "ref_gl/nanogl"]
|
||||
path = 3rdparty/nanogl
|
||||
path = ref_gl/nanogl
|
||||
url = https://github.com/FWGS/nanogl
|
||||
[submodule "ref_gl/gl-wes-v2"]
|
||||
path = 3rdparty/gl-wes-v2
|
||||
path = ref_gl/gl-wes-v2
|
||||
url = https://github.com/FWGS/gl-wes-v2
|
||||
[submodule "vgui-dev"]
|
||||
path = vgui-dev
|
||||
url = https://github.com/FWGS/vgui-dev
|
||||
[submodule "ref_gl/gl4es"]
|
||||
path = 3rdparty/gl4es/gl4es
|
||||
path = ref_gl/gl4es
|
||||
url = https://github.com/ptitSeb/gl4es
|
||||
[submodule "vgui_support"]
|
||||
path = 3rdparty/vgui_support
|
||||
url = https://github.com/FWGS/vgui_support
|
||||
[submodule "opus"]
|
||||
path = 3rdparty/opus/opus
|
||||
url = https://github.com/xiph/opus
|
||||
|
||||
1
3rdparty/gl4es/gl4es
vendored
1
3rdparty/gl4es/gl4es
vendored
Submodule 3rdparty/gl4es/gl4es deleted from 5c28420a38
24
3rdparty/gl4es/wscript
vendored
24
3rdparty/gl4es/wscript
vendored
@@ -1,24 +0,0 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
import os
|
||||
|
||||
def options(opt):
|
||||
pass
|
||||
|
||||
def configure(conf):
|
||||
if not conf.path.find_dir('gl4es') or not conf.path.find_dir('gl4es/src'):
|
||||
conf.fatal('Can\'t find gl4es submodule. Run `git submodule update --init --recursive`.')
|
||||
return
|
||||
|
||||
def build(bld):
|
||||
gl4es_srcdir = bld.path.find_node('gl4es/src')
|
||||
|
||||
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', 'EXTERNAL_GETPROCADDRESS=GL4ES_GetProcAddress', 'NO_LOADER', 'STATICLIB'],
|
||||
cflags = ['-w', '-fvisibility=hidden', '-std=gnu99'],
|
||||
subsystem = bld.env.MSVC_SUBSYSTEM,
|
||||
export_includes = '.')
|
||||
1
3rdparty/mainui
vendored
1
3rdparty/mainui
vendored
Submodule 3rdparty/mainui deleted from 14c0922af7
1
3rdparty/opus/opus
vendored
1
3rdparty/opus/opus
vendored
Submodule 3rdparty/opus/opus deleted from 997fdf54e7
40
3rdparty/opus/wscript
vendored
40
3rdparty/opus/wscript
vendored
@@ -1,40 +0,0 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
import os
|
||||
|
||||
def options(opt):
|
||||
pass
|
||||
|
||||
def configure(conf):
|
||||
if not conf.path.find_dir('opus') or not conf.path.find_dir('opus/src'):
|
||||
conf.fatal('Can\'t find opus submodule. Run `git submodule update --init --recursive`.')
|
||||
return
|
||||
|
||||
# TODO: ARM/x86 intrinsics detection
|
||||
# TODO: maybe call autotools/cmake/meson instead?
|
||||
|
||||
def build(bld):
|
||||
sources = bld.path.ant_glob([
|
||||
'opus/src/*.c',
|
||||
'opus/celt/*.c',
|
||||
'opus/silk/*.c',
|
||||
'opus/silk/float/*.c'
|
||||
], excl = [
|
||||
'opus/src/repacketizer_demo.c',
|
||||
'opus/src/opus_demo.c',
|
||||
'opus/src/opus_compare.c',
|
||||
'opus/celt/opus_custom_demo.c'
|
||||
])
|
||||
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,
|
||||
target = 'opus',
|
||||
features = 'c',
|
||||
includes = includes,
|
||||
defines = defines,
|
||||
subsystem = bld.env.MSVC_SUBSYSTEM,
|
||||
export_includes = ['opus/include/']
|
||||
)
|
||||
1
3rdparty/vgui_support
vendored
1
3rdparty/vgui_support
vendored
Submodule 3rdparty/vgui_support deleted from 63c134f188
@@ -1,17 +0,0 @@
|
||||
# Bug-compatibility in Xash3D FWGS
|
||||
|
||||
Xash3D FWGS has special mode for games that rely on original engine bugs.
|
||||
|
||||
In this mode, we emulate the behaviour of selected functions that may help running mods relying on engine bugs, but enabling them by default may break majority of other games.
|
||||
|
||||
At this time, we only have implemented GoldSrc bug-compatibility. It can be enabled with `-bugcomp` command line switch.
|
||||
|
||||
## GoldSrc bug-compatibility
|
||||
|
||||
### Emulated bugs
|
||||
|
||||
* `pfnPEntityOfEntIndex` in GoldSrc returns NULL for last player due to incorrect player index comparison
|
||||
|
||||
### Games and mods that require this
|
||||
|
||||
* Counter-Strike: Condition Zero - Deleted Scenes
|
||||
@@ -7,5 +7,6 @@
|
||||
|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 |
|
||||
|Sven-Coop |5.0+ |Uses filesystem_stdio library which xash3d does not support |filesystem_stdio replacement already was made: https://github.com/FWGS/filesystem_stdio_xash
|
||||
|XDM |3.0.4.0 | |
|
||||
|
||||
|
||||
@@ -17,16 +17,13 @@ Mirrored on github - https://github.com/JoelTroch/am_src_rebirth
|
||||
Mirrored on github - https://github.com/nekonomicon/BattleGrounds
|
||||
|
||||
## Bubblemod
|
||||
Download page on official site - http://www.bubblemod.org/dl_default.php (dead link!)
|
||||
|
||||
Mirrored on github - https://github.com/HLSources/BubbleMod
|
||||
Download page on official site - http://www.bubblemod.org/dl_default.php
|
||||
|
||||
## Chicken Fortress
|
||||
Official github repository - https://github.com/CKFDevPowered/CKF3Alpha
|
||||
|
||||
## Cold Ice
|
||||
Version 1.9 is available on ModDB - https://www.moddb.com/mods/cold-ice/downloads/cold-ice-sdk
|
||||
|
||||
Version 1.9 mirrored on github - https://github.com/solidi/hl-mods/tree/master/ci
|
||||
|
||||
## Cold Ice Ressurection
|
||||
@@ -45,13 +42,11 @@ Official github repository - https://github.com/adslbarxatov/xash3d-for-ESHQ
|
||||
Available on GamerLab - http://gamer-lab.com/eng/code_mods_goldsrc/Half-Life_2D_(Flat-Life)
|
||||
|
||||
## Gang Wars
|
||||
Mirrored on github - https://github.com/nekonomicon/gw1.45src
|
||||
Mirrored on github - https://github.com/hammermaps/gw1.45src
|
||||
|
||||
## Go-mod
|
||||
Versions 2.0 and 3.0, available in mod archives on ModDB - https://www.moddb.com/mods/go-mod/downloads
|
||||
|
||||
Version 3.0, mirrored on github - https://github.com/nekonomicon/Go-mod30
|
||||
|
||||
## GT mod
|
||||
Available on GamerLab - http://gamer-lab.com/eng/code_mods_goldsrc/GT_mod_(Polnie_ishodniki)
|
||||
|
||||
@@ -68,10 +63,10 @@ Available on ModDB - https://www.moddb.com/mods/half-life-echoes
|
||||
Available on ModDB - https://www.moddb.com/mods/half-life-expanded-arsenal
|
||||
|
||||
## Half-Life: Gravgun mod
|
||||
Branch **gravgun** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/gravgun
|
||||
Branch **gravgun** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/gravgun
|
||||
|
||||
## Half-Life: Invasion
|
||||
Official github repository - https://github.com/jlecorre/hlinvasion
|
||||
official github repository - https://github.com/jlecorre/hlinvasion
|
||||
|
||||
## Half-Life: Pong
|
||||
Mirrored on github - https://github.com/solidi/hl-mods/tree/master/pong
|
||||
@@ -110,7 +105,7 @@ Official github repository - https://github.com/desukuran/half-screwed
|
||||
Version 1.3 on ModDB - https://www.moddb.com/mods/headcrab-frenzy/downloads/headcrab-frenzy-13-beta-source-code
|
||||
|
||||
## Heart of Evil
|
||||
Mirrored on github - https://github.com/nekonomicon/HeartOfEvil
|
||||
Available on ModDB - https://www.moddb.com/mods/heart-of-evil/downloads/heart-of-evil-dlls-source-code
|
||||
|
||||
## Ingram Chillin' Mod
|
||||
Official SourceForge repository - https://sourceforge.net/projects/icm-hl/
|
||||
@@ -173,7 +168,7 @@ Mirrored on github - https://github.com/ZXCmod/ZXCmod
|
||||
|
||||
# Reimplementation
|
||||
## Absolute Redemption
|
||||
Branch **redempt** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/redempt
|
||||
Branch **redempt** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/redempt
|
||||
|
||||
## Adrenaline Gamer
|
||||
OpenAG by YaLTeR - https://github.com/YaLTeR/OpenAG
|
||||
@@ -181,34 +176,34 @@ OpenAG by YaLTeR - https://github.com/YaLTeR/OpenAG
|
||||
## Afraid of Monsters
|
||||
malortie's recreation - https://github.com/malortie/hl-aom
|
||||
|
||||
Branch **aom** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/aom
|
||||
Branch **aom** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/aom
|
||||
|
||||
## Afraid of Monsters: Director's cut
|
||||
Reverse-engineered code, branch **aomdc** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/aomdc
|
||||
Reverse-engineered code, branch **aomdc** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/aomdc
|
||||
|
||||
## Azure Sheep
|
||||
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
|
||||
Reverse-engineered code, branch **asheep** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/asheep
|
||||
|
||||
## Big Lolly
|
||||
malortie's recreation - https://github.com/malortie/hl-biglolly
|
||||
|
||||
Branch **biglolly** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/biglolly
|
||||
Branch **biglolly** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/biglolly
|
||||
|
||||
## Black Ops
|
||||
malortie's recreation - https://github.com/malortie/hl-blackops
|
||||
|
||||
Branch **blackops** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/blackops
|
||||
Branch **blackops** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/blackops
|
||||
|
||||
## Bloody Pizza: Vendetta
|
||||
Branch **caseclosed** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/caseclosed
|
||||
Branch **caseclosed** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/caseclosed
|
||||
|
||||
## Case Closed
|
||||
Branch **caseclosed** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/caseclosed
|
||||
Branch **caseclosed** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/caseclosed
|
||||
|
||||
## Cleaner's Adventures
|
||||
Branch **CAd** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/CAd
|
||||
Branch **CAd** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/CAd
|
||||
|
||||
## Counter Strike
|
||||
Reverse-engineered code of client part by a1batross - https://github.com/FWGS/cs16-client/tree/v1.32
|
||||
@@ -226,60 +221,54 @@ Recreation by lostgamer aka nillerusr - https://github.com/LostGamerHL/crack_lif
|
||||
## Escape from the Darkness
|
||||
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
|
||||
Reverse-engineered code, branch **eftd** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/eftd
|
||||
|
||||
## Half-Life: Blue Shift
|
||||
Unkle Mike's recreation - https://hlfx.ru/forum/showthread.php?s=&threadid=5253
|
||||
|
||||
Reverse-engineered code, branch **bshift** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/bshift
|
||||
Reverse-engineered code, branch **bshift** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/bshift
|
||||
|
||||
## Half-Life: Induction
|
||||
Branch **induction** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/induction
|
||||
Branch **induction** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/induction
|
||||
|
||||
## Half-Life: Opposing Force
|
||||
Recreation by lostgamer aka nillerusr - https://github.com/LostGamerHL/hlsdk-xash3d
|
||||
|
||||
Reverse-engineered code, clean branch **opfor** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/opfor
|
||||
Reverse-engineered code, clean branch **opfor** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/opfor
|
||||
|
||||
Spirit of Half Life: Opposing-Force Edition - https://github.com/Hammermaps-DEV/SOHL-V1.9-Opposing-Force-Edition
|
||||
|
||||
## Half-Life: Rebellion
|
||||
Reverse-engineered code, branch **rebellion** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/rebellion
|
||||
|
||||
## Half-Life: Urbicide
|
||||
Branch **hl_urbicide** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/hl_urbicide
|
||||
Reverse-engineered code, branch **rebellion** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/rebellion
|
||||
|
||||
## Half-Life: 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
|
||||
Reverse-engineered code, branch **visitors** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/visitors
|
||||
|
||||
## Half-Secret
|
||||
Branch **half-secret** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/half-secret
|
||||
Branch **half-secret** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/half-secret
|
||||
|
||||
## Night at the Office
|
||||
malortie's recreation - https://github.com/malortie/hl-nato
|
||||
|
||||
Branch **noffice** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/noffice
|
||||
Branch **noffice** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/noffice
|
||||
|
||||
## Poke 646
|
||||
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
|
||||
Reverse-engineered code, branch **poke646** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/poke646
|
||||
|
||||
## Poke 646: 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
|
||||
Reverse-engineered code, branch **poke646_vendetta** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/poke646_vendetta
|
||||
|
||||
## Residual Life
|
||||
Reverse-engineered code, branch **residual_point** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/residual_point
|
||||
Reverse-engineered code, branch **residual_point** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/residual_point
|
||||
|
||||
## Residual Point
|
||||
Reverse-engineered code, branch **residual_point** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/residual_point
|
||||
|
||||
## Sewer Beta
|
||||
Branch **sewer_beta** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/sewer_beta
|
||||
Reverse-engineered code, branch **residual_point** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/residual_point
|
||||
|
||||
## Team Fortress Classic
|
||||
Reverse-engineered code by Velaron - https://github.com/Velaron/tf15-client
|
||||
@@ -287,64 +276,59 @@ Reverse-engineered code by Velaron - https://github.com/Velaron/tf15-client
|
||||
## The Gate
|
||||
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
|
||||
Reverse-engineered code, branch **thegate** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/thegate
|
||||
|
||||
## They Hunger
|
||||
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
|
||||
Reverse-engineered code, branch **theyhunger** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/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/malortie/hl-tot
|
||||
|
||||
Branch **tot** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/tot
|
||||
Branch **tot** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/tot
|
||||
|
||||
# Derived work
|
||||
## Adrenaline Gamer
|
||||
Branch **aghl** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/aghl
|
||||
Branch **aghl** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/aghl
|
||||
|
||||
## Bubblemod
|
||||
Branch **bubblemod** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/bubblemod
|
||||
Branch **bubblemod** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/bubblemod
|
||||
|
||||
## Deathmatch Classic
|
||||
Deathmatch Classic: Adrenaline Gamer Edition - https://github.com/martinwebrant/agmod/tree/master/src/dmc
|
||||
|
||||
Deathmatch Quaked - https://www.moddb.com/games/deathmatch-classic/downloads/dmq2
|
||||
|
||||
Branch **dmc** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/dmc
|
||||
Branch **dmc** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/dmc
|
||||
|
||||
## Half-Life: Echoes
|
||||
Branch **echoes** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/echoes
|
||||
Branch **echoes** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/echoes
|
||||
|
||||
## Half-Life: Invasion
|
||||
Port to HLSDK 2.4 by malortie - https://github.com/malortie/hl-invasion
|
||||
|
||||
Port to Linux by fmoraw - https://github.com/fmoraw/hlinvasion
|
||||
|
||||
Branch **invasion** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/invasion
|
||||
|
||||
## Half-Life: Top-Down
|
||||
Branch **hltopdown** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/hltopdown
|
||||
Branch **hltopdown** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/hltopdown
|
||||
|
||||
## Half-Screwed
|
||||
Branch **half-screwed** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/half-screwed
|
||||
Branch **half-screwed** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/half-screwed
|
||||
|
||||
## Natural Selection
|
||||
Port to Linux - https://github.com/fmoraw/NS
|
||||
|
||||
## Spirit of Half-Life
|
||||
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/malortie/hl-shall
|
||||
|
||||
Branch **halloween** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/halloween
|
||||
Branch **halloween** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/halloween
|
||||
|
||||
## Threewave CTF
|
||||
Branch **dmc** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/dmc
|
||||
Branch **dmc** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/dmc
|
||||
|
||||
## Zombie-X
|
||||
Branch **zombie-x** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/zombie-x
|
||||
Branch **zombie-x** in hlsdk-xash3d - https://github.com/FWGS/hlsdk-xash3d/tree/zombie-x
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ For mappacks - place *.bsp files to **valve/maps** folder, *.wad files to **valv
|
||||
16. [Betrayal](http://www.moddb.com/mods/betrayal) (this mod has inner bugs; set **gl_allow_mirrors** to **0** to prevent drops of game's perfomance in some areas)
|
||||
17. [Between Two Worlds](https://www.runthinkshootlive.com/posts/between-two-worlds/)
|
||||
18. [Black Mesa Energy Testing Chamber](http://twhl.info/competitions.php?results=17)
|
||||
19. [Black Mesa Sideline](https://www.moddb.com/mods/black-mesa-sideline) (set **gl_allow_mirrors** to **0** to prevent drops of game's perfomance in some areas)
|
||||
19. [Black Mesa Sideline](http://www.isolated-design.de/half-life-mods/black-mesa-sideline/) (set **gl_allow_mirrors** to **0** to prevent drops of game's perfomance in some areas)
|
||||
20. [BlackMesa 2007( Black Mesa Missions 2007 )](http://www.moddb.com/addons/blackmesa-2007)
|
||||
21. [Blood and Bones](https://www.runthinkshootlive.com/posts/blood-and-bones/)
|
||||
22. Boom (Huknenn) v1.0 & [HL Boom: Gold Edition v1.1](http://www.moddb.com/mods/boom)
|
||||
@@ -103,8 +103,8 @@ For mappacks - place *.bsp files to **valve/maps** folder, *.wad files to **valv
|
||||
72. [Freeman](https://www.runthinkshootlive.com/posts/freeman/)
|
||||
73. [Freeman's Escape](http://www.moddb.com/mods/freeman-escape-french) (2 maps by *JiggZ*)
|
||||
74. [Freeman's Fight](https://www.runthinkshootlive.com/posts/freemans-fight/)
|
||||
75. [Freeman's Return](https://www.moddb.com/games/half-life/addons/freemans-return-v12)
|
||||
76. [Freeman's Return 2](https://www.moddb.com/games/half-life/addons/freemans-return-2-v11)
|
||||
75. [Freeman's Return](http://jpmaps.wz.cz/epizody.htm)
|
||||
76. [Freeman's Return 2](http://jpmaps.wz.cz/epizody.htm)
|
||||
77. [Freeman's Revenge](https://www.runthinkshootlive.com/posts/freemans-revenge/)
|
||||
78. [Freeman's Tomb( The Crypt )](http://twhl.info/vault.php?map=3787)
|
||||
79. [G-Invasion v2.5](http://www.moddb.com/mods/g-man-invasion) aka G-Man Invasion (there is an inner crash bug on final titles: some text lines are too long and cannot be properly displayed)
|
||||
@@ -129,7 +129,7 @@ For mappacks - place *.bsp files to **valve/maps** folder, *.wad files to **valv
|
||||
96. [Haunted](https://www.runthinkshootlive.com/posts/haunted/) (set **sv_validate_changelevel** to **0** to avoid a problem with level change between maps **pagan7** and **pagan8**)
|
||||
97. [Hazardous Materials: Episode 1 & 2](http://www.moddb.com/mods/half-life-hazardous-materials)
|
||||
98. [Hazardous-Course 2](http://www.moddb.com/mods/hazardous-course-2)
|
||||
99. [Help Wanted](https://www.moddb.com/games/half-life/addons/help-wanted)
|
||||
99. [Help Wanted](http://maps.mrsucko.org/work/)
|
||||
100. [Hidden Evil v1.01](https://www.runthinkshootlive.com/posts/hidden-evil/)
|
||||
101. [High Speed](http://www.moddb.com/games/half-life/addons/high-speed-english-version)
|
||||
102. [hlife_hotdog_compo26](http://twhl.info/vault.php?map=5181)
|
||||
@@ -155,7 +155,7 @@ For mappacks - place *.bsp files to **valve/maps** folder, *.wad files to **valv
|
||||
122. [Mario Keys](http://www.moddb.com/mods/mario-keys)
|
||||
123. [McBeth](https://www.runthinkshootlive.com/posts/mcbeth/)
|
||||
124. [Medieval World](http://www.moddb.com/mods/medieval-world)
|
||||
125. [Mel Soaring 2: Star Rancor](https://www.moddb.com/addons/mel-soaring-2-star-rancor)
|
||||
125. [Mel Soaring 2: Star Rancor](http://www.etherealhell.com/etherealhell/index.php/my-levels/half-life)
|
||||
126. [MINIMICUS](http://twhl.info/vault.php?map=163)
|
||||
127. [Mission Failed](http://www.moddb.com/mods/mission-failed)
|
||||
128. [Mission MC Poker](http://www.moddb.com/mods/half-life-mission-mc-poker)
|
||||
@@ -176,7 +176,7 @@ For mappacks - place *.bsp files to **valve/maps** folder, *.wad files to **valv
|
||||
143. [Operation: Nova](http://www.moddb.com/mods/half-life-operation-nova) (there is an inner bug with an M60 machinegun on a map with Osprey: it can be activated and used if you are staying in front of it, not behind it)
|
||||
144. [Optimum Fear](https://www.fileplanet.com/7472/0/fileinfo/Optimum-Fear)
|
||||
145. [Outrun](http://www.moddb.com/mods/outrun)
|
||||
146. [Outwards (Day One)](https://drive.google.com/file/d/1mjQ8wUazYbwTq9Ocg0Vs0raq4avbTRne/view?usp=sharing)
|
||||
146. [Outwards (Day One)](http://www.visgi.info/maps/)
|
||||
147. [Overhaul Pack](http://www.moddb.com/mods/half-life-overhaul-pack) (Just HD pack for Half-Life)
|
||||
148. [P.I.Z.D.E.C.](https://www.runthinkshootlive.com/posts/pizdec/)
|
||||
149. [pagoda](http://www.moddb.com/mods/pagoda1)
|
||||
@@ -184,7 +184,7 @@ For mappacks - place *.bsp files to **valve/maps** folder, *.wad files to **valv
|
||||
151. [Phobos IV](http://www.moddb.com/mods/phobos-iv)
|
||||
152. [Pimp My Car](https://www.runthinkshootlive.com/posts/pimp-my-car/) (there is an inner issue with incorrect responses of buttons on combination locks)
|
||||
153. [Point Blank – Stackdeath Complex](https://www.runthinkshootlive.com/posts/half-life-point-blank-stackdeath-complex/)
|
||||
154. [Prisoner Escaped](https://www.moddb.com/mods/prisoner-escaped-1-2)
|
||||
154. [Prisoner Escaped](http://four0four.org/downloads/maps/)
|
||||
155. [Prisoner of Event](http://wp.vondur.net/?page_id=40)
|
||||
156. [Prisoner of War](https://www.runthinkshootlive.com/posts/prisoner-of-war/)
|
||||
157. [Project Quantum Leap](http://www.moddb.com/mods/project-quantum-leap)
|
||||
@@ -282,7 +282,7 @@ For mappacks - place *.bsp files to **valve/maps** folder, *.wad files to **valv
|
||||
6. [Catacombs: Part 1](https://www.runthinkshootlive.com/posts/catacombs/)
|
||||
7. [Cro-man's Office Mappack](http://twhl.info/vault.php?map=5547)
|
||||
8. [Half-Life Episode Two Demo Alpha v1.0](http://hl.loess.ru/?mod=451)
|
||||
9. [Hazardous-Course (first version of Hazardous-Course 2)](https://drive.google.com/file/d/16djJZSpNWKyScSxSyMqX-u_S-2i400rl/view?usp=sharing)
|
||||
9. [Hazardous-Course (first version of Hazardous-Course 2)](http://www.richmans-maps.ch.vu/) (link dead!)
|
||||
10. [High Tech v0.2](http://hl.loess.ru/?mod=499)
|
||||
11. [HL Shadows, Part 1](https://www.fileplanet.com/7466/0/fileinfo/'HL-Shadows',-Part-1)
|
||||
12. [HLNewEnd](http://twhl.info/vault.php?map=2275)
|
||||
@@ -305,11 +305,11 @@ For mappacks - place *.bsp files to **valve/maps** folder, *.wad files to **valv
|
||||
29. [Shortcut v1.0 Beta](https://www.runthinkshootlive.com/posts/shortcut/)
|
||||
30. [Stoka](https://www.ceskemody.cz/mapy.php?lng=1&clanek=222&razeni_hra=1&pn=stoka)
|
||||
31. [Striker's Compo 26](http://twhl.info/vault.php?map=5190) (buggy)
|
||||
32. [Technology Test 2](https://drive.google.com/file/d/1LfldzsMIN5j07bgtNkfY5v0Xl0S9de_G/view?usp=sharing)
|
||||
32. [Technology Test 2](http://www.richmans-maps.ch.vu/) (link dead!)
|
||||
33. [The Gate Playable Demo](https://www.fileplanet.com/116347/110000/fileinfo/The-Gate-Playable-Demo)
|
||||
34. [They are Back](https://www.runthinkshootlive.com/posts/they-are-back/)
|
||||
35. [Tiefseelabor( Deep Sea Laboratory )](https://www.runthinkshootlive.com/posts/deep-sea-laboratory/)
|
||||
36. [Time-Shift](https://drive.google.com/file/d/1pK1s-2SIlSMQHVRPMLdC_94wTa__8_DX/view?usp=sharing)
|
||||
36. [Time-Shift](http://www.richmans-maps.ch.vu/) (link dead!)
|
||||
37. [Train Single Beta](https://cs-mapping.com.ua/forum/showthread.php?t=36394) (Remove **gfx.wad** from **TrainSingle** folder)
|
||||
38. [WAR: The Killer Beta 0.1](http://www.moddb.com/mods/war)
|
||||
39. [White Force Beta( Residual Point prototype )](http://www.moddb.com/mods/hl-residual-point/downloads/white-force-beta-2002)
|
||||
@@ -379,7 +379,7 @@ Mods:
|
||||
5. [Half-Life Baby v1.4](http://www.moddb.com/games/half-life/addons/half-life-baby) (it's an unfinished but playable mod; after installing of the mod open **liblist.gam** or **gameinfo.txt** file in the mod's folder and correct the line **gamedll "..\hlbaby\dlls\hl.dll"** for **gamedll "dlls\hl.dll"**, otherwise you'll not be able to start a game)
|
||||
6. [Half-Secret](http://www.moddb.com/mods/half-secret) (this mod has custom **weapon_snark** code)
|
||||
7. [Induction](http://www.moddb.com/mods/half-life-induction) (this mod has new item - **item_flashlight**)
|
||||
8. [Lost in Black Mesa(first version without HLFX)](https://drive.google.com/file/d/1bEnm_AxJs-ly8hTEZIQBw_v2BsXdSiGa/view?usp=sharing)
|
||||
8. [Lost in Black Mesa(first version without HLFX)](http://half-life.ru/forum/showthread.php?threadid=13959)
|
||||
9. [Soldier](http://www.moddb.com/mods/half-life-soldier)
|
||||
10. [Solo Operations](http://www.moddb.com/mods/solo-operations)
|
||||
11. [The Blood v1.1](http://hl.loess.ru/?mods=&search=The+Blood) (there are some inner bugs in the mod, but they don't interfere with a game progress)
|
||||
@@ -440,7 +440,7 @@ Mods:
|
||||
51. [Data-base](https://www.runthinkshootlive.com/posts/database/)
|
||||
52. [de_dust2_azabetfeN](https://cs-mapping.com.ua/forum/showthread.php?t=36394) (remove **cl_dlls** & **dlls** folders from inside of mod's directory before you start the game)
|
||||
53. [De-railed](http://twhl.info/competitions.php?results=7)
|
||||
54. [Dead Shift Beta](http://www.moddb.com/mods/dead-shift) - [Demo 1](https://www.gamewatcher.com/mods/half-life-mod/dead-shift-1-0-beta) & [Demo 2](https://drive.google.com/file/d/1uHvr8xONogTTNOy-8X6G4ehFV6Eawvbq/view?usp=sharing)
|
||||
54. [Dead Shift Beta](http://www.moddb.com/mods/dead-shift) - [Demo 1](https://www.gamewatcher.com/mods/half-life-mod/dead-shift-1-0-beta) & [Demo 2](https://www.gamefront.com/files/13532512) (3rd link dead!)
|
||||
55. [Deep](http://twhl.info/vault.php?map=1669)
|
||||
56. [Desert Attack](http://fyzzer.narod.ru/index.html)
|
||||
57. [Desert Combat Demo](https://www.fileplanet.com/190487/190000/fileinfo/Half-Life---Desert-Combat-Mod) (despite a big file size there's only one small unfinished map)
|
||||
@@ -469,7 +469,7 @@ Mods:
|
||||
80. [Extinct Lifeform Hunt](https://www.fileplanet.com/13501/10000/fileinfo/Extinct-Lifeform-Hunt)
|
||||
81. [Facility](http://twhl.info/vault.php?map=5482)
|
||||
82. [Facility Escape](http://twhl.info/vault.php?map=3673)
|
||||
83. [Fallout](http://www.thewall.de/forum/thread/hl1-sp-48h-mapping-contest/64975.4.html) (map by *simb*) (link dead!)
|
||||
83. [Fallout](http://www.thewall.de/forum/thread/hl1-sp-48h-mapping-contest/64975.4.html) (map by *simb*)
|
||||
84. [Final Assault](http://twhl.info/vault.php?map=4500)
|
||||
85. [Flat](http://hl.loess.ru/?mods=&search=Flat)
|
||||
86. [Freeman's Allegiance](https://www.runthinkshootlive.com/posts/freemans-allegiance/)
|
||||
@@ -498,8 +498,8 @@ Mods:
|
||||
109. [Hospital](https://gamebanana.com/maps/167446) (you need to edit **liblist.gam** file in the mod's folder - delete *gamedll & type* strings from it before you start to play)
|
||||
110. [Hostage](https://www.runthinkshootlive.com/posts/hostage-2/)
|
||||
111. [House](http://www.artpeter.net/Data/HalfLife/Hl.php)
|
||||
112. [Impulse 101 Fun - The Train](https://drive.google.com/file/d/1jAuMCCmREH0mfAEAscqaG8FQGa2uNknb/view?usp=sharing) (map from *TWHL* by *Archie* aka *The Hunter*)
|
||||
113. [In America](https://drive.google.com/file/d/1gOC8zfnUvBxRy8Rr8juNiUNbLYjoZpnn/view?usp=sharing)
|
||||
112. [Impulse 101 Fun - The Train](http://web.archive.org/web/20070305075816/http://www.twhl.co.za/mapvault/2817.zip) (map from *TWHL* by *Archie* aka *The Hunter*)
|
||||
113. [In America](http://www.lambda-force.org/load/half_life/karty/half_life_in_america/18-1-0-476)
|
||||
114. [In the Kitchen](http://twhl.info/vault.php?map=4314)
|
||||
115. [Infiltration](https://www.fileplanet.com/7467/0/fileinfo/Infiltration)
|
||||
116. [Interactivity & Lots of Entities](http://twhl.info/vault.php?map=5744) (link dead!)
|
||||
@@ -668,7 +668,7 @@ Mods:
|
||||
279. [X-treme Violence](http://www.moddb.com/mods/x-treme-violence)
|
||||
280. [XargoL's Entry for Vassy's Compo](http://twhl.info/vault.php?map=769)
|
||||
281. [Xen Again](https://www.fileplanet.com/9132/0/fileinfo/XEN-AGAIN)
|
||||
282. [Xen World](http://www.lambda-force.org/load/half_life/karty/half_life_xen_world/18-1-0-481) (link dead!)
|
||||
282. [Xen World](http://www.lambda-force.org/load/half_life/karty/half_life_xen_world/18-1-0-481)
|
||||
283. [XUnil](https://www.fileplanet.com/7883/0/fileinfo/XUNIL)
|
||||
284. [Zeeba-G's TWHL Compo 26 Entry](http://twhl.info/competitions.php?results=26)
|
||||
285. [Zombies!](https://gamebanana.com/maps/160812)
|
||||
@@ -694,7 +694,7 @@ For Linux and OS X you must download crossbuild from [here](http://www.moddb.com
|
||||
2. [Big Scientists](http://www.moddb.com/mods/big-scientists)
|
||||
3. [Black Silla Assault DEMO v1.2](http://www.moddb.com/mods/black-silla-assault)
|
||||
4. [Blbej Den](http://www.moddb.com/mods/blbej-den)
|
||||
5. [Cold Experiment v1](https://www.moddb.com/games/half-life/addons/cold-experiment) (you will need some files from SoHL to play it properly; download SoHL 1.2, extract files and copy following folders into **coldexv1** folder: cl_dlls, dlls, models, sprites)
|
||||
5. [Cold Experiment v1](http://jpmaps.wz.cz/epizody.htm) (you will need some files from SoHL to play it properly; download SoHL 1.2, extract files and copy following folders into **coldexv1** folder: cl_dlls, dlls, models, sprites)
|
||||
6. [Dead Sector v1.0a](http://www.moddb.com/mods/dead-sector)
|
||||
7. [Death Is Dead](http://www.moddb.com/games/half-life/addons/death-is-dead) (there is a fog-related inner bug at the first map)
|
||||
8. [Escape from Black Mesa Alpha](http://www.moddb.com/mods/escape-from-black-mesa)
|
||||
@@ -710,9 +710,9 @@ For Linux and OS X you must download crossbuild from [here](http://www.moddb.com
|
||||
18. [Santa's Revenge](http://twhl.info/vault.php?map=4332) (set **fps_max** to **60** to avoid an inner problem of the last map with final scripted sequence, otherwise the mod can not be finished properly)
|
||||
19. [Sector 6](https://www.moddb.com/mods/sector-6/)
|
||||
20. [Space Prisoner v1.1](http://www.moddb.com/games/half-life/addons/space-prisoner-v11) (after installing of the mod open **liblist.gam** or **gameinfo.txt** file in the mod's folder and correct the line **gamedll "..\prison\dlls\spirit.dll"** for **gamedll "dlls\spirit.dll"**, otherwise you'll not be able to start a game; there is also a scripting error on a third map of the mod, so you'll be forced to use **noclip** to pass around bugged place)
|
||||
21. [Terrorist Attack 2](https://www.moddb.com/games/half-life/addons/terrorist-attack-2)
|
||||
21. [Terrorist Attack 2](http://terroristattack.wz.cz/mody.html) (link dead!)
|
||||
22. [Timeline III: The Heart of Darkness](http://www.moddb.com/mods/timeline-series)
|
||||
23. [Underground 2 Demo](https://www.moddb.com/games/half-life/addons/underground-2-demo)
|
||||
23. [Underground 2 Demo](http://www.isolated-design.de/half-life-mods/underground-2/)
|
||||
|
||||
## Mods which based on modified Spirit of Half-Life 1.2 or older(Partially playable with SoHL 1.2 libraries or not playable at all)
|
||||
1. [Black Death](http://www.moddb.com/mods/half-life-black-death)
|
||||
@@ -825,10 +825,10 @@ Mods:
|
||||
3. [Bomb Squad](http://www.snarkpit.net/index.php?s=maps&map=3471)
|
||||
4. [Corruption](http://www.snarkpit.net/index.php?s=maps&map=3154)
|
||||
5. [Critical Mass](http://www.moddb.com/mods/half-life-critical-mass) [C3M1 Build 1 Demo](https://www.fileplanet.com/125746/120000/fileinfo/C3M1-Build-1)
|
||||
6. [EPRST!](https://www.runthinkshootlive.com/posts/ep-rst/)
|
||||
6. [EPRST!](http://www.planetphillip.com/posts/ep-rst-opposing-force/) (link dead!)
|
||||
7. [Firing Range](https://www.runthinkshootlive.com/posts/firing-range/)
|
||||
8. [Friendly Fire](https://www.runthinkshootlive.com/posts/friendly-fire/)
|
||||
9. [Guitar Star Pre-Alpha](http://gamer-lab.com/rus/mods_goldsrc/Guitar_Star_(Prealpha))
|
||||
9. [Guitar Star Pre-Alpha](http://hl-lab.ru/eng/mods_goldsrc/Guitar_Star_(Prealpha)) (link dead!)
|
||||
10. [J2000](https://www.runthinkshootlive.com/posts/j2000/)
|
||||
11. [Killing House for OF](https://www.runthinkshootlive.com/posts/scientist-rescue-aka-cqb/)
|
||||
12. [Klabautermann](https://www.runthinkshootlive.com/posts/klabautermann/) (though the map has some inner issues, it can be properly finished, just don't let the welder soldier die and don't press the fifth button until you mount a special gun in its' place)
|
||||
|
||||
@@ -73,8 +73,7 @@ BRUSH MODELS
|
||||
#define MAX_MAP_FACES 262144 // can be increased without problems
|
||||
#define MAX_MAP_MARKSURFACES 524288 // can be increased without problems
|
||||
#else
|
||||
// increased to match PrimeXT compilers
|
||||
#define MAX_MAP_MODELS 1024 // embedded models
|
||||
#define MAX_MAP_MODELS 768 // embedded models
|
||||
#define MAX_MAP_ENTSTRING 0x100000 // 1 Mb should be enough
|
||||
#define MAX_MAP_PLANES 65536 // can be increased without problems
|
||||
#define MAX_MAP_NODES 32767 // because negative shorts are leafs
|
||||
|
||||
@@ -530,7 +530,7 @@ typedef struct
|
||||
#define MAX_DEMOS 32
|
||||
#define MAX_MOVIES 8
|
||||
#define MAX_CDTRACKS 32
|
||||
#define MAX_CLIENT_SPRITES 512 // SpriteTextures (0-256 hud, 256-512 client)
|
||||
#define MAX_CLIENT_SPRITES 256 // SpriteTextures
|
||||
#define MAX_EFRAGS 8192 // Arcane Dimensions required
|
||||
#define MAX_REQUESTS 64
|
||||
|
||||
|
||||
@@ -87,22 +87,6 @@ typedef uint64_t longtime_t;
|
||||
#define NORETURN
|
||||
#endif
|
||||
|
||||
#if ( __GNUC__ >= 3 )
|
||||
#define unlikely(x) __builtin_expect(x, 0)
|
||||
#define likely(x) __builtin_expect(x, 1)
|
||||
#elif defined( __has_builtin )
|
||||
#if __has_builtin( __builtin_expect )
|
||||
#define unlikely(x) __builtin_expect(x, 0)
|
||||
#define likely(x) __builtin_expect(x, 1)
|
||||
#else
|
||||
#define unlikely(x) (x)
|
||||
#define likely(x) (x)
|
||||
#endif
|
||||
#else
|
||||
#define unlikely(x) (x)
|
||||
#define likely(x) (x)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef XASH_BIG_ENDIAN
|
||||
#define LittleLong(x) (((int)(((x)&255)<<24)) + ((int)((((x)>>8)&255)<<16)) + ((int)(((x)>>16)&255)<<8) + (((x) >> 24)&255))
|
||||
@@ -138,6 +122,7 @@ typedef unsigned int dword;
|
||||
typedef unsigned int uint;
|
||||
typedef char string[MAX_STRING];
|
||||
typedef struct file_s file_t; // normal file
|
||||
typedef struct wfile_s wfile_t; // wad file
|
||||
typedef struct stream_s stream_t; // sound stream for background music playing
|
||||
typedef off_t fs_offset_t;
|
||||
#if XASH_WIN32
|
||||
|
||||
@@ -888,7 +888,7 @@ qboolean CL_DemoReadMessage( byte *buffer, size_t *length )
|
||||
qboolean swallowmessages = true;
|
||||
static int tdlastdemoframe = 0;
|
||||
byte *userbuf = NULL;
|
||||
size_t size = 0;
|
||||
size_t size;
|
||||
byte cmd;
|
||||
|
||||
if( !cls.demofile )
|
||||
|
||||
@@ -1111,13 +1111,9 @@ R_ParticleExplosion2
|
||||
void GAME_EXPORT R_ParticleExplosion2( const vec3_t org, int colorStart, int colorLength )
|
||||
{
|
||||
int i, j;
|
||||
int colorMod = 0, packedColor;
|
||||
int colorMod = 0;
|
||||
particle_t *p;
|
||||
|
||||
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
|
||||
packedColor = 255; // use old code for blob particles
|
||||
else packedColor = 0;
|
||||
|
||||
for( i = 0; i < 512; i++ )
|
||||
{
|
||||
p = R_AllocParticle( NULL );
|
||||
@@ -1125,7 +1121,7 @@ void GAME_EXPORT R_ParticleExplosion2( const vec3_t org, int colorStart, int col
|
||||
|
||||
p->die = cl.time + 0.3f;
|
||||
p->color = colorStart + ( colorMod % colorLength );
|
||||
p->packedColor = packedColor;
|
||||
p->packedColor = 255; // use old code for blob particles
|
||||
colorMod++;
|
||||
|
||||
p->type = pt_blob;
|
||||
@@ -1147,19 +1143,15 @@ R_BlobExplosion
|
||||
void GAME_EXPORT R_BlobExplosion( const vec3_t org )
|
||||
{
|
||||
particle_t *p;
|
||||
int i, j, packedColor;
|
||||
|
||||
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
|
||||
packedColor = 255; // use old code for blob particles
|
||||
else packedColor = 0;
|
||||
int i, j;
|
||||
|
||||
for( i = 0; i < 1024; i++ )
|
||||
{
|
||||
p = R_AllocParticle( NULL );
|
||||
if( !p ) return;
|
||||
|
||||
p->die = cl.time + COM_RandomFloat( 1.0f, 1.4f );
|
||||
p->packedColor = packedColor;
|
||||
p->die = cl.time + COM_RandomFloat( 2.0f, 2.4f );
|
||||
p->packedColor = 255; // use old code for blob particles
|
||||
|
||||
if( i & 1 )
|
||||
{
|
||||
|
||||
@@ -534,7 +534,7 @@ void CL_ComputePlayerOrigin( cl_entity_t *ent )
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
|
||||
if( !ent->player )
|
||||
if( !ent->player || ent->index == ( cl.playernum + 1 ))
|
||||
return;
|
||||
|
||||
if( cl_nointerp->value > 0.f )
|
||||
@@ -1094,9 +1094,6 @@ void CL_LinkPlayers( frame_t *frame )
|
||||
|
||||
if ( i == cl.playernum )
|
||||
{
|
||||
// using interpolation only for local player angles
|
||||
CL_ComputePlayerOrigin( ent );
|
||||
|
||||
if( cls.demoplayback == DEMO_QUAKE1 )
|
||||
VectorLerp( ent->prevstate.origin, cl.lerpFrac, ent->curstate.origin, cl.simorg );
|
||||
VectorCopy( cl.simorg, ent->origin );
|
||||
|
||||
@@ -147,6 +147,21 @@ qboolean CL_IsThirdPerson( void )
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_GetPlayerInfo
|
||||
|
||||
get player info by render request
|
||||
====================
|
||||
*/
|
||||
player_info_t *CL_GetPlayerInfo( int playerIndex )
|
||||
{
|
||||
if( playerIndex < 0 || playerIndex >= cl.maxclients )
|
||||
return NULL;
|
||||
|
||||
return &cl.players[playerIndex];
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_CreatePlaylist
|
||||
@@ -1220,10 +1235,6 @@ static model_t *CL_LoadSpriteModel( const char *filename, uint type, uint texFla
|
||||
model_t *mod;
|
||||
int i;
|
||||
|
||||
// use high indices for client sprites
|
||||
// for GoldSrc bug-compatibility
|
||||
const int start = type != SPR_HUDSPRITE ? MAX_CLIENT_SPRITES / 2 : 0;
|
||||
|
||||
if( !COM_CheckString( filename ))
|
||||
{
|
||||
Con_Reportf( S_ERROR "CL_LoadSpriteModel: bad name!\n" );
|
||||
@@ -1233,7 +1244,8 @@ static model_t *CL_LoadSpriteModel( const char *filename, uint type, uint texFla
|
||||
Q_strncpy( name, filename, sizeof( name ));
|
||||
COM_FixSlashes( name );
|
||||
|
||||
for( i = 0, mod = clgame.sprites + start; i < MAX_CLIENT_SPRITES / 2; i++, mod++ )
|
||||
// slot 0 isn't used
|
||||
for( i = 1, mod = clgame.sprites; i < MAX_CLIENT_SPRITES; i++, mod++ )
|
||||
{
|
||||
if( !Q_stricmp( mod->name, name ))
|
||||
{
|
||||
@@ -1250,12 +1262,12 @@ static model_t *CL_LoadSpriteModel( const char *filename, uint type, uint texFla
|
||||
}
|
||||
|
||||
// find a free model slot spot
|
||||
for( i = 0, mod = clgame.sprites + start; i < MAX_CLIENT_SPRITES / 2; i++, mod++ )
|
||||
for( i = 1, mod = clgame.sprites; i < MAX_CLIENT_SPRITES; i++, mod++ )
|
||||
if( !mod->name[0] ) break; // this is a valid spot
|
||||
|
||||
if( i == MAX_CLIENT_SPRITES / 2 )
|
||||
if( i == MAX_CLIENT_SPRITES )
|
||||
{
|
||||
Con_Printf( S_ERROR "MAX_CLIENT_SPRITES limit exceeded (%d)\n", MAX_CLIENT_SPRITES / 2 );
|
||||
Con_Printf( S_ERROR "MAX_CLIENT_SPRITES limit exceeded (%d)\n", MAX_CLIENT_SPRITES );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1296,7 +1308,7 @@ HSPRITE pfnSPR_LoadExt( const char *szPicName, uint texFlags )
|
||||
if(( spr = CL_LoadSpriteModel( szPicName, SPR_CLIENT, texFlags )) == NULL )
|
||||
return 0;
|
||||
|
||||
return (spr - clgame.sprites) + 1; // return index
|
||||
return (spr - clgame.sprites); // return index
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1312,7 +1324,7 @@ HSPRITE EXPORT pfnSPR_Load( const char *szPicName )
|
||||
if(( spr = CL_LoadSpriteModel( szPicName, SPR_HUDSPRITE, 0 )) == NULL )
|
||||
return 0;
|
||||
|
||||
return (spr - clgame.sprites) + 1; // return index
|
||||
return (spr - clgame.sprites); // return index
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1324,11 +1336,10 @@ CL_GetSpritePointer
|
||||
const model_t *CL_GetSpritePointer( HSPRITE hSprite )
|
||||
{
|
||||
model_t *mod;
|
||||
int index = hSprite - 1;
|
||||
|
||||
if( index < 0 || index >= MAX_CLIENT_SPRITES )
|
||||
if( hSprite <= 0 || hSprite >= MAX_CLIENT_SPRITES )
|
||||
return NULL; // bad image
|
||||
mod = &clgame.sprites[index];
|
||||
mod = &clgame.sprites[hSprite];
|
||||
|
||||
if( mod->needload == NL_NEEDS_LOADED )
|
||||
{
|
||||
@@ -1936,14 +1947,7 @@ prints directly into console (can skip notify)
|
||||
*/
|
||||
static void GAME_EXPORT pfnConsolePrint( const char *string )
|
||||
{
|
||||
if( !COM_CheckString( string ))
|
||||
return;
|
||||
|
||||
// WON GoldSrc behavior
|
||||
if( string[0] != 1 )
|
||||
Con_Printf( "%s", string );
|
||||
else
|
||||
Con_NPrintf( 0, "%s", string + 1 );
|
||||
Con_Printf( "%s", string );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2662,14 +2666,7 @@ pfnLoadMapSprite
|
||||
*/
|
||||
model_t *pfnLoadMapSprite( const char *filename )
|
||||
{
|
||||
model_t *mod;
|
||||
|
||||
mod = Mod_FindName( filename, false );
|
||||
|
||||
if( CL_LoadHudSprite( filename, mod, SPR_MAPSPRITE, 0 ))
|
||||
return mod;
|
||||
|
||||
return NULL;
|
||||
return CL_LoadSpriteModel( filename, SPR_MAPSPRITE, 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3090,7 +3087,11 @@ handle colon separately
|
||||
*/
|
||||
char *pfnParseFile( char *data, char *token )
|
||||
{
|
||||
return COM_ParseFileSafe( data, token, PFILE_TOKEN_MAX_LENGTH, PFILE_HANDLECOLON, NULL, NULL );
|
||||
char *out;
|
||||
|
||||
out = _COM_ParseFileSafe( data, token, PFILE_TOKEN_MAX_LENGTH, PFILE_HANDLECOLON, NULL );
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3311,7 +3312,7 @@ NetAPI_InitNetworking
|
||||
*/
|
||||
void GAME_EXPORT NetAPI_InitNetworking( void )
|
||||
{
|
||||
NET_Config( true, false ); // allow remote
|
||||
NET_Config( true ); // allow remote
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3864,7 +3865,7 @@ static cl_enginefunc_t gEngfuncs =
|
||||
(void*)Cmd_GetName,
|
||||
pfnGetClientOldTime,
|
||||
pfnGetGravity,
|
||||
CL_ModelHandle,
|
||||
Mod_Handle,
|
||||
pfnEnableTexSort,
|
||||
pfnSetLightmapColor,
|
||||
pfnSetLightmapScale,
|
||||
|
||||
@@ -980,7 +980,7 @@ pfnGetGamesList
|
||||
*/
|
||||
static GAMEINFO ** GAME_EXPORT pfnGetGamesList( int *numGames )
|
||||
{
|
||||
if( numGames ) *numGames = FI->numgames;
|
||||
if( numGames ) *numGames = SI.numgames;
|
||||
return gameui.modsInfo;
|
||||
}
|
||||
|
||||
@@ -1060,7 +1060,10 @@ pfnChangeInstance
|
||||
*/
|
||||
static void GAME_EXPORT pfnChangeInstance( const char *newInstance, const char *szFinalMessage )
|
||||
{
|
||||
Con_Reportf( S_ERROR "ChangeInstance menu call is deprecated!\n" );
|
||||
if( !szFinalMessage ) szFinalMessage = "";
|
||||
if( !newInstance || !*newInstance ) return;
|
||||
|
||||
Host_NewInstance( newInstance, szFinalMessage );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1117,30 +1120,6 @@ static char *pfnParseFile( char *buf, char *token )
|
||||
return COM_ParseFile( buf, token, INT_MAX );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnFileExists
|
||||
|
||||
legacy wrapper
|
||||
=============
|
||||
*/
|
||||
static int pfnFileExists( const char *path, int gamedironly )
|
||||
{
|
||||
return FS_FileExists( path, gamedironly );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnDelete
|
||||
|
||||
legacy wrapper
|
||||
=============
|
||||
*/
|
||||
static int pfnDelete( const char *path )
|
||||
{
|
||||
return FS_Delete( path );
|
||||
}
|
||||
|
||||
// engine callbacks
|
||||
static ui_enginefuncs_t gEngfuncs =
|
||||
{
|
||||
@@ -1187,7 +1166,7 @@ static ui_enginefuncs_t gEngfuncs =
|
||||
pfnRenderScene,
|
||||
pfnAddEntity,
|
||||
Host_Error,
|
||||
pfnFileExists,
|
||||
FS_FileExists,
|
||||
pfnGetGameDir,
|
||||
Cmd_CheckMapsList,
|
||||
CL_Active,
|
||||
@@ -1226,7 +1205,7 @@ static ui_enginefuncs_t gEngfuncs =
|
||||
COM_CompareFileTime,
|
||||
VID_GetModeString,
|
||||
(void*)COM_SaveFile,
|
||||
pfnDelete
|
||||
(void*)FS_Delete
|
||||
};
|
||||
|
||||
static void pfnEnableTextInput( int enable )
|
||||
@@ -1248,11 +1227,6 @@ static int pfnGetRenderers( unsigned int num, char *shortName, size_t size1, cha
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char *pfnParseFileSafe( char *data, char *buf, const int size, unsigned int flags, int *len )
|
||||
{
|
||||
return COM_ParseFileSafe( data, buf, size, flags, len, NULL );
|
||||
}
|
||||
|
||||
static ui_extendedfuncs_t gExtendedfuncs =
|
||||
{
|
||||
pfnEnableTextInput,
|
||||
@@ -1261,7 +1235,7 @@ static ui_extendedfuncs_t gExtendedfuncs =
|
||||
Con_UtfMoveRight,
|
||||
pfnGetRenderers,
|
||||
Sys_DoubleTime,
|
||||
pfnParseFileSafe,
|
||||
_COM_ParseFileSafe,
|
||||
NET_AdrToString
|
||||
};
|
||||
|
||||
@@ -1382,13 +1356,13 @@ qboolean UI_LoadProgs( void )
|
||||
Cvar_FullSet( "host_gameuiloaded", "1", FCVAR_READ_ONLY );
|
||||
|
||||
// setup gameinfo
|
||||
for( i = 0; i < FI->numgames; i++ )
|
||||
for( i = 0; i < SI.numgames; i++ )
|
||||
{
|
||||
gameui.modsInfo[i] = Mem_Calloc( gameui.mempool, sizeof( GAMEINFO ));
|
||||
UI_ConvertGameInfo( gameui.modsInfo[i], FI->games[i] );
|
||||
UI_ConvertGameInfo( gameui.modsInfo[i], SI.games[i] );
|
||||
}
|
||||
|
||||
UI_ConvertGameInfo( &gameui.gameInfo, FI->GameInfo ); // current gameinfo
|
||||
UI_ConvertGameInfo( &gameui.gameInfo, SI.GameInfo ); // current gameinfo
|
||||
|
||||
// setup globals
|
||||
gameui.globals->developer = host.allow_console;
|
||||
|
||||
@@ -70,7 +70,6 @@ convar_t *cl_upmax;
|
||||
convar_t *cl_lw;
|
||||
convar_t *cl_charset;
|
||||
convar_t *cl_trace_messages;
|
||||
convar_t *cl_nat;
|
||||
convar_t *hud_utf8;
|
||||
convar_t *ui_renderworld;
|
||||
|
||||
@@ -196,6 +195,8 @@ void CL_CheckClientState( void )
|
||||
Netchan_ReportFlow( &cls.netchan );
|
||||
|
||||
Con_DPrintf( "client connected at %.2f sec\n", Sys_DoubleTime() - cls.timestart );
|
||||
if(( cls.demoplayback || cls.disable_servercount != cl.servercount ) && cl.video_prepped )
|
||||
SCR_EndLoadingPlaque(); // get rid of loading plaque
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +234,6 @@ void CL_SignonReply( void )
|
||||
Mem_PrintStats();
|
||||
break;
|
||||
case 2:
|
||||
SCR_EndLoadingPlaque();
|
||||
if( cl.proxy_redirect && !cls.spectator )
|
||||
CL_Disconnect();
|
||||
cl.proxy_redirect = false;
|
||||
@@ -302,7 +302,7 @@ static float CL_LerpPoint( void )
|
||||
else if( server_frametime > 0.001f )
|
||||
{
|
||||
// automatic lerp (classic mode)
|
||||
frac = ( cl.time - cl.mtime[1] ) / server_frametime;
|
||||
frac = ( cl.time - cl.mtime[1] ) / server_frametime;
|
||||
}
|
||||
#endif
|
||||
return frac;
|
||||
@@ -367,7 +367,7 @@ void CL_ComputeClientInterpolationAmount( usercmd_t *cmd )
|
||||
|
||||
min_interp = 1.0f / cl_updaterate->value;
|
||||
interpolation_time = CL_LerpInterval( );
|
||||
|
||||
|
||||
if( (cl_interp->value + epsilon) < min_interp )
|
||||
{
|
||||
Con_Printf( "ex_interp forced up to %.1f msec\n", min_interp * 1000.f );
|
||||
@@ -864,9 +864,6 @@ void CL_WritePacket( void )
|
||||
cl.commands[cls.netchan.outgoing_sequence & CL_UPDATE_MASK].sendsize = MSG_GetNumBytesWritten( &buf );
|
||||
cl.commands[cls.netchan.outgoing_sequence & CL_UPDATE_MASK].heldback = false;
|
||||
|
||||
// send voice data to the server
|
||||
CL_AddVoiceToDatagram();
|
||||
|
||||
// composite the rest of the datagram..
|
||||
if( MSG_GetNumBitsWritten( &cls.datagram ) <= MSG_GetNumBitsLeft( &buf ))
|
||||
MSG_WriteBits( &buf, MSG_GetData( &cls.datagram ), MSG_GetNumBitsWritten( &cls.datagram ));
|
||||
@@ -1256,7 +1253,7 @@ void CL_Connect_f( void )
|
||||
|
||||
// if running a local server, kill it and reissue
|
||||
if( SV_Active( )) Host_ShutdownServer();
|
||||
NET_Config( true, !CVAR_TO_BOOL( cl_nat )); // allow remote
|
||||
NET_Config( true ); // allow remote
|
||||
|
||||
Con_Printf( "server %s\n", server );
|
||||
CL_Disconnect();
|
||||
@@ -1302,7 +1299,7 @@ void CL_Rcon_f( void )
|
||||
message[3] = (char)255;
|
||||
message[4] = 0;
|
||||
|
||||
NET_Config( true, false ); // allow remote
|
||||
NET_Config( true ); // allow remote
|
||||
|
||||
Q_strcat( message, "rcon " );
|
||||
Q_strcat( message, rcon_client_password->string );
|
||||
@@ -1503,7 +1500,6 @@ void CL_Disconnect( void )
|
||||
cls.connect_time = 0;
|
||||
cls.changedemo = false;
|
||||
cls.max_fragment_size = FRAGMENT_MAX_SIZE; // reset fragment size
|
||||
Voice_Disconnect();
|
||||
CL_Stop_f();
|
||||
|
||||
// send a disconnect message to the server
|
||||
@@ -1566,7 +1562,7 @@ void CL_LocalServers_f( void )
|
||||
netadr_t adr;
|
||||
|
||||
Con_Printf( "Scanning for servers on the local network area...\n" );
|
||||
NET_Config( true, true ); // allow remote
|
||||
NET_Config( true ); // allow remote
|
||||
|
||||
// send a broadcast packet
|
||||
adr.type = NA_BROADCAST;
|
||||
@@ -1588,12 +1584,12 @@ void CL_InternetServers_f( void )
|
||||
char *info = fullquery + sizeof( MS_SCAN_REQUEST ) - 1;
|
||||
const size_t remaining = sizeof( fullquery ) - sizeof( MS_SCAN_REQUEST );
|
||||
|
||||
NET_Config( true, true ); // allow remote
|
||||
NET_Config( true ); // allow remote
|
||||
|
||||
Con_Printf( "Scanning for servers on the internet area...\n" );
|
||||
Info_SetValueForKey( info, "gamedir", GI->gamefolder, remaining );
|
||||
Info_SetValueForKey( info, "clver", XASH_VERSION, remaining ); // let master know about client version
|
||||
Info_SetValueForKey( info, "nat", cl_nat->string, remaining );
|
||||
// Info_SetValueForKey( info, "nat", cl_nat->string, remaining );
|
||||
|
||||
cls.internetservers_wait = NET_SendToMasters( NS_CLIENT, sizeof( MS_SCAN_REQUEST ) + Q_strlen( info ), fullquery );
|
||||
cls.internetservers_pending = true;
|
||||
@@ -1717,23 +1713,16 @@ void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg )
|
||||
static char infostring[MAX_INFO_STRING+8];
|
||||
char *s = MSG_ReadString( msg );
|
||||
int i;
|
||||
const char *magic = ": wrong version\n";
|
||||
size_t len = Q_strlen( s ), magiclen = Q_strlen( magic );
|
||||
|
||||
if( len >= magiclen && !Q_strcmp( s + len - magiclen, magic ))
|
||||
{
|
||||
Netchan_OutOfBandPrint( NS_CLIENT, from, "info %i", PROTOCOL_LEGACY_VERSION );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !Info_IsValid( s ))
|
||||
{
|
||||
Con_Printf( "^1Server^7: %s, invalid infostring\n", NET_AdrToString( from ));
|
||||
return;
|
||||
}
|
||||
|
||||
CL_FixupColorStringsForInfoString( s, infostring );
|
||||
|
||||
if( Q_strstr( infostring, "wrong version" ) )
|
||||
{
|
||||
Netchan_OutOfBandPrint( NS_CLIENT, from, "info %i", PROTOCOL_LEGACY_VERSION );
|
||||
Con_Printf( "^1Server^7: %s, Info: %s\n", NET_AdrToString( from ), infostring );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !COM_CheckString( Info_ValueForKey( infostring, "gamedir" )))
|
||||
{
|
||||
Con_Printf( "^1Server^7: %s, Info: %s\n", NET_AdrToString( from ), infostring );
|
||||
@@ -1743,14 +1732,12 @@ void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg )
|
||||
if( !COM_CheckString( Info_ValueForKey( infostring, "p" )))
|
||||
{
|
||||
Info_SetValueForKey( infostring, "legacy", "1", sizeof( infostring ) );
|
||||
Con_Printf( "^3Server^7: %s, Game: %s\n", NET_AdrToString( from ), Info_ValueForKey( infostring, "gamedir" ));
|
||||
}
|
||||
else
|
||||
{
|
||||
// more info about servers
|
||||
Con_Printf( "^2Server^7: %s, Game: %s\n", NET_AdrToString( from ), Info_ValueForKey( infostring, "gamedir" ));
|
||||
Con_Print("Legacy: ");
|
||||
}
|
||||
|
||||
// more info about servers
|
||||
Con_Printf( "^2Server^7: %s, Game: %s\n", NET_AdrToString( from ), Info_ValueForKey( infostring, "gamedir" ));
|
||||
|
||||
UI_AddServerToList( from, infostring );
|
||||
}
|
||||
|
||||
@@ -2108,12 +2095,6 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
|
||||
}
|
||||
else if( !Q_strcmp( c, "f" ))
|
||||
{
|
||||
if( !NET_IsMasterAdr( from ))
|
||||
{
|
||||
Con_Printf( S_WARN "unexpected server list packet from %s\n", NET_AdrToString( from ));
|
||||
return;
|
||||
}
|
||||
|
||||
// serverlist got from masterserver
|
||||
while( MSG_GetNumBitsLeft( msg ) > 8 )
|
||||
{
|
||||
@@ -2172,7 +2153,7 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
|
||||
}
|
||||
else if( clgame.request_type == NET_REQUEST_GAMEUI )
|
||||
{
|
||||
NET_Config( true, false ); // allow remote
|
||||
NET_Config( true ); // allow remote
|
||||
Netchan_OutOfBandPrint( NS_CLIENT, servadr, "info %i", PROTOCOL_VERSION );
|
||||
}
|
||||
}
|
||||
@@ -2827,8 +2808,6 @@ void CL_InitLocal( void )
|
||||
Cvar_RegisterVariable( &cl_logocolor );
|
||||
Cvar_RegisterVariable( &cl_test_bandwidth );
|
||||
|
||||
Voice_RegisterCvars();
|
||||
|
||||
// register our variables
|
||||
cl_crosshair = Cvar_Get( "crosshair", "1", FCVAR_ARCHIVE, "show weapon chrosshair" );
|
||||
cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0, "disable delta-compression for server messages" );
|
||||
@@ -2851,7 +2830,6 @@ void CL_InitLocal( void )
|
||||
cl_updaterate = Cvar_Get( "cl_updaterate", "20", FCVAR_USERINFO|FCVAR_ARCHIVE, "refresh rate of server messages" );
|
||||
cl_dlmax = Cvar_Get( "cl_dlmax", "0", FCVAR_USERINFO|FCVAR_ARCHIVE, "max allowed outcoming fragment size" );
|
||||
cl_upmax = Cvar_Get( "cl_upmax", "1200", FCVAR_ARCHIVE, "max allowed incoming fragment size" );
|
||||
cl_nat = Cvar_Get( "cl_nat", "0", 0, "show servers running under NAT" );
|
||||
rate = Cvar_Get( "rate", "3500", FCVAR_USERINFO|FCVAR_ARCHIVE|FCVAR_FILTERABLE, "player network rate" );
|
||||
topcolor = Cvar_Get( "topcolor", "0", FCVAR_USERINFO|FCVAR_ARCHIVE, "player top color" );
|
||||
bottomcolor = Cvar_Get( "bottomcolor", "0", FCVAR_USERINFO|FCVAR_ARCHIVE, "player bottom color" );
|
||||
@@ -2894,6 +2872,7 @@ void CL_InitLocal( void )
|
||||
Cmd_AddRestrictedCommand ("kill", NULL, "die instantly" );
|
||||
Cmd_AddCommand ("god", NULL, "enable godmode" );
|
||||
Cmd_AddCommand ("fov", NULL, "set client field of view" );
|
||||
Cmd_AddCommand ("log", NULL, "logging server events" );
|
||||
|
||||
// register our commands
|
||||
Cmd_AddCommand ("pause", NULL, "pause the game (if the server allows pausing)" );
|
||||
@@ -3030,8 +3009,8 @@ void Host_ClientFrame( void )
|
||||
// a new portion updates from server
|
||||
CL_RedoPrediction ();
|
||||
|
||||
// update voice
|
||||
Voice_Idle( host.frametime );
|
||||
// TODO: implement
|
||||
// Voice_Idle( host.frametime );
|
||||
|
||||
// emit visible entities
|
||||
CL_EmitEntities ();
|
||||
@@ -3085,7 +3064,6 @@ void CL_Init( void )
|
||||
|
||||
VID_Init(); // init video
|
||||
S_Init(); // init sound
|
||||
Voice_Init( VOICE_DEFAULT_CODEC, 3 ); // init voice
|
||||
|
||||
// unreliable buffer. unsed for unreliable commands and voice stream
|
||||
MSG_Init( &cls.datagram, "cls.datagram", cls.datagram_buf, sizeof( cls.datagram_buf ));
|
||||
@@ -3113,7 +3091,7 @@ void CL_Shutdown( void )
|
||||
{
|
||||
Con_Printf( "CL_Shutdown()\n" );
|
||||
|
||||
if( !host.crashed && cls.initialized )
|
||||
if( !host.crashed )
|
||||
{
|
||||
Host_WriteOpenGLConfig ();
|
||||
Host_WriteVideoConfig ();
|
||||
|
||||
@@ -103,11 +103,6 @@ static void pfnTouch_RemoveButton( const char *name )
|
||||
Touch_RemoveButton( name, true );
|
||||
}
|
||||
|
||||
static char *pfnParseFileSafe( char *data, char *buf, const int size, unsigned int flags, int *len )
|
||||
{
|
||||
return COM_ParseFileSafe( data, buf, size, flags, len, NULL );
|
||||
}
|
||||
|
||||
static mobile_engfuncs_t gpMobileEngfuncs =
|
||||
{
|
||||
MOBILITY_API_VERSION,
|
||||
@@ -123,7 +118,7 @@ static mobile_engfuncs_t gpMobileEngfuncs =
|
||||
Sys_Warn,
|
||||
pfnGetNativeObject,
|
||||
ID_SetCustomClientID,
|
||||
pfnParseFileSafe
|
||||
_COM_ParseFileSafe
|
||||
};
|
||||
|
||||
qboolean Mobile_Init( void )
|
||||
|
||||
@@ -158,7 +158,6 @@ static void NetGraph_InitColors( void )
|
||||
f = (float)(i - hfrac) / (float)(NETGRAPH_LERP_HEIGHT - hfrac );
|
||||
VectorMA( mincolor[1], f, dc[1], netcolors[NETGRAPH_NET_COLORS + i] );
|
||||
}
|
||||
netcolors[NETGRAPH_NET_COLORS + i][3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,7 +259,7 @@ static void NetGraph_DrawTimes( wrect_t rect, int x, int w )
|
||||
for( a = 0; a < w; a++ )
|
||||
{
|
||||
i = ( cls.netchan.outgoing_sequence - a ) & NET_TIMINGS_MASK;
|
||||
h = Q_min(( netstat_cmdinfo[i].cmd_lerp / 3.0f ) * NETGRAPH_LERP_HEIGHT, net_graphheight->value * 0.7f);
|
||||
h = ( netstat_cmdinfo[i].cmd_lerp / 3.0f ) * NETGRAPH_LERP_HEIGHT;
|
||||
|
||||
fill.left = x + w - a - 1;
|
||||
fill.right = fill.bottom = 1;
|
||||
@@ -396,10 +395,10 @@ static void NetGraph_DrawTextFields( int x, int y, int w, wrect_t rect, int coun
|
||||
if( !out ) out = lastout;
|
||||
else lastout = out;
|
||||
|
||||
Con_DrawString( x, y, va( "in : %i %.2f kb/s", netstat_graph[j].msgbytes, cls.netchan.flow[FLOW_INCOMING].avgkbytespersec ), colors );
|
||||
Con_DrawString( x, y, va( "in : %i %.2f k/s", netstat_graph[j].msgbytes, cls.netchan.flow[FLOW_INCOMING].avgkbytespersec ), colors );
|
||||
y += 15;
|
||||
|
||||
Con_DrawString( x, y, va( "out: %i %.2f kb/s", out, cls.netchan.flow[FLOW_OUTGOING].avgkbytespersec ), colors );
|
||||
Con_DrawString( x, y, va( "out: %i %.2f k/s", out, cls.netchan.flow[FLOW_OUTGOING].avgkbytespersec ), colors );
|
||||
y += 15;
|
||||
|
||||
if( graphtype > 2 )
|
||||
@@ -616,7 +615,7 @@ static void NetGraph_GetScreenPos( wrect_t *rect, int *w, int *x, int *y )
|
||||
*x = rect->left + rect->right - 5 - *w;
|
||||
break;
|
||||
case 2: // center
|
||||
*x = ( rect->left + ( rect->right - 10 - *w )) / 2;
|
||||
*x = rect->left + ( rect->right - 10 - *w ) / 2;
|
||||
break;
|
||||
default: // left sided
|
||||
*x = rect->left + 5;
|
||||
@@ -673,7 +672,7 @@ void SCR_DrawNetGraph( void )
|
||||
|
||||
if( graphtype < 3 )
|
||||
{
|
||||
ref.dllFuncs.GL_SetRenderMode( kRenderTransColor );
|
||||
ref.dllFuncs.GL_SetRenderMode( kRenderTransAdd );
|
||||
ref.dllFuncs.GL_Bind( XASH_TEXTURE0, R_GetBuiltinTexture( REF_WHITE_TEXTURE ) );
|
||||
ref.dllFuncs.Begin( TRI_QUADS ); // draw all the fills as a long solid sequence of quads for speedup reasons
|
||||
|
||||
|
||||
@@ -1348,12 +1348,7 @@ void CL_UpdateUserinfo( sizebuf_t *msg )
|
||||
|
||||
if( slot == cl.playernum ) memcpy( &gameui.playerinfo, player, sizeof( player_info_t ));
|
||||
}
|
||||
else
|
||||
{
|
||||
COM_ClearCustomizationList( &player->customdata, true );
|
||||
|
||||
memset( player, 0, sizeof( *player ));
|
||||
}
|
||||
else memset( player, 0, sizeof( *player ));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1685,10 +1680,7 @@ CL_ParseVoiceInit
|
||||
*/
|
||||
void CL_ParseVoiceInit( sizebuf_t *msg )
|
||||
{
|
||||
char *pszCodec = MSG_ReadString( msg );
|
||||
int quality = MSG_ReadByte( msg );
|
||||
|
||||
Voice_Init( pszCodec, quality );
|
||||
// TODO: ???
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1699,31 +1691,7 @@ CL_ParseVoiceData
|
||||
*/
|
||||
void CL_ParseVoiceData( sizebuf_t *msg )
|
||||
{
|
||||
int size, idx, frames;
|
||||
byte received[8192];
|
||||
|
||||
idx = MSG_ReadByte( msg ) + 1;
|
||||
|
||||
frames = MSG_ReadByte( msg );
|
||||
|
||||
size = MSG_ReadShort( msg );
|
||||
size = Q_min( size, sizeof( received ));
|
||||
|
||||
MSG_ReadBytes( msg, received, size );
|
||||
|
||||
if ( idx <= 0 || idx > cl.maxclients )
|
||||
return;
|
||||
|
||||
// must notify through as both local player and normal client
|
||||
if( idx == cl.playernum + 1 )
|
||||
Voice_StatusAck( &voice.local, VOICE_LOOPBACK_INDEX );
|
||||
|
||||
Voice_StatusAck( &voice.players_status[idx], idx );
|
||||
|
||||
if ( !size )
|
||||
return;
|
||||
|
||||
Voice_AddIncomingData( idx, received, size, frames );
|
||||
// TODO: ???
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2367,7 +2335,6 @@ void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message )
|
||||
break;
|
||||
case svc_voicedata:
|
||||
CL_ParseVoiceData( msg );
|
||||
cl.frames[cl.parsecountmod].graphdata.voicebytes += MSG_GetNumBytesRead( msg ) - bufStart;
|
||||
break;
|
||||
case svc_resourcelocation:
|
||||
CL_ParseResLocation( msg );
|
||||
@@ -3150,6 +3117,12 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message )
|
||||
case svc_director:
|
||||
CL_ParseDirector( msg );
|
||||
break;
|
||||
case svc_voiceinit:
|
||||
CL_ParseVoiceInit( msg );
|
||||
break;
|
||||
case svc_voicedata:
|
||||
CL_ParseVoiceData( msg );
|
||||
break;
|
||||
case svc_resourcelocation:
|
||||
CL_ParseResLocation( msg );
|
||||
break;
|
||||
|
||||
@@ -794,8 +794,6 @@ static float GAME_EXPORT pfnTraceModel( physent_t *pe, float *start, float *end,
|
||||
matrix4x4 matrix;
|
||||
hull_t *hull;
|
||||
|
||||
PM_InitTrace( trace, end );
|
||||
|
||||
old_usehull = clgame.pmove->usehull;
|
||||
clgame.pmove->usehull = 2;
|
||||
|
||||
|
||||
@@ -864,7 +864,7 @@ void CL_QuakeExecStuff( void )
|
||||
|
||||
if( !*text ) break;
|
||||
|
||||
text = COM_ParseFileSafe( text, token, sizeof( token ), PFILE_IGNOREBRACKET, NULL, NULL );
|
||||
text = _COM_ParseFileSafe( text, token, sizeof( token ), PFILE_IGNOREBRACKET, NULL );
|
||||
|
||||
if( !text ) break;
|
||||
|
||||
|
||||
@@ -418,6 +418,7 @@ void SCR_BeginLoadingPlaque( qboolean is_background )
|
||||
cls.draw_changelevel = !is_background;
|
||||
SCR_UpdateScreen();
|
||||
cls.disable_screen = host.realtime;
|
||||
cls.disable_servercount = cl.servercount;
|
||||
cl.background = is_background; // set right state before svc_serverdata is came
|
||||
|
||||
if( !Host_IsDedicated() )
|
||||
|
||||
@@ -1904,7 +1904,7 @@ handle temp-entity messages
|
||||
void CL_ParseTempEntity( sizebuf_t *msg )
|
||||
{
|
||||
sizebuf_t buf;
|
||||
byte pbuf[2048];
|
||||
byte pbuf[256];
|
||||
int iSize;
|
||||
int type, color, count, flags;
|
||||
int decalIndex, modelIndex, entityIndex;
|
||||
@@ -1923,10 +1923,6 @@ void CL_ParseTempEntity( sizebuf_t *msg )
|
||||
|
||||
decalIndex = modelIndex = entityIndex = 0;
|
||||
|
||||
// this will probably be fatal anyway
|
||||
if( iSize > sizeof( pbuf ))
|
||||
Con_Printf( S_ERROR "%s: Temp buffer overflow!\n", __FUNCTION__ );
|
||||
|
||||
// parse user message into buffer
|
||||
MSG_ReadBytes( msg, pbuf, iSize );
|
||||
|
||||
@@ -1974,9 +1970,6 @@ void CL_ParseTempEntity( sizebuf_t *msg )
|
||||
pos[1] = MSG_ReadCoord( &buf );
|
||||
pos[2] = MSG_ReadCoord( &buf );
|
||||
R_BlobExplosion( pos );
|
||||
|
||||
hSound = S_RegisterSound( cl_explode_sounds[0] );
|
||||
S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 1.0f, PITCH_NORM, 0 );
|
||||
break;
|
||||
case TE_SMOKE:
|
||||
pos[0] = MSG_ReadCoord( &buf );
|
||||
@@ -2030,7 +2023,7 @@ void CL_ParseTempEntity( sizebuf_t *msg )
|
||||
dl->decay = 300;
|
||||
|
||||
hSound = S_RegisterSound( cl_explode_sounds[0] );
|
||||
S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 0.6f, PITCH_NORM, 0 );
|
||||
S_StartSound( pos, 0, CHAN_STATIC, hSound, VOL_NORM, 0.6f, PITCH_NORM, 0 );
|
||||
break;
|
||||
case TE_BSPDECAL:
|
||||
case TE_DECAL:
|
||||
|
||||
@@ -286,6 +286,9 @@ qboolean V_PreRender( void )
|
||||
if( !ref.initialized )
|
||||
return false;
|
||||
|
||||
if( host.status == HOST_NOFOCUS )
|
||||
return false;
|
||||
|
||||
if( host.status == HOST_SLEEP )
|
||||
return false;
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ GNU General Public License for more details.
|
||||
#include "net_api.h"
|
||||
#include "world.h"
|
||||
#include "ref_common.h"
|
||||
#include "voice.h"
|
||||
|
||||
// client sprite types
|
||||
#define SPR_CLIENT 0 // client sprite for temp-entities or user-textures
|
||||
@@ -466,7 +465,7 @@ typedef struct
|
||||
|
||||
string cdtracks[MAX_CDTRACKS]; // 32 cd-tracks read from cdaudio.txt
|
||||
|
||||
model_t sprites[MAX_CLIENT_SPRITES]; // hud&client spritetexturesz
|
||||
model_t sprites[MAX_CLIENT_SPRITES]; // client spritetextures
|
||||
int viewport[4]; // viewport sizes
|
||||
|
||||
client_draw_t ds; // draw2d stuff (hud, weaponmenu etc)
|
||||
@@ -528,6 +527,9 @@ typedef struct
|
||||
float disable_screen; // showing loading plaque between levels
|
||||
// or changing rendering dlls
|
||||
// if time gets > 30 seconds ahead, break it
|
||||
int disable_servercount; // when we receive a frame and cl.servercount
|
||||
// > cls.disable_servercount, clear disable_screen
|
||||
|
||||
qboolean draw_changelevel; // draw changelevel image 'Loading...'
|
||||
|
||||
keydest_t key_dest;
|
||||
@@ -703,7 +705,7 @@ dlight_t *CL_GetEntityLight( int number );
|
||||
//
|
||||
// cl_cmds.c
|
||||
//
|
||||
void CL_Quit_f( void );
|
||||
void CL_Quit_f( void ) NORETURN;
|
||||
void CL_ScreenShot_f( void );
|
||||
void CL_SnapShot_f( void );
|
||||
void CL_PlayCDTrack_f( void );
|
||||
|
||||
@@ -283,8 +283,6 @@ void Con_ToggleConsole_f( void )
|
||||
if( !host.allow_console || UI_CreditsActive( ))
|
||||
return; // disabled
|
||||
|
||||
SCR_EndLoadingPlaque();
|
||||
|
||||
// show console only in game or by special call from menu
|
||||
if( cls.state != ca_active || cls.key_dest == key_menu )
|
||||
return;
|
||||
@@ -914,7 +912,7 @@ static int Con_DrawGenericChar( int x, int y, int number, rgba_t color )
|
||||
if( !con.curFont || !con.curFont->valid )
|
||||
return 0;
|
||||
|
||||
number = Con_UtfProcessChar( number );
|
||||
number = Con_UtfProcessChar(number);
|
||||
if( !number )
|
||||
return 0;
|
||||
|
||||
@@ -2041,7 +2039,7 @@ void Con_DrawDebug( void )
|
||||
if( scr_download->value != -1.0f )
|
||||
{
|
||||
Q_snprintf( dlstring, sizeof( dlstring ), "Downloading [%d remaining]: ^2%s^7 %5.1f%% time %.f secs",
|
||||
host.downloadcount, host.downloadfile, scr_download->value, Sys_DoubleTime() - timeStart );
|
||||
host.downloadcount, host.downloadfile, scr_download->value, Sys_DoubleTime() - timeStart );
|
||||
x = refState.width - 500;
|
||||
y = con.curFont->charHeight * 1.05f;
|
||||
Con_DrawString( x, y, dlstring, g_color_table[7] );
|
||||
@@ -2051,7 +2049,7 @@ void Con_DrawDebug( void )
|
||||
timeStart = Sys_DoubleTime();
|
||||
}
|
||||
|
||||
if( !host.allow_console || Cvar_VariableInteger( "cl_background" ) || Cvar_VariableInteger( "sv_background" ))
|
||||
if( !host_developer.value || Cvar_VariableInteger( "cl_background" ) || Cvar_VariableInteger( "sv_background" ))
|
||||
return;
|
||||
|
||||
if( con.draw_notify && !Con_Visible( ))
|
||||
@@ -2077,7 +2075,7 @@ void Con_DrawNotify( void )
|
||||
|
||||
x = con.curFont->charWidths[' ']; // offset one space at left screen side
|
||||
|
||||
if( host.allow_console && ( !Cvar_VariableInteger( "cl_background" ) && !Cvar_VariableInteger( "sv_background" )))
|
||||
if( host_developer.value && ( !Cvar_VariableInteger( "cl_background" ) && !Cvar_VariableInteger( "sv_background" )))
|
||||
{
|
||||
for( i = CON_LINES_COUNT - con.num_times; i < CON_LINES_COUNT; i++ )
|
||||
{
|
||||
@@ -2403,21 +2401,11 @@ void Con_RunConsole( void )
|
||||
FBitSet( cl_charset->flags, FCVAR_CHANGED ) )
|
||||
{
|
||||
// update codepage parameters
|
||||
if( !Q_stricmp( con_charset->string, "cp1251" ))
|
||||
{
|
||||
g_codepage = 0;
|
||||
if( !Q_stricmp( con_charset->string, "cp1251" ) )
|
||||
g_codepage = 1251;
|
||||
}
|
||||
else if( !Q_stricmp( con_charset->string, "cp1252" ))
|
||||
{
|
||||
else if( !Q_stricmp( con_charset->string, "cp1252" ) )
|
||||
g_codepage = 1252;
|
||||
}
|
||||
else
|
||||
{
|
||||
Con_Printf( S_WARN "Unknown charset %s, defaulting to cp1252", con_charset->string );
|
||||
|
||||
Cvar_DirectSet( con_charset, "cp1252" );
|
||||
g_codepage = 1252;
|
||||
}
|
||||
|
||||
g_utf8 = !Q_stricmp( cl_charset->string, "utf-8" );
|
||||
Con_InvalidateFonts();
|
||||
|
||||
@@ -994,7 +994,7 @@ static void Touch_InitEditor( void )
|
||||
|
||||
Touch_ClearList( &touch.list_edit );
|
||||
|
||||
temp = Touch_AddButton( &touch.list_edit, "close", "touch_default/edit_close", "touch_disableedit", 0, y, x, y + 0.1f, color, true );
|
||||
temp = Touch_AddButton( &touch.list_edit, "close", "touch_default/edit_close.tga", "touch_disableedit", 0, y, x, y + 0.1f, color, true );
|
||||
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
||||
|
||||
temp = Touch_AddButton( &touch.list_edit, "close", "#Close and save", "", x, y, x + 0.2f, y + 0.1f, color, true );
|
||||
@@ -1002,7 +1002,7 @@ static void Touch_InitEditor( void )
|
||||
|
||||
y += 0.2f;
|
||||
|
||||
temp = Touch_AddButton( &touch.list_edit, "cancel", "touch_default/edit_reset", "touch_reloadconfig", 0, y, x, y + 0.1f, color, true );
|
||||
temp = Touch_AddButton( &touch.list_edit, "cancel", "touch_default/edit_reset.tga", "touch_reloadconfig", 0, y, x, y + 0.1f, color, true );
|
||||
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
||||
|
||||
temp = Touch_AddButton( &touch.list_edit, "close", "#Cancel and reset", "", x, y, x + 0.2f, y + 0.1f, color, true );
|
||||
@@ -1010,7 +1010,7 @@ static void Touch_InitEditor( void )
|
||||
|
||||
y += 0.2f;
|
||||
|
||||
touch.hidebutton = Touch_AddButton( &touch.list_edit, "showhide", "touch_default/edit_hide", "touch_toggleselection", 0, y, x, y + 0.1f, color, true );
|
||||
touch.hidebutton = Touch_AddButton( &touch.list_edit, "showhide", "touch_default/edit_hide.tga", "touch_toggleselection", 0, y, x, y + 0.1f, color, true );
|
||||
SetBits( touch.hidebutton->flags, TOUCH_FL_HIDE | TOUCH_FL_NOEDIT );
|
||||
}
|
||||
|
||||
@@ -1038,23 +1038,23 @@ void Touch_Init( void )
|
||||
MakeRGBA( color, 255, 255, 255, 255 );
|
||||
Touch_AddDefaultButton( "look", "", "_look", 0.500000, 0.000000, 1.000000, 1, color, 0, 0, 0 );
|
||||
Touch_AddDefaultButton( "move", "", "_move", 0.000000, 0.000000, 0.500000, 1, color, 0, 0, 0 );
|
||||
Touch_AddDefaultButton( "invnext", "touch_default/next_weap", "invnext", 0.000000, 0.530200, 0.120000, 0.757428, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "invprev", "touch_default/prev_weap", "invprev", 0.000000, 0.075743, 0.120000, 0.302971, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "use", "touch_default/use", "+use", 0.880000, 0.454457, 1.000000, 0.681685, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "jump", "touch_default/jump", "+jump", 0.880000, 0.227228, 1.000000, 0.454457, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "attack", "touch_default/shoot", "+attack", 0.760000, 0.530200, 0.880000, 0.757428, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "attack2", "touch_default/shoot_alt", "+attack2", 0.760000, 0.302971, 0.880000, 0.530200, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "loadquick", "touch_default/load", "loadquick", 0.760000, 0.000000, 0.840000, 0.151486, color, 2, 1, 16 );
|
||||
Touch_AddDefaultButton( "savequick", "touch_default/save", "savequick", 0.840000, 0.000000, 0.920000, 0.151486, color, 2, 1, 16 );
|
||||
Touch_AddDefaultButton( "messagemode", "touch_default/keyboard", "messagemode", 0.840000, 0.000000, 0.920000, 0.151486, color, 2, 1, 8 );
|
||||
Touch_AddDefaultButton( "reload", "touch_default/reload", "+reload", 0.000000, 0.302971, 0.120000, 0.530200, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "flashlight", "touch_default/flash_light_filled", "impulse 100", 0.920000, 0.000000, 1.000000, 0.151486, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "scores", "touch_default/map", "+showscores", 0.760000, 0.000000, 0.840000, 0.151486, color, 2, 1, 8 );
|
||||
Touch_AddDefaultButton( "show_numbers", "touch_default/show_weapons", "exec touch_default/numbers.cfg", 0.440000, 0.833171, 0.520000, 0.984656, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "duck", "touch_default/crouch", "+duck", 0.880000, 0.757428, 1.000000, 0.984656, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "tduck", "touch_default/tduck", ";+duck", 0.560000, 0.833171, 0.620000, 0.946785, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "edit", "touch_default/settings", "touch_enableedit", 0.420000, 0.000000, 0.500000, 0.151486, color, 2, 1, 32 );
|
||||
Touch_AddDefaultButton( "menu", "touch_default/menu", "escape", 0.000000, 0.833171, 0.080000, 0.984656, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "invnext", "touch_default/next_weap.tga", "invnext", 0.000000, 0.530200, 0.120000, 0.757428, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "invprev", "touch_default/prev_weap.tga", "invprev", 0.000000, 0.075743, 0.120000, 0.302971, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "use", "touch_default/use.tga", "+use", 0.880000, 0.454457, 1.000000, 0.681685, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "jump", "touch_default/jump.tga", "+jump", 0.880000, 0.227228, 1.000000, 0.454457, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "attack", "touch_default/shoot.tga", "+attack", 0.760000, 0.530200, 0.880000, 0.757428, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "attack2", "touch_default/shoot_alt.tga", "+attack2", 0.760000, 0.302971, 0.880000, 0.530200, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "loadquick", "touch_default/load.tga", "loadquick", 0.760000, 0.000000, 0.840000, 0.151486, color, 2, 1, 16 );
|
||||
Touch_AddDefaultButton( "savequick", "touch_default/save.tga", "savequick", 0.840000, 0.000000, 0.920000, 0.151486, color, 2, 1, 16 );
|
||||
Touch_AddDefaultButton( "messagemode", "touch_default/keyboard.tga", "messagemode", 0.840000, 0.000000, 0.920000, 0.151486, color, 2, 1, 8 );
|
||||
Touch_AddDefaultButton( "reload", "touch_default/reload.tga", "+reload", 0.000000, 0.302971, 0.120000, 0.530200, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "flashlight", "touch_default/flash_light_filled.tga", "impulse 100", 0.920000, 0.000000, 1.000000, 0.151486, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "scores", "touch_default/map.tga", "+showscores", 0.760000, 0.000000, 0.840000, 0.151486, color, 2, 1, 8 );
|
||||
Touch_AddDefaultButton( "show_numbers", "touch_default/show_weapons.tga", "exec touch_default/numbers.cfg", 0.440000, 0.833171, 0.520000, 0.984656, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "duck", "touch_default/crouch.tga", "+duck", 0.880000, 0.757428, 1.000000, 0.984656, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "tduck", "touch_default/tduck.tga", ";+duck", 0.560000, 0.833171, 0.620000, 0.946785, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "edit", "touch_default/settings.tga", "touch_enableedit", 0.420000, 0.000000, 0.500000, 0.151486, color, 2, 1, 32 );
|
||||
Touch_AddDefaultButton( "menu", "touch_default/menu.tga", "escape", 0.000000, 0.833171, 0.080000, 0.984656, color, 2, 1, 0 );
|
||||
|
||||
|
||||
Cmd_AddCommand( "touch_addbutton", Touch_AddButton_f, "add native touch button" );
|
||||
@@ -1106,7 +1106,7 @@ void Touch_Init( void )
|
||||
touch_dpad_radius = Cvar_Get( "touch_dpad_radius", "1.0", FCVAR_FILTERABLE, "dpad radius multiplier" );
|
||||
touch_joy_radius = Cvar_Get( "touch_joy_radius", "1.0", FCVAR_FILTERABLE, "joy radius multiplier" );
|
||||
touch_move_indicator = Cvar_Get( "touch_move_indicator", "0.0", FCVAR_FILTERABLE, "indicate move events (0 to disable)" );
|
||||
touch_joy_texture = Cvar_Get( "touch_joy_texture", "touch_default/joy", FCVAR_FILTERABLE, "texture for move indicator");
|
||||
touch_joy_texture = Cvar_Get( "touch_joy_texture", "touch_default/joy.tga", FCVAR_FILTERABLE, "texture for move indicator");
|
||||
|
||||
// input devices cvar
|
||||
touch_enable = Cvar_Get( "touch_enable", DEFAULT_TOUCH_ENABLE, FCVAR_ARCHIVE | FCVAR_FILTERABLE, "enable touch controls" );
|
||||
@@ -1515,9 +1515,9 @@ static void Touch_EditMove( touchEventType type, int fingerID, float x, float y,
|
||||
touch.hidebutton->flags &= ~TOUCH_FL_HIDE;
|
||||
|
||||
if( FBitSet( button->flags, TOUCH_FL_HIDE ))
|
||||
Q_strcpy( touch.hidebutton->texturefile, "touch_default/edit_show" );
|
||||
Q_strcpy( touch.hidebutton->texturefile, "touch_default/edit_show.tga" );
|
||||
else
|
||||
Q_strcpy( touch.hidebutton->texturefile, "touch_default/edit_hide" );
|
||||
Q_strcpy( touch.hidebutton->texturefile, "touch_default/edit_hide.tga" );
|
||||
}
|
||||
}
|
||||
if( type == event_motion ) // shutdown button move
|
||||
|
||||
@@ -276,8 +276,7 @@ void IN_ActivateMouse( void )
|
||||
return;
|
||||
|
||||
IN_CheckMouseState( true );
|
||||
if( clgame.dllFuncs.IN_ActivateMouse )
|
||||
clgame.dllFuncs.IN_ActivateMouse();
|
||||
clgame.dllFuncs.IN_ActivateMouse();
|
||||
in_mouseactive = true;
|
||||
}
|
||||
|
||||
@@ -294,8 +293,7 @@ void IN_DeactivateMouse( void )
|
||||
return;
|
||||
|
||||
IN_CheckMouseState( false );
|
||||
if( clgame.dllFuncs.IN_DeactivateMouse )
|
||||
clgame.dllFuncs.IN_DeactivateMouse();
|
||||
clgame.dllFuncs.IN_DeactivateMouse();
|
||||
in_mouseactive = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ static player_info_t *pfnPlayerInfo( int index )
|
||||
if( index == -1 ) // special index for menu
|
||||
return &gameui.playerinfo;
|
||||
|
||||
if( index < 0 || index >= cl.maxclients )
|
||||
if( index < 0 || index > cl.maxclients )
|
||||
return NULL;
|
||||
|
||||
return &cl.players[index];
|
||||
@@ -330,10 +330,14 @@ static ref_api_t gEngfuncs =
|
||||
_Mem_Realloc,
|
||||
_Mem_Free,
|
||||
|
||||
COM_LoadLibrary,
|
||||
_COM_LoadLibrary,
|
||||
COM_FreeLibrary,
|
||||
COM_GetProcAddress,
|
||||
|
||||
FS_LoadFile,
|
||||
FS_FileExists,
|
||||
FS_AllowDirectPaths,
|
||||
|
||||
R_Init_Video_,
|
||||
R_Free_Video,
|
||||
|
||||
@@ -379,9 +383,7 @@ static ref_api_t gEngfuncs =
|
||||
|
||||
pfnDrawNormalTriangles,
|
||||
pfnDrawTransparentTriangles,
|
||||
&clgame.drawFuncs,
|
||||
|
||||
&g_fsapi,
|
||||
&clgame.drawFuncs
|
||||
};
|
||||
|
||||
static void R_UnloadProgs( void )
|
||||
|
||||
@@ -533,6 +533,8 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv
|
||||
// spatialize
|
||||
memset( target_chan, 0, sizeof( *target_chan ));
|
||||
|
||||
pitch *= (sys_timescale.value + 1) / 2;
|
||||
|
||||
VectorCopy( pos, target_chan->origin );
|
||||
target_chan->staticsound = ( ent == 0 ) ? true : false;
|
||||
target_chan->use_loop = (flags & SND_STOP_LOOPING) ? false : true;
|
||||
@@ -1127,7 +1129,7 @@ static uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend,
|
||||
S_RawEntSamples
|
||||
===================
|
||||
*/
|
||||
void S_RawEntSamples( int entnum, uint samples, uint rate, word width, word channels, const byte *data, int snd_vol )
|
||||
static void S_RawEntSamples( int entnum, uint samples, uint rate, word width, word channels, const byte *data, int snd_vol )
|
||||
{
|
||||
rawchan_t *ch;
|
||||
|
||||
@@ -1286,9 +1288,6 @@ static void S_FreeIdleRawChannels( void )
|
||||
|
||||
if( ch->s_rawend >= paintedtime )
|
||||
continue;
|
||||
|
||||
if ( ch->entnum > 0 )
|
||||
SND_ForceCloseMouth( ch->entnum );
|
||||
|
||||
if(( paintedtime - ch->s_rawend ) / SOUND_DMA_SPEED >= S_RAW_SOUND_IDLE_SEC )
|
||||
{
|
||||
@@ -1851,7 +1850,7 @@ S_SoundInfo_f
|
||||
*/
|
||||
void S_SoundInfo_f( void )
|
||||
{
|
||||
Con_Printf( "Audio backend: %s\n", dma.backendName );
|
||||
Con_Printf( "Audio: DirectSound\n" );
|
||||
Con_Printf( "%5d channel(s)\n", 2 );
|
||||
Con_Printf( "%5d samples\n", dma.samples );
|
||||
Con_Printf( "%5d bits/sample\n", 16 );
|
||||
@@ -1861,33 +1860,6 @@ void S_SoundInfo_f( void )
|
||||
S_PrintBackgroundTrackState ();
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_VoiceRecordStart_f
|
||||
=================
|
||||
*/
|
||||
void S_VoiceRecordStart_f( void )
|
||||
{
|
||||
if( cls.state != ca_active || cls.legacymode )
|
||||
return;
|
||||
|
||||
Voice_RecordStart();
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_VoiceRecordStop_f
|
||||
=================
|
||||
*/
|
||||
void S_VoiceRecordStop_f( void )
|
||||
{
|
||||
if( cls.state != ca_active || !Voice_IsRecording() )
|
||||
return;
|
||||
|
||||
CL_AddVoiceToDatagram();
|
||||
Voice_RecordStop();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
S_Init
|
||||
@@ -1922,12 +1894,11 @@ qboolean S_Init( void )
|
||||
Cmd_AddCommand( "soundlist", S_SoundList_f, "display loaded sounds" );
|
||||
Cmd_AddCommand( "s_info", S_SoundInfo_f, "print sound system information" );
|
||||
Cmd_AddCommand( "s_fade", S_SoundFade_f, "fade all sounds then stop all" );
|
||||
Cmd_AddCommand( "+voicerecord", S_VoiceRecordStart_f, "start voice recording" );
|
||||
Cmd_AddCommand( "-voicerecord", S_VoiceRecordStop_f, "stop voice recording" );
|
||||
Cmd_AddCommand( "+voicerecord", Cmd_Null_f, "start voice recording (non-implemented)" );
|
||||
Cmd_AddCommand( "-voicerecord", Cmd_Null_f, "stop voice recording (non-implemented)" );
|
||||
Cmd_AddCommand( "spk", S_SayReliable_f, "reliable play a specified sententce" );
|
||||
Cmd_AddCommand( "speak", S_Say_f, "playing a specified sententce" );
|
||||
|
||||
dma.backendName = "None";
|
||||
if( !SNDDMA_Init( ) )
|
||||
{
|
||||
Con_Printf( "Audio: sound system can't be initialized\n" );
|
||||
|
||||
@@ -619,8 +619,6 @@ void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate )
|
||||
ch->pitch = VOX_ModifyPitch( ch, ch->basePitch * 0.01f );
|
||||
else ch->pitch = ch->basePitch * 0.01f;
|
||||
|
||||
ch->pitch *= ( sys_timescale.value + 1 ) / 2;
|
||||
|
||||
if( CL_GetEntityByIndex( ch->entnum ) && ( ch->entchannel == CHAN_VOICE ))
|
||||
{
|
||||
if( pSource->width == 1 )
|
||||
@@ -958,9 +956,6 @@ void MIX_MixRawSamplesBuffer( int end )
|
||||
pbuf[j-paintedtime].left += ( ch->rawsamples[j & ( ch->max_samples - 1 )].left * ch->leftvol ) >> 8;
|
||||
pbuf[j-paintedtime].right += ( ch->rawsamples[j & ( ch->max_samples - 1 )].right * ch->rightvol ) >> 8;
|
||||
}
|
||||
|
||||
if ( ch->entnum > 0 )
|
||||
SND_MoveMouthRaw( ch, &ch->rawsamples[paintedtime & ( ch->max_samples - 1 )], stop - paintedtime );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -150,68 +150,3 @@ void SND_MoveMouth16( channel_t *ch, wavdata_t *pSource, int count )
|
||||
pMouth->sndcount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SND_ForceInitMouth( int entnum )
|
||||
{
|
||||
cl_entity_t *clientEntity;
|
||||
|
||||
clientEntity = CL_GetEntityByIndex( entnum );
|
||||
|
||||
if ( clientEntity )
|
||||
{
|
||||
clientEntity->mouth.mouthopen = 0;
|
||||
clientEntity->mouth.sndavg = 0;
|
||||
clientEntity->mouth.sndcount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SND_ForceCloseMouth( int entnum )
|
||||
{
|
||||
cl_entity_t *clientEntity;
|
||||
|
||||
clientEntity = CL_GetEntityByIndex( entnum );
|
||||
|
||||
if ( clientEntity )
|
||||
clientEntity->mouth.mouthopen = 0;
|
||||
}
|
||||
|
||||
void SND_MoveMouthRaw( rawchan_t *ch, portable_samplepair_t *pData, int count )
|
||||
{
|
||||
cl_entity_t *clientEntity;
|
||||
mouth_t *pMouth = NULL;
|
||||
int savg, data;
|
||||
int scount = 0;
|
||||
uint i;
|
||||
|
||||
clientEntity = CL_GetEntityByIndex( ch->entnum );
|
||||
if( !clientEntity ) return;
|
||||
|
||||
pMouth = &clientEntity->mouth;
|
||||
|
||||
if( pData == NULL )
|
||||
return;
|
||||
|
||||
i = 0;
|
||||
scount = pMouth->sndcount;
|
||||
savg = 0;
|
||||
|
||||
while ( i < count && scount < CAVGSAMPLES )
|
||||
{
|
||||
data = pData[i].left; // mono sound anyway
|
||||
data = ( bound( -32767, data, 0x7ffe ) >> 8 );
|
||||
savg += abs( data );
|
||||
|
||||
i += 80 + ( (byte)data & 0x1F );
|
||||
scount++;
|
||||
}
|
||||
|
||||
pMouth->sndavg += savg;
|
||||
pMouth->sndcount = (byte)scount;
|
||||
|
||||
if ( pMouth->sndcount >= CAVGSAMPLES )
|
||||
{
|
||||
pMouth->mouthopen = pMouth->sndavg / CAVGSAMPLES;
|
||||
pMouth->sndavg = 0;
|
||||
pMouth->sndcount = 0;
|
||||
}
|
||||
}
|
||||
@@ -113,11 +113,10 @@ typedef struct snd_format_s
|
||||
typedef struct
|
||||
{
|
||||
snd_format_t format;
|
||||
int samples; // mono samples in buffer
|
||||
int samplepos; // in mono samples
|
||||
byte *buffer;
|
||||
int samples; // mono samples in buffer
|
||||
int samplepos; // in mono samples
|
||||
byte *buffer;
|
||||
qboolean initialized; // sound engine is active
|
||||
const char *backendName;
|
||||
} dma_t;
|
||||
|
||||
#include "vox.h"
|
||||
@@ -203,7 +202,7 @@ typedef struct
|
||||
|
||||
#define MAX_DYNAMIC_CHANNELS (60 + NUM_AMBIENTS)
|
||||
#define MAX_CHANNELS (256 + MAX_DYNAMIC_CHANNELS) // Scourge Of Armagon has too many static sounds on hip2m4.bsp
|
||||
#define MAX_RAW_CHANNELS 48
|
||||
#define MAX_RAW_CHANNELS 16
|
||||
#define MAX_RAW_SAMPLES 8192
|
||||
|
||||
extern sound_t ambient_sfx[NUM_AMBIENTS];
|
||||
@@ -272,7 +271,6 @@ int S_GetCurrentStaticSounds( soundlist_t *pout, int size );
|
||||
int S_GetCurrentDynamicSounds( soundlist_t *pout, int size );
|
||||
sfx_t *S_GetSfxByHandle( sound_t handle );
|
||||
rawchan_t *S_FindRawChannel( int entnum, qboolean create );
|
||||
void S_RawEntSamples( int entnum, uint samples, uint rate, word width, word channels, const byte *data, int snd_vol );
|
||||
void S_RawSamples( uint samples, uint rate, word width, word channels, const byte *data, int entnum );
|
||||
void S_StopSound( int entnum, int channel, const char *soundname );
|
||||
void S_UpdateFrame( struct ref_viewpass_s *rvp );
|
||||
@@ -285,12 +283,9 @@ void S_FreeSounds( void );
|
||||
// s_mouth.c
|
||||
//
|
||||
void SND_InitMouth( int entnum, int entchannel );
|
||||
void SND_ForceInitMouth( int entnum );
|
||||
void SND_MoveMouth8( channel_t *ch, wavdata_t *pSource, int count );
|
||||
void SND_MoveMouth16( channel_t *ch, wavdata_t *pSource, int count );
|
||||
void SND_MoveMouthRaw( rawchan_t *ch, portable_samplepair_t *pData, int count );
|
||||
void SND_CloseMouth( channel_t *ch );
|
||||
void SND_ForceCloseMouth( int entnum );
|
||||
|
||||
//
|
||||
// s_stream.c
|
||||
|
||||
@@ -1,631 +0,0 @@
|
||||
/*
|
||||
voice.c - voice chat implementation
|
||||
Copyright (C) 2022 Velaron
|
||||
Copyright (C) 2022 SNMetamorph
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define CUSTOM_MODES 1 // required to correctly link with Opus Custom
|
||||
#include <opus_custom.h>
|
||||
#include "common.h"
|
||||
#include "client.h"
|
||||
#include "voice.h"
|
||||
|
||||
voice_state_t voice = { 0 };
|
||||
|
||||
CVAR_DEFINE_AUTO( voice_enable, "1", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "enable voice chat" );
|
||||
CVAR_DEFINE_AUTO( voice_loopback, "0", FCVAR_PRIVILEGED, "loopback voice back to the speaker" );
|
||||
CVAR_DEFINE_AUTO( voice_scale, "1.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "incoming voice volume scale" );
|
||||
CVAR_DEFINE_AUTO( voice_avggain, "0.5", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "automatic voice gain control (average)" );
|
||||
CVAR_DEFINE_AUTO( voice_maxgain, "5.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "automatic voice gain control (maximum)" );
|
||||
CVAR_DEFINE_AUTO( voice_inputfromfile, "0", FCVAR_PRIVILEGED, "input voice from voice_input.wav" );
|
||||
|
||||
static void Voice_ApplyGainAdjust( int16_t *samples, int count );
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
OPUS INTEGRATION
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_InitOpusDecoder
|
||||
|
||||
=========================
|
||||
*/
|
||||
static qboolean Voice_InitOpusDecoder( void )
|
||||
{
|
||||
int err;
|
||||
|
||||
voice.width = sizeof( opus_int16 );
|
||||
voice.samplerate = VOICE_OPUS_CUSTOM_SAMPLERATE;
|
||||
voice.frame_size = VOICE_OPUS_CUSTOM_FRAME_SIZE;
|
||||
|
||||
voice.custom_mode = opus_custom_mode_create( SOUND_44k, voice.frame_size, &err );
|
||||
if( !voice.custom_mode )
|
||||
{
|
||||
Con_Printf( S_ERROR "Can't create Opus Custom mode: %s\n", opus_strerror( err ));
|
||||
return false;
|
||||
}
|
||||
|
||||
voice.decoder = opus_custom_decoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
||||
if( !voice.decoder )
|
||||
{
|
||||
Con_Printf( S_ERROR "Can't create Opus encoder: %s\n", opus_strerror( err ));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_InitOpusEncoder
|
||||
|
||||
=========================
|
||||
*/
|
||||
static qboolean Voice_InitOpusEncoder( int quality )
|
||||
{
|
||||
int err;
|
||||
|
||||
voice.encoder = opus_custom_encoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
||||
if( !voice.encoder )
|
||||
{
|
||||
Con_Printf( S_ERROR "Can't create Opus encoder: %s\n", opus_strerror( err ));
|
||||
return false;
|
||||
}
|
||||
|
||||
switch( quality )
|
||||
{
|
||||
case 1: // 6 kbps
|
||||
opus_custom_encoder_ctl( voice.encoder, OPUS_SET_BITRATE( 6000 ));
|
||||
break;
|
||||
case 2: // 12 kbps
|
||||
opus_custom_encoder_ctl( voice.encoder, OPUS_SET_BITRATE( 12000 ));
|
||||
break;
|
||||
case 4: // 64 kbps
|
||||
opus_custom_encoder_ctl( voice.encoder, OPUS_SET_BITRATE( 64000 ));
|
||||
break;
|
||||
case 5: // 96 kbps
|
||||
opus_custom_encoder_ctl( voice.encoder, OPUS_SET_BITRATE( 96000 ));
|
||||
break;
|
||||
default: // 36 kbps
|
||||
opus_custom_encoder_ctl( voice.encoder, OPUS_SET_BITRATE( 36000 ));
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_ShutdownOpusDecoder
|
||||
|
||||
=========================
|
||||
*/
|
||||
static void Voice_ShutdownOpusDecoder( void )
|
||||
{
|
||||
if( voice.decoder )
|
||||
{
|
||||
opus_custom_decoder_destroy( voice.decoder );
|
||||
voice.decoder = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_ShutdownOpusEncoder
|
||||
|
||||
=========================
|
||||
*/
|
||||
static void Voice_ShutdownOpusEncoder( void )
|
||||
{
|
||||
if( voice.encoder )
|
||||
{
|
||||
opus_custom_encoder_destroy( voice.encoder );
|
||||
voice.encoder = NULL;
|
||||
}
|
||||
|
||||
if( voice.custom_mode )
|
||||
{
|
||||
opus_custom_mode_destroy( voice.custom_mode );
|
||||
voice.custom_mode = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_GetOpusCompressedData
|
||||
|
||||
=========================
|
||||
*/
|
||||
static uint Voice_GetOpusCompressedData( byte *out, uint maxsize, uint *frames )
|
||||
{
|
||||
uint ofs = 0, size = 0;
|
||||
uint frame_size_bytes = voice.frame_size * voice.width;
|
||||
|
||||
if( voice.input_file )
|
||||
{
|
||||
uint numbytes;
|
||||
double updateInterval;
|
||||
|
||||
updateInterval = cl.mtime[0] - cl.mtime[1];
|
||||
numbytes = updateInterval * voice.samplerate * voice.width * VOICE_PCM_CHANNELS;
|
||||
numbytes = Q_min( numbytes, voice.input_file->size - voice.input_file_pos );
|
||||
numbytes = Q_min( numbytes, sizeof( voice.input_buffer ) - voice.input_buffer_pos );
|
||||
|
||||
memcpy( voice.input_buffer + voice.input_buffer_pos, voice.input_file->buffer + voice.input_file_pos, numbytes );
|
||||
voice.input_buffer_pos += numbytes;
|
||||
voice.input_file_pos += numbytes;
|
||||
}
|
||||
|
||||
if( !voice.input_file )
|
||||
VoiceCapture_Lock( true );
|
||||
|
||||
for( ofs = 0; voice.input_buffer_pos - ofs >= frame_size_bytes && ofs <= voice.input_buffer_pos; ofs += frame_size_bytes )
|
||||
{
|
||||
int bytes;
|
||||
|
||||
#if 1
|
||||
if( !voice.input_file )
|
||||
{
|
||||
// adjust gain before encoding, but only for input from voice
|
||||
Voice_ApplyGainAdjust((opus_int16*)(voice.input_buffer + ofs), voice.frame_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
bytes = opus_custom_encode( voice.encoder, (const opus_int16 *)( voice.input_buffer + ofs ),
|
||||
voice.frame_size, out + size + sizeof( uint16_t ), maxsize );
|
||||
|
||||
if( bytes > 0 )
|
||||
{
|
||||
// write compressed frame size
|
||||
*((uint16_t *)&out[size]) = bytes;
|
||||
|
||||
size += bytes + sizeof( uint16_t );
|
||||
maxsize -= bytes + sizeof( uint16_t );
|
||||
|
||||
(*frames)++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: failed to encode frame: %s\n", __func__, opus_strerror( bytes ));
|
||||
}
|
||||
}
|
||||
|
||||
// did we compress anything? update counters
|
||||
if( ofs )
|
||||
{
|
||||
fs_offset_t remaining = voice.input_buffer_pos - ofs;
|
||||
|
||||
// move remaining samples to the beginning of buffer
|
||||
memmove( voice.input_buffer, voice.input_buffer + ofs, remaining );
|
||||
|
||||
voice.input_buffer_pos = remaining;
|
||||
}
|
||||
|
||||
if( !voice.input_file )
|
||||
VoiceCapture_Lock( false );
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
VOICE CHAT INTEGRATION
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_ApplyGainAdjust
|
||||
|
||||
=========================
|
||||
*/
|
||||
static void Voice_ApplyGainAdjust( int16_t *samples, int count )
|
||||
{
|
||||
float gain, modifiedMax;
|
||||
int average, adjustedSample, blockOffset = 0;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
int i, localMax = 0, localSum = 0;
|
||||
int blockSize = Q_min( count - ( blockOffset + voice.autogain.block_size ), voice.autogain.block_size );
|
||||
|
||||
if( blockSize < 1 )
|
||||
break;
|
||||
|
||||
for( i = 0; i < blockSize; ++i )
|
||||
{
|
||||
int sample = samples[blockOffset + i];
|
||||
int absSample = abs( sample );
|
||||
|
||||
if( absSample > localMax )
|
||||
localMax = absSample;
|
||||
|
||||
localSum += absSample;
|
||||
|
||||
gain = voice.autogain.current_gain + i * voice.autogain.gain_multiplier;
|
||||
adjustedSample = Q_min( SHRT_MAX, Q_max(( int )( sample * gain ), SHRT_MIN ));
|
||||
samples[blockOffset + i] = adjustedSample;
|
||||
}
|
||||
|
||||
if( blockOffset % voice.autogain.block_size == 0 )
|
||||
{
|
||||
average = localSum / blockSize;
|
||||
modifiedMax = average + ( localMax - average ) * voice_avggain.value;
|
||||
|
||||
voice.autogain.current_gain = voice.autogain.next_gain * voice_scale.value;
|
||||
voice.autogain.next_gain = Q_min( (float)SHRT_MAX / modifiedMax, voice_maxgain.value ) * voice_scale.value;
|
||||
voice.autogain.gain_multiplier = ( voice.autogain.next_gain - voice.autogain.current_gain ) / ( voice.autogain.block_size - 1 );
|
||||
}
|
||||
blockOffset += blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_Status
|
||||
|
||||
Notify user dll aboit voice transmission
|
||||
=========================
|
||||
*/
|
||||
static void Voice_Status( int entindex, qboolean bTalking )
|
||||
{
|
||||
if( cls.state == ca_active && clgame.dllFuncs.pfnVoiceStatus )
|
||||
clgame.dllFuncs.pfnVoiceStatus( entindex, bTalking );
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_StatusTimeout
|
||||
|
||||
Waits few milliseconds and if there was no
|
||||
voice transmission, sends notification
|
||||
=========================
|
||||
*/
|
||||
static void Voice_StatusTimeout( voice_status_t *status, int entindex, double frametime )
|
||||
{
|
||||
if( status->talking_ack )
|
||||
{
|
||||
status->talking_timeout += frametime;
|
||||
if( status->talking_timeout > 0.2 )
|
||||
{
|
||||
status->talking_ack = false;
|
||||
Voice_Status( entindex, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_StatusAck
|
||||
|
||||
Sends notification to user dll and
|
||||
zeroes timeouts for this client
|
||||
=========================
|
||||
*/
|
||||
void Voice_StatusAck( voice_status_t *status, int playerIndex )
|
||||
{
|
||||
if( !status->talking_ack )
|
||||
Voice_Status( playerIndex, true );
|
||||
|
||||
status->talking_ack = true;
|
||||
status->talking_timeout = 0.0;
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_IsRecording
|
||||
|
||||
=========================
|
||||
*/
|
||||
qboolean Voice_IsRecording( void )
|
||||
{
|
||||
return voice.is_recording;
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_RecordStop
|
||||
|
||||
=========================
|
||||
*/
|
||||
void Voice_RecordStop( void )
|
||||
{
|
||||
if( voice.input_file )
|
||||
{
|
||||
FS_FreeSound( voice.input_file );
|
||||
voice.input_file = NULL;
|
||||
}
|
||||
|
||||
VoiceCapture_Activate( false );
|
||||
voice.is_recording = false;
|
||||
|
||||
Voice_Status( VOICE_LOCALCLIENT_INDEX, false );
|
||||
|
||||
voice.input_buffer_pos = 0;
|
||||
memset( voice.input_buffer, 0, sizeof( voice.input_buffer ));
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_RecordStart
|
||||
|
||||
=========================
|
||||
*/
|
||||
void Voice_RecordStart( void )
|
||||
{
|
||||
Voice_RecordStop();
|
||||
|
||||
if( voice_inputfromfile.value )
|
||||
{
|
||||
voice.input_file = FS_LoadSound( "voice_input.wav", NULL, 0 );
|
||||
|
||||
if( voice.input_file )
|
||||
{
|
||||
Sound_Process( &voice.input_file, voice.samplerate, voice.width, SOUND_RESAMPLE );
|
||||
voice.input_file_pos = 0;
|
||||
|
||||
voice.start_time = Sys_DoubleTime();
|
||||
voice.is_recording = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
FS_FreeSound( voice.input_file );
|
||||
voice.input_file = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if( !Voice_IsRecording() )
|
||||
voice.is_recording = VoiceCapture_Activate( true );
|
||||
|
||||
if( Voice_IsRecording() )
|
||||
Voice_Status( VOICE_LOCALCLIENT_INDEX, true );
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_Disconnect
|
||||
|
||||
We're disconnected from server
|
||||
stop recording and notify user dlls
|
||||
=========================
|
||||
*/
|
||||
void Voice_Disconnect( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
Voice_RecordStop();
|
||||
|
||||
if( voice.local.talking_ack )
|
||||
{
|
||||
Voice_Status( VOICE_LOOPBACK_INDEX, false );
|
||||
voice.local.talking_ack = false;
|
||||
}
|
||||
|
||||
for( i = 0; i < MAX_CLIENTS; i++ )
|
||||
{
|
||||
if( voice.players_status[i].talking_ack )
|
||||
{
|
||||
Voice_Status( i, false );
|
||||
voice.players_status[i].talking_ack = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_StartChannel
|
||||
|
||||
Feed the decoded data to engine sound subsystem
|
||||
=========================
|
||||
*/
|
||||
static void Voice_StartChannel( uint samples, byte *data, int entnum )
|
||||
{
|
||||
SND_ForceInitMouth( entnum );
|
||||
S_RawEntSamples( entnum, samples, voice.samplerate, voice.width, VOICE_PCM_CHANNELS, data, 255 );
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_AddIncomingData
|
||||
|
||||
Received encoded voice data, decode it
|
||||
=========================
|
||||
*/
|
||||
void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames )
|
||||
{
|
||||
int samples = 0;
|
||||
int ofs = 0;
|
||||
|
||||
if( !voice.decoder )
|
||||
return;
|
||||
|
||||
// decode frame by frame
|
||||
for( ;; )
|
||||
{
|
||||
int frame_samples;
|
||||
uint16_t compressed_size;
|
||||
|
||||
// no compressed size mark
|
||||
if( ofs + sizeof( uint16_t ) > size )
|
||||
break;
|
||||
|
||||
compressed_size = *(const uint16_t *)(data + ofs);
|
||||
ofs += sizeof( uint16_t );
|
||||
|
||||
// no frame data
|
||||
if( ofs + compressed_size > size )
|
||||
break;
|
||||
|
||||
frame_samples = opus_custom_decode( voice.decoder, data + ofs, compressed_size,
|
||||
(opus_int16*)voice.decompress_buffer + samples, voice.frame_size );
|
||||
|
||||
ofs += compressed_size;
|
||||
samples += frame_samples;
|
||||
}
|
||||
|
||||
if( samples > 0 )
|
||||
Voice_StartChannel( samples, voice.decompress_buffer, ent );
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
CL_AddVoiceToDatagram
|
||||
|
||||
Encode our voice data and send it to server
|
||||
=========================
|
||||
*/
|
||||
void CL_AddVoiceToDatagram( void )
|
||||
{
|
||||
uint size, frames = 0;
|
||||
|
||||
if( cls.state != ca_active || !Voice_IsRecording() || !voice.encoder )
|
||||
return;
|
||||
|
||||
size = Voice_GetOpusCompressedData( voice.output_buffer, sizeof( voice.output_buffer ), &frames );
|
||||
|
||||
if( size > 0 && MSG_GetNumBytesLeft( &cls.datagram ) >= size + 32 )
|
||||
{
|
||||
MSG_BeginClientCmd( &cls.datagram, clc_voicedata );
|
||||
MSG_WriteByte( &cls.datagram, voice_loopback.value != 0 );
|
||||
MSG_WriteByte( &cls.datagram, frames );
|
||||
MSG_WriteShort( &cls.datagram, size );
|
||||
MSG_WriteBytes( &cls.datagram, voice.output_buffer, size );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_RegisterCvars
|
||||
|
||||
Register voice related cvars and commands
|
||||
=========================
|
||||
*/
|
||||
void Voice_RegisterCvars( void )
|
||||
{
|
||||
Cvar_RegisterVariable( &voice_enable );
|
||||
Cvar_RegisterVariable( &voice_loopback );
|
||||
Cvar_RegisterVariable( &voice_scale );
|
||||
Cvar_RegisterVariable( &voice_avggain );
|
||||
Cvar_RegisterVariable( &voice_maxgain );
|
||||
Cvar_RegisterVariable( &voice_inputfromfile );
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_Shutdown
|
||||
|
||||
Completely shutdown the voice subsystem
|
||||
=========================
|
||||
*/
|
||||
static void Voice_Shutdown( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
Voice_RecordStop();
|
||||
Voice_ShutdownOpusEncoder();
|
||||
Voice_ShutdownOpusDecoder();
|
||||
VoiceCapture_Shutdown();
|
||||
|
||||
if( voice.local.talking_ack )
|
||||
Voice_Status( VOICE_LOOPBACK_INDEX, false );
|
||||
|
||||
for( i = 0; i < MAX_CLIENTS; i++ )
|
||||
{
|
||||
if( voice.players_status[i].talking_ack )
|
||||
Voice_Status( i, false );
|
||||
}
|
||||
|
||||
memset( &voice, 0, sizeof( voice ));
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_Idle
|
||||
|
||||
Run timeout for all clients
|
||||
=========================
|
||||
*/
|
||||
void Voice_Idle( double frametime )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( FBitSet( voice_enable.flags, FCVAR_CHANGED ) && !voice_enable.value )
|
||||
{
|
||||
Voice_Shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
// update local player status first
|
||||
Voice_StatusTimeout( &voice.local, VOICE_LOOPBACK_INDEX, frametime );
|
||||
|
||||
for( i = 0; i < MAX_CLIENTS; i++ )
|
||||
Voice_StatusTimeout( &voice.players_status[i], i, frametime );
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_Init
|
||||
|
||||
Initialize the voice subsystem
|
||||
=========================
|
||||
*/
|
||||
qboolean Voice_Init( const char *pszCodecName, int quality )
|
||||
{
|
||||
if( !voice_enable.value )
|
||||
return false;
|
||||
|
||||
if( Q_strcmp( pszCodecName, VOICE_OPUS_CUSTOM_CODEC ))
|
||||
{
|
||||
Con_Printf( S_ERROR "Server requested unsupported codec: %s\n", pszCodecName );
|
||||
return false;
|
||||
}
|
||||
|
||||
// reinitialize only if codec parameters are different
|
||||
if( Q_strcmp( voice.codec, pszCodecName ) && voice.quality != quality )
|
||||
Voice_Shutdown();
|
||||
|
||||
voice.autogain.block_size = 128;
|
||||
|
||||
if( !Voice_InitOpusDecoder( ))
|
||||
{
|
||||
// no reason to init encoder and open audio device
|
||||
// if we can't hear other players
|
||||
Con_Printf( S_ERROR "Voice chat disabled.\n" );
|
||||
Voice_Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
// we can hear others players, so it's fine to fail now
|
||||
voice.initialized = true;
|
||||
Q_strncpy( voice.codec, pszCodecName, sizeof( voice.codec ));
|
||||
|
||||
if( !Voice_InitOpusEncoder( quality ))
|
||||
{
|
||||
Con_Printf( S_WARN "Other players will not be able to hear you.\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
voice.quality = quality;
|
||||
|
||||
if( !VoiceCapture_Init( ))
|
||||
Con_Printf( S_WARN "No microphone is available.\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
voice.h - voice chat implementation
|
||||
Copyright (C) 2022 Velaron
|
||||
Copyright (C) 2022 SNMetamorph
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef VOICE_H
|
||||
#define VOICE_H
|
||||
|
||||
#include "common.h"
|
||||
#include "protocol.h" // MAX_CLIENTS
|
||||
#include "sound.h"
|
||||
|
||||
typedef struct OpusCustomEncoder OpusCustomEncoder;
|
||||
typedef struct OpusCustomDecoder OpusCustomDecoder;
|
||||
typedef struct OpusCustomMode OpusCustomMode;
|
||||
|
||||
#define VOICE_LOOPBACK_INDEX (-2)
|
||||
#define VOICE_LOCALCLIENT_INDEX (-1)
|
||||
|
||||
#define VOICE_PCM_CHANNELS 1 // always mono
|
||||
|
||||
// never change these parameters when using opuscustom
|
||||
#define VOICE_OPUS_CUSTOM_SAMPLERATE SOUND_44k
|
||||
// must follow opus custom requirements
|
||||
// also be divisible with MAX_RAW_SAMPLES
|
||||
#define VOICE_OPUS_CUSTOM_FRAME_SIZE 1024
|
||||
#define VOICE_OPUS_CUSTOM_CODEC "opus_custom_44k_512"
|
||||
|
||||
// a1ba: do not change, we don't have any re-encoding support now
|
||||
#define VOICE_DEFAULT_CODEC VOICE_OPUS_CUSTOM_CODEC
|
||||
|
||||
typedef struct voice_status_s
|
||||
{
|
||||
qboolean talking_ack;
|
||||
double talking_timeout;
|
||||
} voice_status_t;
|
||||
|
||||
typedef struct voice_state_s
|
||||
{
|
||||
string codec;
|
||||
int quality;
|
||||
|
||||
qboolean initialized;
|
||||
qboolean is_recording;
|
||||
double start_time;
|
||||
|
||||
voice_status_t local;
|
||||
voice_status_t players_status[MAX_CLIENTS];
|
||||
|
||||
// opus stuff
|
||||
OpusCustomMode *custom_mode;
|
||||
OpusCustomEncoder *encoder;
|
||||
OpusCustomDecoder *decoder;
|
||||
|
||||
// audio info
|
||||
uint width;
|
||||
uint samplerate;
|
||||
uint frame_size; // in samples
|
||||
|
||||
// buffers
|
||||
byte input_buffer[MAX_RAW_SAMPLES];
|
||||
byte output_buffer[MAX_RAW_SAMPLES];
|
||||
byte decompress_buffer[MAX_RAW_SAMPLES];
|
||||
fs_offset_t input_buffer_pos; // in bytes
|
||||
|
||||
// input from file
|
||||
wavdata_t *input_file;
|
||||
fs_offset_t input_file_pos; // in bytes
|
||||
|
||||
// automatic gain control
|
||||
struct {
|
||||
int block_size;
|
||||
float current_gain;
|
||||
float next_gain;
|
||||
float gain_multiplier;
|
||||
} autogain;
|
||||
} voice_state_t;
|
||||
|
||||
extern voice_state_t voice;
|
||||
|
||||
void CL_AddVoiceToDatagram( void );
|
||||
|
||||
void Voice_RegisterCvars( void );
|
||||
qboolean Voice_Init( const char *pszCodecName, int quality );
|
||||
void Voice_Idle( double frametime );
|
||||
qboolean Voice_IsRecording( void );
|
||||
void Voice_RecordStop( void );
|
||||
void Voice_RecordStart( void );
|
||||
void Voice_Disconnect( void );
|
||||
void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames );
|
||||
void Voice_StatusAck( voice_status_t *status, int playerIndex );
|
||||
|
||||
#endif // VOICE_H
|
||||
@@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "crtlib.h"
|
||||
#include "common.h"
|
||||
|
||||
static const char *date = __DATE__ ;
|
||||
static const char *mon[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
||||
@@ -95,8 +95,6 @@ const char *Q_buildos( void )
|
||||
osname = "DOS4GW";
|
||||
#elif XASH_HAIKU
|
||||
osname = "haiku";
|
||||
#elif XASH_SERENITY
|
||||
osname = "serenityos";
|
||||
#else
|
||||
#error "Place your operating system name here! If this is a mistake, try to fix conditions above and report a bug"
|
||||
#endif
|
||||
@@ -647,7 +647,7 @@ void Cmd_TokenizeString( const char *text )
|
||||
if( cmd_argc == 1 )
|
||||
cmd_args = text;
|
||||
|
||||
text = COM_ParseFileSafe( (char*)text, cmd_token, sizeof( cmd_token ), PFILE_IGNOREBRACKET, NULL, NULL );
|
||||
text = _COM_ParseFileSafe( (char*)text, cmd_token, sizeof( cmd_token ), PFILE_IGNOREBRACKET, NULL );
|
||||
|
||||
if( !text ) return;
|
||||
|
||||
@@ -1171,21 +1171,17 @@ void Cmd_List_f( void )
|
||||
{
|
||||
cmd_t *cmd;
|
||||
int i = 0;
|
||||
size_t matchlen = 0;
|
||||
const char *match = NULL;
|
||||
const char *match;
|
||||
|
||||
if( Cmd_Argc() > 1 )
|
||||
{
|
||||
match = Cmd_Argv( 1 );
|
||||
matchlen = Q_strlen( match );
|
||||
}
|
||||
if( Cmd_Argc() > 1 ) match = Cmd_Argv( 1 );
|
||||
else match = NULL;
|
||||
|
||||
for( cmd = cmd_functions; cmd; cmd = cmd->next )
|
||||
{
|
||||
if( cmd->name[0] == '@' )
|
||||
continue; // never show system cmds
|
||||
|
||||
if( match && !Q_strnicmpext( match, cmd->name, matchlen ))
|
||||
if( match && !Q_stricmpext( match, cmd->name ))
|
||||
continue;
|
||||
|
||||
Con_Printf( " %-*s ^3%s^7\n", 32, cmd->name, cmd->desc );
|
||||
|
||||
@@ -64,8 +64,6 @@ GNU General Public License for more details.
|
||||
#define DEFAULT_UPDATE_PAGE "https://github.com/FWGS/xash3d-fwgs/releases/latest"
|
||||
|
||||
#define XASH_ENGINE_NAME "Xash3D FWGS"
|
||||
#define XASH_VERSION "0.20" // engine current version
|
||||
#define XASH_COMPAT_VERSION "0.99" // version we are based on
|
||||
|
||||
// renderers order is important, software is always a last chance fallback
|
||||
#define DEFAULT_RENDERERS { "gl", "gles1", "gles2", "gl4es", "soft" }
|
||||
|
||||
@@ -585,6 +585,23 @@ void COM_TrimSpace( const char *source, char *dest )
|
||||
dest[length] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
COM_FixSlashes
|
||||
|
||||
Changes all '/' characters into '\' characters, in place.
|
||||
============
|
||||
*/
|
||||
void COM_FixSlashes( char *pname )
|
||||
{
|
||||
while( *pname )
|
||||
{
|
||||
if( *pname == '\\' )
|
||||
*pname = '/';
|
||||
pname++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
COM_Nibble
|
||||
@@ -1165,22 +1182,22 @@ void Test_RunCommon( void )
|
||||
|
||||
Msg( "Checking COM_ParseFile...\n" );
|
||||
|
||||
file = COM_ParseFileSafe( file, buf, sizeof( buf ), 0, &len, NULL );
|
||||
file = _COM_ParseFileSafe( file, buf, sizeof( buf ), 0, &len );
|
||||
TASSERT( !Q_strcmp( buf, "q" ) && len == 1);
|
||||
|
||||
file = COM_ParseFileSafe( file, buf, sizeof( buf ), 0, &len, NULL );
|
||||
file = _COM_ParseFileSafe( file, buf, sizeof( buf ), 0, &len );
|
||||
TASSERT( !Q_strcmp( buf, "asdf" ) && len == 4);
|
||||
|
||||
file = COM_ParseFileSafe( file, buf, sizeof( buf ), 0, &len, NULL );
|
||||
file = _COM_ParseFileSafe( file, buf, sizeof( buf ), 0, &len );
|
||||
TASSERT( !Q_strcmp( buf, "qwer" ) && len == -1);
|
||||
|
||||
file = COM_ParseFileSafe( file, buf, sizeof( buf ), 0, &len, NULL );
|
||||
file = _COM_ParseFileSafe( file, buf, sizeof( buf ), 0, &len );
|
||||
TASSERT( !Q_strcmp( buf, "f \"f" ) && len == 4);
|
||||
|
||||
file = COM_ParseFileSafe( file, buf, sizeof( buf ), 0, &len, NULL );
|
||||
file = _COM_ParseFileSafe( file, buf, sizeof( buf ), 0, &len );
|
||||
TASSERT( !Q_strcmp( buf, "meow" ) && len == -1);
|
||||
|
||||
file = COM_ParseFileSafe( file, buf, sizeof( buf ), 0, &len, NULL );
|
||||
file = _COM_ParseFileSafe( file, buf, sizeof( buf ), 0, &len );
|
||||
TASSERT( !Q_strcmp( buf, "bark" ) && len == 4);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -76,6 +76,13 @@ XASH SPECIFIC - sort of hack that works only in Xash3D not in GoldSrc
|
||||
|
||||
#define HACKS_RELATED_HLMODS // some HL-mods works differently under Xash and can't be fixed without some hacks at least at current time
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int numfilenames;
|
||||
char **filenames;
|
||||
char *filenamesbuffer;
|
||||
} search_t;
|
||||
|
||||
enum
|
||||
{
|
||||
DEV_NONE = 0,
|
||||
@@ -111,8 +118,9 @@ typedef enum
|
||||
#include "cvar.h"
|
||||
#include "con_nprint.h"
|
||||
#include "crclib.h"
|
||||
#include "ref_api.h"
|
||||
#include "fscallback.h"
|
||||
|
||||
#define XASH_VERSION "0.20" // engine current version
|
||||
#define XASH_COMPAT_VERSION "0.99" // version we are based on
|
||||
|
||||
// PERFORMANCE INFO
|
||||
#define MIN_FPS 20.0f // host minimum fps value for maxfps.
|
||||
@@ -142,6 +150,18 @@ typedef enum
|
||||
#define MAX_STATIC_ENTITIES 32 // static entities that moved on the client when level is spawn
|
||||
#endif
|
||||
|
||||
// filesystem flags
|
||||
#define FS_STATIC_PATH ( 1U << 0 ) // FS_ClearSearchPath will be ignore this path
|
||||
#define FS_NOWRITE_PATH ( 1U << 1 ) // default behavior - last added gamedir set as writedir. This flag disables it
|
||||
#define FS_GAMEDIR_PATH ( 1U << 2 ) // just a marker for gamedir path
|
||||
#define FS_CUSTOM_PATH ( 1U << 3 ) // custom directory
|
||||
#define FS_GAMERODIR_PATH ( 1U << 4 ) // caseinsensitive
|
||||
|
||||
#define FS_GAMEDIRONLY_SEARCH_FLAGS ( FS_GAMEDIR_PATH | FS_CUSTOM_PATH | FS_GAMERODIR_PATH )
|
||||
|
||||
#define GI SI.GameInfo
|
||||
#define FS_Gamedir() SI.GameInfo->gamefolder
|
||||
#define FS_Title() SI.GameInfo->title
|
||||
#define GameState (&host.game)
|
||||
|
||||
#define FORCE_DRAW_VERSION_TIME 5.0f // draw version for 5 seconds
|
||||
@@ -182,6 +202,61 @@ GAMEINFO stuff
|
||||
internal shared gameinfo structure (readonly for engine parts)
|
||||
========================================================================
|
||||
*/
|
||||
typedef struct gameinfo_s
|
||||
{
|
||||
// filesystem info
|
||||
char gamefolder[MAX_QPATH]; // used for change game '-game x'
|
||||
char basedir[MAX_QPATH]; // base game directory (like 'id1' for Quake or 'valve' for Half-Life)
|
||||
char falldir[MAX_QPATH]; // used as second basedir
|
||||
char startmap[MAX_QPATH];// map to start singleplayer game
|
||||
char trainmap[MAX_QPATH];// map to start hazard course (if specified)
|
||||
char title[64]; // Game Main Title
|
||||
float version; // game version (optional)
|
||||
|
||||
// .dll pathes
|
||||
char dll_path[MAX_QPATH]; // e.g. "bin" or "cl_dlls"
|
||||
char game_dll[MAX_QPATH]; // custom path for game.dll
|
||||
|
||||
// .ico path
|
||||
char iconpath[MAX_QPATH]; // "game.ico" by default
|
||||
|
||||
// about mod info
|
||||
string game_url; // link to a developer's site
|
||||
string update_url; // link to updates page
|
||||
char type[MAX_QPATH]; // single, toolkit, multiplayer etc
|
||||
char date[MAX_QPATH];
|
||||
size_t size;
|
||||
|
||||
int gamemode;
|
||||
qboolean secure; // prevent to console acess
|
||||
qboolean nomodels; // don't let player to choose model (use player.mdl always)
|
||||
qboolean noskills; // disable skill menu selection
|
||||
qboolean render_picbutton_text; // use font renderer to render WON buttons
|
||||
|
||||
char sp_entity[32]; // e.g. info_player_start
|
||||
char mp_entity[32]; // e.g. info_player_deathmatch
|
||||
char mp_filter[32]; // filtering multiplayer-maps
|
||||
|
||||
char ambientsound[NUM_AMBIENTS][MAX_QPATH]; // quake ambient sounds
|
||||
|
||||
int max_edicts; // min edicts is 600, max edicts is 8196
|
||||
int max_tents; // min temp ents is 300, max is 2048
|
||||
int max_beams; // min beams is 64, max beams is 512
|
||||
int max_particles; // min particles is 4096, max particles is 32768
|
||||
|
||||
char game_dll_linux[64]; // custom path for game.dll
|
||||
char game_dll_osx[64]; // custom path for game.dll
|
||||
|
||||
qboolean added;
|
||||
} gameinfo_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GAME_NORMAL,
|
||||
GAME_SINGLEPLAYER_ONLY,
|
||||
GAME_MULTIPLAYER_ONLY
|
||||
} gametype_t;
|
||||
|
||||
typedef struct sysinfo_s
|
||||
{
|
||||
string exeName; // exe.filename
|
||||
@@ -189,6 +264,9 @@ typedef struct sysinfo_s
|
||||
string basedirName; // name of base directory
|
||||
string gamedll;
|
||||
string clientlib;
|
||||
gameinfo_t *GameInfo; // current GameInfo
|
||||
gameinfo_t *games[MAX_MODS]; // environment games (founded at each engine start)
|
||||
int numgames;
|
||||
} sysinfo_t;
|
||||
|
||||
typedef enum
|
||||
@@ -307,16 +385,6 @@ typedef struct
|
||||
float scale; // curstate.scale
|
||||
} tentlist_t;
|
||||
|
||||
typedef enum bugcomp_e
|
||||
{
|
||||
// default mode, we assume that user dlls are not relying on engine bugs
|
||||
BUGCOMP_OFF,
|
||||
|
||||
// GoldSrc mode, user dlls are relying on GoldSrc specific bugs
|
||||
// but fixing them may break regular Xash games
|
||||
BUGCOMP_GOLDSRC,
|
||||
} bugcomp_t;
|
||||
|
||||
typedef struct host_parm_s
|
||||
{
|
||||
HINSTANCE hInst;
|
||||
@@ -391,9 +459,6 @@ typedef struct host_parm_s
|
||||
struct decallist_s *decalList; // used for keep decals, when renderer is restarted or changed
|
||||
int numdecals;
|
||||
|
||||
// bug compatibility level, for very "special" games
|
||||
bugcomp_t bugcomp;
|
||||
|
||||
} host_parm_t;
|
||||
|
||||
extern host_parm_t host;
|
||||
@@ -408,13 +473,6 @@ extern sysinfo_t SI;
|
||||
|
||||
typedef void (*xcommand_t)( void );
|
||||
|
||||
//
|
||||
// filesystem_engine.c
|
||||
//
|
||||
qboolean FS_LoadProgs( void );
|
||||
void FS_Init( void );
|
||||
void FS_Shutdown( void );
|
||||
|
||||
//
|
||||
// cmd.c
|
||||
//
|
||||
@@ -474,6 +532,56 @@ void Mem_PrintStats( void );
|
||||
#define Mem_IsAllocated( mem ) Mem_IsAllocatedExt( NULL, mem )
|
||||
#define Mem_Check() _Mem_Check( __FILE__, __LINE__ )
|
||||
|
||||
//
|
||||
// filesystem.c
|
||||
//
|
||||
void FS_Init( void );
|
||||
void FS_Path( void );
|
||||
void FS_Rescan( void );
|
||||
void FS_Shutdown( void );
|
||||
void FS_ClearSearchPath( void );
|
||||
void FS_AllowDirectPaths( qboolean enable );
|
||||
void FS_AddGameDirectory( const char *dir, uint flags );
|
||||
void FS_AddGameHierarchy( const char *dir, uint flags );
|
||||
void FS_LoadGameInfo( const char *rootfolder );
|
||||
const char *FS_GetDiskPath( const char *name, qboolean gamedironly );
|
||||
byte *W_LoadLump( wfile_t *wad, const char *lumpname, size_t *lumpsizeptr, const char type );
|
||||
void W_Close( wfile_t *wad );
|
||||
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
|
||||
qboolean CRC32_File( dword *crcvalue, const char *filename );
|
||||
qboolean MD5_HashFile( byte digest[16], const char *pszFileName, uint seed[4] );
|
||||
byte *FS_LoadDirectFile( const char *path, fs_offset_t *filesizeptr );
|
||||
qboolean FS_WriteFile( const char *filename, const void *data, fs_offset_t len );
|
||||
qboolean COM_ParseVector( char **pfile, float *v, size_t size );
|
||||
void COM_NormalizeAngles( vec3_t angles );
|
||||
int COM_FileSize( const char *filename );
|
||||
void COM_FixSlashes( char *pname );
|
||||
void COM_FreeFile( void *buffer );
|
||||
int COM_CompareFileTime( const char *filename1, const char *filename2, int *iCompare );
|
||||
search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly );
|
||||
file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly );
|
||||
fs_offset_t FS_Write( file_t *file, const void *data, size_t datasize );
|
||||
fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize );
|
||||
int FS_VPrintf( file_t *file, const char *format, va_list ap );
|
||||
int FS_Seek( file_t *file, fs_offset_t offset, int whence );
|
||||
int FS_Gets( file_t *file, byte *string, size_t bufsize );
|
||||
int FS_Printf( file_t *file, const char *format, ... ) _format( 2 );
|
||||
fs_offset_t FS_FileSize( const char *filename, qboolean gamedironly );
|
||||
int FS_FileTime( const char *filename, qboolean gamedironly );
|
||||
int FS_Print( file_t *file, const char *msg );
|
||||
qboolean FS_Rename( const char *oldname, const char *newname );
|
||||
int FS_FileExists( const char *filename, int gamedironly );
|
||||
int FS_SetCurrentDirectory( const char *path );
|
||||
qboolean FS_SysFileExists( const char *path, qboolean casesensitive );
|
||||
qboolean FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize );
|
||||
qboolean FS_Delete( const char *path );
|
||||
int FS_UnGetc( file_t *file, byte c );
|
||||
fs_offset_t FS_Tell( file_t *file );
|
||||
qboolean FS_Eof( file_t *file );
|
||||
int FS_Close( file_t *file );
|
||||
int FS_Getc( file_t *file );
|
||||
fs_offset_t FS_FileLength( file_t *f );
|
||||
|
||||
//
|
||||
// imagelib
|
||||
//
|
||||
@@ -562,6 +670,16 @@ void FS_FreeStream( stream_t *stream );
|
||||
qboolean Sound_Process( wavdata_t **wav, int rate, int width, uint flags );
|
||||
uint Sound_GetApproxWavePlayLen( const char *filepath );
|
||||
|
||||
//
|
||||
// build.c
|
||||
//
|
||||
int Q_buildnum( void );
|
||||
int Q_buildnum_compat( void );
|
||||
const char *Q_buildos( void );
|
||||
const char *Q_buildarch( void );
|
||||
const char *Q_buildcommit( void );
|
||||
|
||||
|
||||
//
|
||||
// host.c
|
||||
//
|
||||
@@ -581,7 +699,7 @@ void Host_WriteConfig( void );
|
||||
qboolean Host_IsLocalGame( void );
|
||||
qboolean Host_IsLocalClient( void );
|
||||
void Host_ShutdownServer( void );
|
||||
void Host_Error( const char *error, ... ) _format( 1 );
|
||||
void Host_Error( const char *error, ... ) _format( 1 ) NORETURN;
|
||||
void Host_PrintEngineFeatures( void );
|
||||
void Host_Frame( float time );
|
||||
void Host_InitDecals( void );
|
||||
@@ -761,6 +879,7 @@ void R_ClearAllDecals( void );
|
||||
void CL_ClearStaticEntities( void );
|
||||
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position );
|
||||
struct cl_entity_s *CL_GetEntityByIndex( int index );
|
||||
struct player_info_s *CL_GetPlayerInfo( int playerIndex );
|
||||
void CL_ServerCommand( qboolean reliable, const char *fmt, ... ) _format( 2 );
|
||||
void CL_HudMessage( const char *pMessage );
|
||||
const char *CL_MsgInfo( int cmd );
|
||||
@@ -836,11 +955,6 @@ void UI_SetActiveMenu( qboolean fActive );
|
||||
void UI_ShowConnectionWarning( void );
|
||||
void Cmd_Null_f( void );
|
||||
void Rcon_Print( const char *pMsg );
|
||||
qboolean COM_ParseVector( char **pfile, float *v, size_t size );
|
||||
void COM_NormalizeAngles( vec3_t angles );
|
||||
int COM_FileSize( const char *filename );
|
||||
void COM_FreeFile( void *buffer );
|
||||
int COM_CompareFileTime( const char *filename1, const char *filename2, int *iCompare );
|
||||
|
||||
// soundlib shared exports
|
||||
qboolean S_Init( void );
|
||||
@@ -868,7 +982,6 @@ void GAME_EXPORT ID_SetCustomClientID( const char *id );
|
||||
void NET_InitMasters( void );
|
||||
void NET_SaveMasters( void );
|
||||
qboolean NET_SendToMasters( netsrc_t sock, size_t len, const void *data );
|
||||
qboolean NET_IsMasterAdr( netadr_t adr );
|
||||
|
||||
#ifdef REF_DLL
|
||||
#error "common.h in ref_dll"
|
||||
|
||||
@@ -761,10 +761,10 @@ qboolean Cmd_GetGamesList( const char *s, char *completedname, int length )
|
||||
// compare gamelist with current keyword
|
||||
len = Q_strlen( s );
|
||||
|
||||
for( i = 0, numgamedirs = 0; i < FI->numgames; i++ )
|
||||
for( i = 0, numgamedirs = 0; i < SI.numgames; i++ )
|
||||
{
|
||||
if(( *s == '*' ) || !Q_strnicmp( FI->games[i]->gamefolder, s, len))
|
||||
Q_strcpy( gamedirs[numgamedirs++], FI->games[i]->gamefolder );
|
||||
if(( *s == '*' ) || !Q_strnicmp( SI.games[i]->gamefolder, s, len))
|
||||
Q_strcpy( gamedirs[numgamedirs++], SI.games[i]->gamefolder );
|
||||
}
|
||||
|
||||
if( !numgamedirs ) return false;
|
||||
|
||||
@@ -21,7 +21,7 @@ GNU General Public License for more details.
|
||||
convar_t *cvar_vars = NULL; // head of list
|
||||
convar_t *cmd_scripting;
|
||||
|
||||
CVAR_DEFINE_AUTO( cl_filterstuffcmd, "0", FCVAR_ARCHIVE | FCVAR_PRIVILEGED, "filter commands coming from server" );
|
||||
CVAR_DEFINE_AUTO( cl_filterstuffcmd, "1", FCVAR_ARCHIVE | FCVAR_PRIVILEGED, "filter commands coming from server" );
|
||||
|
||||
/*
|
||||
============
|
||||
@@ -934,20 +934,16 @@ void Cvar_List_f( void )
|
||||
const char *match = NULL;
|
||||
char *value;
|
||||
int count = 0;
|
||||
size_t matchlen = 0;
|
||||
|
||||
if( Cmd_Argc() > 1 )
|
||||
{
|
||||
match = Cmd_Argv( 1 );
|
||||
matchlen = Q_strlen( match );
|
||||
}
|
||||
|
||||
for( var = cvar_vars; var; var = var->next )
|
||||
{
|
||||
if( var->name[0] == '@' )
|
||||
continue; // never shows system cvars
|
||||
|
||||
if( match && !Q_strnicmpext( match, var->name, matchlen ))
|
||||
if( match && !Q_stricmpext( match, var->name ))
|
||||
continue;
|
||||
|
||||
if( Q_colorstr( var->string ))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
200
engine/common/filesystem.h
Normal file
200
engine/common/filesystem.h
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
filesystem.h - engine FS
|
||||
Copyright (C) 2007 Uncle Mike
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef FILESYSTEM_H
|
||||
#define FILESYSTEM_H
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
PAK FILES
|
||||
|
||||
The .pak files are just a linear collapse of a directory tree
|
||||
========================================================================
|
||||
*/
|
||||
// header
|
||||
#define IDPACKV1HEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P') // little-endian "PACK"
|
||||
|
||||
#define MAX_FILES_IN_PACK 65536 // pak
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int ident;
|
||||
int dirofs;
|
||||
int dirlen;
|
||||
} dpackheader_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[56]; // total 64 bytes
|
||||
int filepos;
|
||||
int filelen;
|
||||
} dpackfile_t;
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
.WAD archive format (WhereAllData - WAD)
|
||||
|
||||
List of compressed files, that can be identify only by TYPE_*
|
||||
|
||||
<format>
|
||||
header: dwadinfo_t[dwadinfo_t]
|
||||
file_1: byte[dwadinfo_t[num]->disksize]
|
||||
file_2: byte[dwadinfo_t[num]->disksize]
|
||||
file_3: byte[dwadinfo_t[num]->disksize]
|
||||
...
|
||||
file_n: byte[dwadinfo_t[num]->disksize]
|
||||
infotable dlumpinfo_t[dwadinfo_t->numlumps]
|
||||
========================================================================
|
||||
*/
|
||||
#define WAD3_NAMELEN 16
|
||||
#define HINT_NAMELEN 5 // e.g. _mask, _norm
|
||||
#define MAX_FILES_IN_WAD 65535 // real limit as above <2Gb size not a lumpcount
|
||||
|
||||
#include "const.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int ident; // should be WAD3
|
||||
int numlumps; // num files
|
||||
int infotableofs; // LUT offset
|
||||
} dwadinfo_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int filepos; // file offset in WAD
|
||||
int disksize; // compressed or uncompressed
|
||||
int size; // uncompressed
|
||||
signed char type; // TYP_*
|
||||
signed char attribs; // file attribs
|
||||
signed char pad0;
|
||||
signed char pad1;
|
||||
char name[WAD3_NAMELEN]; // must be null terminated
|
||||
} dlumpinfo_t;
|
||||
|
||||
#include "custom.h"
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
.HPK archive format (Hash PAK - HPK)
|
||||
|
||||
List of compressed files, that can be identify only by TYPE_*
|
||||
|
||||
<format>
|
||||
header: dwadinfo_t[dwadinfo_t]
|
||||
file_1: byte[dwadinfo_t[num]->disksize]
|
||||
file_2: byte[dwadinfo_t[num]->disksize]
|
||||
file_3: byte[dwadinfo_t[num]->disksize]
|
||||
...
|
||||
file_n: byte[dwadinfo_t[num]->disksize]
|
||||
infotable dlumpinfo_t[dwadinfo_t->numlumps]
|
||||
========================================================================
|
||||
*/
|
||||
|
||||
#define IDHPAKHEADER (('K'<<24)+('A'<<16)+('P'<<8)+'H') // little-endian "HPAK"
|
||||
#define IDHPAK_VERSION 1
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int ident; // should be equal HPAK
|
||||
int version;
|
||||
int infotableofs;
|
||||
} hpak_header_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
resource_t resource;
|
||||
int filepos;
|
||||
int disksize;
|
||||
} hpak_lump_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int count;
|
||||
hpak_lump_t *entries; // variable sized.
|
||||
} hpak_info_t;
|
||||
|
||||
#define ZIP_HEADER_LF (('K'<<8)+('P')+(0x03<<16)+(0x04<<24))
|
||||
#define ZIP_HEADER_SPANNED ((0x08<<24)+(0x07<<16)+('K'<<8)+'P')
|
||||
|
||||
#define ZIP_HEADER_CDF ((0x02<<24)+(0x01<<16)+('K'<<8)+'P')
|
||||
#define ZIP_HEADER_EOCD ((0x06<<24)+(0x05<<16)+('K'<<8)+'P')
|
||||
|
||||
#define ZIP_COMPRESSION_NO_COMPRESSION 0
|
||||
#define ZIP_COMPRESSION_DEFLATED 8
|
||||
|
||||
#define ZIP_ZIP64 0xffffffff
|
||||
|
||||
#pragma pack( push, 1 )
|
||||
typedef struct zip_header_s
|
||||
{
|
||||
unsigned int signature; // little endian ZIP_HEADER
|
||||
unsigned short version; // version of pkzip need to unpack
|
||||
unsigned short flags; // flags (16 bits == 16 flags)
|
||||
unsigned short compression_flags; // compression flags (bits)
|
||||
unsigned int dos_date; // file modification time and file modification date
|
||||
unsigned int crc32; //crc32
|
||||
unsigned int compressed_size;
|
||||
unsigned int uncompressed_size;
|
||||
unsigned short filename_len;
|
||||
unsigned short extrafield_len;
|
||||
} zip_header_t;
|
||||
|
||||
/*
|
||||
in zip64 comp and uncompr size == 0xffffffff remeber this
|
||||
compressed and uncompress filesize stored in extra field
|
||||
*/
|
||||
|
||||
typedef struct zip_header_extra_s
|
||||
{
|
||||
unsigned int signature; // ZIP_HEADER_SPANNED
|
||||
unsigned int crc32;
|
||||
unsigned int compressed_size;
|
||||
unsigned int uncompressed_size;
|
||||
} zip_header_extra_t;
|
||||
|
||||
typedef struct zip_cdf_header_s
|
||||
{
|
||||
unsigned int signature;
|
||||
unsigned short version;
|
||||
unsigned short version_need;
|
||||
unsigned short generalPurposeBitFlag;
|
||||
unsigned short flags;
|
||||
unsigned short modification_time;
|
||||
unsigned short modification_date;
|
||||
unsigned int crc32;
|
||||
unsigned int compressed_size;
|
||||
unsigned int uncompressed_size;
|
||||
unsigned short filename_len;
|
||||
unsigned short extrafield_len;
|
||||
unsigned short file_commentary_len;
|
||||
unsigned short disk_start;
|
||||
unsigned short internal_attr;
|
||||
unsigned int external_attr;
|
||||
unsigned int local_header_offset;
|
||||
} zip_cdf_header_t;
|
||||
|
||||
typedef struct zip_header_eocd_s
|
||||
{
|
||||
unsigned short disk_number;
|
||||
unsigned short start_disk_number;
|
||||
unsigned short number_central_directory_record;
|
||||
unsigned short total_central_directory_record;
|
||||
unsigned int size_of_central_directory;
|
||||
unsigned int central_directory_offset;
|
||||
unsigned short commentary_len;
|
||||
} zip_header_eocd_t;
|
||||
#pragma pack( pop )
|
||||
|
||||
#endif//FILESYSTEM_H
|
||||
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
filesystem.c - game filesystem based on DP fs
|
||||
Copyright (C) 2007 Uncle Mike
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "library.h"
|
||||
|
||||
fs_api_t g_fsapi;
|
||||
fs_globals_t *FI;
|
||||
|
||||
static HINSTANCE fs_hInstance;
|
||||
|
||||
static void FS_Rescan_f( void )
|
||||
{
|
||||
FS_Rescan();
|
||||
}
|
||||
|
||||
static void FS_ClearPaths_f( void )
|
||||
{
|
||||
FS_ClearSearchPath();
|
||||
}
|
||||
|
||||
static void FS_Path_f_( void )
|
||||
{
|
||||
FS_Path_f();
|
||||
}
|
||||
|
||||
static fs_interface_t fs_memfuncs =
|
||||
{
|
||||
Con_Printf,
|
||||
Con_DPrintf,
|
||||
Con_Reportf,
|
||||
Sys_Error,
|
||||
|
||||
_Mem_AllocPool,
|
||||
_Mem_FreePool,
|
||||
_Mem_Alloc,
|
||||
_Mem_Realloc,
|
||||
_Mem_Free,
|
||||
};
|
||||
|
||||
static void FS_UnloadProgs( void )
|
||||
{
|
||||
COM_FreeLibrary( fs_hInstance );
|
||||
fs_hInstance = 0;
|
||||
}
|
||||
|
||||
#ifdef XASH_INTERNAL_GAMELIBS
|
||||
#define FILESYSTEM_STDIO_DLL "filesystem_stdio"
|
||||
#else
|
||||
#define FILESYSTEM_STDIO_DLL "filesystem_stdio." OS_LIB_EXT
|
||||
#endif
|
||||
|
||||
qboolean FS_LoadProgs( void )
|
||||
{
|
||||
const char *name = FILESYSTEM_STDIO_DLL;
|
||||
FSAPI GetFSAPI;
|
||||
|
||||
fs_hInstance = COM_LoadLibrary( name, false, true );
|
||||
|
||||
if( !fs_hInstance )
|
||||
{
|
||||
Host_Error( "FS_LoadProgs: can't load filesystem library %s: %s\n", name, COM_GetLibraryError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !( GetFSAPI = (FSAPI)COM_GetProcAddress( fs_hInstance, GET_FS_API )))
|
||||
{
|
||||
FS_UnloadProgs();
|
||||
Host_Error( "FS_LoadProgs: can't find GetFSAPI entry point in %s\n", name );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !GetFSAPI( FS_API_VERSION, &g_fsapi, &FI, &fs_memfuncs ))
|
||||
{
|
||||
FS_UnloadProgs();
|
||||
Host_Error( "FS_LoadProgs: can't initialize filesystem API: wrong version\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
Con_DPrintf( "FS_LoadProgs: filesystem_stdio successfully loaded\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FS_Init
|
||||
================
|
||||
*/
|
||||
void FS_Init( void )
|
||||
{
|
||||
qboolean hasBaseDir = false;
|
||||
qboolean hasGameDir = false;
|
||||
qboolean caseinsensitive = true;
|
||||
int i;
|
||||
string gamedir;
|
||||
|
||||
Cmd_AddRestrictedCommand( "fs_rescan", FS_Rescan_f, "rescan filesystem search pathes" );
|
||||
Cmd_AddRestrictedCommand( "fs_path", FS_Path_f_, "show filesystem search pathes" );
|
||||
Cmd_AddRestrictedCommand( "fs_clearpaths", FS_ClearPaths_f, "clear filesystem search pathes" );
|
||||
|
||||
#if !XASH_WIN32
|
||||
if( Sys_CheckParm( "-casesensitive" ) )
|
||||
caseinsensitive = false;
|
||||
#endif
|
||||
|
||||
if( !Sys_GetParmFromCmdLine( "-game", gamedir ))
|
||||
Q_strncpy( gamedir, SI.basedirName, sizeof( gamedir )); // gamedir == basedir
|
||||
|
||||
if( !FS_InitStdio( caseinsensitive, host.rootdir, SI.basedirName, gamedir, host.rodir ))
|
||||
{
|
||||
Host_Error( "Can't init filesystem_stdio!\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !Sys_GetParmFromCmdLine( "-dll", SI.gamedll ))
|
||||
SI.gamedll[0] = 0;
|
||||
|
||||
if( !Sys_GetParmFromCmdLine( "-clientlib", SI.clientlib ))
|
||||
SI.clientlib[0] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FS_Shutdown
|
||||
================
|
||||
*/
|
||||
void FS_Shutdown( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
FS_ShutdownStdio();
|
||||
|
||||
memset( &SI, 0, sizeof( sysinfo_t ));
|
||||
|
||||
FS_UnloadProgs();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -151,8 +151,6 @@ void Sys_PrintUsage( void )
|
||||
O("-clientlib <path>","override client DLL path")
|
||||
#endif
|
||||
O("-rodir <path> ","set read-only base directory, experimental")
|
||||
O("-bugcomp ","enable precise bug compatibility. Will break games that don't require it")
|
||||
O(" ","Refer to engine documentation for more info")
|
||||
|
||||
O("-ip <ip> ","set custom ip")
|
||||
O("-port <port> ","set custom host port")
|
||||
@@ -307,9 +305,7 @@ void Host_NewInstance( const char *name, const char *finalmsg )
|
||||
|
||||
host.change_game = true;
|
||||
Q_strncpy( host.finalmsg, finalmsg, sizeof( host.finalmsg ));
|
||||
|
||||
if( !Sys_NewInstance( name ))
|
||||
pChangeGame( name ); // call from hl.exe
|
||||
pChangeGame( name ); // call from hl.exe
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -330,13 +326,13 @@ void Host_ChangeGame_f( void )
|
||||
}
|
||||
|
||||
// validate gamedir
|
||||
for( i = 0; i < FI->numgames; i++ )
|
||||
for( i = 0; i < SI.numgames; i++ )
|
||||
{
|
||||
if( !Q_stricmp( FI->games[i]->gamefolder, Cmd_Argv( 1 )))
|
||||
if( !Q_stricmp( SI.games[i]->gamefolder, Cmd_Argv( 1 )))
|
||||
break;
|
||||
}
|
||||
|
||||
if( i == FI->numgames )
|
||||
if( i == SI.numgames )
|
||||
{
|
||||
Con_Printf( "%s not exist\n", Cmd_Argv( 1 ));
|
||||
}
|
||||
@@ -347,7 +343,7 @@ void Host_ChangeGame_f( void )
|
||||
else
|
||||
{
|
||||
const char *arg1 = va( "%s%s", (host.type == HOST_NORMAL) ? "" : "#", Cmd_Argv( 1 ));
|
||||
const char *arg2 = va( "change game to '%s'", FI->games[i]->title );
|
||||
const char *arg2 = va( "change game to '%s'", SI.games[i]->title );
|
||||
|
||||
Host_NewInstance( arg1, arg2 );
|
||||
}
|
||||
@@ -861,10 +857,10 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha
|
||||
|
||||
if( !Sys_CheckParm( "-disablehelp" ) )
|
||||
{
|
||||
if( Sys_CheckParm( "-help" ) || Sys_CheckParm( "-h" ) || Sys_CheckParm( "--help" ) )
|
||||
{
|
||||
if( Sys_CheckParm( "-help" ) || Sys_CheckParm( "-h" ) || Sys_CheckParm( "--help" ) )
|
||||
{
|
||||
Sys_PrintUsage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !Sys_CheckParm( "-noch" ) )
|
||||
@@ -872,7 +868,7 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha
|
||||
|
||||
host.enabledll = !Sys_CheckParm( "-nodll" );
|
||||
|
||||
host.change_game = bChangeGame || Sys_CheckParm( "-changegame" );
|
||||
host.change_game = bChangeGame;
|
||||
host.config_executed = false;
|
||||
host.status = HOST_INIT; // initialzation started
|
||||
|
||||
@@ -943,13 +939,6 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha
|
||||
// member console allowing
|
||||
host.allow_console_init = host.allow_console;
|
||||
|
||||
if( Sys_CheckParm( "-bugcomp" ))
|
||||
{
|
||||
// add argument check here when we add other levels
|
||||
// of bugcompatibility
|
||||
host.bugcomp = BUGCOMP_GOLDSRC;
|
||||
}
|
||||
|
||||
// timeBeginPeriod( 1 ); // a1ba: Do we need this?
|
||||
|
||||
// NOTE: this message couldn't be passed into game console but it doesn't matter
|
||||
@@ -1036,33 +1025,18 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha
|
||||
if( len && host.rodir[len - 1] == '/' )
|
||||
host.rodir[len - 1] = 0;
|
||||
|
||||
if( !COM_CheckStringEmpty( host.rootdir ))
|
||||
{
|
||||
Sys_Error( "Changing working directory failed (empty working directory)\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
FS_LoadProgs();
|
||||
|
||||
if( FS_SetCurrentDirectory( host.rootdir ) != 0 )
|
||||
if( !COM_CheckStringEmpty( host.rootdir ) || FS_SetCurrentDirectory( host.rootdir ) != 0 )
|
||||
Con_Reportf( "%s is working directory now\n", host.rootdir );
|
||||
else
|
||||
Sys_Error( "Changing working directory to %s failed.\n", host.rootdir );
|
||||
|
||||
FS_Init();
|
||||
|
||||
Sys_InitLog();
|
||||
|
||||
// print bugcompatibility level here, after log was initialized
|
||||
if( host.bugcomp == BUGCOMP_GOLDSRC )
|
||||
{
|
||||
Con_Printf( "^3BUGCOMP^7: GoldSrc bug-compatibility enabled\n" );
|
||||
}
|
||||
|
||||
Cmd_AddCommand( "exec", Host_Exec_f, "execute a script file" );
|
||||
Cmd_AddCommand( "memlist", Host_MemStats_f, "prints memory pool information" );
|
||||
Cmd_AddRestrictedCommand( "userconfigd", Host_Userconfigd_f, "execute all scripts from userconfig.d" );
|
||||
|
||||
FS_Init();
|
||||
Image_Init();
|
||||
Sound_Init();
|
||||
|
||||
@@ -1072,16 +1046,8 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha
|
||||
#endif
|
||||
|
||||
FS_LoadGameInfo( NULL );
|
||||
|
||||
if( FS_FileExists( va( "%s.rc", SI.basedirName ), false ))
|
||||
Q_strncpy( SI.rcName, SI.basedirName, sizeof( SI.rcName )); // e.g. valve.rc
|
||||
else Q_strncpy( SI.rcName, SI.exeName, sizeof( SI.rcName )); // e.g. quake.rc
|
||||
|
||||
Q_strncpy( host.gamefolder, GI->gamefolder, sizeof( host.gamefolder ));
|
||||
|
||||
Image_CheckPaletteQ1 ();
|
||||
Host_InitDecals (); // reload decals
|
||||
|
||||
// DEPRECATED: by FWGS fork
|
||||
#if 0
|
||||
if( GI->secure )
|
||||
@@ -1231,6 +1197,8 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DLL_PrintLeaks( void );
|
||||
|
||||
/*
|
||||
=================
|
||||
Host_Shutdown
|
||||
@@ -1259,6 +1227,8 @@ void EXPORT Host_Shutdown( void )
|
||||
Host_FreeCommon();
|
||||
Platform_Shutdown();
|
||||
|
||||
DLL_PrintLeaks();
|
||||
|
||||
// must be last, console uses this
|
||||
Mem_FreePool( &host.mempool );
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "hpak.h"
|
||||
#include "filesystem.h"
|
||||
|
||||
#define HPAK_MAX_ENTRIES 0x8000
|
||||
#define HPAK_MIN_SIZE (1 * 1024)
|
||||
@@ -402,7 +402,7 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet )
|
||||
FS_Seek( f, hdr.infotableofs, SEEK_SET );
|
||||
FS_Read( f, &num_lumps, sizeof( num_lumps ));
|
||||
|
||||
if( num_lumps < 1 || num_lumps > HPAK_MAX_ENTRIES )
|
||||
if( num_lumps < 1 || num_lumps > MAX_FILES_IN_WAD )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "HPAK_ValidatePak: %s has too many lumps %u.\n", pakname, num_lumps );
|
||||
FS_Close( f );
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
hpak.c - custom user package to send other clients
|
||||
Copyright (C) 2010 Uncle Mike
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
#ifndef HPAK_H
|
||||
#define HPAK_H
|
||||
|
||||
#include "custom.h"
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
.HPK archive format (Hash PAK - HPK)
|
||||
|
||||
List of compressed files, that can be identify only by TYPE_*
|
||||
|
||||
<format>
|
||||
header: dwadinfo_t[dwadinfo_t]
|
||||
file_1: byte[dwadinfo_t[num]->disksize]
|
||||
file_2: byte[dwadinfo_t[num]->disksize]
|
||||
file_3: byte[dwadinfo_t[num]->disksize]
|
||||
...
|
||||
file_n: byte[dwadinfo_t[num]->disksize]
|
||||
infotable dlumpinfo_t[dwadinfo_t->numlumps]
|
||||
========================================================================
|
||||
*/
|
||||
|
||||
#define IDHPAKHEADER (('K'<<24)+('A'<<16)+('P'<<8)+'H') // little-endian "HPAK"
|
||||
#define IDHPAK_VERSION 1
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int ident; // should be equal HPAK
|
||||
int version;
|
||||
int infotableofs;
|
||||
} hpak_header_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
resource_t resource;
|
||||
int filepos;
|
||||
int disksize;
|
||||
} hpak_lump_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int count;
|
||||
hpak_lump_t *entries; // variable sized.
|
||||
} hpak_info_t;
|
||||
|
||||
#endif // HPAK_H
|
||||
@@ -13,6 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define MINIZ_HEADER_FILE_ONLY
|
||||
#include "miniz.h"
|
||||
#include "imagelib.h"
|
||||
#include "xash3d_mathlib.h"
|
||||
@@ -26,8 +27,6 @@ GNU General Public License for more details.
|
||||
|
||||
static const char png_sign[] = {0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n'};
|
||||
static const char ihdr_sign[] = {'I', 'H', 'D', 'R'};
|
||||
static const char trns_sign[] = {'t', 'R', 'N', 'S'};
|
||||
static const char plte_sign[] = {'P', 'L', 'T', 'E'};
|
||||
static const char idat_sign[] = {'I', 'D', 'A', 'T'};
|
||||
static const char iend_sign[] = {'I', 'E', 'N', 'D'};
|
||||
static const int iend_crc32 = 0xAE426082;
|
||||
@@ -42,9 +41,8 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
int ret;
|
||||
short p, a, b, c, pa, pb, pc;
|
||||
byte *buf_p, *pixbuf, *raw, *prior, *idat_buf = NULL, *uncompressed_buffer = NULL, *rowend;
|
||||
byte *pallete = NULL, *trns = NULL;
|
||||
uint chunk_len, trns_len, crc32, crc32_check, oldsize = 0, newsize = 0, rowsize;
|
||||
uint uncompressed_size, pixel_size, i, y, filter_type, chunk_sign, r_alpha, g_alpha, b_alpha;
|
||||
uint chunk_len, crc32, crc32_check, oldsize = 0, newsize = 0, rowsize;
|
||||
uint uncompressed_size, pixel_size, i, y, filter_type, chunk_sign;
|
||||
qboolean has_iend_chunk = false;
|
||||
z_stream stream = {0};
|
||||
png_t png_hdr;
|
||||
@@ -70,7 +68,7 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
// check IHDR chunk length (valid value - 13)
|
||||
if( png_hdr.ihdr_len != sizeof( png_ihdr_t ) )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Invalid IHDR chunk size %u (%s)\n", png_hdr.ihdr_len, name );
|
||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Invalid IHDR chunk size (%s)\n", name );
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -87,7 +85,7 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
|
||||
if( png_hdr.ihdr_chunk.height == 0 || png_hdr.ihdr_chunk.width == 0 )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Invalid image size %ux%u (%s)\n", png_hdr.ihdr_chunk.width, png_hdr.ihdr_chunk.height, name );
|
||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Invalid image size %dx%d (%s)\n", png_hdr.ihdr_chunk.width, png_hdr.ihdr_chunk.height, name );
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -97,25 +95,21 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !( png_hdr.ihdr_chunk.colortype == PNG_CT_RGB
|
||||
|| png_hdr.ihdr_chunk.colortype == PNG_CT_RGBA
|
||||
|| png_hdr.ihdr_chunk.colortype == PNG_CT_GREY
|
||||
|| png_hdr.ihdr_chunk.colortype == PNG_CT_ALPHA
|
||||
|| png_hdr.ihdr_chunk.colortype == PNG_CT_PALLETE ) )
|
||||
if( png_hdr.ihdr_chunk.colortype != PNG_CT_RGB && png_hdr.ihdr_chunk.colortype != PNG_CT_RGBA )
|
||||
{
|
||||
Con_DPrintf( S_WARN "Image_LoadPNG: Unknown color type %u (%s)\n", png_hdr.ihdr_chunk.colortype, name );
|
||||
Con_DPrintf( S_WARN "Image_LoadPNG: Only 8-bit RGB and RGBA images is supported (%s)\n", name );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( png_hdr.ihdr_chunk.compression > 0 )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Unknown compression method %u (%s)\n", png_hdr.ihdr_chunk.compression, name );
|
||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Unknown compression method (%s)\n", name );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( png_hdr.ihdr_chunk.filter > 0 )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Unknown filter type %u (%s)\n", png_hdr.ihdr_chunk.filter, name );
|
||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Unknown filter type (%s)\n", name );
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -127,7 +121,7 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
|
||||
if( png_hdr.ihdr_chunk.interlace > 0 )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Unknown interlacing type %u (%s)\n", png_hdr.ihdr_chunk.interlace, name );
|
||||
Con_DPrintf( S_ERROR "Image_LoadPNG: Unknown interlacing type (%s)\n", name );
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -165,19 +159,8 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
// move pointer
|
||||
buf_p += sizeof( chunk_sign );
|
||||
|
||||
// find transparency
|
||||
if( !memcmp( buf_p, trns_sign, sizeof( trns_sign ) ) )
|
||||
{
|
||||
trns = buf_p + sizeof( trns_sign );
|
||||
trns_len = chunk_len;
|
||||
}
|
||||
// find pallete for indexed image
|
||||
else if( !memcmp( buf_p, plte_sign, sizeof( plte_sign ) ) )
|
||||
{
|
||||
pallete = buf_p + sizeof( plte_sign );
|
||||
}
|
||||
// get all IDAT chunks data
|
||||
else if( !memcmp( buf_p, idat_sign, sizeof( idat_sign ) ) )
|
||||
if( !memcmp( buf_p, idat_sign, sizeof( idat_sign ) ) )
|
||||
{
|
||||
newsize = oldsize + chunk_len;
|
||||
idat_buf = (byte *)Mem_Realloc( host.imagepool, idat_buf, newsize );
|
||||
@@ -211,13 +194,6 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
buf_p += sizeof( crc32 );
|
||||
}
|
||||
|
||||
if( png_hdr.ihdr_chunk.colortype == PNG_CT_PALLETE && !pallete )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "Image_LoadPNG: PLTE chunk not found (%s)\n", name );
|
||||
Mem_Free( idat_buf );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !has_iend_chunk )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "Image_LoadPNG: IEND chunk not found (%s)\n", name );
|
||||
@@ -227,7 +203,7 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
|
||||
if( chunk_len != 0 )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "Image_LoadPNG: IEND chunk has wrong size %u (%s)\n", chunk_len, name );
|
||||
Con_DPrintf( S_ERROR "Image_LoadPNG: IEND chunk has wrong size (%s)\n", name );
|
||||
Mem_Free( idat_buf );
|
||||
return false;
|
||||
}
|
||||
@@ -240,13 +216,6 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
|
||||
switch( png_hdr.ihdr_chunk.colortype )
|
||||
{
|
||||
case PNG_CT_GREY:
|
||||
case PNG_CT_PALLETE:
|
||||
pixel_size = 1;
|
||||
break;
|
||||
case PNG_CT_ALPHA:
|
||||
pixel_size = 2;
|
||||
break;
|
||||
case PNG_CT_RGB:
|
||||
pixel_size = 3;
|
||||
break;
|
||||
@@ -263,11 +232,9 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
image.width = png_hdr.ihdr_chunk.width;
|
||||
image.height = png_hdr.ihdr_chunk.height;
|
||||
image.size = image.height * image.width * 4;
|
||||
image.flags |= IMAGE_HAS_COLOR;
|
||||
|
||||
if( png_hdr.ihdr_chunk.colortype & PNG_CT_RGB )
|
||||
image.flags |= IMAGE_HAS_COLOR;
|
||||
|
||||
if( trns || ( png_hdr.ihdr_chunk.colortype & PNG_CT_ALPHA ) )
|
||||
if( png_hdr.ihdr_chunk.colortype == PNG_CT_RGBA )
|
||||
image.flags |= IMAGE_HAS_ALPHA;
|
||||
|
||||
image.depth = 1;
|
||||
@@ -309,7 +276,7 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
|
||||
raw = uncompressed_buffer;
|
||||
|
||||
if( png_hdr.ihdr_chunk.colortype != PNG_CT_RGBA )
|
||||
if( png_hdr.ihdr_chunk.colortype == PNG_CT_RGB )
|
||||
prior = pixbuf = raw;
|
||||
|
||||
filter_type = *raw++;
|
||||
@@ -411,18 +378,11 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
prior = pixbuf;
|
||||
}
|
||||
|
||||
pixbuf = image.rgba;
|
||||
raw = uncompressed_buffer;
|
||||
|
||||
switch( png_hdr.ihdr_chunk.colortype )
|
||||
// convert RGB-to-RGBA
|
||||
if( png_hdr.ihdr_chunk.colortype == PNG_CT_RGB )
|
||||
{
|
||||
case PNG_CT_RGB:
|
||||
if( trns )
|
||||
{
|
||||
r_alpha = trns[0] << 8 | trns[1];
|
||||
g_alpha = trns[2] << 8 | trns[3];
|
||||
b_alpha = trns[4] << 8 | trns[5];
|
||||
}
|
||||
pixbuf = image.rgba;
|
||||
raw = uncompressed_buffer;
|
||||
|
||||
for( y = 0; y < image.height; y++ )
|
||||
{
|
||||
@@ -432,68 +392,9 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
*pixbuf++ = raw[0];
|
||||
*pixbuf++ = raw[1];
|
||||
*pixbuf++ = raw[2];
|
||||
|
||||
if( trns && r_alpha == raw[0]
|
||||
&& g_alpha == raw[1]
|
||||
&& b_alpha == raw[2] )
|
||||
*pixbuf++ = 0;
|
||||
else
|
||||
*pixbuf++ = 0xFF;
|
||||
*pixbuf++ = 0xFF;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PNG_CT_GREY:
|
||||
if( trns )
|
||||
r_alpha = trns[0] << 8 | trns[1];
|
||||
|
||||
for( y = 0; y < image.height; y++ )
|
||||
{
|
||||
rowend = raw + rowsize;
|
||||
for( ; raw < rowend; raw += pixel_size )
|
||||
{
|
||||
*pixbuf++ = raw[0];
|
||||
*pixbuf++ = raw[0];
|
||||
*pixbuf++ = raw[0];
|
||||
|
||||
if( trns && r_alpha == raw[0] )
|
||||
*pixbuf++ = 0;
|
||||
else
|
||||
*pixbuf++ = 0xFF;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PNG_CT_ALPHA:
|
||||
for( y = 0; y < image.height; y++ )
|
||||
{
|
||||
rowend = raw + rowsize;
|
||||
for( ; raw < rowend; raw += pixel_size )
|
||||
{
|
||||
*pixbuf++ = raw[0];
|
||||
*pixbuf++ = raw[0];
|
||||
*pixbuf++ = raw[0];
|
||||
*pixbuf++ = raw[1];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PNG_CT_PALLETE:
|
||||
for( y = 0; y < image.height; y++ )
|
||||
{
|
||||
rowend = raw + rowsize;
|
||||
for( ; raw < rowend; raw += pixel_size )
|
||||
{
|
||||
*pixbuf++ = pallete[raw[0] + 2];
|
||||
*pixbuf++ = pallete[raw[0] + 1];
|
||||
*pixbuf++ = pallete[raw[0] + 0];
|
||||
|
||||
if( trns && raw[0] < trns_len )
|
||||
*pixbuf++ = trns[raw[0]];
|
||||
else
|
||||
*pixbuf++ = 0xFF;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Mem_Free( uncompressed_buffer );
|
||||
|
||||
@@ -25,8 +25,8 @@ GNU General Public License for more details.
|
||||
enum png_colortype
|
||||
{
|
||||
PNG_CT_GREY,
|
||||
PNG_CT_PALLETE = BIT(0),
|
||||
PNG_CT_RGB = BIT(1),
|
||||
PNG_CT_PALLETE = (PNG_CT_RGB|BIT(0)),
|
||||
PNG_CT_ALPHA = BIT(2),
|
||||
PNG_CT_RGBA = (PNG_CT_RGB|PNG_CT_ALPHA)
|
||||
};
|
||||
|
||||
@@ -96,8 +96,8 @@ static const loadpixformat_t load_null[] =
|
||||
static const loadpixformat_t load_game[] =
|
||||
{
|
||||
{ "%s%s.%s", "dds", Image_LoadDDS, IL_HINT_NO }, // dds for world and studio models
|
||||
{ "%s%s.%s", "bmp", Image_LoadBMP, IL_HINT_NO }, // WON menu images
|
||||
{ "%s%s.%s", "tga", Image_LoadTGA, IL_HINT_NO }, // hl vgui menus
|
||||
{ "%s%s.%s", "bmp", Image_LoadBMP, IL_HINT_NO }, // WON menu images
|
||||
{ "%s%s.%s", "png", Image_LoadPNG, IL_HINT_NO }, // NightFire 007 menus
|
||||
{ "%s%s.%s", "mip", Image_LoadMIP, IL_HINT_NO }, // hl textures from wad or buffer
|
||||
{ "%s%s.%s", "mdl", Image_LoadMDL, IL_HINT_HL }, // hl studio model skins
|
||||
|
||||
@@ -23,78 +23,54 @@ GNU General Public License for more details.
|
||||
|
||||
#if XASH_EMSCRIPTEN
|
||||
#include <emscripten.h>
|
||||
#elif XASH_WIN32
|
||||
extern "C"
|
||||
{
|
||||
// Enable NVIDIA High Performance Graphics while using Integrated Graphics.
|
||||
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
||||
#endif
|
||||
|
||||
// Enable AMD High Performance Graphics while using Integrated Graphics.
|
||||
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
||||
}
|
||||
#if XASH_WIN32
|
||||
#include <process.h> // _execve
|
||||
#else
|
||||
#include <unistd.h> // execve
|
||||
#endif
|
||||
|
||||
extern char **environ;
|
||||
static char szGameDir[128]; // safe place to keep gamedir
|
||||
static int g_iArgc;
|
||||
static char **g_pszArgv;
|
||||
|
||||
#if XASH_WIN32 || XASH_POSIX
|
||||
#define USE_EXECVE_FOR_CHANGE_GAME 1
|
||||
#else
|
||||
#define USE_EXECVE_FOR_CHANGE_GAME 0
|
||||
#endif
|
||||
|
||||
#define E_GAME "XASH3D_GAME" // default env dir to start from
|
||||
#define GAME_PATH "valve" // default dir to start from
|
||||
|
||||
static char szGameDir[128]; // safe place to keep gamedir
|
||||
static int szArgc;
|
||||
static char **szArgv;
|
||||
|
||||
static void Sys_ChangeGame( const char *progname )
|
||||
void Launcher_ChangeGame( const char *progname )
|
||||
{
|
||||
// a1ba: may never be called within engine
|
||||
// if platform supports execv() function
|
||||
char envstr[256];
|
||||
|
||||
#if USE_EXECVE_FOR_CHANGE_GAME
|
||||
Host_Shutdown();
|
||||
|
||||
#if XASH_WIN32
|
||||
_putenv_s( E_GAME, progname );
|
||||
_execve( g_pszArgv[0], g_pszArgv, _environ );
|
||||
#else
|
||||
snprintf( envstr, sizeof( envstr ), E_GAME "=%s", progname );
|
||||
putenv( envstr );
|
||||
execve( g_pszArgv[0], g_pszArgv, environ );
|
||||
#endif
|
||||
|
||||
#else
|
||||
Q_strncpy( szGameDir, progname, sizeof( szGameDir ) - 1 );
|
||||
Host_Shutdown( );
|
||||
exit( Host_Main( szArgc, szArgv, szGameDir, 1, &Sys_ChangeGame ) );
|
||||
exit( Host_Main( g_iArgc, g_pszArgv, szGameDir, 1, &Launcher_ChangeGame ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
_inline int Sys_Start( void )
|
||||
{
|
||||
int ret;
|
||||
const char *game = getenv( E_GAME );
|
||||
|
||||
if( !game )
|
||||
game = GAME_PATH;
|
||||
|
||||
Q_strncpy( szGameDir, game, sizeof( szGameDir ));
|
||||
#if XASH_EMSCRIPTEN
|
||||
#ifdef EMSCRIPTEN_LIB_FS
|
||||
// For some unknown reason emscripten refusing to load libraries later
|
||||
COM_LoadLibrary("menu", 0 );
|
||||
COM_LoadLibrary("server", 0 );
|
||||
COM_LoadLibrary("client", 0 );
|
||||
#endif
|
||||
#if XASH_DEDICATED
|
||||
// NodeJS support for debug
|
||||
EM_ASM(try{
|
||||
FS.mkdir('/xash');
|
||||
FS.mount(NODEFS, { root: '.'}, '/xash' );
|
||||
FS.chdir('/xash');
|
||||
}catch(e){};);
|
||||
#endif
|
||||
#elif XASH_IOS
|
||||
{
|
||||
void IOS_LaunchDialog( void );
|
||||
IOS_LaunchDialog();
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = Host_Main( szArgc, szArgv, game, 0, Sys_ChangeGame );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if !XASH_WIN32
|
||||
int main( int argc, char **argv )
|
||||
{
|
||||
szArgc = argc;
|
||||
szArgv = argv;
|
||||
|
||||
return Sys_Start();
|
||||
}
|
||||
#else
|
||||
#if XASH_WIN32
|
||||
#include <windows.h>
|
||||
#include <shellapi.h> // CommandLineToArgvW
|
||||
int __stdcall WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdLine, int nShow)
|
||||
{
|
||||
LPWSTR* lpArgv;
|
||||
@@ -115,9 +91,9 @@ int __stdcall WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdLine, int n
|
||||
|
||||
LocalFree( lpArgv );
|
||||
|
||||
ret = Sys_Start();
|
||||
ret = main( szArgc, szArgv );
|
||||
|
||||
for( ; i < szArgc; ++i )
|
||||
for( i = 0; i < szArgc; ++i )
|
||||
free( szArgv[i] );
|
||||
free( szArgv );
|
||||
|
||||
@@ -125,5 +101,41 @@ int __stdcall WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdLine, int n
|
||||
}
|
||||
#endif // XASH_WIN32
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
const char *game = getenv( E_GAME );
|
||||
|
||||
if( !game )
|
||||
game = GAME_PATH;
|
||||
|
||||
Q_strncpy( szGameDir, game, sizeof( szGameDir ));
|
||||
|
||||
#if XASH_EMSCRIPTEN
|
||||
#ifdef EMSCRIPTEN_LIB_FS
|
||||
// For some unknown reason emscripten refusing to load libraries later
|
||||
COM_LoadLibrary("menu", 0 );
|
||||
COM_LoadLibrary("server", 0 );
|
||||
COM_LoadLibrary("client", 0 );
|
||||
#endif
|
||||
#if XASH_DEDICATED
|
||||
// NodeJS support for debug
|
||||
EM_ASM(try{
|
||||
FS.mkdir('/xash');
|
||||
FS.mount(NODEFS, { root: '.'}, '/xash' );
|
||||
FS.chdir('/xash');
|
||||
}catch(e){};);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
g_iArgc = argc;
|
||||
g_pszArgv = argv;
|
||||
#if XASH_IOS
|
||||
{
|
||||
void IOS_LaunchDialog( void );
|
||||
IOS_LaunchDialog();
|
||||
}
|
||||
#endif
|
||||
return Host_Main( g_iArgc, g_pszArgv, szGameDir, 0, &Launcher_ChangeGame );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -86,38 +86,6 @@ const char *COM_OffsetNameForFunction( void *function )
|
||||
return sname;
|
||||
}
|
||||
|
||||
dll_user_t *FS_FindLibrary( const char *dllname, qboolean directpath )
|
||||
{
|
||||
dll_user_t *p;
|
||||
fs_dllinfo_t dllInfo;
|
||||
|
||||
// no fs loaded yet, but let engine find fs
|
||||
if( !g_fsapi.FindLibrary )
|
||||
{
|
||||
p = Mem_Calloc( host.mempool, sizeof( dll_user_t ));
|
||||
Q_strncpy( p->shortPath, dllname, sizeof( p->shortPath ));
|
||||
Q_strncpy( p->fullPath, dllname, sizeof( p->fullPath ));
|
||||
Q_strncpy( p->dllName, dllname, sizeof( p->dllName ));
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// fs can't find library
|
||||
if( !g_fsapi.FindLibrary( dllname, directpath, &dllInfo ))
|
||||
return NULL;
|
||||
|
||||
// NOTE: for libraries we not fail even if search is NULL
|
||||
// let the OS find library himself
|
||||
p = Mem_Calloc( host.mempool, sizeof( dll_user_t ));
|
||||
Q_strncpy( p->shortPath, dllInfo.shortPath, sizeof( p->shortPath ));
|
||||
Q_strncpy( p->fullPath, dllInfo.fullPath, sizeof( p->fullPath ));
|
||||
Q_strncpy( p->dllName, dllname, sizeof( p->dllName ));
|
||||
p->custom_loader = dllInfo.custom_loader;
|
||||
p->encrypted = dllInfo.encrypted;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
|
||||
@@ -35,7 +35,11 @@ typedef struct dll_user_s
|
||||
} dll_user_t;
|
||||
|
||||
dll_user_t *FS_FindLibrary( const char *dllname, qboolean directpath );
|
||||
void *COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean directpath );
|
||||
|
||||
#define COM_LoadLibrary( dllname, build_ordinals_table, directpath ) \
|
||||
_COM_LoadLibrary( dllname, build_ordinals_table, directpath, __FILE__, __LINE__ )
|
||||
|
||||
void *_COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean directpath, const char *name, int line );
|
||||
void *COM_GetProcAddress( void *hInstance, const char *name );
|
||||
const char *COM_NameForFunction( void *hInstance, void *function );
|
||||
void *COM_FunctionFromName_SR( void *hInstance, const char *pName ); // Save/Restore version
|
||||
|
||||
@@ -21,7 +21,6 @@ typedef struct master_s
|
||||
qboolean sent;
|
||||
qboolean save;
|
||||
string address;
|
||||
netadr_t adr; // temporary, rewritten after each send
|
||||
} master_t;
|
||||
|
||||
struct masterlist_s
|
||||
@@ -45,32 +44,31 @@ qboolean NET_SendToMasters( netsrc_t sock, size_t len, const void *data )
|
||||
|
||||
for( list = ml.list; list; list = list->next )
|
||||
{
|
||||
netadr_t adr;
|
||||
int res;
|
||||
|
||||
if( list->sent )
|
||||
continue;
|
||||
|
||||
res = NET_StringToAdrNB( list->address, &list->adr );
|
||||
res = NET_StringToAdrNB( list->address, &adr );
|
||||
|
||||
if( !res )
|
||||
{
|
||||
Con_Reportf( "Can't resolve adr: %s\n", list->address );
|
||||
list->sent = true;
|
||||
list->adr.type = NA_UNUSED;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( res == 2 )
|
||||
{
|
||||
list->sent = false;
|
||||
list->adr.type = NA_UNUSED;
|
||||
wait = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
list->sent = true;
|
||||
|
||||
NET_SendPacket( sock, len, data, list->adr );
|
||||
NET_SendPacket( sock, len, data, adr );
|
||||
}
|
||||
|
||||
if( !wait )
|
||||
@@ -87,25 +85,6 @@ qboolean NET_SendToMasters( netsrc_t sock, size_t len, const void *data )
|
||||
return wait;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
NET_IsMasterAdr
|
||||
|
||||
========================
|
||||
*/
|
||||
qboolean NET_IsMasterAdr( netadr_t adr )
|
||||
{
|
||||
master_t *master;
|
||||
|
||||
for( master = ml.list; master; master = master->next )
|
||||
{
|
||||
if( NET_CompareAdr( adr, master->adr ))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
NET_AddMaster
|
||||
@@ -128,7 +107,6 @@ static void NET_AddMaster( const char *addr, qboolean save )
|
||||
master->sent = false;
|
||||
master->save = save;
|
||||
master->next = NULL;
|
||||
master->adr.type = NA_UNUSED;
|
||||
|
||||
// link in
|
||||
if( last )
|
||||
@@ -183,10 +161,7 @@ static void NET_ListMasters_f( void )
|
||||
|
||||
for( i = 1, list = ml.list; list; i++, list = list->next )
|
||||
{
|
||||
Msg( "%d\t%s", i, list->address );
|
||||
if( list->adr.type != NA_UNUSED )
|
||||
Msg( "\t%s\n", NET_AdrToString( list->adr ));
|
||||
else Msg( "\n" );
|
||||
Msg( "%d\t%s\n", i, list->address );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@ model_t *Mod_ForName( const char *name, qboolean crash, qboolean trackCRC );
|
||||
qboolean Mod_ValidateCRC( const char *name, CRC32_t crc );
|
||||
void Mod_NeedCRC( const char *name, qboolean needCRC );
|
||||
void Mod_FreeUnused( void );
|
||||
model_t *Mod_Handle( int handle );
|
||||
|
||||
//
|
||||
// mod_bmodel.c
|
||||
|
||||
@@ -600,3 +600,20 @@ void Mod_NeedCRC( const char *name, qboolean needCRC )
|
||||
if( needCRC ) SetBits( p->flags, FCRC_SHOULD_CHECKSUM );
|
||||
else ClearBits( p->flags, FCRC_SHOULD_CHECKSUM );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
Mod_Handle
|
||||
|
||||
==================
|
||||
*/
|
||||
model_t *GAME_EXPORT Mod_Handle( int handle )
|
||||
{
|
||||
if( handle < 0 || handle >= MAX_MODELS )
|
||||
{
|
||||
Con_Reportf( "Mod_Handle: bad handle #%i\n", handle );
|
||||
return NULL;
|
||||
}
|
||||
return &mod_known[handle];
|
||||
}
|
||||
|
||||
@@ -626,7 +626,7 @@ qboolean NET_IsReservedAdr( netadr_t a )
|
||||
return true;
|
||||
}
|
||||
|
||||
if( a.ip[0] == 192 && a.ip[1] == 168 )
|
||||
if( a.ip[0] == 192 && a.ip[1] >= 168 )
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1472,71 +1472,35 @@ static int NET_IPSocket( const char *net_interface, int port, qboolean multicast
|
||||
NET_OpenIP
|
||||
====================
|
||||
*/
|
||||
static void NET_OpenIP( qboolean change_port )
|
||||
static void NET_OpenIP( void )
|
||||
{
|
||||
int port;
|
||||
qboolean sv_nat = Cvar_VariableInteger("sv_nat");
|
||||
qboolean cl_nat = Cvar_VariableInteger("cl_nat");
|
||||
|
||||
if( change_port && ( FBitSet( net_hostport->flags, FCVAR_CHANGED ) || sv_nat ))
|
||||
{
|
||||
// reopen socket to set random port
|
||||
if( NET_IsSocketValid( net.ip_sockets[NS_SERVER] ))
|
||||
closesocket( net.ip_sockets[NS_SERVER] );
|
||||
|
||||
net.ip_sockets[NS_SERVER] = INVALID_SOCKET;
|
||||
ClearBits( net_hostport->flags, FCVAR_CHANGED );
|
||||
}
|
||||
int port, sv_port = 0, cl_port = 0;
|
||||
|
||||
if( !NET_IsSocketValid( net.ip_sockets[NS_SERVER] ) )
|
||||
{
|
||||
port = net_iphostport->value;
|
||||
if( !port )
|
||||
{
|
||||
if( sv_nat )
|
||||
port = PORT_ANY;
|
||||
else
|
||||
port = net_hostport->value;
|
||||
|
||||
if( !port )
|
||||
port = PORT_SERVER; // forcing to default
|
||||
}
|
||||
if( !port ) port = net_hostport->value;
|
||||
if( !port ) port = PORT_SERVER; // forcing to default
|
||||
net.ip_sockets[NS_SERVER] = NET_IPSocket( net_ipname->string, port, false );
|
||||
|
||||
if( !NET_IsSocketValid( net.ip_sockets[NS_SERVER] ) && Host_IsDedicated() )
|
||||
Host_Error( "Couldn't allocate dedicated server IP port %d.\n", port );
|
||||
sv_port = port;
|
||||
}
|
||||
|
||||
// dedicated servers don't need client ports
|
||||
if( Host_IsDedicated() ) return;
|
||||
|
||||
if (change_port && ( FBitSet( net_clientport->flags, FCVAR_CHANGED ) || cl_nat ))
|
||||
{
|
||||
// reopen socket to set random port
|
||||
if( NET_IsSocketValid(net.ip_sockets[NS_CLIENT] ))
|
||||
closesocket( net.ip_sockets[NS_CLIENT] );
|
||||
|
||||
net.ip_sockets[NS_CLIENT] = INVALID_SOCKET;
|
||||
ClearBits( net_clientport->flags, FCVAR_CHANGED );
|
||||
}
|
||||
|
||||
if( !NET_IsSocketValid( net.ip_sockets[NS_CLIENT] ) )
|
||||
{
|
||||
port = net_ipclientport->value;
|
||||
if( !port )
|
||||
{
|
||||
if( cl_nat )
|
||||
port = PORT_ANY;
|
||||
else
|
||||
port = net_clientport->value;
|
||||
|
||||
if( !port )
|
||||
port = PORT_ANY; // forcing to default
|
||||
}
|
||||
if( !port ) port = net_clientport->value;
|
||||
if( !port ) port = PORT_ANY; // forcing to default
|
||||
net.ip_sockets[NS_CLIENT] = NET_IPSocket( net_ipname->string, port, false );
|
||||
|
||||
if( !NET_IsSocketValid( net.ip_sockets[NS_CLIENT] ) )
|
||||
net.ip_sockets[NS_CLIENT] = NET_IPSocket( net_ipname->string, PORT_ANY, false );
|
||||
cl_port = port;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1606,7 +1570,7 @@ NET_Config
|
||||
A single player game will only use the loopback code
|
||||
====================
|
||||
*/
|
||||
void NET_Config( qboolean multiplayer, qboolean changeport )
|
||||
void NET_Config( qboolean multiplayer )
|
||||
{
|
||||
static qboolean bFirst = true;
|
||||
static qboolean old_config;
|
||||
@@ -1622,7 +1586,7 @@ void NET_Config( qboolean multiplayer, qboolean changeport )
|
||||
if( multiplayer )
|
||||
{
|
||||
// open sockets
|
||||
if( net.allow_ip ) NET_OpenIP( changeport );
|
||||
if( net.allow_ip ) NET_OpenIP();
|
||||
|
||||
// get our local address, if possible
|
||||
if( bFirst )
|
||||
@@ -1731,7 +1695,7 @@ void NET_Init( void )
|
||||
|
||||
net_clockwindow = Cvar_Get( "clockwindow", "0.5", FCVAR_PRIVILEGED, "timewindow to execute client moves" );
|
||||
net_address = Cvar_Get( "net_address", "0", FCVAR_READ_ONLY, "contain local address of current client" );
|
||||
net_ipname = Cvar_Get( "ip", "localhost", 0, "network ip address" );
|
||||
net_ipname = Cvar_Get( "ip", "localhost", FCVAR_READ_ONLY, "network ip address" );
|
||||
net_iphostport = Cvar_Get( "ip_hostport", "0", FCVAR_READ_ONLY, "network ip host port" );
|
||||
net_hostport = Cvar_Get( "hostport", va( "%i", PORT_SERVER ), FCVAR_READ_ONLY, "network default host port" );
|
||||
net_ipclientport = Cvar_Get( "ip_clientport", "0", FCVAR_READ_ONLY, "network ip client port" );
|
||||
@@ -1792,7 +1756,7 @@ void NET_Shutdown( void )
|
||||
|
||||
NET_ClearLagData( true, true );
|
||||
|
||||
NET_Config( false, false );
|
||||
NET_Config( false );
|
||||
#if XASH_WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
@@ -2316,7 +2280,7 @@ void HTTP_Run( void )
|
||||
}
|
||||
|
||||
// update progress
|
||||
if( !Host_IsDedicated() && iProgressCount != 0 )
|
||||
if( !Host_IsDedicated() )
|
||||
Cvar_SetValue( "scr_download", flProgress/iProgressCount * 100 );
|
||||
|
||||
HTTP_AutoClean();
|
||||
|
||||
@@ -31,9 +31,9 @@ typedef enum
|
||||
|
||||
|
||||
#if !XASH_LOW_MEMORY
|
||||
#define MAX_INIT_MSG 0x30000 // max length of possible message
|
||||
#define MAX_INIT_MSG 0x20000 // max length of possible message
|
||||
#else
|
||||
#define MAX_INIT_MSG 0x8000
|
||||
#define MAX_INIT_MSG 0x8000
|
||||
#endif
|
||||
// net packets type
|
||||
#define NET_HEADER_OUTOFBANDPACKET -1
|
||||
@@ -51,7 +51,7 @@ void NET_Shutdown( void );
|
||||
void NET_Sleep( int msec );
|
||||
qboolean NET_IsActive( void );
|
||||
qboolean NET_IsConfigured( void );
|
||||
void NET_Config( qboolean net_enable, qboolean changeport );
|
||||
void NET_Config( qboolean net_enable );
|
||||
qboolean NET_IsLocalAddress( netadr_t adr );
|
||||
const char *NET_AdrToString( const netadr_t a );
|
||||
const char *NET_BaseAdrToString( const netadr_t a );
|
||||
|
||||
@@ -40,22 +40,6 @@ int PM_TruePointContents( playermove_t *pmove, const vec3_t p );
|
||||
int PM_PointContents( playermove_t *pmove, const vec3_t p );
|
||||
void PM_ConvertTrace( trace_t *out, pmtrace_t *in, edict_t *ent );
|
||||
|
||||
static inline void PM_InitTrace( trace_t *trace, const vec3_t end )
|
||||
{
|
||||
memset( trace, 0, sizeof( *trace ));
|
||||
VectorCopy( end, trace->endpos );
|
||||
trace->allsolid = true;
|
||||
trace->fraction = 1.0f;
|
||||
}
|
||||
|
||||
static inline void PM_InitPMTrace( pmtrace_t *trace, const vec3_t end )
|
||||
{
|
||||
memset( trace, 0, sizeof( *trace ));
|
||||
VectorCopy( end, trace->endpos );
|
||||
trace->allsolid = true;
|
||||
trace->fraction = 1.0f;
|
||||
}
|
||||
|
||||
//
|
||||
// pm_surface.c
|
||||
//
|
||||
|
||||
@@ -446,7 +446,10 @@ pmtrace_t PM_PlayerTraceExt( playermove_t *pmove, vec3_t start, vec3_t end, int
|
||||
VectorSubtract( end, offset, end_l );
|
||||
}
|
||||
|
||||
PM_InitPMTrace( &trace_bbox, end );
|
||||
memset( &trace_bbox, 0, sizeof( trace_bbox ));
|
||||
VectorCopy( end, trace_bbox.endpos );
|
||||
trace_bbox.allsolid = true;
|
||||
trace_bbox.fraction = 1.0f;
|
||||
|
||||
if( hullcount < 1 )
|
||||
{
|
||||
@@ -472,7 +475,10 @@ pmtrace_t PM_PlayerTraceExt( playermove_t *pmove, vec3_t start, vec3_t end, int
|
||||
|
||||
for( last_hitgroup = 0, j = 0; j < hullcount; j++ )
|
||||
{
|
||||
PM_InitPMTrace( &trace_hitbox, end );
|
||||
memset( &trace_hitbox, 0, sizeof( trace_hitbox ));
|
||||
VectorCopy( end, trace_hitbox.endpos );
|
||||
trace_hitbox.allsolid = true;
|
||||
trace_hitbox.fraction = 1.0f;
|
||||
|
||||
PM_RecursiveHullCheck( &hull[j], hull[j].firstclipnode, 0, 1, start_l, end_l, &trace_hitbox );
|
||||
|
||||
@@ -616,7 +622,10 @@ int PM_TestPlayerPosition( playermove_t *pmove, vec3_t pos, pmtrace_t *ptrace, p
|
||||
{
|
||||
pmtrace_t trace;
|
||||
|
||||
PM_InitPMTrace( &trace, pos );
|
||||
memset( &trace, 0, sizeof( trace ));
|
||||
VectorCopy( pos, trace.endpos );
|
||||
trace.allsolid = true;
|
||||
trace.fraction = 1.0f;
|
||||
|
||||
// run custom sweep callback
|
||||
if( pmove->server || Host_IsLocalClient( ))
|
||||
|
||||
@@ -126,7 +126,31 @@ uint GAME_EXPORT Sound_GetApproxWavePlayLen( const char *filepath )
|
||||
return msecs;
|
||||
}
|
||||
|
||||
#define drint( v ) (int)( v + 0.5 )
|
||||
/*
|
||||
================
|
||||
Sound_ConvertToSigned
|
||||
|
||||
Convert unsigned data to signed
|
||||
================
|
||||
*/
|
||||
void Sound_ConvertToSigned( const byte *data, int channels, int samples )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( channels == 2 )
|
||||
{
|
||||
for( i = 0; i < samples; i++ )
|
||||
{
|
||||
((signed char *)sound.tempbuffer)[i*2+0] = (int)((byte)(data[i*2+0]) - 128);
|
||||
((signed char *)sound.tempbuffer)[i*2+1] = (int)((byte)(data[i*2+1]) - 128);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < samples; i++ )
|
||||
((signed char *)sound.tempbuffer)[i] = (int)((unsigned char)(data[i]) - 128);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
@@ -137,15 +161,13 @@ We need convert sound to signed even if nothing to resample
|
||||
*/
|
||||
qboolean Sound_ResampleInternal( wavdata_t *sc, int inrate, int inwidth, int outrate, int outwidth )
|
||||
{
|
||||
double stepscale, j;
|
||||
int outcount;
|
||||
int i;
|
||||
qboolean handled = false;
|
||||
float stepscale;
|
||||
int outcount, srcsample;
|
||||
int i, sample, sample2, samplefrac, fracstep;
|
||||
byte *data;
|
||||
|
||||
if( inrate == outrate && inwidth == outwidth )
|
||||
return false;
|
||||
|
||||
stepscale = (double)inrate / outrate; // this is usually 0.5, 1, or 2
|
||||
data = sc->buffer;
|
||||
stepscale = (float)inrate / outrate; // this is usually 0.5, 1, or 2
|
||||
outcount = sc->samples / stepscale;
|
||||
sc->size = outcount * outwidth * sc->channels;
|
||||
|
||||
@@ -155,112 +177,69 @@ qboolean Sound_ResampleInternal( wavdata_t *sc, int inrate, int inwidth, int out
|
||||
if( sc->loopStart != -1 )
|
||||
sc->loopStart = sc->loopStart / stepscale;
|
||||
|
||||
if( inrate == outrate )
|
||||
// resample / decimate to the current source rate
|
||||
if( stepscale == 1.0f && inwidth == 1 && outwidth == 1 )
|
||||
{
|
||||
if( inwidth == 1 && outwidth == 2 ) // S8 to S16
|
||||
{
|
||||
for( i = 0; i < outcount * sc->channels; i++ )
|
||||
((int16_t*)sound.tempbuffer)[i] = ((int8_t *)sc->buffer)[i] * 256;
|
||||
handled = true;
|
||||
}
|
||||
else if( inwidth == 2 && outwidth == 1 ) // S16 to S8
|
||||
{
|
||||
for( i = 0; i < outcount * sc->channels; i++ )
|
||||
((int8_t*)sound.tempbuffer)[i] = ((int16_t *)sc->buffer)[i] / 256;
|
||||
handled = true;
|
||||
}
|
||||
Sound_ConvertToSigned( data, sc->channels, outcount );
|
||||
}
|
||||
else // resample case
|
||||
{
|
||||
if( inwidth == 1 )
|
||||
{
|
||||
int8_t *data = (int8_t *)sc->buffer;
|
||||
|
||||
if( outwidth == 1 )
|
||||
{
|
||||
if( sc->channels == 2 )
|
||||
{
|
||||
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
|
||||
{
|
||||
((int8_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0];
|
||||
((int8_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
|
||||
((int8_t*)sound.tempbuffer)[i] = data[(int)j];
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
else if( outwidth == 2 )
|
||||
{
|
||||
if( sc->channels == 2 )
|
||||
{
|
||||
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
|
||||
{
|
||||
((int16_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0] * 256;
|
||||
((int16_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1] * 256;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
|
||||
((int16_t*)sound.tempbuffer)[i] = data[(int)j] * 256;
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
else if( inwidth == 2 )
|
||||
{
|
||||
int16_t *data = (int16_t *)sc->buffer;
|
||||
|
||||
if( outwidth == 1 )
|
||||
{
|
||||
if( sc->channels == 2 )
|
||||
{
|
||||
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
|
||||
{
|
||||
((int8_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0] / 256;
|
||||
((int8_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1] / 256;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
|
||||
((int8_t*)sound.tempbuffer)[i] = data[(int)j] / 256;
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
else if( outwidth == 2 )
|
||||
{
|
||||
if( sc->channels == 2 )
|
||||
{
|
||||
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
|
||||
{
|
||||
((int16_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0];
|
||||
((int16_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
|
||||
((int16_t*)sound.tempbuffer)[i] = data[(int)j];
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( handled )
|
||||
Con_Reportf( "Sound_Resample: from [%d bit %d Hz] to [%d bit %d Hz]\n", inwidth * 8, inrate, outwidth * 8, outrate );
|
||||
else
|
||||
Con_Reportf( S_ERROR "Sound_Resample: unsupported from [%d bit %d Hz] to [%d bit %d Hz]\n", inwidth * 8, inrate, outwidth * 8, outrate );
|
||||
{
|
||||
// general case
|
||||
samplefrac = 0;
|
||||
fracstep = stepscale * 256;
|
||||
|
||||
if( sc->channels == 2 )
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
srcsample = samplefrac >> 8;
|
||||
samplefrac += fracstep;
|
||||
|
||||
if( inwidth == 2 )
|
||||
{
|
||||
sample = ((short *)data)[srcsample*2+0];
|
||||
sample2 = ((short *)data)[srcsample*2+1];
|
||||
}
|
||||
else
|
||||
{
|
||||
sample = (int)((char)(data[srcsample*2+0])) << 8;
|
||||
sample2 = (int)((char)(data[srcsample*2+1])) << 8;
|
||||
}
|
||||
|
||||
if( outwidth == 2 )
|
||||
{
|
||||
((short *)sound.tempbuffer)[i*2+0] = sample;
|
||||
((short *)sound.tempbuffer)[i*2+1] = sample2;
|
||||
}
|
||||
else
|
||||
{
|
||||
((signed char *)sound.tempbuffer)[i*2+0] = sample >> 8;
|
||||
((signed char *)sound.tempbuffer)[i*2+1] = sample2 >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < outcount; i++ )
|
||||
{
|
||||
srcsample = samplefrac >> 8;
|
||||
samplefrac += fracstep;
|
||||
|
||||
if( inwidth == 2 ) sample = ((short *)data)[srcsample];
|
||||
else sample = (int)( (char)(data[srcsample])) << 8;
|
||||
|
||||
if( outwidth == 2 ) ((short *)sound.tempbuffer)[i] = sample;
|
||||
else ((signed char *)sound.tempbuffer)[i] = sample >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
Con_Reportf( "Sound_Resample: from[%d bit %d kHz] to [%d bit %d kHz]\n", inwidth * 8, inrate, outwidth * 8, outrate );
|
||||
}
|
||||
|
||||
sc->rate = outrate;
|
||||
sc->width = outwidth;
|
||||
|
||||
return handled;
|
||||
return true;
|
||||
}
|
||||
|
||||
qboolean Sound_Process( wavdata_t **wav, int rate, int width, uint flags )
|
||||
|
||||
@@ -14,23 +14,17 @@ GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#if XASH_WIN32
|
||||
#define STDOUT_FILENO 1
|
||||
#include <io.h>
|
||||
#elif XASH_ANDROID
|
||||
#if XASH_ANDROID
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
// do not waste precious CPU cycles on mobiles or low memory devices
|
||||
#if !XASH_WIN32 && !XASH_MOBILE_PLATFORM && !XASH_LOW_MEMORY
|
||||
#define XASH_COLORIZE_CONSOLE true
|
||||
#if !XASH_WIN32 && !XASH_MOBILE_PLATFORM
|
||||
#define XASH_COLORIZE_CONSOLE
|
||||
// use with caution, running engine in Qt Creator may cause a freeze in read() call
|
||||
// I was never encountered this bug anywhere else, so still enable by default
|
||||
// #define XASH_USE_SELECT 1
|
||||
#else
|
||||
#define XASH_COLORIZE_CONSOLE false
|
||||
#endif
|
||||
|
||||
#if XASH_USE_SELECT
|
||||
@@ -135,18 +129,16 @@ void Sys_InitLog( void )
|
||||
if( s_ld.log_active )
|
||||
{
|
||||
s_ld.logfile = fopen( s_ld.log_path, mode );
|
||||
|
||||
if ( !s_ld.logfile )
|
||||
if( !s_ld.logfile )
|
||||
{
|
||||
Con_Reportf( S_ERROR "Sys_InitLog: can't create log file %s: %s\n", s_ld.log_path, strerror( errno ) );
|
||||
return;
|
||||
}
|
||||
|
||||
s_ld.logfileno = fileno( s_ld.logfile );
|
||||
|
||||
fprintf( s_ld.logfile, "=================================================================================\n" );
|
||||
fprintf( s_ld.logfile, "\t%s (build %i) started at %s\n", s_ld.title, Q_buildnum(), Q_timestamp( TIME_FULL ) );
|
||||
fprintf( s_ld.logfile, "=================================================================================\n" );
|
||||
else
|
||||
{
|
||||
fprintf( s_ld.logfile, "=================================================================================\n" );
|
||||
fprintf( s_ld.logfile, "\t%s (build %i) started at %s\n", s_ld.title, Q_buildnum(), Q_timestamp( TIME_FULL ));
|
||||
fprintf( s_ld.logfile, "=================================================================================\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,92 +176,53 @@ void Sys_CloseLog( void )
|
||||
}
|
||||
}
|
||||
|
||||
#if XASH_COLORIZE_CONSOLE == true
|
||||
static void Sys_WriteEscapeSequenceForColorcode( int fd, int c )
|
||||
static void Sys_PrintColorized( const char *logtime, const char *msg )
|
||||
{
|
||||
static const char *q3ToAnsi[ 8 ] =
|
||||
char colored[4096];
|
||||
int len = 0;
|
||||
|
||||
while( *msg && ( len < 4090 ) )
|
||||
{
|
||||
"\033[30m", // COLOR_BLACK
|
||||
"\033[31m", // COLOR_RED
|
||||
"\033[32m", // COLOR_GREEN
|
||||
"\033[33m", // COLOR_YELLOW
|
||||
"\033[34m", // COLOR_BLUE
|
||||
"\033[36m", // COLOR_CYAN
|
||||
"\033[35m", // COLOR_MAGENTA
|
||||
"\033[0m", // COLOR_WHITE
|
||||
};
|
||||
const char *esc = q3ToAnsi[c];
|
||||
|
||||
if( c == 7 )
|
||||
write( fd, esc, 4 );
|
||||
else write( fd, esc, 5 );
|
||||
}
|
||||
#else
|
||||
static void Sys_WriteEscapeSequenceForColorcode( int fd, int c ) {}
|
||||
#endif
|
||||
|
||||
static void Sys_PrintLogfile( const int fd, const char *logtime, const char *msg, const qboolean colorize )
|
||||
{
|
||||
const char *p = msg;
|
||||
|
||||
write( fd, logtime, Q_strlen( logtime ) );
|
||||
|
||||
while( p && *p )
|
||||
{
|
||||
p = Q_strchr( msg, '^' );
|
||||
|
||||
if( p == NULL )
|
||||
static char q3ToAnsi[ 8 ] =
|
||||
{
|
||||
write( fd, msg, Q_strlen( msg ));
|
||||
break;
|
||||
}
|
||||
else if( IsColorString( p ))
|
||||
{
|
||||
if( p != msg )
|
||||
write( fd, msg, p - msg );
|
||||
msg = p + 2;
|
||||
'0', // COLOR_BLACK
|
||||
'1', // COLOR_RED
|
||||
'2', // COLOR_GREEN
|
||||
'3', // COLOR_YELLOW
|
||||
'4', // COLOR_BLUE
|
||||
'6', // COLOR_CYAN
|
||||
'5', // COLOR_MAGENTA
|
||||
0 // COLOR_WHITE
|
||||
};
|
||||
|
||||
if( colorize )
|
||||
Sys_WriteEscapeSequenceForColorcode( fd, ColorIndex( p[1] ));
|
||||
if( IsColorString( msg ) )
|
||||
{
|
||||
int color;
|
||||
|
||||
msg++;
|
||||
color = q3ToAnsi[ *msg++ % 8 ];
|
||||
colored[len++] = '\033';
|
||||
colored[len++] = '[';
|
||||
if( color )
|
||||
{
|
||||
colored[len++] = '3';
|
||||
colored[len++] = color;
|
||||
}
|
||||
else
|
||||
colored[len++] = '0';
|
||||
colored[len++] = 'm';
|
||||
}
|
||||
else
|
||||
{
|
||||
write( fd, msg, p - msg + 1 );
|
||||
msg = p + 1;
|
||||
}
|
||||
colored[len++] = *msg++;
|
||||
}
|
||||
colored[len] = 0;
|
||||
|
||||
// flush the color
|
||||
if( colorize )
|
||||
Sys_WriteEscapeSequenceForColorcode( fd, 7 );
|
||||
}
|
||||
|
||||
static void Sys_PrintStdout( const char *logtime, const char *msg )
|
||||
{
|
||||
#if XASH_MOBILE_PLATFORM
|
||||
static char buf[MAX_PRINT_MSG];
|
||||
|
||||
// strip color codes
|
||||
COM_StripColors( msg, buf );
|
||||
|
||||
// platform-specific output
|
||||
#if XASH_ANDROID && !XASH_DEDICATED
|
||||
__android_log_write( ANDROID_LOG_DEBUG, "Xash", buf );
|
||||
#endif // XASH_ANDROID && !XASH_DEDICATED
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
void IOS_Log( const char * );
|
||||
IOS_Log( buf );
|
||||
#endif // TARGET_OS_IOS
|
||||
#elif !XASH_WIN32 // Wcon does the job
|
||||
Sys_PrintLogfile( STDOUT_FILENO, logtime, msg, XASH_COLORIZE_CONSOLE );
|
||||
Sys_FlushStdout();
|
||||
#endif
|
||||
printf( "\033[34m%s\033[0m%s\033[0m", logtime, colored );
|
||||
}
|
||||
|
||||
void Sys_PrintLog( const char *pMsg )
|
||||
{
|
||||
time_t crt_time;
|
||||
time_t crt_time;
|
||||
const struct tm *crt_tm;
|
||||
char logtime[32] = "";
|
||||
static char lastchar;
|
||||
@@ -277,26 +230,39 @@ void Sys_PrintLog( const char *pMsg )
|
||||
time( &crt_time );
|
||||
crt_tm = localtime( &crt_time );
|
||||
|
||||
// platform-specific output
|
||||
#if XASH_ANDROID && !XASH_DEDICATED
|
||||
__android_log_print( ANDROID_LOG_DEBUG, "Xash", "%s", pMsg );
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
void IOS_Log(const char*);
|
||||
IOS_Log(pMsg);
|
||||
#endif
|
||||
|
||||
if( !lastchar || lastchar == '\n')
|
||||
strftime( logtime, sizeof( logtime ), "[%H:%M:%S] ", crt_tm ); //short time
|
||||
|
||||
// spew to stdout
|
||||
Sys_PrintStdout( logtime, pMsg );
|
||||
// spew to stdout, except mobiles
|
||||
#if !XASH_MOBILE_PLATFORM
|
||||
#ifdef XASH_COLORIZE_CONSOLE
|
||||
Sys_PrintColorized( logtime, pMsg );
|
||||
#else
|
||||
printf( "%s %s", logtime, pMsg );
|
||||
#endif
|
||||
Sys_FlushStdout();
|
||||
#endif
|
||||
|
||||
// save last char to detect when line was not ended
|
||||
lastchar = pMsg[strlen(pMsg)-1];
|
||||
|
||||
if( !s_ld.logfile )
|
||||
{
|
||||
// save last char to detect when line was not ended
|
||||
lastchar = pMsg[Q_strlen( pMsg ) - 1];
|
||||
return;
|
||||
}
|
||||
|
||||
if( !lastchar || lastchar == '\n')
|
||||
strftime( logtime, sizeof( logtime ), "[%Y:%m:%d|%H:%M:%S] ", crt_tm ); //full time
|
||||
|
||||
// save last char to detect when line was not ended
|
||||
lastchar = pMsg[Q_strlen( pMsg ) - 1];
|
||||
strftime( logtime, sizeof( logtime ), "[%Y:%m:%d|%H:%M:%S]", crt_tm ); //full time
|
||||
|
||||
Sys_PrintLogfile( s_ld.logfileno, logtime, pMsg, false );
|
||||
fprintf( s_ld.logfile, "%s %s", logtime, pMsg );
|
||||
Sys_FlushLogfile();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ GNU General Public License for more details.
|
||||
#include "xash3d_mathlib.h"
|
||||
#include "platform/platform.h"
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef XASH_SDL
|
||||
#include <SDL.h>
|
||||
@@ -33,14 +32,9 @@ GNU General Public License for more details.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if XASH_WIN32
|
||||
#include <process.h>
|
||||
#endif
|
||||
|
||||
#include "menu_int.h" // _UPDATE_PAGE macro
|
||||
|
||||
#include "library.h"
|
||||
#include "whereami.h"
|
||||
|
||||
qboolean error_on_exit = false; // arg for exit();
|
||||
#define DEBUG_BREAK
|
||||
@@ -421,12 +415,9 @@ void Sys_Error( const char *error, ... )
|
||||
#if XASH_SDL == 2
|
||||
if( host.hWnd ) SDL_HideWindow( host.hWnd );
|
||||
#endif
|
||||
#if XASH_WIN32
|
||||
Wcon_ShowConsole( false );
|
||||
#endif
|
||||
MSGBOX( text );
|
||||
}
|
||||
else
|
||||
|
||||
if( host_developer.value )
|
||||
{
|
||||
#if XASH_WIN32
|
||||
Wcon_ShowConsole( true );
|
||||
@@ -435,7 +426,14 @@ void Sys_Error( const char *error, ... )
|
||||
Sys_Print( text ); // print error message
|
||||
Sys_WaitForQuit();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
#if XASH_WIN32
|
||||
Wcon_ShowConsole( false );
|
||||
#endif
|
||||
MSGBOX( text );
|
||||
}
|
||||
|
||||
Sys_Quit();
|
||||
}
|
||||
|
||||
@@ -541,67 +539,3 @@ void Sys_Print( const char *pMsg )
|
||||
|
||||
Rcon_Print( pMsg );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Sys_ChangeGame
|
||||
|
||||
This is a special function
|
||||
|
||||
Here we restart engine with new -game parameter
|
||||
but since engine will be unloaded during this call
|
||||
it explicitly doesn't use internal allocation or string copy utils
|
||||
==================
|
||||
*/
|
||||
qboolean Sys_NewInstance( const char *gamedir )
|
||||
{
|
||||
int i = 0;
|
||||
qboolean replacedArg = false;
|
||||
size_t exelen;
|
||||
char *exe, **newargs;
|
||||
|
||||
// don't use engine allocation utils here
|
||||
// they will be freed after Host_Shutdown
|
||||
newargs = calloc( host.argc + 4, sizeof( *newargs ));
|
||||
while( i < host.argc )
|
||||
{
|
||||
newargs[i] = strdup( host.argv[i] );
|
||||
|
||||
// replace existing -game argument
|
||||
if( !Q_stricmp( newargs[i], "-game" ))
|
||||
{
|
||||
newargs[i + 1] = strdup( gamedir );
|
||||
replacedArg = true;
|
||||
i += 2;
|
||||
}
|
||||
else i++;
|
||||
}
|
||||
|
||||
if( !replacedArg )
|
||||
{
|
||||
newargs[i++] = strdup( "-game" );
|
||||
newargs[i++] = strdup( gamedir );
|
||||
}
|
||||
|
||||
newargs[i++] = strdup( "-changegame" );
|
||||
newargs[i] = NULL;
|
||||
|
||||
exelen = wai_getExecutablePath( NULL, 0, NULL );
|
||||
exe = malloc( exelen + 1 );
|
||||
wai_getExecutablePath( exe, exelen, NULL );
|
||||
exe[exelen] = 0;
|
||||
|
||||
Host_Shutdown();
|
||||
|
||||
execv( exe, newargs );
|
||||
|
||||
// if execv returned, it's probably an error
|
||||
printf( "execv failed: %s", strerror( errno ));
|
||||
|
||||
for( ; i >= 0; i-- )
|
||||
free( newargs[i] );
|
||||
free( newargs );
|
||||
free( exe );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ char *Sys_GetClipboardData( void );
|
||||
const char *Sys_GetCurrentUser( void );
|
||||
int Sys_CheckParm( const char *parm );
|
||||
void Sys_Warn( const char *format, ... ) _format( 1 );
|
||||
void Sys_Error( const char *error, ... ) _format( 1 );
|
||||
void Sys_Error( const char *error, ... ) _format( 1 ) NORETURN;
|
||||
qboolean Sys_LoadLibrary( dll_info_t *dll );
|
||||
void* Sys_GetProcAddress( dll_info_t *dll, const char* name );
|
||||
qboolean Sys_FreeLibrary( dll_info_t *dll );
|
||||
@@ -68,7 +68,6 @@ void Sys_PrintLog( const char *pMsg );
|
||||
void Sys_InitLog( void );
|
||||
void Sys_CloseLog( void );
|
||||
void Sys_Quit( void ) NORETURN;
|
||||
qboolean Sys_NewInstance( const char *gamedir );
|
||||
|
||||
//
|
||||
// sys_con.c
|
||||
|
||||
@@ -1,806 +0,0 @@
|
||||
// (‑●‑●)> dual licensed under the WTFPL v2 and MIT licenses
|
||||
// without any warranty.
|
||||
// by Gregory Pakosz (@gpakosz)
|
||||
// https://github.com/gpakosz/whereami
|
||||
|
||||
// in case you want to #include "whereami.c" in a larger compilation unit
|
||||
#if !defined(WHEREAMI_H)
|
||||
#include <whereami.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__CYGWIN__)
|
||||
#undef _DEFAULT_SOURCE
|
||||
#define _DEFAULT_SOURCE
|
||||
#elif defined(__APPLE__)
|
||||
#undef _DARWIN_C_SOURCE
|
||||
#define _DARWIN_C_SOURCE
|
||||
#define _DARWIN_BETTER_REALPATH
|
||||
#endif
|
||||
|
||||
#if !defined(WAI_MALLOC) || !defined(WAI_FREE) || !defined(WAI_REALLOC)
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#if !defined(WAI_MALLOC)
|
||||
#define WAI_MALLOC(size) malloc(size)
|
||||
#endif
|
||||
|
||||
#if !defined(WAI_FREE)
|
||||
#define WAI_FREE(p) free(p)
|
||||
#endif
|
||||
|
||||
#if !defined(WAI_REALLOC)
|
||||
#define WAI_REALLOC(p, size) realloc(p, size)
|
||||
#endif
|
||||
|
||||
#ifndef WAI_NOINLINE
|
||||
#if defined(_MSC_VER)
|
||||
#define WAI_NOINLINE __declspec(noinline)
|
||||
#elif defined(__GNUC__)
|
||||
#define WAI_NOINLINE __attribute__((noinline))
|
||||
#else
|
||||
#error unsupported compiler
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define WAI_RETURN_ADDRESS() _ReturnAddress()
|
||||
#elif defined(__GNUC__)
|
||||
#define WAI_RETURN_ADDRESS() __builtin_extract_return_addr(__builtin_return_address(0))
|
||||
#else
|
||||
#error unsupported compiler
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push, 3)
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <intrin.h>
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
|
||||
static int WAI_PREFIX(getModulePath_)(HMODULE module, char* out, int capacity, int* dirname_length)
|
||||
{
|
||||
wchar_t buffer1[MAX_PATH];
|
||||
wchar_t buffer2[MAX_PATH];
|
||||
wchar_t* path = NULL;
|
||||
int length = -1;
|
||||
bool ok;
|
||||
|
||||
for (ok = false; !ok; ok = true)
|
||||
{
|
||||
DWORD size;
|
||||
int length_, length__;
|
||||
|
||||
size = GetModuleFileNameW(module, buffer1, sizeof(buffer1) / sizeof(buffer1[0]));
|
||||
|
||||
if (size == 0)
|
||||
break;
|
||||
else if (size == (DWORD)(sizeof(buffer1) / sizeof(buffer1[0])))
|
||||
{
|
||||
DWORD size_ = size;
|
||||
do
|
||||
{
|
||||
wchar_t* path_;
|
||||
|
||||
path_ = (wchar_t*)WAI_REALLOC(path, sizeof(wchar_t) * size_ * 2);
|
||||
if (!path_)
|
||||
break;
|
||||
size_ *= 2;
|
||||
path = path_;
|
||||
size = GetModuleFileNameW(module, path, size_);
|
||||
}
|
||||
while (size == size_);
|
||||
|
||||
if (size == size_)
|
||||
break;
|
||||
}
|
||||
else
|
||||
path = buffer1;
|
||||
|
||||
if (!_wfullpath(buffer2, path, MAX_PATH))
|
||||
break;
|
||||
length_ = (int)wcslen(buffer2);
|
||||
length__ = WideCharToMultiByte(CP_UTF8, 0, buffer2, length_ , out, capacity, NULL, NULL);
|
||||
|
||||
if (length__ == 0)
|
||||
length__ = WideCharToMultiByte(CP_UTF8, 0, buffer2, length_, NULL, 0, NULL, NULL);
|
||||
if (length__ == 0)
|
||||
break;
|
||||
|
||||
if (length__ <= capacity && dirname_length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = length__ - 1; i >= 0; --i)
|
||||
{
|
||||
if (out[i] == '\\')
|
||||
{
|
||||
*dirname_length = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
length = length__;
|
||||
}
|
||||
|
||||
if (path != buffer1)
|
||||
WAI_FREE(path);
|
||||
|
||||
return ok ? length : -1;
|
||||
}
|
||||
|
||||
WAI_NOINLINE WAI_FUNCSPEC
|
||||
int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
|
||||
{
|
||||
return WAI_PREFIX(getModulePath_)(NULL, out, capacity, dirname_length);
|
||||
}
|
||||
|
||||
WAI_NOINLINE WAI_FUNCSPEC
|
||||
int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
|
||||
{
|
||||
HMODULE module;
|
||||
int length = -1;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4054)
|
||||
#endif
|
||||
if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)WAI_RETURN_ADDRESS(), &module))
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
{
|
||||
length = WAI_PREFIX(getModulePath_)(module, out, capacity, dirname_length);
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
#elif defined(__linux__) || defined(__CYGWIN__) || defined(__sun) || defined(WAI_USE_PROC_SELF_EXE)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#if defined(__linux__)
|
||||
#include <linux/limits.h>
|
||||
#else
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#endif
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if !defined(WAI_PROC_SELF_EXE)
|
||||
#if defined(__sun)
|
||||
#define WAI_PROC_SELF_EXE "/proc/self/path/a.out"
|
||||
#else
|
||||
#define WAI_PROC_SELF_EXE "/proc/self/exe"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
WAI_FUNCSPEC
|
||||
int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
|
||||
{
|
||||
char buffer[PATH_MAX];
|
||||
char* resolved = NULL;
|
||||
int length = -1;
|
||||
bool ok;
|
||||
|
||||
for (ok = false; !ok; ok = true)
|
||||
{
|
||||
resolved = realpath(WAI_PROC_SELF_EXE, buffer);
|
||||
if (!resolved)
|
||||
break;
|
||||
|
||||
length = (int)strlen(resolved);
|
||||
if (length <= capacity)
|
||||
{
|
||||
memcpy(out, resolved, length);
|
||||
|
||||
if (dirname_length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = length - 1; i >= 0; --i)
|
||||
{
|
||||
if (out[i] == '/')
|
||||
{
|
||||
*dirname_length = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ok ? length : -1;
|
||||
}
|
||||
|
||||
#if !defined(WAI_PROC_SELF_MAPS_RETRY)
|
||||
#define WAI_PROC_SELF_MAPS_RETRY 5
|
||||
#endif
|
||||
|
||||
#if !defined(WAI_PROC_SELF_MAPS)
|
||||
#if defined(__sun)
|
||||
#define WAI_PROC_SELF_MAPS "/proc/self/map"
|
||||
#else
|
||||
#define WAI_PROC_SELF_MAPS "/proc/self/maps"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__) || defined(ANDROID)
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
|
||||
WAI_NOINLINE WAI_FUNCSPEC
|
||||
int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
|
||||
{
|
||||
int length = -1;
|
||||
FILE* maps = NULL;
|
||||
int r;
|
||||
|
||||
for (r = 0; r < WAI_PROC_SELF_MAPS_RETRY; ++r)
|
||||
{
|
||||
maps = fopen(WAI_PROC_SELF_MAPS, "r");
|
||||
if (!maps)
|
||||
break;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char buffer[PATH_MAX < 1024 ? 1024 : PATH_MAX];
|
||||
uint64_t low, high;
|
||||
char perms[5];
|
||||
uint64_t offset;
|
||||
uint32_t major, minor;
|
||||
char path[PATH_MAX];
|
||||
uint32_t inode;
|
||||
|
||||
if (!fgets(buffer, sizeof(buffer), maps))
|
||||
break;
|
||||
|
||||
if (sscanf(buffer, "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " %x:%x %u %s\n", &low, &high, perms, &offset, &major, &minor, &inode, path) == 8)
|
||||
{
|
||||
uint64_t addr = (uintptr_t)WAI_RETURN_ADDRESS();
|
||||
if (low <= addr && addr <= high)
|
||||
{
|
||||
char* resolved;
|
||||
|
||||
resolved = realpath(path, buffer);
|
||||
if (!resolved)
|
||||
break;
|
||||
|
||||
length = (int)strlen(resolved);
|
||||
#if defined(__ANDROID__) || defined(ANDROID)
|
||||
if (length > 4
|
||||
&&buffer[length - 1] == 'k'
|
||||
&&buffer[length - 2] == 'p'
|
||||
&&buffer[length - 3] == 'a'
|
||||
&&buffer[length - 4] == '.')
|
||||
{
|
||||
char *begin, *p;
|
||||
int fd = open(path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
{
|
||||
length = -1; // retry
|
||||
break;
|
||||
}
|
||||
|
||||
begin = (char*)mmap(0, offset, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (begin == MAP_FAILED)
|
||||
{
|
||||
close(fd);
|
||||
length = -1; // retry
|
||||
break;
|
||||
}
|
||||
|
||||
p = begin + offset - 30; // minimum size of local file header
|
||||
while (p >= begin) // scan backwards
|
||||
{
|
||||
if (*((uint32_t*)p) == 0x04034b50UL) // local file header signature found
|
||||
{
|
||||
uint16_t length_ = *((uint16_t*)(p + 26));
|
||||
|
||||
if (length + 2 + length_ < (int)sizeof(buffer))
|
||||
{
|
||||
memcpy(&buffer[length], "!/", 2);
|
||||
memcpy(&buffer[length + 2], p + 30, length_);
|
||||
length += 2 + length_;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
--p;
|
||||
}
|
||||
|
||||
munmap(begin, offset);
|
||||
close(fd);
|
||||
}
|
||||
#endif
|
||||
if (length <= capacity)
|
||||
{
|
||||
memcpy(out, resolved, length);
|
||||
|
||||
if (dirname_length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = length - 1; i >= 0; --i)
|
||||
{
|
||||
if (out[i] == '/')
|
||||
{
|
||||
*dirname_length = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(maps);
|
||||
maps = NULL;
|
||||
|
||||
if (length != -1)
|
||||
break;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
#include <mach-o/dyld.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
WAI_FUNCSPEC
|
||||
int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
|
||||
{
|
||||
char buffer1[PATH_MAX];
|
||||
char buffer2[PATH_MAX];
|
||||
char* path = buffer1;
|
||||
char* resolved = NULL;
|
||||
int length = -1;
|
||||
bool ok;
|
||||
|
||||
for (ok = false; !ok; ok = true)
|
||||
{
|
||||
uint32_t size = (uint32_t)sizeof(buffer1);
|
||||
if (_NSGetExecutablePath(path, &size) == -1)
|
||||
{
|
||||
path = (char*)WAI_MALLOC(size);
|
||||
if (!_NSGetExecutablePath(path, &size))
|
||||
break;
|
||||
}
|
||||
|
||||
resolved = realpath(path, buffer2);
|
||||
if (!resolved)
|
||||
break;
|
||||
|
||||
length = (int)strlen(resolved);
|
||||
if (length <= capacity)
|
||||
{
|
||||
memcpy(out, resolved, length);
|
||||
|
||||
if (dirname_length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = length - 1; i >= 0; --i)
|
||||
{
|
||||
if (out[i] == '/')
|
||||
{
|
||||
*dirname_length = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (path != buffer1)
|
||||
WAI_FREE(path);
|
||||
|
||||
return ok ? length : -1;
|
||||
}
|
||||
|
||||
WAI_NOINLINE WAI_FUNCSPEC
|
||||
int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
|
||||
{
|
||||
char buffer[PATH_MAX];
|
||||
char* resolved = NULL;
|
||||
int length = -1;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
Dl_info info;
|
||||
|
||||
if (dladdr(WAI_RETURN_ADDRESS(), &info))
|
||||
{
|
||||
resolved = realpath(info.dli_fname, buffer);
|
||||
if (!resolved)
|
||||
break;
|
||||
|
||||
length = (int)strlen(resolved);
|
||||
if (length <= capacity)
|
||||
{
|
||||
memcpy(out, resolved, length);
|
||||
|
||||
if (dirname_length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = length - 1; i >= 0; --i)
|
||||
{
|
||||
if (out[i] == '/')
|
||||
{
|
||||
*dirname_length = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
#elif defined(__QNXNTO__)
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if !defined(WAI_PROC_SELF_EXE)
|
||||
#define WAI_PROC_SELF_EXE "/proc/self/exefile"
|
||||
#endif
|
||||
|
||||
WAI_FUNCSPEC
|
||||
int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
|
||||
{
|
||||
char buffer1[PATH_MAX];
|
||||
char buffer2[PATH_MAX];
|
||||
char* resolved = NULL;
|
||||
FILE* self_exe = NULL;
|
||||
int length = -1;
|
||||
bool ok;
|
||||
|
||||
for (ok = false; !ok; ok = true)
|
||||
{
|
||||
self_exe = fopen(WAI_PROC_SELF_EXE, "r");
|
||||
if (!self_exe)
|
||||
break;
|
||||
|
||||
if (!fgets(buffer1, sizeof(buffer1), self_exe))
|
||||
break;
|
||||
|
||||
resolved = realpath(buffer1, buffer2);
|
||||
if (!resolved)
|
||||
break;
|
||||
|
||||
length = (int)strlen(resolved);
|
||||
if (length <= capacity)
|
||||
{
|
||||
memcpy(out, resolved, length);
|
||||
|
||||
if (dirname_length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = length - 1; i >= 0; --i)
|
||||
{
|
||||
if (out[i] == '/')
|
||||
{
|
||||
*dirname_length = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(self_exe);
|
||||
|
||||
return ok ? length : -1;
|
||||
}
|
||||
|
||||
WAI_FUNCSPEC
|
||||
int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
|
||||
{
|
||||
char buffer[PATH_MAX];
|
||||
char* resolved = NULL;
|
||||
int length = -1;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
Dl_info info;
|
||||
|
||||
if (dladdr(WAI_RETURN_ADDRESS(), &info))
|
||||
{
|
||||
resolved = realpath(info.dli_fname, buffer);
|
||||
if (!resolved)
|
||||
break;
|
||||
|
||||
length = (int)strlen(resolved);
|
||||
if (length <= capacity)
|
||||
{
|
||||
memcpy(out, resolved, length);
|
||||
|
||||
if (dirname_length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = length - 1; i >= 0; --i)
|
||||
{
|
||||
if (out[i] == '/')
|
||||
{
|
||||
*dirname_length = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
#elif defined(__DragonFly__) || defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if defined(__OpenBSD__)
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
WAI_FUNCSPEC
|
||||
int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
|
||||
{
|
||||
char buffer1[4096];
|
||||
char buffer2[PATH_MAX];
|
||||
char buffer3[PATH_MAX];
|
||||
char** argv = (char**)buffer1;
|
||||
char* resolved = NULL;
|
||||
int length = -1;
|
||||
bool ok;
|
||||
|
||||
for (ok = false; !ok; ok = true)
|
||||
{
|
||||
int mib[4] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV };
|
||||
size_t size;
|
||||
|
||||
if (sysctl(mib, 4, NULL, &size, NULL, 0) != 0)
|
||||
break;
|
||||
|
||||
if (size > sizeof(buffer1))
|
||||
{
|
||||
argv = (char**)WAI_MALLOC(size);
|
||||
if (!argv)
|
||||
break;
|
||||
}
|
||||
|
||||
if (sysctl(mib, 4, argv, &size, NULL, 0) != 0)
|
||||
break;
|
||||
|
||||
if (strchr(argv[0], '/'))
|
||||
{
|
||||
resolved = realpath(argv[0], buffer2);
|
||||
if (!resolved)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* PATH = getenv("PATH");
|
||||
if (!PATH)
|
||||
break;
|
||||
|
||||
size_t argv0_length = strlen(argv[0]);
|
||||
|
||||
const char* begin = PATH;
|
||||
while (1)
|
||||
{
|
||||
const char* separator = strchr(begin, ':');
|
||||
const char* end = separator ? separator : begin + strlen(begin);
|
||||
|
||||
if (end - begin > 0)
|
||||
{
|
||||
if (*(end -1) == '/')
|
||||
--end;
|
||||
|
||||
if (((end - begin) + 1 + argv0_length + 1) <= sizeof(buffer2))
|
||||
{
|
||||
memcpy(buffer2, begin, end - begin);
|
||||
buffer2[end - begin] = '/';
|
||||
memcpy(buffer2 + (end - begin) + 1, argv[0], argv0_length + 1);
|
||||
|
||||
resolved = realpath(buffer2, buffer3);
|
||||
if (resolved)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!separator)
|
||||
break;
|
||||
|
||||
begin = ++separator;
|
||||
}
|
||||
|
||||
if (!resolved)
|
||||
break;
|
||||
}
|
||||
|
||||
length = (int)strlen(resolved);
|
||||
if (length <= capacity)
|
||||
{
|
||||
memcpy(out, resolved, length);
|
||||
|
||||
if (dirname_length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = length - 1; i >= 0; --i)
|
||||
{
|
||||
if (out[i] == '/')
|
||||
{
|
||||
*dirname_length = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (argv != (char**)buffer1)
|
||||
WAI_FREE(argv);
|
||||
|
||||
return ok ? length : -1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
WAI_FUNCSPEC
|
||||
int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
|
||||
{
|
||||
char buffer1[PATH_MAX];
|
||||
char buffer2[PATH_MAX];
|
||||
char* path = buffer1;
|
||||
char* resolved = NULL;
|
||||
int length = -1;
|
||||
bool ok;
|
||||
|
||||
for (ok = false; !ok; ok = true)
|
||||
{
|
||||
#if defined(__NetBSD__)
|
||||
int mib[4] = { CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME };
|
||||
#else
|
||||
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
|
||||
#endif
|
||||
size_t size = sizeof(buffer1);
|
||||
|
||||
if (sysctl(mib, 4, path, &size, NULL, 0) != 0)
|
||||
break;
|
||||
|
||||
resolved = realpath(path, buffer2);
|
||||
if (!resolved)
|
||||
break;
|
||||
|
||||
length = (int)strlen(resolved);
|
||||
if (length <= capacity)
|
||||
{
|
||||
memcpy(out, resolved, length);
|
||||
|
||||
if (dirname_length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = length - 1; i >= 0; --i)
|
||||
{
|
||||
if (out[i] == '/')
|
||||
{
|
||||
*dirname_length = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ok ? length : -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
WAI_NOINLINE WAI_FUNCSPEC
|
||||
int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
|
||||
{
|
||||
char buffer[PATH_MAX];
|
||||
char* resolved = NULL;
|
||||
int length = -1;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
Dl_info info;
|
||||
|
||||
if (dladdr(WAI_RETURN_ADDRESS(), &info))
|
||||
{
|
||||
resolved = realpath(info.dli_fname, buffer);
|
||||
if (!resolved)
|
||||
break;
|
||||
|
||||
length = (int)strlen(resolved);
|
||||
if (length <= capacity)
|
||||
{
|
||||
memcpy(out, resolved, length);
|
||||
|
||||
if (dirname_length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = length - 1; i >= 0; --i)
|
||||
{
|
||||
if (out[i] == '/')
|
||||
{
|
||||
*dirname_length = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error unsupported platform
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,67 +0,0 @@
|
||||
// (‑●‑●)> dual licensed under the WTFPL v2 and MIT licenses
|
||||
// without any warranty.
|
||||
// by Gregory Pakosz (@gpakosz)
|
||||
// https://github.com/gpakosz/whereami
|
||||
|
||||
#ifndef WHEREAMI_H
|
||||
#define WHEREAMI_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef WAI_FUNCSPEC
|
||||
#define WAI_FUNCSPEC
|
||||
#endif
|
||||
#ifndef WAI_PREFIX
|
||||
#define WAI_PREFIX(function) wai_##function
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the path to the current executable.
|
||||
*
|
||||
* Usage:
|
||||
* - first call `int length = wai_getExecutablePath(NULL, 0, NULL);` to
|
||||
* retrieve the length of the path
|
||||
* - allocate the destination buffer with `path = (char*)malloc(length + 1);`
|
||||
* - call `wai_getExecutablePath(path, length, NULL)` again to retrieve the
|
||||
* path
|
||||
* - add a terminal NUL character with `path[length] = '\0';`
|
||||
*
|
||||
* @param out destination buffer, optional
|
||||
* @param capacity destination buffer capacity
|
||||
* @param dirname_length optional recipient for the length of the dirname part
|
||||
* of the path.
|
||||
*
|
||||
* @return the length of the executable path on success (without a terminal NUL
|
||||
* character), otherwise `-1`
|
||||
*/
|
||||
WAI_FUNCSPEC
|
||||
int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length);
|
||||
|
||||
/**
|
||||
* Returns the path to the current module
|
||||
*
|
||||
* Usage:
|
||||
* - first call `int length = wai_getModulePath(NULL, 0, NULL);` to retrieve
|
||||
* the length of the path
|
||||
* - allocate the destination buffer with `path = (char*)malloc(length + 1);`
|
||||
* - call `wai_getModulePath(path, length, NULL)` again to retrieve the path
|
||||
* - add a terminal NUL character with `path[length] = '\0';`
|
||||
*
|
||||
* @param out destination buffer, optional
|
||||
* @param capacity destination buffer capacity
|
||||
* @param dirname_length optional recipient for the length of the dirname part
|
||||
* of the path.
|
||||
*
|
||||
* @return the length of the module path on success (without a terminal NUL
|
||||
* character), otherwise `-1`
|
||||
*/
|
||||
WAI_FUNCSPEC
|
||||
int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // #ifndef WHEREAMI_H
|
||||
@@ -91,8 +91,8 @@ void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char
|
||||
pool->totalsize += size;
|
||||
|
||||
// big allocations are not clumped
|
||||
pool->realsize += sizeof( memheader_t ) + size + sizeof( size_t );
|
||||
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( size_t ));
|
||||
pool->realsize += sizeof( memheader_t ) + size + sizeof( int );
|
||||
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( int ));
|
||||
if( mem == NULL ) Sys_Error( "Mem_Alloc: out of memory (alloc at %s:%i)\n", filename, fileline );
|
||||
|
||||
mem->filename = filename;
|
||||
@@ -162,7 +162,7 @@ static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline
|
||||
// memheader has been unlinked, do the actual free now
|
||||
pool->totalsize -= mem->size;
|
||||
|
||||
pool->realsize -= sizeof( memheader_t ) + mem->size + sizeof( size_t );
|
||||
pool->realsize -= sizeof( memheader_t ) + mem->size + sizeof( int );
|
||||
Q_free( mem );
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ typedef int HIMAGE; // handle to a graphic
|
||||
#define PIC_NEAREST (1<<0) // disable texfilter
|
||||
#define PIC_KEEP_SOURCE (1<<1) // some images keep source
|
||||
#define PIC_NOFLIP_TGA (1<<2) // Steam background completely ignore tga attribute 0x20
|
||||
#define PIC_EXPAND_SOURCE (1<<3) // don't keep as 8-bit source, expand to RGBA
|
||||
|
||||
// flags for COM_ParseFileSafe
|
||||
#define PFILE_IGNOREBRACKET (1<<0)
|
||||
@@ -54,6 +53,11 @@ typedef struct ui_globalvars_s
|
||||
|
||||
struct ref_viewpass_s;
|
||||
|
||||
#if __GNUC__ == 3
|
||||
#undef NORETURN
|
||||
#define NORETURN
|
||||
#endif // GCC 3.x have problems with noreturn attribute on function pointer
|
||||
|
||||
typedef struct ui_enginefuncs_s
|
||||
{
|
||||
// image handlers
|
||||
@@ -117,7 +121,7 @@ typedef struct ui_enginefuncs_s
|
||||
int (*CL_CreateVisibleEntity)( int type, struct cl_entity_s *ent );
|
||||
|
||||
// misc handlers
|
||||
void (*pfnHostError)( const char *szFmt, ... ) _format( 1 );
|
||||
void (*pfnHostError)( const char *szFmt, ... ) _format( 1 ) NORETURN;
|
||||
int (*pfnFileExists)( const char *filename, int gamedironly );
|
||||
void (*pfnGetGameDir)( char *szGetGameDir );
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ qboolean SNDDMA_Init( void )
|
||||
}
|
||||
|
||||
Msg( "OpenSL ES audio initialized.\n" );
|
||||
dma.backendName = "OpenSL ES";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -254,24 +254,4 @@ void SNDDMA_BeginPainting( void )
|
||||
{
|
||||
pthread_mutex_lock( &snddma_android_mutex );
|
||||
}
|
||||
|
||||
qboolean VoiceCapture_Init( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean VoiceCapture_Activate( qboolean activate )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean VoiceCapture_Lock( qboolean lock )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void VoiceCapture_Shutdown( void )
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -185,12 +185,12 @@ qboolean SNDDMA_Init( void )
|
||||
}
|
||||
|
||||
dma.buffer = Z_Malloc( samples * 2 ); //allocate pcm frame buffer
|
||||
|
||||
dma.samplepos = 0;
|
||||
|
||||
dma.samples = samples;
|
||||
dma.format.width = 2;
|
||||
dma.initialized = 1;
|
||||
dma.backendName = "ALSA";
|
||||
|
||||
snd_pcm_prepare( s_alsa.pcm_handle );
|
||||
snd_pcm_writei( s_alsa.pcm_handle, dma.buffer, 2 * s_alsa.period_size );
|
||||
snd_pcm_start( s_alsa.pcm_handle );
|
||||
@@ -341,24 +341,4 @@ void SNDDMA_Activate( qboolean active )
|
||||
}
|
||||
}
|
||||
|
||||
qboolean VoiceCapture_Init( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean VoiceCapture_Activate( qboolean activate )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean VoiceCapture_Lock( qboolean lock )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void VoiceCapture_Shutdown( void )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -162,9 +162,4 @@ void SNDDMA_Activate( qboolean active ); // pause audio
|
||||
// void SNDDMA_LockSound( void ); // unused
|
||||
// void SNDDMA_UnlockSound( void ); // unused
|
||||
|
||||
qboolean VoiceCapture_Init( void );
|
||||
void VoiceCapture_Shutdown( void );
|
||||
qboolean VoiceCapture_Activate( qboolean activate );
|
||||
qboolean VoiceCapture_Lock( qboolean lock );
|
||||
|
||||
#endif // PLATFORM_H
|
||||
|
||||
@@ -24,6 +24,127 @@ GNU General Public License for more details.
|
||||
#include "platform/emscripten/lib_em.h"
|
||||
#include "platform/apple/lib_ios.h"
|
||||
|
||||
#define ENABLE_REFCOUNT_CHECK
|
||||
|
||||
#ifdef ENABLE_REFCOUNT_CHECK
|
||||
struct dll_t
|
||||
{
|
||||
void *hInstance;
|
||||
char name[256];
|
||||
char file[256];
|
||||
int line;
|
||||
|
||||
int refcount;
|
||||
struct dll_t *next;
|
||||
};
|
||||
|
||||
struct dll_t *dlls = NULL;
|
||||
|
||||
void *DLL_FindInListAndIncrement( const char *name )
|
||||
{
|
||||
struct dll_t *dll;
|
||||
|
||||
for( dll = dlls; dll; dll = dll->next )
|
||||
{
|
||||
if( !Q_strcmp( name, dll->name ))
|
||||
{
|
||||
dll->refcount++;
|
||||
return dll;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *DLL_AddToList( const char *name, void *hInstance, const char *file, int line )
|
||||
{
|
||||
struct dll_t *newdll;
|
||||
|
||||
if( !hInstance ) return NULL;
|
||||
|
||||
newdll = DLL_FindInListAndIncrement( name );
|
||||
if( newdll )
|
||||
return newdll;
|
||||
|
||||
newdll = Mem_Malloc( host.mempool, sizeof( *newdll ));
|
||||
|
||||
newdll->hInstance = hInstance;
|
||||
Q_strncpy( newdll->name, name, sizeof( newdll->name ));
|
||||
Q_strncpy( newdll->file, file, sizeof( newdll->file ));
|
||||
newdll->line = line;
|
||||
newdll->refcount = 1;
|
||||
newdll->next = dlls;
|
||||
|
||||
dlls = newdll;
|
||||
|
||||
return newdll;
|
||||
}
|
||||
|
||||
void *DLL_Free( void *_dll )
|
||||
{
|
||||
struct dll_t *dll = _dll;
|
||||
void *hinst = dll->hInstance;
|
||||
|
||||
dll->refcount--;
|
||||
|
||||
if( dll->refcount == 0 )
|
||||
{
|
||||
struct dll_t **back, *find;
|
||||
|
||||
back = &dlls;
|
||||
while( 1 )
|
||||
{
|
||||
find = *back;
|
||||
if( !find ) break;
|
||||
|
||||
if( find == dll )
|
||||
{
|
||||
*back = dll->next;
|
||||
|
||||
Mem_Free( dll );
|
||||
break;
|
||||
}
|
||||
|
||||
back = &find->next;
|
||||
}
|
||||
}
|
||||
|
||||
return hinst;
|
||||
}
|
||||
|
||||
void *DLL_GetInstance( void *_dll )
|
||||
{
|
||||
struct dll_t *dll = _dll;
|
||||
|
||||
return dll->hInstance;
|
||||
}
|
||||
|
||||
void DLL_PrintLeaks( void )
|
||||
{
|
||||
struct dll_t *dll;
|
||||
|
||||
for( dll = dlls; dll; dll = dll->next )
|
||||
{
|
||||
Con_Printf( S_ERROR "UNLOADED LIBRARY DETECTED: %s loaded at %s:%i!\n", dll->name, dll->file, dll->line );
|
||||
}
|
||||
}
|
||||
#else
|
||||
void *DLL_AddToList( const char *name, void *hInstance, const char *file, int line )
|
||||
{
|
||||
return hInstance;
|
||||
}
|
||||
|
||||
void DLL_Free( void *_dll )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void *DLL_GetInstance( void *_dll )
|
||||
{
|
||||
return _dll;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XASH_DLL_LOADER // wine-based dll loader
|
||||
void * Loader_LoadLibrary (const char *name);
|
||||
void * Loader_GetProcAddress (void *hndl, const char *name);
|
||||
@@ -33,25 +154,24 @@ const char * Loader_GetFuncName( void *hndl, void *func);
|
||||
const char * Loader_GetFuncName_int( void *wm , void *func);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef XASH_NO_LIBDL
|
||||
#ifndef XASH_DLL_LOADER
|
||||
#error Enable at least one dll backend!!!
|
||||
#endif // XASH_DLL_LOADER
|
||||
|
||||
void *dlsym(void *handle, const char *symbol )
|
||||
void *dlsym( void *handle, const char *symbol )
|
||||
{
|
||||
Con_DPrintf( "dlsym( %p, \"%s\" ): stub\n", handle, symbol );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *dlopen(const char *name, int flag )
|
||||
void *dlopen( const char *name, int flag )
|
||||
{
|
||||
Con_DPrintf( "dlopen( \"%s\", %d ): stub\n", name, flag );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dlclose(void *handle)
|
||||
int dlclose( void *handle)
|
||||
{
|
||||
Con_DPrintf( "dlsym( %p ): stub\n", handle );
|
||||
return 0;
|
||||
@@ -74,7 +194,7 @@ qboolean COM_CheckLibraryDirectDependency( const char *name, const char *depname
|
||||
return true;
|
||||
}
|
||||
|
||||
void *COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean directpath )
|
||||
void *_COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean directpath, const char *file, int line )
|
||||
{
|
||||
dll_user_t *hInst = NULL;
|
||||
void *pHandle = NULL;
|
||||
@@ -95,16 +215,16 @@ void *COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean d
|
||||
#ifdef XASH_DLL_LOADER
|
||||
if( host.enabledll && ( pHandle = Loader_LoadLibrary(dllname)) )
|
||||
{
|
||||
return pHandle;
|
||||
return DLL_AddToList( dllname, pHandle, file, line );
|
||||
}
|
||||
#endif
|
||||
|
||||
// try to find by linker(LD_LIBRARY_PATH, DYLD_LIBRARY_PATH, LD_32_LIBRARY_PATH and so on...)
|
||||
if( !pHandle )
|
||||
{
|
||||
pHandle = dlopen( dllname, RTLD_NOW );
|
||||
pHandle = dlopen( dllname, RTLD_LAZY );
|
||||
if( pHandle )
|
||||
return pHandle;
|
||||
return DLL_AddToList( dllname, pHandle, file, line );
|
||||
|
||||
COM_PushLibraryError( va( "Failed to find library %s", dllname ));
|
||||
COM_PushLibraryError( dlerror() );
|
||||
@@ -139,7 +259,7 @@ void *COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean d
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if( !( hInst->hInstance = dlopen( hInst->fullPath, RTLD_NOW ) ) )
|
||||
if( !( hInst->hInstance = dlopen( hInst->fullPath, RTLD_LAZY ) ) )
|
||||
{
|
||||
COM_PushLibraryError( dlerror() );
|
||||
Mem_Free( hInst );
|
||||
@@ -151,44 +271,53 @@ void *COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean d
|
||||
|
||||
Mem_Free( hInst );
|
||||
|
||||
return pHandle;
|
||||
return DLL_AddToList( dllname, pHandle, file, line );
|
||||
}
|
||||
|
||||
void COM_FreeLibrary( void *hInstance )
|
||||
{
|
||||
void *hinst = DLL_Free( hInstance );
|
||||
|
||||
#ifdef XASH_DLL_LOADER
|
||||
void *wm;
|
||||
if( host.enabledll && (wm = Loader_GetDllHandle( hInstance )) )
|
||||
return Loader_FreeLibrary( hInstance );
|
||||
if( host.enabledll && (wm = Loader_GetDllHandle( hinst )) )
|
||||
return Loader_FreeLibrary( hinst );
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef Platform_POSIX_FreeLibrary
|
||||
Platform_POSIX_FreeLibrary( hInstance );
|
||||
Platform_POSIX_FreeLibrary( hinst );
|
||||
#else
|
||||
dlclose( hInstance );
|
||||
dlclose( hinst );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void *COM_GetProcAddress( void *hInstance, const char *name )
|
||||
{
|
||||
void *hinst = DLL_GetInstance( hInstance );
|
||||
|
||||
#ifdef XASH_DLL_LOADER
|
||||
void *wm;
|
||||
if( host.enabledll && (wm = Loader_GetDllHandle( hInstance )) )
|
||||
return Loader_GetProcAddress(hInstance, name);
|
||||
if( host.enabledll && ( wm = Loader_GetDllHandle( hinst )))
|
||||
return Loader_GetProcAddress( hinst, name );
|
||||
else
|
||||
#endif
|
||||
#if Platform_POSIX_GetProcAddress
|
||||
return Platform_POSIX_GetProcAddress( hInstance, name );
|
||||
return Platform_POSIX_GetProcAddress( hinst, name );
|
||||
#else
|
||||
return dlsym( hInstance, name );
|
||||
return dlsym( hinst, name );
|
||||
#endif
|
||||
}
|
||||
|
||||
void *COM_FunctionFromName( void *hInstance, const char *pName )
|
||||
{
|
||||
return COM_GetProcAddress( hInstance, pName );
|
||||
void *function;
|
||||
if( !( function = COM_GetProcAddress( hInstance, pName ) ) )
|
||||
{
|
||||
Con_Reportf( S_ERROR "FunctionFromName: Can't get symbol %s: %s\n", pName, dlerror());
|
||||
}
|
||||
return function;
|
||||
}
|
||||
|
||||
#ifdef XASH_DYNAMIC_DLADDR
|
||||
@@ -211,11 +340,13 @@ static int d_dladdr( void *sym, Dl_info *info )
|
||||
|
||||
const char *COM_NameForFunction( void *hInstance, void *function )
|
||||
{
|
||||
void *hinst = DLL_GetInstance( hInstance );
|
||||
|
||||
#ifdef XASH_DLL_LOADER
|
||||
void *wm;
|
||||
if( host.enabledll && (wm = Loader_GetDllHandle( hInstance )) )
|
||||
if( host.enabledll && ( wm = Loader_GetDllHandle( hinst )))
|
||||
#error ConvertMangledName
|
||||
return Loader_GetFuncName_int(wm, function);
|
||||
return Loader_GetFuncName_int( wm, function );
|
||||
else
|
||||
#endif
|
||||
// NOTE: dladdr() is a glibc extension
|
||||
|
||||
@@ -260,11 +260,11 @@ SDLash_InitCursors
|
||||
*/
|
||||
void SDLash_InitCursors( void )
|
||||
{
|
||||
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
|
||||
if( cursors.initialized )
|
||||
SDLash_FreeCursors();
|
||||
|
||||
// load up all default cursors
|
||||
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
|
||||
cursors.cursors[dc_none] = NULL;
|
||||
cursors.cursors[dc_arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
|
||||
cursors.cursors[dc_ibeam] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
|
||||
@@ -278,8 +278,8 @@ void SDLash_InitCursors( void )
|
||||
cursors.cursors[dc_sizeall] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
|
||||
cursors.cursors[dc_no] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO);
|
||||
cursors.cursors[dc_hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
|
||||
cursors.initialized = true;
|
||||
#endif
|
||||
cursors.initialized = true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -314,10 +314,8 @@ void Platform_SetCursorType( VGUI_DefaultCursor type )
|
||||
{
|
||||
qboolean visible;
|
||||
|
||||
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
|
||||
if( !cursors.initialized )
|
||||
return;
|
||||
#endif
|
||||
|
||||
if( cls.key_dest != key_game || cl.paused )
|
||||
return;
|
||||
@@ -333,32 +331,22 @@ void Platform_SetCursorType( VGUI_DefaultCursor type )
|
||||
break;
|
||||
}
|
||||
|
||||
host.mouse_visible = visible;
|
||||
|
||||
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
|
||||
if( CVAR_TO_BOOL( touch_emulate ))
|
||||
return;
|
||||
|
||||
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
|
||||
if( host.mouse_visible )
|
||||
if( visible && !host.mouse_visible )
|
||||
{
|
||||
SDL_SetCursor( cursors.cursors[type] );
|
||||
SDL_ShowCursor( true );
|
||||
Key_EnableTextInput( true, false );
|
||||
}
|
||||
else
|
||||
else if( !visible && host.mouse_visible )
|
||||
{
|
||||
SDL_ShowCursor( false );
|
||||
Key_EnableTextInput( false, false );
|
||||
}
|
||||
#else
|
||||
if( host.mouse_visible )
|
||||
{
|
||||
SDL_ShowCursor( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_ShowCursor( false );
|
||||
}
|
||||
host.mouse_visible = visible;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ GNU General Public License for more details.
|
||||
#if XASH_SOUND == SOUND_SDL
|
||||
|
||||
#include "sound.h"
|
||||
#include "voice.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
@@ -32,11 +31,9 @@ GNU General Public License for more details.
|
||||
#define SDL_OpenAudioDevice( a, b, c, d, e ) SDL_OpenAudio( ( c ), ( d ) )
|
||||
#define SDL_CloseAudioDevice( a ) SDL_CloseAudio()
|
||||
#define SDL_PauseAudioDevice( a, b ) SDL_PauseAudio( ( b ) )
|
||||
#define SDL_LockAudioDevice( x ) SDL_LockAudio()
|
||||
#define SDL_UnlockAudioDevice( x ) SDL_UnlockAudio()
|
||||
#define SDLash_IsAudioError( x ) (( x ) != 0)
|
||||
#define SDLash_IsAudioError( x ) ( x ) != 0
|
||||
#else
|
||||
#define SDLash_IsAudioError( x ) (( x ) == 0)
|
||||
#define SDLash_IsAudioError( x ) ( x ) == 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -46,9 +43,6 @@ so it can unlock and free the data block after it has been played.
|
||||
=======================================================================
|
||||
*/
|
||||
static int sdl_dev;
|
||||
static SDL_AudioDeviceID in_dev = 0;
|
||||
static SDL_AudioFormat sdl_format;
|
||||
static char sdl_backend_name[32];
|
||||
|
||||
//static qboolean snd_firsttime = true;
|
||||
//static qboolean primary_format_set;
|
||||
@@ -139,12 +133,9 @@ qboolean SNDDMA_Init( void )
|
||||
dma.buffer = Z_Calloc( dma.samples * 2 );
|
||||
dma.samplepos = 0;
|
||||
|
||||
sdl_format = obtained.format;
|
||||
|
||||
Con_Printf( "Using SDL audio driver: %s @ %d Hz\n", SDL_GetCurrentAudioDriver( ), obtained.freq );
|
||||
Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL (%s)", SDL_GetCurrentAudioDriver( ));
|
||||
|
||||
dma.initialized = true;
|
||||
dma.backendName = sdl_backend_name;
|
||||
|
||||
SNDDMA_Activate( true );
|
||||
|
||||
@@ -165,7 +156,7 @@ Makes sure dma.buffer is valid
|
||||
*/
|
||||
void SNDDMA_BeginPainting( void )
|
||||
{
|
||||
SDL_LockAudioDevice( sdl_dev );
|
||||
SDL_LockAudio( );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -178,7 +169,7 @@ Also unlocks the dsound buffer
|
||||
*/
|
||||
void SNDDMA_Submit( void )
|
||||
{
|
||||
SDL_UnlockAudioDevice( sdl_dev );
|
||||
SDL_UnlockAudio( );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -229,98 +220,4 @@ void SNDDMA_Activate( qboolean active )
|
||||
|
||||
SDL_PauseAudioDevice( sdl_dev, !active );
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
SDL_SoundInputCallback
|
||||
===========
|
||||
*/
|
||||
void SDL_SoundInputCallback( void *userdata, Uint8 *stream, int len )
|
||||
{
|
||||
int size = Q_min( len, sizeof( voice.input_buffer ) - voice.input_buffer_pos );
|
||||
|
||||
// engine can't keep up, skip audio
|
||||
if( !size )
|
||||
return;
|
||||
|
||||
memcpy( voice.input_buffer + voice.input_buffer_pos, stream, size );
|
||||
voice.input_buffer_pos += size;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
VoiceCapture_Init
|
||||
===========
|
||||
*/
|
||||
qboolean VoiceCapture_Init( void )
|
||||
{
|
||||
SDL_AudioSpec wanted, spec;
|
||||
|
||||
if( !SDLash_IsAudioError( in_dev ))
|
||||
{
|
||||
VoiceCapture_Shutdown();
|
||||
}
|
||||
|
||||
SDL_zero( wanted );
|
||||
wanted.freq = voice.samplerate;
|
||||
wanted.format = AUDIO_S16LSB;
|
||||
wanted.channels = VOICE_PCM_CHANNELS;
|
||||
wanted.samples = voice.frame_size;
|
||||
wanted.callback = SDL_SoundInputCallback;
|
||||
|
||||
in_dev = SDL_OpenAudioDevice( NULL, SDL_TRUE, &wanted, &spec, 0 );
|
||||
|
||||
if( SDLash_IsAudioError( in_dev ))
|
||||
{
|
||||
Con_Printf( "VoiceCapture_Init: error creating capture device (%s)\n", SDL_GetError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
Con_Printf( S_NOTE "VoiceCapture_Init: capture device creation success (%i: %s)\n", in_dev, SDL_GetAudioDeviceName( in_dev, SDL_TRUE ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
VoiceCapture_Activate
|
||||
===========
|
||||
*/
|
||||
qboolean VoiceCapture_Activate( qboolean activate )
|
||||
{
|
||||
if( SDLash_IsAudioError( in_dev ))
|
||||
return false;
|
||||
|
||||
SDL_PauseAudioDevice( in_dev, activate ? SDL_FALSE : SDL_TRUE );
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
VoiceCapture_Lock
|
||||
===========
|
||||
*/
|
||||
qboolean VoiceCapture_Lock( qboolean lock )
|
||||
{
|
||||
if( SDLash_IsAudioError( in_dev ))
|
||||
return false;
|
||||
|
||||
if( lock ) SDL_LockAudioDevice( in_dev );
|
||||
else SDL_UnlockAudioDevice( in_dev );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
==========
|
||||
VoiceCapture_Shutdown
|
||||
==========
|
||||
*/
|
||||
void VoiceCapture_Shutdown( void )
|
||||
{
|
||||
if( SDLash_IsAudioError( in_dev ))
|
||||
return;
|
||||
|
||||
SDL_CloseAudioDevice( in_dev );
|
||||
}
|
||||
|
||||
#endif // XASH_SOUND == SOUND_SDL
|
||||
|
||||
@@ -553,9 +553,7 @@ static qboolean VID_SetScreenResolution( int width, int height )
|
||||
Uint32 wndFlags = 0;
|
||||
static string wndname;
|
||||
|
||||
#if !XASH_APPLE
|
||||
if( vid_highdpi->value ) wndFlags |= SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
#endif
|
||||
Q_strncpy( wndname, GI->title, sizeof( wndname ));
|
||||
|
||||
want.w = width;
|
||||
@@ -600,7 +598,7 @@ void VID_RestoreScreenResolution( void )
|
||||
#endif // SDL_VERSION_ATLEAST( 2, 0, 0 )
|
||||
}
|
||||
|
||||
#if XASH_WIN32 // ICO support only for Win32
|
||||
#if XASH_WIN32 && !XASH_64BIT // ICO support only for Win32
|
||||
#include "SDL_syswm.h"
|
||||
static void WIN_SetWindowIcon( HICON ico )
|
||||
{
|
||||
@@ -611,7 +609,7 @@ static void WIN_SetWindowIcon( HICON ico )
|
||||
|
||||
if( SDL_GetWindowWMInfo( host.hWnd, &wminfo ) )
|
||||
{
|
||||
SetClassLongPtr( wminfo.info.win.window, GCLP_HICON, (LONG)ico );
|
||||
SetClassLong( wminfo.info.win.window, GCL_HICON, (LONG)ico );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -630,7 +628,6 @@ qboolean VID_CreateWindow( int width, int height, qboolean fullscreen )
|
||||
qboolean iconLoaded = false;
|
||||
char iconpath[MAX_STRING];
|
||||
int xpos, ypos;
|
||||
const char *localIcoPath;
|
||||
|
||||
if( vid_highdpi->value ) wndFlags |= SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
Q_strncpy( wndname, GI->title, sizeof( wndname ));
|
||||
@@ -689,12 +686,14 @@ qboolean VID_CreateWindow( int width, int height, qboolean fullscreen )
|
||||
VID_RestoreScreenResolution();
|
||||
}
|
||||
|
||||
#if XASH_WIN32 // ICO support only for Win32
|
||||
if(( localIcoPath = FS_GetDiskPath( GI->iconpath, true )))
|
||||
#if XASH_WIN32 && !XASH_64BIT // ICO support only for Win32
|
||||
if( FS_FileExists( GI->iconpath, true ) )
|
||||
{
|
||||
HICON ico;
|
||||
char localPath[MAX_PATH];
|
||||
|
||||
ico = (HICON)LoadImage( NULL, localIcoPath, IMAGE_ICON, 0, 0, LR_LOADFROMFILE|LR_DEFAULTSIZE );
|
||||
Q_snprintf( localPath, sizeof( localPath ), "%s/%s", GI->gamefolder, GI->iconpath );
|
||||
ico = (HICON)LoadImage( NULL, localPath, IMAGE_ICON, 0, 0, LR_LOADFROMFILE|LR_DEFAULTSIZE );
|
||||
|
||||
if( ico )
|
||||
{
|
||||
@@ -729,7 +728,7 @@ qboolean VID_CreateWindow( int width, int height, qboolean fullscreen )
|
||||
}
|
||||
}
|
||||
|
||||
#if XASH_WIN32 // ICO support only for Win32
|
||||
#if XASH_WIN32 && !XASH_64BIT // ICO support only for Win32
|
||||
if( !iconLoaded )
|
||||
{
|
||||
WIN_SetWindowIcon( LoadIcon( host.hInst, MAKEINTRESOURCE( 101 ) ) );
|
||||
|
||||
@@ -94,25 +94,5 @@ void SNDDMA_Shutdown( void )
|
||||
}
|
||||
}
|
||||
|
||||
qboolean VoiceCapture_Init( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean VoiceCapture_Activate( qboolean activate )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean VoiceCapture_Lock( qboolean lock )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void VoiceCapture_Shutdown( void )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -27,12 +27,8 @@ GNU General Public License for more details.
|
||||
#include "studio.h"
|
||||
#include "r_efx.h"
|
||||
#include "com_image.h"
|
||||
#include "filesystem.h"
|
||||
|
||||
// RefAPI changelog:
|
||||
// 1. Initial release
|
||||
// 2. FS functions are removed, instead we have full fs_api_t
|
||||
#define REF_API_VERSION 2
|
||||
#define REF_API_VERSION 1
|
||||
|
||||
|
||||
#define TF_SKY (TF_SKYSIDE|TF_NOMIPMAP)
|
||||
@@ -339,7 +335,7 @@ typedef struct ref_api_s
|
||||
|
||||
// utils
|
||||
void (*CL_ExtraUpdate)( void );
|
||||
void (*Host_Error)( const char *fmt, ... ) _format( 1 );
|
||||
void (*Host_Error)( const char *fmt, ... ) _format( 1 ) NORETURN;
|
||||
void (*COM_SetRandomSeed)( int lSeed );
|
||||
float (*COM_RandomFloat)( float rmin, float rmax );
|
||||
int (*COM_RandomLong)( int rmin, int rmax );
|
||||
@@ -367,10 +363,17 @@ typedef struct ref_api_s
|
||||
void (*_Mem_Free)( void *data, const char *filename, int fileline );
|
||||
|
||||
// library management
|
||||
void *(*COM_LoadLibrary)( const char *name, int build_ordinals_table, qboolean directpath );
|
||||
void *(*COM_LoadLibrary)( const char *name, int build_ordinals_table, qboolean directpath, const char *file, int line );
|
||||
void (*COM_FreeLibrary)( void *handle );
|
||||
void *(*COM_GetProcAddress)( void *handle, const char *name );
|
||||
|
||||
// filesystem
|
||||
byte* (*COM_LoadFile)( const char *path, fs_offset_t *pLength, qboolean gamedironly );
|
||||
// use Mem_Free instead
|
||||
// void (*COM_FreeFile)( void *buffer );
|
||||
int (*FS_FileExists)( const char *filename, int gamedironly );
|
||||
void (*FS_AllowDirectPaths)( qboolean enable );
|
||||
|
||||
// video init
|
||||
// try to create window
|
||||
// will call GL_SetupAttributes in case of REF_GL
|
||||
@@ -427,9 +430,6 @@ typedef struct ref_api_s
|
||||
void (*pfnDrawNormalTriangles)( void );
|
||||
void (*pfnDrawTransparentTriangles)( void );
|
||||
render_interface_t *drawFuncs;
|
||||
|
||||
// filesystem exports
|
||||
fs_api_t *fsapi;
|
||||
} ref_api_t;
|
||||
|
||||
struct mip_s;
|
||||
|
||||
@@ -418,8 +418,6 @@ extern convar_t sv_stopspeed;
|
||||
extern convar_t sv_maxspeed;
|
||||
extern convar_t sv_wateralpha;
|
||||
extern convar_t sv_wateramp;
|
||||
extern convar_t sv_voiceenable;
|
||||
extern convar_t sv_voicequality;
|
||||
extern convar_t sv_stepsize;
|
||||
extern convar_t sv_maxvelocity;
|
||||
extern convar_t sv_rollangle;
|
||||
|
||||
@@ -42,35 +42,6 @@ typedef struct ucmd_s
|
||||
|
||||
static int g_userid = 1;
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_GetPlayerCount
|
||||
|
||||
=================
|
||||
*/
|
||||
static void SV_GetPlayerCount( int *players, int *bots )
|
||||
{
|
||||
int i;
|
||||
|
||||
*players = 0;
|
||||
*bots = 0;
|
||||
|
||||
if( !svs.clients )
|
||||
return;
|
||||
|
||||
for( i = 0; i < svs.maxclients; i++ )
|
||||
{
|
||||
if( svs.clients[i].state >= cs_connected )
|
||||
{
|
||||
if( FBitSet( svs.clients[i].flags, FCL_FAKECLIENT ))
|
||||
(*bots)++;
|
||||
else
|
||||
(*players)++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_GetChallenge
|
||||
@@ -848,26 +819,30 @@ Responds with short info for broadcast scans
|
||||
The second parameter should be the current protocol version number.
|
||||
================
|
||||
*/
|
||||
void SV_Info( netadr_t from, int protocolVersion )
|
||||
void SV_Info( netadr_t from )
|
||||
{
|
||||
char string[MAX_INFO_STRING];
|
||||
int version;
|
||||
|
||||
// ignore in single player
|
||||
if( svs.maxclients == 1 || !svs.initialized )
|
||||
return;
|
||||
|
||||
version = Q_atoi( Cmd_Argv( 1 ));
|
||||
string[0] = '\0';
|
||||
|
||||
if( protocolVersion != PROTOCOL_VERSION )
|
||||
if( version != PROTOCOL_VERSION )
|
||||
{
|
||||
Q_snprintf( string, sizeof( string ), "%s: wrong version\n", hostname.string );
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, count, bots;
|
||||
int i, count = 0;
|
||||
qboolean havePassword = COM_CheckStringEmpty( sv_password.string );
|
||||
|
||||
SV_GetPlayerCount( &count, &bots );
|
||||
for( i = 0; i < svs.maxclients; i++ )
|
||||
if( svs.clients[i].state >= cs_connected )
|
||||
count++;
|
||||
|
||||
// a1ba: send protocol version to distinguish old engine and new
|
||||
Info_SetValueForKey( string, "p", va( "%i", PROTOCOL_VERSION ), MAX_INFO_STRING );
|
||||
@@ -1046,7 +1021,7 @@ int SV_CalcPing( sv_client_t *cl )
|
||||
|
||||
// bots don't have a real ping
|
||||
if( FBitSet( cl->flags, FCL_FAKECLIENT ) || !cl->frames )
|
||||
return 0;
|
||||
return 5;
|
||||
|
||||
if( SV_UPDATE_BACKUP <= 31 )
|
||||
{
|
||||
@@ -1316,7 +1291,7 @@ a deathmatch.
|
||||
*/
|
||||
void SV_PutClientInServer( sv_client_t *cl )
|
||||
{
|
||||
static byte msg_buf[MAX_INIT_MSG + 0x200]; // MAX_INIT_MSG + some space
|
||||
static byte msg_buf[0x20200]; // MAX_INIT_MSG + some space
|
||||
edict_t *ent = cl->edict;
|
||||
sizebuf_t msg;
|
||||
|
||||
@@ -2190,11 +2165,22 @@ void SV_TSourceEngineQuery( netadr_t from )
|
||||
{
|
||||
// A2S_INFO
|
||||
char answer[1024] = "";
|
||||
int count, bots;
|
||||
int count = 0, bots = 0;
|
||||
int index;
|
||||
sizebuf_t buf;
|
||||
|
||||
SV_GetPlayerCount( &count, &bots );
|
||||
if( svs.clients )
|
||||
{
|
||||
for( index = 0; index < svs.maxclients; index++ )
|
||||
{
|
||||
if( svs.clients[index].state >= cs_connected )
|
||||
{
|
||||
if( FBitSet( svs.clients[index].flags, FCL_FAKECLIENT ))
|
||||
bots++;
|
||||
else count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MSG_Init( &buf, "TSourceEngineQuery", answer, sizeof( answer ));
|
||||
|
||||
@@ -2271,7 +2257,7 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
|
||||
|
||||
if( !Q_strcmp( pcmd, "ping" )) SV_Ping( from );
|
||||
else if( !Q_strcmp( pcmd, "ack" )) SV_Ack( from );
|
||||
else if( !Q_strcmp( pcmd, "info" )) SV_Info( from, Q_atoi( Cmd_Argv( 1 )));
|
||||
else if( !Q_strcmp( pcmd, "info" )) SV_Info( from );
|
||||
else if( !Q_strcmp( pcmd, "bandwidth" )) SV_TestBandWidth( from );
|
||||
else if( !Q_strcmp( pcmd, "getchallenge" )) SV_GetChallenge( from );
|
||||
else if( !Q_strcmp( pcmd, "connect" )) SV_ConnectClient( from );
|
||||
@@ -2280,17 +2266,6 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
|
||||
else if( !Q_strcmp( pcmd, "s" )) SV_AddToMaster( from, msg );
|
||||
else if( !Q_strcmp( pcmd, "T" "Source" )) SV_TSourceEngineQuery( from );
|
||||
else if( !Q_strcmp( pcmd, "i" )) NET_SendPacket( NS_SERVER, 5, "\xFF\xFF\xFF\xFFj", from ); // A2A_PING
|
||||
else if (!Q_strcmp( pcmd, "c" ))
|
||||
{
|
||||
qboolean sv_nat = Cvar_VariableInteger( "sv_nat" );
|
||||
if( sv_nat )
|
||||
{
|
||||
netadr_t to;
|
||||
|
||||
if( NET_StringToAdr( Cmd_Argv( 1 ), &to ) && !NET_IsReservedAdr( to ))
|
||||
SV_Info( to, PROTOCOL_VERSION );
|
||||
}
|
||||
}
|
||||
else if( svgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len ))
|
||||
{
|
||||
// user out of band message (must be handled in CL_ConnectionlessPacket)
|
||||
@@ -2561,59 +2536,6 @@ void SV_ParseCvarValue2( sv_client_t *cl, sizebuf_t *msg )
|
||||
Con_Reportf( "Cvar query response: name:%s, request ID %d, cvar:%s, value:%s\n", cl->name, requestID, name, value );
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
SV_ParseVoiceData
|
||||
===================
|
||||
*/
|
||||
void SV_ParseVoiceData( sv_client_t *cl, sizebuf_t *msg )
|
||||
{
|
||||
char received[4096];
|
||||
sv_client_t *cur;
|
||||
int i, client;
|
||||
uint length, size, frames;
|
||||
|
||||
cl->m_bLoopback = MSG_ReadByte( msg );
|
||||
|
||||
frames = MSG_ReadByte( msg );
|
||||
|
||||
size = MSG_ReadShort( msg );
|
||||
client = cl - svs.clients;
|
||||
|
||||
if( size > sizeof( received ))
|
||||
{
|
||||
Con_DPrintf( "SV_ParseVoiceData: invalid incoming packet.\n" );
|
||||
SV_DropClient( cl, false );
|
||||
return;
|
||||
}
|
||||
|
||||
MSG_ReadBytes( msg, received, size );
|
||||
|
||||
if( !sv_voiceenable.value )
|
||||
return;
|
||||
|
||||
for( i = 0, cur = svs.clients; i < svs.maxclients; i++, cur++ )
|
||||
{
|
||||
if ( cur->state < cs_connected && cl != cur )
|
||||
continue;
|
||||
|
||||
length = size;
|
||||
|
||||
// 6 is a number of bytes for other parts of message
|
||||
if( MSG_GetNumBytesLeft( &cur->datagram ) < length + 6 )
|
||||
continue;
|
||||
|
||||
if( cl == cur && !cur->m_bLoopback )
|
||||
length = 0;
|
||||
|
||||
MSG_BeginServerCmd( &cur->datagram, svc_voicedata );
|
||||
MSG_WriteByte( &cur->datagram, client );
|
||||
MSG_WriteByte( &cur->datagram, frames );
|
||||
MSG_WriteShort( &cur->datagram, length );
|
||||
MSG_WriteBytes( &cur->datagram, received, length );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
SV_ExecuteClientMessage
|
||||
@@ -2684,9 +2606,6 @@ void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg )
|
||||
case clc_fileconsistency:
|
||||
SV_ParseConsistencyResponse( cl, msg );
|
||||
break;
|
||||
case clc_voicedata:
|
||||
SV_ParseVoiceData( cl, msg );
|
||||
break;
|
||||
case clc_requestcvarvalue:
|
||||
SV_ParseCvarValue( cl, msg );
|
||||
break;
|
||||
|
||||
@@ -62,23 +62,16 @@ qboolean SV_CheckEdict( const edict_t *e, const char *file, const int line )
|
||||
|
||||
static edict_t *SV_PEntityOfEntIndex( const int iEntIndex, const qboolean allentities )
|
||||
{
|
||||
if( iEntIndex >= 0 && iEntIndex < GI->max_edicts )
|
||||
{
|
||||
edict_t *pEdict = EDICT_NUM( iEntIndex );
|
||||
qboolean player = allentities ? iEntIndex <= svs.maxclients : iEntIndex < svs.maxclients;
|
||||
edict_t *pEdict = EDICT_NUM( iEntIndex );
|
||||
qboolean player = allentities ? iEntIndex <= svs.maxclients : iEntIndex < svs.maxclients;
|
||||
|
||||
if( !iEntIndex || FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
|
||||
return pEdict; // just get access to array
|
||||
if( !SV_IsValidEdict( pEdict ))
|
||||
return NULL;
|
||||
|
||||
if( SV_IsValidEdict( pEdict ) && pEdict->pvPrivateData )
|
||||
return pEdict;
|
||||
if( !player && !pEdict->pvPrivateData )
|
||||
return NULL;
|
||||
|
||||
// g-cont: world and clients can be accessed even without private data
|
||||
if( SV_IsValidEdict( pEdict ) && player )
|
||||
return pEdict;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return pEdict;
|
||||
}
|
||||
|
||||
|
||||
@@ -2680,7 +2673,7 @@ void GAME_EXPORT pfnMessageEnd( void )
|
||||
return;
|
||||
}
|
||||
|
||||
*(word *)&sv.multicast.pData[svgame.msg_size_index] = svgame.msg_realsize;
|
||||
sv.multicast.pData[svgame.msg_size_index] = svgame.msg_realsize;
|
||||
}
|
||||
}
|
||||
else if( svgame.msg[svgame.msg_index].size != -1 )
|
||||
@@ -3375,9 +3368,7 @@ pfnPEntityOfEntIndex
|
||||
static edict_t *pfnPEntityOfEntIndex( int iEntIndex )
|
||||
{
|
||||
// have to be bug-compatible with GoldSrc in this function
|
||||
if( host.bugcomp == BUGCOMP_GOLDSRC )
|
||||
return SV_PEntityOfEntIndex( iEntIndex, false );
|
||||
return SV_PEntityOfEntIndex( iEntIndex, true );
|
||||
return SV_PEntityOfEntIndex( iEntIndex, false );
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,8 +17,6 @@ GNU General Public License for more details.
|
||||
#include "server.h"
|
||||
#include "net_encode.h"
|
||||
#include "library.h"
|
||||
#include "voice.h"
|
||||
|
||||
#if XASH_LOW_MEMORY != 2
|
||||
int SV_UPDATE_BACKUP = SINGLEPLAYER_BACKUP;
|
||||
#endif
|
||||
@@ -388,18 +386,6 @@ void SV_CreateResourceList( void )
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
SV_WriteVoiceCodec
|
||||
================
|
||||
*/
|
||||
void SV_WriteVoiceCodec( sizebuf_t *msg )
|
||||
{
|
||||
MSG_BeginServerCmd( msg, svc_voiceinit );
|
||||
MSG_WriteString( msg, VOICE_DEFAULT_CODEC );
|
||||
MSG_WriteByte( msg, (int)sv_voicequality.value );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
SV_CreateBaseline
|
||||
@@ -418,8 +404,6 @@ void SV_CreateBaseline( void )
|
||||
int delta_type;
|
||||
int entnum;
|
||||
|
||||
SV_WriteVoiceCodec( &sv.signon );
|
||||
|
||||
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
|
||||
playermodel = SV_ModelIndex( DEFAULT_PLAYER_PATH_QUAKE );
|
||||
else playermodel = SV_ModelIndex( DEFAULT_PLAYER_PATH_HALFLIFE );
|
||||
@@ -777,7 +761,7 @@ void SV_SetupClients( void )
|
||||
Con_Reportf( "%s alloced by server packet entities\n", Q_memprint( sizeof( entity_state_t ) * svs.num_client_entities ));
|
||||
|
||||
// init network stuff
|
||||
NET_Config(( svs.maxclients > 1 ), true );
|
||||
NET_Config(( svs.maxclients > 1 ));
|
||||
svgame.numEntities = svs.maxclients + 1; // clients + world
|
||||
ClearBits( sv_maxclients->flags, FCVAR_CHANGED );
|
||||
}
|
||||
|
||||
@@ -18,12 +18,11 @@ GNU General Public License for more details.
|
||||
#include "net_encode.h"
|
||||
#include "platform/platform.h"
|
||||
|
||||
#define HEARTBEAT_SECONDS ((sv_nat.value > 0.0f) ? 60.0f : 300.0f) // 1 or 5 minutes
|
||||
#define HEARTBEAT_SECONDS 300.0f // 300 seconds
|
||||
|
||||
// server cvars
|
||||
CVAR_DEFINE_AUTO( sv_lan, "0", 0, "server is a lan server ( no heartbeat, no authentication, no non-class C addresses, 9999.0 rate, etc." );
|
||||
CVAR_DEFINE_AUTO( sv_lan_rate, "20000.0", 0, "rate for lan server" );
|
||||
CVAR_DEFINE_AUTO( sv_nat, "0", 0, "enable NAT bypass for this server" );
|
||||
CVAR_DEFINE_AUTO( sv_aim, "1", FCVAR_ARCHIVE|FCVAR_SERVER, "auto aiming option" );
|
||||
CVAR_DEFINE_AUTO( sv_unlag, "1", 0, "allow lag compensation on server-side" );
|
||||
CVAR_DEFINE_AUTO( sv_maxunlag, "0.5", 0, "max latency value which can be interpolated (by default ping should not exceed 500 units)" );
|
||||
@@ -112,10 +111,6 @@ CVAR_DEFINE_AUTO( violence_ablood, "1", 0, "draw alien blood" );
|
||||
CVAR_DEFINE_AUTO( violence_hgibs, "1", 0, "show human gib entities" );
|
||||
CVAR_DEFINE_AUTO( violence_agibs, "1", 0, "show alien gib entities" );
|
||||
|
||||
// voice chat
|
||||
CVAR_DEFINE_AUTO( sv_voiceenable, "1", FCVAR_ARCHIVE|FCVAR_SERVER, "enable voice support" );
|
||||
CVAR_DEFINE_AUTO( sv_voicequality, "3", FCVAR_ARCHIVE|FCVAR_SERVER, "voice chat quality level, from 0 to 5, higher is better" );
|
||||
|
||||
convar_t *sv_novis; // disable server culling entities by vis
|
||||
convar_t *sv_pausable;
|
||||
convar_t *timeout; // seconds without any message
|
||||
@@ -718,9 +713,13 @@ Master_Add
|
||||
*/
|
||||
void Master_Add( void )
|
||||
{
|
||||
NET_Config( true, false ); // allow remote
|
||||
if( NET_SendToMasters( NS_SERVER, 2, "q\xFF" ))
|
||||
svs.last_heartbeat = MAX_HEARTBEAT;
|
||||
netadr_t adr;
|
||||
|
||||
NET_Config( true ); // allow remote
|
||||
|
||||
if( !NET_StringToAdr( MASTERSERVER_ADR, &adr ))
|
||||
Con_Printf( "can't resolve adr: %s\n", MASTERSERVER_ADR );
|
||||
else NET_SendPacket( NS_SERVER, 2, "q\xFF", adr );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -757,8 +756,13 @@ Informs all masters that this server is going down
|
||||
*/
|
||||
void Master_Shutdown( void )
|
||||
{
|
||||
NET_Config( true, false ); // allow remote
|
||||
while( NET_SendToMasters( NS_SERVER, 2, "\x62\x0A" ));
|
||||
netadr_t adr;
|
||||
|
||||
NET_Config( true ); // allow remote
|
||||
|
||||
if( !NET_StringToAdr( MASTERSERVER_ADR, &adr ))
|
||||
Con_Printf( "can't resolve addr: %s\n", MASTERSERVER_ADR );
|
||||
else NET_SendPacket( NS_SERVER, 2, "\x62\x0A", adr );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -776,12 +780,6 @@ void SV_AddToMaster( netadr_t from, sizebuf_t *msg )
|
||||
int clients = 0, bots = 0;
|
||||
int len = sizeof( s );
|
||||
|
||||
if( !NET_IsMasterAdr( from ))
|
||||
{
|
||||
Con_Printf( S_WARN "unexpected master server info query packet from %s\n", NET_AdrToString( from ));
|
||||
return;
|
||||
}
|
||||
|
||||
clients = SV_GetConnectedClientsCount( &bots );
|
||||
challenge = MSG_ReadUBitLong( msg, sizeof( uint ) << 3 );
|
||||
|
||||
@@ -800,7 +798,6 @@ void SV_AddToMaster( netadr_t from, sizebuf_t *msg )
|
||||
Info_SetValueForKey( s, "version", va( "%s", XASH_VERSION ), len ); // server region. 255 -- all regions
|
||||
Info_SetValueForKey( s, "region", "255", len ); // server region. 255 -- all regions
|
||||
Info_SetValueForKey( s, "product", GI->gamefolder, len ); // product? Where is the difference with gamedir?
|
||||
Info_SetValueForKey( s, "nat", sv_nat.string, sizeof(s) ); // Server running under NAT, use reverse connection
|
||||
|
||||
NET_SendPacket( NS_SERVER, Q_strlen( s ), s, from );
|
||||
}
|
||||
@@ -959,7 +956,6 @@ void SV_Init( void )
|
||||
sv_hostmap = Cvar_Get( "hostmap", GI->startmap, 0, "keep name of last entered map" );
|
||||
Cvar_RegisterVariable( &sv_password );
|
||||
Cvar_RegisterVariable( &sv_lan );
|
||||
Cvar_RegisterVariable( &sv_nat );
|
||||
Cvar_RegisterVariable( &violence_ablood );
|
||||
Cvar_RegisterVariable( &violence_hblood );
|
||||
Cvar_RegisterVariable( &violence_agibs );
|
||||
@@ -978,8 +974,6 @@ void SV_Init( void )
|
||||
Cvar_RegisterVariable( &listipcfgfile );
|
||||
Cvar_RegisterVariable( &mapchangecfgfile );
|
||||
|
||||
Cvar_RegisterVariable( &sv_voiceenable );
|
||||
Cvar_RegisterVariable( &sv_voicequality );
|
||||
Cvar_RegisterVariable( &sv_trace_messages );
|
||||
|
||||
sv_allow_joystick = Cvar_Get( "sv_allow_joystick", "1", FCVAR_ARCHIVE, "allow connect with joystick enabled" );
|
||||
@@ -1114,7 +1108,7 @@ void SV_Shutdown( const char *finalmsg )
|
||||
if( public_server->value && svs.maxclients != 1 )
|
||||
Master_Shutdown();
|
||||
|
||||
NET_Config( false, false );
|
||||
NET_Config( false );
|
||||
SV_UnloadProgs ();
|
||||
CL_Drop();
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ float SV_VecToYaw( const vec3_t src )
|
||||
}
|
||||
else
|
||||
{
|
||||
yaw = (int)( atan2( src[1], src[0] ) * 180.0 / M_PI );
|
||||
yaw = (int)( atan2( src[1], src[0] ) * 180.0f / M_PI_F );
|
||||
if( yaw < 0 ) yaw += 360.0f;
|
||||
}
|
||||
return yaw;
|
||||
|
||||
@@ -455,8 +455,6 @@ static float GAME_EXPORT pfnTraceModel( physent_t *pe, float *start, float *end,
|
||||
matrix4x4 matrix;
|
||||
hull_t *hull;
|
||||
|
||||
PM_InitTrace( trace, end );
|
||||
|
||||
old_usehull = svgame.pmove->usehull;
|
||||
svgame.pmove->usehull = 2;
|
||||
|
||||
|
||||
@@ -871,7 +871,10 @@ void SV_ClipMoveToEntity( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t
|
||||
qboolean rotated, transform_bbox;
|
||||
matrix4x4 matrix;
|
||||
|
||||
PM_InitTrace( trace, end );
|
||||
memset( trace, 0, sizeof( trace_t ));
|
||||
VectorCopy( end, trace->endpos );
|
||||
trace->fraction = 1.0f;
|
||||
trace->allsolid = 1;
|
||||
|
||||
model = SV_ModelHandle( ent->v.modelindex );
|
||||
|
||||
@@ -942,7 +945,10 @@ void SV_ClipMoveToEntity( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t
|
||||
|
||||
for( i = 0; i < hullcount; i++ )
|
||||
{
|
||||
PM_InitTrace( &trace_hitbox, end );
|
||||
memset( &trace_hitbox, 0, sizeof( trace_t ));
|
||||
VectorCopy( end, trace_hitbox.endpos );
|
||||
trace_hitbox.fraction = 1.0;
|
||||
trace_hitbox.allsolid = 1;
|
||||
|
||||
PM_RecursiveHullCheck( &hull[i], hull[i].firstclipnode, 0.0f, 1.0f, start_l, end_l, (pmtrace_t *)&trace_hitbox );
|
||||
|
||||
@@ -1108,7 +1114,10 @@ or custom physics implementation
|
||||
void SV_CustomClipMoveToEntity( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, trace_t *trace )
|
||||
{
|
||||
// initialize custom trace
|
||||
PM_InitTrace( trace, end );
|
||||
memset( trace, 0, sizeof( trace_t ));
|
||||
VectorCopy( end, trace->endpos );
|
||||
trace->allsolid = true;
|
||||
trace->fraction = 1.0f;
|
||||
|
||||
if( svgame.physFuncs.ClipMoveToEntity != NULL )
|
||||
{
|
||||
|
||||
@@ -65,7 +65,7 @@ def configure(conf):
|
||||
else:
|
||||
conf.load('sdl2')
|
||||
if not conf.env.HAVE_SDL2:
|
||||
conf.fatal('SDL2 not available! If you want to build dedicated server, specify --dedicated')
|
||||
conf.fatal('SDL2 not availiable! If you want to build dedicated server, specify --dedicated')
|
||||
conf.define('XASH_SDL', 2)
|
||||
|
||||
if conf.env.DEST_OS == 'haiku':
|
||||
@@ -106,11 +106,8 @@ def configure(conf):
|
||||
conf.define_cond('PSAPI_VERSION', conf.env.DEST_OS == 'win32') # will be defined as 1
|
||||
|
||||
def build(bld):
|
||||
# public includes for renderers and utils use
|
||||
bld(name = 'engine_includes', export_includes = '. common common/imagelib', use = 'filesystem_includes')
|
||||
|
||||
is_cxx_link = False
|
||||
libs = [ 'engine_includes', 'public', 'dllemu' ]
|
||||
libs = [ 'public', 'dllemu' ]
|
||||
|
||||
# basic build: dedicated only
|
||||
source = bld.path.ant_glob([
|
||||
@@ -168,9 +165,8 @@ def build(bld):
|
||||
'client/*.c',
|
||||
'client/vgui/*.c',
|
||||
'client/avi/*.c'])
|
||||
libs += ['opus']
|
||||
|
||||
includes = ['server', 'client', 'client/vgui' ]
|
||||
includes = ['common', 'server', 'client', 'client/vgui', 'tests', '.', '../public', '../common', '../pm_shared' ]
|
||||
|
||||
if bld.env.SINGLE_BINARY:
|
||||
install_path = bld.env.BINDIR
|
||||
@@ -188,6 +184,5 @@ def build(bld):
|
||||
includes = includes,
|
||||
use = libs,
|
||||
install_path = install_path,
|
||||
subsystem = bld.env.MSVC_SUBSYSTEM,
|
||||
rpath = '$ORIGIN'
|
||||
subsystem = bld.env.MSVC_SUBSYSTEM
|
||||
)
|
||||
|
||||
@@ -1,509 +0,0 @@
|
||||
/*
|
||||
VFileSystem009.h - C++ interface for filesystem_stdio
|
||||
Copyright (C) 2022 Alibek Omarov
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
#include ALLOCA_H
|
||||
#include "crtlib.h"
|
||||
#include "filesystem.h"
|
||||
#include "filesystem_internal.h"
|
||||
#include "VFileSystem009.h"
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
#define override
|
||||
#endif
|
||||
|
||||
// GoldSrc Directories and ID
|
||||
// GAME gamedir
|
||||
// GAMECONFIG gamedir (rodir integration?)
|
||||
// GAMEDOWNLOAD gamedir_downloads (gamedir/downloads for us)
|
||||
// GAME_FALLBACK liblist.gam's fallback_dir
|
||||
// ROOT and BASE rootdir
|
||||
// PLATFORM platform
|
||||
// CONFIG platform/config
|
||||
|
||||
static inline qboolean IsIdGamedir( const char *id )
|
||||
{
|
||||
return !Q_strcmp( id, "GAME" ) ||
|
||||
!Q_strcmp( id, "GAMECONFIG" ) ||
|
||||
!Q_strcmp( id, "GAMEDOWNLOAD" );
|
||||
}
|
||||
|
||||
static inline const char* IdToDir( const char *id )
|
||||
{
|
||||
if( !Q_strcmp( id, "GAME" ))
|
||||
return GI->gamefolder;
|
||||
else if( !Q_strcmp( id, "GAMEDOWNLOAD" ))
|
||||
return va( "%s/downloaded", GI->gamefolder );
|
||||
else if( !Q_strcmp( id, "GAMECONFIG" ))
|
||||
return fs_writedir; // full path here so it's totally our write allowed directory
|
||||
else if( !Q_strcmp( id, "PLATFORM" ))
|
||||
return "platform"; // stub
|
||||
else if( !Q_strcmp( id, "CONFIG" ))
|
||||
return "platform/config"; // stub
|
||||
else // ROOT || BASE
|
||||
return fs_rootdir; // give at least root directory
|
||||
}
|
||||
|
||||
static inline void CopyAndFixSlashes( char *p, const char *in )
|
||||
{
|
||||
Q_strcpy( p, in );
|
||||
COM_FixSlashes( p );
|
||||
}
|
||||
|
||||
class CXashFS : public IVFileSystem009
|
||||
{
|
||||
private:
|
||||
class CSearchState
|
||||
{
|
||||
public:
|
||||
CSearchState( CSearchState **head, search_t *search ) :
|
||||
next( *head ), search( search ), index( 0 )
|
||||
{
|
||||
if( *head )
|
||||
handle = (*head)->handle + 1;
|
||||
else handle = 0;
|
||||
|
||||
*head = this;
|
||||
}
|
||||
~CSearchState()
|
||||
{
|
||||
Mem_Free( search );
|
||||
}
|
||||
|
||||
CSearchState *next;
|
||||
search_t *search;
|
||||
int index;
|
||||
FileFindHandle_t handle;
|
||||
};
|
||||
|
||||
CSearchState *searchHead;
|
||||
|
||||
CSearchState *GetSearchStateByHandle( FileFindHandle_t handle )
|
||||
{
|
||||
for( CSearchState *state = searchHead; state; state = state->next )
|
||||
{
|
||||
if( state->handle == handle )
|
||||
{
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
Con_DPrintf( "Can't find search state by handle %d\n", handle );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
public:
|
||||
CXashFS() : searchHead( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
void RemoveAllSearchPaths() override
|
||||
{
|
||||
FS_ClearSearchPath();
|
||||
}
|
||||
|
||||
void AddSearchPath( const char *path, const char *id ) override
|
||||
{
|
||||
char *p = (char *)alloca( Q_strlen( path ) + 1 );
|
||||
CopyAndFixSlashes( p, path );
|
||||
|
||||
FS_AddGameDirectory( p, FS_CUSTOM_PATH );
|
||||
}
|
||||
|
||||
void AddSearchPathNoWrite( const char *path, const char *id ) override
|
||||
{
|
||||
char *p = (char *)alloca( Q_strlen( path ) + 1 );
|
||||
CopyAndFixSlashes( p, path );
|
||||
|
||||
FS_AddGameDirectory( p, FS_NOWRITE_PATH | FS_CUSTOM_PATH );
|
||||
}
|
||||
|
||||
bool RemoveSearchPath( const char *id ) override
|
||||
{
|
||||
// TODO:
|
||||
return true;
|
||||
}
|
||||
|
||||
void RemoveFile( const char *path, const char *id ) override
|
||||
{
|
||||
FS_Delete( path ); // FS_Delete is aware of slashes
|
||||
}
|
||||
|
||||
void CreateDirHierarchy( const char *path, const char *id ) override
|
||||
{
|
||||
FS_CreatePath( va( "%s/%s", IdToDir( id ), path )); // FS_CreatePath is aware of slashes
|
||||
}
|
||||
|
||||
bool FileExists( const char *path ) override
|
||||
{
|
||||
char *p = (char *)alloca( Q_strlen( path ) + 1 );
|
||||
CopyAndFixSlashes( p, path );
|
||||
|
||||
return FS_FileExists( p, false );
|
||||
}
|
||||
|
||||
bool IsDirectory( const char *path ) override
|
||||
{
|
||||
char *p = (char *)alloca( Q_strlen( path ) + 1 );
|
||||
CopyAndFixSlashes( p, path );
|
||||
|
||||
return FS_SysFolderExists( p );
|
||||
}
|
||||
|
||||
FileHandle_t Open( const char *path, const char *mode, const char *id ) override
|
||||
{
|
||||
char *p = (char *)alloca( Q_strlen( path ) + 1 );
|
||||
CopyAndFixSlashes( p, path );
|
||||
|
||||
file_t *fd = FS_Open( p, mode, IsIdGamedir( id ) );
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
void Close( FileHandle_t handle ) override
|
||||
{
|
||||
FS_Close( (file_t *)handle );
|
||||
}
|
||||
|
||||
void Seek( FileHandle_t handle, int offset, FileSystemSeek_t whence ) override
|
||||
{
|
||||
int whence_ = SEEK_SET;
|
||||
switch( whence )
|
||||
{
|
||||
case FILESYSTEM_SEEK_HEAD: whence_ = SEEK_SET; break;
|
||||
case FILESYSTEM_SEEK_CURRENT: whence_ = SEEK_CUR; break;
|
||||
case FILESYSTEM_SEEK_TAIL: whence_ = SEEK_END; break;
|
||||
}
|
||||
|
||||
FS_Seek( (file_t *)handle, offset, whence_ );
|
||||
}
|
||||
|
||||
unsigned int Tell( FileHandle_t handle ) override
|
||||
{
|
||||
return FS_Tell( (file_t *)handle );
|
||||
}
|
||||
|
||||
unsigned int Size( FileHandle_t handle ) override
|
||||
{
|
||||
file_t *fd = (file_t *)handle;
|
||||
return fd->real_length;
|
||||
}
|
||||
|
||||
unsigned int Size( const char *path ) override
|
||||
{
|
||||
char *p = (char *)alloca( Q_strlen( path ) + 1 );
|
||||
CopyAndFixSlashes( p, path );
|
||||
return FS_FileSize( p, false );
|
||||
}
|
||||
|
||||
long int GetFileTime( const char *path ) override
|
||||
{
|
||||
char *p = (char *)alloca( Q_strlen( path ) + 1 );
|
||||
CopyAndFixSlashes( p, path );
|
||||
return FS_FileTime( p, false );
|
||||
}
|
||||
|
||||
void FileTimeToString( char *p, int size, long int time ) override
|
||||
{
|
||||
time_t curtime = time;
|
||||
char *buf = ctime( &curtime );
|
||||
Q_strncpy( p, buf, size );
|
||||
}
|
||||
|
||||
bool IsOk( FileHandle_t handle ) override
|
||||
{
|
||||
return !FS_Eof( (file_t *)handle );
|
||||
}
|
||||
|
||||
void Flush( FileHandle_t handle ) override
|
||||
{
|
||||
FS_Flush( (file_t *)handle );
|
||||
}
|
||||
|
||||
bool EndOfFile( FileHandle_t handle ) override
|
||||
{
|
||||
return FS_Eof( (file_t *)handle );
|
||||
}
|
||||
|
||||
int Read( void *buf, int size, FileHandle_t handle ) override
|
||||
{
|
||||
return FS_Read( (file_t *)handle, buf, size );
|
||||
}
|
||||
|
||||
int Write( const void *buf, int size, FileHandle_t handle ) override
|
||||
{
|
||||
return FS_Write( (file_t *)handle, buf, size );
|
||||
}
|
||||
|
||||
char *ReadLine( char *buf, int size, FileHandle_t handle ) override
|
||||
{
|
||||
int c = FS_Gets( (file_t *)handle, (byte*)buf, size );
|
||||
|
||||
return c >= 0 ? buf : NULL;
|
||||
}
|
||||
|
||||
int FPrintf( FileHandle_t handle, char *fmt, ... ) override
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start( ap, fmt );
|
||||
ret = FS_VPrintf( (file_t *)handle, fmt, ap );
|
||||
va_end( ap );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void * GetReadBuffer(FileHandle_t, int *size, bool) override
|
||||
{
|
||||
// deprecated by Valve
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ReleaseReadBuffer(FileHandle_t, void *) override
|
||||
{
|
||||
// deprecated by Valve
|
||||
return;
|
||||
}
|
||||
|
||||
const char *FindFirst(const char *pattern, FileFindHandle_t *handle, const char *id) override
|
||||
{
|
||||
if( !handle || !pattern )
|
||||
return NULL;
|
||||
|
||||
char *p = (char *)alloca( Q_strlen( pattern ) + 1 );
|
||||
CopyAndFixSlashes( p, pattern );
|
||||
search_t *search = FS_Search( p, true, IsIdGamedir( id ));
|
||||
|
||||
if( !search )
|
||||
return NULL;
|
||||
|
||||
CSearchState *state = new CSearchState( &searchHead, search );
|
||||
|
||||
*handle = state->handle;
|
||||
|
||||
return state->search->filenames[0];
|
||||
}
|
||||
|
||||
const char *FindNext( FileFindHandle_t handle ) override
|
||||
{
|
||||
CSearchState *state = GetSearchStateByHandle( handle );
|
||||
|
||||
if( !state ) return NULL;
|
||||
|
||||
if( state->index + 1 >= state->search->numfilenames )
|
||||
return NULL;
|
||||
|
||||
return state->search->filenames[++state->index];
|
||||
}
|
||||
|
||||
bool FindIsDirectory( FileFindHandle_t handle ) override
|
||||
{
|
||||
CSearchState *state = GetSearchStateByHandle( handle );
|
||||
|
||||
if( !state )
|
||||
return false;
|
||||
|
||||
if( state->index >= state->search->numfilenames )
|
||||
return false;
|
||||
|
||||
return IsDirectory( state->search->filenames[state->index] );
|
||||
}
|
||||
|
||||
void FindClose( FileFindHandle_t handle ) override
|
||||
{
|
||||
for( CSearchState *state = searchHead, **prev = NULL;
|
||||
state;
|
||||
*prev = state, state = state->next )
|
||||
{
|
||||
if( state->handle == handle )
|
||||
{
|
||||
if( prev )
|
||||
(*prev)->next = state->next;
|
||||
else searchHead = state->next;
|
||||
|
||||
delete state;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Con_DPrintf( "FindClose: Can't find search state by handle %d\n", handle );
|
||||
return;
|
||||
}
|
||||
|
||||
const char * GetLocalPath( const char *name, char *buf, int size ) override
|
||||
{
|
||||
if( !name ) return NULL;
|
||||
|
||||
char *p = (char *)alloca( Q_strlen( name ) + 1 );
|
||||
CopyAndFixSlashes( p, name );
|
||||
|
||||
#if !XASH_WIN32
|
||||
if( p[0] == '/' )
|
||||
#else
|
||||
if( Q_strchr( p, ':' ))
|
||||
#endif
|
||||
{
|
||||
Q_strncpy( buf, p, size );
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
const char *fullpath = FS_GetDiskPath( p, false );
|
||||
if( !fullpath )
|
||||
return NULL;
|
||||
|
||||
Q_strncpy( buf, fullpath, size );
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *ParseFile( char *buf, char *token, bool *quoted ) override
|
||||
{
|
||||
qboolean qquoted;
|
||||
|
||||
char *p = COM_ParseFileSafe( buf, token, PFILE_FS_TOKEN_MAX_LENGTH, 0, NULL, &qquoted );
|
||||
if( quoted ) *quoted = qquoted;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
bool FullPathToRelativePath( const char *path, char *out ) override
|
||||
{
|
||||
if( !COM_CheckString( path ))
|
||||
{
|
||||
*out = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
char *p = (char *)alloca( Q_strlen( path ) + 1 );
|
||||
CopyAndFixSlashes( p, path );
|
||||
searchpath_t *sp;
|
||||
|
||||
for( sp = fs_searchpaths; sp; sp = sp->next )
|
||||
{
|
||||
size_t splen = Q_strlen( sp->filename );
|
||||
|
||||
if( !Q_strnicmp( sp->filename, p, splen ))
|
||||
{
|
||||
Q_strcpy( out, p + splen + 1 );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Q_strcpy( out, p );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetCurrentDirectory( char *p, int size ) override
|
||||
{
|
||||
Q_strncpy( p, fs_rootdir, size );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PrintOpenedFiles() override
|
||||
{
|
||||
// we don't track this yet
|
||||
return;
|
||||
}
|
||||
|
||||
void SetWarningFunc(void (*)(const char *, ...)) override
|
||||
{
|
||||
// TODO:
|
||||
return;
|
||||
}
|
||||
|
||||
void SetWarningLevel(FileWarningLevel_t) override
|
||||
{
|
||||
// TODO:
|
||||
return;
|
||||
}
|
||||
|
||||
int SetVBuf( FileHandle_t handle, char *buf, int mode, long int size ) override
|
||||
{
|
||||
// TODO:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GetInterfaceVersion(char *p, int size) override
|
||||
{
|
||||
Q_strncpy( p, "Stdio", size );
|
||||
}
|
||||
|
||||
bool AddPackFile( const char *path, const char *id ) override
|
||||
{
|
||||
char *p = va( "%s/%s", IdToDir( id ), path );
|
||||
CopyAndFixSlashes( p, path );
|
||||
|
||||
return !!FS_AddPak_Fullpath( p, NULL, FS_CUSTOM_PATH );
|
||||
}
|
||||
|
||||
FileHandle_t OpenFromCacheForRead( const char *path , const char *mode, const char *id ) override
|
||||
{
|
||||
char *p = (char *)alloca( Q_strlen( path ) + 1 );
|
||||
CopyAndFixSlashes( p, path );
|
||||
|
||||
return FS_OpenReadFile( p, mode, IsIdGamedir( id ));
|
||||
}
|
||||
|
||||
// stubs
|
||||
void Mount() override {}
|
||||
void Unmount() override {}
|
||||
void GetLocalCopy(const char *) override {}
|
||||
void LogLevelLoadStarted(const char *) override {}
|
||||
void LogLevelLoadFinished(const char *) override {}
|
||||
void CancelWaitForResources(WaitForResourcesHandle_t) override {}
|
||||
int HintResourceNeed(const char *, int) override { return 0; }
|
||||
WaitForResourcesHandle_t WaitForResources(const char *) override { return 0; }
|
||||
int PauseResourcePreloading() override { return 0; }
|
||||
int ResumeResourcePreloading() override { return 0; }
|
||||
bool IsAppReadyForOfflinePlay(int) override { return true; }
|
||||
bool IsFileImmediatelyAvailable(const char *) override { return true; }
|
||||
bool GetWaitForResourcesProgress(WaitForResourcesHandle_t, float *pProgress, bool *pOverride) override
|
||||
{
|
||||
if( pProgress ) *pProgress = 0;
|
||||
if( pOverride ) *pOverride = true;
|
||||
return false;
|
||||
}
|
||||
} g_VFileSystem009;
|
||||
|
||||
extern "C" void EXPORT *CreateInterface( const char *interface, int *retval )
|
||||
{
|
||||
if( !Q_strcmp( interface, "VFileSystem009" ))
|
||||
{
|
||||
if( retval ) *retval = 0;
|
||||
return &g_VFileSystem009;
|
||||
}
|
||||
|
||||
if( !Q_strcmp( interface, FS_API_CREATEINTERFACE_TAG ))
|
||||
{
|
||||
// return a copy, to disallow overriding
|
||||
static fs_api_t copy = { 0 };
|
||||
|
||||
if( !copy.InitStdio )
|
||||
memcpy( ©, &g_api, sizeof( copy ));
|
||||
|
||||
if( retval ) *retval = 0;
|
||||
return ©
|
||||
}
|
||||
|
||||
if( retval ) *retval = 1;
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
VFileSystem009.h - C++ interface for filesystem_stdio
|
||||
Copyright (C) 2022 Alibek Omarov
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef VFILESYSTEM009_H
|
||||
#define VFILESYSTEM009_H
|
||||
|
||||
// exported from dwarf
|
||||
typedef enum {
|
||||
FILESYSTEM_SEEK_HEAD = 0,
|
||||
FILESYSTEM_SEEK_CURRENT = 1,
|
||||
FILESYSTEM_SEEK_TAIL = 2,
|
||||
} FileSystemSeek_t; /* size: 4 */
|
||||
|
||||
typedef enum {
|
||||
FILESYSTEM_WARNING_QUIET = 0,
|
||||
FILESYSTEM_WARNING_REPORTUNCLOSED = 1,
|
||||
FILESYSTEM_WARNING_REPORTUSAGE = 2,
|
||||
FILESYSTEM_WARNING_REPORTALLACCESSES = 3,
|
||||
} FileWarningLevel_t; /* size: 4 */
|
||||
|
||||
typedef void * FileHandle_t; /* size: 4 */
|
||||
typedef int FileFindHandle_t; /* size: 4 */
|
||||
typedef int WaitForResourcesHandle_t; /* size: 4 */
|
||||
|
||||
class IBaseInterface
|
||||
{
|
||||
public:
|
||||
virtual ~IBaseInterface() {}
|
||||
};
|
||||
|
||||
class IVFileSystem009 : public IBaseInterface
|
||||
{
|
||||
public:
|
||||
virtual void Mount() = 0; /* linkage=_ZN11IFileSystem5MountEv */
|
||||
|
||||
virtual void Unmount() = 0; /* linkage=_ZN11IFileSystem7UnmountEv */
|
||||
|
||||
virtual void RemoveAllSearchPaths() = 0; /* linkage=_ZN11IFileSystem20RemoveAllSearchPathsEv */
|
||||
|
||||
virtual void AddSearchPath(const char *, const char *) = 0; /* linkage=_ZN11IFileSystem13AddSearchPathEPKcS1_ */
|
||||
|
||||
virtual bool RemoveSearchPath(const char *) = 0; /* linkage=_ZN11IFileSystem16RemoveSearchPathEPKc */
|
||||
|
||||
virtual void RemoveFile(const char *, const char *) = 0; /* linkage=_ZN11IFileSystem10RemoveFileEPKcS1_ */
|
||||
|
||||
virtual void CreateDirHierarchy(const char *, const char *) = 0; /* linkage=_ZN11IFileSystem18CreateDirHierarchyEPKcS1_ */
|
||||
|
||||
virtual bool FileExists(const char *) = 0; /* linkage=_ZN11IFileSystem10FileExistsEPKc */
|
||||
|
||||
virtual bool IsDirectory(const char *) = 0; /* linkage=_ZN11IFileSystem11IsDirectoryEPKc */
|
||||
|
||||
virtual FileHandle_t Open(const char *, const char *, const char *) = 0; /* linkage=_ZN11IFileSystem4OpenEPKcS1_S1_ */
|
||||
|
||||
virtual void Close(FileHandle_t) = 0; /* linkage=_ZN11IFileSystem5CloseEPv */
|
||||
|
||||
virtual void Seek(FileHandle_t, int, FileSystemSeek_t) = 0; /* linkage=_ZN11IFileSystem4SeekEPvi16FileSystemSeek_t */
|
||||
|
||||
virtual unsigned int Tell(FileHandle_t) = 0; /* linkage=_ZN11IFileSystem4TellEPv */
|
||||
|
||||
virtual unsigned int Size(FileHandle_t) = 0; /* linkage=_ZN11IFileSystem4SizeEPv */
|
||||
|
||||
virtual unsigned int Size(const char *) = 0; /* linkage=_ZN11IFileSystem4SizeEPKc */
|
||||
|
||||
virtual long int GetFileTime(const char *) = 0; /* linkage=_ZN11IFileSystem11GetFileTimeEPKc */
|
||||
|
||||
virtual void FileTimeToString(char *, int, long int) = 0; /* linkage=_ZN11IFileSystem16FileTimeToStringEPcil */
|
||||
|
||||
virtual bool IsOk(FileHandle_t) = 0; /* linkage=_ZN11IFileSystem4IsOkEPv */
|
||||
|
||||
virtual void Flush(FileHandle_t) = 0; /* linkage=_ZN11IFileSystem5FlushEPv */
|
||||
|
||||
virtual bool EndOfFile(FileHandle_t) = 0; /* linkage=_ZN11IFileSystem9EndOfFileEPv */
|
||||
|
||||
virtual int Read(void *, int, FileHandle_t) = 0; /* linkage=_ZN11IFileSystem4ReadEPviS0_ */
|
||||
|
||||
virtual int Write(const void *, int, FileHandle_t) = 0; /* linkage=_ZN11IFileSystem5WriteEPKviPv */
|
||||
|
||||
virtual char * ReadLine(char *, int, FileHandle_t) = 0; /* linkage=_ZN11IFileSystem8ReadLineEPciPv */
|
||||
|
||||
virtual int FPrintf(FileHandle_t, char *, ...) = 0; /* linkage=_ZN11IFileSystem7FPrintfEPvPcz */
|
||||
|
||||
virtual void * GetReadBuffer(FileHandle_t, int *, bool) = 0; /* linkage=_ZN11IFileSystem13GetReadBufferEPvPib */
|
||||
|
||||
virtual void ReleaseReadBuffer(FileHandle_t, void *) = 0; /* linkage=_ZN11IFileSystem17ReleaseReadBufferEPvS0_ */
|
||||
|
||||
virtual const char * FindFirst(const char *, FileFindHandle_t *, const char *) = 0; /* linkage=_ZN11IFileSystem9FindFirstEPKcPiS1_ */
|
||||
|
||||
virtual const char * FindNext(FileFindHandle_t) = 0; /* linkage=_ZN11IFileSystem8FindNextEi */
|
||||
|
||||
virtual bool FindIsDirectory(FileFindHandle_t) = 0; /* linkage=_ZN11IFileSystem15FindIsDirectoryEi */
|
||||
|
||||
virtual void FindClose(FileFindHandle_t) = 0; /* linkage=_ZN11IFileSystem9FindCloseEi */
|
||||
|
||||
virtual void GetLocalCopy(const char *) = 0; /* linkage=_ZN11IFileSystem12GetLocalCopyEPKc */
|
||||
|
||||
virtual const char * GetLocalPath(const char *, char *, int) = 0; /* linkage=_ZN11IFileSystem12GetLocalPathEPKcPci */
|
||||
|
||||
virtual char * ParseFile(char *, char *, bool *) = 0; /* linkage=_ZN11IFileSystem9ParseFileEPcS0_Pb */
|
||||
|
||||
virtual bool FullPathToRelativePath(const char *, char *) = 0; /* linkage=_ZN11IFileSystem22FullPathToRelativePathEPKcPc */
|
||||
|
||||
virtual bool GetCurrentDirectory(char *, int) = 0; /* linkage=_ZN11IFileSystem19GetCurrentDirectoryEPci */
|
||||
|
||||
virtual void PrintOpenedFiles() = 0; /* linkage=_ZN11IFileSystem16PrintOpenedFilesEv */
|
||||
|
||||
virtual void SetWarningFunc(void (*)(const char *, ...)) = 0; /* linkage=_ZN11IFileSystem14SetWarningFuncEPFvPKczE */
|
||||
|
||||
virtual void SetWarningLevel(FileWarningLevel_t) = 0; /* linkage=_ZN11IFileSystem15SetWarningLevelE18FileWarningLevel_t */
|
||||
|
||||
virtual void LogLevelLoadStarted(const char *) = 0; /* linkage=_ZN11IFileSystem19LogLevelLoadStartedEPKc */
|
||||
|
||||
virtual void LogLevelLoadFinished(const char *) = 0; /* linkage=_ZN11IFileSystem20LogLevelLoadFinishedEPKc */
|
||||
|
||||
virtual int HintResourceNeed(const char *, int) = 0; /* linkage=_ZN11IFileSystem16HintResourceNeedEPKci */
|
||||
|
||||
virtual int PauseResourcePreloading() = 0; /* linkage=_ZN11IFileSystem23PauseResourcePreloadingEv */
|
||||
|
||||
virtual int ResumeResourcePreloading() = 0; /* linkage=_ZN11IFileSystem24ResumeResourcePreloadingEv */
|
||||
|
||||
virtual int SetVBuf(FileHandle_t, char *, int, long int) = 0; /* linkage=_ZN11IFileSystem7SetVBufEPvPcil */
|
||||
|
||||
virtual void GetInterfaceVersion(char *, int) = 0; /* linkage=_ZN11IFileSystem19GetInterfaceVersionEPci */
|
||||
|
||||
virtual bool IsFileImmediatelyAvailable(const char *) = 0; /* linkage=_ZN11IFileSystem26IsFileImmediatelyAvailableEPKc */
|
||||
|
||||
virtual WaitForResourcesHandle_t WaitForResources(const char *) = 0; /* linkage=_ZN11IFileSystem16WaitForResourcesEPKc */
|
||||
|
||||
virtual bool GetWaitForResourcesProgress(WaitForResourcesHandle_t, float *, bool *) = 0; /* linkage=_ZN11IFileSystem27GetWaitForResourcesProgressEiPfPb */
|
||||
|
||||
virtual void CancelWaitForResources(WaitForResourcesHandle_t) = 0; /* linkage=_ZN11IFileSystem22CancelWaitForResourcesEi */
|
||||
|
||||
virtual bool IsAppReadyForOfflinePlay(int) = 0; /* linkage=_ZN11IFileSystem24IsAppReadyForOfflinePlayEi */
|
||||
|
||||
virtual bool AddPackFile(const char *, const char *) = 0; /* linkage=_ZN11IFileSystem11AddPackFileEPKcS1_ */
|
||||
|
||||
virtual FileHandle_t OpenFromCacheForRead(const char *, const char *, const char *) = 0; /* linkage=_ZN11IFileSystem20OpenFromCacheForReadEPKcS1_S1_ */
|
||||
|
||||
virtual void AddSearchPathNoWrite(const char *, const char *) = 0; /* linkage=_ZN11IFileSystem20AddSearchPathNoWriteEPKcS1_ */
|
||||
};
|
||||
|
||||
#endif // VFILESYSTEM009_H
|
||||
@@ -1,210 +0,0 @@
|
||||
/*
|
||||
filesystem.h - engine FS
|
||||
Copyright (C) 2007 Uncle Mike
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef FILESYSTEM_H
|
||||
#define FILESYSTEM_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include "xash3d_types.h"
|
||||
#include "const.h"
|
||||
#include "com_model.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif // __cplusplus
|
||||
|
||||
#define FS_API_VERSION 1 // not stable yet!
|
||||
#define FS_API_CREATEINTERFACE_TAG "XashFileSystem001" // follow FS_API_VERSION!!!
|
||||
|
||||
// search path flags
|
||||
enum
|
||||
{
|
||||
FS_STATIC_PATH = BIT( 0 ), // FS_ClearSearchPath will be ignore this path
|
||||
FS_NOWRITE_PATH = BIT( 1 ), // default behavior - last added gamedir set as writedir. This flag disables it
|
||||
FS_GAMEDIR_PATH = BIT( 2 ), // just a marker for gamedir path
|
||||
FS_CUSTOM_PATH = BIT( 3 ), // gamedir but with custom/mod data
|
||||
FS_GAMERODIR_PATH = BIT( 4 ), // gamedir but read-only
|
||||
|
||||
FS_GAMEDIRONLY_SEARCH_FLAGS = FS_GAMEDIR_PATH | FS_CUSTOM_PATH | FS_GAMERODIR_PATH
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int numfilenames;
|
||||
char **filenames;
|
||||
char *filenamesbuffer;
|
||||
} search_t;
|
||||
|
||||
typedef struct gameinfo_s
|
||||
{
|
||||
// filesystem info
|
||||
char gamefolder[MAX_QPATH]; // used for change game '-game x'
|
||||
char basedir[MAX_QPATH]; // base game directory (like 'id1' for Quake or 'valve' for Half-Life)
|
||||
char falldir[MAX_QPATH]; // used as second basedir
|
||||
char startmap[MAX_QPATH];// map to start singleplayer game
|
||||
char trainmap[MAX_QPATH];// map to start hazard course (if specified)
|
||||
char title[64]; // Game Main Title
|
||||
float version; // game version (optional)
|
||||
|
||||
// .dll pathes
|
||||
char dll_path[MAX_QPATH]; // e.g. "bin" or "cl_dlls"
|
||||
char game_dll[MAX_QPATH]; // custom path for game.dll
|
||||
|
||||
// .ico path
|
||||
char iconpath[MAX_QPATH]; // "game.ico" by default
|
||||
|
||||
// about mod info
|
||||
string game_url; // link to a developer's site
|
||||
string update_url; // link to updates page
|
||||
char type[MAX_QPATH]; // single, toolkit, multiplayer etc
|
||||
char date[MAX_QPATH];
|
||||
size_t size;
|
||||
|
||||
int gamemode;
|
||||
qboolean secure; // prevent to console acess
|
||||
qboolean nomodels; // don't let player to choose model (use player.mdl always)
|
||||
qboolean noskills; // disable skill menu selection
|
||||
qboolean render_picbutton_text; // use font renderer to render WON buttons
|
||||
|
||||
char sp_entity[32]; // e.g. info_player_start
|
||||
char mp_entity[32]; // e.g. info_player_deathmatch
|
||||
char mp_filter[32]; // filtering multiplayer-maps
|
||||
|
||||
char ambientsound[NUM_AMBIENTS][MAX_QPATH]; // quake ambient sounds
|
||||
|
||||
int max_edicts; // min edicts is 600, max edicts is 8196
|
||||
int max_tents; // min temp ents is 300, max is 2048
|
||||
int max_beams; // min beams is 64, max beams is 512
|
||||
int max_particles; // min particles is 4096, max particles is 32768
|
||||
|
||||
char game_dll_linux[64]; // custom path for game.dll
|
||||
char game_dll_osx[64]; // custom path for game.dll
|
||||
|
||||
qboolean added;
|
||||
} gameinfo_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GAME_NORMAL,
|
||||
GAME_SINGLEPLAYER_ONLY,
|
||||
GAME_MULTIPLAYER_ONLY
|
||||
} gametype_t;
|
||||
|
||||
typedef struct fs_dllinfo_t
|
||||
{
|
||||
string fullPath;
|
||||
string shortPath;
|
||||
qboolean encrypted;
|
||||
qboolean custom_loader;
|
||||
} fs_dllinfo_t;
|
||||
|
||||
typedef struct fs_globals_t
|
||||
{
|
||||
gameinfo_t *GameInfo; // current GameInfo
|
||||
gameinfo_t *games[MAX_MODS]; // environment games (founded at each engine start)
|
||||
int numgames;
|
||||
} fs_globals_t;
|
||||
|
||||
typedef void (*fs_event_callback_t)( const char *path );
|
||||
|
||||
|
||||
typedef struct fs_api_t
|
||||
{
|
||||
qboolean (*InitStdio)( qboolean caseinsensitive, const char *rootdir, const char *basedir, const char *gamedir, const char *rodir );
|
||||
void (*ShutdownStdio)( void );
|
||||
|
||||
// search path utils
|
||||
void (*Rescan)( void );
|
||||
void (*ClearSearchPath)( void );
|
||||
void (*AllowDirectPaths)( qboolean enable );
|
||||
void (*AddGameDirectory)( const char *dir, uint flags );
|
||||
void (*AddGameHierarchy)( const char *dir, uint flags );
|
||||
search_t *(*Search)( const char *pattern, int caseinsensitive, int gamedironly );
|
||||
int (*SetCurrentDirectory)( const char *path );
|
||||
qboolean (*FindLibrary)( const char *dllname, qboolean directpath, fs_dllinfo_t *dllinfo );
|
||||
void (*Path_f)( void );
|
||||
|
||||
// gameinfo utils
|
||||
void (*LoadGameInfo)( const char *rootfolder );
|
||||
|
||||
// file ops
|
||||
file_t *(*Open)( const char *filepath, const char *mode, qboolean gamedironly );
|
||||
fs_offset_t (*Write)( file_t *file, const void *data, size_t datasize );
|
||||
fs_offset_t (*Read)( file_t *file, void *buffer, size_t buffersize );
|
||||
int (*Seek)( file_t *file, fs_offset_t offset, int whence );
|
||||
fs_offset_t (*Tell)( file_t *file );
|
||||
qboolean (*Eof)( file_t *file );
|
||||
int (*Flush)( file_t *file );
|
||||
int (*Close)( file_t *file );
|
||||
int (*Gets)( file_t *file, byte *string, size_t bufsize );
|
||||
int (*UnGetc)( file_t *file, byte c );
|
||||
int (*Getc)( file_t *file );
|
||||
int (*VPrintf)( file_t *file, const char *format, va_list ap );
|
||||
int (*Printf)( file_t *file, const char *format, ... ) _format( 2 );
|
||||
int (*Print)( file_t *file, const char *msg );
|
||||
fs_offset_t (*FileLength)( file_t *f );
|
||||
qboolean (*FileCopy)( file_t *pOutput, file_t *pInput, int fileSize );
|
||||
|
||||
// file buffer ops
|
||||
byte *(*LoadFile)( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
|
||||
byte *(*LoadDirectFile)( const char *path, fs_offset_t *filesizeptr );
|
||||
qboolean (*WriteFile)( const char *filename, const void *data, fs_offset_t len );
|
||||
|
||||
// file hashing
|
||||
qboolean (*CRC32_File)( dword *crcvalue, const char *filename );
|
||||
qboolean (*MD5_HashFile)( byte digest[16], const char *pszFileName, uint seed[4] );
|
||||
|
||||
// filesystem ops
|
||||
int (*FileExists)( const char *filename, int gamedironly );
|
||||
int (*FileTime)( const char *filename, qboolean gamedironly );
|
||||
fs_offset_t (*FileSize)( const char *filename, qboolean gamedironly );
|
||||
qboolean (*Rename)( const char *oldname, const char *newname );
|
||||
qboolean (*Delete)( const char *path );
|
||||
qboolean (*SysFileExists)( const char *path, qboolean casesensitive );
|
||||
const char *(*GetDiskPath)( const char *name, qboolean gamedironly );
|
||||
|
||||
// file watcher
|
||||
void (*WatchFrame)( void ); // engine will read all events and call appropriate callbacks
|
||||
qboolean (*AddWatch)( const char *path, fs_event_callback_t callback );
|
||||
} fs_api_t;
|
||||
|
||||
typedef struct fs_interface_t
|
||||
{
|
||||
// logging
|
||||
void (*_Con_Printf)( const char *fmt, ... ) _format( 1 ); // typical console allowed messages
|
||||
void (*_Con_DPrintf)( const char *fmt, ... ) _format( 1 ); // -dev 1
|
||||
void (*_Con_Reportf)( const char *fmt, ... ) _format( 1 ); // -dev 2
|
||||
|
||||
void (*_Sys_Error)( const char *fmt, ... ) _format( 1 );
|
||||
|
||||
// memory
|
||||
poolhandle_t (*_Mem_AllocPool)( const char *name, const char *filename, int fileline );
|
||||
void (*_Mem_FreePool)( poolhandle_t *poolptr, const char *filename, int fileline );
|
||||
void *(*_Mem_Alloc)( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline );
|
||||
void *(*_Mem_Realloc)( poolhandle_t poolptr, void *memptr, size_t size, qboolean clear, const char *filename, int fileline );
|
||||
void (*_Mem_Free)( void *data, const char *filename, int fileline );
|
||||
} fs_interface_t;
|
||||
|
||||
typedef int (*FSAPI)( int version, fs_api_t *api, fs_globals_t **globals, fs_interface_t *interface );
|
||||
#define GET_FS_API "GetFSAPI"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif//FILESYSTEM_H
|
||||
@@ -1,215 +0,0 @@
|
||||
/*
|
||||
filesystem.h - engine FS
|
||||
Copyright (C) 2007 Uncle Mike
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef FILESYSTEM_INTERNAL_H
|
||||
#define FILESYSTEM_INTERNAL_H
|
||||
|
||||
#include "xash3d_types.h"
|
||||
#include "filesystem.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef struct zip_s zip_t;
|
||||
typedef struct pack_s pack_t;
|
||||
typedef struct wfile_s wfile_t;
|
||||
|
||||
#define FILE_BUFF_SIZE (2048)
|
||||
|
||||
struct file_s
|
||||
{
|
||||
int handle; // file descriptor
|
||||
int ungetc; // single stored character from ungetc, cleared to EOF when read
|
||||
fs_offset_t real_length; // uncompressed file size (for files opened in "read" mode)
|
||||
fs_offset_t position; // current position in the file
|
||||
fs_offset_t offset; // offset into the package (0 if external file)
|
||||
time_t filetime; // pak, wad or real filetime
|
||||
// contents buffer
|
||||
fs_offset_t buff_ind, buff_len; // buffer current index and length
|
||||
byte buff[FILE_BUFF_SIZE]; // intermediate buffer
|
||||
#ifdef XASH_REDUCE_FD
|
||||
const char *backup_path;
|
||||
fs_offset_t backup_position;
|
||||
uint backup_options;
|
||||
#endif
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SEARCHPATH_PLAIN = 0,
|
||||
SEARCHPATH_PAK,
|
||||
SEARCHPATH_WAD,
|
||||
SEARCHPATH_ZIP
|
||||
};
|
||||
|
||||
typedef struct stringlist_s
|
||||
{
|
||||
// maxstrings changes as needed, causing reallocation of strings[] array
|
||||
int maxstrings;
|
||||
int numstrings;
|
||||
char **strings;
|
||||
} stringlist_t;
|
||||
|
||||
typedef struct searchpath_s
|
||||
{
|
||||
string filename;
|
||||
int type;
|
||||
int flags;
|
||||
union
|
||||
{
|
||||
pack_t *pack;
|
||||
wfile_t *wad;
|
||||
zip_t *zip;
|
||||
};
|
||||
struct searchpath_s *next;
|
||||
} searchpath_t;
|
||||
|
||||
extern fs_globals_t FI;
|
||||
extern searchpath_t *fs_searchpaths;
|
||||
extern poolhandle_t fs_mempool;
|
||||
extern fs_interface_t g_engfuncs;
|
||||
extern qboolean fs_ext_path;
|
||||
extern char fs_rodir[MAX_SYSPATH];
|
||||
extern char fs_rootdir[MAX_SYSPATH];
|
||||
extern char fs_writedir[MAX_SYSPATH];
|
||||
extern fs_api_t g_api;
|
||||
|
||||
#define GI FI.GameInfo
|
||||
|
||||
#define Mem_Malloc( pool, size ) g_engfuncs._Mem_Alloc( pool, size, false, __FILE__, __LINE__ )
|
||||
#define Mem_Calloc( pool, size ) g_engfuncs._Mem_Alloc( pool, size, true, __FILE__, __LINE__ )
|
||||
#define Mem_Realloc( pool, ptr, size ) g_engfuncs._Mem_Realloc( pool, ptr, size, true, __FILE__, __LINE__ )
|
||||
#define Mem_Free( mem ) g_engfuncs._Mem_Free( mem, __FILE__, __LINE__ )
|
||||
#define Mem_AllocPool( name ) g_engfuncs._Mem_AllocPool( name, __FILE__, __LINE__ )
|
||||
#define Mem_FreePool( pool ) g_engfuncs._Mem_FreePool( pool, __FILE__, __LINE__ )
|
||||
|
||||
#define Con_Printf (*g_engfuncs._Con_Printf)
|
||||
#define Con_DPrintf (*g_engfuncs._Con_DPrintf)
|
||||
#define Con_Reportf (*g_engfuncs._Con_Reportf)
|
||||
#define Sys_Error (*g_engfuncs._Sys_Error)
|
||||
|
||||
//
|
||||
// filesystem.c
|
||||
//
|
||||
qboolean FS_InitStdio( qboolean caseinsensitive, const char *rootdir, const char *basedir, const char *gamedir, const char *rodir );
|
||||
void FS_ShutdownStdio( void );
|
||||
|
||||
// search path utils
|
||||
void FS_Rescan( void );
|
||||
void FS_ClearSearchPath( void );
|
||||
void FS_AllowDirectPaths( qboolean enable );
|
||||
void FS_AddGameDirectory( const char *dir, uint flags );
|
||||
void FS_AddGameHierarchy( const char *dir, uint flags );
|
||||
search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly );
|
||||
int FS_SetCurrentDirectory( const char *path );
|
||||
void FS_Path_f( void );
|
||||
|
||||
// gameinfo utils
|
||||
void FS_LoadGameInfo( const char *rootfolder );
|
||||
|
||||
// file ops
|
||||
file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly );
|
||||
fs_offset_t FS_Write( file_t *file, const void *data, size_t datasize );
|
||||
fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize );
|
||||
int FS_Seek( file_t *file, fs_offset_t offset, int whence );
|
||||
fs_offset_t FS_Tell( file_t *file );
|
||||
qboolean FS_Eof( file_t *file );
|
||||
int FS_Flush( file_t *file );
|
||||
int FS_Close( file_t *file );
|
||||
int FS_Gets( file_t *file, byte *string, size_t bufsize );
|
||||
int FS_UnGetc( file_t *file, byte c );
|
||||
int FS_Getc( file_t *file );
|
||||
int FS_VPrintf( file_t *file, const char *format, va_list ap );
|
||||
int FS_Printf( file_t *file, const char *format, ... ) _format( 2 );
|
||||
int FS_Print( file_t *file, const char *msg );
|
||||
fs_offset_t FS_FileLength( file_t *f );
|
||||
qboolean FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize );
|
||||
|
||||
// file buffer ops
|
||||
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
|
||||
byte *FS_LoadDirectFile( const char *path, fs_offset_t *filesizeptr );
|
||||
qboolean FS_WriteFile( const char *filename, const void *data, fs_offset_t len );
|
||||
|
||||
// file hashing
|
||||
qboolean CRC32_File( dword *crcvalue, const char *filename );
|
||||
qboolean MD5_HashFile( byte digest[16], const char *pszFileName, uint seed[4] );
|
||||
|
||||
// filesystem ops
|
||||
int FS_FileExists( const char *filename, int gamedironly );
|
||||
int FS_FileTime( const char *filename, qboolean gamedironly );
|
||||
fs_offset_t FS_FileSize( const char *filename, qboolean gamedironly );
|
||||
qboolean FS_Rename( const char *oldname, const char *newname );
|
||||
qboolean FS_Delete( const char *path );
|
||||
qboolean FS_SysFileExists( const char *path, qboolean casesensitive );
|
||||
const char *FS_GetDiskPath( const char *name, qboolean gamedironly );
|
||||
void stringlistappend( stringlist_t *list, char *text );
|
||||
void FS_CreatePath( char *path );
|
||||
qboolean FS_SysFolderExists( const char *path );
|
||||
file_t *FS_OpenReadFile( const char *filename, const char *mode, qboolean gamedironly );
|
||||
|
||||
int FS_SysFileTime( const char *filename );
|
||||
file_t *FS_OpenHandle( const char *syspath, int handle, fs_offset_t offset, fs_offset_t len );
|
||||
file_t *FS_SysOpen( const char *filepath, const char *mode );
|
||||
const char *FS_FixFileCase( const char *path );
|
||||
searchpath_t *FS_FindFile( const char *name, int *index, qboolean gamedironly );
|
||||
|
||||
//
|
||||
// pak.c
|
||||
//
|
||||
int FS_FileTimePAK( pack_t *pack );
|
||||
int FS_FindFilePAK( pack_t *pack, const char *name );
|
||||
void FS_PrintPAKInfo( char *dst, size_t size, pack_t *pack );
|
||||
void FS_ClosePAK( pack_t *pack );
|
||||
void FS_SearchPAK( stringlist_t *list, pack_t *pack, const char *pattern );
|
||||
file_t *FS_OpenPackedFile( pack_t *pack, int pack_ind );
|
||||
qboolean FS_AddPak_Fullpath( const char *pakfile, qboolean *already_loaded, int flags );
|
||||
|
||||
//
|
||||
// wad.c
|
||||
//
|
||||
int FS_FileTimeWAD( wfile_t *wad );
|
||||
int FS_FindFileWAD( wfile_t *wad, const char *name );
|
||||
void FS_PrintWADInfo( char *dst, size_t size, wfile_t *wad );
|
||||
void FS_CloseWAD( wfile_t *wad );
|
||||
void FS_SearchWAD( stringlist_t *list, wfile_t *wad, const char *pattern );
|
||||
byte *FS_LoadWADFile( const char *path, fs_offset_t *sizeptr, qboolean gamedironly );
|
||||
qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loaded, int flags );
|
||||
|
||||
//
|
||||
// watch.c
|
||||
//
|
||||
qboolean FS_WatchInitialize( void );
|
||||
int FS_AddWatch( const char *path, fs_event_callback_t callback );
|
||||
void FS_WatchFrame( void );
|
||||
|
||||
//
|
||||
// zip.c
|
||||
//
|
||||
int FS_FileTimeZIP( zip_t *zip );
|
||||
int FS_FindFileZIP( zip_t *zip, const char *name );
|
||||
void FS_PrintZIPInfo( char *dst, size_t size, zip_t *zip );
|
||||
void FS_CloseZIP( zip_t *zip );
|
||||
void FS_SearchZIP( stringlist_t *list, zip_t *zip, const char *pattern );
|
||||
byte *FS_LoadZIPFile( const char *path, fs_offset_t *sizeptr, qboolean gamedironly );
|
||||
file_t *FS_OpenZipFile( zip_t *zip, int pack_ind );
|
||||
qboolean FS_AddZip_Fullpath( const char *zipfile, qboolean *already_loaded, int flags );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // FILESYSTEM_INTERNAL_H
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
fscallback.h - common filesystem callbacks
|
||||
Copyright (C) 2022 Alibek Omarov
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
#ifndef FSCALLBACK_H
|
||||
#define FSCALLBACK_H
|
||||
|
||||
#include "filesystem.h"
|
||||
|
||||
extern fs_api_t g_fsapi;
|
||||
extern fs_globals_t *FI;
|
||||
|
||||
#define GI FI->GameInfo
|
||||
#define FS_Gamedir() GI->gamefolder
|
||||
#define FS_Title() GI->title
|
||||
|
||||
#define FS_InitStdio (*g_fsapi.InitStdio)
|
||||
#define FS_ShutdownStdio (*g_fsapi.ShutdownStdio)
|
||||
|
||||
// search path utils
|
||||
#define FS_Rescan (*g_fsapi.Rescan)
|
||||
#define FS_ClearSearchPath (*g_fsapi.ClearSearchPath)
|
||||
#define FS_AllowDirectPaths (*g_fsapi.AllowDirectPaths)
|
||||
#define FS_AddGameDirectory (*g_fsapi.AddGameDirectory)
|
||||
#define FS_AddGameHierarchy (*g_fsapi.AddGameHierarchy)
|
||||
#define FS_Search (*g_fsapi.Search)
|
||||
#define FS_SetCurrentDirectory (*g_fsapi.SetCurrentDirectory)
|
||||
#define FS_Path_f (*g_fsapi.Path_f)
|
||||
|
||||
// gameinfo utils
|
||||
#define FS_LoadGameInfo (*g_fsapi.LoadGameInfo)
|
||||
|
||||
// file ops
|
||||
#define FS_Open (*g_fsapi.Open)
|
||||
#define FS_Write (*g_fsapi.Write)
|
||||
#define FS_Read (*g_fsapi.Read)
|
||||
#define FS_Seek (*g_fsapi.Seek)
|
||||
#define FS_Tell (*g_fsapi.Tell)
|
||||
#define FS_Eof (*g_fsapi.Eof)
|
||||
#define FS_Flush (*g_fsapi.Flush)
|
||||
#define FS_Close (*g_fsapi.Close)
|
||||
#define FS_Gets (*g_fsapi.Gets)
|
||||
#define FS_UnGetc (*g_fsapi.UnGetc)
|
||||
#define FS_Getc (*g_fsapi.Getc)
|
||||
#define FS_VPrintf (*g_fsapi.VPrintf)
|
||||
#define FS_Printf (*g_fsapi.Printf)
|
||||
#define FS_Print (*g_fsapi.Print)
|
||||
#define FS_FileLength (*g_fsapi.FileLength)
|
||||
#define FS_FileCopy (*g_fsapi.FileCopy)
|
||||
|
||||
// file buffer ops
|
||||
#define FS_LoadFile (*g_fsapi.LoadFile)
|
||||
#define FS_LoadDirectFile (*g_fsapi.LoadDirectFile)
|
||||
#define FS_WriteFile (*g_fsapi.WriteFile)
|
||||
|
||||
// file hashing
|
||||
#define CRC32_File (*g_fsapi.CRC32_File)
|
||||
#define MD5_HashFile (*g_fsapi.MD5_HashFile)
|
||||
|
||||
// filesystem ops
|
||||
#define FS_FileExists (*g_fsapi.FileExists)
|
||||
#define FS_FileTime (*g_fsapi.FileTime)
|
||||
#define FS_FileSize (*g_fsapi.FileSize)
|
||||
#define FS_Rename (*g_fsapi.Rename)
|
||||
#define FS_Delete (*g_fsapi.Delete)
|
||||
#define FS_SysFileExists (*g_fsapi.SysFileExists)
|
||||
#define FS_GetDiskPath (*g_fsapi.GetDiskPath)
|
||||
|
||||
|
||||
#endif // FSCALLBACK_H
|
||||
397
filesystem/pak.c
397
filesystem/pak.c
@@ -1,397 +0,0 @@
|
||||
/*
|
||||
pak.c - PAK support for filesystem
|
||||
Copyright (C) 2007 Uncle Mike
|
||||
Copyright (C) 2022 Alibek Omarov
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "build.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#if XASH_POSIX
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include "port.h"
|
||||
#include "filesystem_internal.h"
|
||||
#include "crtlib.h"
|
||||
#include "common/com_strings.h"
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
PAK FILES
|
||||
|
||||
The .pak files are just a linear collapse of a directory tree
|
||||
========================================================================
|
||||
*/
|
||||
// header
|
||||
#define IDPACKV1HEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P') // little-endian "PACK"
|
||||
|
||||
#define MAX_FILES_IN_PACK 65536 // pak
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int ident;
|
||||
int dirofs;
|
||||
int dirlen;
|
||||
} dpackheader_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[56]; // total 64 bytes
|
||||
int filepos;
|
||||
int filelen;
|
||||
} dpackfile_t;
|
||||
|
||||
// PAK errors
|
||||
#define PAK_LOAD_OK 0
|
||||
#define PAK_LOAD_COULDNT_OPEN 1
|
||||
#define PAK_LOAD_BAD_HEADER 2
|
||||
#define PAK_LOAD_BAD_FOLDERS 3
|
||||
#define PAK_LOAD_TOO_MANY_FILES 4
|
||||
#define PAK_LOAD_NO_FILES 5
|
||||
#define PAK_LOAD_CORRUPTED 6
|
||||
|
||||
struct pack_s
|
||||
{
|
||||
string filename;
|
||||
int handle;
|
||||
int numfiles;
|
||||
time_t filetime; // common for all packed files
|
||||
dpackfile_t *files;
|
||||
};
|
||||
|
||||
/*
|
||||
====================
|
||||
FS_AddFileToPack
|
||||
|
||||
Add a file to the list of files contained into a package
|
||||
====================
|
||||
*/
|
||||
static dpackfile_t *FS_AddFileToPack( const char *name, pack_t *pack, fs_offset_t offset, fs_offset_t size )
|
||||
{
|
||||
int left, right, middle;
|
||||
dpackfile_t *pfile;
|
||||
|
||||
// look for the slot we should put that file into (binary search)
|
||||
left = 0;
|
||||
right = pack->numfiles - 1;
|
||||
|
||||
while( left <= right )
|
||||
{
|
||||
int diff;
|
||||
|
||||
middle = (left + right) / 2;
|
||||
diff = Q_stricmp( pack->files[middle].name, name );
|
||||
|
||||
// If we found the file, there's a problem
|
||||
if( !diff ) Con_Reportf( S_WARN "package %s contains the file %s several times\n", pack->filename, name );
|
||||
|
||||
// If we're too far in the list
|
||||
if( diff > 0 ) right = middle - 1;
|
||||
else left = middle + 1;
|
||||
}
|
||||
|
||||
// We have to move the right of the list by one slot to free the one we need
|
||||
pfile = &pack->files[left];
|
||||
memmove( pfile + 1, pfile, (pack->numfiles - left) * sizeof( *pfile ));
|
||||
pack->numfiles++;
|
||||
|
||||
Q_strncpy( pfile->name, name, sizeof( pfile->name ));
|
||||
pfile->filepos = offset;
|
||||
pfile->filelen = size;
|
||||
|
||||
return pfile;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
FS_LoadPackPAK
|
||||
|
||||
Takes an explicit (not game tree related) path to a pak file.
|
||||
|
||||
Loads the header and directory, adding the files at the beginning
|
||||
of the list so they override previous pack files.
|
||||
=================
|
||||
*/
|
||||
static pack_t *FS_LoadPackPAK( const char *packfile, int *error )
|
||||
{
|
||||
dpackheader_t header;
|
||||
int packhandle;
|
||||
int i, numpackfiles;
|
||||
pack_t *pack;
|
||||
dpackfile_t *info;
|
||||
fs_size_t c;
|
||||
|
||||
packhandle = open( packfile, O_RDONLY|O_BINARY );
|
||||
|
||||
#if !XASH_WIN32
|
||||
if( packhandle < 0 )
|
||||
{
|
||||
const char *fpackfile = FS_FixFileCase( packfile );
|
||||
if( fpackfile != packfile )
|
||||
packhandle = open( fpackfile, O_RDONLY|O_BINARY );
|
||||
}
|
||||
#endif
|
||||
|
||||
if( packhandle < 0 )
|
||||
{
|
||||
Con_Reportf( "%s couldn't open: %s\n", packfile, strerror( errno ));
|
||||
if( error ) *error = PAK_LOAD_COULDNT_OPEN;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
c = read( packhandle, (void *)&header, sizeof( header ));
|
||||
|
||||
if( c != sizeof( header ) || header.ident != IDPACKV1HEADER )
|
||||
{
|
||||
Con_Reportf( "%s is not a packfile. Ignored.\n", packfile );
|
||||
if( error ) *error = PAK_LOAD_BAD_HEADER;
|
||||
close( packhandle );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( header.dirlen % sizeof( dpackfile_t ))
|
||||
{
|
||||
Con_Reportf( S_ERROR "%s has an invalid directory size. Ignored.\n", packfile );
|
||||
if( error ) *error = PAK_LOAD_BAD_FOLDERS;
|
||||
close( packhandle );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
numpackfiles = header.dirlen / sizeof( dpackfile_t );
|
||||
|
||||
if( numpackfiles > MAX_FILES_IN_PACK )
|
||||
{
|
||||
Con_Reportf( S_ERROR "%s has too many files ( %i ). Ignored.\n", packfile, numpackfiles );
|
||||
if( error ) *error = PAK_LOAD_TOO_MANY_FILES;
|
||||
close( packhandle );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( numpackfiles <= 0 )
|
||||
{
|
||||
Con_Reportf( "%s has no files. Ignored.\n", packfile );
|
||||
if( error ) *error = PAK_LOAD_NO_FILES;
|
||||
close( packhandle );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info = (dpackfile_t *)Mem_Malloc( fs_mempool, sizeof( *info ) * numpackfiles );
|
||||
lseek( packhandle, header.dirofs, SEEK_SET );
|
||||
|
||||
if( header.dirlen != read( packhandle, (void *)info, header.dirlen ))
|
||||
{
|
||||
Con_Reportf( "%s is an incomplete PAK, not loading\n", packfile );
|
||||
if( error ) *error = PAK_LOAD_CORRUPTED;
|
||||
close( packhandle );
|
||||
Mem_Free( info );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pack = (pack_t *)Mem_Calloc( fs_mempool, sizeof( pack_t ));
|
||||
Q_strncpy( pack->filename, packfile, sizeof( pack->filename ));
|
||||
pack->files = (dpackfile_t *)Mem_Calloc( fs_mempool, numpackfiles * sizeof( dpackfile_t ));
|
||||
pack->filetime = FS_SysFileTime( packfile );
|
||||
pack->handle = packhandle;
|
||||
pack->numfiles = 0;
|
||||
|
||||
// parse the directory
|
||||
for( i = 0; i < numpackfiles; i++ )
|
||||
FS_AddFileToPack( info[i].name, pack, info[i].filepos, info[i].filelen );
|
||||
|
||||
#ifdef XASH_REDUCE_FD
|
||||
// will reopen when needed
|
||||
close( pack->handle );
|
||||
pack->handle = -1;
|
||||
#endif
|
||||
|
||||
if( error ) *error = PAK_LOAD_OK;
|
||||
Mem_Free( info );
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
FS_OpenPackedFile
|
||||
|
||||
Open a packed file using its package file descriptor
|
||||
===========
|
||||
*/
|
||||
file_t *FS_OpenPackedFile( pack_t *pack, int pack_ind )
|
||||
{
|
||||
dpackfile_t *pfile;
|
||||
|
||||
pfile = &pack->files[pack_ind];
|
||||
|
||||
return FS_OpenHandle( pack->filename, pack->handle, pfile->filepos, pfile->filelen );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FS_AddPak_Fullpath
|
||||
|
||||
Adds the given pack to the search path.
|
||||
The pack type is autodetected by the file extension.
|
||||
|
||||
Returns true if the file was successfully added to the
|
||||
search path or if it was already included.
|
||||
|
||||
If keep_plain_dirs is set, the pack will be added AFTER the first sequence of
|
||||
plain directories.
|
||||
================
|
||||
*/
|
||||
qboolean FS_AddPak_Fullpath( const char *pakfile, qboolean *already_loaded, int flags )
|
||||
{
|
||||
searchpath_t *search;
|
||||
pack_t *pak = NULL;
|
||||
const char *ext = COM_FileExtension( pakfile );
|
||||
int i, errorcode = PAK_LOAD_COULDNT_OPEN;
|
||||
|
||||
for( search = fs_searchpaths; search; search = search->next )
|
||||
{
|
||||
if( search->type == SEARCHPATH_PAK && !Q_stricmp( search->pack->filename, pakfile ))
|
||||
{
|
||||
if( already_loaded ) *already_loaded = true;
|
||||
return true; // already loaded
|
||||
}
|
||||
}
|
||||
|
||||
if( already_loaded )
|
||||
*already_loaded = false;
|
||||
|
||||
if( !Q_stricmp( ext, "pak" ))
|
||||
pak = FS_LoadPackPAK( pakfile, &errorcode );
|
||||
|
||||
if( pak )
|
||||
{
|
||||
string fullpath;
|
||||
|
||||
search = (searchpath_t *)Mem_Calloc( fs_mempool, sizeof( searchpath_t ));
|
||||
search->pack = pak;
|
||||
search->type = SEARCHPATH_PAK;
|
||||
search->next = fs_searchpaths;
|
||||
search->flags |= flags;
|
||||
fs_searchpaths = search;
|
||||
|
||||
Con_Reportf( "Adding pakfile: %s (%i files)\n", pakfile, pak->numfiles );
|
||||
|
||||
// time to add in search list all the wads that contains in current pakfile (if do)
|
||||
for( i = 0; i < pak->numfiles; i++ )
|
||||
{
|
||||
if( !Q_stricmp( COM_FileExtension( pak->files[i].name ), "wad" ))
|
||||
{
|
||||
Q_snprintf( fullpath, MAX_STRING, "%s/%s", pakfile, pak->files[i].name );
|
||||
FS_AddWad_Fullpath( fullpath, NULL, flags );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( errorcode != PAK_LOAD_NO_FILES )
|
||||
Con_Reportf( S_ERROR "FS_AddPak_Fullpath: unable to load pak \"%s\"\n", pakfile );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int FS_FindFilePAK( pack_t *pack, const char *name )
|
||||
{
|
||||
int left, right, middle;
|
||||
|
||||
// look for the file (binary search)
|
||||
left = 0;
|
||||
right = pack->numfiles - 1;
|
||||
while( left <= right )
|
||||
{
|
||||
int diff;
|
||||
|
||||
middle = (left + right) / 2;
|
||||
diff = Q_stricmp( pack->files[middle].name, name );
|
||||
|
||||
// Found it
|
||||
if( !diff )
|
||||
{
|
||||
return middle;
|
||||
}
|
||||
|
||||
// if we're too far in the list
|
||||
if( diff > 0 )
|
||||
right = middle - 1;
|
||||
else left = middle + 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void FS_SearchPAK( stringlist_t *list, pack_t *pack, const char *pattern )
|
||||
{
|
||||
string temp;
|
||||
const char *slash, *backslash, *colon, *separator;
|
||||
int j, i;
|
||||
|
||||
for( i = 0; i < pack->numfiles; i++ )
|
||||
{
|
||||
Q_strncpy( temp, pack->files[i].name, sizeof( temp ));
|
||||
while( temp[0] )
|
||||
{
|
||||
if( matchpattern( temp, pattern, true ))
|
||||
{
|
||||
for( j = 0; j < list->numstrings; j++ )
|
||||
{
|
||||
if( !Q_strcmp( list->strings[j], temp ))
|
||||
break;
|
||||
}
|
||||
|
||||
if( j == list->numstrings )
|
||||
stringlistappend( list, temp );
|
||||
}
|
||||
|
||||
// strip off one path element at a time until empty
|
||||
// this way directories are added to the listing if they match the pattern
|
||||
slash = Q_strrchr( temp, '/' );
|
||||
backslash = Q_strrchr( temp, '\\' );
|
||||
colon = Q_strrchr( temp, ':' );
|
||||
separator = temp;
|
||||
if( separator < slash )
|
||||
separator = slash;
|
||||
if( separator < backslash )
|
||||
separator = backslash;
|
||||
if( separator < colon )
|
||||
separator = colon;
|
||||
*((char *)separator) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int FS_FileTimePAK( pack_t *pack )
|
||||
{
|
||||
return pack->filetime;
|
||||
}
|
||||
|
||||
void FS_PrintPAKInfo( char *dst, size_t size, pack_t *pack )
|
||||
{
|
||||
Q_snprintf( dst, size, "%s (%i files)", pack->filename, pack->numfiles );
|
||||
}
|
||||
|
||||
void FS_ClosePAK( pack_t *pack )
|
||||
{
|
||||
if( pack->files )
|
||||
Mem_Free( pack->files );
|
||||
if( pack->handle >= 0 )
|
||||
close( pack->handle );
|
||||
Mem_Free( pack );
|
||||
}
|
||||
636
filesystem/wad.c
636
filesystem/wad.c
@@ -1,636 +0,0 @@
|
||||
/*
|
||||
wad.c - WAD support for filesystem
|
||||
Copyright (C) 2007 Uncle Mike
|
||||
Copyright (C) 2022 Alibek Omarov
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#if XASH_POSIX
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include "port.h"
|
||||
#include "filesystem_internal.h"
|
||||
#include "crtlib.h"
|
||||
#include "common/com_strings.h"
|
||||
#include "wadfile.h"
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
.WAD archive format (WhereAllData - WAD)
|
||||
|
||||
List of compressed files, that can be identify only by TYPE_*
|
||||
|
||||
<format>
|
||||
header: dwadinfo_t[dwadinfo_t]
|
||||
file_1: byte[dwadinfo_t[num]->disksize]
|
||||
file_2: byte[dwadinfo_t[num]->disksize]
|
||||
file_3: byte[dwadinfo_t[num]->disksize]
|
||||
...
|
||||
file_n: byte[dwadinfo_t[num]->disksize]
|
||||
infotable dlumpinfo_t[dwadinfo_t->numlumps]
|
||||
========================================================================
|
||||
*/
|
||||
#define WAD3_NAMELEN 16
|
||||
#define HINT_NAMELEN 5 // e.g. _mask, _norm
|
||||
#define MAX_FILES_IN_WAD 65535 // real limit as above <2Gb size not a lumpcount
|
||||
|
||||
#include "const.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int ident; // should be WAD3
|
||||
int numlumps; // num files
|
||||
int infotableofs; // LUT offset
|
||||
} dwadinfo_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int filepos; // file offset in WAD
|
||||
int disksize; // compressed or uncompressed
|
||||
int size; // uncompressed
|
||||
signed char type; // TYP_*
|
||||
signed char attribs; // file attribs
|
||||
signed char pad0;
|
||||
signed char pad1;
|
||||
char name[WAD3_NAMELEN]; // must be null terminated
|
||||
} dlumpinfo_t;
|
||||
|
||||
struct wfile_s
|
||||
{
|
||||
string filename;
|
||||
int infotableofs;
|
||||
int numlumps;
|
||||
poolhandle_t mempool; // W_ReadLump temp buffers
|
||||
file_t *handle;
|
||||
dlumpinfo_t *lumps;
|
||||
time_t filetime;
|
||||
};
|
||||
|
||||
// WAD errors
|
||||
#define WAD_LOAD_OK 0
|
||||
#define WAD_LOAD_COULDNT_OPEN 1
|
||||
#define WAD_LOAD_BAD_HEADER 2
|
||||
#define WAD_LOAD_BAD_FOLDERS 3
|
||||
#define WAD_LOAD_TOO_MANY_FILES 4
|
||||
#define WAD_LOAD_NO_FILES 5
|
||||
#define WAD_LOAD_CORRUPTED 6
|
||||
|
||||
typedef struct wadtype_s
|
||||
{
|
||||
const char *ext;
|
||||
signed char type;
|
||||
} wadtype_t;
|
||||
|
||||
// associate extension with wad type
|
||||
static const wadtype_t wad_types[7] =
|
||||
{
|
||||
{ "pal", TYP_PALETTE }, // palette
|
||||
{ "dds", TYP_DDSTEX }, // DDS image
|
||||
{ "lmp", TYP_GFXPIC }, // quake1, hl pic
|
||||
{ "fnt", TYP_QFONT }, // hl qfonts
|
||||
{ "mip", TYP_MIPTEX }, // hl/q1 mip
|
||||
{ "txt", TYP_SCRIPT }, // scripts
|
||||
{ NULL, TYP_NONE }
|
||||
};
|
||||
|
||||
/*
|
||||
===========
|
||||
W_TypeFromExt
|
||||
|
||||
Extracts file type from extension
|
||||
===========
|
||||
*/
|
||||
static signed char W_TypeFromExt( const char *lumpname )
|
||||
{
|
||||
const char *ext = COM_FileExtension( lumpname );
|
||||
const wadtype_t *type;
|
||||
|
||||
// we not known about filetype, so match only by filename
|
||||
if( !Q_strcmp( ext, "*" ) || !Q_strcmp( ext, "" ))
|
||||
return TYP_ANY;
|
||||
|
||||
for( type = wad_types; type->ext; type++ )
|
||||
{
|
||||
if( !Q_stricmp( ext, type->ext ))
|
||||
return type->type;
|
||||
}
|
||||
return TYP_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
W_ExtFromType
|
||||
|
||||
Convert type to extension
|
||||
===========
|
||||
*/
|
||||
static const char *W_ExtFromType( signed char lumptype )
|
||||
{
|
||||
const wadtype_t *type;
|
||||
|
||||
// we not known aboyt filetype, so match only by filename
|
||||
if( lumptype == TYP_NONE || lumptype == TYP_ANY )
|
||||
return "";
|
||||
|
||||
for( type = wad_types; type->ext; type++ )
|
||||
{
|
||||
if( lumptype == type->type )
|
||||
return type->ext;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
W_AddFileToWad
|
||||
|
||||
Add a file to the list of files contained into a package
|
||||
and sort LAT in alpha-bethical order
|
||||
====================
|
||||
*/
|
||||
static dlumpinfo_t *W_AddFileToWad( const char *name, wfile_t *wad, dlumpinfo_t *newlump )
|
||||
{
|
||||
int left, right;
|
||||
dlumpinfo_t *plump;
|
||||
|
||||
// look for the slot we should put that file into (binary search)
|
||||
left = 0;
|
||||
right = wad->numlumps - 1;
|
||||
|
||||
while( left <= right )
|
||||
{
|
||||
int middle = ( left + right ) / 2;
|
||||
int diff = Q_stricmp( wad->lumps[middle].name, name );
|
||||
|
||||
if( !diff )
|
||||
{
|
||||
if( wad->lumps[middle].type < newlump->type )
|
||||
diff = 1;
|
||||
else if( wad->lumps[middle].type > newlump->type )
|
||||
diff = -1;
|
||||
else Con_Reportf( S_WARN "Wad %s contains the file %s several times\n", wad->filename, name );
|
||||
}
|
||||
|
||||
// If we're too far in the list
|
||||
if( diff > 0 ) right = middle - 1;
|
||||
else left = middle + 1;
|
||||
}
|
||||
|
||||
// we have to move the right of the list by one slot to free the one we need
|
||||
plump = &wad->lumps[left];
|
||||
memmove( plump + 1, plump, ( wad->numlumps - left ) * sizeof( *plump ));
|
||||
wad->numlumps++;
|
||||
|
||||
*plump = *newlump;
|
||||
memcpy( plump->name, name, sizeof( plump->name ));
|
||||
|
||||
return plump;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
FS_CloseWAD
|
||||
|
||||
finalize wad or just close
|
||||
===========
|
||||
*/
|
||||
void FS_CloseWAD( wfile_t *wad )
|
||||
{
|
||||
Mem_FreePool( &wad->mempool );
|
||||
if( wad->handle != NULL )
|
||||
FS_Close( wad->handle );
|
||||
Mem_Free( wad ); // free himself
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
W_Open
|
||||
|
||||
open the wad for reading & writing
|
||||
===========
|
||||
*/
|
||||
static wfile_t *W_Open( const char *filename, int *error )
|
||||
{
|
||||
wfile_t *wad = (wfile_t *)Mem_Calloc( fs_mempool, sizeof( wfile_t ));
|
||||
const char *basename;
|
||||
int i, lumpcount;
|
||||
dlumpinfo_t *srclumps;
|
||||
size_t lat_size;
|
||||
dwadinfo_t header;
|
||||
|
||||
// NOTE: FS_Open is load wad file from the first pak in the list (while fs_ext_path is false)
|
||||
if( fs_ext_path ) basename = filename;
|
||||
else basename = COM_FileWithoutPath( filename );
|
||||
|
||||
wad->handle = FS_Open( basename, "rb", false );
|
||||
|
||||
// HACKHACK: try to open WAD by full path for RoDir, when searchpaths are not ready
|
||||
if( COM_CheckStringEmpty( fs_rodir ) && fs_ext_path && wad->handle == NULL )
|
||||
wad->handle = FS_SysOpen( filename, "rb" );
|
||||
|
||||
if( wad->handle == NULL )
|
||||
{
|
||||
Con_Reportf( S_ERROR "W_Open: couldn't open %s\n", filename );
|
||||
if( error ) *error = WAD_LOAD_COULDNT_OPEN;
|
||||
FS_CloseWAD( wad );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// copy wad name
|
||||
Q_strncpy( wad->filename, filename, sizeof( wad->filename ));
|
||||
wad->filetime = FS_SysFileTime( filename );
|
||||
wad->mempool = Mem_AllocPool( filename );
|
||||
|
||||
if( FS_Read( wad->handle, &header, sizeof( dwadinfo_t )) != sizeof( dwadinfo_t ))
|
||||
{
|
||||
Con_Reportf( S_ERROR "W_Open: %s can't read header\n", filename );
|
||||
if( error ) *error = WAD_LOAD_BAD_HEADER;
|
||||
FS_CloseWAD( wad );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( header.ident != IDWAD2HEADER && header.ident != IDWAD3HEADER )
|
||||
{
|
||||
Con_Reportf( S_ERROR "W_Open: %s is not a WAD2 or WAD3 file\n", filename );
|
||||
if( error ) *error = WAD_LOAD_BAD_HEADER;
|
||||
FS_CloseWAD( wad );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lumpcount = header.numlumps;
|
||||
|
||||
if( lumpcount >= MAX_FILES_IN_WAD )
|
||||
{
|
||||
Con_Reportf( S_WARN "W_Open: %s is full (%i lumps)\n", filename, lumpcount );
|
||||
if( error ) *error = WAD_LOAD_TOO_MANY_FILES;
|
||||
}
|
||||
else if( lumpcount <= 0 )
|
||||
{
|
||||
Con_Reportf( S_ERROR "W_Open: %s has no lumps\n", filename );
|
||||
if( error ) *error = WAD_LOAD_NO_FILES;
|
||||
FS_CloseWAD( wad );
|
||||
return NULL;
|
||||
}
|
||||
else if( error ) *error = WAD_LOAD_OK;
|
||||
|
||||
wad->infotableofs = header.infotableofs; // save infotableofs position
|
||||
|
||||
if( FS_Seek( wad->handle, wad->infotableofs, SEEK_SET ) == -1 )
|
||||
{
|
||||
Con_Reportf( S_ERROR "W_Open: %s can't find lump allocation table\n", filename );
|
||||
if( error ) *error = WAD_LOAD_BAD_FOLDERS;
|
||||
FS_CloseWAD( wad );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lat_size = lumpcount * sizeof( dlumpinfo_t );
|
||||
|
||||
// NOTE: lumps table can be reallocated for O_APPEND mode
|
||||
srclumps = (dlumpinfo_t *)Mem_Malloc( wad->mempool, lat_size );
|
||||
|
||||
if( FS_Read( wad->handle, srclumps, lat_size ) != lat_size )
|
||||
{
|
||||
Con_Reportf( S_ERROR "W_ReadLumpTable: %s has corrupted lump allocation table\n", wad->filename );
|
||||
if( error ) *error = WAD_LOAD_CORRUPTED;
|
||||
Mem_Free( srclumps );
|
||||
FS_CloseWAD( wad );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// starting to add lumps
|
||||
wad->lumps = (dlumpinfo_t *)Mem_Calloc( wad->mempool, lat_size );
|
||||
wad->numlumps = 0;
|
||||
|
||||
// sort lumps for binary search
|
||||
for( i = 0; i < lumpcount; i++ )
|
||||
{
|
||||
char name[16];
|
||||
int k;
|
||||
|
||||
// cleanup lumpname
|
||||
Q_strnlwr( srclumps[i].name, name, sizeof( srclumps[i].name ));
|
||||
|
||||
// check for '*' symbol issues (quake1)
|
||||
k = Q_strlen( Q_strrchr( name, '*' ));
|
||||
if( k ) name[Q_strlen( name ) - k] = '!';
|
||||
|
||||
// check for Quake 'conchars' issues (only lmp loader really allows to read this lame pic)
|
||||
if( srclumps[i].type == 68 && !Q_stricmp( srclumps[i].name, "conchars" ))
|
||||
srclumps[i].type = TYP_GFXPIC;
|
||||
|
||||
W_AddFileToWad( name, wad, &srclumps[i] );
|
||||
}
|
||||
|
||||
// release source lumps
|
||||
Mem_Free( srclumps );
|
||||
|
||||
// and leave the file open
|
||||
return wad;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
FS_AddWad_Fullpath
|
||||
====================
|
||||
*/
|
||||
qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loaded, int flags )
|
||||
{
|
||||
searchpath_t *search;
|
||||
wfile_t *wad = NULL;
|
||||
const char *ext = COM_FileExtension( wadfile );
|
||||
int errorcode = WAD_LOAD_COULDNT_OPEN;
|
||||
|
||||
for( search = fs_searchpaths; search; search = search->next )
|
||||
{
|
||||
if( search->type == SEARCHPATH_WAD && !Q_stricmp( search->wad->filename, wadfile ))
|
||||
{
|
||||
if( already_loaded ) *already_loaded = true;
|
||||
return true; // already loaded
|
||||
}
|
||||
}
|
||||
|
||||
if( already_loaded )
|
||||
*already_loaded = false;
|
||||
|
||||
if( !Q_stricmp( ext, "wad" ))
|
||||
wad = W_Open( wadfile, &errorcode );
|
||||
|
||||
if( wad )
|
||||
{
|
||||
search = (searchpath_t *)Mem_Calloc( fs_mempool, sizeof( searchpath_t ));
|
||||
search->wad = wad;
|
||||
search->type = SEARCHPATH_WAD;
|
||||
search->next = fs_searchpaths;
|
||||
search->flags |= flags;
|
||||
fs_searchpaths = search;
|
||||
|
||||
Con_Reportf( "Adding wadfile: %s (%i files)\n", wadfile, wad->numlumps );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( errorcode != WAD_LOAD_NO_FILES )
|
||||
Con_Reportf( S_ERROR "FS_AddWad_Fullpath: unable to load wad \"%s\"\n", wadfile );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
WADSYSTEM PRIVATE ROUTINES
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
===========
|
||||
W_FindLump
|
||||
|
||||
Serach for already existed lump
|
||||
===========
|
||||
*/
|
||||
static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const signed char matchtype )
|
||||
{
|
||||
int left, right;
|
||||
|
||||
if( !wad || !wad->lumps || matchtype == TYP_NONE )
|
||||
return NULL;
|
||||
|
||||
// look for the file (binary search)
|
||||
left = 0;
|
||||
right = wad->numlumps - 1;
|
||||
|
||||
while( left <= right )
|
||||
{
|
||||
int middle = (left + right) / 2;
|
||||
int diff = Q_stricmp( wad->lumps[middle].name, name );
|
||||
|
||||
if( !diff )
|
||||
{
|
||||
if(( matchtype == TYP_ANY ) || ( matchtype == wad->lumps[middle].type ))
|
||||
return &wad->lumps[middle]; // found
|
||||
else if( wad->lumps[middle].type < matchtype )
|
||||
diff = 1;
|
||||
else if( wad->lumps[middle].type > matchtype )
|
||||
diff = -1;
|
||||
else break; // not found
|
||||
}
|
||||
|
||||
// if we're too far in the list
|
||||
if( diff > 0 ) right = middle - 1;
|
||||
else left = middle + 1;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
W_ReadLump
|
||||
|
||||
reading lump into temp buffer
|
||||
===========
|
||||
*/
|
||||
static byte *W_ReadLump( wfile_t *wad, dlumpinfo_t *lump, fs_offset_t *lumpsizeptr )
|
||||
{
|
||||
size_t oldpos, size = 0;
|
||||
byte *buf;
|
||||
|
||||
// assume error
|
||||
if( lumpsizeptr ) *lumpsizeptr = 0;
|
||||
|
||||
// no wads loaded
|
||||
if( !wad || !lump ) return NULL;
|
||||
|
||||
oldpos = FS_Tell( wad->handle ); // don't forget restore original position
|
||||
|
||||
if( FS_Seek( wad->handle, lump->filepos, SEEK_SET ) == -1 )
|
||||
{
|
||||
Con_Reportf( S_ERROR "W_ReadLump: %s is corrupted\n", lump->name );
|
||||
FS_Seek( wad->handle, oldpos, SEEK_SET );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = (byte *)Mem_Malloc( wad->mempool, lump->disksize );
|
||||
size = FS_Read( wad->handle, buf, lump->disksize );
|
||||
|
||||
if( size < lump->disksize )
|
||||
{
|
||||
Con_Reportf( S_WARN "W_ReadLump: %s is probably corrupted\n", lump->name );
|
||||
FS_Seek( wad->handle, oldpos, SEEK_SET );
|
||||
Mem_Free( buf );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( lumpsizeptr ) *lumpsizeptr = lump->disksize;
|
||||
FS_Seek( wad->handle, oldpos, SEEK_SET );
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
FS_LoadWADFile
|
||||
|
||||
loading lump into the tmp buffer
|
||||
===========
|
||||
*/
|
||||
byte *FS_LoadWADFile( const char *path, fs_offset_t *lumpsizeptr, qboolean gamedironly )
|
||||
{
|
||||
searchpath_t *search;
|
||||
int index;
|
||||
|
||||
search = FS_FindFile( path, &index, gamedironly );
|
||||
if( search && search->type == SEARCHPATH_WAD )
|
||||
return W_ReadLump( search->wad, &search->wad->lumps[index], lumpsizeptr );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int FS_FileTimeWAD( wfile_t *wad )
|
||||
{
|
||||
return wad->filetime;
|
||||
}
|
||||
|
||||
void FS_PrintWADInfo( char *dst, size_t size, wfile_t *wad )
|
||||
{
|
||||
Q_snprintf( dst, size, "%s (%i files)", wad->filename, wad->numlumps );
|
||||
}
|
||||
|
||||
int FS_FindFileWAD( wfile_t *wad, const char *name )
|
||||
{
|
||||
dlumpinfo_t *lump;
|
||||
signed char type = W_TypeFromExt( name );
|
||||
qboolean anywadname = true;
|
||||
string wadname, wadfolder;
|
||||
string shortname;
|
||||
|
||||
// quick reject by filetype
|
||||
if( type == TYP_NONE )
|
||||
return -1;
|
||||
|
||||
COM_ExtractFilePath( name, wadname );
|
||||
wadfolder[0] = '\0';
|
||||
|
||||
if( COM_CheckStringEmpty( wadname ) )
|
||||
{
|
||||
COM_FileBase( wadname, wadname );
|
||||
Q_strncpy( wadfolder, wadname, sizeof( wadfolder ));
|
||||
COM_DefaultExtension( wadname, ".wad" );
|
||||
anywadname = false;
|
||||
}
|
||||
|
||||
// make wadname from wad fullpath
|
||||
COM_FileBase( wad->filename, shortname );
|
||||
COM_DefaultExtension( shortname, ".wad" );
|
||||
|
||||
// quick reject by wadname
|
||||
if( !anywadname && Q_stricmp( wadname, shortname ))
|
||||
return -1;
|
||||
|
||||
// NOTE: we can't using long names for wad,
|
||||
// because we using original wad names[16];
|
||||
COM_FileBase( name, shortname );
|
||||
|
||||
lump = W_FindLump( wad, shortname, type );
|
||||
|
||||
if( lump )
|
||||
{
|
||||
return lump - wad->lumps;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
void FS_SearchWAD( stringlist_t *list, wfile_t *wad, const char *pattern )
|
||||
{
|
||||
string wadpattern, wadname, temp2;
|
||||
signed char type = W_TypeFromExt( pattern );
|
||||
qboolean anywadname = true;
|
||||
string wadfolder, temp;
|
||||
int j, i;
|
||||
const char *slash, *backslash, *colon, *separator;
|
||||
|
||||
// quick reject by filetype
|
||||
if( type == TYP_NONE )
|
||||
return;
|
||||
|
||||
COM_ExtractFilePath( pattern, wadname );
|
||||
COM_FileBase( pattern, wadpattern );
|
||||
wadfolder[0] = '\0';
|
||||
|
||||
if( COM_CheckStringEmpty( wadname ))
|
||||
{
|
||||
COM_FileBase( wadname, wadname );
|
||||
Q_strncpy( wadfolder, wadname, sizeof( wadfolder ));
|
||||
COM_DefaultExtension( wadname, ".wad" );
|
||||
anywadname = false;
|
||||
}
|
||||
|
||||
// make wadname from wad fullpath
|
||||
COM_FileBase( wad->filename, temp2 );
|
||||
COM_DefaultExtension( temp2, ".wad" );
|
||||
|
||||
// quick reject by wadname
|
||||
if( !anywadname && Q_stricmp( wadname, temp2 ))
|
||||
return;
|
||||
|
||||
for( i = 0; i < wad->numlumps; i++ )
|
||||
{
|
||||
// if type not matching, we already have no chance ...
|
||||
if( type != TYP_ANY && wad->lumps[i].type != type )
|
||||
continue;
|
||||
|
||||
// build the lumpname with image suffix (if present)
|
||||
Q_strncpy( temp, wad->lumps[i].name, sizeof( temp ));
|
||||
|
||||
while( temp[0] )
|
||||
{
|
||||
if( matchpattern( temp, wadpattern, true ))
|
||||
{
|
||||
for( j = 0; j < list->numstrings; j++ )
|
||||
{
|
||||
if( !Q_strcmp( list->strings[j], temp ))
|
||||
break;
|
||||
}
|
||||
|
||||
if( j == list->numstrings )
|
||||
{
|
||||
// build path: wadname/lumpname.ext
|
||||
Q_snprintf( temp2, sizeof(temp2), "%s/%s", wadfolder, temp );
|
||||
COM_DefaultExtension( temp2, va(".%s", W_ExtFromType( wad->lumps[i].type )));
|
||||
stringlistappend( list, temp2 );
|
||||
}
|
||||
}
|
||||
|
||||
// strip off one path element at a time until empty
|
||||
// this way directories are added to the listing if they match the pattern
|
||||
slash = Q_strrchr( temp, '/' );
|
||||
backslash = Q_strrchr( temp, '\\' );
|
||||
colon = Q_strrchr( temp, ':' );
|
||||
separator = temp;
|
||||
if( separator < slash )
|
||||
separator = slash;
|
||||
if( separator < backslash )
|
||||
separator = backslash;
|
||||
if( separator < colon )
|
||||
separator = colon;
|
||||
*((char *)separator) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user