Compare commits

..

1 Commits

Author SHA1 Message Date
Alibek Omarov
c395acad63 engine: try to detect LoadLibrary/FreeLibrary leaks 2022-06-12 03:08:47 +03:00
189 changed files with 4663 additions and 7510 deletions

3
.gitignore vendored
View File

@@ -331,5 +331,4 @@ __pycache__
.vscode/*
*.code-workspace
.history/*
.cache/*
enc_temp_folder/
.cache/*

17
.gitmodules vendored
View File

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

Submodule 3rdparty/gl4es/gl4es deleted from 5c28420a38

View File

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

Submodule 3rdparty/mainui deleted from 14c0922af7

1
3rdparty/opus/opus vendored

Submodule 3rdparty/opus/opus deleted from 997fdf54e7

40
3rdparty/opus/wscript vendored
View File

@@ -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/']
)

Submodule 3rdparty/vgui_support deleted from 63c134f188

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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,

View File

@@ -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;

View File

@@ -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 ();

View File

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

View File

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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

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

View File

@@ -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:

View File

@@ -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;

View File

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

View File

@@ -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();

View File

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

View File

@@ -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;
}

View File

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

View File

@@ -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" );

View File

@@ -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 );
}
}

View File

@@ -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;
}
}

View File

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

View File

@@ -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;
}

View File

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

View File

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

View File

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

View File

@@ -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" }

View File

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

View File

@@ -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"

View File

@@ -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;

View File

@@ -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
View 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

View File

@@ -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();
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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)
};

View File

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

View File

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

View File

@@ -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;
}
/*
=============================================================================

View File

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

View File

@@ -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 );
}
}

View File

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

View File

@@ -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];
}

View File

@@ -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();

View File

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

View File

@@ -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
//

View File

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

View File

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

View File

@@ -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();
}

View File

@@ -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;
}

View File

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

View File

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

View File

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

View File

@@ -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 );
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
}

View File

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

View File

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

View File

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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 );
}
/*

View File

@@ -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 );
}

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;

View File

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

View File

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

View File

@@ -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( &copy, &g_api, sizeof( copy ));
if( retval ) *retval = 0;
return &copy;
}
if( retval ) *retval = 1;
return NULL;
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 );
}

View File

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